Esempio n. 1
0
        /// <summary>Triggers NAT traversal for a given host.</summary>
        /// <param name="serverName">The public IP address of the host.</param>
        /// <param name="serverPort">The public port of the host.</param>
        /// <returns>If successful an instance of EnabledAddresses is returned, otherwise null.</returns>
        /// <remarks>This method should be called by a client before attempting to connect to the DirectPlay session.</remarks>
        public unsafe static EnabledAddresses TestNatTraversal(string serverName, int serverPort)
        {
            Regex ipAddressRegex = new Regex(@"^(?<1>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Singleline);
            Match ipAddressMatch = ipAddressRegex.Match(serverName);

            if (ipAddressMatch.Success)
            {
                IPAddress publicServerAddress = IPAddress.Parse(ipAddressMatch.Groups[1].Value);
                try {
                    using (UdpClient socket = new UdpClient()) {
                        socket.Client.ReceiveTimeout = 2000;
                        socket.Connect(natTraversalServiceUrl, natTraversalServicePort);

                        IPEndPoint localEndPoint = (IPEndPoint)socket.Client.LocalEndPoint;

                        // send "lookup" message
                        {
                            MsgLookup msg      = new MsgLookup(publicServerAddress, (ushort)serverPort, localEndPoint.Address, (ushort)localEndPoint.Port);
                            byte[]    datagram = new byte[sizeof(MsgLookup)];
                            for (int i = 0; i < datagram.Length; ++i)
                            {
                                datagram[i] = ((byte *)&msg)[i];
                            }
                            socket.Send(datagram, datagram.Length);
                        }

                        // block until a message is received or 2 seconds have elapsed
                        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                        byte[]     bytesReceived  = socket.Receive(ref remoteEndPoint);

                        // handle the message
                        if (bytesReceived.Length >= 3 && bytesReceived[0] == 'z' && bytesReceived[1] == 't')
                        {
                            switch (bytesReceived[2])
                            {
                            case (byte)MessageType.AckLookup:
                                if (bytesReceived.Length == sizeof(MsgAckLookup))
                                {
                                    MsgAckLookup msg = new MsgAckLookup();
                                    for (int i = 0; i < sizeof(MsgAckLookup); ++i)
                                    {
                                        ((byte *)&msg)[i] = bytesReceived[i];
                                    }

                                    // handle MsgAckLookup
                                    // report host's private address
                                    EnabledAddresses result = new EnabledAddresses();
                                    result.HostPublicAddress    = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.HostPublicIp)).ToString();
                                    result.HostPublicPort       = msg.HostPublicPort;
                                    result.HostPrivateAddress   = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.HostPrivateIp)).ToString();
                                    result.HostPrivatePort      = msg.HostPrivatePort;
                                    result.ClientPrivateAddress = ((IPEndPoint)socket.Client.LocalEndPoint).Address.ToString();
                                    result.ClientPrivatePort    = ((IPEndPoint)socket.Client.LocalEndPoint).Port;
                                    return(result);
                                }
                                break;

                            case (byte)MessageType.NotFound:
                                if (bytesReceived.Length == sizeof(MsgNotFound))
                                {
                                    MsgNotFound msg = new MsgNotFound();
                                    for (int i = 0; i < sizeof(MsgNotFound); ++i)
                                    {
                                        ((byte *)&msg)[i] = bytesReceived[i];
                                    }

                                    // handle MsgNotFound
                                    // just exit and return null
                                }
                                break;
                            }
                        }
                    }
                } catch { }
            }
            return(null);
        }
Esempio n. 2
0
        /// <summary>Connect to a server.</summary>
        /// <param name="serverName">IP address or hostname of the server.</param>
        /// <param name="serverPort">IP port on which the server is listening.</param>
        /// <remarks>The first client to connect becomes the hosting player.</remarks>
        public void Connect(string serverName, int serverPort)
        {
            Debug.Assert(status == NetworkStatus.Disconnected);

            serverIsOnSameComputer     = (serverName == "localhost");
            outboundVideoFrameHistory  = new OutboundVideoFrameHistory();
            inboundVideoFrameHistories = new Dictionary <int, InboundVideoFrameHistory>();
            soundBuffers = new Dictionary <int, Buffer3D>();

            client = new Microsoft.DirectX.DirectPlay.Client(InitializeFlags.DisableParameterValidation);
            client.ConnectComplete   += new ConnectCompleteEventHandler(onConnectComplete);
            client.Receive           += new ReceiveEventHandler(onReceive);
            client.SessionTerminated += new SessionTerminatedEventHandler(onSessionTerminated);

            status = NetworkStatus.Connecting;

            // trigger NAT traversal
            EnabledAddresses enabledAddresses = NatResolver.TestNatTraversal(serverName, serverPort);

            ApplicationDescription description = new ApplicationDescription();

            description.GuidApplication = new Guid("{920BAF09-A06C-47d8-BCE0-21B30D0C3586}");
            // try first using the host's public address
            using (Address hostAddress = (enabledAddresses == null ? new Address(serverName, serverPort) : new Address(enabledAddresses.HostPublicAddress, enabledAddresses.HostPublicPort))) {
                hostAddress.ServiceProvider = Address.ServiceProviderTcpIp;
                using (Address device = new Address()) {
                    device.ServiceProvider = Address.ServiceProviderTcpIp;
                    device.AddComponent(Address.KeyTraversalMode, Address.TraversalModeNone);
                    if (enabledAddresses != null)
                    {
                        device.AddComponent(Address.KeyPort, enabledAddresses.ClientPrivatePort);
                    }
                    using (NetworkPacket packet = new NetworkPacket()) {
                        try {
                            client.Connect(description, hostAddress, device, packet, 0);
                        } catch (Exception e) {
                            status = NetworkStatus.Disconnected;
                            ConnectionFailureCause cause =
                                (e is NoConnectionException ? ConnectionFailureCause.NoConnection :
                                 (e is NotHostException ? ConnectionFailureCause.NotHost :
                                  (e is SessionFullException ? ConnectionFailureCause.SessionFull :
                                   ConnectionFailureCause.Other)));

                            // try again using the host's private address
                            if (enabledAddresses != null)
                            {
                                using (Address hostPrivateAddress = new Address(enabledAddresses.HostPrivateAddress, enabledAddresses.HostPrivatePort)) {
                                    try {
                                        client.Connect(description, hostAddress, device, packet, 0);
                                    } catch {
                                        NetworkMessage message = new NetworkMessage(0, (byte)ReservedMessageType.ConnectionFailed, new byte[1] {
                                            (byte)cause
                                        });
                                        lock (networkMessages) {
                                            networkMessages.Enqueue(message);
                                        }
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                NetworkMessage message = new NetworkMessage(0, (byte)ReservedMessageType.ConnectionFailed, new byte[1] {
                                    (byte)cause
                                });
                                lock (networkMessages) {
                                    networkMessages.Enqueue(message);
                                }
                                return;
                            }
                        }
                    }
                }
            }

            // launch a timer to monitor timeout
            timeoutTimer = new System.Threading.Timer(onTimeout, client, 4000, 0);
        }