Example #1
0
        private void onPlayerCreated(object sender, PlayerCreatedEventArgs e)
        {
            if (serverId == 0)
            {
                // this is not a real player, just the server starting
                serverId = e.Message.PlayerID;
                return;
            }
            else if (server.Groups.Count == 0)
            {
                // this is the first player to connect, therefore it becomes the hosting player
                hostingPlayerId = e.Message.PlayerID;
            }
            else
            {
                // add this player to all existing groups of "other players"
                foreach (int groupId in server.Groups)
                {
                    server.AddPlayerToGroup(groupId, e.Message.PlayerID, 0);
                }
                // send a notification to the NAT traversal server
                if (natTraversalSession.Enabled)
                {
                    using (Address playerAddress = server.GetClientAddress(e.Message.PlayerID)) {
                        string playerIpAsString = playerAddress.GetComponentString(Address.KeyHostname);
                        Regex  ipAddressRegex   = new Regex(@"^(?<1>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Singleline);
                        Match  ipAddressMatch   = ipAddressRegex.Match(playerIpAsString);
                        if (ipAddressMatch.Success)
                        {
                            IPAddress playerIp   = IPAddress.Parse(ipAddressMatch.Groups[1].Value);
                            int       playerPort = playerAddress.GetComponentInteger(Address.KeyPort);
                            NatResolver.NotifyPlayerHasJoined(natTraversalSession, playerIp, playerPort);
                        }
                    }
                }
            }

            // link the newly created player's context to the new "other players" group
            PlayerContext playerAndGroupContext = new PlayerContext();

            playerAndGroupContext.AllOtherPlayersGroupId = e.Message.PlayerID;                  // to be passed to onGroupCreated
            e.Message.PlayerContext = playerAndGroupContext;

            // create a new "other players" group for this player
            server.CreateGroup(new GroupInformation(), SyncFlags.CreateGroup, playerAndGroupContext, null);

            // add all players except the owner to this "other players" group
            foreach (int playerId in server.Players)
            {
                if (playerId != e.Message.PlayerID && playerId != serverId)
                {
                    server.AddPlayerToGroup(playerAndGroupContext.AllOtherPlayersGroupId, playerId, 0);
                }
            }

            // notify host
            if (e.Message.PlayerID != hostingPlayerId)
            {
                using (NetworkPacket packet = new NetworkPacket(5)) {
                    packet.Write((byte)ReservedMessageType.PlayerWantsToJoin);
                    packet.Write(e.Message.PlayerID);
                    server.SendTo(hostingPlayerId, packet, 0, SendFlags.Guaranteed | SendFlags.Coalesce | SendFlags.PriorityHigh);
                }
            }
        }
Example #2
0
        /// <summary>Begin a new game as a host.</summary>
        /// <param name="mode">Server codec and mixing policy.</param>
        /// <param name="port">IP port that will listen.</param>
        public void Start(VoiceServerMode mode, int port)
        {
            uncompressJobsPending = new ManualResetEvent(false);

            try {
                ApplicationDescription description = new ApplicationDescription();
                description.GuidApplication = new Guid("{920BAF09-A06C-47d8-BCE0-21B30D0C3586}");
                description.MaxPlayers      = 0;                // unlimited
                description.SessionName     = "ZunTzu";
                description.Flags           =
                    Microsoft.DirectX.DirectPlay.SessionFlags.ClientServer |
                    Microsoft.DirectX.DirectPlay.SessionFlags.FastSigned |
                    Microsoft.DirectX.DirectPlay.SessionFlags.NoDpnServer |
                    Microsoft.DirectX.DirectPlay.SessionFlags.NoEnumerations;

                using (Address address = new Address()) {
                    address.ServiceProvider = Address.ServiceProviderTcpIp;
                    address.AddComponent(Address.KeyPort, port);

                    server.Host(description, address);
                }

                if (System.Environment.OSVersion.Version.Major < 6)                     // not Vista?
                // launch a voice session
                {
                    voiceServer = new Microsoft.DirectX.DirectPlay.Voice.Server(server);
                    SessionDescription desc = new SessionDescription();
                    desc.SessionType          = SessionType.Fowarding;            // (mode == VoiceServerMode.ForwardingAdpcm || mode == VoiceServerMode.ForwardingGsm ? SessionType.Fowarding : SessionType.Mixing);
                    desc.BufferQuality        = BufferQuality.Default;
                    desc.GuidCompressionType  = (mode == VoiceServerMode.ForwardingAdpcm || mode == VoiceServerMode.MixingAdpcm ? CompressionGuid.AdPcm : CompressionGuid.Gsm);
                    desc.BufferAggressiveness = BufferAggressiveness.Default;
                    desc.Flags = Microsoft.DirectX.DirectPlay.Voice.SessionFlags.NoHostMigration;
                    //desc.Flags = Microsoft.DirectX.DirectPlay.Voice.SessionFlags.ServerControlTarget;
                    voiceServer.StartSession(desc);
                }

                // allow NAT traversal (3 trials)
                InternetConnectivity connectivity = InternetConnectivity.Unknown;
                for (int trial = 0; (natTraversalSession == null || !natTraversalSession.Enabled) && trial < 3; ++trial)
                {
                    natTraversalSession = NatResolver.EnableNatTraversal(port);
                }
                string fallbackPublicIpAddress = null;
                if (natTraversalSession.Enabled)
                {
                    // notify the parent process via the standard output
                    connectivity = InternetConnectivity.Full;
                }
                else
                {
                    // fallback: discover public IP through HTTP
                    try {
                        // Start a synchronous request.
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://www.zuntzu.com/hostfallback.php");
                        request.UserAgent   = "ZunTzu";
                        request.Timeout     = 10000;
                        request.Method      = "POST";
                        request.ContentType = "application/x-www-form-urlencoded";

                        byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes("id=" + natTraversalSession.SessionId.ToString("N"));
                        request.ContentLength = bytes.Length;
                        using (Stream requestStream = request.GetRequestStream()) {
                            requestStream.Write(bytes, 0, bytes.Length);
                        }

                        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
                            if (response.StatusCode == HttpStatusCode.OK)
                            {
                                using (Stream stream = response.GetResponseStream()) {
                                    using (StreamReader reader = new StreamReader(stream)) {
                                        string responseContent = reader.ReadToEnd();
                                        Regex  ipAddressRegex  = new Regex(@"^(?<1>[012])(?<2>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Singleline);
                                        Match  ipAddressMatch  = ipAddressRegex.Match(responseContent);
                                        if (ipAddressMatch.Success)
                                        {
                                            switch (ipAddressMatch.Groups[1].Value)
                                            {
                                            case "0":
                                                connectivity = InternetConnectivity.Unknown;
                                                break;

                                            case "1":
                                                connectivity = InternetConnectivity.NoEgress;
                                                break;

                                            case "2":
                                                connectivity = InternetConnectivity.NoIngress;
                                                break;
                                            }
                                            fallbackPublicIpAddress = ipAddressMatch.Groups[2].Value;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                throw new WebException();
                            }
                        }
                    } catch (Exception) {
                        // fallback: query a public web site to check Internet connectivity
                        try {
                            // Start a synchronous request.
                            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://www.google.com/");
                            request.Timeout = 10000;

                            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
                                if (response.StatusCode != HttpStatusCode.OK)
                                {
                                    throw new WebException();
                                }
                            }
                        } catch (Exception) {
                            connectivity = InternetConnectivity.None;
                        }
                    }
                }

                // notify the parent process via the standard output
                switch (connectivity)
                {
                case InternetConnectivity.Unknown:
                case InternetConnectivity.None:
                    Console.Out.WriteLine("Server started {0}/?/?", (int)connectivity);
                    break;

                case InternetConnectivity.NoEgress:
                case InternetConnectivity.NoIngress:
                    Console.Out.WriteLine("Server started {0}/{1}/?", (int)connectivity, fallbackPublicIpAddress);
                    break;

                case InternetConnectivity.Full:
                    Console.Out.WriteLine("Server started {0}/{1}/{2}", (int)connectivity, natTraversalSession.PublicIpAddress, natTraversalSession.PublicPort);
                    break;
                }
            } catch (InvalidDeviceAddressException) {
                // notify the parent process via the standard output
                Console.Out.WriteLine("Invalid Device Address");
            } catch (Exception e) {
                // notify the parent process via the standard output
                Console.Out.WriteLine(e.Message);
            }
            Console.Out.Flush();

            processVideoFrames();
        }
Example #3
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);
        }