├── handout
├── Socket3_SMTP.pdf
├── GettingStarted.pdf
├── Socket1_WebServer.pdf
├── Socket2_UDPpinger.pdf
├── Socket4_ProxyServer.pdf
├── Traceroute (Chapter 4) .pdf
├── Socket5_ICMPpinger(chap4).pdf
└── Socket6_VideoStreaming(chap7).pdf
├── .gitignore
├── README.md
├── UDP
├── Server.py
└── Client.py
├── Implementing an Algorithm
├── node3.c
├── node2.c
├── node1.c
├── node0.c
└── prog3.c
├── SMTP
└── smtp.py
├── ICMP Pinger
└── ping.py
├── Traceroute
└── traceroute.py
└── Implementing a Reliable Transport Protocol
├── Alternating-Bit-Protocol Version
└── prog2.c
└── Go-Back-N version
└── prog2.c
/handout/Socket3_SMTP.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket3_SMTP.pdf
--------------------------------------------------------------------------------
/handout/GettingStarted.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/GettingStarted.pdf
--------------------------------------------------------------------------------
/handout/Socket1_WebServer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket1_WebServer.pdf
--------------------------------------------------------------------------------
/handout/Socket2_UDPpinger.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket2_UDPpinger.pdf
--------------------------------------------------------------------------------
/handout/Socket4_ProxyServer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket4_ProxyServer.pdf
--------------------------------------------------------------------------------
/handout/Traceroute (Chapter 4) .pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Traceroute (Chapter 4) .pdf
--------------------------------------------------------------------------------
/handout/Socket5_ICMPpinger(chap4).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket5_ICMPpinger(chap4).pdf
--------------------------------------------------------------------------------
/handout/Socket6_VideoStreaming(chap7).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhenghaoz/ComputerNetworkingATopDownApproach6E/HEAD/handout/Socket6_VideoStreaming(chap7).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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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)
--------------------------------------------------------------------------------
/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) + "%"
--------------------------------------------------------------------------------
/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/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 | }
--------------------------------------------------------------------------------
/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()
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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")
--------------------------------------------------------------------------------
/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")
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------