├── .gitignore ├── ICMP Pinger └── ping.py ├── Implementing a Reliable Transport Protocol ├── Alternating-Bit-Protocol Version │ └── prog2.c └── Go-Back-N version │ └── prog2.c ├── Implementing an Algorithm ├── node0.c ├── node1.c ├── node2.c ├── node3.c └── prog3.c ├── README.md ├── SMTP └── smtp.py ├── Traceroute └── traceroute.py ├── UDP ├── Client.py └── Server.py └── handout ├── GettingStarted.pdf ├── Socket1_WebServer.pdf ├── Socket2_UDPpinger.pdf ├── Socket3_SMTP.pdf ├── Socket4_ProxyServer.pdf ├── Socket5_ICMPpinger(chap4).pdf ├── Socket6_VideoStreaming(chap7).pdf └── Traceroute (Chapter 4) .pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /ICMP Pinger/ping.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | import os 3 | import sys 4 | import struct 5 | import time 6 | import select 7 | import binascii 8 | 9 | ICMP_ECHO_REQUEST = 8 10 | 11 | def checksum(str): 12 | csum = 0 13 | countTo = (len(str) / 2) * 2 # round to even 14 | 15 | count = 0 16 | while count < countTo: 17 | thisVal = ord(str[count+1]) * 256 + ord(str[count]) 18 | csum = csum + thisVal 19 | csum = csum & 0xffffffffL 20 | count = count + 2 21 | 22 | if countTo < len(str): 23 | csum = csum + ord(str[len(str) - 1]) 24 | csum = csum & 0xffffffffL 25 | 26 | csum = (csum >> 16) + (csum & 0xffff) # convolute first time 27 | csum = csum + (csum >> 16) # convolute second time 28 | answer = ~csum # one's component 29 | answer = answer & 0xffff # get final checksum 30 | answer = answer >> 8 | (answer << 8 & 0xff00)# Convert tp big ending 31 | return answer 32 | 33 | def receiveOnePing(mySocket, ID, timeout, destAddr): 34 | timeLeft = timeout 35 | 36 | while 1: 37 | startedSelect = time.time() 38 | whatReady = select.select([mySocket], [], [], timeLeft) 39 | howLongInSelect = (time.time() - startedSelect) 40 | if whatReady[0] == []: # Timeout 41 | return "Request timed out." 42 | 43 | timeReceived = time.time() 44 | recPacket, addr = mySocket.recvfrom(1024) 45 | 46 | #Fetch the ICMP header from the IP packet 47 | icmpPacket = recPacket[20:] 48 | icmpType, icmpCode, icmpChecksum, icmpID, icmpSeq, icmpTimestamp = struct.unpack('bbHHhd', icmpPacket) 49 | if checksum(icmpPacket) == 0 and icmpType == 0 and icmpCode == 0 and icmpID == ID and icmpSeq == 1: 50 | return time.time() - icmpTimestamp; 51 | 52 | timeLeft = timeLeft - howLongInSelect 53 | if timeLeft <= 0: 54 | return "Request timed out." 55 | 56 | def sendOnePing(mySocket, destAddr, ID): 57 | # Header is type (8), code (8), checksum (16), id (16), sequence (16) 58 | 59 | myChecksum = 0 60 | # Make a dummy header with a 0 checksum. 61 | # struct -- Interpret strings as packed binary data 62 | header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1) 63 | data = struct.pack("d", time.time()) 64 | # Calculate the checksum on the data and the dummy header. 65 | myChecksum = checksum(header + data) 66 | 67 | # Get the right checksum, and put in the header 68 | if sys.platform == 'darwin': 69 | myChecksum = htons(myChecksum) & 0xffff 70 | #Convert 16-bit integers from host to network byte order. 71 | else: 72 | myChecksum = htons(myChecksum) 73 | 74 | header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1) 75 | packet = header + data 76 | 77 | mySocket.sendto(packet, (destAddr, 1)) # AF_INET address must be tuple, not str 78 | #Both LISTS and TUPLES consist of a number of objects 79 | #which can be referenced by their position number within the object 80 | 81 | def doOnePing(destAddr, timeout): 82 | icmp = getprotobyname("icmp") 83 | #SOCK_RAW is a powerful socket type. For more details see: http://sock-raw.org/papers/sock_raw 84 | 85 | #Create Socket here 86 | mySocket = socket(AF_INET, SOCK_RAW, icmp) 87 | 88 | myID = os.getpid() & 0xFFFF #Return the current process i 89 | sendOnePing(mySocket, destAddr, myID) 90 | delay = receiveOnePing(mySocket, myID, timeout, destAddr) 91 | 92 | mySocket.close() 93 | return delay 94 | 95 | def ping(host, timeout=1): 96 | #timeout=1 means: If one second goes by without a reply from the server, 97 | #the client assumes that either the client's ping or the server's pong is lost 98 | dest = gethostbyname(host) 99 | print "Pinging " + dest + " using Python:" 100 | print "" #Send ping requests to a server separated by approximately one second 101 | while 1 : 102 | delay = doOnePing(dest, timeout) 103 | print delay 104 | time.sleep(1)# one second 105 | return delay 106 | 107 | ping("183.136.217.66") -------------------------------------------------------------------------------- /Implementing a Reliable Transport Protocol/Alternating-Bit-Protocol Version/prog2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* ****************************************************************** 4 | ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1 J.F.Kurose 5 | 6 | This code should be used for PA2, unidirectional or bidirectional 7 | data transfer protocols (from A to B. Bidirectional transfer of data 8 | is for extra credit and is not required). Network properties: 9 | - one way network delay averages five time units (longer if there 10 | are other messages in the channel for GBN), but can be larger 11 | - packets can be corrupted (either the header or the data portion) 12 | or lost, according to user-defined probabilities 13 | - packets will be delivered in the order in which they were sent 14 | (although some can be lost). 15 | **********************************************************************/ 16 | 17 | #define BIDIRECTIONAL 0 /* change to 1 if you're doing extra credit */ 18 | /* and write a routine called B_output */ 19 | 20 | /* a "msg" is the data unit passed from layer 5 (teachers code) to layer */ 21 | /* 4 (students' code). It contains the data (characters) to be delivered */ 22 | /* to layer 5 via the students transport level protocol entities. */ 23 | struct msg { 24 | char data[20]; 25 | }; 26 | 27 | /* a packet is the data unit passed from layer 4 (students code) to layer */ 28 | /* 3 (teachers code). Note the pre-defined packet structure, which all */ 29 | /* students must follow. */ 30 | struct pkt { 31 | int seqnum; 32 | int acknum; 33 | int checksum; 34 | char payload[20]; 35 | }; 36 | 37 | /********* STUDENTS WRITE THE NEXT SEVEN ROUTINES *********/ 38 | 39 | #define TIME_OUT 24.0 40 | #define DEBUG 1 41 | 42 | int seq_expect_send; /* Next sequence number of A */ 43 | int seq_expect_recv; /* Next sequence number of B */ 44 | int is_waiting; /* Whether side A is waiting */ 45 | struct pkt waiting_packet; /* Packet hold in A */ 46 | 47 | /* Print payload */ 48 | print_pkt(action, packet) 49 | char *action; 50 | struct pkt packet; 51 | { 52 | printf("%s: ", action); 53 | printf("seq = %d, ack = %d, checksum = %x, ", packet.seqnum, packet.acknum, packet.checksum); 54 | int i; 55 | for (i = 0; i < 20; i++) 56 | putchar(packet.payload[i]); 57 | putchar('\n'); 58 | } 59 | 60 | /* Compute checksum */ 61 | int compute_check_sum(packet) 62 | struct pkt packet; 63 | { 64 | int sum = 0, i = 0; 65 | sum = packet.checksum; 66 | sum += packet.seqnum; 67 | sum += packet.acknum; 68 | sum = (sum >> 16) + (sum & 0xffff); 69 | for (i = 0; i < 20; i += 2) { 70 | sum += (packet.payload[i] << 8) + packet.payload[i+1]; 71 | sum = (sum >> 16) + (sum & 0xffff); 72 | } 73 | sum = (~sum) & 0xffff; 74 | return sum; 75 | } 76 | 77 | /* called from layer 5, passed the data to be sent to other side */ 78 | A_output(message) 79 | struct msg message; 80 | { 81 | /* If A is waiting, ignore the message */ 82 | if (is_waiting) 83 | return; 84 | /* Send packet to B side */ 85 | memcpy(waiting_packet.payload, message.data, sizeof(message.data)); 86 | waiting_packet.seqnum = seq_expect_send; 87 | waiting_packet.checksum = 0; 88 | waiting_packet.checksum = compute_check_sum(waiting_packet); 89 | tolayer3(0, waiting_packet); 90 | starttimer(0, TIME_OUT); 91 | is_waiting = 1; 92 | /* Debug output */ 93 | if (DEBUG) 94 | print_pkt("Sent", waiting_packet); 95 | } 96 | 97 | B_output(message) /* need be completed only for extra credit */ 98 | struct msg message; 99 | { 100 | 101 | } 102 | 103 | /* called from layer 3, when a packet arrives for layer 4 */ 104 | A_input(packet) 105 | struct pkt packet; 106 | { 107 | stoptimer(0); 108 | if (packet.acknum == seq_expect_send) { /* ACK */ 109 | seq_expect_send = 1 - seq_expect_send; 110 | is_waiting = 0; 111 | } else if (packet.acknum == -1) { /* NAK */ 112 | tolayer3(0, waiting_packet); 113 | starttimer(0, TIME_OUT); 114 | } 115 | } 116 | 117 | /* called when A's timer goes off */ 118 | A_timerinterrupt() 119 | { 120 | tolayer3(0, waiting_packet); 121 | starttimer(0, TIME_OUT); 122 | } 123 | 124 | /* the following routine will be called once (only) before any other */ 125 | /* entity A routines are called. You can use it to do any initialization */ 126 | A_init() 127 | { 128 | seq_expect_send = 0; 129 | is_waiting = 0; 130 | } 131 | 132 | 133 | /* Note that with simplex transfer from a-to-B, there is no B_output() */ 134 | 135 | /* called from layer 3, when a packet arrives for layer 4 at B*/ 136 | B_input(packet) 137 | struct pkt packet; 138 | { 139 | if (packet.seqnum == seq_expect_recv) { 140 | /* If corruption occurs, send NAK */ 141 | if (compute_check_sum(packet)) { 142 | struct pkt nakpkt; 143 | nakpkt.acknum = -1; 144 | tolayer3(1, nakpkt); 145 | return; 146 | } 147 | /* Pass data to layer5 */ 148 | struct msg message; 149 | memcpy(message.data, packet.payload, sizeof(packet.payload)); 150 | tolayer5(1, message); 151 | seq_expect_recv = 1 - seq_expect_recv; 152 | /* Debug output */ 153 | if (DEBUG) 154 | print_pkt("Accpeted", packet); 155 | } 156 | /* Send ACK to A side */ 157 | struct pkt ackpkt; 158 | ackpkt.acknum = packet.seqnum; 159 | tolayer3(1, ackpkt); 160 | } 161 | 162 | /* called when B's timer goes off */ 163 | B_timerinterrupt() 164 | { 165 | 166 | } 167 | 168 | /* the following rouytine will be called once (only) before any other */ 169 | /* entity B routines are called. You can use it to do any initialization */ 170 | B_init() 171 | { 172 | seq_expect_recv = 0; 173 | } 174 | 175 | 176 | /***************************************************************** 177 | ***************** NETWORK EMULATION CODE STARTS BELOW *********** 178 | The code below emulates the layer 3 and below network environment: 179 | - emulates the tranmission and delivery (possibly with bit-level corruption 180 | and packet loss) of packets across the layer 3/4 interface 181 | - handles the starting/stopping of a timer, and generates timer 182 | interrupts (resulting in calling students timer handler). 183 | - generates message to be sent (passed from later 5 to 4) 184 | 185 | THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND 186 | THE CODE BELOW. YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY 187 | OF THE DATA STRUCTURES BELOW. If you're interested in how I designed 188 | the emulator, you're welcome to look at the code - but again, you should have 189 | to, and you defeinitely should not have to modify 190 | ******************************************************************/ 191 | 192 | struct event { 193 | float evtime; /* event time */ 194 | int evtype; /* event type code */ 195 | int eventity; /* entity where event occurs */ 196 | struct pkt *pktptr; /* ptr to packet (if any) assoc w/ this event */ 197 | struct event *prev; 198 | struct event *next; 199 | }; 200 | struct event *evlist = NULL; /* the event list */ 201 | 202 | /* possible events: */ 203 | #define TIMER_INTERRUPT 0 204 | #define FROM_LAYER5 1 205 | #define FROM_LAYER3 2 206 | 207 | #define OFF 0 208 | #define ON 1 209 | #define A 0 210 | #define B 1 211 | 212 | 213 | 214 | int TRACE = 1; /* for my debugging */ 215 | int nsim = 0; /* number of messages from 5 to 4 so far */ 216 | int nsimmax = 0; /* number of msgs to generate, then stop */ 217 | float time = 0.000; 218 | float lossprob; /* probability that a packet is dropped */ 219 | float corruptprob; /* probability that one bit is packet is flipped */ 220 | float lambda; /* arrival rate of messages from layer 5 */ 221 | int ntolayer3; /* number sent into layer 3 */ 222 | int nlost; /* number lost in media */ 223 | int ncorrupt; /* number corrupted by media*/ 224 | 225 | main() 226 | { 227 | struct event *eventptr; 228 | struct msg msg2give; 229 | struct pkt pkt2give; 230 | 231 | int i, j; 232 | char c; 233 | 234 | init(); 235 | A_init(); 236 | B_init(); 237 | 238 | while (1) { 239 | eventptr = evlist; /* get next event to simulate */ 240 | if (eventptr == NULL) 241 | goto terminate; 242 | evlist = evlist->next; /* remove this event from event list */ 243 | if (evlist != NULL) 244 | evlist->prev = NULL; 245 | if (TRACE >= 2) { 246 | printf("\nEVENT time: %f,", eventptr->evtime); 247 | printf(" type: %d", eventptr->evtype); 248 | if (eventptr->evtype == 0) 249 | printf(", timerinterrupt "); 250 | else if (eventptr->evtype == 1) 251 | printf(", fromlayer5 "); 252 | else 253 | printf(", fromlayer3 "); 254 | printf(" entity: %d\n", eventptr->eventity); 255 | } 256 | time = eventptr->evtime; /* update time to next event time */ 257 | if (nsim == nsimmax) 258 | break; /* all done with simulation */ 259 | if (eventptr->evtype == FROM_LAYER5 ) { 260 | generate_next_arrival(); /* set up future arrival */ 261 | /* fill in msg to give with string of same letter */ 262 | j = nsim % 26; 263 | for (i = 0; i < 20; i++) 264 | msg2give.data[i] = 97 + j; 265 | if (TRACE > 2) { 266 | printf(" MAINLOOP: data given to student: "); 267 | for (i = 0; i < 20; i++) 268 | printf("%c", msg2give.data[i]); 269 | printf("\n"); 270 | } 271 | nsim++; 272 | if (eventptr->eventity == A) 273 | A_output(msg2give); 274 | else 275 | B_output(msg2give); 276 | } 277 | else if (eventptr->evtype == FROM_LAYER3) { 278 | pkt2give.seqnum = eventptr->pktptr->seqnum; 279 | pkt2give.acknum = eventptr->pktptr->acknum; 280 | pkt2give.checksum = eventptr->pktptr->checksum; 281 | for (i = 0; i < 20; i++) 282 | pkt2give.payload[i] = eventptr->pktptr->payload[i]; 283 | if (eventptr->eventity == A) /* deliver packet by calling */ 284 | A_input(pkt2give); /* appropriate entity */ 285 | else 286 | B_input(pkt2give); 287 | free(eventptr->pktptr); /* free the memory for packet */ 288 | } 289 | else if (eventptr->evtype == TIMER_INTERRUPT) { 290 | if (eventptr->eventity == A) 291 | A_timerinterrupt(); 292 | else 293 | B_timerinterrupt(); 294 | } 295 | else { 296 | printf("INTERNAL PANIC: unknown event type \n"); 297 | } 298 | free(eventptr); 299 | } 300 | 301 | terminate: 302 | printf(" Simulator terminated at time %f\n after sending %d msgs from layer5\n", time, nsim); 303 | } 304 | 305 | 306 | 307 | init() /* initialize the simulator */ 308 | { 309 | int i; 310 | float sum, avg; 311 | float jimsrand(); 312 | 313 | 314 | printf("----- Stop and Wait Network Simulator Version 1.1 -------- \n\n"); 315 | printf("Enter the number of messages to simulate: "); 316 | scanf("%d", &nsimmax); 317 | printf("Enter packet loss probability [enter 0.0 for no loss]:"); 318 | scanf("%f", &lossprob); 319 | printf("Enter packet corruption probability [0.0 for no corruption]:"); 320 | scanf("%f", &corruptprob); 321 | printf("Enter average time between messages from sender's layer5 [ > 0.0]:"); 322 | scanf("%f", &lambda); 323 | printf("Enter TRACE:"); 324 | scanf("%d", &TRACE); 325 | 326 | srand(9999); /* init random number generator */ 327 | sum = 0.0; /* test random number generator for students */ 328 | for (i = 0; i < 1000; i++) 329 | sum = sum + jimsrand(); /* jimsrand() should be uniform in [0,1] */ 330 | avg = sum / 1000.0; 331 | if (avg < 0.25 || avg > 0.75) { 332 | printf("It is likely that random number generation on your machine\n" ); 333 | printf("is different from what this emulator expects. Please take\n"); 334 | printf("a look at the routine jimsrand() in the emulator code. Sorry. \n"); 335 | exit(0); 336 | } 337 | 338 | ntolayer3 = 0; 339 | nlost = 0; 340 | ncorrupt = 0; 341 | 342 | time = 0.0; /* initialize time to 0.0 */ 343 | generate_next_arrival(); /* initialize event list */ 344 | } 345 | 346 | /****************************************************************************/ 347 | /* jimsrand(): return a float in range [0,1]. The routine below is used to */ 348 | /* isolate all random number generation in one location. We assume that the*/ 349 | /* system-supplied rand() function return an int in therange [0,mmm] */ 350 | /****************************************************************************/ 351 | float jimsrand() 352 | { 353 | double mmm = 32767; /* largest int - MACHINE DEPENDENT!!!!!!!! */ 354 | float x; /* individual students may need to change mmm */ 355 | x = rand() / mmm; /* x should be uniform in [0,1] */ 356 | return (x); 357 | } 358 | 359 | /********************* EVENT HANDLINE ROUTINES *******/ 360 | /* The next set of routines handle the event list */ 361 | /*****************************************************/ 362 | 363 | generate_next_arrival() 364 | { 365 | double x, log(), ceil(); 366 | struct event *evptr; 367 | char *malloc(); 368 | float ttime; 369 | int tempint; 370 | 371 | if (TRACE > 2) 372 | printf(" GENERATE NEXT ARRIVAL: creating new arrival\n"); 373 | 374 | x = lambda * jimsrand() * 2; /* x is uniform on [0,2*lambda] */ 375 | /* having mean of lambda */ 376 | evptr = (struct event *)malloc(sizeof(struct event)); 377 | evptr->evtime = time + x; 378 | evptr->evtype = FROM_LAYER5; 379 | if (BIDIRECTIONAL && (jimsrand() > 0.5) ) 380 | evptr->eventity = B; 381 | else 382 | evptr->eventity = A; 383 | insertevent(evptr); 384 | } 385 | 386 | 387 | insertevent(p) 388 | struct event *p; 389 | { 390 | struct event *q, *qold; 391 | 392 | if (TRACE > 2) { 393 | printf(" INSERTEVENT: time is %lf\n", time); 394 | printf(" INSERTEVENT: future time will be %lf\n", p->evtime); 395 | } 396 | q = evlist; /* q points to header of list in which p struct inserted */ 397 | if (q == NULL) { /* list is empty */ 398 | evlist = p; 399 | p->next = NULL; 400 | p->prev = NULL; 401 | } 402 | else { 403 | for (qold = q; q != NULL && p->evtime > q->evtime; q = q->next) 404 | qold = q; 405 | if (q == NULL) { /* end of list */ 406 | qold->next = p; 407 | p->prev = qold; 408 | p->next = NULL; 409 | } 410 | else if (q == evlist) { /* front of list */ 411 | p->next = evlist; 412 | p->prev = NULL; 413 | p->next->prev = p; 414 | evlist = p; 415 | } 416 | else { /* middle of list */ 417 | p->next = q; 418 | p->prev = q->prev; 419 | q->prev->next = p; 420 | q->prev = p; 421 | } 422 | } 423 | } 424 | 425 | printevlist() 426 | { 427 | struct event *q; 428 | int i; 429 | printf("--------------\nEvent List Follows:\n"); 430 | for (q = evlist; q != NULL; q = q->next) { 431 | printf("Event time: %f, type: %d entity: %d\n", q->evtime, q->evtype, q->eventity); 432 | } 433 | printf("--------------\n"); 434 | } 435 | 436 | 437 | 438 | /********************** Student-callable ROUTINES ***********************/ 439 | 440 | /* called by students routine to cancel a previously-started timer */ 441 | stoptimer(AorB) 442 | int AorB; /* A or B is trying to stop timer */ 443 | { 444 | struct event *q, *qold; 445 | 446 | if (TRACE > 2) 447 | printf(" STOP TIMER: stopping timer at %f\n", time); 448 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 449 | for (q = evlist; q != NULL ; q = q->next) 450 | if ( (q->evtype == TIMER_INTERRUPT && q->eventity == AorB) ) { 451 | /* remove this event */ 452 | if (q->next == NULL && q->prev == NULL) 453 | evlist = NULL; /* remove first and only event on list */ 454 | else if (q->next == NULL) /* end of list - there is one in front */ 455 | q->prev->next = NULL; 456 | else if (q == evlist) { /* front of list - there must be event after */ 457 | q->next->prev = NULL; 458 | evlist = q->next; 459 | } 460 | else { /* middle of list */ 461 | q->next->prev = q->prev; 462 | q->prev->next = q->next; 463 | } 464 | free(q); 465 | return; 466 | } 467 | printf("Warning: unable to cancel your timer. It wasn't running.\n"); 468 | } 469 | 470 | 471 | starttimer(AorB, increment) 472 | int AorB; /* A or B is trying to stop timer */ 473 | float increment; 474 | { 475 | 476 | struct event *q; 477 | struct event *evptr; 478 | char *malloc(); 479 | 480 | if (TRACE > 2) 481 | printf(" START TIMER: starting timer at %f\n", time); 482 | /* be nice: check to see if timer is already started, if so, then warn */ 483 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 484 | for (q = evlist; q != NULL ; q = q->next) 485 | if ( (q->evtype == TIMER_INTERRUPT && q->eventity == AorB) ) { 486 | printf("Warning: attempt to start a timer that is already started\n"); 487 | return; 488 | } 489 | 490 | /* create future event for when timer goes off */ 491 | evptr = (struct event *)malloc(sizeof(struct event)); 492 | evptr->evtime = time + increment; 493 | evptr->evtype = TIMER_INTERRUPT; 494 | evptr->eventity = AorB; 495 | insertevent(evptr); 496 | } 497 | 498 | 499 | /************************** TOLAYER3 ***************/ 500 | tolayer3(AorB, packet) 501 | int AorB; /* A or B is trying to stop timer */ 502 | struct pkt packet; 503 | { 504 | struct pkt *mypktptr; 505 | struct event *evptr, *q; 506 | char *malloc(); 507 | float lastime, x, jimsrand(); 508 | int i; 509 | 510 | 511 | ntolayer3++; 512 | 513 | /* simulate losses: */ 514 | if (jimsrand() < lossprob) { 515 | nlost++; 516 | if (TRACE > 0) 517 | printf(" TOLAYER3: packet being lost\n"); 518 | return; 519 | } 520 | 521 | /* make a copy of the packet student just gave me since he/she may decide */ 522 | /* to do something with the packet after we return back to him/her */ 523 | mypktptr = (struct pkt *)malloc(sizeof(struct pkt)); 524 | mypktptr->seqnum = packet.seqnum; 525 | mypktptr->acknum = packet.acknum; 526 | mypktptr->checksum = packet.checksum; 527 | for (i = 0; i < 20; i++) 528 | mypktptr->payload[i] = packet.payload[i]; 529 | if (TRACE > 2) { 530 | printf(" TOLAYER3: seq: %d, ack %d, check: %d ", mypktptr->seqnum, 531 | mypktptr->acknum, mypktptr->checksum); 532 | for (i = 0; i < 20; i++) 533 | printf("%c", mypktptr->payload[i]); 534 | printf("\n"); 535 | } 536 | 537 | /* create future event for arrival of packet at the other side */ 538 | evptr = (struct event *)malloc(sizeof(struct event)); 539 | evptr->evtype = FROM_LAYER3; /* packet will pop out from layer3 */ 540 | evptr->eventity = (AorB + 1) % 2; /* event occurs at other entity */ 541 | evptr->pktptr = mypktptr; /* save ptr to my copy of packet */ 542 | /* finally, compute the arrival time of packet at the other end. 543 | medium can not reorder, so make sure packet arrives between 1 and 10 544 | time units after the latest arrival time of packets 545 | currently in the medium on their way to the destination */ 546 | lastime = time; 547 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 548 | for (q = evlist; q != NULL ; q = q->next) 549 | if ( (q->evtype == FROM_LAYER3 && q->eventity == evptr->eventity) ) 550 | lastime = q->evtime; 551 | evptr->evtime = lastime + 1 + 9 * jimsrand(); 552 | 553 | 554 | 555 | /* simulate corruption: */ 556 | if (jimsrand() < corruptprob) { 557 | ncorrupt++; 558 | if ( (x = jimsrand()) < .75) 559 | mypktptr->payload[0] = 'Z'; /* corrupt payload */ 560 | else if (x < .875) 561 | mypktptr->seqnum = 999999; 562 | else 563 | mypktptr->acknum = 999999; 564 | if (TRACE > 0) 565 | printf(" TOLAYER3: packet being corrupted\n"); 566 | } 567 | 568 | if (TRACE > 2) 569 | printf(" TOLAYER3: scheduling arrival on other side\n"); 570 | insertevent(evptr); 571 | } 572 | 573 | tolayer5(AorB, datasent) 574 | int AorB; 575 | char datasent[20]; 576 | { 577 | int i; 578 | if (TRACE > 2) { 579 | printf(" TOLAYER5: data received: "); 580 | for (i = 0; i < 20; i++) 581 | printf("%c", datasent[i]); 582 | printf("\n"); 583 | } 584 | 585 | } -------------------------------------------------------------------------------- /Implementing a Reliable Transport Protocol/Go-Back-N version/prog2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* ****************************************************************** 4 | ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1 J.F.Kurose 5 | 6 | This code should be used for PA2, unidirectional or bidirectional 7 | data transfer protocols (from A to B. Bidirectional transfer of data 8 | is for extra credit and is not required). Network properties: 9 | - one way network delay averages five time units (longer if there 10 | are other messages in the channel for GBN), but can be larger 11 | - packets can be corrupted (either the header or the data portion) 12 | or lost, according to user-defined probabilities 13 | - packets will be delivered in the order in which they were sent 14 | (although some can be lost). 15 | **********************************************************************/ 16 | 17 | #define BIDIRECTIONAL 1 /* change to 1 if you're doing extra credit */ 18 | /* and write a routine called B_output */ 19 | 20 | /* a "msg" is the data unit passed from layer 5 (teachers code) to layer */ 21 | /* 4 (students' code). It contains the data (characters) to be delivered */ 22 | /* to layer 5 via the students transport level protocol entities. */ 23 | struct msg { 24 | char data[20]; 25 | }; 26 | 27 | /* a packet is the data unit passed from layer 4 (students code) to layer */ 28 | /* 3 (teachers code). Note the pre-defined packet structure, which all */ 29 | /* students must follow. */ 30 | struct pkt { 31 | int seqnum; 32 | int acknum; 33 | int checksum; 34 | char payload[20]; 35 | }; 36 | 37 | /********* STUDENTS WRITE THE NEXT SEVEN ROUTINES *********/ 38 | 39 | #define DEBUG 1 40 | #define POINT 2 41 | #define MAX_SEQ 7 42 | #define MAX_WINDOW (MAX_SEQ+1) 43 | #define MAX_BUF 50 44 | #define TIME_OUT 16.0 45 | #define INC(a) ((a+1)%MAX_WINDOW) 46 | #define DEC(a) ((a+MAX_WINDOW-1)%MAX_WINDOW) 47 | 48 | int expect_ack[POINT]; 49 | int expect_send[POINT]; 50 | int packet_in_buffer[POINT]; 51 | int expect_recv[POINT]; 52 | struct pkt window_buffer[POINT][MAX_WINDOW]; 53 | 54 | /* print packet content */ 55 | print_packet(AorB, action, packet) 56 | char *action; 57 | int AorB; 58 | struct pkt packet; 59 | { 60 | printf("[%d] %s: ", AorB, action); 61 | printf("seq = %d ack = %d checksum = %x ", packet.seqnum, packet.acknum, packet.checksum); 62 | int i; 63 | for (i = 0; i < 20; i++) 64 | putchar(packet.payload[i]); 65 | putchar('\n'); 66 | } 67 | 68 | /* compute checksum */ 69 | int compute_check_sum(packet) 70 | struct pkt packet; 71 | { 72 | int sum = 0, i = 0; 73 | sum = packet.checksum; 74 | sum += packet.seqnum; 75 | sum += packet.acknum; 76 | sum = (sum >> 16) + (sum & 0xffff); 77 | for (i = 0; i < 20; i += 2) { 78 | sum += (packet.payload[i] << 8) + packet.payload[i+1]; 79 | sum = (sum >> 16) + (sum & 0xffff); 80 | } 81 | sum = (~sum) & 0xffff; 82 | return sum; 83 | } 84 | 85 | /* check if a <= b < c circularly */ 86 | int between(a, b, c) 87 | int a, b, c; 88 | { 89 | if ((a <= b && b < c) 90 | || (c < a && a <= b) 91 | || (b < c && c < a)) 92 | return 1; 93 | else 94 | return 0; 95 | } 96 | 97 | /* construct a packet */ 98 | struct pkt construct_packet(AorB, message) 99 | int AorB; 100 | struct msg message; 101 | { 102 | struct pkt packet; 103 | memcpy(packet.payload, message.data, sizeof(message.data)); 104 | packet.seqnum = expect_send[AorB]; 105 | packet.acknum = DEC(expect_recv[AorB]); 106 | packet.checksum = 0; 107 | packet.checksum = compute_check_sum(packet); 108 | window_buffer[AorB][expect_send[AorB]] = packet; 109 | expect_send[AorB] = INC(expect_send[AorB]); 110 | packet_in_buffer[AorB]++; 111 | return packet; 112 | } 113 | 114 | 115 | /* multitimer: 116 | * start a timer for each packet using one timer 117 | */ 118 | float timers_expire[POINT][MAX_WINDOW]; 119 | int timers_seqs[POINT][MAX_WINDOW]; 120 | int timers_seq[POINT] = {0, 0}; 121 | int timers_running[POINT] = {0, 0}; 122 | int timers_head[POINT] = {0, 0}; 123 | int timers_tail[POINT] = {0, 0}; 124 | float time = 0.0; 125 | 126 | /* call this function after the first timer goes off or was be closed */ 127 | interrupt_multitimer(AorB) 128 | int AorB; 129 | { 130 | timers_running[AorB] = 0; 131 | } 132 | 133 | /* start a timer for a packet */ 134 | start_multitimer(AorB, seqnum) 135 | int AorB, seqnum; 136 | { 137 | /* bound check */ 138 | if (timers_head[AorB] == timers_tail[AorB] + 1) { 139 | printf("Warning: you can't create more than %d timers.\n", MAX_WINDOW); 140 | return; 141 | } 142 | if (timers_running[AorB] == 0) { /* if timers isn't running, start the timer right now */ 143 | timers_running[AorB] = 1; 144 | timers_seq[AorB] = seqnum; 145 | starttimer(AorB, TIME_OUT); 146 | } else { /* else, add this timer into the queue */ 147 | timers_expire[AorB][timers_tail[AorB]] = time + TIME_OUT; 148 | timers_seqs[AorB][timers_tail[AorB]] = seqnum; 149 | timers_tail[AorB] = INC(timers_tail[AorB]); 150 | } 151 | } 152 | 153 | /* stop the first timer */ 154 | stop_multitimer(AorB, seqnum) 155 | int AorB, seqnum; 156 | { 157 | /* bound check */ 158 | if (timers_running[AorB] == 0) { 159 | printf("Warning: you are trying to stop a timer isn't running.\n"); 160 | return; 161 | } 162 | /* stop the first timer */ 163 | stoptimer(AorB); 164 | timers_running[AorB] = 0; 165 | /* if there is more timer, run it right now */ 166 | if (timers_head[AorB] != timers_tail[AorB]) { 167 | timers_running[AorB] = 1; 168 | float increment = timers_expire[AorB][timers_head[AorB]] - time; 169 | timers_seq[AorB] = timers_seqs[AorB][timers_head[AorB]]; 170 | timers_head[AorB] = INC(timers_head[AorB]); 171 | starttimer(AorB, increment); 172 | } 173 | } 174 | 175 | 176 | /* queue: 177 | * when message is out of the sender's window, put the messge in queue 178 | */ 179 | int queue_head[POINT] = {0, 0}; 180 | int queue_tail[POINT] = {0, 0}; 181 | struct msg queue_buffer[POINT][MAX_BUF]; 182 | 183 | /* check if queue is empty */ 184 | #define empty(AorB) (queue_head[AorB] == queue_tail[AorB]) 185 | 186 | /* put message in queue */ 187 | push(AorB, message) 188 | int AorB; 189 | struct msg message; 190 | { 191 | /* bound check */ 192 | if (queue_head[AorB] == queue_tail[AorB] + 1) { 193 | printf("Warning: there is no avaliable space in queue.\n"); 194 | return; 195 | } 196 | queue_buffer[AorB][queue_tail[AorB]] = message; 197 | queue_tail[AorB] = INC(queue_tail[AorB]); 198 | } 199 | 200 | /* get messsage out of queue */ 201 | struct msg pop(AorB) 202 | int AorB; 203 | { 204 | /* bound check */ 205 | if (empty(AorB)) { 206 | printf("Warning: no packet in queue.\n"); 207 | return; 208 | } 209 | struct msg message = queue_buffer[AorB][queue_head[AorB]]; 210 | queue_head[AorB] = INC(queue_head[AorB]); 211 | return message; 212 | } 213 | 214 | 215 | /* called from layer 5, passed the data to be sent to other side */ 216 | output(AorB, message) 217 | int AorB; 218 | struct msg message; 219 | { 220 | /* check if msg is in the window */ 221 | if (packet_in_buffer[AorB] < MAX_WINDOW) { 222 | /* construct a packet */ 223 | struct pkt packet = construct_packet(AorB, message); 224 | tolayer3(AorB, packet); 225 | start_multitimer(AorB, packet.seqnum); 226 | /* debug output */ 227 | if (DEBUG) 228 | print_packet(AorB, "Send", packet); 229 | } else { 230 | push(AorB, message); 231 | } 232 | } 233 | 234 | /* called from layer 3, when a packet arrives for layer 4 */ 235 | input(AorB, packet) 236 | int AorB; 237 | struct pkt packet; 238 | { 239 | /* if (DEBUG) 240 | print_packet("Recieved", packet);*/ 241 | if (compute_check_sum(packet) == 0 && expect_recv[AorB] == packet.seqnum) { 242 | /* pass data to layer5 */ 243 | struct msg message; 244 | memcpy(message.data, packet.payload, sizeof(packet.payload)); 245 | tolayer5(AorB, message); 246 | expect_recv[AorB] = INC(expect_recv[AorB]); 247 | /* release ACKed packet */ 248 | while (between(expect_ack[AorB], packet.acknum, expect_send[AorB])) { 249 | /* if (DEBUG) 250 | print_packet(AorB, "Acknowledged", window_buffer[AorB][expect_ack[AorB]]);*/ 251 | expect_ack[AorB] = INC(expect_ack[AorB]); 252 | packet_in_buffer[AorB]--; 253 | stop_multitimer(AorB, expect_ack[AorB]); 254 | } 255 | /* add new packet from queue */ 256 | while (packet_in_buffer[AorB] < MAX_WINDOW && !empty(AorB)) { 257 | struct msg message = pop(AorB); 258 | struct pkt packet = construct_packet(AorB, message); 259 | tolayer3(AorB, packet); 260 | start_multitimer(AorB, packet.seqnum); 261 | /* debug output */ 262 | if (DEBUG) 263 | print_packet(AorB, "Send", AorB, packet); 264 | } 265 | /* debug output */ 266 | if (DEBUG) 267 | print_packet(AorB, "Accepted", packet); 268 | } 269 | } 270 | 271 | /* the following routine will be called once (only) before any other */ 272 | initialize(AorB) 273 | int AorB; 274 | { 275 | packet_in_buffer[AorB] = 0; 276 | expect_send[AorB] = 0; 277 | expect_ack[AorB] = 0; 278 | expect_recv[AorB] = 0; 279 | } 280 | 281 | /* called when A's timer goes off */ 282 | timerinterrupt(AorB) 283 | int AorB; 284 | { 285 | interrupt_multitimer(AorB); 286 | int seqnum; 287 | for (seqnum = expect_ack[AorB]; seqnum != expect_send[AorB]; seqnum = INC(seqnum)) { 288 | if (seqnum != expect_ack[AorB]) 289 | stop_multitimer(AorB, seqnum); 290 | tolayer3(AorB, window_buffer[AorB][seqnum]); 291 | start_multitimer(AorB, seqnum); 292 | /* if (DEBUG) 293 | print_packet(AorB, "Timeout retransmit", window_buffer[AorB][seqnum]);*/ 294 | } 295 | } 296 | 297 | /* called from layer 5, passed the data to be sent to other side */ 298 | A_output(message) 299 | struct msg message; 300 | { 301 | output(0, message); 302 | } 303 | 304 | B_output(message) /* need be completed only for extra credit */ 305 | struct msg message; 306 | { 307 | output(1, message); 308 | } 309 | 310 | /* called from layer 3, when a packet arrives for layer 4 */ 311 | A_input(packet) 312 | struct pkt packet; 313 | { 314 | input(0, packet); 315 | } 316 | 317 | /* called when A's timer goes off */ 318 | A_timerinterrupt() 319 | { 320 | timerinterrupt(0); 321 | } 322 | 323 | /* the following routine will be called once (only) before any other */ 324 | /* entity A routines are called. You can use it to do any initialization */ 325 | A_init() 326 | { 327 | initialize(0); 328 | } 329 | 330 | /* Note that with simplex transfer from a-to-B, there is no B_output() */ 331 | 332 | /* called from layer 3, when a packet arrives for layer 4 at B*/ 333 | B_input(packet) 334 | struct pkt packet; 335 | { 336 | input(1, packet); 337 | } 338 | 339 | /* called when B's timer goes off */ 340 | B_timerinterrupt() 341 | { 342 | timerinterrupt(1); 343 | } 344 | 345 | /* the following rouytine will be called once (only) before any other */ 346 | /* entity B routines are called. You can use it to do any initialization */ 347 | B_init() 348 | { 349 | initialize(1); 350 | } 351 | 352 | 353 | /***************************************************************** 354 | ***************** NETWORK EMULATION CODE STARTS BELOW *********** 355 | The code below emulates the layer 3 and below network environment: 356 | - emulates the tranmission and delivery (possibly with bit-level corruption 357 | and packet loss) of packets across the layer 3/4 interface 358 | - handles the starting/stopping of a timer, and generates timer 359 | interrupts (resulting in calling students timer handler). 360 | - generates message to be sent (passed from later 5 to 4) 361 | 362 | THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND 363 | THE CODE BELOW. YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY 364 | OF THE DATA STRUCTURES BELOW. If you're interested in how I designed 365 | the emulator, you're welcome to look at the code - but again, you should have 366 | to, and you defeinitely should not have to modify 367 | ******************************************************************/ 368 | 369 | struct event { 370 | float evtime; /* event time */ 371 | int evtype; /* event type code */ 372 | int eventity; /* entity where event occurs */ 373 | struct pkt *pktptr; /* ptr to packet (if any) assoc w/ this event */ 374 | struct event *prev; 375 | struct event *next; 376 | }; 377 | struct event *evlist = NULL; /* the event list */ 378 | 379 | /* possible events: */ 380 | #define TIMER_INTERRUPT 0 381 | #define FROM_LAYER5 1 382 | #define FROM_LAYER3 2 383 | 384 | #define OFF 0 385 | #define ON 1 386 | #define A 0 387 | #define B 1 388 | 389 | 390 | 391 | int TRACE = 1; /* for my debugging */ 392 | int nsim = 0; /* number of messages from 5 to 4 so far */ 393 | int nsimmax = 0; /* number of msgs to generate, then stop */ 394 | /*float time = 0.000;*/ 395 | float lossprob; /* probability that a packet is dropped */ 396 | float corruptprob; /* probability that one bit is packet is flipped */ 397 | float lambda; /* arrival rate of messages from layer 5 */ 398 | int ntolayer3; /* number sent into layer 3 */ 399 | int nlost; /* number lost in media */ 400 | int ncorrupt; /* number corrupted by media*/ 401 | 402 | main() 403 | { 404 | struct event *eventptr; 405 | struct msg msg2give; 406 | struct pkt pkt2give; 407 | 408 | int i, j; 409 | char c; 410 | 411 | init(); 412 | A_init(); 413 | B_init(); 414 | 415 | while (1) { 416 | eventptr = evlist; /* get next event to simulate */ 417 | if (eventptr == NULL) 418 | goto terminate; 419 | evlist = evlist->next; /* remove this event from event list */ 420 | if (evlist != NULL) 421 | evlist->prev = NULL; 422 | if (TRACE >= 2) { 423 | printf("\nEVENT time: %f,", eventptr->evtime); 424 | printf(" type: %d", eventptr->evtype); 425 | if (eventptr->evtype == 0) 426 | printf(", timerinterrupt "); 427 | else if (eventptr->evtype == 1) 428 | printf(", fromlayer5 "); 429 | else 430 | printf(", fromlayer3 "); 431 | printf(" entity: %d\n", eventptr->eventity); 432 | } 433 | time = eventptr->evtime; /* update time to next event time */ 434 | if (nsim == nsimmax) 435 | break; /* all done with simulation */ 436 | if (eventptr->evtype == FROM_LAYER5 ) { 437 | generate_next_arrival(); /* set up future arrival */ 438 | /* fill in msg to give with string of same letter */ 439 | j = nsim % 26; 440 | for (i = 0; i < 20; i++) 441 | msg2give.data[i] = 97 + j; 442 | if (TRACE > 2) { 443 | printf(" MAINLOOP: data given to student: "); 444 | for (i = 0; i < 20; i++) 445 | printf("%c", msg2give.data[i]); 446 | printf("\n"); 447 | } 448 | nsim++; 449 | if (eventptr->eventity == A) 450 | A_output(msg2give); 451 | else 452 | B_output(msg2give); 453 | } 454 | else if (eventptr->evtype == FROM_LAYER3) { 455 | pkt2give.seqnum = eventptr->pktptr->seqnum; 456 | pkt2give.acknum = eventptr->pktptr->acknum; 457 | pkt2give.checksum = eventptr->pktptr->checksum; 458 | for (i = 0; i < 20; i++) 459 | pkt2give.payload[i] = eventptr->pktptr->payload[i]; 460 | if (eventptr->eventity == A) /* deliver packet by calling */ 461 | A_input(pkt2give); /* appropriate entity */ 462 | else 463 | B_input(pkt2give); 464 | free(eventptr->pktptr); /* free the memory for packet */ 465 | } 466 | else if (eventptr->evtype == TIMER_INTERRUPT) { 467 | if (eventptr->eventity == A) 468 | A_timerinterrupt(); 469 | else 470 | B_timerinterrupt(); 471 | } 472 | else { 473 | printf("INTERNAL PANIC: unknown event type \n"); 474 | } 475 | free(eventptr); 476 | } 477 | 478 | terminate: 479 | printf(" Simulator terminated at time %f\n after sending %d msgs from layer5\n", time, nsim); 480 | } 481 | 482 | 483 | 484 | init() /* initialize the simulator */ 485 | { 486 | int i; 487 | float sum, avg; 488 | float jimsrand(); 489 | 490 | 491 | printf("----- Stop and Wait Network Simulator Version 1.1 -------- \n\n"); 492 | printf("Enter the number of messages to simulate: "); 493 | scanf("%d", &nsimmax); 494 | printf("Enter packet loss probability [enter 0.0 for no loss]:"); 495 | scanf("%f", &lossprob); 496 | printf("Enter packet corruption probability [0.0 for no corruption]:"); 497 | scanf("%f", &corruptprob); 498 | printf("Enter average time between messages from sender's layer5 [ > 0.0]:"); 499 | scanf("%f", &lambda); 500 | printf("Enter TRACE:"); 501 | scanf("%d", &TRACE); 502 | 503 | srand(9999); /* init random number generator */ 504 | sum = 0.0; /* test random number generator for students */ 505 | for (i = 0; i < 1000; i++) 506 | sum = sum + jimsrand(); /* jimsrand() should be uniform in [0,1] */ 507 | avg = sum / 1000.0; 508 | if (avg < 0.25 || avg > 0.75) { 509 | printf("It is likely that random number generation on your machine\n" ); 510 | printf("is different from what this emulator expects. Please take\n"); 511 | printf("a look at the routine jimsrand() in the emulator code. Sorry. \n"); 512 | exit(0); 513 | } 514 | 515 | ntolayer3 = 0; 516 | nlost = 0; 517 | ncorrupt = 0; 518 | 519 | time = 0.0; /* initialize time to 0.0 */ 520 | generate_next_arrival(); /* initialize event list */ 521 | } 522 | 523 | /****************************************************************************/ 524 | /* jimsrand(): return a float in range [0,1]. The routine below is used to */ 525 | /* isolate all random number generation in one location. We assume that the*/ 526 | /* system-supplied rand() function return an int in therange [0,mmm] */ 527 | /****************************************************************************/ 528 | float jimsrand() 529 | { 530 | double mmm = 32767; /* largest int - MACHINE DEPENDENT!!!!!!!! */ 531 | float x; /* individual students may need to change mmm */ 532 | x = rand() / mmm; /* x should be uniform in [0,1] */ 533 | return (x); 534 | } 535 | 536 | /********************* EVENT HANDLINE ROUTINES *******/ 537 | /* The next set of routines handle the event list */ 538 | /*****************************************************/ 539 | 540 | generate_next_arrival() 541 | { 542 | double x, log(), ceil(); 543 | struct event *evptr; 544 | char *malloc(); 545 | float ttime; 546 | int tempint; 547 | 548 | if (TRACE > 2) 549 | printf(" GENERATE NEXT ARRIVAL: creating new arrival\n"); 550 | 551 | x = lambda * jimsrand() * 2; /* x is uniform on [0,2*lambda] */ 552 | /* having mean of lambda */ 553 | evptr = (struct event *)malloc(sizeof(struct event)); 554 | evptr->evtime = time + x; 555 | evptr->evtype = FROM_LAYER5; 556 | if (BIDIRECTIONAL && (jimsrand() > 0.5) ) 557 | evptr->eventity = B; 558 | else 559 | evptr->eventity = A; 560 | insertevent(evptr); 561 | } 562 | 563 | 564 | insertevent(p) 565 | struct event *p; 566 | { 567 | struct event *q, *qold; 568 | 569 | if (TRACE > 2) { 570 | printf(" INSERTEVENT: time is %lf\n", time); 571 | printf(" INSERTEVENT: future time will be %lf\n", p->evtime); 572 | } 573 | q = evlist; /* q points to header of list in which p struct inserted */ 574 | if (q == NULL) { /* list is empty */ 575 | evlist = p; 576 | p->next = NULL; 577 | p->prev = NULL; 578 | } 579 | else { 580 | for (qold = q; q != NULL && p->evtime > q->evtime; q = q->next) 581 | qold = q; 582 | if (q == NULL) { /* end of list */ 583 | qold->next = p; 584 | p->prev = qold; 585 | p->next = NULL; 586 | } 587 | else if (q == evlist) { /* front of list */ 588 | p->next = evlist; 589 | p->prev = NULL; 590 | p->next->prev = p; 591 | evlist = p; 592 | } 593 | else { /* middle of list */ 594 | p->next = q; 595 | p->prev = q->prev; 596 | q->prev->next = p; 597 | q->prev = p; 598 | } 599 | } 600 | } 601 | 602 | printevlist() 603 | { 604 | struct event *q; 605 | int i; 606 | printf("--------------\nEvent List Follows:\n"); 607 | for (q = evlist; q != NULL; q = q->next) { 608 | printf("Event time: %f, type: %d entity: %d\n", q->evtime, q->evtype, q->eventity); 609 | } 610 | printf("--------------\n"); 611 | } 612 | 613 | 614 | 615 | /********************** Student-callable ROUTINES ***********************/ 616 | 617 | /* called by students routine to cancel a previously-started timer */ 618 | stoptimer(AorB) 619 | int AorB; /* A or B is trying to stop timer */ 620 | { 621 | struct event *q, *qold; 622 | 623 | if (TRACE > 2) 624 | printf(" STOP TIMER: stopping timer at %f\n", time); 625 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 626 | for (q = evlist; q != NULL ; q = q->next) 627 | if ( (q->evtype == TIMER_INTERRUPT && q->eventity == AorB) ) { 628 | /* remove this event */ 629 | if (q->next == NULL && q->prev == NULL) 630 | evlist = NULL; /* remove first and only event on list */ 631 | else if (q->next == NULL) /* end of list - there is one in front */ 632 | q->prev->next = NULL; 633 | else if (q == evlist) { /* front of list - there must be event after */ 634 | q->next->prev = NULL; 635 | evlist = q->next; 636 | } 637 | else { /* middle of list */ 638 | q->next->prev = q->prev; 639 | q->prev->next = q->next; 640 | } 641 | free(q); 642 | return; 643 | } 644 | printf("Warning: unable to cancel your timer. It wasn't running.\n"); 645 | } 646 | 647 | 648 | starttimer(AorB, increment) 649 | int AorB; /* A or B is trying to stop timer */ 650 | float increment; 651 | { 652 | 653 | struct event *q; 654 | struct event *evptr; 655 | char *malloc(); 656 | 657 | if (TRACE > 2) 658 | printf(" START TIMER: starting timer at %f\n", time); 659 | /* be nice: check to see if timer is already started, if so, then warn */ 660 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 661 | for (q = evlist; q != NULL ; q = q->next) 662 | if ( (q->evtype == TIMER_INTERRUPT && q->eventity == AorB) ) { 663 | printf("Warning: attempt to start a timer that is already started\n"); 664 | return; 665 | } 666 | 667 | /* create future event for when timer goes off */ 668 | evptr = (struct event *)malloc(sizeof(struct event)); 669 | evptr->evtime = time + increment; 670 | evptr->evtype = TIMER_INTERRUPT; 671 | evptr->eventity = AorB; 672 | insertevent(evptr); 673 | } 674 | 675 | 676 | /************************** TOLAYER3 ***************/ 677 | tolayer3(AorB, packet) 678 | int AorB; /* A or B is trying to stop timer */ 679 | struct pkt packet; 680 | { 681 | struct pkt *mypktptr; 682 | struct event *evptr, *q; 683 | char *malloc(); 684 | float lastime, x, jimsrand(); 685 | int i; 686 | 687 | 688 | ntolayer3++; 689 | 690 | /* simulate losses: */ 691 | if (jimsrand() < lossprob) { 692 | nlost++; 693 | if (TRACE > 0) 694 | printf(" TOLAYER3: packet being lost\n"); 695 | return; 696 | } 697 | 698 | /* make a copy of the packet student just gave me since he/she may decide */ 699 | /* to do something with the packet after we return back to him/her */ 700 | mypktptr = (struct pkt *)malloc(sizeof(struct pkt)); 701 | mypktptr->seqnum = packet.seqnum; 702 | mypktptr->acknum = packet.acknum; 703 | mypktptr->checksum = packet.checksum; 704 | for (i = 0; i < 20; i++) 705 | mypktptr->payload[i] = packet.payload[i]; 706 | if (TRACE > 2) { 707 | printf(" TOLAYER3: seq: %d, ack %d, check: %d ", mypktptr->seqnum, 708 | mypktptr->acknum, mypktptr->checksum); 709 | for (i = 0; i < 20; i++) 710 | printf("%c", mypktptr->payload[i]); 711 | printf("\n"); 712 | } 713 | 714 | /* create future event for arrival of packet at the other side */ 715 | evptr = (struct event *)malloc(sizeof(struct event)); 716 | evptr->evtype = FROM_LAYER3; /* packet will pop out from layer3 */ 717 | evptr->eventity = (AorB + 1) % 2; /* event occurs at other entity */ 718 | evptr->pktptr = mypktptr; /* save ptr to my copy of packet */ 719 | /* finally, compute the arrival time of packet at the other end. 720 | medium can not reorder, so make sure packet arrives between 1 and 10 721 | time units after the latest arrival time of packets 722 | currently in the medium on their way to the destination */ 723 | lastime = time; 724 | /* for (q=evlist; q!=NULL && q->next!=NULL; q = q->next) */ 725 | for (q = evlist; q != NULL ; q = q->next) 726 | if ( (q->evtype == FROM_LAYER3 && q->eventity == evptr->eventity) ) 727 | lastime = q->evtime; 728 | evptr->evtime = lastime + 1 + 9 * jimsrand(); 729 | 730 | 731 | 732 | /* simulate corruption: */ 733 | if (jimsrand() < corruptprob) { 734 | ncorrupt++; 735 | if ( (x = jimsrand()) < .75) 736 | mypktptr->payload[0] = 'Z'; /* corrupt payload */ 737 | else if (x < .875) 738 | mypktptr->seqnum = 999999; 739 | else 740 | mypktptr->acknum = 999999; 741 | if (TRACE > 0) 742 | printf(" TOLAYER3: packet being corrupted\n"); 743 | } 744 | 745 | if (TRACE > 2) 746 | printf(" TOLAYER3: scheduling arrival on other side\n"); 747 | insertevent(evptr); 748 | } 749 | 750 | tolayer5(AorB, datasent) 751 | int AorB; 752 | char datasent[20]; 753 | { 754 | int i; 755 | if (TRACE > 2) { 756 | printf(" TOLAYER5: data received: "); 757 | for (i = 0; i < 20; i++) 758 | printf("%c", datasent[i]); 759 | printf("\n"); 760 | } 761 | 762 | } 763 | -------------------------------------------------------------------------------- /Implementing an Algorithm/node0.c: -------------------------------------------------------------------------------- 1 | #define INFINITY 999 2 | #define TOTAL 4 3 | #define ME 0 4 | 5 | static int cost[TOTAL][TOTAL]; /* distance table: cost[i][j] represent the cost to j through i */ 6 | static int routing[TOTAL]; /* rounting table: the best path to node i */ 7 | 8 | /* a rtpkt is the packet sent from one routing update process to 9 | another via the call tolayer3() */ 10 | struct rtpkt { 11 | int sourceid; /* id of sending router sending this pkt */ 12 | int destid; /* id of router to which pkt being sent 13 | (must be an immediate neighbor) */ 14 | int mincost[4]; /* min cost to node 0 ... 3 */ 15 | }; 16 | 17 | /* broadcast: broadcast routing packet to neighbor */ 18 | static broadcast() 19 | { 20 | int i, j; 21 | for (i = 0; i < TOTAL; i++) 22 | if (i != ME && cost[i][i] != INFINITY) { 23 | /* Construct routing packets */ 24 | struct rtpkt packet; 25 | packet.sourceid = ME; 26 | packet.destid = i; 27 | for (j = 0; j < TOTAL; j++) 28 | packet.mincost[j] = cost[routing[j]][j]; 29 | /* Send packet */ 30 | tolayer2(packet); 31 | } 32 | } 33 | 34 | printdt0() 35 | { 36 | int i, j; 37 | printf("The distance table of node %d:\n", ME); 38 | for (i = 0; i < TOTAL; i++) { 39 | for (j = 0; j < TOTAL; j++) 40 | printf("%4d", cost[i][j]); 41 | printf("\n"); 42 | } 43 | } 44 | 45 | rtinit0() 46 | { 47 | int i, j; 48 | /* Init distance table */ 49 | for (i = 0; i < TOTAL; i++) 50 | for (j = 0; j < TOTAL; j++) 51 | cost[i][j] = INFINITY; 52 | /* Init routing table */ 53 | for (i = 0; i < TOTAL; i++) 54 | routing[i] = i; 55 | /* Count costs to neighbor */ 56 | cost[ME][ME] = 0; 57 | cost[1][1] = 1; 58 | cost[2][2] = 3; 59 | cost[3][3] = 7; 60 | /* Broadcast */ 61 | broadcast(); 62 | } 63 | 64 | rtupdate0(rcvdpkt) 65 | struct rtpkt *rcvdpkt; 66 | { 67 | int i, j, source = rcvdpkt->sourceid, changed = 0; 68 | for (i = 0; i < TOTAL; i++) { 69 | /* Compute new cost */ 70 | int new_cost = cost[source][source] + rcvdpkt->mincost[i]; 71 | /* Save old cost */ 72 | int old_cost = cost[routing[i]][i]; 73 | /* Update distance table */ 74 | cost[source][i] = new_cost; 75 | /* Update routing table */ 76 | if (new_cost < old_cost) { 77 | changed = 1; 78 | routing[i] = source; 79 | } else if (routing[i] == source && new_cost > old_cost) { 80 | /* Find the best path */ 81 | int best = source; 82 | for (j = 0; j < TOTAL; j++) 83 | if (j != ME && cost[j][i] < cost[best][i]) 84 | best = j; 85 | changed = 1; 86 | routing[i] = best; 87 | } 88 | } 89 | /* If rouitng table changed, notify neighbors */ 90 | if (changed) 91 | broadcast(); 92 | } 93 | 94 | linkhandler0(linkid, newcost) 95 | int linkid, newcost; 96 | { 97 | /* Update distance table */ 98 | int cost_diff = newcost - cost[linkid][linkid], i, j; 99 | for (i = 0; i < TOTAL; i++) 100 | cost[linkid][i] += cost_diff; 101 | cost[linkid][ME] += cost_diff; 102 | /* Rebuild routing table */ 103 | for (i = 0; i < TOTAL; i++) 104 | /* Path through linkid need to be rebuild */ 105 | if (i != ME && routing[i] == linkid) { 106 | /* Find the best new path */ 107 | int best = linkid; 108 | for (j = 0; j < TOTAL; j++) 109 | if (j != ME && cost[j][i] < cost[best][i]) 110 | best = j; 111 | routing[i] = best; 112 | } 113 | /* Broadcast */ 114 | broadcast(); 115 | } 116 | -------------------------------------------------------------------------------- /Implementing an Algorithm/node1.c: -------------------------------------------------------------------------------- 1 | #define INFINITY 999 2 | #define TOTAL 4 3 | #define ME 1 4 | 5 | static int cost[TOTAL][TOTAL]; /* distance table: cost[i][j] represent the cost to j through i */ 6 | static int routing[TOTAL]; /* rounting table: the best path to node i */ 7 | 8 | /* a rtpkt is the packet sent from one routing update process to 9 | another via the call tolayer3() */ 10 | struct rtpkt { 11 | int sourceid; /* id of sending router sending this pkt */ 12 | int destid; /* id of router to which pkt being sent 13 | (must be an immediate neighbor) */ 14 | int mincost[4]; /* min cost to node 0 ... 3 */ 15 | }; 16 | 17 | /* broadcast: broadcast routing packet to neighbor */ 18 | static broadcast() 19 | { 20 | int i, j; 21 | for (i = 0; i < TOTAL; i++) 22 | if (i != ME && cost[i][i] != INFINITY) { 23 | /* Construct routing packets */ 24 | struct rtpkt packet; 25 | packet.sourceid = ME; 26 | packet.destid = i; 27 | for (j = 0; j < TOTAL; j++) 28 | packet.mincost[j] = cost[routing[j]][j]; 29 | /* Send packet */ 30 | tolayer2(packet); 31 | } 32 | } 33 | 34 | printdt1() 35 | { 36 | int i, j; 37 | printf("The distance table of node %d:\n", ME); 38 | for (i = 0; i < TOTAL; i++) { 39 | for (j = 0; j < TOTAL; j++) 40 | printf("%4d", cost[i][j]); 41 | printf("\n"); 42 | } 43 | } 44 | 45 | rtinit1() 46 | { 47 | int i, j; 48 | /* Init distance table */ 49 | for (i = 0; i < TOTAL; i++) 50 | for (j = 0; j < TOTAL; j++) 51 | cost[i][j] = INFINITY; 52 | /* Init routing table */ 53 | for (i = 0; i < TOTAL; i++) 54 | routing[i] = i; 55 | /* Count costs to neighbor */ 56 | cost[ME][ME] = 0; 57 | cost[0][0] = 1; 58 | cost[2][2] = 1; 59 | /* Broadcast */ 60 | broadcast(); 61 | } 62 | 63 | rtupdate1(rcvdpkt) 64 | struct rtpkt *rcvdpkt; 65 | { 66 | int i, j, source = rcvdpkt->sourceid, changed = 0; 67 | for (i = 0; i < TOTAL; i++) { 68 | /* Compute new cost */ 69 | int new_cost = cost[source][source] + rcvdpkt->mincost[i]; 70 | /* Save old cost */ 71 | int old_cost = cost[routing[i]][i]; 72 | /* Update distance table */ 73 | cost[source][i] = new_cost; 74 | /* Update routing table */ 75 | if (new_cost < old_cost) { 76 | changed = 1; 77 | routing[i] = source; 78 | } else if (routing[i] == source && new_cost > old_cost) { 79 | /* Find the best path */ 80 | int best = source; 81 | for (j = 0; j < TOTAL; j++) 82 | if (j != ME && cost[j][i] < cost[best][i]) 83 | best = j; 84 | changed = 1; 85 | routing[i] = best; 86 | } 87 | } 88 | /* If rouitng table changed, notify neighbors */ 89 | if (changed) 90 | broadcast(); 91 | } 92 | 93 | linkhandler1(linkid, newcost) 94 | int linkid, newcost; 95 | { 96 | /* Update distance table */ 97 | int cost_diff = newcost - cost[linkid][linkid], i, j; 98 | for (i = 0; i < TOTAL; i++) 99 | cost[linkid][i] += cost_diff; 100 | cost[linkid][ME] += cost_diff; 101 | /* Rebuild routing table */ 102 | for (i = 0; i < TOTAL; i++) 103 | /* Path through linkid need to be rebuild */ 104 | if (i != ME && routing[i] == linkid) { 105 | /* Find the best new path */ 106 | int best = linkid; 107 | for (j = 0; j < TOTAL; j++) 108 | if (j != ME && cost[j][i] < cost[best][i]) 109 | best = j; 110 | routing[i] = best; 111 | } 112 | /* Broadcast */ 113 | broadcast(); 114 | } 115 | -------------------------------------------------------------------------------- /Implementing an Algorithm/node2.c: -------------------------------------------------------------------------------- 1 | #define INFINITY 999 2 | #define TOTAL 4 3 | #define ME 2 4 | 5 | static int cost[TOTAL][TOTAL]; /* distance table: cost[i][j] represent the cost to j through i */ 6 | static int routing[TOTAL]; /* rounting table: the best path to node i */ 7 | 8 | /* a rtpkt is the packet sent from one routing update process to 9 | another via the call tolayer3() */ 10 | struct rtpkt { 11 | int sourceid; /* id of sending router sending this pkt */ 12 | int destid; /* id of router to which pkt being sent 13 | (must be an immediate neighbor) */ 14 | int mincost[4]; /* min cost to node 0 ... 3 */ 15 | }; 16 | 17 | /* broadcast: broadcast routing packet to neighbor */ 18 | static broadcast() 19 | { 20 | int i, j; 21 | for (i = 0; i < TOTAL; i++) 22 | if (i != ME && cost[i][i] != INFINITY) { 23 | /* Construct routing packets */ 24 | struct rtpkt packet; 25 | packet.sourceid = ME; 26 | packet.destid = i; 27 | for (j = 0; j < TOTAL; j++) 28 | packet.mincost[j] = cost[routing[j]][j]; 29 | /* Send packet */ 30 | tolayer2(packet); 31 | } 32 | } 33 | 34 | printdt2() 35 | { 36 | int i, j; 37 | printf("The distance table of node %d:\n", ME); 38 | for (i = 0; i < TOTAL; i++) { 39 | for (j = 0; j < TOTAL; j++) 40 | printf("%4d", cost[i][j]); 41 | printf("\n"); 42 | } 43 | } 44 | 45 | rtinit2() 46 | { 47 | int i, j; 48 | /* Init distance table */ 49 | for (i = 0; i < TOTAL; i++) 50 | for (j = 0; j < TOTAL; j++) 51 | cost[i][j] = INFINITY; 52 | /* Init routing table */ 53 | for (i = 0; i < TOTAL; i++) 54 | routing[i] = i; 55 | /* Count costs to neighbor */ 56 | cost[ME][ME] = 0; 57 | cost[0][0] = 3; 58 | cost[1][1] = 1; 59 | cost[3][3] = 2; 60 | /* Broadcast */ 61 | broadcast(); 62 | } 63 | 64 | rtupdate2(rcvdpkt) 65 | struct rtpkt *rcvdpkt; 66 | { 67 | int i, j, source = rcvdpkt->sourceid, changed = 0; 68 | for (i = 0; i < TOTAL; i++) { 69 | /* Compute new cost */ 70 | int new_cost = cost[source][source] + rcvdpkt->mincost[i]; 71 | /* Save old cost */ 72 | int old_cost = cost[routing[i]][i]; 73 | /* Update distance table */ 74 | cost[source][i] = new_cost; 75 | /* Update routing table */ 76 | if (new_cost < old_cost) { 77 | changed = 1; 78 | routing[i] = source; 79 | } else if (routing[i] == source && new_cost > old_cost) { 80 | /* Find the best path */ 81 | int best = source; 82 | for (j = 0; j < TOTAL; j++) 83 | if (j != ME && cost[j][i] < cost[best][i]) 84 | best = j; 85 | changed = 1; 86 | routing[i] = best; 87 | } 88 | } 89 | /* If rouitng table changed, notify neighbors */ 90 | if (changed) 91 | broadcast(); 92 | } -------------------------------------------------------------------------------- /Implementing an Algorithm/node3.c: -------------------------------------------------------------------------------- 1 | #define INFINITY 999 2 | #define TOTAL 4 3 | #define ME 3 4 | 5 | static int cost[TOTAL][TOTAL]; /* distance table: cost[i][j] represent the cost to j through i */ 6 | static int routing[TOTAL]; /* rounting table: the best path to node i */ 7 | 8 | /* a rtpkt is the packet sent from one routing update process to 9 | another via the call tolayer3() */ 10 | struct rtpkt { 11 | int sourceid; /* id of sending router sending this pkt */ 12 | int destid; /* id of router to which pkt being sent 13 | (must be an immediate neighbor) */ 14 | int mincost[4]; /* min cost to node 0 ... 3 */ 15 | }; 16 | 17 | /* broadcast: broadcast routing packet to neighbor */ 18 | static broadcast() 19 | { 20 | int i, j; 21 | for (i = 0; i < TOTAL; i++) 22 | if (i != ME && cost[i][i] != INFINITY) { 23 | /* Construct routing packets */ 24 | struct rtpkt packet; 25 | packet.sourceid = ME; 26 | packet.destid = i; 27 | for (j = 0; j < TOTAL; j++) 28 | packet.mincost[j] = cost[routing[j]][j]; 29 | /* Send packet */ 30 | tolayer2(packet); 31 | } 32 | } 33 | 34 | printdt3() 35 | { 36 | int i, j; 37 | printf("The distance table of node %d:\n", ME); 38 | for (i = 0; i < TOTAL; i++) { 39 | for (j = 0; j < TOTAL; j++) 40 | printf("%4d", cost[i][j]); 41 | printf("\n"); 42 | } 43 | } 44 | 45 | rtinit3() 46 | { 47 | int i, j; 48 | /* Init distance table */ 49 | for (i = 0; i < TOTAL; i++) 50 | for (j = 0; j < TOTAL; j++) 51 | cost[i][j] = INFINITY; 52 | /* Init routing table */ 53 | for (i = 0; i < TOTAL; i++) 54 | routing[i] = i; 55 | /* Count costs to neighbor */ 56 | cost[ME][ME] = 0; 57 | cost[0][0] = 7; 58 | cost[2][2] = 2; 59 | /* Broadcast */ 60 | broadcast(); 61 | } 62 | 63 | rtupdate3(rcvdpkt) 64 | struct rtpkt *rcvdpkt; 65 | { 66 | int i, j, source = rcvdpkt->sourceid, changed = 0; 67 | for (i = 0; i < TOTAL; i++) { 68 | /* Compute new cost */ 69 | int new_cost = cost[source][source] + rcvdpkt->mincost[i]; 70 | /* Save old cost */ 71 | int old_cost = cost[routing[i]][i]; 72 | /* Update distance table */ 73 | cost[source][i] = new_cost; 74 | /* Update routing table */ 75 | if (new_cost < old_cost) { 76 | changed = 1; 77 | routing[i] = source; 78 | } else if (routing[i] == source && new_cost > old_cost) { 79 | /* Find the best path */ 80 | int best = source; 81 | for (j = 0; j < TOTAL; j++) 82 | if (j != ME && cost[j][i] < cost[best][i]) 83 | best = j; 84 | changed = 1; 85 | routing[i] = best; 86 | } 87 | } 88 | /* If rouitng table changed, notify neighbors */ 89 | if (changed) 90 | broadcast(); 91 | } -------------------------------------------------------------------------------- /Implementing an Algorithm/prog3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LINKCHANGES 1 4 | /* ****************************************************************** 5 | Programming assignment 3: implementing distributed, asynchronous, 6 | distance vector routing. 7 | 8 | THIS IS THE MAIN ROUTINE. IT SHOULD NOT BE TOUCHED AT ALL BY STUDENTS! 9 | 10 | **********************************************************************/ 11 | 12 | 13 | /* a rtpkt is the packet sent from one routing update process to 14 | another via the call tolayer3() */ 15 | struct rtpkt { 16 | int sourceid; /* id of sending router sending this pkt */ 17 | int destid; /* id of router to which pkt being sent 18 | (must be an immediate neighbor) */ 19 | int mincost[4]; /* min cost to node 0 ... 3 */ 20 | }; 21 | 22 | int TRACE = 1; /* for my debugging */ 23 | int YES = 1; 24 | int NO = 0; 25 | 26 | creatertpkt( initrtpkt, srcid, destid, mincosts) 27 | struct rtpkt *initrtpkt; 28 | int srcid; 29 | int destid; 30 | int mincosts[]; 31 | 32 | { 33 | int i; 34 | initrtpkt->sourceid = srcid; 35 | initrtpkt->destid = destid; 36 | for (i = 0; i < 4; i++) 37 | initrtpkt->mincost[i] = mincosts[i]; 38 | } 39 | 40 | 41 | /***************************************************************** 42 | ***************** NETWORK EMULATION CODE STARTS BELOW *********** 43 | The code below emulates the layer 2 and below network environment: 44 | - emulates the tranmission and delivery (with no loss and no 45 | corruption) between two physically connected nodes 46 | - calls the initializations routines rtinit0, etc., once before 47 | beginning emulation 48 | 49 | THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND 50 | THE CODE BELOW. YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY 51 | OF THE DATA STRUCTURES BELOW. If you're interested in how I designed 52 | the emulator, you're welcome to look at the code - but again, you should have 53 | to, and you defeinitely should not have to modify 54 | ******************************************************************/ 55 | 56 | struct event { 57 | float evtime; /* event time */ 58 | int evtype; /* event type code */ 59 | int eventity; /* entity where event occurs */ 60 | struct rtpkt *rtpktptr; /* ptr to packet (if any) assoc w/ this event */ 61 | struct event *prev; 62 | struct event *next; 63 | }; 64 | struct event *evlist = NULL; /* the event list */ 65 | 66 | /* possible events: */ 67 | #define FROM_LAYER2 2 68 | #define LINK_CHANGE 10 69 | 70 | float clocktime = 0.000; 71 | 72 | 73 | main() 74 | { 75 | struct event *eventptr; 76 | 77 | init(); 78 | 79 | while (1) { 80 | 81 | eventptr = evlist; /* get next event to simulate */ 82 | if (eventptr == NULL) 83 | goto terminate; 84 | evlist = evlist->next; /* remove this event from event list */ 85 | if (evlist != NULL) 86 | evlist->prev = NULL; 87 | if (TRACE > 1) { 88 | printf("MAIN: rcv event, t=%.3f, at %d", 89 | eventptr->evtime, eventptr->eventity); 90 | if (eventptr->evtype == FROM_LAYER2 ) { 91 | printf(" src:%2d,", eventptr->rtpktptr->sourceid); 92 | printf(" dest:%2d,", eventptr->rtpktptr->destid); 93 | printf(" contents: %3d %3d %3d %3d\n", 94 | eventptr->rtpktptr->mincost[0], eventptr->rtpktptr->mincost[1], 95 | eventptr->rtpktptr->mincost[2], eventptr->rtpktptr->mincost[3]); 96 | } 97 | } 98 | clocktime = eventptr->evtime; /* update time to next event time */ 99 | if (eventptr->evtype == FROM_LAYER2 ) { 100 | if (eventptr->eventity == 0) 101 | rtupdate0(eventptr->rtpktptr); 102 | else if (eventptr->eventity == 1) 103 | rtupdate1(eventptr->rtpktptr); 104 | else if (eventptr->eventity == 2) 105 | rtupdate2(eventptr->rtpktptr); 106 | else if (eventptr->eventity == 3) 107 | rtupdate3(eventptr->rtpktptr); 108 | else { printf("Panic: unknown event entity\n"); exit(0); } 109 | } 110 | else if (eventptr->evtype == LINK_CHANGE ) { 111 | if (clocktime < 10001.0) { 112 | linkhandler0(1, 20); 113 | linkhandler1(0, 20); 114 | } 115 | else { 116 | linkhandler0(1, 1); 117 | linkhandler1(0, 1); 118 | } 119 | } 120 | else 121 | { printf("Panic: unknown event type\n"); exit(0); } 122 | if (eventptr->evtype == FROM_LAYER2 ) 123 | free(eventptr->rtpktptr); /* free memory for packet, if any */ 124 | free(eventptr); /* free memory for event struct */ 125 | } 126 | 127 | 128 | terminate: 129 | printf("\nSimulator terminated at t=%f, no packets in medium\n", clocktime); 130 | } 131 | 132 | 133 | 134 | init() /* initialize the simulator */ 135 | { 136 | int i; 137 | float sum, avg; 138 | float jimsrand(); 139 | struct event *evptr; 140 | 141 | printf("Enter TRACE:"); 142 | scanf("%d", &TRACE); 143 | 144 | srand(9999); /* init random number generator */ 145 | sum = 0.0; /* test random number generator for students */ 146 | for (i = 0; i < 1000; i++) 147 | sum = sum + jimsrand(); /* jimsrand() should be uniform in [0,1] */ 148 | avg = sum / 1000.0; 149 | if (avg < 0.25 || avg > 0.75) { 150 | printf("It is likely that random number generation on your machine\n" ); 151 | printf("is different from what this emulator expects. Please take\n"); 152 | printf("a look at the routine jimsrand() in the emulator code. Sorry. \n"); 153 | exit(0); 154 | } 155 | 156 | clocktime = 0.0; /* initialize time to 0.0 */ 157 | rtinit0(); 158 | rtinit1(); 159 | rtinit2(); 160 | rtinit3(); 161 | 162 | /* initialize future link changes */ 163 | if (LINKCHANGES == 1) { 164 | evptr = (struct event *)malloc(sizeof(struct event)); 165 | evptr->evtime = 10000.0; 166 | evptr->evtype = LINK_CHANGE; 167 | evptr->eventity = -1; 168 | evptr->rtpktptr = NULL; 169 | insertevent(evptr); 170 | evptr = (struct event *)malloc(sizeof(struct event)); 171 | evptr->evtype = LINK_CHANGE; 172 | evptr->evtime = 20000.0; 173 | evptr->rtpktptr = NULL; 174 | insertevent(evptr); 175 | } 176 | 177 | } 178 | 179 | /****************************************************************************/ 180 | /* jimsrand(): return a float in range [0,1]. The routine below is used to */ 181 | /* isolate all random number generation in one location. We assume that the*/ 182 | /* system-supplied rand() function return an int in therange [0,mmm] */ 183 | /****************************************************************************/ 184 | float jimsrand() 185 | { 186 | double mmm = 32767; /* largest int - MACHINE DEPENDENT!!!!!!!! */ 187 | float x; /* individual students may need to change mmm */ 188 | x = rand() / mmm; /* x should be uniform in [0,1] */ 189 | return (x); 190 | } 191 | 192 | /********************* EVENT HANDLINE ROUTINES *******/ 193 | /* The next set of routines handle the event list */ 194 | /*****************************************************/ 195 | 196 | 197 | insertevent(p) 198 | struct event *p; 199 | { 200 | struct event *q, *qold; 201 | 202 | if (TRACE > 3) { 203 | printf(" INSERTEVENT: time is %lf\n", clocktime); 204 | printf(" INSERTEVENT: future time will be %lf\n", p->evtime); 205 | } 206 | q = evlist; /* q points to header of list in which p struct inserted */ 207 | if (q == NULL) { /* list is empty */ 208 | evlist = p; 209 | p->next = NULL; 210 | p->prev = NULL; 211 | } 212 | else { 213 | for (qold = q; q != NULL && p->evtime > q->evtime; q = q->next) 214 | qold = q; 215 | if (q == NULL) { /* end of list */ 216 | qold->next = p; 217 | p->prev = qold; 218 | p->next = NULL; 219 | } 220 | else if (q == evlist) { /* front of list */ 221 | p->next = evlist; 222 | p->prev = NULL; 223 | p->next->prev = p; 224 | evlist = p; 225 | } 226 | else { /* middle of list */ 227 | p->next = q; 228 | p->prev = q->prev; 229 | q->prev->next = p; 230 | q->prev = p; 231 | } 232 | } 233 | } 234 | 235 | printevlist() 236 | { 237 | struct event *q; 238 | printf("--------------\nEvent List Follows:\n"); 239 | for (q = evlist; q != NULL; q = q->next) { 240 | printf("Event time: %f, type: %d entity: %d\n", q->evtime, q->evtype, q->eventity); 241 | } 242 | printf("--------------\n"); 243 | } 244 | 245 | 246 | /************************** TOLAYER2 ***************/ 247 | tolayer2(packet) 248 | struct rtpkt packet; 249 | 250 | { 251 | struct rtpkt *mypktptr; 252 | struct event *evptr, *q; 253 | float jimsrand(), lastime; 254 | int i; 255 | 256 | int connectcosts[4][4]; 257 | 258 | /* initialize by hand since not all compilers allow array initilization */ 259 | connectcosts[0][0] = 0; connectcosts[0][1] = 1; connectcosts[0][2] = 3; 260 | connectcosts[0][3] = 7; 261 | connectcosts[1][0] = 1; connectcosts[1][1] = 0; connectcosts[1][2] = 1; 262 | connectcosts[1][3] = 999; 263 | connectcosts[2][0] = 3; connectcosts[2][1] = 1; connectcosts[2][2] = 0; 264 | connectcosts[2][3] = 2; 265 | connectcosts[3][0] = 7; connectcosts[3][1] = 999; connectcosts[3][2] = 2; 266 | connectcosts[3][3] = 0; 267 | 268 | /* be nice: check if source and destination id's are reasonable */ 269 | if (packet.sourceid < 0 || packet.sourceid > 3) { 270 | printf("WARNING: illegal source id in your packet, ignoring packet!\n"); 271 | return; 272 | } 273 | if (packet.destid < 0 || packet.destid > 3) { 274 | printf("WARNING: illegal dest id in your packet, ignoring packet!\n"); 275 | return; 276 | } 277 | if (packet.sourceid == packet.destid) { 278 | printf("WARNING: source and destination id's the same, ignoring packet!\n"); 279 | return; 280 | } 281 | if (connectcosts[packet.sourceid][packet.destid] == 999) { 282 | printf("WARNING: source and destination not connected, ignoring packet!\n"); 283 | return; 284 | } 285 | 286 | /* make a copy of the packet student just gave me since he/she may decide */ 287 | /* to do something with the packet after we return back to him/her */ 288 | mypktptr = (struct rtpkt *) malloc(sizeof(struct rtpkt)); 289 | mypktptr->sourceid = packet.sourceid; 290 | mypktptr->destid = packet.destid; 291 | for (i = 0; i < 4; i++) 292 | mypktptr->mincost[i] = packet.mincost[i]; 293 | if (TRACE > 2) { 294 | printf(" TOLAYER2: source: %d, dest: %d\n costs:", 295 | mypktptr->sourceid, mypktptr->destid); 296 | for (i = 0; i < 4; i++) 297 | printf("%d ", mypktptr->mincost[i]); 298 | printf("\n"); 299 | } 300 | 301 | /* create future event for arrival of packet at the other side */ 302 | evptr = (struct event *)malloc(sizeof(struct event)); 303 | evptr->evtype = FROM_LAYER2; /* packet will pop out from layer3 */ 304 | evptr->eventity = packet.destid; /* event occurs at other entity */ 305 | evptr->rtpktptr = mypktptr; /* save ptr to my copy of packet */ 306 | 307 | /* finally, compute the arrival time of packet at the other end. 308 | medium can not reorder, so make sure packet arrives between 1 and 10 309 | time units after the latest arrival time of packets 310 | currently in the medium on their way to the destination */ 311 | lastime = clocktime; 312 | for (q = evlist; q != NULL ; q = q->next) 313 | if ( (q->evtype == FROM_LAYER2 && q->eventity == evptr->eventity) ) 314 | lastime = q->evtime; 315 | evptr->evtime = lastime + 2.*jimsrand(); 316 | 317 | 318 | if (TRACE > 2) 319 | printf(" TOLAYER2: scheduling arrival on other side\n"); 320 | insertevent(evptr); 321 | } 322 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computer Networking: A Top Down Approach, 6/E 2 | 3 | 4 | 5 | Part of solutions for labs in *Computer Networking: A Top Down Approach, 6/E*. 6 | 7 | ## Note(Simplified Chinsese) 8 | 9 | 1. [计算机网络:SMTP邮件客户端](http://sine-x.com/kurose-ross-smtp/) 10 | 11 | 1. [计算机网络:UDP Pinger](http://sine-x.com/kurose-ross-udp-pinger/) 12 | 13 | 1. [计算机网络:ICMP Pinger](http://sine-x.com/kurose-ross-icmp-pinger/) 14 | 15 | 1. [计算机网络:Traceroute](http://sine-x.com/kurose-ross-traceroute/) 16 | 17 | 1. [计算机网络:实现一个路由算法](http://sine-x.com/kurose-ross-route-algorithm/) 18 | 19 | 1. [计算机网络:实现一个可靠的运输协议](http://sine-x.com/kurose-ross-a-reliable-transport-protocol/) 20 | -------------------------------------------------------------------------------- /SMTP/smtp.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | 3 | # Mail content 4 | subject = "I love computer networks!" 5 | contenttype = "text/html" 6 | content = "

I love computer networks!

" 7 | 8 | # Choose a mail server (e.g. Google mail server) and call it mailserver 9 | mailserver = 'smtp.126.com' 10 | 11 | # Sender and reciever 12 | fromaddress = "chungchenghao@126.com" 13 | toaddress = "1041474530@qq.com" 14 | 15 | # Auth information (Encode with base64) 16 | username = "Y2h1bmdjaGVuZ2hhb0AxMjYuY29t" 17 | password = "MzI1NjAwdmFs" 18 | 19 | # Create socket called clientSocket and establish a TCP connection with mailserver 20 | clientSocket = socket(AF_INET,SOCK_STREAM) 21 | clientSocket.connect((mailserver, 25)) 22 | 23 | recv = clientSocket.recv(1024) 24 | print recv 25 | if recv[:3] != '220': 26 | print '220 reply not received from server.' 27 | 28 | # Send EHLO command and print server response. 29 | heloCommand = 'EHLO Alice\r\n' 30 | clientSocket.send(heloCommand) 31 | recv1 = clientSocket.recv(1024) 32 | print recv1 33 | if recv1[:3] != '250': 34 | print '250 reply not received from server.' 35 | 36 | # Auth 37 | clientSocket.sendall('AUTH LOGIN\r\n') 38 | recv = clientSocket.recv(1024) 39 | print recv 40 | if (recv[:3] != '334'): 41 | print '334 reply not received from server' 42 | clientSocket.sendall(username + '\r\n') 43 | recv = clientSocket.recv(1024) 44 | print recv 45 | if (recv[:3] != '334'): 46 | print '334 reply not received from server' 47 | clientSocket.sendall(password + '\r\n') 48 | recv = clientSocket.recv(1024) 49 | print recv 50 | if (recv[:3] != '235'): 51 | print '235 reply not received from server' 52 | 53 | # Send MAIL FROM command and print server response. 54 | clientSocket.sendall('MAIL FROM: <' + fromaddress + '>\r\n') 55 | recv = clientSocket.recv(1024) 56 | print recv 57 | if (recv[:3] != '250'): 58 | print '250 reply not received from server' 59 | 60 | # Send RCPT TO command and print server response. 61 | clientSocket.sendall('RCPT TO: <' + toaddress + '>\r\n') 62 | recv = clientSocket.recv(1024) 63 | print recv 64 | if (recv[:3] != '250'): 65 | print '250 reply not received from server' 66 | 67 | # Send DATA command and print server response. 68 | clientSocket.send('DATA\r\n') 69 | recv = clientSocket.recv(1024) 70 | print recv 71 | if (recv[:3] != '354'): 72 | print '354 reply not received from server' 73 | 74 | # Send message data. 75 | msg = 'from:' + fromaddress + '\r\n' 76 | msg += 'subject:' + subject + '\r\n' 77 | msg += 'Content-Type:' + contenttype + '\t\n' 78 | msg += '\r\n' + content 79 | clientSocket.sendall(msg) 80 | 81 | # Message ends with a single period. 82 | clientSocket.sendall('\r\n.\r\n') 83 | recv = clientSocket.recv(1024) 84 | print recv 85 | if (recv[:3] != '250'): 86 | print '250 reply not received from server' 87 | 88 | # Send QUIT command and get server response. 89 | clientSocket.sendall('QUIT\r\n') 90 | 91 | # Close connection 92 | clientSocket.close() -------------------------------------------------------------------------------- /Traceroute/traceroute.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | import os 3 | import sys 4 | import struct 5 | import time 6 | import select 7 | import binascii 8 | 9 | ICMP_ECHO_REQUEST = 8 10 | MAX_HOPS = 30 11 | TIMEOUT = 2.0 12 | TRIES = 2 13 | ID = os.getpid() & 0xffff 14 | 15 | # The packet that we shall send to each router along the path is the ICMP echo 16 | # request packet, which is exactly what we had used in the ICMP ping exercise. 17 | # We shall use the same packet that we built in the Ping exercise 18 | 19 | def checksum(str): 20 | # In this function we make the checksum of our packet 21 | # hint: see icmpPing lab 22 | csum = 0 23 | countTo = (len(str) / 2) * 2 # round to even 24 | 25 | count = 0 26 | while count < countTo: 27 | thisVal = ord(str[count+1]) * 256 + ord(str[count]) 28 | csum = csum + thisVal 29 | csum = csum & 0xffffffffL 30 | count = count + 2 31 | 32 | if countTo < len(str): 33 | csum = csum + ord(str[len(str) - 1]) 34 | csum = csum & 0xffffffffL 35 | 36 | csum = (csum >> 16) + (csum & 0xffff) # convolute first time 37 | csum = csum + (csum >> 16) # convolute second time 38 | answer = ~csum # one's component 39 | answer = answer & 0xffff # get final checksum 40 | answer = answer >> 8 | (answer << 8 & 0xff00)# Convert tp big ending 41 | return answer 42 | 43 | def build_packet(): 44 | # In the sendOnePing() method of the ICMP Ping exercise ,firstly the header of our 45 | # packet to be sent was made, secondly the checksum was appended to the header and 46 | # then finally the complete packet was sent to the destination. 47 | 48 | # Make the header in a similar way to the ping exercise. 49 | # Append checksum to the header. 50 | 51 | # Don't send the packet yet , just return the final packet in this function. 52 | 53 | # So the function ending should look like this 54 | 55 | myChecksum = 0 56 | 57 | # Make a dummy header with a 0 checksum. 58 | # struct -- Interpret strings as packed binary data 59 | header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1) 60 | data = struct.pack('d', time.time()) 61 | 62 | # Calculate the checksum on the dfata and the dummy header. 63 | myChecksum = checksum(header + data) 64 | 65 | # Get the right checksum, and put in the header 66 | if sys.platform == 'darwin': 67 | myChecksum = htons(myChecksum) & 0xffff 68 | #Convert 16-bit integers from host to network byte order. 69 | else: 70 | myChecksum = htons(myChecksum) 71 | 72 | header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1) 73 | packet = header + data 74 | return packet 75 | 76 | def get_route(hostname): 77 | timeLeft = TIMEOUT 78 | for ttl in xrange(1,MAX_HOPS): 79 | for tries in xrange(TRIES): 80 | destAddr = gethostbyname(hostname) 81 | # Make a raw socket named mySocket 82 | mySocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) 83 | mySocket.setsockopt(IPPROTO_IP, IP_TTL, struct.pack('I', ttl)) 84 | mySocket.settimeout(TIMEOUT) 85 | try: 86 | d = build_packet() 87 | mySocket.sendto(d, (hostname, 0)) 88 | t = time.time() 89 | startedSelect = time.time() 90 | whatReady = select.select([mySocket], [], [], TIMEOUT) 91 | howLongInSelect = (time.time() - startedSelect) 92 | if whatReady[0] == []: # Timeout 93 | print " * * * Request timed out." 94 | recvPacket, addr = mySocket.recvfrom(1024) 95 | timeReceived = time.time() 96 | timeLeft = timeLeft - howLongInSelect 97 | if timeLeft <= 0: 98 | print " * * * Request timed out." 99 | except timeout: 100 | continue 101 | else: 102 | # Fetch the icmp type from the IP packet 103 | type, = struct.unpack('b', recvPacket[20:21]) 104 | if type == 11: 105 | bytes = struct.calcsize("d") 106 | timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0] 107 | print " %d rtt=%.0f ms %s" %(ttl, (timeReceived -t)*1000, addr[0]) 108 | elif type == 3: 109 | bytes = struct.calcsize("d") 110 | timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0] 111 | print " %d rtt=%.0f ms %s" %(ttl, (timeReceived-t)*1000, addr[0]) 112 | elif type == 0: 113 | bytes = struct.calcsize("d") 114 | timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0] 115 | print " %d rtt=%.0f ms %s" %(ttl, (timeReceived - timeSent)*1000, addr[0]) 116 | return 117 | else: 118 | print "error" 119 | break 120 | finally: 121 | mySocket.close() 122 | 123 | get_route("183.136.217.66") -------------------------------------------------------------------------------- /UDP/Client.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | import time 3 | import datetime 4 | # Host 5 | host = ('127.0.0.1', 12000) 6 | # Statistic data 7 | max_rtt = 0.0; 8 | min_rtt = 1.0; 9 | sum_rtt = 0.0; 10 | lost_count = 0.0; 11 | # Create a UDP socket 12 | # Notice the use of SOCK_DGRAM for UDP packets 13 | clientSocket = socket(AF_INET, SOCK_DGRAM) 14 | # Assign IP and port for socket 15 | clientSocket.bind(('', 10002)) 16 | # Set timeout 17 | clientSocket.settimeout(1) 18 | for x in xrange(1,11): 19 | # Get start timestamp 20 | start = time.time() 21 | # Make Ping message 22 | message = 'Ping ' + str(x) + ' ' + datetime.datetime.fromtimestamp(start).strftime('%H:%M:%S') 23 | # Send message 24 | clientSocket.sendto(message, host) 25 | try: 26 | message, address = clientSocket.recvfrom(1024) 27 | # Get end timestamp 28 | end = time.time() 29 | # Caculate RTT 30 | rtt = end - start 31 | # Count statis 32 | max_rtt = max(max_rtt, rtt) 33 | min_rtt = min(min_rtt, rtt) 34 | sum_rtt += rtt 35 | print message + " RTT =", rtt 36 | except timeout: 37 | # Timeout 38 | lost_count += 1.0 39 | print 'Request timed out' 40 | # Report 41 | print "maximum RTT = " + str(max_rtt) + ", minimum RTT = " + str(min_rtt) + ", average RTT = " + str(sum_rtt/(10-lost_count)) 42 | print "Sent = 10, Reciced = " + str(10-lost_count) + ", Lost = " + str(lost_count) + ", Lost rate = " + str(lost_count*10) + "%" -------------------------------------------------------------------------------- /UDP/Server.py: -------------------------------------------------------------------------------- 1 | # UDPPingerServer.py 2 | # We will need the following module to generate randomized lost packets 3 | import random 4 | from socket import * 5 | # Create a UDP socket 6 | # Notice the use of SOCK_DGRAM for UDP packets 7 | serverSocket = socket(AF_INET, SOCK_DGRAM) 8 | # Assign IP address and port number to socket 9 | serverSocket.bind(('', 12000)) 10 | while True: 11 | # Generate random number in the range of 0 to 10 12 | rand = random.randint(0, 10) 13 | # Receive the client packet along with the address it is coming from 14 | message, address = serverSocket.recvfrom(1024) 15 | # Capitalize the message from the client 16 | message = message.upper() 17 | # If rand is less is than 4, we consider the packet lost and do not respond 18 | if rand < 4: 19 | continue 20 | # Otherwise, the server responds 21 | serverSocket.sendto(message, address) -------------------------------------------------------------------------------- /handout/GettingStarted.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/GettingStarted.pdf -------------------------------------------------------------------------------- /handout/Socket1_WebServer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket1_WebServer.pdf -------------------------------------------------------------------------------- /handout/Socket2_UDPpinger.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket2_UDPpinger.pdf -------------------------------------------------------------------------------- /handout/Socket3_SMTP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket3_SMTP.pdf -------------------------------------------------------------------------------- /handout/Socket4_ProxyServer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket4_ProxyServer.pdf -------------------------------------------------------------------------------- /handout/Socket5_ICMPpinger(chap4).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket5_ICMPpinger(chap4).pdf -------------------------------------------------------------------------------- /handout/Socket6_VideoStreaming(chap7).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Socket6_VideoStreaming(chap7).pdf -------------------------------------------------------------------------------- /handout/Traceroute (Chapter 4) .pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/67d917af2a4d2903151ca67ed4a4534e731c1fca/handout/Traceroute (Chapter 4) .pdf --------------------------------------------------------------------------------