void SendUdpControl(SocketNetDriverConnection connection)
 {
     controlCodeBytes[0] = (byte)EControlCode.SetChannelID;
     controlCodeBytes[1] = (byte)(connection.channelID & 0xff);
     controlCodeBytes[2] = (byte)((connection.channelID >> 8) & 0xff);
     connection.SendUnreliable(controlCodeBytes, 3);
 }
 internal void ReliableSendWouldBlock(SocketNetDriverConnection connection)
 {
     if (_serverCallbacks != null)
     {
         _serverCallbacks.OnReliableSendWouldBlock(connection);
     }
     if (_clientCallbacks != null)
     {
         _clientCallbacks.OnReliableSendWouldBlock(connection);
     }
 }
    public bool Connect(string address, int port, INetDriverCallbacks callbacks)
    {
        if (address == "localhost")
        {
            address = "127.0.0.1";
        }

        var serverIP = GetIPAddressFromString(address);

        if (serverIP == null)
        {
            Debug.LogError("Could not resolve " + address);
            return(false);
        }

        _clientCallbacks = callbacks;

        var serverEndPoint = new IPEndPoint(serverIP, port);

        var clientSocks = new Socket[2];

        clientSocks[0] = new Socket(serverEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        clientSocks[1] = new Socket(serverEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

        try {
            clientSocks[0].NoDelay           = true;
            clientSocks[0].SendTimeout       = 500;
            clientSocks[0].ReceiveBufferSize = World.MAX_RELIABLE_MESSAGE_SIZE;

            clientSocks[1].SendBufferSize    = World.MAX_UNRELIABLE_MESSAGE_SIZE * 4;
            clientSocks[1].ReceiveBufferSize = World.MAX_UNRELIABLE_MESSAGE_SIZE * 4;
            clientSocks[1].DisableICMPUnreachablePortError();

            Debug.Log("Connecting to " + serverEndPoint.Address.ToString());

            clientSocks[0].Connect(serverEndPoint);
            clientSocks[1].Bind(new IPEndPoint(IPAddress.Any, 0));

            Debug.Log("Connected to " + serverEndPoint.Address.ToString());

            _serverConnection             = new SocketNetDriverConnection(this, clientSocks, -1);
            _serverConnection.udpEndpoint = clientSocks[0].RemoteEndPoint;
        } catch (Exception e) {
            Debug.LogException(e);
            return(false);
        }

        return(true);
    }
    internal void ConnectionDisposed(SocketNetDriverConnection connection)
    {
        if (connection == _serverConnection)
        {
            try {
                connection.sockets[1].Close();
            } catch (Exception) {}

            _serverConnection = null;
            if ((_clientCallbacks != null) && connection.didHandshake)
            {
                _clientCallbacks.OnDisconnect(connection);
            }
        }
        else
        {
            bool r = _tcpConnections.Remove(connection.tcpEndpoint);
            Assert.IsTrue(r);

            if (connection.udpEndpoint != null)
            {
                r = _udpConnections.Remove(connection.udpEndpoint);
                Assert.IsTrue(r);
            }

            if ((_serverCallbacks != null) && connection.didHandshake)
            {
                _serverCallbacks.OnDisconnect(connection);
            }
        }

        try {
            connection.sockets[0].Close();
        } catch (Exception) { }

        connection.sockets[0] = null;
        connection.sockets[1] = null;
    }
    public void TickServer(float dt, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics)
    {
        Perf.Begin("SocketNetDriver.TickServer");

        for (;;)
        {
            Socket newSocket;
            try {
                newSocket = _serverSock[0].Accept();
            } catch (SocketException) {
                break;
            }

            if (_tcpConnections.ContainsKey(newSocket.RemoteEndPoint))
            {
                Debug.LogError("Connection attempt from already connected client!");
                newSocket.Close();
                continue;
            }

            var clientSocks = new Socket[2];
            clientSocks[0] = newSocket;
            clientSocks[1] = _serverSock[1];

            newSocket.Blocking = false;
            //newSocket.NoDelay = true;
            newSocket.SendBufferSize = World.MAX_RELIABLE_MESSAGE_SIZE * 8;
            newSocket.SendTimeout    = 500;

            var newConn = new SocketNetDriverConnection(this, clientSocks, nextChannelID++);
            _tcpConnections.Add(newSocket.RemoteEndPoint, newConn);
            SendTcpControl(newConn);
        }

        for (int i = 0; i < _tcpConnections.Values.Count;)
        {
            var c = _tcpConnections.Values[i];

            bool wasReset   = false;
            bool isDisposed = false;

            try {
                wasReset = c.sockets[0].Poll(0, SelectMode.SelectRead);
            } catch (Exception) {
                isDisposed = true;
            }

            if (isDisposed || (wasReset && (c.sockets[0].Available == 0)))
            {
                c.Dispose();
                continue;
            }

            Recv(c, _serverCallbacks, c.sockets[0], recvBuffer, ref reliableChannelMetrics, false);

            if (c.isValid && !c.didHandshake)
            {
                c.handshakeTime += dt;
                if (c.handshakeTime > UDP_CONTROL_DISCONNECT_TIMEOUT)
                {
                    // handshake failed
                    Debug.LogError("Disconnecting " + c.tcpEndpoint.ToString() + ": udp handshake timed out");
                    c.Dispose();
                }
            }

            if (c.isValid)
            {
                ++i;
            }
        }

        RecvFrom(_serverCallbacks, _serverSock[1], recvBuffer, ref unreliableChannelMetrics);

        Perf.End();
    }
    void Recv(SocketNetDriverConnection connection, INetDriverCallbacks callbacks, Socket socket, byte[] buffer, ref NetIOMetrics metrics, bool isDatagram)
    {
        Perf.Begin("SocketNetDriver.Recv");

        if (isDatagram)
        {
            while (connection.isValid && (socket.Available > 0))
            {
                int r;
                try {
                    r = socket.Receive(buffer, 0, World.MAX_UNRELIABLE_MESSAGE_SIZE, SocketFlags.None);
                    if (r <= 0)
                    {
                        throw new SocketException((int)SocketError.SocketError);
                    }
                    metrics.bytesRecv += r;
                    ++metrics.numPacketsRecv;
                } catch (Exception e) {
                    Debug.LogException(e);
                    callbacks.OnInvalidMessageReceived(connection);
                    continue;
                }

                if (!connection.didHandshake)
                {
                    // client may receive a UDP packet before receiving control ACK
                    // so discard the packet until we process the ACK.
                    continue;
                }

                callbacks.OnMessageReceived(connection, buffer, r);
            }
        }
        else
        {
            while (connection.isValid && (socket.Available > 0))
            {
                if (connection.pendingRecvSize <= 0)
                {
                    if (socket.Available < 2)
                    {
                        break;
                    }

                    // read from socket.
                    if (socket.Receive(connection.pendingBytes, 0, 2, SocketFlags.None) != 2)
                    {
                        throw new SocketException((int)SocketError.SocketError);
                    }

                    connection.pendingRecvSize      = ((int)connection.pendingBytes[0]) | (((int)connection.pendingBytes[1]) << 8);
                    connection.pendingBytesReceived = 0;

                    if (connection.pendingRecvSize > connection.pendingBytes.Length)
                    {
                        callbacks.OnInvalidMessageReceived(connection);
                        continue;
                    }
                }

                {
                    // read from socket.
                    var numBytesToRead = Mathf.Min(socket.Available, connection.pendingRecvSize - connection.pendingBytesReceived);
                    if (numBytesToRead > 0)
                    {
                        if (socket.Receive(connection.pendingBytes, connection.pendingBytesReceived, numBytesToRead, SocketFlags.None) != numBytesToRead)
                        {
                            throw new SocketException((int)SocketError.SocketError);
                        }
                        connection.pendingBytesReceived += numBytesToRead;
                    }
                }

                Assert.IsTrue(connection.pendingBytesReceived <= connection.pendingRecvSize);

                if (connection.pendingBytesReceived >= connection.pendingRecvSize)
                {
                    if (!connection.didHandshake)
                    {
                        if (callbacks == _clientCallbacks)
                        {
                            if (connection.channelID == -1)
                            {
                                var id = RecvControl(connection.pendingBytes, connection.pendingRecvSize);
                                if (id == -1)
                                {
                                    connection.Dispose();
                                    break;
                                }
                                connection.channelID   = id;
                                _sendUdpControlTimeout = UDP_CONTROL_RESEND_TIMEOUT;
                                SendUdpControl(connection);
                            }
                            else if (connection.pendingBytes[0] == (byte)EControlCode.AckChannelID)
                            {
                                connection.didHandshake = true;
                                callbacks.OnConnect(connection);
                            }
                            else
                            {
                                // invalid response
                                connection.Dispose();
                                break;
                            }
                        }
                        else
                        {
                            connection.Dispose();
                            break;
                        }

                        connection.pendingRecvSize      = 0;
                        connection.pendingBytesReceived = 0;
                        continue;
                    }

                    Array.Copy(connection.pendingBytes, buffer, connection.pendingRecvSize);

                    var r = connection.pendingRecvSize;

                    connection.pendingBytesReceived = 0;
                    connection.pendingRecvSize      = 0;

                    metrics.bytesRecv += r;
                    ++metrics.numPacketsRecv;

                    callbacks.OnMessageReceived(connection, buffer, r);
                    continue;
                }

                // not enough data ready
                break;
            }
        }

        Perf.End();
    }
 void SendTcpControlAck(SocketNetDriverConnection connection)
 {
     controlCodeBytes[0] = (byte)EControlCode.AckChannelID;
     connection.SendReliable(controlCodeBytes, 1);
 }