agent.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1990-1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  * This product includes software developed by the Computer Systems
  17.  * Engineering Group at Lawrence Berkeley Laboratory.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34. #ifndef lint
  35. static const char rcsid[] =
  36.     "@(#) $Header: /cvsroot/nsnam/ns-2/common/agent.cc,v 1.79 2006/02/21 15:20:17 mahrenho Exp $ (LBL)";
  37. #endif
  38. #include <assert.h>
  39. #include <stdlib.h>
  40. #include "config.h"
  41. #include "agent.h"
  42. #include "ip.h"
  43. #include "flags.h"
  44. #include "address.h"
  45. #include "app.h"
  46. #ifdef HAVE_STL
  47. #include "nix/hdr_nv.h"
  48. #include "nix/nixnode.h"
  49. #endif //HAVE_STL
  50. #ifndef min
  51. #define min(a, b) (((a) < (b)) ? (a) : (b))
  52. #endif
  53. static class AgentClass : public TclClass {
  54. public:
  55. AgentClass() : TclClass("Agent") {} 
  56. TclObject* create(int, const char*const*) {
  57. return (new Agent(PT_NTYPE));
  58. }
  59. } class_agent;
  60. int Agent::uidcnt_; /* running unique id */
  61. Agent::Agent(packet_t pkttype) : 
  62. size_(0), type_(pkttype), 
  63. channel_(0), traceName_(NULL),
  64. oldValueList_(NULL), app_(0), et_(0)
  65. {
  66. }
  67. void
  68. Agent::delay_bind_init_all()
  69. {
  70. delay_bind_init_one("agent_addr_");
  71. delay_bind_init_one("agent_port_");
  72. delay_bind_init_one("dst_addr_");
  73. delay_bind_init_one("dst_port_");
  74. delay_bind_init_one("fid_");
  75. delay_bind_init_one("prio_");
  76. delay_bind_init_one("flags_");
  77. delay_bind_init_one("ttl_");
  78. delay_bind_init_one("class_");
  79. Connector::delay_bind_init_all();
  80. }
  81. int
  82. Agent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
  83. {
  84. if (delay_bind(varName, localName, "agent_addr_", (int*)&(here_.addr_), tracer)) return TCL_OK;
  85. if (delay_bind(varName, localName, "agent_port_", (int*)&(here_.port_), tracer)) return TCL_OK;
  86. if (delay_bind(varName, localName, "dst_addr_", (int*)&(dst_.addr_), tracer)) return TCL_OK;
  87. if (delay_bind(varName, localName, "dst_port_", (int*)&(dst_.port_), tracer)) return TCL_OK;
  88. if (delay_bind(varName, localName, "fid_", (int*)&fid_, tracer)) return TCL_OK;
  89. if (delay_bind(varName, localName, "prio_", (int*)&prio_, tracer)) return TCL_OK;
  90. if (delay_bind(varName, localName, "flags_", (int*)&flags_, tracer)) return TCL_OK;
  91. if (delay_bind(varName, localName, "ttl_", &defttl_, tracer)) return TCL_OK;
  92. if (delay_bind(varName, localName, "class_", (int*)&fid_, tracer)) return TCL_OK;
  93. return Connector::delay_bind_dispatch(varName, localName, tracer);
  94. }
  95. Agent::~Agent()
  96. {
  97. if (oldValueList_ != NULL) {
  98. OldValue *p = oldValueList_;
  99. while (oldValueList_ != NULL) {
  100. oldValueList_ = oldValueList_->next_;
  101. delete p;
  102. p = oldValueList_; 
  103. }
  104. }
  105. }
  106. int Agent::command(int argc, const char*const* argv)
  107. {
  108. Tcl& tcl = Tcl::instance();
  109. if (argc == 2) {
  110. if (strcmp(argv[1], "delete-agent-trace") == 0) {
  111. if ((traceName_ == 0) || (channel_ == 0))
  112. return (TCL_OK);
  113. deleteAgentTrace();
  114. return (TCL_OK);
  115. } else if (strcmp(argv[1], "show-monitor") == 0) {
  116. if ((traceName_ == 0) || (channel_ == 0))
  117. return (TCL_OK);
  118. monitorAgentTrace();
  119. return (TCL_OK);
  120. } else if (strcmp(argv[1], "close") == 0) {
  121. close();
  122. return (TCL_OK);
  123. } else if (strcmp(argv[1], "listen") == 0) {
  124.                         listen();
  125.                         return (TCL_OK);
  126.                 } else if (strcmp(argv[1], "dump-namtracedvars") == 0) {
  127. enum_tracedVars();
  128. return (TCL_OK);
  129. }
  130. }
  131. else if (argc == 3) {
  132. if (strcmp(argv[1], "attach") == 0) {
  133. int mode;
  134. const char* id = argv[2];
  135. channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  136. if (channel_ == 0) {
  137. tcl.resultf("trace: can't attach %s for writing", id);
  138. return (TCL_ERROR);
  139. }
  140. return (TCL_OK);
  141. } else if (strcmp(argv[1], "add-agent-trace") == 0) {
  142. // we need to write nam traces and set agent trace name
  143. if (channel_ == 0) {
  144. tcl.resultf("agent %s: no trace file attached", name_);
  145. return (TCL_OK);
  146. }
  147. addAgentTrace(argv[2]);
  148. return (TCL_OK);
  149. } else if (strcmp(argv[1], "connect") == 0) {
  150. connect((nsaddr_t)atoi(argv[2]));
  151. return (TCL_OK);
  152. } else if (strcmp(argv[1], "send") == 0) {
  153. sendmsg(atoi(argv[2]));
  154. return (TCL_OK);
  155. } else if (strcmp(argv[1], "set_pkttype") == 0) {
  156. set_pkttype(packet_t(atoi(argv[2])));
  157. return (TCL_OK);
  158. }
  159. }
  160. else if (argc == 4) {
  161. if (strcmp(argv[1], "sendmsg") == 0) {
  162. sendmsg(atoi(argv[2]), argv[3]);
  163. return (TCL_OK);
  164. }
  165. }
  166. else if (argc == 5) {
  167. if (strcmp(argv[1], "sendto") == 0) {
  168. sendto(atoi(argv[2]), argv[3], (nsaddr_t)atoi(argv[4]));
  169. return (TCL_OK);
  170. }
  171. }
  172. if (strcmp(argv[1], "tracevar") == 0) {
  173. // wrapper of TclObject's trace command, because some tcl
  174. // agents (e.g. srm) uses it.
  175. const char* args[4];
  176. char tmp[6];
  177. strcpy(tmp, "trace");
  178. args[0] = argv[0];
  179. args[1] = tmp;
  180. args[2] = argv[2];
  181. if (argc > 3)
  182. args[3] = argv[3];
  183. return (Connector::command(argc, args));
  184. }
  185. return (Connector::command(argc, argv));
  186. }
  187. void Agent::flushAVar(TracedVar *v)
  188. {
  189. char wrk[256], value[128];
  190. int n;
  191. // XXX we need to keep track of old values. What's the best way?
  192. v->value(value, 128);
  193. if (strcmp(value, "") == 0) 
  194. // no value, because no writes has occurred to this var
  195. return;
  196. sprintf(wrk, "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -o %s -T v -x",
  197. Scheduler::instance().clock(), addr(), dst_.addr_,
  198. v->name(), traceName_, value); 
  199. n = strlen(wrk);
  200. wrk[n] = 'n';
  201. wrk[n+1] = 0;
  202. (void)Tcl_Write(channel_, wrk, n+1);
  203. }
  204. void Agent::deleteAgentTrace()
  205. {
  206. char wrk[256];
  207. // XXX we don't know InstVar outside of Tcl! Is there any
  208. // tracedvars hidden in InstVar? If so, shall we have a tclclInt.h?
  209. TracedVar* var = tracedvar_;
  210. for ( ;  var != 0;  var = var->next_) 
  211. flushAVar(var);
  212. // we need to flush all var values to trace file, 
  213. // so nam can do backtracing
  214. sprintf(wrk, "a -t "TIME_FORMAT" -s %d -d %d -n %s -x",
  215. Scheduler::instance().clock(), here_.addr_,
  216. dst_.addr_, traceName_); 
  217. if (traceName_ != NULL)
  218. delete[] traceName_;
  219. traceName_ = NULL;
  220. }
  221. OldValue* Agent::lookupOldValue(TracedVar *v)
  222. {
  223. OldValue *p = oldValueList_;
  224. while ((p != NULL) && (p->var_ != v))
  225. p = p->next_;
  226. return p;
  227. }
  228. void Agent::insertOldValue(TracedVar *v, const char *value)
  229. {
  230. OldValue *p = new OldValue;
  231. assert(p != NULL);
  232. strncpy(p->val_, value, min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
  233. p->var_ = v;
  234. p->next_ = NULL;
  235. if (oldValueList_ == NULL) 
  236. oldValueList_ = p;
  237. else {
  238. p->next_ = oldValueList_;
  239. oldValueList_ = p;
  240. }
  241. }
  242. // callback from traced variable updates
  243. void Agent::trace(TracedVar* v) 
  244. {
  245. if (channel_ == 0)
  246. return;
  247. char wrk[256], value[128];
  248. int n;
  249. // XXX we need to keep track of old values. What's the best way?
  250. v->value(value, 128);
  251. // XXX hack: how do I know ns has not started yet?
  252. // if there's nothing in value, return
  253. static int started = 0;
  254. if (!started) {
  255. Tcl::instance().evalc("[Simulator instance] is-started");
  256. if (Tcl::instance().result()[0] == '0')
  257. // Simulator not started, do nothing
  258. return;
  259. // remember for next time (so we don't always have to call to tcl)
  260. started = 1;
  261. };
  262. OldValue *ov = lookupOldValue(v);
  263. if (ov != NULL) {
  264. sprintf(wrk, 
  265. "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -v %s -o %s -T v",
  266. Scheduler::instance().clock(), here_.addr_,
  267. dst_.addr_, v->name(), traceName_, value, ov->val_);
  268. strncpy(ov->val_, 
  269. value,
  270. min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
  271. } else {
  272. // if there is value, insert it into old value list
  273. sprintf(wrk, "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -v %s -T v",
  274. Scheduler::instance().clock(), here_.addr_,
  275. dst_.addr_, v->name(), traceName_, value);
  276. insertOldValue(v, value);
  277. }
  278. n = strlen(wrk);
  279. wrk[n] = 'n';
  280. wrk[n+1] = 0;
  281. (void)Tcl_Write(channel_, wrk, n+1);
  282. }
  283. void Agent::monitorAgentTrace()
  284. {
  285. char wrk[256];
  286. int n;
  287. double curTime = (&Scheduler::instance() == NULL ? 0 : 
  288.   Scheduler::instance().clock());
  289. sprintf(wrk, "v -t "TIME_FORMAT" -e monitor_agent %d %s",
  290. curTime, here_.addr_, traceName_);
  291. n = strlen(wrk);
  292. wrk[n] = 'n';
  293. wrk[n+1] = 0;
  294. if (channel_)
  295. (void)Tcl_Write(channel_, wrk, n+1);
  296. }
  297. void Agent::addAgentTrace(const char *name)
  298. {
  299. char wrk[256];
  300. int n;
  301. double curTime = (&Scheduler::instance() == NULL ? 0 : 
  302.   Scheduler::instance().clock());
  303. sprintf(wrk, "a -t "TIME_FORMAT" -s %d -d %d -n %s",
  304. curTime, here_.addr_, dst_.addr_, name);
  305. n = strlen(wrk);
  306. wrk[n] = 'n';
  307. wrk[n+1] = 0;
  308. if (channel_)
  309. (void)Tcl_Write(channel_, wrk, n+1);
  310. // keep agent trace name
  311. if (traceName_ != NULL)
  312. delete[] traceName_;
  313. traceName_ = new char[strlen(name)+1];
  314. strcpy(traceName_, name);
  315. }
  316. void Agent::timeout(int)
  317. {
  318. }
  319. /* 
  320.  * Callback to application to notify the reception of a number of bytes  
  321.  */
  322. void Agent::recvBytes(int nbytes)
  323. {
  324. if (app_)
  325. app_->recv(nbytes);
  326. }
  327. /* 
  328.  * Callback to application to notify the termination of a connection  
  329.  */
  330. void Agent::idle()
  331. {
  332. if (app_)
  333. app_->resume();
  334. }
  335. /* 
  336.  * Assign application pointer for callback purposes    
  337.  */
  338. void Agent::attachApp(Application *app)
  339. {
  340. app_ = app;
  341. }
  342. void Agent::close()
  343. {
  344. }
  345. void Agent::listen()
  346. {
  347. }
  348. /* 
  349.  * This function is a placeholder in case applications want to dynamically
  350.  * connect to agents (presently, must be done at configuration time).
  351.  */
  352. void Agent::connect(nsaddr_t /*dst*/)
  353. {
  354. /*
  355. dst_ = dst;
  356. */
  357. }
  358. /*
  359.  * Place holders for sending application data
  360.  */ 
  361. void Agent::sendmsg(int /*sz*/, AppData* /*data*/, const char* /*flags*/)
  362. {
  363. fprintf(stderr, 
  364. "Agent::sendmsg(int, AppData*, const char*) not implementedn");
  365. abort();
  366. }
  367. void Agent::sendmsg(int /*nbytes*/, const char* /*flags*/)
  368. {
  369. }
  370. void Agent::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/,
  371.    nsaddr_t /*dst*/)
  372. {
  373. fprintf(stderr, 
  374. "Agent::sendmsg(int, AppData*, const char*) not implementedn");
  375. abort();
  376. }
  377. // to support application using message passing
  378. void Agent::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/,
  379.    ns_addr_t /*dst*/)
  380. {
  381. }
  382. /* 
  383.  * This function is a placeholder in case applications want to dynamically
  384.  * connect to agents (presently, must be done at configuration time).
  385.  */
  386. void Agent::sendto(int /*nbytes*/, const char /*flags*/[], nsaddr_t /*dst*/)
  387. {
  388. /*
  389. dst_ = dst;
  390. sendmsg(nbytes, flags);
  391. */
  392. }
  393. // to support application using message passing
  394. void Agent::sendto(int /*nbytes*/, const char /*flags*/[], ns_addr_t /*dst*/)
  395. {
  396. }
  397. void Agent::recv(Packet* p, Handler*)
  398. {
  399. if (app_)
  400. app_->recv(hdr_cmn::access(p)->size());
  401. /*
  402.  * didn't expect packet (or we're a null agent?)
  403.  */
  404. Packet::free(p);
  405. }
  406. /*
  407.  * initpkt: fill in all the generic fields of a pkt
  408.  */
  409. void
  410. Agent::initpkt(Packet* p) const
  411. {
  412. hdr_cmn* ch = hdr_cmn::access(p);
  413. ch->uid() = uidcnt_++;
  414. ch->ptype() = type_;
  415. ch->size() = size_;
  416. ch->timestamp() = Scheduler::instance().clock();
  417. ch->iface() = UNKN_IFACE.value(); // from packet.h (agent is local)
  418. ch->direction() = hdr_cmn::NONE;
  419. ch->error() = 0; /* pkt not corrupt to start with */
  420. hdr_ip* iph = hdr_ip::access(p);
  421. iph->saddr() = here_.addr_;
  422. iph->sport() = here_.port_;
  423. iph->daddr() = dst_.addr_;
  424. iph->dport() = dst_.port_;
  425. //DEBUG
  426. //if (dst_ != -1)
  427. //  printf("pl breakn");
  428. iph->flowid() = fid_;
  429. iph->prio() = prio_;
  430. iph->ttl() = defttl_;
  431. hdr_flags* hf = hdr_flags::access(p);
  432. hf->ecn_capable_ = 0;
  433. hf->ecn_ = 0;
  434. hf->eln_ = 0;
  435. hf->ecn_to_echo_ = 0;
  436. hf->fs_ = 0;
  437. hf->no_ts_ = 0;
  438. hf->pri_ = 0;
  439. hf->cong_action_ = 0;
  440. hf->qs_ = 0;
  441. #ifdef HAVE_STL
  442.   hdr_nv* nv = hdr_nv::access(p);
  443.   if (0)
  444. printf("Off hdr_nv %d, ip_hdr %d myaddr %dn",
  445.        hdr_nv::offset(), hdr_ip::offset(), here_.addr_);
  446.   NixNode* pNixNode = NixNode::GetNodeObject(here_.addr_);
  447. //  if (0)
  448. // printf("Node Object %pn", reinterpret_cast<void *>(pNixNode) );
  449.   if (pNixNode) { 
  450.   // If we get non-null, indicates nixvector routing in use
  451.   // Delete any left over nv in the packet
  452.   // Get a nixvector to the target (may create new)
  453.   NixVec* pNv = pNixNode->GetNixVector(dst_.addr_);
  454.   pNv->Reset();
  455.   nv->nv() = pNv; // And set the nixvec in the packet
  456.   nv->h_used = 0; // And reset used portion to 0
  457.   }
  458. #endif //HAVE_STL
  459. }
  460. /*
  461.  * allocate a packet and fill in all the generic fields
  462.  */
  463. Packet*
  464. Agent::allocpkt() const
  465. {
  466. Packet* p = Packet::alloc();
  467. initpkt(p);
  468. return (p);
  469. }
  470. /* allocate a packet and fill in all the generic fields and allocate
  471.  * a buffer of n bytes for data
  472.  */
  473. Packet*
  474. Agent::allocpkt(int n) const
  475. {
  476.         Packet* p = allocpkt();
  477. if (n > 0)
  478.         p->allocdata(n);
  479. return(p);
  480. }