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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  * This product includes software developed by the Daedalus Research
  17.  * Group at the University of California Berkeley.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  * Contributed by the Daedalus Research Group, UC Berkeley 
  35.  * (http://daedalus.cs.berkeley.edu)
  36.  *
  37.  * Multi-state error model patches contributed by Jianping Pan 
  38.  * (jpan@bbcr.uwaterloo.ca).
  39.  *
  40.  * @(#) $Header: /cvsroot/nsnam/ns-2/queue/errmodel.cc,v 1.83 2006/03/01 19:28:04 padmah Exp $ (UCB)
  41.  */
  42. #ifndef lint
  43. static const char rcsid[] =
  44.     "@(#) $Header: /cvsroot/nsnam/ns-2/queue/errmodel.cc,v 1.83 2006/03/01 19:28:04 padmah Exp $ (UCB)";
  45. #endif
  46. #include "config.h"
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include "packet.h"
  50. #include "flags.h"
  51. #include "mcast_ctrl.h"
  52. #include "errmodel.h"
  53. #include "srm-headers.h" // to get the hdr_srm structure
  54. #include "classifier.h"
  55. static class ErrorModelClass : public TclClass {
  56. public:
  57. ErrorModelClass() : TclClass("ErrorModel") {}
  58. TclObject* create(int, const char*const*) {
  59. return (new ErrorModel);
  60. }
  61. } class_errormodel;
  62. static class TwoStateErrorModelClass : public TclClass {
  63. public:
  64. TwoStateErrorModelClass() : TclClass("ErrorModel/TwoState") {}
  65. TclObject* create(int, const char*const*) {
  66. return (new TwoStateErrorModel);
  67. }
  68. } class_errormodel_twostate;
  69. static class ComplexTwoStateMarkovModelClass : public TclClass {
  70. public:
  71.   ComplexTwoStateMarkovModelClass() : TclClass("ErrorModel/ComplexTwoStateMarkov") {}
  72.   TclObject* create(int, const char*const*) {
  73.   return (new ComplexTwoStateErrorModel);
  74.   }
  75. } class_errormodel_complextwostatemarkov;
  76. static class MultiStateErrorModelClass : public TclClass {
  77. public:
  78. MultiStateErrorModelClass() : TclClass("ErrorModel/MultiState") {}
  79. TclObject* create(int, const char*const*) {
  80. return (new MultiStateErrorModel);
  81. }
  82. } class_errormodel_multistate;
  83. static class TraceErrorModelClass : public TclClass {
  84. public:
  85. TraceErrorModelClass() : TclClass("ErrorModel/Trace") {}
  86. TclObject* create(int, const char*const*) {
  87. return (new TraceErrorModel);
  88. }
  89. } class_traceerrormodel;
  90. static char* eu_names[] = { EU_NAMES };
  91. inline double comb(int n, int k) {
  92. int i;
  93. double sum = 1.0;
  94. for(i = 0; i < k; i++) 
  95. sum *= (n - i)/(i + 1);
  96. return sum;
  97. }
  98. ErrorModel::ErrorModel() : et_(0), firstTime_(1), unit_(EU_PKT), ranvar_(0), FECstrength_(1)
  99. {
  100. bind("enable_", &enable_);
  101. bind("rate_", &rate_);
  102. bind("delay_", &delay_);
  103. bind_bw("bandwidth_", &bandwidth_); // required for EU_TIME
  104. bind_bool("markecn_", &markecn_);
  105. bind_bool("delay_pkt_", &delay_pkt_);
  106. }
  107. int ErrorModel::command(int argc, const char*const* argv)
  108. {
  109. Tcl& tcl = Tcl::instance();
  110. //ErrorModel *em;
  111. if (argc == 3) {
  112. if (strcmp(argv[1], "unit") == 0) {
  113. unit_ = STR2EU(argv[2]);
  114. return (TCL_OK);
  115. if (strcmp(argv[1], "ranvar") == 0) {
  116. ranvar_ = (RandomVariable*) TclObject::lookup(argv[2]);
  117. return (TCL_OK);
  118. }
  119. if (strcmp(argv[1], "FECstrength") == 0) {
  120. FECstrength_ = atoi(argv[2]);
  121. return (TCL_OK);
  122. }
  123. if (strcmp(argv[1], "datapktsize") == 0) {
  124. datapktsize_ = atoi(argv[2]);
  125. return (TCL_OK);
  126. }
  127. if (strcmp(argv[1], "cntrlpktsize") == 0) {
  128. cntrlpktsize_ = atoi(argv[2]);
  129. return (TCL_OK);
  130. }
  131. if (strcmp(argv[1], "eventtrace") == 0) {
  132. et_ = (EventTrace *)TclObject::lookup(argv[2]);
  133. return (TCL_OK);
  134. }
  135. } else if (argc == 2) {
  136. if (strcmp(argv[1], "unit") == 0) {
  137. tcl.resultf("%s", eu_names[unit_]);
  138. return (TCL_OK);
  139. }
  140. if (strcmp(argv[1], "ranvar") == 0) {
  141. tcl.resultf("%s", ranvar_->name());
  142. return (TCL_OK);
  143. if (strcmp(argv[1], "FECstrength") == 0) {
  144. tcl.resultf("%d", FECstrength_);
  145. return (TCL_OK);
  146. return Connector::command(argc, argv);
  147. }
  148. void ErrorModel::reset()
  149. {
  150. firstTime_ = 1;
  151. }
  152. void ErrorModel::recv(Packet* p, Handler* h)
  153. {
  154. // 1.  Determine the error by calling corrupt(p)
  155. // 2.  Set the packet's error flag if it is corrupted
  156. // 3.  If there is no error,  no drop_ target or markecn is true,
  157. // let pkt continue, otherwise hand the corrupted packet to drop_
  158. hdr_cmn* ch = hdr_cmn::access(p);
  159. int error = corrupt(p);
  160. // XXX When we do ECN, the packet is marked but NOT dropped.
  161. // So we don't resume handler here. 
  162. if (!markecn_ && !delay_pkt_ && (h && ((error && drop_) || !target_))) {
  163. // if we drop or there is no target_, then resume handler
  164. double delay = Random::uniform(8.0 * ch->size() / bandwidth_);
  165. if (intr_.uid_ <= 0 ) 
  166. // schedule only if nothing scheduled already
  167. Scheduler::instance().schedule(h, &intr_, delay);
  168. if (error) {
  169. ch->error() |= error;
  170. if (markecn_) {
  171. hdr_flags* hf = hdr_flags::access(p);
  172. hf->ce() = 1;
  173. } else if (delay_pkt_) {
  174. // Delay the packet.
  175. Scheduler::instance().schedule(target_, p, delay_);
  176. return;
  177. } else if (drop_) {
  178. drop_->recv(p);
  179. return;
  180. }
  181. }
  182. if (target_) {
  183.         target_->recv(p, h);
  184. }
  185. }
  186. int ErrorModel::corrupt(Packet* p)
  187. {
  188. hdr_cmn* ch;
  189. // a temp hack
  190. ch = HDR_CMN(p);
  191. if (enable_ == 0)
  192. return 0;
  193. switch (unit_) {
  194. case EU_TIME:
  195. return (CorruptTime(p) != 0);
  196. case EU_BYTE:
  197. return (CorruptByte(p) != 0);
  198. case EU_BIT:
  199. ch = hdr_cmn::access(p);
  200. ch->errbitcnt() = CorruptBit(p);
  201. return (ch->errbitcnt() != 0);
  202. default:
  203. return (CorruptPkt(p) != 0);
  204. }
  205. return 0;
  206. }
  207. double ErrorModel::PktLength(Packet* p)
  208. {
  209. //double now;
  210. if (unit_ == EU_PKT)
  211. return 1;
  212. int byte = hdr_cmn::access(p)->size();
  213. if (unit_ == EU_BYTE)
  214. return byte;
  215. if (unit_ == EU_BIT)
  216. return 8.0 * byte;
  217. return 8.0 * byte / bandwidth_;
  218. }
  219. double * ErrorModel::ComputeBitErrProb(int size) 
  220. {
  221. double *dptr;
  222. int i;
  223.         dptr = (double *)calloc((FECstrength_ + 2), sizeof(double));
  224.         for (i = 0; i < (FECstrength_ + 1) ; i++) 
  225. dptr[i] = comb(size, i) * pow(rate_, (double)i) * pow(1.0 - rate_, (double)(size - i));
  226. // Cumulative probability
  227. for (i = 0; i < FECstrength_ ; i++) 
  228. dptr[i + 1] += dptr[i];
  229. dptr[FECstrength_ + 1] = 1.0;
  230. /* printf("Size = %dn", size);
  231. for (i = 0; i <(FECstrength_ + 2); i++)
  232. printf("Ptr[%d] = %gn", i, dptr[i]); */
  233. return dptr;
  234. }
  235. int ErrorModel::CorruptPkt(Packet*) 
  236. {
  237. // if no random var is specified, assume uniform random variable
  238. double u = ranvar_ ? ranvar_->value() : Random::uniform();
  239. return (u < rate_);
  240. }
  241. int ErrorModel::CorruptByte(Packet* p)
  242. {
  243. // compute pkt error rate, assume uniformly distributed byte error
  244. double per = 1 - pow(1.0 - rate_, PktLength(p));
  245. double u = ranvar_ ? ranvar_->value() : Random::uniform();
  246. return (u < per);
  247. }
  248. int ErrorModel::CorruptBit(Packet* p)
  249. {
  250. double u, *dptr;
  251. int i;
  252. if (firstTime_ && FECstrength_) {
  253. // precompute the probabilies for each bit-error cnts
  254. cntrlprb_ = ComputeBitErrProb(cntrlpktsize_);
  255. dataprb_ = ComputeBitErrProb(datapktsize_);
  256. firstTime_ = 0;
  257. }
  258. u = ranvar_ ? ranvar_->value() : Random::uniform();
  259. dptr = (hdr_cmn::access(p)->size() >= datapktsize_) ? dataprb_ : cntrlprb_;
  260.         for (i = 0; i < (FECstrength_ + 2); i++)
  261. if (dptr[i] > u) break;
  262. return(i);
  263. }
  264. int ErrorModel::CorruptTime(Packet *)
  265. {
  266. fprintf(stderr, "Warning:  uniform rate error cannot be time-basedn");
  267. return 0;
  268. }
  269. #if 0
  270. /*
  271.  * Decide whether or not to corrupt this packet, for a continuous 
  272.  * time-based error model.  The main parameter used is errLength,
  273.  * which is the time to the next error, from the last time an error 
  274.  * occured on  the channel.  It is dependent on the random variable 
  275.  * being used  internally.
  276.  * rate_ is the user-specified mean
  277.  */
  278. int ErrorModel::CorruptTime(Packet *p)
  279. {
  280. /* 
  281.  * First get MAC header.  It has the transmission time (txtime)
  282.  * of the packet in one of it's fields.  Then, get the time
  283.  * interval [t-txtime, t], where t is the current time.  The
  284.  * goal is to figure out whether the channel would have
  285.  * corrupted the packet during that interval. 
  286.  */
  287. Scheduler &s = Scheduler::instance();
  288. double now = s.clock(), rv;
  289. int numerrs = 0;
  290. double start = now - hdr_mac::access(p)->txtime();
  291. while (remainLen_ < start) {
  292. rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
  293. remainLen_ += rv;
  294. }
  295. while (remainLen_ < now) { /* corrupt the packet */
  296. numerrs++;
  297. rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
  298. remainLen_ += rv;
  299. }
  300. return numerrs;
  301. }
  302. #endif
  303. void ErrorModel::trace_event(char *eventtype)
  304. {
  305. if (et_ == NULL) return;
  306. char *wrk = et_->buffer();
  307. char *nwrk = et_->nbuffer();
  308. if (wrk != 0)
  309. sprintf(wrk,
  310. "E "TIME_FORMAT" ErrModelTimer %p %s",
  311. et_->round(Scheduler::instance().clock()),   // time
  312. this,
  313. eventtype                    // event type
  314. );
  315. if (nwrk != 0)
  316. sprintf(nwrk,
  317. "E -t "TIME_FORMAT" ErrModelTimer %p %s",
  318. et_->round(Scheduler::instance().clock()),   // time
  319. this,
  320. eventtype                    // event type
  321. );
  322. et_->trace();
  323. }
  324. /*
  325.  * Two-State:  error-free and error
  326.  */
  327. TwoStateErrorModel::TwoStateErrorModel() : remainLen_(0), twoStateTimer_(NULL)
  328. {
  329. ranvar_[0] = ranvar_[1] = 0;
  330. }
  331. int TwoStateErrorModel::command(int argc, const char*const* argv)
  332. {
  333. Tcl& tcl = Tcl::instance();
  334. if (strcmp(argv[1], "ranvar") == 0) {
  335. int i = atoi(argv[2]);
  336. if (i < 0 || i > 1) {
  337. tcl.resultf("%s does not has ranvar_[%d]", name_, i);
  338. return (TCL_ERROR);
  339. }
  340. if (argc == 3) {
  341. tcl.resultf("%s", ranvar_[i]->name());
  342. return (TCL_OK);
  343. }
  344. if (argc == 4) {
  345. ranvar_[i] = (RandomVariable*)TclObject::lookup(argv[3]);
  346. if (ranvar_[0] != 0 && ranvar_[1] != 0)
  347. checkUnit();
  348. return (TCL_OK);
  349. }
  350. return ErrorModel::command(argc, argv);
  351. }
  352. int TwoStateErrorModel::corruptPkt(Packet* p)
  353. {
  354. #define ZERO 0.00000
  355. int error;
  356. if (firstTime_) {
  357. firstTime_ = 0;
  358. state_ = 0;
  359. remainLen_ = ranvar_[state_]->value();
  360. }
  361. // if remainLen_ is outside the range of 0, then error = state_
  362. error = state_ && (remainLen_ > ZERO);
  363. remainLen_ -= PktLength(p);
  364. // state transition until remainLen_ > 0 to covers the packet length
  365. while (remainLen_ <= ZERO) {
  366. state_ ^= 1; // state transition: 0 <-> 1
  367. remainLen_ += ranvar_[state_]->value();
  368. error |= state_;
  369. }
  370. return error;
  371. }
  372. void TwoStateErrorModel::checkUnit() 
  373. {
  374. if (unit_ == EU_TIME) {
  375. // setup timer for keeping states in time
  376. twoStateTimer_ = new TwoStateErrModelTimer(this, &TwoStateErrorModel::transitionState);
  377. transitionState();
  378. }
  379. }
  380. void TwoStateErrorModel::transitionState()
  381. {
  382. char buf[SMALL_LEN];
  383. if (firstTime_) {
  384. firstTime_ = 0;
  385. state_ = 0;
  386. remainLen_ = ranvar_[state_]->value();
  387. twoStateTimer_->sched(remainLen_);
  388. sprintf (buf,"STATE %d, DURATION %f",state_,remainLen_);
  389. trace_event(buf);
  390. return;
  391. }
  392. state_ ^= 1;
  393. remainLen_ = ranvar_[state_]->value();
  394. if (state_ == 1 && remainLen_ > 120)
  395. remainLen_ = 120;
  396. twoStateTimer_->resched(remainLen_);
  397. sprintf (buf,"STATE %d, DURATION %f",state_,remainLen_);
  398. trace_event(buf);
  399. }
  400. int TwoStateErrorModel::corrupt(Packet* p)
  401. {
  402. if (unit_ == EU_TIME)
  403. return corruptTime(p);
  404. else
  405. return corruptPkt(p);
  406. }
  407. int TwoStateErrorModel::corruptTime(Packet* p)
  408. {
  409. int error = 0;
  410. if (state_ == 1)
  411. error = 1;
  412. return error;
  413. }
  414. ComplexTwoStateErrorModel::ComplexTwoStateErrorModel() 
  415. {
  416. em_[0] = new TwoStateErrorModel();
  417. em_[1] = new TwoStateErrorModel();
  418. }
  419. ComplexTwoStateErrorModel::~ComplexTwoStateErrorModel()
  420. {
  421. delete em_[0];
  422. delete em_[1];
  423. }
  424. int ComplexTwoStateErrorModel::command(int argc, const char*const* argv)
  425. {
  426. Tcl& tcl = Tcl::instance();
  427. if (argc == 3) {
  428. if (strcmp(argv[1], "unit") == 0) {
  429. unit_ = STR2EU(argv[2]);
  430. em_[0]->setunit(unit_); 
  431. em_[1]->setunit(unit_);
  432. return TCL_OK;
  433. }
  434. if (strcmp(argv[1], "eventtrace") == 0) {
  435. EventTrace* et = (EventTrace *)TclObject::lookup(argv[2]);
  436. em_[0]->et_ = et;
  437. em_[1]->et_ = et;
  438. return (TCL_OK);
  439. }
  440. }
  441. else if (argc == 5) {
  442. if (strcmp(argv[1], "ranvar") == 0) {
  443. int i = atoi(argv[2]);
  444. int j = atoi(argv[3]);
  445. if (i < 0 || i > 1) {
  446. tcl.add_errorf("%s does not has em_[%d]", name_, i);
  447. return (TCL_ERROR);
  448. }
  449. if (j < 0 || j > 1) {
  450. tcl.add_errorf("%s does not has ranvar_[%d]", name_, i);
  451. return (TCL_ERROR);
  452. }
  453. em_[i]->ranvar_[j] = (RandomVariable*)TclObject::lookup(argv[4]);
  454. if (em_[i]->ranvar_[0] != 0 && em_[i]->ranvar_[1] != 0)
  455. em_[i]->checkUnit();
  456. return (TCL_OK);
  457. }
  458. }
  459. return ErrorModel::command(argc, argv);
  460. }
  461. int ComplexTwoStateErrorModel::corruptTime(Packet* p)
  462. {
  463. int error = 0;
  464. if (em_[0]->state_ == 1 && em_[1]->state_ == 1) 
  465. error = 1;
  466. return error;
  467. }
  468. int ComplexTwoStateErrorModel::corruptPkt(Packet* p)
  469. {
  470. fprintf(stderr, "Error model defined in time; not in packetsn");
  471. return -1;
  472. }
  473. static char * st_names[]={ST_NAMES};
  474. /*
  475. // MultiState ErrorModel:
  476. //   corrupt(pkt) invoke Tcl method "corrupt" to do state transition
  477. // Tcl corrupt either:
  478. //    - assign em_, the error-model to be use
  479. //    - return the status of the packet
  480. // If em_ is assigned, then invoke em_->corrupt(p)
  481. */
  482. MultiStateErrorModel::MultiStateErrorModel() : prevTime_(0.0), em_(0)
  483. {
  484. bind("sttype_", &sttype_);
  485. bind("texpired_", &texpired_);
  486. bind("curperiod_", &curperiod_);
  487. }
  488. int MultiStateErrorModel::command(int argc, const char*const* argv)
  489. {
  490. Tcl& tcl = Tcl::instance();
  491. if (argc == 3) {
  492. if (strcmp(argv[1], "error-model") == 0) {
  493. em_ = (ErrorModel*) TclObject::lookup(argv[2]);
  494. return TCL_OK;
  495. }
  496. if (strcmp(argv[1], "sttype") == 0) {
  497. sttype_ = STR2ST(argv[2]);
  498. return TCL_OK;
  499. }
  500. } else if (argc == 2) {
  501. if (strcmp(argv[1], "sttype") == 0) {
  502. tcl.resultf("%s", st_names[sttype_]);
  503. return TCL_OK;
  504. }
  505. if (strcmp(argv[1], "error-model") == 0) {
  506. tcl.resultf("%s", (ErrorModel*) em_->name());
  507. return TCL_OK;
  508. }
  509. }
  510. return ErrorModel::command(argc, argv);
  511. }
  512. int MultiStateErrorModel::corrupt(Packet* p)
  513. {
  514. int retval;
  515. double now;
  516. // static double prevTime_ = 0.0;
  517. Scheduler & s = Scheduler::instance();
  518. now = s.clock();
  519. if (sttype_ == ST_TIME)
  520. if ((now - prevTime_) >= curperiod_)
  521. texpired_ = 1;
  522. Tcl& tcl = Tcl::instance();
  523. tcl.evalf("%s corrupt", name());
  524. retval = em_ ? em_->corrupt(p) : atoi(tcl.result());
  525. if (firstTime_) {
  526. firstTime_ = 0;
  527. prevTime_ = s.clock();
  528. texpired_ = 0;
  529. }
  530. return (retval);
  531. }
  532. TraceErrorModel::TraceErrorModel() : loss_(0), good_(123456789)
  533. {
  534. bind("good_", &good_);
  535. bind("loss_", &loss_);
  536. }
  537. /* opening and reading the trace file/info is done in OTcl */
  538. int TraceErrorModel::corrupt(Packet* p)
  539. {
  540. Tcl& tcl = Tcl::instance();
  541. if (! match(p))
  542. return 0;
  543. if ((good_ <= 0) && (loss_ <= 0)) {
  544. tcl.evalf("%s read",name());
  545. if (good_ < 0)
  546. good_ = 123456789;
  547. }
  548. if (good_-- > 0)
  549. return 0;
  550. return (loss_-- > 0);
  551. }
  552. int TraceErrorModel::match(Packet*)
  553. {
  554. return 1;
  555. }
  556. /*
  557.  * Periodic ErrorModel
  558.  */
  559. static class PeriodicErrorModelClass : public TclClass {
  560. public:
  561. PeriodicErrorModelClass() : TclClass("ErrorModel/Periodic") {}
  562. TclObject* create(int, const char*const*) {
  563. return (new PeriodicErrorModel);
  564. }
  565. } class_periodic_error_model;
  566. PeriodicErrorModel::PeriodicErrorModel() : cnt_(0), last_time_(0.0), first_time_(-1.0)
  567. {
  568. bind("period_", &period_);
  569. bind("offset_", &offset_);
  570. bind("burstlen_", &burstlen_);
  571. bind("default_drop_", &default_drop_);
  572. }
  573. int PeriodicErrorModel::corrupt(Packet* p)
  574. {
  575. hdr_cmn *ch = hdr_cmn::access(p);
  576. double now = Scheduler::instance().clock();
  577. if (unit_ == EU_TIME) {
  578. if (first_time_ < 0.0) {
  579. if (now >= offset_) {
  580. first_time_ = last_time_ = now;
  581. return 1;
  582. }
  583. } else {
  584. if ((now - last_time_) > period_) {
  585. last_time_ = now;
  586. return 1;
  587. }
  588. if ((now - last_time_) < burstlen_) {
  589. return 1;
  590. }
  591. }
  592. return 0;
  593. }
  594. cnt_ += (unit_ == EU_PKT) ? 1 : ch->size();
  595. if (default_drop_) {
  596. if (int(first_time_) < 0) {
  597. if (cnt_ >= int(offset_)) {
  598. last_time_ = first_time_ = 1.0;
  599. cnt_ = 0;
  600. return 0;
  601. }
  602. return 0;
  603. } else {
  604. if (cnt_ >= int(period_)) {
  605. cnt_ = 0;
  606. return 0;
  607. }
  608. }
  609. return 1;
  610. } else {
  611. if (int(first_time_) < 0) {
  612. if (cnt_ >= int(offset_)) {
  613. last_time_ = first_time_ = 1.0;
  614. cnt_ = 0;
  615. return 1;
  616. }
  617. return 0;
  618. } else {
  619. if (cnt_ >= int(period_)) {
  620. cnt_ = 0;
  621. return 1;
  622. }
  623. if (cnt_ < burstlen_)
  624. return 1;
  625. }
  626. return 0;
  627. }
  628. }
  629. /*
  630.  * List ErrorModel: specify a list of packets/bytes to drop
  631.  * can be specified in any order
  632.  */
  633. static class ListErrorModelClass : public TclClass {
  634. public:
  635. ListErrorModelClass() : TclClass("ErrorModel/List") {}
  636. TclObject* create(int, const char*const*) {
  637. return (new ListErrorModel);
  638. }
  639. } class_list_error_model;
  640. int ListErrorModel::corrupt(Packet* p)
  641. {
  642. /* assumes droplist_ is sorted */
  643. int rval = 0; // no drop
  644. if (unit_ == EU_TIME) {
  645. fprintf(stderr,
  646. "ListErrorModel: error, EU_TIME not supportedn");
  647. return 0;
  648. }
  649. if (droplist_ == NULL || dropcnt_ == 0) {
  650. fprintf(stderr, "warning: ListErrorModel: null drop listn");
  651. return 0;
  652. }
  653. if (unit_ == EU_PKT) {
  654. //printf("TEST: cur_:%d, dropcnt_:%d, droplist_[cur_]:%d, cnt_:%dn",
  655. //cur_, dropcnt_, droplist_[cur_], cnt_);
  656. if ((cur_ < dropcnt_) && droplist_[cur_] == cnt_) {
  657. rval = 1;
  658. cur_++;
  659. }
  660. cnt_++;
  661. } else if (unit_ == EU_BYTE) {
  662. int sz = hdr_cmn::access(p)->size();
  663. if ((cur_ < dropcnt_) && (cnt_ + sz) >= droplist_[cur_]) {
  664. rval = 1;
  665. cur_++;
  666. }
  667. cnt_ += sz;
  668. }
  669. return (rval);
  670. }
  671. int
  672. ListErrorModel::command(int argc, const char*const* argv)
  673. {
  674. /*
  675.  * works for variable args:
  676.  * $lem droplist "1 3 4 5"
  677.  * and
  678.  * $lem droplist 1 3 4 5
  679.  */
  680. Tcl& tcl = Tcl::instance();
  681. if (strcmp(argv[1], "droplist") == 0) {
  682. int cnt;
  683. if ((cnt = parse_droplist(argc-2, argv + 2)) < 0)
  684. return (TCL_ERROR);
  685. tcl.resultf("%u", cnt);
  686. return(TCL_OK);
  687. }
  688. return (ErrorModel::command(argc, argv));
  689. }
  690. int
  691. ListErrorModel::intcomp(const void *p1, const void *p2)
  692. {
  693. int a = *((int*) p1);
  694. int b = *((int*) p2);
  695. return (a - b);
  696. }
  697. /*
  698.  * nextval: find the next value in the string
  699.  *
  700.  * skip white space, update pointer to first non-white-space
  701.  * character.  Return the number of characters in the next
  702.  * token.
  703.  */
  704. int
  705. ListErrorModel::nextval(const char*& p)
  706. {
  707. while (*p && isspace(*p))
  708. ++p;
  709. if (!*p) {
  710. /* end of string */
  711. return (0);
  712. }
  713. const char *q = p;
  714. while (*q && !isspace(*q))
  715. ++q;
  716. return (q-p);
  717. }
  718. int
  719. ListErrorModel::parse_droplist(int argc, const char *const* argv)
  720. {
  721. int cnt = 0; // counter for argc list
  722. int spaces = 0; // counts # of spaces in an argv entry
  723. int total = 0; // total entries in the drop list
  724. int n; // # of chars in the next drop number
  725. const char *p; // ptr into current string
  726. /*
  727.  * loop over argc list:  figure out how many numbers
  728.  * have been specified
  729.  */
  730. while (cnt < argc) {
  731. p = argv[cnt];
  732. spaces = 0;
  733. while ((n = nextval(p))) {
  734. if (!isdigit(*p)) {
  735. /* problem... */
  736. fprintf(stderr, "ListErrorModel(%s): parse_droplist: unknown drop specifier starting at >>>%sn",
  737. name(), p);
  738. return (-1);
  739. }
  740. ++spaces;
  741. p += n;
  742. }
  743. total += spaces;
  744. cnt++;
  745. }
  746. /*
  747.  * parse the numbers, put them in an array (droplist_)
  748.  * set dropcnt_ to the total # of drops.  Also, free any
  749.  * previous drop list.
  750.  */
  751. if ((total == 0) || (dropcnt_ > 0 && droplist_ != NULL)) {
  752. delete[] droplist_;
  753. droplist_ = NULL;
  754. }
  755. if ((dropcnt_ = total) == 0)
  756. return (0);
  757. droplist_ = new int[dropcnt_];
  758. if (droplist_ == NULL) {
  759. fprintf(stderr,
  760. "ListErrorModel(%s): no memory for drop list!n",
  761. name());
  762. return (-1);
  763. }
  764. int idx = 0;
  765. cnt = 0;
  766. while (cnt < argc) {
  767. p = argv[cnt];
  768. while ((n = nextval(p))) {
  769. /*
  770.  * this depends on atoi(s) returning the
  771.  * value of the first number in s
  772.  */
  773. droplist_[idx++] = atoi(p);
  774. p += n;
  775. }
  776. cnt++;
  777. }
  778. qsort(droplist_, dropcnt_, sizeof(int), intcomp);
  779. /*
  780.  * sanity check the array, looking for (wrong) dups
  781.  */
  782. cnt = 0;
  783. while (cnt < (dropcnt_ - 1)) {
  784. if (droplist_[cnt] == droplist_[cnt+1]) {
  785. fprintf(stderr,
  786. "ListErrorModel: error: dup %d in listn",
  787. droplist_[cnt]);
  788. total = -1; /* error */
  789. }
  790. ++cnt;
  791. }
  792. if (total < 0) {
  793. if (droplist_)
  794. delete[] droplist_;
  795. dropcnt_ = 0;
  796. droplist_ = NULL;
  797. return (-1);
  798. }
  799. #ifdef notdef
  800. printf("sorted list:n");
  801. {
  802. register i;
  803. for (i =0; i < dropcnt_; i++) {
  804. printf("list[%d] = %dn", i, droplist_[i]);
  805. }
  806. }
  807. #endif
  808. return dropcnt_;
  809. }
  810. /***** ***/
  811. static class SelectErrorModelClass : public TclClass {
  812. public:
  813. SelectErrorModelClass() : TclClass("SelectErrorModel") {}
  814. TclObject* create(int, const char*const*) {
  815. return (new SelectErrorModel);
  816. }
  817. } class_selecterrormodel;
  818. SelectErrorModel::SelectErrorModel()
  819. {
  820. bind("pkt_type_", (int*)&pkt_type_);
  821. bind("drop_cycle_", &drop_cycle_);
  822. bind("drop_offset_", &drop_offset_);
  823. }
  824. int SelectErrorModel::command(int argc, const char*const* argv)
  825. {
  826. if (strcmp(argv[1], "drop-packet") == 0) {
  827. pkt_type_ = packet_t(atoi(argv[2]));
  828. drop_cycle_ = atoi(argv[3]);
  829. drop_offset_ = atoi(argv[4]);
  830. return TCL_OK;
  831. }
  832. return ErrorModel::command(argc, argv);
  833. }
  834. int SelectErrorModel::corrupt(Packet* p)
  835. {
  836. if (unit_ == EU_PKT) {
  837. hdr_cmn *ch = hdr_cmn::access(p);
  838. // XXX Backward compatibility for cbr agents
  839. if (ch->ptype() == PT_UDP && pkt_type_ == PT_CBR)
  840. pkt_type_ = PT_UDP; // "udp" rather than "cbr"
  841. if (ch->ptype() == pkt_type_ && ch->uid() % drop_cycle_ 
  842.     == drop_offset_) {
  843. //printf ("dropping packet type %d, uid %dn", 
  844. // ch->ptype(), ch->uid());
  845. return 1;
  846. }
  847. }
  848. return 0;
  849. }
  850. /* Error model for srm experiments */
  851. class SRMErrorModel : public SelectErrorModel {
  852. public:
  853. SRMErrorModel();
  854. virtual int corrupt(Packet*);
  855. protected:
  856. int command(int argc, const char*const* argv);
  857. };
  858. static class SRMErrorModelClass : public TclClass {
  859. public:
  860. SRMErrorModelClass() : TclClass("SRMErrorModel") {}
  861. TclObject* create(int, const char*const*) {
  862. return (new SRMErrorModel);
  863. }
  864. } class_srmerrormodel;
  865. SRMErrorModel::SRMErrorModel()
  866. {
  867. }
  868. int SRMErrorModel::command(int argc, const char*const* argv)
  869. {
  870. //int ac = 0;
  871. if (strcmp(argv[1], "drop-packet") == 0) {
  872. pkt_type_ = packet_t(atoi(argv[2]));
  873. drop_cycle_ = atoi(argv[3]);
  874. drop_offset_ = atoi(argv[4]);
  875. return TCL_OK;
  876. }
  877. return ErrorModel::command(argc, argv);
  878. }
  879. int SRMErrorModel::corrupt(Packet* p)
  880. {
  881. if (unit_ == EU_PKT) {
  882. hdr_srm *sh = hdr_srm::access(p);
  883. hdr_cmn *ch = hdr_cmn::access(p);
  884. // XXX Backward compatibility for cbr agents
  885. if (ch->ptype()==PT_UDP && pkt_type_==PT_CBR && sh->type() == SRM_DATA)
  886. pkt_type_ = PT_UDP; // "udp" rather than "cbr"
  887. if ((ch->ptype() == pkt_type_) && (sh->type() == SRM_DATA) && 
  888.     (sh->seqnum() % drop_cycle_ == drop_offset_)) {
  889. //printf ("dropping packet type SRM-DATA, seqno %dn", 
  890. //sh->seqnum());
  891. return 1;
  892. }
  893. }
  894. return 0;
  895. }
  896. static class MrouteErrorModelClass : public TclClass {
  897. public:
  898. MrouteErrorModelClass() : TclClass("ErrorModel/Trace/Mroute") {}
  899. TclObject* create(int, const char*const*) {
  900. return (new MrouteErrorModel);
  901. }
  902. } class_mrouteerrormodel;
  903.  
  904. MrouteErrorModel::MrouteErrorModel() : TraceErrorModel()
  905. {
  906. }
  907. int MrouteErrorModel::command(int argc, const char*const* argv)
  908. {
  909. if (argc == 3) {
  910. if (strcmp(argv[1], "drop-packet") == 0) {
  911. const char* s = argv[2];
  912. int n = strlen(s);
  913. if (n >= this->maxtype()) {
  914. // tcl.result("message type too big");
  915. return (TCL_ERROR);
  916. }
  917. strcpy(msg_type,s);
  918. return(TCL_OK);
  919. }
  920. }
  921. return TraceErrorModel::command(argc, argv);
  922. }
  923. int MrouteErrorModel::match(Packet* p)
  924. {
  925. hdr_mcast_ctrl* ph = hdr_mcast_ctrl::access(p);
  926. int indx = strcspn(ph->type(),"/");
  927. if (!strncmp(ph->type(),msg_type,indx)) {
  928. return 1;
  929. }
  930. return 0;
  931. }
  932. static class ErrorModuleClass : public TclClass {
  933. public:
  934. ErrorModuleClass() : TclClass("ErrorModule") {}
  935. TclObject* create(int, const char*const*) {
  936. return (new ErrorModule);
  937. }
  938. } class_errormodule;
  939. void ErrorModule::recv(Packet *p, Handler *h)
  940. {
  941. classifier_->recv(p, h);
  942. }
  943. int ErrorModule::command(int argc, const char*const* argv)
  944. {
  945. Tcl& tcl = Tcl::instance();
  946. if (argc == 2) {
  947. if (strcmp(argv[1], "classifier") == 0) {
  948. if (classifier_)
  949. tcl.resultf("%s", classifier_->name());
  950. else
  951. tcl.resultf("");
  952. return (TCL_OK);
  953. }
  954. } else if (argc == 3) {
  955. if (strcmp(argv[1], "classifier") == 0) {
  956. classifier_ = (Classifier*)
  957. TclObject::lookup(argv[2]);
  958. if (classifier_ == NULL) {
  959. tcl.resultf("Couldn't look up classifier %s", argv[2]);
  960. return (TCL_ERROR);
  961. }
  962. return (TCL_OK);
  963. }
  964. }
  965. return (Connector::command(argc, argv));
  966. }
  967. #include "config.h"
  968. #ifdef HAVE_STL //pgm uses STL
  969. #include "pgm/pgm.h"
  970. static class PGMErrorModelClass : public TclClass {
  971. public:
  972.        PGMErrorModelClass() : TclClass("PGMErrorModel") {}
  973.         TclObject* create(int, const char*const*) {
  974.                 return (new PGMErrorModel);
  975.         }
  976. } class_pgm_errormodel;
  977. PGMErrorModel::PGMErrorModel() : ErrorModel(), pgm_type_(-1), count_(0)
  978. {
  979.         ndrops_ = 0;
  980.         bind("ndrops_", &ndrops_);
  981. }
  982. int PGMErrorModel::command(int argc, const char*const* argv)
  983. {
  984.         if (strcmp(argv[1], "drop-packet") == 0) {
  985. if (!strcasecmp(argv[2], "SPM")) {
  986. pgm_type_ = PGM_SPM;
  987. }
  988. else if (!strcasecmp(argv[2], "ODATA")) {
  989. pgm_type_ = PGM_ODATA;
  990. }
  991. else if (!strcasecmp(argv[2], "RDATA")) {
  992. pgm_type_ = PGM_RDATA;
  993. }
  994. else if (!strcasecmp(argv[2], "NAK")) {
  995. pgm_type_ = PGM_NAK;
  996. }
  997. else if (!strcasecmp(argv[2], "NCF")) {
  998. pgm_type_ = PGM_NCF;
  999. }
  1000. else {
  1001. fprintf(stderr, "PGMErrorModel: drop-packet PGM type "%s" unknown.n", argv[2]);
  1002. return TCL_ERROR;
  1003. }
  1004.                 drop_cycle_ = atoi(argv[3]);
  1005.                 drop_offset_ = atoi(argv[4]);
  1006.                 return TCL_OK;
  1007.         }
  1008.         return ErrorModel::command(argc, argv);
  1009. }
  1010. int PGMErrorModel::corrupt(Packet* p)
  1011. {
  1012.         if (unit_ == EU_PKT) {
  1013.                 hdr_cmn *ch = HDR_CMN(p);
  1014.                 hdr_pgm *hp = HDR_PGM(p);
  1015.                 if ((ch->ptype() == PT_PGM) && (hp->type_ == pgm_type_)) {
  1016. count_++;
  1017. if (count_ % drop_cycle_ == drop_offset_) {
  1018. #ifdef PGM_DEBUG
  1019. printf ("DROPPING PGM packet type %d, seqno %dn", pgm_type_, hp->seqno_);
  1020. #endif
  1021. ++ndrops_;
  1022. return 1;
  1023. }
  1024. }
  1025.         }
  1026.         return 0;
  1027. }
  1028. #endif //HAVE_STL
  1029. //
  1030. // LMS Error Model
  1031. //
  1032. #include "rtp.h"                
  1033. #include "mcast/lms.h"
  1034. static class LMSErrorModelClass : public TclClass {
  1035. public:
  1036.         LMSErrorModelClass() : TclClass("LMSErrorModel") {}
  1037.         TclObject* create(int, const char*const*) {
  1038.                 return (new LMSErrorModel);
  1039.         }
  1040. } class_lms_errormodel;
  1041.  
  1042.  
  1043. LMSErrorModel::LMSErrorModel() : ErrorModel()
  1044. {
  1045.         ndrops_ = 0;
  1046.         bind("ndrops_", &ndrops_);
  1047. }
  1048.  
  1049. int LMSErrorModel::command(int argc, const char*const* argv)
  1050. {
  1051.         if (strcmp(argv[1], "drop-packet") == 0)
  1052. {
  1053.                 pkt_type_ = packet_t(atoi(argv[2]));
  1054.                 drop_cycle_ = atoi(argv[3]);
  1055.                 drop_offset_ = atoi(argv[4]);
  1056.                 return TCL_OK;
  1057. }
  1058.         return ErrorModel::command(argc, argv);
  1059. }
  1060. int LMSErrorModel::corrupt(Packet* p)
  1061. {
  1062.         if (unit_ == EU_PKT)
  1063. {
  1064.                 hdr_cmn *ch = HDR_CMN(p);
  1065.                 hdr_lms *lh = HDR_LMS(p);
  1066.                 hdr_rtp *rh = HDR_RTP(p);
  1067.  
  1068.                 if ((ch->ptype() == pkt_type_) && (lh->type_ != LMS_DMCAST) &&
  1069.                     (rh->seqno() % drop_cycle_ == drop_offset_))
  1070. {
  1071. #ifdef LMS_DEBUG
  1072. printf ("Error Model: DROPPING pkt type %d, seqno %dn", pkt_type_, rh->seqno());
  1073. #endif
  1074.                         ++ndrops_;
  1075. return 1;
  1076. }
  1077.          }
  1078. return 0;
  1079. }
  1080. void TwoStateErrModelTimer::expire(Event *e) 
  1081. {
  1082. (*a_.*call_back_)();
  1083. }