/*** dequeue_gre **************************************************************/ int dequeue_gre (callback_t callback, int cl) { pqueue_t *head; int status; /* process packets in the queue that either are expected or have * timed out. */ head = pqueue_head(); while ( head != NULL && ( (head->seq == seq_recv + 1) || /* wrap-around safe */ (pqueue_expiry_time(head) <= 0) ) ) { /* if it is timed out... */ if (head->seq != seq_recv + 1 ) { /* wrap-around safe */ stats.rx_lost += head->seq - seq_recv - 1; if (log_level >= 2) log("timeout waiting for %d packets", head->seq - seq_recv - 1); } if (log_level >= 2) log("accepting %d from queue", head->seq); seq_recv = head->seq; status = callback(cl, head->packet, head->packlen); pqueue_del(head); if (status < 0) return status; head = pqueue_head(); } return 0; }
Packet* pqueue_pop(PQueue* queue) { Packet* tmp = pqueue_head(queue); assert (pqueue_length(queue) > 0); queue->head++; queue->length--; queue->head = PMOD(queue->head, queue->maxsize); return tmp; }
void pqueue_debug_print(PQueue* queue) { if (pqueue_length(queue) > 0) { printf("Queue head seq#%d, tail seq#%d, size %d, window size %d\n", pqueue_head(queue)->seqn, pqueue_tail(queue)->seqn, pqueue_length(queue), queue->maxsize); } else { printf("Empty queue, window size %d\n", queue->maxsize); } }
/* Main sender function. Taken from the state diagram on slide 6, chapter 5 */ void sender(int window, int timeout) { int base = 1; int nextseqnum = 1; bool allsent = false; PQueue sendQ; pqueue_init(&sendQ, window); while ( !(allsent && pqueue_empty(&sendQ)) ) { int acknum = -1; /* Send new data */ if (!allsent && nextseqnum < base + window) { Packet* packet = add_packet(&sendQ, nextseqnum); if (packet == NULL) { allsent = true; } else { send_packet(packet); if (base == nextseqnum) start_timer(timeout); nextseqnum++; } } /* Attempt to receive an ACK. */ acknum = get_ack(0); if (acknum > 0) { base = acknum + 1; if (base == nextseqnum) stop_timer(); else start_timer(timeout); } /* Clean up the queue */ while (!pqueue_empty(&sendQ) && pqueue_head(&sendQ)->seqn < base) { pqueue_pop(&sendQ); } /* Handle timeouts */ if (cnt_active && cnt_time >= cnt_timeout) { start_timer(cnt_timeout); pqueue_map(&sendQ, &send_packet); } pqueue_debug_print(&sendQ); } pqueue_destroy(&sendQ); }
/*** pptp_gre_copy ************************************************************/ void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, int pty_fd, int gre_fd) { int max_fd; pptp_gre_call_id = call_id; pptp_gre_peer_call_id = peer_call_id; /* Pseudo-terminal already open. */ ack_sent = ack_recv = seq_sent = seq_recv = 0; /* weird select semantics */ max_fd = gre_fd; if (pty_fd > max_fd) max_fd = pty_fd; /* Dispatch loop */ for (;;) { /* until error happens on gre_fd or pty_fd */ struct timeval tv = {0, 0}; struct timeval *tvp; fd_set rfds; int retval; pqueue_t *head; int block_usecs = -1; /* wait forever */ /* watch terminal and socket for input */ FD_ZERO(&rfds); FD_SET(gre_fd, &rfds); FD_SET(pty_fd, &rfds); /* * if there are multiple pending ACKs, then do a minimal timeout; * else if there is a single pending ACK then timeout after 0,5 seconds; * else block until data is available. */ if (ack_sent != seq_recv) { if (ack_sent + 1 == seq_recv) /* u_int wrap-around safe */ block_usecs = 500000; else /* don't use zero, this will force a resceduling */ /* when calling select(), giving pppd a chance to */ /* run. */ block_usecs = 1; } /* otherwise block_usecs == -1, which means wait forever */ /* * If there is a packet in the queue, then don't wait longer than * the time remaining until it expires. */ head = pqueue_head(); if (head != NULL) { int expiry_time = pqueue_expiry_time(head); if (block_usecs == -1 || expiry_time < block_usecs) block_usecs = expiry_time; } if (block_usecs == -1) { tvp = NULL; } else { tvp = &tv; tv.tv_usec = block_usecs; tv.tv_sec = tv.tv_usec / 1000000; tv.tv_usec %= 1000000; } retval = select(max_fd + 1, &rfds, NULL, NULL, tvp); if (retval > 0 && FD_ISSET(pty_fd, &rfds)) { if (decaps_hdlc(pty_fd, encaps_gre, gre_fd) < 0) break; } else if (retval == 0 && ack_sent != seq_recv) { /* if outstanding ack */ /* send ack with no payload */ encaps_gre(gre_fd, NULL, 0); } if (retval > 0 && FD_ISSET(gre_fd, &rfds)) { if (decaps_gre (gre_fd, encaps_hdlc, pty_fd) < 0) break; } if (dequeue_gre (encaps_hdlc, pty_fd) < 0) break; } /* Close up when done. */ close(gre_fd); close(pty_fd); }