forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
Console.cpp
Go to the documentation of this file.
1 
9 #include <list>
10 #include "CommonDefs.h"
11 #include "PacketHeader.h"
12 #include "CtlPkt.h"
13 
14 namespace forest {
15 
16 
17 const short NM_PORT = 30122;
18 
19 // various helper routines
20 bool sendReqPkt(int, CtlPkt&, fAdr_t, CtlPkt&);
21 bool setAttributes(CtlPkt&, CpTypeIndex, CtlPkt&);
22 void parseLine(string, list<string>&);
23 void buildWordList(string, list<string>&);
24 bool validTokenList(list<string>);
25 void processTokenList(list<string>, fAdr_t&, CpTypeIndex&, CtlPkt&);
26 void posResponse(CtlPkt&);
27 
31 int main(int argc, char *argv[]) {
32  ipa_t nmIp;
33 
34  if (argc != 2 || (nmIp = Np4d::getIpAdr(argv[1])) == 0)
35  fatal("usage: fConsole netMgrIp");
36 
37  int sock = Np4d::streamSocket();
38  if (sock < 0 ||
39  !Np4d::connect4d(sock,nmIp,NM_PORT) ||
40  !Np4d::nonblock(sock))
41  fatal("can't connect to NetMgr");
42 
43  // start processing command line input
44 
45  fAdr_t target = 0; // forest address of request packet target
46  CtlPkt cpTemplate; // template used to store attributes
47 
48  while (true) {
49  cout << "console: ";
50 
51  string line; getline(cin,line);
52  if (line.find("quit") == 0) break;
53  if (line.find("clear") == 0) {
54  target = 0; cpTemplate.reset(); continue;
55  }
56  if (line.find("show") == 0) {
57  // show target and all defined attributes
58  if (target != 0) {
59  string s;
60  cout << "target="
61  << Forest::fAdr2string(target,s) << endl;
62  }
63  for (int i = CPA_START+1; i < CPA_END; i++) {
64  CpAttrIndex ii = CpAttrIndex(i);
65  if (cpTemplate.isSet(ii)) {
66  string s;
67  cout << cpTemplate.avPair2string(ii,s)
68  << endl;
69  }
70  }
71  continue;
72  }
73 
74  list<string> tokenList;
75  parseLine(line, tokenList);
76  if (validTokenList(tokenList)) {
77  CpTypeIndex reqType = CPT_START;
78  processTokenList(tokenList,target,reqType,cpTemplate);
79  if (reqType == CPT_START) continue;
80 
81  if (target == 0) {
82  cout << "no target defined for command\n";
83  continue;
84  }
85 
86  CtlPkt reqPkt, replyPkt;
87  reqPkt.reset();
88  reqPkt.setCpType(reqType);
89  reqPkt.setRrType(REQUEST);
90 
91  replyPkt.reset();
92 
93  if (!setAttributes(cpTemplate,reqType,reqPkt)) {
94  cout << "missing one or more required "
95  "attributes\n";
96  } else if (!sendReqPkt(sock,reqPkt,target,replyPkt)) {
97  cout << "no valid reply received\n";
98  } else {
99  if (replyPkt.getRrType() == POS_REPLY) {
100  posResponse(replyPkt);
101  //cout << "success\n";
102  } else {
103  cout << "error reported: "
104  << replyPkt.getErrMsg() << endl;
105  }
106  }
107  } else {
108  cout << "cannot recognize command\n";
109  }
110  }
111 }
112 
113 void posResponse(CtlPkt& cp) {
114  bool printedSomething = false;
115  CpTypeIndex cpType = cp.getCpType();
116  for (int i = CPA_START+1; i < CPA_END; i++) {
117  CpAttrIndex ii = CpAttrIndex(i);
118  if (!CpType::isRepAttr(cpType,ii)) continue;
119  printedSomething = true;
120  cout << CpAttr::getName(ii) << "=";
121  int32_t val = cp.getAttr(ii);
122  if (ii == COMTREE_OWNER || ii == LEAF_ADR ||
123  ii == PEER_ADR || ii == PEER_DEST ||
124  ii == DEST_ADR) {
125  string s;
126  cout << Forest::fAdr2string((fAdr_t) val,s);
127  } else if (ii == LOCAL_IP || ii == PEER_IP || ii == RTR_IP) {
128  string s; cout << Np4d::ip2string(val,s);
129  } else if (ii == PEER_TYPE) {
130  string s;
131  cout << Forest::nodeType2string((ntyp_t) val,s);
132  } else {
133  cout << val;
134  }
135  cout << " ";
136  }
137  if (printedSomething) cout << endl;
138 }
139 
149 bool sendReqPkt(int sock, CtlPkt& reqPkt,
150  fAdr_t target, CtlPkt& replyPkt) {
151  buffer_t reqBuf, replyBuf;
152  PacketHeader reqHdr, replyHdr;
153 
154  int pleng = Forest::HDR_LENG + sizeof(uint32_t) +
155  reqPkt.pack(&reqBuf[Forest::HDR_LENG/sizeof(uint32_t)]);
156 
157  reqHdr.setLength(pleng);
158  reqHdr.setPtype(NET_SIG);
159  reqHdr.setFlags(0);
160  reqHdr.setComtree(Forest::CLIENT_SIG_COMT);
161  reqHdr.setSrcAdr(0); // to be filled in by NetMgr
162  reqHdr.setDstAdr(target);
163 
164  reqHdr.pack(reqBuf);
165 
166  if (Np4d::sendBuf(sock, (char *) &reqBuf[0], pleng) != pleng)
167  fatal("can't send control packet to NetMgr");
168 
169  for (int i = 0; i < 3; i++) {
170  usleep(1000000);
171  // if there is a reply, unpack and return true
172  int nbytes = Np4d::recvBuf(sock, (char *) &replyBuf[0],
174  if (nbytes <= 0) {
175  cout << "."; cout.flush();
176  Np4d::sendBuf(sock, (char *) &reqBuf[0], pleng);
177  continue;
178  }
179  replyHdr.unpack(replyBuf);
180  if (!replyPkt.unpack(&replyBuf[Forest::HDR_LENG/sizeof(uint32_t)],
181  nbytes-(Forest::HDR_LENG + sizeof(uint32_t))))
182  return false;
183  return replyHdr.getSrcAdr() == target;
184  }
185  return false;
186 }
187 
195 bool setAttributes(CtlPkt& cpTemplate, CpTypeIndex type, CtlPkt& reqPkt) {
196  for (int i = CPA_START+1; i < CPA_END; i++) {
197  CpAttrIndex ii = CpAttrIndex(i);
198  if (CpType::isReqAttr(type, ii)) {
199  if (cpTemplate.isSet(ii)) {
200  reqPkt.setAttr(ii,cpTemplate.getAttr(ii));
201  } else if (CpType::isReqReqAttr(type, ii)) {
202  return false;
203  }
204  }
205  }
206  return true;
207 }
208 
215 void parseLine(string line, list<string>& tokenList) {
216  // build a list of words, where a word may be the string "="
217  // or a string containing no white space and no equal sign
218  list<string> wordList;
219  buildWordList(line, wordList);
220 
221  tokenList.clear();
222 
223  // find first "=" in wordList
224  list<string>::iterator p = wordList.begin();
225  int pos = 0;
226  while (p != wordList.end()) {
227  if ((*p)[0] == '=') break;
228  p++; pos++;
229  }
230 
231  // now check for a command abbreviation or phrase
232  if (pos == 0) return;
233  if (p != wordList.end() && pos == 1) {
234  // no command abbreviation or phrase
235  p = wordList.begin();
236  } else {
237  int last = (p == wordList.end() ? pos-1 : pos-2);
238  // words 0 1 .. last, could be command abbreviation or phrase
239  string s;
240  p = wordList.begin();
241  for (int i = 0; i <= last; i++) {
242  s += (*p++);
243  if (i < last) s += " ";
244  }
245  tokenList.push_back(s);
246  s.clear();
247  }
248 
249  // at this point, remaining words should consist of triples of the form
250  // attribute = value
251  while (p != wordList.end()) {
252  list<string>::iterator pp, ppp;
253  pp = p; pp++; if (pp == wordList.end()) return;
254  ppp = pp; ppp++; if (ppp == wordList.end()) return;
255  if ((*pp)[0] != '=') return;
256  string s;
257  s += *p; s += "="; s+= *ppp;
258  tokenList.push_back(s);
259  p = ppp; p++;
260  s.clear();
261  }
262 }
263 
271 void buildWordList(string line, list<string>& wordList) {
272  char white[] = " \t\n"; char delim[] = " =\t\n";
273 
274  wordList.clear();
275  int pos = 0;
276  while (true) {
277  int start = line.find_first_not_of(white,pos);
278  if (start == (int) string::npos) return;
279  int end;
280  if (line[start] == '=') {
281  wordList.push_back("=");
282  pos = start+1;
283  } else if (isalnum(line[start]) || line[start] == '-') {
284  end = line.find_first_of(delim,start);
285  string s = (end == (int) string::npos ?
286  line.substr(start) :
287  line.substr(start,end-start));
288  wordList.push_back(s);
289  pos = end;
290  } else return; // only legal possibility is #
291  }
292 }
293 
302 bool validTokenList(list<string> tokenList) {
303  // if first token is not an assignment verify that it's a valid
304  // command abbreviation or phrase
305  list<string>::iterator p = tokenList.begin();
306  if (p == tokenList.end()) return true;
307  if ((*p).find('=') == string::npos) {
308  // so first token must be a command phrase or abbreviation
309  for (int i = CPT_START+1; true ; i++) {
310  CpTypeIndex ii = CpTypeIndex(i);
311  if (i == CPT_END) return false;
312  if ((*p).compare(CpType::getName(ii)) == 0)
313  break;
314  if ((*p).compare(CpType::getAbbrev(ii)) == 0)
315  break;
316  }
317  p++;
318  }
319 
320  // for each remaining token, verify that left part is a
321  // valid control packet attribute name or a CLI "pseudo-attribute"
322  while (p != tokenList.end()) {
323  int pos = (*p).find('=');
324  string attrib = (*p).substr(0,pos);
325  for (int i = CPA_START+1; true ; i++) {
326  CpAttrIndex ii = CpAttrIndex(i);
327 
328  if (i == CPA_END) {
329  if (attrib.compare("target") == 0) break;
330  else return false;
331  }
332  if (attrib.compare(CpAttr::getName(ii)) == 0)
333  break;
334  }
335  p++;
336  }
337  return true;
338 }
339 
352 void processTokenList(list<string> tokenList, fAdr_t& target,
353  CpTypeIndex& cpType, CtlPkt& cpTemplate) {
354  // get the control packet index if there is one
355  list<string>::iterator p = tokenList.begin();
356  if ((*p).find('=') == string::npos) {
357  for (int i = CPT_START+1; i < CPT_END ; i++) {
358  CpTypeIndex ii = CpTypeIndex(i);
359  if ((*p).compare(CpType::getName(ii)) == 0) {
360  cpType = ii; break;
361  }
362  if ((*p).compare(CpType::getAbbrev(ii)) == 0) {
363  cpType = ii; break;
364  }
365  }
366  p++;
367  }
368 
369  // process all the assignments storing attributes
370  // in the control packet template
371  for (/* nada */; p != tokenList.end(); p++) {
372  int pos = (*p).find('=');
373  string leftSide = (*p).substr(0,pos);
374  string rightSide = (*p).substr(pos+1);
375  CpAttrIndex attr = CPA_START;
376  for (int i = CPA_START+1; i < CPA_END ; i++) {
377  CpAttrIndex ii = CpAttrIndex(i);
378  if (leftSide.compare(CpAttr::getName(ii)) == 0) {
379  attr = ii; break;
380  }
381  }
382 
383  if ((*p).find("target") == 0) {
384  target = Forest::forestAdr(rightSide.c_str());
385  continue;
386  }
387  switch (attr) {
388  // set the attribute appropriately
389  // in the control packet template
390  case DEST_ADR: case LEAF_ADR:
391  case PEER_ADR: case PEER_DEST:
392  fAdr_t fa;
393  fa = Forest::forestAdr(rightSide.c_str());
394  if (fa != 0) cpTemplate.setAttr(attr, fa);
395  break;
396  case LOCAL_IP: case PEER_IP: case RTR_IP:
397  ipa_t ipa;
398  ipa = Np4d::ipAddress(rightSide.c_str());
399  if (ipa != 0) cpTemplate.setAttr(attr, ipa);
400  break;
401  case PEER_TYPE:
402  ntyp_t nt;
403  nt = Forest::getNodeType(rightSide);
404  if (nt != UNDEF_NODE)
405  cpTemplate.setAttr(attr, nt);
406  break;
407  default: // remaining attributes have integer values
408  uint32_t value = atoi(rightSide.c_str());
409  cpTemplate.setAttr(attr, value);
410  break;
411  }
412  }
413 }
414 
415 } // ends namespace
416