Example #1
0
bool NetManager::HandleUnknownClient (LPSOCKADDR_IN addr, MsgEntry* me)
{
    psMessageBytes* msg = me->bytes;

    // The first msg from client must be "firstmsg", "alt_first_msg" or "PING"
    if (msg->type!=client_firstmsg && msg->type!=npcclient_firstmsg && msg->type!=MSGTYPE_PING)
        return false;

    if ( msg->type == MSGTYPE_PING )
    {
        psPingMsg ping(me);

        if (!(ping.flags & PINGFLAG_REQUESTFLAGS) && !psserver->IsReady())
            return false;

        int flags = 0;
        if (psserver->IsReady()) flags |= PINGFLAG_READY;
        if (psserver->HasBeenReady()) flags |= PINGFLAG_HASBEENREADY;
        if (psserver->IsFull(clients.Count(),NULL)) flags |= PINGFLAG_SERVERFULL;

        // Create the reply to the ping
        psPingMsg pong(0,ping.id,flags);
        pong.msg->msgid = GetRandomID();

        csRef<psNetPacketEntry> pkt;
        pkt.AttachNew(new
                      psNetPacketEntry(pong.msg->priority, 0,
                                       0, 0, (uint32_t) pong.msg->bytes->GetTotalSize(),
                                       (uint16_t) pong.msg->bytes->GetTotalSize(), pong.msg->bytes));

        SendFinalPacket(pkt,addr);
        return false;
    }

    // Don't accept any new clients when not ready, npcclients is accepted
    if(msg->type==client_firstmsg && !psserver->IsReady())
        return false;

    // Create and add the client object to client list
    Client* client = clients.Add(addr);
    if (!client)
        return false;

    // This is for the accept message that will be sent back
    me->clientnum = client->GetClientNum();

    return true;
}
Example #2
0
bool NetBase::HandleAck(csRef<psNetPacketEntry> pkt, Connection* connection,
                        LPSOCKADDR_IN addr)
{
    psNetPacket* packet = pkt->packet;

    // REVERTED 3/8/03 Until I can figure out why this is causing client conencts to fail -  Andrew Mann (Rhad)
    // If we don't know who this connection is, don't handle ACKs
    //if (!connection)
    //    return false;


    if (packet->pktsize == PKTSIZE_ACK)  // special pktsize means ACK packet here
    {
#ifdef PACKETDEBUG
        Debug1(LOG_NET,0,"Ack received.\n");
#endif

        // receipt of ack packet is good enough to keep alive connection
        if (connection)
        {
            connection->heartbeat          = 0;
            connection->lastRecvPacketTime = csGetTicks();
            connection->pcknumin++;
        }

        csRef<psNetPacketEntry> ack;
        
        // The hash only keys on the clientnum and pktid so we need to go looking for the offset
        csArray<csRef<psNetPacketEntry> > acks = awaitingack.GetAll(PacketKey(pkt->clientnum, pkt->packet->pktid));
        for(size_t i = 0;i < acks.GetSize(); i++)
        {
            if(acks[i]->packet->offset == pkt->packet->offset)
                ack = acks[i];
        }
                

        if (ack) // if acked pkt is found, simply remove it.  We're done.
        {
            // Only update RTT estimate when packet has not been retransmitted
            if (!ack->retransmitted && connection)
            {
                csTicks elapsed = csGetTicks() - ack->timestamp;
      
                if (connection->estRTT > 0)
                {
                    int diff = (int) (elapsed - connection->estRTT);
                    connection->estRTT += (int) (0.125 * diff);
                    if(diff < 0)
                        diff = -diff;

                    connection->devRTT += (int) (0.125 * (diff - connection->devRTT));
                }
                else
                {
                    // Initialise the RTT estimates
                    connection->estRTT = elapsed;
                    connection->devRTT = elapsed / 2;
                }

                // Update the packet timeout
                connection->RTO = (int) (connection->estRTT + 4 * connection->devRTT);
                if (connection->RTO > PKTMAXRTO)
                {
                    connection->RTO = PKTMAXRTO;
                }
                else if(connection->RTO < PKTMINRTO)
                {
                    connection->RTO = PKTMINRTO;
                }

                netInfos.AddPingTicks(elapsed);
            }
            // printf ("Ping time: %i, average: %i\n", elapsed, netInfos.GetAveragePingTicks());


            if (!awaitingack.Delete(PacketKey(pkt->clientnum, pkt->packet->pktid), ack))
            {
#ifdef PACKETDEBUG
                Debug2(LOG_NET,0,"No packet in ack queue :%d\n", ack->packet->pktid);
#endif
            }
            else if(connection)
            {
                connection->RemoveFromWindow(ack->packet->GetPacketSize());
            }
        }
        else // if not found, it is probably a resent ACK which is redundant so do nothing
        {
#ifdef PACKETDEBUG
            Debug1(LOG_NET,0,"No matching packet found. No problem though.\n");
#endif
        }

        return true;   // eat the packet
    }

    if (pkt->packet->GetPriority() == PRIORITY_HIGH) // a HIGH_PRIORITY packet -> ack
    {
        
#ifdef PACKETDEBUG
        Debug1(LOG_NET,0,"High priority packet received.\n");
#endif
        
        if (connection)
        {
            csRef<psNetPacketEntry> ack;
            ack.AttachNew(new psNetPacketEntry(PRIORITY_LOW,
                    pkt->clientnum,
                    pkt->packet->pktid,
                    pkt->packet->offset,
                    pkt->packet->msgsize,
                    PKTSIZE_ACK,(char *)NULL));
            
            SendFinalPacket(ack, addr);
            // ack should be unre'd here
        }
    }

    return false;
}
Example #3
0
void NetManager::Broadcast(MsgEntry *me, int scope, int guildID)
{
    switch (scope)
    {
    case NetBase::BC_EVERYONE:
    case NetBase::BC_EVERYONEBUTSELF:
    {
        // send the message to each client (except perhaps the client that originated it)
        uint32_t originalclient = me->clientnum;

        // Copy message to send out to everyone
        csRef<MsgEntry> newmsg;
        newmsg.AttachNew(new MsgEntry(me));
        newmsg->msgid = GetRandomID();

        // Message is copied again into packet sections, so we can reuse same one.
        ClientIterator i(clients);

        while(i.HasNext())
        {
            Client *p = i.Next();
            if (scope==NetBase::BC_EVERYONEBUTSELF
                    && p->GetClientNum() == originalclient)
                continue;

            // send to superclient only the messages he needs
            if (p->IsSuperClient()) {
                // time of the day is needed
                if (me->GetType()!=MSGTYPE_WEATHER)
                    continue;
            }

            // Only clients that finished connecting get broadcastet
            // stuff
            if (!p->IsReady())
                continue;

            newmsg->clientnum = p->GetClientNum();
            SendMessage (newmsg);
        }

        CHECK_FINAL_DECREF(newmsg, "BroadcastMsg");
        break;
    }
    // TODO: NetBase::BC_GROUP
    case NetBase::BC_GUILD:
    {
        CS_ASSERT_MSG("NetBase::BC_GUILD broadcast must specify guild ID", guildID != -1 );

        /**
         * Send the message to each client with the same guildID
         */

        // Copy message to send out to everyone
        csRef<MsgEntry> newmsg;
        newmsg.AttachNew(new MsgEntry(me));
        newmsg->msgid = GetRandomID();

        // Message is copied again into packet sections, so we can reuse same one.
        ClientIterator i(clients);

        while(i.HasNext())
        {
            Client *p = i.Next();
            if (p->GetGuildID() == guildID)
            {
                newmsg->clientnum = p->GetClientNum();
                SendMessage (newmsg);
            }
        }

        CHECK_FINAL_DECREF(newmsg, "GuildMsg");
        break;
    }
    case NetBase::BC_FINALPACKET:
    {
        csRef<MsgEntry> newmsg;
        newmsg.AttachNew(new MsgEntry(me));
        newmsg->msgid = GetRandomID();

        LogMessages('F',newmsg);

        // XXX: This is hacky, but we need to send the message to the client
        // here and now! Because in the next moment he'll be deleted

        csRef<psNetPacketEntry> pkt;
        pkt.AttachNew( new psNetPacketEntry(me->priority, newmsg->clientnum,
                                            0, 0, (uint32_t) newmsg->bytes->GetTotalSize(),
                                            (uint16_t) newmsg->bytes->GetTotalSize(), newmsg->bytes));
        // this will also delete the pkt
        SendFinalPacket(pkt);

        CHECK_FINAL_DECREF(newmsg, "FinalPacket");
        break;
    }
    default:
        psprintf("\nIllegal Broadcast scope %d!\n",scope);
        return;
    }
}