private async Task <KeyValuePair <string, UDPClientListener> > CreteUdpClientAsync() { UdpClient udp = new UdpClient(); udp.Client.ReceiveTimeout = 4321; udp.Client.SendTimeout = 4321; udp.Send(System.Text.Encoding.ASCII.GetBytes("whoami"), 6, this.Connector.ServerHost, 6023); this.LogMessage("Warning:udp.ReceiveAsync"); var rr = await udp.ReceiveAsync(); string exp = System.Text.Encoding.ASCII.GetString(rr.Buffer); this.LogMessage("Warning:udp get " + exp); if (!exp.StartsWith("UDP=")) { throw (new Exception("failed")); } string natinfo = exp.Remove(0, 4); UDPClientListener udpc = new UDPClientListener(udp); return(new KeyValuePair <string, UDPClientListener>(natinfo, udpc)); }
private async Task <KeyValuePair <string, UDPClientListener> > GetUdpClientAsync() { if (!this.Connector.UDPCachePort) { return(await this.CreteUdpClientAsync()); } TryAgain: if (this.lastudp != null && DateTime.Now - this.timeudp < TimeSpan.FromSeconds(8)) { lock (this) { return(new KeyValuePair <string, UDPClientListener>(this.lastnat, this.lastudp)); } } bool ctsCreated = false; CancellationTokenSource cts = this.ctsudpnew; if (cts == null) { lock (this) { if (this.ctsudpnew == null) { this.ctsudpnew = new CancellationTokenSource(); ctsCreated = true; } cts = this.ctsudpnew; } } if (!ctsCreated) { await cts.Token.WaitForSignalSettedAsync(3000); goto TryAgain; } try { //TODO: cache the port and reuse. var kvp = await this.CreteUdpClientAsync(); lock (this) { this.lastnat = kvp.Key; this.lastudp = kvp.Value; this.timeudp = DateTime.Now; } return(kvp); } finally { lock (this) { cts.Cancel(); this.ctsudpnew = null; } } }
private async Task ProcessSocketAsync(Socket tcpSocket) { TryAgain: string connmode = null; if (this.Connector.UseRouterClientPort && DateTime.Now > this.stopUseRouterClientPortUntil) { connmode = "RCP"; } else if (this.Connector.UseUDPPunching && DateTime.Now > this.stopUseRouterClientPortUntil) { connmode = "UDP"; } else if (this.Connector.UseServerBandwidth) { connmode = "USB"; } else { //TODO: try .. connmode = this.Connector.UseUDPPunching ? "UDP" : this.Connector.UseRouterClientPort ? "RCP" : throw new Exception("No connection mode."); } Task <KeyValuePair <string, UDPClientListener> > task2 = null; if (connmode == "UDP") { //TODO: shall cache the UDPClientListener ... task2 = Task.Run(this.GetUdpClientAsync); } Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.InitTcp(); await serverSocket.ConnectAsync(this.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) { this.OnError(x); this.LogMessage("UDP Failed , switch ..."); connmode = this.Connector.UseServerBandwidth ? "USB" : throw new Exception(x.Message, x); } } bool supportEncrypt = this.Connector.UseEncrypt; CommandMessage connmsg = new CommandMessage { Name = "ConnectorConnect" }; List <string> arglist = new List <string> { this.Connector.License.Key, this.Connector.ServerPort.ToString() }; this.Connector.License.GenerateSecureKeyAndHash(out byte[] clientKeyIV, out byte[] encryptedKeyIV, out byte[] 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) { this.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; this.LogMessage("Warning:server don't support encryption : " + this.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) { this.LogMessage("Error:Invalid configuration , remote-client-side don't provide RouterClientPort , stop use RCP for 1min"); this.stopUseRouterClientPortUntil = DateTime.Now.AddSeconds(60); goto TryAgain;//TODO: reuse the serverSocket and switch to another mode } this.LogMessage("Warning:" + tcpSocket.LocalEndPoint + " forward to " + ip + ":" + port); await tcpSocket.ForwardToAndWorkAsync(ip, port); return; } if (connmode == "UDP") { this.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; this.LogMessage("UDP Connected #" + stream.SessionId + " " + connArgument + " .. " + connmsg.Args[2]); } catch (Exception x) { this.LogMessage("UDP ERROR " + connArgument + " .. " + connmsg.Args[2] + " " + x.Message); throw; } } else { if (supportEncrypt) { this.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); }