networkprotocols/tcpipv4v6prt/src/tcp_sap.cpp
changeset 37 052078dda061
parent 18 39bb7c3571e9
child 56 ea8d11a88e23
--- a/networkprotocols/tcpipv4v6prt/src/tcp_sap.cpp	Mon May 03 13:58:16 2010 +0300
+++ b/networkprotocols/tcpipv4v6prt/src/tcp_sap.cpp	Tue Jun 29 19:20:22 2010 +0530
@@ -260,6 +260,13 @@
 	iRetransTimer->InitL();
 	iLingerTimer->InitL();
 	iSockInBufSize        = Protocol()->RecvBuf();
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	if(iSockInBufSize == Protocol()->RecvBufFromIniFile())
+	    iSocketStartupCase = ETrue;
+	else
+	    iSocketStartupCase = EFalse;
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW    	
+	
 	iSockOutBufSize       = Protocol()->SendBuf();
 	iSsthresh		= KMaxTInt32;
 	iRTO			= Protocol()->InitialRTO();
@@ -619,48 +626,137 @@
                 iSockInBufSize = KTcpMinimumWindow;
             else
                 {
-
-		        //If new TCP window is larger then the previous window, increase the 
-		        //iSockInBufSize right now. TCP recv function takes  care of
-		        //advertising a new effective TCP window. 
-		            if (intValue >= iSockInBufSize)
-		                {
-		                //Make it Zero so TCP could avoid the
-		                //TCP window shrinking processing in Recv.  
-		                iNewTcpWindow = 0;
-		                //FreeWindow has to be increased at the same time.
-		                iFreeWindow += intValue - iSockInBufSize;
-		                // Make the new TCP receive buffer change effective now.
-		                iSockInBufSize = intValue;                                                          
-		                }
-		            else
-		                {
-		                //This sets iNewTcpWindow to a non-zero value, which indicates 
-		                //to the TCP that window is shrunk and process TCP segments
-		                //which are in air before setting a new TCP receive buffer.         
-		                //TCP Receive window starts moving only when TCP hidden window
-		                //size exceeds the size of the shrunk window.
-		                   
-		                iNewTcpWindow = intValue;
-		                //Even in case of window shrink we can set the receive buffer size
-		                //immediately. This will be helpful, for processing SYN-ACK and other
-		                //receiver side processing.
-		                //For already connected sockets iNewTcpWindow will be taking care
-		                //of shrinking the window size for that TCP session.
-		                iSockInBufSize = iNewTcpWindow;
-		                if( iAdvertisedWindow > iNewTcpWindow )
-		                    {
-		                    iShrinkedWindowSize = iAdvertisedWindow - iNewTcpWindow;
-		                    }
-		                else
-		                    {
-		                    // No Need to process TCP receive window processing.
-		                    iNewTcpWindow = 0;
-		                    }
-		                }
-					
-                } 
-
+                //If its the startup case, then there should be no algorithm used to shrink
+				//or expand the window size from the default value provided in the ini file
+                //the new value should be set directly
+                if(iSocketStartupCase)
+                    {
+					//Add the extra window to free window pool
+					//if the window being set is greater than what is specified in ini file (startup case), then just overwrite the new window.
+					//Add difference to free window
+					//else set free window to zero
+					if(intValue > iSockInBufSize)
+						iFreeWindow += intValue - iSockInBufSize;
+					else
+						iFreeWindow = 0;
+					//set the buffer
+                    iSockInBufSize = intValue;
+					//disable startup flag.
+                    iSocketStartupCase = EFalse;
+                    }
+                else 
+                {
+					// Check for minimum value
+	                if (intValue < STATIC_CAST(TInt, KTcpMinimumWindow))
+	                    {
+	                    intValue = STATIC_CAST(TInt, KTcpMinimumWindow);
+	                    }
+	                // Handle the situation where the connection has been established and 
+	                // window scaling is not in use
+	                if ( InState( ETcpSynReceived | ETcpEstablished ) && !iRcvWscale )
+	                    {
+	                    // Do not allow window sizes larger than 0xFFFF
+	                    intValue = Min ( intValue, 0xFFFF );
+	                    }
+
+	                // Check whether we are increasing or decreasing window size
+	                if ( intValue >= iSockInBufSize )
+	                    {
+	                    // New window is larger than current one, check if a
+	                    // shrinking process is active
+	                    if ( !iNewTcpWindow )
+	                        {
+	                        // Mark new "space" as free, it will be updated to
+	                        // peer on next operation.
+	                        iFreeWindow += intValue - iSockInBufSize;
+	                        }
+	                    else
+	                        {
+	                        // In the middle of shrinking process.
+                      if ( iShrinkedWindowSize <= ( intValue - iSockInBufSize ))
+	                            {
+	                            // Increment to window size is enough to complete
+	                            // shrinking process. Update variables and exit
+	                            // from shrinking process.
+                          iFreeWindow = ( intValue - iSockInBufSize ) - iShrinkedWindowSize;
+	                            iShrinkedWindowSize = 0;
+	                            iNewTcpWindow = 0;
+	                            }
+	                        else
+	                            {
+	                            // Not quite there yet but closer. Less to shrink,
+	                            // update this, but do not exit from shrinking
+	                            // process
+                          iShrinkedWindowSize -= intValue - iSockInBufSize;
+	                            iNewTcpWindow = intValue;
+	                            }
+	                        }
+	                    }
+	                else
+	                    {
+	                    // Requested window is smaller than current one. Start or
+	                    // continue shrinking process. RCV window can be occupied
+	                    // for two different purpose at the moment
+	                    // 1. Client data in iSockInQ not read by application
+	                    // 2. Free window "opened" to peer (iAdvertisedWindow)
+	                    // When shrinking, we must ensure that when reopening
+	                    // the window to client there must be truly empty space
+	                    // in the window. Thus, freeze the right edge of the
+	                    // window (iRCV.NXT + iRCV.WND stays constant) until
+	                    // shrinking is completed.
+	                
+	                    if ( iNewTcpWindow )
+	                        {
+	                        // There is an ongoing shrink process, add the
+	                        // change to the amount to be shrinked
+	                        iShrinkedWindowSize += iSockInBufSize - intValue;
+	                        iNewTcpWindow = intValue;
+	                        }
+	                    else
+	                        {
+	                        // This is a new shrinking process, count how much
+	                        // needs to be shrinked
+                      iShrinkedWindowSize = iSockInQLen + iRCV.WND;
+	                        if ( iShrinkedWindowSize >= intValue )
+	                            {
+	                            // We need to shrink since the currently occupied
+	                            // window does not fit to new one
+	                            iShrinkedWindowSize -= intValue;
+	                            // There is now free space in the window
+	                            iFreeWindow = 0;
+	                            // iNewTcpWindow is used as a state variable for
+	                            // shrinking
+	                            iNewTcpWindow = intValue;
+	                            }
+	                        else
+	                            {
+	                            // No need to shrink since we can fit the current
+	                            // contents to the new window, update free window
+	                            // If TCP connection is not yet setup, the free
+	                            // window will be updated on connection setup, 
+	                            // for existing connection it will be used
+	                            // next time application reads data
+	                            if ( iFreeWindow >= ( iSockInBufSize - intValue ))
+	                                {
+	                                iFreeWindow -= iSockInBufSize - intValue;
+	                                }
+	                            else 
+	                                {
+	                                // Something wrong. Try to reevaluate...
+	                                iFreeWindow = intValue - iShrinkedWindowSize;
+	                                }
+	                            iShrinkedWindowSize = 0;
+	                            }
+	                        }
+	                    }
+	                // Even in case of window shrink we can set the receive buffer size
+	                // immediately. This will be helpful, for processing SYN-ACK and other
+	                // receiver side processing.
+	                // For already connected sockets iNewTcpWindow will be taking care
+	                // of shrinking the window size for that TCP session.
+	                iSockInBufSize = intValue;
+	                }
+	            } 
 		    }
 		    break;
 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
@@ -1362,32 +1458,23 @@
 	//if This is true, then it is a case of TCP window shrink and we need 
 	//to handle it.
 	if ( iNewTcpWindow )
-		{
-	   	//Log  this message for information, that Window is shrinked
-	   	LOG(Log::Printf(_L("\ttcp SAP[%u] TCP window shrinking mode on"), (TInt)this));
-	   
-	   	//Increase the hidden free TCP receive window.
-	   	iHiddenFreeWindow += aLength;
-	   
-	   	if (iHiddenFreeWindow >= iShrinkedWindowSize)
-			{
-			//Disable window shrink processing, so that TCP could switch
-			//to the normal processing.    
-			iSockInBufSize = iNewTcpWindow;
-			
-			//Add the usable window to the free window.
-			iFreeWindow += iHiddenFreeWindow - iShrinkedWindowSize;
-			
-			//There are chances that TCP receive window might further shrink.
-			iHiddenFreeWindow = 0;
-			
-			//TCP Receive window shrink phase is over.
-			iNewTcpWindow = 0;
-			
-			//Log  this message for information, that Window is shrinked
-			LOG(Log::Printf(_L("\ttcp SAP[%u] TCP window shrinking mode off"), (TInt)this));
-			}
-		}
+	    {
+	    // Check if we can complete shrinking process
+	    if ( aLength > iShrinkedWindowSize )
+	        {
+	        // We can exit from the shrinking process. Reset variables and
+	        // update free window.
+	        iFreeWindow = aLength - iShrinkedWindowSize;
+	        iShrinkedWindowSize = 0;
+	        iNewTcpWindow = 0;
+	        }
+	    else
+	        {
+	        // Substract the needed shrinking amount by the amount of bytes client
+	        // read from the buffer
+	        iShrinkedWindowSize -= aLength;
+	        }
+	    }
 	else
 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
 	
@@ -1684,7 +1771,8 @@
 		if (iFlags.iRetransmitPending)
 			{
 			iFlags.iRetransmitPending = EFalse;
-			RetransmitSegments();
+			if(RetransmitSegments())
+				return;
 			}
 
 		if (iFlags.iTransmitPending)
@@ -2288,7 +2376,12 @@
 		++iBackoff;
 		if (iRTO < Protocol()->MaxRTO())  // Avoid RTO overflow
 			ResetRTO();
-
+		
+		if(DetachIfDead())
+			{
+			Expire();
+			return;
+			}
 		//
 		// Timeout?
 		//
@@ -2403,7 +2496,7 @@
 //  - directly from RetransmitTimeout()
 //  - from CanSend(), in which case this is a delayed retransmission timeout
 //
-void CProviderTCP6::RetransmitSegments()
+TBool CProviderTCP6::RetransmitSegments()
 	{
 	ASSERT(iRetransTimer);
 
@@ -2419,7 +2512,7 @@
 		{
 		LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Flow pending"), (TInt)this));
 		ReSchedRetransmit();
-		return;
+		return EFalse;
 		}
 
 	//
@@ -2477,14 +2570,14 @@
 			// the receiver suddenly shrinks its window. The current solution covers
 			// both cases.
 			//
-			return;
+			return EFalse;
 			}
 
 		//
 		// This is a retransmit timout. Do we have anything to do?
 		//
 		if (!unacked)
-			return;
+			return EFalse;
 
 		LOG(if (iFlags.iFastRetransMode) Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Leaving FAST RETRANS mode"), (TInt)this));
 		iFlags.iFastRetransMode = EFalse;
@@ -2557,7 +2650,7 @@
 		// If the server doesn't respond because of broken NAT/FW or other, don't keep interface up.
 		if (InState(ETcpFinWait1|ETcpClosing|ETcpLastAck))
 			DetachIfDead();
-		return;
+		return EFalse;
 		}
 
 	//
@@ -2567,14 +2660,14 @@
 		{
 		// Retransmit SYN
 		SendSegment(KTcpCtlSYN, iSND.UNA);
-		return;
+		return EFalse;
 		}
 
 	if (InState(ETcpSynReceived))
 		{
 		// Retransmit SYN,ACK
 		SendSegment(KTcpCtlSYN|KTcpCtlACK, iSND.UNA);
-		return;
+		return EFalse;
 		}
 
 	if (InState(ETcpFinWait1|ETcpClosing|ETcpLastAck))
@@ -2584,18 +2677,22 @@
 	    //TSW error:JHAA-82JBNG -- FIN retransmission 
 		//Depending on the function return value the decision to
 	    //retransmitt FIN is decided
-
-		TBool continue_send = DetachIfDead();
+	
 		// Retransmit FIN
-		if(continue_send == EFalse)
+		if(DetachIfDead()== EFalse)
+			{
 			SendSegment(KTcpCtlFIN|KTcpCtlACK, iSND.UNA);
-		return;
+			return EFalse;
+			}
 		}
 
 	LOG(Log::Printf(_L("\ttcp SAP[%u] RetransmitSegments(): Retransmitter stopping"), (TInt)this));
 	if (!iSockFlags.iAttached)
+		{
 		Expire();
-	return;
+		return ETrue;
+		}
+	return EFalse;
 	}