|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // tcp_sap.cpp - TCP service access point |
|
15 // TCP Service Access Point and most of the protocol logic. |
|
16 // |
|
17 |
|
18 |
|
19 |
|
20 /** |
|
21 @file tcp_sap.cpp |
|
22 */ |
|
23 |
|
24 #include "tcp.h" |
|
25 #include <in6_dstcache.h> |
|
26 #include <in6_opt.h> |
|
27 #include <in6_if.h> |
|
28 #include <in6_dstcache_internal.h> |
|
29 #include <nifman_internal.h> |
|
30 |
|
31 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
32 #include <in_sock.h> |
|
33 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
34 |
|
35 // speed optimisations |
|
36 #ifdef __ARMCC__ |
|
37 #pragma push |
|
38 #pragma arm |
|
39 #endif |
|
40 |
|
41 #define SIGNED_UNSIGNED_FIX |
|
42 |
|
43 // Copied from ip6.cpp. Should move to some common definition file? |
|
44 static const TLitC8<sizeof(TInt)> KInetOptionDisable = {sizeof(TInt), {0}}; |
|
45 |
|
46 #define SYMBIAN_NETWORKING_UPS |
|
47 |
|
48 // |
|
49 // |
|
50 // TCP state diagram from RFC793 |
|
51 // |
|
52 // |
|
53 // +---------+ ---------\ active OPEN |
|
54 // | CLOSED | \ ----------- |
|
55 // +---------+<---------\ \ create TCB |
|
56 // | ^ \ \ snd SYN |
|
57 // passive OPEN | | CLOSE \ \. |
|
58 // ------------ | | ---------- \ \. |
|
59 // create TCB | | delete TCB \ \. |
|
60 // V | \ \. |
|
61 // +---------+ CLOSE | \. |
|
62 // | LISTEN | ---------- | | |
|
63 // +---------+ delete TCB | | |
|
64 // rcv SYN | | SEND | | |
|
65 // ----------- | | ------- | V |
|
66 // +---------+ snd SYN,ACK / \ snd SYN +---------+ |
|
67 // | |<----------------- ------------------>| | |
|
68 // | SYN | rcv SYN | SYN | |
|
69 // | RCVD |<-----------------------------------------------| SENT | |
|
70 // | | snd ACK | | |
|
71 // | |------------------ -------------------| | |
|
72 // +---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+ |
|
73 // | -------------- | | ----------- |
|
74 // | x | | snd ACK |
|
75 // | V V |
|
76 // | CLOSE +---------+ |
|
77 // | ------- | ESTAB | |
|
78 // | snd FIN +---------+ |
|
79 // | CLOSE | | rcv FIN |
|
80 // V ------- | | ------- |
|
81 // +---------+ snd FIN / \ snd ACK +---------+ |
|
82 // | FIN |<----------------- ------------------>| CLOSE | |
|
83 // | WAIT-1 |------------------ | WAIT | |
|
84 // +---------+ rcv FIN \ +---------+ |
|
85 // | rcv ACK of FIN ------- | CLOSE | |
|
86 // | -------------- snd ACK | ------- | |
|
87 // V x V snd FIN V |
|
88 // +---------+ +---------+ +---------+ |
|
89 // |FINWAIT-2| | CLOSING | | LAST-ACK| |
|
90 // +---------+ +---------+ +---------+ |
|
91 // | rcv ACK of FIN | rcv ACK of FIN | |
|
92 // | rcv FIN -------------- | Timeout=2MSL -------------- | |
|
93 // | ------- x V ------------ x V |
|
94 // \ snd ACK +---------+delete TCB +---------+ |
|
95 // ------------------------>|TIME WAIT|------------------>| CLOSED | |
|
96 // +---------+ +---------+ |
|
97 // |
|
98 // LISTEN - represents waiting for a connection request from any remote |
|
99 // TCP and port. |
|
100 // |
|
101 // SYN-SENT - represents waiting for a matching connection request |
|
102 // after having sent a connection request. |
|
103 // |
|
104 // SYN-RECEIVED - represents waiting for a confirming connection |
|
105 // request acknowledgment after having both received and sent a |
|
106 // connection request. |
|
107 // |
|
108 // ESTABLISHED - represents an open connection, data received can be |
|
109 // delivered to the user. The normal state for the data transfer phase |
|
110 // of the connection. |
|
111 // |
|
112 // FIN-WAIT-1 - represents waiting for a connection termination request |
|
113 // from the remote TCP, or an acknowledgment of the connection |
|
114 // termination request previously sent. |
|
115 // |
|
116 // FIN-WAIT-2 - represents waiting for a connection termination request |
|
117 // from the remote TCP. |
|
118 // |
|
119 // CLOSE-WAIT - represents waiting for a connection termination request |
|
120 // from the local user. |
|
121 // |
|
122 // CLOSING - represents waiting for a connection termination request |
|
123 // acknowledgment from the remote TCP. |
|
124 // |
|
125 // LAST-ACK - represents waiting for an acknowledgment of the |
|
126 // connection termination request previously sent to the remote TCP |
|
127 // (which includes an acknowledgment of its connection termination request). |
|
128 // |
|
129 // TIME-WAIT - represents waiting for enough time to pass to be sure |
|
130 // the remote TCP received the acknowledgment of its connection |
|
131 // termination request. |
|
132 // |
|
133 // CLOSED - represents no connection state at all. |
|
134 // |
|
135 // CONNECT - represents waiting for a network path to become ready after |
|
136 // the user has issued an active OPEN request. The request waits in this |
|
137 // state until all the necessary negotiations have been accomplished, |
|
138 // including the establishment of security and mobility bindings. CONNECT is |
|
139 // specific to this TCP implementation and is therefore not visible in the |
|
140 // state chart above. It would be located between CLOSED and SYN-SENT. |
|
141 // |
|
142 |
|
143 |
|
144 #ifdef _LOG |
|
145 const TText *CProviderTCP6::TcpState(TUint aState) |
|
146 { |
|
147 TInt i; |
|
148 static const TText* const tcpStates[] = { |
|
149 _S("CONSTRUCTING"), |
|
150 _S("INITIAL"), |
|
151 _S("LISTEN"), |
|
152 _S("SYN-SENT"), |
|
153 _S("SYN-RECEIVED"), |
|
154 _S("ESTABLISHED"), |
|
155 _S("FIN-WAIT-1"), |
|
156 _S("FIN-WAIT-2"), |
|
157 _S("CLOSE-WAIT"), |
|
158 _S("CLOSING"), |
|
159 _S("LAST-ACK"), |
|
160 _S("TIME-WAIT"), |
|
161 _S("CLOSED"), |
|
162 _S("CONNECT"), |
|
163 _S("INVALID"), |
|
164 NULL |
|
165 }; |
|
166 |
|
167 if (aState == ~0UL) |
|
168 aState = iState; |
|
169 for (i = 0; aState && tcpStates[i+1]; aState >>= 1) |
|
170 i++; |
|
171 return tcpStates[i]; |
|
172 } |
|
173 #endif |
|
174 |
|
175 CProviderTCP6::CProviderTCP6(CProtocolInet6Base* aProtocol) |
|
176 : CProviderInet6Transport(aProtocol) |
|
177 { |
|
178 __DECLARE_NAME(_S("CProviderTCP6")); |
|
179 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
180 iWindowSetByUser = EFalse; |
|
181 #endif |
|
182 } |
|
183 |
|
184 CProviderTCP6::~CProviderTCP6() |
|
185 { |
|
186 LOG(Log::Printf(_L("\ttcp SAP[%u] being deleted"), (TInt)this)); |
|
187 Stop(); |
|
188 FreeQueues(); |
|
189 |
|
190 delete iTransmitter; |
|
191 delete iDelayAckTimer; |
|
192 delete iRetransTimer; |
|
193 delete iLingerTimer; |
|
194 |
|
195 // Delete server socket state |
|
196 if (iParent) |
|
197 { |
|
198 // Notify parent. |
|
199 iParent->SetChildDeleted(ETrue); |
|
200 iParent->DetachChild(this); |
|
201 } |
|
202 else if (iListenQueue) |
|
203 { |
|
204 // |
|
205 // Delete all pending child sockets. The child socket destructor will |
|
206 // call DetachChild(), removing itself from the socket queue. If the |
|
207 // socket has already been registered with the socket server, we will |
|
208 // simply detach it here. |
|
209 // |
|
210 while (iConnectCount) |
|
211 { |
|
212 ASSERT(iListenQueue[0]->iParent == this); |
|
213 if (iListenQueue[0]->iSockFlags.iAttached) |
|
214 DetachChild(iListenQueue[0]); |
|
215 else |
|
216 { |
|
217 if (iListenQueue[0]->InState(ETcpSynReceived)) |
|
218 { |
|
219 iListenQueue[0]->ClearSYNSettings(); |
|
220 iListenQueue[0]->iSockFlags.iSendClose = ETrue; |
|
221 iListenQueue[0]->iSockFlags.iRecvClose = ETrue; |
|
222 iListenQueue[0]->SendSegments(); |
|
223 DetachChild(iListenQueue[0]); |
|
224 } |
|
225 else |
|
226 delete iListenQueue[0]; |
|
227 } |
|
228 } |
|
229 delete[] iListenQueue; |
|
230 } |
|
231 } |
|
232 |
|
233 // |
|
234 // Initialize a SAP with default values |
|
235 // |
|
236 void CProviderTCP6::InitL() |
|
237 { |
|
238 TCallBack sender(SenderCallBack, this); |
|
239 TCallBack receiver(ReceiverCallBack, this); |
|
240 TCallBack delack(DelayAckCallBack, this); |
|
241 TCallBack transmitter(TransmitterCallBack, this); |
|
242 TCallBack retransmitter(RetransmitterCallBack, this); |
|
243 TCallBack linger(LingerTimerCallBack, this); |
|
244 |
|
245 CProviderInet6Base::InitL(); |
|
246 iFlow.SetProtocol(KProtocolInetTcp); |
|
247 iFlow.SetNotify(this); |
|
248 |
|
249 iSendQ.InitL(transmitter, 13); |
|
250 iRecvQ.InitL(receiver, 12); |
|
251 |
|
252 iTransmitter = new CAsyncCallBack(sender, KInet6DefaultPriority); |
|
253 iDelayAckTimer = new CTcpTimer(delack); |
|
254 iRetransTimer = new CTcpTimer(retransmitter); |
|
255 iLingerTimer = new CTcpTimer(linger); |
|
256 if (!iTransmitter || !iDelayAckTimer || !iRetransTimer || !iLingerTimer) |
|
257 User::Leave(KErrNoMemory); |
|
258 |
|
259 iDelayAckTimer->InitL(); |
|
260 iRetransTimer->InitL(); |
|
261 iLingerTimer->InitL(); |
|
262 iSockInBufSize = Protocol()->RecvBuf(); |
|
263 iSockOutBufSize = Protocol()->SendBuf(); |
|
264 iSsthresh = KMaxTInt32; |
|
265 iRTO = Protocol()->InitialRTO(); |
|
266 ClearRTT(); |
|
267 iMSS = Protocol()->MSS(); |
|
268 iSMSS = KTcpStandardMSS; |
|
269 iRMSS = KTcpStandardMSS; |
|
270 iLinger = -1; // linger disabled |
|
271 iFlags.iSackOk = Protocol()->Sack(); |
|
272 iFlags.iUseTimeStamps = Protocol()->TimeStamps(); |
|
273 iFlags.iEcn = (Protocol()->Ecn() != 0); |
|
274 |
|
275 // Report ICMP errors to application |
|
276 iSockFlags.iReportIcmp = ETrue; |
|
277 |
|
278 if (iFlags.iUseTimeStamps) |
|
279 iOptions.SetTimeStamps(0, 0); |
|
280 |
|
281 if (iFlags.iSackOk) |
|
282 iOptions.SetSackOk(); |
|
283 |
|
284 iOptions.SetAlignOpt(Protocol()->AlignOpt()); |
|
285 iStartTime.UniversalTime(); |
|
286 |
|
287 iState = ETcpInitial; |
|
288 |
|
289 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
290 iHiddenFreeWindow = 0; |
|
291 iNewTcpWindow = 0; |
|
292 iTcpMaxRecvWin = Protocol()->RecvMaxWnd(); |
|
293 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
294 |
|
295 } |
|
296 |
|
297 |
|
298 void CProviderTCP6::ReadDestinationCache() |
|
299 { |
|
300 if (!Protocol()->DstCache()) // Dest. cache is not enabled as ini parameter |
|
301 { |
|
302 return; |
|
303 } |
|
304 |
|
305 const TInetAddr& dstaddr = iFlow.FlowContext()->RemoteAddr(); |
|
306 if (dstaddr.IsUnspecified()) |
|
307 { |
|
308 LOG(Log::Printf(_L("\ttcp SAP[%u] ReadDestinationCache() : No destination address"), (TInt)this)); |
|
309 return; |
|
310 } |
|
311 |
|
312 TInt err = KErrNone; |
|
313 MDestinationCache *dcache = NULL; |
|
314 TRAP(err, dcache = IMPORT_API_L(Protocol()->Interfacer(), MDestinationCache)); |
|
315 if (err != KErrNone || dcache == NULL) |
|
316 { |
|
317 LOG(Log::Printf(_L("\ttcp SAP[%u] ReadDestinationCache() : DstCache not available"), (TInt)this)); |
|
318 return; |
|
319 } |
|
320 |
|
321 const TCacheInfo *cinfo = dcache->Find(dstaddr); |
|
322 if (!cinfo) |
|
323 { |
|
324 LOG(Log::Printf(_L("\ttcp SAP[%u] ReadDestinationCache() : No match for address in cache"), (TInt)this)); |
|
325 return; |
|
326 } |
|
327 |
|
328 if (cinfo->iMetrics[TCacheInfo::ESsThresh]) |
|
329 { |
|
330 iSsthresh = cinfo->iMetrics[TCacheInfo::ESsThresh]; |
|
331 } |
|
332 if (cinfo->iMetrics[TCacheInfo::ESRtt]) |
|
333 { |
|
334 iSRTT = cinfo->iMetrics[TCacheInfo::ESRtt]; |
|
335 } |
|
336 if (cinfo->iMetrics[TCacheInfo::ERto]) |
|
337 { |
|
338 iRTO = cinfo->iMetrics[TCacheInfo::ERto]; |
|
339 } |
|
340 |
|
341 LOG(Log::Printf(_L( |
|
342 "\ttcp SAP[%u] ReadDestinationCache() : Matching DstCache entry found [0x%08x] - ssthresh: %d"), |
|
343 (TInt)this, cinfo, iSsthresh)); |
|
344 } |
|
345 |
|
346 void CProviderTCP6::StoreDestinationCache() |
|
347 { |
|
348 if (!Protocol()->DstCache() || !iFlow.FlowContext()) |
|
349 { |
|
350 return; |
|
351 } |
|
352 |
|
353 const TInetAddr& dstaddr = iFlow.FlowContext()->RemoteAddr(); |
|
354 if (dstaddr.IsUnspecified()) |
|
355 { |
|
356 LOG(Log::Printf(_L("\ttcp SAP[%u] StoreDestinationCache() : No destination address"), (TInt)this)); |
|
357 return; |
|
358 } |
|
359 |
|
360 TInt err = KErrNone; |
|
361 MDestinationCache *dcache = NULL; |
|
362 TRAP(err, dcache = IMPORT_API_L(Protocol()->Interfacer(), MDestinationCache)); |
|
363 if (err != KErrNone || dcache == NULL) |
|
364 { |
|
365 LOG(Log::Printf(_L("\ttcp SAP[%u] StoreDestinationCache() : DstCache not available"), (TInt)this)); |
|
366 return; |
|
367 } |
|
368 |
|
369 TCacheInfo cinfo; |
|
370 cinfo.ClearAll(); |
|
371 cinfo.iMetrics[TCacheInfo::ESsThresh] = iSsthresh; |
|
372 cinfo.iMetrics[TCacheInfo::ESRtt] = iSRTT; |
|
373 cinfo.iMetrics[TCacheInfo::ERto] = iRTO; |
|
374 |
|
375 TRAP(err, dcache->StoreL(dstaddr, cinfo)); |
|
376 if (err != KErrNone) |
|
377 { |
|
378 LOG(Log::Printf(_L("\ttcp SAP[%u] StoreDestinationCache() : DstCache store failed"), (TInt)this)); |
|
379 return; |
|
380 } |
|
381 } |
|
382 |
|
383 |
|
384 void CProviderTCP6::Start() |
|
385 { |
|
386 LOG(Log::Printf(_L("Start\ttcp SAP[%u] enter"), (TInt)this)); |
|
387 CProviderInet6Transport::Start(); |
|
388 iFlags.iStarted = ETrue; |
|
389 |
|
390 // |
|
391 // Detach from parent socket |
|
392 // |
|
393 if (iParent) |
|
394 { |
|
395 iSockFlags.iNotify = ETrue; |
|
396 iParent->DetachChild(this); |
|
397 |
|
398 // |
|
399 // Tell ESock which network interface the child socket is using. |
|
400 // |
|
401 const MInterface *iface = Protocol()->Interfacer()->Interface(iFlow.FlowContext()->Interface()); |
|
402 if (iface != NULL) |
|
403 { |
|
404 TPckgBuf<TSoIfConnectionInfo> netinfo; |
|
405 netinfo().iIAPId = iface->Scope(EScopeType_IAP); |
|
406 netinfo().iNetworkId = iface->Scope(EScopeType_NET); |
|
407 LOG(Log::Printf(_L("\ttcp SAP[%u] Bearer IAP=%d, NID=%d"), (TInt)this, netinfo().iIAPId, netinfo().iNetworkId)); |
|
408 iSocket->Bearer(netinfo); |
|
409 } |
|
410 // |
|
411 // Report error if TCP has been disconnected already |
|
412 // |
|
413 if (InState(ETcpClosed)) |
|
414 { |
|
415 LOG(Log::Printf(_L("\ttcp SAP[%u] %s, Error %d"), (TInt)this, TcpState(), KErrDisconnected)); |
|
416 Error(KErrDisconnected); |
|
417 } |
|
418 } |
|
419 |
|
420 // |
|
421 // If an error has occurred, we must deliver it to the |
|
422 // socket server now that the socket notifier has been |
|
423 // initialised. |
|
424 // |
|
425 if (iLastError.iStatus != KErrNone && iErrorMask != 0) |
|
426 { |
|
427 LOG(Log::Printf(_L("\ttcp SAP[%u] Delayed error %d, mask %b delivered."), |
|
428 (TInt)this, iLastError.iStatus, iErrorMask)); |
|
429 iSocket->Error(iLastError.iStatus, iErrorMask); |
|
430 } |
|
431 |
|
432 // Wake up the receiver. We might have something to do. |
|
433 iRecvQ.Wake(); |
|
434 LOG(Log::Printf(_L("Start\ttcp SAP[%u] exit"), (TInt)this)); |
|
435 } |
|
436 |
|
437 |
|
438 // |
|
439 // Stop all transmission (except for iSendQ, which will be allowed to drain) |
|
440 // |
|
441 void CProviderTCP6::Stop() |
|
442 { |
|
443 if (iTransmitter) |
|
444 CancelTransmit(); |
|
445 if (iRetransTimer) |
|
446 CancelRetransmit(); |
|
447 if (iDelayAckTimer) |
|
448 CancelDelayACK(); |
|
449 if (iLingerTimer) |
|
450 iLingerTimer->Cancel(); |
|
451 } |
|
452 |
|
453 |
|
454 // |
|
455 // Empty all queues |
|
456 // |
|
457 void CProviderTCP6::FreeQueues() |
|
458 { |
|
459 iSockInQ.Free(); |
|
460 iSockInQLen = 0; |
|
461 iSockOutQ.Free(); |
|
462 iSockOutQLen = 0; |
|
463 iFragQ.Free(); |
|
464 iRecvQ.Free(); |
|
465 iSendQ.Cancel(); |
|
466 iSendQ.Free(); |
|
467 } |
|
468 |
|
469 |
|
470 // |
|
471 // Close the socket down |
|
472 // |
|
473 void CProviderTCP6::Close() |
|
474 { |
|
475 StoreDestinationCache(); |
|
476 |
|
477 iSockFlags.iSendClose = ETrue; |
|
478 iSockFlags.iRecvClose = ETrue; |
|
479 Protocol()->UnbindProvider(this); |
|
480 Stop(); |
|
481 FreeQueues(); |
|
482 EnterState(ETcpClosed); |
|
483 } |
|
484 |
|
485 |
|
486 void CProviderTCP6::Ioctl(TUint aLevel, TUint aName, TDes8* aOption) |
|
487 { |
|
488 LOG(Log::Printf(_L("Ioctl\ttcp SAP[%u] %x, %x"), (TInt)this, aLevel, aName)); |
|
489 if (aLevel == KSolInetTcp && aName == KIoctlTcpNotifyDataSent) |
|
490 { |
|
491 iFlags.iDataSentIoctl = ETrue; |
|
492 CompleteIoctl(KErrNone); |
|
493 } |
|
494 else |
|
495 CProviderInet6Transport::Ioctl(aLevel, aName, aOption); |
|
496 } |
|
497 |
|
498 |
|
499 void CProviderTCP6::CancelIoctl(TUint aLevel, TUint aName) |
|
500 { |
|
501 LOG(Log::Printf(_L("CancelIoctl\ttcp SAP[%u] %x, %x"), (TInt)this, aLevel, aName)); |
|
502 if (aLevel == KSolInetTcp && aName == KIoctlTcpNotifyDataSent) |
|
503 CompleteIoctl(KErrCancel); |
|
504 else |
|
505 CProviderInet6Transport::CancelIoctl(aLevel, aName); |
|
506 } |
|
507 |
|
508 |
|
509 TInt CProviderTCP6::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption) |
|
510 { |
|
511 TInt ret = KErrNotSupported; |
|
512 |
|
513 if (aLevel == KSolInetTcp) |
|
514 { |
|
515 TInt intValue; |
|
516 ret = GetOptionInt(aOption, intValue); |
|
517 |
|
518 #ifdef _LOG |
|
519 if (ret == KErrNone) |
|
520 Log::Printf(_L("SetOpt\ttcp SAP[%u] KSolInetTcp, %d, %d"), (TInt)this, aName, intValue); |
|
521 else |
|
522 Log::Printf(_L("SetOpt\ttcp SAP[%u] KSolInetTcp, %d"), (TInt)this, aName); |
|
523 #endif |
|
524 |
|
525 switch (aName) |
|
526 { |
|
527 case KSoTcpAsync2MslWait: |
|
528 // Not implemented. Not very useful. |
|
529 ret = KErrNotSupported; |
|
530 break; |
|
531 |
|
532 case KSoTcpKeepAlive: |
|
533 if (ret == KErrNone) |
|
534 { |
|
535 if (!intValue) |
|
536 { |
|
537 iFlags.iHaveKeepAlive = FALSE; |
|
538 iFlags.iHaveTriggeredKeepAlive = FALSE; |
|
539 } |
|
540 if (intValue & 1) |
|
541 iFlags.iHaveKeepAlive = TRUE; |
|
542 if (intValue & 2) |
|
543 iFlags.iHaveTriggeredKeepAlive = TRUE; |
|
544 } |
|
545 break; |
|
546 |
|
547 case KSoTcpMaxSegSize: |
|
548 if (ret == KErrNone) |
|
549 { |
|
550 if (!InState(ETcpInitial)) |
|
551 ret = KErrLocked; |
|
552 else if (intValue < STATIC_CAST(TInt, KTcpMinimumMSS)) |
|
553 ret = KErrArgument; |
|
554 else |
|
555 { |
|
556 iMSS = intValue; |
|
557 iSMSS = iMSS; |
|
558 iRMSS = iMSS; |
|
559 } |
|
560 } |
|
561 break; |
|
562 |
|
563 case KSoTcpNextSendUrgentData: |
|
564 if (ret == KErrNone) |
|
565 iFlags.iNextIsUrgent = intValue ? TRUE : FALSE; |
|
566 break; |
|
567 |
|
568 case KSoTcpNoDelay: |
|
569 if (ret == KErrNone) |
|
570 iFlags.iNoDelay = intValue ? TRUE : FALSE; |
|
571 break; |
|
572 |
|
573 case KSoTcpCork: |
|
574 case KSoTcpNoPush: |
|
575 if (ret == KErrNone) |
|
576 { |
|
577 iFlags.iCork = intValue ? TRUE : FALSE; |
|
578 if (iFlags.iCork == EFalse && aName == KSoTcpCork) |
|
579 { |
|
580 // When turning Cork off, send pending data from output queue immediately. |
|
581 // This is the only difference between Cork and NoPush |
|
582 SchedTransmit(); |
|
583 } |
|
584 } |
|
585 break; |
|
586 |
|
587 case KSoTcpOobInline: |
|
588 if (ret == KErrNone) |
|
589 iFlags.iOobInline = intValue ? TRUE : FALSE; |
|
590 break; |
|
591 |
|
592 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
593 case KSoTcpMaxRecvWin: |
|
594 //Case to set the Max window size from shim. |
|
595 if(ret == KErrNone) |
|
596 { |
|
597 if (InState(ETcpClosed|ETcpFinWait2|ETcpCloseWait|ETcpLastAck)) |
|
598 ret = KErrLocked; |
|
599 else |
|
600 if(intValue > iTcpMaxRecvWin) |
|
601 { |
|
602 iTcpMaxRecvWin = intValue; |
|
603 } |
|
604 |
|
605 } |
|
606 break; |
|
607 case KSoTcpRecvWinAuto: |
|
608 { |
|
609 // If user sets the window size, we have to give the preference for user setting. Automatic |
|
610 // window setting will be then disabled by default, once user calls the SetOption to set the |
|
611 // receive window, this feature will be diabled by default till the socket is opened. |
|
612 if(iWindowSetByUser) |
|
613 { |
|
614 return KErrNone; |
|
615 } |
|
616 else if (InState(ETcpClosed|ETcpFinWait2|ETcpCloseWait|ETcpLastAck)) |
|
617 ret = KErrLocked; |
|
618 else if (intValue < STATIC_CAST(TInt, KTcpMinimumWindow)) |
|
619 iSockInBufSize = KTcpMinimumWindow; |
|
620 else |
|
621 { |
|
622 |
|
623 //If new TCP window is larger then the previous window, increase the |
|
624 //iSockInBufSize right now. TCP recv function takes care of |
|
625 //advertising a new effective TCP window. |
|
626 if (intValue >= iSockInBufSize) |
|
627 { |
|
628 //Make it Zero so TCP could avoid the |
|
629 //TCP window shrinking processing in Recv. |
|
630 iNewTcpWindow = 0; |
|
631 //FreeWindow has to be increased at the same time. |
|
632 iFreeWindow += intValue - iSockInBufSize; |
|
633 // Make the new TCP receive buffer change effective now. |
|
634 iSockInBufSize = intValue; |
|
635 } |
|
636 else |
|
637 { |
|
638 //This sets iNewTcpWindow to a non-zero value, which indicates |
|
639 //to the TCP that window is shrunk and process TCP segments |
|
640 //which are in air before setting a new TCP receive buffer. |
|
641 //TCP Receive window starts moving only when TCP hidden window |
|
642 //size exceeds the size of the shrunk window. |
|
643 |
|
644 iNewTcpWindow = intValue; |
|
645 //Even in case of window shrink we can set the receive buffer size |
|
646 //immediately. This will be helpful, for processing SYN-ACK and other |
|
647 //receiver side processing. |
|
648 //For already connected sockets iNewTcpWindow will be taking care |
|
649 //of shrinking the window size for that TCP session. |
|
650 iSockInBufSize = iNewTcpWindow; |
|
651 if( iAdvertisedWindow > iNewTcpWindow ) |
|
652 { |
|
653 iShrinkedWindowSize = iAdvertisedWindow - iNewTcpWindow; |
|
654 } |
|
655 else |
|
656 { |
|
657 // No Need to process TCP receive window processing. |
|
658 iNewTcpWindow = 0; |
|
659 } |
|
660 } |
|
661 |
|
662 } |
|
663 |
|
664 } |
|
665 break; |
|
666 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
667 case KSoTcpRecvWinSize: |
|
668 { |
|
669 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
670 iWindowSetByUser = ETrue; |
|
671 #endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
672 if (ret == KErrNone) |
|
673 { |
|
674 if (!InState(ETcpInitial)) |
|
675 ret = KErrLocked; |
|
676 else if (intValue < STATIC_CAST(TInt, KTcpMinimumWindow)) |
|
677 iSockInBufSize = KTcpMinimumWindow; |
|
678 else |
|
679 { |
|
680 iSockInBufSize = intValue; |
|
681 } |
|
682 } |
|
683 } |
|
684 break; |
|
685 |
|
686 case KSoTcpSendWinSize: |
|
687 if (ret == KErrNone) |
|
688 { |
|
689 if (!InState(ETcpInitial)) |
|
690 ret = KErrLocked; |
|
691 else if (intValue < STATIC_CAST(TInt, KTcpMinimumWindow)) |
|
692 iSockOutBufSize = KTcpMinimumWindow; |
|
693 else |
|
694 iSockOutBufSize = intValue; |
|
695 } |
|
696 break; |
|
697 |
|
698 case KSoTcpLinger: |
|
699 if (aOption.Length() < (TInt)sizeof(TSoTcpLingerOpt)) |
|
700 { |
|
701 return KErrArgument; |
|
702 } |
|
703 if (iSockFlags.iSendClose) |
|
704 { |
|
705 return KErrInUse; |
|
706 } |
|
707 |
|
708 { |
|
709 TSoTcpLingerOpt *opt = (TSoTcpLingerOpt *)aOption.Ptr(); |
|
710 if (opt->iOnOff != 0 && opt->iLinger >= 0) |
|
711 { |
|
712 if (opt->iLinger > KTcpMaxLingerTime) |
|
713 { |
|
714 return KErrArgument; |
|
715 } |
|
716 iLinger = opt->iLinger; // linger enabled. |
|
717 } |
|
718 else |
|
719 { |
|
720 iLinger = -1; // linger disabled. |
|
721 } |
|
722 } |
|
723 break; |
|
724 |
|
725 default: |
|
726 ret = KErrNotSupported; |
|
727 break; |
|
728 } |
|
729 } |
|
730 |
|
731 if (aLevel == KSolInetIp) |
|
732 { |
|
733 TInt intValue; |
|
734 ret = GetOptionInt(aOption, intValue); |
|
735 |
|
736 switch(aName) |
|
737 { |
|
738 case KSoIpTOS: |
|
739 // Silently filter out the ECN bits from TOS setting. |
|
740 // We're assuming that Protocol->Ecn() (based on ini params) holds the correct |
|
741 // values for ECN bits. |
|
742 { |
|
743 intValue = (intValue & 0xfc) | Protocol()->Ecn(); |
|
744 TPckgBuf<TInt> tosopt(intValue); |
|
745 |
|
746 // Rest of the option processing is done at the lower levels. |
|
747 return CProviderInet6Transport::SetOption(aLevel, aName, tosopt); |
|
748 } |
|
749 |
|
750 case KSoHeaderIncluded: |
|
751 case KSoRawMode: |
|
752 // The base class implements HeaderIncluded and RawMode by default. |
|
753 // Force "Not Supported" for TCP here! |
|
754 return KErrNotSupported; |
|
755 default: |
|
756 ret = KErrNotSupported; |
|
757 } |
|
758 } |
|
759 |
|
760 |
|
761 if (ret == KErrNotSupported) |
|
762 ret = CProviderInet6Transport::SetOption(aLevel, aName, aOption); |
|
763 |
|
764 return ret; |
|
765 } |
|
766 |
|
767 |
|
768 TInt CProviderTCP6::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const |
|
769 { |
|
770 LOG(Log::Printf(_L("GetOpt\ttcp SAP[%u] %d, %d"), (TInt)this, aLevel, aName)); |
|
771 CProviderTCP6 *This = CONST_CAST(CProviderTCP6*, this); |
|
772 TInt ret = KErrNotSupported, urgentChar; |
|
773 |
|
774 switch (aLevel) |
|
775 { |
|
776 case KSOLSocket: |
|
777 switch (aName) |
|
778 { |
|
779 case KSOReadBytesPending: |
|
780 ret = SetOptionInt(aOption, iPending); |
|
781 break; |
|
782 |
|
783 case KSOUrgentDataOffset: |
|
784 ret = SetOptionInt(aOption, iUpCount ? UrgentOffset() - iUpCount + 1 : 0); |
|
785 LOG(Log::Printf(_L("\ttcp SAP[%u] Urgent data offset = %d"), |
|
786 (TInt)this, iUpCount ? UrgentOffset() : 0)); |
|
787 break; |
|
788 |
|
789 default: |
|
790 break; |
|
791 } |
|
792 break; |
|
793 |
|
794 case KSolInetTcp: |
|
795 switch (aName) |
|
796 { |
|
797 case KSoTcpAsync2MslWait: |
|
798 // XXX - Not implemented. Not very useful. |
|
799 break; |
|
800 |
|
801 case KSoTcpKeepAlive: |
|
802 ret = SetOptionInt(aOption, iFlags.iHaveKeepAlive); |
|
803 break; |
|
804 |
|
805 case KSoTcpMaxSegSize: |
|
806 ret = SetOptionInt(aOption, iMSS); |
|
807 break; |
|
808 |
|
809 case KSoTcpNextSendUrgentData: |
|
810 ret = SetOptionInt(aOption, iFlags.iNextIsUrgent); |
|
811 break; |
|
812 |
|
813 case KSoTcpNoDelay: |
|
814 ret = SetOptionInt(aOption, iFlags.iNoDelay); |
|
815 break; |
|
816 |
|
817 case KSoTcpCork: |
|
818 case KSoTcpNoPush: |
|
819 ret = SetOptionInt(aOption, iFlags.iCork); |
|
820 break; |
|
821 |
|
822 case KSoTcpOobInline: |
|
823 ret = SetOptionInt(aOption, iFlags.iOobInline); |
|
824 break; |
|
825 |
|
826 case KSoTcpRecvWinSize: |
|
827 ret = SetOptionInt(aOption, iSockInBufSize); |
|
828 break; |
|
829 |
|
830 case KSoTcpSendWinSize: |
|
831 ret = SetOptionInt(aOption, iSockOutBufSize); |
|
832 break; |
|
833 |
|
834 case KSoTcpListening: |
|
835 ret = SetOptionInt(aOption, InState(ETcpListen) ? 1 : 0); |
|
836 break; |
|
837 |
|
838 case KSoTcpNumSockets: |
|
839 ret = SetOptionInt(aOption, Protocol()->SapCount()); |
|
840 break; |
|
841 |
|
842 case KSoTcpLinger: |
|
843 if (aOption.MaxLength() < (TInt)sizeof(TSoTcpLingerOpt)) |
|
844 { |
|
845 return KErrTooBig; |
|
846 } |
|
847 |
|
848 TSoTcpLingerOpt opt; |
|
849 if (iLinger == -1) |
|
850 { |
|
851 opt.iOnOff = 0; |
|
852 opt.iLinger = 0; |
|
853 } |
|
854 else |
|
855 { |
|
856 opt.iOnOff = 1; |
|
857 opt.iLinger = iLinger; |
|
858 } |
|
859 aOption.SetLength(sizeof(opt)); |
|
860 aOption.Copy((TUint8*)&opt, sizeof(opt)); |
|
861 ret = KErrNone; |
|
862 break; |
|
863 |
|
864 case KSoTcpPeekUrgentData: |
|
865 if (ret = This->GetUrgent(urgentChar, KSockReadPeek), ret == KErrNone) |
|
866 ret = SetOptionInt(aOption, urgentChar); |
|
867 break; |
|
868 |
|
869 case KSoTcpRcvAtMark: |
|
870 ret = SetOptionInt(aOption, (UrgentOffset() == 0) ? 1 : 0); |
|
871 break; |
|
872 |
|
873 case KSoTcpReadBytesPending: |
|
874 ret = SetOptionInt(aOption, iPending); |
|
875 break; |
|
876 |
|
877 case KSoTcpReadUrgentData: |
|
878 if (ret = This->GetUrgent(urgentChar, 0), ret == KErrNone) |
|
879 ret = SetOptionInt(aOption, urgentChar); |
|
880 break; |
|
881 |
|
882 case KSoTcpSendBytesPending: |
|
883 ret = SetOptionInt(aOption, iSockOutQLen); |
|
884 break; |
|
885 |
|
886 default: |
|
887 break; |
|
888 } |
|
889 break; |
|
890 |
|
891 case KSolInetIp: |
|
892 switch(aName) |
|
893 { |
|
894 case KSoIpTOS: |
|
895 // Clear the ECN bits from the returned value before delivering it to socket. |
|
896 ret = CProviderInet6Transport::GetOption(aLevel, aName, aOption); |
|
897 if (ret != KErrNone) |
|
898 { |
|
899 TInt intValue; |
|
900 if (GetOptionInt(aOption, intValue) == KErrNone) |
|
901 ret = SetOptionInt(aOption, intValue & 0xfc); |
|
902 } |
|
903 break; |
|
904 case KSoHeaderIncluded: |
|
905 case KSoRawMode: |
|
906 // The base class implements HeaderIncluded and RawMode by default. |
|
907 // Force "Not Supported" for TCP here! |
|
908 return KErrNotSupported; |
|
909 default: |
|
910 break; |
|
911 } |
|
912 break; |
|
913 |
|
914 default: |
|
915 break; |
|
916 } |
|
917 |
|
918 if (ret == KErrNotSupported) |
|
919 ret = CProviderInet6Transport::GetOption(aLevel, aName, aOption); |
|
920 |
|
921 return ret; |
|
922 } |
|
923 |
|
924 |
|
925 TInt CProviderTCP6::SetRemName(TSockAddr &aAddr) |
|
926 { |
|
927 TInt err; |
|
928 TInetAddr addr = aAddr; |
|
929 |
|
930 // Check port range |
|
931 if (addr.Port() < 1 || addr.Port() > 65535) |
|
932 return KErrGeneral; |
|
933 |
|
934 // Check address |
|
935 if (addr.IsUnspecified() || !addr.IsUnicast()) |
|
936 return KErrBadName; |
|
937 |
|
938 if (addr.Family() == KAfInet) |
|
939 addr.ConvertToV4Mapped(); |
|
940 |
|
941 TInt family = addr.IsV4Mapped() ? KAfInet : KAfInet6; |
|
942 |
|
943 if(iSockFamily == KAFUnspec) |
|
944 iSockFamily = family; |
|
945 else if (iSockFamily != family) |
|
946 return KErrBadName; |
|
947 |
|
948 // |
|
949 // If we're reusing a local address we must check for an existing |
|
950 // connection before we can accept the remote address. |
|
951 // |
|
952 if (iSockFlags.iReuse && iFlow.FlowContext()->LocalPort() != KInetPortNone) |
|
953 { |
|
954 if (Protocol()->LocateSap(EMatchConnection, KAFUnspec, iFlow.FlowContext()->LocalAddr(), addr)) |
|
955 return KErrInUse; |
|
956 } |
|
957 |
|
958 // Set remote address and port.. use original to get iAppFamily valid. |
|
959 if (err = CProviderInet6Transport::SetRemName(aAddr), err != KErrNone) |
|
960 return err; |
|
961 |
|
962 return KErrNone; |
|
963 } |
|
964 |
|
965 |
|
966 void CProviderTCP6::ActiveOpen() |
|
967 { |
|
968 LOG(Log::Printf(_L("ActiveOpen\ttcp SAP[%u]"), (TInt)this)); |
|
969 ASSERT(InState(ETcpInitial)); |
|
970 |
|
971 TInt status = iFlow.Connect(); |
|
972 if (status < 0) |
|
973 { |
|
974 LOG(Log::Printf(_L("\ttcp SAP[%u] Flow status = %d"), (TInt)this, status)); |
|
975 iSockFlags.iConnected = EFalse; |
|
976 Error(status, MSocketNotify::EErrorConnect); |
|
977 return; |
|
978 } |
|
979 |
|
980 // Store KeepInterfaceUp to be restored when entering Established state. |
|
981 StoreKeepInterfaceUp(); |
|
982 |
|
983 EnterState(ETcpConnect); |
|
984 if (status == EFlow_READY) |
|
985 SendSYN(); |
|
986 } |
|
987 |
|
988 |
|
989 TInt CProviderTCP6::PassiveOpen(TUint aQueSize) |
|
990 { |
|
991 ASSERT(InState(ETcpInitial)); |
|
992 ASSERT(!iListenQueue); |
|
993 LOG(Log::Printf(_L("PassiveOpen\ttcp SAP[%u] QueSize=%d"), (TInt)this, aQueSize)); |
|
994 |
|
995 // |
|
996 // On EPOC you can only call listen once, so it is safe to do this here. |
|
997 // |
|
998 iListenQueue = new CProviderTCP6*[aQueSize]; |
|
999 if (!iListenQueue) |
|
1000 return KErrNoMemory; |
|
1001 |
|
1002 iListenQueueSize = aQueSize; |
|
1003 for (TUint i=0; i < iListenQueueSize; i++) |
|
1004 iListenQueue[i] = 0; |
|
1005 EnterState(ETcpListen); |
|
1006 return KErrNone; |
|
1007 } |
|
1008 |
|
1009 // |
|
1010 // This routine tries to detach the socket from the socket server. |
|
1011 // Detach() is called from Shutdown(), when the user has called |
|
1012 // Close() or Shutdown(ENormal). |
|
1013 // |
|
1014 // If linger timeout is active, Shutdown() will complete with |
|
1015 // error KErrWouldBlock. |
|
1016 // |
|
1017 void CProviderTCP6::Detach() |
|
1018 { |
|
1019 LOG(Log::Printf(_L("\ttcp SAP[%u] Detach()"), (TInt)this)); |
|
1020 |
|
1021 StoreDestinationCache(); |
|
1022 |
|
1023 CompleteIoctl(KErrCancel); |
|
1024 if (iLinger > 0) |
|
1025 { |
|
1026 iLingerTimer->Cancel(); |
|
1027 Error(KErrWouldBlock, MSocketNotify::EErrorClose); |
|
1028 } |
|
1029 iLinger = -1; |
|
1030 NoSecurityChecker(); // The checker will be unusable. |
|
1031 iSocket->CanClose(MSocketNotify::EDetach); |
|
1032 iSockFlags.iNotify = EFalse; // No more upcalls |
|
1033 iSockFlags.iAttached = (iSocket != 0); // Did we get detached? |
|
1034 LOG(if (iSockFlags.iAttached) Log::Printf(_L("\ttcp SAP[%u] DETACH FAILED!"), (TInt)this)); |
|
1035 ASSERT(!iSockFlags.iAttached); |
|
1036 } |
|
1037 |
|
1038 void CProviderTCP6::Expire() |
|
1039 { |
|
1040 if (!iSockFlags.iAttached) |
|
1041 { |
|
1042 LOG(Log::Printf(_L("\ttcp SAP[%u] Expire(): SELF DESTRUCT!"), (TInt)this)); |
|
1043 delete this; |
|
1044 return; |
|
1045 } |
|
1046 if (iSockFlags.iNotify) |
|
1047 { |
|
1048 LOG(Log::Printf(_L("\ttcp SAP[%u] Expire(): DISCONNECT!"), (TInt)this)); |
|
1049 Close(); |
|
1050 iSockFlags.iNotify = EFalse; |
|
1051 iSocket->Disconnect(); |
|
1052 } |
|
1053 } |
|
1054 |
|
1055 void CProviderTCP6::Shutdown(TCloseType aOption) |
|
1056 { |
|
1057 LOG(Log::Printf(_L("Shutdown\ttcp SAP[%u] TCloseType=%d"), (TInt)this, aOption)); |
|
1058 |
|
1059 switch(aOption) |
|
1060 { |
|
1061 case ENormal: |
|
1062 if (InState(ETcpListen|ETcpInitial|ETcpConnect|ETcpSynSent|ETcpClosed)) |
|
1063 { |
|
1064 // Just do a brutal shutdown in these states. |
|
1065 Close(); |
|
1066 break; |
|
1067 } |
|
1068 |
|
1069 // No need to negotiate parameters as we only want to notify other end point. |
|
1070 if (InState(ETcpSynReceived)) |
|
1071 ClearSYNSettings(); |
|
1072 |
|
1073 // Send RST if receive queue is not empty. |
|
1074 if (iLinger == 0 || SockInQLen() || !iFragQ.IsEmpty()) |
|
1075 { |
|
1076 SendReset(iSND.NXT); |
|
1077 if (FatalState()) |
|
1078 break; |
|
1079 |
|
1080 // If linger is enabled and timer==0, close the socket immediately |
|
1081 if (iLinger == 0) |
|
1082 { |
|
1083 Close(); |
|
1084 break; |
|
1085 } |
|
1086 } |
|
1087 |
|
1088 iSockFlags.iSendClose = ETrue; |
|
1089 iSockFlags.iRecvClose = ETrue; |
|
1090 iSockInQ.Free(); |
|
1091 iSockInQLen = 0; |
|
1092 iFragQ.Free(); |
|
1093 iNewData = 0; |
|
1094 |
|
1095 if (iLinger == -1 || iSockOutQLen == 0) |
|
1096 { |
|
1097 Detach(); |
|
1098 } |
|
1099 else |
|
1100 { |
|
1101 // |
|
1102 // Start linger timer. RSocket::Close() returns when timer |
|
1103 // expires or when all data has been succesfully transmitted. |
|
1104 // |
|
1105 iLingerTimer->Start(iLinger * KOneSecondUs); |
|
1106 } |
|
1107 SchedTransmit(); |
|
1108 |
|
1109 break; |
|
1110 |
|
1111 case EStopInput: |
|
1112 case EStopOutput: |
|
1113 if (InState(ETcpListen|ETcpInitial)) |
|
1114 { |
|
1115 Error(KErrNotSupported, MSocketNotify::EErrorClose); |
|
1116 return; |
|
1117 } |
|
1118 |
|
1119 if (aOption == EStopInput) |
|
1120 { |
|
1121 iSockFlags.iRecvClose = ETrue; |
|
1122 |
|
1123 // Send RST if receive queue is not empty. |
|
1124 if (SockInQLen() || !iFragQ.IsEmpty()) |
|
1125 { |
|
1126 SendReset(iSND.NXT); |
|
1127 if (FatalState()) |
|
1128 break; |
|
1129 } |
|
1130 iSockInQ.Free(); |
|
1131 iFragQ.Free(); |
|
1132 iNewData = 0; |
|
1133 } |
|
1134 else |
|
1135 { |
|
1136 // HalfDuplex Close and simultaneous SYN_RCVD -> FIN_WAIT_1 is not supported. |
|
1137 iSockFlags.iSendClose = ETrue; |
|
1138 SchedTransmit(); |
|
1139 } |
|
1140 |
|
1141 Error(KErrNone, MSocketNotify::EErrorClose); |
|
1142 Nif::SetSocketState(ENifSocketConnected, this); |
|
1143 break; |
|
1144 |
|
1145 case EImmediate: |
|
1146 if (InState(ETcpSynReceived|ETcpEstablished|ETcpFinWait1|ETcpFinWait2|ETcpCloseWait)) |
|
1147 SendReset(iSND.NXT); |
|
1148 CompleteIoctl(KErrCancel); |
|
1149 Close(); |
|
1150 return; |
|
1151 |
|
1152 default: |
|
1153 Panic(EInet6Panic_NotSupported); |
|
1154 break; |
|
1155 } |
|
1156 |
|
1157 // |
|
1158 // If we encountered a fatal error during the above processing, |
|
1159 // stop everything and enter CLOSED state. |
|
1160 // |
|
1161 if (FatalState()) |
|
1162 Close(); |
|
1163 |
|
1164 if (InState(ETcpFinWait2) && iSockFlags.iRecvClose) |
|
1165 { |
|
1166 LOG(Log::Printf(_L("\ttcp SAP[%u] Setting FIN-WAIT-2 timeout"), (TInt)this)); |
|
1167 SchedMsl2Wait(); |
|
1168 } |
|
1169 |
|
1170 // |
|
1171 // If we're in CLOSED state and we're not detached, |
|
1172 // tell the socket server that we're ready to die. |
|
1173 // |
|
1174 if (iSocket && InState(ETcpClosed)) |
|
1175 iSocket->CanClose(); |
|
1176 |
|
1177 // |
|
1178 // Note! The socket server can immediately delete the socket |
|
1179 // within CanClose(). Don't add anything here! |
|
1180 // |
|
1181 } |
|
1182 |
|
1183 |
|
1184 // |
|
1185 // PRTv1.0 API |
|
1186 // |
|
1187 TUint CProviderTCP6::Write(const TDesC8 & aDesc, TUint aOptions, TSockAddr* /*aAddr*/ /*=NULL*/) |
|
1188 { |
|
1189 TDualBufPtr buf(aDesc); |
|
1190 return Send(buf, aDesc.Length(), aOptions); |
|
1191 } |
|
1192 |
|
1193 void CProviderTCP6::GetData(TDes8 & aDesc, TUint aOptions, TSockAddr* /*aAddr*/) |
|
1194 { |
|
1195 TDualBufPtr aBuf(aDesc); |
|
1196 Recv(aBuf, aDesc.Length(), aOptions); |
|
1197 } |
|
1198 |
|
1199 // |
|
1200 // PRTv1.5 API |
|
1201 // |
|
1202 TInt CProviderTCP6::Write(RMBufChain& aData, TUint aOptions, TSockAddr* /* anAddr*/) |
|
1203 { |
|
1204 TDualBufPtr buf(aData); |
|
1205 return Send(buf, aData.Length(), aOptions); |
|
1206 } |
|
1207 |
|
1208 TInt CProviderTCP6::GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* /*aAddr*/) |
|
1209 { |
|
1210 TDualBufPtr aBuf(aData); |
|
1211 return Recv(aBuf, aLength, aOptions); |
|
1212 } |
|
1213 |
|
1214 TInt CProviderTCP6::Send(TDualBufPtr& aBuf, TInt aLength, TUint aOptions) |
|
1215 { |
|
1216 LOG(Log::Printf(_L("Write\ttcp SAP[%u] len=%d, options=%d"), (TInt)this, aLength, aOptions)); |
|
1217 ASSERT(aLength > 0); |
|
1218 |
|
1219 // |
|
1220 // Limit queue size to maximum socket buffer size rounded down to nearest multiple segment. |
|
1221 // Note: during fast recover we allow the socket buffer to expand in order to have enough |
|
1222 // data to keep the transmission going. |
|
1223 // |
|
1224 TInt effMSS = EffectiveMSS(); |
|
1225 TInt bufSize = iSockOutBufSize + |
|
1226 (iSacked.Count() ? (iSacked.Last()->iRight - iSND.UNA) : (iDupAcks * iSMSS)); |
|
1227 TInt reserve = (bufSize - (iSND.NXT - iSND.UNA)) % effMSS; |
|
1228 TInt space = bufSize - iSockOutQLen - reserve; |
|
1229 |
|
1230 LOG(Log::Printf(_L("\ttcp SAP[%u] len=%d space=%d"), (TInt)this, aLength, space)); |
|
1231 |
|
1232 if ((aOptions & KSockWriteUrgent) || iFlags.iNextIsUrgent) |
|
1233 { |
|
1234 // |
|
1235 // According to RFC1122 the urgent pointer should point to the |
|
1236 // last byte of urgent data. However, practically all TCP stacks |
|
1237 // today choose to conform to BSD unix and follow the original |
|
1238 // behaviour stated in RFC793. Therefore, we set the urgent pointer |
|
1239 // to point to the first non-urgent byte following the urgent data. |
|
1240 // |
|
1241 iFlags.iNextIsUrgent = EFalse; |
|
1242 iSND.UP = iSND.UNA + iSockOutQLen + aLength; |
|
1243 LOG(Log::Printf(_L("\ttcp SAP[%u] Urgent pointer set, seq = %u"), (TInt)this, iSND.UP.Uint32())); |
|
1244 } |
|
1245 |
|
1246 if (space <= 0) |
|
1247 { |
|
1248 LOG(Log::Printf(_L("\ttcp SAP[%u] FLOW STOPPED"), (TInt)this)); |
|
1249 iSockFlags.iFlowStopped = ETrue; |
|
1250 return 0; |
|
1251 } |
|
1252 |
|
1253 // Append data to socket queue. |
|
1254 aLength = aBuf.Append(iSockOutQ, (aLength < space) ? aLength : space); |
|
1255 iSockOutQLen += aLength; |
|
1256 |
|
1257 // We make a simple Nagle check here to avoid starting the transmitter unnecessarily. |
|
1258 // To spell it out: |
|
1259 // - If Cork option is set, always wait for full-sized segment before sending. |
|
1260 // - Without Cork option one under-sized segment is allowed to be outstanding. |
|
1261 // - TODO: With NoPush option segments are only sent when send buffer is full or |
|
1262 // when the connection is closed. |
|
1263 if (!iSND.WND) |
|
1264 { |
|
1265 // Start probing |
|
1266 SchedRetransmit(); |
|
1267 } |
|
1268 else if ((iPartialSeq <= iSND.UNA && !iFlags.iCork) || |
|
1269 iSND.UNA + iSockOutQLen + aLength >= iSND.NXT + effMSS || |
|
1270 iFlags.iNoDelay) |
|
1271 { |
|
1272 // Start transmitter |
|
1273 SchedTransmit(); |
|
1274 } |
|
1275 |
|
1276 return aLength; |
|
1277 } |
|
1278 |
|
1279 |
|
1280 TInt CProviderTCP6::Recv(TDualBufPtr& aBuf, TInt aLength, TUint aOptions) |
|
1281 { |
|
1282 LOG(Log::Printf(_L("GetData\ttcp SAP[%u] len=%d, options=%d"), (TInt)this, aLength, aOptions)); |
|
1283 |
|
1284 // Update iPending |
|
1285 if (!(aOptions & KSocketInternalReadBit)) |
|
1286 iPending -= aLength; |
|
1287 |
|
1288 // This might happen when aborting a connection. |
|
1289 if (iSockInQ.IsEmpty()) |
|
1290 { |
|
1291 LOG(Log::Printf(_L("\ttcp SAP[%u] No data available!"), (TInt)this)); |
|
1292 return 0; |
|
1293 } |
|
1294 |
|
1295 // |
|
1296 // Discard in-band urgent data junk |
|
1297 // |
|
1298 while (iUpCount && UrgentOffset(0) == 0 && (!iFlags.iUrgentMode || UrgentOffset() > 0)) |
|
1299 { |
|
1300 iSockInQ.TrimStart(1); |
|
1301 --iSockInQLen; |
|
1302 ++iFreeWindow; |
|
1303 ForgetUrgentPointer(); |
|
1304 } |
|
1305 |
|
1306 ASSERT((aOptions & KSockReadPeek) || !iCopyOutOffset); |
|
1307 ASSERT(iCopyOutOffset + aLength <= (TInt)iSockInQLen); |
|
1308 |
|
1309 // |
|
1310 // Peek. Copy from queue, fix counters and force receiver restart. |
|
1311 // |
|
1312 if (aOptions & KSockReadPeek) |
|
1313 { |
|
1314 LOG(Log::Printf(_L("\ttcp SAP[%u] Peek"), (TInt)this)); |
|
1315 |
|
1316 TInt err = aBuf.CopyIn(iSockInQ, iCopyOutOffset, aLength); |
|
1317 if (err != KErrNone) |
|
1318 return KErrNoMBufs; |
|
1319 |
|
1320 if (!(aOptions & KSocketInternalReadBit)) |
|
1321 { |
|
1322 iFlags.iCompleteRecv = ETrue; |
|
1323 iNewData += aLength; |
|
1324 iCopyOutOffset += aLength; |
|
1325 iRecvQ.Wake(); |
|
1326 } |
|
1327 |
|
1328 return aLength; |
|
1329 } |
|
1330 |
|
1331 // |
|
1332 // Normal read. Consume data from the queue. |
|
1333 // |
|
1334 // Note: aBuf.Consume() may return less than we asked |
|
1335 // if it is unable to allocate an MBuf for splitting the |
|
1336 // inbound queue. This can only happen with PRTv1.5. |
|
1337 // If we get nothing at all we return KErrNoMBufs here. |
|
1338 // |
|
1339 aLength = aBuf.Consume(iSockInQ, aLength, iBufAllocator); |
|
1340 if (aLength == 0) |
|
1341 return KErrNoMBufs; |
|
1342 |
|
1343 // |
|
1344 // If we are now reading the actual urgent data, force the |
|
1345 // application level read operation to complete and exit |
|
1346 // urgent mode. |
|
1347 // |
|
1348 if (iFlags.iUrgentMode && UrgentOffset() == 0) |
|
1349 { |
|
1350 LOG(Log::Printf(_L("\ttcp SAP[%u] Reading urgent data. Clear urgent mode"), (TInt)this)); |
|
1351 iFlags.iUrgentMode = EFalse; |
|
1352 iFlags.iCompleteRecv = !(aOptions & KSocketInternalReadBit); |
|
1353 ForgetUrgentPointer(); |
|
1354 } |
|
1355 |
|
1356 iSockInQLen -= aLength; |
|
1357 |
|
1358 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
1359 //Application is reading the data from the receive Q buffer |
|
1360 //We need to make sure, that we will show that window is not shrinked |
|
1361 //to the sender, so tha right edge of the sender window remains constant. |
|
1362 //if This is true, then it is a case of TCP window shrink and we need |
|
1363 //to handle it. |
|
1364 if ( iNewTcpWindow ) |
|
1365 { |
|
1366 //Log this message for information, that Window is shrinked |
|
1367 LOG(Log::Printf(_L("\ttcp SAP[%u] TCP window shrinking mode on"), (TInt)this)); |
|
1368 |
|
1369 //Increase the hidden free TCP receive window. |
|
1370 iHiddenFreeWindow += aLength; |
|
1371 |
|
1372 if (iHiddenFreeWindow >= iShrinkedWindowSize) |
|
1373 { |
|
1374 //Disable window shrink processing, so that TCP could switch |
|
1375 //to the normal processing. |
|
1376 iSockInBufSize = iNewTcpWindow; |
|
1377 |
|
1378 //Add the usable window to the free window. |
|
1379 iFreeWindow += iHiddenFreeWindow - iShrinkedWindowSize; |
|
1380 |
|
1381 //There are chances that TCP receive window might further shrink. |
|
1382 iHiddenFreeWindow = 0; |
|
1383 |
|
1384 //TCP Receive window shrink phase is over. |
|
1385 iNewTcpWindow = 0; |
|
1386 |
|
1387 //Log this message for information, that Window is shrinked |
|
1388 LOG(Log::Printf(_L("\ttcp SAP[%u] TCP window shrinking mode off"), (TInt)this)); |
|
1389 } |
|
1390 } |
|
1391 else |
|
1392 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
1393 |
|
1394 { |
|
1395 iFreeWindow += aLength; |
|
1396 } |
|
1397 |
|
1398 // |
|
1399 // If we have read everything upto the urgent data, |
|
1400 // force the application level read to complete. |
|
1401 // If the urgent data has not yet been read, signal |
|
1402 // the application again (read completion will clear |
|
1403 // the signal). |
|
1404 // |
|
1405 if (UrgentOffset() == 0) |
|
1406 { |
|
1407 iFlags.iCompleteRecv = ETrue; |
|
1408 if (iFlags.iUrgentMode) |
|
1409 { |
|
1410 LOG(Log::Printf(_L("\ttcp SAP[%u] Now at urgent data"), (TInt)this)); |
|
1411 iFlags.iNotifyUrgent = ETrue; |
|
1412 } |
|
1413 } |
|
1414 |
|
1415 // |
|
1416 // Increase receive window in multiples of RMSS |
|
1417 // |
|
1418 // The following assumes that the path MTU is symmetric and that |
|
1419 // the peer uses the same options as we do. We could use some |
|
1420 // kind of peer effective MSS detection heuristic in order to |
|
1421 // make this smarter. |
|
1422 // |
|
1423 TUint effMSS = EffectiveMSS(); |
|
1424 if (iFreeWindow >= effMSS) |
|
1425 { |
|
1426 // |
|
1427 // Round down to nearest multiple of RMSS. However, be careful not to |
|
1428 // shrink a previously advertised window. |
|
1429 // |
|
1430 iFreeWindow += iRCV.WND; |
|
1431 iRCV.WND = Max(iRCV.WND, effMSS * (iFreeWindow / effMSS)); |
|
1432 iFreeWindow -= iRCV.WND; // Leave reminder for later. |
|
1433 |
|
1434 // |
|
1435 // If our last advertised window is so small that the sender might |
|
1436 // block before we would normally send our next ack, we will send |
|
1437 // a window update. This will prevent the sender from unnecessarily |
|
1438 // going into probe mode. We will only do this if we can advertise |
|
1439 // at least half a window. |
|
1440 // |
|
1441 if (InState(ETcpEstablished|ETcpFinWait1|ETcpFinWait2)) |
|
1442 { |
|
1443 if ((TInt)iAdvertisedWindow <= iSockInBufSize/4 && iRCV.WND >= iSockInBufSize/2) |
|
1444 { |
|
1445 LOG(Log::Printf(_L("\ttcp SAP[%u] Sending window update %d -> %d"), (TInt)this, iAdvertisedWindow, iRCV.WND)); |
|
1446 SendSegment(KTcpCtlACK); |
|
1447 } |
|
1448 } |
|
1449 } |
|
1450 |
|
1451 // |
|
1452 // If we have data that has not yet been announced to the socket server, |
|
1453 // make sure we get around to it. |
|
1454 // |
|
1455 if (iNewData) |
|
1456 iRecvQ.Wake(); |
|
1457 |
|
1458 LOG(Log::Printf(_L("GetData\ttcp SAP[%u] returns %d bytes, %d bytes pending"), (TInt)this, aLength, iPending)); |
|
1459 return aLength; |
|
1460 } |
|
1461 |
|
1462 |
|
1463 // |
|
1464 // Process ICMP Error. Treat it as a soft error unless we're trying to connect. |
|
1465 // |
|
1466 void CProviderTCP6::IcmpError(TInt aError, TUint aOperationMask, TInt aType, TInt aCode, |
|
1467 const TInetAddr& aSrcAddr, const TInetAddr& aDstAddr, const TInetAddr& aErrAddr) |
|
1468 { |
|
1469 CProviderInet6Transport::IcmpError(aError,InState(ETcpSynSent|ETcpSynReceived) ? |
|
1470 MSocketNotify::EErrorAllOperations : aOperationMask, |
|
1471 aType, aCode, aSrcAddr, aDstAddr, aErrAddr); |
|
1472 } |
|
1473 |
|
1474 // |
|
1475 // This routine maintains a sorted rotating array of detected urgent pointers. |
|
1476 // The lowest detected UP is always stored in iUpArray[iUpIndex] and the highest |
|
1477 // one is stored in iUpArray[(iUpIndex + iUpCount - 1) % KTcpUpMax]. |
|
1478 // If the array overflows, the lowest UP is always discarded. |
|
1479 // |
|
1480 void CProviderTCP6::RememberUrgentPointer(TTcpSeqNum aUp) |
|
1481 { |
|
1482 // Insert new UP into the sorted list. |
|
1483 TInt i; |
|
1484 TTcpSeqNum up; |
|
1485 |
|
1486 for (i = iUpIndex + iUpCount; i > iUpIndex; --i) |
|
1487 { |
|
1488 up = iUpArray[(i - 1) % KTcpUpMax]; |
|
1489 if (aUp > up) |
|
1490 break; |
|
1491 if (aUp == up) |
|
1492 return; |
|
1493 } |
|
1494 |
|
1495 if (i == iUpIndex && iUpCount == KTcpUpMax) |
|
1496 return; |
|
1497 TUint index; |
|
1498 while (i < iUpIndex + iUpCount) |
|
1499 { |
|
1500 index = i % KTcpUpMax; |
|
1501 up = iUpArray[index]; |
|
1502 iUpArray[index] = aUp; |
|
1503 aUp = up; |
|
1504 ++i; |
|
1505 } |
|
1506 |
|
1507 iUpArray[i % KTcpUpMax] = aUp; |
|
1508 if (iUpCount < KTcpUpMax) |
|
1509 { |
|
1510 ++iUpCount; |
|
1511 } |
|
1512 else |
|
1513 { |
|
1514 iUpIndex += 1; |
|
1515 if(iUpIndex >= KTcpUpMax) |
|
1516 iUpIndex -= KTcpUpMax; |
|
1517 } |
|
1518 |
|
1519 iFlags.iUrgentMode = ETrue; |
|
1520 iFlags.iNotifyUrgent = !iFlags.iOobInline; |
|
1521 } |
|
1522 |
|
1523 void CProviderTCP6::ForgetUrgentPointer() |
|
1524 { |
|
1525 if (iUpCount) |
|
1526 { |
|
1527 if (++iUpIndex >= KTcpUpMax) |
|
1528 iUpIndex = 0; |
|
1529 --iUpCount; |
|
1530 } |
|
1531 } |
|
1532 |
|
1533 |
|
1534 TInt CProviderTCP6::GetUrgent(TInt& aUrgentChar, TUint aOptions) |
|
1535 { |
|
1536 TTcpSeqNum up; |
|
1537 RMBuf *m; |
|
1538 TBool found = EFalse; |
|
1539 TInt urgentOffset = UrgentOffset(); |
|
1540 |
|
1541 if (!iFlags.iUrgentMode || iFlags.iOobInline) |
|
1542 return KErrNotFound; |
|
1543 |
|
1544 up = UrgentHigh(); |
|
1545 if (up <= iRCV.NXT) |
|
1546 { |
|
1547 // It's in the socket queue. |
|
1548 if (urgentOffset == 0 && !(aOptions & KSockReadPeek)) |
|
1549 { |
|
1550 // |
|
1551 // It's first in queue. Fetch it with Recv(), so that receive |
|
1552 // window is correctly updated. |
|
1553 // |
|
1554 TBuf8<1> buf(1); |
|
1555 TDualBufPtr p(buf); |
|
1556 iNewData--; |
|
1557 Recv(p, 1, aOptions | KSocketInternalReadBit); |
|
1558 aUrgentChar = buf[0]; |
|
1559 LOG(Log::Printf(_L("\ttcp SAP[%u] GetUrgent(): Urgent char first in socket queue = %02x"), (TInt)this, aUrgentChar)); |
|
1560 found = ETrue; |
|
1561 } |
|
1562 else |
|
1563 { |
|
1564 for (m = iSockInQ.First(); m != NULL; m = m->Next()) |
|
1565 { |
|
1566 if (urgentOffset < m->Length()) |
|
1567 { |
|
1568 aUrgentChar = *(m->Ptr() + urgentOffset); |
|
1569 LOG(Log::Printf(_L("\ttcp SAP[%u] GetUrgent(): Urgent char in socket queue = %02x"), (TInt)this, aUrgentChar)); |
|
1570 found = ETrue; |
|
1571 break; |
|
1572 } |
|
1573 urgentOffset -= m->Length(); |
|
1574 } |
|
1575 } |
|
1576 } |
|
1577 else if (up <= iSND.WL1 + iRMSS) |
|
1578 { |
|
1579 // Maybe it's in the fragment queue. |
|
1580 TMBufPktQIter iter(iFragQ); |
|
1581 for (iter.SetToFirst(); iter.More(); iter++) |
|
1582 { |
|
1583 RMBufTcpFrag& frag = (RMBufTcpFrag&)iter.Current(); |
|
1584 TTcpSeqNum seq = frag.Offset(); |
|
1585 TUint32 len = frag.FragmentLength(); |
|
1586 |
|
1587 if (up <= seq) |
|
1588 break; |
|
1589 |
|
1590 if (up <= seq + len) |
|
1591 { |
|
1592 TTcpPacket seg(frag); |
|
1593 RMBuf *m, *prev; |
|
1594 TInt off, len; |
|
1595 frag.Goto(seg.iHdr->HeaderLength() + (up - seq) - 1, |
|
1596 m, off, len, prev); |
|
1597 aUrgentChar = *(m->Ptr() + off); |
|
1598 LOG(Log::Printf(_L("\ttcp SAP[%u] GetUrgent(): Urgent char in fragment queue = %02x"), (TInt)this, aUrgentChar)); |
|
1599 found = ETrue; |
|
1600 break; |
|
1601 } |
|
1602 } |
|
1603 } |
|
1604 |
|
1605 if (!found) |
|
1606 { |
|
1607 LOG(Log::Printf(_L("\ttcp SAP[%u] GetUrgent(): Would block"), (TInt)this)); |
|
1608 return KErrWouldBlock; |
|
1609 } |
|
1610 |
|
1611 if (!(aOptions & KSockReadPeek)) |
|
1612 { |
|
1613 iFlags.iUrgentMode = EFalse; |
|
1614 |
|
1615 // Clear urgent mode exception flag |
|
1616 if (iSockFlags.iNotify) |
|
1617 iSocket->Error(KErrNone, 0); |
|
1618 } |
|
1619 |
|
1620 return KErrNone; |
|
1621 } |
|
1622 |
|
1623 |
|
1624 void CProviderTCP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/) |
|
1625 { |
|
1626 RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket); |
|
1627 #ifdef SYMBIAN_NETWORKING_UPS |
|
1628 if (info == NULL || (!HasNetworkServices() && (ConnectionInfoSet() == EFalse) && (info->iFlags & KIpLoopbackPacket) == 0)) |
|
1629 #else |
|
1630 if (info == NULL || (!HasNetworkServices() && (info->iFlags & KIpLoopbackPacket) == 0)) |
|
1631 #endif |
|
1632 { |
|
1633 LOG(Log::Printf(_L("\ttcp SAP[%u] Not allowed to receive external packets"), (TInt)this)); |
|
1634 aPacket.Free(); |
|
1635 return; |
|
1636 } |
|
1637 iRecvQ.Append(aPacket); |
|
1638 iRecvQ.Wake(); |
|
1639 } |
|
1640 |
|
1641 |
|
1642 void CProviderTCP6::ErrorExpire(TInt aError) |
|
1643 { |
|
1644 LOG(Log::Printf(_L("\ttcp SAP[%u] ErrorExpire(): Closing SAP on fatal error: %d"), (TInt)this, aError)); |
|
1645 if (!iSockFlags.iAttached) |
|
1646 { |
|
1647 Expire(); |
|
1648 return; |
|
1649 } |
|
1650 Close(); |
|
1651 CProviderInet6Transport::Error(aError); |
|
1652 } |
|
1653 |
|
1654 void CProviderTCP6::CanSend() |
|
1655 { |
|
1656 LOG(Log::Printf(_L("\ttcp SAP[%u] CanSend()"), (TInt)this)); |
|
1657 |
|
1658 // |
|
1659 // If the flow has become unblocked, process all missed events |
|
1660 // and restart transmitter. |
|
1661 // |
|
1662 TInt flowStatus = iFlow.Status(); |
|
1663 if (flowStatus < 0) |
|
1664 { |
|
1665 ErrorExpire(flowStatus); |
|
1666 return; |
|
1667 } |
|
1668 |
|
1669 if (flowStatus == EFlow_READY) |
|
1670 { |
|
1671 LOG(Log::Printf(_L("\ttcp SAP[%u] CanSend(): Flow UNBLOCKED"), (TInt)this)); |
|
1672 |
|
1673 if (InState(ETcpListen|ETcpConnect)) |
|
1674 { |
|
1675 // |
|
1676 // Get the SAP started. |
|
1677 // |
|
1678 if (InState(ETcpConnect)) |
|
1679 SendSYN(); |
|
1680 else if (InState(ETcpListen) && !iRecvQ.IsEmpty()) |
|
1681 iRecvQ.Wake(); |
|
1682 } |
|
1683 |
|
1684 if (iFlags.iRetransmitPending) |
|
1685 { |
|
1686 iFlags.iRetransmitPending = EFalse; |
|
1687 RetransmitSegments(); |
|
1688 } |
|
1689 |
|
1690 if (iFlags.iTransmitPending) |
|
1691 { |
|
1692 iFlags.iTransmitPending = EFalse; |
|
1693 SendSegments(); |
|
1694 } |
|
1695 |
|
1696 if (!iSendQ.IsEmpty()) |
|
1697 iSendQ.Wake(); |
|
1698 |
|
1699 if (CanTriggerKeepAlive()) |
|
1700 { |
|
1701 // The heaviest time check only if we are otherwise allowed to send the keepalive. |
|
1702 TUint32 time_now = TimeStamp(); |
|
1703 if (time_now - iLastTriggeredKeepAlive > KTcpKeepAliveTH * KOneSecondUs) |
|
1704 { |
|
1705 iLastTriggeredKeepAlive = time_now; |
|
1706 LOG(Log::Printf(_L("\ttcp SAP[%u] CanSend(): Sending a Keep-Alive probe"), (TInt)this)); |
|
1707 SendSegment(KTcpCtlACK, iSND.UNA - 1, 0); |
|
1708 } |
|
1709 } |
|
1710 } |
|
1711 } |
|
1712 |
|
1713 |
|
1714 // |
|
1715 // This is the actual event driven asynchronous transmitter loop. |
|
1716 // |
|
1717 void CProviderTCP6::Transmit() |
|
1718 { |
|
1719 LOG(Log::Printf(_L("\ttcp SAP[%u] Transmit"), (TInt)this)); |
|
1720 |
|
1721 RMBufSendPacket packet; |
|
1722 TInt flowStatus; |
|
1723 LOG(TInt count = 0); |
|
1724 |
|
1725 ASSERT(!iSendQ.IsEmpty()); |
|
1726 RMBufSendInfo *info = NULL; |
|
1727 // Transmit packets when flow is ready |
|
1728 while ((flowStatus = iFlow.Status()) == EFlow_READY && iSendQ.Remove(packet)) |
|
1729 { |
|
1730 info = packet.PeekInfo(); |
|
1731 info->iFlow.Open(iFlow); |
|
1732 Protocol()->Send(packet); |
|
1733 LOG(count++); |
|
1734 } |
|
1735 |
|
1736 // Local congestion control |
|
1737 if (flowStatus == EFlow_HOLD && !iSendQ.IsEmpty()) |
|
1738 SourceQuench(); |
|
1739 |
|
1740 LOG(Log::Printf(_L("\ttcp SAP[%u] %d segments transmitted"), (TInt)this, count)); |
|
1741 LOG(if (flowStatus > EFlow_READY) Log::Printf(_L("\ttcp SAP[%u] Flow BLOCKED"), (TInt)this)); |
|
1742 //LOG(if (flowStatus != EFlow_READY) Log::Printf(_L("CProviderTCP6::Transmit(): Flow status = %d.\r\n"), flowStatus)); |
|
1743 |
|
1744 if (flowStatus < 0) |
|
1745 { |
|
1746 LOG(Log::Printf(_L("\ttcp SAP[%u] Error %d. Segments"), (TInt)this, flowStatus)); |
|
1747 ErrorExpire(flowStatus); |
|
1748 } |
|
1749 } |
|
1750 |
|
1751 |
|
1752 // NOTE: There are a few tricks in the ECN implementation that should be considered. ECT bit MUST NOT |
|
1753 // be set in IP packets in the following cases [RFC 3168, Sec. 6.1.4 -- 6.1.6]: |
|
1754 // 1) pure ACKs |
|
1755 // 2) retransmitted segments |
|
1756 // 3) zero window probes |
|
1757 |
|
1758 |
|
1759 // |
|
1760 // This routine generates and transmits a TCP segment. |
|
1761 // |
|
1762 TInt CProviderTCP6::SendSegment(TUint8 aFlags, TTcpSeqNum aSeq, TUint32 aDataLen) |
|
1763 { |
|
1764 //LOG(Log::Printf(_L("CProviderTCP6::SendSegment(%06b,%d,%d)\r\n"),aFlags,aSeq,aMaxLen)); |
|
1765 |
|
1766 ASSERT(!(aFlags & KTcpCtlRST)); |
|
1767 |
|
1768 RMBufSendPacket seg; |
|
1769 RMBufSendInfo *info = NULL; |
|
1770 TInt err; |
|
1771 TInt up = iSND.UP - aSeq; |
|
1772 TInt seqLen = aDataLen; |
|
1773 if (aFlags & (KTcpCtlSYN|KTcpCtlFIN)) |
|
1774 ++seqLen; |
|
1775 |
|
1776 if (iFlags.iEcnHaveCongestion) |
|
1777 { |
|
1778 aFlags |= KTcpCtlECE; |
|
1779 } |
|
1780 |
|
1781 if (iFlags.iEcnSendCWR) |
|
1782 { |
|
1783 aFlags |= KTcpCtlCWR; |
|
1784 iFlags.iEcnSendCWR = EFalse; |
|
1785 } |
|
1786 |
|
1787 // |
|
1788 // Don't output SACK blocks with data segments |
|
1789 // |
|
1790 iOptions.SuppressSack(aDataLen > 0); |
|
1791 TUint headerLen = KTcpMinHeaderLength + iOptions.Length(); |
|
1792 |
|
1793 // |
|
1794 // Allocate memory for TCP segment and IP headers. |
|
1795 // |
|
1796 // Important: we assume that, when using the TimeStamps option, |
|
1797 // iOptions always contains timestamps, so that the header length |
|
1798 // does not change when we update them below. |
|
1799 // |
|
1800 for (;;) |
|
1801 { |
|
1802 TInt hdrReserve = iFlow.FlowContext()->HeaderSize() + headerLen; |
|
1803 if (aDataLen) |
|
1804 { |
|
1805 err = iSockOutQ.Copy(seg, aSeq - iSND.UNA, aDataLen, hdrReserve); |
|
1806 if(err == KErrNone) |
|
1807 { |
|
1808 err = seg.Prepend(hdrReserve, iBufAllocator); |
|
1809 } |
|
1810 } |
|
1811 else |
|
1812 { |
|
1813 err = seg.Alloc(hdrReserve, iBufAllocator); |
|
1814 } |
|
1815 if(err == KErrNone) |
|
1816 { |
|
1817 info = seg.NewInfo(); |
|
1818 if(info) |
|
1819 { |
|
1820 break; |
|
1821 } |
|
1822 else |
|
1823 { |
|
1824 err = KErrNoMBufs; |
|
1825 } |
|
1826 } |
|
1827 |
|
1828 // Allocation failed. Try to recover. |
|
1829 seg.Free(); |
|
1830 |
|
1831 // Try to free up some memory. XXX - We could do better here. |
|
1832 if (!iFragQ.IsEmpty()) |
|
1833 { |
|
1834 LOG(Log::Printf(_L("\ttcp SAP[%u] SendSegment(): RENEGE!!!"), (TInt)this)); |
|
1835 iFragQ.Free(); |
|
1836 continue; |
|
1837 } |
|
1838 |
|
1839 // If we can't scrounge up a buffer, the packet will be dropped. |
|
1840 LOG(Log::Printf(_L("\ttcp SAP[%u] SendSegment(): No memory, packet DROPPED!"), (TInt)this)); |
|
1841 break; |
|
1842 } |
|
1843 |
|
1844 if (err == KErrNone) |
|
1845 { |
|
1846 // Reserve space for IP headers |
|
1847 seg.TrimStart(iFlow.FlowContext()->HeaderSize()); |
|
1848 |
|
1849 // Check for urgent data |
|
1850 if (up > 0 && up < 0x10000) |
|
1851 aFlags |= KTcpCtlURG; |
|
1852 else |
|
1853 up = 0; |
|
1854 |
|
1855 // |
|
1856 // Fill in TCP header. Note that the header length has already |
|
1857 // been set and the checksum will be calculated later. |
|
1858 // |
|
1859 // Note: If we're probing or the receiver has shrunk its advertised |
|
1860 // window our iSND.NXT may be pointing beyond its advertised window. |
|
1861 // If the packet we're trying to send does not occupy any sequence |
|
1862 // space, we will adjust the sequence number so that it falls withín |
|
1863 // the receiver's window. This will make sure that our ACK and RST |
|
1864 // packets will be accepted. In the worst case, a buggy receiver |
|
1865 // might still ignore our window updates, which might lead to a probe |
|
1866 // deadlock. Well, a TCP that shrinks its window without adjusting |
|
1867 // SND.WL1 deserves what it gets... |
|
1868 // |
|
1869 TTcpPacket pkt(seg); |
|
1870 TTcpSeqNum windowEdge = iSND.UNA + iSND.WND; |
|
1871 pkt.iHdr->SetSrcPort(iFlow.FlowContext()->LocalPort()); |
|
1872 pkt.iHdr->SetDstPort(iFlow.FlowContext()->RemotePort()); |
|
1873 pkt.iHdr->SetSequence(seqLen > 0 || aSeq <= windowEdge ? aSeq : windowEdge); |
|
1874 pkt.iHdr->SetAcknowledgment((aFlags & KTcpCtlACK) ? iRCV.NXT.Uint32() : 0); |
|
1875 if (aFlags & KTcpCtlSYN) |
|
1876 { |
|
1877 // Window scale must not be used in SYN or SYN-ACK segments. |
|
1878 // We do not truncate window size to be divisible by MSS. |
|
1879 // The next window advertisments are properly aligned, though. |
|
1880 pkt.iHdr->SetWindow(Min(iRCV.WND, 0xffff)); |
|
1881 } |
|
1882 else |
|
1883 { |
|
1884 pkt.iHdr->SetWindow(iRCV.WND >> iRcvWscale); |
|
1885 } |
|
1886 pkt.iHdr->SetUrgent(up); |
|
1887 pkt.iHdr->SetControl(aFlags); |
|
1888 |
|
1889 // |
|
1890 // Fill in info struct |
|
1891 // |
|
1892 // coverity[dead_error_condition] |
|
1893 // ASSERT statement required here as the condition "info != NULL" could be false |
|
1894 ASSERT(info != NULL); |
|
1895 info->iProtocol = KProtocolInetTcp; |
|
1896 info->iSrcAddr = iFlow.FlowContext()->LocalAddr(); |
|
1897 info->iDstAddr = iFlow.FlowContext()->RemoteAddr(); |
|
1898 info->iLength = headerLen + aDataLen; |
|
1899 info->iFlags = iFlags.iDoPMTUD ? KIpDontFragment : 0; |
|
1900 |
|
1901 // Check if we have to clear the ECN ECT flag because of the few exception cases listed above. |
|
1902 if (iFlags.iEcn && (aSeq < iSND.NXT || aDataLen < 1)) |
|
1903 { |
|
1904 info->iFlags |= KIpNoEcnEct; |
|
1905 } |
|
1906 |
|
1907 // |
|
1908 // Output TCP options (except for RST packets) |
|
1909 // |
|
1910 if (!(aFlags & KTcpCtlRST)) |
|
1911 { |
|
1912 // Get current time |
|
1913 TUint32 usec = TimeStamp(); |
|
1914 |
|
1915 // |
|
1916 // Measure RTT |
|
1917 // |
|
1918 if (iFlags.iUseTimeStamps) |
|
1919 { |
|
1920 #if 0 |
|
1921 // XXX - This code can cause tsVal to go backwards. |
|
1922 TUint32 lastSent, lastEchoed; |
|
1923 iOptions.TimeStamps(lastSent, lastEchoed); |
|
1924 if (usec == lastSent) |
|
1925 usec++; |
|
1926 #endif |
|
1927 iOptions.SetTimeStamps(usec, iTsRecent); |
|
1928 } |
|
1929 if (iFlags.iTiming) |
|
1930 { |
|
1931 // Check for retransmission. We shouldn't do RTT measurements on |
|
1932 // retransmitted segments because of ambiguity (Karn algorithm). |
|
1933 if (iTimingSeq > aSeq && iTimingSeq <= aSeq + aDataLen) |
|
1934 iFlags.iTiming = EFalse; |
|
1935 } |
|
1936 else if (aSeq == iSND.NXT && seqLen > 0 && iSND.WND > 0) |
|
1937 { |
|
1938 // New segment and not a probe. Start timing. |
|
1939 iFlags.iTiming = ETrue; |
|
1940 iTimingSeq = aSeq + aDataLen; |
|
1941 iTimeStamp = usec; |
|
1942 } |
|
1943 |
|
1944 // |
|
1945 // Output TCP options into the segment header. |
|
1946 // |
|
1947 pkt.iHdr->SetOptions(iOptions); |
|
1948 } |
|
1949 |
|
1950 // |
|
1951 // Compute checksum and send the segment. |
|
1952 // |
|
1953 pkt.ComputeChecksum(seg, info); |
|
1954 LOG(CProtocolTCP6::LogPacket('>', seg, info)); |
|
1955 seg.Pack(); |
|
1956 |
|
1957 if(!iFlags.iFastRetransMode) |
|
1958 { |
|
1959 iSendQ.Append(seg); |
|
1960 } |
|
1961 else |
|
1962 { |
|
1963 //If the fast retransmission mode is set then add the segment in the begining of the sendqueue. |
|
1964 iSendQ.Prepend(seg); |
|
1965 } |
|
1966 iSendQ.Wake(); |
|
1967 } |
|
1968 |
|
1969 CancelDelayACK(); |
|
1970 |
|
1971 // Schedule a retransmission. Restart RTO if there was no outstanding segments, otherwise |
|
1972 // it is only restarted if it was not running already. |
|
1973 if (seqLen) |
|
1974 { |
|
1975 if (iSND.NXT == iSND.UNA) |
|
1976 ReSchedRetransmit(); |
|
1977 else |
|
1978 SchedRetransmit(); |
|
1979 } |
|
1980 |
|
1981 aSeq += seqLen; |
|
1982 if (aSeq > iSND.NXT) |
|
1983 iSND.NXT = aSeq; |
|
1984 iLastAck = iRCV.NXT; |
|
1985 iAdvertisedWindow = iRCV.WND; |
|
1986 |
|
1987 return aDataLen; |
|
1988 } |
|
1989 |
|
1990 // |
|
1991 // Transmit one data segment at given position. Use current |
|
1992 // MTU, send window, and congestion window to limit segment |
|
1993 // size. Return number of bytes advanced in the transmit queue. |
|
1994 // This may be less than transmitted bytes if SACK is being used. |
|
1995 // |
|
1996 TInt CProviderTCP6::SendDataSegment(TTcpSeqNum aSeq, TBool aNagleOverride) |
|
1997 { |
|
1998 TInt effMSS = EffectiveMSS(); |
|
1999 #ifdef SIGNED_UNSIGNED_FIX //if user app set the value which is bigger than 0x7ffffff,The largest possible value for a TInt16. |
|
2000 TUint effWND = MinUU(iSND.WND, iSockOutQLen); |
|
2001 #else |
|
2002 TUint effWND = Min(iSND.WND, iSockOutQLen); |
|
2003 #endif |
|
2004 TTcpSeqNum seq = aSeq; |
|
2005 TUint8 flags = KTcpCtlACK; |
|
2006 TInt len; |
|
2007 |
|
2008 // If RTO just occurred and F-RTO processing is underway, override Nagle. |
|
2009 if (iFRTOsent) |
|
2010 { |
|
2011 aNagleOverride = ETrue; |
|
2012 } |
|
2013 |
|
2014 // |
|
2015 // Transmission guided by SACK (RFC2018) |
|
2016 // |
|
2017 if (iFlags.iSackOk) |
|
2018 { |
|
2019 TTcpSeqNum limitSeq, limit; |
|
2020 TInt awnd, sacked; |
|
2021 |
|
2022 // Find a slot between SACKed blocks |
|
2023 sacked = iSacked.FindGap(seq, limit); |
|
2024 |
|
2025 if (iFlags.iFastRetransMode) |
|
2026 { |
|
2027 // Apply the FACK algorithm |
|
2028 TTcpSeqNum fack = iSacked.Count() ? iSacked.Last()->iRight : iSND.UNA; |
|
2029 awnd = iCwnd - (iSND.NXT - fack); |
|
2030 // |
|
2031 // Allow at least one segment if there are no retransmits out. |
|
2032 // This combines new-Reno style retransmit behaviour with the |
|
2033 // FACK algorithm. Pure FACK is somewhat tardy sending out the |
|
2034 // first retransmit, which causes problems in the usual single |
|
2035 // segment loss case. |
|
2036 // |
|
2037 if (iRetranData) |
|
2038 awnd -= iRetranData; |
|
2039 else if (awnd < (TInt)iSMSS) |
|
2040 awnd = iSMSS; |
|
2041 limitSeq = iSND.UNA + effWND; |
|
2042 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): FAST RECOVERY: una=%u fack=%u awnd=%d"), (TInt)this, (iSND.UNA).Uint32(), fack.Uint32(), awnd)); |
|
2043 } |
|
2044 else |
|
2045 { |
|
2046 // |
|
2047 // Apply congestion window and limited transmit window |
|
2048 // |
|
2049 // Note: if there are SACKed blocks within the congestion window, |
|
2050 // the window is extended accordingly. This is compatible with |
|
2051 // the congestion control principles, since we will not be |
|
2052 // retransmitting the SACKed blocks. |
|
2053 // |
|
2054 #ifdef SIGNED_UNSIGNED_FIX |
|
2055 awnd = (TInt)MinUU(effWND, iCwnd + iLwnd + (TUint)Max(sacked, 0)); |
|
2056 #else |
|
2057 awnd = Min(effWND, iCwnd + iLwnd + (sacked < 0 ? 0 : sacked)); |
|
2058 #endif |
|
2059 limitSeq = iSND.UNA + awnd; |
|
2060 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): NORMAL MODE: una=%u limit=%u wnd=%u"), (TInt)this, (iSND.UNA).Uint32(), limitSeq.Uint32(), awnd)); |
|
2061 } |
|
2062 |
|
2063 if (sacked >= 0) |
|
2064 { |
|
2065 if (limit < limitSeq) |
|
2066 { |
|
2067 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): SACK Adjust: RIGHT %u -> %u"), (TInt)this, limitSeq.Uint32(), limit.Uint32())); |
|
2068 limitSeq = limit; |
|
2069 if (limit <= seq + awnd) |
|
2070 { |
|
2071 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): NAGLE override (SACK)"), (TInt)this)); |
|
2072 aNagleOverride = ETrue; |
|
2073 } |
|
2074 } |
|
2075 } |
|
2076 else if (iFlags.iFastRetransMode) |
|
2077 { |
|
2078 // |
|
2079 // We are beyond the last SACK block. Skip to new data. |
|
2080 // |
|
2081 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): SACK Adjust: SEND NEW DATA"), (TInt)this)); |
|
2082 iSendHigh = seq; // Store position of SACK transmit |
|
2083 seq = iSND.NXT; // Start transmitting new data |
|
2084 } |
|
2085 |
|
2086 LOG(if (seq > aSeq) Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): SACK Adjust: LEFT %u -> %u"), (TInt)this, aSeq.Uint32(), seq.Uint32())); |
|
2087 #ifdef SIGNED_UNSIGNED_FIX |
|
2088 if(limitSeq > seq) |
|
2089 { |
|
2090 len = (TInt)MinUS(limitSeq - seq, awnd); |
|
2091 } |
|
2092 else |
|
2093 { |
|
2094 len = Min(limitSeq - seq, awnd); |
|
2095 } |
|
2096 #else |
|
2097 len = Min(limitSeq - seq, awnd); |
|
2098 #endif |
|
2099 } |
|
2100 else |
|
2101 { |
|
2102 #ifdef SIGNED_UNSIGNED_FIX |
|
2103 len = iSND.UNA + MinUU(effWND, iCwnd + iLwnd) - seq; |
|
2104 #else |
|
2105 len = iSND.UNA + Min(effWND, iCwnd + iLwnd) - seq; |
|
2106 #endif |
|
2107 } |
|
2108 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(%u, %d): una=%u nxt=%u off=%d noff=%d len=%d"), |
|
2109 (TInt)this, aSeq.Uint32(), aNagleOverride, (iSND.UNA).Uint32(), (iSND.NXT).Uint32(), aSeq - iSND.UNA, seq - iSND.UNA, len)); |
|
2110 LOG(Log::Printf(_L("\ttcp SAP[%u] Transmit state: effMSS=%d iCwnd=%d iLwnd=%d effWND=%d iRetranData=%d recovery=%d"), |
|
2111 (TInt)this, effMSS, iCwnd, iLwnd, effWND, iRetranData, iFlags.iFastRetransMode)); |
|
2112 |
|
2113 // |
|
2114 // Sender side SWS avoidance and Nagle. |
|
2115 // |
|
2116 if (len <= 0) |
|
2117 len = 0; |
|
2118 else if (len >= effMSS) |
|
2119 len = effMSS; |
|
2120 else if (seq > iSND.NXT && seq + len < iSND.UNA + iSockOutQLen && !aNagleOverride) |
|
2121 // |
|
2122 // Nagle override is not on and we're trying to send a partial |
|
2123 // segment from the middle of the send queue. Therefore, we must |
|
2124 // be constrained by the receiver window or the congestion window. |
|
2125 // |
|
2126 // If receiver window is very small we must allow a small packet out. |
|
2127 // |
|
2128 len = 0; |
|
2129 else |
|
2130 { |
|
2131 // |
|
2132 // Minshall's modification to the Nagle algorithm. We are |
|
2133 // allowed to transmit a partial segment if there are no |
|
2134 // other unacknowledged partial segments in flight. |
|
2135 // |
|
2136 if (iPartialSeq <= iSND.UNA && !Protocol()->StrictNagle() && !iFlags.iCork) |
|
2137 { |
|
2138 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): NAGLE override (Minshall), seq=%u"), (TInt)this, seq.Uint32())); |
|
2139 aNagleOverride = ETrue; |
|
2140 iPartialSeq = seq + len; |
|
2141 } |
|
2142 |
|
2143 // |
|
2144 // Standard Nagle algorithm. Do not send partial packets |
|
2145 // if there are outstanding unacknowledged segments. |
|
2146 // We also refrain from sending small packets if we have |
|
2147 // blocked the application as that means our send buffer |
|
2148 // is full. |
|
2149 // |
|
2150 // Update: With Cork option enabled, only full-sized segments are sent |
|
2151 // |
|
2152 // Note that we temporarily disable Nagle if we have |
|
2153 // some urgent data to send or if the user has already |
|
2154 // closed the outgoing direction of the connection. |
|
2155 // |
|
2156 if((iSockFlags.iFlowStopped || iSND.UNA < seq || iFlags.iCork) |
|
2157 && iSND.UP <= seq && !iFlags.iNoDelay |
|
2158 && !iSockFlags.iSendClose && !aNagleOverride) |
|
2159 { |
|
2160 LOG(Log::Printf(_L("\ttcp SAP[%u] SendDataSegment(): NAGLE kicked in"), (TInt)this)); |
|
2161 len = 0; |
|
2162 } |
|
2163 else |
|
2164 flags |= KTcpCtlPSH; // Set PSH on all partial segments |
|
2165 } |
|
2166 |
|
2167 if (len) |
|
2168 { |
|
2169 if (seq + len == iSND.UNA + iSockOutQLen) |
|
2170 { |
|
2171 // Send queue has drained. Set PSH if application is not blocked. |
|
2172 if (!iSockFlags.iFlowStopped) |
|
2173 flags |= KTcpCtlPSH; |
|
2174 |
|
2175 // Set FIN if the socket is closing. |
|
2176 if (iSockFlags.iSendClose) |
|
2177 { |
|
2178 flags |= KTcpCtlFIN; |
|
2179 if (InState(ETcpEstablished|ETcpCloseWait)) |
|
2180 EnterState(InState(ETcpEstablished) ? ETcpFinWait1 : ETcpLastAck); |
|
2181 } |
|
2182 } |
|
2183 |
|
2184 if (len = SendSegment(flags, seq, len), len >= 0) |
|
2185 { |
|
2186 // Count retransmitted data for FACK |
|
2187 if (iSacked.Count() && seq < iSacked.Last()->iRight) |
|
2188 { |
|
2189 iSendHigh = seq + len; |
|
2190 if (iFlags.iFastRetransMode) |
|
2191 iRetranData += len; |
|
2192 } |
|
2193 |
|
2194 // Take SACK advance into account |
|
2195 len += (seq - aSeq); |
|
2196 } |
|
2197 } |
|
2198 else if (iSND.WND < (TUint)effMSS) |
|
2199 SchedRetransmit(); // Start probing |
|
2200 |
|
2201 // |
|
2202 // Return the number of bytes by which to advance transmit sequence. |
|
2203 // Note: With SACK this is not necessarily the number of bytes sent. |
|
2204 // |
|
2205 return len; |
|
2206 } |
|
2207 |
|
2208 |
|
2209 // |
|
2210 // Send multiple data segments. |
|
2211 // |
|
2212 void CProviderTCP6::SendSegments(TBool aNagleOverride) |
|
2213 { |
|
2214 LOG(Log::Printf(_L("\ttcp SAP[%u] SendSegments(): queue=%u wnd=%u cwnd=%u, ssthresh=%u"), |
|
2215 (TInt)this, iSockOutQLen, iSND.WND, iCwnd, iSsthresh)); |
|
2216 |
|
2217 iFlags.iTransmitPending = (iFlow.Status() == EFlow_PENDING); |
|
2218 if (iFlags.iTransmitPending) |
|
2219 { |
|
2220 LOG(Log::Printf(_L("\ttcp SAP[%u] SendSegments(): Flow pending"), (TInt)this)); |
|
2221 return; |
|
2222 } |
|
2223 |
|
2224 if (InState(ETcpSynReceived|ETcpEstablished|ETcpCloseWait|ETcpLastAck|ETcpFinWait1|ETcpClosing)) |
|
2225 { |
|
2226 TInt advance; |
|
2227 TUint count = 0; |
|
2228 |
|
2229 if (iTransmitSeq < iSND.UNA) |
|
2230 iTransmitSeq = iSND.UNA; |
|
2231 |
|
2232 // Transmit segments from queue |
|
2233 while (advance = SendDataSegment(iTransmitSeq, aNagleOverride), advance > 0) |
|
2234 { |
|
2235 iTransmitSeq += advance; |
|
2236 // |
|
2237 // Limit transmission to KTcpMaxTransmit segments during |
|
2238 // fast retransmit/recovery. |
|
2239 // |
|
2240 if (iFlags.iFastRetransMode && ++count >= Protocol()->MaxBurst()) |
|
2241 break; |
|
2242 } |
|
2243 |
|
2244 // |
|
2245 // User has closed the connection and send queue has drained? |
|
2246 // |
|
2247 // Note: Normally the FIN bit is slapped on the last data segment |
|
2248 // in SendDataSegment(). However, if we have to send a FIN segement |
|
2249 // with no data, we do it here. |
|
2250 // |
|
2251 if (iSockFlags.iSendClose && |
|
2252 ((InState(ETcpEstablished|ETcpCloseWait) && iSND.NXT == iSND.UNA + iSockOutQLen && advance >= 0) || |
|
2253 (InState(ETcpSynReceived) && iSockFlags.iRecvClose))) |
|
2254 { |
|
2255 EnterState(InState(ETcpSynReceived|ETcpEstablished) ? ETcpFinWait1 : ETcpLastAck); |
|
2256 SendSegment(KTcpCtlFIN|KTcpCtlACK); |
|
2257 } |
|
2258 } |
|
2259 } |
|
2260 |
|
2261 |
|
2262 // |
|
2263 // Handle retransmission timeout |
|
2264 // |
|
2265 // The retransmission timer is shared for multiple purposes. |
|
2266 // There are different reasons why we might end up here: |
|
2267 // |
|
2268 // 1) A normal retransmission timeout. In this case, iSND.NXT > iSND.UNA. |
|
2269 // 2) We are probing a zero window. In this case iSND.WND == 0. |
|
2270 // 3) The Nagle override timeout has expired. In this case, |
|
2271 // iSND.WND != 0 and unsent < effMSS. |
|
2272 // 4) TIME-WAIT or FIN-WAIT-2 timeout. |
|
2273 // 5) If TCP keepalive option is set, expiry of the keepalive timer |
|
2274 // |
|
2275 void CProviderTCP6::RetransmitTimeout() |
|
2276 { |
|
2277 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitTimeout(): backoff=%d"), (TInt)this, iBackoff)); |
|
2278 |
|
2279 TUint maxRetries = InState(ETcpSynSent|ETcpSynReceived) |
|
2280 ? Protocol()->SynRetries() : Protocol()->Retries2(); |
|
2281 |
|
2282 // Handle backoff and expiration |
|
2283 if (iSND.NXT > iSND.UNA || iSND.WND == 0) |
|
2284 { |
|
2285 // |
|
2286 // Exponential backoff. |
|
2287 // |
|
2288 ++iBackoff; |
|
2289 if (iRTO < Protocol()->MaxRTO()) // Avoid RTO overflow |
|
2290 ResetRTO(); |
|
2291 |
|
2292 // |
|
2293 // Timeout? |
|
2294 // |
|
2295 // Note: we time out if this is a connect attempt or a retransmission, |
|
2296 // but we must not time out if we're probing a zero window. |
|
2297 // Exception: probing timeouts if application has closed and we have zero window |
|
2298 // |
|
2299 if ((iBackoff > maxRetries) && |
|
2300 (iSND.WND > 0 |
|
2301 || InState(ETcpSynSent|ETcpSynReceived) |
|
2302 || (iSockFlags.iSendClose && iSockFlags.iRecvClose))) |
|
2303 { |
|
2304 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitTimeout(): TCP timed out"), (TInt)this)); |
|
2305 ErrorExpire(iLastError.iStatus != KErrNone ? iLastError.iStatus : KErrTimedOut); |
|
2306 return; |
|
2307 } |
|
2308 // |
|
2309 // Simple black hole detection for PMTUD. Currently, we never try to re-enable |
|
2310 // PMTUD after hitting a black hole. |
|
2311 // |
|
2312 if (iBackoff > Protocol()->Retries1() && iSND.WND > 0) |
|
2313 { |
|
2314 iFlags.iDoPMTUD = EFalse; |
|
2315 iSMSS = Min(iSMSS, KTcpStandardMSS); |
|
2316 } |
|
2317 } |
|
2318 |
|
2319 else if (iFlags.iHaveKeepAlive && !iSockOutQLen && InState(ETcpEstablished | ETcpCloseWait)) |
|
2320 { |
|
2321 KeepAliveTimeout(); |
|
2322 return; |
|
2323 } |
|
2324 |
|
2325 // TIME-WAIT or FIN-WAIT-2 timeout |
|
2326 if (InState(ETcpTimeWait) || (InState(ETcpFinWait2) && iSockFlags.iRecvClose)) |
|
2327 { |
|
2328 Expire(); |
|
2329 return; |
|
2330 } |
|
2331 |
|
2332 // Not dead yet. Go retransmit some segments. |
|
2333 RetransmitSegments(); |
|
2334 } |
|
2335 |
|
2336 |
|
2337 void CProviderTCP6::KeepAliveTimeout() |
|
2338 { |
|
2339 // Keepalive timer expired. Because 32-bit microseconds are not enough for the minimum keepalive |
|
2340 // timeout of two hours, the keepalive interval needs to be consumed one hour at a time. |
|
2341 |
|
2342 ASSERT(iRetransTimer); |
|
2343 |
|
2344 if (iBackoff >= Protocol()->NumKeepAlives()) |
|
2345 { |
|
2346 // No response from the peer. Terminate connection |
|
2347 LOG(Log::Printf(_L("\ttcp SAP[%u] KeepAliveTimeout(): No response to Keep-Alive probes. Closing connection"), (TInt)this)); |
|
2348 ErrorExpire(KErrTimedOut); |
|
2349 return; |
|
2350 } |
|
2351 |
|
2352 TUint32 usec = TimeStamp(); |
|
2353 |
|
2354 if (!iLastTimeout) |
|
2355 iLastTimeout = usec; |
|
2356 |
|
2357 TUint32 distance = (usec - iLastTimeout) / KOneSecondUs; // seconds |
|
2358 TUint32 interval = iBackoff ? Protocol()->KeepAliveRxmt() : Protocol()->KeepAliveIntv(); |
|
2359 |
|
2360 if (distance > interval) |
|
2361 { |
|
2362 // Send a keepalive probe. If no ack arrives, next one is sent after a shorter time (75 s) |
|
2363 LOG(Log::Printf(_L("\ttcp SAP[%u] KeepAliveTimeout(): Sending a Keep-Alive probe"), (TInt)this)); |
|
2364 SendSegment(KTcpCtlACK, iSND.UNA - 1, 0); |
|
2365 iBackoff++; |
|
2366 iRetransTimer->Restart(Protocol()->KeepAliveRxmt() * KOneSecondUs); |
|
2367 } |
|
2368 else |
|
2369 { |
|
2370 // This branch is entered when the first keepalive has to be issued after an idle period. |
|
2371 distance = Protocol()->KeepAliveIntv() - distance; |
|
2372 iRetransTimer->Restart((distance > 1800) ? |
|
2373 1800 * KOneSecondUs : (distance * KOneSecondUs)); |
|
2374 } |
|
2375 } |
|
2376 |
|
2377 |
|
2378 void CProviderTCP6::ResetKeepAlives() |
|
2379 { |
|
2380 ASSERT(iRetransTimer); |
|
2381 iRetransTimer->Restart((Protocol()->KeepAliveIntv() > 1800) ? |
|
2382 1800 * KOneSecondUs : (Protocol()->KeepAliveIntv() * KOneSecondUs)); |
|
2383 // Backoff is used for counting unacknowledged keepalive retransmissions during idle periods |
|
2384 iBackoff = 0; |
|
2385 iLastTimeout = TimeStamp(); |
|
2386 } |
|
2387 |
|
2388 inline TBool CProviderTCP6::CanTriggerKeepAlive() |
|
2389 { |
|
2390 // |
|
2391 // We can only send keep-alive if we're idle and established. |
|
2392 // |
|
2393 return iFlags.iHaveTriggeredKeepAlive |
|
2394 && !iSockOutQLen |
|
2395 && iSendQ.IsEmpty() |
|
2396 && InState(ETcpEstablished) |
|
2397 && iSND.NXT == iSND.UNA |
|
2398 && iSND.WND > 0; |
|
2399 } |
|
2400 |
|
2401 // |
|
2402 // Try to retransmit segments. This routine gets called from two places: |
|
2403 // - directly from RetransmitTimeout() |
|
2404 // - from CanSend(), in which case this is a delayed retransmission timeout |
|
2405 // |
|
2406 void CProviderTCP6::RetransmitSegments() |
|
2407 { |
|
2408 ASSERT(iRetransTimer); |
|
2409 |
|
2410 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): queue=%u wnd=%u cwnd=%u, ssthresh=%u dupacks=%d"), |
|
2411 (TInt)this, iSockOutQLen, iSND.WND, iCwnd, iSsthresh, iDupAcks)); |
|
2412 |
|
2413 TInt unacked = Min(iSND.NXT - iSND.UNA, iSockOutQLen); // Adjust for FIN |
|
2414 TInt effMSS = EffectiveMSS(); |
|
2415 |
|
2416 // Delay retransmission if the flow is pending |
|
2417 iFlags.iRetransmitPending = (iFlow.Status() == EFlow_PENDING); |
|
2418 if (iFlags.iRetransmitPending) |
|
2419 { |
|
2420 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Flow pending"), (TInt)this)); |
|
2421 ReSchedRetransmit(); |
|
2422 return; |
|
2423 } |
|
2424 |
|
2425 // |
|
2426 // Handle retransmission of data segments and zero window probing. |
|
2427 // We must have something in output queue. SYN or FIN retransmissions |
|
2428 // and TIME-WAIT or FIN-WAIT-2 timeouts are handled later. |
|
2429 // |
|
2430 if (iSockOutQLen && InState(ETcpEstablished|ETcpFinWait1|ETcpClosing|ETcpCloseWait|ETcpLastAck)) |
|
2431 { |
|
2432 if (iSND.WND == 0) |
|
2433 { |
|
2434 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Window PROBE"), (TInt)this)); |
|
2435 |
|
2436 // |
|
2437 // We are probing a zero window. |
|
2438 // |
|
2439 switch (Protocol()->ProbeStyle()) |
|
2440 { |
|
2441 case 1: |
|
2442 // Probe with a full segment (BSD style) |
|
2443 SendSegment(KTcpCtlACK, iSND.UNA, Min(iSockOutQLen - unacked, effMSS)); |
|
2444 break; |
|
2445 |
|
2446 case 2: |
|
2447 // |
|
2448 // Probe with a below-window ACK (Linux style). |
|
2449 // |
|
2450 // Note: SendSegment() does not allow sending an above-window ACK. |
|
2451 // Below-window ACK is fine, though. |
|
2452 // |
|
2453 // Note 2: If we have urgent data to send, we fall back on standard probe. |
|
2454 // since a pure ack can not deliver the urgent pointer. |
|
2455 // |
|
2456 if (iSND.UP <= iSND.UNA) |
|
2457 { |
|
2458 SendSegment(KTcpCtlACK, iSND.UNA - 1); |
|
2459 SchedRetransmit(); |
|
2460 break; |
|
2461 } |
|
2462 // Fall through |
|
2463 |
|
2464 default: |
|
2465 // Standard probe. We use a single byte to probe a zero window. |
|
2466 SendSegment(KTcpCtlACK, iSND.UNA, 1); |
|
2467 } |
|
2468 // |
|
2469 // Note 1: With probes including data iSND.NXT will now be pointing beyond |
|
2470 // the advertised window of the receiver! This will allow us to accept the |
|
2471 // incoming probe ack without any special hacks. However, it also means |
|
2472 // that if we send an ACK or RST, we need to make sure the sequence number |
|
2473 // is within the receiver window! SendSegment() now makes this adjustment |
|
2474 // as a special case. |
|
2475 // |
|
2476 // Note 2: We may also end up with iSND.NXT pointing beyond the window if |
|
2477 // the receiver suddenly shrinks its window. The current solution covers |
|
2478 // both cases. |
|
2479 // |
|
2480 return; |
|
2481 } |
|
2482 |
|
2483 // |
|
2484 // This is a retransmit timout. Do we have anything to do? |
|
2485 // |
|
2486 if (!unacked) |
|
2487 return; |
|
2488 |
|
2489 LOG(if (iFlags.iFastRetransMode) Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Leaving FAST RETRANS mode"), (TInt)this)); |
|
2490 iFlags.iFastRetransMode = EFalse; |
|
2491 iDupAcks = 0; |
|
2492 |
|
2493 // |
|
2494 // Congestion control |
|
2495 // |
|
2496 iSsthresh = Max((iSND.NXT - iSND.UNA) / 2, 2 * iSMSS); |
|
2497 iCwnd = EffectiveMSS(); |
|
2498 iLwnd = 0; |
|
2499 iRetranData = 0; |
|
2500 iPartialSeq = iSND.UNA; |
|
2501 |
|
2502 // |
|
2503 // The receiver may have reneged. Clear SACK info. |
|
2504 // |
|
2505 // Only clear the SACK queue if we have a SACKed block immediately |
|
2506 // after iSND.UNA. In this case the sender has clearly reneged. |
|
2507 // If the peer does this even once, we will no longer trust it |
|
2508 // to retain its above-sequence queue and will revert to the normal |
|
2509 // RFC2018 behaviour of clearing all SACK info on retransmit timeout. |
|
2510 // |
|
2511 if (!iFlags.iSackOk || (iFlags.iPeerHasReneged || |
|
2512 (iSacked.Count() && iSacked.First()->iLeft == iSND.UNA))) |
|
2513 { |
|
2514 if (iFlags.iSackOk) |
|
2515 { |
|
2516 LOG(if(!iFlags.iPeerHasReneged) Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Peer reneged"), (TInt)this)); |
|
2517 iFlags.iPeerHasReneged = ETrue; |
|
2518 iSacked.Clear(); |
|
2519 } |
|
2520 |
|
2521 // |
|
2522 // New reno "bugfix" [RFC2582] is applied only if we are forced |
|
2523 // to discard the SACK info. If we can keep the info we will |
|
2524 // never send spurious retransmits and thus there will be no |
|
2525 // dupacks to trigger fast recovery, unless segments have |
|
2526 // really been lost. |
|
2527 // |
|
2528 iSendHigh = iSND.NXT; |
|
2529 } |
|
2530 |
|
2531 iRealSendHigh = iSND.NXT; |
|
2532 |
|
2533 // Save timestamp for delay spike detection |
|
2534 if (iFlags.iUseTimeStamps) |
|
2535 iLastTimeout = TimeStamp(); |
|
2536 |
|
2537 // |
|
2538 // Retransmit segments. |
|
2539 // |
|
2540 if (Protocol()->FRTO()) |
|
2541 { |
|
2542 // F-RTO: Send first unacknowledged segment and continue transmitting new data |
|
2543 iFRTOsent = 1; |
|
2544 SendDataSegment(iSND.UNA, ETrue); |
|
2545 } |
|
2546 else |
|
2547 { |
|
2548 // Normal retransmit |
|
2549 iTransmitSeq = iSND.UNA; |
|
2550 SendSegments(ETrue); |
|
2551 } |
|
2552 |
|
2553 // Store retransmit sequence for SACK retransmit |
|
2554 if (iTransmitSeq > iSendHigh && !iFRTOsent) |
|
2555 iSendHigh = iTransmitSeq; |
|
2556 |
|
2557 // If the server doesn't respond because of broken NAT/FW or other, don't keep interface up. |
|
2558 if (InState(ETcpFinWait1|ETcpClosing|ETcpLastAck)) |
|
2559 DetachIfDead(); |
|
2560 return; |
|
2561 } |
|
2562 |
|
2563 // |
|
2564 // Ok, this is either a SYN/FIN retransmit or a TIME-WAIT/FIN-WAIT-2 timeout. |
|
2565 // |
|
2566 if (InState(ETcpSynSent)) |
|
2567 { |
|
2568 // Retransmit SYN |
|
2569 SendSegment(KTcpCtlSYN, iSND.UNA); |
|
2570 return; |
|
2571 } |
|
2572 |
|
2573 if (InState(ETcpSynReceived)) |
|
2574 { |
|
2575 // Retransmit SYN,ACK |
|
2576 SendSegment(KTcpCtlSYN|KTcpCtlACK, iSND.UNA); |
|
2577 return; |
|
2578 } |
|
2579 |
|
2580 if (InState(ETcpFinWait1|ETcpClosing|ETcpLastAck)) |
|
2581 { |
|
2582 // If the server doesn't respond because of broken NAT/FW or other, don't keep interface up. |
|
2583 DetachIfDead(); |
|
2584 // Retransmit FIN |
|
2585 SendSegment(KTcpCtlFIN|KTcpCtlACK, iSND.UNA); |
|
2586 return; |
|
2587 } |
|
2588 |
|
2589 LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Retransmitter stopping"), (TInt)this)); |
|
2590 if (!iSockFlags.iAttached) |
|
2591 Expire(); |
|
2592 return; |
|
2593 } |
|
2594 |
|
2595 |
|
2596 // |
|
2597 // Respond to an explicit congestion control signal. |
|
2598 // Currently, the signal can come from the link layer |
|
2599 // or from the network as an ICMP source quench. |
|
2600 // |
|
2601 TBool CProviderTCP6::SourceQuench() |
|
2602 { |
|
2603 // |
|
2604 // Allow source quenching approximately once per window. |
|
2605 // Note: the test is written in such a way that iQuenchSeq |
|
2606 // does not need to be updated during normal TCP operation. |
|
2607 // |
|
2608 // Do not shrink the congestion window if we're doing fast |
|
2609 // retransmits. That would mess up the congestion window |
|
2610 // deflation when exiting fast retransmit mode. |
|
2611 // |
|
2612 if (iQuenchSeq.Outside(iSND.NXT, iSND.NXT + iSND.WND) && !iFlags.iFastRetransMode) |
|
2613 { |
|
2614 iSsthresh = Max((iSND.NXT - iSND.UNA) / 2, 2 * iSMSS); |
|
2615 iCwnd = iSsthresh; |
|
2616 iQuenchSeq = iSND.NXT + iSND.WND; |
|
2617 LOG(Log::Printf(_L("\ttcp SAP[%u] SourceQuench(): flight=%d, cwnd=%d, ssthresh=%d"), |
|
2618 (TInt)this, iSND.NXT - iSND.UNA, iCwnd, iSsthresh)); |
|
2619 return ETrue; |
|
2620 } |
|
2621 return EFalse; |
|
2622 } |
|
2623 |
|
2624 |
|
2625 TInt CProviderTCP6::SenderCallBack(TAny* aProviderTCP) |
|
2626 { |
|
2627 LOG(Log::Printf(_L("<>\ttcp SAP[%u] SenderCallBack"), (TInt)aProviderTCP)); |
|
2628 ((CProviderTCP6*)aProviderTCP)->SendSegments(); |
|
2629 return 0; |
|
2630 } |
|
2631 |
|
2632 TInt CProviderTCP6::ReceiverCallBack(TAny* aProviderTCP) |
|
2633 { |
|
2634 LOG(Log::Printf(_L("<>\ttcp SAP[%u] ReceiverCallBack"), (TInt)aProviderTCP)); |
|
2635 ((CProviderTCP6*)aProviderTCP)->ProcessSegments(); |
|
2636 return 0; |
|
2637 } |
|
2638 |
|
2639 TInt CProviderTCP6::DelayAckCallBack(TAny* aProviderTCP) |
|
2640 { |
|
2641 LOG(Log::Printf(_L("<>\ttcp SAP[%u] DelayAckCallBack"), (TInt)aProviderTCP)); |
|
2642 ((CProviderTCP6*)aProviderTCP)->SendSegment(KTcpCtlACK); |
|
2643 return 0; |
|
2644 } |
|
2645 |
|
2646 TInt CProviderTCP6::TransmitterCallBack(TAny* aProviderTCP) |
|
2647 { |
|
2648 LOG(Log::Printf(_L("<>\ttcp SAP[%u] TransmitterCallBack"), (TInt)aProviderTCP)); |
|
2649 ((CProviderTCP6*)aProviderTCP)->Transmit(); |
|
2650 return 0; |
|
2651 } |
|
2652 |
|
2653 TInt CProviderTCP6::RetransmitterCallBack(TAny* aProviderTCP) |
|
2654 { |
|
2655 LOG(Log::Printf(_L("<>\ttcp SAP[%u] RetransmitterCallback"), (TInt)aProviderTCP)); |
|
2656 ((CProviderTCP6*)aProviderTCP)->RetransmitTimeout(); |
|
2657 return 0; |
|
2658 } |
|
2659 |
|
2660 |
|
2661 TInt CProviderTCP6::LingerTimerCallBack(TAny *aProviderTCP) |
|
2662 { |
|
2663 LOG(Log::Printf(_L("<>\ttcp SAP[%u] Linger timeout()"), (TInt)aProviderTCP)); |
|
2664 ((CProviderTCP6*)aProviderTCP)->Detach(); |
|
2665 return 0; |
|
2666 } |
|
2667 |
|
2668 |
|
2669 // |
|
2670 // Initialize SRTT measurement |
|
2671 // |
|
2672 void CProviderTCP6::ClearRTT() |
|
2673 { |
|
2674 iSRTT = 0; |
|
2675 iMDEV = Protocol()->MdevSmooth() * Protocol()->InitialRTO(); |
|
2676 if (Protocol()->RTO_K()) |
|
2677 iMDEV /= Protocol()->RTO_K(); |
|
2678 } |
|
2679 |
|
2680 |
|
2681 // |
|
2682 // Update RTO using van Jacobson's algorithm |
|
2683 // |
|
2684 void CProviderTCP6::UpdateRTO(TUint32 aRTT) |
|
2685 { |
|
2686 if (!iSRTT && aRTT > Protocol()->InitialRTO() / 2) |
|
2687 { |
|
2688 iSRTT = Protocol()->SrttSmooth() * aRTT; |
|
2689 iMDEV = Protocol()->MdevSmooth() * aRTT / 2; |
|
2690 } |
|
2691 else |
|
2692 { |
|
2693 TInt delta = aRTT - (iSRTT / Protocol()->SrttSmooth()); // delta >= -iSRTT |
|
2694 iSRTT += delta; |
|
2695 if (!iSRTT) |
|
2696 iSRTT = 1; |
|
2697 if (delta < 0) |
|
2698 delta = -delta; |
|
2699 delta -= (iMDEV / Protocol()->MdevSmooth()); // delta >= -iMDEV |
|
2700 iMDEV += delta; |
|
2701 } |
|
2702 |
|
2703 ResetRTO(); |
|
2704 LOG(Log::Printf(_L("\ttcp SAP[%u] UpdateRTO(): RTT=%d SRTT=%d MDEV=%d BACKOFF=%d RTO=%d"), |
|
2705 (TInt)this, aRTT, iSRTT / Protocol()->SrttSmooth(), iMDEV / Protocol()->MdevSmooth(), iBackoff, iRTO)); |
|
2706 } |
|
2707 |
|
2708 // |
|
2709 // Calculate RTO with backoff |
|
2710 // |
|
2711 void CProviderTCP6::ResetRTO() |
|
2712 { |
|
2713 iRTO = (iSRTT / Protocol()->SrttSmooth()) + |
|
2714 Max(Protocol()->RTO_K() * iMDEV / Protocol()->MdevSmooth(), Protocol()->RTO_G()); |
|
2715 if (iRTO < Protocol()->MinRTO()) |
|
2716 iRTO = Protocol()->MinRTO(); |
|
2717 iRTO <<= iBackoff; |
|
2718 if (iRTO > Protocol()->MaxRTO()) |
|
2719 iRTO = Protocol()->MaxRTO(); |
|
2720 LOG(Log::Printf(_L("\ttcp SAP[%u] ResetRTO(): SRTT=%d MDEV=%d BACKOFF=%d RTO=%d"), |
|
2721 (TInt)this, iSRTT / Protocol()->SrttSmooth(), iMDEV / Protocol()->MdevSmooth(), iBackoff, iRTO)); |
|
2722 } |
|
2723 |
|
2724 // |
|
2725 // Set initial congestion window |
|
2726 // |
|
2727 void CProviderTCP6::ResetCwnd(TUint aSMSS) |
|
2728 { |
|
2729 if (Protocol()->RFC2414()) |
|
2730 iCwnd = Min(4 * aSMSS, Max(2 * aSMSS, 4380)); |
|
2731 else |
|
2732 iCwnd = Protocol()->InitialCwnd() * aSMSS; |
|
2733 LOG(Log::Printf(_L("\ttcp SAP[%u] ResetCwnd(): cwnd=%d"), (TInt)this, iCwnd)); |
|
2734 } |
|
2735 |
|
2736 |
|
2737 // |
|
2738 // Schedule a FIN-WAIT-2 or TIME-WAIT timeout |
|
2739 // |
|
2740 void CProviderTCP6::SchedMsl2Wait() |
|
2741 { |
|
2742 ASSERT(iRetransTimer); |
|
2743 |
|
2744 iBackoff = 0; |
|
2745 iRetransTimer->Restart(Protocol()->Msl2Delay()); |
|
2746 |
|
2747 // |
|
2748 // Remove this SAP from the user socket count. |
|
2749 // |
|
2750 DetachFromInterface(); |
|
2751 } |
|
2752 |
|
2753 // |
|
2754 // Detach the SAP if the application has closed and we seem to keep resending stuff. |
|
2755 // |
|
2756 void CProviderTCP6::DetachIfDead() |
|
2757 { |
|
2758 if (iSockFlags.iRecvClose && iSockFlags.iSendClose && Protocol()->FinPersistency() |
|
2759 && iBackoff >= Protocol()->FinPersistency()) |
|
2760 { |
|
2761 LOG(Log::Printf(_L("\ttcp SAP[%u] Peer looks dead while %d bytes unacked data. Detach!"), |
|
2762 (TInt)this, Min(iSND.NXT - iSND.UNA, iSockOutQLen))); |
|
2763 DetachFromInterface(); |
|
2764 } |
|
2765 } |
|
2766 |
|
2767 void CProviderTCP6::DetachFromInterface() |
|
2768 /** |
|
2769 Removes this SAP from the user socket count and interface flow count. |
|
2770 This allows link layer and TCP/IP stack go down if no one else uses it. |
|
2771 */ |
|
2772 { |
|
2773 const TInt off = 0; |
|
2774 SetOption(KSolInetIp, KSoUserSocket, TPtr8((TUint8*)&off, sizeof(TInt), sizeof(TInt))); |
|
2775 SetOption(KSolInetIp, KSoKeepInterfaceUp, TPtr8((TUint8*)&off, sizeof(TInt), sizeof(TInt))); |
|
2776 } |
|
2777 |
|
2778 |
|
2779 // |
|
2780 // Check ioctl completion |
|
2781 // |
|
2782 void CProviderTCP6::CompleteIoctl(TInt aError) |
|
2783 { |
|
2784 if (iFlags.iDataSentIoctl && iSockFlags.iNotify) |
|
2785 { |
|
2786 if (!iSockOutQLen) |
|
2787 { |
|
2788 iFlags.iDataSentIoctl = EFalse; |
|
2789 iSocket->IoctlComplete(0); |
|
2790 } |
|
2791 else if (aError != KErrNone) |
|
2792 { |
|
2793 iFlags.iDataSentIoctl = EFalse; |
|
2794 Error(KErrCancel, MSocketNotify::EErrorIoctl); |
|
2795 } |
|
2796 } |
|
2797 } |
|
2798 |
|
2799 // |
|
2800 // Main incoming segment processing loop |
|
2801 // |
|
2802 void CProviderTCP6::ProcessSegments() |
|
2803 { |
|
2804 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments()"), (TInt)this)); |
|
2805 |
|
2806 ASSERT(iRetransTimer); |
|
2807 |
|
2808 RMBufRecvPacket packet; |
|
2809 TBool immediateAck = EFalse; |
|
2810 |
|
2811 while (iRecvQ.Remove(packet)) |
|
2812 { |
|
2813 RMBufRecvInfo* info = packet.Unpack(); |
|
2814 TIpHeader *ip = ((RMBufPacketPeek &)packet).GetIpHeader(); |
|
2815 TTcpPacket seg(packet, info->iOffset); |
|
2816 TTcpOptions opt; |
|
2817 seg.iHdr->Options(opt); |
|
2818 TInt len = packet.Length() - seg.iHdr->HeaderLength() - info->iOffset; |
|
2819 TTcpSeqNum seq = seg.iHdr->Sequence(); |
|
2820 TTcpSeqNum ack = seg.iHdr->ACK() ? seg.iHdr->Acknowledgment() : TTcpSeqNum(0); |
|
2821 TInt fin = seg.iHdr->FIN(); // Save this for FIN processing |
|
2822 CProviderTCP6 *nSAP = NULL; |
|
2823 TTcpSeqNum rcvNxt = iRCV.NXT; // Used in SYN_RECEIVED state |
|
2824 |
|
2825 // Get current time |
|
2826 TUint32 usec = TimeStamp(); |
|
2827 |
|
2828 if (InState(ETcpListen)) |
|
2829 { |
|
2830 TUint32 tsEcr; |
|
2831 |
|
2832 if (!iParent) |
|
2833 { |
|
2834 // |
|
2835 // Server socket LISTEN state processing. |
|
2836 // |
|
2837 |
|
2838 // Sanity checks. |
|
2839 if (iConnectCount >= iListenQueueSize || seg.iHdr->RST()) |
|
2840 goto discard; |
|
2841 |
|
2842 // Check invalid address. |
|
2843 if (!TInetAddr::Cast(info->iSrcAddr).IsUnicast() || |
|
2844 !TInetAddr::Cast(info->iDstAddr).IsUnicast()) |
|
2845 goto discard; |
|
2846 |
|
2847 if (IsLandAttack(info)) |
|
2848 goto discard; |
|
2849 |
|
2850 if (seg.iHdr->ACK()) |
|
2851 { |
|
2852 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): ACK received in LISTEN state. Sending RST"), (TInt)this)); |
|
2853 SendReset(ack, info->iDstAddr, info->iSrcAddr); |
|
2854 goto discard; |
|
2855 } |
|
2856 |
|
2857 if (!seg.iHdr->SYN()) |
|
2858 goto discard; |
|
2859 |
|
2860 if (opt.Error()) |
|
2861 { |
|
2862 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid TCP options"), (TInt)this)); |
|
2863 SendResetNoSync(seq+len+1, info->iDstAddr, info->iSrcAddr); |
|
2864 goto discard; |
|
2865 } |
|
2866 |
|
2867 if (opt.MSS() > 0 && opt.MSS() < STATIC_CAST(TInt, KTcpMinimumMSS)) |
|
2868 { |
|
2869 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid MSS option"), (TInt)this)); |
|
2870 SendResetNoSync(seq+len+1, info->iDstAddr, info->iSrcAddr); |
|
2871 goto discard; |
|
2872 } |
|
2873 |
|
2874 // |
|
2875 // Sometimes SYN retransmissions get compressed in the network |
|
2876 // and get queued in the listen socket. If this happens we just |
|
2877 // punt the SYN packet to the correct SAP. |
|
2878 // |
|
2879 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
2880 nSAP = (CProviderTCP6*)Protocol()->LocateSap(EMatchConnection, KAFUnspec, |
|
2881 info->iDstAddr, info->iSrcAddr); |
|
2882 #else |
|
2883 nSAP = (CProviderTCP6*)Protocol()->LocateSap(EMatchConnection, KAFUnspec, |
|
2884 info->iDstAddr, info->iSrcAddr, NULL, info->iInterfaceIndex); |
|
2885 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
2886 if (nSAP == NULL) |
|
2887 { |
|
2888 // Create a new SAP and initialize it |
|
2889 if (CreateChild(nSAP) != KErrNone) |
|
2890 goto discard; |
|
2891 |
|
2892 #ifdef SYMBIAN_NETWORKING_UPS |
|
2893 nSAP->iConnectionInfoReceived = 1; |
|
2894 #endif |
|
2895 RFlowContext flowCtxt = nSAP->iFlow; |
|
2896 flowCtxt.SetLocalAddr(info->iDstAddr); |
|
2897 flowCtxt.SetRemoteAddr(info->iSrcAddr); |
|
2898 nSAP->EnterState(ETcpListen); |
|
2899 |
|
2900 // Create a flow context |
|
2901 TInt status = flowCtxt.Connect(); |
|
2902 if (status < KErrNone) |
|
2903 { |
|
2904 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSYN(): Error %d opening flow context"), (TInt)this, status)); |
|
2905 delete nSAP; |
|
2906 SendResetNoSync(seq+len+1, info->iDstAddr, info->iSrcAddr); |
|
2907 goto discard; |
|
2908 } |
|
2909 |
|
2910 // Disable on-demand interface setup for the child |
|
2911 flowCtxt.FlowContext()->iInfo.iNoInterfaceUp = 1; |
|
2912 nSAP->iSockFlags.iConnected = ETrue; |
|
2913 Protocol()->BindProvider(nSAP); |
|
2914 } |
|
2915 |
|
2916 // Get the new SAP started. It will handle the rest, |
|
2917 packet.Pack(); |
|
2918 nSAP->Process(packet); |
|
2919 continue; |
|
2920 } |
|
2921 |
|
2922 |
|
2923 // |
|
2924 // Child socket LISTEN state processing. |
|
2925 // |
|
2926 |
|
2927 /* |
|
2928 Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other |
|
2929 control or text should be queued for processing later. ISS |
|
2930 should be selected and a SYN segment sent of the form: |
|
2931 |
|
2932 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> |
|
2933 |
|
2934 SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection |
|
2935 state should be changed to SYN-RECEIVED. Note that any other |
|
2936 incoming control or data (combined with SYN) will be processed |
|
2937 in the SYN-RECEIVED state, but processing of SYN and ACK should |
|
2938 not be repeated. If the listen was not fully specified (i.e., |
|
2939 the foreign socket was not fully specified), then the |
|
2940 unspecified fields should be filled in now. |
|
2941 */ |
|
2942 |
|
2943 // Peer groks timestamps? |
|
2944 iFlags.iUseTimeStamps &= opt.TimeStamps(iTsRecent, tsEcr); |
|
2945 if (!iFlags.iUseTimeStamps) |
|
2946 iOptions.ClearTimeStamps(); |
|
2947 |
|
2948 // Peer groks SACK? |
|
2949 iFlags.iSackOk &= opt.SackOk(); |
|
2950 if (!iFlags.iSackOk) |
|
2951 iOptions.ClearSackOk(); |
|
2952 |
|
2953 // Peer denies ECN |
|
2954 if (!seg.iHdr->ECE() || !seg.iHdr->CWR()) |
|
2955 { |
|
2956 iFlags.iEcn = EFalse; |
|
2957 } |
|
2958 |
|
2959 // Note: the parent does error checking before instantiating a child socket. |
|
2960 if (opt.MSS() >= 0) |
|
2961 iSMSS = opt.MSS(); |
|
2962 |
|
2963 // |
|
2964 // The following is based on network interface MTU. |
|
2965 // We limit the advertised MSS to window size divided by four, |
|
2966 // in case the interface supportes a large (or infinite) MTU. |
|
2967 // |
|
2968 iRMSS = Min(LinkRMSS(), iSockInBufSize / 2); |
|
2969 iOptions.SetMSS(iRMSS); |
|
2970 |
|
2971 // Initialise send sequence number |
|
2972 iTransmitSeq = iSND.NXT = Protocol()->RandomSequence(); |
|
2973 |
|
2974 if (!opt.WindowScale() || Protocol()->WinScale() == -1) |
|
2975 { |
|
2976 iRcvWscale = 0; |
|
2977 iOptions.SetWindowScale(0); |
|
2978 iSockInBufSize = Min(iSockInBufSize, 0xffff); |
|
2979 } |
|
2980 else |
|
2981 { |
|
2982 iSndWscale = opt.WindowScale() - 1; |
|
2983 iRcvWscale = (Protocol()->WinScale() > 0 ? |
|
2984 Protocol()->WinScale() - 1 : NeedWindowScale()); |
|
2985 iOptions.SetWindowScale((TUint8)(iRcvWscale + 1)); |
|
2986 } |
|
2987 |
|
2988 // Initialize receiver sequence and window |
|
2989 iFreeWindow = iSockInBufSize % iRMSS; |
|
2990 iRCV.WND = iSockInBufSize - iFreeWindow; |
|
2991 iRCV.NXT = seg.iHdr->Sequence() + 1; |
|
2992 |
|
2993 TUint8 flags = KTcpCtlSYN|KTcpCtlACK; |
|
2994 if (iFlags.iEcn) |
|
2995 { |
|
2996 flags |= KTcpCtlECE; |
|
2997 } |
|
2998 |
|
2999 // Do not kick idle timers until we are in established state |
|
3000 StoreKeepInterfaceUp(); |
|
3001 iFlow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable); |
|
3002 |
|
3003 // Send SYN-ACK |
|
3004 iSND.UNA = iSND.NXT; |
|
3005 SendSegment(flags); |
|
3006 ++iTransmitSeq; |
|
3007 |
|
3008 // Make sure we don't miss our window update. |
|
3009 iSND.WL1 = iRCV.NXT; |
|
3010 iSND.WL2 = iSND.NXT; |
|
3011 |
|
3012 iPartialSeq = iSND.UNA; |
|
3013 |
|
3014 EnterState(ETcpSynReceived); |
|
3015 goto accept; |
|
3016 } |
|
3017 |
|
3018 if (InState(ETcpSynSent)) |
|
3019 { |
|
3020 if (seg.iHdr->ACK() && ack.Outside(iSND.UNA, iSND.NXT)) |
|
3021 { |
|
3022 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid ack=%u"), (TInt)this, ack.Uint32())); |
|
3023 if (!seg.iHdr->RST()) |
|
3024 SendReset(ack); |
|
3025 goto discard; |
|
3026 } |
|
3027 |
|
3028 if (seg.iHdr->RST()) |
|
3029 { |
|
3030 if (seg.iHdr->ACK()) // No need to check ack sequence because it was tested above |
|
3031 { |
|
3032 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): RST packet"), (TInt)this)); |
|
3033 Error(KErrCouldNotConnect, MSocketNotify::EErrorConnect); |
|
3034 EnterState(ETcpClosed); |
|
3035 goto wrapup; |
|
3036 } |
|
3037 else |
|
3038 goto discard; |
|
3039 } |
|
3040 |
|
3041 if (!seg.iHdr->SYN()) |
|
3042 goto discard; |
|
3043 |
|
3044 // Process options for SYN packet. |
|
3045 if (opt.Error()) |
|
3046 { |
|
3047 // In case we receive invalid optons, we should just report an error and reset the connection. |
|
3048 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid options, reset connection"), (TInt)this)); |
|
3049 if (seg.iHdr->ACK()) |
|
3050 SendReset(ack); |
|
3051 else |
|
3052 SendResetNoSync(seq+len+1); |
|
3053 Error(KErrCouldNotConnect, MSocketNotify::EErrorConnect); |
|
3054 EnterState(ETcpClosed); |
|
3055 goto wrapup; |
|
3056 } |
|
3057 |
|
3058 if (opt.MSS() > 0) |
|
3059 { |
|
3060 if (opt.MSS() < STATIC_CAST(TInt, KTcpMinimumMSS)) |
|
3061 { |
|
3062 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid MSS option"), (TInt)this)); |
|
3063 if (seg.iHdr->ACK()) |
|
3064 SendReset(ack); |
|
3065 else |
|
3066 SendResetNoSync(seq+len+1); |
|
3067 goto discard; |
|
3068 } |
|
3069 iSMSS = opt.MSS(); |
|
3070 } |
|
3071 |
|
3072 iFlags.iUseTimeStamps &= opt.TimeStamps(); |
|
3073 iFlags.iSackOk &= opt.SackOk(); |
|
3074 |
|
3075 if (opt.WindowScale()) |
|
3076 { |
|
3077 iSndWscale = opt.WindowScale() - 1; |
|
3078 iFreeWindow = iSockInBufSize % iRMSS; |
|
3079 iRCV.WND = iSockInBufSize - iFreeWindow; |
|
3080 } |
|
3081 else |
|
3082 { |
|
3083 // iFreeWindow and iRCV.WND were confirmed to be less than 0xffff with SYN |
|
3084 iRcvWscale = 0; |
|
3085 iSockInBufSize = Min(iSockInBufSize, 0xffff); |
|
3086 } |
|
3087 |
|
3088 iRCV.NXT = seq+1; |
|
3089 |
|
3090 // Our SYN was acked? |
|
3091 if (seg.iHdr->ACK() && ack == iSND.NXT) |
|
3092 { |
|
3093 iSND.UNA = ack; |
|
3094 iPartialSeq = ack; |
|
3095 |
|
3096 TUint32 tsEcr; |
|
3097 // Check that the timestamp echo has sane values |
|
3098 if (iFlags.iUseTimeStamps && opt.TimeStamps(iTsRecent, tsEcr) |
|
3099 && tsEcr && usec > tsEcr && usec - tsEcr <= Protocol()->MaxRTO()) |
|
3100 UpdateRTO(usec - tsEcr); |
|
3101 else if (iFlags.iTiming) |
|
3102 UpdateRTO(usec - iTimeStamp); |
|
3103 iFlags.iTiming = EFalse; |
|
3104 |
|
3105 // |
|
3106 // Initial window update as per RFC1122. |
|
3107 // |
|
3108 //LOG(Log::Printf(_L("CProviderTCP6::ProcessSegments(): Window update.\r\n"))); |
|
3109 iSND.WND = seg.iHdr->Window(); // no scaling in SYN |
|
3110 iSND.WL1 = seq; |
|
3111 iSND.WL2 = ack; |
|
3112 iLastWnd = seg.iHdr->Window(); // no scaling in SYN |
|
3113 |
|
3114 ResetCwnd(iSMSS); |
|
3115 iSsthresh = KMaxTInt; |
|
3116 |
|
3117 ClearSYNSettings(); |
|
3118 |
|
3119 // Peer denies ECN with SYN-ACK. |
|
3120 if (!seg.iHdr->ECE()) |
|
3121 { |
|
3122 iFlags.iEcn = EFalse; |
|
3123 } |
|
3124 |
|
3125 ReadDestinationCache(); |
|
3126 |
|
3127 // Open up the window for sender |
|
3128 SendSegment(KTcpCtlACK); |
|
3129 EnterState(ETcpEstablished); |
|
3130 //__ASSERT_DEBUG(iSockFlags.iNotify, User::Panic(_L("notifier"),0)); |
|
3131 // Assert removed. There's a rare case when the stack is unloading. -MikaL |
|
3132 |
|
3133 // if ECN negotiation was succesful, tell IP layer (iface.cpp) that ECT bit can be enabled. |
|
3134 if (iFlags.iEcn) |
|
3135 { |
|
3136 SetEcn(Protocol()->Ecn()); |
|
3137 } |
|
3138 |
|
3139 if (iSockFlags.iNotify) |
|
3140 iSocket->ConnectComplete(); |
|
3141 |
|
3142 // SYN uses one slot in sequence number space. Account for it before processing data. |
|
3143 ++seq; |
|
3144 |
|
3145 goto process_data; |
|
3146 } |
|
3147 |
|
3148 // |
|
3149 // Simultaneous open, send SYN+ACK |
|
3150 // |
|
3151 --iSND.NXT; |
|
3152 |
|
3153 // Peer denies ECN in SYN |
|
3154 if (!seg.iHdr->ECE() || !seg.iHdr->CWR()) |
|
3155 { |
|
3156 iFlags.iEcn = EFalse; |
|
3157 } |
|
3158 |
|
3159 TUint8 flags = KTcpCtlSYN|KTcpCtlACK; |
|
3160 if (iFlags.iEcn) |
|
3161 { |
|
3162 flags |= KTcpCtlECE; |
|
3163 } |
|
3164 SendSegment(flags); |
|
3165 EnterState(ETcpSynReceived); |
|
3166 // |
|
3167 // According to RFC793 we should queue any additional data |
|
3168 // and controls (e.g. URG) for processing once the established |
|
3169 // state has been reached. |
|
3170 // |
|
3171 // No current TCP implementations actually do this (aside from |
|
3172 // T/TCP), because of its vulnerability to DoS attacks. In any |
|
3173 // case, we're compatible with a peer that wants to send data with |
|
3174 // the SYN packet, since the peer will retransmit the data after |
|
3175 // we only ack the SYN. |
|
3176 // |
|
3177 goto accept; |
|
3178 } |
|
3179 |
|
3180 if (!InState(ETcpSynReceived|ETcpEstablished|ETcpFinWait1|ETcpFinWait2| |
|
3181 ETcpCloseWait|ETcpClosing|ETcpLastAck|ETcpTimeWait)) |
|
3182 { |
|
3183 if (InState(ETcpClosed)) |
|
3184 { |
|
3185 // We have extra segments after entering CLOSED state. Send RST. |
|
3186 if (seg.iHdr->ACK()) |
|
3187 SendReset(ack, info->iDstAddr, info->iSrcAddr); |
|
3188 else |
|
3189 SendResetNoSync(seq+len, info->iDstAddr, info->iSrcAddr); |
|
3190 } |
|
3191 goto wrapup; |
|
3192 } |
|
3193 |
|
3194 /* |
|
3195 Four cases From RFC793 to test in order to determine whether |
|
3196 an arriving segment is acceptable: |
|
3197 |
|
3198 Segment Receive Test |
|
3199 Length Window |
|
3200 ------- ------- ------------------------------------------- |
|
3201 0 0 SEG.SEQ = RCV.NXT |
|
3202 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND |
|
3203 >0 0 not acceptable |
|
3204 >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND |
|
3205 or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND |
|
3206 |
|
3207 We transform these into two basic tests, both of which must evaluate |
|
3208 true in order to DISCARD a segment. The first test clears the majority |
|
3209 of segments that are correctly within receive window. The second test |
|
3210 clears special cases where receive window is zero or the incoming segment |
|
3211 is only partially within receive window. |
|
3212 |
|
3213 Note that we accept a segment that is straddling iRCV.NXT even if |
|
3214 the receive window is zero. In this case the segment is discarded |
|
3215 later during data segment processing. |
|
3216 */ |
|
3217 |
|
3218 // Eliminate earlier DSACK blocks. One duplicate segment can be reported only once. |
|
3219 if (iFlags.iSackOk && Protocol()->DSack()) |
|
3220 iOptions.SackBlocks().Prune(iRCV.NXT); |
|
3221 |
|
3222 if (InState(ETcpSynReceived)) |
|
3223 { |
|
3224 // In case of simultanous connections TCP retransmits SYN with initial sequence |
|
3225 // number when it gets incoming SYN in SYN_SENT state |
|
3226 // (it acks received SYN+1 in that case). |
|
3227 // Since RCV.NXT is increased after receiving the first SYN, the SYN retransmission |
|
3228 // would appear as out-of-order segment, in which case it would be ignored and the TCP |
|
3229 // session would never get to ESTABLISHED state. |
|
3230 // |
|
3231 // This adjustment is meant to avoid the above problem while causing minimal compromise |
|
3232 // to TCP sequence number check safety. |
|
3233 rcvNxt = iRCV.NXT - 1; |
|
3234 } |
|
3235 |
|
3236 // if ((seq < iRCV.NXT || seq >= iRCV.NXT + iRCV.WND) && // 1st test |
|
3237 // ((iRCV.WND > 0) ? (seq + len <= iRCV.NXT) : (len > 0 || seq > iRCV.NXT))) // 2nd test |
|
3238 // PeLu: The above test passed case where seq > nxt+wnd |
|
3239 if ((seq < rcvNxt || seq >= iRCV.NXT + iRCV.WND) && // 1st test |
|
3240 ((iRCV.WND > 0) ? ((len > 0) ? (seq+len <= iRCV.NXT) || (seq+len > iRCV.NXT + iRCV.WND) : 1) |
|
3241 : ((len > 0) ? 1 : (seq.Outside(rcvNxt, iRCV.NXT))))) |
|
3242 { |
|
3243 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Segment out of window"), (TInt)this)); |
|
3244 if (!seg.iHdr->RST()) |
|
3245 { |
|
3246 // if receiving data partially below RCV.NXT, |
|
3247 // generate DSACK only for the duplicate portion |
|
3248 if (iFlags.iSackOk && Protocol()->DSack() && seq < iRCV.NXT && len > 0) |
|
3249 { |
|
3250 if (seq + len <= iRCV.NXT) |
|
3251 { |
|
3252 iOptions.SackBlocks().AddUnordered(seq, seq + len); |
|
3253 } |
|
3254 else |
|
3255 { |
|
3256 iOptions.SackBlocks().AddUnordered(seq, iRCV.NXT); |
|
3257 } |
|
3258 iOptions.SackBlocks().Limit(4); |
|
3259 } |
|
3260 SendSegment(KTcpCtlACK); |
|
3261 } |
|
3262 if (InState(ETcpTimeWait|ETcpFinWait2)) |
|
3263 SchedMsl2Wait(); |
|
3264 // Accept RST segments that fit within the last advertised window. |
|
3265 if (seg.iHdr->RST() && !seq.Outside(iLastAck, iLastAck + iRCV.WND)) |
|
3266 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Lagged RST"), (TInt)this)); |
|
3267 else if (iRCV.WND > 0 || iRCV.NXT.Outside(seq, seq+len)) |
|
3268 goto discard; |
|
3269 } |
|
3270 |
|
3271 if (seg.iHdr->RST()) |
|
3272 { |
|
3273 // Ignore RST in TIME-WAIT state to prevent TIME-WAIT assassination |
|
3274 if (InState(ETcpTimeWait)) |
|
3275 goto discard; |
|
3276 |
|
3277 // Stop processing and enter CLOSED state |
|
3278 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): RST packet"), (TInt)this)); |
|
3279 Error(KErrDisconnected); |
|
3280 EnterState(ETcpClosed); |
|
3281 goto wrapup; |
|
3282 } |
|
3283 |
|
3284 if (seg.iHdr->SYN() && seq >= iRCV.NXT) |
|
3285 { |
|
3286 /* If the SYN is in the window it is an error, send a reset, any |
|
3287 outstanding RECEIVEs and SEND should receive "reset" responses, |
|
3288 all segment queues should be flushed, the user should also |
|
3289 receive an unsolicited general "connection reset" signal, enter |
|
3290 the CLOSED state, delete the TCB, and return. |
|
3291 |
|
3292 Note: the extra test against RCV.NXT is there to let through a SYN-ACK |
|
3293 with the sequence number RCV.NXT-1. This may happen in a simultaneous |
|
3294 connect case, where the SYN-ACK packet is retransmitted. The SYN-ACK |
|
3295 will be hanled below as part of SYN-RECEIVED state processing. |
|
3296 |
|
3297 Otherwise, if the SYN is not in the window this step would not be |
|
3298 reached and an ack would have been sent in the first step (sequence |
|
3299 number check). |
|
3300 */ |
|
3301 SendReset(iSND.NXT); |
|
3302 Error(KErrDisconnected); |
|
3303 EnterState(ETcpClosed); |
|
3304 goto wrapup; |
|
3305 } |
|
3306 |
|
3307 |
|
3308 // |
|
3309 // ACK PROCESSING |
|
3310 // |
|
3311 if (!seg.iHdr->ACK()) |
|
3312 { |
|
3313 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): No ACK"), (TInt)this)); |
|
3314 goto discard; |
|
3315 } |
|
3316 |
|
3317 // Check options |
|
3318 if (opt.Error()) |
|
3319 { |
|
3320 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Invalid options"), (TInt)this)); |
|
3321 SendReset(ack); |
|
3322 goto discard; |
|
3323 } |
|
3324 |
|
3325 if (InState(ETcpSynReceived)) |
|
3326 if(ack.Inside(iSND.UNA, iSND.NXT)) |
|
3327 { |
|
3328 EnterState(ETcpEstablished); |
|
3329 |
|
3330 const TInt ifup = iFlags.iKeepInterfaceUp; |
|
3331 SetOption(KSolInetIp, KSoKeepInterfaceUp, TPtr8((TUint8*)&ifup, sizeof(TInt), sizeof(TInt))); |
|
3332 |
|
3333 // if ECN negotiation was succesful, tell IP layer that ECT bit can be enabled. |
|
3334 if (iFlags.iEcn) |
|
3335 { |
|
3336 SetEcn(Protocol()->Ecn()); |
|
3337 } |
|
3338 |
|
3339 // |
|
3340 // Initial window update as per RFC1122. |
|
3341 // |
|
3342 //LOG(Log::Printf(_L("CProviderTCP6::ProcessSegments(): Window update.\r\n"))); |
|
3343 iSND.WND = seg.iHdr->Window() << iSndWscale; |
|
3344 iSND.WL1 = seq; |
|
3345 iSND.WL2 = ack; |
|
3346 iLastWnd = seg.iHdr->Window() << iSndWscale; |
|
3347 |
|
3348 ResetCwnd(iSMSS); |
|
3349 iCwnd -= iSMSS; // Compensate for cwnd increase below during ack processing |
|
3350 iSsthresh = KMaxTInt; |
|
3351 |
|
3352 ClearSYNSettings(); |
|
3353 |
|
3354 ReadDestinationCache(); |
|
3355 |
|
3356 // The following causes the socket server to (eventually) call Start() |
|
3357 if (iParent) |
|
3358 { |
|
3359 iSockFlags.iAttached = ETrue; |
|
3360 ASSERT(iParent->iSockFlags.iNotify); |
|
3361 if (iParent->CompleteChildConnect(this) == KErrAbort) |
|
3362 { |
|
3363 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): SAP Deleted, abort ProcessSegments()"), (TInt)this)); |
|
3364 // Object in use was deleted. Just free the packet and return. |
|
3365 packet.Free(); |
|
3366 return; |
|
3367 } |
|
3368 } |
|
3369 else |
|
3370 { |
|
3371 //__ASSERT_DEBUG(iSockFlags.iNotify, User::Panic(_L("notifier"), 0)); |
|
3372 // Assert removed. There's a rare case when the stack is unloading. -MikaL |
|
3373 if (iSockFlags.iNotify) |
|
3374 iSocket->ConnectComplete(); |
|
3375 } |
|
3376 } |
|
3377 else |
|
3378 { |
|
3379 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Bad SYN-ACK"), (TInt)this)); |
|
3380 SendReset(ack); |
|
3381 goto discard; |
|
3382 } |
|
3383 |
|
3384 // |
|
3385 // Check ack sequence for all remaining states |
|
3386 // |
|
3387 if(ack > iSND.NXT) |
|
3388 { |
|
3389 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): ACK above window"), (TInt)this)); |
|
3390 SendSegment(KTcpCtlACK); |
|
3391 goto discard; |
|
3392 } |
|
3393 |
|
3394 // A good packet arrived and the connection is idle, reset the keep-alives state |
|
3395 if (CanFireKeepAlives()) |
|
3396 ResetKeepAlives(); |
|
3397 |
|
3398 // Check for ECN congestion established bit. |
|
3399 if (info->iVersion == 4) |
|
3400 { |
|
3401 if (iFlags.iEcn && ip->ip4.EcnIsCongestion()) |
|
3402 { |
|
3403 iFlags.iEcnHaveCongestion = ETrue; |
|
3404 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Have ECN CE bit in IPv4 packet"), (TInt)this)); |
|
3405 } |
|
3406 } |
|
3407 else |
|
3408 { |
|
3409 if (iFlags.iEcn && ip->ip6.EcnIsCongestion()) |
|
3410 { |
|
3411 iFlags.iEcnHaveCongestion = ETrue; |
|
3412 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Have ECN CE bit in IPv6 packet"), (TInt)this)); |
|
3413 } |
|
3414 } |
|
3415 |
|
3416 if (InState(ETcpEstablished|ETcpFinWait1|ETcpFinWait2|ETcpCloseWait|ETcpClosing|ETcpLastAck)) |
|
3417 { |
|
3418 TInt acked = ack - iSND.UNA; |
|
3419 |
|
3420 if (acked >= 0) |
|
3421 { |
|
3422 // ECN CWR means that receiver has noticed our Congestion Echo. No more congestion. |
|
3423 if (seg.iHdr->CWR()) |
|
3424 { |
|
3425 iFlags.iEcnHaveCongestion = EFalse; |
|
3426 } |
|
3427 |
|
3428 if (iFlags.iUseTimeStamps) |
|
3429 { |
|
3430 TUint32 tsVal, tsEcr; |
|
3431 // Check that tsEcr has sane values |
|
3432 if (opt.TimeStamps(tsVal, tsEcr) && tsEcr && usec - tsEcr <= KTcpMaxRTO) |
|
3433 { |
|
3434 if (acked > 0) |
|
3435 { |
|
3436 UpdateRTO(usec - tsEcr); |
|
3437 |
|
3438 // Got one RTT with timestamps. Don't take another. |
|
3439 if (iFlags.iTiming && ack >= iTimingSeq) |
|
3440 iFlags.iTiming = EFalse; |
|
3441 |
|
3442 // |
|
3443 // Delay spike detection. If the echoed timestamp predates |
|
3444 // our last retransmission timeout we abort the retransmission |
|
3445 // sequence. However, we do not inflate the congestion window |
|
3446 // for two reasons: 1) a long delay might also be a sign of |
|
3447 // congestion, and 2) this feature could potentially be used |
|
3448 // by a hostile peer to artificially inflate our congestion |
|
3449 // window. |
|
3450 // |
|
3451 // PS: Delay spike detection with timestamps is not in use with F-RTO |
|
3452 if (!Protocol()->FRTO() && tsEcr < iLastTimeout && |
|
3453 !opt.SackBlocks().Count()) |
|
3454 { |
|
3455 iTransmitSeq = iSND.NXT; |
|
3456 SpuriousTimeout(acked); |
|
3457 } |
|
3458 } |
|
3459 |
|
3460 // |
|
3461 // The condition in RFC1323 is buggy(?): |
|
3462 // |
|
3463 // SEG.SEQ <= Last.ACK.sent < SEG.SEQ + SEG.LEN |
|
3464 // |
|
3465 // The best current practise is the following, because it updates |
|
3466 // TSrecent also on pure ACKs: |
|
3467 // |
|
3468 // SEG.TSval >= TSrecent and SEG.SEQ <= Last.ACK.sent |
|
3469 // |
|
3470 if (tsVal > iTsRecent && seq <= iLastAck) |
|
3471 iTsRecent = tsVal; |
|
3472 } |
|
3473 } |
|
3474 if (iFlags.iTiming && ack >= iTimingSeq) |
|
3475 { |
|
3476 UpdateRTO(usec - iTimeStamp); |
|
3477 iFlags.iTiming = EFalse; |
|
3478 } |
|
3479 |
|
3480 // SACK book keeping |
|
3481 if (iFlags.iSackOk) |
|
3482 { |
|
3483 // Remove acknowledged blocks |
|
3484 if (opt.SackBlocks().Count()) |
|
3485 { |
|
3486 SequenceBlockQueueIter iter(opt.SackBlocks()); |
|
3487 SequenceBlock *block; |
|
3488 while (block = iter++, block != NULL) |
|
3489 { |
|
3490 // |
|
3491 // Record SACK block but do some sanity checking first. |
|
3492 // |
|
3493 if (ack < block->iLeft && block->iLeft < block->iRight |
|
3494 && block->iRight <= iSND.NXT) |
|
3495 { |
|
3496 iSacked.AddOrdered(block); |
|
3497 } |
|
3498 } |
|
3499 |
|
3500 // Take RTT estimate using SACK info |
|
3501 if (iFlags.iTiming && iSacked.Count() && iSacked.Last()->iRight >= iTimingSeq) |
|
3502 { |
|
3503 UpdateRTO(usec - iTimeStamp); |
|
3504 iFlags.iTiming = EFalse; |
|
3505 } |
|
3506 } |
|
3507 iSacked.Prune(ack); |
|
3508 |
|
3509 // Update iRetranData |
|
3510 if (iSacked.Count() && ack < iSendHigh) |
|
3511 { |
|
3512 iRetranData = iSendHigh - ack; |
|
3513 SequenceBlockQueueIter iter(opt.SackBlocks()); |
|
3514 SequenceBlock *block; |
|
3515 while (block = iter++, block != NULL && block->iLeft < iSendHigh) |
|
3516 { |
|
3517 if (block->iRight < iSendHigh) |
|
3518 iRetranData -= (block->iRight - block->iLeft); |
|
3519 else |
|
3520 iRetranData -= (iSendHigh - block->iLeft); |
|
3521 } |
|
3522 } |
|
3523 else |
|
3524 iRetranData = 0; |
|
3525 |
|
3526 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): acked=%d iRetranData = %d"), |
|
3527 (TInt)this, acked, iRetranData)); |
|
3528 } |
|
3529 |
|
3530 // Did they acknowledge any new data? |
|
3531 if (acked > 0) |
|
3532 { |
|
3533 // Reset retransmit backoff |
|
3534 if (iBackoff && iSND.WND > 0) |
|
3535 { |
|
3536 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Some data ACKed, clearing Backoff"), (TInt)this)); |
|
3537 iBackoff = 0; |
|
3538 } |
|
3539 |
|
3540 // Trim send queue |
|
3541 iSND.UNA = ack; |
|
3542 if ((TInt)iSockOutQLen > acked) // Avoid barfing on acked SYN or FIN packet |
|
3543 { |
|
3544 iSockOutQ.TrimStart(acked); |
|
3545 iSockOutQLen -= acked; |
|
3546 } |
|
3547 else |
|
3548 { |
|
3549 iSockOutQ.Free(); |
|
3550 iSockOutQLen = 0; |
|
3551 CompleteIoctl(KErrNone); |
|
3552 } |
|
3553 |
|
3554 // Tag along |
|
3555 if (iSND.UP < ack) |
|
3556 iSND.UP = ack - 1; |
|
3557 |
|
3558 // Tag along |
|
3559 if (iPartialSeq < ack) |
|
3560 iPartialSeq = ack; |
|
3561 |
|
3562 // Tag along |
|
3563 if (iSendHigh < ack) |
|
3564 iSendHigh = ack - 1; |
|
3565 |
|
3566 if (iFlags.iFastRetransMode) |
|
3567 { |
|
3568 if (iFlags.iSackOk ? !iSacked.Count() : ack >= iRecoverSeq) |
|
3569 { |
|
3570 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Leaving FAST RETRANS mode"), (TInt)this)); |
|
3571 iFlags.iFastRetransMode = EFalse; |
|
3572 iDupAcks = 0; |
|
3573 // Deflate congestion window |
|
3574 iCwnd = Min(iSsthresh, iSND.NXT - iSND.UNA + iSMSS); |
|
3575 } |
|
3576 else if (!iFlags.iSackOk) |
|
3577 { |
|
3578 // NewReno partial ACK processing. |
|
3579 |
|
3580 /* From RFC2582: |
|
3581 If this ACK does *not* acknowledge all of the data up to and |
|
3582 including "recover", then this is a partial ACK. In this case, |
|
3583 retransmit the first unacknowledged segment. Deflate the |
|
3584 congestion window by the amount of new data acknowledged, then |
|
3585 add back one MSS and send a new segment if permitted by the new |
|
3586 value of cwnd. This "partial window deflation" attempts to |
|
3587 ensure that, when Fast Recovery eventually ends, approximately |
|
3588 ssthresh amount of data will be outstanding in the network. Do |
|
3589 not exit the Fast Recovery procedure (i.e., if any duplicate ACKs |
|
3590 subsequently arrive, execute Steps 3 and 4 above). |
|
3591 |
|
3592 For the first partial ACK that arrives during Fast Recovery, also |
|
3593 reset the retransmit timer. |
|
3594 */ |
|
3595 |
|
3596 iCwnd -= acked; |
|
3597 iCwnd += iSMSS; |
|
3598 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): FAST RETRANSMIT on PARTIAL ACK"), (TInt)this)); |
|
3599 SendDataSegment(ack); |
|
3600 |
|
3601 // |
|
3602 // Socket write makes use of the duplicate ack count to |
|
3603 // temporarily extend the send buffer during fast recovery. |
|
3604 // We deflate the buffer here. |
|
3605 // |
|
3606 ASSERT(iSMSS); |
|
3607 iDupAcks = Max(iDupAcks - acked / (TInt)iSMSS, 0); |
|
3608 } |
|
3609 } |
|
3610 |
|
3611 // Reset limited transmit window |
|
3612 iLwnd = 0; |
|
3613 |
|
3614 // Everything acked? |
|
3615 if (ack == iSND.NXT) |
|
3616 { |
|
3617 iTransmitSeq = iSND.NXT; |
|
3618 } |
|
3619 else |
|
3620 { |
|
3621 // Restart retransmission timeout |
|
3622 ReSchedRetransmit(); |
|
3623 } |
|
3624 |
|
3625 // |
|
3626 // Adjust congestion window. |
|
3627 // |
|
3628 TUint incr = iSMSS; |
|
3629 |
|
3630 if (iCwnd < iSsthresh) |
|
3631 iCwnd += incr; // Slow-start |
|
3632 else |
|
3633 iCwnd += Max(incr * incr / iCwnd, 1); // Congestion avoidance |
|
3634 } |
|
3635 |
|
3636 else if (ack < iSND.NXT) |
|
3637 |
|
3638 { |
|
3639 // |
|
3640 // Fast retransmit algorithm. |
|
3641 // |
|
3642 // Note! We only reset the duplicate ack count if the received |
|
3643 // segment acknowledges some new data or if a timeout has |
|
3644 // occurred. However, we simply ignore window updates and piggy-back |
|
3645 // acknowledgements unless they also acknowledge new data. Other |
|
3646 // duplicate acknowledgements increase the duplicate ack count and |
|
3647 // may trigger a fast retransmission. |
|
3648 // |
|
3649 if (len == 0 && (seg.iHdr->Window() << iSndWscale) == iLastWnd) |
|
3650 { |
|
3651 if (iFlags.iSackOk) |
|
3652 { |
|
3653 TTcpSeqNum fack = iSacked.Count() ? iSacked.Last()->iRight : iSND.UNA; |
|
3654 |
|
3655 // Acks caused by out-of-window segments don't count |
|
3656 if (opt.SackBlocks().Count() && opt.SackBlocks().First()->iRight > iSND.UNA) |
|
3657 iDupAcks++; |
|
3658 |
|
3659 //Removed the conditional checking ack > iSendHigh as it is only being used for if SACK option is not set. |
|
3660 // Set the retransmission mode as the fast retransmit if the three TCP duplicate ACKs are received from the server and |
|
3661 //send the lost segment(s) to the server. |
|
3662 if ( |
|
3663 (iDupAcks >= Protocol()->Reordering() || |
|
3664 fack > iSND.UNA + Protocol()->Reordering() * iRMSS)) |
|
3665 { |
|
3666 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): SACK RETRANSMIT!"), (TInt)this)); |
|
3667 iFlags.iFastRetransMode = ETrue; |
|
3668 iSsthresh = Max((iSND.NXT - iSND.UNA) / 2, 2 * iSMSS); |
|
3669 iCwnd = iSsthresh; |
|
3670 iSendHigh = ack; |
|
3671 ReSchedRetransmit(); // Restart retransmission timeout |
|
3672 iTransmitSeq = iSendHigh; // Rewind transmitter for SACK retransmit |
|
3673 SendSegments(ETrue); |
|
3674 iDupAcks = 0; |
|
3675 |
|
3676 } |
|
3677 } |
|
3678 else |
|
3679 { |
|
3680 if (ack > iSendHigh) // Never retransmitted? |
|
3681 iDupAcks++; |
|
3682 if (iFlags.iFastRetransMode) |
|
3683 { |
|
3684 iCwnd += iSMSS; // Inflate congestion window |
|
3685 } |
|
3686 else if (iDupAcks == Protocol()->Reordering()) |
|
3687 { |
|
3688 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): FAST RETRANSMIT!"), (TInt)this)); |
|
3689 iFlags.iFastRetransMode = ETrue; |
|
3690 iSsthresh = Max((iSND.NXT - iSND.UNA) / 2, 2 * iSMSS); |
|
3691 iCwnd = iSsthresh + 3 * iSMSS; |
|
3692 iRecoverSeq = iSND.NXT; |
|
3693 iLwnd = 0; // Reset limited transmit window |
|
3694 ReSchedRetransmit(); // Restart retransmission timeout |
|
3695 SendDataSegment(ack); // Retransmit a single segment |
|
3696 } |
|
3697 } |
|
3698 if (!iFlags.iFastRetransMode) |
|
3699 { |
|
3700 // |
|
3701 // Increment limited transmit window |
|
3702 // |
|
3703 if (iSND.UNA + iCwnd >= iSND.NXT) // FIXME. Prevent lwnd increase during RTO |
|
3704 iLwnd = Min(iLwnd + iSMSS, iSMSS * Protocol()->LtxWindow()); |
|
3705 ReSchedRetransmit(); |
|
3706 } |
|
3707 } |
|
3708 |
|
3709 } |
|
3710 else |
|
3711 iDupAcks = 0; |
|
3712 |
|
3713 // F-RTO stuff. If we enter here, RTO has just occurred, and e.g. iDupAcks should be 0 |
|
3714 if (iFRTOsent) |
|
3715 { |
|
3716 LOG(Log::Printf(_L("\ttcp SAP[%u] F-RTO: iFRTOsent=%d acked=%d ack-sndhigh=%d"), |
|
3717 (TInt)this, iFRTOsent, acked, (ack - iSendHigh))); |
|
3718 |
|
3719 // The ack following the RTO did not advance window, or we cannot transmit new |
|
3720 // unsent data => conventional recovery |
|
3721 // |
|
3722 // The last term of the condition below is due to special case: |
|
3723 // If the first ack after RTO covers all outstanding data, the RTO was due |
|
3724 // to lost retransmit and fixed the whole outstanding window). |
|
3725 if (!acked || !CanForwardTransmit() || (ack >= iRealSendHigh && iFRTOsent == 1)) |
|
3726 { |
|
3727 |
|
3728 LOG(Log::Printf(_L("\ttcp SAP[%u] F-RTO: Doing go-back-N"), (TInt)this)); |
|
3729 iTransmitSeq = iSND.UNA; |
|
3730 if (iFRTOsent == 1 && !acked) |
|
3731 { |
|
3732 // dupack arrives before RTO retransmission is acknowledged. |
|
3733 // don't retransmit the same segment again. |
|
3734 iTransmitSeq += EffectiveMSS(); |
|
3735 } |
|
3736 iCwnd = EffectiveMSS() * iFRTOsent; // number of RTTs after RTO |
|
3737 iFRTOsent = 0; |
|
3738 } |
|
3739 else |
|
3740 { |
|
3741 // Force 2 segments out on first ack after RTO. For that purpose we have to |
|
3742 // estimate the current flightsize (-> iCwnd) and set iLwnd to 2. |
|
3743 // Note that after this step iCwnd is set either to 2*MSS or iSsthresh, so |
|
3744 // the setup below is very temporary. |
|
3745 if (iFRTOsent == 1) // first new ACK after RTO |
|
3746 { |
|
3747 iCwnd = iSND.NXT - iSND.UNA - iSacked.ByteCount() + 2 * iSMSS; |
|
3748 } |
|
3749 else if (iFRTOsent == 2) |
|
3750 { |
|
3751 // Spurious RTO. |
|
3752 // second new ACK after RTO, continue in earlier state because the second |
|
3753 // ACK was delayed and the RTO was likely spurious. |
|
3754 SpuriousTimeout(acked); |
|
3755 } |
|
3756 // coverity[write_write_order] |
|
3757 iFRTOsent = (++iFRTOsent) % 3; |
|
3758 } |
|
3759 } |
|
3760 |
|
3761 iLastWnd = seg.iHdr->Window() << iSndWscale; |
|
3762 |
|
3763 if (iSND.WL1 < seq || (iSND.WL1 == seq && iSND.WL2 <= ack)) |
|
3764 { |
|
3765 iSND.WND = seg.iHdr->Window() << iSndWscale; |
|
3766 iSND.WL1 = seq; |
|
3767 iSND.WL2 = ack; |
|
3768 //LOG(Log::Printf(_L("CProviderTCP6::ProcessSegments(): Window update: %d.\r\n"), iSND.WND)); |
|
3769 } |
|
3770 |
|
3771 // if we are not yet in recovery, reduce congestion window on ECN CE Echo. |
|
3772 if (iFlags.iEcn && seg.iHdr->ECE()) |
|
3773 { |
|
3774 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Got ECN echo"), (TInt)this)); |
|
3775 |
|
3776 // SourceQuench returns False, if congestion window was reduced for some other |
|
3777 // reason in the last RTT. However, if it was reduced due to FR |
|
3778 // (i.e. last QuenchSeq was more than one RTT ago), we better send CWR to suppress |
|
3779 // ECE flags at the other end. |
|
3780 if (SourceQuench() || iQuenchSeq.Outside(iSND.NXT, iSND.NXT + iSND.WND)) |
|
3781 { |
|
3782 iFlags.iEcnSendCWR = ETrue; |
|
3783 } |
|
3784 } |
|
3785 if((iSND.NXT - ack) >0 && InState(ETcpEstablished) && (acked ==0)) |
|
3786 { |
|
3787 iRetryAck++; |
|
3788 if(iRetryAck >=4) // 4 an arbitary number; as this count does not refer to dup_ack, this will not interfere with Fast retransmission |
|
3789 { |
|
3790 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): retransmitting the segment"), (TInt)this)); |
|
3791 SendSegments(ETrue); |
|
3792 iRetryAck = 0; // reset the retry count |
|
3793 } |
|
3794 } |
|
3795 |
|
3796 } |
|
3797 } |
|
3798 |
|
3799 // |
|
3800 // Everything acked? Check if we need to do a state transition. |
|
3801 // |
|
3802 if (ack == iSND.NXT) |
|
3803 { |
|
3804 if (InState(ETcpFinWait1)) |
|
3805 { |
|
3806 EnterState(ETcpFinWait2); |
|
3807 |
|
3808 // |
|
3809 // If the peer does not send a FIN for some reason, |
|
3810 // we might hang in FIN-WAIT-2 indefinitely. We use |
|
3811 // a 2*MSL timeout to break out of FIN-WAIT-2. |
|
3812 // |
|
3813 // Note that we can only do this if the application |
|
3814 // has closed both directions of the connection. |
|
3815 // However, this should take care of cleanup in the |
|
3816 // the most common case where a server socket hangs |
|
3817 // in FIN-WAIT-2, because the client has crashed or |
|
3818 // disappeared before sending a FIN-ACK. |
|
3819 // |
|
3820 if (iSockFlags.iRecvClose) |
|
3821 { |
|
3822 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Setting FIN-WAIT-2 timeout"), (TInt)this)); |
|
3823 SchedMsl2Wait(); |
|
3824 } |
|
3825 } |
|
3826 |
|
3827 // |
|
3828 // If we have a lingering Close() or Shutdown(ENormal), complete it with KErrNone. |
|
3829 // |
|
3830 if (iLinger > 0 && InState(ETcpFinWait2|ETcpClosing|ETcpLastAck)) |
|
3831 { |
|
3832 /* |
|
3833 In addition to the processing for the ESTABLISHED state, if |
|
3834 the retransmission queue is empty, the user's CLOSE can be |
|
3835 acknowledged ("ok") but do not delete the TCB.*/ |
|
3836 iLinger = -1; |
|
3837 iLingerTimer->Cancel(); |
|
3838 Detach(); |
|
3839 } |
|
3840 |
|
3841 if (InState(ETcpClosing)) |
|
3842 { |
|
3843 EnterState(ETcpTimeWait); |
|
3844 } |
|
3845 |
|
3846 if (InState(ETcpLastAck)) |
|
3847 { |
|
3848 if (!Protocol()->LocalTimeWait()) |
|
3849 { |
|
3850 // |
|
3851 // Local resource optimization. If the peer is on localhost, |
|
3852 // we will terminate it here. Normally, it would wait for |
|
3853 // a duration of 2*MSL in TIME-WAIT state before deleting |
|
3854 // itself. |
|
3855 // |
|
3856 CFlowContext *flow = iFlow.FlowContext(); |
|
3857 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
3858 CProviderTCP6 *sap = |
|
3859 (CProviderTCP6*)Protocol()->LocateSap(EMatchConnection, |
|
3860 KAFUnspec, |
|
3861 flow->RemoteAddr(), |
|
3862 flow->LocalAddr()); |
|
3863 #else |
|
3864 CProviderTCP6 *sap = |
|
3865 (CProviderTCP6*)Protocol()->LocateSap(EMatchConnection, |
|
3866 KAFUnspec, |
|
3867 flow->RemoteAddr(), |
|
3868 flow->LocalAddr(), |
|
3869 NULL, info->iInterfaceIndex); |
|
3870 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
3871 if (sap != NULL && sap->InState(ETcpTimeWait)) |
|
3872 { |
|
3873 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Deleting local peer"), (TInt)this)); |
|
3874 sap->Expire(); |
|
3875 } |
|
3876 } |
|
3877 /* |
|
3878 The only thing that can arrive in this state is an |
|
3879 acknowledgment of our FIN. If our FIN is now acknowledged, |
|
3880 delete the TCB, enter the CLOSED state, and return.*/ |
|
3881 EnterState(ETcpClosed); |
|
3882 goto wrapup; |
|
3883 } |
|
3884 } |
|
3885 |
|
3886 if (InState(ETcpTimeWait)) |
|
3887 { |
|
3888 /* |
|
3889 The only thing that can arrive in this state is a |
|
3890 retransmission of the remote FIN. Acknowledge it, and restart |
|
3891 the 2 MSL timeout.*/ |
|
3892 // |
|
3893 // RFC793 appears to be wrong here. A retransmitted FIN should |
|
3894 // already have been acknowledged as an out-of-sequence packet. |
|
3895 // Also, a simultaneous close can cause both end points to send |
|
3896 // an ack and enter the TIME-WAIT state at the same time. In this |
|
3897 // rare case, the following line will cause an ack storm, where |
|
3898 // each side is acknowledging ack packets from the other side. |
|
3899 // |
|
3900 //SendSegment(KTcpCtlACK); |
|
3901 SchedMsl2Wait(); |
|
3902 } |
|
3903 |
|
3904 process_data: |
|
3905 |
|
3906 // |
|
3907 // DATA SEGMENT PROCESSING |
|
3908 // |
|
3909 if (InState(ETcpEstablished|ETcpFinWait1|ETcpFinWait2)) |
|
3910 { |
|
3911 if (seg.iHdr->URG()) |
|
3912 { |
|
3913 TTcpSeqNum up = seq + seg.iHdr->Urgent(); |
|
3914 /* |
|
3915 If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal |
|
3916 the user that the remote side has urgent data if the urgent |
|
3917 pointer (RCV.UP) is in advance of the data consumed. If the |
|
3918 user has already been signaled (or is still in the "urgent |
|
3919 mode") for this continuous sequence of urgent data, do not |
|
3920 signal the user again.*/ |
|
3921 if (up > seq) |
|
3922 RememberUrgentPointer(up); |
|
3923 } |
|
3924 |
|
3925 // |
|
3926 // Process data segments. |
|
3927 // |
|
3928 if (len > 0) |
|
3929 { |
|
3930 if (iSockFlags.iRecvClose) |
|
3931 { |
|
3932 // Receive direction has been shut down. Send RST. |
|
3933 SendReset(ack); |
|
3934 } |
|
3935 else |
|
3936 { |
|
3937 // |
|
3938 // Zero window? We will already have sent and ACK in response, |
|
3939 // so we can just discard the segment. |
|
3940 // |
|
3941 if (!iRCV.WND) |
|
3942 goto accept; |
|
3943 |
|
3944 TInt maxLen = iRCV.NXT + iRCV.WND - seq; |
|
3945 if (len > maxLen) |
|
3946 { |
|
3947 // |
|
3948 // Part of segment is above window -> truncate. This |
|
3949 // can happen when peer is probing a zero window. |
|
3950 // |
|
3951 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Above window payload: %u"), (TInt)this, len - maxLen)); |
|
3952 if (maxLen <= 0) // Sanity check |
|
3953 goto accept; |
|
3954 |
|
3955 len = maxLen; |
|
3956 packet.TrimEnd(seg.iHdr->HeaderLength() + info->iOffset + len); |
|
3957 fin = 0; // Cannot process FIN yet. |
|
3958 } |
|
3959 |
|
3960 // Remember to ack a pushed segment immediately |
|
3961 if (seg.iHdr->PSH() && Protocol()->PushAck()) |
|
3962 immediateAck = ETrue; |
|
3963 |
|
3964 if (seq <= iRCV.NXT) |
|
3965 { |
|
3966 // |
|
3967 // WARNING! This will destroy the segment header! |
|
3968 // |
|
3969 LOG(if(seq<iRCV.NXT)Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Below window payload: %d"), (TInt)this, iRCV.NXT - seq)); |
|
3970 |
|
3971 // Remove segment header and below-window payload. |
|
3972 packet.TrimStart(iRCV.NXT - seq + seg.iHdr->HeaderLength() + info->iOffset); |
|
3973 |
|
3974 // Put in receive queue. |
|
3975 iSockInQ.Append(packet); |
|
3976 len -= (iRCV.NXT - seq); |
|
3977 iSockInQLen += len; |
|
3978 iNewData += len; |
|
3979 iRCV.NXT += len; |
|
3980 iRCV.WND -= len; |
|
3981 |
|
3982 // |
|
3983 // Check if we can take something out of the reassembly queue. |
|
3984 // |
|
3985 TTcpSeqNum fragOff; |
|
3986 TBool fastAck = !iFragQ.IsEmpty(); |
|
3987 while (!iFragQ.IsEmpty()) |
|
3988 { |
|
3989 fragOff = iFragQ.First().Offset(); |
|
3990 if (fragOff > iRCV.NXT) |
|
3991 break; |
|
3992 |
|
3993 RMBufTcpFrag frag; |
|
3994 iFragQ.Remove(frag); |
|
3995 TUint32 fragLen = frag.FragmentLength(); |
|
3996 |
|
3997 // Already got this? |
|
3998 if (fragOff + fragLen <= iRCV.NXT) |
|
3999 { |
|
4000 frag.Free(); |
|
4001 continue; |
|
4002 } |
|
4003 |
|
4004 // Ok. Trim it and put it in receive queue. |
|
4005 TTcpPacket seg(frag); |
|
4006 |
|
4007 frag.TrimStart(seg.iHdr->HeaderLength() + (iRCV.NXT - fragOff)); |
|
4008 fragLen -= (iRCV.NXT - fragOff); |
|
4009 |
|
4010 ASSERT(fragLen == (TUint)frag.Length()); |
|
4011 |
|
4012 iSockInQ.Append(frag); |
|
4013 iSockInQLen += fragLen; |
|
4014 iNewData += fragLen; |
|
4015 |
|
4016 ASSERT((TUint)iSockInQLen >= iNewData); |
|
4017 |
|
4018 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Took %d:%d(%d) from reassembly queue"), |
|
4019 (TInt)this, iRCV.NXT.Uint32(), (iRCV.NXT + fragLen).Uint32(), fragLen)); |
|
4020 |
|
4021 iRCV.NXT += fragLen; |
|
4022 iRCV.WND -= fragLen; |
|
4023 |
|
4024 } |
|
4025 // |
|
4026 // Update SACK book keeping |
|
4027 // |
|
4028 if (iFlags.iSackOk) |
|
4029 iOptions.SackBlocks().Prune(iRCV.NXT); |
|
4030 |
|
4031 /* |
|
4032 To provide feedback to senders recovering from losses, the receiver |
|
4033 SHOULD send an immediate ACK when it receives a data segment that |
|
4034 fills in all or part of a gap in the sequence space. */ |
|
4035 if (fastAck) |
|
4036 SendSegment(KTcpCtlACK); |
|
4037 } |
|
4038 else |
|
4039 { |
|
4040 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Processing out-of-order segment!"), (TInt)this)); |
|
4041 TTcpSeqNum blockSeq; |
|
4042 TUint32 blockLen; |
|
4043 |
|
4044 // Fragment queue assumes packet starts from TCP header |
|
4045 packet.TrimStart(info->iOffset); |
|
4046 |
|
4047 //packet.FreeInfo(); -- Leave the info. We need it below. |
|
4048 RMBufTcpFrag frag; |
|
4049 frag.Assign(packet); |
|
4050 iFragQ.Add(frag, (TUint32*)&blockSeq, &blockLen); |
|
4051 if (iFlags.iSackOk) |
|
4052 { |
|
4053 iOptions.SackBlocks().AddUnordered(blockSeq, blockSeq + blockLen); |
|
4054 iOptions.SackBlocks().Limit(4); |
|
4055 } |
|
4056 |
|
4057 /* |
|
4058 Out-of-order data segments SHOULD be acknowledged immediately, in |
|
4059 order to accelerate loss recovery. To trigger the fast retransmit |
|
4060 algorithm, the receiver SHOULD send an immediate duplicate ACK when |
|
4061 it receives a data segment above a gap in the sequence space. */ |
|
4062 SendSegment(KTcpCtlACK); |
|
4063 } |
|
4064 } |
|
4065 } |
|
4066 } |
|
4067 |
|
4068 |
|
4069 // |
|
4070 // FIN PROCESSING |
|
4071 // |
|
4072 |
|
4073 /* |
|
4074 If the FIN bit is set, signal the user "connection closing" and |
|
4075 return any pending RECEIVEs with same message, advance RCV.NXT |
|
4076 over the FIN, and send an acknowledgment for the FIN. Note that |
|
4077 FIN implies PUSH for any segment text not yet delivered to the |
|
4078 user. |
|
4079 */ |
|
4080 // |
|
4081 // Remember that we have received a FIN. Note: the FIN may have |
|
4082 // been received as part of an out-of-sequence segment, in which |
|
4083 // case we may not be ready to process it yet. |
|
4084 // |
|
4085 if (fin && !iFlags.iFinReceived) |
|
4086 { |
|
4087 iFlags.iFinReceived = ETrue; |
|
4088 iFinSeq = seq + len; |
|
4089 } |
|
4090 |
|
4091 // |
|
4092 // Process FIN when all data has been received. |
|
4093 // |
|
4094 if (iFlags.iFinReceived && iRCV.NXT == iFinSeq) |
|
4095 { |
|
4096 // |
|
4097 // Advance iRCV.NXT past the FIN. This also ensures |
|
4098 // that we never end up here again. |
|
4099 // |
|
4100 iRCV.NXT++; |
|
4101 |
|
4102 if (InState(ETcpFinWait1|ETcpFinWait2)) |
|
4103 { |
|
4104 //LOG(Log::Printf(_L("IMMEDIATE FIN ACK\r\n"))); |
|
4105 SendSegment(KTcpCtlACK); |
|
4106 } |
|
4107 else |
|
4108 { |
|
4109 //LOG(Log::Printf(_L("DELAYED FIN ACK\r\n"))); |
|
4110 SendDelayACK(); |
|
4111 } |
|
4112 |
|
4113 /* |
|
4114 SYN-RECEIVED STATE |
|
4115 ESTABLISHED STATE |
|
4116 |
|
4117 Enter the CLOSE-WAIT state. |
|
4118 */ |
|
4119 if (InState(ETcpSynReceived|ETcpEstablished)) |
|
4120 { |
|
4121 EnterState(ETcpCloseWait); |
|
4122 } |
|
4123 |
|
4124 /* |
|
4125 FIN-WAIT-1 STATE |
|
4126 |
|
4127 If our FIN has been ACKed (perhaps in this segment), then |
|
4128 enter TIME-WAIT, start the time-wait timer, turn off the other |
|
4129 timers; otherwise enter the CLOSING state. |
|
4130 */ |
|
4131 if (InState(ETcpFinWait1)) |
|
4132 { |
|
4133 /* |
|
4134 If our FIN has been ACKed (perhaps in this segment), then |
|
4135 enter TIME-WAIT, start the time-wait timer, turn off the other |
|
4136 timers; otherwise enter the CLOSING state.*/ |
|
4137 if (iSND.UNA == iSND.NXT) |
|
4138 { |
|
4139 EnterState(ETcpTimeWait); |
|
4140 SchedMsl2Wait(); |
|
4141 } |
|
4142 else |
|
4143 EnterState(ETcpClosing); |
|
4144 } |
|
4145 |
|
4146 /* |
|
4147 FIN-WAIT-2 STATE |
|
4148 |
|
4149 Enter the TIME-WAIT state. Start the time-wait timer, turn |
|
4150 off the other timers. |
|
4151 */ |
|
4152 if (InState(ETcpFinWait2)) |
|
4153 { |
|
4154 /* |
|
4155 Enter the TIME-WAIT state. Start the time-wait timer, turn |
|
4156 off the other timers.*/ |
|
4157 Stop(); |
|
4158 EnterState(ETcpTimeWait); |
|
4159 SchedMsl2Wait(); |
|
4160 } |
|
4161 |
|
4162 // |
|
4163 // Anything that could arrive in TIME-WAIT is an out-of-window |
|
4164 // segment and should never end up here. |
|
4165 // |
|
4166 #ifdef notdef |
|
4167 /* |
|
4168 TIME-WAIT STATE |
|
4169 |
|
4170 Remain in the TIME-WAIT state. Restart the 2 MSL time-wait |
|
4171 timeout. |
|
4172 */ |
|
4173 if (InState(ETcpTimeWait)) |
|
4174 { |
|
4175 /* |
|
4176 Remain in the TIME-WAIT state. Restart the 2 MSL time-wait |
|
4177 timeout.*/ |
|
4178 SchedMsl2Wait(); |
|
4179 } |
|
4180 #endif |
|
4181 } |
|
4182 |
|
4183 wrapup: |
|
4184 // |
|
4185 // Time to die. |
|
4186 // |
|
4187 if (InState(ETcpClosed) && iRecvQ.IsEmpty()) |
|
4188 { |
|
4189 packet.Free(); |
|
4190 Close(); |
|
4191 Expire(); |
|
4192 return; |
|
4193 } |
|
4194 |
|
4195 accept: |
|
4196 // Reset idle timers |
|
4197 Protocol()->Interfacer()->PacketAccepted(info->iOriginalIndex); |
|
4198 |
|
4199 discard: |
|
4200 packet.Free(); |
|
4201 } |
|
4202 |
|
4203 // Complete application level read. |
|
4204 if (iFlags.iCompleteRecv) |
|
4205 { |
|
4206 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Complete application read"), (TInt)this)); |
|
4207 iFlags.iCompleteRecv = EFalse; |
|
4208 iCopyOutOffset = 0; |
|
4209 if (iSockFlags.iNotify) |
|
4210 iSocket->Error(KErrNone, MSocketNotify::EErrorRecv); |
|
4211 } |
|
4212 |
|
4213 // This may cause an immediate ACK to be sent from within GetData() |
|
4214 if (iNewData) |
|
4215 { |
|
4216 TInt newData = iNewData, up = 0; |
|
4217 |
|
4218 // Adjust for urgent data. |
|
4219 if (iUpCount) |
|
4220 { |
|
4221 // |
|
4222 // Find the offset of an urgent byte following a block of |
|
4223 // non-urgent data. The number of junked (already delivered) |
|
4224 // urgent bytes will be left in <up>. This looks complicated |
|
4225 // but should normally be very quick. |
|
4226 // |
|
4227 newData = iSockInQLen; |
|
4228 for (up = 0; up < iUpCount; up++) |
|
4229 { |
|
4230 TInt offset = UrgentOffset(up); |
|
4231 if (offset > up) |
|
4232 { |
|
4233 newData = Min(offset, iSockInQLen); |
|
4234 break; |
|
4235 } |
|
4236 } |
|
4237 |
|
4238 // We have an undelivered urgent byte within the block. |
|
4239 if (iFlags.iUrgentMode && !iFlags.iOobInline && newData > UrgentOffset()) |
|
4240 newData = UrgentOffset(); |
|
4241 |
|
4242 ASSERT(newData <= (TInt)iSockInQLen); |
|
4243 |
|
4244 // Subtract bytes that have already been advertised to ESock |
|
4245 newData -= (iSockInQLen - iNewData); |
|
4246 |
|
4247 // Subtract out-of-band bytes |
|
4248 if (!iFlags.iOobInline) |
|
4249 newData -= up; |
|
4250 } |
|
4251 |
|
4252 // Do we have something? |
|
4253 if (newData > 0 && iFlags.iStarted && iSockFlags.iNotify) |
|
4254 { |
|
4255 ASSERT(newData + (iFlags.iOobInline ? 0 : up) <= (TInt)iNewData); |
|
4256 iNewData -= newData; |
|
4257 if (!iFlags.iOobInline) |
|
4258 iNewData -= up; |
|
4259 |
|
4260 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): NewData(%d), %d urgent bytes %s, %d bytes not reported"), |
|
4261 (TInt)this, newData, up, iFlags.iOobInline ? _S("inline") : _S("junked"), iNewData)); |
|
4262 iPending += newData; |
|
4263 iSocket->NewData(newData); |
|
4264 } |
|
4265 } |
|
4266 |
|
4267 // Notify urgent data to application |
|
4268 if (iFlags.iNotifyUrgent && iSockFlags.iNotify) |
|
4269 { |
|
4270 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Urgent data notification"), (TInt)this)); |
|
4271 iFlags.iNotifyUrgent = EFalse; |
|
4272 iSocket->Error(KErrUrgentData, 0); |
|
4273 } |
|
4274 |
|
4275 // Notify application that connection has been closed by peer. |
|
4276 if (InState(ETcpCloseWait|ETcpClosing|ETcpTimeWait) && !iFlags.iCloseNotified && !iNewData) |
|
4277 { |
|
4278 iFlags.iCloseNotified = ETrue; |
|
4279 if (iFlags.iStarted && iSockFlags.iNotify && !iSockFlags.iRecvClose) |
|
4280 { |
|
4281 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): Calling NewData(KNewDataEndOfData)"), (TInt)this)); |
|
4282 if(iSocket) |
|
4283 iSocket->NewData(KNewDataEndofData); |
|
4284 } |
|
4285 } |
|
4286 |
|
4287 if (iLastAck < iRCV.NXT) |
|
4288 { |
|
4289 // |
|
4290 // We are required to send an ACK for at least every two full sized |
|
4291 // segments but at most once every full sized segment. |
|
4292 // |
|
4293 // In steady state the following rule will acknowledge every second |
|
4294 // segment regardless of the options in the segments (unless maximum |
|
4295 // segment size is VERY small). However, if we receive segments smaller |
|
4296 // than MSS/2, we will send an ACK roughly once for every full segment |
|
4297 // of received data. This works out pretty good. However, if the |
|
4298 // received segments are significantly smaller, we will start to |
|
4299 // experience stretch ACK problems. This might happen, for instance, |
|
4300 // if peer is using PMTUD and the path is constrained. Currently, we |
|
4301 // ignore the problem. |
|
4302 // |
|
4303 // We ack all pushed segments immediately. This improves performance |
|
4304 // for interactive traffic, since partial segments typically have the |
|
4305 // PSH bit set. |
|
4306 // |
|
4307 if (iLastAck + iRMSS < iRCV.NXT || immediateAck) |
|
4308 SendSegment(KTcpCtlACK); |
|
4309 else |
|
4310 SendDelayACK(); |
|
4311 } |
|
4312 |
|
4313 // Wake up transmitter. |
|
4314 SchedTransmit(); |
|
4315 |
|
4316 // |
|
4317 // Wake up application |
|
4318 // |
|
4319 // Note: We do this even if send window is zero, because |
|
4320 // new data from application will trigger zero window probing. |
|
4321 // |
|
4322 // Note 2: Do not wake up app, if lingering close is pending. |
|
4323 // |
|
4324 if (iSockFlags.iFlowStopped) |
|
4325 { |
|
4326 LOG(Log::Printf(_L("\ttcp SAP[%u] ProcessSegments(): FLOW STARTED"), (TInt)this)); |
|
4327 iSockFlags.iFlowStopped = EFalse; |
|
4328 if (iSocket && iSockFlags.iNotify && (iLinger == -1 || !iSockFlags.iSendClose)) |
|
4329 iSocket->CanSend(); |
|
4330 } |
|
4331 } |
|
4332 |
|
4333 |
|
4334 void CProviderTCP6::SpuriousTimeout(TUint aAcked) |
|
4335 /** |
|
4336 Spurious timeout occurred. |
|
4337 |
|
4338 Sets the congestion control parameters depending on the ini setting "tcp_spurious_rto_recovery". |
|
4339 |
|
4340 @param aAcked Number of bytes acknowledged with the ACK that triggered this method. |
|
4341 */ |
|
4342 { |
|
4343 // TODO: if ACK has ECN-Echo flag, congestion control should not be reverted |
|
4344 LOG(Log::Printf(_L("\ttcp SAP[%u] SpuriousTimeout(%u) ENTER: cwnd: %u ssthresh: %u"), |
|
4345 (TInt)this, aAcked, iCwnd, iSsthresh)); |
|
4346 |
|
4347 switch(Protocol()->SpuriousRtoResponse()) |
|
4348 { |
|
4349 case 1: |
|
4350 default: |
|
4351 // Eifel response (draft uses initial window as burst limit, we use MaxBurst) |
|
4352 // Assume that ssthresh was set to FlightSize / 2 when RTO occurred. |
|
4353 iSsthresh = iSsthresh << 1; |
|
4354 iCwnd = iSND.NXT - iSND.UNA + Min(aAcked, Protocol()->MaxBurst()); |
|
4355 break; |
|
4356 |
|
4357 case 2: |
|
4358 // Half sending rate (ssthresh has been adjusted when RTO occurred) |
|
4359 iCwnd = iSsthresh; |
|
4360 break; |
|
4361 |
|
4362 case 3: |
|
4363 // DCLOR - like behaviour (from earlier draft versions) |
|
4364 iSsthresh = iSsthresh << 1; |
|
4365 iCwnd = 1; |
|
4366 } |
|
4367 LOG(Log::Printf(_L("\ttcp SAP[%u] SpuriousTimeout() EXIT: cwnd: %u ssthresh: %u"), |
|
4368 (TInt)this, iCwnd, iSsthresh)); |
|
4369 // TODO: Do we want to do the RTO adjustment required in Eifel Response draft? Maybe not. -PS |
|
4370 } |
|
4371 |
|
4372 |
|
4373 // |
|
4374 // Initiate a connection by sending the first SYN. |
|
4375 // |
|
4376 // Note: The flow MUST be ready when calling this method. |
|
4377 // |
|
4378 void CProviderTCP6::SendSYN() |
|
4379 { |
|
4380 ASSERT(iState == ETcpConnect); |
|
4381 ASSERT(iFlow.FlowContext() != 0); |
|
4382 |
|
4383 // Initialise send sequence number |
|
4384 iTransmitSeq = iSND.NXT = Protocol()->RandomSequence(); |
|
4385 |
|
4386 if (Protocol()->WinScale() != -1) |
|
4387 { |
|
4388 iRcvWscale = (Protocol()->WinScale() > 0 ? Protocol()->WinScale() - 1 : NeedWindowScale()); |
|
4389 iOptions.SetWindowScale((TUint8)(iRcvWscale + 1)); |
|
4390 } |
|
4391 |
|
4392 iRMSS = Min(LinkRMSS(), iSockInBufSize / 2); |
|
4393 iOptions.SetMSS(iRMSS); |
|
4394 iFreeWindow = Min(iSockInBufSize, 0xffff) % iRMSS; |
|
4395 iRCV.WND = Min(iSockInBufSize, 0xffff) - iFreeWindow; |
|
4396 iSND.UNA = iSND.NXT; |
|
4397 |
|
4398 TUint8 flags = KTcpCtlSYN; |
|
4399 // Start ECN negotiation by setting both ECN bits on in a SYN packet [RFC 3168]. |
|
4400 if (iFlags.iEcn) |
|
4401 { |
|
4402 flags |= KTcpCtlECE | KTcpCtlCWR; |
|
4403 } |
|
4404 |
|
4405 SendSegment(flags); |
|
4406 iTransmitSeq++; |
|
4407 EnterState(ETcpSynSent); |
|
4408 |
|
4409 // Disable on-demand interface setup for this flow |
|
4410 iFlow.FlowContext()->iInfo.iNoInterfaceUp = 1; |
|
4411 |
|
4412 // Lock source address for this flow. It needs to persist over link change events. |
|
4413 iFlow.FlowContext()->iInfo.iLocalSet = 1; |
|
4414 } |
|
4415 |
|
4416 |
|
4417 TInt CProviderTCP6::CreateChild(CProviderTCP6*& aSAP) |
|
4418 { |
|
4419 ASSERT(iConnectCount < iListenQueueSize); |
|
4420 ASSERT(iListenQueue); |
|
4421 |
|
4422 // Create a new SAP and initialize it |
|
4423 TRAPD(err, aSAP = (CProviderTCP6*)Protocol()->NewSAPL(KSockStream)); |
|
4424 if (err == KErrNone) //lint -save -esym(613, aSAP) Possible NULL trapped here |
|
4425 { |
|
4426 aSAP->iParent = this; |
|
4427 aSAP->iSockFamily = iSockFamily; |
|
4428 aSAP->iAppFamily = iAppFamily; |
|
4429 |
|
4430 // The new SAP is not yet known to socket server |
|
4431 aSAP->iSockFlags.iAttached = EFalse; |
|
4432 aSAP->iSockFlags.iNotify = EFalse; |
|
4433 aSAP->iHasNetworkServices = HasNetworkServices(); |
|
4434 // Copy TCP options to the new socket. |
|
4435 aSAP->iSockInBufSize = iSockInBufSize; |
|
4436 aSAP->iSockOutBufSize = iSockOutBufSize; |
|
4437 aSAP->iMSS = iMSS; |
|
4438 aSAP->iSockFlags.iReuse = iSockFlags.iReuse; |
|
4439 aSAP->iFlags.iOobInline = iFlags.iOobInline; |
|
4440 aSAP->iFlags.iNoDelay = iFlags.iNoDelay; |
|
4441 aSAP->iFlags.iEcn = iFlags.iEcn; |
|
4442 |
|
4443 // Clone the flow. Lower layer socket options get copied to the new flow. |
|
4444 aSAP->iFlow.Clone(iFlow); |
|
4445 |
|
4446 // Clone currently resets the notifier, so we reinstall it here |
|
4447 aSAP->iFlow.SetNotify(aSAP); |
|
4448 |
|
4449 // If the listen queue is full, kill a random connection. |
|
4450 if (iConnectCount == iListenQueueSize) |
|
4451 { |
|
4452 TInt i = Protocol()->Random(iListenQueueSize); |
|
4453 CProviderTCP6 *sap = iListenQueue[i]; |
|
4454 sap->iParent = 0; |
|
4455 iListenQueue[i] = iListenQueue[--iConnectCount]; |
|
4456 iListenQueue[iConnectCount] = 0; |
|
4457 sap->Expire(); |
|
4458 } |
|
4459 |
|
4460 // Add the new connection into listen queue. |
|
4461 iListenQueue[iConnectCount++] = aSAP; |
|
4462 } //lint -restore |
|
4463 return err; |
|
4464 } |
|
4465 |
|
4466 |
|
4467 void CProviderTCP6::DetachChild(CProviderTCP6* aSAP) |
|
4468 { |
|
4469 ASSERT(iConnectCount > 0); |
|
4470 ASSERT(iListenQueue); |
|
4471 |
|
4472 // Remove child from listen queue |
|
4473 for (TUint i = 0; i < iConnectCount; i++) |
|
4474 if (iListenQueue[i] == aSAP) |
|
4475 { |
|
4476 aSAP->iParent = 0; |
|
4477 iListenQueue[i] = iListenQueue[--iConnectCount]; |
|
4478 iListenQueue[iConnectCount] = 0; |
|
4479 return; |
|
4480 } |
|
4481 |
|
4482 #ifdef _DEBUG |
|
4483 User::Panic(_L("CProviderTCP6::DetachChild()"), 0); |
|
4484 #endif |
|
4485 } |
|
4486 |
|
4487 TInt CProviderTCP6::CompleteChildConnect(CProviderTCP6* aSAP) |
|
4488 { |
|
4489 ASSERT(aSAP); |
|
4490 ASSERT(iSocket); |
|
4491 iChildDeleted = EFalse; |
|
4492 iSocket->ConnectComplete(*aSAP); |
|
4493 // In some cases SocketServer might have destroyed SAP. |
|
4494 // If this happens, return error for deleted SAP. |
|
4495 return iChildDeleted ? KErrAbort : KErrNone; |
|
4496 } |
|
4497 |
|
4498 inline void CProviderTCP6::SetChildDeleted(TBool aDeleted) |
|
4499 { |
|
4500 iChildDeleted = aDeleted; |
|
4501 } |
|
4502 |
|
4503 |
|
4504 // |
|
4505 // Clear all set option bits for SYNs |
|
4506 // |
|
4507 void CProviderTCP6::ClearSYNSettings() |
|
4508 { |
|
4509 // Remove SYN options from active TCP options. |
|
4510 iOptions.SetWindowScale(0); |
|
4511 iOptions.ClearMSS(); |
|
4512 iOptions.ClearSackOk(); |
|
4513 if (!iFlags.iUseTimeStamps) |
|
4514 iOptions.ClearTimeStamps(); |
|
4515 } |
|
4516 |
|
4517 TUint8 CProviderTCP6::NeedWindowScale() |
|
4518 { |
|
4519 TUint bufbits = 0; |
|
4520 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
4521 //Window scaling factor needs to be negotiated if the iMaxRecvWin |
|
4522 //is more than the 64K, irrespective of the socket receive buffer |
|
4523 //size. This will help in achieving the maximum throughput in case |
|
4524 //modulation changes |
|
4525 if(iTcpMaxRecvWin > iSockInBufSize ) |
|
4526 { |
|
4527 bufbits = iTcpMaxRecvWin >> 16; |
|
4528 } |
|
4529 else |
|
4530 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
4531 { |
|
4532 bufbits = iSockInBufSize >> 16; |
|
4533 } |
|
4534 TUint8 scale = 0; |
|
4535 |
|
4536 while (bufbits) |
|
4537 { |
|
4538 scale++; |
|
4539 bufbits >>= 1; |
|
4540 } |
|
4541 |
|
4542 return scale; |
|
4543 } |
|
4544 |
|
4545 TInt CProviderTCP6::CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic) |
|
4546 { |
|
4547 return iParent ? iParent->CheckPolicy(aPolicy, aDiagnostic) : CProviderInet6Transport::CheckPolicy(aPolicy, aDiagnostic); |
|
4548 } |
|
4549 // |
|
4550 // TCP reassembly queue implementation |
|
4551 // |
|
4552 TUint RMBufTcpFrag::Offset() |
|
4553 { |
|
4554 //LOG(Log::Printf(_L("RMBufTcpFrag::FragOffset()\r\n"))); |
|
4555 |
|
4556 TTcpPacket seg(*this); |
|
4557 return seg.iHdr->Sequence().Uint32(); |
|
4558 } |
|
4559 |
|
4560 TUint RMBufTcpFrag::FragmentLength() |
|
4561 { |
|
4562 //LOG(Log::Printf(_L("RMBufTcpFrag::FragLength(): length = %d\r\n"), Length())); |
|
4563 |
|
4564 TTcpPacket seg(*this); |
|
4565 return Length() - seg.iHdr->HeaderLength(); |
|
4566 } |
|
4567 |
|
4568 void RMBufTcpFrag::Join(RMBufChain& aSeg) |
|
4569 { |
|
4570 //LOG(Log::Printf(_L("RMBufTcpFrag::Join()\r\n"))); |
|
4571 |
|
4572 TTcpPacket thisSeg(*this), newSeg(aSeg); |
|
4573 |
|
4574 // Remove header and overlapping data from aSeg. |
|
4575 aSeg.TrimStart(newSeg.iHdr->HeaderLength() + |
|
4576 (Length() - thisSeg.iHdr->HeaderLength()) - |
|
4577 (newSeg.iHdr->Sequence() - thisSeg.iHdr->Sequence())); |
|
4578 |
|
4579 // Append. |
|
4580 Append(aSeg); |
|
4581 } |
|
4582 |
|
4583 #ifdef __ARMCC__ |
|
4584 #pragma pop |
|
4585 #endif |