static void readyToEndCallback (NetConnection *conn, void *arg) { // This callback function gets called from inside the function that // updates the frame counter, but this is not a problem as the // ending frame count will at least be 1 greater than the current // frame count. BattleStateData *battleStateData; battleStateData = (BattleStateData *) NetConnection_getStateData(conn); #ifdef NETPLAY_DEBUG fprintf (stderr, "Both sides are ready to end the battle; starting " "end-of-battle synchronisation.\n"); #endif NetConnection_setState (conn, NetState_endingBattle); if (battleFrameCount + 1 > battleStateData->endFrameCount) battleStateData->endFrameCount = battleFrameCount + 1; Netplay_Notify_frameCount (conn, battleFrameCount + 1); // The +1 is to ensure that after the remote side receives the // frame count it will still receive one more frame data packet, // so it will know in advance when the last frame data packet // will come so it won't block. It also ensures that the // local frame counter won't go past the sent number, which // could happen when the function triggering the call to this // function is the frame update function which might update // the frame counter one more time. flushPacketQueue (conn); #ifdef NETPLAY_DEBUG fprintf (stderr, "NETPLAY: [%d] ==> Sent battleFrameCount %d.\n", NetConnection_getPlayerNr(conn), battleFrameCount + 1); #endif Netplay_localReady(conn, readyToEnd2Callback, NULL, false); (void) arg; }
// Try to get a single packet from a stream of data. // Returns 0 if the packet was successfully processed, or // -1 on an error, in which case the state is unchanged. static ssize_t dataReceivedSingle(NetConnection *conn, const uint8 *data, size_t dataLen) { uint32 packetLen; PacketType type; int result; if (dataLen < sizeof (PacketHeader)) { // Incomplete packet. We'll have to wait for the rest. return 0; } packetLen = packetLength((const Packet *) data); type = packetType((const Packet *) data); if (!validPacketType(type)) { log_add(log_Warning, "Packet with invalid type %d received.\n", type); errno = EBADMSG; return -1; } if (packetLen < packetTypeData[type].len) { // Bad len field of packet. log_add(log_Warning, "Packet with bad length field received (type=" "%s, lenfield=%d.\n", packetTypeData[type].name, packetLen); errno = EBADMSG; return -1; } if (dataLen < packetLen) { // Incomplete packet. We'll have to wait for the rest. return 0; } #ifdef NETPLAY_STATISTICS NetConnection_getStatistics(conn)->packetsReceived++; NetConnection_getStatistics(conn)->packetTypeReceived[type]++; #endif #ifdef NETPLAY_DEBUG if (type != PACKET_BATTLEINPUT && type != PACKET_CHECKSUM) { // Reporting BattleInput and Checksum would get so spammy that it // would slow down the battle. log_add(log_Debug, "NETPLAY: [%d] <== Received packet of type %s.\n", NetConnection_getPlayerNr(conn), packetTypeData[type].name); } #endif result = packetTypeData[type].handler(conn, data); if (result == -1) { // An error occured. errno is set by the handler. return -1; } return packetLen; }
void queuePacket(NetConnection *conn, Packet *packet, bool urgent) { PacketQueue *queue; PacketQueueLink *link; assert(NetConnection_isConnected(conn)); assert(!urgent || !packetTypeData[packetType(packet)].inTurn); // Urgent packets should never stall the connection. queue = &conn->queue; link = PacketQueueLink_alloc(); link->packet = packet; link->next = NULL; if (urgent) { *queue->endUrgent = link; queue->endUrgent = &link->next; } else { *queue->end = link; queue->end = &link->next; } queue->size++; // XXX: perhaps check that this queue isn't getting too large? #ifdef NETPLAY_DEBUG if (packetType(packet) != PACKET_BATTLEINPUT && packetType(packet) != PACKET_CHECKSUM) { // Reporting BattleInput or Checksum would get so spammy that it // would slow down the battle. log_add(log_Debug, "NETPLAY: [%d] ==> Queueing packet of type %s.\n", NetConnection_getPlayerNr(conn), packetTypeData[packetType(packet)].name); } #endif }