forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
Host.cpp
Go to the documentation of this file.
1 
9 #include "stdinc.h"
10 #include "Host.h"
11 
12 using namespace forest;
13 
14 
56 int main(int argc, char *argv[]) {
57  ipa_t myIpAdr, rtrIpAdr;
58  int repeatFlag, delta, finTime;
59 
60  if (argc != 6 ||
61  (myIpAdr = Np4d::ipAddress(argv[1])) == 0 ||
62  (rtrIpAdr = Np4d::ipAddress(argv[2])) == 0 ||
63  sscanf(argv[3],"%d", &repeatFlag) != 1 ||
64  sscanf(argv[4],"%d", &delta) != 1 ||
65  sscanf(argv[5],"%d", &finTime) != 1)
66  fatal("usage: fHost myIpAdr routerIpAdr repeatCnt "
67  "delta finTime");
68 
69  Host host(myIpAdr,rtrIpAdr);
70  if (!host.init()) fatal("Host:: initialization failure");
71  host.run((repeatFlag ? true : false), delta, 1000000*finTime);
72 }
73 
74 namespace forest {
75 
76 // Constructor for Host, allocates space and initializes private data
77 Host::Host(ipa_t mipa, ipa_t ripa) : myIpAdr(mipa) , rtrIpAdr(ripa) {
78  nPkts = 10000;
79  ps = new PacketStore(nPkts+1, nPkts+1);
80 }
81 
82 Host::~Host() { delete ps; }
83 
88 bool Host::init() {
89  sock = Np4d::datagramSocket();
90 
91  return sock >= 0 &&
92  Np4d::bind4d(sock, myIpAdr, 0) &&
93  Np4d::nonblock(sock);
94 }
95 
96 void Host::run(bool repeatFlag, uint32_t delta, uint32_t finishTime) {
97 // Run the host. If repeatFlag is false, then all repeat specifications
98 // are ignored. Delta is the minimum time between packets.
99 // FinishTime and delta are expressed in microseconds.
100 
101  int i, pause, cnt, np;
102  pktx px;
103  const int MAXEVENTS = 200;
104  struct { bool sendFlag; uint32_t time; int pkt;} events[MAXEVENTS];
105  int evCnt = 0;
106  int nRcvd = 0; int nSent = 0; // counts of received and sent packets
107  bool didNothing;
108  struct { int pause, p, cnt, iter; } pkt[nPkts+1];
109 
110  // read packets from file into packetStore
111  np = 0;
112  while (np < nPkts) {
113  px = ps->alloc();
114  if (px == Null) fatal("Host::run: too many packets");
115  if (!readPacket(px,pause,cnt)) break;
116  pkt[np].pause = pause;
117  if (pause >= 0) {
118  pkt[np++].p = px;
119  } else if (repeatFlag) {
120  if (pause + np < 0) pause = -np;
121  pkt[np].cnt = cnt; pkt[np++].iter = cnt;
122  ps->free(px);
123  } else {
124  ps->free(px);
125  }
126  }
127  if (np == 0) return;
128 
129  uint32_t now; // free-running microsecond count
130  uint32_t nextTime; // time next packet is to go out
131  struct timeval ct, pt; // current and previous time values
132  if (gettimeofday(&ct, NULL) < 0)
133  fatal("Host::run: gettimeofday failure");
134  i = 0; // index in pkt[] of next outgoing packet
135  now = 0; nextTime = 1000000;
136  while (now <= finishTime) {
137  // receive packet if any and record statistics
138  didNothing = true;
139  // input processing
140  px = receive();
141  Packet& p = ps->getPacket(px);
142  if (px != Null) {
143  didNothing = false;
144  nRcvd++;
145  p.unpack();
146  if (evCnt < MAXEVENTS) {
147  events[evCnt].sendFlag = false;
148  events[evCnt].time = now;
149  events[evCnt].pkt = px;
150  evCnt++;
151  } else {
152  ps->free(px);
153  }
154  }
155 
156  // send next packet
157  if (i < np && now >= nextTime) {
158  send(pkt[i].p);
159  didNothing = false;
160  nSent++;
161  if (evCnt < MAXEVENTS) {
162  pktx px1 = ps->clone(pkt[i].p);
163  events[evCnt].sendFlag = true;
164  events[evCnt].time = now;
165  events[evCnt].pkt = px1;
166  evCnt++;
167  }
168  i++;
169  while (i < np && pkt[i].pause < 0) { // repeat spec
170  if (pkt[i].cnt <= 0) { // repeat forever
171  i += pkt[i].pause;
172  } else if (pkt[i].iter <= 0) {
173  pkt[i].iter = pkt[i].cnt;
174  i += 1;
175  } else {
176  pkt[i].iter -= 1;
177  i += pkt[i].pause;
178  }
179  }
180  if (i < np) nextTime += max(delta,pkt[i].pause);
181  }
182  // update time variables
183  pt = ct;
184  if (gettimeofday(&ct,Null) < 0)
185  fatal("Host::run: gettimeofday failure");
186  now += (ct.tv_sec == pt.tv_sec ?
187  ct.tv_usec - pt.tv_usec :
188  ct.tv_usec + (1000000 - pt.tv_usec)
189  );
190  if (!didNothing) continue;
191 
192  // if next packet not due to go soon, sleep until almost time
193  if (now + 500 >= nextTime) continue;
194  struct timespec sleeptime, rem;
195  sleeptime.tv_sec = 0;
196  if (nextTime - (now + 500) < 2500)
197  sleeptime.tv_nsec = (nextTime - (now + 500))*1000;
198  else
199  sleeptime.tv_nsec = 2500000;
200  nanosleep(&sleeptime,&rem);
201  // update time variables again following sleep
202  pt = ct;
203  if (gettimeofday(&ct,Null) < 0)
204  fatal("Host::run: gettimeofday failure");
205  now += (ct.tv_sec == pt.tv_sec ?
206  ct.tv_usec - pt.tv_usec :
207  ct.tv_usec + (1000000 - pt.tv_usec)
208  );
209  }
210 
211  // print recorded events
212  for (int i = 0; i < evCnt; i++) {
213  if (events[i].sendFlag)
214  cout << "send[";
215  else
216  cout << "recv[";
217  cout << setw(2) << setw(8) << events[i].time << "] ";
218  px = events[i].pkt;
219  string s;
220  Packet& p = ps->getPacket(px);
221  cout << p.toString(s);
222  }
223  cout << endl;
224  cout << nRcvd << " packets received, " << nSent << " packets sent, ";
225 }
226 
227 bool Host::readPacket(pktx px, int& pause, int& cnt) {
228 // Read an input packet from stdin and return it in p.
229  Misc::skipBlank(cin);
230  if (!Misc::readNum(cin,pause)) return false;
231  if (pause < 0) {
232  if (!Misc::readNum(cin,cnt)) cnt = 0;
233  Misc::cflush(cin,'\n');
234  return true;
235  }
236  Packet& p = ps->getPacket(px);
237  bool success = p.read(cin);
238  Misc::cflush(cin,'\n');
239  return success;
240 }
241 
242 void Host::send(pktx px) {
243 // Send packet and recycle storage.
244  Packet& p = ps->getPacket(px);
245  int rv = Np4d::sendto4d(sock,(void *) p.buffer, p.length,
246  rtrIpAdr, Forest::ROUTER_PORT);
247  if (rv == -1) fatal("Host::send: failure in sendto");
248 }
249 
250 int Host::receive() {
251 // Return next waiting packet or Null if there is none.
252  int nbytes; // number of bytes in received packet
253 
254  pktx px = ps->alloc();
255  if (px == Null) return Null;
256  Packet& p = ps->getPacket(px);
257 
258  ipa_t remoteIp; ipp_t remotePort;
259  nbytes = Np4d::recvfrom4d(sock, p.buffer, 1500,
260  remoteIp, remotePort);
261  if (nbytes < 0) {
262  if (errno == EWOULDBLOCK) {
263  ps->free(px); return Null;
264  }
265  fatal("Host::receive: error in recvfrom call");
266  }
267 
268  p.bufferLen = nbytes;
269  p.tunIp = remoteIp;
270  p.tunPort = remotePort;
271 
272  return px;
273 }
274 
275 } // ends namespace
276