Ejemplo n.º 1
0
        async Task <CommandMessage> SendCmdAsync(string cmd, string arg)
        {
            int            timeout = 18000;
            long           reqid   = Interlocked.Increment(ref nextreqid);
            CommandMessage msg     = new CommandMessage();

            msg.Name = cmd;
            msg.Args = new string[] { reqid.ToString(), arg, timeout.ToString() };

            RequestItem ritem = new RequestItem();

            reqmap.TryAdd(reqid, ritem);
            try
            {
                _worker.LogMessage("TcpMapServerClient sending #" + reqid + " : " + msg);

                await _swrite.WriteAsync(msg.Pack());

                await _swrite.FlushAsync();

                if (!await ritem.cts.Token.WaitForSignalSettedAsync(timeout))                //TODO:const
                {
                    throw new Exception($"request timeout #{reqid} '{msg}'");
                }

                if (ritem.Response == null)
                {
                    throw new Exception($"No Response ? ");
                }

                if (ritem.Response.Args[1] == "Error")
                {
                    throw new Exception("Command Failed.");
                }

                return(ritem.Response);
            }
            finally
            {
                reqmap.TryRemove(reqid, out _);
            }
        }
Ejemplo n.º 2
0
        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);
        }