protected override async Task <CommandMessage> ReadMessageAsync() { if (this.sread == null) { await this.WaitForAttachAsync(); } ReadAgain: var msg = await CommandMessage.ReadFromStreamAsync(this.sread); if (msg == null || msg.Name == "data") { return(msg); } //TcpMapService.LogMessage("ServerSession:get message " + msg); switch (msg.Name) { case "_ping_": await this.swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: TcpMapService.LogMessage("Error: 6 Ignore message " + msg); break; } goto ReadAgain; }
protected override async Task <CommandMessage> ReadMessageAsync() { ReadAgain: CommandMessage msg; CancellationTokenSource cts = null; if (DateTime.Now - _lastwritetime > TimeSpan.FromMilliseconds(12000)) { _lastwritetime = DateTime.Now; await _swrite.WriteAsync(new CommandMessage("_ping_", "forwrite").Pack()); } else { cts = new CancellationTokenSource(); _ = Task.Run(async delegate { if (await cts.Token.WaitForSignalSettedAsync(16000)) { return; } _lastwritetime = DateTime.Now; await _swrite.WriteAsync(new CommandMessage("_ping_", "forread").Pack()); }); } try { msg = await CommandMessage.ReadFromStreamAsync(_sread); } finally { if (cts != null) { cts.Cancel(); } } if (msg == null || msg.Name == "data") { return(msg); } //TcpMapService.LogMessage("ClientSession:get message " + msg); switch (msg.Name) { case "_ping_": await _swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: TcpMapService.LogMessage("Error: 2 Ignore message " + msg); break; } goto ReadAgain; }
internal async Task UpgradeSessionAsync(string newsid) { SessionId = newsid; await _swrite.WriteAsync(new CommandMessage("UpgradeSession", newsid).Pack()); ReadAgain: var res = await CommandMessage.ReadFromStreamAsync(_sread); if (res == null) { throw (new Exception("Invalid null message ")); } if (res.Name == "_ping_" || res.Name == "_ping_result_") { goto ReadAgain; } if (res.Name != "UpgradeSessionResult") { throw (new Exception("Invalid message : " + res)); } if (res.Args[0] == "OK") { return; } throw (new Exception("Upgrade Session Failed : " + res)); }
protected override async Task<CommandMessage> ReadMessageAsync() { ReadAgain: CommandMessage msg; var cts = new CancellationTokenSource(); _ = Task.Run(async delegate { if (await cts.Token.WaitForSignalSettedAsync(16000)) return; try { await _swrite.WriteAsync(new CommandMessage("_ping_", "forread").Pack()); } catch (Exception x) { OnError(x); } }); try { msg = await CommandMessage.ReadFromStreamAsync(_sread); } finally { cts.Cancel(); } if (msg == null || msg.Name == "data") return msg; //TcpMapService.LogMessage("ServerSession:get message " + msg); switch (msg.Name) { case "_ping_": await _swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: TcpMapService.LogMessage("Error: 3 Ignore message " + msg); break; } goto ReadAgain; }
private async Task WorkAsync() { this.IsConnected = false; this.LogMessage("ClientWorker WorkAsync start"); int connectedTimes = 0; try { int againTimeout = 125; StartAgain: this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.socket.InitTcp(); this.cts_connect = new CancellationTokenSource(); try { await this.socket.ConnectAsync(this.Client.ServerHost, 6022); this.LogMessage("connected to 6022"); } catch (Exception x) { this.OnError(x); this.socket.CloseSocket(); this.socket = null; this.cts_connect = new CancellationTokenSource(); if (!this.IsStarted) { return; } if (againTimeout < 4) { againTimeout *= 2; } if (await this.cts_connect.Token.WaitForSignalSettedAsync(againTimeout)) { return; } goto StartAgain; } try { bool supportEncrypt = this.Client.UseEncrypt; byte[] clientKeyIV; { CommandMessage connmsg = new CommandMessage { Name = "ClientConnect" }; List <string> arglist = new List <string> { this.Client.License.Key, this.Client.ServerPort.ToString() }; this.Client.License.GenerateSecureKeyAndHash(out clientKeyIV, out byte[] encryptedKeyIV, out byte[] sourceHash); arglist.Add(Convert.ToBase64String(encryptedKeyIV)); arglist.Add(Convert.ToBase64String(sourceHash)); arglist.Add(supportEncrypt ? "1" : "0"); connmsg.Args = arglist.ToArray(); await this.socket.SendAsync(connmsg.Pack(), SocketFlags.None); //LogMessage("wait for conn msg"); connmsg = await CommandMessage.ReadFromSocketAsync(this.socket); if (connmsg == null) { TcpMapService.LogMessage("no message ? Connected:" + this.socket.Connected); return; } this.LogMessage("connmsg : " + connmsg.Name + " : " + string.Join(",", connmsg.Args)); if (connmsg.Name != "ConnectOK") { this.IsStarted = false;//don't go until start it again. throw new Exception(connmsg.Name + " : " + string.Join(",", connmsg.Args)); } if (supportEncrypt && connmsg.Args[1] == "0") { supportEncrypt = false; this.LogMessage("Warning:server don't support encryption."); } } this.IsConnected = true; connectedTimes++; this.LogMessage("ConnectOK #" + connectedTimes); if (supportEncrypt) { this.Client.License.OverrideStream(this.socket.CreateStream(), clientKeyIV, out this.sread, out this.swrite); } else { this.sread = this.swrite = this.socket.CreateStream(); } for (int i = 0; i < Math.Min(5, this.Client.PreSessionCount); i++)//TODO:const of 5 { _ = Task.Run(this.ProvidePreSessionAsync); } _ = Task.Run(this.MaintainSessionsAsync); if (this.Client.RouterClientPort > 0) { _ = this.swrite.WriteAsync(new CommandMessage("SetOption", "RouterClientPort", this.Client.RouterClientPort.ToString()).Pack()); } byte[] readbuff = new byte[TcpMapService.defaultBufferSize]; while (this.IsStarted) { CommandMessage msg; var cts = new CancellationTokenSource(); _ = Task.Run(async delegate { if (await cts.Token.WaitForSignalSettedAsync(16000)) { return; } try { await this.swrite.WriteAsync(new CommandMessage("_ping_", "forread").Pack()); } catch (Exception x) { this.OnError(x); } }); try { msg = await CommandMessage.ReadFromStreamAsync(this.sread); } finally { cts.Cancel(); } if (msg == null) { TcpMapService.LogMessage("no message ? Connected:" + this.socket.Connected); return; } //this.LogMessage("TcpMapClientWorker get msg " + msg); switch (msg.Name) { case "StartSession": Task.Run(async delegate { try { await this.DoStartSessionAsync(msg); } catch (Exception x) { this.OnError(x); } }).ToString(); break; case "CloseSession": Task.Run(async delegate { try { await this.DoCloseSessionAsync(msg); } catch (Exception x) { this.OnError(x); } }).ToString(); break; case "CreateUDPNat": Task.Run(async delegate { try { await this.DoCreateUDPNatAsync(msg); } catch (Exception x) { this.OnError(x); } }).ToString(); break; case "_ping_": await this.swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: this.LogMessage("Error: 4 Ignore message " + msg); break; } } } catch (SocketException) { //no log } catch (Exception x) { this.OnError(x); } if (this.IsStarted) { this.socket.CloseSocket();//logic failed.. againTimeout = 125; goto StartAgain; } } catch (Exception x) { this.OnError(x); } this.IsStarted = false; this.IsConnected = false; if (this.socket != null) { try { this.socket.CloseSocket(); } catch (Exception x) { this.OnError(x); } this.socket = null; } }
async Task WorkAsync() { IsStarted = true; IsConnected = false; //LogMessage("ClientSession WorkAsync start"); int connectedTimes = 0; try { int againTimeout = 125; StartAgain: _sock_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _sock_server.InitTcp(); _cts_connect = new CancellationTokenSource(); try { await _sock_server.ConnectAsync(Client.ServerHost, 6022); //LogMessage("connected to 6022"); } catch (Exception x) { OnError(x); _sock_server.CloseSocket(); _sock_server = null; _cts_connect = new CancellationTokenSource(); if (!IsStarted) { return; } if (againTimeout < 4) { againTimeout = againTimeout * 2; } if (await _cts_connect.Token.WaitForSignalSettedAsync(againTimeout)) { return; } goto StartAgain; } try { bool supportEncrypt = false; byte[] clientKeyIV; { CommandMessage connmsg = new CommandMessage(); connmsg.Name = "SessionConnect"; List <string> arglist = new List <string>(); arglist.Add(this.Client.License.Key); arglist.Add(this.Client.ServerPort.ToString()); byte[] encryptedKeyIV, sourceHash; Client.License.GenerateSecureKeyAndHash(out clientKeyIV, out encryptedKeyIV, out sourceHash); arglist.Add(Convert.ToBase64String(encryptedKeyIV)); arglist.Add(Convert.ToBase64String(sourceHash)); arglist.Add(supportEncrypt ? "1" : "0"); arglist.Add(SessionId); //sessionid at [5] connmsg.Args = arglist.ToArray(); await _sock_server.SendAsync(connmsg.Pack(), SocketFlags.None); //LogMessage("wait for conn msg"); connmsg = await CommandMessage.ReadFromSocketAsync(_sock_server); if (connmsg == null) { TcpMapService.LogMessage("no message ? Connected:" + _sock_server.Connected); return; } //LogMessage("connmsg : " + connmsg.Name + " : " + string.Join(",", connmsg.Args)); if (connmsg.Name != "ConnectOK") { IsStarted = false; //don't go until start it again. throw new Exception(connmsg.Name + " : " + string.Join(",", connmsg.Args)); } if (connmsg.Args[1] == "0") { supportEncrypt = false; } } IsConnected = true; connectedTimes++; //LogMessage("ConnectOK #" + connectedTimes); if (supportEncrypt) { Client.License.OverrideStream(_sock_server.CreateStream(), clientKeyIV, out _sread, out _swrite); } else { _sread = _swrite = _sock_server.CreateStream(); } if (string.IsNullOrEmpty(SessionId)) { //wait for Upgrade while (SessionId == null) { CommandMessage msg; var cts = new CancellationTokenSource(); _ = Task.Run(async delegate { if (await cts.Token.WaitForSignalSettedAsync(16000)) { return; } await _swrite.WriteAsync(new CommandMessage("_ping_", "forread").Pack()); }); try { msg = await CommandMessage.ReadFromStreamAsync(_sread); } finally { cts.Cancel(); } if (msg == null) { throw (new SocketException(995)); } switch (msg.Name) { case "UpgradeSession": try { _sock_local = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _sock_local.InitTcp(); await _sock_local.ConnectWithTimeoutAsync(Client.ClientHost, Client.ClientPort, 12000); } catch (Exception x) { TcpMapService.OnError(x); await _swrite.WriteAsync(new CommandMessage("UpgradeSessionResult", "Failed").Pack()); continue; } SessionId = msg.Args[0]; if (_cts_upgrade != null) { _cts_upgrade.Cancel(); } await _swrite.WriteAsync(new CommandMessage("UpgradeSessionResult", "OK").Pack()); break; case "_ping_": await _swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: LogMessage("Error: 1 Ignore message " + msg); break; } } } await WorkAsync(_sock_local.CreateStream()); } catch (Exception x) { OnError(x); } } catch (SocketException) { } catch (Exception x) { OnError(x); } IsStarted = false; IsConnected = false; _sock_server?.CloseSocket(); _sock_local?.CloseSocket(); _workend = true; }
async Task WorkAsync(CommandMessage connmsg) { if (connmsg.Name == "SessionConnect") { _is_client = false; _is_session = true; } byte[] clientKeyIV; _worker = TcpMapService.FindServerWorkerByKey(connmsg.Args[0], int.Parse(connmsg.Args[1])); string failedreason = null; if (_worker == null) { failedreason = "NotFound"; } else if (!_worker.Server.IsValidated) { failedreason = "NotValidated"; } else if (_worker.Server.IsDisabled) { failedreason = "NotEnabled"; } if (_worker == null || !string.IsNullOrEmpty(failedreason)) { var failedmsg = new CommandMessage("ConnectFailed", failedreason); await _socket.SendAsync(failedmsg.Pack(), SocketFlags.None); return; } bool supportEncrypt = _worker.Server.UseEncrypt; if (connmsg.Args[4] == "0") { supportEncrypt = false; } try { _worker.Server.License.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 _socket.SendAsync(failedmsg.Pack(), SocketFlags.None); return; } var successMsg = new CommandMessage("ConnectOK", "ConnectOK", supportEncrypt ? "1" : "0"); await _socket.SendAsync(successMsg.Pack(), SocketFlags.None); if (supportEncrypt) { _worker.Server.License.OverrideStream(_socket.CreateStream(), clientKeyIV, out _sread, out _swrite); } else { _sread = _swrite = _socket.CreateStream(); } if (_is_session) { this.SessionId = connmsg.Args[5]; if (SessionId == null) { _cts_wait_upgrade = new CancellationTokenSource(); } } _worker.AddClientOrSession(this); try { if (_is_client) { _ = _swrite.WriteAsync(new CommandMessage("SetOption", "ClientEndPoint", _socket.RemoteEndPoint.ToString()).Pack()); while (true) { var msg = await CommandMessage.ReadFromStreamAsync(_sread); //process it... if (msg == null) { //TcpMapService.LogMessage("no message ? Connected:" + _socket.Connected); throw new SocketException(995); } //_worker.LogMessage("TcpMapServerClient get msg " + msg); switch (msg.Name) { case "SetOption": string optvalue = msg.Args[1]; switch (msg.Args[0]) { case "RouterClientPort": this.OptionRouterClientPort = int.Parse(optvalue); break; default: _worker.LogMessage("Error:Ignore option " + msg); break; } break; case "StartSessionResult": case "CloseSessionResult": case "CreateUDPNatResult": long reqid = long.Parse(msg.Args[0]); if (reqmap.TryGetValue(reqid, out var ritem)) { ritem.Response = msg; ritem.cts.Cancel(); } else { _worker.LogMessage("Request Expired : " + msg); } break; case "_ping_": this._lastPingTime = DateTime.Now; await _swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: _worker.LogMessage("Error: 5 Ignore message " + msg); break; } } } else if (_is_session) { if (SessionId == null) { _worker.LogMessage($"Warning:ServerClient*{_scid} Wait for Upgrade To Session "); while (SessionId == null) { if (await _cts_wait_upgrade.Token.WaitForSignalSettedAsync(28000)) //check the presession closed or not every 28 seconds { if (SessionId != null) { break; //OK, session attached. } throw new SocketException(995); //_cts_wait_upgrade Cancelled , by SessionId is not seted } //if (!_socket.Connected) //NEVER useful.. //{ // _worker.LogMessage("Warning:presession exit."); // throw new SocketException(995); //} if (!_socket.Poll(0, SelectMode.SelectRead)) //WORKS.. { continue; } if (_socket.Available == 0) { _worker.LogMessage("Warning:presession exit!"); throw new SocketException(995); } //_worker.LogMessage("Warning:presession send message before upgrade ?"+_socket.Available); if (!_cts_wait_upgrade.IsCancellationRequested) { //TODO:not locked/sync, not so safe it the presession is upgrading var msg = await CommandMessage.ReadFromSocketAsync(_socket); if (msg.Name == "_ping_") { byte[] resp = new CommandMessage("_ping_result_").Pack(); await _socket.SendAsync(resp, SocketFlags.None); } else { _worker.LogMessage("Warning:presession unexpected msg : " + msg); } } } _worker.LogMessage($"Warning:ServerClient*{_scid} SessionId:" + SessionId); } int waitMapTimes = 0; TryGetMap: if (_attachedSession != null) { _worker.LogMessage($"ServerClient*{_scid} use attached Session : {SessionId} *{waitMapTimes}"); await _attachedSession.UseThisSocketAsync(_sread, _swrite); } else if (_worker.sessionMap.TryGetValue(SessionId, out var session)) { _worker.LogMessage($"ServerClient*{_scid} session server ok : {SessionId} *{waitMapTimes}"); await session.UseThisSocketAsync(_sread, _swrite); } else { if (waitMapTimes < 5) { waitMapTimes++; await Task.Delay(10); //wait sessionMap be added.. goto TryGetMap; } _worker.LogMessage($"Warning:ServerClient*{_scid} session not found : {SessionId}"); throw new Exception($"ServerClient*{_scid} session not found : {SessionId}"); } } else { throw new InvalidOperationException(); } } catch (SocketException) { //no log } catch (Exception x) { _worker.OnError(x); } finally { _worker.RemoveClientOrSession(this); } _worker.LogMessage($"ServerClient*{_scid} WorkAsync END " + SessionId); }