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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8 -*- */
  2. /*
  3.  * Copyright (c) 1990-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 Computer Systems
  17.  * Engineering Group at Lawrence Berkeley Laboratory.
  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.  * @(#) $Header: /cvsroot/nsnam/ns-2/trace/trace.cc,v 1.81 2005/07/13 03:51:33 tomh Exp $ (LBL)
  35.  */
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include "packet.h"
  39. #include "ip.h"
  40. #include "tcp.h"
  41. #include "sctp.h"
  42. #include "rtp.h"
  43. #include "srm.h"
  44. #include "tfrc.h"
  45. #include "flags.h"
  46. #include "address.h"
  47. #include "trace.h"
  48. #include "rap/rap.h"
  49. //const double Trace::PRECISION = 1.0e+6; 
  50. class TraceClass : public TclClass {
  51. public:
  52. TraceClass() : TclClass("Trace") { }
  53. TclObject* create(int argc, const char*const* argv) {
  54. if (argc >= 5)
  55. return (new Trace(*argv[4]));
  56. return 0;
  57. }
  58. } trace_class;
  59. Trace::Trace(int type)
  60. : Connector(), callback_(0), pt_(0), type_(type)
  61. {
  62. bind("src_", (int*)&src_);
  63. bind("dst_", (int*)&dst_);
  64. bind("callback_", &callback_);
  65. bind("show_tcphdr_", &show_tcphdr_);
  66. bind("show_sctphdr_", &show_sctphdr_);
  67. pt_ = new BaseTrace;
  68. }
  69. Trace::~Trace()
  70. {
  71. }
  72. /*
  73.  * $trace detach
  74.  * $trace flush
  75.  * $trace attach $fileID
  76.  */
  77. int Trace::command(int argc, const char*const* argv)
  78. {
  79. Tcl& tcl = Tcl::instance();
  80. if (argc == 2) {
  81. if (strcmp(argv[1], "detach") == 0) {
  82. pt_->channel(0) ;
  83. pt_->namchannel(0) ;
  84. return (TCL_OK);
  85. }
  86. if (strcmp(argv[1], "flush") == 0) {
  87. Tcl_Channel ch = pt_->channel();
  88. Tcl_Channel namch = pt_->namchannel();
  89. if (ch != 0) 
  90. pt_->flush(ch);
  91. //Tcl_Flush(pt_.channel());
  92. if (namch != 0)
  93. //Tcl_Flush(pt_->namchannel());
  94. pt_->flush(namch);
  95. return (TCL_OK);
  96. }
  97.                 if (strcmp(argv[1], "tagged") == 0) {
  98. tcl.resultf("%d", pt_->tagged());
  99.                         return (TCL_OK);
  100.                 }
  101. } else if (argc == 3) {
  102. if (strcmp(argv[1], "annotate") == 0) {
  103. if (pt_->channel() != 0)
  104. annotate(argv[2]);
  105. return (TCL_OK);
  106. }
  107. if (strcmp(argv[1], "attach") == 0) {
  108. int mode;
  109. const char* id = argv[2];
  110. Tcl_Channel ch = Tcl_GetChannel(tcl.interp(), (char*)id,
  111.   &mode);
  112. pt_->channel(ch); 
  113. if (pt_->channel() == 0) {
  114. tcl.resultf("trace: can't attach %s for writing", id);
  115. return (TCL_ERROR);
  116. }
  117. return (TCL_OK);
  118. }
  119. if (strcmp(argv[1], "namattach") == 0) {
  120. int mode;
  121. const char* id = argv[2];
  122. Tcl_Channel namch = Tcl_GetChannel(tcl.interp(), 
  123.    (char*)id, &mode);
  124. pt_->namchannel(namch); 
  125. if (pt_->namchannel() == 0) {
  126. tcl.resultf("trace: can't attach %s for writing", id);
  127. return (TCL_ERROR);
  128. }
  129. return (TCL_OK);
  130. }
  131. if (strcmp(argv[1], "ntrace") == 0) {
  132. if (pt_->namchannel() != 0) 
  133. write_nam_trace(argv[2]);
  134. return (TCL_OK);
  135. }
  136. if (strcmp(argv[1], "tagged") == 0) {
  137.                         int tag;
  138. if (Tcl_GetBoolean(tcl.interp(),
  139.    (char*)argv[2], &tag) == TCL_OK) {
  140. pt_->tagged(tag);
  141. return (TCL_OK);
  142. } else return (TCL_ERROR);
  143.                 }
  144. }
  145. return (Connector::command(argc, argv));
  146. }
  147. void Trace::write_nam_trace(const char *s)
  148. {
  149. sprintf(pt_->nbuffer(), "%s", s);
  150. pt_->namdump();
  151. }
  152. void Trace::annotate(const char* s)
  153. {
  154. if (pt_->tagged()) {
  155. sprintf(pt_->buffer(),
  156. "v "TIME_FORMAT" -e {sim_annotation %g %s}",
  157. Scheduler::instance().clock(), 
  158. Scheduler::instance().clock(), s);
  159. } else {
  160. sprintf(pt_->buffer(),
  161. "v "TIME_FORMAT" eval {set sim_annotation {%s}}", 
  162. pt_->round(Scheduler::instance().clock()), s);
  163. }
  164. pt_->dump();
  165. callback();
  166. sprintf(pt_->nbuffer(), "v -t "TIME_FORMAT" -e sim_annotation %g %s", 
  167. Scheduler::instance().clock(), 
  168. Scheduler::instance().clock(), s);
  169. pt_->namdump();
  170. }
  171. char* srm_names[] = {
  172.         SRM_NAMES
  173. };
  174. int
  175. Trace::get_seqno(Packet* p)
  176. {
  177. hdr_cmn *th = hdr_cmn::access(p);
  178. hdr_tcp *tcph = hdr_tcp::access(p);
  179. hdr_rtp *rh = hdr_rtp::access(p);
  180.         hdr_rap *raph = hdr_rap::access(p);
  181. hdr_tfrc *tfrch = hdr_tfrc::access(p);
  182. hdr_tfrc_ack *tfrch_ack = hdr_tfrc_ack::access(p);
  183. packet_t t = th->ptype();
  184. int seqno;
  185. /* UDP's now have seqno's too */
  186. if (t == PT_RTP || t == PT_CBR || t == PT_UDP || t == PT_EXP ||
  187.     t == PT_PARETO)
  188. seqno = rh->seqno();
  189.         else if (t == PT_RAP_DATA || t == PT_RAP_ACK)
  190.                 seqno = raph->seqno();
  191. else if (t == PT_TCP || t == PT_ACK || t == PT_HTTP || t == PT_FTP ||
  192.     t == PT_TELNET || t == PT_XCP)
  193. seqno = tcph->seqno();
  194. else if (t == PT_TFRC)
  195. seqno = tfrch->seqno;
  196. else if (t == PT_TFRC_ACK)
  197.                 seqno = tfrch_ack->seqno;
  198. else
  199. seqno = -1;
  200.   return seqno;
  201. }
  202. // this function should retain some backward-compatibility, so that
  203. // scripts don't break.
  204. void Trace::format(int tt, int s, int d, Packet* p)
  205. {
  206. hdr_cmn *th = hdr_cmn::access(p);
  207. hdr_ip *iph = hdr_ip::access(p);
  208. hdr_tcp *tcph = hdr_tcp::access(p);
  209. hdr_sctp *sctph = hdr_sctp::access(p);
  210. hdr_srm *sh = hdr_srm::access(p); 
  211. const char* sname = "null";
  212. packet_t t = th->ptype();
  213. const char* name = packet_info.name(t);
  214.         /* SRM-specific */
  215. if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
  216.             if ( sh->type() < 5 && sh->type() > 0 ) {
  217.         sname = srm_names[sh->type()];
  218.     }
  219. }
  220. if (name == 0)
  221. abort();
  222. int seqno = get_seqno(p);
  223.         /* 
  224.          * When new flags are added, make sure to change NUMFLAGS
  225.          * in trace.h
  226.          */
  227.         char flags[NUMFLAGS+1];
  228.         for (int i = 0; i < NUMFLAGS; i++)
  229. flags[i] = '-';
  230.         flags[NUMFLAGS] = 0;
  231. hdr_flags* hf = hdr_flags::access(p);
  232. flags[0] = hf->ecn_ ? 'C' : '-';          // Ecn Echo
  233. flags[1] = hf->pri_ ? 'P' : '-'; 
  234. flags[2] = '-';
  235. flags[3] = hf->cong_action_ ? 'A' : '-';   // Congestion Action
  236. flags[4] = hf->ecn_to_echo_ ? 'E' : '-';   // Congestion Experienced
  237. flags[5] = hf->fs_ ? 'F' : '-';    // Fast start: see tcp-fs and tcp-int
  238. flags[6] = hf->ecn_capable_ ? 'N' : '-';
  239. flags[7] = 0; // only for SCTP
  240. #ifdef notdef
  241. flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
  242. flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
  243. flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
  244. flags[5] = 0;
  245. #endif
  246. char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
  247. char *src_portaddr = Address::instance().print_portaddr(iph->sport());
  248. char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
  249. char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
  250. if (pt_->tagged()) {
  251. sprintf(pt_->buffer(), 
  252. "%c "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
  253. tt,
  254. Scheduler::instance().clock(),
  255. s,
  256.   d,
  257. name,
  258. th->size(),
  259. iph->flowid(),
  260. th->uid(),
  261. iph->flowid(),
  262. src_nodeaddr,
  263. src_portaddr,
  264. dst_nodeaddr,
  265. dst_portaddr,
  266. seqno,flags,sname);
  267. } else if (show_sctphdr_ && t == PT_SCTP) {
  268. double timestamp;
  269. timestamp = Scheduler::instance().clock();
  270. for(unsigned int i = 0; i < sctph->NumChunks(); i++) {
  271. switch(sctph->SctpTrace()[i].eType) {
  272. case SCTP_CHUNK_INIT:
  273. case SCTP_CHUNK_INIT_ACK:
  274. case SCTP_CHUNK_COOKIE_ECHO:
  275. case SCTP_CHUNK_COOKIE_ACK:
  276. flags[7] = 'I';     // connection initialization
  277. break;
  278. case SCTP_CHUNK_DATA:
  279. flags[7] = 'D';
  280. break;
  281. case SCTP_CHUNK_SACK:
  282. flags[7] = 'S';
  283. break;
  284. case SCTP_CHUNK_FORWARD_TSN:
  285. flags[7] = 'R';
  286. break;
  287. case SCTP_CHUNK_HB:
  288. flags[7] = 'H';
  289. break;
  290. case SCTP_CHUNK_HB_ACK:
  291. flags[7] = 'B';
  292. break;
  293. default:
  294. assert (false);
  295. }
  296. sprintf(pt_->buffer(),
  297. "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d %d %d %d",
  298. tt,
  299. pt_->round(timestamp),
  300. s,
  301. d,
  302. name,
  303. th->size(),
  304. flags,
  305. iph->flowid(), /* was p->class_ */
  306. src_nodeaddr,
  307. src_portaddr,
  308. dst_nodeaddr,
  309. dst_portaddr,
  310. sctph->NumChunks(),
  311. sctph->SctpTrace()[i].uiTsn,
  312. th->uid(), /* was p->uid_ */
  313. sctph->SctpTrace()[i].usStreamId,
  314. sctph->SctpTrace()[i].usStreamSeqNum);      
  315. /* The caller already calls pt_->dump() for us,
  316.  * but since SCTP needs to dump once per chunk, we
  317.  * call dump ourselves for all but the last chunk.
  318.  */
  319. assert (sctph->NumChunks() >= 1);
  320. if(i < sctph->NumChunks() - 1)
  321. pt_->dump();
  322. }
  323. } else if (!show_tcphdr_) {
  324. sprintf(pt_->buffer(), "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d",
  325. tt,
  326. pt_->round(Scheduler::instance().clock()),
  327. s,
  328. d,
  329. name,
  330. th->size(),
  331. flags,
  332. iph->flowid() /* was p->class_ */,
  333. // iph->src() >> (Address::instance().NodeShift_[1]), 
  334.                         // iph->src() & (Address::instance().PortMask_), 
  335.                         // iph->dst() >> (Address::instance().NodeShift_[1]), 
  336.                         // iph->dst() & (Address::instance().PortMask_),
  337. src_nodeaddr,
  338. src_portaddr,
  339. dst_nodeaddr,
  340. dst_portaddr,
  341. seqno,
  342. th->uid() /* was p->uid_ */);
  343. } else {
  344. sprintf(pt_->buffer(), 
  345. "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d %d 0x%x %d %d",
  346. tt,
  347. pt_->round(Scheduler::instance().clock()),
  348. s,
  349. d,
  350. name,
  351. th->size(),
  352. flags,
  353. iph->flowid(), /* was p->class_ */
  354.         // iph->src() >> (Address::instance().NodeShift_[1]), 
  355. // iph->src() & (Address::instance().PortMask_), 
  356.            // iph->dst() >> (Address::instance().NodeShift_[1]), 
  357.            // iph->dst() & (Address::instance().PortMask_),
  358. src_nodeaddr,
  359. src_portaddr,
  360. dst_nodeaddr,
  361. dst_portaddr,
  362. seqno,
  363. th->uid(), /* was p->uid_ */
  364. tcph->ackno(),
  365. tcph->flags(),
  366. tcph->hlen(),
  367. tcph->sa_length());
  368. }
  369. if (pt_->namchannel() != 0)
  370. sprintf(pt_->nbuffer(), 
  371. "%c -t "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
  372. tt,
  373. Scheduler::instance().clock(),
  374. s,
  375.   d,
  376. name,
  377. th->size(),
  378. iph->flowid(),
  379. th->uid(),
  380. iph->flowid(),
  381. src_nodeaddr,
  382. src_portaddr,
  383. dst_nodeaddr,
  384. dst_portaddr,
  385. seqno,flags,sname);
  386. delete [] src_nodeaddr;
  387.    delete [] src_portaddr;
  388.    delete [] dst_nodeaddr;
  389.     delete [] dst_portaddr;
  390. }
  391. void Trace::recv(Packet* p, Handler* h)
  392. {
  393. format(type_, src_, dst_, p);
  394. pt_->dump();
  395. callback();
  396. pt_->namdump();
  397. /* hack: if trace object not attached to anything free packet */
  398. if (target_ == 0)
  399. Packet::free(p);
  400. else
  401. send(p, h);
  402. }
  403. void Trace::recvOnly(Packet *p)
  404. {
  405. format(type_, src_, dst_, p);
  406. pt_->dump();
  407. callback();
  408. pt_->namdump();
  409. target_->recvOnly(p);
  410. }
  411. void Trace::trace(TracedVar* var)
  412. {
  413. char tmp[256] = "";
  414. Scheduler& s = Scheduler::instance();
  415. if (&s == 0)
  416. return;
  417. if (pt_->tagged()) {
  418. sprintf(pt_->buffer(), "%c "TIME_FORMAT" -a %s -n %s -v %s",
  419. type_,
  420. pt_->round(s.clock()),
  421. var->owner()->name(),
  422. var->name(),
  423. var->value(tmp, 256));
  424. } else {
  425. // format: use Mark's nam feature code without the '-' prefix
  426. sprintf(pt_->buffer(), "%c t"TIME_FORMAT" a%s n%s v%s",
  427. type_,
  428. pt_->round(s.clock()),
  429. var->owner()->name(),
  430. var->name(),
  431. var->value(tmp, 256));
  432. }
  433. pt_->dump();
  434. callback();
  435. }
  436. void Trace::callback() 
  437. {
  438. if (callback_) {
  439. Tcl& tcl = Tcl::instance();
  440. tcl.evalf("%s handle { %s }", name(), pt_->buffer());
  441. }
  442. }
  443. //
  444. // we need a DequeTraceClass here because a 'h' event need to go together
  445. // with the '-' event. It's possible to use a postprocessing script, but 
  446. // seems that's inconvient.
  447. //
  448. static class DequeTraceClass : public TclClass {
  449. public:
  450. DequeTraceClass() : TclClass("Trace/Deque") { }
  451. TclObject* create(int args, const char*const* argv) {
  452. if (args >= 5)
  453. return (new DequeTrace(*argv[4]));
  454. return NULL;
  455. }
  456. } dequetrace_class;
  457. DequeTrace::~DequeTrace()
  458. {
  459. }
  460. void 
  461. DequeTrace::recv(Packet* p, Handler* h)
  462. {
  463. // write the '-' event first
  464. format(type_, src_, dst_, p);
  465. pt_->dump();
  466. callback();
  467. pt_->namdump();
  468. if (pt_->namchannel() != 0 ||
  469.     (pt_->tagged() && pt_->channel() !=0)) {
  470. hdr_cmn *th = hdr_cmn::access(p);
  471. hdr_ip *iph = hdr_ip::access(p);
  472. hdr_srm *sh = hdr_srm::access(p);
  473. const char* sname = "null";   
  474. packet_t t = th->ptype();
  475. const char* name = packet_info.name(t);
  476. if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
  477.     if ( sh->type() < 5 && sh->type() > 0  ) {
  478.         sname = srm_names[sh->type()];
  479.     }
  480. }   
  481. char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
  482. char *src_portaddr = Address::instance().print_portaddr(iph->sport());
  483. char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
  484. char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
  485. char flags[NUMFLAGS+1];
  486. for (int i = 0; i < NUMFLAGS; i++)
  487. flags[i] = '-';
  488. flags[NUMFLAGS] = 0;
  489. hdr_flags* hf = hdr_flags::access(p);
  490. flags[0] = hf->ecn_ ? 'C' : '-';          // Ecn Echo
  491. flags[1] = hf->pri_ ? 'P' : '-'; 
  492. flags[2] = '-';
  493. flags[3] = hf->cong_action_ ? 'A' : '-';   // Congestion Action
  494. flags[4] = hf->ecn_to_echo_ ? 'E' : '-';   // Congestion Experienced
  495. flags[5] = hf->fs_ ? 'F' : '-';
  496. flags[6] = hf->ecn_capable_ ? 'N' : '-';
  497. flags[7] = 0; // only for SCTP
  498. #ifdef notdef
  499. flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
  500. flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
  501. flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
  502. flags[5] = 0;
  503. #endif
  504. if (pt_->nbuffer() != 0) {
  505. sprintf(pt_->nbuffer(), 
  506. "%c -t "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
  507. 'h',
  508. Scheduler::instance().clock(),
  509. src_,
  510.    dst_,
  511. name,
  512. th->size(),
  513. iph->flowid(),
  514. th->uid(),
  515. iph->flowid(),
  516. src_nodeaddr,
  517. src_portaddr,
  518. dst_nodeaddr,
  519. dst_portaddr,
  520. -1, flags, sname);
  521. pt_->namdump();
  522. }
  523. if (pt_->tagged() && pt_->buffer() != 0) {
  524. sprintf(pt_->buffer(), 
  525. "%c "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
  526. 'h',
  527. Scheduler::instance().clock(),
  528. src_,
  529.    dst_,
  530. name,
  531. th->size(),
  532. iph->flowid(),
  533. th->uid(),
  534. iph->flowid(),
  535. src_nodeaddr,
  536. src_portaddr,
  537. dst_nodeaddr,
  538. dst_portaddr,
  539. -1, flags, sname);
  540. pt_->dump();
  541. }
  542. delete [] src_nodeaddr;
  543. delete [] src_portaddr;
  544. delete [] dst_nodeaddr;
  545. delete [] dst_portaddr;
  546. }
  547. /* hack: if trace object not attached to anything free packet */
  548. if (target_ == 0)
  549. Packet::free(p);
  550. else
  551. send(p, h);
  552. }