void SendToForwarder::AddConnection(UserID userID, const NetworkConnectionPtr& primaryConnection, const NetworkConnectionPtr& secondaryConnection) { primaryConnection->AddListener(MessageID::SendTo, this); secondaryConnection->AddListener(MessageID::SendTo, this); ConnectionInfo newConnection; newConnection.m_primaryConnection = primaryConnection; newConnection.m_secondaryConnection = secondaryConnection; m_connections[userID] = newConnection; }
void SyncManagerImpl::OnIdentityInfoReceived(const NetworkConnectionPtr& connection, NetworkInMessage& msg) { size_t connectionIndex; if (GetIndexOfConnection(connection, connectionIndex)) { #if defined(SYNC_DEBUG) LogInfo("Sync: Received Handshake"); #endif RemoteSyncPeer& remotePeer = m_remoteHosts[connectionIndex]; remotePeer.m_authorityLevel = static_cast<AuthorityLevel>(msg.ReadByte()); remotePeer.m_systemID = msg.ReadInt32(); remotePeer.m_userName = msg.ReadStdString(); remotePeer.m_userID = msg.ReadInt32(); // Verify that this systemID is not already in use by another machine. If so, force a disconnection // rather than risk data corruption, because GUIDS are based on SystemIDs bool duplicateSystemIDFound = (m_syncContext->GetLocalSystemID() == remotePeer.m_systemID); if (!duplicateSystemIDFound) { for (size_t i = 0; i < m_remoteHosts.size(); ++i) { if (i == connectionIndex) continue; if (m_remoteHosts[i].m_systemID == remotePeer.m_systemID) { duplicateSystemIDFound = true; break; } } } // The sync system will break down if two machines of equal authority level connect. // So verify that they are different levels, or else disconnect bool authLevelsMatch = (remotePeer.m_authorityLevel == m_syncContext->GetAuthorityLevel()); if (duplicateSystemIDFound || authLevelsMatch) { // We're registered to receive disconnect callbacks, so we know that SyncManagerImpl::OnDisconnected() // will be called as a result of calling this. if (authLevelsMatch) { LogError("Two machines with equal authority levels have connected: breaking the connection to avoid sync data corruption"); } else { LogError("Duplicate system ID detected: breaking the connection to avoid sync data corruption"); } XTASSERT(!duplicateSystemIDFound); connection->Disconnect(); } // We should not be receiving a handshake message more than once XTASSERT(remotePeer.m_bHandshakeComplete == false); remotePeer.m_bHandshakeComplete = true; } }
void SessionImpl::OnConnected(const NetworkConnectionPtr& connection) { // We have successfully connected to this session. // Now send it information about us so it lets us in all the way XTASSERT(m_curState == MachineSessionState::JOINING); JoinSessionRequest request( m_context->GetLocalUser()->GetName()->GetString(), m_context->GetLocalUser()->GetID(), m_context->GetLocalUser()->GetMuteState() ); NetworkOutMessagePtr msg = connection->CreateMessage(MessageID::SessionControl); msg->Write(new XString(request.ToJSONString())); connection->Send(msg); }
void SessionServer::OnListSessionsRequest(const ListSessionsRequest&, const NetworkConnectionPtr& connection) { // Fill in a message with a list of all the sessions and send it ListSessionsReply reply; reply.SetSessionCount(static_cast<int32>(m_sessions.size())); for (size_t i = 0; i < m_sessions.size(); ++i) { XSessionImplPtr currentSession = m_sessions[i]; reply.SetSessionDescriptor((int32)i, currentSession->GetSessionDescription(connection->GetSocket())); } NetworkOutMessagePtr msg = connection->CreateMessage(MessageID::SessionControl); msg->Write(reply.ToJSONString()); connection->Send(msg); }
void SendToForwarder::OnMessageReceived(const NetworkConnectionPtr& connection, NetworkInMessage& message) { const byte* inMsg = message.GetData(); const uint32 inMsgSize = message.GetSize(); // Get the sendto header const SendToNetworkHeader* sendToHeader = reinterpret_cast<const SendToNetworkHeader*>(inMsg); // Extract the payload from the sendto message and put in a new outgoing message const byte* payload = inMsg + sizeof(SendToNetworkHeader); const uint32 payloadSize = inMsgSize - sizeof(SendToNetworkHeader); if (payloadSize > 0) { NetworkOutMessagePtr outMsg = connection->CreateMessage(*payload); outMsg->WriteArray(payload + 1, payloadSize - 1); // Send the payload to the correct remote peer auto userConnectionItr = m_connections.find(sendToHeader->m_userID); if (userConnectionItr != m_connections.end()) { ClientRole role = sendToHeader->m_deviceRole; if (role == ClientRole::Primary || role == ClientRole::Unspecified) { // Forward the message on with the same settings that it was sent here with userConnectionItr->second.m_primaryConnection ->Send(outMsg, sendToHeader->m_priority, sendToHeader->m_reliability, sendToHeader->m_channel, false); } if (role == ClientRole::Secondary || role == ClientRole::Unspecified) { // Forward the message on with the same settings that it was sent here with userConnectionItr->second.m_secondaryConnection->Send(outMsg, sendToHeader->m_priority, sendToHeader->m_reliability, sendToHeader->m_channel, false); } } connection->ReturnMessage(outMsg); } }
void SyncManagerImpl::AddConnection(const NetworkConnectionPtr& newConnection) { #if defined(SYNC_DEBUG) LogInfo("%s Adding Connection", m_syncContext->GetLocalUser()->GetName().GetString().c_str()); #endif newConnection->AddListener(m_messageID, this); m_remoteHosts.resize(m_remoteHosts.size() + 1, RemoteSyncPeer()); RemoteSyncPeer& newPeer = m_remoteHosts.back(); newPeer.m_connection = newConnection; // Automatically remove this object as a listener when newPeer is destroyed newPeer.m_listenerReceipt = CreateRegistrationReceipt(newConnection, &NetworkConnection::RemoveListener, m_messageID, this); if (newConnection->IsConnected()) { SendHandshakeMessage(newPeer); } }
void SessionServer::OnMessageReceived(const NetworkConnectionPtr& connection, NetworkInMessage& message) { XStringPtr command = message.ReadString(); JSONMessagePtr jMsg = JSONMessage::CreateFromMessage(command->GetString()); // Route the incoming message to the appropriate function to handle it if (!m_messageRouter.CallHandler(jMsg, connection)) { // We got a bad or unexpected message; break the connection connection->Disconnect(); } }
void XSessionImpl::OnMessageReceived(const NetworkConnectionPtr& connection, NetworkInMessage& message) { XStringPtr command = message.ReadString(); JSONMessagePtr jMsg = JSONMessage::CreateFromMessage(command->GetString()); // Route the incoming message to the appropriate function to handle it if (!m_messageRouter.CallHandler(jMsg, connection)) { // There was a problem with the message that was sent. Boot the connection connection->Disconnect(); } }
void SessionServer::OnNewSessionRequest(const NewSessionRequest& request, const NetworkConnectionPtr& connection) { std::string name = request.GetSessionName(); XSessionImplPtr session; std::string failureReason; // Cannot create a session with a name that is too short if (name.length() < kMinSessionNameLength) { failureReason = "Session name must have at least " + std::to_string(kMinSessionNameLength) + " letters"; } // Cannot create a session with a name that is too long else if (name.length() > kMaxSessionNameLength) { failureReason = "Session name cannot be more than " + std::to_string(kMaxSessionNameLength) + " letters"; } else { // Check to make sure that the requested session name is not already taken for (size_t i = 0; i < m_sessions.size(); ++i) { if (m_sessions[i]->GetName() == name) { failureReason = "A session with that name already exists"; break; } } } if (failureReason.empty()) { session = CreateNewSession(name, request.GetSessionType()); } // If the session was successfully created... if (session) { // Report success. std::string address = m_socketMgr->GetLocalAddressForRemoteClient(connection->GetSocket()); uint16 port = session->GetPort(); NewSessionReply reply( session->GetId(), session->GetType(), name, address, port); NetworkOutMessagePtr response = connection->CreateMessage(MessageID::SessionControl); response->Write(reply.ToJSONString()); connection->Send(response); } else { // Report failure NewSessionReply reply(failureReason); NetworkOutMessagePtr response = connection->CreateMessage(MessageID::SessionControl); response->Write(reply.ToJSONString()); connection->Send(response); } }
void XSessionImpl::OnJoinSessionRequest(const JoinSessionRequest& request, const NetworkConnectionPtr& connection) { // Note: this call will remove the remote client from the list of pending connections RemoteClientPtr remoteClient = GetPendingClientForConnection(connection); if (remoteClient) { // Fill in the rest of the info about the user remoteClient->m_userName = request.GetUserName(); remoteClient->m_userID = request.GetUserID(); remoteClient->m_userMuteState = request.GetMuteState(); // Check to see if this userID is already in use by someone in the session bool bDuplicateUserID = false; for (size_t clientIndex = 0; clientIndex < m_clients.size(); ++clientIndex) { if (m_clients[clientIndex]->m_userID == remoteClient->m_userID) { bDuplicateUserID = true; LogError("UserID %i in session join request is a duplicate of a user already in this session. ", remoteClient->m_userID); break; } } // Check to see if the userID is valid bool bIsInvalidUserID = false; if (remoteClient->m_userID == User::kInvalidUserID) { LogError("Received invalid userID"); bIsInvalidUserID = true; } // If the connecting user is invalid, then send a failure response and shut down the connection if (bIsInvalidUserID || bDuplicateUserID) { // Reply to the user that they have failed to join the session { JoinSessionReply reply(false); NetworkOutMessagePtr msg = connection->CreateMessage(MessageID::SessionControl); msg->Write(reply.ToJSONString()); connection->Send(msg); } // Disconnect connection->Disconnect(); } else { LogInfo("User %s at address %s joined session %s", remoteClient->m_userName.c_str(), remoteClient->m_primaryConnection->GetRemoteAddress()->GetString().c_str(), GetName().c_str()); // Add the user to the real list of clients in the session m_clients.push_back(remoteClient); // Reply to the user that they have now joined the session successfully { JoinSessionReply reply(true); NetworkOutMessagePtr msg = connection->CreateMessage(MessageID::SessionControl); msg->Write(reply.ToJSONString()); connection->Send(msg); } // Add the remoteClient to the list that can send and receive broadcasts m_broadcaster->AddConnection(remoteClient->m_primaryConnection); m_broadcaster->AddConnection(remoteClient->m_secondaryConnection); // Add the remoteClient to the sendto forwarder m_sendToForwarder->AddConnection(remoteClient->m_userID, remoteClient->m_primaryConnection, remoteClient->m_secondaryConnection); // Add the remoteClient to the audio packet processor m_audioSessionProcessor->AddConnection(remoteClient->m_primaryConnection); m_audioSessionProcessor->AddConnection(remoteClient->m_secondaryConnection); // Add the connections to the room manager m_roomMgr->AddConnection(remoteClient->m_primaryConnection); m_roomMgr->AddConnection(remoteClient->m_secondaryConnection); // Add the remoteClient to the list that can share the session's sync data m_syncMgr->AddConnection(remoteClient->m_primaryConnection); m_internalSyncMgr->AddConnection(remoteClient->m_primaryConnection); // Notify the session server to tell all the clients that the new user has joined this session m_callback->OnUserJoinedSession(m_id, remoteClient->m_userName, remoteClient->m_userID, remoteClient->m_userMuteState); } } }