예제 #1
0
        private void ReceiveCallback(IAsyncResult target)
        {
            Logger.WriteLine("--- ReceiveCallback");
            Message.MessageType requestType = Message.MessageType.Unknown;
            Socket handler = null;
            try
            {
                object[] obj = new object[2];
                obj = (object[])target.AsyncState;

                byte[] buffer = (byte[]) obj[0];
                handler = (Socket) obj[1];

                Logger.WriteLine("ReceiveCallback from " + (handler.RemoteEndPoint as IPEndPoint).Address + ":" + (handler.RemoteEndPoint as IPEndPoint).Port);

                bool quit = false;

                int bytesRead = handler.EndReceive(target);
                if (bytesRead > 0)
                {
                    Message request = new Message(buffer);
                    Message response;

                    requestType = request.GetMessageType();
                    if (requestType == Message.MessageType.HandshakePeerCreator) // Peer client mau join ke room ini
                    {
                        #region Handshake
                        Logger.WriteLine("HandshakePeerCreator");
                        if (Room.Members.Count < Room.MaxPlayer)
                        {
                            int newPeerId, newPeerListenPort;
                            IPAddress newPeerIp = (handler.RemoteEndPoint as IPEndPoint).Address;
                            request.GetHandshakePeerCreator(out newPeerId, out newPeerListenPort);
                            Room.Members.Add(new Peer(newPeerId, newPeerIp, newPeerListenPort));

                            Logger.WriteLine("Peer ID : " + newPeerId);
                            Logger.WriteLine("Peer IP : " + newPeerIp + ":" + newPeerListenPort);

                            // Send SUCCESS message
                            response = Message.CreateMessageSuccess();
                            handler.Send(response.data, 0, response.data.Length, SocketFlags.None);

                            if (nextPeerSocket != null)
                            {
                                Logger.WriteLine("Sending NEW MEMBER to nextPeerSocket: " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address + ":" + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Port);
                                // Send NewMember message to next peer
                                response = Message.CreateMessageNewMember(newPeerId, (handler.RemoteEndPoint as IPEndPoint).Address, newPeerListenPort);
                                nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                            }
                            else
                            {
                                IPEndPoint ipEndPoint = new IPEndPoint(newPeerIp, newPeerListenPort);
                                nextPeerSocket = new Socket(
                                    newPeerIp.AddressFamily,
                                    SocketType.Stream,
                                    ProtocolType.Tcp
                                   );
                                nextPeerSocket.NoDelay = false;
                                nextPeerSocket.Connect(ipEndPoint);

                                Logger.WriteLine("Setting up nextPeerSocket to " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address + ":" + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Port);

                                response = Message.CreateMessageRoomModel(Room);
                                nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                                Logger.WriteLine("Send room info");

                                keepAliveRoom = new Thread(new ThreadStart(SendAliveNextPeer));
                                keepAliveRoom.Start();
                            }

                            response = Message.CreateMessageAdd(newPeerId, Room.RoomId);
                            lock (trackerPaddle)
                            {
                                trackerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                                byte[] bufferRecv = new byte[1024];
                                trackerSocket.Receive(bufferRecv, 0, bufferRecv.Length, SocketFlags.None);
                            }
                        }
                        else
                        {
                            Logger.WriteLine("Send FAILED: Room penuh");
                            // Send FAILED message akibat ruang penuh
                            response = Message.CreateMessageFailed();
                            handler.Send(response.data, 0, response.data.Length, SocketFlags.None);
                            handler.Close();
                            quit = true;
                        }
                        #endregion
                    }
                    else if (requestType == Message.MessageType.KeepAlive)
                    {
                        #region Keep Alive
                        int peerId;
                        request.GetKeepAlive(out peerId);
                        Peer peer = Room.Members.Find(fpeer => fpeer.PeerId == peerId);
                        if (peer != null)
                        {
                            //Send KeepAlive Message back
                            response = request;
                            handler.Send(response.data, 0, response.data.Length, SocketFlags.None);
                        }
                        else
                        {
                            response = Message.CreateMessageFailed();
                            handler.Send(response.data, 0, response.data.Length, SocketFlags.None);
                        }
                        #endregion
                    }
                    else if (requestType == Message.MessageType.NewMember)
                    {
                        #region NewMember
                        Logger.WriteLine("NewMember");
                        if (IsCreator)
                        {
                            Logger.WriteLine("NewMember has been received by peer creator");
                            Logger.WriteLine("Closing connection from " + (handler.RemoteEndPoint as IPEndPoint).Address + ":" + (handler.RemoteEndPoint as IPEndPoint).Port);
                            handler.Close();
                            quit = true;
                        }
                        else
                        {
                            bool isLast = Room.Members.Last().PeerId == PeerId;

                            int newPeerId, newPeerListenPort;
                            IPAddress newPeerIp;
                            request.GetNewMember(out newPeerId, out newPeerIp, out newPeerListenPort);
                            Room.Members.Add(new Peer(newPeerId, newPeerIp, newPeerListenPort));

                            Logger.WriteLine("Sending NEW MEMBER to nextPeerSocket: " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address + ":" + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Port);
                            response = request;
                            nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);

                            if (isLast)
                            {
                                Logger.WriteLine("Closing connection " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address + ":" + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Port);
                                nextPeerSocket.Close();

                                IPEndPoint ipEndPoint = new IPEndPoint(newPeerIp, newPeerListenPort);
                                nextPeerSocket = new Socket(
                                    newPeerIp.AddressFamily,
                                    SocketType.Stream,
                                    ProtocolType.Tcp
                                   );

                                nextPeerSocket.NoDelay = false;
                                nextPeerSocket.Connect(ipEndPoint);

                                Logger.WriteLine("Setting up nextPeerSocket to " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address + ":" + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Port);

                                response = Message.CreateMessageRoomModel(Room);
                                nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                                Logger.WriteLine("Send room info");
                            }
                        }
                        #endregion
                    }
                    else if (requestType == Message.MessageType.RoomModel)
                    {
                        #region Room
                        Logger.WriteLine("RoomModel");
                        Room room;
                        request.GetRoomModel(out room);
                        Room = room;
                        #endregion
                    }
                    else if (requestType == Message.MessageType.Quit)
                    {
                        int peerId;
                        request.GetQuit(out peerId);
                        Peer peer = Room.Members.Find(fpeer => fpeer.PeerId == peerId);
                        byte[] bufferRecv;

                        if (Room.Members.Count != 2)
                        {
                            if (PeerId == peerId)
                            {
                                Logger.WriteLine("Quit done");
                            }
                            else
                            {
                                int i = 0;
                                for (; i < Room.Members.Count; i++)
                                {// i adalah indeks peer yang ingin quit
                                    if (Room.Members[i].PeerId == peerId)
                                    {
                                        break;
                                    }
                                }

                                int j = 0;
                                for (; j < Room.Members.Count; j++)
                                {// j adalah indeks current peer
                                    if (Room.Members[j].PeerId == PeerId)
                                    {
                                        break;
                                    }
                                }

                                if (j == i + 1 || (j == 0 && i == Room.Members.Count - 1)) // yg mau quit adalah peer sebelum current peer
                                {
                                    quit = true;
                                }

                                response = request;

                                lock (nextPeerPaddle)
                                {
                                    nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                                    Logger.WriteLine("Forward Quit to " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address);
                                    bufferRecv = new byte[1024];
                                    nextPeerSocket.Receive(bufferRecv, 0, bufferRecv.Length, SocketFlags.None);
                                }

                                if (i == j + 1 || (i == 0 && j == Room.Members.Count - 1))// yg mau quit adalah peer setelah current peer
                                {
                                    nextPeerSocket.Close();
                                    IPAddress ip = Room.Members[(i + 1) % (Room.Members.Count - 1)].IPAddress;
                                    IPEndPoint ipEndPoint = new IPEndPoint(ip, Room.Members[(i + 1) % (Room.Members.Count - 1)].ListeningPort);
                                    nextPeerSocket = new Socket(
                                        ip.AddressFamily,
                                        SocketType.Stream,
                                        ProtocolType.Tcp
                                        );

                                    nextPeerSocket.NoDelay = false;
                                    nextPeerSocket.Connect(ipEndPoint);

                                    nextPeerSocket = null;
                                }

                                if (this.PeerId == Room.Creator.PeerId || (peerId == Room.Creator.PeerId && Room.Members[1].PeerId == this.PeerId))
                                {
                                    lock (trackerPaddle)
                                    {
                                        response = Message.CreateMessageRemove(peerId, PeerId, Configuration.ListenPort, Room.RoomId);
                                        trackerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);

                                        bufferRecv = new byte[1024];
                                        trackerSocket.Receive(bufferRecv, 0, bufferRecv.Length, SocketFlags.None);
                                    }
                                }

                                if (peerId == Room.Creator.PeerId)
                                {
                                    Room.Creator = Room.Members[1];
                                }

                                response = Message.CreateMessageSuccess();
                                handler.Send(response.data, 0, response.data.Length, SocketFlags.None);

                                bufferRecv = new byte[1024];
                                nextPeerSocket.Receive(bufferRecv, 0, bufferRecv.Length, SocketFlags.None);
                            }
                        }
                        else
                        {
                            lock (trackerPaddle)
                            {
                                response = Message.CreateMessageRemove(peerId, PeerId, Configuration.ListenPort, Room.RoomId);
                                trackerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);

                                bufferRecv = new byte[1024];
                                trackerSocket.Receive(bufferRecv, 0, bufferRecv.Length, SocketFlags.None);
                            }
                        }
                        Room.Members.Remove(peer);
                    }
                    else if (requestType == Message.MessageType.Start)
                    {
                        #region Start
                        Logger.WriteLine("Start");
                        int peerId;
                        string roomId;
                        request.GetStart(out peerId, out roomId);

                        Logger.WriteLine("Received START message with PeerId : " + peerId + " RoomId : " + roomId);

                        if (peerId == PeerId)
                        {
                            // do nothing
                            Logger.WriteLine("FINISHED");
                        }
                        else
                        {
                            // Send NewMember message to next peer
                            response = request;
                            nextPeerSocket.Send(response.data, 0, response.data.Length, SocketFlags.None);
                            Logger.WriteLine("Forward START to " + (nextPeerSocket.RemoteEndPoint as IPEndPoint).Address);
                        }
                    }
                    else
                    {
                        Logger.WriteLine("Listener receive unknown message");
                        // Send FAILED message akibat ruang penuh
                        response = Message.CreateMessageFailed();
                        handler.Send(response.data, 0, response.data.Length, SocketFlags.None);
                    }
                        #endregion
                }

                if (!quit)
                {
                    IAsyncResult nextAsyncResult = handler.BeginReceive(
                        buffer,
                        0,
                        buffer.Length,
                        SocketFlags.None,
                        new AsyncCallback(ReceiveCallback),
                        obj
                    );

                    if (!nextAsyncResult.AsyncWaitHandle.WaitOne(Configuration.MaxTimeout))
                    {
                        Logger.WriteLine("Connection timeout for peer with IP Address " + (handler.LocalEndPoint as IPEndPoint).Address + ":" + (handler.LocalEndPoint as IPEndPoint).Port + " -> " + (handler.RemoteEndPoint as IPEndPoint).Address + ":" + (handler.RemoteEndPoint as IPEndPoint).Port);
                        Logger.WriteLine("Closing connection " + (handler.RemoteEndPoint as IPEndPoint).Address + ":" + (handler.RemoteEndPoint as IPEndPoint).Port);
                        handler.Close();
                    }
                }
            }
            catch (SocketException exc)
            {
                Logger.WriteLine(exc);
                if (exc.SocketErrorCode == SocketError.HostDown || exc.SocketErrorCode == SocketError.ConnectionReset)
                {
                    if (Room.Members.Count > 2)
                    {
                        int index = -1;
                        for (int i = 0; i < Room.Members.Count; i++)
                        {
                            Peer p = Room.Members[i];
                            if (p.IPAddress.Equals((handler.LocalEndPoint as IPEndPoint).Address))
                            {
                                index = i;
                            }
                        }

                        if (index == 0)
                        {
                            index = Room.Members.Count - 2;
                        }
                        else
                        {
                            index--;
                        }

                        Peer backPeer = Room.Members[index];
                        byte[] buffer = new byte[1024];
                        Message request = Message.CreateMessageQuit(backPeer.PeerId);
                        lock (nextPeerPaddle)
                        {
                            nextPeerSocket.Send(request.data, 0, request.data.Length, SocketFlags.None);
                            nextPeerSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                        }
                    }
                    else
                    {
                        // Remove last element
                        Room.Members.RemoveAt(1);
                        lock (nextPeerPaddle)
                        {
                            nextPeerSocket = null;
                        }
                    }
                }
            }

            Logger.WriteLine();
        }
예제 #2
0
        public bool CreateRoom(string roomId, int maxPlayers)
        {
            try
            {
                if (IsConnected && !IsInRoom)
                {
                    Logger.WriteLine("Requesting to create room");

                    byte[] buffer = new byte[1024];
                    Message request = Message.CreateMessageCreate(PeerId, maxPlayers, roomId, Configuration.ListenPort);

                    lock (trackerPaddle)
                    {
                        trackerSocket.Send(request.data, 0, request.data.Length, SocketFlags.None);
                        trackerSocket.Receive(buffer, buffer.Length, SocketFlags.None);
                    }

                    Message response = new Message(buffer);
                    Message.MessageType responseType = response.GetMessageType();
                    if (responseType == Message.MessageType.Success)
                    {
                        Logger.WriteLine("Request create room success: " + roomId);

                        Room = new Room(roomId, new Peer(PeerId, (trackerSocket.LocalEndPoint as IPEndPoint).Address, Configuration.ListenPort), maxPlayers);
                        Room.Members.Add(Room.Creator);

                        IsInRoom = true;
                        IsCreator = true;

                        return true;
                    }
                    else if (responseType == Message.MessageType.Failed)
                    {
                        Logger.WriteLine("Request create room failed.");
                        return false;
                    }
                    else
                    {
                        Logger.WriteLine("Response unrecognized.");
                        return false;
                    }
                }
                else if (!IsConnected)
                {
                    Logger.WriteLine("Not connected to tracker, connect to tracker first.");
                    return false;
                }
                else if (IsInRoom)
                {
                    Logger.WriteLine("Currently in room, quit room first.");
                    return false;
                }
                else
                {
                    Logger.WriteLine("Unknown error.");
                    return false;
                }
            }
            catch (Exception exc)
            {
                Logger.WriteLine(exc);
                return false;
            }
        }