agent.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1990-1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 #ifndef lint
00036 static const char rcsid[] =
00037     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/common/agent.cc,v 1.78 2005/07/13 03:51:23 tomh Exp $ (LBL)";
00038 #endif
00039 
00040 #include <assert.h>
00041 #include <stdlib.h>
00042 
00043 #include "config.h"
00044 #include "agent.h"
00045 #include "ip.h"
00046 #include "flags.h"
00047 #include "address.h"
00048 #include "app.h"
00049 #ifdef HAVE_STL
00050 #include "nix/hdr_nv.h"
00051 #include "nix/nixnode.h"
00052 #endif //HAVE_STL
00053 
00054 
00055 
00056 #ifndef min
00057 #define min(a, b) (((a) < (b)) ? (a) : (b))
00058 #endif
00059 
00060 static class AgentClass : public TclClass {
00061 public:
00062     AgentClass() : TclClass("Agent") {} 
00063     TclObject* create(int, const char*const*) {
00064         return (new Agent(PT_NTYPE));
00065     }
00066 } class_agent;
00067 
00068 int Agent::uidcnt_;     /* running unique id */
00069 
00070 Agent::Agent(packet_t pkttype) : 
00071     size_(0), type_(pkttype), 
00072     channel_(0), traceName_(NULL),
00073     oldValueList_(NULL), app_(0), et_(0)
00074 {
00075 }
00076 
00077 void
00078 Agent::delay_bind_init_all()
00079 {
00080     delay_bind_init_one("agent_addr_");
00081     delay_bind_init_one("agent_port_");
00082     delay_bind_init_one("dst_addr_");
00083     delay_bind_init_one("dst_port_");
00084     delay_bind_init_one("fid_");
00085     delay_bind_init_one("prio_");
00086     delay_bind_init_one("flags_");
00087     delay_bind_init_one("ttl_");
00088     delay_bind_init_one("class_");
00089     Connector::delay_bind_init_all();
00090 }
00091 
00092 int
00093 Agent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00094 {
00095     if (delay_bind(varName, localName, "agent_addr_", (int*)&(here_.addr_), tracer)) return TCL_OK;
00096     if (delay_bind(varName, localName, "agent_port_", (int*)&(here_.port_), tracer)) return TCL_OK;
00097     if (delay_bind(varName, localName, "dst_addr_", (int*)&(dst_.addr_), tracer)) return TCL_OK;
00098     if (delay_bind(varName, localName, "dst_port_", (int*)&(dst_.port_), tracer)) return TCL_OK;
00099     if (delay_bind(varName, localName, "fid_", (int*)&fid_, tracer)) return TCL_OK;
00100     if (delay_bind(varName, localName, "prio_", (int*)&prio_, tracer)) return TCL_OK;
00101     if (delay_bind(varName, localName, "flags_", (int*)&flags_, tracer)) return TCL_OK;
00102     if (delay_bind(varName, localName, "ttl_", &defttl_, tracer)) return TCL_OK;
00103     if (delay_bind(varName, localName, "class_", (int*)&fid_, tracer)) return TCL_OK;
00104     return Connector::delay_bind_dispatch(varName, localName, tracer);
00105 }
00106 
00107 
00108 Agent::~Agent()
00109 {
00110     if (oldValueList_ != NULL) {
00111         OldValue *p = oldValueList_;
00112         while (oldValueList_ != NULL) {
00113             oldValueList_ = oldValueList_->next_;
00114             delete p;
00115             p = oldValueList_; 
00116         }
00117     }
00118 }
00119 
00120 int Agent::command(int argc, const char*const* argv)
00121 {
00122     Tcl& tcl = Tcl::instance();
00123     if (argc == 2) {
00124         if (strcmp(argv[1], "delete-agent-trace") == 0) {
00125             if ((traceName_ == 0) || (channel_ == 0))
00126                 return (TCL_OK);
00127             deleteAgentTrace();
00128             return (TCL_OK);
00129         } else if (strcmp(argv[1], "show-monitor") == 0) {
00130             if ((traceName_ == 0) || (channel_ == 0))
00131                 return (TCL_OK);
00132             monitorAgentTrace();
00133             return (TCL_OK);
00134         } else if (strcmp(argv[1], "close") == 0) {
00135             close();
00136             return (TCL_OK);
00137         } else if (strcmp(argv[1], "listen") == 0) {
00138                         listen();
00139                         return (TCL_OK);
00140                 } else if (strcmp(argv[1], "dump-namtracedvars") == 0) {
00141             enum_tracedVars();
00142             return (TCL_OK);
00143         }
00144         
00145     }
00146     else if (argc == 3) {
00147         if (strcmp(argv[1], "attach") == 0) {
00148             int mode;
00149             const char* id = argv[2];
00150             channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00151             if (channel_ == 0) {
00152                 tcl.resultf("trace: can't attach %s for writing", id);
00153                 return (TCL_ERROR);
00154             }
00155             return (TCL_OK);
00156         } else if (strcmp(argv[1], "add-agent-trace") == 0) {
00157             // we need to write nam traces and set agent trace name
00158             if (channel_ == 0) {
00159                 tcl.resultf("agent %s: no trace file attached", name_);
00160                 return (TCL_OK);
00161             }
00162             addAgentTrace(argv[2]);
00163             return (TCL_OK);
00164         } else if (strcmp(argv[1], "connect") == 0) {
00165             connect((nsaddr_t)atoi(argv[2]));
00166             return (TCL_OK);
00167         } else if (strcmp(argv[1], "send") == 0) {
00168             sendmsg(atoi(argv[2]));
00169             return (TCL_OK);
00170         } else if (strcmp(argv[1], "set_pkttype") == 0) {
00171             set_pkttype(packet_t(atoi(argv[2])));
00172             return (TCL_OK);
00173         }
00174     }
00175     else if (argc == 4) {   
00176         if (strcmp(argv[1], "sendmsg") == 0) {
00177             sendmsg(atoi(argv[2]), argv[3]);
00178             return (TCL_OK);
00179         }
00180     }
00181     else if (argc == 5) {
00182         if (strcmp(argv[1], "sendto") == 0) {
00183             sendto(atoi(argv[2]), argv[3], (nsaddr_t)atoi(argv[4]));
00184             return (TCL_OK);
00185         }
00186     }
00187     if (strcmp(argv[1], "tracevar") == 0) {
00188         // wrapper of TclObject's trace command, because some tcl
00189         // agents (e.g. srm) uses it.
00190         const char* args[4];
00191         char tmp[6];
00192         strcpy(tmp, "trace");
00193         args[0] = argv[0];
00194         args[1] = tmp;
00195         args[2] = argv[2];
00196         if (argc > 3)
00197             args[3] = argv[3];
00198         return (Connector::command(argc, args));
00199     }
00200     return (Connector::command(argc, argv));
00201 }
00202 
00203 void Agent::flushAVar(TracedVar *v)
00204 {
00205     char wrk[256], value[128];
00206     int n;
00207 
00208     // XXX we need to keep track of old values. What's the best way?
00209     v->value(value, 128);
00210     if (strcmp(value, "") == 0) 
00211         // no value, because no writes has occurred to this var
00212         return;
00213     sprintf(wrk, "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -o %s -T v -x",
00214         Scheduler::instance().clock(), addr(), dst_.addr_,
00215         v->name(), traceName_, value); 
00216     n = strlen(wrk);
00217     wrk[n] = '\n';
00218     wrk[n+1] = 0;
00219     (void)Tcl_Write(channel_, wrk, n+1);
00220 }
00221 
00222 void Agent::deleteAgentTrace()
00223 {
00224     char wrk[256];
00225 
00226     // XXX we don't know InstVar outside of Tcl! Is there any
00227     // tracedvars hidden in InstVar? If so, shall we have a tclclInt.h?
00228     TracedVar* var = tracedvar_;
00229     for ( ;  var != 0;  var = var->next_) 
00230         flushAVar(var);
00231 
00232     // we need to flush all var values to trace file, 
00233     // so nam can do backtracing
00234     sprintf(wrk, "a -t "TIME_FORMAT" -s %d -d %d -n %s -x",
00235         Scheduler::instance().clock(), here_.addr_,
00236         dst_.addr_, traceName_); 
00237     if (traceName_ != NULL)
00238         delete[] traceName_;
00239     traceName_ = NULL;
00240 }
00241 
00242 OldValue* Agent::lookupOldValue(TracedVar *v)
00243 {
00244     OldValue *p = oldValueList_;
00245     while ((p != NULL) && (p->var_ != v))
00246         p = p->next_;
00247     return p;
00248 }
00249 
00250 void Agent::insertOldValue(TracedVar *v, const char *value)
00251 {
00252     OldValue *p = new OldValue;
00253     assert(p != NULL);
00254     strncpy(p->val_, value, min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
00255     p->var_ = v;
00256     p->next_ = NULL;
00257     if (oldValueList_ == NULL) 
00258         oldValueList_ = p;
00259     else {
00260         p->next_ = oldValueList_;
00261         oldValueList_ = p;
00262     }
00263 }
00264 
00265 // callback from traced variable updates
00266 void Agent::trace(TracedVar* v) 
00267 {
00268     if (channel_ == 0)
00269         return;
00270     char wrk[256], value[128];
00271     int n;
00272 
00273     // XXX we need to keep track of old values. What's the best way?
00274     v->value(value, 128);
00275 
00276     // XXX hack: how do I know ns has not started yet?
00277     // if there's nothing in value, return
00278     static int started = 0;
00279     if (!started) {
00280         Tcl::instance().evalc("[Simulator instance] is-started");
00281         if (Tcl::instance().result()[0] == '0')
00282             // Simulator not started, do nothing
00283             return;
00284         // remember for next time (so we don't always have to call to tcl)
00285         started = 1;
00286     };
00287 
00288     OldValue *ov = lookupOldValue(v);
00289     if (ov != NULL) {
00290         sprintf(wrk, 
00291             "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -v %s -o %s -T v",
00292             Scheduler::instance().clock(), here_.addr_,
00293             dst_.addr_, v->name(), traceName_, value, ov->val_);
00294         strncpy(ov->val_, 
00295             value,
00296             min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
00297     } else {
00298         // if there is value, insert it into old value list
00299         sprintf(wrk, "f -t "TIME_FORMAT" -s %d -d %d -n %s -a %s -v %s -T v",
00300             Scheduler::instance().clock(), here_.addr_,
00301             dst_.addr_, v->name(), traceName_, value);
00302         insertOldValue(v, value);
00303     }
00304     n = strlen(wrk);
00305     wrk[n] = '\n';
00306     wrk[n+1] = 0;
00307     (void)Tcl_Write(channel_, wrk, n+1);
00308 }
00309 
00310 void Agent::monitorAgentTrace()
00311 {
00312     char wrk[256];
00313     int n;
00314     double curTime = (&Scheduler::instance() == NULL ? 0 : 
00315               Scheduler::instance().clock());
00316     
00317     sprintf(wrk, "v -t "TIME_FORMAT" -e monitor_agent %d %s",
00318         curTime, here_.addr_, traceName_);
00319     n = strlen(wrk);
00320     wrk[n] = '\n';
00321     wrk[n+1] = 0;
00322     if (channel_)
00323         (void)Tcl_Write(channel_, wrk, n+1);
00324 }
00325 
00326 void Agent::addAgentTrace(const char *name)
00327 {
00328     char wrk[256];
00329     int n;
00330     double curTime = (&Scheduler::instance() == NULL ? 0 : 
00331               Scheduler::instance().clock());
00332     
00333     sprintf(wrk, "a -t "TIME_FORMAT" -s %d -d %d -n %s",
00334         curTime, here_.addr_, dst_.addr_, name);
00335     n = strlen(wrk);
00336     wrk[n] = '\n';
00337     wrk[n+1] = 0;
00338     if (channel_)
00339         (void)Tcl_Write(channel_, wrk, n+1);
00340     // keep agent trace name
00341     if (traceName_ != NULL)
00342         delete[] traceName_;
00343     traceName_ = new char[strlen(name)+1];
00344     strcpy(traceName_, name);
00345 }
00346 
00347 void Agent::timeout(int)
00348 {
00349 }
00350 
00351 /* 
00352  * Callback to application to notify the reception of a number of bytes  
00353  */
00354 void Agent::recvBytes(int nbytes)
00355 {
00356     if (app_)
00357         app_->recv(nbytes); 
00358 }
00359 
00360 /* 
00361  * Callback to application to notify the termination of a connection  
00362  */
00363 void Agent::idle()
00364 {
00365     if (app_)
00366         app_->resume();
00367 }
00368 
00369 /* 
00370  * Assign application pointer for callback purposes    
00371  */
00372 void Agent::attachApp(Application *app)
00373 {
00374     app_ = app;
00375 }
00376 
00377 void Agent::close()
00378 {
00379 }
00380 
00381 void Agent::listen()
00382 {
00383 }
00384 
00385 /* 
00386  * This function is a placeholder in case applications want to dynamically
00387  * connect to agents (presently, must be done at configuration time).
00388  */
00389 void Agent::connect(nsaddr_t /*dst*/)
00390 {
00391 /*
00392     dst_ = dst;
00393 */
00394 }
00395 
00396 /*
00397  * Place holders for sending application data
00398  */ 
00399 
00400 void Agent::sendmsg(int /*sz*/, AppData* /*data*/, const char* /*flags*/)
00401 {
00402     fprintf(stderr, 
00403     "Agent::sendmsg(int, AppData*, const char*) not implemented\n");
00404     abort();
00405 }
00406 
00407 void Agent::sendmsg(int /*nbytes*/, const char* /*flags*/)
00408 {
00409 }
00410 
00411 void Agent::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/,
00412            nsaddr_t /*dst*/)
00413 {
00414     fprintf(stderr, 
00415     "Agent::sendmsg(int, AppData*, const char*) not implemented\n");
00416     abort();
00417 }
00418 
00419 // to support application using message passing
00420 void Agent::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/,
00421            ns_addr_t /*dst*/)
00422 {
00423 }
00424 
00425 /* 
00426  * This function is a placeholder in case applications want to dynamically
00427  * connect to agents (presently, must be done at configuration time).
00428  */
00429 void Agent::sendto(int /*nbytes*/, const char /*flags*/[], nsaddr_t /*dst*/)
00430 {
00431 /*
00432     dst_ = dst;
00433     sendmsg(nbytes, flags);
00434 */
00435 }
00436 // to support application using message passing
00437 void Agent::sendto(int /*nbytes*/, const char /*flags*/[], ns_addr_t /*dst*/)
00438 {
00439 }
00440 
00441 void Agent::recv(Packet* p, Handler*)
00442 {
00443     if (app_)
00444         app_->recv(hdr_cmn::access(p)->size());
00445     /*
00446      * didn't expect packet (or we're a null agent?)
00447      */
00448     Packet::free(p);
00449 }
00450 
00451 /*
00452  * initpkt: fill in all the generic fields of a pkt
00453  */
00454 
00455 void
00456 Agent::initpkt(Packet* p) const
00457 {
00458     hdr_cmn* ch = hdr_cmn::access(p);
00459     ch->uid() = uidcnt_++;
00460     ch->ptype() = type_;
00461     ch->size() = size_;
00462     ch->timestamp() = Scheduler::instance().clock();
00463     ch->iface() = UNKN_IFACE.value(); // from packet.h (agent is local)
00464     ch->direction() = hdr_cmn::NONE;
00465 
00466     ch->error() = 0;    /* pkt not corrupt to start with */
00467 
00468     hdr_ip* iph = hdr_ip::access(p);
00469     iph->saddr() = here_.addr_;
00470     iph->sport() = here_.port_;
00471     iph->daddr() = dst_.addr_;
00472     iph->dport() = dst_.port_;
00473     
00474     //DEBUG
00475     //if (dst_ != -1)
00476     //  printf("pl break\n");
00477     
00478     iph->flowid() = fid_;
00479     iph->prio() = prio_;
00480     iph->ttl() = defttl_;
00481 
00482     hdr_flags* hf = hdr_flags::access(p);
00483     hf->ecn_capable_ = 0;
00484     hf->ecn_ = 0;
00485     hf->eln_ = 0;
00486     hf->ecn_to_echo_ = 0;
00487     hf->fs_ = 0;
00488     hf->no_ts_ = 0;
00489     hf->pri_ = 0;
00490     hf->cong_action_ = 0;
00491     hf->qs_ = 0;
00492 #ifdef HAVE_STL
00493 
00494     hdr_nv* nv = hdr_nv::access(p);
00495     if (0)
00496         printf("Off hdr_nv %d, ip_hdr %d myaddr %d\n",
00497                hdr_nv::offset(), hdr_ip::offset(), here_.addr_);
00498     NixNode* pNixNode = NixNode::GetNodeObject(here_.addr_);
00499     if (0)
00500         printf("Node Object %p\n", pNixNode);
00501     if (pNixNode) { 
00502         // If we get non-null, indicates nixvector routing in use
00503         // Delete any left over nv in the packet
00504         // Get a nixvector to the target (may create new)
00505         NixVec* pNv = pNixNode->GetNixVector(dst_.addr_);
00506         pNv->Reset();
00507         nv->nv() = pNv; // And set the nixvec in the packet
00508         nv->h_used = 0; // And reset used portion to 0
00509     }
00510 #endif //HAVE_STL
00511 }
00512 
00513 /*
00514  * allocate a packet and fill in all the generic fields
00515  */
00516 Packet*
00517 Agent::allocpkt() const
00518 {
00519     Packet* p = Packet::alloc();
00520     initpkt(p);
00521     return (p);
00522 }
00523 
00524 /* allocate a packet and fill in all the generic fields and allocate
00525  * a buffer of n bytes for data
00526  */
00527 Packet*
00528 Agent::allocpkt(int n) const
00529 {
00530         Packet* p = allocpkt();
00531 
00532     if (n > 0)
00533             p->allocdata(n);
00534 
00535     return(p);
00536 }

Generated on Tue Mar 6 16:47:43 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6