Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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.74 2002/06/14 23:15:02 yuri 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::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/,
00408                    nsaddr_t /*dst*/)
00409 {
00410         fprintf(stderr, 
00411         "Agent::sendmsg(int, AppData*, const char*) not implemented\n");
00412         abort();
00413 }
00414 
00415 void Agent::sendmsg(int /*nbytes*/, const char* /*flags*/)
00416 {
00417 }
00418 
00419 /* 
00420  * This function is a placeholder in case applications want to dynamically
00421  * connect to agents (presently, must be done at configuration time).
00422  */
00423 void Agent::sendto(int /*nbytes*/, const char /*flags*/[], nsaddr_t /*dst*/)
00424 {
00425 /*
00426         dst_ = dst;
00427         sendmsg(nbytes, flags);
00428 */
00429 }
00430 
00431 void Agent::recv(Packet* p, Handler*)
00432 {
00433         if (app_)
00434                 app_->recv(hdr_cmn::access(p)->size());
00435         /*
00436          * didn't expect packet (or we're a null agent?)
00437          */
00438         Packet::free(p);
00439 }
00440 
00441 /*
00442  * initpkt: fill in all the generic fields of a pkt
00443  */
00444 
00445 void
00446 Agent::initpkt(Packet* p) const
00447 {
00448         hdr_cmn* ch = hdr_cmn::access(p);
00449         ch->uid() = uidcnt_++;
00450         ch->ptype() = type_;
00451         ch->size() = size_;
00452         ch->timestamp() = Scheduler::instance().clock();
00453         ch->iface() = UNKN_IFACE.value(); // from packet.h (agent is local)
00454         ch->direction() = hdr_cmn::NONE;
00455 
00456         ch->error() = 0;        /* pkt not corrupt to start with */
00457 
00458         hdr_ip* iph = hdr_ip::access(p);
00459         iph->saddr() = here_.addr_;
00460         iph->sport() = here_.port_;
00461         iph->daddr() = dst_.addr_;
00462         iph->dport() = dst_.port_;
00463         
00464         //DEBUG
00465         //if (dst_ != -1)
00466         //  printf("pl break\n");
00467         
00468         iph->flowid() = fid_;
00469         iph->prio() = prio_;
00470         iph->ttl() = defttl_;
00471 
00472         hdr_flags* hf = hdr_flags::access(p);
00473         hf->ecn_capable_ = 0;
00474         hf->ecn_ = 0;
00475         hf->eln_ = 0;
00476         hf->ecn_to_echo_ = 0;
00477         hf->fs_ = 0;
00478         hf->no_ts_ = 0;
00479         hf->pri_ = 0;
00480         hf->cong_action_ = 0;
00481 #ifdef HAVE_STL
00482 
00483         hdr_nv* nv = hdr_nv::access(p);
00484         if (0)
00485                 printf("Off hdr_nv %d, ip_hdr %d myaddr %ld\n",
00486                        hdr_nv::offset(), hdr_ip::offset(), here_.addr_);
00487         NixNode* pNixNode = NixNode::GetNodeObject(here_.addr_);
00488         if (0)
00489                 printf("Node Object %p\n", pNixNode);
00490         if (pNixNode) { 
00491                 // If we get non-null, indicates nixvector routing in use
00492                 // Delete any left over nv in the packet
00493                 // Get a nixvector to the target (may create new)
00494                 NixVec* pNv = pNixNode->GetNixVector(dst_.addr_);
00495                 pNv->Reset();
00496                 nv->nv() = pNv; // And set the nixvec in the packet
00497                 nv->h_used = 0; // And reset used portion to 0
00498         }
00499 #endif //HAVE_STL
00500 }
00501 
00502 /*
00503  * allocate a packet and fill in all the generic fields
00504  */
00505 Packet*
00506 Agent::allocpkt() const
00507 {
00508         Packet* p = Packet::alloc();
00509         initpkt(p);
00510         return (p);
00511 }
00512 
00513 /* allocate a packet and fill in all the generic fields and allocate
00514  * a buffer of n bytes for data
00515  */
00516 Packet*
00517 Agent::allocpkt(int n) const
00518 {
00519         Packet* p = allocpkt();
00520 
00521         if (n > 0)
00522                 p->allocdata(n);
00523 
00524         return(p);
00525 }

Generated on Tue Apr 20 12:14:10 2004 for NS2.26SourcesOriginal by doxygen 1.3.3