XSessionImplPtr SessionServer::CreateNewSession(const std::string& sessionName, SessionType type) { XSessionImplPtr xsession; uint16 sessionPort; // Better way to check for error? if (m_portPool->GetPort(sessionPort)) { uint32 id = GetNewSessionId(); xsession = new XSessionImpl(sessionName, sessionPort, type, id); // Check that the session was able to set itself up, open a socket to listen on, etc for (int creationCount = 0; !xsession->IsInitialized() && creationCount < 10; ++creationCount) { m_portPool->ReleasePort(sessionPort); if (m_portPool->GetPort(sessionPort)) { xsession = new XSessionImpl(sessionName, sessionPort, type, id); } else { break; } } if (xsession->IsInitialized()) { m_sessionChangeListener[xsession] = xsession->RegisterCallback(this); m_sessions.push_back(xsession); LogInfo("Created Session \"%s\" with ID %u on port %i", sessionName.c_str(), id, sessionPort); // Notify the listeners about the new session for (size_t i = 0; i < m_clients.size(); ++i) { SessionAddedMsg sessionAddedMsg; sessionAddedMsg.SetSessionDescriptor(xsession->GetSessionDescription(m_clients[i].m_connection->GetSocket())); NetworkOutMessagePtr msg = m_clients[i].m_connection->CreateMessage((byte)MessageID::SessionControl); msg->Write(sessionAddedMsg.ToJSONString()); m_clients[i].m_connection->Send(msg, MessagePriority::Medium, MessageReliability::ReliableOrdered, MessageChannel::Default, true); } } else { LogError("Failed to create new session %s", sessionName.c_str()); xsession = NULL; } } return xsession; }
void UserPresenceManagerLeaderImpl::PushPresenceUpdate() { // Tell any connected baraboo about the new mute state. if (m_barabooConnection->IsConnected()) { NetworkOutMessagePtr message = m_barabooConnection->CreateMessage(MessageID::UserPresenceChange); message->Write(m_localUser ? m_localUser->GetName() : NULL); message->Write(int32((m_localUser && m_localUser->GetMuteState()) ? 1 : 0)); m_barabooConnection->Send(message); } UpdateListeners(); }
void SessionServer::SendSessionMessageToAllClients(const std::string& message) { NetworkOutMessagePtr msg = m_messagePool->AcquireMessage(); msg->Write((byte)MessageID::SessionControl); msg->Write(message); for (size_t i = 0; i < m_clients.size(); ++i) { m_clients[i].m_connection->Send(msg, MessagePriority::Medium, MessageReliability::ReliableOrdered, MessageChannel::Default, false); } m_messagePool->ReturnMessage(msg); }
void SessionImpl::UpdateUser(const UserPtr& updatedUser) { // Expect this only to be called on sessions we are joined to. XTASSERT(IsJoined()); UserPtr user = FindUser(updatedUser->GetID()); // Assert that we aren't updating for a user who's not present. if (XTVERIFY(user)) { UserChangedSessionMsg userUpdateMsg(m_id, user->GetName()->GetString(), user->GetID(), user->GetMuteState()); NetworkOutMessagePtr msg = m_sessionConnection->CreateMessage(MessageID::SessionControl); msg->Write(new XString(userUpdateMsg.ToJSONString())); m_sessionConnection->Send(msg); } }
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::SendSyncMessage(RemoteSyncPeer& remotePeer) { if (remotePeer.m_bHandshakeComplete) { // If our list of ops to send is empty, and we have more than 2 ops that we have not acknowledged, // send a noop so the remote machine can release its outgoing queue and save some memory if (remotePeer.m_sendList.empty() && remotePeer.m_lastAcknowledgedVersion < remotePeer.m_localState.m_opsReceived) { VersionedOp op; op.m_op = new AckOperation(AuthorityLevel::Unknown); op.m_state = remotePeer.m_localState; remotePeer.m_sendList.push_back(op); } if (!remotePeer.m_sendList.empty()) // We have ops to send { #if defined(SYNC_DEBUG) LogInfo("Sending messages to %s", remotePeer.m_userName.c_str()); #endif NetworkOutMessagePtr msg = remotePeer.m_connection->CreateMessage(m_messageID); // Add the sub-type of the message msg->Write((byte)SyncChanges); // Write out the number of ops sent in this message msg->Write((int32)remotePeer.m_sendList.size()); // Write out each of the ops for (VersionedOpList::iterator it = remotePeer.m_sendList.begin(); it != remotePeer.m_sendList.end(); ++it) { VersionedOp& currentOp = *it; #if defined(SYNC_DEBUG) LogInfo(" - %s, version %i %i", currentOp.m_op->GetOpDescription().c_str(), currentOp.m_state.m_opsSent, currentOp.m_state.m_opsReceived); #endif // Add our view of the messages sent and received msg->Write(currentOp.m_state.m_opsSent); msg->Write(currentOp.m_state.m_opsReceived); // Write the type of the op msg->Write((byte)currentOp.m_op->GetType()); // Write the op data currentOp.m_op->Serialize(msg); // Record that we have acknowledged all the messages received remotePeer.m_lastAcknowledgedVersion = currentOp.m_state.m_opsReceived; } // Send the message remotePeer.m_connection->Send(msg); remotePeer.m_sendList.clear(); } } }
void CreateOperation::Serialize(const NetworkOutMessagePtr& msg) const { msg->Write((byte)m_elementType); msg->Write(m_name); msg->Write(m_elementGuid); msg->Write(m_parentGuid); m_startingValue.Serialize(msg); // Write the number of ancestors msg->Write(static_cast<uint32>(m_hierarchy.size())); // Write the GUIDs of the ancestors for (size_t i = 0; i < m_hierarchy.size(); ++i) { msg->Write(m_hierarchy[i]); } // NOTE: authority level is NOT included in the op when serialized; it changes as the op is sent around the network }
void SyncManagerImpl::SendHandshakeMessage(RemoteSyncPeer& remotePeer) { #if defined(SYNC_DEBUG) LogInfo("%s Sending Handshake", m_syncContext->GetLocalUser()->GetName().GetString().c_str()); #endif // We should not be sending a handshake message if its already complete XTASSERT(remotePeer.m_bHandshakeComplete == false); // Ask the remote machine to send over its systemID and its sync auth level NetworkOutMessagePtr identityMsg = remotePeer.m_connection->CreateMessage(m_messageID); identityMsg->Write((byte)IdentityInfo); identityMsg->Write((byte)m_syncContext->GetAuthorityLevel()); identityMsg->Write(m_syncContext->GetLocalSystemID()); identityMsg->Write(m_syncContext->GetLocalUser()->GetName()); identityMsg->Write(m_syncContext->GetLocalUser()->GetID()); remotePeer.m_connection->Send(identityMsg); }
void ProfileManagerImpl::Update() { // If we're connected to the profiling tool... if (m_isConnected) { // Send the accumulated profiling entries to the profiler tool NetworkOutMessagePtr msg = m_connection->CreateMessage(MessageID::Profiling); EndRange(); // Record the time it takes to pack up and send the data ProfileEntry sendInfoEntry("Send Profiling Data", 0); sendInfoEntry.Start(); // Add the profiling entries to the outgoing packet { ScopedLock threadMapLock(m_threadStackMutex); // Write the number of threads int32 numThreads = (int32)m_threadEntries.size(); msg->Write(numThreads); for (auto mapIt = m_threadEntries.begin(); mapIt != m_threadEntries.end(); ++mapIt) { ThreadInfoPtr threadInfo = mapIt->second; ScopedLock entryListLock(threadInfo->m_mutex); // Write the threadID msg->Write(threadInfo->m_threadID); std::vector<ProfileEntry>& entries = threadInfo->m_entries; // Write the number of entries in this thread uint32 numEntries = (uint32)threadInfo->m_entries.size(); msg->Write(numEntries); // Write each entry for (size_t i = 0; i < numEntries; ++i) { msg->Write(entries[i].GetName()); // Write the name msg->Write(entries[i].GetStartTime()); msg->Write(entries[i].GetDuration()); msg->Write(entries[i].GetParent()); } // Clear out the list and get ready for the next frame threadInfo->m_currentIndex = -1; } m_threadEntries.clear(); } // Add the log messages to the packet { ScopedLock lock(m_logMutex); // Write the number of log messages uint32 numMessages = (uint32)m_logMessages.size(); msg->Write(numMessages); for (uint32 i = 0; i < numMessages; ++i) { msg->Write((byte)m_logMessages[i].m_severity); msg->Write(m_logMessages[i].m_message); } m_logMessages.clear(); } BeginRange("Profile Frame"); m_connection->Send(msg, MessagePriority::Low, MessageReliability::ReliableOrdered, MessageChannel::ProfileChannel); // Add the time it took to pack up and send the data to the start of the next frame sendInfoEntry.End(); ThreadInfoPtr threadInfo = GetLocalThreadInfo(); if (threadInfo) { ScopedLock lock(threadInfo->m_mutex); threadInfo->m_entries.push_back(sendInfoEntry); } } }
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 SessionHandshakeLogic::CreateMessageFromDesktop(const NetworkOutMessagePtr& msg) const { // Schema version msg->Write(kXToolsSchemaVersion); }
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); } } }