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; }
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; }
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; } }