|
@@ -0,0 +1,484 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include "prog2.h"
|
|
|
+
|
|
|
+/* ******************************************************************
|
|
|
+ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1 J.F.Kurose
|
|
|
+
|
|
|
+This code should be used for PA2, unidirectional or bidirectional
|
|
|
+data transfer protocols (from A to B. Bidirectional transfer of data
|
|
|
+is for extra credit and is not required). Network properties:
|
|
|
+- one way network delay averages five time units (longer if there
|
|
|
+are other messages in the channel for GBN), but can be larger
|
|
|
+- packets can be corrupted (either the header or the data portion)
|
|
|
+or lost, according to user-defined probabilities
|
|
|
+- packets will be delivered in the order in which they were sent
|
|
|
+(although some can be lost).
|
|
|
+**********************************************************************/
|
|
|
+
|
|
|
+/*****************************************************************
|
|
|
+***************** NETWORK EMULATION CODE STARTS BELOW ***********
|
|
|
+The code below emulates the layer 3 and below network environment:
|
|
|
+- emulates the tranmission and delivery (possibly with bit-level corruption
|
|
|
+and packet loss) of packets across the layer 3/4 interface
|
|
|
+- handles the starting/stopping of a timer, and generates timer
|
|
|
+interrupts (resulting in calling students timer handler).
|
|
|
+- generates message to be sent (passed from later 5 to 4)
|
|
|
+
|
|
|
+THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND
|
|
|
+THE CODE BELOW. YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY
|
|
|
+OF THE DATA STRUCTURES BELOW. If you're interested in how I designed
|
|
|
+the emulator, you're welcome to look at the code - but again, you should have
|
|
|
+to, and you defeinitely should not have to modify
|
|
|
+******************************************************************/
|
|
|
+
|
|
|
+event_t *evlist = NULL; /* the event list */
|
|
|
+
|
|
|
+int TRACE = 1; /* for my debugging */
|
|
|
+int nsim = 0; /* number of messages from 5 to 4 so far */
|
|
|
+int nsimmax = 0; /* number of msgs to generate, then stop */
|
|
|
+float time = 0.000;
|
|
|
+float lossprob; /* probability that a packet is dropped */
|
|
|
+float corruptprob; /* probability that one bit is packet is flipped */
|
|
|
+float lambda; /* arrival rate of messages from layer 5 */
|
|
|
+int ntolayer3; /* number sent into layer 3 */
|
|
|
+int nlost; /* number lost in media */
|
|
|
+int ncorrupt; /* number corrupted by media*/
|
|
|
+
|
|
|
+int main() {
|
|
|
+
|
|
|
+ event_t *eventptr;
|
|
|
+ msg_t msg2give;
|
|
|
+ pkt_t pkt2give;
|
|
|
+
|
|
|
+ int i,j;
|
|
|
+
|
|
|
+ init();
|
|
|
+
|
|
|
+ A_init();
|
|
|
+ B_init();
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+
|
|
|
+ /* get next event to simulate */
|
|
|
+ eventptr = evlist;
|
|
|
+
|
|
|
+ if ( eventptr == NULL )
|
|
|
+ goto terminate;
|
|
|
+
|
|
|
+ /* remove this event from event list */
|
|
|
+ evlist = evlist->next;
|
|
|
+
|
|
|
+ if (evlist != NULL)
|
|
|
+ evlist->prev=NULL;
|
|
|
+
|
|
|
+ if ( TRACE >= 2 ) {
|
|
|
+ printf("\nEVENT time: %f,",eventptr->evtime);
|
|
|
+ printf(" type: %d",eventptr->evtype);
|
|
|
+
|
|
|
+ if ( eventptr->evtype == 0 )
|
|
|
+ printf(", timerinterrupt ");
|
|
|
+ else if ( eventptr->evtype == 1 )
|
|
|
+ printf(", fromlayer5 ");
|
|
|
+ else
|
|
|
+ printf(", fromlayer3 ");
|
|
|
+
|
|
|
+ printf(" entity: %d\n",eventptr->eventity);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* update time to next event time */
|
|
|
+ time = eventptr->evtime;
|
|
|
+
|
|
|
+ if ( nsim == nsimmax )
|
|
|
+ break; /* all done with simulation */
|
|
|
+
|
|
|
+ if ( eventptr->evtype == FROM_LAYER5 ) {
|
|
|
+
|
|
|
+ /* set up future arrival */
|
|
|
+ generate_next_arrival();
|
|
|
+
|
|
|
+ /* fill in msg to give with string of same letter */
|
|
|
+ j = nsim % 26;
|
|
|
+
|
|
|
+ for ( i = 0; i < 20; i++ )
|
|
|
+ msg2give.data[i] = 97 + j;
|
|
|
+
|
|
|
+ if ( TRACE > 2 ) {
|
|
|
+
|
|
|
+ printf(" MAINLOOP: data given to student: ");
|
|
|
+
|
|
|
+ for ( i = 0; i < 20; i++ )
|
|
|
+ printf("%c", msg2give.data[i]);
|
|
|
+
|
|
|
+ printf("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ nsim++;
|
|
|
+
|
|
|
+ if ( eventptr->eventity == A )
|
|
|
+ A_output(msg2give);
|
|
|
+ else
|
|
|
+ B_output(msg2give);
|
|
|
+
|
|
|
+ } else if ( eventptr->evtype == FROM_LAYER3 ) {
|
|
|
+
|
|
|
+ pkt2give.seqnum = eventptr->pktptr->seqnum;
|
|
|
+ pkt2give.acknum = eventptr->pktptr->acknum;
|
|
|
+ pkt2give.checksum = eventptr->pktptr->checksum;
|
|
|
+
|
|
|
+ for (i=0; i<20; i++)
|
|
|
+ pkt2give.payload[i] = eventptr->pktptr->payload[i];
|
|
|
+
|
|
|
+ if ( eventptr->eventity == A ) /* deliver packet by calling */
|
|
|
+ A_input(pkt2give); /* appropriate entity */
|
|
|
+ else
|
|
|
+ B_input(pkt2give);
|
|
|
+
|
|
|
+ free( eventptr->pktptr ); /* free the memory for packet */
|
|
|
+
|
|
|
+ } else if ( eventptr->evtype == TIMER_INTERRUPT ) {
|
|
|
+
|
|
|
+ if ( eventptr->eventity == A )
|
|
|
+ A_timerinterrupt();
|
|
|
+ else
|
|
|
+ B_timerinterrupt();
|
|
|
+
|
|
|
+ } else
|
|
|
+ printf("INTERNAL PANIC: unknown event type \n");
|
|
|
+
|
|
|
+ free(eventptr);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ terminate:
|
|
|
+ printf(" Simulator terminated at time %f\n after sending %d msgs from layer5\n",time,nsim);
|
|
|
+ return EXIT_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* initialize the simulator */
|
|
|
+void init() {
|
|
|
+
|
|
|
+ int i;
|
|
|
+ float sum, avg;
|
|
|
+ float jimsrand();
|
|
|
+
|
|
|
+ printf("----- Stop and Wait Network Simulator Version 1.1 -------- \n\n");
|
|
|
+ printf("Enter the number of messages to simulate: ");
|
|
|
+ scanf("%d",&nsimmax);
|
|
|
+ printf("Enter packet loss probability [enter 0.0 for no loss]:");
|
|
|
+ scanf("%f",&lossprob);
|
|
|
+ printf("Enter packet corruption probability [0.0 for no corruption]:");
|
|
|
+ scanf("%f",&corruptprob);
|
|
|
+ printf("Enter average time between messages from sender's layer5 [ > 0.0]:");
|
|
|
+ scanf("%f",&lambda);
|
|
|
+ printf("Enter TRACE:");
|
|
|
+ scanf("%d",&TRACE);
|
|
|
+
|
|
|
+ /* init random number generator */
|
|
|
+ srand(9999);
|
|
|
+ /* test random number generator for students */
|
|
|
+ sum = 0.0;
|
|
|
+
|
|
|
+ /* jimsrand() should be uniform in [0,1] */
|
|
|
+ for ( i = 0; i < 1000; i++ )
|
|
|
+ sum = sum + jimsrand();
|
|
|
+
|
|
|
+ avg = sum / 1000.0;
|
|
|
+
|
|
|
+ if ( avg < 0.25 || avg > 0.75 ) {
|
|
|
+ printf("It is likely that random number generation on your machine\n" );
|
|
|
+ printf("is different from what this emulator expects. Please take\n");
|
|
|
+ printf("a look at the routine jimsrand() in the emulator code. Sorry. \n");
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ ntolayer3 = 0;
|
|
|
+ nlost = 0;
|
|
|
+ ncorrupt = 0;
|
|
|
+
|
|
|
+ /* initialize time to 0.0 */
|
|
|
+ time=0.0;
|
|
|
+
|
|
|
+ /* initialize event list */
|
|
|
+ generate_next_arrival();
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************/
|
|
|
+/* jimsrand(): return a float in range [0,1]. The routine below is used to */
|
|
|
+/* isolate all random number generation in one location. We assume that the*/
|
|
|
+/* system-supplied rand() function return an int in therange [0,mmm] */
|
|
|
+/****************************************************************************/
|
|
|
+float jimsrand() {
|
|
|
+
|
|
|
+ /* largest int - MACHINE DEPENDENT!!!!!!!! */
|
|
|
+ double mmm = 2147483647;
|
|
|
+
|
|
|
+ /* individual students may need to change mmm */
|
|
|
+ float x;
|
|
|
+
|
|
|
+ /* x should be uniform in [0,1] */
|
|
|
+ x = rand() / mmm;
|
|
|
+
|
|
|
+ return(x);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/********************* EVENT HANDLINE ROUTINES *******/
|
|
|
+/* The next set of routines handle the event list */
|
|
|
+/*****************************************************/
|
|
|
+
|
|
|
+void generate_next_arrival()
|
|
|
+{
|
|
|
+ double x, log(), ceil();
|
|
|
+ event_t *evptr;
|
|
|
+
|
|
|
+ if ( TRACE > 2 )
|
|
|
+ printf(" GENERATE NEXT ARRIVAL: creating new arrival\n");
|
|
|
+
|
|
|
+ /* x is uniform on [0,2*lambda] */
|
|
|
+ x = lambda * jimsrand()*2;
|
|
|
+ /* having mean of lambda */
|
|
|
+
|
|
|
+ evptr = (event_t *)malloc(sizeof(event_t));
|
|
|
+
|
|
|
+ evptr->evtime = time + x;
|
|
|
+ evptr->evtype = FROM_LAYER5;
|
|
|
+
|
|
|
+ if (BIDIRECTIONAL && (jimsrand()>0.5) )
|
|
|
+ evptr->eventity = B;
|
|
|
+ else
|
|
|
+ evptr->eventity = A;
|
|
|
+
|
|
|
+ insertevent(evptr);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void insertevent( event_t *p ) {
|
|
|
+ event_t *q,*qold;
|
|
|
+
|
|
|
+ if ( TRACE > 2 ) {
|
|
|
+ printf(" INSERTEVENT: time is %f\n",time);
|
|
|
+ printf(" INSERTEVENT: future time will be %f\n",p->evtime);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* q points to header of list in which p struct inserted */
|
|
|
+ q = evlist;
|
|
|
+
|
|
|
+ if ( q == NULL ) {
|
|
|
+
|
|
|
+ /* list is empty */
|
|
|
+ evlist=p;
|
|
|
+ p->next=NULL;
|
|
|
+ p->prev=NULL;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ for ( qold = q; q != NULL && p->evtime > q->evtime; q = q->next )
|
|
|
+ qold=q;
|
|
|
+
|
|
|
+ if ( q == NULL ) {
|
|
|
+
|
|
|
+ /* end of list */
|
|
|
+ qold->next = p;
|
|
|
+ p->prev = qold;
|
|
|
+ p->next = NULL;
|
|
|
+
|
|
|
+ } else if ( q == evlist ) {
|
|
|
+
|
|
|
+ /* front of list */
|
|
|
+ p->next=evlist;
|
|
|
+ p->prev=NULL;
|
|
|
+ p->next->prev=p;
|
|
|
+ evlist = p;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ /* middle of list */
|
|
|
+ p->next=q;
|
|
|
+ p->prev=q->prev;
|
|
|
+ q->prev->next=p;
|
|
|
+ q->prev=p;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void printevlist()
|
|
|
+{
|
|
|
+ event_t *q;
|
|
|
+
|
|
|
+ printf("--------------\nEvent List Follows:\n");
|
|
|
+
|
|
|
+ for(q = evlist; q!=NULL; q=q->next)
|
|
|
+ printf("Event time: %f, type: %d entity: %d\n",q->evtime,q->evtype,q->eventity);
|
|
|
+
|
|
|
+ printf("--------------\n");
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/********************** Student-callable ROUTINES ***********************/
|
|
|
+
|
|
|
+/* called by students routine to cancel a previously-started timer */
|
|
|
+void stoptimer(int AorB) {
|
|
|
+
|
|
|
+ event_t *q;
|
|
|
+
|
|
|
+ if ( TRACE > 2 )
|
|
|
+ printf(" STOP TIMER: stopping timer at %f\n",time);
|
|
|
+
|
|
|
+ /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */
|
|
|
+ for ( q = evlist; q != NULL; q = q->next )
|
|
|
+ if ( ( q->evtype == TIMER_INTERRUPT && q->eventity == AorB ) ) {
|
|
|
+
|
|
|
+ /* remove this event */
|
|
|
+ if (q->next==NULL && q->prev==NULL) {
|
|
|
+ /* remove first and only event on list */
|
|
|
+ evlist = NULL;
|
|
|
+ } else if ( q->next == NULL ) {
|
|
|
+ /* end of list - there is one in front */
|
|
|
+ q->prev->next = NULL;
|
|
|
+ } else if ( q== evlist ) {
|
|
|
+ /* front of list - there must be event after */
|
|
|
+ q->next->prev = NULL;
|
|
|
+ evlist = q->next;
|
|
|
+ } else {
|
|
|
+ /* middle of list */
|
|
|
+ q->next->prev = q->prev;
|
|
|
+ q->prev->next = q->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ free(q);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ printf("Warning: unable to cancel your timer. It wasn't running.\n");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void starttimer( int AorB, float increment ) {
|
|
|
+
|
|
|
+ event_t *q;
|
|
|
+ event_t *evptr;
|
|
|
+
|
|
|
+ if ( TRACE > 2 )
|
|
|
+ printf(" START TIMER: starting timer at %f\n",time);
|
|
|
+
|
|
|
+ /* be nice: check to see if timer is already started, if so, then warn */
|
|
|
+ /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */
|
|
|
+
|
|
|
+ for ( q = evlist; q != NULL; q = q->next )
|
|
|
+ if ( ( q->evtype == TIMER_INTERRUPT && q->eventity == AorB ) ) {
|
|
|
+ printf("Warning: attempt to start a timer that is already started\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* create future event for when timer goes off */
|
|
|
+ evptr = (event_t *) malloc( sizeof( event_t ) );
|
|
|
+ evptr->evtime = time + increment;
|
|
|
+ evptr->evtype = TIMER_INTERRUPT;
|
|
|
+ evptr->eventity = AorB;
|
|
|
+
|
|
|
+ insertevent(evptr);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/************************** TOLAYER3 ***************/
|
|
|
+/* A or B is trying to stop timer*/
|
|
|
+void tolayer3( int AorB, pkt_t packet ) {
|
|
|
+ pkt_t *mypktptr;
|
|
|
+ event_t *evptr,*q;
|
|
|
+ float lastime, x, jimsrand();
|
|
|
+ int i;
|
|
|
+
|
|
|
+ ntolayer3++;
|
|
|
+
|
|
|
+ /* simulate losses: */
|
|
|
+ if (jimsrand() < lossprob) {
|
|
|
+ nlost++;
|
|
|
+
|
|
|
+ if ( TRACE > 0 )
|
|
|
+ printf(" TOLAYER3: packet being lost\n");
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* make a copy of the packet student just gave me since he/she may decide */
|
|
|
+ /* to do something with the packet after we return back to him/her */
|
|
|
+ mypktptr = (pkt_t *)malloc(sizeof(pkt_t));
|
|
|
+ mypktptr->seqnum = packet.seqnum;
|
|
|
+ mypktptr->acknum = packet.acknum;
|
|
|
+ mypktptr->checksum = packet.checksum;
|
|
|
+
|
|
|
+ for ( i = 0; i < 20; i++ )
|
|
|
+ mypktptr->payload[i] = packet.payload[i];
|
|
|
+
|
|
|
+ if ( TRACE > 2 ) {
|
|
|
+ printf(" TOLAYER3: seq: %d, ack %d, check: %d ", mypktptr->seqnum,
|
|
|
+
|
|
|
+ mypktptr->acknum, mypktptr->checksum);
|
|
|
+
|
|
|
+ for ( i = 0; i < 20; i++ )
|
|
|
+ printf( "%c", mypktptr->payload[i] );
|
|
|
+
|
|
|
+ printf("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* create future event for arrival of packet at the other side */
|
|
|
+ evptr = (event_t *)malloc(sizeof(event_t));
|
|
|
+ evptr->evtype = FROM_LAYER3; /* packet will pop out from layer3 */
|
|
|
+ evptr->eventity = (AorB+1) % 2; /* event occurs at other entity */
|
|
|
+ evptr->pktptr = mypktptr; /* save ptr to my copy of packet */
|
|
|
+
|
|
|
+ /* finally, compute the arrival time of packet at the other end.
|
|
|
+ medium can not reorder, so make sure packet arrives between 1 and 10
|
|
|
+ time units after the latest arrival time of packets
|
|
|
+ currently in the medium on their way to the destination */
|
|
|
+ lastime = time;
|
|
|
+
|
|
|
+ /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */
|
|
|
+ for ( q = evlist; q != NULL; q = q->next )
|
|
|
+ if ( ( q->evtype == FROM_LAYER3 && q->eventity == evptr->eventity ) )
|
|
|
+ lastime = q->evtime;
|
|
|
+
|
|
|
+ evptr->evtime = lastime + 1 + 9*jimsrand();
|
|
|
+
|
|
|
+ /* simulate corruption: */
|
|
|
+ if (jimsrand() < corruptprob) {
|
|
|
+
|
|
|
+ ncorrupt++;
|
|
|
+
|
|
|
+ if ( (x = jimsrand()) < .75) /* corrupt payload */
|
|
|
+ mypktptr->payload[0]='Z';
|
|
|
+ else if (x < .875)
|
|
|
+ mypktptr->seqnum = 999999;
|
|
|
+ else
|
|
|
+ mypktptr->acknum = 999999;
|
|
|
+
|
|
|
+ if ( TRACE > 0 )
|
|
|
+ printf(" TOLAYER3: packet being corrupted\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( TRACE > 2 )
|
|
|
+ printf(" TOLAYER3: scheduling arrival on other side\n");
|
|
|
+
|
|
|
+ insertevent(evptr);
|
|
|
+}
|
|
|
+
|
|
|
+void tolayer5(int AorB, char datasent[20]) {
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (TRACE>2) {
|
|
|
+ printf(" TOLAYER5: data received: ");
|
|
|
+
|
|
|
+ for ( i = 0; i < 20; i++ )
|
|
|
+ printf("%c",datasent[i]);
|
|
|
+
|
|
|
+ printf("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+}
|