17 * |
17 * |
18 * Author: Raj Bhattacharjea <raj.b@gatech.edu> |
18 * Author: Raj Bhattacharjea <raj.b@gatech.edu> |
19 */ |
19 */ |
20 |
20 |
21 |
21 |
|
22 #include "ns3/abort.h" |
22 #include "ns3/node.h" |
23 #include "ns3/node.h" |
23 #include "ns3/inet-socket-address.h" |
24 #include "ns3/inet-socket-address.h" |
24 #include "ns3/log.h" |
25 #include "ns3/log.h" |
25 #include "ns3/ipv4.h" |
26 #include "ns3/ipv4.h" |
26 #include "ns3/ipv4-interface-address.h" |
27 #include "ns3/ipv4-interface-address.h" |
27 #include "ns3/ipv4-route.h" |
28 #include "ns3/ipv4-route.h" |
28 #include "tcp-socket-impl.h" |
29 #include "ns3/ipv4-routing-protocol.h" |
29 #include "tcp-l4-protocol.h" |
|
30 #include "ipv4-end-point.h" |
|
31 #include "ns3/simulation-singleton.h" |
30 #include "ns3/simulation-singleton.h" |
32 #include "tcp-typedefs.h" |
|
33 #include "ns3/simulator.h" |
31 #include "ns3/simulator.h" |
34 #include "ns3/packet.h" |
32 #include "ns3/packet.h" |
35 #include "ns3/uinteger.h" |
33 #include "ns3/uinteger.h" |
36 #include "ns3/trace-source-accessor.h" |
34 #include "ns3/trace-source-accessor.h" |
|
35 #include "tcp-typedefs.h" |
|
36 #include "tcp-socket-impl.h" |
|
37 #include "tcp-l4-protocol.h" |
|
38 #include "ipv4-end-point.h" |
37 |
39 |
38 #include <algorithm> |
40 #include <algorithm> |
39 |
41 |
40 NS_LOG_COMPONENT_DEFINE ("TcpSocketImpl"); |
42 NS_LOG_COMPONENT_DEFINE ("TcpSocketImpl"); |
41 |
43 |
81 m_lastRxAck (0), |
83 m_lastRxAck (0), |
82 m_nextRxSequence (0), |
84 m_nextRxSequence (0), |
83 m_rxAvailable (0), |
85 m_rxAvailable (0), |
84 m_rxBufSize (0), |
86 m_rxBufSize (0), |
85 m_pendingData (0), |
87 m_pendingData (0), |
|
88 m_segmentSize (0), // For attribute initialization consistency (quiet valgrind) |
86 m_rxWindowSize (0), |
89 m_rxWindowSize (0), |
|
90 m_initialCWnd (0), // For attribute initialization consistency (quiet valgrind) |
87 m_persistTime (Seconds(6)), //XXX hook this into attributes? |
91 m_persistTime (Seconds(6)), //XXX hook this into attributes? |
88 m_rtt (0), |
92 m_rtt (0), |
89 m_lastMeasuredRtt (Seconds(0.0)) |
93 m_lastMeasuredRtt (Seconds(0.0)) |
90 { |
94 { |
91 NS_LOG_FUNCTION (this); |
95 NS_LOG_FUNCTION (this); |
169 NS_LOG_FUNCTION(this); |
173 NS_LOG_FUNCTION(this); |
170 m_node = 0; |
174 m_node = 0; |
171 if (m_endPoint != 0) |
175 if (m_endPoint != 0) |
172 { |
176 { |
173 NS_ASSERT (m_tcp != 0); |
177 NS_ASSERT (m_tcp != 0); |
174 /** |
178 /* |
175 * Note that this piece of code is a bit tricky: |
179 * Note that this piece of code is seriously convoluted: When we do a |
176 * when DeAllocate is called, it will call into |
180 * Bind we allocate an Ipv4Endpoint. Immediately thereafter we always do |
177 * Ipv4EndPointDemux::Deallocate which triggers |
181 * a FinishBind which sets the DestroyCallback of that endpoint to be |
178 * a delete of the associated endPoint which triggers |
182 * TcpSocketImpl::Destroy, below. When m_tcp->DeAllocate is called, it |
179 * in turn a call to the method ::Destroy below |
183 * will in turn call into Ipv4EndpointDemux::DeAllocate with the endpoint |
180 * will will zero the m_endPoint field. |
184 * (m_endPoint). The demux will look up the endpoint and destroy it (the |
|
185 * corollary is that we don't own the object pointed to by m_endpoint, we |
|
186 * just borrowed it). The destructor for the endpoint will call the |
|
187 * DestroyCallback which will then invoke TcpSocketImpl::Destroy below. |
|
188 * Destroy will zero m_node, m_tcp and m_endpoint. The zero of m_node and |
|
189 * m_tcp need to be here also in case the endpoint is deallocated before |
|
190 * shutdown. |
181 */ |
191 */ |
182 NS_ASSERT (m_endPoint != 0); |
192 NS_ASSERT (m_endPoint != 0); |
183 m_tcp->DeAllocate (m_endPoint); |
193 m_tcp->DeAllocate (m_endPoint); |
184 NS_ASSERT (m_endPoint == 0); |
194 NS_ASSERT (m_endPoint == 0); |
185 } |
195 } |
190 |
200 |
191 void |
201 void |
192 TcpSocketImpl::SetNode (Ptr<Node> node) |
202 TcpSocketImpl::SetNode (Ptr<Node> node) |
193 { |
203 { |
194 m_node = node; |
204 m_node = node; |
195 // Initialize some variables |
205 /* |
|
206 * Set the congestion window to IW. This method is called from the L4 |
|
207 * Protocol after it creates the socket. The Attribute system takes |
|
208 * care of setting m_initialCWnd and m_segmentSize to their default |
|
209 * values. m_cWnd depends on m_initialCwnd and m_segmentSize so it |
|
210 * also needs to be updated in SetInitialCwnd and SetSegSize. |
|
211 */ |
196 m_cWnd = m_initialCWnd * m_segmentSize; |
212 m_cWnd = m_initialCWnd * m_segmentSize; |
197 } |
213 } |
198 |
214 |
199 void |
215 void |
200 TcpSocketImpl::SetTcp (Ptr<TcpL4Protocol> tcp) |
216 TcpSocketImpl::SetTcp (Ptr<TcpL4Protocol> tcp) |
347 |
362 |
348 if (ipv4->GetRoutingProtocol () != 0) |
363 if (ipv4->GetRoutingProtocol () != 0) |
349 { |
364 { |
350 Ipv4Header header; |
365 Ipv4Header header; |
351 header.SetDestination (m_remoteAddress); |
366 header.SetDestination (m_remoteAddress); |
352 Socket::SocketErrno errno; |
367 Socket::SocketErrno errno_; |
353 Ptr<Ipv4Route> route; |
368 Ptr<Ipv4Route> route; |
354 uint32_t oif = 0; //specify non-zero if bound to a source address |
369 uint32_t oif = 0; //specify non-zero if bound to a source address |
355 // XXX here, cache the route in the endpoint? |
370 // XXX here, cache the route in the endpoint? |
356 route = ipv4->GetRoutingProtocol ()->RouteOutput (header, oif, errno); |
371 route = ipv4->GetRoutingProtocol ()->RouteOutput (Ptr<Packet> (), header, oif, errno_); |
357 if (route != 0) |
372 if (route != 0) |
358 { |
373 { |
359 NS_LOG_LOGIC ("Route exists"); |
374 NS_LOG_LOGIC ("Route exists"); |
360 m_endPoint->SetLocalAddress (route->GetSource ()); |
375 m_endPoint->SetLocalAddress (route->GetSource ()); |
361 } |
376 } |
362 else |
377 else |
363 { |
378 { |
364 NS_LOG_LOGIC ("TcpSocketImpl::Connect(): Route to " << m_remoteAddress << " does not exist"); |
379 NS_LOG_LOGIC ("TcpSocketImpl::Connect(): Route to " << m_remoteAddress << " does not exist"); |
365 NS_LOG_ERROR (errno); |
380 NS_LOG_ERROR (errno_); |
366 m_errno = errno; |
381 m_errno = errno_; |
367 return -1; |
382 return -1; |
368 } |
383 } |
369 } |
384 } |
370 else |
385 else |
371 { |
386 { |
652 States_t saveState = m_state; |
667 States_t saveState = m_state; |
653 NS_LOG_LOGIC ("TcpSocketImpl " << this << " processing event " << e); |
668 NS_LOG_LOGIC ("TcpSocketImpl " << this << " processing event " << e); |
654 // simulation singleton is a way to get a single global static instance of a |
669 // simulation singleton is a way to get a single global static instance of a |
655 // class intended to be a singleton; see simulation-singleton.h |
670 // class intended to be a singleton; see simulation-singleton.h |
656 SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e); |
671 SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e); |
|
672 NS_LOG_LOGIC ("TcpSocketImpl::ProcessEvent stateAction " << stateAction.action); |
657 // debug |
673 // debug |
658 if (stateAction.action == RST_TX) |
674 if (stateAction.action == RST_TX) |
659 { |
675 { |
660 NS_LOG_LOGIC ("TcpSocketImpl " << this << " sending RST from state " |
676 NS_LOG_LOGIC ("TcpSocketImpl " << this << " sending RST from state " |
661 << saveState << " event " << e); |
677 << saveState << " event " << e); |
676 Simulator::ScheduleNow(&TcpSocketImpl::ConnectionSucceeded, this); |
692 Simulator::ScheduleNow(&TcpSocketImpl::ConnectionSucceeded, this); |
677 //NotifyConnectionSucceeded (); |
693 //NotifyConnectionSucceeded (); |
678 m_connected = true; |
694 m_connected = true; |
679 m_endPoint->SetPeer (m_remoteAddress, m_remotePort); |
695 m_endPoint->SetPeer (m_remoteAddress, m_remotePort); |
680 NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); |
696 NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); |
|
697 } |
|
698 if (saveState < CLOSING && (m_state == CLOSING || m_state == TIMED_WAIT) ) |
|
699 { |
|
700 NS_LOG_LOGIC ("TcpSocketImpl peer closing, send EOF to application"); |
|
701 NotifyDataRecv (); |
681 } |
702 } |
682 |
703 |
683 if (needCloseNotify && !m_closeNotified) |
704 if (needCloseNotify && !m_closeNotified) |
684 { |
705 { |
685 NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " |
706 NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " |
691 << " event " << e); |
712 << " event " << e); |
692 NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " |
713 NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " |
693 << m_state << " event " << e |
714 << m_state << " event " << e |
694 << " set CloseNotif "); |
715 << " set CloseNotif "); |
695 } |
716 } |
|
717 |
|
718 if (m_state == CLOSED && saveState != CLOSED && m_endPoint != 0) |
|
719 { |
|
720 NS_ASSERT (m_tcp != 0); |
|
721 /* |
|
722 * We want to deallocate the endpoint now. We can't just naively call |
|
723 * Deallocate (see the comment in TcpSocketImpl::~TcpSocketImpl), we |
|
724 * have to turn off the DestroyCallback to keep it from calling back |
|
725 * into TcpSocketImpl::Destroy and closing pretty much everything down. |
|
726 * Once we have the callback disconnected, we can DeAllocate the |
|
727 * endpoint which actually deals with destroying the actual endpoint, |
|
728 * and then zero our member varible on general principles. |
|
729 */ |
|
730 m_endPoint->SetDestroyCallback(MakeNullCallback<void>()); |
|
731 m_tcp->DeAllocate (m_endPoint); |
|
732 m_endPoint = 0; |
|
733 } |
|
734 |
696 return stateAction.action; |
735 return stateAction.action; |
697 } |
736 } |
698 |
737 |
699 void TcpSocketImpl::SendEmptyPacket (uint8_t flags) |
738 void TcpSocketImpl::SendEmptyPacket (uint8_t flags) |
700 { |
739 { |
848 |
888 |
849 // Look up the source address |
889 // Look up the source address |
850 if (ipv4->GetRoutingProtocol () != 0) |
890 if (ipv4->GetRoutingProtocol () != 0) |
851 { |
891 { |
852 Ipv4Header header; |
892 Ipv4Header header; |
853 Socket::SocketErrno errno; |
893 Socket::SocketErrno errno_; |
854 Ptr<Ipv4Route> route; |
894 Ptr<Ipv4Route> route; |
855 uint32_t oif = 0; //specify non-zero if bound to a source address |
895 uint32_t oif = 0; //specify non-zero if bound to a source address |
856 header.SetDestination (m_remoteAddress); |
896 header.SetDestination (m_remoteAddress); |
857 route = ipv4->GetRoutingProtocol ()->RouteOutput (header, oif, errno); |
897 route = ipv4->GetRoutingProtocol ()->RouteOutput (Ptr<Packet> (), header, oif, errno_); |
858 if (route != 0) |
898 if (route != 0) |
859 { |
899 { |
860 NS_LOG_LOGIC ("Route exists"); |
900 NS_LOG_LOGIC ("Route exists"); |
861 m_endPoint->SetLocalAddress (route->GetSource ()); |
901 m_endPoint->SetLocalAddress (route->GetSource ()); |
862 } |
902 } |
863 else |
903 else |
864 { |
904 { |
865 NS_LOG_ERROR (errno); |
905 NS_LOG_ERROR (errno_); |
866 m_errno = errno; |
906 m_errno = errno_; |
867 return -1; |
907 return -1; |
868 } |
908 } |
869 } |
909 } |
870 else |
910 else |
871 { |
911 { |
1151 NS_LOG_FUNCTION (this << p << "tcpHeader " << fromAddress); |
1191 NS_LOG_FUNCTION (this << p << "tcpHeader " << fromAddress); |
1152 NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewRx," |
1192 NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewRx," |
1153 << " seq " << tcpHeader.GetSequenceNumber() |
1193 << " seq " << tcpHeader.GetSequenceNumber() |
1154 << " ack " << tcpHeader.GetAckNumber() |
1194 << " ack " << tcpHeader.GetAckNumber() |
1155 << " p.size is " << p->GetSize () ); |
1195 << " p.size is " << p->GetSize () ); |
1156 NS_LOG_DEBUG ("TcpSocketImpl " << this << |
|
1157 " NewRx," << |
|
1158 " seq " << tcpHeader.GetSequenceNumber() << |
|
1159 " ack " << tcpHeader.GetAckNumber() << |
|
1160 " p.size is " << p->GetSize()); |
|
1161 States_t origState = m_state; |
1196 States_t origState = m_state; |
1162 if (RxBufferFreeSpace() < p->GetSize()) |
1197 if (RxBufferFreeSpace() < p->GetSize()) |
1163 { //if not enough room, fragment |
1198 { //if not enough room, fragment |
1164 p = p->CreateFragment(0, RxBufferFreeSpace()); |
1199 p = p->CreateFragment(0, RxBufferFreeSpace()); |
1165 } |
1200 } |
1623 |
1658 |
1624 void |
1659 void |
1625 TcpSocketImpl::SetSegSize (uint32_t size) |
1660 TcpSocketImpl::SetSegSize (uint32_t size) |
1626 { |
1661 { |
1627 m_segmentSize = size; |
1662 m_segmentSize = size; |
|
1663 /* |
|
1664 * Make sure that the congestion window is initialized for IW properly. We |
|
1665 * can't do this after the connection starts up or would would most likely |
|
1666 * change m_cWnd out from under the protocol. That would be Bad (TM). |
|
1667 */ |
|
1668 NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpSocketImpl::SetSegSize(): Cannot change segment size dynamically."); |
|
1669 m_cWnd = m_initialCWnd * m_segmentSize; |
1628 } |
1670 } |
1629 |
1671 |
1630 uint32_t |
1672 uint32_t |
1631 TcpSocketImpl::GetSegSize (void) const |
1673 TcpSocketImpl::GetSegSize (void) const |
1632 { |
1674 { |
1647 |
1689 |
1648 void |
1690 void |
1649 TcpSocketImpl::SetInitialCwnd (uint32_t cwnd) |
1691 TcpSocketImpl::SetInitialCwnd (uint32_t cwnd) |
1650 { |
1692 { |
1651 m_initialCWnd = cwnd; |
1693 m_initialCWnd = cwnd; |
|
1694 /* |
|
1695 * Make sure that the congestion window is initialized for IW properly. We |
|
1696 * can't do this after the connection starts up or would would most likely |
|
1697 * change m_cWnd out from under the protocol. That would be Bad (TM). |
|
1698 */ |
|
1699 NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpSocketImpl::SetInitialCwnd(): Cannot change initial cwnd dynamically."); |
|
1700 m_cWnd = m_initialCWnd * m_segmentSize; |
1652 } |
1701 } |
1653 |
1702 |
1654 uint32_t |
1703 uint32_t |
1655 TcpSocketImpl::GetInitialCwnd (void) const |
1704 TcpSocketImpl::GetInitialCwnd (void) const |
1656 { |
1705 { |