-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetwork.cc
184 lines (153 loc) · 6 KB
/
network.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// network.cc
// Routines to simulate a network interface, using UNIX sockets
// to deliver packets between multiple invocations of nachos.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "network.h"
#include "main.h"
//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
// Initialize the simulation for the network input
//
// "toCall" is the interrupt handler to call when packet arrives
//-----------------------------------------------------------------------
NetworkInput::NetworkInput(CallBackObj *toCall)
{
// set up the stuff to emulate asynchronous interrupts
callWhenAvail = toCall;
packetAvail = FALSE;
inHdr.length = 0;
sock = OpenSocket();
sprintf(sockName, "SOCKET_%d", kernel->hostName);
AssignNameToSocket(sockName, sock); // Bind socket to a filename
// in the current directory.
// start polling for incoming packets
kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt);
}
//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
// Deallocate the simulation for the network input
// (basically, deallocate the input mailbox)
//-----------------------------------------------------------------------
NetworkInput::~NetworkInput()
{
CloseSocket(sock);
DeAssignNameToSocket(sockName);
}
//-----------------------------------------------------------------------
// NetworkInput::CallBack
// Simulator calls this when a packet may be available to
// be read in from the simulated network.
//
// First check to make sure packet is available & there's space to
// pull it in. Then invoke the "callBack" registered by whoever
// wants the packet.
//-----------------------------------------------------------------------
void NetworkInput::CallBack()
{
// schedule the next time to poll for a packet
kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt);
if (inHdr.length != 0) // do nothing if packet is already buffered
return;
if (!PollSocket(sock)) // do nothing if no packet to be read
return;
// otherwise, read packet in
char *buffer = new char[MaxWireSize];
ReadFromSocket(sock, buffer, MaxWireSize);
// divide packet into header and data
inHdr = *(PacketHeader *)buffer;
ASSERT((inHdr.to == kernel->hostName) && (inHdr.length <= MaxPacketSize));
bcopy(buffer + sizeof(PacketHeader), inbox, inHdr.length);
delete[] buffer;
DEBUG(dbgNet, "Network received packet from " << inHdr.from << ", length " << inHdr.length);
kernel->stats->numPacketsRecvd++;
// tell post office that the packet has arrived
callWhenAvail->CallBack();
}
//-----------------------------------------------------------------------
// NetworkInput::Receive
// Read a packet, if one is buffered
//-----------------------------------------------------------------------
PacketHeader
NetworkInput::Receive(char *data)
{
PacketHeader hdr = inHdr;
inHdr.length = 0;
if (hdr.length != 0)
{
bcopy(inbox, data, hdr.length);
}
return hdr;
}
//-----------------------------------------------------------------------
// NetworkOutput::NetworkOutput
// Initialize the simulation for sending network packets
//
// "reliability" says whether we drop packets to emulate unreliable links
// "toCall" is the interrupt handler to call when next packet can be sent
//-----------------------------------------------------------------------
NetworkOutput::NetworkOutput(double reliability, CallBackObj *toCall)
{
if (reliability < 0)
chanceToWork = 0;
else if (reliability > 1)
chanceToWork = 1;
else
chanceToWork = reliability;
// set up the stuff to emulate asynchronous interrupts
callWhenDone = toCall;
sendBusy = FALSE;
sock = OpenSocket();
}
//-----------------------------------------------------------------------
// NetworkOutput::~NetworkOutput
// Deallocate the simulation for sending network packets
//-----------------------------------------------------------------------
NetworkOutput::~NetworkOutput()
{
CloseSocket(sock);
}
//-----------------------------------------------------------------------
// NetworkOutput::CallBack
// Called by simulator when another packet can be sent.
//-----------------------------------------------------------------------
void NetworkOutput::CallBack()
{
sendBusy = FALSE;
kernel->stats->numPacketsSent++;
callWhenDone->CallBack();
}
//-----------------------------------------------------------------------
// NetworkOutput::Send
// Send a packet into the simulated network, to the destination in hdr.
// Concatenate hdr and data, and schedule an interrupt to tell the user
// when the next packet can be sent
//
// Note we always pad out a packet to MaxWireSize before putting it into
// the socket, because it's simpler at the receive end.
//-----------------------------------------------------------------------
void NetworkOutput::Send(PacketHeader hdr, char *data)
{
char toName[32];
sprintf(toName, "SOCKET_%d", (int)hdr.to);
ASSERT((sendBusy == FALSE) && (hdr.length > 0) &&
(hdr.length <= MaxPacketSize) && (hdr.from == kernel->hostName));
DEBUG(dbgNet, "Sending to addr " << hdr.to << ", length " << hdr.length);
kernel->interrupt->Schedule(this, NetworkTime, NetworkSendInt);
if (RandomNumber() % 100 >= chanceToWork * 100)
{ // emulate a lost packet
DEBUG(dbgNet, "oops, lost it!");
return;
}
// concatenate hdr and data into a single buffer, and send it out
char *buffer = new char[MaxWireSize];
*(PacketHeader *)buffer = hdr;
bcopy(data, buffer + sizeof(PacketHeader), hdr.length);
SendToSocket(sock, buffer, MaxWireSize, toName);
delete[] buffer;
}