public void TestRemoting() { using (RemoteTCPService<RemoteService> service = new RemoteTCPService<RemoteService>(50315, "TestRemoting", WellKnownObjectMode.Singleton)) { service.Connect(); using (RemoteTCPClient<IRemoteService> client = new RemoteTCPClient<IRemoteService>(new IPAddress(new byte[] { 127, 0, 0, 1 }), 50315, "TestRemoting")) { client.Connect(); Assert.IsTrue(client.ServiceObject.Add(1.2d, 3.5d) == (1.2d + 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Sub(1.2d, 3.5d) == (1.2d - 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Div(1.2d, 3.5d) == (1.2d / 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Mul(1.2d, 3.5d) == (1.2d * 3.5d), "Wrong add!"); client.Disconnect(); } service.Disconnect(); } }
public void TestRemoting() { using (RemoteTCPService <RemoteService> service = new RemoteTCPService <RemoteService>(50315, "TestRemoting", WellKnownObjectMode.Singleton)) { service.Connect(); using (RemoteTCPClient <IRemoteService> client = new RemoteTCPClient <IRemoteService>(new IPAddress(new byte[] { 127, 0, 0, 1 }), 50315, "TestRemoting")) { client.Connect(); Assert.IsTrue(client.ServiceObject.Add(1.2d, 3.5d) == (1.2d + 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Sub(1.2d, 3.5d) == (1.2d - 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Div(1.2d, 3.5d) == (1.2d / 3.5d), "Wrong add!"); Assert.IsTrue(client.ServiceObject.Mul(1.2d, 3.5d) == (1.2d * 3.5d), "Wrong add!"); client.Disconnect(); } service.Disconnect(); } }
/// <summary> /// Begin listening for client requests. /// </summary> public void Listen() { using (NetworkStream clientStream = ClientTCPClient.GetStream()) { //Authentication and Endpoint request process. while (IsRunning) { try { //How much bytes is our client sending. byte[] buffer = new byte[ClientTCPClient.Available]; if (buffer.Length > 0) { Inactivity.Restart(); //Read those bytes. var read = clientStream.Read(buffer, 0, buffer.Length); //Parse the header. var message = ReadMessageType(this, buffer); //Process MessageType switch (message) { //Client requeste with NoAuth method. case MessageType.MethodRequest: { //Parse the client method request. using (MethodRequest mReq = new MethodRequest(buffer)) { if (mReq.Valid) //We successfully built the packet. { AuthMethod = mReq.Method; if (AuthMethod == Method.NoAuthentication) { NonBlockingConsole.WriteLine($"Client {ClientTCPClient?.Client?.RemoteEndPoint} AUTHENTICATION complete."); Authenticated = true; //Flag as authenticated. } //Write response onto our client stream. using (MethodResponse response = new MethodResponse(mReq)) clientStream.Write(response.Data, 0, response.Data.Length); } else { throw new Exception($"Client {ClientTCPClient?.Client?.RemoteEndPoint} Invalid Method request."); } break; } } //Client sent auth request, in this case, UserPass which is the only "secure" method supported. case MessageType.AuthRequest: { //Parse the client auth request. using (AuthenticationRequest authReq = new AuthenticationRequest(buffer)) { if (authReq.Valid) //We successfully built the packet. { //Create our response which will also validate login information. using (AuthenticationResponse authRes = new AuthenticationResponse(authReq)) { if (authRes.Valid) { NonBlockingConsole.WriteLine($"Client {ClientTCPClient?.Client?.RemoteEndPoint} AUTHENTICATION complete."); Authenticated = true; //Flag as authenticated. } //Send handshake result. clientStream.Write(authRes.Data, 0, authRes.Data.Length); } if (!Authenticated) //Wrong authentication, throw and disconnect this client. { throw new Exception($"Client {ClientTCPClient?.Client?.RemoteEndPoint} Invalid authentication request."); } } else //Wrong authentication, throw and disconnect this client. { throw new Exception($"Client {ClientTCPClient?.Client?.RemoteEndPoint} Invalid authentication request."); } break; } } //After a successful handshake, the client tell us his request. case MessageType.DataRequest: { //Parse the datarequest from the client. using (var dReq = new DataRequest(buffer)) { //Handle the command, so far we only support 0x01 CONNECT. switch (dReq.Command) { case Command.Connect: //Create the remote socket according to the request AddressFamily if (RemoteTCPClient == null) { RemoteTCPClient = new TcpClient(dReq.DestinationAddress.AddressFamily); RemoteTCPClient.ReceiveBufferSize = 512000; //512Kb RemoteTCPClient.SendBufferSize = 512000; //512Kb } NonBlockingConsole.WriteLine($"Client {ClientTCPClient?.Client?.RemoteEndPoint} CONNECT request to {dReq?.DestinationAddress}:{dReq?.Port}"); //Try to connect to the remote endpoint the client is requesting. RemoteTCPClient.Connect(dReq.DestinationAddress, dReq.Port); Result result; if (RemoteTCPClient.Connected) { result = Result.Succeeded; NonBlockingConsole.WriteLine($"Client {ClientTCPClient?.Client?.RemoteEndPoint} GRANTED connection. Entering tunnel mode."); } else { result = Result.Network_Unreachable; NonBlockingConsole.WriteLine($"Client {ClientTCPClient?.Client?.RemoteEndPoint} host REJECTED the connection."); } //Write the result to our client stream. using (DataResponse dResponse = new DataResponse(result, dReq.AddressType, dReq.DestinationBytes, dReq.PortBytes)) clientStream.Write(dResponse.Data, 0, dResponse.Data.Length); if (result != Result.Succeeded) { throw new Exception($"Client {ClientTCPClient?.Client?.RemoteEndPoint} Remote host reject the connection."); } break; default: throw new Exception($"Client {ClientTCPClient?.Client?.RemoteEndPoint} Unsuported message, disconnecting client."); } } break; } case MessageType.Null: throw new Exception("Invalid routing."); } } buffer = null; //At this point, if we have stablished a remote connection we go on and break in order to enter tunnel mode. if (RemoteTCPClient != null && RemoteTCPClient.Connected) { break; } //If this client has reported no activity in 10 seconds, kill it. We have no better way of knowing with TcpClients. if (Inactivity.Elapsed.TotalSeconds > 10) { break; } Thread.Sleep(1); } catch (Exception ex) { //Something went wrong, exit loop, this will unstuck the calling thread and will call Dispose on this object. NonBlockingConsole.WriteLine($"[ERROR] {ex.Message}"); break; } } try { if (Authenticated) { //The client already went through handshake and datarequest, at this point we are just passing data between client <-> remote using (NetworkStream remoteStream = RemoteTCPClient.GetStream()) { while (IsRunning && Authenticated) { if (Inactivity.Elapsed.TotalSeconds > 10) { break; } try { byte[] buffer = new byte[ClientTCPClient.Available]; if (buffer.Length > 0) { Inactivity.Restart(); var read = clientStream.Read(buffer, 0, buffer.Length); remoteStream.Write(buffer, 0, buffer.Length); } byte[] remoteBuff = new byte[RemoteTCPClient.Available]; if (remoteBuff.Length > 0) { Inactivity.Restart(); remoteStream.Read(remoteBuff, 0, remoteBuff.Length); clientStream.Write(remoteBuff, 0, remoteBuff.Length); } Thread.Sleep(1); } catch (Exception ex) { //Something went wrong, exit loop, this will unstuck the calling thread and will call Dispose on this object. NonBlockingConsole.WriteLine($"[ERROR] {ex.Message}"); break; } } } } } catch (Exception ex) { NonBlockingConsole.WriteLine($"[ERROR] {ex.Message}"); } } }