forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
ClientMgrSave.cpp
1 
11 #include "ClientMgr.h"
12 #include <map>
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16 
17 using namespace forest;
18 
27 int main(int argc, char *argv[]) {
28  ipa_t nmIp, myIp; uint32_t finTime = 0;
29 
30  if(argc != 4 ||
31  (nmIp = Np4d::ipAddress(argv[1])) == 0 ||
32  (myIp = Np4d::ipAddress(argv[2])) == 0 ||
33  (sscanf(argv[3],"%d", &finTime)) != 1)
34  fatal("usage: ClientMgr nmIp myIp fintime");
35 
36  if (!init(nmIp, myIp))
37  fatal("init: Failed to initialize ClientMgr");
38 
39  sub->run(finTime);
40 
41  return 0;
42 }
43 
44 namespace forest {
45 
51 bool init(ipa_t nmIp1, ipa_t myIp1) {
52  nmIp = nmIp1; myIp = myIp1;
53 
54  ps = new PacketStoreTs(10000);
55  cliTbl = new ClientTable(10000,30000);
56  logger = new Logger();
57 
58  if (!cliTbl->init()) {
59  logger->log("ClientMgr::init: could not initialize "
60  "client data",2);
61  return false;
62  }
63 
64  uint64_t nonce;
65  if (!bootMe(nmIp, myIp, nmAdr, myAdr, rtrAdr, rtrIp, rtrPort, nonce)) {
66  return false;
67  }
68 
69  sub = new Substrate(myAdr, myIp, rtrAdr, rtrIp, rtrPort, nonce,
71  if (!sub->init()) return false;
72  sub->setRtrReady(true);
73 
74  dummyRecord = 0; maxRecord = 0;
75 
76  // read clientData file
77  clientFile.open("clientData");
78  if (!clientFile.good() || !cliTbl->read(clientFile)) {
79  logger->log("ClientMgr::init: could not read clientData "
80  "file",2);
81  return false;
82  }
83  clientFile.clear();
84 
85  // if size of file is not equal to count*RECORD_SIZE
86  // re-write the file using padded records
87  int n = cliTbl->getMaxClx();
88  clientFile.seekp(0,ios_base::end);
89  long len = clientFile.tellp();
90  if (len != (n+1)*RECORD_SIZE) {
91  for (int clx = 0; clx <= n; clx++) writeRecord(clx);
92  }
93  if (pthread_mutex_init(&clientFileLock,NULL) != 0) {
94  logger->log("ClientMgr::init: could not initialize lock "
95  "on client data file",2);
96  return false;
97  }
98 
99  acctFile.open("acctRecords",fstream::app);
100  if (!acctFile.good()) {
101  logger->log("ClientMgr::init: could not open acctRecords "
102  "file",2);
103  return false;
104  }
105  return true;
106 }
107 
124 bool bootMe(ipa_t nmIp, ipa_t myIp, fAdr_t& nmAdr, fAdr_t& myAdr,
125  fAdr_t& rtrAdr, ipa_t& rtrIp, ipp_t& rtrPort, uint64_t& nonce) {
126 
127  // open boot socket
128  int bootSock = Np4d::datagramSocket();
129  if (bootSock < 0) return false;
130  if (!Np4d::bind4d(bootSock,myIp,0) || !Np4d::nonblock(bootSock)) {
131  close(bootSock);
132  return false;
133  }
134 
135  // setup boot leaf packet to net manager
136  Packet p; buffer_t buf1; p.buffer = &buf1;
137  CtlPkt cp(CtlPkt::BOOT_LEAF,CtlPkt::REQUEST,1,p.payload());
138  int plen = cp.pack();
139  if (plen == 0) { close(bootSock); return false; }
141  p.flags = 0; p.srcAdr = p.dstAdr = 0; p.comtree = Forest::NET_SIG_COMT;
142  p.pack();
143 
144  // setup reply packet
145  Packet reply; buffer_t buf2; reply.buffer = &buf2;
146  CtlPkt repCp;
147 
148  int resendTime = Misc::getTime();
149  ipa_t srcIp; ipp_t srcPort;
150  while (true) {
151  int now = Misc::getTime();
152  if (now > resendTime) {
153  if (Np4d::sendto4d(bootSock,(void *) p.buffer, p.length,
154  nmIp,Forest::NM_PORT) == -1) {
155  close(bootSock); return false;
156  }
157  resendTime += 1000000; // retry after 1 second
158  }
159  usleep(10000);
160  int nbytes = Np4d::recvfrom4d(bootSock,reply.buffer,1500,
161  srcIp, srcPort);
162  if (nbytes < 0) continue;
163  reply.unpack();
164 
165  // do some checking
166  if (srcIp != nmIp || reply.type != Forest::NET_SIG) {
167  logger->log("unexpected response to boot request",
168  2,reply);
169  close(bootSock); return false;
170  }
171  repCp.reset(reply);
172  if (repCp.type != CtlPkt::CONFIG_LEAF ||
173  repCp.mode != CtlPkt::REQUEST) {
174  logger->log("unexpected response from NetMgr",2,reply);
175  close(bootSock); return false;
176  }
177 
178  // unpack data from packet
179  myAdr = repCp.adr1; rtrAdr = repCp.adr2;
180  rtrIp = repCp.ip1; rtrPort = repCp.port1;
181  nonce = repCp.nonce;
182  nmAdr = reply.srcAdr;
183 
184  // send positive reply
185  repCp.reset(CtlPkt::CONFIG_LEAF,CtlPkt::POS_REPLY,repCp.seqNum,
186  repCp.payload);
187  plen = repCp.pack();
188  if (plen == 0) { close(bootSock); return false; }
189  reply.length = Forest::OVERHEAD + plen;
190  reply.srcAdr = myAdr; reply.dstAdr = nmAdr;
191  reply.pack();
192  if (Np4d::sendto4d(bootSock,(void *) reply.buffer, reply.length,
193  nmIp,Forest::NM_PORT) == -1) {
194  close(bootSock); return false;
195  }
196  break; // proceed to next step
197  }
198  // we have the configuration information, now just wait for
199  // final ack
200  while (true) {
201  int now = Misc::getTime();
202  if (now > resendTime) {
203  if (Np4d::sendto4d(bootSock,(void *) p.buffer, p.length,
204  nmIp,Forest::NM_PORT) == -1) {
205  close(bootSock); return false;
206  }
207  resendTime += 1000000; // retry after 1 second
208  }
209  int nbytes = Np4d::recvfrom4d(bootSock,reply.buffer,1500,
210  srcIp, srcPort);
211  if (nbytes < 0) { usleep(100000); continue; }
212  reply.unpack();
213  if (srcIp != nmIp || reply.type != Forest::NET_SIG) {
214  logger->log("unexpected response to boot request",
215  2,reply);
216  close(bootSock); return false;
217  }
218  // do some checking
219  repCp.reset(reply);
220  if (repCp.type == CtlPkt::CONFIG_LEAF &&
221  repCp.mode == CtlPkt::REQUEST) {
222  // our reply must have been lost, send it again
223  repCp.reset(CtlPkt::CONFIG_LEAF,CtlPkt::POS_REPLY,
224  repCp.seqNum, repCp.payload);
225  plen = repCp.pack();
226  if (plen == 0) { close(bootSock); return false; }
227  reply.length = Forest::OVERHEAD + plen;
228  reply.srcAdr = myAdr; reply.dstAdr = nmAdr;
229  reply.pack();
230  if (Np4d::sendto4d(bootSock,(void *) reply.buffer,
231  reply.length,nmIp,Forest::NM_PORT)
232  == -1) {
233  close(bootSock); return false;
234  }
235  } else if (repCp.type != CtlPkt::BOOT_LEAF ||
236  repCp.mode != CtlPkt::POS_REPLY) {
237  logger->log("unexpected response from NetMgr",
238  2,reply);
239  close(bootSock); return false;
240  }
241  break; // success
242  }
243  close(bootSock); return true;
244 }
245 
255 void* handler(void *qp) {
256  Queue& inq = ((Substrate::QueuePair *) qp)->in;
257  Queue& outq = ((Substrate::QueuePair *) qp)->out;
258  CpHandler cph(&inq, &outq, myAdr, logger, ps);
259 
260  while (true) {
261  pktx px = inq.deq();
262  bool success = false;
263  if (px < 0) {
264  // in this case, p is really a negated socket number
265  // for a remote client
266  int sock = -px;
267  success = handleClient(sock, cph);
268  close(sock);
269  } else {
270  Packet& p = ps->getPacket(px);
271 string s;
272 cerr << "handler, got packet " << p.toString(s) << endl;
273  CtlPkt cp(p);
274  switch (cp.type) {
275  case CtlPkt::CLIENT_CONNECT:
276  case CtlPkt::CLIENT_DISCONNECT:
277  success = handleConnDisc(px, cp, cph);
278  break;
279  default:
280  cph.errReply(px,cp,"invalid control packet "
281  "type for ClientMgr");
282  break;
283  }
284  if (!success) {
285  string s;
286  cerr << "handler: operation failed\n"
287  << p.toString(s);
288  }
289  }
290  ps->free(px); // release px now that we're done
291  outq.enq(0); // signal completion to main thread
292  }
293 }
294 
303 bool handleClient(int sock,CpHandler& cph) {
304  NetBuffer buf(sock,1024);
305  string cmd, reply, clientName;
306  bool loggedIn;
307 
308  // verify initial "greeting"
309  if (!buf.readLine(cmd) || cmd != "Forest-login-v1") {
310  Np4d::sendString(sock,"misformatted user dialog\n"
311  "overAndOut\n");
312  return false;
313  }
314  // main processing loop for requests from client
315  loggedIn = false;
316  while (buf.readAlphas(cmd)) {
317 cerr << "cmd=" << cmd << endl;
318  reply = "success";
319  if (cmd == "over") {
320  // shouldn't happen, but ignore it, if it does
321  buf.nextLine(); continue;
322  } else if (cmd == "overAndOut") {
323  buf.nextLine(); return true;
324  } else if (cmd == "login") {
325  loggedIn = login(buf,clientName,reply);
326  } else if (cmd == "newAccount") {
327  loggedIn = newAccount(buf,clientName,reply);
328  } else if (!loggedIn) {
329  continue; // must login before anything else
330  } else if (cmd == "newSession") {
331  newSession(sock,cph,buf,clientName,reply);
332  } else if (cmd == "getProfile") {
333  getProfile(buf,clientName,reply);
334  } else if (cmd == "updateProfile") {
335  updateProfile(buf,clientName,reply);
336  } else if (cmd == "changePassword") {
337  changePassword(buf,clientName,reply);
338  } else if (cmd == "uploadPhoto") {
339  uploadPhoto(sock,buf,clientName,reply);
340  } else if (cmd == "getSessions") {
341  getSessions(buf,clientName,reply);
342  } else if (cmd == "cancelSession") {
343  cancelSession(buf,clientName,cph,reply);
344  } else if (cmd == "cancelAllSessions") {
345  cancelAllSessions(buf,clientName,cph,reply);
346  } else if (cmd == "addComtree" && buf.nextLine()) {
347  addComtree(buf,clientName,reply);
348  } else {
349  reply = "unrecognized input";
350  }
351 cerr << "sending reply: " << reply << endl;
352  reply += "\nover\n";
353  Np4d::sendString(sock,reply);
354  }
355  return true;
356 cerr << "terminating" << endl;
357 }
358 
368 bool login(NetBuffer& buf, string& clientName, string& reply) {
369  string pwd, s1, s2;
370  if (buf.verify(':') && buf.readName(clientName) && buf.nextLine() &&
371  buf.readAlphas(s1) && s1 == "password" &&
372  buf.verify(':') && buf.readWord(pwd) && buf.nextLine() &&
373  buf.readLine(s2) && s2 == "over") {
374  int clx =cliTbl->getClient(clientName);
375  // locks clx
376  if (clx == 0) {
377  reply = "login failed: try again";
378  return false;
379  } else if (cliTbl->checkPassword(clx,pwd)) {
380 cerr << "login succeeded " << clientName << endl;
381  cliTbl->releaseClient(clx);
382  return true;
383  } else {
384  cliTbl->releaseClient(clx);
385  reply = "login failed: try again";
386  return false;
387  }
388  } else {
389  reply = "misformatted login request";
390  return false;
391  }
392 }
393 
403 bool newAccount(NetBuffer& buf, string& clientName, string& reply) {
404  string pwd, s1, s2;
405  if (buf.verify(':') && buf.readName(clientName) && buf.nextLine() &&
406  buf.readAlphas(s1) && s1 == "password" &&
407  buf.verify(':') && buf.readWord(pwd) && buf.nextLine() &&
408  buf.readLine(s2) && s2 == "over") {
409  int clx =cliTbl->getClient(clientName);
410  // locks clx
411  if (clx != 0) {
412  cliTbl->releaseClient(clx);
413  reply = "name not available, select another";
414  return false;
415  }
416  clx = cliTbl->addClient(clientName,pwd,ClientTable::STANDARD);
417  if (clx != 0) {
418  writeRecord(clx);
419  cliTbl->releaseClient(clx);
420  return true;
421  } else {
422  reply = "unable to add client";
423  return false;
424  }
425  } else {
426  reply = "misformatted new account request";
427  return false;
428  }
429 }
430 
442 void newSession(int sock, CpHandler& cph, NetBuffer& buf,
443  string& clientName, string& reply) {
444  string s1;
445  RateSpec rs;
446  if (buf.verify(':')) {
447  if (!buf.readRspec(rs) || !buf.nextLine() ||
448  !buf.readLine(s1) || s1 != "over") {
449  reply = "misformatted new session request";
450  return;
451  }
452  } else {
453  if (!buf.nextLine() || !buf.readLine(s1) || s1 != "over") {
454  reply = "misformatted new session request";
455  return;
456  }
457  }
458  int clx = cliTbl->getClient(clientName);
459  if (clx == 0) {
460  reply = "cannot access client data(" + clientName + ")";
461  return;
462  }
463  if (!rs.isSet()) rs = cliTbl->getDefRates(clx);
464  // make sure we have sufficient capacity
465  if (!rs.leq(cliTbl->getAvailRates(clx))) {
466  cliTbl->releaseClient(clx);
467  reply = "session rate exceeds available capacity";
468  return;
469  }
470  cliTbl->getAvailRates(clx).subtract(rs);
471  cliTbl->releaseClient(clx);
472  // proceed with new session setup
473  CtlPkt repCp;
474  ipa_t clientIp = Np4d::getPeerIp(sock);
475  pktx rpx = cph.newSession(nmAdr, clientIp, rs, repCp);
476  clx = cliTbl->getClient(clientName);
477  if (clx == 0) {
478  reply = "cannot update client data(" + clientName + ")";
479  logger->log("ClientMgr::newSession: cannot update session data "
480  "session state may be inconsistent",2);
481  return;
482  }
483  if (rpx == 0) {
484  cliTbl->getAvailRates(clx).add(rs);
485  cliTbl->releaseClient(clx);
486  reply = "cannot setup session: NetMgr never responded";
487  return;
488  }
489  ps->free(rpx);
490  if (repCp.mode != CtlPkt::POS_REPLY) {
491  cliTbl->getAvailRates(clx).add(rs);
492  cliTbl->releaseClient(clx);
493  reply = "cannot setup new session: NetMgr failed (" +
494  repCp.errMsg + ")";
495  return;
496  }
497  int sess = cliTbl->addSession(repCp.adr1, repCp.adr2, clx);
498  if (sess == 0) {
499  cliTbl->getAvailRates(clx).add(rs);
500  cliTbl->releaseClient(clx);
501  reply = "cannot setup new session: could not create "
502  "session record";
503  return;
504  }
505 
506  // set session information
507  cliTbl->setClientIp(sess,clientIp);
508  cliTbl->setRouterAdr(sess,repCp.adr2);
509  cliTbl->setState(sess,ClientTable::PENDING);
511  cliTbl->getSessRates(sess) = rs;
512  cliTbl->releaseClient(clx);
513 
514  // output accounting record
515  writeAcctRecord(clientName,repCp.adr1,clientIp,repCp.adr2,NEWSESSION);
516 
517  // send information back to client
518  stringstream ss; string s;
519  ss << "yourAddress: " << Forest::fAdr2string(repCp.adr1,s) << endl;
520  ss << "yourRouter: (" << Np4d::ip2string(repCp.ip1,s)
521  << "," << repCp.port1 << ",";
522  ss << Forest::fAdr2string(repCp.adr2,s) << ")\n";
523  ss << "comtCtlAddress: " << Forest::fAdr2string(repCp.adr3,s) << endl;
524  ss << "connectNonce: " << repCp.nonce << "\noverAndOut\n";
525  reply = ss.str();
526 
527  ps->free(rpx); return;
528 }
529 
540 int checkPrivileges(string clientName, string targetName) {
541  // if names match, get and return client index (or 0 if no match)
542  if (targetName == clientName) return cliTbl->getClient(clientName);
543 
544  // get client's privileges and check if privileged
545  int clx = cliTbl->getClient(clientName);
546  if (clx == 0) return 0;
547  ClientTable::privileges priv = cliTbl->getPrivileges(clx);
548  cliTbl->releaseClient(clx);
549  if (priv != ClientTable::ADMIN && priv != ClientTable::ROOT) return 0;
550 
551  // get target's privileges
552  int tclx = cliTbl->getClient(targetName);
553  if (tclx == 0) return 0;
554  ClientTable::privileges tpriv = cliTbl->getPrivileges(tclx);
555  if (priv == ClientTable::ADMIN &&
556  (tpriv == ClientTable::ADMIN || tpriv == ClientTable::ROOT)) {
557  cliTbl->releaseClient(tclx); return 0;
558  }
559  return tclx;
560 }
561 
571 void getProfile(NetBuffer& buf, string& clientName, string& reply) {
572  string s, targetName;
573  if (!buf.verify(':') || !buf.readName(targetName) ||
574  !buf.nextLine() || !buf.readLine(s) || s != "over") {
575  reply = "misformatted get profile request"; return;
576  }
577  int tclx = checkPrivileges(clientName, targetName);
578  if (tclx == 0) {
579  reply = "insufficient privileges for requested operation";
580  return;
581  }
582  reply = "realName: \"" + cliTbl->getRealName(tclx) + "\"\n";
583  reply += "email: " + cliTbl->getEmail(tclx) + "\n";
584  reply += "defRates: " + cliTbl->getDefRates(tclx).toString(s) + "\n";
585  reply += "totalRates: " + cliTbl->getTotalRates(tclx).toString(s) +"\n";
586  cliTbl->releaseClient(tclx);
587 }
588 
598 void updateProfile(NetBuffer& buf, string& clientName, string& reply) {
599  string s, targetName;
600  if (!buf.verify(':') || !buf.readName(targetName) ||
601  !buf.nextLine()) {
602  reply = "misformatted updateProfile request"; return;
603  }
604  // read profile information from client
605  string item; RateSpec rates;
606  string realName, email; RateSpec defRates, totRates;
607  while (buf.readAlphas(item)) {
608  if (item == "realName" && buf.verify(':') &&
609  buf.readString(realName) && buf.nextLine()) {
610  // that's all for now
611  } else if (item == "email" && buf.verify(':') &&
612  buf.readWord(email) && buf.nextLine()) {
613  // that's all for now
614  } else if (item == "defRates" && buf.verify(':') &&
615  buf.readRspec(defRates) && buf.nextLine()) {
616  // that's all for now
617  } else if (item == "totalRates" && buf.verify(':') &&
618  buf.readRspec(totRates) && buf.nextLine()) {
619  // that's all for now
620  } else if (item == "over" && buf.nextLine()) {
621  break;
622  } else {
623  reply = "misformatted update profile request (" +
624  item + ")";
625  return;
626  }
627  }
628  int tclx = checkPrivileges(clientName, targetName);
629  if (tclx == 0) {
630  reply = "insufficient privileges for requested operation";
631  return;
632  }
633  if (realName.length() > 0) cliTbl->setRealName(tclx,realName);
634  if (email.length() > 0) cliTbl->setEmail(tclx,email);
635  ClientTable::privileges tpriv = cliTbl->getPrivileges(tclx);
636  if (tpriv != ClientTable::LIMITED) {
637  if (defRates.isSet() &&
638  defRates.leq(cliTbl->getTotalRates(tclx)))
639  cliTbl->getDefRates(tclx) = defRates;
640  if (totRates.isSet() &&
641  defRates.leq(cliTbl->getTotalRates(tclx)))
642  cliTbl->getTotalRates(tclx) = totRates;
643  }
644  writeRecord(tclx);
645  cliTbl->releaseClient(tclx);
646  return;
647 }
648 
658 void changePassword(NetBuffer& buf, string& clientName, string& reply) {
659  string targetName, pwd;
660  if (!buf.verify(':') || !buf.readName(targetName) ||
661  !buf.readWord(pwd) && buf.nextLine()) {
662  reply = "misformatted change password request"; return;
663  }
664  int tclx = checkPrivileges(clientName, targetName);
665  if (tclx == 0) {
666  reply = "insufficient privileges for requested operation";
667  return;
668  }
669  cliTbl->setPassword(tclx,pwd);
670  writeRecord(tclx);
671  cliTbl->releaseClient(tclx);
672  return;
673 }
674 
685 void uploadPhoto(int sock, NetBuffer& buf, string& clientName, string& reply) {
686  int length;
687  if (!buf.verify(':') || !buf.readInt(length) || !buf.nextLine()) {
688  reply = "misformatted upload photo request"; return;
689  }
690  if (length > 50000) {
691  reply = "photo file exceeds 50000 byte limit"; return;
692  }
693  int clx = cliTbl->getClient(clientName);
694  ofstream photoFile;
695  string photoName = "clientPhotos/"; photoName += clientName + ".jpg";
696  photoFile.open(photoName.c_str(), ofstream::binary);
697  if (!photoFile.good()) {
698  reply = "cannot open photo file"; return;
699  }
700  cliTbl->releaseClient(clx);
701  Np4d::sendString(sock,"proceed\n");
702  char xbuf[1001];
703  int numRcvd = 0;
704  while (true) {
705  int n = buf.readBlock(xbuf,min(1000,length-numRcvd));
706  if (n <= 0) break;
707  photoFile.write(xbuf,n);
708  numRcvd += n;
709  if (numRcvd == length) break;
710  }
711  if (numRcvd != length) {
712  reply = "could not transfer complete file"; return;
713  }
714  string s1, s2;
715  if (!buf.readLine(s1) || s1 != "photo finished" ||
716  !buf.readLine(s2) || s2 != "over") {
717  reply = "misformatted photo request"; return;
718  }
719  photoFile.close();
720  return;
721 }
722 
729 void getSessions(NetBuffer& buf, string& clientName, string& reply) {
730  string s, targetName;
731  if (!buf.verify(':') || !buf.readName(targetName) ||
732  !buf.nextLine() || !buf.readLine(s) || s != "over") {
733  reply = "misformatted get sessions request"; return;
734  }
735  int tclx = checkPrivileges(clientName, targetName);
736  if (tclx == 0) {
737  reply = "insufficient privileges for requested operation";
738  return;
739  }
740  int sess = cliTbl->firstSession(tclx);
741  reply += "\n";
742  while (sess != 0) {
743  string sessString;
744  cliTbl->session2string(sess, sessString);
745  reply += sessString;
746  sess = cliTbl->nextSession(sess,tclx);
747  }
748  reply.erase(reply.end()-1);
749  cliTbl->releaseClient(tclx);
750  return;
751 }
752 
760 void cancelSession(NetBuffer& buf, string& clientName, CpHandler& cph,
761  string& reply) {
762  string s, targetName, cancelAdrStr;
763  if (!buf.verify(':') || !buf.readName(targetName) ||
764  !buf.readForestAddress(cancelAdrStr) || !buf.nextLine() ||
765  !buf.readLine(s) || s != "over") {
766  reply = "misformatted cancel session request"; return;
767  }
768  fAdr_t cancelAdr = Forest::forestAdr(cancelAdrStr.c_str());
769  if (cancelAdr == 0) {
770  reply = "misformatted address"; return;
771  }
772  int tclx = checkPrivileges(clientName, targetName);
773  if (tclx == 0) {
774  reply = "insufficient privileges for requested operation";
775  return;
776  }
777  cliTbl->releaseClient(tclx); // release before calling getSession()
778  int sess = cliTbl->getSession(cancelAdr); // locked again
779  if (sess == 0) {
780  reply = "invalid session address"; return;
781  }
782  if (cliTbl->getClientIndex(sess) != tclx) {
783  reply = "session address belongs to another client"; return;
784  }
785  ipa_t cliIp = cliTbl->getClientIp(sess);
786  fAdr_t rtrAdr = cliTbl->getRouterAdr(sess);
787 
788  // release lock on entry while waiting for reply from NetMgr
789  cliTbl->releaseClient(tclx);
790 
791  CtlPkt repCp;
792  pktx rpx = cph.cancelSession(nmAdr, cancelAdr, rtrAdr, repCp);
793  if (rpx == 0) {
794  reply = "cannot cancel session: NetMgr never responded";
795  return;
796  }
797  ps->free(rpx);
798  if (repCp.mode != CtlPkt::POS_REPLY) {
799  reply = "cannot complete cancelSession: NetMgr failed (" +
800  repCp.errMsg + ")";
801  return;
802  }
803  tclx = cliTbl->getClient(targetName); // re-acquire lock on entry
804  if (tclx == 0) {
805  reply = "cannot update session data for " + targetName;
806  logger->log("ClientMgr::cancelSession: cannot update session "
807  "data session state may be inconsistent",2);
808  return;
809  }
810  cliTbl->getAvailRates(tclx).add(cliTbl->getSessRates(sess));
811  writeAcctRecord(clientName,cancelAdr,cliIp,rtrAdr,CANCELSESSION);
812  cliTbl->removeSession(sess);
813  cliTbl->releaseClient(tclx);
814  return;
815 }
816 
823 void cancelAllSessions(NetBuffer& buf, string& clientName, CpHandler& cph,
824  string& reply) {
825  string s, targetName;
826  if (!buf.verify(':') || !buf.readName(targetName) || !buf.nextLine() ||
827  !buf.readLine(s) || s != "over") {
828  reply = "misformatted cancel all sessions request"; return;
829  }
830  int tclx = checkPrivileges(clientName, targetName);
831  if (tclx == 0) {
832  reply = "insufficient privileges for requested operation";
833  return;
834  }
835  int sess = cliTbl->firstSession(tclx);
836  while (sess != 0) {
837  fAdr_t cliAdr = cliTbl->getClientAdr(sess);
838  ipa_t cliIp = cliTbl->getClientIp(sess);
839  fAdr_t rtrAdr = cliTbl->getRouterAdr(sess);
840 
841  cliTbl->releaseClient(tclx); // release while waiting for reply
842  CtlPkt repCp;
843  pktx rpx = cph.cancelSession(nmAdr, cliAdr, rtrAdr, repCp);
844  if (rpx == 0) {
845  reply = "cannot cancel session: NetMgr never responded";
846  return;
847  }
848  ps->free(rpx);
849  if (repCp.mode != CtlPkt::POS_REPLY) {
850  reply = "cannot complete cancelSession: NetMgr failed "
851  "(" + repCp.errMsg + ")";
852  return;
853  }
854  tclx = cliTbl->getClient(targetName); // re-acquire lock
855 
856  cliTbl->getAvailRates(tclx).add(cliTbl->getSessRates(sess));
857  writeAcctRecord(clientName,cliAdr,cliIp,rtrAdr,CANCELSESSION);
858  cliTbl->removeSession(sess);
859  sess = cliTbl->firstSession(tclx);
860  }
861  cliTbl->releaseClient(tclx);
862  return;
863 }
864 
865 void addComtree(NetBuffer& buf, string& clientName, string& reply) {
866 }
867 
874 bool handleConnDisc(pktx px, CtlPkt& cp, CpHandler& cph) {
875  Packet& p = ps->getPacket(px);
876  if (p.srcAdr != nmAdr || cp.mode != CtlPkt::REQUEST) {
877  return false;
878  }
879  fAdr_t cliAdr = cp.adr1;
880  int sess = cliTbl->getSession(cliAdr); // locks client
881  if (sess == 0) {
882  cph.errReply(px,cp,"no record of session for "
883  "specified client address");
884  return false;
885  }
886  int clx = cliTbl->getClientIndex(sess);
887  const string& cliName = cliTbl->getClientName(clx);
888  ipa_t cliIp = cliTbl->getClientIp(sess);
889  fAdr_t rtrAdr = cliTbl->getRouterAdr(sess);
890 
891  if (cp.type == CtlPkt::CLIENT_CONNECT) {
892  cliTbl->setState(sess,ClientTable::CONNECTED);
893  } else {
894  cliTbl->removeSession(sess);
895  }
896 
897  cliTbl->releaseClient(clx);
898  acctRecType typ = (cp.type == CtlPkt::CLIENT_CONNECT ?
899  CONNECT_REC : DISCONNECT_REC);
900  writeAcctRecord(cliName, cliAdr, cliIp, rtrAdr, typ);
901 
902  // send reply to original request
903  CtlPkt repCp(cp.type,CtlPkt::POS_REPLY,cp.seqNum);
904  cph.sendReply(repCp, p.srcAdr);
905  return true;
906 }
907 
915 void writeAcctRecord(const string& cname, fAdr_t cliAdr, ipa_t cliIp,
916  fAdr_t rtrAdr, acctRecType recType) {
917  // should really lock while writing
918  if (!acctFile.good()) {
919  logger->log("ClientMgr::writeAcctRecord: cannot write "
920  "to accouting file",2);
921  return;
922  }
923  string typeStr = (recType == NEWSESSION ? "new session" :
924  (recType == CANCELSESSION ? "cancel session" :
925  (recType == CONNECT_REC ? "connect" :
926  (recType == DISCONNECT_REC ?
927  "disconnect" : "undefined record"))));
928  time_t t = Misc::currentTime();
929  string now = string(ctime(&t)); now.erase(now.end()-1);
930  string s;
931  acctFile << typeStr << ", " << now << ", " << cname << ", "
932  << Np4d::ip2string(cliIp,s) << ", ";
933  acctFile << Forest::fAdr2string(cliAdr,s) << ", ";
934  acctFile << Forest::fAdr2string(rtrAdr,s) << "\n";
935  acctFile.flush();
936 }
937 
942 void writeRecord(int clx) {
943  if (clx < 0 || clx >= cliTbl->getMaxClients()) return;
944 
945  pthread_mutex_lock(&clientFileLock);
946  if (dummyRecord == 0) {
947  // create dummy record, for padding clientFile
948  dummyRecord = new char[RECORD_SIZE];
949  for (char *p = dummyRecord; p < dummyRecord+RECORD_SIZE; p++)
950  *p = ' ';
951  dummyRecord[0] = '-'; dummyRecord[RECORD_SIZE-1] = '\n';
952  }
953  if (maxRecord == 0) {
954  clientFile.seekp(0,ios_base::end);
955  maxRecord = clientFile.tellp()/RECORD_SIZE;
956  }
957 
958 
959  // position file pointer, adding dummy records if needed
960  if (clx > maxRecord) {
961  clientFile.seekp((maxRecord+1)*RECORD_SIZE);
962  while (clx > maxRecord) {
964  maxRecord++;
965  }
966  }
967  clientFile.seekp(clx*RECORD_SIZE);
968 
969  if (cliTbl->validClient(clx)) {
970  string s;
971  cliTbl->client2string(clx,s);
972  s = "+ " + s;
973  if (s.length() > RECORD_SIZE) {
974  s.erase(RECORD_SIZE-1); s += "\n";
975  } else {
976  s.erase(s.length()-1);
977  int len = RECORD_SIZE - s.length();
978  char *p = dummyRecord + s.length();
979  s.append(p,len);
980  }
981  clientFile.write(s.c_str(),RECORD_SIZE);
982  } else {
983  //s.assign(dummyRecord,RECORD_SIZE);
984  clientFile.write(dummyRecord,RECORD_SIZE);
985  }
986  clientFile.flush();
987  maxRecord = max(clx,maxRecord);
988  pthread_mutex_unlock(&clientFileLock);
989  return;
990 }
991 
992 } // ends namespace