00001 // network.cc 00002 // Routines to simulate a network interface, using UNIX sockets 00003 // to deliver packets between multiple invocations of nachos. 00004 // 00005 // DO NOT CHANGE -- part of the machine emulation 00006 // 00007 // Copyright (c) 1992-1996 The Regents of the University of California. 00008 // All rights reserved. See copyright.h for copyright notice and limitation 00009 // of liability and disclaimer of warranty provisions. 00010 00011 #include "copyright.h" 00012 #include "network.h" 00013 #include "main.h" 00014 00015 //----------------------------------------------------------------------- 00016 // NetworkInput::NetworkInput 00017 // Initialize the simulation for the network input 00018 // 00019 // "toCall" is the interrupt handler to call when packet arrives 00020 //----------------------------------------------------------------------- 00021 00022 NetworkInput::NetworkInput(CallBackObj *toCall) 00023 { 00024 // set up the stuff to emulate asynchronous interrupts 00025 callWhenAvail = toCall; 00026 packetAvail = FALSE; 00027 inHdr.length = 0; 00028 00029 sock = OpenSocket(); 00030 sprintf(sockName, "SOCKET_%d", kernel->hostName); 00031 AssignNameToSocket(sockName, sock); // Bind socket to a filename 00032 // in the current directory. 00033 00034 // start polling for incoming packets 00035 kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt); 00036 } 00037 00038 //----------------------------------------------------------------------- 00039 // NetworkInput::NetworkInput 00040 // Deallocate the simulation for the network input 00041 // (basically, deallocate the input mailbox) 00042 //----------------------------------------------------------------------- 00043 00044 NetworkInput::~NetworkInput() 00045 { 00046 CloseSocket(sock); 00047 DeAssignNameToSocket(sockName); 00048 } 00049 00050 //----------------------------------------------------------------------- 00051 // NetworkInput::CallBack 00052 // Simulator calls this when a packet may be available to 00053 // be read in from the simulated network. 00054 // 00055 // First check to make sure packet is available & there's space to 00056 // pull it in. Then invoke the "callBack" registered by whoever 00057 // wants the packet. 00058 //----------------------------------------------------------------------- 00059 00060 void 00061 NetworkInput::CallBack() 00062 { 00063 // schedule the next time to poll for a packet 00064 kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt); 00065 00066 if (inHdr.length != 0) // do nothing if packet is already buffered 00067 return; 00068 if (!PollSocket(sock)) // do nothing if no packet to be read 00069 return; 00070 00071 // otherwise, read packet in 00072 char *buffer = new char[MaxWireSize]; 00073 ReadFromSocket(sock, buffer, MaxWireSize); 00074 00075 // divide packet into header and data 00076 inHdr = *(PacketHeader *)buffer; 00077 ASSERT((inHdr.to == kernel->hostName) && (inHdr.length <= MaxPacketSize)); 00078 bcopy(buffer + sizeof(PacketHeader), inbox, inHdr.length); 00079 delete [] buffer ; 00080 00081 DEBUG(dbgNet, "Network received packet from " << inHdr.from << ", length " << inHdr.length); 00082 kernel->stats->numPacketsRecvd++; 00083 00084 // tell post office that the packet has arrived 00085 callWhenAvail->CallBack(); 00086 } 00087 00088 //----------------------------------------------------------------------- 00089 // NetworkInput::Receive 00090 // Read a packet, if one is buffered 00091 //----------------------------------------------------------------------- 00092 00093 PacketHeader 00094 NetworkInput::Receive(char* data) 00095 { 00096 PacketHeader hdr = inHdr; 00097 00098 inHdr.length = 0; 00099 if (hdr.length != 0) { 00100 bcopy(inbox, data, hdr.length); 00101 } 00102 return hdr; 00103 } 00104 00105 //----------------------------------------------------------------------- 00106 // NetworkOutput::NetworkOutput 00107 // Initialize the simulation for sending network packets 00108 // 00109 // "reliability" says whether we drop packets to emulate unreliable links 00110 // "toCall" is the interrupt handler to call when next packet can be sent 00111 //----------------------------------------------------------------------- 00112 00113 NetworkOutput::NetworkOutput(double reliability, CallBackObj *toCall) 00114 { 00115 if (reliability < 0) chanceToWork = 0; 00116 else if (reliability > 1) chanceToWork = 1; 00117 else chanceToWork = reliability; 00118 00119 // set up the stuff to emulate asynchronous interrupts 00120 callWhenDone = toCall; 00121 sendBusy = FALSE; 00122 sock = OpenSocket(); 00123 } 00124 00125 //----------------------------------------------------------------------- 00126 // NetworkOutput::~NetworkOutput 00127 // Deallocate the simulation for sending network packets 00128 //----------------------------------------------------------------------- 00129 00130 NetworkOutput::~NetworkOutput() 00131 { 00132 CloseSocket(sock); 00133 } 00134 00135 //----------------------------------------------------------------------- 00136 // NetworkOutput::CallBack 00137 // Called by simulator when another packet can be sent. 00138 //----------------------------------------------------------------------- 00139 00140 void 00141 NetworkOutput::CallBack() 00142 { 00143 sendBusy = FALSE; 00144 kernel->stats->numPacketsSent++; 00145 callWhenDone->CallBack(); 00146 } 00147 00148 //----------------------------------------------------------------------- 00149 // NetworkOutput::Send 00150 // Send a packet into the simulated network, to the destination in hdr. 00151 // Concatenate hdr and data, and schedule an interrupt to tell the user 00152 // when the next packet can be sent 00153 // 00154 // Note we always pad out a packet to MaxWireSize before putting it into 00155 // the socket, because it's simpler at the receive end. 00156 //----------------------------------------------------------------------- 00157 00158 void 00159 NetworkOutput::Send(PacketHeader hdr, char* data) 00160 { 00161 char toName[32]; 00162 00163 sprintf(toName, "SOCKET_%d", (int)hdr.to); 00164 00165 ASSERT((sendBusy == FALSE) && (hdr.length > 0) && 00166 (hdr.length <= MaxPacketSize) && (hdr.from == kernel->hostName)); 00167 DEBUG(dbgNet, "Sending to addr " << hdr.to << ", length " << hdr.length); 00168 00169 kernel->interrupt->Schedule(this, NetworkTime, NetworkSendInt); 00170 00171 if (RandomNumber() % 100 >= chanceToWork * 100) { // emulate a lost packet 00172 DEBUG(dbgNet, "oops, lost it!"); 00173 return; 00174 } 00175 00176 // concatenate hdr and data into a single buffer, and send it out 00177 char *buffer = new char[MaxWireSize]; 00178 *(PacketHeader *)buffer = hdr; 00179 bcopy(data, buffer + sizeof(PacketHeader), hdr.length); 00180 SendToSocket(sock, buffer, MaxWireSize, toName); 00181 delete [] buffer; 00182 }