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

tora.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) 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  * Ported from CMU/Monarch's code
00035  *
00036  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tora/tora.cc,v 1.14 2002/03/18 17:32:36 haldar Exp $
00037  */
00038 
00039 #include <agent.h>
00040 #include <random.h>
00041 #include <trace.h>
00042 
00043 #include <ll.h>
00044 #include <priqueue.h>
00045 #include <tora/tora_packet.h>
00046 #include <tora/tora.h>
00047 
00048 #define LOG(s)                                                  \
00049         fprintf(stdout, "%s --- %s (index: %d, time: %f)\n",    \
00050                 __PRETTY_FUNCTION__, (s), index, Scheduler::instance().clock())
00051 
00052 // #define DEBUG
00053 #define CURRENT_TIME    Scheduler::instance().clock()
00054 
00055 /* sec of spacing inserted between pkts when a bunch of packets are
00056    dumped into the link layer all at once.  Allows arp time to resolve
00057    dst, preventing the dumping of all but the last pkt on the floor */
00058 #define ARP_SEPARATION_DELAY 0.030
00059           
00060 
00061 /* ======================================================================
00062    TCL Hooks
00063    ====================================================================== */
00064 int hdr_tora::offset_;
00065 static class TORAHeaderClass : public PacketHeaderClass {
00066 public:
00067         TORAHeaderClass() : PacketHeaderClass("PacketHeader/TORA",
00068                                               TORA_HDR_LEN) { 
00069                 bind_offset(&hdr_tora::offset_);
00070         } 
00071 } class_toraAgent_hdr;
00072 
00073 static class toraAgentclass : public TclClass {
00074 public:
00075         toraAgentclass() : TclClass("Agent/TORA") {}
00076         TclObject* create(int argc, const char*const* argv) {
00077                 assert(argc == 5);
00078                 return (new toraAgent((nsaddr_t) atoi(argv[4])));
00079         }
00080 } class_toraAgent;
00081 
00082 
00083 /* ======================================================================
00084    toraAgent Class Functions
00085    ====================================================================== */
00086 toraAgent::toraAgent(nsaddr_t id) :
00087         rtAgent(id, PT_TORA),
00088         rqueue()
00089 {
00090         LIST_INIT(&dstlist);
00091         imepagent = 0;
00092         logtarget = 0;
00093         ifqueue = 0;
00094 }
00095 
00096 void
00097 toraAgent::reset()
00098 {
00099         Packet *p;
00100         while((p = rqueue.deque())) {
00101                 drop(p,DROP_END_OF_SIMULATION);
00102         }
00103 }
00104 
00105 int
00106 toraAgent::command(int argc, const char*const* argv)
00107 {
00108         if(argc == 2) {
00109                 Tcl& tcl = Tcl::instance();
00110 
00111                 if(strncasecmp(argv[1], "id", 2) == 0) {
00112                         tcl.resultf("%d", index);
00113                         return TCL_OK;
00114                 }
00115         }
00116         else if(argc == 3) {
00117 
00118                 if(strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0 ) {
00119                         logtarget = (Trace*) TclObject::lookup(argv[2]);
00120                         if(logtarget == 0)
00121                                 return TCL_ERROR;
00122                         return TCL_OK;
00123                 }
00124                 else if(strcmp(argv[1], "drop-target") == 0) {
00125                         int stat = rqueue.command(argc,argv);
00126                         if (stat != TCL_OK) return stat;
00127                         return Agent::command(argc, argv);
00128                 }
00129                 else if(strcmp(argv[1], "if-queue") == 0) {
00130                         ifqueue = (PriQueue*) TclObject::lookup(argv[2]);
00131                         if(ifqueue == 0)
00132                                 return TCL_ERROR;
00133                         return TCL_OK;
00134                 }
00135                 else if(strcmp(argv[1], "imep-agent") == 0) {
00136                         imepagent = (imepAgent*) TclObject::lookup(argv[2]);
00137                         if(imepagent == 0)
00138                                 return TCL_ERROR;
00139                         imepagent->imepRegister((rtAgent*) this);
00140                         return TCL_OK;
00141                 }
00142         }
00143         return Agent::command(argc, argv);
00144 }
00145 
00146 
00147 /* ======================================================================
00148    Destination Management Functions
00149    ====================================================================== */
00150 TORADest*
00151 toraAgent::dst_find(nsaddr_t id)
00152 {
00153         TORADest* td = dstlist.lh_first;
00154         for( ; td; td = td->link.le_next) {
00155                 if(td->index == id)
00156                         return td;
00157         }
00158         return 0;
00159 }
00160 
00161 TORADest*
00162 toraAgent::dst_add(nsaddr_t id)
00163 {
00164         TORADest *td = new TORADest(id, this);
00165         assert(td);
00166 
00167         LIST_INSERT_HEAD(&dstlist, td, link);
00168 
00169         int *nblist = 0, nbcnt = 0;
00170         imepagent->imepGetBiLinks(nblist, nbcnt);
00171 
00172         for(int i = 0; i < nbcnt; i++)
00173                 (void) td->nb_add(nblist[i]);
00174 
00175         if(nblist) delete[] nblist;
00176 
00177         return td;
00178 }
00179 
00180 void
00181 toraAgent::dst_dump()
00182 {
00183         TORADest *td = dstlist.lh_first;
00184 
00185         for( ; td; td = td = td->link.le_next)
00186                 td->dump();
00187 }
00188 
00189 
00190 /* ======================================================================
00191    Route Resolution
00192    ====================================================================== */
00193 void
00194 toraAgent::forward(Packet *p, nsaddr_t nexthop, Time delay)
00195 {
00196         struct hdr_cmn *ch = HDR_CMN(p);
00197 
00198 #ifdef TORA_DISALLOW_ROUTE_LOOP
00199         if(nexthop == ch->prev_hop_) {
00200                 log_route_loop(ch->prev_hop_, nexthop);
00201                 drop(p, DROP_RTR_ROUTE_LOOP);
00202                 return;
00203         }
00204 #endif
00205         ch->next_hop() = nexthop;
00206         ch->prev_hop_ = ipaddr();
00207         ch->addr_type() = NS_AF_INET;
00208 
00209         // change the packet direction to DOWN
00210         ch->direction() = hdr_cmn::DOWN;
00211 
00212         if (0.0 == delay) {
00213           tora_output(p);
00214         } else {
00215           Scheduler::instance().schedule(target_, p, delay);
00216         }
00217 }
00218 
00219 
00220 void
00221 toraAgent::rt_resolve(Packet *p)
00222 {
00223         struct hdr_ip *ih = HDR_IP(p);
00224         TORADest *td;
00225         TORANeighbor *tn;
00226 
00227         td = dst_find(ih->daddr());
00228         if(td == 0) {
00229                 td = dst_add(ih->daddr());
00230         }
00231 
00232         tn = td->nb_find_next_hop();
00233         if(tn == 0) {
00234                 rqueue.enque(p);
00235 
00236                 trace("T %.9f _%d_ tora enq %d->%d",
00237                       Scheduler::instance().clock(), ipaddr(), 
00238                       ih->saddr(), ih->daddr());
00239 
00240                 if(!td->rt_req)
00241                   { // if no QRY pending, then send one
00242                     sendQRY(ih->daddr());
00243                     td->time_tx_qry = CURRENT_TIME;
00244                     td->rt_req = 1;
00245                   }
00246         }
00247         else {
00248                 forward(p, tn->index);
00249         }
00250 }
00251 
00252 
00253 /* ======================================================================
00254    Incoming Packets
00255    ====================================================================== */
00256 void
00257 toraAgent::recv(Packet *p, Handler *)
00258 {
00259         struct hdr_cmn *ch = HDR_CMN(p);
00260         struct hdr_ip *ih = HDR_IP(p);
00261 
00262         assert(initialized());
00263 
00264         if(ch->ptype() == PT_TORA) {
00265                 recvTORA(p);
00266                 return;
00267         }
00268 
00269         /*
00270          *  Must be a packet I'm originating...
00271          */
00272         if(ih->saddr() == ipaddr() && ch->num_forwards() == 0) {
00273                 /*
00274                  *  Add the IP Header.
00275                  */
00276                 ch->size() += IP_HDR_LEN;
00277                 
00278                 ih->ttl_ = IP_DEF_TTL;
00279         }
00280 
00281 #ifdef TORA_DISALLOW_ROUTE_LOOP
00282         /*
00283          *  I received a packet that I sent.  Probably
00284          *  a routing loop.
00285          */
00286         else if(ih->saddr() == ipaddr()) {
00287                 drop(p, DROP_RTR_ROUTE_LOOP);
00288                 return;
00289         }
00290 #endif
00291         /*
00292          *  Packet I'm forwarding...
00293          */
00294         else {
00295                 /*
00296                  *  Check the TTL.  If it is zero, then discard.
00297                  */
00298                 if(--ih->ttl_ == 0) {
00299                         drop(p, DROP_RTR_TTL);
00300                         return;
00301                 }
00302         }
00303 
00304         rt_resolve(p);
00305 }
00306 
00307 void
00308 toraAgent::recvTORA(Packet *p)
00309 {
00310         struct hdr_ip *ih = HDR_IP(p);
00311         struct hdr_tora *th = HDR_TORA(p);
00312         TORADest *td;
00313         TORANeighbor *tn;
00314 
00315         /*
00316          * Fix the source IP address.
00317          */
00318         assert(ih->sport() == RT_PORT);
00319         assert(ih->dport() == RT_PORT);
00320 
00321         /*
00322          * Incoming Packets.
00323          */
00324         switch(th->th_type) {
00325                 case TORATYPE_QRY:
00326                         recvQRY(p);
00327                         Packet::free(p);
00328                         return;         // don't add/change routing state
00329 
00330                 case TORATYPE_UPD:
00331                         log_recv_upd(p);
00332                         recvUPD(p);
00333                         break;
00334 
00335                 case TORATYPE_CLR:
00336                         log_recv_clr(p);
00337                         recvCLR(p);
00338                         break;
00339 
00340                 default:
00341                         fprintf(stderr,
00342                                 "%s: Invalid TORA type (%x)\n",
00343                                 __PRETTY_FUNCTION__, th->th_type);
00344                         exit(1);
00345         }
00346 
00347         if((td = dst_find(th->th_dst)) == 0) {
00348                 Packet::free(p);
00349                 return;
00350         }
00351 
00352         logNextHopChange(td);
00353 
00354         if((tn = td->nb_find_next_hop())) {
00355                 Packet *p0;
00356                 Time delay = 0.0;
00357 
00358                 while((p0 = rqueue.deque(td->index))) {
00359                         forward(p0, tn->index, delay);
00360                         delay += ARP_SEPARATION_DELAY;
00361                 }
00362         }
00363         Packet::free(p);
00364 }
00365 
00366 
00367 
00368 /*
00369  *  IETF Draft - TORA Specification, section 3.7.6
00370  */
00371 void
00372 toraAgent::recvQRY(Packet *p)
00373 {
00374         struct hdr_ip *ih = HDR_IP(p);
00375         struct hdr_tora_qry *qh = HDR_TORA_QRY(p);
00376         TORADest *td;
00377         TORANeighbor *tn;
00378 
00379         if(qh->tq_dst == ipaddr()) {
00380 #ifdef DEBUG
00381                 fprintf(stderr, "node %d received `QRY` for itself.\n", index);
00382 #endif
00383                 return;
00384         }
00385 
00386         td = dst_find(qh->tq_dst);
00387         if(td == 0)
00388                 td = dst_add(qh->tq_dst);
00389 
00390         if(td->rt_req) {
00391                 return;
00392         }
00393 
00394         if(td->height.r == 0) {                                 // II, A
00395                 tn = td->nb_find(ih->saddr());
00396 
00397                 if(tn && tn->time_act > td->time_upd) {         // II, A, 1
00398                         td->time_upd = Scheduler::instance().clock();
00399                         sendUPD(td->index);
00400                 }
00401                 else {                                          // II, A, 2
00402                 }
00403         }
00404         else {
00405                 tn = td->nb_find_min_height(0);
00406 
00407                 if(tn) {                                        // II, B, 1
00408                         td->update_height(tn->height.tau,
00409                                           tn->height.oid,
00410                                           tn->height.r,
00411                                           tn->height.delta + 1,
00412                                           ipaddr());
00413 
00414                         td->time_upd = Scheduler::instance().clock();
00415 
00416                         sendUPD(td->index);
00417                 }
00418                 else {
00419                         td->rt_req = 1;
00420                         td->time_rt_req = CURRENT_TIME;
00421 
00422                         if(td->num_active > 1) {                // II, B, 1, a
00423                                 sendQRY(td->index);
00424                         }
00425                         else {                                  // II, B, 1, b
00426 
00427                         }
00428                 }
00429         }
00430 }
00431 
00432 
00433 /*
00434  *  IETF Draft - TORA Specification, section 3.7.7
00435  */
00436 void
00437 toraAgent::recvUPD(Packet *p)
00438 {
00439         struct hdr_ip *ih = HDR_IP(p);
00440         struct hdr_tora_upd *uh = HDR_TORA_UPD(p);
00441         TORADest *td;
00442         TORANeighbor *tn;
00443 
00444         if(uh->tu_dst == ipaddr()) {
00445                 return;
00446         }
00447 
00448         td = dst_find(uh->tu_dst);
00449         if(td == 0)
00450                 td = dst_add(uh->tu_dst);
00451 
00452         tn = td->nb_find(ih->saddr());
00453         if(tn == 0) {
00454                 /*
00455                  * update link status? -josh
00456                  */
00457 
00458                  // No, don't update linkstatus: it may be an update
00459                  // that was delayed in the IMEP layer for sequencing -dam
00460                  // no way at the TORA level to tell if we're connected...
00461                  trace("T %.9f _%d_ received `UPD` from non-neighbor %d",
00462                        CURRENT_TIME, ipaddr(), ih->saddr());             
00463 #ifdef DEBUG
00464                 fprintf(stderr,
00465                         "node %d received `UPD` from non-neighbor %d\n",
00466                         index, ih->src_);
00467 #endif
00468                 return;
00469         }
00470 
00471         /*
00472          *  Update height and link status for neighbor [j][k].
00473          */
00474         td->update_height_nb(tn, uh);
00475 
00476         if(td->rt_req && tn->height.r == 0) {                                                           // I
00477 
00478                 td->update_height(tn->height.tau,
00479                                   tn->height.oid,
00480                                   tn->height.r,
00481                                   tn->height.delta + 1,
00482                                   ipaddr());
00483 
00484                 td->rt_req = 0;
00485 
00486                 td->time_upd = Scheduler::instance().clock();
00487 
00488                 sendUPD(td->index);
00489         }
00490         else if(td->num_down == 0) {                                                                    // II
00491                 if(td->num_up == 0) {                                                                   // II, A
00492                         if(td->height.isNull())                                                         // II, A, 1
00493                                 return;                                                                 // II, A, 1, a
00494                         else {
00495                                 td->height.Null();                                                      // II, A, 1, b 
00496 
00497                                 td->time_upd = Scheduler::instance().clock();
00498 
00499                                 sendUPD(td->index);
00500                         }
00501                 }
00502                 else {
00503                         if(td->nb_check_same_ref()) {                                                   // II, A, 2
00504                                 TORANeighbor *tn;
00505 
00506                                 if( (tn = td->nb_find_min_height(0)) ) {                        // II, A, 2, a
00507                                         td->update_height(tn->height.tau,                               // II, A, 2, a, i 
00508                                                           tn->height.oid,
00509                                                           1,
00510                                                           0,
00511                                                           ipaddr());
00512                                         td->time_upd = Scheduler::instance().clock();
00513 
00514                                         sendUPD(td->index);
00515                                 }
00516                                 else {
00517                                         if(td->height.oid == ipaddr()) {                                        // II, A, 2, a, ii
00518                                                 double temp_tau = td->height.tau;                       // II, A, 2, a, ii, x 
00519                                                 nsaddr_t temp_oid = td->height.oid;
00520 
00521                                                 td->height.Null();
00522                                                 td->num_down = 0;
00523                                                 td->num_up = 0;
00524 
00525                                                 /*
00526                                                  *  For every active link n, if the neighbor connected
00527                                                  *  via link n is the destination j, set HT_NEIGH[j][n]=ZERO
00528                                                  *  and LNK_STAT[j][n] = DN.
00529                                                  *  Otherwise, set HT_NEIGH[j][n] = NULL and LNK_STAT[j][n] = UN.
00530                                                  */
00531                                                 for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00532                                                         if(tn->index == td->index) {
00533                                                                 tn->height.Zero();
00534                                                                 tn->lnk_stat = LINK_DN;
00535 
00536                                                         }
00537                                                         else {
00538                                                                 tn->height.Null();
00539                                                                 tn->lnk_stat = LINK_UN;
00540                                                         }
00541                                                 }
00542 
00543                                                 sendCLR(td->index, temp_tau, temp_oid);
00544                                         }
00545                                         else {
00546                                                 td->update_height(Scheduler::instance().clock(),        // II, A, 2, a, ii, y
00547                                                                   ipaddr(),
00548                                                                   0,
00549                                                                   0,
00550                                                                   ipaddr());
00551                                                 td->rt_req = 0;
00552                                                 td->time_upd = Scheduler::instance().clock();
00553 
00554 #ifdef DEBUG
00555                                                 // under what circumstances does this rule fire?
00556                                                 // seems like it will prevent the detection of 
00557                                                 // partitions...??? -dam 8/24/98
00558 
00559                                                 if (logtarget) 
00560                                                   {
00561                                                     sprintf(logtarget->pt_->buffer(), "T %.9f _%d_ rule IIA2a(ii)x fires %d",
00562                                                             Scheduler::instance().clock(), ipaddr(), td->index);
00563                                                     logtarget->pt_->dump();
00564                                                   }
00565 #endif
00566                                                 sendUPD(td->index);
00567                                         }
00568                                 }
00569 
00570                         }
00571                         else {
00572                                 TORANeighbor *n = td->nb_find_max_height();                             // II, A, 2, b
00573                                 assert(n);
00574                                 TORANeighbor *m = td->nb_find_min_nonnull_height(&n->height);
00575                                 assert(m);
00576 
00577                                 td->update_height(m->height.tau,
00578                                                   m->height.oid,
00579                                                   m->height.r,
00580                                                   m->height.delta - 1,
00581                                                   ipaddr());
00582 
00583                                 td->time_upd = Scheduler::instance().clock();
00584 
00585                                 sendUPD(td->index);
00586                         }
00587                 }
00588         }
00589         else {                                                                                          // II, B
00590 
00591         }
00592 }
00593 
00594 
00595 /*
00596  *  IETF Draft - TORA Specification, section 3.7.8
00597  */
00598 void
00599 toraAgent::recvCLR(Packet *p)
00600 {
00601         struct hdr_ip *ih = HDR_IP(p);
00602         struct hdr_tora_clr *th = HDR_TORA_CLR(p);
00603         TORADest *td;
00604         TORANeighbor *tn;
00605 
00606         if(th->tc_dst == ipaddr()) {
00607                 return;
00608         }
00609 
00610         td = dst_find(th->tc_dst);
00611         if(td == 0)
00612                 td = dst_add(th->tc_dst);
00613         assert(td);
00614 
00615         if(td->height.tau == th->tc_tau &&
00616            td->height.oid == th->tc_oid &&
00617            td->height.r == 1) {                                 // I
00618                 double temp_tau = td->height.tau;
00619                 nsaddr_t temp_oid = td->height.oid;
00620 
00621                 td->height.Null();
00622                 td->num_up = 0;
00623                 td->num_down = 0;
00624 
00625                 for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00626                         if(tn->index == td->index) {
00627                                 tn->height.Zero();
00628                                 tn->lnk_stat = LINK_DN;
00629                         }
00630                         else {
00631                                 tn->height.Null();
00632                                 tn->lnk_stat = LINK_UN;
00633                         }
00634                 }
00635                 if(td->num_active > 1) {                        // I, A
00636                         sendCLR(td->index, temp_tau, temp_oid);
00637                 }
00638                 else {                                          // I, B
00639                 }
00640         }
00641         else {
00642                 tn = td->nb_find(ih->saddr());                  // II
00643                 if(tn == 0) {
00644                         /*
00645                          *  XXX - update link status?
00646                          */
00647                         trace("T %.9f _%d_ received `CLR` from non-neighbor %d",
00648                                CURRENT_TIME, index, ih->saddr());               
00649 #ifdef DEBUG
00650                         fprintf(stderr,
00651                                 "node %d received `CLR` from non-neighbor %d\n",
00652                                 index, ih->src_);
00653 #endif
00654                         return;
00655                 }
00656 
00657                 tn->height.Null();
00658                 tn->lnk_stat = LINK_UN;
00659 
00660                 for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00661                         if(tn->height.tau == th->tc_tau &&
00662                            tn->height.oid == th->tc_oid &&
00663                            tn->height.r == 1) {
00664                                 tn->height.Null();
00665                                 tn->lnk_stat = LINK_UN;
00666                         }
00667                 }
00668                 if(td->num_down == 0) {                         // II, A
00669                         if(td->num_up == 0) {                   // II, A, 1
00670                                 if(td->height.isNull()) {       // II, A, 1, a
00671                                 }
00672                                 else {
00673                                         td->height.Null();
00674                                         td->time_upd = Scheduler::instance().clock();
00675                                         sendUPD(td->index);
00676                                 }
00677                         }
00678                         else {
00679                                 td->update_height(Scheduler::instance().clock(),
00680                                                   ipaddr(),
00681                                                   0,
00682                                                   0,
00683                                                   ipaddr());
00684                                 td->rt_req = 0;
00685                                 td->time_upd = Scheduler::instance().clock();
00686                                 sendUPD(td->index);
00687                         }
00688                 }
00689                 else {
00690                                                                 // II, B
00691                 }
00692         }
00693 }
00694 
00695 void
00696 toraAgent::trace(char* fmt, ...)
00697 {
00698   va_list ap;
00699   
00700   if (!logtarget) return;
00701 
00702   va_start(ap, fmt);
00703   vsprintf(logtarget->pt_->buffer(), fmt, ap);
00704   logtarget->pt_->dump();
00705   va_end(ap);
00706 }
00707 
00708 

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