public InitializationResponse ConnectToServer() { client.Connect(server_endpoint); this.private_endpoint = ((IPEndPoint)client.LocalEndPoint).Convert(); System.Console.WriteLine($"{client.LocalEndPoint}"); System.Console.WriteLine($"Local endpoint: {private_endpoint.GetAddress()}:{private_endpoint.Port}"); this.state = Tcp_State.Initialization; this.stream = new NetworkStream(client); InitializationRequest info = new InitializationRequest { ClientId = id, PrivateEndpoint = private_endpoint }; info.WriteDelimitedTo(stream); var response = InitializationResponse.Parser.ParseDelimitedFrom(stream); this.state = Tcp_State.WithoutLobby; return(response); }
public PeerWithinLobbyResponse ReceiveWithinLobbyPeerRequest() { // same spiel as above goes for here as well if (!TryGetMessageOrStateChange(out PeerWithinLobbyRequest request)) { return(null); } switch (request.MessageCase) { case PeerWithinLobbyRequest.MessageOneofCase.LeaveLobbyRequest: { LeaveLobby(); state = Tcp_State.WithoutLobby; var response = new LeaveLobbyResponse(); response.Success = true; return(new PeerWithinLobbyResponse { LeaveLobbyResponse = response }); } default: Log($"Unexpected within lobby request message."); return(null); } }
public bool TryJoinLobby(int id, string password) { var request = new WithoutLobbyRequest(); var message = new JoinLobbyRequest(); message.Password = password; message.LobbyId = id; request.JoinLobbyRequest = message; System.Console.WriteLine($"Joining lobby {id}"); request.WriteDelimitedTo(stream); var response = JoinLobbyResponse.Parser.ParseDelimitedFrom(stream); if (response.LobbyInfo != null) { System.Console.WriteLine($"Successfully joined lobby: {response.LobbyInfo}"); this.state = Tcp_State.PeerWithinLobby; this.joined_lobby = response.LobbyInfo; return(true); } this.state = Tcp_State.WithoutLobby; return(false); }
public Client(IPEndPoint server_endpoint) { this.server_endpoint = server_endpoint; this.client = CreateSocket(); this.id = new Random().Next(); this.state = Tcp_State.Connecting; }
public bool TryCreateLobby(string password) { var request = new WithoutLobbyRequest(); var message = new CreateLobbyRequest(); message.Password = password; message.Capacity = 2; request.CreateLobbyRequest = message; System.Console.WriteLine($"Creating lobby {id}"); request.WriteDelimitedTo(stream); var response = CreateLobbyResponse.Parser.ParseDelimitedFrom(stream); if (response.LobbyId != 0) { System.Console.WriteLine($"Successfully created lobby {response.LobbyId}"); this.state = Tcp_State.HostWithinLobby; this.joined_lobby = new LobbyInfo { HostId = id, LobbyId = response.LobbyId, Capacity = message.Capacity }; return(true); } this.state = Tcp_State.WithoutLobby; return(false); }
public void Start() { try { Initialize(); server.sessions.Add(id, this); state = Tcp_State.WithoutLobby; while (state != Tcp_State.Closed && client.Connected) { switch (state) { case Tcp_State.WithoutLobby: ReceiveMessageAndRespond(ReceiveWithoutLobbyRequest); break; case Tcp_State.PeerWithinLobby: ReceiveMessageAndRespond(ReceiveWithinLobbyPeerRequest); break; case Tcp_State.HostWithinLobby: ReceiveMessageAndRespond(ReceiveWithinLobbyHostRequest); break; case Tcp_State.Closing: // for now, just end the session Log("Closing session in 10 seconds, since lobby has been locked."); Thread.Sleep(10 * 1000); state = Tcp_State.Closed; break; } } Log($"Ending session."); } catch (System.Exception e) { Log($"Session prematurely ended due to the exception: {e}"); } server.sessions.Remove(id); if (joined_lobby != null) { LeaveLobby(); foreach (var lobby in server.lobbies.Values) { server.Log(lobby.GetInfo().ToString()); } } if (client.Connected) { client.Close(); } }
public void ListenHost() { var response = ReceiveMessage <HostWithinLobbyResponse>(); switch (response.MessageCase) { case HostWithinLobbyResponse.MessageOneofCase.PeerJoinedNotification: System.Console.WriteLine("Peer joined"); AddPeerToLobby(response.PeerJoinedNotification); break; case MakeHostResponse: System.Console.WriteLine("Made smb host"); break; case HostWithinLobbyResponse.MessageOneofCase.LeaveLobbyResponse: System.Console.WriteLine("Leave lobby response"); break; case GoResponse: if (response.GoResponse.PeerAddressInfo.Count > 0) { var tasks = new Task <Socket> [response.GoResponse.PeerAddressInfo.Count]; for (int i = 0; i < tasks.Length; i++) { var info = response.GoResponse.PeerAddressInfo[i]; tasks[i] = Task.Run(() => EstablishOutboundTcp(info)); System.Console.WriteLine(info.ToPrettyString()); } Task.WaitAll(tasks); for (int i = 0; i < tasks.Length; i++) { System.Console.WriteLine($"{i}: Connection established? {tasks[i].Result != null}"); } } ConnectedToPeerEvent?.Invoke(); state = Tcp_State.Closing; break; default: System.Console.WriteLine("Unexpected response/notification"); break; } }
public void StartReceiving() { while (state != Tcp_State.Closed && client.Connected) { switch (state) { case Tcp_State.PeerWithinLobby: ListenPeer(); break; case Tcp_State.HostWithinLobby: ListenHost(); break; case Tcp_State.Closing: System.Console.WriteLine("Closing"); state = Tcp_State.Closed; break; } } }
public void ListenPeer() { var response = ReceiveMessage <PeerWithinLobbyResponse>(); switch (response.MessageCase) { case PeerWithinLobbyResponse.MessageOneofCase.PeerJoinedNotification: AddPeerToLobby(response.PeerJoinedNotification); System.Console.WriteLine("Peer joined"); break; case LeaveLobbyNotification: System.Console.WriteLine("Leave lobby notification"); break; case BecomeHostNotification: System.Console.WriteLine("Promoted to host"); break; case PeerWithinLobbyResponse.MessageOneofCase.LeaveLobbyResponse: System.Console.WriteLine("Leave lobby response"); break; case HostAddressInfo: { var info = response.HostAddressInfo; System.Console.WriteLine(info.ToPrettyString()); var task = Task.Run(() => EstablishOutboundTcp(response.HostAddressInfo)); Task.WaitAll(task); System.Console.WriteLine($"Connection to host established? {task.Result != null}"); state = Tcp_State.Closing; ConnectedToPeerEvent?.Invoke(); break; } default: System.Console.WriteLine("Unexpected response/notification"); break; } }
public HostWithinLobbyResponse ReceiveWithinLobbyHostRequest() { // same spiel as above goes for here as well if (!TryGetMessageOrStateChange(out HostWithinLobbyRequest request)) { return(null); } var outerResponse = new HostWithinLobbyResponse(); switch (request.MessageCase) { case HostWithinLobbyRequest.MessageOneofCase.LeaveLobbyRequest: { LeaveLobby(); var response = new LeaveLobbyResponse(); response.Success = true; state = Tcp_State.WithoutLobby; return(new HostWithinLobbyResponse { LeaveLobbyResponse = response }); } case MakeHostRequest: { var response = new MakeHostResponse(); int peer_id = request.MakeHostRequest.PeerId; if (id != peer_id && // since we are host joined_lobby.peers.ContainsKey(peer_id)) { response.NewHostId = peer_id; MakeHost(joined_lobby.peers[peer_id]); } return(new HostWithinLobbyResponse { MakeHostResponse = response }); } case GoRequest: { var host_response = new GoResponse(); var host_address_message = CreateAddressMessage(); var peer_notification = new PeerWithinLobbyResponse { HostAddressInfo = host_address_message }; // TODO: run concurrently (although sending is pretty fast, I suppose) foreach (var peer_id in joined_lobby.GetNonHostPeerIds()) { var peer = joined_lobby.peers[peer_id]; try { peer.joined_lobby = null; peer.TransitionState(Tcp_State.Closing); peer_notification.WriteDelimitedTo(peer.stream); host_response.PeerAddressInfo.Add(peer.CreateAddressMessage()); } catch { peer.Log($"An error has been catched while trying to send PeerAddressInfo"); } } server.lobbies.Remove(joined_lobby.id); joined_lobby = null; state = Tcp_State.Closing; return(new HostWithinLobbyResponse { GoResponse = host_response }); } default: Log($"Unexpected within lobby request message."); return(null); } }
public Tcp_Session(Socket client, Server server) { this.client = client; this.state = Tcp_State.Connecting; this.server = server; }
public IMessage ReceiveWithoutLobbyRequest() { // so, this happens in 2 cases: // 1. either a state has been changed, which would rerun the loop condition and // it would exit into the main loop; // 2. or it were not, in which case the reading of stream failed. // Either invalid data has been received or the client has diconnected. // This is also checked in the while conditon. // UDPATE: the client.Connected property does not reflect the fact whether the // client is connected. However, the stream does get closed when the connection dies down. if (!TryGetMessageOrStateChange(out WithoutLobbyRequest request)) { return(null); } switch (request.MessageCase) { // TODO: do stuff with the password case CreateLobbyRequest: { Log("Creating a new lobby..."); CreateLobbyResponse response = new CreateLobbyResponse(); if (server.TryCreateLobby(id, out Lobby lobby) && lobby.TryJoin(this)) { Log($"Creating a new lobby {lobby.id}"); joined_lobby = lobby; response.LobbyId = lobby.id; state = Tcp_State.HostWithinLobby; } return(response); } case JoinLobbyRequest: { Log($"Joining lobby {request.JoinLobbyRequest.LobbyId}..."); JoinLobbyResponse response = new JoinLobbyResponse(); if (server.lobbies.TryGetValue(request.JoinLobbyRequest.LobbyId, out Lobby lobby) && lobby.TryJoin(this)) { Log($"Joined lobby {request.JoinLobbyRequest.LobbyId}."); joined_lobby = lobby; response.LobbyInfo = lobby.GetInfo(); state = Tcp_State.PeerWithinLobby; // notify other peers var peer_joined_notification = new PeerJoinedNotification(); peer_joined_notification.PeerId = id; foreach (var peer_id in lobby.peers.Keys) { if (peer_id != id) { lobby.peers[peer_id].SendPeerJoinedNotification(peer_joined_notification); } } } return(response); } case MyAddressInfoRequest: { Log($"Sending address info message."); return(CreateAddressMessage()); } default: Log($"Unexpected WithoutLobby request message. {request}"); return(null); } }
/* * This method is useful when changing the state of some other session from without * its thread, so e.g. if thread of session with id = 1 transitions thread with id = 2 * into another state. * * This potentially might be dangerous to do while the other thread is in the process * of receiving messages, which is why: * a. the listen task gets cancelled to not misinterpret the message. * b. if in the middle of parsing, the message and the buffered data is all discarded. * * An ideal solution would be to finish parsing, if in the middle of parsing, but then discard * the message, however, I have no way of knowing that information, since I'm using protobuf for packets. */ public void TransitionState(Tcp_State state) { this.state = state; this.change_state_task_completion_source.SetResult(state); }