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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1991,1993 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  * This product includes software developed by the Computer Systems
  16.  * Engineering Group at Lawrence Berkeley Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#) $Header: /cvsroot/nsnam/nam-1/edge.cc,v 1.54 2003/10/11 22:56:49 xuanc Exp $ (LBL)
  34.  */
  35. #include <tclcl.h>
  36. #include "config.h"
  37. #include "sincos.h"
  38. #include "edge.h"
  39. #include "queuehandle.h"
  40. #include "node.h"
  41. #include "packet.h"
  42. #include "view.h"
  43. #include "netview.h"
  44. #include "psview.h"
  45. #include "transform.h"
  46. #include "paint.h"
  47. #include "monitor.h"
  48. #include "agent.h"
  49. #include "lossmodel.h"
  50. //----------------------------------------------------------------------
  51. //  Wrapper for tcl creation of Edges (links) 
  52. //----------------------------------------------------------------------
  53. static class EdgeClass : public TclClass {
  54. public:
  55.   EdgeClass() : TclClass("Edge") {} 
  56.   TclObject * create(int argc, const char*const* argv) {
  57.     // set <Edge> [new Node node_id type size]
  58.     Edge * edge;
  59.     double bandwidth, delay, length, angle, label_size;
  60.     bandwidth = strtod(argv[4], NULL);
  61.     delay  = strtod(argv[5], NULL);
  62.     length = strtod(argv[6], NULL);
  63.     angle = strtod(argv[7], NULL);
  64.     label_size = strtod(argv[8], NULL);
  65.     edge = new Edge(label_size, bandwidth, delay, length, angle);
  66.     return edge;
  67.   }
  68. } class_edge;
  69. //----------------------------------------------------------------------
  70. // Edge::Edge(double ps, double bw, double delay,
  71. //            double length, double angle)
  72. //    - Creates an edge that is not attached to any nodes.
  73. //      Used by nam editor when loading in an existing enam file.
  74. //    - With this constructor, the nodes need to be added 
  75. //      to this edge using Edge::attachNodes() 
  76. //----------------------------------------------------------------------
  77. Edge::Edge(double ps, double bw, double delay,
  78.            double length, double angle) :
  79.   Animation(0,0) {
  80.   psize_ = ps;
  81.   angle_ = angle;
  82.   bandwidth_ = bw;
  83.   delay_ = delay;
  84.   length_ = length;
  85.   state_ = UP;
  86.   paint_ = Paint::instance()->thick();
  87.   
  88.   setupDefaults(); 
  89. }
  90. //----------------------------------------------------------------------
  91. // Edge::Edge(Node* src, Node* dst, double ps, double bw,
  92. //            double delay, double length, double angle)
  93. //   - creates an edge which is a one way network link
  94. //   - the edge is automaticall attached to nodes src and dst
  95. //----------------------------------------------------------------------
  96. Edge::Edge(Node * src, Node * dst, double ps, double bw,
  97.            double _delay, double length, double angle) :
  98.   Animation(0,0),
  99.   psize_(ps),
  100.   angle_(angle),
  101.   bandwidth_(bw),
  102.   delay_(_delay),
  103.   length_(length) {
  104.   setupDefaults();
  105.   src_ = src->num();
  106.   dst_ = dst->num();
  107.   start_ = src;
  108.   neighbor_ = dst;
  109.   paint_ = Paint::instance()->thick();
  110.   if (length_ == 0) {
  111.     length_ = delay_;
  112.   }
  113. }
  114. //----------------------------------------------------------------------
  115. // Edge::Edge(Node* src, Node* dst, double ps, double bw,
  116. //            double delay, double length, double angle, int ws)
  117. //   - creates an edge for wireless 
  118. //----------------------------------------------------------------------
  119. Edge::Edge(Node* src, Node* dst, double ps,
  120.      double bw, double _delay, double length, double angle, int ws) :
  121.   Animation(0,0),
  122.   psize_(ps),
  123.   angle_(angle),
  124.   bandwidth_(bw),
  125.   delay_(_delay),
  126.   length_(length),
  127.   wireless_(ws) 
  128. {
  129.   setupDefaults();
  130.   src_ = src->num();
  131.   dst_ = dst->num();
  132.   start_ = src;
  133.   neighbor_ = dst;
  134.   paint_ = Paint::instance()->thick();
  135.   if (length_ == 0) {
  136.     length_ = delay_;
  137.   }
  138. }
  139. //----------------------------------------------------------------------
  140. // void
  141. // Edge::setupDefaults()
  142. //----------------------------------------------------------------------
  143. void
  144. Edge::setupDefaults() {
  145. x0_ = 0.0;
  146. y0_ = 0.0;
  147. state_ = UP;
  148. packets_ = NULL;
  149. no_of_packets_ = 0;
  150. last_packet_ = NULL;
  151. marked_ = 0;
  152. visible_ = 1;
  153. dlabel_ = NULL;
  154. dcolor_ = NULL;
  155. direction_ = 0;
  156. used_ = 0;
  157. // Set initial (x0,y0), (x1,y1) so that they reflect the current 
  158. // angle. This enables netmodel to share the same placeEdge() and
  159. // placeAgent() with AutoNetModel.
  160. SINCOSPI(angle_, &x1_, &y1_);
  161. lossmodel_ = NULL;
  162. queue_handle_ = NULL;
  163. }
  164. //----------------------------------------------------------------------
  165. //----------------------------------------------------------------------
  166. Edge::~Edge() {
  167.   if (queue_handle_) {
  168.     delete queue_handle_;
  169.   }
  170. }
  171. //----------------------------------------------------------------------
  172. // void
  173. // Edge::attachNodes(Node * source, Node * destination)
  174. //----------------------------------------------------------------------
  175. void
  176. Edge::attachNodes(Node * source, Node * destination) {
  177.   src_ = source->num();
  178.   dst_ = destination->num();
  179.   start_ = source;
  180.   neighbor_ = destination;
  181.   if (length_ == 0) {
  182.     length_ = delay_;
  183.   }
  184.   start_->add_link(this);
  185. }
  186. //----------------------------------------------------------------------
  187. // void
  188. // Edge::addLossModel(LossModel * lossmodel)
  189. //----------------------------------------------------------------------
  190. void
  191. Edge::addLossModel(LossModel * lossmodel) {
  192. if (!lossmodel_) {
  193. lossmodel_ = lossmodel;
  194. lossmodel_->attachTo(this);
  195. lossmodel_->place();
  196. }
  197. }
  198. //----------------------------------------------------------------------
  199. //----------------------------------------------------------------------
  200. LossModel * 
  201. Edge::getLossModel() {
  202. return lossmodel_;
  203. }
  204. //----------------------------------------------------------------------
  205. //----------------------------------------------------------------------
  206. void
  207. Edge::clearLossModel() {
  208. // Delete previous loss model if it exists
  209. if (lossmodel_) {
  210. lossmodel_ = NULL;
  211. }
  212. }
  213. //----------------------------------------------------------------------
  214. //----------------------------------------------------------------------
  215. void
  216. Edge::addQueueHandle(QueueHandle * q_handle) {
  217. queue_handle_ = q_handle;
  218. queue_handle_->place();
  219. }
  220. //----------------------------------------------------------------------
  221. //----------------------------------------------------------------------
  222. float Edge::distance(float x, float y) const 
  223. {
  224. // TODO: Look it up when back home...
  225. matrix_.imap(x, y);
  226. return y;
  227. }
  228. //----------------------------------------------------------------------
  229. // inline double
  230. // Edge::delay() const
  231. //   - delay_ is stored in milliseconds
  232. //   - this function returns the delay in seconds
  233. //
  234. //   - look at tcl/netModel.tcl layout_link and layout_lan
  235. //     for the conversion to milliseconds
  236. //
  237. //   - delay_ is kept in milliseconds so that Edge::info()
  238. //     is displayed in millseconds and so that delay can be
  239. //     entered in milliseconds by the nam editor
  240. //
  241. //----------------------------------------------------------------------
  242. double
  243. Edge::delay() const {
  244. return (delay_/1000.0);
  245. void Edge::init_color(const char *clr)
  246. {
  247. color(clr);
  248.         dcolor(clr);
  249. oldPaint_ = paint_;
  250. }
  251. void Edge::set_down(char *color)
  252. {
  253. // If current color is down, don't change it again.
  254. // Assuming only one down color. User can change this behavior
  255. // by adding tcl code for link-up and link-down events.
  256. if (state_ == UP) {
  257. int pno = Paint::instance()->lookup(color, 3);
  258. oldPaint_ = paint_;
  259. paint_ = pno;
  260. state_ = DOWN;
  261. }
  262. }
  263. void Edge::set_up()
  264. {
  265. if (state_ == DOWN) {
  266. state_ = UP;
  267. toggle_color();
  268. }
  269. }
  270. void Edge::place(double x0, double y0, double x1, double y1)
  271. {
  272. x0_ = x0;
  273. y0_ = y0;
  274. x1_ = x1;
  275. y1_ = y1;
  276. double dx = x1 - x0;
  277. double dy = y1 - y0;
  278. /*XXX*/
  279. // delay should not be equal to edge's position
  280. // delay_ = sqrt(dx * dx + dy * dy);
  281. matrix_.clear();
  282. matrix_.rotate((180 / M_PI) * atan2(dy, dx));
  283. matrix_.translate(x0, y0);
  284.   if (x1>x0) {
  285.   bb_.xmin = x0; bb_.xmax = x1;
  286. } else {
  287.   bb_.xmin = x1; bb_.xmax = x0;
  288.   }
  289.   if (y1>y0) {
  290.   bb_.ymin = y0; bb_.ymax = y1;
  291.   } else {
  292.   bb_.ymin = y1; bb_.ymax = y0;
  293.   }
  294. eb_.xmin = -0.1 * start_->size();
  295. eb_.xmax = sqrt(dx*dx+dy*dy) + 0.1*neighbor_->size(); 
  296. eb_.ymin = -0.1 * start_->size();
  297.   eb_.ymax = 0.1 * start_->size();
  298. if (queue_handle_) {
  299.   queue_handle_->place();
  300. }
  301. if (lossmodel_) {
  302. lossmodel_->place();
  303. }
  304. }
  305. void Edge::AddPacket(Packet *p)
  306. {
  307. p->next(packets_);
  308. if (packets_!=NULL)
  309. packets_->prev(p);
  310. p->prev(NULL);
  311. packets_=p;
  312. if (last_packet_==NULL)
  313. last_packet_=p;
  314. no_of_packets_++;
  315. #define PARANOID
  316. #ifdef PARANOID
  317. int ctr=0;
  318. for(Packet *tp=packets_;tp!=NULL;tp=tp->next()) {
  319. ctr++;
  320. if (ctr>no_of_packets_) 
  321. abort();
  322. }
  323. if (last_packet_->next()!=NULL) 
  324. abort();
  325. #ifdef DEBUG
  326. printf("AddPacket: %d->%d OKn", src_, dst_);
  327. #endif
  328. #endif
  329. #undef PARANOID
  330. }
  331. void Edge::arrive_packet(Packet *p, double atime)
  332. {
  333. /*Trigger any arrival event at the node*/
  334. neighbor_->arrive_packet(p, this, atime);
  335. }
  336. void Edge::DeletePacket(Packet *p)
  337. {
  338. /*Trigger any deletion event at the node*/
  339. if (neighbor_)  neighbor_->delete_packet(p);
  340. else return ;
  341. no_of_packets_--;
  342. if (last_packet_==p) {
  343. /*Normal case - it's the last packet*/
  344. last_packet_ = p->prev();
  345. if (packets_!=p)
  346. p->prev()->next(NULL);
  347. else
  348. packets_=NULL;
  349. } else {
  350. /*Abnormal case - need to search the list*/
  351. Packet *tp;
  352. tp=packets_;
  353. while((tp!=p)&&(tp!=NULL)) {
  354. tp=tp->next();
  355. }
  356. if (tp==p) {
  357. if (tp==packets_)
  358. /*it was the first packet*/
  359. packets_=tp->next();
  360. else
  361. tp->prev()->next(tp->next());
  362. if (tp==last_packet_) {
  363. /*this shouldn't ever happen*/
  364. fprintf(stderr, "**it happenedn");
  365. last_packet_=tp->prev();
  366. } else
  367. tp->next()->prev(tp->prev());
  368. }
  369. }
  370. #define PARANOID
  371. #ifdef PARANOID
  372. int ctr=0;
  373. for(Packet *tp=packets_;tp!=NULL;tp=tp->next()) {
  374. ctr++;
  375. if (ctr>no_of_packets_) abort();
  376. }
  377. if ((last_packet_!=NULL)&&(last_packet_->next()!=NULL)) abort();
  378. #ifdef DEBUG
  379. printf("DeletePacket: %d->%d OKn", src_, dst_);
  380. #endif
  381. #endif
  382. #undef PARANOID
  383. }
  384. void Edge::dlabel(const char* name)
  385. {
  386.         if (name[0] == 0) {
  387.                 if (dlabel_) {
  388.                         delete []dlabel_;
  389.                         dlabel_ = 0;
  390.                 }
  391.                 return;
  392.         }
  393.         if (dlabel_)
  394.                 delete []dlabel_;
  395.         dlabel_ = new char[strlen(name) + 1];
  396.         strcpy(dlabel_, name);
  397. }
  398. void Edge::dcolor(const char* name)
  399. {
  400.   if (name[0] == 0) {
  401.     if (dcolor_) {
  402.                         delete []dcolor_;
  403.                         dcolor_ = 0;
  404.     }
  405.                 return;
  406.   }
  407.         if (dcolor_)
  408.                 delete []dcolor_;
  409.         dcolor_ = new char[strlen(name) + 1];
  410.         strcpy(dcolor_, name);
  411. }
  412. void Edge::direction(const char* name)
  413. {
  414. if (name[0] == 0) {
  415. if (direction_)  
  416. direction_ = 0;
  417. return;
  418. }
  419.         if (!strcmp(name, "SOUTH"))          direction_ = 1;
  420.         else if (!strcmp(name, "NORTH"))     direction_ = 2;
  421.         else if (!strcmp(name, "EAST"))      direction_ = 3;
  422.         else if (!strcmp(name, "WEST"))      direction_ = 4;
  423.         else                                 direction_ = 2;
  424. }
  425. void Edge::draw(View* view, double now) {
  426.   if (visible()) {
  427.    view->line(x0_, y0_, x1_, y1_, paint_);
  428. }
  429. if (monitor_!=NULL)
  430.   monitor_->draw(view, (x0_+x1_)/2, (y0_+y1_)/2);
  431.         if (dlabel_ == 0) 
  432. return;
  433. // Draw dynamic label
  434. switch (direction_) {
  435. case 0:
  436. view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, 
  437.      psize_*2.3, dlabel_, direction_, dcolor_);
  438. break;
  439. case 1:
  440. view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0-psize_*1.5, 
  441.      psize_*2.3, dlabel_, direction_, dcolor_);
  442. break;
  443. case 2:
  444. view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, 
  445.      psize_*2.3, dlabel_, direction_, dcolor_);
  446. break;
  447. case 3:
  448. view->string((x0_+x1_)/2.0-psize_*1.5, (y0_+y1_)/2.0, 
  449.      psize_*2.3, dlabel_, direction_, dcolor_);
  450. break;
  451. case 4:
  452. view->string((x0_+x1_)/2.0+psize_*1.5, (y0_+y1_)/2.0, 
  453.      psize_*2.3, dlabel_, direction_, dcolor_);
  454. break;
  455. default:
  456. view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, 
  457.      psize_*2.3, dlabel_, direction_, dcolor_);
  458. break;
  459. }
  460. }
  461. void Edge::reset(double)
  462. {
  463. // paint_ = Paint::instance()->thick();
  464. no_of_packets_=0;
  465. packets_=NULL;
  466. last_packet_=NULL;
  467. }
  468. int Edge::inside(double, float px, float py) const
  469. {
  470. // matrix_.imap(px, py);
  471. // return eb_.inside(px, py);
  472. return inside(px, py);
  473. }
  474. int Edge::inside(float px, float py) const
  475. {
  476. matrix_.imap(px, py);
  477. return eb_.inside(px, py);
  478. }
  479. const char* Edge::info() const
  480. {
  481. static char text[128];
  482. sprintf(text, "Link: %d<->%dn  Bandwidth: %g Mbits/secn  Delay: %g msn",
  483. src_, dst_, bandwidth_, delay_);
  484. return (text);
  485. }
  486. const char* Edge::property() {
  487.   rgb *color;
  488.   color=Paint::instance()->paint_to_rgb(paint_);
  489.  
  490.   static char text[256];
  491.   char *p;
  492.  
  493.   // object type and id
  494.   p = text;
  495.   if (!wireless_) {
  496.     sprintf(text, "{"Link %d-%d" title title "Link %d-%d"} ", 
  497.     src_, dst_, src_, dst_);
  498.   } else {
  499.     sprintf(text, "{"Wireless Link %d-%d" title title "Wireless Link %d-%d"} ", 
  500.     src_, dst_, src_, dst_);
  501.   }
  502.   p = &text[strlen(text)];
  503.   sprintf(p, "{Color color_ color %s} ", color->colorname); // color & value
  504.   // label
  505.   p = &text[strlen(text)];
  506.   if (dlabel_) {
  507.     sprintf(p, "{Label dlabel_ text %s} ", dlabel_); 
  508.   } else {
  509.     sprintf(p, "{Label dlabel_ text  } "); 
  510.   }
  511.   
  512.   //p = &text[strlen(text)];
  513.   //sprintf(p, "{LABEL-DIRECTION %d} ", direction_); // label-direction $ value
  514.   
  515.   // Link Bandwidth
  516.   p = &text[strlen(text)];
  517.   sprintf(p, "{"Bandwidth (Mbits per second)" bandwidth_ text %-f} ", bandwidth_);
  518.   // Link Delay
  519.   p = &text[strlen(text)];
  520.   sprintf(p, "{"Delay (ms)" delay_ text %-f} ", delay_);
  521.   return(text);
  522. }
  523. const char* Edge::getname() const
  524. {
  525. static char text[128];
  526. sprintf(text, "l %d %d",
  527. src_, dst_);
  528. return (text);
  529. }
  530. void Edge::monitor(Monitor *m, double /*now*/, char *result, int /*len*/)
  531. {
  532. monitor_=m;
  533. sprintf(result, "link %d-%d:n bw: %g Mbits/secn delay: %g ms",
  534. src_, dst_, bandwidth_, delay_);
  535. return;
  536. }
  537. int Edge::save(FILE *file)
  538. {
  539. rgb *color;
  540. color=Paint::instance()->paint_to_rgb(paint_);
  541. char state[10];
  542. double angle,length;
  543. float dx,dy;
  544. //Edges in the tracefile are bidirectional, so don't need to save
  545. //both unidirectional edges
  546. if (src_>dst_) return 0;
  547. if (state_==UP)
  548. strcpy(state, " -S UP");
  549. else if (state_==DOWN)
  550. strcpy(state, " -S DOWN");
  551. else
  552. state[0]='';
  553. if (angle_<0)
  554. angle=180*(angle_+2*M_PI)/M_PI;
  555. else
  556. angle=180*(angle_/M_PI);
  557. dx=x0_-x1_;
  558. dy=y0_-y1_;
  559. length=sqrt(dx*dx+dy*dy);
  560. //  printf("%d->%d, angle=%f (%fdeg)n", src_, dst_, angle_, angle);
  561. fprintf(file, "l -t * -s %d -d %d -r %f -D %f -c %s -o %.1fdeg -l %f%sn", 
  562. src_, dst_, bandwidth_, delay_, color->colorname,angle, length, state);
  563. return 0;
  564. }
  565. int Edge::saveAsEnam(FILE *file)
  566. {
  567. rgb *color;
  568. color=Paint::instance()->paint_to_rgb(paint_);
  569. char state[10];
  570. double angle,length;
  571. float dx,dy;
  572. // XXX Should never set edge size outside scale_estimate()!!!!
  573. //    psize_ = 25.0;
  574. // Edges in the tracefile are bidirectional, so don't need to save
  575. // both unidirectional edges
  576. if (src_>dst_) return 0; 
  577.  
  578. if (state_==UP)
  579. strcpy(state, " -S UP");
  580. else if (state_==DOWN)
  581. strcpy(state, " -S DOWN");
  582. else
  583. state[0]='';
  584. if (angle_<0)
  585. angle=180*(angle_+2*M_PI)/M_PI;
  586. else
  587. angle=180*(angle_/M_PI);
  588. dx=x0_-x1_;
  589. dy=y0_-y1_;
  590. length=sqrt(dx*dx+dy*dy);
  591. //  printf("%d->%d, angle=%f (%fdeg)n", src_, dst_, angle_, angle);
  592. fprintf(file, "##l -t * -s %d -d %d -r %f -D %f -c %s -o %.1fdeg -l %f%s -b %sn",
  593. src_, dst_, bandwidth_, delay_, color->colorname,angle, length, state, dlabel_);
  594. return 0;
  595. }
  596. //----------------------------------------------------------------------
  597. // int
  598. // Edge::writeNsScript(FILE *file)
  599. //   - Edges in the tracefile are bidirectional, so don't need to save
  600. //     both unidirectional edges
  601. //----------------------------------------------------------------------
  602. int
  603. Edge::writeNsScript(FILE *file) {
  604.   rgb *color;
  605.   double angle,length;
  606.   float dx,dy;
  607.   color = Paint::instance()->paint_to_rgb(paint_); 
  608.   if (angle_ < 0) { 
  609.      angle = 180 * (angle_ + 2 * M_PI) / M_PI;
  610.    } else {
  611.      angle = 180 * (angle_ / M_PI);
  612.    }
  613.    dx = x0_ - x1_;
  614.    dy = y0_ - y1_;
  615.    length = sqrt(dx * dx + dy * dy);
  616.    // Create the link
  617.    if (queue_handle_) {
  618.      //fprintf(file, "$ns simplex-link $node(%d) $node(%d) %f %f DropTailn",
  619.      fprintf(file, "$ns simplex-link $node(%d) $node(%d) %fMb %fms %sn",
  620.                     src_, dst_, bandwidth_, delay_, queue_handle_->name());
  621.    } else {
  622.      fprintf(file, "$ns simplex-link $node(%d) $node(%d) %fMb %fms DropTailn",
  623.                     src_, dst_, bandwidth_, delay_);
  624.    }
  625.    // Add a packet queue
  626.    fprintf(file, "$ns simplex-link-op $node(%d) $node(%d) queuePos 0.5n",
  627.                   src_, dst_);
  628.    // Set different options for the link
  629.    // - Color
  630.    fprintf(file, "$ns simplex-link-op $node(%d) $node(%d) color %sn",
  631.                   src_, dst_, color->colorname);
  632.    // - Orientation
  633.    fprintf(file, "$ns simplex-link-op $node(%d) $node(%d) orient %.1fdegn",
  634.                   src_, dst_, angle);
  635.    
  636.    if (dlabel_){
  637.      // - label
  638.      fprintf(file, "$ns simplex-link-op $node(%d) $node(%d) label %sn",
  639.                     src_, dst_, dlabel_);
  640.    }
  641.    if (direction_!=0) {
  642.      // - label orientation
  643.      fprintf(file, "$ns simplex-link-op $node(%d) $node(%d) label-at %dn",
  644.                     src_, dst_, direction_);
  645.    }
  646.    if (queue_handle_) {
  647.      queue_handle_->writeNsScript(file);
  648.    }
  649.    fprintf(file, "n");
  650.   return 0;
  651. }