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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1991,1993 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *      This product includes software developed by the Computer Systems
  16.  *      Engineering Group at Lawrence Berkeley Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#) $Header: /cvsroot/nsnam/nam-1/netmodel.cc,v 1.113 2006/11/19 00:12:29 tom_henderson Exp $ (LBL)
  34.  */
  35. #include <stdlib.h>
  36. #ifdef WIN32
  37. #include <windows.h>
  38. #endif
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. #include <math.h>
  42. #include <tcl.h>
  43. #include <tclcl.h>
  44. #include "config.h"
  45. #include "netview.h"
  46. #include "psview.h"
  47. #include "testview.h"
  48. #include "animation.h"
  49. #include "group.h"
  50. #include "tag.h"
  51. #include "queue.h"
  52. #include "drop.h"
  53. #include "packet.h"
  54. #include "edge.h"
  55. #include "lan.h"
  56. #include "node.h"
  57. #include "agent.h"
  58. #include "feature.h"
  59. #include "route.h"
  60. #include "netmodel.h"
  61. #include "monitor.h"
  62. #include "trace.h"
  63. #include "paint.h"
  64. #include "sincos.h"
  65. #include "state.h"
  66. #include "editview.h"
  67. #include "address.h"
  68. #include "animator.h"
  69. #include <float.h>
  70. extern int lineno;
  71. // not used
  72. //static int next_pat;
  73. class NetworkModelClass : public TclClass {
  74. public:
  75. NetworkModelClass() : TclClass("NetworkModel") {}
  76. TclObject* create(int argc, const char*const* argv) {
  77. if (argc < 5) 
  78. return 0;
  79. return (new NetModel(argv[4]));
  80. }
  81. } networkmodel_class;
  82. //----------------------------------------------------------------------
  83. //----------------------------------------------------------------------
  84. NetModel::NetModel(const char *animator) :
  85. TraceHandler(animator),
  86. drawables_(0),
  87. animations_(0),
  88. queues_(0),
  89. views_(0),
  90. nodes_(0),
  91. lans_(0), 
  92. node_sizefac_(NODE_EDGE_RATIO),
  93. mon_count_(0),
  94. monitors_(NULL),
  95. wireless_(0),
  96. resetf_(0),
  97. selectedSrc_(-1),
  98. selectedDst_(-1),
  99. selectedFid_(-1),
  100. hideSrc_(-1),
  101. hideDst_(-1),
  102. hideFid_(-1),
  103. colorSrc_(-1),
  104. colorDst_(-1),
  105. colorFid_(-1),
  106. showData_(1), 
  107. showRouting_(1),
  108. showMac_(1),
  109. selectedColor_(-1),
  110. nGroup_(0), 
  111. nTag_(0),
  112. parsetable_(&traceevent_) {
  113. int i;
  114. for (i = 0; i < EDGE_HASH_SIZE; ++i) {
  115. hashtab_[i] = 0;
  116. }
  117. for (i = 0; i < PTYPELEN; ++i) {
  118. selectedTraffic_[i] = '' ;
  119. colorTraffic_[i] = '' ;
  120. hideTraffic_[i] = '' ;
  121. }
  122. // Default node size is 10.0 so a default packet will be 25% of that (2.5)
  123. // This value is modified whenever a node is added.  It will be based on 
  124. // the running average of the size of the last 5 nodes.  Look at 
  125. // NetModel::addNode(const TraceEvent &e) for more details
  126. packet_size_ = 2.5;
  127.   
  128. /*XXX*/
  129. nymin_ = 1e6;
  130. nymax_ = -1e6;
  131. Paint *paint = Paint::instance();
  132. int p = paint->thin();
  133. // Initially 256 colors. Can be extended later.
  134. // See handling of otcl binding "color"
  135. nclass_ = 256;
  136. paintMask_ = 0xff;
  137. paint_ = new int[nclass_];
  138. oldpaint_ = new int[nclass_];
  139. for (i = 0; i < nclass_; ++i) {
  140. paint_[i] = p;
  141. oldpaint_[i] = p;
  142.   }
  143. addrHash_ = new Tcl_HashTable;
  144. Tcl_InitHashTable(addrHash_, TCL_ONE_WORD_KEYS);
  145. grpHash_ = new Tcl_HashTable;
  146. Tcl_InitHashTable(grpHash_, TCL_ONE_WORD_KEYS);
  147. tagHash_ = new Tcl_HashTable;
  148. Tcl_InitHashTable(tagHash_, TCL_STRING_KEYS);
  149. objnameHash_ = new Tcl_HashTable;
  150. Tcl_InitHashTable(objnameHash_, TCL_STRING_KEYS);
  151. registerObjName("ALL", ClassAllID);
  152. registerObjName("ANIMATION", ClassAnimationID);
  153. registerObjName("NODE", ClassNodeID);
  154. registerObjName("PACKET", ClassPacketID);
  155. registerObjName("EDGE", ClassEdgeID);
  156. registerObjName("QUEUEITEM", ClassQueueItemID);
  157. registerObjName("LAN", ClassLanID);
  158. registerObjName("TAG", ClassTagID);
  159. registerObjName("AGENT", ClassAgentID);
  160. bind("bcast_duration_", &bcast_duration_);
  161. bind("bcast_radius_", &bcast_radius_);
  162. }
  163. NetModel::~NetModel()
  164. {
  165. // We should delete everything here, if we want deletable netmodel...
  166. delete paint_;
  167. Animation *a, *n;
  168. for (a = animations_; a != 0; a = n) {
  169. n = a->next();
  170. delete a;
  171. }
  172. for (a = drawables_; a != 0; a = n) {
  173. n = a->next();
  174. delete a;
  175. }
  176. Tcl_DeleteHashTable(grpHash_);
  177. delete grpHash_;
  178. Tcl_DeleteHashTable(tagHash_);
  179. delete tagHash_;
  180. Tcl_DeleteHashTable(objnameHash_);
  181. delete objnameHash_;
  182. }
  183. void NetModel::update(double now)
  184. {
  185. Animation *a, *n;
  186. for (a = animations_; a != 0; a = n) {
  187. n = a->next();
  188. a->update(now);
  189. }
  190. /*
  191.  * Draw all animations and drawables on display to reflect
  192.  * current time.
  193.  */
  194. now_ = now;
  195. for (View* p = views_; p != 0; p = p->next_) {
  196. //  Calls View::draw() which calls NetView::render()
  197. //  which calls NetModel::render(View*)
  198. p->draw();
  199. }
  200. }
  201. void NetModel::update(double now, Animation* a) {
  202. a->update(now);
  203. for (View* p = views_; p != 0; p = p->next_)
  204. a->draw(p, now);
  205. }
  206. //----------------------------------------------------------------------
  207. // void
  208. // NetModel::reset(double now)
  209. //   - Reset all animations and queues to time 'now'.
  210. //----------------------------------------------------------------------
  211. void
  212. NetModel::reset(double now) {
  213. Animation* a;
  214. for (a = animations_; a != 0; a = a->next())
  215. a->reset(now);
  216. for (a = drawables_; a != 0; a = a->next())
  217. a->reset(now);
  218. for (Queue* q = queues_; q != 0; q = q->next_)
  219. q->reset(now);
  220. }
  221. //----------------------------------------------------------------------
  222. // void
  223. // NetModel::render(View * view)
  224. //   - Draw this NetModel's drawables, animations, and monitors.
  225. //     (tags, nodes, edges, packets, queues, etc.)
  226. //----------------------------------------------------------------------
  227. void
  228. NetModel::render(View* view) {
  229. Animation *a;
  230. Monitor *m;
  231. for (a = drawables_; a != 0; a = a->next()) 
  232.   a->draw(view, now_);
  233. for (a = animations_; a != 0; a = a->next())
  234.   a->draw(view, now_);
  235. for ( m = monitors_; m != NULL; m = m->next())
  236.   m->draw_monitor(view, nymin_, nymax_);
  237. }
  238. void NetModel::render(PSView* view) {
  239. Animation *a;
  240. for (a = drawables_; a != 0; a = a->next())
  241.   a->draw(view, now_);
  242. for (a = animations_; a != 0; a = a->next())
  243.   a->draw(view, now_);
  244. }
  245. void NetModel::render(TestView* view) {
  246. Animation *a;
  247. for (a = drawables_; a != 0; a = a->next())
  248.   a->draw(view, now_);
  249. for (a = animations_; a != 0; a = a->next())
  250.   a->draw(view, now_);
  251. }
  252. //----------------------------------------------------------------------
  253. // NetModel::EdgeHashNode *
  254. // NetModel::lookupEdgeHashNode(int src, int dst) const
  255. //   - Return a pointer to the edge between 'src' and 'dst'. 
  256. //----------------------------------------------------------------------
  257. NetModel::EdgeHashNode *
  258. NetModel::lookupEdgeHashNode(int source, int destination) const
  259. {
  260. EdgeHashNode* h;
  261. for (h = hashtab_[ehash(source, destination)]; h != 0; h = h->next)
  262. if (h->src == source && h->dst == destination)
  263. break;
  264. return (h);
  265. }
  266. int NetModel::addAddress(int id, int addr) const
  267. {
  268. int newEntry = 1;
  269. Tcl_HashEntry *he = 
  270. Tcl_CreateHashEntry(addrHash_, (const char *)addr, &newEntry);
  271. if (he == NULL)
  272. return -1;
  273. if (newEntry) {
  274. Tcl_SetHashValue(he, (ClientData)id);
  275. }
  276. return 0;
  277. }
  278. int NetModel::addr2id(int addr) const 
  279. {
  280. Tcl_HashEntry *he = Tcl_FindHashEntry(addrHash_, (const char *)addr);
  281. if (he == NULL)
  282. return -1;
  283. return *Tcl_GetHashValue(he);
  284. }
  285. //----------------------------------------------------------------------
  286. //  Adds an edge to a hash table?
  287. //----------------------------------------------------------------------
  288. void NetModel::enterEdge(Edge* e) {
  289. int src = e->src();
  290. int dst = e->dst();
  291. EdgeHashNode *h = lookupEdgeHashNode(src, dst);
  292. if (h != 0) {
  293. /* XXX */
  294. fprintf(stderr, "nam: duplicate edge (%d,%d)n", src, dst);
  295. //exit(1);
  296. return;
  297. }
  298. h = new EdgeHashNode;
  299. h->src = src;
  300. h->dst = dst;
  301. h->queue = 0;
  302. h->edge = e;
  303. int k = ehash(src, dst);
  304. h->next = hashtab_[k];
  305. hashtab_[k] = h;
  306. }
  307. //----------------------------------------------------------------------
  308. // void
  309. // NetModel::removeEdge(Edge* e)
  310. //   - Remove an edge from the network model and delete it
  311. //----------------------------------------------------------------------
  312. void
  313. NetModel::removeEdge(Edge* e) {
  314.   int k;
  315.   int src = e->src();
  316.   int dst = e->dst();
  317.   EdgeHashNode * h = lookupEdgeHashNode(src, dst);
  318.   EdgeHashNode * f, * g;  
  319.   if (h == 0) {
  320.     fprintf(stderr, "nam: trying to delete nonesisting edge (%d,%d)n", src, dst);
  321.     exit(1);
  322.   }
  323.   //XXX do we need to process queue ? leave it to the future 10/01/98
  324.   k = ehash(src, dst);
  325.   for (f = hashtab_[k]; f != 0; f = f->next) {
  326.     if (h->src == f->src && h->dst == f->dst) {
  327.       if (f == hashtab_[k]) {
  328.         hashtab_[k] = f->next;
  329.         break;
  330.       } else {
  331.         g->next = f->next;      
  332.         break;
  333.       } 
  334.     }
  335.     g = f;
  336.   }
  337.   
  338.   
  339.   delete h;
  340. }
  341. //----------------------------------------------------------------------
  342. // void 
  343. // NetModel::BoundingBox(BBox& bb) {
  344. // XXX Make this cheaper (i.e. cache it)
  345. //----------------------------------------------------------------------
  346. void NetModel::BoundingBox(BBox& bb) {
  347. /* ANSI C limits, from float.h */
  348. bb.xmin = bb.ymin = FLT_MAX;
  349. bb.xmax = bb.ymax = -FLT_MAX;
  350. for (Animation* a = drawables_; a != 0; a = a->next()) 
  351. a->merge(bb);
  352. }
  353. /*
  354.  Animation* NetModel::inside(double now, float px, float py) const
  355.  {
  356.   for (Animation* a = animations_; a != 0; a = a->next())
  357.   if (a->inside(now, px, py))
  358.   return (a);
  359.   for (Animation* d = drawables_; d != 0; d = d->next())
  360.   if (d->inside(now, px, py))
  361.   return (d);
  362.   return (0);
  363.  }
  364. */
  365. // Used exclusively for start_info() in nam.tcl. It ignores all tag objects
  366. // and therefore should *not* be used for editing.
  367. Animation* NetModel::inside(float px, float py) const
  368. {
  369. for (Animation* a = animations_; a != 0; a = a->next()) {
  370.      if (a->type() == BPACKET) {
  371.         BPacket* b = (BPacket* ) a ;
  372. if ((b->inside(px, py)) && (a->classid() != ClassTagID))
  373. return (a);
  374.      } 
  375.      else  {
  376. if ((a->inside(px, py)) && (a->classid() != ClassTagID))
  377. return (a);
  378.      }
  379. }
  380. for (Animation* d = drawables_; d != 0; d = d->next()) {
  381. if ((d->inside(px, py) && (d->classid() != ClassTagID)))
  382. return (d);
  383. }
  384. return (0);
  385. }
  386. int NetModel::add_monitor(Animation *a)
  387. {
  388.   Monitor *m = new Monitor(mon_count_, a, node_size_);
  389.   m->next(monitors_);
  390.   monitors_=m;
  391.   return mon_count_++;
  392. }
  393. int NetModel::monitor(double now, int monitor, char *result, int len)
  394. {
  395.   /*XXX should get rid of this search*/
  396.   for(Monitor *m=monitors_; m!=NULL; m=m->next()) {
  397.     if (m->monitor_number()==monitor) {
  398.       m->update(now, result, len);
  399.       if (strlen(result)==0)
  400. delete_monitor(m);
  401.       return 0;
  402.     }
  403.   }
  404.   result[0]='';
  405.   return -1;
  406. }
  407. //----------------------------------------------------------------------
  408. // void NetModel::check_monitors(Animation *a)
  409. //   - A new animation just got created.  Check to see if we should 
  410. //     already have a monitor on it.
  411. //----------------------------------------------------------------------
  412. void NetModel::check_monitors(Animation *a) {
  413. MonState * ms;
  414. Monitor * m;
  415. // Returns a "newed" MonState
  416. ms = a->monitor_state();
  417. if (ms == NULL) {
  418. return;
  419. }
  420. for(m = monitors_; m != NULL; m = m->next()) {
  421. if ((m->mon_state_ != NULL) &&
  422. (m->mon_state_->type = ms->type)) {
  423. switch (ms->type) {
  424. case MON_PACKET:
  425. if (m->mon_state_->pkt.id == ms->pkt.id) {
  426. m->anim(a);
  427. delete ms;
  428.   return;
  429. }
  430. break;
  431. case MON_ROUTE: 
  432. if ((m->mon_state_->route.src == ms->route.src)&&
  433. (m->mon_state_->route.group == ms->route.group)) {
  434. m->anim(a);
  435. delete ms;
  436. return;
  437. }
  438. break;
  439. }
  440. }
  441. }
  442. //  What happens to ms after the end of this function?  Maybe the memory leak?
  443. // fprintf(stderr, "Reached outside of check_monitorsn");
  444. }
  445. void NetModel::delete_monitor(int monitor)
  446. {
  447.   /*this version of delete_monitor is called from the GUI*/
  448.   /*given a monitor, remove it from the model's monitor list*/
  449.   Monitor *tm1, *tm2;
  450.   if (monitors_==NULL)
  451.     return;
  452.   tm1=monitors_;
  453.   tm2=monitors_;
  454.   while ((tm1!=NULL)&&(tm1->monitor_number()!=monitor))
  455.     {
  456.       tm2=tm1;
  457.       tm1=tm1->next();
  458.     }
  459.   if (tm1!=NULL)
  460.     {
  461.       tm2->next(tm1->next());
  462.       if (tm1==monitors_)
  463. monitors_=tm1->next();
  464.       if (tm1->anim()!=NULL)
  465. tm1->anim()->remove_monitor();
  466.       delete tm1;
  467.     }
  468. }
  469. void NetModel::delete_monitor(Monitor *m)
  470. {
  471.   /*given a monitor, remove it from a node's agent list*/
  472.   Monitor *tm1, *tm2;
  473.   if (monitors_==NULL)
  474.     return;
  475.   tm1=monitors_;
  476.   tm2=monitors_;
  477.   while ((tm1!=m)&&(tm1!=NULL))
  478.     {
  479.       tm2=tm1;
  480.       tm1=tm1->next();
  481.     }
  482.   if (tm1!=NULL)
  483.     {
  484.       tm2->next(tm1->next());
  485.       if (tm1==monitors_)
  486. monitors_=tm1->next();
  487.       tm1->anim()->remove_monitor();
  488.       delete tm1;
  489.     }
  490. }
  491. void NetModel::delete_monitor(Animation *a)
  492. {
  493.   /*given a monitor, remove it from a node's agent list*/
  494.   /*this version gets called when an animation deletes itself*/
  495.   /*XXX animations sometimes get deleted when the packet changed link*/
  496.   Monitor *tm1, *tm2;
  497.   if (monitors_==NULL)
  498.     return;
  499.   tm1=monitors_;
  500.   tm2=monitors_;
  501.   while ((tm1!=NULL)&&(tm1->anim()!=a))
  502.     {
  503.       tm2=tm1;
  504.       tm1=tm1->next();
  505.     }
  506.   if (tm1!=NULL)
  507.     {
  508.       tm2->next(tm1->next());
  509.       if (tm1==monitors_)
  510. monitors_=tm1->next();
  511.       delete tm1;
  512.     }
  513. }
  514. void NetModel::saveState(double tim)
  515. {
  516. State* state = State::instance();
  517. StateInfo min;
  518. min.time = 10e6;
  519. min.offset = 0;
  520. Animation *a, *n;
  521. StateInfo si;
  522. /*
  523.  * Update the animation list first to remove any unnecessary
  524.  * objects in the list.
  525.  */
  526. for (a = animations_; a != 0; a = n) {
  527. n = a->next();
  528. a->update(tim);
  529. }
  530. for (a = animations_; a != 0; a = n) {
  531. n = a->next();
  532. si = a->stateInfo();
  533. if (si.time < min.time)
  534. min = si;
  535. }
  536. if (min.offset)
  537. state->set(tim, min);
  538. }
  539. //---------------------------------------------------------------------
  540. // void 
  541. // NetModel::handle(const TraceEvent& e, double now, int direction)
  542. //   - Trace event handler.
  543. //---------------------------------------------------------------------
  544. void 
  545. NetModel::handle(const TraceEvent& e, double now, int direction) {
  546.   QueueItem *q;
  547.   EdgeHashNode *ehn, *ehnrev;
  548.   Edge* ep;
  549.   Node *n;
  550.   //Packet *p;
  551.   Route *r;
  552.   Agent *a;
  553.   Feature *f;
  554.   float x, y;
  555.   int pno;
  556.   double txtime;
  557.   bool do_relayout = false;
  558.   if (e.time > State::instance()->next())
  559.     saveState(e.time);
  560.   switch (e.tt) {
  561.     case 'T':
  562.       // Dummy event no-op used for realtime time synchronization
  563.       break;
  564.               
  565.     case 'v': {  
  566.       // 'variable' -- just execute it as a tcl command 
  567.       if (nam_ == 0) {
  568.         fprintf(stderr, "Couldn't evaluate %s without animatorn",
  569.           e.image);
  570.         break;
  571.       }
  572.       const char *p = e.image + e.ve.str;
  573.       char *q = new char[strlen(nam_->name()) + strlen(p) + 2];
  574.       sprintf(q, "%s %s", nam_->name(), p);
  575.       Tcl::instance().eval(q);
  576.       delete []q;
  577.       break;
  578.     }
  579.     
  580.     case 'h':
  581.       // traffic filter
  582.       if (wireless_) {
  583.         if (strcmp(e.pe.pkt.wtype,"AGT") == 0 ) return ; 
  584.         if (!showData_) { // filter out data packet
  585.            if ((strcmp(e.pe.pkt.wtype,"RTR") == 0 ) ||
  586.                (strcmp(e.pe.pkt.wtype,"MAC") == 0 )) {
  587.               if (((strcmp(e.pe.pkt.type,"cbr") == 0) ||
  588.                    (strcmp(e.pe.pkt.type,"tcp") == 0) ||
  589.                    (strcmp(e.pe.pkt.type,"ack") == 0))) 
  590.               return ;
  591.            }
  592.         }
  593.         if (!showRouting_){ // filter out routing packet
  594.            if (strcmp(e.pe.pkt.wtype,"RTR") == 0 ) {
  595.               if (!((strcmp(e.pe.pkt.type,"cbr") == 0)||
  596.                    (strcmp(e.pe.pkt.type,"tcp") == 0)   ||
  597.                    (strcmp(e.pe.pkt.type,"ack") == 0))) 
  598.               return ;
  599.            }
  600.         }
  601.         if (!showMac_){ // filter out routing packet
  602.            if (strcmp(e.pe.pkt.wtype,"MAC") == 0 ) {
  603.               if (!((strcmp(e.pe.pkt.type,"cbr") == 0)||
  604.                    (strcmp(e.pe.pkt.type,"tcp") == 0)   ||
  605.                    (strcmp(e.pe.pkt.type,"ack") == 0))) 
  606.               return ;
  607.            }
  608.         }
  609.       }
  610.       // show only packet with same chracteristics as selected packet
  611.       if (selectedSrc_ != -1) { //filter being trigger
  612.         if (e.pe.pkt.esrc != selectedSrc_ ) return ;
  613.       }
  614.       if (selectedDst_ != -1) { 
  615.         if (e.pe.pkt.edst != selectedDst_ ) return ;
  616.       }
  617.       if (selectedFid_ != -1) { 
  618.         if (atoi(e.pe.pkt.convid) != selectedFid_ ) return ;
  619.       }
  620.       if (selectedTraffic_[0] != '') { 
  621.         if (strcmp(e.pe.pkt.type,selectedTraffic_) != 0 ) return ;
  622.       }
  623.       // hide packet with same chracteristics as selected packet
  624.       if (hideSrc_ != -1) { // filter being trigger
  625.         if (e.pe.pkt.esrc == hideSrc_ ) return ;
  626.       }
  627.       if (hideDst_ != -1) { 
  628.         if (e.pe.pkt.edst == hideDst_ ) return ;
  629.       }
  630.       if (hideFid_ != -1) { 
  631.         if (atoi(e.pe.pkt.convid) == hideFid_ ) return ;
  632.       }
  633.       if (hideTraffic_[0] != '') { 
  634.         if (strcmp(e.pe.pkt.type,hideTraffic_) == 0 ) return ;
  635.       }
  636.       //change the packet color on the fly
  637.       if (selectedColor_ < 0 ) {
  638.         Paint *paint = Paint::instance();
  639.         selectedColor_ = paint->lookup("black",1);
  640.       }
  641.       if (colorSrc_ != -1) { 
  642.         if (e.pe.pkt.esrc == colorSrc_ ) 
  643.           paint_[atoi(e.pe.pkt.convid)] = selectedColor_  ;
  644.       }
  645.       if (colorDst_ != -1) { 
  646.         if (e.pe.pkt.edst == colorDst_ ) 
  647.           paint_[atoi(e.pe.pkt.convid)] = selectedColor_  ;
  648.       }
  649.       if (colorFid_ != -1) { 
  650.         if (atoi(e.pe.pkt.convid) == colorFid_ ) 
  651.           paint_[atoi(e.pe.pkt.convid)] = selectedColor_  ;
  652.       }
  653.       if (colorTraffic_[0] != '') { 
  654.         if (strcmp(e.pe.pkt.type,colorTraffic_) == 0 ) 
  655.             paint_[atoi(e.pe.pkt.convid)] = selectedColor_  ;
  656.       }
  657.       if (resetf_) 
  658.          paint_[atoi(e.pe.pkt.convid)] = oldpaint_[atoi(e.pe.pkt.convid)] ;
  659.       if (direction==BACKWARDS)
  660.         break;
  661.       if (e.pe.dst == -1) { //broadcasting
  662.         //a quick hack to give fixed transmission + delay time for
  663.         //broadcasting packet
  664.         if (e.time + BPACKET_TXT_TIME < now)
  665.           break ;
  666.         n = lookupNode(e.pe.src);
  667.         BPacket * p = new BPacket(n->x(), n->y(),e.pe.pkt,
  668.                                   e.time,e.offset,direction,
  669.   e.pe.pkt.wBcastDuration
  670.    ? e.pe.pkt.wBcastDuration
  671. : bcast_duration_,
  672.   e.pe.pkt.wBcastRadius
  673.    ? e.pe.pkt.wBcastRadius
  674. : bcast_radius_);
  675.         p->insert(&animations_);
  676.         p->paint(paint_[e.pe.pkt.attr & paintMask_]);
  677.         check_monitors(p);
  678.         break;
  679.       }
  680.       ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst);
  681.       if (ehn == 0 || (ep = ehn->edge) == 0)
  682.         return;
  683.       /*
  684.        * If the current packet will arrive at its destination
  685.        * at a later time, insert the arrival into the queue
  686.        * of animations and set its paint id (id for X graphics
  687.        * context.
  688.        */
  689.       txtime = ep->txtime(e.pe.pkt.size);
  690.       if (e.time + txtime + ep->delay() >= now) {
  691.         /* XXX */
  692.         Packet *p = new Packet(ep, e.pe.pkt, e.time,
  693.                                txtime, e.offset);
  694.         p->insert(&animations_);
  695.         p->paint(paint_[e.pe.pkt.attr & paintMask_]);
  696.         check_monitors(p);
  697.        // fprintf(stderr, "packet %d sent from %d towards %dn",
  698.        //         e.pe.pkt.id, e.pe.src, e.pe.dst);
  699.       }
  700.       break;
  701.     case 'a':
  702.       n = lookupNode(e.ae.src);
  703.       if (n == 0)
  704.         return;
  705.       a = n->find_agent((char *) e.ae.agent.name);
  706.       if ((direction==FORWARDS)&&(e.ae.agent.expired==0)) {
  707.         if (a == NULL) {
  708.           // will only create an agent if there isn't one already 
  709.           // there with the same name
  710.           a = new BoxAgent(e.ae.agent.name, n->size());
  711.           a->Animation::insert(&animations_);
  712.           n->add_agent(a);
  713.           placeAgent(a, n);
  714.         }
  715.       } else {
  716.         if (a != NULL) {
  717.           n->delete_agent(a);
  718.           delete a;
  719.         }
  720.       }
  721.       break;
  722.     case 'f':
  723.       // We don't need any redraw for this, because it's always 
  724.       // displayed in monitors in a separate pane
  725.       n = lookupNode(e.fe.src);
  726.       if (n == 0)
  727.         return;
  728.       a = n->find_agent((char *)e.fe.feature.agent);
  729.       if (a == 0)
  730.         return;
  731.       f = a->find_feature((char *)e.fe.feature.name);
  732.       if (f == 0) {
  733.         switch (e.fe.feature.type) {
  734.         case 'v':
  735.           f = new VariableFeature(a, e.fe.feature.name);
  736.           break;
  737.         case 'l':
  738.           f = new ListFeature(a, e.fe.feature.name);
  739.           break;
  740.         case 's':
  741.         case 'u':
  742.         case 'd':
  743.           f = new TimerFeature(a, e.fe.feature.name);
  744.           break;
  745.         }
  746.         a->add_feature(f);
  747.       }
  748.       if (((direction==FORWARDS) && (e.fe.feature.expired == 0)) ||
  749.           ((direction==BACKWARDS) && (strlen(e.fe.feature.oldvalue) > 0))) {
  750.         char *value;
  751.         double time_set;
  752.         if (direction==FORWARDS) {
  753.           value=(char *)e.fe.feature.value;
  754.           time_set=now;
  755.         } else {
  756.           value=(char *)e.fe.feature.oldvalue;
  757.           /*XXX need an extra value here*/
  758.           time_set=0.0;
  759.         }
  760.         switch (e.fe.feature.type) {
  761.           case 'v':
  762.           case 'l':
  763.             f->set_feature(value);
  764.             break;
  765.           case 's':
  766.             f->set_feature(atof(value), TIMER_STOPPED, time_set);
  767.             break;
  768.           case 'u':
  769.             f->set_feature(atof(value), TIMER_UP, time_set);
  770.             break;
  771.           case 'd':
  772.             f->set_feature(atof(value), TIMER_DOWN, time_set);
  773.             break;
  774.         }
  775.       } else {
  776.         a->delete_feature(f);
  777.         delete f;
  778.       }
  779.       break;
  780.     case 'r':
  781.       if (direction == FORWARDS)
  782.         break;
  783.       if (e.pe.dst == -1) { //broadcasting
  784.         //a quick hack to give fixed transmission + delay time for
  785.         //broadcasting packet
  786.         if (e.time - BPACKET_TXT_TIME > now)
  787.           break ;
  788.         n = lookupNode(e.pe.src);
  789.         BPacket * p = new BPacket(n->x(), n->y(),e.pe.pkt,
  790.                                   e.time,e.offset,direction,
  791.   e.pe.pkt.wBcastDuration
  792.    ? e.pe.pkt.wBcastDuration
  793. : bcast_duration_,
  794.   e.pe.pkt.wBcastRadius
  795.    ? e.pe.pkt.wBcastRadius
  796. : bcast_radius_);
  797.         p->insert(&animations_);
  798.         p->paint(paint_[e.pe.pkt.attr & paintMask_]);
  799.         check_monitors(p);
  800.         break;
  801.       }
  802.       ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst);
  803.       if (ehn == 0 || (ep = ehn->edge) == 0)
  804.         return;
  805.       /*
  806.        * If the current packet will arrive at its destination
  807.        * at a later time, insert the arrival into the queue
  808.        * of animations and set its paint id (id for X graphics
  809.        * context.
  810.        */
  811.       txtime = ep->txtime(e.pe.pkt.size);
  812.       if (e.time - (txtime + ep->delay()) <= now) {
  813.         /* XXX */
  814.         Packet *p = new Packet(ep, e.pe.pkt,
  815.                                e.time-(ep->delay() + txtime),
  816.                                txtime, e.offset);
  817.         p->insert(&animations_);
  818.         p->paint(paint_[e.pe.pkt.attr & paintMask_]);
  819.         check_monitors(p);
  820.       }
  821.       break;
  822.     case '+':
  823.       ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst);
  824.       if (direction == FORWARDS) {
  825.         if (ehn != 0 && ehn->queue != 0) {
  826.           QueueItem *qi = new QueueItem(e.pe.pkt, e.time,
  827.                                         e.offset);
  828.           qi->paint(paint_[e.pe.pkt.attr & paintMask_]);
  829.           ehn->queue->enque(qi,QUEUE_TAIL);
  830.           qi->insert(&animations_);
  831.           check_monitors(qi);
  832.         }
  833.       } else {
  834.         if (ehn != 0 && ehn->queue != 0) {
  835.           q = ehn->queue->remove(e.pe.pkt);
  836.           delete q;
  837.         }
  838.       }
  839.       break;
  840.     case '-':
  841.       ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst);
  842.       if (direction == FORWARDS) {
  843.         if (ehn != 0 && ehn->queue != 0) {
  844.           q = ehn->queue->remove(e.pe.pkt);
  845.           delete q;
  846.         }
  847.       } else {
  848.         if (ehn != 0 && ehn->queue != 0) {
  849.           QueueItem *qi = new QueueItem(e.pe.pkt, e.time,
  850.                                         e.offset);
  851.           qi->paint(paint_[e.pe.pkt.attr & paintMask_]);
  852.           ehn->queue->enque(qi,QUEUE_HEAD);
  853.           qi->insert(&animations_);
  854.           check_monitors(qi);
  855.         }
  856.       }
  857.       break;
  858.     case 'E': {
  859.       // Nothing for now
  860.       Group *grp = lookupGroup(e.pe.dst);
  861.       if (grp == NULL) {
  862.         fprintf(stderr, "Packet destination group %d not foundn",
  863.           e.pe.dst);
  864.         return;
  865.       }
  866.       int *mbr = new int[grp->size()];
  867.       grp->get_members(mbr);
  868.       for (int i = 0; i < grp->size(); i++) {
  869.         QueueItem *qi = new QueueItem(e.pe.pkt, e.time,
  870.               e.offset);
  871.         qi->paint(paint_[e.pe.pkt.attr & paintMask_]);
  872.         n = lookupNode(mbr[i]);
  873.         if (n == 0) {
  874.           fprintf(stderr, 
  875.             "Group member %d not foundn",
  876.             mbr[i]);
  877.           return;
  878.         }
  879.         if (direction == FORWARDS) {
  880.           n->queue()->enque(qi, QUEUE_TAIL);
  881.           qi->insert(&animations_);
  882.           check_monitors(qi);
  883.         } else {
  884.           qi = n->queue()->remove(e.pe.pkt);
  885.           delete qi;
  886.         }
  887.       }
  888.       delete mbr;    
  889.       break;
  890.     }
  891.     case 'D': {
  892.       n = lookupNode(e.pe.dst);
  893.       if (n == NULL) {
  894.         fprintf(stderr, "Bad node id %d for session deque eventn",
  895.           e.pe.dst);
  896.         return;
  897.       }
  898.       if (direction == FORWARDS) {
  899.         q = n->queue()->remove(e.pe.pkt);
  900.         delete q;
  901.       } else {
  902.         QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset);
  903.         qi->paint(paint_[e.pe.pkt.attr & paintMask_]);
  904.         n->queue()->enque(qi, QUEUE_HEAD);
  905.         qi->insert(&animations_);
  906.         check_monitors(qi);
  907.       }
  908.       break;
  909.     }
  910.     case 'P':  // session drop
  911.       // Get packet to drop.
  912.       if (direction == FORWARDS) {
  913.         // fprintf(stderr, "drop on %d -> %dn", e.pe.src, e.pe.dst);
  914.         n = lookupNode(e.pe.dst);
  915.         if (n == 0)
  916.           return;
  917.         q = 0;
  918.         if (n->queue() != 0) {
  919.           // Remove packet from session queue 
  920.           q = n->queue()->remove(e.pe.pkt);
  921.           if (q == 0) {
  922.             // No such packet in queue??? 
  923.             fprintf(stderr, "No packet drop %id in queuen",
  924.                             e.pe.pkt.id);
  925.             return;
  926.           }
  927.           q->position(x,y);
  928.           pno = q->paint();
  929.           delete q;
  930.         }
  931.         
  932.       // Compute the point at which the dropped packet disappears.
  933.       // Let's just make this sufficiently far below the lowest
  934.       // thing on the screen.
  935.     
  936.       // Watch out for topologies that have all their nodes lined
  937.       // up horizontally. In this case, nymin_ == nymax_ == 0.
  938.       // Set the bottom to -0.028. This was chosen empirically.
  939.       // The nam display was set to the maximum size and the lowest
  940.       // position on the display was around -0.028.
  941.      
  942.       float bot;
  943.       if (nymin_ - nymax_ < 0.01)
  944.         bot = nymin_ - 10 * n->size() ;
  945.       else
  946.         bot = nymin_ - (nymax_ - nymin_);
  947.     
  948.       Drop *d = new Drop(x, y, bot, n->size()*0.5, /* This is a hack */
  949.                          e.time, e.offset, e.pe.pkt);
  950.       d->paint(pno);
  951.       d->insert(&animations_);
  952.       check_monitors(d);
  953.       break;
  954.     } else {
  955.       /*direction is BACKWARDS - need to create the packet*/
  956.       //fprintf(stderr, "Packet drop backwardsn");
  957.     }
  958.     case 'G': {
  959.       /* Group event */
  960.       Group *grp = lookupGroup(e.ge.src);
  961.       if (grp == NULL) {
  962.         grp = new Group(e.ge.grp.name, e.ge.src);
  963.         add_group(grp);
  964.       }
  965.       
  966.       if (e.ge.grp.flag == GROUP_EVENT_JOIN) {
  967.         grp->join(e.ge.grp.mbr);
  968.         // XXX
  969.         // Hard-coded queue angle for session queues. :(
  970.         // Create session queue here because they are not like
  971.         // traditional queues which are created when nam
  972.         // started. Group member may dynamically join/leave,
  973.         // so may session queues. We create them here because 
  974.         // there's a 1-1 relationship between join and creating
  975.         // session queues.
  976.         n = lookupNode(e.ge.grp.mbr);
  977.         if (n == NULL) {
  978.           fprintf(stderr, "Bad node %d for group eventn",
  979.             e.ge.grp.mbr);
  980.           return;
  981.         }
  982.         // Need more consideration on the placement of these queues
  983.         Queue *q = new Queue(0.5);
  984.         q->next_ = queues_;
  985.         queues_ = q;
  986.         n->add_sess_queue(e.ge.src, q);
  987.       } else if (e.ge.grp.flag == GROUP_EVENT_LEAVE)
  988.         // No deletion of session queues.
  989.         grp->leave(e.ge.grp.mbr);
  990.       break;
  991.     }
  992.     case 'l': 
  993.       /*link event*/
  994.       // if src or dst = -1 this is a layout link (-t *)
  995.       // so skip over it
  996.       if (e.le.src == -1 || e.le.dst == -1)
  997.         return;
  998.       ehn = lookupEdgeHashNode(e.le.src, e.le.dst);
  999.       if (ehn == 0) {
  1000.         // if edge doesn't exist try to create it dynamically
  1001.         ep = addEdge(e.le.src, e.le.dst, e);
  1002.         if (!ep) {
  1003.           fprintf(stderr, "Unable to create edge(%d,%d) dynamically.n",
  1004.                            e.le.src, e.le.dst);
  1005.           return;
  1006.         }
  1007.         ehn = lookupEdgeHashNode(e.le.src, e.le.dst);
  1008.         do_relayout= true;
  1009.       }
  1010.       ehnrev = lookupEdgeHashNode(e.le.dst, e.le.src);
  1011.       if (ehnrev == 0) {
  1012.         // if edge doesn't exist try to create it dynamically
  1013.         ep = addEdge(e.le.dst, e.le.src, e);
  1014.         if (!ep) {
  1015.           fprintf(stderr, "Unable to create reverse edge(%d,%d) dynamically.n",
  1016.                            e.le.dst, e.le.src);
  1017.           return;
  1018.         }
  1019.         ehnrev = lookupEdgeHashNode(e.le.dst, e.le.src);
  1020.         do_relayout = true;
  1021.       }
  1022.       if (do_relayout) {
  1023.         //relayout();
  1024.         relayoutNode(lookupNode(e.le.src));
  1025.         relayoutNode(lookupNode(e.le.dst));
  1026.         do_relayout = false;
  1027.       }
  1028.       /*note: many link events are bidirectional events so be careful to
  1029.         apply them to both a link and the reverse of it*/
  1030.       if (direction==FORWARDS)  {
  1031.         // Always save the color before the last DOWN event
  1032.         if (strncmp(e.le.link.state, "DOWN", 4)==0) {
  1033.           ehn->edge->set_down("red");
  1034.           ehnrev->edge->set_down("red");
  1035.         } else if (strncmp(e.le.link.state, "UP", 2)==0) {
  1036.           /* XXX Assume an UP event always follows a DOWN event */
  1037.           ehn->edge->set_up();
  1038.           ehnrev->edge->set_up();
  1039.         } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) {
  1040.           ehn->edge->color((char *)e.le.link.color);
  1041.            ehnrev->edge->color((char *)e.le.link.color);
  1042.         } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) {
  1043.           ehn->edge->dlabel((char *)e.le.link.dlabel);
  1044.           ehnrev->edge->dlabel((char *)e.le.link.dlabel);
  1045.         } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) {
  1046.           ehn->edge->dcolor((char *)e.le.link.dcolor);
  1047.           ehnrev->edge->dcolor((char *)e.le.link.dcolor);
  1048.         } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) {
  1049.           ehn->edge->direction((char *)e.le.link.direction);
  1050.           ehnrev->edge->direction((char *)e.le.link.direction);
  1051.         } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) {
  1052.           ehn->edge->direction((char *)e.le.link.direction);
  1053.           ehnrev->edge->direction((char *)e.le.link.direction);
  1054.         } 
  1055.       } else {
  1056.         if (strncmp(e.le.link.state, "UP", 2)==0) {
  1057.           ehn->edge->set_down("red");
  1058.           ehnrev->edge->set_down("red");
  1059.         } else if (strncmp(e.le.link.state, "DOWN", 4)==0) {
  1060.           ehn->edge->set_up();
  1061.         } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) {
  1062.           ehn->edge->color((char *)e.le.link.oldColor);
  1063.           ehnrev->edge->color((char *)e.le.link.oldColor);
  1064.         } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) {
  1065.           ehn->edge->dlabel((char *)e.le.link.odlabel);
  1066.           ehnrev->edge->dlabel((char *)e.le.link.odlabel);
  1067.         } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) {
  1068.           ehn->edge->dcolor((char *)e.le.link.odcolor);
  1069.           ehnrev->edge->dcolor((char *)e.le.link.odcolor);
  1070.         } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) {
  1071.           ehn->edge->direction((char *)e.le.link.odirection);
  1072.           ehnrev->edge->direction((char *)e.le.link.odirection);
  1073.         } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) {
  1074.           ehn->edge->direction((char *)e.le.link.odirection);
  1075.           ehnrev->edge->direction((char *)e.le.link.odirection);
  1076.         }
  1077.     }
  1078.       break;
  1079.     case 'n':
  1080.       /* node event */
  1081.       // Return if node has -t * 
  1082.       // Ths node is only used for initial layout
  1083.       if (e.ne.src == -1)
  1084.         return;
  1085.       n = lookupNode(e.ne.src);
  1086.       if (n == 0) {
  1087.         // if node doesn't exist try to create it dynamically
  1088.         n = addNode(e);
  1089.         if (!n)
  1090.           return;
  1091.       }
  1092.       if (direction==FORWARDS) {
  1093.         if (strncmp(e.ne.node.state, "DOWN", 4)==0) {
  1094.                 n->set_down("gray");
  1095.         } else if (strncmp(e.ne.node.state, "UP", 2)==0) {
  1096.                 n->set_up();
  1097.         } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) {
  1098.                 // normal color can be defined by user
  1099.                 n->color((char *)e.ne.node.color);
  1100.                 n->lcolor((char *)e.ne.node.lcolor);
  1101.         } else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) {
  1102.                 n->dlabel((char *)e.ne.node.dlabel); 
  1103.         } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) {
  1104.                 n->dcolor((char *)e.ne.node.dcolor);
  1105.         } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) {
  1106.                 n->direction((char *)e.ne.node.direction);
  1107.         }
  1108.       } else {
  1109.         if (strncmp(e.ne.node.state, "UP", 4)==0) {
  1110.                 n->set_down("gray");
  1111.         } else if (strncmp(e.ne.node.state, "DOWN", 2)==0) {
  1112.                 n->set_up();
  1113.         } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) {
  1114.                 n->color((char *)e.ne.node.oldColor);
  1115.                 n->lcolor((char *)e.ne.node.olcolor);
  1116.         }  else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) {
  1117.                 n->dlabel((char *)e.ne.node.odlabel);
  1118.         } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) {
  1119.                 n->dcolor((char *)e.ne.node.odcolor);
  1120.         } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) {
  1121.                 n->direction((char *)e.ne.node.odirection);
  1122.         }
  1123.       }  
  1124.       break;
  1125.     case 'm':
  1126.       /* node mark event */
  1127.       NodeMark *cm;
  1128.       n = lookupNode(e.me.src);
  1129.       if (n == 0)
  1130.         return;
  1131.       cm = n->find_mark((char *) e.me.mark.name);
  1132.       if (direction == FORWARDS) {
  1133.         if (e.me.mark.expired == 0) {
  1134.           /* once created, a node mark cannot be changed*/
  1135.           if (cm == NULL) 
  1136.             n->add_mark((char *)e.me.mark.name, 
  1137.                         (char *)e.me.mark.color,
  1138.                         (char *)e.me.mark.shape);
  1139.         } else 
  1140.           /* expired */
  1141.           n->delete_mark((char *)e.me.mark.name);
  1142.       } else {
  1143.         /* 
  1144.          * backward: 
  1145.          * (1) create it if expired == 1
  1146.          * (2) delete it if expired == 0
  1147.          */
  1148.         if (e.me.mark.expired == 0) 
  1149.           n->delete_mark((char *)e.me.mark.name);
  1150.         else {
  1151.           /* re-create the circle */
  1152.           if (cm == NULL)
  1153.             n->add_mark((char *)e.me.mark.name, 
  1154.             (char *)e.me.mark.color,
  1155.             (char *)e.me.mark.shape);
  1156.         }
  1157.       }
  1158.       break;
  1159.     case 'R':
  1160.       // route event
  1161.       if (((e.re.route.expired==0)&&(direction==FORWARDS))||
  1162.           ((e.re.route.expired==1)&&(direction==BACKWARDS))) {
  1163.          // this is a new route
  1164.         n = lookupNode(e.re.src);
  1165.         if (n == 0)
  1166.           return;
  1167.         ehn = lookupEdgeHashNode(e.re.src, e.re.dst);
  1168.         if (ehn == 0)
  1169.           return;
  1170.         int oif=1;
  1171.         if (strncmp(e.re.route.mode, "iif", 3)==0)
  1172.           oif=0;
  1173.         r = new Route(n, ehn->edge, e.re.route.group, e.re.route.pktsrc, 
  1174.                       e.re.route.neg, oif, e.re.route.timeout, now);
  1175.         n->add_route(r);
  1176.         n->place_route(r);
  1177.         r->insert(&animations_);
  1178.         r->paint(paint_[e.re.route.group & paintMask_]);
  1179.         check_monitors(r);
  1180.       } else {
  1181.         // an old route expired
  1182.         n = lookupNode(e.re.src);
  1183.         if (n == 0)
  1184.           return;
  1185.         
  1186.         // src and dst are node ids 
  1187.         ehn = lookupEdgeHashNode(e.re.src, e.re.dst);
  1188.         if (ehn == 0)
  1189.           return;
  1190.         int oif = 1;
  1191.         if (strncmp(e.re.route.mode, "iif", 3) == 0) {
  1192.           oif=0;
  1193.         }
  1194.         r = n->find_route(ehn->edge, e.re.route.group,
  1195.                           e.re.route.pktsrc, oif);
  1196.         if (r == 0) {
  1197.           fprintf(stderr, "nam: attempt to delete non-existent routen");
  1198.           abort();
  1199.         }
  1200.         n->delete_route(r);
  1201.         delete r;
  1202.       }
  1203.       break;
  1204.     case 'd':
  1205.       add_drop(e, now, direction);
  1206.   }
  1207. }
  1208. //---------------------------------------------------------------------
  1209. //  void
  1210. // NetModel::add_drop(const TraceEvent &e, double now, int direction)
  1211. //   - This method adds a packet drop animation to the animations_ list
  1212. //   - Packet drops can occur from queues and edges.  If the queue is 
  1213. //     not being displayed the packet is dropped from the node
  1214. //     position.
  1215. //   - If the animation direction is BACKWARDS a packet should be
  1216. //     created but it appears that this code does not do that.
  1217. //---------------------------------------------------------------------
  1218. void
  1219. NetModel::add_drop(const TraceEvent &e, double now, int direction) {
  1220.   EdgeHashNode *ehn;
  1221.   QueueItem *q;
  1222.   Packet *p;
  1223.   Lan *lan;
  1224.   float x, y;
  1225.   int pno;  // paint number (color with which to draw)
  1226.   
  1227.   // Get packet to drop. 
  1228.   if (direction == FORWARDS) {
  1229.     ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst);
  1230.     if (ehn == 0) {
  1231.      return;
  1232.     }
  1233.     q = 0;
  1234.     if (ehn->queue != 0) {
  1235.       // if there's a queue, try removing it from the queue first
  1236.       // queue drops are more common than link drops...
  1237.       q = ehn->queue->remove(e.pe.pkt);
  1238.     }
  1239.     if (q == 0) {
  1240.       // perhaps it's a link packet drop
  1241.       p = lookupPacket(e.pe.src, e.pe.dst, e.pe.pkt.id);
  1242.       if (p != NULL) {
  1243.         // it was a link packet drop
  1244.         p->position(x, y, now);
  1245.         ehn->edge->DeletePacket(p);
  1246.         pno = p->paint();
  1247.         delete p;
  1248.       } else if ((lan = lookupLan(e.pe.src)) != NULL) {
  1249.         /* 
  1250.          * If it's a Lan (selective) packet drop, which means
  1251.          * the packet is only dropped on some of the lan links,
  1252.          * register the packet on the lan and drop it when the
  1253.          * packet is actually transmitted to that lan link.
  1254.          *
  1255.          * When the packet is actually dropped, this function will be 
  1256.          * called again, but at that time the packet will be actually
  1257.          * on the link and this code will not be executed.
  1258.          */
  1259.         lan->register_drop(e);
  1260.         return;
  1261.       } else {
  1262.         // probably it was a queue drop, but we're not displaying
  1263.         // that queue
  1264.        
  1265.         // It's possible that this packet is dropped directly from 
  1266.         // the queue, even before the enqT_ module. In this case, 
  1267.         // we should still produce a packet drop; we use the position
  1268.         // of the node to generate the drop.
  1269.         Node *s = lookupNode(e.pe.src);
  1270.         if (s == NULL) {
  1271.           fprintf(stderr, "NetModel::add_drop(): cannot find src node for packet drop.n");
  1272.           abort();
  1273.         }
  1274.         x = s->x();
  1275.         y = s->y();
  1276.         pno = paint_[e.pe.pkt.attr & paintMask_];
  1277.       }
  1278.     } else {
  1279.       // packet dropped from queue
  1280.       // get x,y position of queue item
  1281.       q->position(x, y);
  1282.       pno = q->paint();
  1283.       delete q;
  1284.     }
  1285.     /*
  1286.      * Compute the point at which the dropped packet disappears.
  1287.      * Let's just make this sufficiently far below the lowest
  1288.      * thing on the screen.
  1289.      *
  1290.      * Watch out for topologies that have all their nodes lined
  1291.      * up horizontally. In this case, nymin_ == nymax_ == 0.
  1292.      * Set the bottom to -0.028. This was chosen empirically.
  1293.      * The nam display was set to the maximum size and the lowest
  1294.      * position on the display was around -0.028.
  1295.      */
  1296.     float bottom;
  1297.     if (nymin_ - nymax_ < 0.01) {
  1298.       bottom = nymin_ - 20.0 * ehn->edge->PacketHeight() ;
  1299.     } else {
  1300.       bottom = nymin_ - (nymax_ - nymin_);
  1301.     }
  1302.     
  1303.     // The drop animation is taken care of by the drop class
  1304.     Drop * d = new Drop(x, y, bottom, 4 * ehn->edge->PacketHeight(),
  1305.                         e.time, e.offset, e.pe.pkt);
  1306.     d->paint(pno);
  1307.     d->insert(&animations_);
  1308.     check_monitors(d);
  1309.     return;
  1310.   } else {
  1311.     // direction is BACKWARDS - need to create the packet
  1312.     Lan *lan = lookupLan(e.pe.src);
  1313.     if (lan != NULL) {
  1314.        // We need to remove drop status in lans
  1315.       lan->remove_drop(e);
  1316.       //fprintf(stderr, "lan dropped packet %d is removed on lan link %d->%dn",
  1317.       //                e.pe.pkt.id, e.pe.src, e.pe.dst);
  1318.       return;
  1319.     }
  1320.   }
  1321. }
  1322. //----------------------------------------------------------------------------
  1323. // Node *
  1324. // NetModel::addNode(const TraceEvent &e)
  1325. //   - adds a node to the netmodel getting configuration info from the fields
  1326. //     in the TraceEvent
  1327. //----------------------------------------------------------------------------
  1328. Node *
  1329. NetModel::addNode(const TraceEvent &e)  {
  1330.   Node * n = NULL;
  1331.   char src[32];
  1332.   if (e.tt == 'n') {
  1333.     sprintf(src, "%d", e.ne.src);
  1334.     n = lookupNode(e.ne.src);
  1335.     // And remove them to be replaced by this node
  1336.     if (n != NULL) {
  1337.       fprintf(stderr, "Skipping duplicate node %s definition. n", src);
  1338.       //removeNode(n);
  1339.     }
  1340.     // Determine Node Type
  1341.     if (!strncmp(e.ne.mark.shape, "circle",6)) {
  1342.       n = new CircleNode(src, e.ne.size);
  1343.     } else if (!strncmp(e.ne.mark.shape, "box", 3) || 
  1344.                !strncmp(e.ne.mark.shape, "square", 6)) {
  1345.       n = new BoxNode(src, e.ne.size);
  1346.     } else if (!strncmp(e.ne.mark.shape, "hexagon",7)) { 
  1347.       n = new HexagonNode(src, e.ne.size);
  1348.     } else {
  1349.       return NULL;
  1350.     }
  1351.     // Check for wireless node
  1352.     if (e.ne.wireless) {
  1353.       n->wireless_ = true;
  1354.       //fprintf(stderr, "We have wireless nodes :-) !!!n");
  1355.     }
  1356.     // Node Address
  1357.     //  May need to check for no address passed in
  1358.     n->setaddr(e.ne.node.addr);
  1359.     addAddress(n->num(), e.ne.node.addr);
  1360.     // Node Color
  1361.     n->init_color(e.ne.node.color);
  1362.     n->lcolor(e.ne.node.lcolor);
  1363.     // dlabel initilization
  1364.     n->dlabel(e.ne.node.dlabel);
  1365.     // Set X,Y cordinates
  1366.     n->place(e.ne.x, e.ne.y);
  1367.     
  1368.     // Add Node to drawables list
  1369.     n->next_ = nodes_;
  1370.     nodes_ = n;
  1371.     n->Animation::insert(&drawables_);
  1372.     // Set Packet size to be running average of the last 5 nodes (25% of node size)
  1373.     packet_size_ = (4.0 * packet_size_ + e.ne.size*0.25)/5.0;
  1374.   }
  1375.   return (n);
  1376. }
  1377. //----------------------------------------------------------------------------
  1378. // Edge * 
  1379. // NetModel::addEdge(int argc, const char *const *argv)
  1380. //
  1381. //  <net> link <src> <dst> <bandwidth> <delay> <angle>
  1382. //  Create a link/edge between the specified source
  1383. //  and destination. Add it to this NetModel's list
  1384. //  of drawables and to the source's list of links.
  1385. //----------------------------------------------------------------------------
  1386. Edge * 
  1387. NetModel::addEdge(int argc, const char *const *argv) {
  1388.   Node * src, * dst;
  1389.   Edge * edge = NULL;
  1390.   double bandwidth, delay, length, angle;
  1391.   if (strcmp(argv[1], "link") == 0) {
  1392.     src = lookupNode(atoi(argv[2]));
  1393.     dst = lookupNode(atoi(argv[3]));
  1394.     
  1395.     if (src && dst) {
  1396.       bandwidth = atof(argv[4]);
  1397.       delay = atof(argv[5]);
  1398.       length = atof(argv[6]);
  1399.       angle = atof(argv[7]);
  1400.                         
  1401.       //enlarge link if the topology is a mixture of
  1402.       //wired and wireless network
  1403.       if (wireless_) {
  1404.         length = delay * WIRELESS_SCALE ;
  1405.       }
  1406.       edge = new Edge(src, dst, packet_size_, bandwidth, delay, length, angle, wireless_);
  1407.       edge->init_color("black");
  1408.       enterEdge(edge);
  1409.       edge->Animation::insert(&drawables_);
  1410.       src->add_link(edge);
  1411.     }
  1412.   }
  1413.   return edge;
  1414. }
  1415. //----------------------------------------------------------------------------
  1416. //
  1417. //----------------------------------------------------------------------------
  1418. Edge * 
  1419. NetModel::addEdge(int src_id, int dst_id, const TraceEvent &e) {
  1420.   Node *src, *dst;
  1421.   Edge * edge = NULL;
  1422.   double bandwidth, delay, length, angle;
  1423.   if (e.tt == 'l') {
  1424.     src = lookupNode(src_id);
  1425.     dst = lookupNode(dst_id);
  1426.     
  1427.     if (src && dst) {
  1428.       bandwidth = e.le.link.rate;
  1429.       delay = e.le.link.delay;
  1430.       length = e.le.link.length;
  1431.       angle = e.le.link.angle;
  1432.                         
  1433.       //enlarge link if the topology is a mixture of
  1434.       //wired and wireless network
  1435.       if (wireless_) {
  1436.         length = delay * WIRELESS_SCALE ;
  1437.       }
  1438.       edge = new Edge(src, dst, packet_size_, bandwidth, delay, length, angle, wireless_);
  1439.       edge->init_color("black");
  1440.       enterEdge(edge);
  1441.       edge->Animation::insert(&drawables_);
  1442.       src->add_link(edge);
  1443.     }
  1444.   }
  1445.   return edge;
  1446. }
  1447. void NetModel::addView(NetView* p)
  1448. {
  1449. p->next_ = views_;
  1450. views_ = p;
  1451. }
  1452. //----------------------------------------------------------------------
  1453. // Node * 
  1454. // NetModel::lookupNode(int nn) const
  1455. //----------------------------------------------------------------------
  1456. Node *
  1457. NetModel::lookupNode(int nn) const {
  1458.   for (Node* n = nodes_; n != 0; n = n->next_)
  1459.     if (n->num() == nn)
  1460.       return (n);
  1461.   return NULL;
  1462. }
  1463. //----------------------------------------------------------------------
  1464. // Edge *
  1465. // NetModel::lookupEdge(int source, int destination) const
  1466. //----------------------------------------------------------------------
  1467. Edge *
  1468. NetModel::lookupEdge(int source, int destination) const {
  1469. EdgeHashNode * edge_hash_node;
  1470. edge_hash_node = lookupEdgeHashNode(source, destination);
  1471. return edge_hash_node->edge;
  1472. }
  1473. void NetModel::removeNode(Node *n) 
  1474. {
  1475. Node *p, *q;
  1476. // Remove node n from nodes_ list, then delete it
  1477. for (p = nodes_; p != 0; q = p, p = p->next_)
  1478. if (p == n)
  1479. break;
  1480. if (p == nodes_)
  1481. nodes_ = p->next_;
  1482. else
  1483. q->next_ = p->next_;
  1484. delete p;
  1485. }
  1486. Agent *NetModel::lookupAgent(int id) const
  1487. {
  1488. for (Node* n = nodes_; n != 0; n = n->next_) 
  1489. for(Agent* a= n->agents(); a != 0; a = a->next_) 
  1490. if (a->number() == id) 
  1491. return (a);
  1492. return (0); 
  1493. }
  1494. Lan *NetModel::lookupLan(int nn) const
  1495. {
  1496. for (Lan* l = lans_; l != 0; l = l->next_)
  1497. if (l->num() == nn)
  1498. return (l);
  1499. /* XXX */
  1500. //fprintf(stderr, "nam: no such lan %dn", nn);
  1501. //exit(1);
  1502. return (0);// make visual c++ happy
  1503. }
  1504. Packet *NetModel::newPacket(PacketAttr &pkt, Edge *e, double time)
  1505. {
  1506.   /*this is called when we get a triggered event such as a packet
  1507.     getting duplicated within a LAN*/
  1508.   Packet *p = new Packet(e, pkt, time, e->txtime(pkt.size), 0);
  1509.   p->insert(&animations_);
  1510.   p->paint(paint_[pkt.attr & paintMask_]);
  1511.   check_monitors(p);
  1512.   return p;
  1513. }
  1514. Packet *NetModel::lookupPacket(int src, int dst, int id) const
  1515. {
  1516.   EdgeHashNode *h = lookupEdgeHashNode(src, dst);
  1517.   if (h == 0)
  1518.     return NULL;
  1519.   int ctr=0;
  1520.   for (Packet *p=h->edge->packets(); p!=NULL; p=p->next())
  1521.     {
  1522. #define PARANOID
  1523. #ifdef PARANOID
  1524.       ctr++;
  1525.       if (ctr>h->edge->no_of_packets()) abort();
  1526. #endif
  1527.       if (p->id() == id)
  1528. return p;
  1529.     }
  1530.   /*have to fail silent or we can't cope with link drops when doing settime*/
  1531.   return 0;
  1532. }
  1533. /* Do not delete groups, because they are not explicitly deleted */
  1534. int NetModel::add_group(Group *grp)
  1535. {
  1536. int newEntry = 1;
  1537. Tcl_HashEntry *he = Tcl_CreateHashEntry(grpHash_,
  1538.                                         (const char *)grp->addr(), 
  1539.                                         &newEntry);
  1540. if (he == NULL)
  1541. return -1;
  1542. if (newEntry) {
  1543. Tcl_SetHashValue(he, (ClientData)grp);
  1544. nGroup_++;
  1545. }
  1546. return 0;
  1547. }
  1548. Group* NetModel::lookupGroup(unsigned int addr)
  1549. {
  1550. Tcl_HashEntry *he = Tcl_FindHashEntry(grpHash_, (const char *)addr);
  1551. if (he == NULL)
  1552. return NULL;
  1553. return (Group *)Tcl_GetHashValue(he);
  1554. }
  1555. // Remove a view from the views link, but not delete it
  1556. void NetModel::remove_view(View *v)
  1557. {
  1558. View *p, *q;
  1559. p = q = views_;
  1560. if (p == v) {
  1561. views_ = p->next_;
  1562. return;
  1563. }
  1564. while (p != NULL) {
  1565. q = p;
  1566. p = p->next_;
  1567. if (p == v) {
  1568. q->next_ = p->next_;
  1569. return;
  1570. }
  1571. }
  1572. }
  1573. //----------------------------------------------------------------------
  1574. // int
  1575. // NetModel::command(int argc, const char *const *argv)
  1576. //   - Parses tcl commands (hook to enter c++ code from tcl)
  1577. //----------------------------------------------------------------------
  1578. int NetModel::command(int argc, const char *const *argv) {
  1579. Tcl& tcl = Tcl::instance();
  1580. int i;
  1581. Node * node;
  1582. double time;
  1583. if (argc == 2) {
  1584. if (strcmp(argv[1], "layout") == 0) {
  1585. /*
  1586.  * <net> layout
  1587.  * Compute reasonable defaults for missing node or edge
  1588.  * sizes based on the maximum link delay. Lay out the
  1589.  * nodes and edges as specified in the layout file.
  1590.  */
  1591. scale_estimate();
  1592. placeEverything();
  1593. return (TCL_OK);
  1594. }
  1595. if (strcmp(argv[1], "showtrees") == 0) {
  1596. /*
  1597.  * <net> showtrees
  1598.  */
  1599. color_subtrees();
  1600. for (View* p = views_; p != 0; p = p->next_) {
  1601. p->draw();
  1602. }
  1603. return (TCL_OK);
  1604. }
  1605. if (strcmp(argv[1],"resetFilter")==0) {
  1606.         resetf_ = 1 ;
  1607.                 selectedSrc_ = -1 ;
  1608.         selectedDst_ = -1 ;
  1609.         selectedFid_ = -1 ;
  1610.                 colorSrc_ = -1 ;
  1611.         colorDst_ = -1 ;
  1612.         colorFid_ = -1 ;
  1613.                 hideSrc_ = -1 ;
  1614.         hideDst_ = -1 ;
  1615.         hideFid_ = -1 ;
  1616.                 for (i = 0; i < PTYPELEN; ++i) {
  1617.                    selectedTraffic_[i] = '' ;
  1618.                    colorTraffic_[i] = '' ;
  1619.                    hideTraffic_[i] = '' ;
  1620.                         }
  1621. return (TCL_OK);
  1622. }
  1623. } else if (argc == 3) {
  1624. if (strcmp(argv[1], "incr-nodesize") == 0) {
  1625. /*
  1626.  * <net> incr-nodesize <factor>
  1627.  */
  1628. node_sizefac_ *= atof(argv[2]);
  1629. for (Node *n = nodes_; n != 0; n = n->next_)
  1630. for (Edge *e=n->links(); e != 0; e = e->next_)
  1631. e->unmark();
  1632. scale_estimate();
  1633. placeEverything();
  1634. for (View *p = views_; p != 0; p = p->next_)
  1635. if ((p->width() > 0) && (p->height() > 0)) {
  1636. p->redrawModel();
  1637. p->draw();
  1638. }
  1639. return (TCL_OK);
  1640. }
  1641. if (strcmp(argv[1], "decr-nodesize") == 0) {
  1642. node_sizefac_ /= atof(argv[2]);
  1643. for (Node *n = nodes_; n != 0; n = n->next_)
  1644. for (Edge *e=n->links(); e != 0; e = e->next_)
  1645. e->unmark();
  1646. scale_estimate();
  1647. placeEverything();
  1648. for (View *p = views_; p != 0; p = p->next_)
  1649. if ((p->width() > 0) && (p->height() > 0)) {
  1650. p->redrawModel();
  1651. p->draw();
  1652. }
  1653. return(TCL_OK);
  1654. }
  1655. if (strcmp(argv[1], "updateNodePositions") == 0) {
  1656. time = strtod(argv[2], NULL);
  1657. for (node = nodes_; node; node = node->next_) {
  1658. node->updatePositionAt(time);
  1659. moveNode(node);  // This updates the links and agents connected to the node
  1660. }
  1661. return TCL_OK;
  1662. }
  1663. if (strcmp(argv[1], "view") == 0) {
  1664. /*
  1665.  * <net> view <viewName>
  1666.  * Create the window for the network layout/topology.
  1667.  * Used for nam editor
  1668.  */
  1669. EditView *v = new EditView(argv[2], this, 300, 700);
  1670. v->next_ = views_;
  1671. views_ = v;
  1672. return (TCL_OK);
  1673. }
  1674. if (strcmp(argv[1], "psview") == 0) {
  1675. /*
  1676.  * <net> PSView <fileName>
  1677.  * Print the topology to a file
  1678.  */
  1679. PSView *v = new PSView(argv[2], this);
  1680. v->render();
  1681. delete(v);
  1682. return (TCL_OK);
  1683. }
  1684. if (strcmp(argv[1], "testview") == 0) {
  1685. /*
  1686.  * Added for nam validation test 
  1687.  */
  1688. TestView *v = new TestView(argv[2], this);
  1689. v->render();
  1690. delete(v);
  1691. return (TCL_OK);
  1692. }
  1693. if (strcmp(argv[1], "editview") == 0) {
  1694. /*
  1695.  * <net> editview <viewname>
  1696.  */
  1697. EditView *v = new EditView(argv[2], this);
  1698. v->next_ = views_;
  1699. views_ = v;
  1700. return (TCL_OK);
  1701. }
  1702. if (strcmp(argv[1],"savelayout")==0) {
  1703.         save_layout(argv[2]);
  1704. return (TCL_OK);
  1705. }
  1706. if (strcmp(argv[1],"select-traffic")==0) {
  1707.         strcpy(selectedTraffic_,argv[2]);
  1708. return (TCL_OK);
  1709. }
  1710. if (strcmp(argv[1],"select-src")==0) {
  1711.         selectedSrc_ = atoi(argv[2]);
  1712. return (TCL_OK);
  1713. }
  1714. if (strcmp(argv[1],"select-dst")==0) {
  1715.         selectedDst_ = atoi(argv[2]);
  1716. return (TCL_OK);
  1717. }
  1718. if (strcmp(argv[1],"select-fid")==0) {
  1719.         selectedFid_ = atoi(argv[2]);
  1720. return (TCL_OK);
  1721. }
  1722. if (strcmp(argv[1],"hide-traffic")==0) {
  1723.         strcpy(hideTraffic_,argv[2]);
  1724. return (TCL_OK);
  1725. }
  1726. if (strcmp(argv[1],"hide-src")==0) {
  1727.         hideSrc_ = atoi(argv[2]);
  1728. return (TCL_OK);
  1729. }
  1730. if (strcmp(argv[1],"hide-dst")==0) {
  1731.         hideDst_ = atoi(argv[2]);
  1732. return (TCL_OK);
  1733. }
  1734. if (strcmp(argv[1],"hide-fid")==0) {
  1735.         hideFid_ = atoi(argv[2]);
  1736. return (TCL_OK);
  1737. }
  1738. if (strcmp(argv[1],"color-traffic")==0) {
  1739.         resetf_ = 0 ;
  1740.         strcpy(colorTraffic_,argv[2]);
  1741. return (TCL_OK);
  1742. }
  1743. if (strcmp(argv[1],"color-src")==0) {
  1744.         resetf_ = 0 ;
  1745.         colorSrc_ = atoi(argv[2]);
  1746. return (TCL_OK);
  1747. }
  1748. if (strcmp(argv[1],"color-dst")==0) {
  1749.         resetf_ = 0 ;
  1750.         colorDst_ = atoi(argv[2]);
  1751. return (TCL_OK);
  1752. }
  1753. if (strcmp(argv[1],"color-fid")==0) {
  1754.         resetf_ = 0 ;
  1755.         colorFid_ = atoi(argv[2]);
  1756. return (TCL_OK);
  1757. }
  1758. if (strcmp(argv[1],"select-color")==0) {
  1759. Paint *paint = Paint::instance();
  1760.         selectedColor_ = paint->lookup(argv[2], 1);
  1761. if (selectedColor_ < 0) {
  1762.   fprintf(stderr,"%s color: no such color: %sn",
  1763.   argv[0], argv[2]);
  1764.   selectedColor_ = paint->lookup("black",1);
  1765.   if (selectedColor_ < 0) {
  1766.     tcl.resultf("%s no black! - bailing");
  1767.     return (TCL_ERROR);
  1768.   }
  1769. }
  1770. return (TCL_OK);
  1771.     }
  1772.   if (strcmp(argv[1], "node") == 0) {
  1773. //  else if (argc == 3 && strcmp(argv[1], "node") == 0)
  1774. /*
  1775.  * <net> node <name> <shape> <color> <addr> [<size>]
  1776.  * Create a node using the specified name
  1777.  * and the default size and insert it into this
  1778.  * NetModel's list of drawables.
  1779.  */
  1780. //Node* n = addNode(argc, argv);
  1781.       
  1782.       char * line = new char[strlen(argv[2])];
  1783.       strncpy(line, argv[2],strlen(argv[2]));
  1784.       parsetable_.parseLine(line);
  1785.    Node * node = addNode(traceevent_);
  1786.       delete line;
  1787.    if (node) {
  1788.    return (TCL_OK);
  1789.    } else {
  1790.    tcl.resultf("Unable to create Node %s.", argv[2]);
  1791.    return (TCL_ERROR);
  1792.    }
  1793.     }
  1794. } else if (argc >= 4 && strcmp(argv[1], "agent") == 0) {
  1795. // Create a new agent
  1796.     
  1797. /*
  1798.  * <net> agent <label> <role> <node> <flowcolor> <winInit> 
  1799.  *             <win> <maxcwnd>
  1800.  *             <tracevar> <start> <producemore> <stop>
  1801.  * <net> agent <label> <role> <node> <flowcolor> <packetSize>
  1802.  *       <interval> <start> <stop>
  1803.  */
  1804. int node = atoi(argv[4]);
  1805. int partner_num;
  1806. Node *n = lookupNode(node);
  1807.     
  1808. if (n == 0) {
  1809. tcl.resultf("Node %d doesn't exist.", node);
  1810. return (TCL_ERROR);
  1811. }
  1812. Agent *a = new BoxAgent((char *)argv[2], n->size());
  1813. if (a == 0) {
  1814. tcl.resultf("Cannot create Agent %s exist on Node %d",
  1815.     argv[2], node);
  1816. return (TCL_ERROR);
  1817. }
  1818. placeAgent(a, n);
  1819. a->node_ = n;
  1820. n->add_agent(a);
  1821.     
  1822. a->AgentRole_ = (atoi(argv[3]));
  1823. if (a->AgentRole_ == 20) {
  1824. a->setNumber(atoi(argv[5]));
  1825. partner_num = (atoi(argv[6]));
  1826. Agent *partner = lookupAgent(partner_num);
  1827. if (partner) {
  1828. a->AgentPartner_ = partner;
  1829. partner->AgentPartner_ = a;
  1830. }
  1831. } else if ((a->AgentRole_ == 10) && 
  1832.    (strcmp(argv[2], "CBR") == 0)) {
  1833. if (strcmp(argv[5],"(null)")!=0)
  1834. a->flowcolor((char *)argv[5]);
  1835. a->packetSize(atoi(argv[6]));
  1836. a->interval(atoi(argv[7]));
  1837. a->startAt(atof(argv[8]));
  1838. a->stopAt(atof(argv[9]));
  1839. a->setNumber(atoi(argv[10]));
  1840. partner_num = (atoi(argv[11]));
  1841. Agent *partner = lookupAgent(partner_num);
  1842. if (partner) {
  1843. a->AgentPartner_ = partner;
  1844. partner->AgentPartner_ = a;
  1845. }
  1846. } else if (a->AgentRole_ != 0) {
  1847. if (strcmp(argv[5],"(null)")!=0)
  1848. a->flowcolor((char *)argv[5]);
  1849. a->windowInit(atoi(argv[6]));
  1850. a->window(atoi(argv[7]));
  1851. a->maxcwnd(atoi(argv[8]));
  1852. a->tracevar((char *)argv[9]);
  1853. a->startAt(atof(argv[10]));
  1854. a->produce(atoi(argv[11]));
  1855. a->stopAt(atof(argv[12]));
  1856. a->setNumber(atoi(argv[13]));
  1857. partner_num = (atoi(argv[14]));
  1858. Agent *partner = lookupAgent(partner_num);
  1859. if (partner) {
  1860. a->AgentPartner_ = partner;
  1861. partner->AgentPartner_ = a;
  1862. }
  1863. }
  1864. a->Animation::insert(&animations_);
  1865. return (TCL_OK);
  1866. } else if (argc == 4) {
  1867. if (strcmp(argv[1], "new_monitor_agent") == 0) {
  1868. /* 
  1869.  * <net> new_monitor_agent <node_id> <agent_name>
  1870.  */
  1871. int node = atoi(argv[2]);
  1872. Node *n = lookupNode(node);
  1873. if (n == 0) {
  1874. tcl.resultf("Node %d doesn't exist.", node);
  1875. return (TCL_ERROR);
  1876. }
  1877. Agent *a = n->find_agent((char *)argv[3]);
  1878. if (a == 0) {
  1879. tcl.resultf("Agent %s not exist at node %d",
  1880.     argv[3], node);
  1881. return (TCL_ERROR);
  1882. }
  1883. tcl.resultf("%d", add_monitor(a));
  1884. return (TCL_OK);
  1885. }
  1886. if (strcmp(argv[1], "color") == 0) {
  1887. /*
  1888.  * <net> color <packetClass> <colorName>
  1889.  * Display packets of the specified class using
  1890.  * the specified color.
  1891.  */
  1892. int c = atoi(argv[2]);
  1893. //   if ((unsigned int)c > 1024) {
  1894. //   tcl.resultf("%s color: class %d out of range",
  1895. //       argv[0], c);
  1896. //   return (TCL_ERROR);
  1897. //   }
  1898. // Convert this color index to [0,255], so that 
  1899. // it matches correctly with packet flow ids.
  1900. Paint *paint = Paint::instance();
  1901. if (c > nclass_) {
  1902. int n, i;
  1903. for (n = nclass_; n < c; n <<= 1);
  1904. int *p = new int[n];
  1905. for (i = 0; i < nclass_; ++i)
  1906. p[i] = paint_[i];
  1907. delete paint_;
  1908. paint_ = p;
  1909. nclass_ = n;
  1910. paintMask_ = nclass_ - 1;
  1911. int pno = paint->thin();
  1912. for (; i < n; ++i)
  1913. paint_[i] = pno;
  1914. }
  1915. int pno = paint->lookup(argv[3], 1);
  1916. if (pno < 0) {
  1917.   fprintf(stderr,"%s color: no such color: %sn",
  1918.   argv[0], argv[3]);
  1919.   pno = paint->lookup("black",1);
  1920.   if (pno < 0) {
  1921.     tcl.resultf("%s no black! - bailing");
  1922.     return (TCL_ERROR);
  1923.   }
  1924. }
  1925. paint_[c] = pno;
  1926. oldpaint_[c] = pno;
  1927. return (TCL_OK);
  1928. }
  1929.     
  1930. if (strcmp(argv[1], "ncolor") == 0) {
  1931. /*
  1932.  * <net> ncolor <node> <colorName>
  1933.  * set color of node to the specified color.
  1934.  */
  1935. Paint *paint = Paint::instance();
  1936. Node *n = lookupNode(atoi(argv[2]));
  1937. if (n == NULL) {
  1938. fprintf(stderr, "No such node %sn", argv[2]);
  1939. exit(1);
  1940. }
  1941. int pno = paint->lookup(argv[3], 3);
  1942. if (pno < 0) {
  1943.   fprintf(stderr,"%s ncolor: no such color: %sn",
  1944.   argv[0], argv[3]);
  1945.   int pno = paint->lookup("black",1);
  1946.   if (pno < 0) {
  1947.     tcl.resultf("%s no black! - bailing");
  1948.     return (TCL_ERROR);
  1949.   }
  1950. }
  1951. n->paint(pno);
  1952. return (TCL_OK);
  1953. }
  1954.       
  1955.   // ----- 5 tcl arguments ------
  1956. } else if (argc == 5) {
  1957. if (strcmp(argv[1], "select-pkt") == 0) {
  1958. selectPkt(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
  1959. return(TCL_OK);
  1960. }
  1961. if (strcmp(argv[1], "lookupColorName") == 0) {
  1962. /*
  1963.  * <net> lookupColorName red green blue
  1964.  * get color name from its rgb value 
  1965.  */   
  1966.  Paint *paint = Paint::instance();
  1967.  int r = atoi(argv[2]);
  1968.  int g = atoi(argv[3]);
  1969.  int b = atoi(argv[4]);
  1970.  tcl.resultf("%s",paint->lookupName(r,g,b));
  1971.  return(TCL_OK);
  1972. }
  1973. if (strcmp(argv[1], "queue") == 0) {
  1974. /*
  1975.  * <net> queue <src> <dst> <angle>
  1976.  * Create a queue for the edge from 'src' to 'dst'.
  1977.  * Add it to this NetModel's queue list.
  1978.  * Display the queue at the specified angle from
  1979.  * the edge to which it belongs.
  1980.  */
  1981. int src = atoi(argv[2]);
  1982. int dst = atoi(argv[3]);
  1983. EdgeHashNode *h = lookupEdgeHashNode(src, dst);
  1984. if (h == 0) {
  1985. tcl.resultf("%s queue: no such edge (%d,%d)",
  1986.     argv[0], src, dst);
  1987. return (TCL_ERROR);
  1988. }
  1989. /* XXX can we assume no duplicate queues? */
  1990. double angle = atof(argv[4]);
  1991. Edge *e = h->edge;
  1992. angle += e->angle();
  1993. Queue *q = new Queue(angle);
  1994. h->queue = q;
  1995. q->next_ = queues_;
  1996. queues_ = q;
  1997. return (TCL_OK);
  1998. }
  1999. if (strcmp(argv[1], "ecolor") == 0) {
  2000. /*
  2001.  * <net> ecolor <src> <dst> <colorName>
  2002.  * set color of edge to the specified color.
  2003.  */
  2004. Paint *paint = Paint::instance();
  2005. EdgeHashNode* h = lookupEdgeHashNode(atoi(argv[2]), atoi(argv[3]));
  2006. if (h == 0) {
  2007. tcl.resultf("%s ecolor: no such edge (%s,%s)",
  2008.     argv[0], argv[2], argv[3]);
  2009. return (TCL_ERROR);
  2010. }
  2011. int pno = paint->lookup(argv[4], 3);
  2012. if (pno < 0) {
  2013.   fprintf(stderr,"%s ncolor: no such color: %sn",
  2014.   argv[0], argv[3]);
  2015.   pno = paint->lookup("black",1);
  2016.   if (pno < 0) {
  2017.     tcl.resultf("%s no black! - bailing");
  2018.     return (TCL_ERROR);
  2019.   }
  2020. }
  2021. h->edge->paint(pno);
  2022. return (TCL_OK);
  2023. }
  2024. if (strcmp(argv[1], "edlabel") == 0) {
  2025. /*
  2026.  * <net> edlabel <src> <dst> <colorName>
  2027.  * set label of edge.
  2028.  */
  2029. EdgeHashNode* h = lookupEdgeHashNode(atoi(argv[2]), 
  2030.      atoi(argv[3]));
  2031. if (h == 0) {
  2032. tcl.resultf("%s ecolor: no such edge (%s,%s)",
  2033.     argv[0], argv[2], argv[3]);
  2034. return (TCL_ERROR);
  2035. }
  2036. if (strcmp(argv[4],"(null)")!=0) {
  2037. h->edge->dlabel((char *)argv[4]);
  2038. // XXX Should never set edge size outside
  2039. // scale_estimate()!!!!
  2040. //   h->edge->size(25.0);
  2041. }
  2042. return (TCL_OK);
  2043. }
  2044. if (strcmp(argv[1], "lanlink") == 0) {
  2045. /*
  2046.  * <net> lanlink <src> <lan> <angle>
  2047.  * Create a link/edge between the specified source
  2048.  * and a lan.
  2049.  */
  2050. Node * src = lookupNode(atoi(argv[2]));
  2051. Lan * lan = lookupLan(atoi(argv[3]));
  2052. if (lan == NULL) {
  2053. fprintf(stderr, "Error: lan %s does not exist.n", argv[3]);
  2054. exit(1);
  2055. }
  2056. double angle = atof(argv[4]);
  2057. double bw = lan->bw();
  2058. double delay = (lan->delay())/2.0;
  2059. Edge *e1 = new Edge(src, lan->virtual_node(), packet_size_, bw, delay, 0, angle+1);
  2060. e1->init_color("black");
  2061. enterEdge(e1);
  2062. e1->Animation::insert(&drawables_);
  2063. src->add_link(e1);
  2064. Edge *e2 = new Edge(lan->virtual_node(), src, packet_size_, bw, delay, 0, angle);
  2065. e2->init_color("black");
  2066. enterEdge(e2);
  2067. e2->Animation::insert(&drawables_);
  2068. lan->add_link(e2);
  2069. return (TCL_OK);
  2070. }
  2071. if (strcmp(argv[1], "set_node_tclscript") == 0) {
  2072. //------------------------------------------------------------------
  2073. // $netModel set_node_tclscript $node_id $button_label $tcl_command
  2074. //   - from tcl/node.tcl
  2075. //          Animator instproc node_tclscript
  2076. //------------------------------------------------------------------
  2077. // Sets the tcl_script for a node to be run when the
  2078. // start_info exec button is pressed.
  2079. Node * node = lookupNode(atoi(argv[2]));
  2080. if (node) {
  2081. // The following strings are deleted by the node when it 
  2082. // changes to another script or it is deleted
  2083. node->setTclScript(argv[3], argv[4]);
  2084. return TCL_OK;
  2085. } else {
  2086. return TCL_ERROR;
  2087. }
  2088. }
  2089. } else if (argc == 6) {
  2090. if (strcmp(argv[1], "lan") == 0) {
  2091. /*
  2092.  * <net> lan <name> <bandwidth> <delay> <angle>
  2093.  * Create a link/edge between the specified source
  2094.  * and destination. Add it to this NetModel's list
  2095.  * of drawables and to the source's list of links.
  2096.  */
  2097. double bw = atof(argv[3]);
  2098. double delay = atof(argv[4]);
  2099. double angle = atof(argv[5]);
  2100. Lan *l = new Lan(argv[2], this, packet_size_, bw, delay, angle);
  2101. l->next_ = lans_;
  2102. lans_ = l;
  2103. l->insert(&drawables_);
  2104. Node *n = l->virtual_node();
  2105. n->next_ = nodes_;
  2106. nodes_ = n;
  2107. return (TCL_OK);
  2108. }
  2109. } else if (argc == 8) {
  2110. if (strcmp(argv[1], "link") == 0) {
  2111. /*
  2112.  * <net> link <src> <dst> <bandwidth> <delay> <angle>
  2113.  * Create a link/edge between the specified source
  2114.  * and destination. Add it to this NetModel's list
  2115.  * of drawables and to the source's list of links.
  2116.  */
  2117. Edge * edge = addEdge(argc,argv);
  2118. if (!edge) {
  2119. tcl.resultf("node %s or %s is not defined... ", argv[2], argv[3]);
  2120. return TCL_ERROR;
  2121. } else { 
  2122. tcl.resultf("%g", edge->delay());
  2123. return (TCL_OK);
  2124. }
  2125. }
  2126. }
  2127. /* If no NetModel commands matched, try the Object commands. */
  2128. fprintf(stderr, "No matching command found for %sn",argv[0]);
  2129. return (TclObject::command(argc, argv));
  2130. }
  2131. void NetModel::selectPkt(int sData, int sRoute, int sMac) 
  2132. {
  2133.     showData_ = sData;
  2134.     showRouting_ = sRoute;
  2135.     showMac_ = sMac;
  2136. }
  2137. // ---------------------------------------------------------------------
  2138. // void
  2139. // NetModel::placeEdgeByAngle(Edge* e, Node* src) const {
  2140. // Place edges by their angles
  2141. // ---------------------------------------------------------------------
  2142. void 
  2143. NetModel::placeEdgeByAngle(Edge * e, Node * src) const {
  2144.   double nsin, ncos, x0, x1, y0, y1;
  2145.   Node * destination;
  2146.   EdgeHashNode * h;
  2147.   if (e->marked() == 0) {
  2148.     // get destination node
  2149.     destination = e->neighbor();
  2150.     SINCOSPI(e->angle(), &nsin, &ncos);
  2151.     x0 = src->x(e) + src->size() * ncos * 0.75;
  2152.     y0 = src->y(e) + src->size() * nsin * 0.75;
  2153.     x1 = destination->x(e) - destination->size() * ncos * 0.75;
  2154.     y1 = destination->y(e) - destination->size() * nsin * 0.75;
  2155.     e->place(x0, y0, x1, y1);
  2156.     
  2157.     // Place the queue here too.
  2158.     h = lookupEdgeHashNode(e->src(), e->dst());
  2159.     if (h->queue != 0) {
  2160.       h->queue->place(e->size(), e->x0(), e->y0());
  2161.     }
  2162.     e->mark();
  2163.   }
  2164. }
  2165. void NetModel::placeEdge(Edge * e, Node * src) const {
  2166. if (e->marked() == 0) {
  2167. double hyp, dx, dy;
  2168. Node * dst = e->neighbor();
  2169. dx = dst->x(e) - src->x(e);
  2170. dy = dst->y(e) - src->y(e);
  2171. hyp = sqrt(dx*dx + dy*dy);
  2172. e->setAngle(atan2(dy,dx));
  2173. double x0 = src->x(e) + src->size() * (dx/hyp) * .75;
  2174. double y0 = src->y(e) + src->size() * (dy/hyp) * .75;
  2175. double x1 = dst->x(e) - dst->size() * (dx/hyp) * .75;
  2176. double y1 = dst->y(e) - dst->size() * (dy/hyp) * .75;
  2177. e->place(x0, y0, x1, y1);
  2178. /* Place the queue here too.  */
  2179. EdgeHashNode *h = lookupEdgeHashNode(e->src(), e->dst());
  2180. if (h->queue != 0)
  2181. h->queue->place(e->size(), e->x0(), e->y0());
  2182. e->mark();
  2183. }
  2184. }
  2185. //----------------------------------------------------------------------
  2186. // void
  2187. // NetModel::placeAgent(Agent *a, Node *src) const
  2188. //----------------------------------------------------------------------
  2189. void 
  2190. NetModel::placeAgent(Agent *a, Node *src) const {
  2191.   double x0, y0, nsin, ncos;
  2192.   Agent * agents;
  2193.   Edge * links;
  2194.   int choices[8], i, ix;
  2195.   double angle;
  2196.   TrafficSource * traffic_source;
  2197.   if (a->marked() == 0) {
  2198.     if (a->angle()==NO_ANGLE) {
  2199.       if (a->edge()==NULL) {
  2200.         /* determine where to put the label so it
  2201.            won't overlap a link (if possible) */
  2202.         for(i = 0; i < 8; i++) {
  2203.           choices[i] = 1;
  2204.         }
  2205.         // Get list of agents attached to the src node
  2206.         agents = src->agents();
  2207.         // Loop through list of agents checking their locations
  2208.         while (agents != NULL) {
  2209.           angle = agents->angle();
  2210.           if (angle < 0) {
  2211.             angle = angle+2*M_PI;
  2212.           }
  2213.           ix = int(angle*4);
  2214.           if (ix < 8) {
  2215.             choices[ix] = 0;
  2216.           }
  2217.           agents=agents->next_;
  2218.         }
  2219.         // Get a list of links attached to the src node
  2220.         links = src->links();
  2221.         // Loop through the list checking their locations
  2222.         while (links!=NULL) {
  2223.           angle = links->angle();
  2224.           if (angle < 0) {
  2225.             angle = angle + 2*M_PI;
  2226.           }
  2227.           ix = int(angle * 4);
  2228.           if (ix < 8) {
  2229.             choices[ix] = 0;
  2230.           }
  2231.           links=links->next_;
  2232.         }
  2233.         // Choose an angle from the marked choices list
  2234.         if (choices[0] == 1) {
  2235.           a->angle(0);
  2236.         } else if (choices[4] == 1) {
  2237.           a->angle(1.0);
  2238.         } else if ((choices[1] == 1) && (choices[2] == 1)) {
  2239.           a->angle(0.5);
  2240.         } else if ((choices[6]==1)&&(choices[7]==1)) {
  2241.           a->angle(1.5);
  2242.         } else if (choices[1]==1) {
  2243.           a->angle(0.25);
  2244.         } else {
  2245.           a->angle(1.75);
  2246.         }
  2247.       } else {
  2248.         a->angle(a->edge()->angle() + 0.25);
  2249.       }
  2250.     }
  2251.     SINCOSPI(a->angle(), &nsin, &ncos);
  2252.     x0 = src->x() + src->size() * ncos * .75;
  2253.     y0 = src->y() + src->size() * nsin * .75;
  2254.     a->place(x0, y0);
  2255.     a->mark(1);
  2256.     // Place any traffic sources that are connected to this agent
  2257.     for (traffic_source = a->traffic_sources_;
  2258.          traffic_source;
  2259.          traffic_source = traffic_source->next_) {
  2260.       traffic_source->place();
  2261.     }
  2262.     
  2263.   }
  2264. }
  2265. //----------------------------------------------------------------------
  2266. //----------------------------------------------------------------------
  2267. void
  2268. NetModel::hideAgentLinks() {
  2269. for (Node* n = nodes_; n != 0; n = n->next_) 
  2270. for(Agent* a= n->agents(); a != 0; a = a->next_) 
  2271. a->hideLink();
  2272. }
  2273. //----------------------------------------------------------------------
  2274. //----------------------------------------------------------------------
  2275. void NetModel::set_wireless() {
  2276. wireless_ = 1 ;
  2277. for (Node *n = nodes_; n != 0; n = n->next_)
  2278. for (Edge *e=n->links(); e != 0; e = e->next_)
  2279. e->unmark();
  2280. scale_estimate();
  2281. placeEverything();
  2282. for (View *p = views_; p != 0; p = p->next_)
  2283. if ((p->width() > 0) && (p->height() > 0)) {
  2284. p->redrawModel();
  2285. p->draw();
  2286. }
  2287. }
  2288. //----------------------------------------------------------------------
  2289. // void
  2290. // NetModel::scale_estimate() {
  2291. //   - Compute reasonable defaults for missing node or edge sizes
  2292. //     based on the maximum link delay.
  2293. //----------------------------------------------------------------------
  2294. void
  2295. NetModel::scale_estimate() {
  2296.   /* Determine the maximum link delay. */
  2297.   // XXX Must use length(). This is essential for appropriate 
  2298.   // packet height when using a pre-made layout.
  2299.   double emax = 0.;
  2300.   Node *n;
  2301.   for (n = nodes_; n != 0; n = n->next_) {
  2302.     for (Edge* e = n->links(); e != 0; e = e->next_)
  2303.       if (e->length() > emax)
  2304.         emax = e->length();
  2305.   }
  2306.   /*store this because we need it for monitors*/
  2307.   node_size_ = node_sizefac_ * emax;
  2308.   /*
  2309.    * Check for missing node or edge sizes. If any are found,
  2310.    * compute a reasonable default based on the maximum edge
  2311.    * dimension.
  2312.    */
  2313.   for (n = nodes_; n != 0; n = n->next_) {
  2314.     if (n->size() <= 0.)
  2315.       n->size(node_size_);
  2316.     for (Edge* e = n->links(); e != 0; e = e->next_)
  2317.       if (e->size() <= 0.)
  2318.         e->size(.03 * emax);
  2319.   }
  2320. }
  2321. //----------------------------------------------------------------------
  2322. //----------------------------------------------------------------------
  2323. void NetModel::placeEverything() {
  2324.   // If there is no fixed node, anchor the first one entered at (0,0).
  2325.   Node *n;
  2326.   Edge * e;
  2327.   int nodes_to_be_placed;
  2328.   for (n = nodes_; n != 0; n = n->next_) {
  2329.     n->mark(0);
  2330.     n->clear_routes();
  2331.   }
  2332.   if (nodes_) {
  2333.     //nodes_->place(0., 0.);
  2334.     nodes_->place(nodes_->x(), nodes_->y());
  2335.   }
  2336.   do {
  2337.     nodes_to_be_placed = 0;
  2338.     for (n = nodes_; n != 0; n = n->next_) {
  2339.       nodes_to_be_placed |= traverseNodeConnections(n);
  2340.     }
  2341.   } while (nodes_to_be_placed);
  2342.   // Place edges
  2343.   for (n = nodes_; n != 0; n = n->next_) { 
  2344.     for (e = n->links(); e != 0; e = e->next_) {
  2345.       placeEdgeByAngle(e, n);
  2346.     }
  2347.   }
  2348.   // After edges are laied out, place all routes.
  2349.   for (n = nodes_; n != 0; n = n->next_) {
  2350.     n->place_all_routes();
  2351.   }
  2352. }
  2353. //----------------------------------------------------------------------
  2354. //----------------------------------------------------------------------
  2355. void NetModel::move(double& x, double& y, double angle, double d) const {
  2356. double ncos, nsin;
  2357. SINCOSPI(angle, &nsin, &ncos);
  2358. x += d * ncos;
  2359. y += d * nsin;
  2360. }
  2361. //----------------------------------------------------------------------
  2362. // int NetModel::traverseNodeConnections(Node* n)
  2363. //   - Traverse node n's neighbors and place them based on the
  2364. //     delay of their links to n.  The two branches of the if..else
  2365. //     are to handle unidirectional links -- we place ourselves if
  2366. //     we haven't been placed & our downstream neighbor has.
  2367. //----------------------------------------------------------------------
  2368. int NetModel::traverseNodeConnections(Node* n) {
  2369.   double x, y, distance;
  2370.   int placed_node = 0;
  2371.   for (Edge* e = n->links(); e != 0; e = e->next_) {
  2372.     Node *neighbor = e->neighbor();
  2373.     distance = e->length() + (n->size() + neighbor->size()) * 0.75;
  2374.     if (n->marked() && !neighbor->marked()) {
  2375.       x = n->x(e);
  2376.       y = n->y(e);
  2377.       move(x, y, e->angle(), distance);
  2378.       neighbor->place(x, y);
  2379.       placed_node |= traverseNodeConnections(neighbor);
  2380.       if (nymax_ < y)
  2381.         nymax_ = y;
  2382.       if (nymin_ > y)
  2383.         nymin_ = y;
  2384.     } else if (!n->marked() && neighbor->marked()) {
  2385.       x = neighbor->x(e);
  2386.       y = neighbor->y(e);
  2387.       move(x, y, e->angle(), -distance);
  2388.       n->place(x, y);
  2389.       placed_node = 1;
  2390.     }
  2391.   }
  2392.   return placed_node;
  2393. }
  2394. int NetModel::save_layout(const char *filename)
  2395. {
  2396.   FILE *file;
  2397.   Node *n;
  2398.   Edge *e;
  2399.   int ret;
  2400.   file=fopen(filename, "w");
  2401.   if (file==0)
  2402.   {
  2403.     fprintf(stderr, "nam: Couldn't open file: %sn", filename);
  2404.     return -1;
  2405.   }
  2406.   for (n = nodes_; n != 0; n = n->next_)
  2407.   {
  2408.     ret = n->save(file);
  2409.     if (ret!=0) {
  2410.       fclose(file);
  2411.       return -1;
  2412.     }
  2413.   }
  2414.   for (n = nodes_; n != 0; n = n->next_)
  2415.     for(e= n->links(); e !=0; e = e->next_)
  2416.     {
  2417.       ret = e->save(file);
  2418.       if (ret!=0) {
  2419. fclose(file);
  2420. return -1;
  2421.       }
  2422.     }
  2423.   return(fclose(file));
  2424. }
  2425. void NetModel::color_subtrees()
  2426. {
  2427.   Node *n, *dst, *prevdst, *newdst;
  2428.   Edge* e;
  2429.   for (n = nodes_; n != 0; n = n->next_) {
  2430.     int ctr=0;
  2431.     for (e = n->links(); e != 0; e = e->next_)
  2432.       ctr++;
  2433.     if (ctr==1)
  2434.     {
  2435.       n->color("grey");
  2436.       n->links()->color("grey");
  2437.       dst=n->links()->neighbor();
  2438.       for (e = dst->links(); e != 0; e = e->next_)
  2439. if (e->neighbor()==n)
  2440. {
  2441.   e->color("grey");
  2442.   break;
  2443. }
  2444.       ctr=2;
  2445.       prevdst=n;
  2446.       while(ctr==2) {
  2447. ctr=0;
  2448. for (e = dst->links(); e != 0; e = e->next_)
  2449.   ctr++;
  2450. if (ctr==2) {
  2451.   dst->color("grey");
  2452.   dst->links()->color("grey");
  2453.   for (e = dst->links(); e != 0; e = e->next_)
  2454.     if (e->neighbor()!=prevdst)
  2455.     {
  2456.       newdst=e->neighbor();
  2457.       break;
  2458.     }
  2459.   e->color("grey");
  2460.   for (e = newdst->links(); e != 0; e = e->next_)
  2461.     if (e->neighbor()==dst)
  2462.     {
  2463.       e->color("grey");
  2464.       break;
  2465.     }
  2466.   prevdst=dst;
  2467.   dst=newdst;
  2468. }
  2469.       }
  2470.     }
  2471.   }
  2472. }
  2473. //----------------------------------------------------------------------
  2474. // int
  2475. // NetModel::add_tag(Tag *tag)
  2476. //----------------------------------------------------------------------
  2477. int
  2478. NetModel::add_tag(Tag *tag) {
  2479.   int newEntry = 1;
  2480.   Tcl_HashEntry * he;
  2481.   he = Tcl_CreateHashEntry(tagHash_, (const char *)tag->name(), &newEntry);
  2482.   if (he == NULL) {
  2483.     return (TCL_ERROR);
  2484.   }
  2485.   if (newEntry) {
  2486.     Tcl_SetHashValue(he, (ClientData)tag);
  2487.     nTag_++;
  2488.   }
  2489.   tag->insert(&drawables_);
  2490.   return (TCL_OK);
  2491. }
  2492. // Remove a tag from netmodel, and clear all its memberships but not 
  2493. // actually delete it
  2494. void NetModel::delete_tag(const char *tn)
  2495. {
  2496. Tcl_HashEntry *he = 
  2497. Tcl_FindHashEntry(tagHash_, (const char *)tn);
  2498. if (he != NULL) {
  2499. // Do *NOT* delete tag here.
  2500. Tcl_DeleteHashEntry(he);
  2501. nTag_--;
  2502. }
  2503.   
  2504. }
  2505. Tag* NetModel::lookupTag(const char *tn)
  2506. {
  2507. Tcl_HashEntry *he = Tcl_FindHashEntry(tagHash_, tn);
  2508. if (he == NULL)
  2509. return NULL;
  2510. return (Tag *)Tcl_GetHashValue(he);
  2511. }
  2512. int NetModel::registerObjName(const char *name, int id)
  2513. {
  2514. int newEntry = 1;
  2515. Tcl_HashEntry *he = 
  2516. Tcl_CreateHashEntry(objnameHash_, name, &newEntry);
  2517. if (he == NULL)
  2518. return (TCL_ERROR);
  2519. if (newEntry) {
  2520. Tcl_SetHashValue(he, (ClientData)id);
  2521. nTag_++;
  2522. }
  2523. return (TCL_OK);
  2524. }
  2525. //XXX: maximum name length is 256. 
  2526. int NetModel::lookupObjname(const char *name)
  2527. {
  2528. #define STATIC_NAMELEN 256
  2529. char n[STATIC_NAMELEN];
  2530. size_t len = strlen(name);
  2531. len = (len < STATIC_NAMELEN) ? len : STATIC_NAMELEN;
  2532. for (size_t i = 0; i < len; i++)
  2533. n[i] = toupper(name[i]);
  2534. Tcl_HashEntry *he = Tcl_FindHashEntry(objnameHash_, n);
  2535. if (he == NULL)
  2536. return -1;
  2537. return *Tcl_GetHashValue(he);
  2538. #undef STATIC_NAMELEN
  2539. }
  2540. /*
  2541.  * Unite tag name space and animation id space:
  2542.  * 
  2543.  * (1) if tag is a number, we'll first look it up in our 
  2544.  *     animation objects table. 
  2545.  * (2) if tag is a string, it must be in the tag table
  2546.  */
  2547. Animation* NetModel::lookupTagOrID(const char *name)
  2548. {
  2549. char end[256];
  2550. if (name == NULL)
  2551. return NULL;
  2552. unsigned int id = (unsigned int)strtoul(name, (char **)&end, 0);
  2553. if (*end != 0)
  2554. // This must be a tag string name
  2555. return lookupTag(name);
  2556. else 
  2557. return Animation::find(id);
  2558. }
  2559. /*
  2560.  * Handling Tcl command "addtags" of EditView
  2561.  *
  2562.  * <view> addtag tag <searchSpec> arg...
  2563.  *
  2564.  * searchSpec can be: 
  2565.  *   all <ObjectType>
  2566.  *   closest x y ?halo? 
  2567.  *   enclosed x1 y1 x2 y2
  2568.  *   overlapping x1 y1 x2 y2
  2569.  *   withTag tagOrID
  2570.  * specification copied from Tk's canvas
  2571.  *
  2572.  * If newTag isn't null, then first lookup the tag. If found, add
  2573.  * the searchSpec results to that tag, otherwise create a new tag
  2574.  * and add results to that tag.
  2575.  * Return error if newTag == NULL.
  2576.  *
  2577.  * Tagging policies, e.g., whether an object can simultaneously belong 
  2578.  * to multiple tags, are left to the users.
  2579.  */
  2580. int NetModel::tagCmd(View *v, int argc, char **argv, 
  2581.      char *newTag, char *cmdName)
  2582. {
  2583. Tag *tag = NULL;
  2584. size_t length;
  2585. Tcl& tcl = Tcl::instance();
  2586. int res = (TCL_OK), bNew = 0;
  2587. if (newTag != NULL) {
  2588. tag = (Tag *)lookupTagOrID(newTag);
  2589. if ((tag != NULL) && (tag->classid() != ClassTagID)) {
  2590. Tcl_AppendResult(tcl.interp(),
  2591.  newTag, "should be a tag ",
  2592.  (char *)NULL);
  2593. return TCL_ERROR;
  2594. }
  2595. if (tag == NULL) {
  2596. tag = new Tag(newTag);
  2597. bNew = 1;
  2598. }
  2599. }
  2600. int c = argv[0][0];
  2601. length = strlen(argv[0]);
  2602. if ((c == 'a') && (strncmp(argv[0], "all", length) == 0)
  2603.     && (length >= 2)) {
  2604. if (argc > 2) {
  2605. Tcl_AppendResult(tcl.interp(), 
  2606.  "wrong # args: should be "", cmdName,
  2607.  " all ?Obj?", (char *) NULL);
  2608. res = TCL_ERROR;
  2609. goto error;
  2610. }
  2611. Animation *a;
  2612. int objType = ClassAllID;
  2613. if (argc == 2) {
  2614. // Map object name to class id
  2615. objType = lookupObjname(argv[1]);
  2616. if (objType == -1) {
  2617. Tcl_AppendResult(tcl.interp(),
  2618.  "Bad object name ", argv[1]);
  2619. res = (TCL_ERROR);
  2620. goto error;
  2621. }
  2622. }
  2623. if (objType == ClassAllID) {
  2624. for (a = animations_; a != NULL; a = a->next())
  2625. if (!a->isTagged())
  2626. tagObject(tag, a);
  2627. for (a = drawables_; a != NULL; a = a->next())
  2628. if (!a->isTagged())
  2629. tagObject(tag, a);
  2630. } else {
  2631. for (a = animations_; a != NULL; a = a->next())
  2632. if (!a->isTagged() && a->classid() == objType)
  2633. tagObject(tag, a);
  2634. for (a = drawables_; a != NULL; a = a->next())
  2635. if (!a->isTagged() && a->classid() == objType)
  2636. tagObject(tag, a);
  2637. }
  2638. } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) {
  2639. /* 
  2640.  * enclosed x1 y1 x2 y2
  2641.  */
  2642. if (argc != 5) {
  2643. Tcl_AppendResult(tcl.interp(), 
  2644.  "wrong # args: should be "",
  2645.  cmdName, " enclosed x1 y1 x2 y2", 
  2646.  (char *) NULL);
  2647. res = TCL_ERROR;
  2648. goto error;
  2649. }
  2650. BBox bb;
  2651. // Translation/scaling will not change the order of bbox. :)
  2652. if ((v->getCoord(argv[1], argv[2],
  2653.  bb.xmin, bb.ymin) != TCL_OK) ||
  2654.     (v->getCoord(argv[3], argv[4], bb.xmax, bb.ymax)!=TCL_OK))
  2655. res = TCL_ERROR;
  2656. else 
  2657. res = tagArea(bb, tag, 1);
  2658. } else if ((c == 'o') && 
  2659.    (strncmp(argv[0], "overlapping", length) == 0)) {
  2660. /*
  2661.  * Overlapping x1 y1 x2 y2 
  2662.  */
  2663. if (argc != 5) {
  2664. Tcl_AppendResult(tcl.interp(), 
  2665.  "wrong # args: should be "",
  2666.  cmdName, " overlapping x1 y1 x2 y2",
  2667.  (char *) NULL);
  2668. res = TCL_ERROR;
  2669. goto error;
  2670. }
  2671. BBox bb;
  2672. // Translation/scaling will not change the order of bbox. :)
  2673. if ((v->getCoord(argv[1], argv[2],
  2674.  bb.xmin, bb.ymin) != TCL_OK) ||
  2675.     (v->getCoord(argv[3], argv[4], bb.xmax, bb.ymax)!=TCL_OK))
  2676. res = TCL_ERROR;
  2677. else 
  2678. res = tagArea(bb, tag, 0);
  2679. } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) {
  2680. if (argc != 2) {
  2681. Tcl_AppendResult(tcl.interp(), 
  2682.  "wrong # args: should be "",
  2683.  cmdName, " withtag tagOrId", 
  2684.  (char *) NULL);
  2685. res = TCL_ERROR;
  2686. goto error;
  2687. }
  2688. // Find that tag or ID
  2689. Animation *p = lookupTagOrID(argv[1]);
  2690. if (p == NULL) {
  2691. // Wrong tag
  2692. Tcl_AppendResult(tcl.interp(),
  2693.  "wrong tag ", argv[1],
  2694.  (char *)NULL);
  2695. res = TCL_ERROR;
  2696. } else {
  2697. // Label them as this tag
  2698. tagObject(tag, p);
  2699. }
  2700. } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) {
  2701. float coords[2], halo;
  2702. if ((argc < 3) || (argc > 5)) {
  2703. Tcl_AppendResult(tcl.interp(), 
  2704.  "wrong # args: should be "",
  2705.  cmdName, " closest x y ?halo? ",
  2706.  (char *) NULL);
  2707. res = TCL_ERROR;
  2708. goto error;
  2709. }
  2710. if (v->getCoord(argv[1], argv[2], 
  2711. coords[0], coords[1]) != TCL_OK) {
  2712. Tcl_AppendResult(tcl.interp(),
  2713.  "bad coordinates ",
  2714.  argv[1], " ", argv[2], (char *)NULL);
  2715. res = TCL_ERROR;
  2716. goto error;
  2717. }
  2718. if (argc > 3) {
  2719. // XXX: It's impossible to convert length in 
  2720. // screen space to world space with translation
  2721. // and scaling. We think it's in world space
  2722. halo = strtod(argv[3], NULL);
  2723. if (halo < 0.0) {
  2724. Tcl_AppendResult(tcl.interp(), 
  2725.        "can't have negative halo value "",
  2726.  argv[3], """, (char *) NULL);
  2727. res = TCL_ERROR;
  2728. goto error;
  2729. }
  2730. } else {
  2731. halo = 0.0;
  2732. }
  2733. Animation *p = findClosest(coords[0], coords[1], halo);
  2734. if (p != NULL)
  2735. tagObject(tag, p);
  2736. else 
  2737. res = TCL_ERROR;
  2738. } else  {
  2739. Tcl_AppendResult(tcl.interp(), 
  2740.  "bad search command "", argv[0],
  2741.  "": must be above, all, below, closest, enclosed, ",
  2742.  "overlapping, or withtag", (char *) NULL);
  2743. res = TCL_ERROR;
  2744. goto error;
  2745. }
  2746. if (res == TCL_OK) {
  2747. if (bNew)
  2748. add_tag(tag);
  2749. return TCL_OK;
  2750. }
  2751. error:
  2752. if (tag != NULL)
  2753. delete tag;
  2754. return res;
  2755. }
  2756. Animation* NetModel::findClosest(float dx, float dy, double halo)
  2757. {
  2758. double closestDist;
  2759. Animation *startPtr, *closestPtr, *itemPtr;
  2760. BBox bb;
  2761. startPtr = animations_;
  2762. itemPtr = startPtr;
  2763. if (itemPtr == NULL) {
  2764. return NULL;
  2765. }
  2766. closestDist = itemPtr->distance(dx, dy) - halo;
  2767. if (closestDist < 0.0) {
  2768. closestDist = 0.0;
  2769. }
  2770. while (1) {
  2771. double newDist;
  2772. /*
  2773.  * Update the bounding box using itemPtr, which is the
  2774.  * new closest item.
  2775.  */
  2776. bb.xmin = dx - closestDist - halo - 1,
  2777. bb.ymin = dy - closestDist - halo - 1,
  2778. bb.xmax = dx + closestDist + halo + 1,
  2779. bb.ymax = dy + closestDist + halo + 1;
  2780. closestPtr = itemPtr;
  2781. /*
  2782.  * Search for an item that beats the current closest 
  2783.  * one.
  2784.  * Work circularly through the canvas's item list until
  2785.  * getting back to the starting item.
  2786.  */
  2787. while (1) {
  2788. itemPtr = itemPtr->next();
  2789. if (itemPtr == NULL) {
  2790. if (startPtr == animations_) {
  2791. startPtr = drawables_;
  2792. itemPtr = startPtr;
  2793. } else 
  2794. return closestPtr;
  2795. }
  2796. if (itemPtr->isTagged()|| !itemPtr->bbox().overlap(bb))
  2797. continue;
  2798. newDist = itemPtr->distance(dx, dy)-halo;
  2799. if (newDist < 0.0) {
  2800. newDist = 0.0;
  2801. }
  2802. if (newDist <= closestDist) {
  2803. closestDist = newDist;
  2804. break;
  2805. }
  2806. }
  2807. }
  2808. }
  2809. //----------------------------------------------------------------------
  2810. // void
  2811. // NetModel::tagObject(Tag *tag, Animation * animation_object)
  2812. //----------------------------------------------------------------------
  2813. void
  2814. NetModel::tagObject(Tag *tag, Animation * animation_object) {
  2815. Tcl & tcl = Tcl::instance();
  2816. if (tag == NULL) {
  2817. char str[20];
  2818. sprintf(str, "No tag for %d", animation_object->id());
  2819. Tcl_AppendElement(tcl.interp(), str);
  2820. return;
  2821. }
  2822. if (tag == animation_object)
  2823. return;
  2824. // add animation object to the tag group 
  2825. tag->add(animation_object);
  2826. }
  2827. //----------------------------------------------------------------------
  2828. //----------------------------------------------------------------------
  2829. int NetModel::tagArea(BBox &bb, Tag *tag, int bEnclosed)
  2830. {
  2831. Animation *p;
  2832. // Because the area is a rectangle, we only need to 
  2833. // find out all objects whose bounding boxes are 
  2834. // within/overlapping the given rectangle.
  2835. if (bEnclosed == 0) {
  2836. // overlapping and enclosed
  2837. for (p = animations_; p != NULL; p = p->next()) 
  2838. if (!p->isTagged() && p->bbox().overlap(bb) 
  2839.     && (p != tag))
  2840. tagObject(tag, p);
  2841. for (p = drawables_; p != NULL; p = p->next())
  2842. if (!p->isTagged() && p->bbox().overlap(bb)
  2843.     && (p != tag))
  2844. tagObject(tag, p);
  2845. } else {
  2846. // enclosed only
  2847. for (p = animations_; p != NULL; p = p->next()) 
  2848. if (!p->isTagged() && bb.inside(p->bbox())
  2849.     && (p != tag))
  2850. tagObject(tag, p);
  2851. for (p = drawables_; p != NULL; p = p->next())
  2852. if (!p->isTagged() && bb.inside(p->bbox())
  2853.     && (p != tag))
  2854. tagObject(tag, p);
  2855. }
  2856. return TCL_OK;
  2857. }
  2858. int NetModel::deleteTagCmd(char *tagName, char *tagDel)
  2859. {
  2860. Tag *p;
  2861. Animation *q = NULL;
  2862. p = (Tag *)lookupTagOrID(tagName);
  2863. if (tagDel != NULL)
  2864. q = lookupTagOrID(tagDel);
  2865. if (p == NULL) {
  2866. Tcl_AppendResult(Tcl::instance().interp(),
  2867.  "bad tag ", tagName, (char *)NULL);
  2868. return (TCL_ERROR);
  2869. }
  2870. if ((p->classid() != ClassTagID) || (p == q) || (q == NULL)){
  2871. // If given an ID, or given a group only
  2872. // delete it and do nothing else
  2873. delete p;
  2874. return TCL_OK; 
  2875. }
  2876. // Now delete tag p from object q
  2877. q->deleteTag(p);
  2878. return TCL_OK;
  2879. }
  2880. // ---------------------------------------------------------------------
  2881. // void
  2882. // NetModel::render(EditView* view, BBox &bb)
  2883. //   - This is a partial render which does not seem to be complete.
  2884. //     Above here are several other render functions which redisplay 
  2885. //     the entire model.
  2886. //
  2887. // XXX: Partial redraw is only working for EditView! Not for other
  2888. // animation views for now. We need a method in each Animation object
  2889. // to decide their "dirtiness" to make this redraw work. :( And the
  2890. // computation of clipping box should be purely within NetModel but
  2891. // not fed in externally
  2892. // ---------------------------------------------------------------------
  2893. void
  2894. NetModel::render(EditView* view, BBox &bb) {
  2895.   Animation *a;
  2896.   for (a = drawables_; a != 0; a = a->next()) {
  2897.     if (!a->bbox().overlap(bb)) {
  2898.       // if outside of our views bounding box then skip 
  2899.       // this animation object
  2900.       continue;
  2901.     }
  2902.     a->draw(view, now_);
  2903.   }
  2904.   for (a = animations_; a != 0; a = a->next()) {
  2905.     if (!a->bbox().overlap(bb)) {
  2906.       // if outside of our views bounding box then skip 
  2907.       // this animation object
  2908.       continue;
  2909.     }
  2910.     a->draw(view, now_);
  2911.   }
  2912. }
  2913. void NetModel::moveNode(Node *n) {
  2914. //fprintf(stderr, "Moving nodes can only be performed by NetModel.n");
  2915. for (Edge *e = n->links(); e != 0; e = e->next_) {
  2916. e->unmark();
  2917. placeEdge(e, n);
  2918. Node *dst = e->neighbor();
  2919. // Should place reverse edges too
  2920. Edge *p = dst->find_edge(n->num());
  2921. if (p != NULL) {
  2922. p->unmark();
  2923. placeEdge(p, dst);
  2924. }
  2925. dst->clear_routes();
  2926. dst->place_all_routes();
  2927. }
  2928. for (Agent *a = n->agents(); a != NULL; a = a->next()) {
  2929. a->mark(0), a->angle(NO_ANGLE);
  2930. placeAgent(a, n);
  2931. }
  2932. // Relayout all routes
  2933. n->clear_routes();
  2934. n->place_all_routes();
  2935. }