internal void AddClientOrSession(TcpMapServerClient client) { var list = client._is_client ? _clients : (client.SessionId != null ? _sessions : _presessions); lock (list) list.Add(client); if (list.Count > 1) { //TODO:shall test alive for other clients //When client switch IP , the socket will not timeout for read List <TcpMapServerClient> others = new List <TcpMapServerClient>(); lock (list) { others = new List <TcpMapServerClient>(list); } foreach (var other in others) { if (other == client) { continue; } other.TestAlive(); } } }
internal TcpMapServerClient FindClient() { TryAgain: TcpMapServerClient sclient = null; lock (_clients) { if (_clients.Count == 1) { sclient = _clients[0]; } else if (_clients.Count != 0) { sclient = _clients[Interlocked.Increment(ref nextclientindex) % _clients.Count]; if (DateTime.Now - sclient._lastPingTime > TimeSpan.FromSeconds(90)) { //TODO:maybe the client socket has timeout sclient.Stop(); //RemoveClientOrSession(sclient); goto TryAgain; } } else { // no client } } return(sclient); }
internal void AddClientOrSession(TcpMapServerClient client) { var list = client._is_client ? _clients : (client.SessionId != null ? _sessions : _presessions); lock (list) list.Add(client); }
internal void RemoveClientOrSession(TcpMapServerClient client) { _lastDisconnectTime = DateTime.Now; var list = client._is_client ? _clients : (client.SessionId != null ? _sessions : _presessions); lock (list) list.Remove(client); }
static public async Task AcceptConnectAndWorkAsync(Socket socket, CommandMessage connmsg) { System.Diagnostics.Debug.Assert(connmsg.Name == "ClientConnect" || connmsg.Name == "SessionConnect"); TcpMapServerClient client = new TcpMapServerClient(); client._socket = socket; await client.WorkAsync(connmsg); }
static async Task ProcesSocketAsync(Socket socket) { while (true) { var msg = await CommandMessage.ReadFromSocketAsync(socket); if (msg == null) { //LogMessage("no message ? Connected:" + socket.Connected); return; } //LogMessage("new msg : " + msg); switch (msg.Name) { case "ClientConnect": case "SessionConnect": await TcpMapServerClient.AcceptConnectAndWorkAsync(socket, msg); return; case "ConnectorConnect": var server = FindServerWorkerByPort(int.Parse(msg.Args[1])); string failedmsg = null; if (server == null) { failedmsg = "NoPort"; } else if (server.Server.IsDisabled) { failedmsg = "IsDisabled"; } else if (!server.Server.AllowConnector) { failedmsg = "NotAllow"; } else if (server.Server.ConnectorLicense == null) { failedmsg = "NotLicense"; } else if (server.Server.ConnectorLicense.Key != msg.Args[0]) { failedmsg = "LicenseNotMatch"; } if (failedmsg != null) { var resmsg = new CommandMessage("ConnectFailed", failedmsg); await socket.SendAsync(resmsg.Pack(), SocketFlags.None); } else { await server.AcceptConnectorAndWorkAsync(socket, msg); } break; case "": //other direct request.. default: throw new Exception("Invaild command " + msg.Name); } } }
internal async Task AcceptConnectorAndWorkAsync(Socket clientSock, CommandMessage connmsg) { bool supportEncrypt = _worker.Server.UseEncrypt; if (connmsg.Args[4] == "0") { supportEncrypt = false; } byte[] clientKeyIV; try { _worker.Server.ConnectorLicense.DescriptSourceKey(Convert.FromBase64String(connmsg.Args[2]), Convert.FromBase64String(connmsg.Args[3]), out clientKeyIV); } catch (Exception x) { _worker.OnError(x); var failedmsg = new CommandMessage("ConnectFailed", "InvalidSecureKey"); await clientSock.SendAsync(failedmsg.Pack(), SocketFlags.None); return; } TcpMapServerClient sclient = _worker.FindClient(); if (sclient == null) { var failedmsg = new CommandMessage("ConnectFailed", "NoClient"); await clientSock.SendAsync(failedmsg.Pack(), SocketFlags.None); return; } string mode = connmsg.Args[5]; string connArgument = connmsg.Args[6]; if (mode == "USB") //use server bandwidth { var resmsg = new CommandMessage("ConnectOK", "ConnectOK", supportEncrypt ? "1" : "0"); await clientSock.SendAsync(resmsg.Pack(), SocketFlags.None); Stream _sread, _swrite; if (supportEncrypt) { _worker.Server.ConnectorLicense.OverrideStream(clientSock.CreateStream(), clientKeyIV, out _sread, out _swrite); } else { _sread = _swrite = clientSock.CreateStream(); } using Socket localsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); string ip = _worker.Server.ServerBind; if (ip == "0.0.0.0") { ip = "127.0.0.1"; } localsock.InitTcp(); await localsock.ConnectAsync(ip, _worker.Server.ServerPort); TcpMapConnectorSession session = new TcpMapConnectorSession(new SimpleSocketStream(localsock)); await session.DirectWorkAsync(_sread, _swrite); } else if (mode == "UDP") { if (_udpcache == null) { lock (typeof(TcpMapServerConnector)) { if (_udpcache == null) { var opt = new MemoryCacheOptions(); Microsoft.Extensions.Options.IOptions <MemoryCacheOptions> iopt = Microsoft.Extensions.Options.Options.Create(opt); _udpcache = new MemoryCache(iopt); } } } UdpInfoItem natinfo; string key = connArgument + ":" + sclient.SessionId; if (!_udpcache.TryGetValue(key, out natinfo) || natinfo.HasExpired()) { var udpmsg = await sclient.CreateUDPNatAsync(connArgument); string[] pair = udpmsg.Args[1].Split(':'); string addr = pair[0]; int port = int.Parse(pair[1]); natinfo = new UdpInfoItem(addr + ":" + port); _udpcache.Set(key, natinfo); } var resmsg = new CommandMessage("ConnectOK", "ConnectOK", supportEncrypt ? "1" : "0", natinfo.NatInfo); await clientSock.SendAsync(resmsg.Pack(), SocketFlags.None); resmsg = await CommandMessage.ReadFromSocketAsync(clientSock); if (resmsg == null) { return; } throw new NotImplementedException("work for " + resmsg); } else if (mode == "RCP") { var resmsg = new CommandMessage("ConnectOK", "ConnectOK", supportEncrypt ? "1" : "0" , ((IPEndPoint)sclient._socket.RemoteEndPoint).Address.ToString(), sclient.OptionRouterClientPort.ToString()); await clientSock.SendAsync(resmsg.Pack(), SocketFlags.None); } else { throw new NotImplementedException(); } }
async Task ProcessSocketAsync(Socket socket) { //LogMessage("new server conn : " + socket.LocalEndPoint + " , " + socket.RemoteEndPoint); string sessionid = Guid.NewGuid().ToString(); int tryagainIndex = 0; TryAgain: if (!socket.Connected) //this property is not OK .. actually the client has disconnect { return; } tryagainIndex++; if (tryagainIndex > 3) //only try 3 times. { return; } TcpMapServerClient sclient = FindClient(); if (sclient == null) { if (DateTime.Now - _lastDisconnectTime < TimeSpan.FromSeconds(8)) //TODO:const connect wait sclient timeout { await Task.Delay(500); goto TryAgain; } throw new Exception("no sclient."); } TcpMapServerClient presession = null; try { lock (_presessions) { if (_presessions.Count != 0) { presession = _presessions[0]; _presessions.RemoveAt(0); } } if (presession != null) { try { await presession.UpgradeSessionAsync(sessionid); } catch (Exception x) { OnError(x); LogMessage("Error:ServerWorker presession upgrade failed @" + tryagainIndex + " , " + sessionid); goto TryAgain; } lock (_sessions) _sessions.Add(presession); LogMessage("ServerWorker session upgraded @" + tryagainIndex + " , " + sessionid); } else { await sclient.StartSessionAsync(sessionid); LogMessage("ServerWorker session created @" + tryagainIndex + " , " + sessionid); } } catch (Exception x) { OnError(x); await Task.Delay(500); //TODO:const... goto TryAgain; } try { TcpMapServerSession session = new TcpMapServerSession(socket.CreateStream(), sessionid); sessionMap.TryAdd(sessionid, session); LogMessage("Warning: TcpMapServerSession added:" + sessionid); try { if (presession != null) { presession.AttachToSession(session); } await session.WorkAsync(); } finally { sessionMap.TryRemove(sessionid, out _); LogMessage("Warning: TcpMapServerSession removed:" + sessionid); } } catch (Exception x) { OnError(x); } await sclient.CloseSessionAsync(sessionid); //LogMessage("ServerWorker session closed @" + tryagainIndex); }