// return a free acknum and copy netbuffer in the ackpak table static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) { node_t *node = &nodes[doomcom->remotenode]; INT32 i, numfreeslote = 0; if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) { DEBFILE(va("too fast %d %d\n",node->remotefirstack,node->nextacknum)); return false; } for (i = 0; i < MAXACKPACKETS; i++) if (!ackpak[i].acknum) { // for low priority packet, make sure let freeslotes so urgents packets can be sent numfreeslote++; if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM) continue; ackpak[i].acknum = node->nextacknum; ackpak[i].nextacknum = node->nextacknum; node->nextacknum++; if (!node->nextacknum) node->nextacknum++; ackpak[i].destinationnode = (UINT8)(node - nodes); ackpak[i].length = doomcom->datalength; if (lowtimer) { // lowtime mean can't be sent now so try it soon as possible ackpak[i].senttime = 0; ackpak[i].resentnum = 1; } else { ackpak[i].senttime = I_GetTime(); ackpak[i].resentnum = 0; } M_Memcpy(ackpak[i].pak.raw, netbuffer, ackpak[i].length); *freeack = ackpak[i].acknum; sendackpacket++; // for stat return true; } #ifdef PARANOIA if (devparm) I_OutputMsg("No more free ackpacket\n"); #endif if (netbuffer->packettype < PT_CANFAIL) I_Error("Connection lost\n"); return false; }
static void GotAcks(void) { INT32 i, j; for (j = 0; j < MAXACKTOSEND; j++) if (netbuffer->u.textcmd[j]) for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) { if (ackpak[i].acknum == netbuffer->u.textcmd[j]) Removeack(i); else // nextacknum is first equal to acknum, then when receiving bigger ack // there is big chance the packet is lost // when resent, nextacknum = nodes[node].nextacknum // will redo the same but with different value if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0 && ackpak[i].senttime > 0) { ackpak[i].senttime--; // hurry up } } }
// we have got a packet proceed the ack request and ack return static boolean Processackpak(void) { INT32 i; boolean goodpacket = true; node_t *node = &nodes[doomcom->remotenode]; // received an ack return, so remove the ack in the list if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0) { node->remotefirstack = netbuffer->ackreturn; // search the ackbuffer and free it for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) { Removeack(i); } } // received a packet with ack, queue it to send the ack back if (netbuffer->ack) { UINT8 ack = netbuffer->ack; getackpacket++; if (cmpack(ack, node->firstacktosend) <= 0) { DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack)); duppacket++; goodpacket = false; // discard packet (duplicate) } else { // check if it is not already in the queue for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) if (node->acktosend[i] == ack) { DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); duppacket++; goodpacket = false; // discard packet (duplicate) break; } if (goodpacket) { // is a good packet so increment the acknowledge number, // then search for a "hole" in the queue UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1); if (!nextfirstack) nextfirstack = 1; if (ack == nextfirstack) { UINT8 hm1; // head - 1 boolean change = true; node->firstacktosend = nextfirstack++; if (!nextfirstack) nextfirstack = 1; hm1 = (UINT8)((node->acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND); while (change) { change = false; for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) { if (cmpack(node->acktosend[i], nextfirstack) <= 0) { if (node->acktosend[i] == nextfirstack) { node->firstacktosend = nextfirstack++; if (!nextfirstack) nextfirstack = 1; change = true; } if (i == node->acktosend_tail) { node->acktosend[node->acktosend_tail] = 0; node->acktosend_tail = (UINT8)((i+1) % MAXACKTOSEND); } else if (i == hm1) { node->acktosend[hm1] = 0; node->acktosend_head = hm1; hm1 = (UINT8)((hm1-1+MAXACKTOSEND) % MAXACKTOSEND); } } } } } else // out of order packet { // don't increment firsacktosend, put it in asktosend queue // will be incremented when the nextfirstack comes (code above) UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND); DEBFILE(va("out of order packet (%d expected)\n", nextfirstack)); if (newhead != node->acktosend_tail) { node->acktosend[node->acktosend_head] = ack; node->acktosend_head = newhead; } else // buffer full discard packet, sender will resend it { // we can admit the packet but we will not detect the duplication after :( DEBFILE("no more freeackret\n"); goodpacket = false; } } } } } return goodpacket; }