nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : OVR_Session.h nuclear@0: Content : One network session that provides connection/disconnection events. nuclear@0: Created : June 10, 2014 nuclear@0: Authors : Kevin Jenkins, Chris Taylor nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #include "OVR_Session.h" nuclear@0: #include "OVR_PacketizedTCPSocket.h" nuclear@0: #include "../Kernel/OVR_Log.h" nuclear@0: #include "../Service/Service_NetSessionCommon.h" nuclear@0: nuclear@0: namespace OVR { namespace Net { nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------- nuclear@0: // Protocol nuclear@0: nuclear@0: static const char* OfficialHelloString = "OculusVR_Hello"; nuclear@0: static const char* OfficialAuthorizedString = "OculusVR_Authorized"; nuclear@0: nuclear@0: void RPC_C2S_Hello::Generate(Net::BitStream* bs) nuclear@0: { nuclear@0: RPC_C2S_Hello hello; nuclear@0: hello.HelloString = OfficialHelloString; nuclear@0: hello.MajorVersion = RPCVersion_Major; nuclear@0: hello.MinorVersion = RPCVersion_Minor; nuclear@0: hello.PatchVersion = RPCVersion_Patch; nuclear@0: hello.Serialize(bs); nuclear@0: } nuclear@0: nuclear@0: bool RPC_C2S_Hello::Validate() nuclear@0: { nuclear@0: return MajorVersion == RPCVersion_Major && nuclear@0: MinorVersion <= RPCVersion_Minor && nuclear@0: HelloString.CompareNoCase(OfficialHelloString) == 0; nuclear@0: } nuclear@0: nuclear@0: void RPC_S2C_Authorization::Generate(Net::BitStream* bs, String errorString) nuclear@0: { nuclear@0: RPC_S2C_Authorization auth; nuclear@0: if (errorString.IsEmpty()) nuclear@0: { nuclear@0: auth.AuthString = OfficialAuthorizedString; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: auth.AuthString = errorString; nuclear@0: } nuclear@0: auth.MajorVersion = RPCVersion_Major; nuclear@0: auth.MinorVersion = RPCVersion_Minor; nuclear@0: auth.PatchVersion = RPCVersion_Patch; nuclear@0: auth.Serialize(bs); nuclear@0: } nuclear@0: nuclear@0: bool RPC_S2C_Authorization::Validate() nuclear@0: { nuclear@0: return AuthString.CompareNoCase(OfficialAuthorizedString) == 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------- nuclear@0: // Session nuclear@0: nuclear@0: void Session::Shutdown() nuclear@0: { nuclear@0: { nuclear@0: Lock::Locker locker(&SocketListenersLock); nuclear@0: nuclear@0: const int count = SocketListeners.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: SocketListeners[i]->Close(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: const int count = AllConnections.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: Connection* arrayItem = AllConnections[i].GetPtr(); nuclear@0: nuclear@0: if (arrayItem->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: PacketizedTCPConnection* ptcp = (PacketizedTCPConnection*)arrayItem; nuclear@0: nuclear@0: ptcp->pSocket->Close(); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: SessionResult Session::Listen(ListenerDescription* pListenerDescription) nuclear@0: { nuclear@0: if (pListenerDescription->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: BerkleyListenerDescription* bld = (BerkleyListenerDescription*)pListenerDescription; nuclear@0: TCPSocket* tcpSocket = (TCPSocket*)bld->BoundSocketToListenWith.GetPtr(); nuclear@0: nuclear@0: if (tcpSocket->Listen() < 0) nuclear@0: { nuclear@0: return SessionResult_ListenFailure; nuclear@0: } nuclear@0: nuclear@0: Lock::Locker locker(&SocketListenersLock); nuclear@0: SocketListeners.PushBack(tcpSocket); nuclear@0: } nuclear@0: else if (pListenerDescription->Transport == TransportType_Loopback) nuclear@0: { nuclear@0: HasLoopbackListener = true; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: nuclear@0: return SessionResult_OK; nuclear@0: } nuclear@0: nuclear@0: SessionResult Session::Connect(ConnectParameters *cp) nuclear@0: { nuclear@0: if (cp->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: ConnectParametersBerkleySocket* cp2 = (ConnectParametersBerkleySocket*)cp; nuclear@0: Ptr c; nuclear@0: nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: int connIndex; nuclear@0: Ptr conn = findConnectionBySocket(AllConnections, cp2->BoundSocketToConnectWith, &connIndex); nuclear@0: if (conn) nuclear@0: { nuclear@0: return SessionResult_AlreadyConnected; nuclear@0: } nuclear@0: nuclear@0: TCPSocketBase* tcpSock = (TCPSocketBase*)cp2->BoundSocketToConnectWith.GetPtr(); nuclear@0: nuclear@0: int ret = tcpSock->Connect(&cp2->RemoteAddress); nuclear@0: if (ret < 0) nuclear@0: { nuclear@0: return SessionResult_ConnectFailure; nuclear@0: } nuclear@0: nuclear@0: Ptr newConnection = AllocConnection(cp2->Transport); nuclear@0: if (!newConnection) nuclear@0: { nuclear@0: return SessionResult_ConnectFailure; nuclear@0: } nuclear@0: nuclear@0: c = (PacketizedTCPConnection*)newConnection.GetPtr(); nuclear@0: c->pSocket = (TCPSocket*) cp2->BoundSocketToConnectWith.GetPtr(); nuclear@0: c->Address = cp2->RemoteAddress; nuclear@0: c->Transport = cp2->Transport; nuclear@0: c->SetState(Client_Connecting); nuclear@0: nuclear@0: AllConnections.PushBack(c); nuclear@0: nuclear@0: } nuclear@0: nuclear@0: if (cp2->Blocking) nuclear@0: { nuclear@0: c->WaitOnConnecting(); nuclear@0: } nuclear@0: nuclear@0: if (c->State == State_Connected) nuclear@0: { nuclear@0: return SessionResult_OK; nuclear@0: } nuclear@0: else if (c->State == Client_Connecting) nuclear@0: { nuclear@0: return SessionResult_ConnectInProgress; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: return SessionResult_ConnectFailure; nuclear@0: } nuclear@0: } nuclear@0: else if (cp->Transport == TransportType_Loopback) nuclear@0: { nuclear@0: if (HasLoopbackListener) nuclear@0: { nuclear@0: Ptr c = AllocConnection(cp->Transport); nuclear@0: if (!c) nuclear@0: { nuclear@0: return SessionResult_ConnectFailure; nuclear@0: } nuclear@0: nuclear@0: c->Transport = cp->Transport; nuclear@0: c->SetState(State_Connected); nuclear@0: nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: AllConnections.PushBack(c); nuclear@0: } nuclear@0: nuclear@0: invokeSessionEvent(&SessionListener::OnConnectionRequestAccepted, c); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: nuclear@0: return SessionResult_OK; nuclear@0: } nuclear@0: nuclear@0: SessionResult Session::ListenPTCP(OVR::Net::BerkleyBindParameters *bbp) nuclear@0: { nuclear@0: Ptr listenSocket = *new OVR::Net::PacketizedTCPSocket(); nuclear@0: if (listenSocket->Bind(bbp) == INVALID_SOCKET) nuclear@0: { nuclear@0: return SessionResult_BindFailure; nuclear@0: } nuclear@0: nuclear@0: BerkleyListenerDescription bld; nuclear@0: bld.BoundSocketToListenWith = listenSocket.GetPtr(); nuclear@0: bld.Transport = TransportType_PacketizedTCP; nuclear@0: nuclear@0: return Listen(&bld); nuclear@0: } nuclear@0: nuclear@0: SessionResult Session::ConnectPTCP(OVR::Net::BerkleyBindParameters* bbp, SockAddr* remoteAddress, bool blocking) nuclear@0: { nuclear@0: ConnectParametersBerkleySocket cp(NULL, remoteAddress, blocking, TransportType_PacketizedTCP); nuclear@0: Ptr connectSocket = *new PacketizedTCPSocket(); nuclear@0: nuclear@0: cp.BoundSocketToConnectWith = connectSocket.GetPtr(); nuclear@0: if (connectSocket->Bind(bbp) == INVALID_SOCKET) nuclear@0: { nuclear@0: return SessionResult_BindFailure; nuclear@0: } nuclear@0: nuclear@0: return Connect(&cp); nuclear@0: } nuclear@0: nuclear@0: Ptr Session::findConnectionBySockAddr(SockAddr* address) nuclear@0: { nuclear@0: const int count = AllConnections.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: Connection* arrayItem = AllConnections[i].GetPtr(); nuclear@0: nuclear@0: if (arrayItem->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: PacketizedTCPConnection* conn = (PacketizedTCPConnection*)arrayItem; nuclear@0: nuclear@0: if (conn->Address == *address) nuclear@0: { nuclear@0: return conn; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int Session::Send(SendParameters *payload) nuclear@0: { nuclear@0: if (payload->pConnection->Transport == TransportType_Loopback) nuclear@0: { nuclear@0: Lock::Locker locker(&SessionListenersLock); nuclear@0: nuclear@0: const int count = SessionListeners.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: SessionListener* sl = SessionListeners[i]; nuclear@0: nuclear@0: // FIXME: This looks like it needs to be reviewed at some point.. nuclear@0: ReceivePayload rp; nuclear@0: rp.Bytes = payload->Bytes; nuclear@0: rp.pConnection = payload->pConnection; nuclear@0: rp.pData = (uint8_t*)payload->pData; // FIXME nuclear@0: ListenerReceiveResult lrr = LRR_CONTINUE; nuclear@0: sl->OnReceive(&rp, &lrr); nuclear@0: if (lrr == LRR_RETURN) nuclear@0: { nuclear@0: return payload->Bytes; nuclear@0: } nuclear@0: else if (lrr == LRR_BREAK) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return payload->Bytes; nuclear@0: } nuclear@0: else if (payload->pConnection->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: PacketizedTCPConnection* conn = (PacketizedTCPConnection*)payload->pConnection.GetPtr(); nuclear@0: nuclear@0: return conn->pSocket->Send(payload->pData, payload->Bytes); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: nuclear@0: return 0; nuclear@0: } nuclear@0: void Session::Broadcast(BroadcastParameters *payload) nuclear@0: { nuclear@0: SendParameters sp; nuclear@0: sp.Bytes=payload->Bytes; nuclear@0: sp.pData=payload->pData; nuclear@0: nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: const int connectionCount = FullConnections.GetSizeI(); nuclear@0: for (int i = 0; i < connectionCount; ++i) nuclear@0: { nuclear@0: sp.pConnection = FullConnections[i]; nuclear@0: Send(&sp); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: // DO NOT CALL Poll() FROM MULTIPLE THREADS due to allBlockingTcpSockets being a member nuclear@0: void Session::Poll(bool listeners) nuclear@0: { nuclear@0: allBlockingTcpSockets.Clear(); nuclear@0: nuclear@0: if (listeners) nuclear@0: { nuclear@0: Lock::Locker locker(&SocketListenersLock); nuclear@0: nuclear@0: const int listenerCount = SocketListeners.GetSizeI(); nuclear@0: for (int i = 0; i < listenerCount; ++i) nuclear@0: { nuclear@0: allBlockingTcpSockets.PushBack(SocketListeners[i]); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: const int connectionCount = AllConnections.GetSizeI(); nuclear@0: for (int i = 0; i < connectionCount; ++i) nuclear@0: { nuclear@0: Connection* arrayItem = AllConnections[i].GetPtr(); nuclear@0: nuclear@0: if (arrayItem->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: PacketizedTCPConnection* ptcp = (PacketizedTCPConnection*)arrayItem; nuclear@0: nuclear@0: allBlockingTcpSockets.PushBack(ptcp->pSocket); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: const int count = allBlockingTcpSockets.GetSizeI(); nuclear@0: if (count > 0) nuclear@0: { nuclear@0: TCPSocketPollState state; nuclear@0: nuclear@0: // Add all the sockets for polling, nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: Net::TCPSocket* sock = allBlockingTcpSockets[i].GetPtr(); nuclear@0: nuclear@0: // If socket handle is invalid, nuclear@0: if (sock->GetSocketHandle() == INVALID_SOCKET) nuclear@0: { nuclear@0: OVR_DEBUG_LOG(("[Session] Detected an invalid socket handle - Treating it as a disconnection.")); nuclear@0: sock->IsConnecting = false; nuclear@0: TCP_OnClosed(sock); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: state.Add(sock); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // If polling returns with an event, nuclear@0: if (state.Poll(allBlockingTcpSockets[0]->GetBlockingTimeoutUsec(), allBlockingTcpSockets[0]->GetBlockingTimeoutSec())) nuclear@0: { nuclear@0: // Handle any events for each socket nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: state.HandleEvent(allBlockingTcpSockets[i], this); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Session::AddSessionListener(SessionListener* se) nuclear@0: { nuclear@0: Lock::Locker locker(&SessionListenersLock); nuclear@0: nuclear@0: const int count = SessionListeners.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: if (SessionListeners[i] == se) nuclear@0: { nuclear@0: // Already added nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: SessionListeners.PushBack(se); nuclear@0: se->OnAddedToSession(this); nuclear@0: } nuclear@0: nuclear@0: void Session::RemoveSessionListener(SessionListener* se) nuclear@0: { nuclear@0: Lock::Locker locker(&SessionListenersLock); nuclear@0: nuclear@0: const int count = SessionListeners.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: if (SessionListeners[i] == se) nuclear@0: { nuclear@0: se->OnRemovedFromSession(this); nuclear@0: nuclear@0: SessionListeners.RemoveAtUnordered(i); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: SInt32 Session::GetActiveSocketsCount() nuclear@0: { nuclear@0: Lock::Locker locker1(&SocketListenersLock); nuclear@0: Lock::Locker locker2(&ConnectionsLock); nuclear@0: return SocketListeners.GetSize() + AllConnections.GetSize()>0; nuclear@0: } nuclear@0: Ptr Session::AllocConnection(TransportType transport) nuclear@0: { nuclear@0: switch (transport) nuclear@0: { nuclear@0: case TransportType_Loopback: return *new Connection(); nuclear@0: case TransportType_TCP: return *new TCPConnection(); nuclear@0: case TransportType_PacketizedTCP: return *new PacketizedTCPConnection(); nuclear@0: default: nuclear@0: OVR_ASSERT(false); nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: Ptr Session::findConnectionBySocket(Array< Ptr >& connectionArray, Socket* s, int *connectionIndex) nuclear@0: { nuclear@0: const int count = connectionArray.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: Connection* arrayItem = connectionArray[i].GetPtr(); nuclear@0: nuclear@0: if (arrayItem->Transport == TransportType_PacketizedTCP) nuclear@0: { nuclear@0: PacketizedTCPConnection* ptc = (PacketizedTCPConnection*)arrayItem; nuclear@0: nuclear@0: if (ptc->pSocket == s) nuclear@0: { nuclear@0: if (connectionIndex) nuclear@0: { nuclear@0: *connectionIndex = i; nuclear@0: } nuclear@0: return ptc; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: int Session::invokeSessionListeners(ReceivePayload* rp) nuclear@0: { nuclear@0: Lock::Locker locker(&SessionListenersLock); nuclear@0: nuclear@0: const int count = SessionListeners.GetSizeI(); nuclear@0: for (int j = 0; j < count; ++j) nuclear@0: { nuclear@0: ListenerReceiveResult lrr = LRR_CONTINUE; nuclear@0: SessionListeners[j]->OnReceive(rp, &lrr); nuclear@0: nuclear@0: if (lrr == LRR_RETURN || lrr == LRR_BREAK) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return rp->Bytes; nuclear@0: } nuclear@0: nuclear@0: void Session::TCP_OnRecv(Socket* pSocket, uint8_t* pData, int bytesRead) nuclear@0: { nuclear@0: // KevinJ: 9/2/2014 Fix deadlock - Watchdog calls Broadcast(), which locks ConnectionsLock(). nuclear@0: // Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: // Look for the connection in the full connection list first nuclear@0: int connIndex; nuclear@0: ConnectionsLock.DoLock(); nuclear@0: Ptr conn = findConnectionBySocket(AllConnections, pSocket, &connIndex); nuclear@0: ConnectionsLock.Unlock(); nuclear@0: if (conn) nuclear@0: { nuclear@0: if (conn->State == State_Connected) nuclear@0: { nuclear@0: ReceivePayload rp; nuclear@0: rp.Bytes = bytesRead; nuclear@0: rp.pConnection = conn; nuclear@0: rp.pData = pData; nuclear@0: nuclear@0: // Call listeners nuclear@0: invokeSessionListeners(&rp); nuclear@0: } nuclear@0: else if (conn->State == Client_ConnectedWait) nuclear@0: { nuclear@0: // Check the version data from the message nuclear@0: BitStream bsIn((char*)pData, bytesRead, false); nuclear@0: nuclear@0: RPC_S2C_Authorization auth; nuclear@0: if (!auth.Deserialize(&bsIn) || nuclear@0: !auth.Validate()) nuclear@0: { nuclear@0: LogError("{ERR-001} [Session] REJECTED: OVRService did not authorize us: %s", auth.AuthString.ToCStr()); nuclear@0: nuclear@0: conn->SetState(State_Zombie); nuclear@0: invokeSessionEvent(&SessionListener::OnIncompatibleProtocol, conn); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // Read remote version nuclear@0: conn->RemoteMajorVersion = auth.MajorVersion; nuclear@0: conn->RemoteMinorVersion = auth.MinorVersion; nuclear@0: conn->RemotePatchVersion = auth.PatchVersion; nuclear@0: nuclear@0: // Mark as connected nuclear@0: conn->SetState(State_Connected); nuclear@0: ConnectionsLock.DoLock(); nuclear@0: int connIndex2; nuclear@0: if (findConnectionBySocket(AllConnections, pSocket, &connIndex2)==conn && findConnectionBySocket(FullConnections, pSocket, &connIndex2)==NULL) nuclear@0: { nuclear@0: FullConnections.PushBack(conn); nuclear@0: } nuclear@0: ConnectionsLock.Unlock(); nuclear@0: invokeSessionEvent(&SessionListener::OnConnectionRequestAccepted, conn); nuclear@0: } nuclear@0: } nuclear@0: else if (conn->State == Server_ConnectedWait) nuclear@0: { nuclear@0: // Check the version data from the message nuclear@0: BitStream bsIn((char*)pData, bytesRead, false); nuclear@0: nuclear@0: RPC_C2S_Hello hello; nuclear@0: if (!hello.Deserialize(&bsIn) || nuclear@0: !hello.Validate()) nuclear@0: { nuclear@0: LogError("{ERR-002} [Session] REJECTED: Rift application is using an incompatible version %d.%d.%d (my version=%d.%d.%d)", nuclear@0: hello.MajorVersion, hello.MinorVersion, hello.PatchVersion, nuclear@0: RPCVersion_Major, RPCVersion_Minor, RPCVersion_Patch); nuclear@0: nuclear@0: conn->SetState(State_Zombie); nuclear@0: nuclear@0: // Send auth response nuclear@0: BitStream bsOut; nuclear@0: RPC_S2C_Authorization::Generate(&bsOut, "Incompatible protocol version. Please make sure your OVRService and SDK are both up to date."); nuclear@0: conn->pSocket->Send(bsOut.GetData(), bsOut.GetNumberOfBytesUsed()); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // Read remote version nuclear@0: conn->RemoteMajorVersion = hello.MajorVersion; nuclear@0: conn->RemoteMinorVersion = hello.MinorVersion; nuclear@0: conn->RemotePatchVersion = hello.PatchVersion; nuclear@0: nuclear@0: // Send auth response nuclear@0: BitStream bsOut; nuclear@0: RPC_S2C_Authorization::Generate(&bsOut); nuclear@0: conn->pSocket->Send(bsOut.GetData(), bsOut.GetNumberOfBytesUsed()); nuclear@0: nuclear@0: // Mark as connected nuclear@0: conn->SetState(State_Connected); nuclear@0: ConnectionsLock.DoLock(); nuclear@0: int connIndex2; nuclear@0: if (findConnectionBySocket(AllConnections, pSocket, &connIndex2)==conn && findConnectionBySocket(FullConnections, pSocket, &connIndex2)==NULL) nuclear@0: { nuclear@0: FullConnections.PushBack(conn); nuclear@0: } nuclear@0: ConnectionsLock.Unlock(); nuclear@0: invokeSessionEvent(&SessionListener::OnNewIncomingConnection, conn); nuclear@0: nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR_ASSERT(false); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Session::TCP_OnClosed(TCPSocket* s) nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: // If found in the full connection list, nuclear@0: int connIndex; nuclear@0: Ptr conn = findConnectionBySocket(AllConnections, s, &connIndex); nuclear@0: if (conn) nuclear@0: { nuclear@0: AllConnections.RemoveAtUnordered(connIndex); nuclear@0: nuclear@0: // If in the full connection list, nuclear@0: if (findConnectionBySocket(FullConnections, s, &connIndex)) nuclear@0: { nuclear@0: FullConnections.RemoveAtUnordered(connIndex); nuclear@0: } nuclear@0: nuclear@0: // Generate an appropriate event for the current state nuclear@0: switch (conn->State) nuclear@0: { nuclear@0: case Client_Connecting: nuclear@0: invokeSessionEvent(&SessionListener::OnConnectionAttemptFailed, conn); nuclear@0: break; nuclear@0: case Client_ConnectedWait: nuclear@0: case Server_ConnectedWait: nuclear@0: invokeSessionEvent(&SessionListener::OnHandshakeAttemptFailed, conn); nuclear@0: break; nuclear@0: case State_Connected: nuclear@0: case State_Zombie: nuclear@0: invokeSessionEvent(&SessionListener::OnDisconnected, conn); nuclear@0: break; nuclear@0: default: nuclear@0: OVR_ASSERT(false); nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: conn->SetState(State_Zombie); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Session::TCP_OnAccept(TCPSocket* pListener, SockAddr* pSockAddr, SocketHandle newSock) nuclear@0: { nuclear@0: OVR_UNUSED(pListener); nuclear@0: OVR_ASSERT(pListener->Transport == TransportType_PacketizedTCP); nuclear@0: nuclear@0: nuclear@0: Ptr newSocket = *new PacketizedTCPSocket(newSock, false); nuclear@0: // If pSockAddr is not localhost, then close newSock nuclear@0: if (pSockAddr->IsLocalhost()==false) nuclear@0: { nuclear@0: newSocket->Close(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: if (newSocket) nuclear@0: { nuclear@0: Ptr b = AllocConnection(TransportType_PacketizedTCP); nuclear@0: Ptr c = (PacketizedTCPConnection*)b.GetPtr(); nuclear@0: c->pSocket = newSocket; nuclear@0: c->Address = *pSockAddr; nuclear@0: c->State = Server_ConnectedWait; nuclear@0: nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: AllConnections.PushBack(c); nuclear@0: } nuclear@0: nuclear@0: // Server does not send the first packet. It waits for the client to send its version nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Session::TCP_OnConnected(TCPSocket *s) nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: // If connection was found, nuclear@0: PacketizedTCPConnection* conn = findConnectionBySocket(AllConnections, s); nuclear@0: if (conn) nuclear@0: { nuclear@0: OVR_ASSERT(conn->State == Client_Connecting); nuclear@0: nuclear@0: // Send hello message nuclear@0: BitStream bsOut; nuclear@0: RPC_C2S_Hello::Generate(&bsOut); nuclear@0: conn->pSocket->Send(bsOut.GetData(), bsOut.GetNumberOfBytesUsed()); nuclear@0: nuclear@0: // Just update state but do not generate any notifications yet nuclear@0: conn->State = Client_ConnectedWait; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Session::invokeSessionEvent(void(SessionListener::*f)(Connection*), Connection* conn) nuclear@0: { nuclear@0: Lock::Locker locker(&SessionListenersLock); nuclear@0: nuclear@0: const int count = SessionListeners.GetSizeI(); nuclear@0: for (int i = 0; i < count; ++i) nuclear@0: { nuclear@0: (SessionListeners[i]->*f)(conn); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: Ptr Session::GetConnectionAtIndex(int index) nuclear@0: { nuclear@0: Lock::Locker locker(&ConnectionsLock); nuclear@0: nuclear@0: const int count = FullConnections.GetSizeI(); nuclear@0: nuclear@0: if (index < count) nuclear@0: { nuclear@0: return FullConnections[index]; nuclear@0: } nuclear@0: nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: }} // OVR::Net