Exemple #1
0
        /// <summary>
        /// Session init; ban and multilogin checks
        /// </summary>
        /// <param name="message"></param>
        private void LoginState(object message)
        {
            var msg = (byte[])message;

            if (msg[0] == 0x01 && msg.Length == 1)
            {
                // Keepalive
                //byte[] omsg = { 0xFF };
                Context.Sender.Tell(new byte[] { 0xFF });
            }
            else if (msg[0] == 0x01 && msg.Length == 75)
            {
                // Save login information.
                var pos       = 3;
                var accountid = FLMsgType.GetUnicodeStringLen16(msg, ref pos);

                byte[] omsg = { 0x02, 0x02 };
                //    // If the account is banned kick the player.
                _accountID = accountid;
                var accs = Database.GetAccount(accountid);
                //    //TODO: check if banning works; possibly make separate table for ID bans
                var isbanned = false;
                if (accs != null)
                {
                    if (accs[0].IsBanned)
                    {
                        isbanned = true;
                    }
                }
                //    // If the account is already logged in or banned, reject the login


                var findAccID =
                    Context.ActorSelection("user/server/player/*").Ask <bool>(new PlayerActor.CheckAccountID(accountid), TimeSpan.FromMilliseconds(100));
                //findAccID.Wait(250);

                var accOnline = false;
                //TODO: heeeavy
                try
                {
                    if (findAccID.Result)
                    {
                        accOnline = true;
                    }
                }
                catch { }

                if (isbanned)
                {
                    //TODO: send and close session
                    FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_BANNED);
                }
                else
                if (accOnline)
                {
                    FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_INUSE);
                }
                else
                {
                    FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_OKAY);
                }
                Context.Parent.Tell(new PlayerActor.SetAccountID(accountid, _flPlayerID));

                Context.Sender.Tell(omsg);
            }
            else if (msg[0] == 0x05 && msg[1] == 0x03)
            {
                // char info request
                //player.SaveCharFile();
                SendCharInfoResponse();
                Context.Become(SelectCharState, false);
                _log.Debug("New state id {0} select-char", _flPlayerID);
            }
            else
            {
                // Unexpected packet. Log and ignore it.
                _log.Warn("Unexpected message from FLID {0} in LoginState: {1}", _flPlayerID, msg);
                //player.Log.AddLog(LogType.FL_MSG, "Unexpected message: client rx", player.DPSess, msg);
            }
        }
Exemple #2
0
        /// <summary>
        /// Character selection state.
        /// </summary>
        /// <param name="message"></param>
        private void SelectCharState(object message)
        {
            var msg = (byte[])message;

            if (msg[0] == 0x01 && msg.Length == 1)
            {
                // Keepalive
                //byte[] omsg = { 0xFF };
                Context.Sender.Tell(new byte[] { 0xFF });
            }
            else if (msg[0] == 0x05 && msg[1] == 0x03)
            {
                // FLPACKET_CLIENT_REQUESTCHARINFO
                //player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_REQUESTCHARINFO");
                SendCharInfoResponse();
            }
            else if (msg[0] == 0x06 && msg[1] == 0x03)
            {
                //TODO: SelectCharacter
                // FLPACKET_CLIENT_SELECTCHARACTER
                //var nameBefore = player.Name;
                var pos          = 2;
                var charfilename = FLMsgType.GetAsciiStringLen16(msg, ref pos);

                var acct = Database.GetOneAccount(_accountID, charfilename);

                //var result = player.LoadCharFile(acct, player.Log);

                if (acct == null)
                {
                    _log.Error("Cannot load character id={0} name={1}",
                               _accountID, charfilename);
                    return;
                }

                //player.Log.AddLog(LogType.GENERAL,
                //"FLPACKET_CLIENT_SELECTCHARACTER charfilename={0} name={1} system={2}", charfilename, player.Name,
                //player.Ship.System.Nickname);
                //if (player.Ship != null && player.Ship.Objid != 0)
                //player.Runner.DelSimObject(player.Ship);

                _log.Debug("Char selected: {0}", _accountID);
                Context.Parent.Tell(new PlayerActor.CharSelected(acct, _flPlayerID), Context.Sender);
                _baseRef = Context.ActorOf <BaseState>("base");
                SendVisitedState(acct.Visits);
                SendMissionLog();
                SendInterfaceState();
                SendInitSetReputation();
                SendCharSelectVerified();

                //SendMiscObjUpdate UNK 2
                //TODO: figure out what that means
                byte[] omsg = { 0x54, 0x02, 0x28, 0x00 };
                FLMsgType.AddUInt32(ref omsg, 0);
                FLMsgType.AddInt32(ref omsg, -1); // faction?
                Sender.Tell(omsg);

                //do we really need enum it again?
                SendCharInfoResponse();

                //TODO: infocard update
                //if ((Runner.Server.IntroMsg != null) && firstLogin)
                //{
                //    Packets.SendInfocardUpdate(this, 500000, "Welcome to Discovery");

                //    string intro = Runner.Server.IntroMsg.Replace("$$player$$", Name);
                //    Packets.SendInfocardUpdate(this, 500001, intro);

                //    Packets.SendPopupDialog(this, new FLFormatString(500000), new FLFormatString(500001),
                //        PopupDialogButtons.POPUPDIALOG_BUTTONS_CENTER_OK);
                //}

                Context.ActorSelection("../chat").Tell(new ConsoleMessage(ServerUtils.WelcomeMessage.Replace(@"$$player$$", acct.CharName)), Context.Sender);

                Become(InBaseState, false);

                //player.Update();
            }
            else if (msg[0] == 0x39 && msg[1] == 0x03)
            {
                //player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_CREATENEWCHAR");
                // New character
                var pos      = 2;
                var charname = FLMsgType.GetUnicodeStringLen16(msg, ref pos);

                //TODO: do nothing when charname exists?
                //BUG: client hangs
                if (Database.CheckIfNameOccupied(charname))
                {
                    return;
                }

                Database.AddAccount(_accountID, charname);

                SendCharInfoResponse();
            }
            else if (msg[0] == 0x3a && msg[1] == 0x03)
            {
                //player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_DESTROYCHAR");

                // Delete character
                var pos      = 2;
                var charfile = FLMsgType.GetAsciiStringLen16(msg, ref pos);

                Database.DelAccount(_accountID, charfile);

                SendCharInfoResponse();
            }
            else
            {
                // Unexpected packet. Log and ignore it.
                _log.Warn("Unexpected message from FLID {0} in SelectCharState: {1}", _flPlayerID, BitConverter.ToString(msg));
            }
        }
Exemple #3
0
        /// <summary>
        /// Sends character list for current account.
        /// </summary>
        private void SendCharInfoResponse()
        {
            var accs = Database.GetAccount(_accountID);

            byte[] omsg = { 0x03, 0x02 };
            FLMsgType.AddUInt8(ref omsg, 0);     // chars
            if (accs != null)
            {
                foreach (var acct in accs)
                {
                    //try
                    //{

                    FLMsgType.AddAsciiStringLen16(ref omsg, FLMsgType.FLNameToFile(acct.CharName));
                    FLMsgType.AddUInt16(ref omsg, 0);
                    FLMsgType.AddUnicodeStringLen16(ref omsg, acct.CharName);
                    FLMsgType.AddUnicodeStringLen16(ref omsg, "");
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, acct.Ship);
                    if (acct.Money > 2000000000)
                    {
                        FLMsgType.AddInt32(ref omsg, 2000000000);
                    }
                    else
                    {
                        FLMsgType.AddInt32(ref omsg, acct.Money);
                    }

                    //TODO: ideally we should check if base, system and equip exists
                    FLMsgType.AddUInt32(ref omsg, FLUtility.CreateID(acct.System));
                    if (acct.ShipState.Base != null)
                    {
                        FLMsgType.AddUInt32(ref omsg, FLUtility.CreateID(acct.ShipState.Base));
                    }
                    else
                    {
                        FLMsgType.AddUInt32(ref omsg, 0);
                    }
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, FLUtility.CreateID(acct.Appearance.Voice));
                    FLMsgType.AddUInt32(ref omsg, acct.Rank);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddFloat(ref omsg, acct.ShipState.Hull);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddUInt32(ref omsg, 0);

                    FLMsgType.AddUInt8(ref omsg, 1);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.Body);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.Head);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.LeftHand);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.RightHand);
                    FLMsgType.AddUInt32(ref omsg, 0);

                    FLMsgType.AddUInt8(ref omsg, 1);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.Body);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.Head);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.LeftHand);
                    FLMsgType.AddUInt32(ref omsg, acct.Appearance.RightHand);
                    FLMsgType.AddUInt32(ref omsg, 0);

                    FLMsgType.AddUInt8(ref omsg, (uint)acct.Equipment.Count);
                    uint hpid = 2;
                    foreach (var item in acct.Equipment)
                    {
                        //item.count?
                        FLMsgType.AddUInt32(ref omsg, 1);
                        FLMsgType.AddFloat(ref omsg, item.Health);
                        FLMsgType.AddUInt32(ref omsg, item.Arch);
                        FLMsgType.AddUInt16(ref omsg, hpid);
                        hpid++;
                        //item.mounted
                        FLMsgType.AddUInt16(ref omsg, (1u));
                        if (item.HpName != "")
                        {
                            FLMsgType.AddAsciiStringLen16(ref omsg, item.HpName + "\0");
                        }
                        else
                        {
                            FLMsgType.AddAsciiStringLen16(ref omsg, "BAY\0");
                        }
                    }

                    FLMsgType.AddUInt32(ref omsg, 0);

                    omsg[2]++;
                    //}
                    //catch (Exception e)
                    //{
                    //    _log.Error("Corrupt character when processing charinforequest '{0}'",
                    //        e.Message);
                    //}
                }
            }
            FLMsgType.AddUInt32(ref omsg, 0);
            Context.Sender.Tell(omsg);
        }
        /// <summary>
        ///     Send a dummy trans
        /// </summary>
        /// <param name="sess"></param>
        private void SendTUDSessionInfo(Session sess)
        {
            var pkt = new byte[0];

            FLMsgType.AddUInt32(ref pkt, 0xC2);                           // dwPacketType
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwReplyOffset
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwReplySize

            FLMsgType.AddUInt32(ref pkt, 0x50);                           // dwApplicationDescSize
            FLMsgType.AddUInt32(ref pkt, 0x01);                           // dwFlags
            FLMsgType.AddUInt32(ref pkt, max_players + 1);                // dwMaxPlayers
            FLMsgType.AddUInt32(ref pkt, (uint)_dplaySessions.Count + 1); // dwCurrentPlayers
            FLMsgType.AddUInt32(ref pkt, 0x6C + 0x60);                    // dwSessionNameOffset
            FLMsgType.AddUInt32(ref pkt, (uint)server_name.Length * 2);   // dwSessionNameSize
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwPasswordOffset
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwPasswordSize
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwReservedDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwReservedDataSize
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwApplicationReservedDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);                              // dwApplicationReservedDataSize
            FLMsgType.AddArray(ref pkt, ApplicationInstanceGUID);
            FLMsgType.AddArray(ref pkt, ApplicationGUID);
            FLMsgType.AddUInt32(ref pkt, sess.DPlayID); // dpnid
            FLMsgType.AddUInt32(ref pkt, sess.DPlayID); // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);            // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 2);            // dwEntryCount
            FLMsgType.AddUInt32(ref pkt, 0);            // dwMembershipCount

            // server name table entry
            FLMsgType.AddUInt32(ref pkt, 1);        // dpnid
            FLMsgType.AddUInt32(ref pkt, 0);        // dpnidOwner
            FLMsgType.AddUInt32(ref pkt, 0x000402); // dwFlags
            FLMsgType.AddUInt32(ref pkt, 2);        // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 7);        // dwDNETVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLSize

            // connecting client name table entry
            FLMsgType.AddUInt32(ref pkt, sess.DPlayID); // dpnid
            FLMsgType.AddUInt32(ref pkt, 0);            // dpnidOwner
            FLMsgType.AddUInt32(ref pkt, 0x020000);     // dwFlags
            FLMsgType.AddUInt32(ref pkt, sess.DPlayID); // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);            // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 7);            // dwDNETVersion
            FLMsgType.AddUInt32(ref pkt, 0);            // dwNameOffset
            FLMsgType.AddUInt32(ref pkt, 0);            // dwNameSize
            FLMsgType.AddUInt32(ref pkt, 0);            // dwDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);            // dwDataSize
            FLMsgType.AddUInt32(ref pkt, 0);            // dwURLOffset
            FLMsgType.AddUInt32(ref pkt, 0);            // dwURLSize

            FLMsgType.AddUnicodeStringLen0(ref pkt, server_name);

            sess.UserData.AddLast(pkt);
            SendDFrame(sess);
        }
        /// <summary>
        ///     Try to send a dframe or a keep alive if no user data is waiting to be sent.
        /// </summary>
        /// <param name="sess"></param>
        /// <returns>Return true if a dframe was sent</returns>
        public bool SendDFrame(Session sess)
        {
            lock (sess)
            {
                if (sess.UserData.Count > 0)
                {
                    // If the window is full, don't send any thing
                    if (IsAckWindowFull(sess))
                    {
                        return(false);
                    }

                    // If we have sent a user data message that had to be carried in multiple
                    // dframes then stop sending. We can't have more than one of these on the
                    // wire at one time (if I've intepreted the specs correctly).
                    if (sess.MultipleDframePacket)
                    {
                        return(false);
                    }

                    // The retry time should start at 100 + rtt * 2.5 according to the specs but we use
                    // 2 as this is a round number.
                    uint retry_time = 100 + (sess.Rtt * 2);
                    while (sess.UserData.Count > 0)
                    {
                        byte[] ud = sess.UserData.First();
                        sess.UserData.RemoveFirst();

                        // Break the user data block into sizes smaller than the ethernet mtu. We
                        // assume an MTU of 1450 as some infrastructure steals some bytes.
                        int  offset       = 0;
                        bool first_packet = true;
                        bool last_packet  = false;
                        while (offset < ud.Length)
                        {
                            int length;
                            if ((ud.Length - offset) > 1450)
                            {
                                length = 1450;
                                sess.MultipleDframePacket = true;
                            }
                            else
                            {
                                length      = ud.Length - offset;
                                last_packet = true;
                            }

                            byte[] pkt = { 0x07, 0x00, sess.NextTxSeq, sess.NextRxSeq };

                            // If this is the first packet, set the flag to indicate this.
                            if (first_packet)
                            {
                                pkt[0] |= 0x10;
                            }

                            // If this is the last packet, set the flag to indicate this
                            if (last_packet)
                            {
                                pkt[0] |= 0x20;
                            }

                            // If the session isn't fully connected then this must be a session establishment
                            // message
                            if (sess.SessionState == Session.State.CONNECTING_SESSINFO)
                            {
                                pkt[0] |= 0x40;
                            }

                            FLMsgType.AddArray(ref pkt, ud, offset, length);

                            var spkt = new Session.Pkt();
                            spkt.Data      = pkt;
                            spkt.RetryTime = DateTime.UtcNow.AddMilliseconds(retry_time);
                            spkt.SendTime  = DateTime.UtcNow;

                            sess.UserDataPendingAck[sess.NextTxSeq] = spkt;
                            sess.BytesTx += pkt.Length;
                            TxStart(pkt, sess.Client);

                            // Increase the retry times if multiple packets are sent so that
                            // we're less likely to send a massive burst of packets to retry.
                            retry_time += 5;

                            sess.NextTxSeq++;

                            first_packet = false;
                            offset      += length;

                            // fixme: it's possible for a multi-dframe user data message to overrun
                            // the valid seq window size. this is bad and the connection will fail.
                        }

                        // If we have sent a user data message that had to be carried in multiple
                        // dframes then stop sending. We can't have more than one of these on the
                        // wire at one time (if I've intepreted the specs correctly).
                        if (sess.MultipleDframePacket)
                        {
                            break;
                        }

                        // If the window is full, don't send any more
                        if (IsAckWindowFull(sess))
                        {
                            break;
                        }
                    }

                    return(true);
                }
            }

            return(false);
        }
Exemple #6
0
        public void InBaseState(object message)
        {
            //TODO: handle discon in base state, do save and gracefully exit
            //for InSpaceState we'll need to remove SimObj and/or
            //add some kind of timer so player won't F1 into nowhere
            //keep in mind, client reports awfully big position coords before discon
            var msg = (byte[])message;

            if (msg[0] == 0x01 && msg.Length == 1)
            {
                // Keepalive
                //byte[] omsg = { 0xFF };
                Context.Sender.Tell(new byte[] { 0xFF });
            }
            else if (msg.Length >= 2)
            {
                int type = msg[0] << 8 | msg[1];
                switch (type)
                {
                case 0x0101:
                    //RxCommonUpdateObject(player, msg);
                    break;

                case 0x0201:
                    //RxCommonFireWeapon(player, msg);
                    break;

                case 0x0401:
                    //RxSetTarget(player, msg);
                    break;

                case 0x0501:
                    //RxChat(player, msg);
                    break;

                case 0x0801:
                    //RxActivateEquip(player, msg);
                    break;

                case 0x0E01:
                    //RxActivateCruise(player, msg);
                    break;

                case 0x0F01:
                    //RxGoTradelane(player, msg);
                    break;

                case 0x1001:
                    //RxStopTradelane(player, msg);
                    break;

                case 0x1101:
                    //RxSetWeaponsGroup(player, msg);
                    break;

                case 0x1301:
                    //RxSetVisitedState(player, msg);
                    break;

                case 0x1401:
                    //RxJettisionCargo(player, msg);
                    break;

                case 0x1501:
                    //RxActivateThrusters(player, msg);
                    break;

                case 0x1601:
                    //RxRequestBestPath(player, msg);
                    break;

                case 0x1701:
                    //RxRequestNavMap(player, msg);
                    break;

                case 0x1801:
                    Context.Parent.Tell(new PlayerStatsRequest());
                    //RxRequestPlayerStats(player, msg);
                    break;

                case 0x1A01:
                    //RxRequestRank
                    //FLPACKET_COMMON_REQUEST_RANK_LEVEL
                    //answer: 1A 01 04 00 00 00 FF FF FF FF
                    _baseRef.Tell(new RankRequest(), Context.Sender);
                    break;

                case 0x1c01:
                    //RxSetInterfaceState(player, msg);
                    break;

                case 0x0303:
                    //RxMunitionCollision(player, msg);
                    break;

                case 0x0403:
                    //RxRequestLaunch(player, msg);
                    break;

                case 0x0503:
                    //RxRequestCharInfo(player, msg);
                    break;

                case 0x0703:
                    //RxEnterBase(player, msg);
                {
                    var pos    = 2;
                    var baseid = FLMsgType.GetUInt32(msg, ref pos);

                    var acc = Context.Parent.Ask <PlayerActor.AccountShipData>(new PlayerActor.EnterBase(baseid),
                                                                               TimeSpan.FromMilliseconds(850));
                    _baseRef.Tell(new EnterBaseData(acc.Result.Account, acc.Result.ShipData, baseid), Context.Sender);
                }
                    //_baseID = baseid;

                    break;

                case 0x0803:
                    //RxRequestBaseInfo(msg);
                    _baseRef.Tell(new BaseInfoRequest(msg), Context.Sender);
                    break;

                case 0x0903:
                    //RxRequestLocationInfo(player, msg);
                    _baseRef.Tell(new LocInfoRequest(msg), Context.Sender);
                    break;

                case 0x0B03:
                    //RxSystemSwitchOutComplete(player, msg);
                    break;

                case 0x0C03:
                    //RxObjectCollision(player, msg);
                    break;

                case 0x0D03:
                    //RxExitBase(player, msg);
                    break;

                case 0x0E03:
                    //RxEnterLocation(msg);
                {
                    int  pos    = 2;
                    uint roomid = FLMsgType.GetUInt32(msg, ref pos);
                    _baseRef.Tell(new EnterLocation(roomid), Context.Sender);
                }
                break;

                case 0x0F03:
                    //RxExitLocation(player, msg);
                {
                    int  pos    = 2;
                    uint roomid = FLMsgType.GetUInt32(msg, ref pos);
                    _baseRef.Tell(new ExitLocation(roomid), Context.Sender);
                }
                break;

                case 0x1003:
                    //RxRequestCreateShip(player, msg);
                    break;

                case 0x1103:
                    //RxGoodSell(player, msg); - we ignore this, look RxRequestRemoveItem
                    break;

                case 0x1203:
                    //RxGoodBuy(player, msg); - we ignore this, look RxRequestAddItem
                    break;

                case 0x1303:
                    //RxGFSelectObject(player, msg);
                {
                    var pos    = 2;
                    var charid = FLMsgType.GetUInt32(msg, ref pos);
                    _baseRef.Tell(new SelectObject(charid));
                }
                break;

                case 0x1403:
                    //RxMissionResponse(player, msg);
                    break;

                case 0x1503:
                    //RxRequestShipArch(player, msg);
                    break;

                case 0x1603:
                    //RxRequestEquipment(player, msg);
                    break;

                case 0x1803:
                    //RxRequestAddItem(player, msg);
                    _baseRef.Tell(new RequestAddItem(msg), Context.Sender);
                    break;

                case 0x1903:
                    //RxRequestRemoveItem(player, msg);
                    break;

                case 0x1B03:
                    //RxRequestSetCash(player, msg); - we ignore this, count based on buy\sell, RxRequest{add,remove}Item
                    break;

                case 0x1C03:
                    //RxRequestChangeCash(player, msg); - we ignore this, count based on buy\sell, RxRequest{add,remove}Item
                    break;

                case 0x2F03:
                    //RxSetManeuver(player, msg);
                    break;

                case 0x3103:
                    //RxRequestEvent(player, msg);
                    break;

                case 0x3203:
                    //RxRequestCancel(player, msg);
                    break;

                case 0x3b03:
                    //RxRequestSetHullStatus(player, msg);
                    break;

                case 0x3E03:
                    //RxLaunchComplete(player, msg);
                    break;

                case 0x3F03:
                    //RxClientHail(player, msg);
                    break;

                case 0x4003:
                    //RxRequestUseItem(player, msg);
                    break;

                case 0x4303:
                    //RxJumpInComplete(player, msg);
                    break;

                case 0x4403:
                    //RxRequestInvincibility(player, msg);
                    break;

                default:
                    // Unexpected packet. Log and ignore it.
                    _log.Warn("Unexpected message from FLID {0} in InBaseState: {1}", _flPlayerID, BitConverter.ToString(msg));
                    break;
                }
            }
            else
            {
                // Unexpected packet. Log and ignore it.
                _log.Warn("Unexpected message from FLID {0} in InBaseState: {1}", _flPlayerID, BitConverter.ToString(msg));
            }
        }
        public void ProcessPktFromClient(byte[] pkt, IPEndPoint client)
        {
            _log.AddLog(LogType.DPLAY_MSG, "c>s client={0} pkt={1}", client, pkt);

            // If this message is too short, chuck it away
            if (pkt.Length < 2)
            {
                return;
            }

            // If this message is a enum server status then reply to the query. This tricks people
            // into thinking the server has a better ping than it does.
            int  pos = 0;
            uint cmd = FLMsgType.GetUInt8(pkt, ref pos);

            if (cmd == 0x00 && pkt.Length >= 4)
            {
                uint opcode = FLMsgType.GetUInt8(pkt, ref pos);
                if (opcode == 0x02 && pkt.Length >= 4)
                {
                    uint enum_payload = FLMsgType.GetUInt16(pkt, ref pos);
                    SendCmdEnumResponse(client, (ushort)enum_payload);
                }
            }

            // If the data is at least 12 bytes and the first byte is
            // either 0x80 or 0x88 (PACKET_COMMAND_CFRAME or PACKET_COMMAND_CFRAME |
            // PACKET_COMMAND_POLL), it MUST process the message as a CFRAME
            // (section 3.1.5.1) command frame.
            else if ((cmd == 0x80 || cmd == 0x88) && pkt.Length >= 12)
            {
                uint opcode = FLMsgType.GetUInt8(pkt, ref pos);

                // The CONNECT packet is used to request a connection. If accepted, the response
                // is a CONNECTED (section 2.2.1.2) packet
                if (opcode == 0x01)
                {
                    byte msg_id = FLMsgType.GetUInt8(pkt, ref pos);
                    byte rsp_id = FLMsgType.GetUInt8(pkt, ref pos);

                    uint version   = FLMsgType.GetUInt32(pkt, ref pos);
                    uint dplayid   = FLMsgType.GetUInt32(pkt, ref pos);
                    uint timestamp = FLMsgType.GetUInt32(pkt, ref pos);

                    // Create a new session.
                    Session sess = GetSession(client);
                    if (sess == null)
                    {
                        sess         = new Session(client);
                        sess.DPlayID = dplayid;
                        lock (_dplaySessions)
                        {
                            _dplaySessions[client] = sess;
                        }
                    }

                    lock (sess)
                    {
                        // If the session id has changed, assume that the server is wrong
                        // and kill the existing connection and start a new one.
                        // This behaviour differs from the dplay specification.
                        if (sess.DPlayID != 0 && sess.DPlayID != dplayid)
                        {
                            Destroy(sess, "changed dsessid");
                        }

                        // If the session is fully connected because the client has
                        // sent us a connect acknowledge then ignore this.
                        if (sess.SessionState == Session.State.CONNECTED)
                        {
                            return;
                        }

                        // Otherwise this is a new connection. Reset the session information.
                        sess.SessionState     = Session.State.CONNECTING;
                        sess.LastClientRxTime = DateTime.UtcNow;
                        sess.StartTime        = DateTime.Now;

                        sess.Rtt     = 200;
                        sess.LostRx  = 0;
                        sess.BytesRx = 0;
                        sess.LostTx  = 0;
                        sess.BytesTx = 0;

                        sess.NextRxSeq = 0;
                        sess.NextTxSeq = 0;

                        sess.MsgID = 0;
                        sess.OutOfOrder.Clear();
                        sess.UserData.Clear();
                        sess.UserDataPendingAck.Clear();

                        sess.MultipleDframePacket = false;
                        sess.SessionTimer         = new Timer(SessionTimer, sess, 100, 20);

                        SendCmdConnectAccept(sess, msg_id);
                    }
                }
                // Receive a SACK and process it
                else if (opcode == 0x06)
                {
                    byte flags = FLMsgType.GetUInt8(pkt, ref pos);
                    byte retry = FLMsgType.GetUInt8(pkt, ref pos);
                    // The seq field indicates the seq of the next message that the client will send.
                    byte seq = FLMsgType.GetUInt8(pkt, ref pos);
                    // The next_rx field indicates the message seq that the client is waiting to receive
                    byte nrcv = FLMsgType.GetUInt8(pkt, ref pos);
                    pos += 2; // skip padding
                    uint timestamp = FLMsgType.GetUInt32(pkt, ref pos);

                    // Ignore packets for sessions that don't exist
                    Session sess = GetSession(client);
                    if (sess == null)
                    {
                        return;
                    }

                    lock (sess)
                    {
                        sess.LastClientRxTime = DateTime.UtcNow;
                        sess.BytesRx         += pkt.Length;

                        // If the hi sack mask is present, resend any requested packets.
                        if ((flags & 0x02) == 0x02)
                        {
                            uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                            DoRetryOnSACKMask(sess, mask, nrcv);
                        }

                        // If the hi sack mask is present, resend any requested packets.
                        if ((flags & 0x04) == 0x04)
                        {
                            uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                            DoRetryOnSACKMask(sess, mask, (byte)(nrcv + 32));
                        }

                        // At this point bSeq sequence ID is valid, the bNRcv field
                        // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                        // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                        // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                        // acknowledged. These packets do not have to be remembered any longer, and their
                        // retry timers can be canceled.
                        DoAcknowledgeUserData(sess, nrcv);

                        // Try to send data if there's data waiting to be sent and send a
                        // selective acknowledgement if we didn't sent a dframe and the client
                        // requested an acknowledgement.
                        if (!SendDFrame(sess) && cmd == 0x88)
                        {
                            SendCmdSACK(sess);
                        }
                    }
                }
            }

            // If a packet arrives, the recipient SHOULD first check whether
            // it is large enough to be a minimal data frame (DFRAME) (4 bytes)
            // and whether the first byte has the low bit (PACKET_COMMAND_DATA) set.
            else if ((cmd & 0x01) == 0x01 && pkt.Length >= 4)
            {
                uint control = FLMsgType.GetUInt8(pkt, ref pos);
                byte seq     = FLMsgType.GetUInt8(pkt, ref pos);
                byte nrcv    = FLMsgType.GetUInt8(pkt, ref pos);

                // Ignore packets for sessions that don't exist
                Session sess = GetSession(client);
                if (sess == null)
                {
                    return;
                }

                lock (sess)
                {
                    sess.LastClientRxTime = DateTime.UtcNow;
                    sess.BytesRx         += pkt.Length;

                    // This is a disconnect. We ignore the soft disconnect and immediately
                    // drop the session repeating the disconnect a few times to improve the
                    // probability of it getting through.
                    if ((control & 0x08) == 0x08)
                    {
                        Destroy(sess, "client request");
                        return;
                    }

                    // TRANS_USERDATA_HEADER bSeq field MUST be either the next sequence
                    // ID expected or within 63 packets beyond the ID expected by the receiver.
                    // If the sequence ID is not within this range, the payload MUST be ignored.
                    // In addition, a SACK packet SHOULD be sent indicating the expected sequence ID.
                    if (!InWindow(seq, sess.NextRxSeq))
                    {
                        SendCmdSACK(sess);
                        return;
                    }

                    // If the sequence ID is out of order, but still within 63 packets,
                    // the receiver SHOULD queue the payload until it receives either:
                    // - A delayed or retried transmission of the missing packet or packets,
                    // and can now process the sequence in order.
                    // - A subsequent packet with a send mask indicating that the missing
                    // packet or packets did not use PACKET_COMMAND_RELIABLE and will never
                    // be retried. Therefore, the receiver should advance its sequence as if
                    // it had already received and processed the packets.
                    if (seq != sess.NextRxSeq)
                    {
                        _log.AddLog(LogType.DPLAY_MSG,
                                    "c>s out of order pkt received client={0} queuing seq={1:X} next_rx_seq={2:X}",
                                    sess.Client, seq, sess.NextRxSeq);
                        sess.OutOfOrder[seq] = pkt;
                        SendCmdSACK(sess);
                        return;
                    }

                    //Test code to simulate packet loss
                    //if (rand.Next(5) == 1)
                    //{
                    //    log.AddLog(String.Format("c>s: DROPPING THE PACKET NOW {0:X}", seq));
                    //    return;
                    //}

                    // Note if this was a retried dframe.
                    if ((control & 0x01) == 0x01)
                    {
                        sess.LostRx++;
                    }

                    // When one or both of the optional SACK mask 32-bit fields is present, and one
                    // or more bits are set in the fields, the sender is indicating that it received a
                    // packet or packets out of order, presumably due to packet loss. The two 32-bit,
                    // little-endian fields MUST be considered as one 64-bit field, where dwSACKMask1
                    // is the low 32 bits and dwSACKMask2 is the high 32 bits. If either 32-bit field
                    // is not available, the entire contents of the 64-bit field MUST be considered as all 0.

                    // The receiver of a SACK mask SHOULD loop through each bit of the combined 64-bit value
                    // in the ascending order of significance. Each bit corresponds to a sequence ID after
                    // bNRcv. If the bit is set, it indicates that the corresponding packet was received
                    // out of order.

                    // The receiver of a SACK mask SHOULD shorten the retry timer for the first frame of
                    // the window to speed recovery from the packet loss. The recommended duration is
                    // 10 milliseconds. This value can be modified according to application and network
                    // requirements. The receiver MAY also choose to remove the selectively acknowledged
                    // packets from its list to retry.
                    if ((control & 0x10) == 0x10)
                    {
                        uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                        DoRetryOnSACKMask(sess, mask, nrcv);
                    }
                    if ((control & 0x20) == 0x20)
                    {
                        uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                        DoRetryOnSACKMask(sess, mask, (byte)(nrcv + 32));
                    }


                    // When one or both of the optional send mask 32-bit fields is present, and one or
                    // more bits are set the fields, the sender is indicating that it sent a packet or
                    // packets that were not marked as reliable and did not receive an acknowledgement yet.
                    // The two 32-bit, little-endian fields MUST be considered as one 64-bit field, where
                    // dwSendMask1 is the low 32 bits and dwSendMask2 is the high 32 bits. If either 32-bit
                    // field is not available, the entire contents of the 64-bit field MUST be considered
                    // as all 0.

                    // The receiver of a send mask SHOULD loop through each bit of the combined 64-bit
                    // value from the least significant bit to the most significant in little-endian byte
                    // order. Each bit corresponds to a sequence ID prior to bSeq, and if that is the bit
                    // that is set, it indicates that the corresponding packet was not sent reliably and
                    // will not be retried. If the recipient of the send mask had not received the packet
                    // and had not already processed a send mask that identified the sequence ID, it SHOULD
                    // consider the packet as dropped and release its placeholder in the sequence. That is,
                    // any sequential messages that could not be indicated because of the gap in the sequence
                    // where the packet that was not marked as reliable had been SHOULD now be reported to
                    // the upper layer.
                    if ((control & 0x40) == 0x40)
                    {
                        FLMsgType.GetUInt32(pkt, ref pos);
                    }
                    if ((control & 0x80) == 0x80)
                    {
                        FLMsgType.GetUInt32(pkt, ref pos);
                    }
                    // However, freelancer always uses reliable packets and so ignore sendmasks.

                    // At this point, we've received the packet we wanted to. Advance the sequence number count
                    // and process this message.
                    sess.NextRxSeq++;
                    ProcessTransUserData(sess, pkt, pos);

                    // If there are queued out of order packets, try to process these.
                    while (sess.OutOfOrder.ContainsKey(sess.NextRxSeq))
                    {
                        _log.AddLog(LogType.DPLAY_MSG, "c>s unqueuing out of order pkt client={0} seq={1:X}",
                                    sess.Client,
                                    sess.NextRxSeq);
                        pkt = sess.OutOfOrder[sess.NextRxSeq];
                        sess.OutOfOrder.Remove(sess.NextRxSeq);
                        sess.NextRxSeq++;
                        ProcessTransUserData(sess, pkt, pos); // fixme: pos could be wrong if we received a sack mask
                    }

                    // At this point bSeq sequence ID is valid, the bNRcv field
                    // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                    // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                    // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                    // acknowledged. These packets do not have to be remembered any longer, and their
                    // retry timers can be canceled.
                    DoAcknowledgeUserData(sess, nrcv);

                    // We always do an immediate acknowledge as bandwidth isn't a particular concern
                    // but fast recovery from lost packets is.
                    if (!SendDFrame(sess))
                    {
                        SendCmdSACK(sess);
                    }
                }
            }
        }
        /// <summary>
        ///     FLPACKET_SERVER_LAUNCH
        /// </summary>
        /// <param name="player"></param>
        public static void SendServerLaunch(Player player)
        {
            {
                Vector eulerRot = Matrix.MatrixToEulerDeg(player.Ship.Orientation);
                player.Log.AddLog(LogType.FL_MSG, "tx FLPACKET_SERVER_SERVERLAUNCH objid={0} position={1} orient={2}",
                                  player.Ship.Objid, player.Ship.Position, eulerRot);

                // If we're spawning in a base solar, send the solar id
                if (player.Ship.CurrentAction is LaunchFromBaseAction)
                {
                    var action = player.Ship.CurrentAction as LaunchFromBaseAction;

                    player.Ship.Position    = action.Position;
                    player.Ship.Orientation = Quaternion.QuaternionToMatrix(action.Orientation);

                    byte[] omsg = { 0x07, 0x02 };
                    FLMsgType.AddUInt32(ref omsg, player.Ship.Objid);
                    FLMsgType.AddUInt32(ref omsg, action.DockingObj.Solar.Objid);
                    FLMsgType.AddUInt32(ref omsg, action.DockingObj.Index);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.x);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.y);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.z);
                    Quaternion q = Quaternion.MatrixToQuaternion(player.Ship.Orientation);
                    FLMsgType.AddFloat(ref omsg, (float)q.W);
                    FLMsgType.AddFloat(ref omsg, (float)q.I);
                    FLMsgType.AddFloat(ref omsg, (float)q.J);
                    FLMsgType.AddFloat(ref omsg, (float)q.K);
                    player.SendMsgToClient(omsg);

                    action.DockingObj.Activate(player.Runner, player.Ship);
                }
                // Otherwise we're spawning in a space or at a jump/moor point
                else if (player.Ship.CurrentAction is LaunchInSpaceAction)
                {
                    var action = player.Ship.CurrentAction as LaunchInSpaceAction;

                    player.Ship.Position    = action.Position;
                    player.Ship.Orientation = Quaternion.QuaternionToMatrix(action.Orientation);

                    byte[] omsg = { 0x07, 0x02 };
                    FLMsgType.AddUInt32(ref omsg, player.Ship.Objid);
                    FLMsgType.AddUInt32(ref omsg, 0);
                    FLMsgType.AddInt32(ref omsg, -1);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.x);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.y);
                    FLMsgType.AddFloat(ref omsg, (float)player.Ship.Position.z);
                    FLMsgType.AddFloat(ref omsg, (float)action.Orientation.W);
                    FLMsgType.AddFloat(ref omsg, (float)action.Orientation.I);
                    FLMsgType.AddFloat(ref omsg, (float)action.Orientation.J);
                    FLMsgType.AddFloat(ref omsg, (float)action.Orientation.K);
                    player.SendMsgToClient(omsg);
                }
            }

            {
                byte[] omsg = { 0x54, 0x02, 0x09, 0x00 }; // flag (objid + dunno)
                FLMsgType.AddUInt32(ref omsg, player.Ship.Objid);
                FLMsgType.AddUInt32(ref omsg, 0);         // dunnno
                player.SendMsgToClient(omsg);
            }

            {
                byte[] omsg = { 0x54, 0x02, 0x28, 0x00 }; // flag (faction + objid)
                FLMsgType.AddUInt32(ref omsg, player.Ship.Objid);
                FLMsgType.AddFloat(ref omsg, 0);          // faction
                player.SendMsgToClient(omsg);
            }


            player.Ship.Basedata = null;
        }
Exemple #9
0
        /// <summary>
        /// Rewrite of <see cref="FLServer.Server.DirectPlayServer.ProcessPktFromClient"/>
        /// </summary>
        /// <param name="message"></param>
        public void Handle(RxMessage message)
        {
            var  pos = 0;
            uint cmd = FLMsgType.GetUInt8(message.Bytes, ref pos);

            if (cmd == 0x00 && message.Bytes.Length >= 4)
            {
                uint opcode = FLMsgType.GetUInt8(message.Bytes, ref pos);

                if (opcode != 0x02 || message.Bytes.Length < 4)
                {
                    return;
                }

                //That's enum request, spit out server info.
                uint enumPayload = FLMsgType.GetUInt16(message.Bytes, ref pos);
                var  glob        = Context.ActorSelection("/user/server/globals");
                glob.Tell(new EnumRequest((ushort)enumPayload));
            }

            // If the data is at least 12 bytes and the first byte is
            // either 0x80 or 0x88 (PACKET_COMMAND_CFRAME or PACKET_COMMAND_CFRAME |
            // PACKET_COMMAND_POLL), it MUST process the message as a CFRAME
            // (section 3.1.5.1) command frame.
            else if ((cmd == 0x80 || cmd == 0x88) && message.Bytes.Length >= 12)
            {
                uint opcode = FLMsgType.GetUInt8(message.Bytes, ref pos);

                // The CONNECT packet is used to request a connection. If accepted, the response
                // is a CONNECTED (section 2.2.1.2) packet
                switch (opcode)
                {
                case 0x01:
                {
                    //now created on session start
                    //var session = Context.Child("dplay-session");
                    //if (session.IsNobody())
                    //{
                    //session = Context.ActorOf<DPlaySession.DPlaySession>("dplay-session");
                    //Context.ActorOf<Congestion.Congestion>("congestion");
                    //}

                    if (!_dpInitialized)
                    {
                        _dpInitialized = true;
                    }
                    var msgID = FLMsgType.GetUInt8(message.Bytes, ref pos);
                    var rspID = FLMsgType.GetUInt8(message.Bytes, ref pos);

                    var version   = FLMsgType.GetUInt32(message.Bytes, ref pos);
                    var dplayid   = FLMsgType.GetUInt32(message.Bytes, ref pos);
                    var timestamp = FLMsgType.GetUInt32(message.Bytes, ref pos);

                    // If the session id has changed, assume that the server is wrong
                    // and kill the existing connection and start a new one.
                    // This behaviour differs from the dplay specification.
                    // If the session is fully connected because the client has
                    // sent us a connect acknowledge then ignore this.
                    //if (sess.SessionState == Session.State.CONNECTED)
                    //    return;
                    //Whole thing done in DPlaySession

                    //this part is done in ConnectingMessage handler
                    //we're nullifying all counters

                    _dplaySession.Tell(new DPlaySession.DPlaySession.ConnectRequest(msgID, dplayid, rspID), Context.Child("socket"));
                }
                break;

                case 0x06:
                {
                    var flags = FLMsgType.GetUInt8(message.Bytes, ref pos);
                    var retry = FLMsgType.GetUInt8(message.Bytes, ref pos);
                    // The seq field indicates the seq of the next message that the client will send.
                    var seq = FLMsgType.GetUInt8(message.Bytes, ref pos);
                    // The next_rx field indicates the message seq that the client is waiting to receive
                    var nrcv = FLMsgType.GetUInt8(message.Bytes, ref pos);
                    pos += 2;                             // skip padding
                    var timestamp = FLMsgType.GetUInt32(message.Bytes, ref pos);

                    // Ignore packets for sessions that don't exist

                    if (!_dpInitialized)
                    {
                        return;
                    }

                    //sess.BytesRx += pkt.Length;

                    // If the hi sack mask is present, resend any requested packets.
                    if ((flags & 0x02) == 0x02)
                    {
                        var mask = FLMsgType.GetUInt32(message.Bytes, ref pos);
                        _congestion.Tell(new Congestion.Congestion.DoRetryOnSACKMessage(mask, nrcv));
                    }

                    // If the hi sack mask is present, resend any requested packets.
                    if ((flags & 0x04) == 0x04)
                    {
                        var mask = FLMsgType.GetUInt32(message.Bytes, ref pos);
                        _congestion.Tell(new Congestion.Congestion.DoRetryOnSACKMessage(mask, (byte)(nrcv + 32)));
                    }

                    // At this point bSeq sequence ID is valid, the bNRcv field
                    // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                    // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                    // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                    // acknowledged. These packets do not have to be remembered any longer, and their
                    // retry timers can be canceled.

                    _congestion.Tell(new Congestion.Congestion.AckUserData(nrcv));

                    // Try to send data if there's data waiting to be sent and send a
                    // selective acknowledgement if we didn't sent a dframe and the client
                    // requested an acknowledgement.
                    if (cmd == 0x88)
                    {
                        _congestion.Tell("SendSACK");
                    }
                }
                break;
                }
            }

            // If a packet arrives, the recipient SHOULD first check whether
            // it is large enough to be a minimal data frame (DFRAME) (4 bytes)
            // and whether the first byte has the low bit (PACKET_COMMAND_DATA) set.
            else if ((cmd & 0x01) == 0x01 && message.Bytes.Length >= 4)
            {
                uint control = FLMsgType.GetUInt8(message.Bytes, ref pos);
                var  seq     = FLMsgType.GetUInt8(message.Bytes, ref pos);
                var  nrcv    = FLMsgType.GetUInt8(message.Bytes, ref pos);

                // Ignore packets for sessions that don't exist
                //Session sess = GetSession(client);
                //if (sess == null)
                //return;

                // This is a disconnect. We ignore the soft disconnect and immediately
                // drop the session repeating the disconnect a few times to improve the
                // probability of it getting through.
                if ((control & 0x08) == 0x08)
                {
                    Context.ActorSelection("./*").Tell(PoisonPill.Instance, Context.Self);
                    _log.Debug("{0} shutting down: Client request", Self.Path);
                    SendCmdHardDisconnect();
                    Context.Stop(Context.Self);
                    return;
                }

                //var cong = Context.Child("congestion");
                //if (cong.IsNobody()) return;
                if (!_dpInitialized)
                {
                    return;
                }

                var ticks = new TimeSpan(45);
                // TRANS_USERDATA_HEADER bSeq field MUST be either the next sequence
                // ID expected or within 63 packets beyond the ID expected by the receiver.
                // If the sequence ID is not within this range, the payload MUST be ignored.
                // In addition, a SACK packet SHOULD be sent indicating the expected sequence ID.
                {
                    var resp = _congestion.Ask <bool>(new Congestion.Congestion.AckIfInWindow(seq));
                    resp.Wait(ticks);
                    if (resp.Result)
                    {
                        return;
                    }
                }
                // If the sequence ID is out of order, but still within 63 packets,
                // the receiver SHOULD queue the payload until it receives either:
                // - A delayed or retried transmission of the missing packet or packets,
                // and can now process the sequence in order.
                // - A subsequent packet with a send mask indicating that the missing
                // packet or packets did not use PACKET_COMMAND_RELIABLE and will never
                // be retried. Therefore, the receiver should advance its sequence as if
                // it had already received and processed the packets.

                {
                    //var ask = new Congestion.CheckIfOutOfOrder(seq, message.Bytes);
                    var resp = _congestion.Ask <bool>(new Congestion.Congestion.CheckIfOutOfOrder(seq, message.Bytes));
                    resp.Wait(ticks);
                    if (resp.Result)
                    {
                        _log.Debug("{0} enqueued out of order packet {1}", Context.Self.Path, seq);
                        return;
                    }
                }

                //Test code to simulate packet loss
                //if (rand.Next(5) == 1)
                //{
                //    log.AddLog(String.Format("c>s: DROPPING THE PACKET NOW {0:X}", seq));
                //    return;
                //}

                // Note if this was a retried dframe.
                if ((control & 0x01) == 0x01)
                {
                    _congestion.Tell("LostRx");
                }

                // When one or both of the optional SACK mask 32-bit fields is present, and one
                // or more bits are set in the fields, the sender is indicating that it received a
                // packet or packets out of order, presumably due to packet loss. The two 32-bit,
                // little-endian fields MUST be considered as one 64-bit field, where dwSACKMask1
                // is the low 32 bits and dwSACKMask2 is the high 32 bits. If either 32-bit field
                // is not available, the entire contents of the 64-bit field MUST be considered as all 0.

                // The receiver of a SACK mask SHOULD loop through each bit of the combined 64-bit value
                // in the ascending order of significance. Each bit corresponds to a sequence ID after
                // bNRcv. If the bit is set, it indicates that the corresponding packet was received
                // out of order.

                // The receiver of a SACK mask SHOULD shorten the retry timer for the first frame of
                // the window to speed recovery from the packet loss. The recommended duration is
                // 10 milliseconds. This value can be modified according to application and network
                // requirements. The receiver MAY also choose to remove the selectively acknowledged
                // packets from its list to retry.
                if ((control & 0x10) == 0x10)
                {
                    var mask = FLMsgType.GetUInt32(message.Bytes, ref pos);
                    _congestion.Tell(new Congestion.Congestion.DoRetryOnSACKMessage(mask, nrcv));
                }
                if ((control & 0x20) == 0x20)
                {
                    var mask = FLMsgType.GetUInt32(message.Bytes, ref pos);
                    _congestion.Tell(new Congestion.Congestion.DoRetryOnSACKMessage(mask, (byte)(nrcv + 32)));
                }


                // When one or both of the optional send mask 32-bit fields is present, and one or
                // more bits are set the fields, the sender is indicating that it sent a packet or
                // packets that were not marked as reliable and did not receive an acknowledgement yet.
                // The two 32-bit, little-endian fields MUST be considered as one 64-bit field, where
                // dwSendMask1 is the low 32 bits and dwSendMask2 is the high 32 bits. If either 32-bit
                // field is not available, the entire contents of the 64-bit field MUST be considered
                // as all 0.

                // The receiver of a send mask SHOULD loop through each bit of the combined 64-bit
                // value from the least significant bit to the most significant in little-endian byte
                // order. Each bit corresponds to a sequence ID prior to bSeq, and if that is the bit
                // that is set, it indicates that the corresponding packet was not sent reliably and
                // will not be retried. If the recipient of the send mask had not received the packet
                // and had not already processed a send mask that identified the sequence ID, it SHOULD
                // consider the packet as dropped and release its placeholder in the sequence. That is,
                // any sequential messages that could not be indicated because of the gap in the sequence
                // where the packet that was not marked as reliable had been SHOULD now be reported to
                // the upper layer.
                if ((control & 0x40) == 0x40)
                {
                    FLMsgType.GetUInt32(message.Bytes, ref pos);
                }
                if ((control & 0x80) == 0x80)
                {
                    FLMsgType.GetUInt32(message.Bytes, ref pos);
                }
                // However, freelancer always uses reliable packets and so ignore sendmasks.

                // At this point, we've received the packet we wanted to. Advance the sequence number count later
                // and process this message.
                _dplaySession.Tell(new DPlaySession.DPlaySession.ByteMessage(message.Bytes, pos), Context.Child("socket"));



                //ProcessTransUserData(sess, message.Bytes, pos);

                // If there are queued out of order packets, try to process these.
                // Done in Congestion on NextRxSeq
                // Advance the sequence number as well.
                _congestion.Tell("NextRxSeq");
                // At this point bSeq sequence ID is valid, the bNRcv field
                // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                // acknowledged. These packets do not have to be remembered any longer, and their
                // retry timers can be canceled.
                _congestion.Tell(new Congestion.Congestion.AckUserData(nrcv));

                // We always do an immediate acknowledge as bandwidth isn't a particular concern
                // but fast recovery from lost packets is.
                _congestion.Tell("SendSACK");
            }
        }
        public static void SendMiscObjUpdate(Player player, Player.MiscObjUpdateType update, params uint[] values)
        {
            switch (update)
            {
            case Player.MiscObjUpdateType.RANK:
            {
                player.Log.AddLog(LogType.FL_MSG, "tx FLPACKET_SERVER_MISCOBJUPDATE type=rank playerid={0} rank={1}",
                                  values[0], values[1]);
                byte[] omsg = { 0x54, 0x02, 0x44, 0x00 };
                FLMsgType.AddUInt32(ref omsg, values[0]);
                FLMsgType.AddUInt16(ref omsg, values[1]);
                player.SendMsgToClient(omsg);
                return;
            }

            case Player.MiscObjUpdateType.SYSTEM:
            {
                player.Log.AddLog(LogType.FL_MSG,
                                  "tx FLPACKET_SERVER_MISCOBJUPDATE type=system playerid={0} systemid={1}",
                                  values[0], values[1]);
                byte[] omsg = { 0x54, 0x02, 0x84, 0x00 };
                FLMsgType.AddUInt32(ref omsg, values[0]);
                FLMsgType.AddUInt32(ref omsg, values[1]);
                player.SendMsgToClient(omsg);
                return;
            }

            case Player.MiscObjUpdateType.GROUP:
            {
                player.Log.AddLog(LogType.FL_MSG,
                                  "tx FLPACKET_SERVER_MISCOBJUPDATE type=group playerid={0} group={1}",
                                  values[0], values[1]);
                byte[] omsg = { 0x54, 0x02, 0x05, 0x00 };
                FLMsgType.AddUInt32(ref omsg, values[0]);
                FLMsgType.AddUInt32(ref omsg, values[1]);
                player.SendMsgToClient(omsg);
                return;
            }

            case Player.MiscObjUpdateType.UNK2:
            {
                player.Log.AddLog(LogType.FL_MSG, "tx FLPACKET_SERVER_MISCOBJUPDATE type=unknown2 objid={0}",
                                  values[0]);
                byte[] omsg = { 0x54, 0x02, 0x28, 0x00 };
                FLMsgType.AddUInt32(ref omsg, values[0]);
                FLMsgType.AddInt32(ref omsg, -1);     // faction?
                player.SendMsgToClient(omsg);
                return;
            }

            case Player.MiscObjUpdateType.UNK3:
            {
                player.Log.AddLog(LogType.FL_MSG, "tx FLPACKET_SERVER_MISCOBJUPDATE type=unknown3 objid={0}",
                                  values[0]);
                byte[] omsg = { 0x54, 0x02, 0x09, 0x00 };
                FLMsgType.AddUInt32(ref omsg, values[0]);
                FLMsgType.AddUInt32(ref omsg, 0);
                player.SendMsgToClient(omsg);
                return;
            }

            default:
                return;
            }
        }
        /// <summary>
        ///     Process a charinforequest from a player.
        /// </summary>
        /// <param name="player"></param>
        public static void SendCharInfoRequestResponse(Player player)
        {
            List <Account> accs = Database.GetAccount(player.AccountID);

            //string accdir_path = Runner.Server.AcctPath + Path.DirectorySeparatorChar +
            //FLMsgType.FLNameToFile(AccountID);
            try
            {
                byte[] omsg = { 0x03, 0x02 };
                FLMsgType.AddUInt8(ref omsg, 0); // chars
                //foreach (var path in Directory.GetFiles(accdir_path, "??-????????.fl"))
                if (accs != null)
                {
                    foreach (Account acct in accs)
                    {
                        try
                        {
                            var dummy = new CharacterData {
                                Ship = new Old.Object.Ship.Ship(null)
                            };

                            // If the charfile is not valid ignore it.
                            string result = dummy.LoadCharFile(acct, player.Log);
                            if (result != null)
                            {
                                player.Log.AddLog(LogType.ERROR, "error: " + result);
                                continue;
                            }

                            FLMsgType.AddAsciiStringLen16(ref omsg, FLMsgType.FLNameToFile(acct.CharName));
                            FLMsgType.AddUInt16(ref omsg, 0);
                            FLMsgType.AddUnicodeStringLen16(ref omsg, acct.CharName);
                            FLMsgType.AddUnicodeStringLen16(ref omsg, "");
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, acct.Ship);
                            if (dummy.Money > 2000000000)
                            {
                                FLMsgType.AddInt32(ref omsg, 2000000000);
                            }
                            else
                            {
                                FLMsgType.AddInt32(ref omsg, acct.Money);
                            }

                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.System.SystemID);
                            if (dummy.Ship.Basedata != null)
                            {
                                FLMsgType.AddUInt32(ref omsg, dummy.Ship.Basedata.BaseID);
                            }
                            else
                            {
                                FLMsgType.AddUInt32(ref omsg, 0);
                            }
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.voiceid);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.Rank);
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddFloat(ref omsg, dummy.Ship.Health);
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, 0);
                            FLMsgType.AddUInt32(ref omsg, 0);

                            FLMsgType.AddUInt8(ref omsg, 1);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_body);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_head);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_lefthand);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_righthand);
                            FLMsgType.AddUInt32(ref omsg, 0);

                            FLMsgType.AddUInt8(ref omsg, 1);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_body);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_head);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_lefthand);
                            FLMsgType.AddUInt32(ref omsg, dummy.Ship.com_righthand);
                            FLMsgType.AddUInt32(ref omsg, 0);

                            FLMsgType.AddUInt8(ref omsg, (uint)dummy.Ship.Items.Count);
                            foreach (ShipItem item in dummy.Ship.Items.Values)
                            {
                                FLMsgType.AddUInt32(ref omsg, item.count);
                                FLMsgType.AddFloat(ref omsg, item.health);
                                FLMsgType.AddUInt32(ref omsg, item.arch.ArchetypeID);
                                FLMsgType.AddUInt16(ref omsg, item.hpid);
                                FLMsgType.AddUInt16(ref omsg, (item.mounted ? 1u : 0u));
                                if (item.hpname.Length > 0)
                                {
                                    FLMsgType.AddAsciiStringLen16(ref omsg, item.hpname + "\0");
                                }
                                else
                                {
                                    FLMsgType.AddAsciiStringLen16(ref omsg, "BAY\0");
                                }
                            }

                            FLMsgType.AddUInt32(ref omsg, 0);

                            omsg[2]++;
                        }
                        catch (Exception e)
                        {
                            player.Log.AddLog(LogType.ERROR, "error: corrupt file when processing charinforequest '{0}'",
                                              e.Message);
                        }
                    }
                }
                FLMsgType.AddUInt32(ref omsg, 0);
                player.SendMsgToClient(omsg);
            }
            catch (Exception e)
            {
                player.Log.AddLog(LogType.ERROR, "error: unable to process charinforequest '{0}'", e.Message);
            }
        }
Exemple #12
0
 public void AddStyle(uint style)
 {
     FLMsgType.AddUInt32(ref _msg, 0x06); // rdl type of style
     FLMsgType.AddUInt32(ref _msg, 0x02); // size of data
     FLMsgType.AddUInt16(ref _msg, style);
 }
Exemple #13
0
 public void AddText(string text)
 {
     FLMsgType.AddUInt32(ref _msg, 0x02);
     FLMsgType.AddUInt32(ref _msg, 2 + (uint)text.Length * 2);
     FLMsgType.AddUnicodeStringLen0(ref _msg, text + "\0");
 }
        /// <summary>
        ///     Send a dummy trans
        /// </summary>
        private void SendTUDSessionInfo()
        {
            var pkt = new byte[0];

            FLMsgType.AddUInt32(ref pkt, 0xC2); // dwPacketType
            FLMsgType.AddUInt32(ref pkt, 0);    // dwReplyOffset
            FLMsgType.AddUInt32(ref pkt, 0);    // dwReplySize

            FLMsgType.AddUInt32(ref pkt, 0x50); // dwApplicationDescSize
            FLMsgType.AddUInt32(ref pkt, 0x01); // dwFlags



            var resp = _globals.Ask <Globals.ServerInfo>("GetInfo");

            resp.Wait(5);
            var result = resp.Result;

            FLMsgType.AddUInt32(ref pkt, result.MaxPlayers + 1);              // dwMaxPlayers
            FLMsgType.AddUInt32(ref pkt, (uint)result.CurrentPlayers + 1);    // dwCurrentPlayers
            FLMsgType.AddUInt32(ref pkt, 0x6C + 0x60);                        // dwSessionNameOffset
            FLMsgType.AddUInt32(ref pkt, (uint)result.ServerName.Length * 2); // dwSessionNameSize
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwPasswordOffset
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwPasswordSize
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwReservedDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwReservedDataSize
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwApplicationReservedDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);                                  // dwApplicationReservedDataSize
            FLMsgType.AddArray(ref pkt, result.InstanceGUID);
            FLMsgType.AddArray(ref pkt, result.AppGUID);
            FLMsgType.AddUInt32(ref pkt, _dPlayID); // dpnid
            FLMsgType.AddUInt32(ref pkt, _dPlayID); // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 2);        // dwEntryCount
            FLMsgType.AddUInt32(ref pkt, 0);        // dwMembershipCount

            // server name table entry
            FLMsgType.AddUInt32(ref pkt, 1);        // dpnid
            FLMsgType.AddUInt32(ref pkt, 0);        // dpnidOwner
            FLMsgType.AddUInt32(ref pkt, 0x000402); // dwFlags
            FLMsgType.AddUInt32(ref pkt, 2);        // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 7);        // dwDNETVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLSize

            // connecting client name table entry
            FLMsgType.AddUInt32(ref pkt, _dPlayID); // dpnid
            FLMsgType.AddUInt32(ref pkt, 0);        // dpnidOwner
            FLMsgType.AddUInt32(ref pkt, 0x020000); // dwFlags
            FLMsgType.AddUInt32(ref pkt, _dPlayID); // dwVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwVersionNotUsed
            FLMsgType.AddUInt32(ref pkt, 7);        // dwDNETVersion
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwNameSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwDataSize
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLOffset
            FLMsgType.AddUInt32(ref pkt, 0);        // dwURLSize

            FLMsgType.AddUnicodeStringLen0(ref pkt, result.ServerName);
            Context.ActorSelection("../congestion").Tell(pkt);
            //UserData.AddLast(pkt);
            //SendDFrame(sess);
        }