183 lines
5.9 KiB
C++
183 lines
5.9 KiB
C++
// 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;
|
|
}
|