#include #include #include #include #include "osc/OscOutboundPacketStream.h" #include "defines.h" #include "Connection.h" #include "Log.h" Connection::Connection() { receiver_ = nullptr; } bool Connection::init() { // add default info for myself connections_.push_back(ConnectionInfo()); // try to open a socket at base handshake port int trial = 0; while (trial < MAX_HANDSHAKE) { try { // increment the port to have unique ports connections_[0].port_handshake = HANDSHAKE_PORT + trial; connections_[0].port_stream_send = STREAM_REQUEST_PORT + trial; connections_[0].port_stream_receive = STREAM_RESPONSE_PORT + trial; // try to create listenning socket // through exception runtime if fails receiver_ = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, connections_[0].port_handshake ), &listener_ ); // all good trial = MAX_HANDSHAKE; } catch(const std::runtime_error& e) { // arg, the receiver could not be initialized // because the port was not available receiver_ = nullptr; } // try again trial++; } // perfect, we could initialize the receiver if (receiver_!=nullptr) { // listen for answers std::thread(listen).detach(); // regularly check for available streaming hosts std::thread(ask).detach(); } return receiver_ != nullptr; } void Connection::terminate() { if (receiver_!=nullptr) receiver_->AsynchronousBreak(); } int Connection::numHosts () const { return connections_.size(); } ConnectionInfo Connection::info(int index) { if (connections_.empty()) { connections_.push_back(ConnectionInfo()); } index = CLAMP(index, 0, connections_.size()); return connections_[index]; } void Connection::print() { for(int i = 0; i::const_iterator p = std::find(connections_.begin(), connections_.end(), i); if (p != connections_.end()) id = std::distance(connections_.begin(), p); return id; } void Connection::listen() { // Log::Info("Accepting handshake on %d", Connection::manager().connections_[0].port_handshake); Connection::manager().receiver_->Run(); } void Connection::ask() { // Log::Info("Broadcasting handshakes with info %d", Connection::manager().connections_[0].port_handshake); // prepare OSC PING message char buffer[IP_MTU_SIZE]; osc::OutboundPacketStream p( buffer, IP_MTU_SIZE ); p.Clear(); p << osc::BeginMessage( OSC_PREFIX OSC_PING ); p << Connection::manager().connections_[0].port_handshake; p << osc::EndMessage; // broadcast on several ports, except myself std::vector handshake_ports; for(int i=HANDSHAKE_PORT; iAsInt32(); // Log::Info("Receive PING from %s:%d", remote_ip.c_str(), remote_port); // build message char buffer[IP_MTU_SIZE]; osc::OutboundPacketStream p( buffer, IP_MTU_SIZE ); p.Clear(); p << osc::BeginMessage( OSC_PREFIX OSC_PONG ); p << Connection::manager().connections_[0].port_handshake; p << Connection::manager().connections_[0].port_stream_send; p << Connection::manager().connections_[0].port_stream_receive; p << osc::EndMessage; // send OSC message to port indicated by remote IpEndpointName host( remote_ip.c_str(), remote_port ); UdpTransmitSocket socket( host ); socket.Send( p.Data(), p.Size() ); // Log::Info("reply PONG to %s:%d", remote_ip.c_str(), remote_port); } // pong response: add info else if( std::strcmp( m.AddressPattern(), OSC_PREFIX OSC_PONG) == 0 ){ // create info struct ConnectionInfo info; info.address_ = remote_ip; // add all ports info osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); info.port_handshake = (arg++)->AsInt32(); info.port_stream_send = (arg++)->AsInt32(); info.port_stream_receive = (arg++)->AsInt32(); int i = Connection::manager().index(info); if ( i < 0) { // add to list info.status = 3; Connection::manager().connections_.push_back(info); // Log::Info("Received PONG from %s:%d : added", info.address_.c_str(), info.port_handshake); // Connection::manager().print(); } else { // set high (== ALIVE) Connection::manager().connections_[i].status = 3; } } } catch( osc::Exception& e ){ // any parsing errors such as unexpected argument types, or // missing arguments get thrown as exceptions. Log::Info("error while parsing message '%s' from %s : %s", m.AddressPattern(), sender, e.what()); } }