⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp-sock.cc

📁 升级版的p2p文件共享linux环境ns2仿真软件
💻 CC
📖 第 1 页 / 共 3 页
字号:
/*-------------------------------------------------------------------------*//* SocketTcp: subclass of AdvwTcpAgent that implements the services        *//* provided by real system TCP socket, e.g.,                               *//*      limited sender buffer,                                             *//*      spawning new connections on request,                               *//*      real payload transfer.                                             */ /* Author: Qi He <http://www.cc.gatech.edu/~qhe> 01Aug2003                 *//* $Revision:$ $Name:$ $Date:$                                             *//*-------------------------------------------------------------------------*/#include "tcp-sock.h"#include "ip.h"#include "flags.h"#include "nssocket.h"#ifdef PDNSextern NsObject* GetLocalIP(ipaddr_t ipaddr);#endif#define MIN(a, b)	((a) < (b) ? (a) : (b))static int pfcnt=0, pdfcnt=0, pcnt=0, opcnt=0, apcnt=0, dropcnt=0;static class SocketTcpClass: public TclClass {public:	SocketTcpClass(): TclClass("Agent/TCP/FullTcp/AdvwTcp/SocketTcp") {}	TclObject* create(int, const char*const*argv) {		return (new SocketTcp());	}} class_socket_tcp;PktDataEntry::PktDataEntry(int seqno, PacketData *p) {  key_ = seqno;  if(p)    pktdata_ = (PacketData *)p->copy();   else    pktdata_ = NULL;}SocketTcp::SocketTcp(): AdvwTcpAgent() {	bind("inf_rcv_", &infinite_rcv_);	bind("snd_wnd_", &snd_wnd_);	listen_only_ = FALSE; }int SocketTcp::command(int argc, const char*const* argv) {	if(argc==3) {		if(strcmp(argv[1], "listen")==0) {			listen(atoi(argv[2]));			return TCL_OK;		}		if(strcmp(argv[1], "send-dummy")==0) {			send_dummy(atoi(argv[2]));			return TCL_OK;		}	}	return AdvwTcpAgent::command(argc, argv);}	int SocketTcp::send_dummy(int nbytes) {	PacketData *p = new PacketData(nbytes);	sendmsg(p, nbytes);	}int SocketTcp::sendmsg(PacketData *p, int len) {  int res;  res = r_sendmsg(p, 0);  if(p)    delete p;  return res;}int SocketTcp::r_send(int bytes) {  return r_sendmsg(bytes, NULL);}int SocketTcp::r_send(PacketData *p) {  return r_sendmsg(p, 0);}int SocketTcp::r_sendmsg(int nbytes, const char *flags = 0) {	if (flags && strcmp(flags, "MSG_EOF") == 0) 		close_on_empty_ = TRUE;	if (nbytes == -1) {		infinite_send_ = TRUE;		return r_advance_bytes(0);	} else		return r_advance_bytes(nbytes);}int SocketTcp::r_sendmsg(PacketData *p, const char *flags = 0 ) {	if (flags && strcmp(flags, "MSG_EOF") == 0) 		close_on_empty_ = TRUE;		return r_advance_pkt(p);}void SocketTcp::newack(Packet* pkt){	hdr_tcp *tcph = hdr_tcp::access(pkt);	register int ackno = tcph->ackno();	int progress = (ackno > highest_ack_);	if (ackno == maxseq_) {		cancel_rtx_timer();	// all data ACKd	} else if (progress) {		set_rtx_timer();	}	//advance the ack number if this is for new data	if (progress) {		highest_ack_ = ackno;		Islist_iter<PktDataEntry> pkt_iter(snd_buf_);		PktDataEntry *cur, *last=NULL;		while((cur=pkt_iter())!=NULL) {		  if(cur->key_ < ackno) {		    delete cur->pktdata_;		    snd_buf_.remove(cur, last);		  } else		    break;		}		if(app_) {		  ((NSSocket *)app_)->upcall_send();		}	}	// if we have suffered a retransmit timeout, t_seqno_	// will have been reset to highest_ ack.  If the	// receiver has cached some data above t_seqno_, the	// new-ack value could (should) jump forward.  We must	// update t_seqno_ here, otherwise we would be doing	// go-back-n.	if (t_seqno_ < highest_ack_)		t_seqno_ = highest_ack_; // seq# to send next        /*         * Update RTT only if it's OK to do so from info in the flags header.         * This is needed for protocols in which intermediate agents         * in the network intersperse acks (e.g., ack-reconstructors) for         * various reasons (without violating e2e semantics).         */        hdr_flags *fh = hdr_flags::access(pkt);        if (!fh->no_ts_) {                if (ts_option_) {			recent_age_ = now();			recent_ = tcph->ts();                        rtt_update(now() - tcph->ts_echo());		} else if (rtt_active_ && ackno > rtt_seq_) {			// got an RTT sample, record it                        t_backoff_ = 1;                        rtt_active_ = FALSE;			rtt_update(now() - rtt_ts_);                }        } else {		printf("no_ts\n");	}	return;}int SocketTcp::foutput(int seqno, int reason){	int quiet = (highest_ack_ == maxseq_);	int pflags = outflags();	int syn = (seqno == iss_);	int emptying_buffer = FALSE;	int win = window() * maxseg_;	// window (in bytes)	int datalen;	PacketData *data = NULL;	PktDataEntry *pe = snd_buf_.find(seqno);	if(pe) {	  data = pe->pktdata_;	}	if ((syn && !data_on_syn_) || pe==NULL || data==NULL) 	  datalen = 0;	else	  datalen = data->size();	//	// this is an option that causes us to slow-start if we've	// been idle for a "long" time, where long means a rto or longer	// the slow-start is a sort that does not set ssthresh	//	if (slow_start_restart_ && quiet && datalen > 0) {		if (idle_restart()) {			slowdown(CLOSE_CWND_INIT);		}	}	//	// see if sending this packet will empty the send buffer	// a dataless SYN packet counts also	//	if (!infinite_send_ && ((seqno + datalen) > curseq_ || 	    (syn && datalen == 0))) {		emptying_buffer = TRUE;		//		// if not a retransmission, notify application that 		// everything has been sent out at least once.		//		if (!syn) {			idle();			if (close_on_empty_ && quiet) {				flags_ |= TF_NEEDCLOSE;			}		}		pflags |= TH_PUSH;		//		// if close_on_empty set, we are finished		// with this connection; close it		//	} else  {		/* not emptying buffer, so can't be FIN */		pflags &= ~TH_FIN;	}	pflags |= TH_PUSH;	/* sender SWS avoidance (Nagle) */send:	syn = (pflags & TH_SYN) ? 1 : 0;	int fin = (pflags & TH_FIN) ? 1 : 0;	sendpacket(seqno, rcv_nxt_, pflags, datalen, data, reason);        /*               * Data sent (as far as we can tell).         * Any pending ACK has now been sent.         */      	flags_ &= ~(TF_ACKNOW|TF_DELACK);	/*	 * if we have reacted to congestion recently, the	 * slowdown() procedure will have set cong_action_ and	 * sendpacket will have copied that to the outgoing pkt	 * CACT field. If that packet contains data, then	 * it will be reliably delivered, so we are free to turn off the	 * cong_action_ state now  If only a pure ACK, we keep the state	 * around until we actually send a segment	 */	int reliable = datalen + syn + fin; // seq #'s reliably sent	if (cong_action_ && reliable > 0)		cong_action_ = FALSE;	/*	 * SYNs and FINs each use up one sequence number, but	 * there's no reason to advance t_seqno_ by one for a FIN	 */	if (!fin && seqno == t_seqno_) {		t_seqno_ += reliable;	}	// highest: greatest sequence number sent + 1	//	and adjusted for SYNs and FINs which use up one number	int highest = seqno + reliable;	if (highest > maxseq_) {		maxseq_ = highest;		//		// if we are using conventional RTT estimation,		// establish timing on this segment		//		if (!ts_option_ && rtt_active_ == FALSE) {			rtt_active_ = TRUE;	// set timer			rtt_seq_ = seqno; 	// timed seq #			rtt_ts_ = now();	// when set		}	}	/*	 * Set retransmit timer if not currently set,	 * and not doing an ack or a keep-alive probe.	 * Initial value for retransmit timer is smoothed	 * round-trip time + 2 * round-trip time variance.	 * Future values are rtt + 4 * rttvar.	 */	if (rtx_timer_.status() != TIMER_PENDING && reliable) {		set_rtx_timer();  // no timer pending, schedule one	}	if (flags_ & TF_NEEDCLOSE) {		flags_ &= ~TF_NEEDCLOSE;		if (state_ <= TCPS_ESTABLISHED && state_ != TCPS_CLOSED)			usrclosed();	}	return reliable;}void SocketTcp::recvBytes(int nbytes){        int rcv_buf_free, byte_read=0, seqno, acksent = FALSE;	PktDataEntry *cur, *last=NULL;	PacketData *pkt;	num_bytes_avail_ += nbytes;	Islist_iter<PktDataEntry> pkt_iter(rcv_buf_);	while(((cur=pkt_iter())!=NULL) && num_bytes_avail_ > 0) {	  pkt = cur->pktdata_;	  	  if(app_) {	    if(pkt==NULL) {	      printf("ERROR: Rcv Buffer Entry without Pkt\n");	      break;	    }   	    byte_read = ((NSSocket*)app_)->upcall_recv(pkt);	  } else	    byte_read = pkt->size();	  if(byte_read==0) 	    break;	  num_bytes_avail_ -= byte_read;	  num_bytes_req_ -= byte_read;	  if (byte_read > 0) {	    delete pkt;	    rcv_buf_.remove(cur, last);	  }		  if(num_bytes_avail_<0) {	    fprintf(stderr,"SocketTcp::recvBytes(): agent %d %d num_bytes_avail_ %d < 0\n", here_.addr_, here_.port_, num_bytes_avail_);	    break;	  }		  rcv_buf_free = rcv_buff_ - num_bytes_avail_;	  if(rcv_buf_free >= rcv_wnd_ + MIN (rcv_buff_/2, maxseg_) && !acksent){	    rcv_wnd_ = rcv_buf_free;	    acksent = TRUE;	    sendpacket(0, rcv_nxt_, TH_ACK, 0, NULL, REASON_NORMAL);	  }	};}void SocketTcp::insert(Islist<PktDataEntry> *list, PktDataEntry *pe) {  Islist_iter<PktDataEntry> pkt_iter(*list);  PktDataEntry *last=NULL, *cur;    while((cur=pkt_iter())!=NULL && cur->key_ < pe->key_) {    last = cur;  };    if(last!=NULL) {    if(cur==NULL) {      list->append(pe);      return;    }    if(cur->key_==pe->key_) {      free(pe);      return;     }    pe->next_ = last->next_;     last->next_ = pe;  } else {    if(cur && cur->key_==pe->key_) {      free(pe);      return;    }    list->insert(pe);  }}void SocketTcp::recv(Packet *pkt, Handler* handler){       if(handler) { 	 int nb = ((PacketData *)pkt->userdata())->size();	 if(r_send(((PacketData *)pkt->userdata()))>0)	   handler->handle(NULL);	 return;       }        hdr_ip *iph = hdr_ip::access(pkt);  	hdr_tcp *tcph = hdr_tcp::access(pkt);	hdr_cmn *th = hdr_cmn::access(pkt);	hdr_flags *fh = hdr_flags::access(pkt);	int needoutput = FALSE;	int ourfinisacked = FALSE;	int dupseg = FALSE;	int todrop = 0;	last_state_ = state_;	int datalen = th->size() - tcph->hlen(); // # payload bytes	int ackno = tcph->ackno();		 // ack # from packet	int tiflags = tcph->flags() ; 		 // tcp flags from packet		if (state_ == TCPS_CLOSED)		goto drop;	if (state_ != TCPS_LISTEN)		dooptions(pkt);	if(!listen_only_) {	  if (delack_interval_ > 0.0 &&	      (delack_timer_.status() != TIMER_PENDING)) {	    int last = int(now() / delack_interval_);	    delack_timer_.resched(delack_interval_ * (last + 1.0) - now());	  }	}	wnd_ = (double)tcph->advwin()/(double)size_;	if (fh->ce() && !fh->ect()) {	    fprintf(stderr,	    "%f: FullTcpAgent::recv(%s): warning: CE bit on, but ECT false!\n",		now(), name());	}	if(listen_only_ && state_ != TCPS_LISTEN) {	  printf("listening socket not in TCPS_LISTEN\n");	  return;	} 	switch (state_) {        /*         * If the segment contains an ACK then it is bad and do reset.         * If it does not contain a SYN then it is not interesting; drop it.         * Otherwise initialize tp->rcv_nxt, and tp->irs, iss is already	 * selected, and send a segment:         *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>         * Initialize tp->snd_nxt to tp->iss.         * Enter SYN_RECEIVED state, and process any other fields of this         * segment in this state.         */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -