/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /cvsroot/nsnam/nam-1/netmodel.cc,v 1.112 2003/10/11 22:56:50 xuanc Exp $ (LBL) */ #include #ifdef WIN32 #include #endif #include #include #include #include #include #include "config.h" #include "netview.h" #include "psview.h" #include "testview.h" #include "animation.h" #include "group.h" #include "tag.h" #include "queue.h" #include "drop.h" #include "packet.h" #include "edge.h" #include "lan.h" #include "node.h" #include "agent.h" #include "feature.h" #include "route.h" #include "netmodel.h" #include "monitor.h" #include "trace.h" #include "paint.h" #include "sincos.h" #include "state.h" #include "editview.h" #include "address.h" #include "animator.h" #include extern int lineno; // not used //static int next_pat; class NetworkModelClass : public TclClass { public: NetworkModelClass() : TclClass("NetworkModel") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return (new NetModel(argv[4])); } } networkmodel_class; //---------------------------------------------------------------------- //---------------------------------------------------------------------- NetModel::NetModel(const char *animator) : TraceHandler(animator), drawables_(0), animations_(0), queues_(0), views_(0), nodes_(0), lans_(0), node_sizefac_(NODE_EDGE_RATIO), mon_count_(0), monitors_(NULL), wireless_(0), resetf_(0), selectedSrc_(-1), selectedDst_(-1), selectedFid_(-1), hideSrc_(-1), hideDst_(-1), hideFid_(-1), colorSrc_(-1), colorDst_(-1), colorFid_(-1), showData_(1), showRouting_(1), showMac_(1), selectedColor_(-1), nGroup_(0), nTag_(0), parsetable_(&traceevent_) { int i; for (i = 0; i < EDGE_HASH_SIZE; ++i) { hashtab_[i] = 0; } for (i = 0; i < PTYPELEN; ++i) { selectedTraffic_[i] = '\0' ; colorTraffic_[i] = '\0' ; hideTraffic_[i] = '\0' ; } // Default node size is 10.0 so a default packet will be 25% of that (2.5) // This value is modified whenever a node is added. It will be based on // the running average of the size of the last 5 nodes. Look at // NetModel::addNode(const TraceEvent &e) for more details packet_size_ = 2.5; /*XXX*/ nymin_ = 1e6; nymax_ = -1e6; Paint *paint = Paint::instance(); int p = paint->thin(); // Initially 256 colors. Can be extended later. // See handling of otcl binding "color" nclass_ = 256; paintMask_ = 0xff; paint_ = new int[nclass_]; oldpaint_ = new int[nclass_]; for (i = 0; i < nclass_; ++i) { paint_[i] = p; oldpaint_[i] = p; } addrHash_ = new Tcl_HashTable; Tcl_InitHashTable(addrHash_, TCL_ONE_WORD_KEYS); grpHash_ = new Tcl_HashTable; Tcl_InitHashTable(grpHash_, TCL_ONE_WORD_KEYS); tagHash_ = new Tcl_HashTable; Tcl_InitHashTable(tagHash_, TCL_STRING_KEYS); objnameHash_ = new Tcl_HashTable; Tcl_InitHashTable(objnameHash_, TCL_STRING_KEYS); registerObjName("ALL", ClassAllID); registerObjName("ANIMATION", ClassAnimationID); registerObjName("NODE", ClassNodeID); registerObjName("PACKET", ClassPacketID); registerObjName("EDGE", ClassEdgeID); registerObjName("QUEUEITEM", ClassQueueItemID); registerObjName("LAN", ClassLanID); registerObjName("TAG", ClassTagID); registerObjName("AGENT", ClassAgentID); bind("bcast_duration_", &bcast_duration_); bind("bcast_radius_", &bcast_radius_); } NetModel::~NetModel() { // We should delete everything here, if we want deletable netmodel... delete paint_; Animation *a, *n; for (a = animations_; a != 0; a = n) { n = a->next(); delete a; } for (a = drawables_; a != 0; a = n) { n = a->next(); delete a; } Tcl_DeleteHashTable(grpHash_); delete grpHash_; Tcl_DeleteHashTable(tagHash_); delete tagHash_; Tcl_DeleteHashTable(objnameHash_); delete objnameHash_; } void NetModel::update(double now) { Animation *a, *n; for (a = animations_; a != 0; a = n) { n = a->next(); a->update(now); } /* * Draw all animations and drawables on display to reflect * current time. */ now_ = now; for (View* p = views_; p != 0; p = p->next_) { // Calls View::draw() which calls NetView::render() // which calls NetModel::render(View*) p->draw(); } } void NetModel::update(double now, Animation* a) { a->update(now); for (View* p = views_; p != 0; p = p->next_) a->draw(p, now); } //---------------------------------------------------------------------- // void // NetModel::reset(double now) // - Reset all animations and queues to time 'now'. //---------------------------------------------------------------------- void NetModel::reset(double now) { Animation* a; for (a = animations_; a != 0; a = a->next()) a->reset(now); for (a = drawables_; a != 0; a = a->next()) a->reset(now); for (Queue* q = queues_; q != 0; q = q->next_) q->reset(now); } //---------------------------------------------------------------------- // void // NetModel::render(View * view) // - Draw this NetModel's drawables, animations, and monitors. // (tags, nodes, edges, packets, queues, etc.) //---------------------------------------------------------------------- void NetModel::render(View* view) { Animation *a; Monitor *m; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); for ( m = monitors_; m != NULL; m = m->next()) m->draw_monitor(view, nymin_, nymax_); } void NetModel::render(PSView* view) { Animation *a; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); } void NetModel::render(TestView* view) { Animation *a; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); } //---------------------------------------------------------------------- // NetModel::EdgeHashNode * // NetModel::lookupEdgeHashNode(int src, int dst) const // - Return a pointer to the edge between 'src' and 'dst'. //---------------------------------------------------------------------- NetModel::EdgeHashNode * NetModel::lookupEdgeHashNode(int source, int destination) const { EdgeHashNode* h; for (h = hashtab_[ehash(source, destination)]; h != 0; h = h->next) if (h->src == source && h->dst == destination) break; return (h); } int NetModel::addAddress(int id, int addr) const { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(addrHash_, (const char *)addr, &newEntry); if (he == NULL) return -1; if (newEntry) { Tcl_SetHashValue(he, (ClientData)id); } return 0; } int NetModel::addr2id(int addr) const { Tcl_HashEntry *he = Tcl_FindHashEntry(addrHash_, (const char *)addr); if (he == NULL) return -1; return (intptr_t)Tcl_GetHashValue(he); } //---------------------------------------------------------------------- // Adds an edge to a hash table? //---------------------------------------------------------------------- void NetModel::enterEdge(Edge* e) { int src = e->src(); int dst = e->dst(); EdgeHashNode *h = lookupEdgeHashNode(src, dst); if (h != 0) { /* XXX */ fprintf(stderr, "nam: duplicate edge (%d,%d)\n", src, dst); //exit(1); return; } h = new EdgeHashNode; h->src = src; h->dst = dst; h->queue = 0; h->edge = e; int k = ehash(src, dst); h->next = hashtab_[k]; hashtab_[k] = h; } //---------------------------------------------------------------------- // void // NetModel::removeEdge(Edge* e) // - Remove an edge from the network model and delete it //---------------------------------------------------------------------- void NetModel::removeEdge(Edge* e) { int k; int src = e->src(); int dst = e->dst(); EdgeHashNode * h = lookupEdgeHashNode(src, dst); EdgeHashNode * f, * g; if (h == 0) { fprintf(stderr, "nam: trying to delete nonesisting edge (%d,%d)\n", src, dst); exit(1); } //XXX do we need to process queue ? leave it to the future 10/01/98 k = ehash(src, dst); for (f = hashtab_[k]; f != 0; f = f->next) { if (h->src == f->src && h->dst == f->dst) { if (f == hashtab_[k]) { hashtab_[k] = f->next; break; } else { g->next = f->next; break; } } g = f; } delete h; } //---------------------------------------------------------------------- // void // NetModel::BoundingBox(BBox& bb) { // XXX Make this cheaper (i.e. cache it) //---------------------------------------------------------------------- void NetModel::BoundingBox(BBox& bb) { /* ANSI C limits, from float.h */ bb.xmin = bb.ymin = FLT_MAX; bb.xmax = bb.ymax = -FLT_MAX; for (Animation* a = drawables_; a != 0; a = a->next()) a->merge(bb); } /* Animation* NetModel::inside(double now, float px, float py) const { for (Animation* a = animations_; a != 0; a = a->next()) if (a->inside(now, px, py)) return (a); for (Animation* d = drawables_; d != 0; d = d->next()) if (d->inside(now, px, py)) return (d); return (0); } */ // Used exclusively for start_info() in nam.tcl. It ignores all tag objects // and therefore should *not* be used for editing. Animation* NetModel::inside(float px, float py) const { for (Animation* a = animations_; a != 0; a = a->next()) { if (a->type() == BPACKET) { BPacket* b = (BPacket* ) a ; if ((b->inside(px, py)) && (a->classid() != ClassTagID)) return (a); } else { if ((a->inside(px, py)) && (a->classid() != ClassTagID)) return (a); } } for (Animation* d = drawables_; d != 0; d = d->next()) { if ((d->inside(px, py) && (d->classid() != ClassTagID))) return (d); } return (0); } int NetModel::add_monitor(Animation *a) { Monitor *m = new Monitor(mon_count_, a, node_size_); m->next(monitors_); monitors_=m; return mon_count_++; } int NetModel::monitor(double now, int monitor, char *result, int len) { /*XXX should get rid of this search*/ for(Monitor *m=monitors_; m!=NULL; m=m->next()) { if (m->monitor_number()==monitor) { m->update(now, result, len); if (strlen(result)==0) delete_monitor(m); return 0; } } result[0]='\0'; return -1; } //---------------------------------------------------------------------- // void NetModel::check_monitors(Animation *a) // - A new animation just got created. Check to see if we should // already have a monitor on it. //---------------------------------------------------------------------- void NetModel::check_monitors(Animation *a) { MonState * ms; Monitor * m; // Returns a "newed" MonState ms = a->monitor_state(); if (ms == NULL) { return; } for(m = monitors_; m != NULL; m = m->next()) { if ((m->mon_state_ != NULL) && (m->mon_state_->type = ms->type)) { switch (ms->type) { case MON_PACKET: if (m->mon_state_->pkt.id == ms->pkt.id) { m->anim(a); delete ms; return; } break; case MON_ROUTE: if ((m->mon_state_->route.src == ms->route.src)&& (m->mon_state_->route.group == ms->route.group)) { m->anim(a); delete ms; return; } break; } } } // What happens to ms after the end of this function? Maybe the memory leak? // fprintf(stderr, "Reached outside of check_monitors\n"); } void NetModel::delete_monitor(int monitor) { /*this version of delete_monitor is called from the GUI*/ /*given a monitor, remove it from the model's monitor list*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=NULL)&&(tm1->monitor_number()!=monitor)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); if (tm1->anim()!=NULL) tm1->anim()->remove_monitor(); delete tm1; } } void NetModel::delete_monitor(Monitor *m) { /*given a monitor, remove it from a node's agent list*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=m)&&(tm1!=NULL)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); tm1->anim()->remove_monitor(); delete tm1; } } void NetModel::delete_monitor(Animation *a) { /*given a monitor, remove it from a node's agent list*/ /*this version gets called when an animation deletes itself*/ /*XXX animations sometimes get deleted when the packet changed link*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=NULL)&&(tm1->anim()!=a)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); delete tm1; } } void NetModel::saveState(double tim) { State* state = State::instance(); StateInfo min; min.time = 10e6; min.offset = 0; Animation *a, *n; StateInfo si; /* * Update the animation list first to remove any unnecessary * objects in the list. */ for (a = animations_; a != 0; a = n) { n = a->next(); a->update(tim); } for (a = animations_; a != 0; a = n) { n = a->next(); si = a->stateInfo(); if (si.time < min.time) min = si; } if (min.offset) state->set(tim, min); } //--------------------------------------------------------------------- // void // NetModel::handle(const TraceEvent& e, double now, int direction) // - Trace event handler. //--------------------------------------------------------------------- void NetModel::handle(const TraceEvent& e, double now, int direction) { QueueItem *q; EdgeHashNode *ehn, *ehnrev; Edge* ep; Node *n; //Packet *p; Route *r; Agent *a; Feature *f; float x, y; int pno; double txtime; bool do_relayout = false; if (e.time > State::instance()->next()) saveState(e.time); switch (e.tt) { case 'T': // Dummy event no-op used for realtime time synchronization break; case 'v': { // 'variable' -- just execute it as a tcl command if (nam_ == 0) { fprintf(stderr, "Couldn't evaluate %s without animator\n", e.image); break; } const char *p = e.image + e.ve.str; char *q = new char[strlen(nam_->name()) + strlen(p) + 2]; sprintf(q, "%s %s", nam_->name(), p); Tcl::instance().eval(q); delete []q; break; } case 'h': // traffic filter if (wireless_) { if (strcmp(e.pe.pkt.wtype,"AGT") == 0 ) return ; if (!showData_) { // filter out data packet if ((strcmp(e.pe.pkt.wtype,"RTR") == 0 ) || (strcmp(e.pe.pkt.wtype,"MAC") == 0 )) { if (((strcmp(e.pe.pkt.type,"cbr") == 0) || (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } if (!showRouting_){ // filter out routing packet if (strcmp(e.pe.pkt.wtype,"RTR") == 0 ) { if (!((strcmp(e.pe.pkt.type,"cbr") == 0)|| (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } if (!showMac_){ // filter out routing packet if (strcmp(e.pe.pkt.wtype,"MAC") == 0 ) { if (!((strcmp(e.pe.pkt.type,"cbr") == 0)|| (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } } // show only packet with same chracteristics as selected packet if (selectedSrc_ != -1) { //filter being trigger if (e.pe.pkt.esrc != selectedSrc_ ) return ; } if (selectedDst_ != -1) { if (e.pe.pkt.edst != selectedDst_ ) return ; } if (selectedFid_ != -1) { if (atoi(e.pe.pkt.convid) != selectedFid_ ) return ; } if (selectedTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,selectedTraffic_) != 0 ) return ; } // hide packet with same chracteristics as selected packet if (hideSrc_ != -1) { // filter being trigger if (e.pe.pkt.esrc == hideSrc_ ) return ; } if (hideDst_ != -1) { if (e.pe.pkt.edst == hideDst_ ) return ; } if (hideFid_ != -1) { if (atoi(e.pe.pkt.convid) == hideFid_ ) return ; } if (hideTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,hideTraffic_) == 0 ) return ; } //change the packet color on the fly if (selectedColor_ < 0 ) { Paint *paint = Paint::instance(); selectedColor_ = paint->lookup("black",1); } if (colorSrc_ != -1) { if (e.pe.pkt.esrc == colorSrc_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorDst_ != -1) { if (e.pe.pkt.edst == colorDst_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorFid_ != -1) { if (atoi(e.pe.pkt.convid) == colorFid_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,colorTraffic_) == 0 ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (resetf_) paint_[atoi(e.pe.pkt.convid)] = oldpaint_[atoi(e.pe.pkt.convid)] ; if (direction==BACKWARDS) break; if (e.pe.dst == -1) { //broadcasting //a quick hack to give fixed transmission + delay time for //broadcasting packet if (e.time + BPACKET_TXT_TIME < now) break ; n = lookupNode(e.pe.src); BPacket * p = new BPacket(n->x(), n->y(),e.pe.pkt, e.time,e.offset,direction, e.pe.pkt.wBcastDuration ? e.pe.pkt.wBcastDuration : bcast_duration_, e.pe.pkt.wBcastRadius ? e.pe.pkt.wBcastRadius : bcast_radius_); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); break; } ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst); if (ehn == 0 || (ep = ehn->edge) == 0) return; /* * If the current packet will arrive at its destination * at a later time, insert the arrival into the queue * of animations and set its paint id (id for X graphics * context. */ txtime = ep->txtime(e.pe.pkt.size); if (e.time + txtime + ep->delay() >= now) { /* XXX */ Packet *p = new Packet(ep, e.pe.pkt, e.time, txtime, e.offset); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); // fprintf(stderr, "packet %d sent from %d towards %d\n", // e.pe.pkt.id, e.pe.src, e.pe.dst); } break; case 'a': n = lookupNode(e.ae.src); if (n == 0) return; a = n->find_agent((char *) e.ae.agent.name); if ((direction==FORWARDS)&&(e.ae.agent.expired==0)) { if (a == NULL) { // will only create an agent if there isn't one already // there with the same name a = new BoxAgent(e.ae.agent.name, n->size()); a->Animation::insert(&animations_); n->add_agent(a); placeAgent(a, n); } } else { if (a != NULL) { n->delete_agent(a); delete a; } } break; case 'f': // We don't need any redraw for this, because it's always // displayed in monitors in a separate pane n = lookupNode(e.fe.src); if (n == 0) return; a = n->find_agent((char *)e.fe.feature.agent); if (a == 0) return; f = a->find_feature((char *)e.fe.feature.name); if (f == 0) { switch (e.fe.feature.type) { case 'v': f = new VariableFeature(a, e.fe.feature.name); break; case 'l': f = new ListFeature(a, e.fe.feature.name); break; case 's': case 'u': case 'd': f = new TimerFeature(a, e.fe.feature.name); break; } a->add_feature(f); } if (((direction==FORWARDS) && (e.fe.feature.expired == 0)) || ((direction==BACKWARDS) && (strlen(e.fe.feature.oldvalue) > 0))) { char *value; double time_set; if (direction==FORWARDS) { value=(char *)e.fe.feature.value; time_set=now; } else { value=(char *)e.fe.feature.oldvalue; /*XXX need an extra value here*/ time_set=0.0; } switch (e.fe.feature.type) { case 'v': case 'l': f->set_feature(value); break; case 's': f->set_feature(atof(value), TIMER_STOPPED, time_set); break; case 'u': f->set_feature(atof(value), TIMER_UP, time_set); break; case 'd': f->set_feature(atof(value), TIMER_DOWN, time_set); break; } } else { a->delete_feature(f); delete f; } break; case 'r': if (direction == FORWARDS) break; if (e.pe.dst == -1) { //broadcasting //a quick hack to give fixed transmission + delay time for //broadcasting packet if (e.time - BPACKET_TXT_TIME > now) break ; n = lookupNode(e.pe.src); BPacket * p = new BPacket(n->x(), n->y(),e.pe.pkt, e.time,e.offset,direction, e.pe.pkt.wBcastDuration ? e.pe.pkt.wBcastDuration : bcast_duration_, e.pe.pkt.wBcastRadius ? e.pe.pkt.wBcastRadius : bcast_radius_); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); break; } ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst); if (ehn == 0 || (ep = ehn->edge) == 0) return; /* * If the current packet will arrive at its destination * at a later time, insert the arrival into the queue * of animations and set its paint id (id for X graphics * context. */ txtime = ep->txtime(e.pe.pkt.size); if (e.time - (txtime + ep->delay()) <= now) { /* XXX */ Packet *p = new Packet(ep, e.pe.pkt, e.time-(ep->delay() + txtime), txtime, e.offset); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); } break; case '+': ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst); if (direction == FORWARDS) { if (ehn != 0 && ehn->queue != 0) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); ehn->queue->enque(qi,QUEUE_TAIL); qi->insert(&animations_); check_monitors(qi); } } else { if (ehn != 0 && ehn->queue != 0) { q = ehn->queue->remove(e.pe.pkt); delete q; } } break; case '-': ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst); if (direction == FORWARDS) { if (ehn != 0 && ehn->queue != 0) { q = ehn->queue->remove(e.pe.pkt); delete q; } } else { if (ehn != 0 && ehn->queue != 0) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); ehn->queue->enque(qi,QUEUE_HEAD); qi->insert(&animations_); check_monitors(qi); } } break; case 'E': { // Nothing for now Group *grp = lookupGroup(e.pe.dst); if (grp == NULL) { fprintf(stderr, "Packet destination group %d not found\n", e.pe.dst); return; } int *mbr = new int[grp->size()]; grp->get_members(mbr); for (int i = 0; i < grp->size(); i++) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); n = lookupNode(mbr[i]); if (n == 0) { fprintf(stderr, "Group member %d not found\n", mbr[i]); return; } if (direction == FORWARDS) { n->queue()->enque(qi, QUEUE_TAIL); qi->insert(&animations_); check_monitors(qi); } else { qi = n->queue()->remove(e.pe.pkt); delete qi; } } delete mbr; break; } case 'D': { n = lookupNode(e.pe.dst); if (n == NULL) { fprintf(stderr, "Bad node id %d for session deque event\n", e.pe.dst); return; } if (direction == FORWARDS) { q = n->queue()->remove(e.pe.pkt); delete q; } else { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); n->queue()->enque(qi, QUEUE_HEAD); qi->insert(&animations_); check_monitors(qi); } break; } case 'P': // session drop // Get packet to drop. if (direction == FORWARDS) { // fprintf(stderr, "drop on %d -> %d\n", e.pe.src, e.pe.dst); n = lookupNode(e.pe.dst); if (n == 0) return; q = 0; if (n->queue() != 0) { // Remove packet from session queue q = n->queue()->remove(e.pe.pkt); if (q == 0) { // No such packet in queue??? fprintf(stderr, "No packet drop %id in queue\n", e.pe.pkt.id); return; } q->position(x,y); pno = q->paint(); delete q; } // Compute the point at which the dropped packet disappears. // Let's just make this sufficiently far below the lowest // thing on the screen. // Watch out for topologies that have all their nodes lined // up horizontally. In this case, nymin_ == nymax_ == 0. // Set the bottom to -0.028. This was chosen empirically. // The nam display was set to the maximum size and the lowest // position on the display was around -0.028. float bot; if (nymin_ - nymax_ < 0.01) bot = nymin_ - 10 * n->size() ; else bot = nymin_ - (nymax_ - nymin_); Drop *d = new Drop(x, y, bot, n->size()*0.5, /* This is a hack */ e.time, e.offset, e.pe.pkt); d->paint(pno); d->insert(&animations_); check_monitors(d); break; } else { /*direction is BACKWARDS - need to create the packet*/ //fprintf(stderr, "Packet drop backwards\n"); } case 'G': { /* Group event */ Group *grp = lookupGroup(e.ge.src); if (grp == NULL) { grp = new Group(e.ge.grp.name, e.ge.src); add_group(grp); } if (e.ge.grp.flag == GROUP_EVENT_JOIN) { grp->join(e.ge.grp.mbr); // XXX // Hard-coded queue angle for session queues. :( // Create session queue here because they are not like // traditional queues which are created when nam // started. Group member may dynamically join/leave, // so may session queues. We create them here because // there's a 1-1 relationship between join and creating // session queues. n = lookupNode(e.ge.grp.mbr); if (n == NULL) { fprintf(stderr, "Bad node %d for group event\n", e.ge.grp.mbr); return; } // Need more consideration on the placement of these queues Queue *q = new Queue(0.5); q->next_ = queues_; queues_ = q; n->add_sess_queue(e.ge.src, q); } else if (e.ge.grp.flag == GROUP_EVENT_LEAVE) // No deletion of session queues. grp->leave(e.ge.grp.mbr); break; } case 'l': /*link event*/ // if src or dst = -1 this is a layout link (-t *) // so skip over it if (e.le.src == -1 || e.le.dst == -1) return; ehn = lookupEdgeHashNode(e.le.src, e.le.dst); if (ehn == 0) { // if edge doesn't exist try to create it dynamically ep = addEdge(e.le.src, e.le.dst, e); if (!ep) { fprintf(stderr, "Unable to create edge(%d,%d) dynamically.\n", e.le.src, e.le.dst); return; } ehn = lookupEdgeHashNode(e.le.src, e.le.dst); do_relayout= true; } ehnrev = lookupEdgeHashNode(e.le.dst, e.le.src); if (ehnrev == 0) { // if edge doesn't exist try to create it dynamically ep = addEdge(e.le.dst, e.le.src, e); if (!ep) { fprintf(stderr, "Unable to create reverse edge(%d,%d) dynamically.\n", e.le.dst, e.le.src); return; } ehnrev = lookupEdgeHashNode(e.le.dst, e.le.src); do_relayout = true; } if (do_relayout) { //relayout(); relayoutNode(lookupNode(e.le.src)); relayoutNode(lookupNode(e.le.dst)); do_relayout = false; } /*note: many link events are bidirectional events so be careful to apply them to both a link and the reverse of it*/ if (direction==FORWARDS) { // Always save the color before the last DOWN event if (strncmp(e.le.link.state, "DOWN", 4)==0) { ehn->edge->set_down("red"); ehnrev->edge->set_down("red"); } else if (strncmp(e.le.link.state, "UP", 2)==0) { /* XXX Assume an UP event always follows a DOWN event */ ehn->edge->set_up(); ehnrev->edge->set_up(); } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) { ehn->edge->color((char *)e.le.link.color); ehnrev->edge->color((char *)e.le.link.color); } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) { ehn->edge->dlabel((char *)e.le.link.dlabel); ehnrev->edge->dlabel((char *)e.le.link.dlabel); } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) { ehn->edge->dcolor((char *)e.le.link.dcolor); ehnrev->edge->dcolor((char *)e.le.link.dcolor); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.direction); ehnrev->edge->direction((char *)e.le.link.direction); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.direction); ehnrev->edge->direction((char *)e.le.link.direction); } } else { if (strncmp(e.le.link.state, "UP", 2)==0) { ehn->edge->set_down("red"); ehnrev->edge->set_down("red"); } else if (strncmp(e.le.link.state, "DOWN", 4)==0) { ehn->edge->set_up(); } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) { ehn->edge->color((char *)e.le.link.oldColor); ehnrev->edge->color((char *)e.le.link.oldColor); } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) { ehn->edge->dlabel((char *)e.le.link.odlabel); ehnrev->edge->dlabel((char *)e.le.link.odlabel); } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) { ehn->edge->dcolor((char *)e.le.link.odcolor); ehnrev->edge->dcolor((char *)e.le.link.odcolor); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.odirection); ehnrev->edge->direction((char *)e.le.link.odirection); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.odirection); ehnrev->edge->direction((char *)e.le.link.odirection); } } break; case 'n': /* node event */ // Return if node has -t * // Ths node is only used for initial layout if (e.ne.src == -1) return; n = lookupNode(e.ne.src); if (n == 0) { // if node doesn't exist try to create it dynamically n = addNode(e); if (!n) return; } if (direction==FORWARDS) { if (strncmp(e.ne.node.state, "DOWN", 4)==0) { n->set_down("gray"); } else if (strncmp(e.ne.node.state, "UP", 2)==0) { n->set_up(); } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) { // normal color can be defined by user n->color((char *)e.ne.node.color); n->lcolor((char *)e.ne.node.lcolor); } else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) { n->dlabel((char *)e.ne.node.dlabel); } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) { n->dcolor((char *)e.ne.node.dcolor); } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) { n->direction((char *)e.ne.node.direction); } } else { if (strncmp(e.ne.node.state, "UP", 4)==0) { n->set_down("gray"); } else if (strncmp(e.ne.node.state, "DOWN", 2)==0) { n->set_up(); } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) { n->color((char *)e.ne.node.oldColor); n->lcolor((char *)e.ne.node.olcolor); } else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) { n->dlabel((char *)e.ne.node.odlabel); } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) { n->dcolor((char *)e.ne.node.odcolor); } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) { n->direction((char *)e.ne.node.odirection); } } break; case 'm': /* node mark event */ NodeMark *cm; n = lookupNode(e.me.src); if (n == 0) return; cm = n->find_mark((char *) e.me.mark.name); if (direction == FORWARDS) { if (e.me.mark.expired == 0) { /* once created, a node mark cannot be changed*/ if (cm == NULL) n->add_mark((char *)e.me.mark.name, (char *)e.me.mark.color, (char *)e.me.mark.shape); } else /* expired */ n->delete_mark((char *)e.me.mark.name); } else { /* * backward: * (1) create it if expired == 1 * (2) delete it if expired == 0 */ if (e.me.mark.expired == 0) n->delete_mark((char *)e.me.mark.name); else { /* re-create the circle */ if (cm == NULL) n->add_mark((char *)e.me.mark.name, (char *)e.me.mark.color, (char *)e.me.mark.shape); } } break; case 'R': // route event if (((e.re.route.expired==0)&&(direction==FORWARDS))|| ((e.re.route.expired==1)&&(direction==BACKWARDS))) { // this is a new route n = lookupNode(e.re.src); if (n == 0) return; ehn = lookupEdgeHashNode(e.re.src, e.re.dst); if (ehn == 0) return; int oif=1; if (strncmp(e.re.route.mode, "iif", 3)==0) oif=0; r = new Route(n, ehn->edge, e.re.route.group, e.re.route.pktsrc, e.re.route.neg, oif, e.re.route.timeout, now); n->add_route(r); n->place_route(r); r->insert(&animations_); r->paint(paint_[e.re.route.group & paintMask_]); check_monitors(r); } else { // an old route expired n = lookupNode(e.re.src); if (n == 0) return; // src and dst are node ids ehn = lookupEdgeHashNode(e.re.src, e.re.dst); if (ehn == 0) return; int oif = 1; if (strncmp(e.re.route.mode, "iif", 3) == 0) { oif=0; } r = n->find_route(ehn->edge, e.re.route.group, e.re.route.pktsrc, oif); if (r == 0) { fprintf(stderr, "nam: attempt to delete non-existent route\n"); abort(); } n->delete_route(r); delete r; } break; case 'd': add_drop(e, now, direction); } } //--------------------------------------------------------------------- // void // NetModel::add_drop(const TraceEvent &e, double now, int direction) // - This method adds a packet drop animation to the animations_ list // - Packet drops can occur from queues and edges. If the queue is // not being displayed the packet is dropped from the node // position. // - If the animation direction is BACKWARDS a packet should be // created but it appears that this code does not do that. //--------------------------------------------------------------------- void NetModel::add_drop(const TraceEvent &e, double now, int direction) { EdgeHashNode *ehn; QueueItem *q; Packet *p; Lan *lan; float x, y; int pno; // paint number (color with which to draw) // Get packet to drop. if (direction == FORWARDS) { ehn = lookupEdgeHashNode(e.pe.src, e.pe.dst); if (ehn == 0) { return; } q = 0; if (ehn->queue != 0) { // if there's a queue, try removing it from the queue first // queue drops are more common than link drops... q = ehn->queue->remove(e.pe.pkt); } if (q == 0) { // perhaps it's a link packet drop p = lookupPacket(e.pe.src, e.pe.dst, e.pe.pkt.id); if (p != NULL) { // it was a link packet drop p->position(x, y, now); ehn->edge->DeletePacket(p); pno = p->paint(); delete p; } else if ((lan = lookupLan(e.pe.src)) != NULL) { /* * If it's a Lan (selective) packet drop, which means * the packet is only dropped on some of the lan links, * register the packet on the lan and drop it when the * packet is actually transmitted to that lan link. * * When the packet is actually dropped, this function will be * called again, but at that time the packet will be actually * on the link and this code will not be executed. */ lan->register_drop(e); return; } else { // probably it was a queue drop, but we're not displaying // that queue // It's possible that this packet is dropped directly from // the queue, even before the enqT_ module. In this case, // we should still produce a packet drop; we use the position // of the node to generate the drop. Node *s = lookupNode(e.pe.src); if (s == NULL) { fprintf(stderr, "NetModel::add_drop(): cannot find src node for packet drop.\n"); abort(); } x = s->x(); y = s->y(); pno = paint_[e.pe.pkt.attr & paintMask_]; } } else { // packet dropped from queue // get x,y position of queue item q->position(x, y); pno = q->paint(); delete q; } /* * Compute the point at which the dropped packet disappears. * Let's just make this sufficiently far below the lowest * thing on the screen. * * Watch out for topologies that have all their nodes lined * up horizontally. In this case, nymin_ == nymax_ == 0. * Set the bottom to -0.028. This was chosen empirically. * The nam display was set to the maximum size and the lowest * position on the display was around -0.028. */ float bottom; if (nymin_ - nymax_ < 0.01) { bottom = nymin_ - 20.0 * ehn->edge->PacketHeight() ; } else { bottom = nymin_ - (nymax_ - nymin_); } // The drop animation is taken care of by the drop class Drop * d = new Drop(x, y, bottom, 4 * ehn->edge->PacketHeight(), e.time, e.offset, e.pe.pkt); d->paint(pno); d->insert(&animations_); check_monitors(d); return; } else { // direction is BACKWARDS - need to create the packet Lan *lan = lookupLan(e.pe.src); if (lan != NULL) { // We need to remove drop status in lans lan->remove_drop(e); //fprintf(stderr, "lan dropped packet %d is removed on lan link %d->%d\n", // e.pe.pkt.id, e.pe.src, e.pe.dst); return; } } } //---------------------------------------------------------------------------- // Node * // NetModel::addNode(const TraceEvent &e) // - adds a node to the netmodel getting configuration info from the fields // in the TraceEvent //---------------------------------------------------------------------------- Node * NetModel::addNode(const TraceEvent &e) { Node * n = NULL; char src[32]; if (e.tt == 'n') { sprintf(src, "%d", e.ne.src); n = lookupNode(e.ne.src); // And remove them to be replaced by this node if (n != NULL) { fprintf(stderr, "Skipping duplicate node %s definition. \n", src); //removeNode(n); } // Determine Node Type if (!strncmp(e.ne.mark.shape, "circle",6)) { n = new CircleNode(src, e.ne.size); } else if (!strncmp(e.ne.mark.shape, "box", 3) || !strncmp(e.ne.mark.shape, "square", 6)) { n = new BoxNode(src, e.ne.size); } else if (!strncmp(e.ne.mark.shape, "hexagon",7)) { n = new HexagonNode(src, e.ne.size); } else { return NULL; } // Check for wireless node if (e.ne.wireless) { n->wireless_ = true; //fprintf(stderr, "We have wireless nodes :-) !!!\n"); } // Node Address // May need to check for no address passed in n->setaddr(e.ne.node.addr); addAddress(n->num(), e.ne.node.addr); // Node Color n->init_color(e.ne.node.color); n->lcolor(e.ne.node.lcolor); // dlabel initilization n->dlabel(e.ne.node.dlabel); // Set X,Y cordinates n->place(e.ne.x, e.ne.y); // Add Node to drawables list n->next_ = nodes_; nodes_ = n; n->Animation::insert(&drawables_); // Set Packet size to be running average of the last 5 nodes (25% of node size) packet_size_ = (4.0 * packet_size_ + e.ne.size*0.25)/5.0; } return (n); } //---------------------------------------------------------------------------- // Edge * // NetModel::addEdge(int argc, const char *const *argv) // // link // Create a link/edge between the specified source // and destination. Add it to this NetModel's list // of drawables and to the source's list of links. //---------------------------------------------------------------------------- Edge * NetModel::addEdge(int argc, const char *const *argv) { Node * src, * dst; Edge * edge = NULL; double bandwidth, delay, length, angle; if (strcmp(argv[1], "link") == 0) { src = lookupNode(atoi(argv[2])); dst = lookupNode(atoi(argv[3])); if (src && dst) { bandwidth = atof(argv[4]); delay = atof(argv[5]); length = atof(argv[6]); angle = atof(argv[7]); //enlarge link if the topology is a mixture of //wired and wireless network if (wireless_) { length = delay * WIRELESS_SCALE ; } edge = new Edge(src, dst, packet_size_, bandwidth, delay, length, angle, wireless_); edge->init_color("black"); enterEdge(edge); edge->Animation::insert(&drawables_); src->add_link(edge); } } return edge; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- Edge * NetModel::addEdge(int src_id, int dst_id, const TraceEvent &e) { Node *src, *dst; Edge * edge = NULL; double bandwidth, delay, length, angle; if (e.tt == 'l') { src = lookupNode(src_id); dst = lookupNode(dst_id); if (src && dst) { bandwidth = e.le.link.rate; delay = e.le.link.delay; length = e.le.link.length; angle = e.le.link.angle; //enlarge link if the topology is a mixture of //wired and wireless network if (wireless_) { length = delay * WIRELESS_SCALE ; } edge = new Edge(src, dst, packet_size_, bandwidth, delay, length, angle, wireless_); edge->init_color("black"); enterEdge(edge); edge->Animation::insert(&drawables_); src->add_link(edge); } } return edge; } void NetModel::addView(NetView* p) { p->next_ = views_; views_ = p; } //---------------------------------------------------------------------- // Node * // NetModel::lookupNode(int nn) const //---------------------------------------------------------------------- Node * NetModel::lookupNode(int nn) const { for (Node* n = nodes_; n != 0; n = n->next_) if (n->num() == nn) return (n); return NULL; } //---------------------------------------------------------------------- // Edge * // NetModel::lookupEdge(int source, int destination) const //---------------------------------------------------------------------- Edge * NetModel::lookupEdge(int source, int destination) const { EdgeHashNode * edge_hash_node; edge_hash_node = lookupEdgeHashNode(source, destination); return edge_hash_node->edge; } void NetModel::removeNode(Node *n) { Node *p, *q; // Remove node n from nodes_ list, then delete it for (p = nodes_; p != 0; q = p, p = p->next_) if (p == n) break; if (p == nodes_) nodes_ = p->next_; else q->next_ = p->next_; delete p; } Agent *NetModel::lookupAgent(int id) const { for (Node* n = nodes_; n != 0; n = n->next_) for(Agent* a= n->agents(); a != 0; a = a->next_) if (a->number() == id) return (a); return (0); } Lan *NetModel::lookupLan(int nn) const { for (Lan* l = lans_; l != 0; l = l->next_) if (l->num() == nn) return (l); /* XXX */ //fprintf(stderr, "nam: no such lan %d\n", nn); //exit(1); return (0);// make visual c++ happy } Packet *NetModel::newPacket(PacketAttr &pkt, Edge *e, double time) { /*this is called when we get a triggered event such as a packet getting duplicated within a LAN*/ Packet *p = new Packet(e, pkt, time, e->txtime(pkt.size), 0); p->insert(&animations_); p->paint(paint_[pkt.attr & paintMask_]); check_monitors(p); return p; } Packet *NetModel::lookupPacket(int src, int dst, int id) const { EdgeHashNode *h = lookupEdgeHashNode(src, dst); if (h == 0) return NULL; int ctr=0; for (Packet *p=h->edge->packets(); p!=NULL; p=p->next()) { #define PARANOID #ifdef PARANOID ctr++; if (ctr>h->edge->no_of_packets()) abort(); #endif if (p->id() == id) return p; } /*have to fail silent or we can't cope with link drops when doing settime*/ return 0; } /* Do not delete groups, because they are not explicitly deleted */ int NetModel::add_group(Group *grp) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(grpHash_, (const char *)grp->addr(), &newEntry); if (he == NULL) return -1; if (newEntry) { Tcl_SetHashValue(he, (ClientData)grp); nGroup_++; } return 0; } Group* NetModel::lookupGroup(unsigned int addr) { Tcl_HashEntry *he = Tcl_FindHashEntry(grpHash_, (const char *)addr); if (he == NULL) return NULL; return (Group *)Tcl_GetHashValue(he); } // Remove a view from the views link, but not delete it void NetModel::remove_view(View *v) { View *p, *q; p = q = views_; if (p == v) { views_ = p->next_; return; } while (p != NULL) { q = p; p = p->next_; if (p == v) { q->next_ = p->next_; return; } } } //---------------------------------------------------------------------- // int // NetModel::command(int argc, const char *const *argv) // - Parses tcl commands (hook to enter c++ code from tcl) //---------------------------------------------------------------------- int NetModel::command(int argc, const char *const *argv) { Tcl& tcl = Tcl::instance(); int i; Node * node; double time; if (argc == 2) { if (strcmp(argv[1], "layout") == 0) { /* * layout * Compute reasonable defaults for missing node or edge * sizes based on the maximum link delay. Lay out the * nodes and edges as specified in the layout file. */ scale_estimate(); placeEverything(); return (TCL_OK); } if (strcmp(argv[1], "showtrees") == 0) { /* * showtrees */ color_subtrees(); for (View* p = views_; p != 0; p = p->next_) { p->draw(); } return (TCL_OK); } if (strcmp(argv[1],"resetFilter")==0) { resetf_ = 1 ; selectedSrc_ = -1 ; selectedDst_ = -1 ; selectedFid_ = -1 ; colorSrc_ = -1 ; colorDst_ = -1 ; colorFid_ = -1 ; hideSrc_ = -1 ; hideDst_ = -1 ; hideFid_ = -1 ; for (i = 0; i < PTYPELEN; ++i) { selectedTraffic_[i] = '\0' ; colorTraffic_[i] = '\0' ; hideTraffic_[i] = '\0' ; } return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "incr-nodesize") == 0) { /* * incr-nodesize */ node_sizefac_ *= atof(argv[2]); for (Node *n = nodes_; n != 0; n = n->next_) for (Edge *e=n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } return (TCL_OK); } if (strcmp(argv[1], "decr-nodesize") == 0) { node_sizefac_ /= atof(argv[2]); for (Node *n = nodes_; n != 0; n = n->next_) for (Edge *e=n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } return(TCL_OK); } if (strcmp(argv[1], "updateNodePositions") == 0) { time = strtod(argv[2], NULL); for (node = nodes_; node; node = node->next_) { node->updatePositionAt(time); moveNode(node); // This updates the links and agents connected to the node } return TCL_OK; } if (strcmp(argv[1], "view") == 0) { /* * view * Create the window for the network layout/topology. * Used for nam editor */ EditView *v = new EditView(argv[2], this, 300, 700); v->next_ = views_; views_ = v; return (TCL_OK); } if (strcmp(argv[1], "psview") == 0) { /* * PSView * Print the topology to a file */ PSView *v = new PSView(argv[2], this); v->render(); delete(v); return (TCL_OK); } if (strcmp(argv[1], "testview") == 0) { /* * Added for nam validation test */ TestView *v = new TestView(argv[2], this); v->render(); delete(v); return (TCL_OK); } if (strcmp(argv[1], "editview") == 0) { /* * editview */ EditView *v = new EditView(argv[2], this); v->next_ = views_; views_ = v; return (TCL_OK); } if (strcmp(argv[1],"savelayout")==0) { save_layout(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-traffic")==0) { strcpy(selectedTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-src")==0) { selectedSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-dst")==0) { selectedDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-fid")==0) { selectedFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-traffic")==0) { strcpy(hideTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-src")==0) { hideSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-dst")==0) { hideDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-fid")==0) { hideFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-traffic")==0) { resetf_ = 0 ; strcpy(colorTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-src")==0) { resetf_ = 0 ; colorSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-dst")==0) { resetf_ = 0 ; colorDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-fid")==0) { resetf_ = 0 ; colorFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-color")==0) { Paint *paint = Paint::instance(); selectedColor_ = paint->lookup(argv[2], 1); if (selectedColor_ < 0) { fprintf(stderr,"%s color: no such color: %s\n", argv[0], argv[2]); selectedColor_ = paint->lookup("black",1); if (selectedColor_ < 0) { tcl.resultf("%s no black! - bailing"); return (TCL_ERROR); } } return (TCL_OK); } if (strcmp(argv[1], "node") == 0) { // else if (argc == 3 && strcmp(argv[1], "node") == 0) /* * node [] * Create a node using the specified name * and the default size and insert it into this * NetModel's list of drawables. */ //Node* n = addNode(argc, argv); char * line = new char[strlen(argv[2])]; strncpy(line, argv[2],strlen(argv[2])); parsetable_.parseLine(line); Node * node = addNode(traceevent_); delete line; if (node) { return (TCL_OK); } else { tcl.resultf("Unable to create Node %s.", argv[2]); return (TCL_ERROR); } } } else if (argc >= 4 && strcmp(argv[1], "agent") == 0) { // Create a new agent /* * agent