Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ | |
2 /* | |
3 * Copyright (c) 2010 Adrian Sai-wah Tam | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License version 2 as | |
7 * published by the Free Software Foundation; | |
8 * | |
9 * This program is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with this program; if not, write to the Free Software | |
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
17 * | |
18 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com> | |
19 */ | |
20 | |
21 #define NS_LOG_APPEND_CONTEXT \ | |
22 if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_n ode->GetId () << "] "; } | |
23 | |
24 #include "ns3/abort.h" | |
25 #include "ns3/node.h" | |
26 #include "ns3/inet-socket-address.h" | |
27 #include "ns3/log.h" | |
28 #include "ns3/ipv4.h" | |
29 #include "ns3/ipv4-interface-address.h" | |
30 #include "ns3/ipv4-route.h" | |
31 #include "ns3/ipv4-routing-protocol.h" | |
32 #include "ns3/simulation-singleton.h" | |
33 #include "ns3/simulator.h" | |
34 #include "ns3/packet.h" | |
35 #include "ns3/uinteger.h" | |
36 #include "ns3/trace-source-accessor.h" | |
37 #include "tcp-socket-base.h" | |
38 #include "tcp-l4-protocol.h" | |
39 #include "ipv4-end-point.h" | |
40 #include "tcp-header.h" | |
41 #include "rtt-estimator.h" | |
42 | |
43 #include <algorithm> | |
44 | |
45 NS_LOG_COMPONENT_DEFINE ("TcpSocketBase"); | |
46 | |
47 namespace ns3 { | |
48 | |
49 NS_OBJECT_ENSURE_REGISTERED (TcpSocketBase); | |
50 | |
51 TypeId | |
52 TcpSocketBase::GetTypeId () | |
53 { | |
54 static TypeId tid = TypeId ("ns3::TcpSocketBase") | |
55 .SetParent<TcpSocket> () | |
56 .AddAttribute ("PersistTimeout", | |
57 "Persist timeout to probe for rwin", | |
58 TimeValue (Seconds (6)), | |
59 MakeTimeAccessor (&TcpSocketBase::m_persistTime), | |
60 MakeTimeChecker ()) | |
61 ; | |
62 return tid; | |
63 } | |
64 | |
65 TcpSocketBase::TcpSocketBase () | |
66 : m_dupAckCount (0), | |
67 m_delAckCount (0), | |
68 m_endPoint (0), | |
69 m_node (0), | |
70 m_tcp (0), | |
71 m_rtt (0), | |
72 m_nextTxSequence (0), // Change this for non-zero initial sequence num ber | |
73 m_highTxMark (0), | |
74 m_rxBuffer (0), | |
75 m_txBuffer (0), | |
76 m_state (CLOSED), | |
77 m_errno (ERROR_NOTERROR), | |
78 m_closeNotified (false), | |
79 m_closeOnEmpty (false), | |
80 m_shutdownSend (false), | |
81 m_shutdownRecv (false), | |
82 m_connected (false), | |
83 m_segmentSize (0), // For attribute initialization consistency (qui et valgrind) | |
84 m_rxWindowSize (0) | |
85 { | |
86 NS_LOG_FUNCTION (this); | |
87 } | |
88 | |
89 TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock) | |
90 : TcpSocket (sock), //copy object::m_tid and socket::callbacks | |
91 m_dupAckCount (sock.m_dupAckCount), | |
92 m_delAckCount (0), | |
93 m_delAckMaxCount (sock.m_delAckMaxCount), | |
94 m_cnCount (sock.m_cnCount), | |
95 m_delAckTimeout (sock.m_delAckTimeout), | |
96 m_persistTime (sock.m_persistTime), | |
97 m_cnTimeout (sock.m_cnTimeout), | |
98 m_endPoint (0), | |
99 m_node (sock.m_node), | |
100 m_tcp (sock.m_tcp), | |
101 m_rtt (0), | |
102 m_nextTxSequence (sock.m_nextTxSequence), | |
103 m_highTxMark (sock.m_highTxMark), | |
104 m_rxBuffer (sock.m_rxBuffer), | |
105 m_txBuffer (sock.m_txBuffer), | |
106 m_state (sock.m_state), | |
107 m_errno (sock.m_errno), | |
108 m_closeNotified (sock.m_closeNotified), | |
109 m_closeOnEmpty (sock.m_closeOnEmpty), | |
110 m_shutdownSend (sock.m_shutdownSend), | |
111 m_shutdownRecv (sock.m_shutdownRecv), | |
112 m_connected (sock.m_connected), | |
113 m_segmentSize (sock.m_segmentSize), | |
114 m_rxWindowSize (sock.m_rxWindowSize) | |
115 { | |
116 NS_LOG_FUNCTION (this); | |
117 NS_LOG_LOGIC ("Invoked the copy constructor"); | |
118 // Copy the rtt estimator if it is set | |
119 if (sock.m_rtt) | |
120 { | |
121 m_rtt = sock.m_rtt->Copy (); | |
122 } | |
123 // Reset all callbacks to null | |
124 Callback<void, Ptr< Socket > > vPS = MakeNullCallback<void, Ptr<Socket> > (); | |
125 Callback<void, Ptr<Socket>, const Address &> vPSA = MakeNullCallback<void, Ptr <Socket>, const Address &> (); | |
126 Callback<void, Ptr<Socket>, uint32_t> vPSUI = MakeNullCallback<void, Ptr<Socke t>, uint32_t> (); | |
127 SetConnectCallback (vPS, vPS); | |
128 SetDataSentCallback (vPSUI); | |
129 SetSendCallback (vPSUI); | |
130 SetRecvCallback (vPS); | |
131 } | |
132 | |
133 TcpSocketBase::~TcpSocketBase () | |
134 { | |
135 NS_LOG_FUNCTION (this); | |
136 m_node = 0; | |
137 if (m_endPoint != 0) | |
138 { | |
139 NS_ASSERT (m_tcp != 0); | |
140 /* | |
141 * Note that this piece of code is seriously convoluted: When we do a | |
142 * Bind we allocate an Ipv4Endpoint. Immediately thereafter we always do | |
143 * a FinishBind which sets the DestroyCallback of that endpoint to be | |
144 * TcpSocketBase::Destroy, below. When m_tcp->DeAllocate is called, it | |
145 * will in turn call into Ipv4EndpointDemux::DeAllocate with the endpoint | |
146 * (m_endPoint). The demux will look up the endpoint and destroy it (the | |
147 * corollary is that we don't own the object pointed to by m_endpoint, we | |
148 * just borrowed it). The destructor for the endpoint will call the | |
149 * DestroyCallback which will then invoke TcpSocketBase::Destroy below. | |
150 * Destroy will zero m_node, m_tcp and m_endpoint. The zero of m_node | |
151 * and m_tcp need to be here also in case the endpoint is deallocated | |
152 * before shutdown. | |
153 */ | |
154 NS_ASSERT (m_endPoint != 0); | |
155 m_tcp->DeAllocate (m_endPoint); | |
156 NS_ASSERT (m_endPoint == 0); | |
157 } | |
158 m_tcp = 0; | |
159 CancelAllTimers (); | |
160 } | |
161 | |
162 /* Associate a node with this TCP socket */ | |
163 void | |
164 TcpSocketBase::SetNode (Ptr<Node> node) | |
165 { | |
166 m_node = node; | |
167 } | |
168 | |
169 /* Associate the L4 protocol (e.g. mux/demux) with this socket */ | |
170 void | |
171 TcpSocketBase::SetTcp (Ptr<TcpL4Protocol> tcp) | |
172 { | |
173 m_tcp = tcp; | |
174 } | |
175 | |
176 /* Set an RTT estimator with this socket */ | |
177 void | |
178 TcpSocketBase::SetRtt (Ptr<RttEstimator> rtt) | |
179 { | |
180 m_rtt = rtt; | |
181 } | |
182 | |
183 /* From Socket class: Returns error code */ | |
184 enum Socket::SocketErrno | |
185 TcpSocketBase::GetErrno (void) const | |
186 { | |
187 NS_LOG_FUNCTION_NOARGS (); | |
188 return m_errno; | |
189 } | |
190 | |
191 /* From Socket class: Returns associated node */ | |
192 Ptr<Node> | |
193 TcpSocketBase::GetNode (void) const | |
194 { | |
195 NS_LOG_FUNCTION_NOARGS (); | |
196 return m_node; | |
197 } | |
198 | |
199 /* From Socket class: Bind socket to an end-point in TcpL4Protocol */ | |
200 int | |
201 TcpSocketBase::Bind (void) | |
202 { | |
203 NS_LOG_FUNCTION_NOARGS (); | |
204 m_endPoint = m_tcp->Allocate (); | |
205 return SetupCallback (); | |
206 } | |
207 | |
208 /* From Socket class: Bind socket (with specific address) to an end-point in Tcp L4Protocol */ | |
209 int | |
210 TcpSocketBase::Bind (const Address &address) | |
211 { | |
212 NS_LOG_FUNCTION (this << address); | |
213 if (!InetSocketAddress::IsMatchingType (address)) | |
214 { | |
215 m_errno = ERROR_INVAL; | |
216 return -1; | |
217 } | |
218 InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); | |
219 Ipv4Address ipv4 = transport.GetIpv4 (); | |
220 uint16_t port = transport.GetPort (); | |
221 if (ipv4 == Ipv4Address::GetAny () && port == 0) | |
222 { | |
223 m_endPoint = m_tcp->Allocate (); | |
224 } | |
225 else if (ipv4 == Ipv4Address::GetAny () && port != 0) | |
226 { | |
227 m_endPoint = m_tcp->Allocate (port); | |
228 } | |
229 else if (ipv4 != Ipv4Address::GetAny () && port == 0) | |
230 { | |
231 m_endPoint = m_tcp->Allocate (ipv4); | |
232 } | |
233 else if (ipv4 != Ipv4Address::GetAny () && port != 0) | |
234 { | |
235 m_endPoint = m_tcp->Allocate (ipv4, port); | |
236 } | |
237 NS_LOG_LOGIC ("TcpSocketBase " << this << " got an endpoint: " << m_endPoint); | |
238 | |
239 return SetupCallback (); | |
240 } | |
241 | |
242 /* From Socket class: Initiate connection to a remote address:port */ | |
243 int | |
244 TcpSocketBase::Connect (const Address & address) | |
245 { | |
246 NS_LOG_FUNCTION (this << address); | |
247 | |
248 // If haven't do so, Bind() this socket first | |
249 if (m_endPoint == 0) | |
250 { | |
251 if (Bind () == -1) | |
252 { | |
253 NS_ASSERT (m_endPoint == 0); | |
254 return -1; // Bind() failed | |
255 } | |
256 NS_ASSERT (m_endPoint != 0); | |
257 } | |
258 | |
259 InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); | |
260 m_endPoint->SetPeer (transport.GetIpv4 (), transport.GetPort ()); | |
261 | |
262 // Get the appropriate local address and port number from the routing protocol and set up endpoint | |
263 if (SetupEndpoint () != 0) | |
264 { // Route to destination does not exist | |
265 return -1; | |
266 } | |
267 | |
268 // DoConnect() will do state-checking and send a SYN packet | |
269 return DoConnect (); | |
270 } | |
271 | |
272 /* From Socket class: Listen on the endpoint for an incoming connection */ | |
273 int | |
274 TcpSocketBase::Listen (void) | |
275 { | |
276 NS_LOG_FUNCTION (this); | |
277 // Linux quits EINVAL if we're not in CLOSED state, so match what they do | |
278 if (m_state != CLOSED) | |
279 { | |
280 m_errno = ERROR_INVAL; | |
281 return -1; | |
282 } | |
283 // In other cases, set the state to LISTEN and done | |
284 m_state = LISTEN; | |
285 NS_LOG_LOGIC ("CLOSED -> LISTEN"); | |
286 return 0; | |
287 } | |
288 | |
289 /* From Socket class: Kill this socket and signal the peer (if any) */ | |
290 int | |
291 TcpSocketBase::Close (void) | |
292 { | |
293 NS_LOG_FUNCTION (this); | |
294 // First we check to see if there is any unread rx data | |
295 // Bug number 426 claims we should send reset in this case. | |
296 if (m_rxBuffer.Size () != 0) | |
297 { | |
298 SendRST (); | |
299 return 0; | |
300 } | |
301 if (m_txBuffer.SizeFromSeq (m_nextTxSequence) > 0) | |
302 { // App close with pending data must wait until all data transmitted | |
303 m_closeOnEmpty = true; | |
304 NS_LOG_LOGIC ("Socket " << this << " deferring close, state " << m_state); | |
305 return 0; | |
306 } | |
307 return DoClose (); | |
308 } | |
309 | |
310 /* From Socket class: Signal a termination of send */ | |
311 int | |
312 TcpSocketBase::ShutdownSend (void) | |
313 { | |
314 NS_LOG_FUNCTION (this); | |
315 m_shutdownSend = true; | |
316 return 0; | |
317 } | |
318 | |
319 /* From Socket class: Signal a termination of receive */ | |
320 int | |
321 TcpSocketBase::ShutdownRecv (void) | |
322 { | |
323 NS_LOG_FUNCTION (this); | |
324 m_shutdownRecv = true; | |
325 return 0; | |
326 } | |
327 | |
328 /* From Socket class: Send a packet. Parameter flags is not used. Packet has no | |
329 TCP header. Invoked by upper-layer application */ | |
330 int | |
331 TcpSocketBase::Send (Ptr<Packet> p, uint32_t flags) | |
332 { | |
333 NS_LOG_FUNCTION (this << p); | |
334 if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) | |
335 { | |
336 // Store the packet into Tx buffer | |
337 if (!m_txBuffer.Add (p)) | |
338 { // TxBuffer overflow, send failed | |
339 m_errno = ERROR_MSGSIZE; | |
340 return -1; | |
341 } | |
342 // Submit the data to lower layers | |
343 NS_LOG_DEBUG ("txBufSize=" << m_txBuffer.Size () << " state " << m_state); | |
344 if (m_state == ESTABLISHED || m_state == CLOSE_WAIT) | |
345 { // Try to send the data out | |
346 SendPendingData (m_connected); | |
347 } | |
348 return p->GetSize (); | |
349 } | |
350 else | |
351 { // Connection not established yet | |
352 m_errno = ERROR_NOTCONN; | |
353 return -1; // Send failure | |
354 } | |
355 } | |
356 | |
357 /* From Socket class: In TcpSocketBase, it is same as Send() call */ | |
358 int | |
359 TcpSocketBase::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address) | |
360 { | |
361 return Send (p, flags); // SendTo() and Send() are the same | |
362 } | |
363 | |
364 /* From Socket class: Return data to upper-layer application. Parameter flags | |
365 is not used. Data is returned as a packet of size no larger than maxSize */ | |
366 Ptr<Packet> | |
367 TcpSocketBase::Recv (uint32_t maxSize, uint32_t flags) | |
368 { | |
369 NS_LOG_FUNCTION (this); | |
370 if (m_rxBuffer.Size () == 0 && m_state == CLOSE_WAIT) | |
371 { | |
372 return Create<Packet> (); // Send EOF on connection close | |
373 } | |
374 Ptr<Packet> outPacket = m_rxBuffer.Extract (maxSize); | |
375 if (outPacket != 0 && outPacket->GetSize () != 0) | |
376 { | |
377 SocketAddressTag tag; | |
378 tag.SetAddress (InetSocketAddress (m_endPoint->GetPeerAddress (), m_endPoi nt->GetPeerPort ())); | |
379 outPacket->AddPacketTag (tag); | |
380 } | |
381 return outPacket; | |
382 } | |
383 | |
384 /* From Socket class: Recv and return the remote's address */ | |
385 Ptr<Packet> | |
386 TcpSocketBase::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress) | |
387 { | |
388 NS_LOG_FUNCTION (this << maxSize << flags); | |
389 Ptr<Packet> packet = Recv (maxSize, flags); | |
390 // Null packet means no data to read, and an empty packet indicates EOF | |
391 if (packet != 0 && packet->GetSize () != 0) | |
392 { | |
393 GetSockName (fromAddress); | |
394 } | |
395 return packet; | |
396 } | |
397 | |
398 /* From Socket class: Get the max number of bytes an app can send */ | |
399 uint32_t | |
400 TcpSocketBase::GetTxAvailable (void) const | |
401 { | |
402 NS_LOG_FUNCTION (this); | |
403 return m_txBuffer.Available (); | |
404 } | |
405 | |
406 /* From Socket class: Get the max number of bytes an app can read */ | |
407 uint32_t | |
408 TcpSocketBase::GetRxAvailable (void) const | |
409 { | |
410 NS_LOG_FUNCTION (this); | |
411 return m_rxBuffer.Available (); | |
412 } | |
413 | |
414 /* From Socket class: Return local address:port */ | |
415 int | |
416 TcpSocketBase::GetSockName (Address &address) const | |
417 { | |
418 NS_LOG_FUNCTION (this); | |
419 if (m_endPoint != 0) | |
420 { | |
421 address = InetSocketAddress (m_endPoint->GetLocalAddress (), m_endPoint->G etLocalPort ()); | |
422 } | |
423 else | |
424 { // It is possible to call this method on a socket without a name | |
425 // in which case, behavior is unspecified | |
426 address = InetSocketAddress (Ipv4Address::GetZero (), 0); | |
427 } | |
428 return 0; | |
429 } | |
430 | |
431 /* From Socket class: Bind this socket to the specified NetDevice */ | |
432 void | |
433 TcpSocketBase::BindToNetDevice (Ptr<NetDevice> netdevice) | |
434 { | |
435 NS_LOG_FUNCTION (netdevice); | |
436 Socket::BindToNetDevice (netdevice); // Includes sanity check | |
437 if (m_endPoint == 0) | |
438 { | |
439 if (Bind () == -1) | |
440 { | |
441 NS_ASSERT (m_endPoint == 0); | |
442 return; | |
443 } | |
444 NS_ASSERT (m_endPoint != 0); | |
445 } | |
446 m_endPoint->BindToNetDevice (netdevice); | |
447 return; | |
448 } | |
449 | |
450 /* Clean up. Set up callback functions in the end-point. */ | |
451 int | |
452 TcpSocketBase::SetupCallback (void) | |
453 { | |
454 NS_LOG_FUNCTION (this); | |
455 if (m_endPoint == 0) | |
456 { | |
457 return -1; | |
458 } | |
459 m_endPoint->SetRxCallback (MakeCallback (&TcpSocketBase::ForwardUp, Ptr<TcpSoc ketBase> (this))); | |
460 m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocketBase::Destroy, Ptr<Tcp SocketBase> (this))); | |
461 return 0; | |
462 } | |
463 | |
464 /* Perform the real connection tasks: Send SYN if allowed, RST if invalid */ | |
465 int | |
466 TcpSocketBase::DoConnect (void) | |
467 { | |
468 NS_LOG_FUNCTION (this); | |
469 | |
470 // A new connection is allowed only if this socket does not have a connection | |
471 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state = = LAST_ACK || m_state == CLOSE_WAIT) | |
472 { // send a SYN packet and change state into SYN_SENT | |
473 SendEmptyPacket (TcpHeader::SYN); | |
474 m_state = SYN_SENT; | |
475 NS_LOG_LOGIC ("moved to SYN_SENT state"); | |
476 } | |
477 else if (m_state != TIME_WAIT) | |
478 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, a n connection | |
479 // exists. We send RST, tear down everything, and close this socket. | |
480 CloseAndNotify (); | |
481 SendRST (); | |
482 } | |
483 return 0; | |
484 } | |
485 | |
486 /* Do the action to close the socket. Usually send a packet with appropriate | |
487 flags depended on the current m_state. */ | |
488 int | |
489 TcpSocketBase::DoClose (void) | |
490 { | |
491 NS_LOG_FUNCTION (this); | |
492 switch (m_state) | |
493 { | |
494 case SYN_RCVD: | |
495 case ESTABLISHED: | |
496 // send FIN to close the peer | |
497 SendEmptyPacket (TcpHeader::FIN); | |
498 m_state = FIN_WAIT_1; | |
499 NS_LOG_LOGIC ("ESTABLISHED -> FIN_WAIT_1"); | |
500 break; | |
501 case CLOSE_WAIT: | |
502 // send FIN+ACK to close the peer | |
503 SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK); | |
504 m_state = LAST_ACK; | |
505 NS_LOG_LOGIC ("CLOSE_WAIT -> LAST_ACK"); | |
506 break; | |
507 case SYN_SENT: | |
508 case CLOSING: | |
509 // Send RST if application closes in SYN_SENT and CLOSING | |
510 CloseAndNotify (); | |
511 SendRST (); | |
512 break; | |
513 case LISTEN: | |
514 case LAST_ACK: | |
515 // In these three states, move to CLOSED and tear down the end point | |
516 CloseAndNotify (); | |
517 break; | |
518 case CLOSED: | |
519 case FIN_WAIT_1: | |
520 case FIN_WAIT_2: | |
521 case TIME_WAIT: | |
522 default: /* mute compiler */ | |
523 // Do nothing in these four states | |
524 break; | |
525 } | |
526 return 0; | |
527 } | |
528 | |
529 /* Peacefully close the socket by notifying the upper layer and deallocate end p oint */ | |
530 void | |
531 TcpSocketBase::CloseAndNotify (void) | |
532 { | |
533 NS_LOG_FUNCTION (this); | |
534 | |
535 if (!m_closeNotified) NotifyNormalClose (); | |
536 m_closeNotified = true; | |
537 m_state = CLOSED; | |
538 DeallocateEndPoint (); | |
539 NS_LOG_LOGIC ("moved to CLOSED state"); | |
540 } | |
541 | |
542 /* Function called by the L3 protocol when it received a packet to pass on to | |
543 the TCP. This function is registered as the "RxCallback" function in | |
544 SetupCallback(), which invoked by Bind(), and CompleteFork() */ | |
545 void | |
546 TcpSocketBase::ForwardUp (Ptr<Packet> packet, Ipv4Address saddr, Ipv4Address dad dr, uint16_t port) | |
547 { | |
548 NS_LOG_FUNCTION (this << packet << saddr << daddr << port); | |
549 NS_LOG_DEBUG ("Socket " << this << " got forward up" << | |
550 " saddr " << m_endPoint->GetPeerAddress () << | |
551 " sport " << m_endPoint->GetPeerPort () << | |
552 " daddr " << m_endPoint->GetLocalAddress () << | |
553 " dport " << m_endPoint->GetLocalPort ()); | |
554 Address fromAddress = InetSocketAddress (saddr, port); | |
555 Address toAddress = InetSocketAddress (daddr, m_endPoint->GetLocalPort ()); | |
556 | |
557 // Peel off TCP header, and look for ACK flag | |
558 TcpHeader tcpHeader; | |
559 packet->RemoveHeader (tcpHeader); | |
560 if (tcpHeader.GetFlags () & TcpHeader::ACK) | |
561 { // TODO: This RTT function shall be changed to handle timestamp options | |
562 // One solution is to pass the whole header instead of just the number | |
563 m_rtt->AckSeq (tcpHeader.GetAckNumber () ); | |
564 } | |
565 | |
566 // Update Rx window size, i.e. the flow control window | |
567 if (m_rxWindowSize == 0 && tcpHeader.GetWindowSize () != 0) | |
568 { // persist probes end | |
569 NS_LOG_LOGIC (this << " Leaving zerowindow persist state"); | |
570 m_persistEvent.Cancel (); | |
571 } | |
572 m_rxWindowSize = tcpHeader.GetWindowSize (); | |
573 | |
574 // TCP state machine code in different process functions | |
575 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel | |
576 switch (m_state) | |
577 { | |
578 case ESTABLISHED: | |
579 ProcessEstablished (packet, tcpHeader); | |
580 break; | |
581 case LISTEN: | |
582 ProcessListen (packet, tcpHeader, fromAddress, toAddress); | |
583 break; | |
584 case TIME_WAIT: | |
585 // Do nothing | |
586 break; | |
587 case CLOSED: | |
588 // Send RST if the incoming packet is not a RST | |
589 if ((tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHea der::RST) | |
590 { | |
591 SendRST (); | |
592 } | |
593 break; | |
594 case SYN_SENT: | |
595 ProcessSynSent (packet, tcpHeader); | |
596 break; | |
597 case SYN_RCVD: | |
598 ProcessSynRcvd (packet, tcpHeader, fromAddress, toAddress); | |
599 break; | |
600 case FIN_WAIT_1: | |
601 case FIN_WAIT_2: | |
602 case CLOSE_WAIT: | |
603 ProcessWait (packet, tcpHeader); | |
604 break; | |
605 case CLOSING: | |
606 ProcessClosing (packet, tcpHeader); | |
607 break; | |
608 case LAST_ACK: | |
609 ProcessLastAck (packet, tcpHeader); | |
610 break; | |
611 default: // mute compiler | |
612 break; | |
613 } | |
614 } | |
615 | |
616 /* Received a packet upon ESTABLISHED state. This function is mimicking the | |
617 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */ | |
618 void | |
619 TcpSocketBase::ProcessEstablished (Ptr<Packet> packet, const TcpHeader& tcpHeade r) | |
620 { | |
621 NS_LOG_FUNCTION (this << tcpHeader); | |
622 | |
623 // Extract the flags. PSH and URG are not honoured. | |
624 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
625 | |
626 // Different flags are different events | |
627 if (tcpflags == TcpHeader::ACK) | |
628 { | |
629 ReceivedAck (packet, tcpHeader); | |
630 } | |
631 else if (tcpflags == TcpHeader::SYN) | |
632 { // Received SYN, set state to SYN_RCVD and respond with a SYN+ACK | |
633 m_state = SYN_RCVD; | |
634 NS_LOG_LOGIC ("ESTABLISHED -> SYN_RCVD"); | |
635 m_rxBuffer.SetNextRxSeq (tcpHeader.GetSequenceNumber () + SequenceNumber ( 1)); | |
636 SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); | |
637 // TODO: Isn't it illegal to get a SYN if it is already ESTABLISHED? | |
638 } | |
639 else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK)) | |
640 { // No action for received SYN+ACK, it is probably a duplicated packet | |
641 } | |
642 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader ::ACK)) | |
643 { // Received FIN or FIN+ACK, bring down this socket nicely | |
644 PeerClose (packet, tcpHeader); | |
645 if (m_rxBuffer.Finished ()) | |
646 { | |
647 m_state = CLOSE_WAIT; | |
648 NS_LOG_LOGIC ("ESTABLISHED -> CLOSE_WAIT"); | |
649 } | |
650 } | |
651 else if (tcpflags == 0) | |
652 { // No flags means there is only data | |
653 ReceivedData (packet, tcpHeader); | |
Adrian
2010/06/25 08:46:10
Function name change: NewRx->ReceivedData
| |
654 if (m_rxBuffer.Finished ()) | |
655 { | |
656 m_state = CLOSE_WAIT; | |
657 NS_LOG_LOGIC ("ESTABLISHED -> CLOSE_WAIT"); | |
658 PeerClose (packet, tcpHeader); | |
659 } | |
660 } | |
661 else if (m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
662 { // Received RST or the TCP flags is invalid, in either case, terminate thi s socket | |
663 CloseAndNotify (); | |
664 if (tcpflags != TcpHeader::RST) | |
665 { // this must be an invalid flag, send reset | |
666 SendRST (); | |
667 } | |
668 } | |
669 } | |
670 | |
671 /* Process the newly received ACK */ | |
672 void | |
673 TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader) | |
674 { | |
675 NS_LOG_FUNCTION (this << tcpHeader); | |
676 | |
677 // Received ACK. Compare the ACK number against highest unacked seqno | |
678 if (tcpHeader.GetAckNumber () < m_txBuffer.HeadSeq ()) | |
679 { // Case 1: Old ACK, ignored. | |
680 } | |
681 else if (tcpHeader.GetAckNumber () == m_txBuffer.HeadSeq ()) | |
682 { // Case 2: Potentially a duplicated ACK | |
683 if (tcpHeader.GetAckNumber () < m_nextTxSequence) | |
684 { | |
685 DupAck (tcpHeader, ++m_dupAckCount); | |
686 } | |
687 // otherwise, the ACK is precisely equal to the nextTxSequence | |
688 NS_ASSERT (tcpHeader.GetAckNumber () <= m_nextTxSequence); | |
689 } | |
690 else if (tcpHeader.GetAckNumber () > m_txBuffer.HeadSeq ()) | |
691 { // Case 3: New ACK, reset m_dupAckCount and update m_txBuffer | |
692 NewAck (tcpHeader.GetAckNumber ()); | |
693 m_dupAckCount = 0; | |
694 } | |
695 // If there is any data piggybacked, store it into m_rxBuffer | |
696 if (packet->GetSize () > 0) | |
697 { | |
698 ReceivedData (packet, tcpHeader); | |
699 } | |
700 } | |
701 | |
702 /* Received a packet upon LISTEN state. */ | |
703 void | |
704 TcpSocketBase::ProcessListen (Ptr<Packet> packet, const TcpHeader& tcpHeader, | |
705 const Address& fromAddress, const Address& toAddre ss) | |
706 { | |
707 NS_LOG_FUNCTION (this << tcpHeader); | |
708 | |
709 // Extract the flags. PSH and URG are not honoured. | |
710 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
711 | |
712 // Fork a socket if received a SYN. Do nothing otherwise. | |
713 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel | |
714 if (tcpflags != TcpHeader::SYN) return; | |
715 | |
716 // Call socket's notify function to let the server app know we got a SYN | |
717 // If the server app refuses the connection, do nothing | |
718 if (!NotifyConnectionRequest (fromAddress)) return; | |
719 // Clone the socket, simulate fork | |
720 Ptr<TcpSocketBase> newSock = Fork (); | |
721 NS_LOG_LOGIC ("Cloned a TcpSocketBase " << newSock); | |
722 Simulator::ScheduleNow (&TcpSocketBase::CompleteFork, newSock, | |
723 packet, tcpHeader, fromAddress, toAddress); | |
724 } | |
725 | |
726 /* Received a packet upon SYN_SENT */ | |
727 void | |
728 TcpSocketBase::ProcessSynSent (Ptr<Packet> packet, const TcpHeader& tcpHeader) | |
729 { | |
730 NS_LOG_FUNCTION (this << tcpHeader); | |
731 | |
732 // Extract the flags. PSH and URG are not honoured. | |
733 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
734 | |
735 if (tcpflags == 0) | |
736 { // Bare data, accept it and move to ESTABLISHED state. This is not a norma l behaviour. Remove this? | |
737 m_state = ESTABLISHED; | |
738 m_connected = true; | |
739 ReceivedData (packet, tcpHeader); | |
740 Simulator::ScheduleNow (&TcpSocketBase::ConnectionSucceeded, this); | |
741 NS_LOG_LOGIC ("SYN_SENT -> ESTABLISHED"); | |
742 } | |
743 else if (tcpflags == TcpHeader::ACK) | |
744 { // Ignore ACK in SYN_SENT | |
745 } | |
746 else if (tcpflags == TcpHeader::SYN) | |
747 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK | |
748 m_state = SYN_RCVD; | |
749 m_rxBuffer.SetNextRxSeq (tcpHeader.GetSequenceNumber () + SequenceNumber ( 1)); | |
750 SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); | |
751 NS_LOG_LOGIC ("SYN_SENT -> SYN_RCVD"); | |
752 } | |
753 else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK) | |
754 && m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
755 { // Handshake completed | |
756 m_state = ESTABLISHED; | |
757 m_connected = true; | |
758 m_rxBuffer.SetNextRxSeq (tcpHeader.GetSequenceNumber () + SequenceNumber ( 1)); | |
759 m_nextTxSequence = tcpHeader.GetAckNumber (); | |
760 m_txBuffer.SetHeadSeq (m_nextTxSequence); | |
761 SendEmptyPacket (TcpHeader::ACK); | |
762 if (GetTxAvailable () > 0) | |
763 { | |
764 NotifySend (GetTxAvailable ()); | |
765 } | |
766 SendPendingData (m_connected); | |
767 Simulator::ScheduleNow (&TcpSocketBase::ConnectionSucceeded, this); | |
768 NS_LOG_LOGIC ("SYN_SENT -> ESTABLISHED"); | |
769 } | |
770 else if (m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
771 { // Other in-sequence input | |
772 CloseAndNotify (); | |
773 if (tcpflags != TcpHeader::RST) | |
774 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags | |
775 SendRST (); | |
776 } | |
777 } | |
778 } | |
779 | |
780 /* Received a packet upon SYN_RCVD */ | |
781 void | |
782 TcpSocketBase::ProcessSynRcvd (Ptr<Packet> packet, const TcpHeader& tcpHeader, | |
783 const Address& fromAddress, const Address& toAddr ess) | |
784 { | |
785 NS_LOG_FUNCTION (this << tcpHeader); | |
786 | |
787 // Extract the flags. PSH and URG are not honoured. | |
788 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
789 | |
790 if (tcpflags == 0) | |
791 { // Bare data, accept it and move to ESTABLISHED state. This is not a norma l behaviour. | |
792 m_endPoint->SetPeer (m_endPoint->GetPeerAddress (), m_endPoint->GetPeerPor t ()); | |
793 NotifyNewConnectionCreated (this, fromAddress); | |
794 m_state = ESTABLISHED; | |
795 m_connected = true; | |
796 #if 0 | |
797 // Always respond to first data packet to speed up the connection. | |
798 // Remove to get the behaviour of old NS-3 code. | |
799 m_delAckCount = m_delAckMaxCount; | |
800 #endif | |
801 ReceivedData (packet, tcpHeader); | |
802 NS_LOG_LOGIC ("SYN_RCVD -> ESTABLISHED"); | |
803 } | |
804 else if (tcpflags == TcpHeader::ACK | |
805 && m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
806 { // Handshake completed. | |
807 m_state = ESTABLISHED; | |
808 m_connected = true; | |
809 m_endPoint->SetPeer (m_endPoint->GetPeerAddress (), m_endPoint->GetPeerPor t ()); | |
810 #if 0 | |
811 // Always respond to first data packet to speed up the connection. | |
812 // Remove to get the behaviour of old NS-3 code. | |
813 m_delAckCount = m_delAckMaxCount; | |
814 #endif | |
815 ReceivedAck (packet, tcpHeader); | |
Adrian
2010/06/25 08:46:10
This was NewAck but now replaced with ReceivedAck
| |
816 NotifyNewConnectionCreated (this, fromAddress); | |
817 NS_LOG_LOGIC ("SYN_RCVD -> ESTABLISHED"); | |
818 } | |
819 else if (tcpflags == TcpHeader::SYN) | |
820 { // Probably the peer lost my SYN+ACK | |
821 m_rxBuffer.SetNextRxSeq (tcpHeader.GetSequenceNumber () + SequenceNumber ( 1)); | |
822 SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); | |
823 } | |
824 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK)) | |
825 { | |
826 PeerClose (packet, tcpHeader); | |
827 if (m_rxBuffer.Finished ()) | |
828 { | |
829 m_state = CLOSE_WAIT; | |
830 NS_LOG_LOGIC ("SYN_RCVD -> CLOSE_WAIT"); | |
831 } | |
832 } | |
833 else if (m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
834 { // Other in-sequence input | |
835 CloseAndNotify (); | |
836 if (tcpflags != TcpHeader::RST) | |
837 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags | |
838 SendRST (); | |
839 } | |
840 } | |
841 } | |
842 | |
843 /* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */ | |
844 void | |
845 TcpSocketBase::ProcessWait (Ptr<Packet> packet, const TcpHeader& tcpHeader) | |
846 { | |
847 NS_LOG_FUNCTION (this << tcpHeader); | |
848 | |
849 // Extract the flags. PSH and URG are not honoured. | |
850 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
851 | |
852 if (tcpflags == 0) | |
853 { // Bare data, accept it | |
854 ReceivedData (packet, tcpHeader); | |
855 } | |
856 else if (tcpflags == TcpHeader::ACK) | |
857 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2 | |
858 ReceivedAck (packet, tcpHeader); | |
859 if (m_state == FIN_WAIT_1 && tcpHeader.GetSequenceNumber () == m_rxBuffer. NextRxSeq ()) | |
860 { // This ACK corresponds to the FIN sent | |
861 m_state = FIN_WAIT_2; | |
862 NS_LOG_LOGIC ("FIN_WAIT_1 -> FIN_WAIT_2"); | |
863 } | |
864 } | |
865 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader ::ACK)) | |
866 { // Got FIN, respond with ACK and move to next state | |
867 m_rxBuffer.SetFinSeq (tcpHeader.GetSequenceNumber ()); | |
868 if (m_rxBuffer.Finished ()) | |
869 { // Action only if the FIN received is in-sequence | |
870 SendEmptyPacket (TcpHeader::ACK); | |
871 if (m_state == FIN_WAIT_1 && tcpflags == TcpHeader::FIN) | |
872 { | |
873 m_state = CLOSING; | |
874 if (!m_shutdownRecv) NotifyDataRecv (); | |
875 NS_LOG_LOGIC ("FIN_WAIT_1 -> CLOSING"); | |
876 } | |
877 else if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) | |
878 { | |
879 m_state = TIME_WAIT; | |
880 if (!m_shutdownRecv) NotifyDataRecv (); | |
881 NS_LOG_LOGIC ("moved to TIME_WAIT state"); | |
882 // TODO: In TIME_WAIT, we supposed to move to CLOSED after 2*MSL t ime | |
883 // but this move is not yet implemeneted. Is this necessary? | |
884 } | |
885 } | |
886 } | |
887 else if (m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
888 { // This is a SYN or SYN+ACK or RST or bad flags | |
889 CloseAndNotify (); | |
890 if (tcpflags != TcpHeader::RST) | |
891 { | |
892 SendRST (); | |
893 } | |
894 } | |
895 } | |
896 | |
897 /* Received a packet upon CLOSING */ | |
898 void | |
899 TcpSocketBase::ProcessClosing (Ptr<Packet> packet, const TcpHeader& tcpHeader) | |
900 { | |
901 NS_LOG_FUNCTION (this << tcpHeader); | |
902 | |
903 // Extract the flags. PSH and URG are not honoured. | |
904 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
905 | |
906 if (tcpflags == TcpHeader::ACK) | |
907 { | |
908 if (tcpHeader.GetSequenceNumber () == m_rxBuffer.NextRxSeq ()) | |
909 { // This ACK corresponds to the FIN sent | |
910 m_state = TIME_WAIT; | |
911 NS_LOG_LOGIC ("CLOSING -> TIME_WAIT"); | |
912 // TODO: In TIME_WAIT, we supposed to move to CLOSED after 2*MSL time | |
913 // but this move is not yet implemeneted. Is this necessary? | |
914 } | |
915 } | |
916 else if (m_rxBuffer.NextRxSeq () == tcpHeader.GetSequenceNumber ()) | |
917 { | |
918 CloseAndNotify (); | |
919 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader: :ACK)) | |
920 { // FIN from the peer as well. We can close immediately. | |
921 SendEmptyPacket (TcpHeader::ACK); | |
922 } | |
923 else if (tcpflags != TcpHeader::RST) | |
924 { // Receive of SYN or SYN+ACK or bad flags or pure data | |
925 SendRST (); | |
926 } | |
927 } | |
928 } | |
929 | |
930 /* Received a packet upon LAST_ACK */ | |
931 void | |
932 TcpSocketBase::ProcessLastAck (Ptr<Packet> packet, const TcpHeader& tcpHeader) | |
933 { | |
934 NS_LOG_FUNCTION (this << tcpHeader); | |
935 | |
936 // Extract the flags. PSH and URG are not honoured. | |
937 uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG); | |
938 | |
939 if (tcpflags == 0) | |
940 { | |
941 ReceivedData (packet, tcpHeader); | |
942 } | |
943 else if (tcpflags == TcpHeader::ACK) | |
944 { | |
945 if (tcpHeader.GetSequenceNumber () == m_rxBuffer.NextRxSeq ()) | |
946 { // This ACK corresponds to the FIN sent. This socket closed peacefully . | |
947 CloseAndNotify (); | |
948 } | |
949 } | |
950 else if (tcpflags == TcpHeader::FIN) | |
951 { // Received FIN again, the peer probably lost the FIN+ACK | |
952 SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK); | |
953 } | |
954 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeade r::RST) | |
955 { | |
956 CloseAndNotify (); | |
957 } | |
958 else | |
959 { // Received a SYN or SYN+ACK or bad flags | |
960 CloseAndNotify (); | |
961 SendRST (); | |
962 } | |
963 } | |
964 | |
965 /* Peer sent me a FIN. Close down this socket. */ | |
966 void | |
967 TcpSocketBase::PeerClose (Ptr<Packet> p, const TcpHeader& tcpHeader) | |
968 { | |
969 NS_LOG_FUNCTION (this << tcpHeader); | |
970 | |
971 // If FIN is out of sequence, remember it and process new sequence rx | |
972 if (tcpHeader.GetSequenceNumber () != m_rxBuffer.NextRxSeq ()) | |
973 { | |
974 if (tcpHeader.GetSequenceNumber () > m_rxBuffer.NextRxSeq ()) | |
975 { | |
976 m_rxBuffer.SetFinSeq (tcpHeader.GetSequenceNumber () + SequenceNumber (p->GetSize ())); | |
Adrian
2010/06/25 08:46:10
In case FIN piggybacked with data, the correct FIN
| |
977 NS_LOG_LOGIC ("TcpSocketBase " << this << " accpeted FIN at rxseq" << | |
978 tcpHeader.GetSequenceNumber () << | |
979 " nextRxSeq " << m_rxBuffer.NextRxSeq ()); | |
980 ReceivedData (p, tcpHeader); | |
981 } | |
982 return; | |
983 } | |
984 // If FIN is in sequence with new data, call ReceivedData | |
985 if (tcpHeader.GetSequenceNumber () + SequenceNumber (p->GetSize ()) > m_rxBuff er.NextRxSeq ()) | |
986 { | |
987 ReceivedData (p, tcpHeader); | |
988 // This is the old NS-3 behaviour that if a FIN is piggybacked with data, | |
989 // the data and the FIN are ACKed separately. RFC didn't require this. | |
990 SendEmptyPacket (TcpHeader::ACK); | |
991 } | |
992 // For all in-sequence FIN, close the socket immediately | |
993 m_rxBuffer.SetFinSeq (tcpHeader.GetSequenceNumber () + SequenceNumber (p->GetS ize ())); | |
994 States_t saveState = m_state; // Used to see if app responds | |
995 NS_LOG_LOGIC ("TcpSocketBase " << this << " peer close, state " << m_state); | |
996 if (!m_closeNotified) | |
997 { | |
998 NS_LOG_LOGIC ("TCP " << this << " calling AppCloseRequest"); | |
999 if (!m_closeNotified) NotifyNormalClose (); | |
1000 m_closeNotified = true; | |
1001 } | |
1002 NS_LOG_LOGIC ("TcpSocketBase " << this << " peer close, state after " << m_sta te); | |
1003 if (m_state == saveState) | |
1004 { // Need to ack, the application will close later | |
1005 SendEmptyPacket (TcpHeader::ACK); | |
1006 } | |
1007 if (m_state == LAST_ACK) | |
1008 { | |
1009 NS_LOG_LOGIC ("TcpSocketBase " << this << " scheduling LATO1"); | |
1010 m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (), | |
1011 &TcpSocketBase::LastAckTimeout, this ); | |
1012 } | |
1013 } | |
1014 | |
1015 /* Kill this socket. This is a callback function configured to m_endpoint in | |
1016 SetupCallback(), invoked when the endpoint is destroyed. */ | |
1017 void | |
1018 TcpSocketBase::Destroy (void) | |
1019 { | |
1020 NS_LOG_FUNCTION (this); | |
1021 m_node = 0; | |
1022 m_endPoint = 0; | |
1023 m_tcp = 0; | |
1024 NS_LOG_LOGIC (this << " Cancelled ReTxTimeout event which was set to expire at " << | |
1025 (Simulator::Now () + Simulator::GetDelayLeft (m_retxEvent)).GetS econds ()); | |
1026 CancelAllTimers (); | |
1027 } | |
1028 | |
1029 /* Send an empty packet with specified TCP flags */ | |
1030 void | |
1031 TcpSocketBase::SendEmptyPacket (uint8_t flags) | |
1032 { | |
1033 NS_LOG_FUNCTION (this << (uint32_t)flags); | |
1034 Ptr<Packet> p = Create<Packet> (); | |
1035 TcpHeader header; | |
1036 | |
1037 if (m_endPoint == 0) | |
1038 { | |
1039 NS_LOG_WARN ("Failed to send empty packet due to null endpoint"); | |
1040 return; | |
1041 } | |
1042 if (flags & TcpHeader::FIN) | |
1043 { | |
1044 flags |= TcpHeader::ACK; | |
1045 } | |
1046 | |
1047 header.SetFlags (flags); | |
1048 header.SetSequenceNumber (m_nextTxSequence); | |
1049 header.SetAckNumber (m_rxBuffer.NextRxSeq ()); | |
1050 header.SetSourcePort (m_endPoint->GetLocalPort ()); | |
1051 header.SetDestinationPort (m_endPoint->GetPeerPort ()); | |
1052 header.SetWindowSize (AdvertisedWindowSize ()); | |
1053 m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), m_endPoint->GetP eerAddress (), m_boundnetdevice); | |
1054 Time rto = m_rtt->RetransmitTimeout (); | |
1055 bool hasSyn = flags & TcpHeader::SYN; | |
1056 bool hasFin = flags & TcpHeader::FIN; | |
1057 bool isAck = flags == TcpHeader::ACK; | |
1058 if (hasSyn) | |
1059 { // Exponential backoff of connection time out | |
1060 rto = m_cnTimeout; | |
1061 m_cnTimeout = m_cnTimeout + m_cnTimeout; | |
1062 m_cnCount--; | |
1063 } | |
1064 if (flags & TcpHeader::ACK) | |
1065 { // If sending an ACK, cancel the delay ACK as well | |
1066 m_delAckEvent.Cancel (); | |
1067 m_delAckCount = 0; | |
1068 } | |
1069 if (m_retxEvent.IsExpired () && (hasSyn || hasFin) && !isAck ) | |
1070 { // Setup ReTx timer if not have one at the moment | |
1071 NS_LOG_LOGIC ("Schedule retransmission timeout at time " | |
1072 << Simulator::Now ().GetSeconds () << " to expire at time " | |
1073 << (Simulator::Now () + rto).GetSeconds ()); | |
1074 m_retxEvent = Simulator::Schedule (rto, &TcpSocketBase::ReTxTimeout, this) ; | |
1075 } | |
1076 } | |
1077 | |
1078 /* This function closes the endpoint completely. Called upon RST_TX action. */ | |
1079 void | |
1080 TcpSocketBase::SendRST (void) | |
1081 { | |
1082 NS_LOG_FUNCTION (this); | |
1083 SendEmptyPacket (TcpHeader::RST); | |
1084 NotifyErrorClose (); | |
1085 DeallocateEndPoint (); | |
1086 } | |
1087 | |
1088 /* Deallocate the end point the cancel all the timers */ | |
1089 void | |
1090 TcpSocketBase::DeallocateEndPoint (void) | |
1091 { | |
1092 if (m_endPoint != 0) | |
1093 { | |
1094 m_endPoint->SetDestroyCallback (MakeNullCallback<void> ()); | |
1095 m_tcp->DeAllocate (m_endPoint); | |
1096 m_endPoint = 0; | |
1097 CancelAllTimers (); | |
1098 } | |
1099 } | |
1100 | |
1101 /* Configure the endpoint to a local address. Called by Connect() if Bind() didn 't specify one. */ | |
1102 int | |
1103 TcpSocketBase::SetupEndpoint () | |
1104 { | |
1105 NS_LOG_FUNCTION (this); | |
1106 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> (); | |
1107 NS_ASSERT (ipv4 != 0); | |
1108 if (ipv4->GetRoutingProtocol () == 0) | |
1109 { | |
1110 NS_FATAL_ERROR ("No Ipv4RoutingProtocol in the node"); | |
1111 } | |
1112 // Create a dummy packet, then ask the routing function for the best output | |
1113 // interface's address | |
1114 Ipv4Header header; | |
1115 header.SetDestination (m_endPoint->GetPeerAddress ()); | |
1116 Socket::SocketErrno errno_; | |
1117 Ptr<Ipv4Route> route; | |
1118 Ptr<NetDevice> oif = m_boundnetdevice; | |
1119 route = ipv4->GetRoutingProtocol ()->RouteOutput (Ptr<Packet> (), header, oif, errno_); | |
1120 if (route == 0) | |
1121 { | |
1122 NS_LOG_LOGIC ("Route to " << m_endPoint->GetPeerAddress () << " does not e xist"); | |
1123 NS_LOG_ERROR (errno_); | |
1124 m_errno = errno_; | |
1125 return -1; | |
1126 } | |
1127 NS_LOG_LOGIC ("Route exists"); | |
1128 m_endPoint->SetLocalAddress (route->GetSource ()); | |
1129 return 0; | |
1130 } | |
1131 | |
1132 /* This function is called only if a SYN received in LISTEN state. After | |
1133 TcpSocketBase cloned, allocate a new end point to handle the incoming | |
1134 connection and send a SYN+ACK to complete the handshake. */ | |
1135 void | |
1136 TcpSocketBase::CompleteFork (Ptr<Packet> p, const TcpHeader& h, | |
1137 const Address& fromAddress, const Address& toAddres s) | |
1138 { | |
1139 // Get port and address from peer (connecting host) | |
1140 m_endPoint = m_tcp->Allocate (InetSocketAddress::ConvertFrom (toAddress).GetIp v4 (), | |
1141 InetSocketAddress::ConvertFrom (toAddress).GetPo rt (), | |
1142 InetSocketAddress::ConvertFrom (fromAddress).Get Ipv4 (), | |
1143 InetSocketAddress::ConvertFrom (fromAddress).Get Port ()); | |
1144 | |
1145 // Change the cloned socket from LISTEN state to SYN_RCVD | |
1146 m_state = SYN_RCVD; | |
1147 NS_LOG_LOGIC ("LISTEN -> SYN_RCVD"); | |
1148 // Setup callback and call ProcessPacketAction to continue the handshake | |
1149 SetupCallback (); | |
1150 // Set the sequence number and send SYN+ACK | |
1151 m_rxBuffer.SetNextRxSeq (h.GetSequenceNumber () + SequenceNumber (1)); | |
1152 SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); | |
1153 } | |
1154 | |
1155 void | |
1156 TcpSocketBase::ConnectionSucceeded () | |
1157 { // Wrapper to protected function NotifyConnectionSucceeded() so that it can | |
1158 // be called as a scheduled event | |
1159 NotifyConnectionSucceeded (); | |
1160 } | |
1161 | |
1162 // Send as much pending data as possible according to the Tx window. Note that | |
1163 // this function did not implement the PSH flag | |
1164 bool | |
1165 TcpSocketBase::SendPendingData (bool withAck) | |
1166 { | |
1167 NS_LOG_FUNCTION (this << withAck); | |
1168 if (m_txBuffer.Size () == 0) return false; // Nothing to send | |
1169 if (m_endPoint == 0) | |
1170 { | |
1171 NS_LOG_INFO ("TcpSocketImpl::SendPendingData: No endpoint; m_shutdownSend= " << m_shutdownSend); | |
1172 return false; // Is this the right way to handle this condition? | |
1173 } | |
1174 uint32_t nPacketsSent = 0; | |
1175 while (m_txBuffer.SizeFromSeq (m_nextTxSequence)) | |
1176 { | |
1177 uint32_t w = AvailableWindow (); // Get available window size | |
1178 NS_LOG_LOGIC ("TcpSocketBase " << this << " SendPendingData" << | |
1179 " w " << w << | |
1180 " rxwin " << m_rxWindowSize << | |
1181 " segsize " << m_segmentSize << | |
1182 " nextTxSeq " << m_nextTxSequence << | |
1183 " highestRxAck " << m_txBuffer.HeadSeq () << | |
1184 " pd->Size " << m_txBuffer.Size () << | |
1185 " pd->SFS " << m_txBuffer.SizeFromSeq (m_nextTxSequence)); | |
1186 // Quit if send disallowed | |
1187 if (m_shutdownSend) | |
1188 { | |
1189 m_errno = ERROR_SHUTDOWN; | |
1190 return false; | |
1191 } | |
1192 // Stop sending if we need to wait for a larger Tx window | |
1193 if (w < m_segmentSize && m_txBuffer.SizeFromSeq (m_nextTxSequence) > w) | |
1194 { | |
1195 break; // No more | |
1196 } | |
1197 uint32_t s = std::min (w, m_segmentSize); // Send no more than window | |
1198 Ptr<Packet> p = m_txBuffer.CopyFromSeq (s, m_nextTxSequence); | |
1199 NS_LOG_LOGIC ("TcpSocketBase " << this << " SendPendingData" << | |
1200 " txseq " << m_nextTxSequence << | |
1201 " s " << s << " datasize " << p->GetSize ()); | |
1202 uint8_t flags = 0; | |
1203 uint32_t sz = p->GetSize (); // Size of packet | |
1204 uint32_t remainingData = m_txBuffer.SizeFromSeq (m_nextTxSequence + Sequen ceNumber (sz)); | |
1205 if (m_closeOnEmpty && (remainingData == 0)) | |
1206 { | |
1207 flags = TcpHeader::FIN; | |
1208 m_state = FIN_WAIT_1; | |
1209 NS_LOG_LOGIC ("moved to FIN_WAIT_1 state"); | |
1210 } | |
1211 if (withAck) | |
1212 { | |
1213 flags |= TcpHeader::ACK; | |
1214 } | |
1215 TcpHeader header; | |
1216 header.SetFlags (flags); | |
1217 header.SetSequenceNumber (m_nextTxSequence); | |
1218 header.SetAckNumber (m_rxBuffer.NextRxSeq ()); | |
1219 header.SetSourcePort (m_endPoint->GetLocalPort ()); | |
1220 header.SetDestinationPort (m_endPoint->GetPeerPort ()); | |
1221 header.SetWindowSize (AdvertisedWindowSize ()); | |
1222 if (m_retxEvent.IsExpired () ) | |
1223 { // Schedule retransmit | |
1224 Time rto = m_rtt->RetransmitTimeout (); | |
1225 NS_LOG_LOGIC (this << " SendPendingData Schedule ReTxTimeout at time " << | |
1226 Simulator::Now ().GetSeconds () << " to expire at time " << | |
1227 (Simulator::Now () + rto).GetSeconds () ); | |
1228 m_retxEvent = Simulator::Schedule (rto, &TcpSocketBase::ReTxTimeout, t his); | |
1229 } | |
1230 NS_LOG_LOGIC ("About to send a packet with flags: " << flags); | |
1231 m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), | |
1232 m_endPoint->GetPeerAddress (), m_boundnetdevice); | |
1233 m_rtt->SentSeq (m_nextTxSequence, sz); // notify the RTT | |
1234 // Notify the application of the data being sent | |
1235 Simulator::ScheduleNow (&TcpSocketBase::NotifyDataSent, this, sz); | |
1236 nPacketsSent++; // Count sent this loop | |
1237 m_nextTxSequence += sz; // Advance next tx sequence | |
1238 // Update highTxMark | |
1239 m_highTxMark = std::max (m_nextTxSequence, m_highTxMark); | |
1240 } | |
1241 NS_LOG_LOGIC ("SendPendingData Sent " << nPacketsSent << " packets"); | |
1242 NS_LOG_LOGIC ("RETURN SendPendingData"); | |
1243 return (nPacketsSent > 0); | |
1244 } | |
1245 | |
1246 uint32_t | |
1247 TcpSocketBase::UnAckDataCount () | |
1248 { | |
1249 NS_LOG_FUNCTION (this); | |
1250 return m_nextTxSequence - m_txBuffer.HeadSeq (); | |
1251 } | |
1252 | |
1253 uint32_t | |
1254 TcpSocketBase::BytesInFlight () | |
1255 { | |
1256 NS_LOG_FUNCTION (this); | |
1257 return m_highTxMark - m_txBuffer.HeadSeq (); | |
1258 } | |
1259 | |
1260 uint32_t | |
1261 TcpSocketBase::Window () | |
1262 { | |
1263 NS_LOG_FUNCTION (this); | |
1264 return m_rxWindowSize; | |
1265 } | |
1266 | |
1267 uint32_t | |
1268 TcpSocketBase::AvailableWindow () | |
1269 { | |
1270 NS_LOG_FUNCTION_NOARGS (); | |
1271 uint32_t unack = UnAckDataCount (); // Number of outstanding bytes | |
1272 uint32_t win = Window (); // Number of bytes allowed to be outstanding | |
1273 NS_LOG_LOGIC ("UnAckCount=" << unack << ", Win=" << win); | |
1274 return (win < unack) ? 0 : (win - unack); | |
1275 } | |
1276 | |
1277 uint16_t | |
1278 TcpSocketBase::AdvertisedWindowSize () | |
1279 { | |
1280 uint32_t max = 0xffff; | |
1281 return std::min (m_rxBuffer.MaxBufferSize () - m_rxBuffer.Size (), max); | |
1282 } | |
1283 | |
1284 // Receipt of new packet, put into Rx buffer | |
1285 void | |
1286 TcpSocketBase::ReceivedData (Ptr<Packet> p, const TcpHeader& tcpHeader) | |
1287 { | |
1288 NS_LOG_FUNCTION (this << tcpHeader); | |
1289 NS_LOG_LOGIC ("seq " << tcpHeader.GetSequenceNumber () << | |
1290 " ack " << tcpHeader.GetAckNumber () << | |
1291 " pkt size " << p->GetSize () ); | |
1292 | |
1293 // Put into Rx buffer | |
1294 States_t origState = m_state; | |
1295 SequenceNumber origSeq = m_rxBuffer.NextRxSeq (); | |
1296 if (!m_rxBuffer.Add (p, tcpHeader)) | |
1297 { // Insert failed: No data or RX buffer full | |
1298 SendEmptyPacket (TcpHeader::ACK); | |
1299 return; | |
1300 } | |
1301 // Now send a new ACK packet acknowledging all received and delivered data | |
1302 if (++m_delAckCount >= m_delAckMaxCount) | |
1303 { | |
1304 SendEmptyPacket (TcpHeader::ACK); | |
1305 } | |
1306 else if (m_delAckEvent.IsExpired ()) | |
1307 { | |
1308 m_delAckEvent = Simulator::Schedule (m_delAckTimeout, &TcpSocketBase::DelA ckTimeout, this); | |
1309 } | |
1310 // Notify app to receive if necessary | |
1311 if (origSeq < m_rxBuffer.NextRxSeq ()) | |
1312 { // NextRxSeq advanced, we have something to send to the app | |
1313 if (!m_shutdownRecv) NotifyDataRecv (); | |
1314 // Handle exceptions | |
1315 if (m_closeNotified) | |
1316 { | |
1317 NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif"); | |
1318 } | |
1319 if ((m_rxBuffer.Finished () || (origState > ESTABLISHED)) && (m_rxBuffer.S ize () == 0)) | |
1320 { // No more data to forward to app, we can close now | |
1321 PeerClose (p, tcpHeader); | |
1322 } | |
1323 } | |
1324 } | |
1325 | |
1326 // Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd() | |
1327 // when the three-way handshake completed. This cancels retransmission timer | |
1328 // and advances Tx window | |
1329 void | |
1330 TcpSocketBase::NewAck (SequenceNumber const& ack) | |
1331 { | |
1332 NS_LOG_FUNCTION (this << ack); | |
1333 | |
1334 if (m_state != SYN_RCVD) | |
1335 { // Set RTO unless the ACK is received in SYN_RCVD state | |
1336 NS_LOG_LOGIC (this << " Cancelled ReTxTimeout event which was set to expir e at " << | |
1337 (Simulator::Now () + Simulator::GetDelayLeft (m_retxEvent)). GetSeconds ()); | |
1338 m_retxEvent.Cancel (); | |
1339 // On recieving a "New" ack we restart retransmission timer .. RFC 2988 | |
1340 Time rto = m_rtt->RetransmitTimeout (); | |
1341 NS_LOG_LOGIC (this << " Schedule ReTxTimeout at time " << | |
1342 Simulator::Now ().GetSeconds () << " to expire at time " << | |
1343 (Simulator::Now () + rto).GetSeconds ()); | |
1344 m_retxEvent = Simulator::Schedule (rto, &TcpSocketBase::ReTxTimeout, this) ; | |
1345 } | |
1346 if (m_rxWindowSize == 0 && m_persistEvent.IsExpired ()) | |
1347 { // Zero window: Enter persist state to send 1 byte to probe | |
1348 NS_LOG_LOGIC (this << "Enter zerowindow persist state"); | |
1349 NS_LOG_LOGIC (this << "Cancelled ReTxTimeout event which was set to expire at " << | |
1350 (Simulator::Now () + Simulator::GetDelayLeft (m_retxEvent)). GetSeconds ()); | |
1351 m_retxEvent.Cancel (); | |
1352 NS_LOG_LOGIC ("Schedule persist timeout at time " << | |
1353 Simulator::Now ().GetSeconds () << " to expire at time " << | |
1354 (Simulator::Now () + m_persistTime).GetSeconds ()); | |
1355 m_persistEvent = Simulator::Schedule (m_persistTime, &TcpSocketBase::Persi stTimeout, this); | |
1356 NS_ASSERT (m_persistTime == Simulator::GetDelayLeft (m_persistEvent)); | |
1357 } | |
1358 // Note the highest ACK and tell app to send more | |
1359 NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack << | |
1360 " numberAck " << (ack - m_txBuffer.HeadSeq ())); // Number bytes ack'ed | |
1361 m_txBuffer.SetHeadSeq (ack); | |
1362 if (GetTxAvailable () > 0) | |
1363 { | |
1364 NotifySend (GetTxAvailable ()); | |
1365 } | |
1366 if (ack > m_nextTxSequence) | |
1367 { | |
1368 m_nextTxSequence = ack; // If advanced | |
1369 } | |
1370 if (m_txBuffer.Size () == 0) | |
1371 { // No retransmit timer if no data to retransmit | |
1372 NS_LOG_LOGIC (this << " Cancelled ReTxTimeout event which was set to expir e at " << | |
1373 (Simulator::Now () + Simulator::GetDelayLeft (m_retxEvent)). GetSeconds ()); | |
1374 m_retxEvent.Cancel (); | |
1375 } | |
1376 // Try to send more data | |
1377 SendPendingData (m_connected); | |
1378 } | |
1379 | |
1380 // Retransmit timeout | |
1381 void | |
1382 TcpSocketBase::ReTxTimeout () | |
1383 { | |
1384 NS_LOG_FUNCTION (this); | |
1385 NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().Get Seconds ()); | |
1386 // If erroneous timeout in closed/timed-wait state, just return | |
1387 if (m_state == CLOSED || m_state == TIME_WAIT) return; | |
1388 // If all data are received, just return | |
1389 if (m_txBuffer.HeadSeq () >= m_nextTxSequence) return; | |
1390 | |
1391 Retransmit (); | |
Adrian
2010/06/25 08:46:10
Put the variant-specific behaviour in Retransmit()
| |
1392 } | |
1393 | |
1394 void | |
1395 TcpSocketBase::DelAckTimeout () | |
1396 { | |
1397 SendEmptyPacket (TcpHeader::ACK); | |
1398 } | |
1399 | |
1400 void | |
1401 TcpSocketBase::LastAckTimeout () | |
1402 { | |
1403 m_lastAckEvent.Cancel (); | |
1404 if (m_state == LAST_ACK) | |
1405 { | |
1406 CloseAndNotify (); | |
1407 } | |
1408 if (!m_closeNotified) | |
1409 { | |
1410 m_closeNotified = true; | |
1411 } | |
1412 } | |
1413 | |
1414 // Send 1-byte data to probe for the window size at the receiver when | |
1415 // the local knowledge tells that the receiver has zero window size | |
1416 // C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17 | |
1417 void | |
1418 TcpSocketBase::PersistTimeout () | |
1419 { | |
1420 NS_LOG_LOGIC ("PersistTimeout expired at " << Simulator::Now ().GetSeconds ()) ; | |
1421 m_persistTime = std::min (Seconds (60), Scalar (2) * m_persistTime); // max pe rsist timeout = 60s | |
1422 Ptr<Packet> p = m_txBuffer.CopyFromSeq (1, m_nextTxSequence); | |
1423 TcpHeader tcpHeader; | |
1424 tcpHeader.SetSequenceNumber (m_nextTxSequence); | |
1425 tcpHeader.SetAckNumber (m_rxBuffer.NextRxSeq ()); | |
1426 tcpHeader.SetSourcePort (m_endPoint->GetLocalPort ()); | |
1427 tcpHeader.SetDestinationPort (m_endPoint->GetPeerPort ()); | |
1428 tcpHeader.SetWindowSize (AdvertisedWindowSize ()); | |
1429 | |
1430 m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), | |
1431 m_endPoint->GetPeerAddress (), m_boundnetdevice); | |
1432 NS_LOG_LOGIC ("Schedule persist timeout at time " | |
1433 << Simulator::Now ().GetSeconds () << " to expire at time " | |
1434 << (Simulator::Now () + m_persistTime).GetSeconds ()); | |
1435 m_persistEvent = Simulator::Schedule (m_persistTime, &TcpSocketBase::PersistTi meout, this); | |
1436 } | |
1437 | |
1438 void | |
1439 TcpSocketBase::Retransmit () | |
1440 { | |
1441 m_nextTxSequence = m_txBuffer.HeadSeq (); // Start from highest Ack | |
1442 m_rtt->IncreaseMultiplier (); // Double the timeout value for next retx timer | |
1443 m_dupAckCount = 0; | |
1444 DoRetransmit (); // Retransmit the packet | |
1445 } | |
Adrian
2010/06/25 08:46:10
This is the baseline behaviour (as of RFC793, exce
| |
1446 | |
1447 void | |
1448 TcpSocketBase::DoRetransmit () | |
1449 { | |
Adrian
2010/06/25 08:46:10
DoRetransmit blindly re-send the packet at m_nextT
| |
1450 NS_LOG_FUNCTION (this); | |
1451 uint8_t flags = TcpHeader::ACK; | |
1452 // Retransmit SYN packet | |
1453 if (m_state == SYN_SENT) | |
1454 { | |
1455 if (m_cnCount > 0) | |
1456 { | |
1457 SendEmptyPacket (TcpHeader::SYN); | |
1458 } | |
1459 else | |
1460 { | |
1461 NotifyConnectionFailed (); | |
1462 } | |
1463 return; | |
1464 } | |
1465 // Retransmit non-data packet: Only if in FIN_WAIT_1 state | |
1466 if (m_txBuffer.SizeFromSeq (m_nextTxSequence) == 0) | |
1467 { | |
1468 if (m_state == FIN_WAIT_1) | |
1469 { // Must have lost FIN, re-send | |
1470 SendEmptyPacket (TcpHeader::FIN); | |
1471 } | |
1472 return; | |
1473 } | |
1474 // Retransmit a data packet: Extract data | |
1475 NS_ASSERT (m_nextTxSequence == m_txBuffer.HeadSeq ()); | |
1476 Ptr<Packet> p = m_txBuffer.CopyFromSeq (m_segmentSize, m_nextTxSequence); | |
1477 // Close-on-Empty check | |
1478 if (m_closeOnEmpty && m_txBuffer.SizeFromSeq (m_nextTxSequence) == p->GetSize ()) | |
1479 { | |
1480 flags |= TcpHeader::FIN; | |
1481 } | |
1482 // Reset transmission timeout | |
1483 NS_LOG_LOGIC ("TcpSocketBase " << this << " retxing seq " << m_txBuffer.HeadSe q ()); | |
1484 if (m_retxEvent.IsExpired ()) | |
1485 { | |
1486 Time rto = m_rtt->RetransmitTimeout (); | |
1487 NS_LOG_LOGIC (this << " Schedule ReTxTimeout at time " << | |
1488 Simulator::Now ().GetSeconds () << " to expire at time " << | |
1489 (Simulator::Now () + rto).GetSeconds ()); | |
1490 m_retxEvent = Simulator::Schedule (rto, &TcpSocketBase::ReTxTimeout, this) ; | |
1491 } | |
1492 m_rtt->SentSeq (m_txBuffer.HeadSeq (), p->GetSize ()); | |
1493 // And send the packet | |
1494 TcpHeader tcpHeader; | |
1495 tcpHeader.SetSequenceNumber (m_nextTxSequence); | |
1496 tcpHeader.SetAckNumber (m_rxBuffer.NextRxSeq ()); | |
1497 tcpHeader.SetSourcePort (m_endPoint->GetLocalPort ()); | |
1498 tcpHeader.SetDestinationPort (m_endPoint->GetPeerPort ()); | |
1499 tcpHeader.SetFlags (flags); | |
1500 tcpHeader.SetWindowSize (AdvertisedWindowSize ()); | |
1501 | |
1502 m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), | |
1503 m_endPoint->GetPeerAddress (), m_boundnetdevice); | |
1504 } | |
1505 | |
1506 void | |
1507 TcpSocketBase::CancelAllTimers () | |
1508 { | |
1509 m_retxEvent.Cancel (); | |
1510 m_persistEvent.Cancel (); | |
1511 m_delAckEvent.Cancel (); | |
1512 m_lastAckEvent.Cancel (); | |
1513 } | |
1514 | |
1515 /* Below are the attribute get/set functions */ | |
1516 | |
1517 void | |
1518 TcpSocketBase::SetSndBufSize (uint32_t size) | |
1519 { | |
1520 m_txBuffer.SetMaxBufferSize (size); | |
1521 } | |
1522 | |
1523 uint32_t | |
1524 TcpSocketBase::GetSndBufSize (void) const | |
1525 { | |
1526 return m_txBuffer.MaxBufferSize (); | |
1527 } | |
1528 | |
1529 void | |
1530 TcpSocketBase::SetRcvBufSize (uint32_t size) | |
1531 { | |
1532 m_rxBuffer.SetMaxBufferSize (size); | |
1533 } | |
1534 | |
1535 uint32_t | |
1536 TcpSocketBase::GetRcvBufSize (void) const | |
1537 { | |
1538 return m_rxBuffer.MaxBufferSize (); | |
1539 } | |
1540 | |
1541 void | |
1542 TcpSocketBase::SetSegSize (uint32_t size) | |
1543 { | |
1544 m_segmentSize = size; | |
1545 NS_ABORT_MSG_UNLESS (m_state == CLOSED, "Cannot change segment size dynamicall y."); | |
1546 } | |
1547 | |
1548 uint32_t | |
1549 TcpSocketBase::GetSegSize (void) const | |
1550 { | |
1551 return m_segmentSize; | |
1552 } | |
1553 | |
1554 void | |
1555 TcpSocketBase::SetConnTimeout (Time timeout) | |
1556 { | |
1557 m_cnTimeout = timeout; | |
1558 } | |
1559 | |
1560 Time | |
1561 TcpSocketBase::GetConnTimeout (void) const | |
1562 { | |
1563 return m_cnTimeout; | |
1564 } | |
1565 | |
1566 void | |
1567 TcpSocketBase::SetConnCount (uint32_t count) | |
1568 { | |
1569 m_cnCount = count; | |
1570 } | |
1571 | |
1572 uint32_t | |
1573 TcpSocketBase::GetConnCount (void) const | |
1574 { | |
1575 return m_cnCount; | |
1576 } | |
1577 | |
1578 void | |
1579 TcpSocketBase::SetDelAckTimeout (Time timeout) | |
1580 { | |
1581 m_delAckTimeout = timeout; | |
1582 } | |
1583 | |
1584 Time | |
1585 TcpSocketBase::GetDelAckTimeout (void) const | |
1586 { | |
1587 return m_delAckTimeout; | |
1588 } | |
1589 | |
1590 void | |
1591 TcpSocketBase::SetDelAckMaxCount (uint32_t count) | |
1592 { | |
1593 m_delAckMaxCount = count; | |
1594 } | |
1595 | |
1596 uint32_t | |
1597 TcpSocketBase::GetDelAckMaxCount (void) const | |
1598 { | |
1599 return m_delAckMaxCount; | |
1600 } | |
1601 | |
1602 } // namespace ns3 | |
OLD | NEW |