async Task ProcessSocketAsync(Socket tcpSocket) { TryAgain: string connmode = null; if (Connector.UseRouterClientPort && DateTime.Now > _stopUseRouterClientPortUntil) { connmode = "RCP"; } else if (Connector.UseUDPPunching && DateTime.Now > _stopUseRouterClientPortUntil) { connmode = "UDP"; } else if (Connector.UseServerBandwidth) { connmode = "USB"; } else { //TODO: try .. if (Connector.UseUDPPunching) { connmode = "UDP"; } else if (Connector.UseRouterClientPort) { connmode = "RCP"; } else { throw new Exception("No connection mode."); } } Task <KeyValuePair <string, UDPClientListener> > task2 = null; if (connmode == "UDP") { //TODO: shall cache the UDPClientListener ... task2 = Task.Run(GetUdpClientAsync); } Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.InitTcp(); await serverSocket.ConnectAsync(Connector.ServerHost, 6022); string connArgument = null; UDPClientListener udp = null; if (task2 != null) { try { var kvp = await task2; connArgument = kvp.Key; udp = kvp.Value; } catch (Exception x) { OnError(x); LogMessage("UDP Failed , switch ..."); if (Connector.UseServerBandwidth) { connmode = "USB"; } else { throw new Exception(x.Message, x); } } } bool supportEncrypt = Connector.UseEncrypt; byte[] clientKeyIV; CommandMessage connmsg = new CommandMessage(); connmsg.Name = "ConnectorConnect"; List <string> arglist = new List <string>(); arglist.Add(this.Connector.License.Key); arglist.Add(this.Connector.ServerPort.ToString()); byte[] encryptedKeyIV, sourceHash; Connector.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(connmode); arglist.Add(connArgument); connmsg.Args = arglist.ToArray(); await serverSocket.SendAsync(connmsg.Pack(), SocketFlags.None); connmsg = await CommandMessage.ReadFromSocketAsync(serverSocket); if (connmsg == null) { LogMessage("Warning:ConnectorWorker : remote closed connection."); return; } //LogMessage("Warning:connmsg : " + connmsg); if (connmsg.Name != "ConnectOK") { return; } //TODO: add to session list if (supportEncrypt && connmsg.Args[1] == "0") { supportEncrypt = false; LogMessage("Warning:server don't support encryption : " + Connector.ServerHost); } Stream _sread, _swrite; if (connmode == "RCP") { serverSocket.CloseSocket(); string ip = connmsg.Args[2]; int port = int.Parse(connmsg.Args[3]); if (port < 1) { LogMessage("Error:Invalid configuration , remote-client-side don't provide RouterClientPort , stop use RCP for 1min"); _stopUseRouterClientPortUntil = DateTime.Now.AddSeconds(60); goto TryAgain; //TODO: reuse the serverSocket and switch to another mode } LogMessage("Warning:" + tcpSocket.LocalEndPoint + " forward to " + ip + ":" + port); await tcpSocket.ForwardToAndWorkAsync(ip, port); return; } if (connmode == "UDP") { LogMessage("MY UDP..." + connArgument + " REMOTE..." + connmsg.Args[2]); string mynat = connArgument; string[] pair = connmsg.Args[2].Split(':'); serverSocket.CloseSocket(); try { UDPClientStream stream = await UDPClientStream.ConnectAsync(udp, pair[0], int.Parse(pair[1]), TimeSpan.FromSeconds(6)); _sread = stream; _swrite = stream; LogMessage("UDP Connected #" + stream.SessionId + " " + connArgument + " .. " + connmsg.Args[2]); } catch (Exception x) { LogMessage("UDP ERROR " + connArgument + " .. " + connmsg.Args[2] + " " + x.Message); throw; } } else { if (supportEncrypt) { Connector.License.OverrideStream(serverSocket.CreateStream(), clientKeyIV, out _sread, out _swrite); } else { _sread = _swrite = serverSocket.CreateStream(); } } TcpMapConnectorSession session = new TcpMapConnectorSession(new SimpleSocketStream(tcpSocket)); await session.DirectWorkAsync(_sread, _swrite); }
async Task WorkAsync() { IsConnected = false; LogMessage("ClientWorker WorkAsync start"); int connectedTimes = 0; try { int againTimeout = 125; StartAgain: _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.InitTcp(); _cts_connect = new CancellationTokenSource(); try { await _socket.ConnectAsync(Client.ServerHost, 6022); LogMessage("connected to 6022"); } catch (Exception x) { OnError(x); _socket.CloseSocket(); _socket = 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 = "ClientConnect"; 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"); connmsg.Args = arglist.ToArray(); await _socket.SendAsync(connmsg.Pack(), SocketFlags.None); //LogMessage("wait for conn msg"); connmsg = await CommandMessage.ReadFromSocketAsync(_socket); if (connmsg == null) { TcpMapService.LogMessage("no message ? Connected:" + _socket.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(_socket.CreateStream(), clientKeyIV, out _sread, out _swrite); } else { _sread = _swrite = _socket.CreateStream(); } for (int i = 0; i < Math.Min(5, Client.PreSessionCount); i++) //TODO:const of 5 { _ = Task.Run(ProvidePreSessionAsync); } _ = Task.Run(MaintainSessionsAsync); byte[] readbuff = new byte[TcpMapService.DefaultBufferSize]; while (IsStarted) { 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) { TcpMapService.LogMessage("no message ? Connected:" + _socket.Connected); return; } //this.LogMessage("TcpMapClientWorker get msg " + msg); switch (msg.Name) { case "StartSession": Task.Run(async delegate { try { await DoStartSessionAsync(msg); } catch (Exception x) { OnError(x); } }).ToString(); break; case "CloseSession": Task.Run(async delegate { try { await DoCloseSessionAsync(msg); } catch (Exception x) { OnError(x); } }).ToString(); break; case "_ping_": await _swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: LogMessage("Error: 4 Ignore message " + msg); break; } } } catch (SocketException) { //no log } catch (Exception x) { OnError(x); } if (IsStarted) { _socket.CloseSocket(); //logic failed.. againTimeout = 125; goto StartAgain; } } catch (Exception x) { OnError(x); } IsStarted = false; IsConnected = false; if (_socket != null) { try { _socket.CloseSocket(); } catch (Exception x) { OnError(x); } _socket = null; } }
protected abstract Task WriteMessageAsync(CommandMessage msg);
protected override async Task WriteMessageAsync(CommandMessage msg) { await _swrite.WriteAsync(msg.Pack()); }
private 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 { TcpMapServerConnector connector = new TcpMapServerConnector(server); await connector.AcceptConnectorAndWorkAsync(socket, msg); } break; case "": //other direct request.. default: throw new Exception("Invaild command " + msg.Name); } } }
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); }
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(); } }
private async Task WorkAsync() { this.IsStarted = true; this.IsConnected = false; //LogMessage("ClientSession WorkAsync start"); int connectedTimes = 0; try { int againTimeout = 125; StartAgain: this.sock_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.sock_server.InitTcp(); this.cts_connect = new CancellationTokenSource(); try { await this.sock_server.ConnectAsync(this.Client.ServerHost, 6022); //LogMessage("connected to 6022"); } catch (Exception x) { this.OnError(x); this.sock_server.CloseSocket(); this.sock_server = 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 = "SessionConnect" }; 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"); arglist.Add(this.SessionId);//sessionid at [5] connmsg.Args = arglist.ToArray(); await this.sock_server.SendAsync(connmsg.Pack(), SocketFlags.None); //LogMessage("wait for conn msg"); connmsg = await CommandMessage.ReadFromSocketAsync(this.sock_server); if (connmsg == null) { TcpMapService.LogMessage("no message ? Connected:" + this.sock_server.Connected); return; } //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++; //LogMessage("ConnectOK #" + connectedTimes); if (supportEncrypt) { this.Client.License.OverrideStream(this.sock_server.CreateStream(), clientKeyIV, out this.sread, out this.swrite); } else { this.sread = this.swrite = this.sock_server.CreateStream(); } if (string.IsNullOrEmpty(this.SessionId)) { //wait for Upgrade while (this.SessionId == null) { CommandMessage msg; var cts = new CancellationTokenSource(); _ = Task.Run(async delegate { if (await cts.Token.WaitForSignalSettedAsync(16000)) { return; } await this.swrite.WriteAsync(new CommandMessage("_ping_", "forread").Pack()); }); try { msg = await CommandMessage.ReadFromStreamAsync(this.sread); } finally { cts.Cancel(); } if (msg == null) { throw (new SocketException(995)); } switch (msg.Name) { case "UpgradeSession": try { this.sock_local = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.sock_local.InitTcp(); await this.sock_local.ConnectWithTimeoutAsync(this.Client.ClientHost, this.Client.ClientPort, 12000); } catch (Exception x) { TcpMapService.OnError(x); await this.swrite.WriteAsync(new CommandMessage("UpgradeSessionResult", "Failed").Pack()); continue; } this.SessionId = msg.Args[0]; if (this.cts_upgrade != null) { this.cts_upgrade.Cancel(); } await this.swrite.WriteAsync(new CommandMessage("UpgradeSessionResult", "OK").Pack()); break; case "_ping_": await this.swrite.WriteAsync(new CommandMessage("_ping_result_").Pack()); break; case "_ping_result_": break; default: this.LogMessage("Error: 1 Ignore message " + msg); break; } } } await this.WorkAsync(this.sock_local.CreateStream()); } catch (Exception x) { this.OnError(x); } } catch (SocketException) { } catch (Exception x) { this.OnError(x); } this.IsStarted = false; this.IsConnected = false; this.sock_server?.CloseSocket(); this.sock_local?.CloseSocket(); this.workend = true; }
protected override async Task WriteMessageAsync(CommandMessage msg) { this.lastwritetime = DateTime.Now; await this.swrite.WriteAsync(msg.Pack()); }
private async Task DoCreateUDPNatAsync(CommandMessage msg) { try { string[] peerinfo = msg.Args[1].Split(":"); string peeraddr = peerinfo[0]; int peerport = int.Parse(peerinfo[1]); LogMessage("Warning:send whoami to " + Client.ServerHost + ":6023"); UdpClient udp = new UdpClient(); udp.Client.ReceiveTimeout = 4321; udp.Client.SendTimeout = 4321; udp.Send(Encoding.ASCII.GetBytes("whoami"), 6, Client.ServerHost, 6023); LogMessage("Warning:udp.ReceiveAsync"); ReadAgain: var rr = await udp.ReceiveAsync(); //TODO: add timeout.. if (rr.RemoteEndPoint.Port != 6023) { goto ReadAgain; } string exp = Encoding.ASCII.GetString(rr.Buffer); LogMessage("Warning:udp get " + exp); if (!exp.StartsWith("UDP=")) { throw (new Exception("failed")); } exp = exp.Remove(0, 4); msg.Args[1] = exp; //TODO: shall cache and reuse this address ? but always send "hello" to new peer again.. ClientWorkerUDPConnector udpconn = new ClientWorkerUDPConnector(); udpconn.Start(this, udp, exp); IPEndPoint pperep = new IPEndPoint(IPAddress.Parse(peeraddr), peerport); _ = Task.Run(async delegate { byte[] msgdata = UDPMeta.CreateSessionIdle(-1); for (int i = 0; i < 10; i++) { if (udpconn.IsEverConnected(pperep)) { return; } udp.Send(msgdata, msgdata.Length, pperep); Console.WriteLine("SENT " + pperep + " via " + exp); await Task.Delay(100); } }); } catch (Exception x) { OnError(x); msg.Args[1] = "Error"; } msg.Name = "CreateUDPNatResult"; this.LogMessage("TcpMapClientWorker sending " + msg); await _swrite.WriteAsync(msg.Pack()); }