|
raj@2224
|
1 |
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
|
raj@2224
|
2 |
/*
|
|
raj@2224
|
3 |
* Copyright (c) 2007 Georgia Tech Research Corporation
|
|
raj@2224
|
4 |
*
|
|
raj@2224
|
5 |
* This program is free software; you can redistribute it and/or modify
|
|
raj@2224
|
6 |
* it under the terms of the GNU General Public License version 2 as
|
|
raj@2224
|
7 |
* published by the Free Software Foundation;
|
|
raj@2224
|
8 |
*
|
|
raj@2224
|
9 |
* This program is distributed in the hope that it will be useful,
|
|
raj@2224
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
raj@2224
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
raj@2224
|
12 |
* GNU General Public License for more details.
|
|
raj@2224
|
13 |
*
|
|
raj@2224
|
14 |
* You should have received a copy of the GNU General Public License
|
|
raj@2224
|
15 |
* along with this program; if not, write to the Free Software
|
|
raj@2224
|
16 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
raj@2224
|
17 |
*
|
|
raj@2224
|
18 |
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
|
|
raj@2224
|
19 |
*/
|
|
raj@2224
|
20 |
|
|
raj@2224
|
21 |
|
|
raj@2224
|
22 |
#include "ns3/node.h"
|
|
raj@2224
|
23 |
#include "ns3/inet-socket-address.h"
|
|
raj@2224
|
24 |
#include "ns3/log.h"
|
|
raj@2224
|
25 |
#include "ns3/ipv4.h"
|
|
raj@2224
|
26 |
#include "tcp-socket.h"
|
|
raj@2224
|
27 |
#include "tcp-l4-protocol.h"
|
|
raj@2224
|
28 |
#include "ipv4-end-point.h"
|
|
raj@2224
|
29 |
#include "ipv4-l4-demux.h"
|
|
raj@2224
|
30 |
#include "ns3/simulation-singleton.h"
|
|
raj@2224
|
31 |
#include "tcp-typedefs.h"
|
|
raj@2224
|
32 |
#include "ns3/simulator.h"
|
|
raj@2224
|
33 |
#include "ns3/packet.h"
|
|
raj@2224
|
34 |
|
|
raj@2224
|
35 |
#include <algorithm>
|
|
raj@2224
|
36 |
|
|
raj@2224
|
37 |
NS_LOG_COMPONENT_DEFINE ("TcpSocket");
|
|
raj@2224
|
38 |
|
|
raj@2224
|
39 |
using namespace std;
|
|
raj@2224
|
40 |
|
|
raj@2224
|
41 |
namespace ns3 {
|
|
raj@2224
|
42 |
|
|
mathieu@2592
|
43 |
TcpSocket::TcpSocket ()
|
|
raj@2224
|
44 |
: m_skipRetxResched (false),
|
|
raj@2224
|
45 |
m_dupAckCount (0),
|
|
raj@2224
|
46 |
m_endPoint (0),
|
|
mathieu@2592
|
47 |
m_node (0),
|
|
mathieu@2592
|
48 |
m_tcp (0),
|
|
raj@2224
|
49 |
m_errno (ERROR_NOTERROR),
|
|
raj@2224
|
50 |
m_shutdownSend (false),
|
|
raj@2224
|
51 |
m_shutdownRecv (false),
|
|
raj@2224
|
52 |
m_connected (false),
|
|
raj@2224
|
53 |
m_state (CLOSED),
|
|
raj@2224
|
54 |
m_closeNotified (false),
|
|
raj@2224
|
55 |
m_closeRequestNotified (false),
|
|
raj@2224
|
56 |
m_closeOnEmpty (false),
|
|
tomh@2226
|
57 |
m_pendingClose (false),
|
|
raj@2224
|
58 |
m_nextTxSequence (0),
|
|
raj@2224
|
59 |
m_highTxMark (0),
|
|
raj@2224
|
60 |
m_highestRxAck (0),
|
|
raj@2224
|
61 |
m_lastRxAck (0),
|
|
raj@2224
|
62 |
m_nextRxSequence (0),
|
|
raj@2224
|
63 |
m_pendingData (0),
|
|
mathieu@2592
|
64 |
m_rtt (0),
|
|
mathieu@2556
|
65 |
m_lastMeasuredRtt (Seconds(0.0))
|
|
raj@2224
|
66 |
{
|
|
raj@2224
|
67 |
NS_LOG_FUNCTION;
|
|
mathieu@2592
|
68 |
NS_LOG_PARAMS (this);
|
|
mathieu@2556
|
69 |
|
|
raj@2224
|
70 |
}
|
|
raj@2224
|
71 |
|
|
mathieu@2608
|
72 |
TcpSocket::TcpSocket(const TcpSocket& sock)
|
|
mathieu@2608
|
73 |
: Socket(sock), //copy the base class callbacks
|
|
mathieu@2608
|
74 |
m_skipRetxResched (sock.m_skipRetxResched),
|
|
mathieu@2608
|
75 |
m_dupAckCount (sock.m_dupAckCount),
|
|
mathieu@2608
|
76 |
m_endPoint (0),
|
|
mathieu@2608
|
77 |
m_node (sock.m_node),
|
|
mathieu@2608
|
78 |
m_tcp (sock.m_tcp),
|
|
mathieu@2608
|
79 |
m_remoteAddress (sock.m_remoteAddress),
|
|
mathieu@2608
|
80 |
m_remotePort (sock.m_remotePort),
|
|
mathieu@2608
|
81 |
m_localAddress (sock.m_localAddress),
|
|
mathieu@2608
|
82 |
m_localPort (sock.m_localPort),
|
|
mathieu@2608
|
83 |
m_errno (sock.m_errno),
|
|
mathieu@2608
|
84 |
m_shutdownSend (sock.m_shutdownSend),
|
|
mathieu@2608
|
85 |
m_shutdownRecv (sock.m_shutdownRecv),
|
|
mathieu@2608
|
86 |
m_connected (sock.m_connected),
|
|
mathieu@2608
|
87 |
m_state (sock.m_state),
|
|
mathieu@2608
|
88 |
m_closeNotified (sock.m_closeNotified),
|
|
mathieu@2608
|
89 |
m_closeRequestNotified (sock.m_closeRequestNotified),
|
|
mathieu@2608
|
90 |
m_closeOnEmpty (sock.m_closeOnEmpty),
|
|
mathieu@2608
|
91 |
m_pendingClose (sock.m_pendingClose),
|
|
mathieu@2608
|
92 |
m_nextTxSequence (sock.m_nextTxSequence),
|
|
mathieu@2608
|
93 |
m_highTxMark (sock.m_highTxMark),
|
|
mathieu@2608
|
94 |
m_highestRxAck (sock.m_highestRxAck),
|
|
mathieu@2608
|
95 |
m_lastRxAck (sock.m_lastRxAck),
|
|
mathieu@2608
|
96 |
m_nextRxSequence (sock.m_nextRxSequence),
|
|
mathieu@2608
|
97 |
m_pendingData (0),
|
|
mathieu@2608
|
98 |
m_segmentSize (sock.m_segmentSize),
|
|
mathieu@2608
|
99 |
m_rxWindowSize (sock.m_rxWindowSize),
|
|
mathieu@2608
|
100 |
m_advertisedWindowSize (sock.m_advertisedWindowSize),
|
|
mathieu@2608
|
101 |
m_cWnd (sock.m_cWnd),
|
|
mathieu@2608
|
102 |
m_ssThresh (sock.m_ssThresh),
|
|
mathieu@2608
|
103 |
m_initialCWnd (sock.m_initialCWnd),
|
|
mathieu@2608
|
104 |
m_rtt (0),
|
|
mathieu@2608
|
105 |
m_lastMeasuredRtt (Seconds(0.0)),
|
|
mathieu@2608
|
106 |
m_cnTimeout (sock.m_cnTimeout),
|
|
mathieu@2608
|
107 |
m_cnCount (sock.m_cnCount)
|
|
mathieu@2608
|
108 |
{
|
|
mathieu@2608
|
109 |
NS_LOG_FUNCTION;
|
|
mathieu@2608
|
110 |
NS_LOG_LOGIC("Invoked the copy constructor");
|
|
mathieu@2608
|
111 |
//copy the pending data if necessary
|
|
mathieu@2608
|
112 |
if(sock.m_pendingData)
|
|
mathieu@2608
|
113 |
{
|
|
mathieu@2608
|
114 |
m_pendingData = sock.m_pendingData->Copy();
|
|
mathieu@2608
|
115 |
}
|
|
mathieu@2608
|
116 |
//copy the rtt if necessary
|
|
mathieu@2608
|
117 |
if (sock.m_rtt)
|
|
mathieu@2608
|
118 |
{
|
|
mathieu@2608
|
119 |
m_rtt = sock.m_rtt->Copy();
|
|
mathieu@2608
|
120 |
}
|
|
mathieu@2608
|
121 |
//can't "copy" the endpoint just yes, must do this when we know the peer info
|
|
mathieu@2608
|
122 |
//too; this is in SYN_ACK_TX
|
|
mathieu@2608
|
123 |
}
|
|
mathieu@2608
|
124 |
|
|
raj@2224
|
125 |
TcpSocket::~TcpSocket ()
|
|
raj@2224
|
126 |
{
|
|
raj@2224
|
127 |
NS_LOG_FUNCTION;
|
|
raj@2668
|
128 |
NS_LOG_PARAMS(this);
|
|
raj@2224
|
129 |
m_node = 0;
|
|
raj@2224
|
130 |
if (m_endPoint != 0)
|
|
raj@2224
|
131 |
{
|
|
raj@2224
|
132 |
NS_ASSERT (m_tcp != 0);
|
|
raj@2224
|
133 |
/**
|
|
raj@2224
|
134 |
* Note that this piece of code is a bit tricky:
|
|
raj@2224
|
135 |
* when DeAllocate is called, it will call into
|
|
raj@2224
|
136 |
* Ipv4EndPointDemux::Deallocate which triggers
|
|
raj@2224
|
137 |
* a delete of the associated endPoint which triggers
|
|
raj@2224
|
138 |
* in turn a call to the method ::Destroy below
|
|
raj@2224
|
139 |
* will will zero the m_endPoint field.
|
|
raj@2224
|
140 |
*/
|
|
raj@2224
|
141 |
NS_ASSERT (m_endPoint != 0);
|
|
raj@2224
|
142 |
m_tcp->DeAllocate (m_endPoint);
|
|
raj@2224
|
143 |
NS_ASSERT (m_endPoint == 0);
|
|
raj@2224
|
144 |
}
|
|
raj@2224
|
145 |
m_tcp = 0;
|
|
raj@2224
|
146 |
delete m_pendingData; //prevents leak
|
|
raj@2353
|
147 |
m_pendingData = 0;
|
|
raj@2224
|
148 |
}
|
|
raj@2224
|
149 |
|
|
mathieu@2592
|
150 |
void
|
|
mathieu@2592
|
151 |
TcpSocket::SetNode (Ptr<Node> node)
|
|
mathieu@2592
|
152 |
{
|
|
mathieu@2592
|
153 |
m_node = node;
|
|
mathieu@2592
|
154 |
Ptr<Tcp> t = node->GetObject<Tcp> ();
|
|
mathieu@2592
|
155 |
m_segmentSize = t->GetDefaultSegSize ();
|
|
mathieu@2592
|
156 |
m_rxWindowSize = t->GetDefaultAdvWin ();
|
|
mathieu@2592
|
157 |
m_advertisedWindowSize = t->GetDefaultAdvWin ();
|
|
mathieu@2592
|
158 |
m_cWnd = t->GetDefaultInitialCwnd () * m_segmentSize;
|
|
mathieu@2592
|
159 |
m_ssThresh = t->GetDefaultSsThresh ();
|
|
mathieu@2592
|
160 |
m_initialCWnd = t->GetDefaultInitialCwnd ();
|
|
mathieu@2592
|
161 |
m_cnTimeout = Seconds (t->GetDefaultConnTimeout ());
|
|
mathieu@2592
|
162 |
m_cnCount = t->GetDefaultConnCount ();
|
|
mathieu@2592
|
163 |
}
|
|
mathieu@2592
|
164 |
|
|
mathieu@2592
|
165 |
void
|
|
mathieu@2592
|
166 |
TcpSocket::SetTcp (Ptr<TcpL4Protocol> tcp)
|
|
mathieu@2592
|
167 |
{
|
|
mathieu@2592
|
168 |
m_tcp = tcp;
|
|
mathieu@2592
|
169 |
}
|
|
mathieu@2592
|
170 |
void
|
|
mathieu@2592
|
171 |
TcpSocket::SetRtt (Ptr<RttEstimator> rtt)
|
|
mathieu@2592
|
172 |
{
|
|
mathieu@2592
|
173 |
m_rtt = rtt;
|
|
mathieu@2592
|
174 |
}
|
|
mathieu@2592
|
175 |
|
|
mathieu@2592
|
176 |
|
|
raj@2224
|
177 |
enum Socket::SocketErrno
|
|
raj@2224
|
178 |
TcpSocket::GetErrno (void) const
|
|
raj@2224
|
179 |
{
|
|
raj@2224
|
180 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
181 |
return m_errno;
|
|
raj@2224
|
182 |
}
|
|
raj@2224
|
183 |
|
|
raj@2224
|
184 |
Ptr<Node>
|
|
raj@2224
|
185 |
TcpSocket::GetNode (void) const
|
|
raj@2224
|
186 |
{
|
|
raj@2224
|
187 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
188 |
return m_node;
|
|
raj@2224
|
189 |
}
|
|
raj@2224
|
190 |
|
|
raj@2224
|
191 |
void
|
|
raj@2224
|
192 |
TcpSocket::Destroy (void)
|
|
raj@2224
|
193 |
{
|
|
raj@2224
|
194 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
195 |
m_node = 0;
|
|
raj@2224
|
196 |
m_endPoint = 0;
|
|
raj@2224
|
197 |
m_tcp = 0;
|
|
raj@2353
|
198 |
m_retxEvent.Cancel ();
|
|
raj@2224
|
199 |
}
|
|
raj@2224
|
200 |
int
|
|
raj@2224
|
201 |
TcpSocket::FinishBind (void)
|
|
raj@2224
|
202 |
{
|
|
raj@2224
|
203 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
204 |
if (m_endPoint == 0)
|
|
raj@2224
|
205 |
{
|
|
raj@2224
|
206 |
return -1;
|
|
raj@2224
|
207 |
}
|
|
raj@2668
|
208 |
m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
|
|
raj@2668
|
209 |
m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
|
|
mathieu@2608
|
210 |
m_localAddress = m_endPoint->GetLocalAddress ();
|
|
mathieu@2608
|
211 |
m_localPort = m_endPoint->GetLocalPort ();
|
|
raj@2224
|
212 |
return 0;
|
|
raj@2224
|
213 |
}
|
|
raj@2224
|
214 |
|
|
raj@2224
|
215 |
int
|
|
raj@2224
|
216 |
TcpSocket::Bind (void)
|
|
raj@2224
|
217 |
{
|
|
raj@2224
|
218 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
219 |
m_endPoint = m_tcp->Allocate ();
|
|
raj@2224
|
220 |
return FinishBind ();
|
|
raj@2224
|
221 |
}
|
|
raj@2224
|
222 |
int
|
|
raj@2224
|
223 |
TcpSocket::Bind (const Address &address)
|
|
raj@2224
|
224 |
{
|
|
raj@2224
|
225 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
226 |
NS_LOG_PARAMS (this<<address);
|
|
raj@2224
|
227 |
if (!InetSocketAddress::IsMatchingType (address))
|
|
raj@2224
|
228 |
{
|
|
raj@2224
|
229 |
return ERROR_INVAL;
|
|
raj@2224
|
230 |
}
|
|
raj@2224
|
231 |
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
|
raj@2224
|
232 |
Ipv4Address ipv4 = transport.GetIpv4 ();
|
|
raj@2224
|
233 |
uint16_t port = transport.GetPort ();
|
|
raj@2224
|
234 |
if (ipv4 == Ipv4Address::GetAny () && port == 0)
|
|
raj@2224
|
235 |
{
|
|
raj@2224
|
236 |
m_endPoint = m_tcp->Allocate ();
|
|
raj@2224
|
237 |
NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
|
|
raj@2224
|
238 |
}
|
|
raj@2224
|
239 |
else if (ipv4 == Ipv4Address::GetAny () && port != 0)
|
|
raj@2224
|
240 |
{
|
|
raj@2224
|
241 |
m_endPoint = m_tcp->Allocate (port);
|
|
raj@2224
|
242 |
NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
|
|
raj@2224
|
243 |
}
|
|
raj@2224
|
244 |
else if (ipv4 != Ipv4Address::GetAny () && port == 0)
|
|
raj@2224
|
245 |
{
|
|
mathieu@2608
|
246 |
m_endPoint = m_tcp->Allocate (ipv4);
|
|
raj@2224
|
247 |
NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
|
|
raj@2224
|
248 |
}
|
|
raj@2224
|
249 |
else if (ipv4 != Ipv4Address::GetAny () && port != 0)
|
|
raj@2224
|
250 |
{
|
|
mathieu@2608
|
251 |
m_endPoint = m_tcp->Allocate (ipv4, port);
|
|
raj@2224
|
252 |
NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
|
|
raj@2224
|
253 |
}
|
|
raj@2224
|
254 |
|
|
raj@2224
|
255 |
return FinishBind ();
|
|
raj@2224
|
256 |
}
|
|
raj@2224
|
257 |
|
|
raj@2224
|
258 |
int
|
|
raj@2224
|
259 |
TcpSocket::ShutdownSend (void)
|
|
raj@2224
|
260 |
{
|
|
raj@2224
|
261 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
262 |
m_shutdownSend = true;
|
|
raj@2224
|
263 |
return 0;
|
|
raj@2224
|
264 |
}
|
|
raj@2224
|
265 |
int
|
|
raj@2224
|
266 |
TcpSocket::ShutdownRecv (void)
|
|
raj@2224
|
267 |
{
|
|
raj@2224
|
268 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
269 |
m_shutdownRecv = false;
|
|
raj@2224
|
270 |
return 0;
|
|
raj@2224
|
271 |
}
|
|
raj@2224
|
272 |
|
|
raj@2224
|
273 |
int
|
|
raj@2224
|
274 |
TcpSocket::Close (void)
|
|
raj@2224
|
275 |
{
|
|
raj@2224
|
276 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
277 |
if (m_state == CLOSED)
|
|
raj@2224
|
278 |
{
|
|
raj@2224
|
279 |
return -1;
|
|
raj@2224
|
280 |
}
|
|
mathieu@2608
|
281 |
if (m_pendingData && m_pendingData->Size() != 0)
|
|
mathieu@2608
|
282 |
{ // App close with pending data must wait until all data transmitted
|
|
mathieu@2608
|
283 |
m_closeOnEmpty = true;
|
|
mathieu@2608
|
284 |
NS_LOG_LOGIC("Socket " << this <<
|
|
mathieu@2608
|
285 |
" deferring close, state " << m_state);
|
|
mathieu@2608
|
286 |
return 0;
|
|
mathieu@2608
|
287 |
}
|
|
mathieu@2608
|
288 |
|
|
raj@2224
|
289 |
Actions_t action = ProcessEvent (APP_CLOSE);
|
|
raj@2224
|
290 |
ProcessAction (action);
|
|
raj@2224
|
291 |
ShutdownSend ();
|
|
raj@2224
|
292 |
return 0;
|
|
raj@2224
|
293 |
}
|
|
raj@2224
|
294 |
|
|
raj@2224
|
295 |
int
|
|
raj@2224
|
296 |
TcpSocket::Connect (const Address & address)
|
|
raj@2224
|
297 |
{
|
|
raj@2224
|
298 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
299 |
NS_LOG_PARAMS (this << address);
|
|
raj@2224
|
300 |
if (m_endPoint == 0)
|
|
raj@2224
|
301 |
{
|
|
raj@2224
|
302 |
if (Bind () == -1)
|
|
raj@2224
|
303 |
{
|
|
raj@2224
|
304 |
NS_ASSERT (m_endPoint == 0);
|
|
raj@2224
|
305 |
return -1;
|
|
raj@2224
|
306 |
}
|
|
raj@2224
|
307 |
NS_ASSERT (m_endPoint != 0);
|
|
raj@2224
|
308 |
}
|
|
raj@2224
|
309 |
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
|
mathieu@2608
|
310 |
m_remoteAddress = transport.GetIpv4 ();
|
|
mathieu@2608
|
311 |
m_remotePort = transport.GetPort ();
|
|
raj@2224
|
312 |
|
|
raj@2224
|
313 |
uint32_t localIfIndex;
|
|
mathieu@2257
|
314 |
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
|
|
raj@2224
|
315 |
|
|
mathieu@2608
|
316 |
if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
|
|
raj@2224
|
317 |
{
|
|
raj@2224
|
318 |
m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex));
|
|
raj@2224
|
319 |
}
|
|
raj@2224
|
320 |
else
|
|
raj@2224
|
321 |
{
|
|
raj@2224
|
322 |
m_errno = ERROR_NOROUTETOHOST;
|
|
raj@2224
|
323 |
return -1;
|
|
raj@2224
|
324 |
}
|
|
raj@2224
|
325 |
|
|
raj@2224
|
326 |
Actions_t action = ProcessEvent (APP_CONNECT);
|
|
raj@2224
|
327 |
bool success = ProcessAction (action);
|
|
raj@2224
|
328 |
if (success)
|
|
raj@2224
|
329 |
{
|
|
raj@2224
|
330 |
return 0;
|
|
raj@2224
|
331 |
}
|
|
raj@2224
|
332 |
return -1;
|
|
raj@2224
|
333 |
}
|
|
raj@2224
|
334 |
int
|
|
raj@2224
|
335 |
TcpSocket::Send (const Ptr<Packet> p) //p here is just data, no headers
|
|
mathieu@2608
|
336 |
{ // TCP Does not deal with packets from app, just data
|
|
mathieu@2608
|
337 |
return Send(p->PeekData(), p->GetSize());
|
|
raj@2224
|
338 |
}
|
|
raj@2224
|
339 |
|
|
raj@2224
|
340 |
int TcpSocket::Send (const uint8_t* buf, uint32_t size)
|
|
raj@2224
|
341 |
{
|
|
raj@2224
|
342 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
343 |
NS_LOG_PARAMS (this << buf << size);
|
|
raj@2224
|
344 |
if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
|
|
raj@2224
|
345 |
{ // Ok to buffer some data to send
|
|
raj@2224
|
346 |
if (!m_pendingData)
|
|
raj@2224
|
347 |
{
|
|
raj@2224
|
348 |
m_pendingData = new PendingData (); // Create if non-existent
|
|
raj@2224
|
349 |
m_firstPendingSequence = m_nextTxSequence; // Note seq of first
|
|
raj@2224
|
350 |
}
|
|
raj@2224
|
351 |
//PendingData::Add always copies the data buffer, never modifies
|
|
raj@2224
|
352 |
m_pendingData->Add (size,buf);
|
|
mathieu@2608
|
353 |
NS_LOG_DEBUG("TcpSock::Send, pdsize " << m_pendingData->Size() <<
|
|
mathieu@2608
|
354 |
" state " << m_state);
|
|
raj@2224
|
355 |
Actions_t action = ProcessEvent (APP_SEND);
|
|
mathieu@2608
|
356 |
NS_LOG_DEBUG(" action " << action);
|
|
raj@2224
|
357 |
if (!ProcessAction (action))
|
|
raj@2224
|
358 |
{
|
|
raj@2224
|
359 |
return -1; // Failed, return zero
|
|
raj@2224
|
360 |
}
|
|
raj@2224
|
361 |
return size;
|
|
raj@2224
|
362 |
}
|
|
raj@2224
|
363 |
else
|
|
raj@2224
|
364 |
{
|
|
raj@2224
|
365 |
m_errno = ERROR_NOTCONN;
|
|
raj@2224
|
366 |
return -1;
|
|
raj@2224
|
367 |
}
|
|
raj@2224
|
368 |
}
|
|
raj@2224
|
369 |
|
|
raj@2224
|
370 |
int TcpSocket::DoSendTo (Ptr<Packet> p, const Address &address)
|
|
raj@2224
|
371 |
{
|
|
raj@2224
|
372 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
373 |
NS_LOG_PARAMS (this << p << address);
|
|
raj@2224
|
374 |
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
|
raj@2224
|
375 |
Ipv4Address ipv4 = transport.GetIpv4 ();
|
|
raj@2224
|
376 |
uint16_t port = transport.GetPort ();
|
|
raj@2224
|
377 |
return DoSendTo (p, ipv4, port);
|
|
raj@2224
|
378 |
}
|
|
raj@2224
|
379 |
|
|
raj@2224
|
380 |
int TcpSocket::DoSendTo (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port)
|
|
raj@2224
|
381 |
{
|
|
raj@2224
|
382 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
383 |
NS_LOG_PARAMS (this << p << ipv4 << port);
|
|
raj@2224
|
384 |
if (m_endPoint == 0)
|
|
raj@2224
|
385 |
{
|
|
raj@2224
|
386 |
if (Bind () == -1)
|
|
raj@2224
|
387 |
{
|
|
raj@2224
|
388 |
NS_ASSERT (m_endPoint == 0);
|
|
raj@2224
|
389 |
return -1;
|
|
raj@2224
|
390 |
}
|
|
raj@2224
|
391 |
NS_ASSERT (m_endPoint != 0);
|
|
raj@2224
|
392 |
}
|
|
raj@2224
|
393 |
if (m_shutdownSend)
|
|
raj@2224
|
394 |
{
|
|
raj@2224
|
395 |
m_errno = ERROR_SHUTDOWN;
|
|
raj@2224
|
396 |
return -1;
|
|
raj@2224
|
397 |
}
|
|
raj@2224
|
398 |
m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
|
|
raj@2224
|
399 |
m_endPoint->GetLocalPort (), port);
|
|
raj@2224
|
400 |
NotifyDataSent (p->GetSize ());
|
|
raj@2224
|
401 |
return 0;
|
|
raj@2224
|
402 |
}
|
|
raj@2224
|
403 |
|
|
raj@2224
|
404 |
int
|
|
raj@2224
|
405 |
TcpSocket::SendTo (const Address &address, Ptr<Packet> p)
|
|
raj@2224
|
406 |
{
|
|
raj@2224
|
407 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
408 |
NS_LOG_PARAMS (this << address << p);
|
|
raj@2224
|
409 |
if (!m_connected)
|
|
raj@2224
|
410 |
{
|
|
raj@2224
|
411 |
m_errno = ERROR_NOTCONN;
|
|
raj@2224
|
412 |
return -1;
|
|
raj@2224
|
413 |
}
|
|
raj@2224
|
414 |
else
|
|
raj@2224
|
415 |
{
|
|
raj@2224
|
416 |
return Send (p); //drop the address according to BSD manpages
|
|
raj@2224
|
417 |
}
|
|
raj@2224
|
418 |
}
|
|
raj@2224
|
419 |
|
|
raj@2224
|
420 |
int
|
|
raj@2224
|
421 |
TcpSocket::Listen (uint32_t q)
|
|
raj@2224
|
422 |
{
|
|
raj@2224
|
423 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
424 |
NS_LOG_PARAMS (this << q);
|
|
raj@2224
|
425 |
Actions_t action = ProcessEvent (APP_LISTEN);
|
|
raj@2224
|
426 |
ProcessAction (action);
|
|
raj@2224
|
427 |
return 0;
|
|
raj@2224
|
428 |
}
|
|
raj@2224
|
429 |
|
|
raj@2224
|
430 |
void
|
|
raj@2224
|
431 |
TcpSocket::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
|
|
raj@2224
|
432 |
{
|
|
mathieu@2608
|
433 |
NS_LOG_DEBUG("Socket " << this << " got forward up" <<
|
|
mathieu@2608
|
434 |
" dport " << m_endPoint->GetLocalPort() <<
|
|
mathieu@2608
|
435 |
" daddr " << m_endPoint->GetLocalAddress() <<
|
|
mathieu@2608
|
436 |
" sport " << m_endPoint->GetPeerPort() <<
|
|
mathieu@2608
|
437 |
" saddr " << m_endPoint->GetPeerAddress());
|
|
mathieu@2608
|
438 |
|
|
raj@2224
|
439 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
440 |
NS_LOG_PARAMS (this << packet << ipv4 << port);
|
|
raj@2224
|
441 |
if (m_shutdownRecv)
|
|
raj@2224
|
442 |
{
|
|
raj@2224
|
443 |
return;
|
|
raj@2224
|
444 |
}
|
|
raj@2224
|
445 |
TcpHeader tcpHeader;
|
|
raj@2224
|
446 |
packet->RemoveHeader (tcpHeader);
|
|
raj@2224
|
447 |
|
|
raj@2224
|
448 |
if (tcpHeader.GetFlags () & TcpHeader::ACK)
|
|
raj@2224
|
449 |
{
|
|
raj@2224
|
450 |
Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () );
|
|
raj@2224
|
451 |
if (m != Seconds (0.0))
|
|
raj@2224
|
452 |
{
|
|
raj@2224
|
453 |
m_lastMeasuredRtt = m;
|
|
raj@2224
|
454 |
}
|
|
raj@2224
|
455 |
}
|
|
raj@2224
|
456 |
|
|
raj@2224
|
457 |
Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
|
|
raj@2224
|
458 |
Actions_t action = ProcessEvent (event); //updates the state
|
|
raj@2224
|
459 |
Address address = InetSocketAddress (ipv4, port);
|
|
mathieu@2608
|
460 |
NS_LOG_DEBUG("Socket " << this <<
|
|
mathieu@2608
|
461 |
" processing pkt action, " << action <<
|
|
mathieu@2608
|
462 |
" current state " << m_state);
|
|
raj@2224
|
463 |
ProcessPacketAction (action, packet, tcpHeader, address);
|
|
raj@2224
|
464 |
}
|
|
raj@2224
|
465 |
|
|
raj@2224
|
466 |
Actions_t TcpSocket::ProcessEvent (Events_t e)
|
|
raj@2224
|
467 |
{
|
|
raj@2224
|
468 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
469 |
NS_LOG_PARAMS (this << e);
|
|
raj@2224
|
470 |
States_t saveState = m_state;
|
|
raj@2224
|
471 |
NS_LOG_LOGIC ("TcpSocket " << this << " processing event " << e);
|
|
raj@2224
|
472 |
// simulation singleton is a way to get a single global static instance of a
|
|
raj@2224
|
473 |
// class intended to be a singleton; see simulation-singleton.h
|
|
raj@2224
|
474 |
SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e);
|
|
raj@2224
|
475 |
// debug
|
|
raj@2224
|
476 |
if (stateAction.action == RST_TX)
|
|
raj@2224
|
477 |
{
|
|
raj@2224
|
478 |
NS_LOG_LOGIC ("TcpSocket " << this << " sending RST from state "
|
|
raj@2224
|
479 |
<< saveState << " event " << e);
|
|
raj@2224
|
480 |
}
|
|
raj@2224
|
481 |
bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED
|
|
raj@2224
|
482 |
&& e != TIMEOUT);
|
|
raj@2224
|
483 |
m_state = stateAction.state;
|
|
raj@2224
|
484 |
NS_LOG_LOGIC ("TcpSocket " << this << " moved from state " << saveState
|
|
raj@2224
|
485 |
<< " to state " <<m_state);
|
|
raj@2224
|
486 |
NS_LOG_LOGIC ("TcpSocket " << this << " pendingData " << m_pendingData);
|
|
mathieu@2608
|
487 |
|
|
mathieu@2608
|
488 |
//extra event logic is here for RX events
|
|
mathieu@2608
|
489 |
//e = SYN_ACK_RX
|
|
raj@2224
|
490 |
if (saveState == SYN_SENT && m_state == ESTABLISHED)
|
|
raj@2224
|
491 |
// this means the application side has completed its portion of
|
|
raj@2224
|
492 |
// the handshaking
|
|
raj@2224
|
493 |
{
|
|
mathieu@2608
|
494 |
Simulator::ScheduleNow(&TcpSocket::ConnectionSucceeded, this);
|
|
mathieu@2608
|
495 |
//NotifyConnectionSucceeded ();
|
|
raj@2224
|
496 |
m_connected = true;
|
|
mathieu@2608
|
497 |
m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
|
|
raj@2224
|
498 |
NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
|
|
raj@2224
|
499 |
}
|
|
mathieu@2608
|
500 |
|
|
raj@2224
|
501 |
if (needCloseNotify && !m_closeNotified)
|
|
raj@2224
|
502 |
{
|
|
raj@2224
|
503 |
NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from "
|
|
raj@2224
|
504 |
<< m_state << " event " << e << " closeNot " << m_closeNotified
|
|
raj@2224
|
505 |
<< " action " << stateAction.action);
|
|
raj@2224
|
506 |
NotifyCloseCompleted ();
|
|
raj@2224
|
507 |
m_closeNotified = true;
|
|
raj@2224
|
508 |
NS_LOG_LOGIC ("TcpSocket " << this << " calling Closed from PE"
|
|
raj@2224
|
509 |
<< " origState " << saveState
|
|
raj@2224
|
510 |
<< " event " << e);
|
|
raj@2224
|
511 |
NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from "
|
|
raj@2224
|
512 |
<< m_state << " event " << e
|
|
raj@2224
|
513 |
<< " set CloseNotif ");
|
|
raj@2224
|
514 |
}
|
|
raj@2224
|
515 |
return stateAction.action;
|
|
raj@2224
|
516 |
}
|
|
raj@2224
|
517 |
|
|
raj@2224
|
518 |
void TcpSocket::SendEmptyPacket (uint8_t flags)
|
|
raj@2224
|
519 |
{
|
|
raj@2224
|
520 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
521 |
NS_LOG_PARAMS (this << flags);
|
|
raj@2224
|
522 |
Ptr<Packet> p = Create<Packet> ();
|
|
raj@2224
|
523 |
TcpHeader header;
|
|
raj@2224
|
524 |
|
|
raj@2224
|
525 |
header.SetFlags (flags);
|
|
raj@2224
|
526 |
header.SetSequenceNumber (m_nextTxSequence);
|
|
raj@2224
|
527 |
header.SetAckNumber (m_nextRxSequence);
|
|
raj@2224
|
528 |
header.SetSourcePort (m_endPoint->GetLocalPort ());
|
|
mathieu@2608
|
529 |
header.SetDestinationPort (m_remotePort);
|
|
raj@2224
|
530 |
header.SetWindowSize (m_advertisedWindowSize);
|
|
raj@2224
|
531 |
m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (),
|
|
mathieu@2608
|
532 |
m_remoteAddress);
|
|
raj@2224
|
533 |
Time rto = m_rtt->RetransmitTimeout ();
|
|
raj@2224
|
534 |
if (flags & TcpHeader::SYN)
|
|
raj@2224
|
535 |
{
|
|
raj@2224
|
536 |
rto = m_cnTimeout;
|
|
m@2352
|
537 |
m_cnTimeout = m_cnTimeout + m_cnTimeout;
|
|
raj@2224
|
538 |
m_cnCount--;
|
|
raj@2224
|
539 |
}
|
|
raj@2224
|
540 |
if (m_retxEvent.IsExpired () ) //no outstanding timer
|
|
raj@2224
|
541 |
{
|
|
raj@2224
|
542 |
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
|
raj@2224
|
543 |
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
|
raj@2224
|
544 |
<< (Simulator::Now () + rto).GetSeconds ());
|
|
raj@2224
|
545 |
m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this);
|
|
raj@2224
|
546 |
}
|
|
raj@2224
|
547 |
}
|
|
raj@2224
|
548 |
|
|
raj@2224
|
549 |
bool TcpSocket::ProcessAction (Actions_t a)
|
|
raj@2224
|
550 |
{ // These actions do not require a packet or any TCP Headers
|
|
raj@2224
|
551 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
552 |
NS_LOG_PARAMS (this << a);
|
|
raj@2224
|
553 |
switch (a)
|
|
raj@2224
|
554 |
{
|
|
raj@2224
|
555 |
case NO_ACT:
|
|
raj@2224
|
556 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action: NO_ACT");
|
|
raj@2224
|
557 |
break;
|
|
raj@2224
|
558 |
case ACK_TX:
|
|
raj@2224
|
559 |
SendEmptyPacket (TcpHeader::ACK);
|
|
raj@2224
|
560 |
break;
|
|
raj@2224
|
561 |
case ACK_TX_1:
|
|
raj@2224
|
562 |
NS_ASSERT (false); // This should be processed in ProcessPacketAction
|
|
raj@2224
|
563 |
break;
|
|
raj@2224
|
564 |
case RST_TX:
|
|
raj@2224
|
565 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action RST_TX");
|
|
raj@2224
|
566 |
SendEmptyPacket (TcpHeader::RST);
|
|
raj@2224
|
567 |
break;
|
|
raj@2224
|
568 |
case SYN_TX:
|
|
raj@2224
|
569 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_TX");
|
|
raj@2224
|
570 |
// TCP SYN Flag consumes one byte
|
|
raj@2316
|
571 |
// is the above correct? we're SENDING a syn, not acking back -- Raj
|
|
raj@2316
|
572 |
// commented out for now
|
|
raj@2316
|
573 |
// m_nextTxSequence+= 1;
|
|
raj@2224
|
574 |
SendEmptyPacket (TcpHeader::SYN);
|
|
raj@2224
|
575 |
break;
|
|
raj@2224
|
576 |
case SYN_ACK_TX:
|
|
raj@2224
|
577 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
|
|
mathieu@2608
|
578 |
// TCP SYN Flag consumes one byte
|
|
mathieu@2608
|
579 |
++m_nextRxSequence;
|
|
raj@2224
|
580 |
SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
|
|
raj@2224
|
581 |
break;
|
|
raj@2224
|
582 |
case FIN_TX:
|
|
raj@2224
|
583 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_TX");
|
|
raj@2224
|
584 |
SendEmptyPacket (TcpHeader::FIN);
|
|
raj@2224
|
585 |
break;
|
|
raj@2224
|
586 |
case FIN_ACK_TX:
|
|
raj@2224
|
587 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_ACK_TX");
|
|
raj@2224
|
588 |
SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK);
|
|
raj@2224
|
589 |
break;
|
|
raj@2224
|
590 |
case NEW_ACK:
|
|
raj@2224
|
591 |
NS_ASSERT (false); // This should be processed in ProcessPacketAction
|
|
raj@2224
|
592 |
break;
|
|
raj@2224
|
593 |
case NEW_SEQ_RX:
|
|
raj@2224
|
594 |
NS_ASSERT (false); // This should be processed in ProcessPacketAction
|
|
raj@2224
|
595 |
break;
|
|
raj@2224
|
596 |
case RETX:
|
|
raj@2224
|
597 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action RETX");
|
|
raj@2224
|
598 |
break;
|
|
raj@2224
|
599 |
case TX_DATA:
|
|
raj@2224
|
600 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action TX_DATA");
|
|
raj@2224
|
601 |
SendPendingData ();
|
|
raj@2224
|
602 |
break;
|
|
raj@2224
|
603 |
case PEER_CLOSE:
|
|
raj@2224
|
604 |
NS_ASSERT (false); // This should be processed in ProcessPacketAction
|
|
raj@2224
|
605 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action PEER_CLOSE");
|
|
raj@2224
|
606 |
break;
|
|
raj@2224
|
607 |
case APP_CLOSED:
|
|
raj@2224
|
608 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_CLOSED");
|
|
raj@2224
|
609 |
break;
|
|
raj@2224
|
610 |
case CANCEL_TM:
|
|
raj@2224
|
611 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action CANCEL_TM");
|
|
raj@2224
|
612 |
break;
|
|
raj@2224
|
613 |
case APP_NOTIFY:
|
|
raj@2224
|
614 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_NOTIFY");
|
|
raj@2224
|
615 |
break;
|
|
raj@2224
|
616 |
case SERV_NOTIFY:
|
|
raj@2316
|
617 |
NS_ASSERT (false); // This should be processed in ProcessPacketAction
|
|
raj@2224
|
618 |
break;
|
|
raj@2224
|
619 |
case LAST_ACTION:
|
|
raj@2224
|
620 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action LAST_ACTION");
|
|
raj@2224
|
621 |
break;
|
|
raj@2224
|
622 |
}
|
|
raj@2224
|
623 |
return true;
|
|
raj@2224
|
624 |
}
|
|
raj@2224
|
625 |
|
|
raj@2224
|
626 |
bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
|
raj@2224
|
627 |
const TcpHeader& tcpHeader,
|
|
raj@2224
|
628 |
const Address& fromAddress)
|
|
raj@2224
|
629 |
{
|
|
raj@2224
|
630 |
NS_LOG_FUNCTION;
|
|
mathieu@2608
|
631 |
NS_LOG_PARAMS (this << a << p << fromAddress);
|
|
raj@2224
|
632 |
uint32_t localIfIndex;
|
|
mathieu@2257
|
633 |
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
|
|
raj@2224
|
634 |
switch (a)
|
|
raj@2224
|
635 |
{
|
|
raj@2224
|
636 |
case SYN_ACK_TX:
|
|
raj@2224
|
637 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
|
|
mathieu@2608
|
638 |
// m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
|
|
mathieu@2608
|
639 |
// m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
|
|
mathieu@2608
|
640 |
// if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
|
|
mathieu@2608
|
641 |
// {
|
|
mathieu@2608
|
642 |
// m_localAddress = ipv4->GetAddress (localIfIndex);
|
|
mathieu@2608
|
643 |
// }
|
|
mathieu@2608
|
644 |
if (m_state == LISTEN) //this means we should fork a new TcpSocket
|
|
raj@2224
|
645 |
{
|
|
mathieu@2608
|
646 |
NS_LOG_DEBUG("In SYN_ACK_TX, m_state is LISTEN, this " << this);
|
|
mathieu@2608
|
647 |
//notify the server that we got a SYN
|
|
mathieu@2608
|
648 |
// If server refuses connection do nothing
|
|
mathieu@2608
|
649 |
if (!NotifyConnectionRequest(fromAddress)) return true;
|
|
mathieu@2608
|
650 |
// Clone the socket
|
|
mathieu@2608
|
651 |
Ptr<TcpSocket> newSock = Copy ();
|
|
mathieu@2608
|
652 |
NS_LOG_LOGIC ("Cloned a TcpSocket " << newSock);
|
|
mathieu@2608
|
653 |
//this listening socket should do nothing more
|
|
mathieu@2608
|
654 |
Simulator::ScheduleNow (&TcpSocket::CompleteFork, newSock,
|
|
mathieu@2608
|
655 |
p, tcpHeader,fromAddress);
|
|
mathieu@2608
|
656 |
return true;
|
|
raj@2224
|
657 |
}
|
|
mathieu@2608
|
658 |
// This is the cloned endpoint
|
|
mathieu@2608
|
659 |
m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
|
|
mathieu@2608
|
660 |
if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
|
|
mathieu@2608
|
661 |
{
|
|
mathieu@2608
|
662 |
m_localAddress = ipv4->GetAddress (localIfIndex);
|
|
mathieu@2608
|
663 |
m_endPoint->SetLocalAddress (m_localAddress);
|
|
mathieu@2608
|
664 |
// Leave local addr in the portmap to any, as the path from
|
|
mathieu@2608
|
665 |
// remote can change and packets can arrive on different interfaces
|
|
mathieu@2608
|
666 |
//m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
|
|
mathieu@2608
|
667 |
}
|
|
mathieu@2608
|
668 |
// TCP SYN consumes one byte
|
|
mathieu@2608
|
669 |
m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
|
|
mathieu@2608
|
670 |
SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
|
|
raj@2224
|
671 |
break;
|
|
raj@2224
|
672 |
case ACK_TX_1:
|
|
raj@2224
|
673 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action ACK_TX_1");
|
|
raj@2224
|
674 |
// TCP SYN consumes one byte
|
|
raj@2316
|
675 |
m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
|
|
mathieu@2608
|
676 |
NS_LOG_DEBUG ("TcpSocket " << this << " ACK_TX_1" <<
|
|
mathieu@2608
|
677 |
" nextRxSeq " << m_nextRxSequence);
|
|
raj@2224
|
678 |
SendEmptyPacket (TcpHeader::ACK);
|
|
raj@2224
|
679 |
m_rxWindowSize = tcpHeader.GetWindowSize ();
|
|
raj@2316
|
680 |
m_nextTxSequence = tcpHeader.GetAckNumber ();
|
|
raj@2224
|
681 |
if (tcpHeader.GetAckNumber () > m_highestRxAck)
|
|
raj@2224
|
682 |
{
|
|
raj@2224
|
683 |
m_highestRxAck = tcpHeader.GetAckNumber ();
|
|
raj@2224
|
684 |
}
|
|
raj@2224
|
685 |
SendPendingData ();
|
|
raj@2224
|
686 |
break;
|
|
raj@2224
|
687 |
case NEW_ACK:
|
|
raj@2224
|
688 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_ACK_TX");
|
|
raj@2224
|
689 |
if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing
|
|
raj@2224
|
690 |
{
|
|
raj@2224
|
691 |
break;
|
|
raj@2224
|
692 |
}
|
|
raj@2224
|
693 |
if (tcpHeader.GetAckNumber () == m_highestRxAck &&
|
|
raj@2224
|
694 |
tcpHeader.GetAckNumber () < m_nextTxSequence)
|
|
raj@2224
|
695 |
{
|
|
raj@2224
|
696 |
DupAck (tcpHeader, ++m_dupAckCount);
|
|
raj@2224
|
697 |
break;
|
|
raj@2224
|
698 |
}
|
|
raj@2224
|
699 |
if (tcpHeader.GetAckNumber () > m_highestRxAck)
|
|
raj@2224
|
700 |
{
|
|
raj@2224
|
701 |
m_dupAckCount = 0;
|
|
raj@2224
|
702 |
}
|
|
raj@2224
|
703 |
NewAck (tcpHeader.GetAckNumber ());
|
|
raj@2224
|
704 |
break;
|
|
raj@2224
|
705 |
case NEW_SEQ_RX:
|
|
mathieu@2608
|
706 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_SEQ_RX");
|
|
raj@2224
|
707 |
NewRx (p, tcpHeader, fromAddress); // Process new data received
|
|
raj@2224
|
708 |
break;
|
|
raj@2224
|
709 |
case PEER_CLOSE:
|
|
raj@2224
|
710 |
{
|
|
raj@2224
|
711 |
// First we have to be sure the FIN packet was not received
|
|
raj@2224
|
712 |
// out of sequence. If so, note pending close and process
|
|
raj@2224
|
713 |
// new sequence rx
|
|
raj@2224
|
714 |
if (tcpHeader.GetSequenceNumber () != m_nextRxSequence)
|
|
raj@2224
|
715 |
{ // process close later
|
|
raj@2224
|
716 |
m_pendingClose = true;
|
|
raj@2224
|
717 |
NS_LOG_LOGIC ("TcpSocket " << this << " setting pendingClose"
|
|
raj@2224
|
718 |
<< " rxseq " << tcpHeader.GetSequenceNumber ()
|
|
raj@2224
|
719 |
<< " nextRxSeq " << m_nextRxSequence);
|
|
raj@2224
|
720 |
NewRx (p, tcpHeader, fromAddress);
|
|
raj@2224
|
721 |
return true;
|
|
raj@2224
|
722 |
}
|
|
raj@2224
|
723 |
// Now we need to see if any data came with the FIN
|
|
raj@2224
|
724 |
// if so, call NewRx
|
|
raj@2224
|
725 |
if (p->GetSize () != 0)
|
|
raj@2224
|
726 |
{
|
|
raj@2224
|
727 |
NewRx (p, tcpHeader, fromAddress);
|
|
raj@2224
|
728 |
}
|
|
raj@2224
|
729 |
States_t saveState = m_state; // Used to see if app responds
|
|
raj@2224
|
730 |
NS_LOG_LOGIC ("TcpSocket " << this
|
|
raj@2224
|
731 |
<< " peer close, state " << m_state);
|
|
raj@2224
|
732 |
if (!m_closeRequestNotified)
|
|
raj@2224
|
733 |
{
|
|
raj@2224
|
734 |
NS_LOG_LOGIC ("TCP " << this
|
|
raj@2224
|
735 |
<< " calling AppCloseRequest");
|
|
mathieu@2608
|
736 |
NotifyHalfClose ();
|
|
raj@2224
|
737 |
m_closeRequestNotified = true;
|
|
raj@2224
|
738 |
}
|
|
raj@2224
|
739 |
NS_LOG_LOGIC ("TcpSocket " << this
|
|
raj@2224
|
740 |
<< " peer close, state after " << m_state);
|
|
raj@2224
|
741 |
if (m_state == saveState)
|
|
raj@2224
|
742 |
{ // Need to ack, the application will close later
|
|
raj@2224
|
743 |
SendEmptyPacket (TcpHeader::ACK);
|
|
raj@2224
|
744 |
// Also need to re-tx the ack if we
|
|
raj@2224
|
745 |
}
|
|
raj@2224
|
746 |
if (m_state == LAST_ACK)
|
|
raj@2224
|
747 |
{
|
|
raj@2224
|
748 |
NS_LOG_LOGIC ("TcpSocket " << this << " scheduling LATO1");
|
|
raj@2224
|
749 |
m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (),
|
|
raj@2224
|
750 |
&TcpSocket::LastAckTimeout,this);
|
|
raj@2224
|
751 |
}
|
|
raj@2224
|
752 |
break;
|
|
raj@2224
|
753 |
}
|
|
raj@2316
|
754 |
case SERV_NOTIFY:
|
|
raj@2316
|
755 |
NS_LOG_LOGIC ("TcpSocket " << this <<" Action SERV_NOTIFY");
|
|
raj@2316
|
756 |
NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
|
|
raj@2330
|
757 |
NotifyNewConnectionCreated (this, fromAddress);
|
|
raj@2316
|
758 |
m_connected = true; // ! This is bogus; fix when we clone the tcp
|
|
mathieu@2608
|
759 |
m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
|
|
raj@2316
|
760 |
//treat the connection orientation final ack as a newack
|
|
raj@2316
|
761 |
CommonNewAck (tcpHeader.GetAckNumber (), true);
|
|
raj@2316
|
762 |
break;
|
|
raj@2224
|
763 |
default:
|
|
raj@2224
|
764 |
break;
|
|
raj@2224
|
765 |
}
|
|
raj@2224
|
766 |
return true;
|
|
raj@2224
|
767 |
}
|
|
raj@2224
|
768 |
|
|
mathieu@2608
|
769 |
void TcpSocket::CompleteFork(Ptr<Packet> p, const TcpHeader& h, const Address& fromAddress)
|
|
mathieu@2608
|
770 |
{
|
|
mathieu@2608
|
771 |
// Get port and address from peer (connecting host)
|
|
mathieu@2608
|
772 |
m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
|
|
mathieu@2608
|
773 |
m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
|
|
mathieu@2608
|
774 |
m_endPoint = m_tcp->Allocate (m_localAddress,
|
|
mathieu@2608
|
775 |
m_localPort,
|
|
mathieu@2608
|
776 |
m_remoteAddress,
|
|
mathieu@2608
|
777 |
m_remotePort);
|
|
mathieu@2608
|
778 |
//the cloned socket with be in listen state, so manually change state
|
|
mathieu@2608
|
779 |
m_state = SYN_RCVD;
|
|
mathieu@2608
|
780 |
//equivalent to FinishBind
|
|
raj@2668
|
781 |
m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
|
|
raj@2668
|
782 |
m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
|
|
mathieu@2608
|
783 |
ProcessPacketAction(SYN_ACK_TX, p, h, fromAddress);
|
|
mathieu@2608
|
784 |
}
|
|
mathieu@2608
|
785 |
|
|
mathieu@2608
|
786 |
void TcpSocket::ConnectionSucceeded()
|
|
mathieu@2608
|
787 |
{ // We would preferred to have scheduled an event directly to
|
|
mathieu@2608
|
788 |
// NotifyConnectionSucceeded, but (sigh) these are protected
|
|
mathieu@2608
|
789 |
// and we can get the address of it :(
|
|
mathieu@2608
|
790 |
NotifyConnectionSucceeded();
|
|
mathieu@2608
|
791 |
}
|
|
mathieu@2608
|
792 |
|
|
raj@2224
|
793 |
bool TcpSocket::SendPendingData (bool withAck)
|
|
raj@2224
|
794 |
{
|
|
raj@2224
|
795 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
796 |
NS_LOG_PARAMS (this << withAck);
|
|
raj@2224
|
797 |
NS_LOG_LOGIC ("ENTERING SendPendingData");
|
|
raj@2224
|
798 |
if (!m_pendingData)
|
|
raj@2224
|
799 |
{
|
|
raj@2224
|
800 |
return false; // No data exists
|
|
raj@2224
|
801 |
}
|
|
raj@2224
|
802 |
uint32_t nPacketsSent = 0;
|
|
raj@2224
|
803 |
while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence))
|
|
raj@2224
|
804 |
{
|
|
raj@2224
|
805 |
uint32_t w = AvailableWindow ();// Get available window size
|
|
raj@2224
|
806 |
NS_LOG_LOGIC ("TcpSocket " << this << " SendPendingData"
|
|
raj@2224
|
807 |
<< " w " << w
|
|
raj@2224
|
808 |
<< " rxwin " << m_rxWindowSize
|
|
raj@2224
|
809 |
<< " cWnd " << m_cWnd
|
|
raj@2224
|
810 |
<< " segsize " << m_segmentSize
|
|
raj@2224
|
811 |
<< " nextTxSeq " << m_nextTxSequence
|
|
raj@2224
|
812 |
<< " highestRxAck " << m_highestRxAck
|
|
raj@2224
|
813 |
<< " pd->Size " << m_pendingData->Size ()
|
|
raj@2224
|
814 |
<< " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
|
|
raj@2224
|
815 |
|
|
raj@2224
|
816 |
if (w < m_segmentSize && m_pendingData->Size () > w)
|
|
raj@2224
|
817 |
{
|
|
raj@2224
|
818 |
break; // No more
|
|
raj@2224
|
819 |
}
|
|
raj@2224
|
820 |
uint32_t s = std::min (w, m_segmentSize); // Send no more than window
|
|
raj@2354
|
821 |
Ptr<Packet> p = m_pendingData->CopyFromSeq (s, m_firstPendingSequence,
|
|
raj@2224
|
822 |
m_nextTxSequence);
|
|
raj@2224
|
823 |
NS_LOG_LOGIC("TcpSocket " << this << " sendPendingData"
|
|
raj@2224
|
824 |
<< " txseq " << m_nextTxSequence
|
|
raj@2224
|
825 |
<< " s " << s
|
|
raj@2354
|
826 |
<< " datasize " << p->GetSize() );
|
|
raj@2224
|
827 |
uint8_t flags = 0;
|
|
raj@2224
|
828 |
if (withAck)
|
|
raj@2224
|
829 |
{
|
|
raj@2224
|
830 |
flags |= TcpHeader::ACK;
|
|
raj@2224
|
831 |
}
|
|
raj@2354
|
832 |
uint32_t sz = p->GetSize (); // Size of packet
|
|
raj@2224
|
833 |
uint32_t remainingData = m_pendingData->SizeFromSeq(
|
|
raj@2224
|
834 |
m_firstPendingSequence,
|
|
raj@2224
|
835 |
m_nextTxSequence + SequenceNumber (sz));
|
|
raj@2224
|
836 |
if (m_closeOnEmpty && (remainingData == 0))
|
|
raj@2224
|
837 |
{
|
|
raj@2224
|
838 |
flags = TcpHeader::FIN;
|
|
raj@2224
|
839 |
m_state = FIN_WAIT_1;
|
|
raj@2224
|
840 |
}
|
|
raj@2224
|
841 |
|
|
raj@2224
|
842 |
TcpHeader header;
|
|
raj@2224
|
843 |
header.SetFlags (flags);
|
|
raj@2224
|
844 |
header.SetSequenceNumber (m_nextTxSequence);
|
|
raj@2224
|
845 |
header.SetAckNumber (m_nextRxSequence);
|
|
raj@2224
|
846 |
header.SetSourcePort (m_endPoint->GetLocalPort());
|
|
mathieu@2608
|
847 |
header.SetDestinationPort (m_remotePort);
|
|
raj@2224
|
848 |
if (m_shutdownSend)
|
|
raj@2224
|
849 |
{
|
|
raj@2224
|
850 |
m_errno = ERROR_SHUTDOWN;
|
|
raj@2224
|
851 |
return -1;
|
|
raj@2224
|
852 |
}
|
|
raj@2224
|
853 |
|
|
raj@2224
|
854 |
Time rto = m_rtt->RetransmitTimeout ();
|
|
raj@2224
|
855 |
if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
|
|
raj@2224
|
856 |
{
|
|
raj@2224
|
857 |
NS_LOG_LOGIC ("Schedule retransmission timeout at time " <<
|
|
raj@2224
|
858 |
Simulator::Now ().GetSeconds () << " to expire at time " <<
|
|
raj@2224
|
859 |
(Simulator::Now () + rto).GetSeconds () );
|
|
raj@2224
|
860 |
m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
|
|
raj@2224
|
861 |
}
|
|
raj@2224
|
862 |
NS_LOG_LOGIC ("About to send a packet with flags: " << flags);
|
|
raj@2224
|
863 |
m_tcp->SendPacket (p, header,
|
|
raj@2224
|
864 |
m_endPoint->GetLocalAddress (),
|
|
mathieu@2608
|
865 |
m_remoteAddress);
|
|
tomh@2340
|
866 |
m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT
|
|
tomh@2340
|
867 |
// Notify the application
|
|
tomh@2340
|
868 |
Simulator::ScheduleNow(&TcpSocket::NotifyDataSent, this, p->GetSize ());
|
|
tomh@2340
|
869 |
nPacketsSent++; // Count sent this loop
|
|
tomh@2340
|
870 |
m_nextTxSequence += sz; // Advance next tx sequence
|
|
tomh@2340
|
871 |
// Note the high water mark
|
|
tomh@2340
|
872 |
m_highTxMark = std::max (m_nextTxSequence, m_highTxMark);
|
|
raj@2224
|
873 |
}
|
|
raj@2224
|
874 |
NS_LOG_LOGIC ("Sent "<<nPacketsSent<<" packets");
|
|
raj@2224
|
875 |
NS_LOG_LOGIC("RETURN SendPendingData");
|
|
raj@2224
|
876 |
return (nPacketsSent>0);
|
|
raj@2224
|
877 |
}
|
|
raj@2224
|
878 |
|
|
raj@2224
|
879 |
uint32_t TcpSocket::UnAckDataCount ()
|
|
raj@2224
|
880 |
{
|
|
raj@2224
|
881 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
882 |
return m_nextTxSequence - m_highestRxAck;
|
|
raj@2224
|
883 |
}
|
|
raj@2224
|
884 |
|
|
raj@2224
|
885 |
uint32_t TcpSocket::BytesInFlight ()
|
|
raj@2224
|
886 |
{
|
|
raj@2224
|
887 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
888 |
return m_highTxMark - m_highestRxAck;
|
|
raj@2224
|
889 |
}
|
|
raj@2224
|
890 |
|
|
raj@2224
|
891 |
uint32_t TcpSocket::Window ()
|
|
raj@2224
|
892 |
{
|
|
raj@2224
|
893 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
894 |
NS_LOG_LOGIC ("TcpSocket::Window() "<<this);
|
|
raj@2224
|
895 |
return std::min (m_rxWindowSize, m_cWnd);
|
|
raj@2224
|
896 |
}
|
|
raj@2224
|
897 |
|
|
raj@2224
|
898 |
uint32_t TcpSocket::AvailableWindow ()
|
|
raj@2224
|
899 |
{
|
|
raj@2224
|
900 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
901 |
uint32_t unack = UnAckDataCount (); // Number of outstanding bytes
|
|
raj@2224
|
902 |
uint32_t win = Window ();
|
|
raj@2224
|
903 |
if (win < unack)
|
|
raj@2224
|
904 |
{
|
|
raj@2224
|
905 |
return 0; // No space available
|
|
raj@2224
|
906 |
}
|
|
raj@2224
|
907 |
return (win - unack); // Amount of window space available
|
|
raj@2224
|
908 |
}
|
|
raj@2224
|
909 |
|
|
raj@2224
|
910 |
void TcpSocket::NewRx (Ptr<Packet> p,
|
|
raj@2224
|
911 |
const TcpHeader& tcpHeader,
|
|
raj@2224
|
912 |
const Address& fromAddress)
|
|
raj@2224
|
913 |
{
|
|
raj@2224
|
914 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
915 |
NS_LOG_PARAMS (this << p << "tcpHeader " << fromAddress);
|
|
mathieu@2608
|
916 |
NS_LOG_LOGIC ("TcpSocket " << this << " NewRx,"
|
|
mathieu@2608
|
917 |
<< " seq " << tcpHeader.GetSequenceNumber()
|
|
mathieu@2608
|
918 |
<< " ack " << tcpHeader.GetAckNumber()
|
|
mathieu@2608
|
919 |
<< " p.size is " << p->GetSize () );
|
|
mathieu@2608
|
920 |
NS_LOG_DEBUG ("TcpSocket " << this <<
|
|
mathieu@2608
|
921 |
" NewRx," <<
|
|
mathieu@2608
|
922 |
" seq " << tcpHeader.GetSequenceNumber() <<
|
|
mathieu@2608
|
923 |
" ack " << tcpHeader.GetAckNumber() <<
|
|
mathieu@2608
|
924 |
" p.size is " << p->GetSize());
|
|
raj@2224
|
925 |
States_t origState = m_state;
|
|
raj@2224
|
926 |
uint32_t s = p->GetSize (); // Size of associated data
|
|
raj@2224
|
927 |
if (s == 0)
|
|
raj@2224
|
928 |
{// Nothing to do if no associated data
|
|
raj@2224
|
929 |
return;
|
|
raj@2224
|
930 |
}
|
|
raj@2224
|
931 |
// Log sequence received if enabled
|
|
raj@2224
|
932 |
// NoteTimeSeq(LOG_SEQ_RX, h->sequenceNumber);
|
|
raj@2224
|
933 |
// Three possibilities
|
|
raj@2224
|
934 |
// 1) Received seq is expected, deliver this and any buffered data
|
|
raj@2224
|
935 |
// 2) Received seq is < expected, just re-ack previous
|
|
raj@2224
|
936 |
// 3) Received seq is > expected, just re-ack previous and buffer data
|
|
raj@2224
|
937 |
if (tcpHeader.GetSequenceNumber () == m_nextRxSequence)
|
|
raj@2224
|
938 |
{ // If seq is expected seq
|
|
raj@2224
|
939 |
// 1) Update nextRxSeq
|
|
raj@2224
|
940 |
// 2) Deliver to application this packet
|
|
raj@2224
|
941 |
// 3) See if any buffered can be delivered
|
|
raj@2224
|
942 |
// 4) Send the ack
|
|
raj@2224
|
943 |
m_nextRxSequence += s; // Advance next expected sequence
|
|
raj@2224
|
944 |
//bytesReceived += s; // Statistics
|
|
raj@2224
|
945 |
NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
|
|
mathieu@2608
|
946 |
NotifyDataReceived (p, fromAddress);
|
|
raj@2224
|
947 |
if (m_closeNotified)
|
|
raj@2224
|
948 |
{
|
|
raj@2224
|
949 |
NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif");
|
|
raj@2224
|
950 |
}
|
|
raj@2224
|
951 |
NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq by " << s);
|
|
raj@2224
|
952 |
// Look for buffered data
|
|
raj@2224
|
953 |
UnAckData_t::iterator i;
|
|
raj@2224
|
954 |
// Note that the bufferedData list DOES contain the tcp header
|
|
raj@2224
|
955 |
while (!m_bufferedData.empty ())
|
|
raj@2224
|
956 |
{ // Check the buffered data for delivery
|
|
raj@2224
|
957 |
NS_LOG_LOGIC("TCP " << this << " bufferedData.size() "
|
|
raj@2224
|
958 |
<< m_bufferedData.size ()
|
|
raj@2224
|
959 |
<< " time " << Simulator::Now ());
|
|
raj@2224
|
960 |
i = m_bufferedData.begin ();
|
|
raj@2224
|
961 |
Ptr<Packet> p1 = i->second;
|
|
raj@2224
|
962 |
SequenceNumber s1 = 0;
|
|
raj@2224
|
963 |
if (i->first > m_nextRxSequence)
|
|
raj@2224
|
964 |
{
|
|
raj@2224
|
965 |
break; // Not next expected
|
|
raj@2224
|
966 |
}
|
|
raj@2224
|
967 |
// already have the header as a param
|
|
raj@2224
|
968 |
//TCPHeader* h = dynamic_cast<TCPHeader*>(p1->PopPDU());
|
|
raj@2224
|
969 |
// Check non-null here...
|
|
raj@2224
|
970 |
uint8_t flags = tcpHeader.GetFlags (); // Flags (used below)
|
|
raj@2224
|
971 |
if (i->first < m_nextRxSequence)
|
|
raj@2224
|
972 |
{ // remove already delivered data
|
|
raj@2224
|
973 |
// Two cases here.
|
|
raj@2224
|
974 |
// 1) seq + length <= nextRxSeq, just discard
|
|
raj@2224
|
975 |
// 2) seq + length > nextRxSeq, can deliver partial
|
|
raj@2224
|
976 |
s1 = p->GetSize ();
|
|
raj@2224
|
977 |
if (i->first + s1 < m_nextRxSequence)
|
|
raj@2224
|
978 |
{ // Just remove from list
|
|
raj@2224
|
979 |
//bufferedData.erase(i);
|
|
raj@2224
|
980 |
p1 = 0; // Nothing to deliver
|
|
raj@2224
|
981 |
}
|
|
raj@2224
|
982 |
else
|
|
raj@2224
|
983 |
{ // Remove partial data to prepare for delivery
|
|
raj@2224
|
984 |
uint32_t dup = m_nextRxSequence - i->first;
|
|
raj@2224
|
985 |
i->second = p1->CreateFragment (0, p1->GetSize () - dup);
|
|
raj@2224
|
986 |
p1 = i->second;
|
|
raj@2224
|
987 |
}
|
|
raj@2224
|
988 |
}
|
|
raj@2224
|
989 |
else
|
|
raj@2224
|
990 |
{ // At this point i->first must equal nextRxSeq
|
|
raj@2224
|
991 |
if (i->first != m_nextRxSequence)
|
|
raj@2224
|
992 |
{
|
|
raj@2224
|
993 |
NS_FATAL_ERROR ("HuH? NexRx failure, first "
|
|
raj@2224
|
994 |
<< i->first << " nextRxSeq " << m_nextRxSequence);
|
|
raj@2224
|
995 |
}
|
|
raj@2224
|
996 |
s1 = p1->GetSize ();
|
|
raj@2224
|
997 |
}
|
|
raj@2224
|
998 |
NotifyDataReceived (p1, fromAddress);
|
|
raj@2224
|
999 |
|
|
raj@2224
|
1000 |
NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq1 by " << s1 );
|
|
raj@2224
|
1001 |
m_nextRxSequence += s1; // Note data received
|
|
raj@2224
|
1002 |
m_bufferedData.erase (i); // Remove from list
|
|
raj@2224
|
1003 |
if (flags & TcpHeader::FIN)
|
|
raj@2224
|
1004 |
NS_LOG_LOGIC("TcpSocket " << this
|
|
raj@2224
|
1005 |
<< " found FIN in buffered");
|
|
raj@2224
|
1006 |
}
|
|
raj@2224
|
1007 |
|
|
raj@2224
|
1008 |
if (m_pendingClose || (origState > ESTABLISHED))
|
|
raj@2224
|
1009 |
{ // See if we can close now
|
|
raj@2224
|
1010 |
if (m_bufferedData.empty())
|
|
raj@2224
|
1011 |
{
|
|
raj@2224
|
1012 |
ProcessPacketAction (PEER_CLOSE, p, tcpHeader, fromAddress);
|
|
raj@2224
|
1013 |
}
|
|
raj@2224
|
1014 |
}
|
|
raj@2224
|
1015 |
}
|
|
raj@2224
|
1016 |
else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence)
|
|
raj@2224
|
1017 |
{ // Need to buffer this one
|
|
raj@2224
|
1018 |
NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () );
|
|
raj@2224
|
1019 |
UnAckData_t::iterator i =
|
|
raj@2224
|
1020 |
m_bufferedData.find (tcpHeader.GetSequenceNumber () );
|
|
raj@2224
|
1021 |
if (i != m_bufferedData.end () )
|
|
raj@2224
|
1022 |
{
|
|
raj@2224
|
1023 |
i->second = 0; // relase reference to already buffered
|
|
raj@2224
|
1024 |
}
|
|
raj@2224
|
1025 |
// Save for later delivery
|
|
raj@2224
|
1026 |
m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
|
|
raj@2224
|
1027 |
}
|
|
raj@2224
|
1028 |
else
|
|
raj@2224
|
1029 |
{ // debug
|
|
raj@2224
|
1030 |
NS_LOG_LOGIC("TCP " << this
|
|
raj@2224
|
1031 |
<< " got seq " << tcpHeader.GetSequenceNumber ()
|
|
raj@2224
|
1032 |
<< " expected " << m_nextRxSequence
|
|
raj@2224
|
1033 |
<< " flags " << tcpHeader.GetFlags ());
|
|
raj@2224
|
1034 |
}
|
|
raj@2224
|
1035 |
// Now send a new ack packet acknowledging all received and delivered data
|
|
raj@2224
|
1036 |
SendEmptyPacket (TcpHeader::ACK);
|
|
raj@2224
|
1037 |
}
|
|
raj@2224
|
1038 |
|
|
raj@2224
|
1039 |
|
|
raj@2224
|
1040 |
void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer)
|
|
raj@2224
|
1041 |
{ // CommonNewAck is called only for "New" (non-duplicate) acks
|
|
raj@2224
|
1042 |
// and MUST be called by any subclass, from the NewAck function
|
|
raj@2224
|
1043 |
// Always cancel any pending re-tx timer on new acknowledgement
|
|
raj@2224
|
1044 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
1045 |
NS_LOG_PARAMS (this << ack << skipTimer);
|
|
raj@2224
|
1046 |
//DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
|
|
raj@2224
|
1047 |
if (!skipTimer)
|
|
raj@2224
|
1048 |
{
|
|
raj@2224
|
1049 |
m_retxEvent.Cancel ();
|
|
raj@2224
|
1050 |
}
|
|
raj@2224
|
1051 |
NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack
|
|
tomh@2227
|
1052 |
<< " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
|
|
raj@2224
|
1053 |
m_highestRxAck = ack; // Note the highest recieved Ack
|
|
raj@2224
|
1054 |
if (ack > m_nextTxSequence)
|
|
raj@2224
|
1055 |
{
|
|
raj@2224
|
1056 |
m_nextTxSequence = ack; // If advanced
|
|
raj@2224
|
1057 |
}
|
|
raj@2224
|
1058 |
// See if all pending ack'ed; if so we can delete the data
|
|
raj@2224
|
1059 |
if (m_pendingData)
|
|
raj@2224
|
1060 |
{ // Data exists, see if can be deleted
|
|
raj@2224
|
1061 |
if (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck) == 0)
|
|
raj@2224
|
1062 |
{ // All pending acked, can be deleted
|
|
raj@2224
|
1063 |
m_pendingData->Clear ();
|
|
raj@2224
|
1064 |
delete m_pendingData;
|
|
raj@2224
|
1065 |
m_pendingData = 0;
|
|
raj@2224
|
1066 |
// Insure no re-tx timer
|
|
raj@2353
|
1067 |
m_retxEvent.Cancel ();
|
|
raj@2224
|
1068 |
}
|
|
raj@2224
|
1069 |
}
|
|
raj@2224
|
1070 |
// Try to send more data
|
|
raj@2224
|
1071 |
SendPendingData();
|
|
raj@2224
|
1072 |
}
|
|
raj@2224
|
1073 |
|
|
mathieu@2608
|
1074 |
Ptr<TcpSocket> TcpSocket::Copy ()
|
|
mathieu@2608
|
1075 |
{
|
|
mathieu@2608
|
1076 |
return CopyObject<TcpSocket> (this);
|
|
mathieu@2608
|
1077 |
}
|
|
mathieu@2608
|
1078 |
|
|
raj@2224
|
1079 |
void TcpSocket::NewAck (SequenceNumber seq)
|
|
raj@2224
|
1080 |
{ // New acknowledgement up to sequence number "seq"
|
|
raj@2224
|
1081 |
// Adjust congestion window in response to new ack's received
|
|
raj@2224
|
1082 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
1083 |
NS_LOG_PARAMS (this << seq);
|
|
raj@2224
|
1084 |
NS_LOG_LOGIC ("TcpSocket " << this << " NewAck "
|
|
raj@2224
|
1085 |
<< " seq " << seq
|
|
raj@2224
|
1086 |
<< " cWnd " << m_cWnd
|
|
raj@2224
|
1087 |
<< " ssThresh " << m_ssThresh);
|
|
raj@2224
|
1088 |
if (m_cWnd < m_ssThresh)
|
|
raj@2224
|
1089 |
{ // Slow start mode, add one segSize to cWnd
|
|
raj@2224
|
1090 |
m_cWnd += m_segmentSize;
|
|
raj@2224
|
1091 |
NS_LOG_LOGIC ("TcpSocket " << this << " NewCWnd SlowStart, cWnd " << m_cWnd
|
|
raj@2224
|
1092 |
<< " sst " << m_ssThresh);
|
|
raj@2224
|
1093 |
}
|
|
raj@2224
|
1094 |
else
|
|
raj@2224
|
1095 |
{ // Congestion avoidance mode, adjust by (ackBytes*segSize) / cWnd
|
|
raj@2224
|
1096 |
double adder = ((double) m_segmentSize * m_segmentSize) / m_cWnd;
|
|
raj@2224
|
1097 |
if (adder < 1.0)
|
|
raj@2224
|
1098 |
{
|
|
raj@2224
|
1099 |
adder = 1.0;
|
|
raj@2224
|
1100 |
}
|
|
raj@2224
|
1101 |
m_cWnd += (uint32_t) adder;
|
|
raj@2224
|
1102 |
NS_LOG_LOGIC ("NewCWnd CongAvoid, cWnd " << m_cWnd
|
|
raj@2224
|
1103 |
<< " sst " << m_ssThresh);
|
|
raj@2224
|
1104 |
}
|
|
raj@2224
|
1105 |
CommonNewAck (seq, false); // Complete newAck processing
|
|
raj@2224
|
1106 |
}
|
|
raj@2224
|
1107 |
|
|
raj@2224
|
1108 |
void TcpSocket::DupAck (const TcpHeader& t, uint32_t count)
|
|
raj@2224
|
1109 |
{
|
|
raj@2224
|
1110 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
1111 |
NS_LOG_PARAMS (this << "t " << count);
|
|
raj@2224
|
1112 |
NS_LOG_LOGIC ("TcpSocket " << this << " DupAck " << t.GetAckNumber ()
|
|
raj@2224
|
1113 |
<< ", count " << count
|
|
raj@2224
|
1114 |
<< ", time " << Simulator::Now ());
|
|
raj@2224
|
1115 |
if (count == 3)
|
|
raj@2224
|
1116 |
{ // Count of three indicates triple duplicate ack
|
|
raj@2224
|
1117 |
m_ssThresh = Window () / 2; // Per RFC2581
|
|
raj@2224
|
1118 |
m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
|
|
raj@2224
|
1119 |
NS_LOG_LOGIC("TcpSocket " << this << "Tahoe TDA, time " << Simulator::Now ()
|
|
raj@2224
|
1120 |
<< " seq " << t.GetAckNumber ()
|
|
raj@2224
|
1121 |
<< " in flight " << BytesInFlight ()
|
|
raj@2224
|
1122 |
<< " new ssthresh " << m_ssThresh);
|
|
raj@2224
|
1123 |
|
|
raj@2224
|
1124 |
m_cWnd = m_segmentSize; // Collapse cwnd (re-enter slowstart)
|
|
raj@2224
|
1125 |
// For Tahoe, we also reset nextTxSeq
|
|
raj@2224
|
1126 |
m_nextTxSequence = m_highestRxAck;
|
|
raj@2224
|
1127 |
SendPendingData ();
|
|
raj@2224
|
1128 |
}
|
|
raj@2224
|
1129 |
}
|
|
raj@2224
|
1130 |
|
|
raj@2224
|
1131 |
void TcpSocket::ReTxTimeout ()
|
|
raj@2224
|
1132 |
{ // Retransmit timeout
|
|
raj@2224
|
1133 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
1134 |
NS_LOG_PARAMS (this);
|
|
raj@2224
|
1135 |
m_ssThresh = Window () / 2; // Per RFC2581
|
|
raj@2224
|
1136 |
m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
|
|
raj@2224
|
1137 |
// Set cWnd to segSize on timeout, per rfc2581
|
|
raj@2224
|
1138 |
// Collapse congestion window (re-enter slowstart)
|
|
raj@2224
|
1139 |
m_cWnd = m_segmentSize;
|
|
raj@2224
|
1140 |
m_nextTxSequence = m_highestRxAck; // Start from highest Ack
|
|
raj@2224
|
1141 |
m_rtt->IncreaseMultiplier (); // Double timeout value for next retx timer
|
|
raj@2224
|
1142 |
Retransmit (); // Retransmit the packet
|
|
raj@2224
|
1143 |
}
|
|
raj@2224
|
1144 |
|
|
raj@2224
|
1145 |
void TcpSocket::LastAckTimeout ()
|
|
raj@2224
|
1146 |
{
|
|
raj@2224
|
1147 |
m_lastAckEvent.Cancel ();
|
|
raj@2224
|
1148 |
if (m_state == LAST_ACK)
|
|
raj@2224
|
1149 |
{
|
|
raj@2224
|
1150 |
Actions_t action = ProcessEvent (TIMEOUT);
|
|
raj@2224
|
1151 |
ProcessAction (action);
|
|
raj@2224
|
1152 |
}
|
|
raj@2224
|
1153 |
if (!m_closeNotified)
|
|
raj@2224
|
1154 |
{
|
|
raj@2224
|
1155 |
m_closeNotified = true;
|
|
raj@2224
|
1156 |
}
|
|
raj@2224
|
1157 |
}
|
|
raj@2224
|
1158 |
|
|
raj@2224
|
1159 |
void TcpSocket::Retransmit ()
|
|
raj@2224
|
1160 |
{
|
|
raj@2224
|
1161 |
NS_LOG_FUNCTION;
|
|
raj@2224
|
1162 |
NS_LOG_PARAMS (this);
|
|
raj@2224
|
1163 |
uint8_t flags = TcpHeader::NONE;
|
|
raj@2224
|
1164 |
if (m_state == SYN_SENT)
|
|
raj@2224
|
1165 |
{
|
|
raj@2224
|
1166 |
if (m_cnCount > 0)
|
|
raj@2224
|
1167 |
{
|
|
raj@2224
|
1168 |
SendEmptyPacket (TcpHeader::SYN);
|
|
raj@2224
|
1169 |
return;
|
|
raj@2224
|
1170 |
}
|
|
raj@2224
|
1171 |
else
|
|
raj@2224
|
1172 |
{
|
|
raj@2224
|
1173 |
NotifyConnectionFailed ();
|
|
raj@2224
|
1174 |
return;
|
|
raj@2224
|
1175 |
}
|
|
raj@2224
|
1176 |
}
|
|
raj@2224
|
1177 |
if (!m_pendingData)
|
|
raj@2224
|
1178 |
{
|
|
raj@2224
|
1179 |
if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2)
|
|
raj@2224
|
1180 |
{ // Must have lost FIN, re-send
|
|
raj@2224
|
1181 |
SendEmptyPacket (TcpHeader::FIN);
|
|
raj@2224
|
1182 |
}
|
|
raj@2224
|
1183 |
return;
|
|
raj@2224
|
1184 |
}
|
|
raj@2354
|
1185 |
Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
|
|
raj@2224
|
1186 |
m_firstPendingSequence,
|
|
raj@2224
|
1187 |
m_highestRxAck);
|
|
raj@2224
|
1188 |
// Calculate remaining data for COE check
|
|
raj@2354
|
1189 |
uint32_t remainingData = m_pendingData->SizeFromSeq (
|
|
raj@2354
|
1190 |
m_firstPendingSequence,
|
|
raj@2354
|
1191 |
m_nextTxSequence + SequenceNumber(p->GetSize ()));
|
|
raj@2224
|
1192 |
if (m_closeOnEmpty && remainingData == 0)
|
|
raj@2224
|
1193 |
{ // Add the FIN flag
|
|
raj@2224
|
1194 |
flags = flags | TcpHeader::FIN;
|
|
raj@2224
|
1195 |
}
|
|
raj@2354
|
1196 |
|
|
raj@2224
|
1197 |
NS_LOG_LOGIC ("TcpSocket " << this << " retxing seq " << m_highestRxAck);
|
|
raj@2224
|
1198 |
if (m_retxEvent.IsExpired () )
|
|
raj@2224
|
1199 |
{
|
|
raj@2224
|
1200 |
Time rto = m_rtt->RetransmitTimeout ();
|
|
raj@2224
|
1201 |
NS_LOG_LOGIC ("Schedule retransmission timeout at time "
|
|
raj@2224
|
1202 |
<< Simulator::Now ().GetSeconds () << " to expire at time "
|
|
raj@2224
|
1203 |
<< (Simulator::Now () + rto).GetSeconds ());
|
|
raj@2224
|
1204 |
m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
|
|
raj@2224
|
1205 |
}
|
|
raj@2354
|
1206 |
m_rtt->SentSeq (m_highestRxAck,p->GetSize ());
|
|
raj@2224
|
1207 |
// And send the packet
|
|
raj@2224
|
1208 |
TcpHeader tcpHeader;
|
|
raj@2224
|
1209 |
tcpHeader.SetSequenceNumber (m_nextTxSequence);
|
|
raj@2224
|
1210 |
tcpHeader.SetAckNumber (m_nextRxSequence);
|
|
raj@2224
|
1211 |
tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
|
|
mathieu@2608
|
1212 |
tcpHeader.SetDestinationPort (m_remotePort);
|
|
raj@2224
|
1213 |
tcpHeader.SetFlags (flags);
|
|
raj@2224
|
1214 |
tcpHeader.SetWindowSize (m_advertisedWindowSize);
|
|
raj@2224
|
1215 |
|
|
raj@2224
|
1216 |
m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
|
|
mathieu@2608
|
1217 |
m_remoteAddress);
|
|
raj@2224
|
1218 |
}
|
|
raj@2224
|
1219 |
|
|
raj@2224
|
1220 |
}//namespace ns3
|