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

通讯编程

开发平台:

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 Research Group may be
  19.  *    used 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/tcp/tcp-session.cc,v 1.18 2000/09/01 03:04:07 haoboy Exp $
  35.  */
  36. #include <stdlib.h>
  37. #include <math.h>
  38. #include "ip.h"
  39. #include "flags.h"
  40. #include "random.h"
  41. #include "template.h"
  42. #include "nilist.h"
  43. #include "tcp.h"
  44. #include "tcp-int.h"
  45. #include "tcp-session.h"
  46. /*
  47.  * We separate TCP functionality into two parts: that having to do with 
  48.  * providing a reliable, ordered byte-stream service, and that having to do with
  49.  * congestion control and loss recovery. The former is done on a per-connection
  50.  * basis and is implemented as part of IntTcpAgent ("integrated TCP"). The 
  51.  * latter is done in an integrated fashion across multiple TCP connections, and
  52.  * is implemented as part of TcpSessionAgent ("TCP session"). TcpSessionAgent is
  53.  * derived from CorresHost ("correspondent host"), which keeps track of the 
  54.  * state of all TCP (TCP/Int) connections to a host that it is corresponding 
  55.  * with.
  56.  *
  57.  * The motivation for this separation of functionality is to make an ensemble of
  58.  * connection more well-behaved than a set of independent TCP connections.
  59.  * The packet loss rate is cut down and the chances of losses being recovered 
  60.  * via data-driven techniques (rather than via timeouts) is improved. At the 
  61.  * same time, we do not introduce any unnecessary coupling between the 
  62.  * logically-independent byte-streams that the set of connections represents. 
  63.  * This is in contrast to the coupling that is inherent in the multiplexing at 
  64.  * the application layer of multiple byte-streams onto a single TCP connection.
  65.  *
  66.  * For questions/comments, please contact:
  67.  *   Venkata N. Padmanabhan (padmanab@cs.berkeley.edu)
  68.  *   http://www.cs.berkeley.edu/~padmanab
  69.  */
  70. static class TcpSessionClass : public TclClass {
  71. public:
  72. TcpSessionClass() : TclClass("Agent/TCP/Session") {}
  73. TclObject* create(int, const char*const*) {
  74. return (new TcpSessionAgent()); 
  75. }
  76. } class_tcpsession;
  77. TcpSessionAgent::TcpSessionAgent() : CorresHost(), 
  78. rtx_timer_(this), burstsnd_timer_(this), sessionSeqno_(0),
  79. last_send_time_(-1), curConn_(0), numConsecSegs_(0), 
  80. schedDisp_(FINE_ROUND_ROBIN), wtSum_(0), dynWtSum_(0) 
  81. {
  82. bind("ownd_", &ownd_);
  83. bind("owndCorr_", &owndCorrection_);
  84. bind_bool("proxyopt_", &proxyopt_);
  85. bind_bool("fixedIw_", &fixedIw_);
  86. bind("schedDisp_", &schedDisp_);
  87. bind_bool("disableIntLossRecov_", &disableIntLossRecov_);
  88. sessionList_.append(this);
  89. }
  90. int
  91. TcpSessionAgent::command(int argc, const char*const* argv)
  92. {
  93. if (argc == 2) {
  94. if (!strcmp(argv[1], "resetwt")) {
  95. Islist_iter<IntTcpAgent> conn_iter(conns_);
  96. IntTcpAgent *tcp;
  97. while ((tcp = conn_iter()) != NULL) 
  98. tcp->wt_ = 1;
  99. wtSum_ = conn_iter.count();
  100. return (TCL_OK);
  101. }
  102. }
  103. return (CorresHost::command(argc, argv));
  104. }
  105. void
  106. SessionRtxTimer::expire(Event*)
  107. {
  108. a_->timeout(TCP_TIMER_RTX);
  109. }
  110. void
  111. SessionResetTimer::expire(Event*)
  112. {
  113. a_->timeout(TCP_TIMER_RESET);
  114. }
  115. void
  116. SessionBurstSndTimer::expire(Event*)
  117. {
  118. a_->timeout(TCP_TIMER_BURSTSND);
  119. }
  120. void
  121. TcpSessionAgent::reset_rtx_timer(int /*mild*/, int backoff)
  122. {
  123. if (backoff)
  124. rtt_backoff();
  125. set_rtx_timer();
  126. rtt_active_ = 0;
  127. }
  128. void
  129. TcpSessionAgent::set_rtx_timer()
  130. {
  131. if (rtx_timer_.status() == TIMER_PENDING)
  132. rtx_timer_.cancel();
  133. if (reset_timer_.status() == TIMER_PENDING)
  134. reset_timer_.cancel();
  135. if (fs_enable_ && fs_mode_)
  136. reset_timer_.resched(rtt_exact_timeout());
  137. else
  138. rtx_timer_.resched(rtt_timeout());
  139. }
  140. void
  141. TcpSessionAgent::cancel_rtx_timer()
  142. {
  143. rtx_timer_.force_cancel();
  144. reset_timer_.force_cancel();
  145. }
  146. void
  147. TcpSessionAgent::cancel_timers()
  148. {
  149. rtx_timer_.force_cancel();
  150. reset_timer_.force_cancel();
  151. burstsnd_timer_.force_cancel();
  152. delsnd_timer_.force_cancel();
  153. }
  154. int
  155. TcpSessionAgent::fs_pkt() {
  156. return (fs_enable_ && fs_mode_ && sessionSeqno_-1 >= fs_startseq_ &&
  157. sessionSeqno_-1 < fs_endseq_);
  158. }
  159. void
  160. TcpSessionAgent::rtt_update_exact(double tao)
  161. {
  162. double g = 1/8; /* gain used for smoothing rtt */
  163. double h = 1/4; /* gain used for smoothing rttvar */
  164. double delta;
  165. if (t_exact_srtt_ != 0) {
  166. delta = tao - t_exact_srtt_;
  167. if (delta < 0)
  168. delta = -delta;
  169. /* update the fine-grained estimate of the smoothed RTT */
  170. if (t_exact_srtt_ != 0) 
  171. t_exact_srtt_ = g*tao + (1-g)*t_exact_srtt_;
  172. else
  173. t_exact_srtt_ = tao;
  174. /* update the fine-grained estimate of mean deviation in RTT */
  175. delta -= t_exact_rttvar_;
  176. t_exact_rttvar_ += h*delta;
  177. }
  178. else {
  179. t_exact_srtt_ = tao;
  180. t_exact_rttvar_ = tao/2;
  181. }
  182. }
  183. void
  184. TcpSessionAgent::newack(Packet *pkt) 
  185. {
  186. double now = Scheduler::instance().clock();
  187. Islist_iter<Segment> seg_iter(seglist_);
  188. hdr_tcp *tcph = hdr_tcp::access(pkt);
  189. hdr_flags *fh = hdr_flags::access(pkt);
  190. if (!fh->no_ts_) {
  191. /* if the timestamp option is being used */
  192. if (ts_option_) {
  193. rtt_update(now - tcph->ts_echo());
  194. rtt_update_exact(now - tcph->ts_echo());
  195. }
  196. /* if segment being timed just got acked */
  197. if (rtt_active_ && rtt_seg_ == NULL) {
  198. t_backoff_ = 1;
  199. rtt_active_ = 0;
  200. if (!ts_option_)
  201. rtt_update(now - rtt_ts_);
  202. }
  203. }
  204. if (seg_iter.count() > 0)
  205. set_rtx_timer();
  206. else
  207. cancel_rtx_timer();
  208. }
  209. void
  210. TcpSessionAgent::timeout(int tno)
  211. {
  212. if (tno == TCP_TIMER_BURSTSND)
  213. send_much(NULL,0,0);
  214. else if (tno == TCP_TIMER_RESET) {
  215. Islist_iter<Segment> seg_iter(seglist_);
  216. Segment *curseg;
  217. Islist_iter<IntTcpAgent> conn_iter(conns_);
  218. IntTcpAgent *curconn;
  219. fs_mode_ = 0;
  220. if (seg_iter.count() == 0 && !slow_start_restart_) {
  221. return;
  222. }
  223. recover_ = sessionSeqno_ - 1;
  224. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  225. ownd_ = 0;
  226. owndCorrection_ = 0;
  227. while ((curconn = conn_iter()) != NULL) {
  228. curconn->maxseq_ = curconn->highest_ack_;
  229. curconn->t_seqno_ = curconn->highest_ack_ + 1;
  230. curconn->recover_ = curconn->maxseq_;
  231. curconn->last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  232. }
  233. while ((curseg = seg_iter()) != NULL) {
  234. /* XXX exclude packets sent "recently"? */
  235. curseg->size_ = 0;
  236. }
  237. /* 
  238.  * If first pkt sent before fast start has not gotten through, 
  239.  * treat this as a regular rtx timeout. Otherwise, close cwnd
  240.  * and reset timer but don't back off timer.
  241.  */
  242. if (connWithPktBeforeFS_) {
  243. connWithPktBeforeFS_ = NULL;
  244. timeout(TCP_TIMER_RTX);
  245. }
  246. else {
  247. slowdown(CLOSE_CWND_INIT);
  248. reset_rtx_timer(0,0);
  249. send_much(NULL, 0, TCP_REASON_TIMEOUT);
  250. }
  251. }
  252. else if (tno == TCP_TIMER_RTX) {
  253. Islist_iter<Segment> seg_iter(seglist_);
  254. Segment *curseg;
  255. Islist_iter<IntTcpAgent> conn_iter(conns_);
  256. IntTcpAgent *curconn;
  257. if (seg_iter.count() == 0 && !slow_start_restart_) {
  258. return;
  259. }
  260. recover_ = sessionSeqno_ - 1;
  261. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  262. if (seg_iter.count() == 0 && restart_bugfix_) {
  263. slowdown(CLOSE_CWND_INIT);
  264. reset_rtx_timer(0,0);
  265. }
  266. else {
  267. slowdown(CLOSE_CWND_RESTART|CLOSE_SSTHRESH_HALF);
  268. reset_rtx_timer(0,1);
  269. }
  270. nrexmit_++;
  271. ownd_ = 0;
  272. owndCorrection_ = 0;
  273. while ((curconn = conn_iter()) != NULL) {
  274. curconn->t_seqno_ = curconn->highest_ack_ + 1;
  275. curconn->recover_ = curconn->maxseq_;
  276. curconn->last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  277. }
  278. while ((curseg = seg_iter()) != NULL) {
  279. /* XXX exclude packets sent "recently"? */
  280. curseg->size_ = 0;
  281. }
  282. send_much(NULL, 0, TCP_REASON_TIMEOUT);
  283. }
  284. else
  285. printf("TcpSessionAgent::timeout(): ignoring unknown timer %dn", tno);
  286. }
  287. Segment* 
  288. TcpSessionAgent::add_pkts(int size, int seqno, int sessionSeqno, int daddr, 
  289.   int dport, int sport, double ts, IntTcpAgent *sender)
  290. {
  291. /*
  292.  * set rtx timer afresh either if it is not set now or if there are no 
  293.  * data packets outstanding at this time
  294.  */
  295. if (!(rtx_timer_.status() == TIMER_PENDING) || seglist_.count() == 0)
  296. set_rtx_timer();
  297. last_seg_sent_ = CorresHost::add_pkts(size, seqno, sessionSeqno, daddr, dport, sport, ts, sender);
  298. return last_seg_sent_;
  299. }
  300. void
  301. TcpSessionAgent::add_agent(IntTcpAgent *agent, int size, double winMult, 
  302.    int winInc, int ssthresh)
  303. {
  304. CorresHost::add_agent(agent,size,winMult,winInc,ssthresh);
  305. wtSum_ += agent->wt_;
  306. reset_dyn_weights();
  307. }
  308. int
  309. TcpSessionAgent::window()
  310. {
  311. if (maxcwnd_ == 0)
  312. return (int(cwnd_));
  313. else
  314. return (int(min(cwnd_,maxcwnd_)));
  315. }
  316. void
  317. TcpSessionAgent::set_weight(IntTcpAgent *tcp, int wt)
  318. {
  319. wtSum_ -= tcp->wt_;
  320. tcp->wt_ = wt;
  321. wtSum_ += tcp->wt_;
  322. }
  323. void
  324. TcpSessionAgent::reset_dyn_weights()
  325. {
  326. IntTcpAgent *tcp;
  327. Islist_iter<IntTcpAgent> conn_iter(conns_);
  328. while ((tcp = conn_iter()) != NULL)
  329. tcp->dynWt_ = tcp->wt_;
  330. dynWtSum_ = wtSum_;
  331. }
  332. IntTcpAgent *
  333. TcpSessionAgent::who_to_snd(int how)
  334. {
  335. int i = 0;
  336. switch (how) {
  337. /* fine-grained interleaving of connections (per pkt) */
  338. case FINE_ROUND_ROBIN: { 
  339. IntTcpAgent *next;
  340. int wtOK = 0;
  341. if (dynWtSum_ == 0) 
  342. reset_dyn_weights();
  343. do {
  344. wtOK = 0;
  345. if ((next = (*connIter_)()) == NULL) {
  346. connIter_->set_cur(connIter_->get_last());
  347. next = (*connIter_)();
  348. }
  349. i++;
  350. if (next && next->dynWt_>0) {
  351. next->dynWt_--;
  352. dynWtSum_--;
  353. wtOK = 1;
  354. }
  355. } while (next && (!next->data_left_to_send() || !wtOK)
  356.  && (i < connIter_->count()));
  357. if (!next->data_left_to_send())
  358. next = NULL;
  359. return next;
  360. }
  361. /* coarse-grained interleaving across connections (per block of pkts) */
  362. case COARSE_ROUND_ROBIN: {
  363. int maxConsecSegs;
  364. if (curConn_)
  365. maxConsecSegs = (window()*curConn_->wt_)/wtSum_;
  366. if (curConn_ && numConsecSegs_++ < maxConsecSegs && 
  367. curConn_->data_left_to_send())
  368. return curConn_;
  369. else {
  370. numConsecSegs_ = 0;
  371. curConn_ = who_to_snd(FINE_ROUND_ROBIN);
  372. if (curConn_)
  373. numConsecSegs_++;
  374. }
  375. return curConn_;
  376. }
  377. case RANDOM: {
  378. IntTcpAgent *next;
  379. do {
  380. int foo = int(Random::uniform() * nActive_ + 1);
  381. connIter_->set_cur(connIter_->get_last());
  382. for (;foo > 0; foo--)
  383. (*connIter_)();
  384. next = (*connIter_)();
  385. } while (next && !next->data_left_to_send());
  386. return(next);
  387. }
  388. default:
  389. return NULL;
  390. }
  391. }
  392. void
  393. TcpSessionAgent::send_much(IntTcpAgent* /*agent*/, int force, int reason) 
  394. {
  395. int npackets = 0;
  396. Islist_iter<Segment> seg_iter(seglist_);
  397. if (reason != TCP_REASON_TIMEOUT &&
  398.     burstsnd_timer_.status() == TIMER_PENDING)
  399. return;
  400. /* no outstanding data and idle time >= t_rtxcur_ */
  401. if ((seg_iter.count() == 0) && (last_send_time_ != -1) &&
  402.     (Scheduler::instance().clock() - last_send_time_ >= t_rtxcur_)) {
  403. if (slow_start_restart_ && restart_bugfix_)
  404. slowdown(CLOSE_CWND_INIT);
  405. else if (slow_start_restart_)
  406. slowdown(CLOSE_CWND_RESTART|CLOSE_SSTHRESH_HALF);
  407. else if (fs_enable_) {
  408. if (cwnd_ < ssthresh_)
  409. cwnd_ = int(cwnd_/2);
  410. else
  411. cwnd_ -= 1;
  412. fs_startseq_ = sessionSeqno_ + 1;
  413. fs_endseq_ = sessionSeqno_ + window();
  414. fs_mode_ = 1;
  415. }
  416. }
  417. while (ok_to_snd(size_)) {
  418. {
  419. IntTcpAgent *sender = who_to_snd(schedDisp_);
  420. if (sender) {
  421. /*
  422.  * remember the connection over which the first
  423.  * packet just before fast start is sent
  424.  */
  425. if (fs_enable_ && fs_mode_ && 
  426.     sessionSeqno_ == fs_startseq_)
  427. connWithPktBeforeFS_ = sender;
  428. /* if retransmission */
  429. /* XXX we pick random conn even if rtx timeout */
  430. if (sender->t_seqno_ < sender->maxseq_) {
  431. int i = 
  432. findSessionSeqno(sender, sender->t_seqno_);
  433. removeSessionSeqno(i);
  434. sender->send_one(i);
  435. }
  436. else {
  437. sender->send_one(sessionSeqno_++);
  438. if (!rtt_active_) {
  439. rtt_active_ = 1;
  440. rtt_seg_ = last_seg_sent_;
  441. }
  442. }
  443. npackets++;
  444. }
  445. else
  446. break;
  447. }
  448. reason = 0;
  449. force = 0;
  450. if (maxburst_ && npackets == maxburst_) {
  451. if (ok_to_snd(size_))
  452. burstsnd_timer_.resched(t_exact_srtt_*maxburst_/window());
  453. break;
  454. }
  455. }
  456. if (npackets > 0)
  457. last_send_time_ = Scheduler::instance().clock();
  458. }
  459. void
  460. TcpSessionAgent::recv(IntTcpAgent *agent, Packet *pkt, int amt_data_acked)
  461. {
  462. hdr_tcp *tcph = hdr_tcp::access(pkt);
  463. if (hdr_flags::access(pkt)->ecnecho() && ecn_)
  464. quench(1, agent, tcph->seqno());
  465. clean_segs(size_, pkt, agent, sessionSeqno_,amt_data_acked);
  466. /* XXX okay to do this after clean_segs? */
  467. /* if new data acked and this is not a partial ack */
  468. if (amt_data_acked > 0 && (tcph->seqno() >= agent->recover_ ||
  469.    agent->last_cwnd_action_ != CWND_ACTION_DUPACK /* XXX 1*/) 
  470.     && !dontIncrCwnd_) {
  471. int i = count_bytes_acked_ ? amt_data_acked:1;
  472. while (i-- > 0)
  473. opencwnd(size_,agent);
  474. }
  475. dontIncrCwnd_ = 0;
  476. if (amt_data_acked > 0) {
  477. if (fs_enable_ && fs_mode_ && connWithPktBeforeFS_ == agent)
  478. connWithPktBeforeFS_ = NULL;
  479. newack(pkt);
  480. }
  481. Packet::free(pkt);
  482. send_much(NULL,0,0);
  483. }
  484. void
  485. TcpSessionAgent::setflags(Packet *pkt)
  486. {
  487. hdr_flags *hf = hdr_flags::access(pkt);
  488. if (ecn_)
  489. hf->ect() = 1;
  490. }
  491. int
  492. TcpSessionAgent::findSessionSeqno(IntTcpAgent *sender, int seqno)
  493. {
  494. Islist_iter<Segment> seg_iter(seglist_);
  495. Segment *cur;
  496. int min = sessionSeqno_;
  497. while ((cur = seg_iter()) != NULL) {
  498. if (sender == cur->sender_ && cur->seqno_ >= seqno && 
  499.     cur->sessionSeqno_ < min)
  500. min = cur->sessionSeqno_;
  501. }
  502. if (min == sessionSeqno_) {
  503. printf("In TcpSessionAgent::findSessionSeqno: search unsuccessfuln");
  504. min = sessionSeqno_ - 1;
  505. }
  506. return (min);
  507. }
  508. void
  509. TcpSessionAgent::removeSessionSeqno(int sessionSeqno) 
  510. {
  511. Islist_iter<Segment> seg_iter(seglist_);
  512. Segment *cur, *prev=NULL;
  513. while ((cur = seg_iter()) != NULL) {
  514. if (cur->sessionSeqno_ == sessionSeqno) {
  515. seglist_.remove(cur, prev);
  516. adjust_ownd(cur->size_);
  517. return;
  518. }
  519. prev = cur;
  520. }
  521. printf("In removeSessionSeqno(): unable to find segment with sessionSeqno = %dn", sessionSeqno);
  522. }
  523. void
  524. TcpSessionAgent::quench(int how, IntTcpAgent *sender, int seqno)
  525. {
  526. int i = findSessionSeqno(sender,seqno);
  527. if (i > recover_) {
  528. recover_ = sessionSeqno_ - 1;
  529. last_cwnd_action_ = CWND_ACTION_ECN;
  530. sender->recover_ = sender->maxseq_;
  531. sender->last_cwnd_action_ = CWND_ACTION_ECN;
  532. closecwnd(how,sender);
  533. }
  534. }
  535. void
  536. TcpSessionAgent::traceVar(TracedVar* v)
  537. {
  538. double curtime;
  539. Scheduler& s = Scheduler::instance();
  540. char wrk[500];
  541. int n;
  542. curtime = &s ? s.clock() : 0;
  543. if (!strcmp(v->name(), "ownd_") || !strcmp(v->name(), "owndCorr_")) {
  544. if (!strcmp(v->name(), "ownd_"))
  545. sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f", 
  546. curtime, addr(), port(), daddr(), dport(),
  547. v->name(), double(*((TracedDouble*) v))); 
  548. else if (!strcmp(v->name(), "owndCorr_"))
  549. sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %d", 
  550. curtime, addr(), port(), daddr(), dport(),
  551. v->name(), int(*((TracedInt*) v))); 
  552. n = strlen(wrk);
  553. wrk[n] = 'n';
  554. wrk[n+1] = 0;
  555. if (channel_)
  556. (void)Tcl_Write(channel_, wrk, n+1);
  557. wrk[n] = 0;
  558. }
  559. else
  560. TcpAgent::traceVar(v);
  561. }