TCP.c

Go to the documentation of this file.
00001 
00002 
00003 
00029 /*********************************************************************
00030  * Software License Agreement
00031  *
00032  * Copyright (C) 2002-2008 Microchip Technology Inc.  All rights 
00033  * reserved.
00034  *
00035  * Microchip licenses to you the right to use, modify, copy, and 
00036  * distribute: 
00037  * (i)  the Software when embedded on a Microchip microcontroller or 
00038  *      digital signal controller product ("Device") which is 
00039  *      integrated into Licensee's product; or
00040  * (ii) ONLY the Software driver source files ENC28J60.c and 
00041  *      ENC28J60.h ported to a non-Microchip device used in 
00042  *      conjunction with a Microchip ethernet controller for the 
00043  *      sole purpose of interfacing with the ethernet controller. 
00044  *
00045  * You should refer to the license agreement accompanying this 
00046  * Software for additional information regarding your rights and 
00047  * obligations.
00048  *
00049  * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT 
00050  * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT 
00051  * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A 
00052  * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL 
00053  * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR 
00054  * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF 
00055  * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS 
00056  * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE 
00057  * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER 
00058  * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT 
00059  * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
00060  *
00061  *
00062  * Author               Date        Comment
00063  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00064  * Nilesh Rajbharti     5/8/01      Original        (Rev 1.0)
00065  * Howard Schlunder     12/11/06    Changed almost everything to 
00066  *                                  better meet RFC 793.
00067  ********************************************************************/
00068 #define __TCP_C
00069 
00070 #include "TCPIP.h"
00071 
00072 /****************************************************************************
00073   Section:
00074     Configuration Parameters
00075   ***************************************************************************/
00076 
00077 // Starting port for client sockets
00078 #define LOCAL_PORT_START_NUMBER (1024u)
00079 // End port for client sockets
00080 #define LOCAL_PORT_END_NUMBER   (5000u)
00081 
00082 // For debugging only.  Normal applications should never enable these
00083 //#define DEBUG_GENERATE_TX_LOSS        31129
00084 //#define DEBUG_GENERATE_RX_LOSS        32113
00085 
00086 // A lot of pointer dereference code can be removed if you 
00087 // locally copy TCBStubs to an absolute memory location.
00088 // If you define TCP_OPTIMIZE_FOR_SIZE, local caching will 
00089 // occur and will substantially decrease the entire TCP ROM 
00090 // footprint (up to 35%).  If you leave TCP_OPTIMIZE_FOR_SIZE 
00091 // undefined, the local caching will be disabled.  On PIC18 
00092 // products, this will improve TCP performance/throughput by 
00093 // approximately 15%.
00094 #define TCP_OPTIMIZE_FOR_SIZE
00095 
00096 // For smallest size and best throughput, TCP_OPTIMIZE_FOR_SIZE 
00097 // should always be enabled on PIC24/dsPIC products.  On PIC32 
00098 // products there is very little difference and depnds on compiler 
00099 // optimization level
00100 #if defined(__C30__) && !defined(TCP_OPTIMIZE_FOR_SIZE)
00101     #define TCP_OPTIMIZE_FOR_SIZE
00102 #elif defined(__C32__) && defined(TCP_OPTIMIZE_FOR_SIZE)
00103     #undef TCP_OPTIMIZE_FOR_SIZE
00104 #endif
00105 
00106 // TCP Maximum Segment Size (TX and RX)
00107 #define TCP_MAX_SEG_SIZE            (536u)
00108 
00109 // TCP Timeout and retransmit numbers
00110 #define TCP_START_TIMEOUT_VAL       ((TICK)TICK_SECOND*1)   // Timeout to retransmit unacked data
00111 #define TCP_DELAYED_ACK_TIMEOUT     ((TICK)TICK_SECOND/10)  // Timeout for delayed-acknowledgement algorithm
00112 #define TCP_FIN_WAIT_2_TIMEOUT      ((TICK)TICK_SECOND*5)   // Timeout for FIN WAIT 2 state
00113 #define TCP_KEEP_ALIVE_TIMEOUT      ((TICK)TICK_SECOND*10)  // Timeout for keep-alive messages when no traffic is sent
00114 #define TCP_CLOSE_WAIT_TIMEOUT      ((TICK)TICK_SECOND/5)   // Timeout for the CLOSE_WAIT state
00115 #define TCP_MAX_RETRIES             (5u)                    // Maximum number of retransmission attempts
00116 #define TCP_MAX_UNACKED_KEEP_ALIVES (6u)                    // Maximum number of keep-alive messages that can be sent without receiving a response before automatically closing the connection
00117 #define TCP_MAX_SYN_RETRIES         (2u)    // Smaller than all other retries to reduce SYN flood DoS duration
00118 
00119 #define TCP_AUTO_TRANSMIT_TIMEOUT_VAL   (TICK_SECOND/25ull) // Timeout before automatically tranmitting unflushed data
00120 
00121 #define TCP_SYN_QUEUE_MAX_ENTRIES   (3u)                    // Number of TCP RX SYN packets to save if they cannot be serviced immediately
00122 #define TCP_SYN_QUEUE_TIMEOUT       ((TICK)TICK_SECOND*3)   // Timeout for when SYN queue entries are deleted if unserviceable
00123 
00124 /****************************************************************************
00125   Section:
00126     TCP Header Data Types
00127   ***************************************************************************/
00128 
00129 #define FIN     (0x01)      // FIN Flag as defined in RFC
00130 #define SYN     (0x02)      // SYN Flag as defined in RFC
00131 #define RST     (0x04)      // Reset Flag as defined in RFC
00132 #define PSH     (0x08)      // Push Flag as defined in RFC
00133 #define ACK     (0x10)      // Acknowledge Flag as defined in RFC
00134 #define URG     (0x20)      // Urgent Flag as defined in RFC
00135 
00136 // TCP Header Data Structure
00137 typedef struct _TCP_HEADER
00138 {
00139     WORD    SourcePort;     // Local port number
00140     WORD    DestPort;       // Remote port number
00141     DWORD   SeqNumber;      // Local sequence number
00142     DWORD   AckNumber;      // Acknowledging remote sequence number
00143 
00144     struct
00145     {
00146         unsigned char Reserved3      : 4;
00147         unsigned char Val            : 4;
00148     } DataOffset;           // Data offset flags nibble
00149 
00150     union
00151     {
00152         struct
00153         {
00154             unsigned char flagFIN    : 1;
00155             unsigned char flagSYN    : 1;
00156             unsigned char flagRST    : 1;
00157             unsigned char flagPSH    : 1;
00158             unsigned char flagACK    : 1;
00159             unsigned char flagURG    : 1;
00160             unsigned char Reserved2  : 2;
00161         } bits;
00162         BYTE byte;
00163     } Flags;                // TCP Flags as defined in RFC
00164 
00165     WORD    Window;         // Local free RX buffer window
00166     WORD    Checksum;       // Data payload checksum
00167     WORD    UrgentPointer;  // Urgent pointer
00168 } TCP_HEADER;
00169 
00170 #define TCP_OPTIONS_END_OF_LIST     (0x00u)     // End of List TCP Option Flag
00171 #define TCP_OPTIONS_NO_OP           (0x01u)     // No Op TCP Option
00172 #define TCP_OPTIONS_MAX_SEG_SIZE    (0x02u)     // Maximum segment size TCP flag
00173 typedef struct _TCP_OPTIONS
00174 {
00175     BYTE        Kind;                           // Type of option
00176     BYTE        Length;                         // Length
00177     WORD_VAL    MaxSegSize;                     // Maximum segment size
00178 } TCP_OPTIONS;                                  // TCP Options data structure                           
00179 
00180 // Structure containing all the important elements of an incomming 
00181 // SYN packet in order to establish a connection at a future time 
00182 // if all sockets on the listening port are already connected to 
00183 // someone
00184 typedef struct 
00185 {
00186     NODE_INFO   niSourceAddress;// Remote IP address and MAC address
00187     WORD        wSourcePort;    // Remote TCP port number that the response SYN needs to be sent to
00188     DWORD       dwSourceSEQ;    // Remote TCP SEQuence number that must be ACKnowledged when we send our response SYN
00189     WORD        wDestPort;      // Local TCP port which the original SYN was destined for
00190     WORD        wTimestamp;     // Timer to expire old SYN packets that can't be serviced at all
00191 } TCP_SYN_QUEUE;
00192 
00193 
00194 #if defined(STACK_CLIENT_MODE)
00195 static WORD NextPort __attribute__((persistent));   // Tracking variable for next local client port number
00196 #endif
00197 
00198 /****************************************************************************
00199   Section:
00200     TCB Definitions
00201   ***************************************************************************/
00202 
00203 // Determines the number of defined TCP sockets
00204 #define TCP_SOCKET_COUNT    (sizeof(TCPSocketInitializer)/sizeof(TCPSocketInitializer[0]))
00205 
00206 
00207 #if defined(HI_TECH_C)
00208     // The initializer forces this large array out of the bss section 
00209     // so we can link correctly.
00210     #pragma psect bigdata=TCB_uRAM_BIG
00211     #pragma psect data=TCB_uRAM
00212     static TCB_STUB TCBStubs[TCP_SOCKET_COUNT] = {'\0'};    
00213     #pragma psect data=ordinary_data_sect
00214     #pragma psect bigdata=ordinary_data_sect_big
00215 #else
00216     // The TCB array is very large.  With the C18 compiler, one must 
00217     // modify the linker script to make an array that spans more than 
00218     // one memory bank.  To do this, make the necessary changes to your 
00219     // processor's linker script (.lkr).  Here is an example showing 
00220     // gpr11 and 128 bytes of gpr12 being combined into one 384 byte 
00221     // block used exclusively by the TCB_uRAM data section:
00222     // ...
00223     // //DATABANK   NAME=gpr11      START=0xB00          END=0xBFF
00224     // //DATABANK   NAME=gpr12      START=0xC00          END=0xCFF
00225     // DATABANK   NAME=gpr11b     START=0xB00          END=0xC7F           PROTECTED
00226     // DATABANK   NAME=gpr12      START=0xC80          END=0xCFF
00227     // ...
00228     // SECTION    NAME=TCB_uRAM    RAM=gpr11b
00229     // ...
00230     #pragma udata TCB_uRAM
00231     static TCB_STUB TCBStubs[TCP_SOCKET_COUNT];
00232     #pragma udata                   // Return to any other RAM section
00233 #endif
00234 
00235 static TCB MyTCB;                                   // Currently loaded TCB
00236 static TCP_SOCKET hCurrentTCP = INVALID_SOCKET;     // Current TCP socket
00237 #if TCP_SYN_QUEUE_MAX_ENTRIES
00238     #pragma udata SYN_QUEUE_RAM_SECT
00239     static TCP_SYN_QUEUE SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES];   // Array of saved incoming SYN requests that need to be serviced later
00240     #pragma udata
00241 #endif
00242 
00243 /****************************************************************************
00244   Section:
00245     Function Prototypes
00246   ***************************************************************************/
00247 
00248 static void TCPRAMCopy(PTR_BASE wDest, BYTE vDestType, PTR_BASE wSource, BYTE vSourceType, WORD wLength);
00249 
00250 #if defined(__18CXX)
00251     static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource, WORD wLength);
00252 #else
00253     #define TCPRAMCopyROM(a,b,c,d)  TCPRAMCopy(a,b,c,TCP_PIC_RAM,d)
00254 #endif
00255 
00256 static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags);
00257 static void HandleTCPSeg(TCP_HEADER* h, WORD len);
00258 static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote);
00259 static void SwapTCPHeader(TCP_HEADER* header);
00260 static void CloseSocket(void);
00261 static void SyncTCB(void);
00262 
00263 // Indicates if this packet is a retransmission (no reset) or a new packet (reset required)
00264 #define SENDTCP_RESET_TIMERS    0x01
00265 // Instead of transmitting normal data, a garbage octet is transmitted according to RFC 1122 section 4.2.3.6
00266 #define SENDTCP_KEEP_ALIVE      0x02
00267 
00268 
00269 /****************************************************************************
00270   Section:
00271     TCB Optimization Configuration
00272   ***************************************************************************/
00273 
00274 #if defined(TCP_OPTIMIZE_FOR_SIZE)
00275     static TCB_STUB MyTCBStub;
00276     
00277     // Flushes MyTCBStub cache and loads up the specified TCB_STUB.
00278     // Does nothing on cache hit.
00279     static void SyncTCBStub(TCP_SOCKET hTCP)
00280     {
00281         if(hCurrentTCP == hTCP)
00282             return;
00283     
00284         if(hCurrentTCP != INVALID_SOCKET)
00285         {
00286             // Save the current TCB stub
00287             memcpy((void*)&TCBStubs[hCurrentTCP], (void*)&MyTCBStub, sizeof(MyTCBStub));
00288         }
00289     
00290         hCurrentTCP = hTCP;
00291     
00292         if(hTCP == INVALID_SOCKET)
00293             return;
00294     
00295         // Load up the new TCB stub
00296         memcpy((void*)&MyTCBStub, (void*)&TCBStubs[hTCP], sizeof(MyTCBStub));
00297     }
00298 #else
00299     // Flushes MyTCBStub cache and loads up the specified TCB_STUB.
00300     // Does nothing on cache hit.
00301     #define SyncTCBStub(a)  hCurrentTCP = a
00302     // Alias to current TCP stub.
00303     #define MyTCBStub       TCBStubs[hCurrentTCP]
00304 #endif
00305 
00306 
00307 
00308 // Flushes MyTCB cache and loads up the specified TCB.
00309 // Does nothing on cache hit.
00310 static void SyncTCB(void)
00311 {
00312     static TCP_SOCKET hLastTCB = INVALID_SOCKET;
00313     
00314     if(hLastTCB == hCurrentTCP)
00315         return;
00316 
00317     if(hLastTCB != INVALID_SOCKET)
00318     {
00319         // Save the current TCB
00320         TCPRAMCopy(TCBStubs[hLastTCB].bufferTxStart - sizeof(MyTCB), TCBStubs[hLastTCB].vMemoryMedium, (PTR_BASE)&MyTCB, TCP_PIC_RAM, sizeof(MyTCB));
00321     }
00322 
00323     // Load up the new TCB
00324     hLastTCB = hCurrentTCP;
00325     TCPRAMCopy((PTR_BASE)&MyTCB, TCP_PIC_RAM, TCBStubs[hCurrentTCP].bufferTxStart - sizeof(MyTCB), TCBStubs[hLastTCB].vMemoryMedium, sizeof(MyTCB));
00326 }
00327 
00328 
00329 /*****************************************************************************
00330   Function:
00331     void TCPInit(void)
00332 
00333   Summary:
00334     Initializes the TCP module.
00335 
00336   Description:
00337     Initializes the TCP module.  This function sets up the TCP buffers
00338     in memory and initializes each socket to the CLOSED state.  If
00339     insufficient memory was allocated for the TCP sockets, the function
00340     will hang here to be captured by the debugger.
00341 
00342   Precondition:
00343     None
00344 
00345   Parameters:
00346     None
00347 
00348   Returns:
00349     None
00350     
00351   Remarks:
00352     This function is called only one during lifetime of the application.
00353   ***************************************************************************/
00354 void TCPInit(void)
00355 {
00356     BYTE i;
00357     BYTE vSocketsAllocated;
00358     WORD wTXSize, wRXSize;
00359     PTR_BASE ptrBaseAddress;
00360     BYTE vMedium;
00361     #if TCP_ETH_RAM_SIZE > 0
00362     WORD wCurrentETHAddress = TCP_ETH_RAM_BASE_ADDRESS;
00363     #endif
00364     #if TCP_PIC_RAM_SIZE > 0
00365     PTR_BASE ptrCurrentPICAddress = TCP_PIC_RAM_BASE_ADDRESS;
00366     #endif
00367     #if TCP_SPI_RAM_SIZE > 0
00368     WORD wCurrentSPIAddress = TCP_SPI_RAM_BASE_ADDRESS;
00369     #endif
00370     
00371     // Mark all SYN Queue entries as invalid by zeroing the memory
00372     #if TCP_SYN_QUEUE_MAX_ENTRIES
00373         memset((void*)SYNQueue, 0x00, sizeof(SYNQueue));
00374     #endif
00375     
00376     // Allocate all socket FIFO addresses
00377     vSocketsAllocated = 0;
00378     for(i = 0; i < TCP_SOCKET_COUNT; i++)
00379     {
00380         // Generate all needed sockets of each type (TCP_PURPOSE_*)
00381         SyncTCBStub(i);
00382         SyncTCB();
00383     
00384         vMedium = TCPSocketInitializer[i].vMemoryMedium;
00385         wTXSize = TCPSocketInitializer[i].wTXBufferSize;
00386         wRXSize = TCPSocketInitializer[i].wRXBufferSize;
00387     
00388         switch(vMedium)
00389         {
00390             #if TCP_ETH_RAM_SIZE > 0
00391             case TCP_ETH_RAM:
00392                 ptrBaseAddress = wCurrentETHAddress;
00393                 wCurrentETHAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
00394                 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
00395                 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h.  See the TCP memory allocation section.  More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
00396                 while(wCurrentETHAddress > TCP_ETH_RAM_BASE_ADDRESS + TCP_ETH_RAM_SIZE);
00397                 break;
00398             #endif
00399                 
00400             #if TCP_PIC_RAM_SIZE > 0
00401             case TCP_PIC_RAM:
00402                 ptrBaseAddress = ptrCurrentPICAddress;
00403                 ptrCurrentPICAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
00404                 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
00405                 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h.  See the TCP memory allocation section.  More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
00406                 while(ptrCurrentPICAddress > TCP_PIC_RAM_BASE_ADDRESS + TCP_PIC_RAM_SIZE);
00407                 break;
00408             #endif
00409                 
00410             #if TCP_SPI_RAM_SIZE > 0
00411             case TCP_SPI_RAM:
00412                 ptrBaseAddress = wCurrentSPIAddress;
00413                 wCurrentSPIAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
00414                 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
00415                 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h.  See the TCP memory allocation section.  More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
00416                 while(wCurrentSPIAddress > TCP_SPI_RAM_BASE_ADDRESS + TCP_SPI_RAM_SIZE);
00417                 break;
00418             #endif
00419             
00420             default:
00421                 while(1); // Undefined allocation medium.  Go fix your TCPIPConfig.h TCP memory allocations.
00422         }
00423     
00424         MyTCB.vSocketPurpose = TCPSocketInitializer[i].vSocketPurpose;
00425         
00426         MyTCBStub.vMemoryMedium = vMedium;
00427         MyTCBStub.bufferTxStart = ptrBaseAddress + sizeof(TCB);
00428         MyTCBStub.bufferRxStart = MyTCBStub.bufferTxStart + wTXSize + 1;
00429         MyTCBStub.bufferEnd     = MyTCBStub.bufferRxStart + wRXSize;
00430         MyTCBStub.smState       = TCP_CLOSED;
00431         MyTCBStub.Flags.bServer = FALSE;
00432         #if defined(STACK_USE_SSL)
00433         MyTCBStub.sslStubID = SSL_INVALID_ID;
00434         #endif      
00435         
00436         CloseSocket();
00437     }
00438 }
00439 
00440 /****************************************************************************
00441   Section:
00442     Connection Management Functions
00443   ***************************************************************************/
00444 
00445 
00446 /****************************************************************************
00447   Function:
00448       TCP_SOCKET TCPOpen(DWORD dwRemoteHost,
00449                           BYTE vRemoteHostType,
00450                           WORD wPort,
00451                           BYTE vSocketPurpose)
00452     
00453   Summary:
00454     Opens a TCP socket for listening or as a client.
00455     
00456   Description:
00457     Provides a unified method for opening TCP sockets. This function can
00458     open both client and server sockets. For client sockets, it can accept
00459     host name string to query in DNS, and IP address as a string, an IP
00460     address in binary form, or a previously resolved NODE_INFO structure.
00461     When a host name or IP address only is provided, the TCP module will
00462     internally perform the necessary DNS and/or ARP resolution steps before
00463     reporting that the TCP socket is connected (via a call to
00464     TCPISConnected returning TRUE). Server sockets ignore this destination
00465     parameter and listen only on the indicated port.
00466     
00467     The vSocketPurpose field allows sockets to be opened with varying
00468     buffer size parameters and memory storage mediums. This field
00469     corresponds to pre-defined sockets types in TCPIPConfig.h or the
00470     TCPIPConfig utility.
00471     
00472     Sockets are statically allocated on boot, but can be claimed with this
00473     \function and freed using TCPDisconnect (for client sockets). Server
00474     sockets are opened permanently for the duration of the application.
00475     Calls to TCPDisconnect will only release the socket to the listening
00476     state.
00477     
00478   Conditions:
00479     TCP is initialized.
00480     
00481   Input:
00482     dwRemoteHost -     For client sockets only. Provide a pointer to a
00483                        null\-terminated string of the remote host name (ex\:
00484                        "www.microchip.com" or "192.168.1.123"), a literal
00485                        destination IP address (ex\: 0x7B01A8C0 or an IP_ADDR
00486                        data type), or a pointer to a NODE_INFO structure
00487                        with the remote IP address and remote node or gateway
00488                        MAC address specified. If a string is provided, note
00489                        that it must be statically allocated in memory and
00490                        cannot be modified or deallocated until
00491                        TCPIsConnected returns TRUE. This parameter is
00492                        ignored for server sockets.
00493     vRemoteHostType -  TCP_OPEN_SERVER, TCP_OPEN_RAM_HOST,
00494                        TCP_OPEN_ROM_HOST, TCP_OPEN_IP_ADDRESS, or
00495                        TCP_OPEN_NODE_INFO.
00496     wPort -            For client sockets, the remote TCP port to which a
00497                        connection should be made. For server sockets, the
00498                        local TCP port on which to listen for connections.
00499     vSocketPurpose -   Any of the TCP_PURPOSE_* constants defined in
00500                        TCPIPConfig.h or the TCPIPConfig utility.
00501 
00502   Return Values:
00503     INVALID_SOCKET -  No sockets of the specified type were available to be
00504                       opened.
00505     Otherwise -       A TCP_SOCKET handle. Save this handle and use it when
00506                       calling all other TCP APIs.
00507   
00508   Remarks:
00509     This function replaces the old TCPConnect and TCPListen functions.
00510     
00511     If TCP_OPEN_RAM_HOST or TCP_OPEN_ROM_HOST are used for the destination
00512     type, the DNS client module must also be enabled.
00513     
00514   Example:
00515     <code>
00516     // Open a server socket
00517     skt = TCPOpen(NULL, TCP_OPEN_SERVER, HTTP_PORT, TCP_PURPOSE_HTTP_SERVER);
00518     
00519     // Open a client socket to www.microchip.com
00520     // The double cast here prevents compiler warnings
00521     skt = TCPOpen((DWORD)(PTR_BASE)"www.microchip.com",
00522                     TCP_OPEN_ROM_HOST, 80, TCP_PURPOSE_DEFAULT);
00523     
00524     // Reopen a client socket without repeating DNS or ARP
00525     SOCKET_INFO cache = TCPGetSocketInfo(skt);  // Call with the old socket
00526     skt = TCPOpen((DWORD)(PTR_BASE)&cache.remote, TCP_OPEN_NODE_INFO, 
00527                     cache.remotePort.Val, TCP_PURPOSE_DEFAULT);
00528     </code>                                                             
00529   ****************************************************************************/
00530 TCP_SOCKET TCPOpen(DWORD dwRemoteHost, BYTE vRemoteHostType, WORD wPort, BYTE vSocketPurpose)
00531 {
00532     TCP_SOCKET hTCP;
00533 
00534     // Find an available socket that matches the specified socket type
00535     for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
00536     {
00537         SyncTCBStub(hTCP);
00538 
00539         // Sockets that are in use will be in a non-closed state
00540         if(MyTCBStub.smState != TCP_CLOSED)
00541             continue;
00542 
00543         SyncTCB();
00544 
00545         // See if this socket matches the desired type
00546         if(MyTCB.vSocketPurpose != vSocketPurpose)
00547             continue;
00548 
00549         // See if this is a server socket
00550         if(vRemoteHostType == TCP_OPEN_SERVER)
00551         {
00552             MyTCB.localPort.Val = wPort;
00553             MyTCBStub.Flags.bServer = TRUE;
00554             MyTCBStub.smState = TCP_LISTEN;
00555             MyTCBStub.remoteHash.Val = wPort;
00556             #if defined(STACK_USE_SSL_SERVER)
00557             MyTCB.localSSLPort.Val = 0;
00558             #endif
00559         }
00560         // Handle all the client mode socket types
00561         else
00562         {
00563             #if defined(STACK_CLIENT_MODE)
00564             {
00565                 // Each new socket that is opened by this node, gets the 
00566                 // next sequential local port number.
00567                 if(NextPort < LOCAL_PORT_START_NUMBER || NextPort > LOCAL_PORT_END_NUMBER)
00568                     NextPort = LOCAL_PORT_START_NUMBER;
00569                 
00570                 // Set the non-zero TCB fields
00571                 MyTCB.localPort.Val = NextPort++;
00572                 MyTCB.remotePort.Val = wPort;
00573     
00574                 // Flag to start the DNS, ARP, SYN processes
00575                 MyTCBStub.eventTime = TickGet();
00576                 MyTCBStub.Flags.bTimerEnabled = 1;
00577                 MyTCBStub.Flags.bSocketReset = 0;
00578     
00579                 switch(vRemoteHostType)
00580                 {
00581                     #if defined(STACK_USE_DNS)
00582                     case TCP_OPEN_RAM_HOST:
00583                     case TCP_OPEN_ROM_HOST:
00584                         MyTCB.remote.dwRemoteHost = dwRemoteHost;
00585                         MyTCB.flags.bRemoteHostIsROM = (vRemoteHostType == TCP_OPEN_ROM_HOST);
00586                         MyTCBStub.smState = TCP_GET_DNS_MODULE;
00587                         break;
00588                     #endif
00589         
00590                     case TCP_OPEN_IP_ADDRESS:
00591                         // dwRemoteHost is a literal IP address.  This 
00592                         // doesn't need DNS and can skip directly to the 
00593                         // Gateway ARPing step.
00594                         MyTCBStub.remoteHash.Val = (((DWORD_VAL*)&dwRemoteHost)->w[1]+((DWORD_VAL*)&dwRemoteHost)->w[0] + wPort) ^ MyTCB.localPort.Val;
00595                         MyTCB.remote.niRemoteMACIP.IPAddr.Val = dwRemoteHost;
00596                         MyTCB.retryCount = 0;
00597                         MyTCB.retryInterval = (TICK_SECOND/4)/256;
00598                         MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
00599                         break;
00600         
00601                     case TCP_OPEN_NODE_INFO:
00602                         MyTCBStub.remoteHash.Val = (((NODE_INFO*)(PTR_BASE)dwRemoteHost)->IPAddr.w[1]+((NODE_INFO*)(PTR_BASE)dwRemoteHost)->IPAddr.w[0] + wPort) ^ MyTCB.localPort.Val;
00603                         memcpy((void*)(BYTE*)&MyTCB.remote, (void*)(BYTE*)(PTR_BASE)dwRemoteHost, sizeof(NODE_INFO));
00604                         MyTCBStub.smState = TCP_SYN_SENT;
00605                         SendTCP(SYN, SENDTCP_RESET_TIMERS);
00606                         break;
00607                 }
00608             }       
00609             #else
00610             {
00611                 return INVALID_SOCKET;
00612             }   
00613             #endif
00614         }
00615         
00616         return hTCP;        
00617     }
00618 
00619     // If there is no socket available, return error.
00620     return INVALID_SOCKET;
00621 }
00622 
00623 
00624 /*****************************************************************************
00625   Function:
00626     BOOL TCPWasReset(TCP_SOCKET hTCP)
00627 
00628   Summary:
00629     Self-clearing semaphore inidicating socket reset.
00630 
00631   Description:
00632     This function is a self-clearing semaphore indicating whether or not
00633     a socket has been disconnected since the previous call.  This function
00634     works for all possible disconnections: a call to TCPDisconnect, a FIN 
00635     from the remote node, or an acknowledgement timeout caused by the loss
00636     of a network link.  It also returns TRUE after the first call to TCPInit.
00637     Applications should use this function to reset their state machines.
00638     
00639     This function was added due to the possibility of an error when relying
00640     on TCPIsConnected returing FALSE to check for a condition requiring a
00641     state machine reset.  If a socket is closed (due to a FIN ACK) and then
00642     immediately reopened (due to a the arrival of a new SYN) in the same
00643     cycle of the stack, calls to TCPIsConnected by the application will 
00644     never return FALSE even though the socket has been disconnected.  This 
00645     can cause errors for protocols such as HTTP in which a client will 
00646     immediately open a new connection upon closing of a prior one.  Relying
00647     on this function instead allows applications to trap those conditions 
00648     and properly reset their internal state for the new connection.
00649 
00650   Precondition:
00651     TCP is initialized.
00652 
00653   Parameters:
00654     hTCP - The socket to check.
00655 
00656   Return Values:
00657     TRUE - The socket has been disconnected since the previous call.
00658     FALSE - The socket has not been disconnected since the previous call.
00659   ***************************************************************************/
00660 BOOL TCPWasReset(TCP_SOCKET hTCP)
00661 {
00662     SyncTCBStub(hTCP);
00663     
00664     if(MyTCBStub.Flags.bSocketReset)
00665     {
00666         MyTCBStub.Flags.bSocketReset = 0;
00667         return TRUE;
00668     }   
00669     
00670     return FALSE;
00671 }
00672 
00673 
00674 /*****************************************************************************
00675   Function:
00676     BOOL TCPIsConnected(TCP_SOCKET hTCP)
00677 
00678   Summary:
00679     Determines if a socket has an established connection.
00680 
00681   Description:
00682     This function determines if a socket has an established connection to 
00683     a remote node.  Call this function after calling TCPOpen to determine 
00684     when the connection is set up and ready for use.  This function was 
00685     historically used to check for disconnections, but TCPWasReset is now a
00686     more appropriate solution. 
00687 
00688   Precondition:
00689     TCP is initialized.
00690 
00691   Parameters:
00692     hTCP - The socket to check.
00693 
00694   Return Values:
00695     TRUE - The socket has an established connection to a remote node.
00696     FALSE - The socket is not currently connected.
00697 
00698   Remarks:
00699     A socket is said to be connected only if it is in the TCP_ESTABLISHED
00700     state.  Sockets in the process of opening or closing will return FALSE.
00701   ***************************************************************************/
00702 BOOL TCPIsConnected(TCP_SOCKET hTCP)
00703 {
00704     SyncTCBStub(hTCP);
00705     return (MyTCBStub.smState == TCP_ESTABLISHED);
00706 }
00707 
00708 
00709 /*****************************************************************************
00710   Function:
00711     void TCPDisconnect(TCP_SOCKET hTCP)
00712 
00713   Summary:
00714     Disconnects an open socket.
00715 
00716   Description:
00717     This function closes a connection to a remote node by sending a FIN.
00718     The function can be called a second time to force a socket closed by 
00719     sending a RST packet.  This is useful when the application knows that 
00720     the remote node will not send an ACK (if it has crashed or lost its link),
00721     or when the application needs to reuse the socket immediately regardless
00722     of whether or not the remote node would like to transmit more data before
00723     closing.
00724 
00725   Precondition:
00726     TCP is initialized.
00727 
00728   Parameters:
00729     hTCP - The socket to check.
00730 
00731   Returns:
00732     None
00733 
00734   Remarks:
00735     This function does nothing if the socket is not already connected.
00736     
00737     If the socket is using SSL, a CLOSE_NOTIFY record will be transmitted
00738     first to allow the SSL session to be resumed at a later time.
00739   ***************************************************************************/
00740 void TCPDisconnect(TCP_SOCKET hTCP)
00741 {
00742     SyncTCBStub(hTCP);
00743 
00744     // Delete all data in the RX FIFO
00745     // In this stack's API, the application TCP handle is 
00746     // immediately invalid after calling this function, so there 
00747     // is no longer any way to receive data from the TCP RX FIFO, 
00748     // even though the data is still there.  Leaving the data there 
00749     // could interfere with the remote node sending us a FIN if our
00750     // RX window is zero
00751     MyTCBStub.rxTail = MyTCBStub.rxHead;
00752 
00753     switch(MyTCBStub.smState)
00754     {
00755         #if defined(STACK_CLIENT_MODE) && defined(STACK_USE_DNS)
00756         case TCP_DNS_RESOLVE:
00757             DNSEndUsage();  // Release the DNS module, since the user is aborting
00758             CloseSocket();
00759             break;
00760         #endif
00761 
00762         case TCP_SYN_SENT:
00763             CloseSocket();
00764             break;
00765 
00766         case TCP_SYN_RECEIVED:
00767         case TCP_ESTABLISHED:
00768             #if defined(STACK_USE_SSL)
00769             // When disconnecting SSL sockets, send a close_notify so we can resume later
00770             if(MyTCBStub.sslStubID != SSL_INVALID_ID)
00771             {
00772                 // Flush pending data and send close_notify
00773                 SSLTxRecord(hTCP, MyTCBStub.sslStubID, SSL_APPLICATION);
00774                 SSLTxMessage(hTCP, MyTCBStub.sslStubID, SSL_ALERT_CLOSE_NOTIFY);
00775             }
00776             #endif
00777 
00778             // Send the FIN
00779             SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
00780             MyTCBStub.smState = TCP_FIN_WAIT_1;
00781             break;
00782 
00783         case TCP_CLOSE_WAIT:
00784             // Send the FIN
00785             SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
00786             MyTCBStub.smState = TCP_LAST_ACK;
00787             break;
00788             
00789         // These states are all already closed or don't need explicit disconnecting -- they will disconnect by themselves after a while
00790         //case TCP_CLOSED:
00791         //case TCP_LISTEN:
00792         //case TCP_CLOSING:
00793         //case TCP_TIME_WAIT:
00794         //  return;
00795 
00796         case TCP_CLOSED_BUT_RESERVED:
00797             MyTCBStub.smState = TCP_CLOSED;
00798             break;
00799 
00800         // This state will close itself after some delay, however, 
00801         // this is handled so that the user can call TCPDisconnect() 
00802         // twice to immediately close a socket (using an RST) without 
00803         // having to get an ACK back from the remote node.  This is 
00804         // great for instance when the application determines that 
00805         // the remote node has been physically disconnected and 
00806         // already knows that no ACK will be returned.  Alternatively, 
00807         // if the application needs to immediately reuse the socket 
00808         // regardless of what the other node's state is in (half open).
00809         case TCP_FIN_WAIT_1:
00810         case TCP_FIN_WAIT_2:
00811         case TCP_LAST_ACK:
00812         default:
00813             SendTCP(RST | ACK, 0);
00814             CloseSocket();
00815             break;
00816     }
00817 }
00818 
00819 
00820 /*****************************************************************************
00821   Function:
00822     SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
00823 
00824   Summary:
00825     Obtains information about a currently open socket.
00826 
00827   Description:
00828     Returns the SOCKET_INFO structure associated with this socket.  This 
00829     contains the NODE_INFO structure with IP and MAC address (or gateway
00830     MAC) and the remote port.
00831 
00832   Precondition:
00833     TCP is initialized and the socket is connected.
00834 
00835   Parameters:
00836     hTCP - The socket to check.
00837 
00838   Returns:
00839     The SOCKET_INFO structure associated with this socket.  This structure is 
00840     allocated statically by the function and is valid only until the next 
00841     time TCPGetRemoteInfo() is called.
00842   ***************************************************************************/
00843 SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
00844 {
00845     static SOCKET_INFO  RemoteInfo;
00846 
00847     SyncTCB();
00848     memcpy((void*)&RemoteInfo.remote, (void*)&MyTCB.remote, sizeof(NODE_INFO));
00849     RemoteInfo.remotePort.Val = MyTCB.remotePort.Val;
00850 
00851     return &RemoteInfo;
00852 }
00853 
00854 
00855 
00856 /****************************************************************************
00857   Section:
00858     Transmit Functions
00859   ***************************************************************************/
00860 
00861 /*****************************************************************************
00862   Function:
00863     void TCPFlush(TCP_SOCKET hTCP)
00864 
00865   Summary:
00866     Immediately transmits all pending TX data.
00867 
00868   Description:
00869     This function immediately transmits all pending TX data with a PSH 
00870     flag.  If this function is not called, data will automatically be sent
00871     when either a) the TX buffer is half full or b) the 
00872     TCP_AUTO_TRANSMIT_TIMEOUT_VAL (default: 40ms) has elapsed.
00873 
00874   Precondition:
00875     TCP is initialized and the socket is connected.
00876 
00877   Parameters:
00878     hTCP - The socket whose data is to be transmitted.
00879 
00880   Returns:
00881     None
00882 
00883   Remarks:
00884     SSL application data is automatically flushed, so this function has 
00885     no effect for SSL sockets.
00886   ***************************************************************************/
00887 void TCPFlush(TCP_SOCKET hTCP)
00888 {
00889     SyncTCBStub(hTCP);
00890     SyncTCB();
00891 
00892     // NOTE: Pending SSL data will NOT be transferred here
00893 
00894     if(MyTCBStub.txHead != MyTCB.txUnackedTail)
00895     {
00896         // Send the TCP segment with all unacked bytes
00897         SendTCP(ACK, SENDTCP_RESET_TIMERS);
00898     }
00899 }
00900 
00901 
00902 /*****************************************************************************
00903   Function:
00904     void WORD TCPIsPutReady(TCP_SOCKET hTCP)
00905 
00906   Summary:
00907     Determines how much free space is available in the TCP TX buffer.
00908 
00909   Description:
00910     Call this function to determine how many bytes can be written to the 
00911     TCP TX buffer.  If this function returns zero, the application must 
00912     return to the main stack loop before continuing in order to transmit
00913     more data.
00914 
00915   Precondition:
00916     TCP is initialized.
00917 
00918   Parameters:
00919     hTCP - The socket to check.
00920 
00921   Returns:
00922     The number of bytes available to be written in the TCP TX buffer.
00923   ***************************************************************************/
00924 WORD TCPIsPutReady(TCP_SOCKET hTCP)
00925 {
00926     BYTE i;
00927 
00928     SyncTCBStub(hTCP);
00929 
00930     i = MyTCBStub.smState;
00931 
00932     // Unconnected sockets shouldn't be transmitting anything.
00933     if(!( (i == TCP_ESTABLISHED) || (i == TCP_CLOSE_WAIT) ))
00934         return 0;
00935 
00936     // Calculate the free space in this socket's TX FIFO
00937     #if defined(STACK_USE_SSL)
00938     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
00939     {// Use sslTxHead as the head pointer when SSL is active
00940         WORD rem;
00941         
00942         // Find out raw free space
00943         if(MyTCBStub.sslTxHead >= MyTCBStub.txTail)
00944             rem = (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.sslTxHead - MyTCBStub.txTail);
00945         else
00946             rem = MyTCBStub.txTail - MyTCBStub.sslTxHead - 1;
00947             
00948         // Reserve space for a new MAC and header
00949         if(rem > 22)
00950             return rem - 22;
00951         else
00952             return 0;
00953     }
00954     #endif
00955     
00956     if(MyTCBStub.txHead >= MyTCBStub.txTail)
00957         return (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.txHead - MyTCBStub.txTail);
00958     else
00959         return MyTCBStub.txTail - MyTCBStub.txHead - 1;
00960 }
00961 
00962 
00963 /*****************************************************************************
00964   Function:
00965     BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
00966 
00967   Description:
00968     Writes a single byte to a TCP socket.
00969 
00970   Precondition:
00971     TCP is initialized.
00972 
00973   Parameters:
00974     hTCP - The socket to which data is to be written.
00975     byte - The byte to write.
00976 
00977   Return Values:
00978     TRUE - The byte was written to the transmit buffer.
00979     FALSE - The transmit buffer was full, or the socket is not connected.
00980   ***************************************************************************/
00981 BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
00982 {
00983     WORD wFreeTXSpace;
00984 
00985     SyncTCBStub(hTCP);
00986 
00987     wFreeTXSpace = TCPIsPutReady(hTCP);
00988     if(wFreeTXSpace == 0u)
00989         return FALSE;
00990     else if(wFreeTXSpace == 1u) // About to run out of space, lets transmit so the remote node might send an ACK back faster
00991         TCPFlush(hTCP); 
00992 
00993     // Send all current bytes if we are crossing half full
00994     // This is required to improve performance with the delayed 
00995     // acknowledgement algorithm
00996     if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
00997     {
00998         TCPFlush(hTCP); 
00999         MyTCBStub.Flags.bHalfFullFlush = TRUE;
01000     }
01001 
01002     #if defined(STACK_USE_SSL)
01003     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
01004     {
01005         TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
01006         if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
01007             MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
01008     }
01009     else
01010     {
01011         TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
01012         if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
01013             MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01014     }
01015     #else
01016     TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
01017     if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
01018         MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01019     #endif
01020     
01021 
01022     // Send the last byte as a separate packet (likely will make the remote node send back ACK faster)
01023     if(wFreeTXSpace == 1u)
01024     {
01025         TCPFlush(hTCP);
01026     }
01027     // If not already enabled, start a timer so this data will 
01028     // eventually get sent even if the application doens't call
01029     // TCPFlush()
01030     else if(!MyTCBStub.Flags.bTimer2Enabled)
01031     {
01032         MyTCBStub.Flags.bTimer2Enabled = TRUE;
01033         MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
01034     }
01035 
01036     return TRUE;
01037 }
01038 
01039 /*****************************************************************************
01040   Function:
01041     WORD TCPPutArray(TCP_SOCKET hTCP, BYTE* data, WORD len)
01042 
01043   Description:
01044     Writes an array from RAM to a TCP socket.
01045 
01046   Precondition:
01047     TCP is initialized.
01048 
01049   Parameters:
01050     hTCP - The socket to which data is to be written.
01051     data - Pointer to the array to be written.
01052     len  - Number of bytes to be written.
01053 
01054   Returns:
01055     The number of bytes written to the socket.  If less than len, the
01056     buffer became full or the socket is not conected.
01057   ***************************************************************************/
01058 WORD TCPPutArray(TCP_SOCKET hTCP, BYTE* data, WORD len)
01059 {
01060     WORD wActualLen;
01061     WORD wFreeTXSpace;
01062     WORD wRightLen = 0;
01063 
01064     SyncTCBStub(hTCP);
01065 
01066     wFreeTXSpace = TCPIsPutReady(hTCP);
01067     if(wFreeTXSpace == 0u)
01068     {
01069         TCPFlush(hTCP);
01070         return 0;
01071     }
01072 
01073     wActualLen = wFreeTXSpace;
01074     if(wFreeTXSpace > len)
01075         wActualLen = len;
01076 
01077     // Send all current bytes if we are crossing half full
01078     // This is required to improve performance with the delayed 
01079     // acknowledgement algorithm
01080     if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
01081     {
01082         TCPFlush(hTCP); 
01083         MyTCBStub.Flags.bHalfFullFlush = TRUE;
01084     }
01085     
01086     #if defined(STACK_USE_SSL)
01087     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
01088     {
01089         // See if we need a two part put
01090         if(MyTCBStub.sslTxHead + wActualLen >= MyTCBStub.bufferRxStart)
01091         {
01092             wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
01093             TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
01094             data += wRightLen;
01095             wActualLen -= wRightLen;
01096             MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
01097         }
01098     
01099         TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
01100         MyTCBStub.sslTxHead += wActualLen;
01101     }
01102     else
01103     {
01104         // See if we need a two part put
01105         if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
01106         {
01107             wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
01108             TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
01109             data += wRightLen;
01110             wActualLen -= wRightLen;
01111             MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01112         }
01113     
01114         TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
01115         MyTCBStub.txHead += wActualLen;
01116     }
01117     #else
01118     // See if we need a two part put
01119     if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
01120     {
01121         wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
01122         TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
01123         data += wRightLen;
01124         wActualLen -= wRightLen;
01125         MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01126     }
01127 
01128     TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
01129     MyTCBStub.txHead += wActualLen;
01130     #endif
01131 
01132     // Send these bytes right now if we are out of TX buffer space
01133     if(wFreeTXSpace <= len)
01134     {
01135         TCPFlush(hTCP);
01136     }
01137     // If not already enabled, start a timer so this data will 
01138     // eventually get sent even if the application doens't call
01139     // TCPFlush()
01140     else if(!MyTCBStub.Flags.bTimer2Enabled)
01141     {
01142         MyTCBStub.Flags.bTimer2Enabled = TRUE;
01143         MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
01144     }
01145 
01146     return wActualLen + wRightLen;
01147 }
01148 
01149 /*****************************************************************************
01150   Function:
01151     WORD TCPPutROMArray(TCP_SOCKET hTCP, ROM BYTE* data, WORD len)
01152 
01153   Description:
01154     Writes an array from ROM to a TCP socket.
01155 
01156   Precondition:
01157     TCP is initialized.
01158 
01159   Parameters:
01160     hTCP - The socket to which data is to be written.
01161     data - Pointer to the array to be written.
01162     len  - Number of bytes to be written.
01163 
01164   Returns:
01165     The number of bytes written to the socket.  If less than len, the
01166     buffer became full or the socket is not conected.
01167 
01168   Remarks:
01169     This function is aliased to TCPPutArray on non-PIC18 platforms.
01170   ***************************************************************************/
01171 #if defined(__18CXX)
01172 WORD TCPPutROMArray(TCP_SOCKET hTCP, ROM BYTE* data, WORD len)
01173 {
01174     WORD wActualLen;
01175     WORD wFreeTXSpace;
01176     WORD wRightLen = 0;
01177 
01178     SyncTCBStub(hTCP);
01179 
01180     wFreeTXSpace = TCPIsPutReady(hTCP);
01181     if(wFreeTXSpace == 0u)
01182     {
01183         TCPFlush(hTCP);
01184         return 0;
01185     }
01186 
01187     // Send all current bytes if we are crossing half full
01188     // This is required to improve performance with the delayed 
01189     // acknowledgement algorithm
01190     if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
01191     {
01192         TCPFlush(hTCP); 
01193         MyTCBStub.Flags.bHalfFullFlush = TRUE;
01194     }
01195     
01196     wActualLen = wFreeTXSpace;
01197     if(wFreeTXSpace > len)
01198         wActualLen = len;
01199     
01200     #if defined(STACK_USE_SSL)
01201     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
01202     {
01203         // See if we need a two part put
01204         if(MyTCBStub.sslTxHead + wActualLen >= MyTCBStub.bufferRxStart)
01205         {
01206             wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
01207             TCPRAMCopyROM(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, data, wRightLen);
01208             data += wRightLen;
01209             wActualLen -= wRightLen;
01210             MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
01211         }
01212     
01213         TCPRAMCopyROM(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, data, wActualLen);
01214         MyTCBStub.sslTxHead += wActualLen;
01215     }
01216     else
01217     {
01218         // See if we need a two part put
01219         if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
01220         {
01221             wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
01222             TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wRightLen);
01223             data += wRightLen;
01224             wActualLen -= wRightLen;
01225             MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01226         }
01227     
01228         TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wActualLen);
01229         MyTCBStub.txHead += wActualLen;
01230     }
01231     #else
01232     // See if we need a two part put
01233     if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
01234     {
01235         wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
01236         TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wRightLen);
01237         data += wRightLen;
01238         wActualLen -= wRightLen;
01239         MyTCBStub.txHead = MyTCBStub.bufferTxStart;
01240     }
01241 
01242     TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wActualLen);
01243     MyTCBStub.txHead += wActualLen;
01244     #endif
01245 
01246     // Send these bytes right now if we are out of TX buffer space
01247     if(wFreeTXSpace <= len)
01248     {
01249         TCPFlush(hTCP);
01250     }
01251     // If not already enabled, start a timer so this data will 
01252     // eventually get sent even if the application doens't call
01253     // TCPFlush()
01254     else if(!MyTCBStub.Flags.bTimer2Enabled)
01255     {
01256         MyTCBStub.Flags.bTimer2Enabled = TRUE;
01257         MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
01258     }
01259 
01260     return wActualLen + wRightLen;
01261 }
01262 #endif
01263 
01264 /*****************************************************************************
01265   Function:
01266     BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE* data)
01267 
01268   Description:
01269     Writes a null-terminated string from RAM to a TCP socket.  The 
01270     null-terminator is not copied to the socket.
01271 
01272   Precondition:
01273     TCP is initialized.
01274 
01275   Parameters:
01276     hTCP - The socket to which data is to be written.
01277     data - Pointer to the string to be written.
01278 
01279   Returns:
01280     Pointer to the byte following the last byte written to the socket.  If
01281     this pointer does not dereference to a NUL byte, the buffer became full
01282     or the socket is not connected.
01283 
01284   Remarks:
01285     The return value of this function differs from that of TCPPutArray.  To
01286     write long strings in a single state, initialize the *data pointer to the
01287     first byte, then call this function repeatedly (breaking to the main 
01288     stack loop after each call) until the return value dereferences to a NUL
01289     byte.  Save the return value as the new starting *data pointer otherwise.
01290   ***************************************************************************/
01291 BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE* data)
01292 {
01293     return data + TCPPutArray(hTCP, data, strlen((char*)data));
01294 }
01295 
01296 /*****************************************************************************
01297   Function:
01298     BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE* data)
01299 
01300   Description:
01301     Writes a null-terminated string from ROM to a TCP socket.  The 
01302     null-terminator is not copied to the socket.
01303 
01304   Precondition:
01305     TCP is initialized.
01306 
01307   Parameters:
01308     hTCP - The socket to which data is to be written.
01309     data - Pointer to the string to be written.
01310 
01311   Returns:
01312     Pointer to the byte following the last byte written to the socket.  If
01313     this pointer does not dereference to a NUL byte, the buffer became full
01314     or the socket is not connected.
01315 
01316   Remarks:
01317     The return value of this function differs from that of TCPPutArray.  To
01318     write long strings in a single state, initialize the *data pointer to the
01319     first byte, then call this function repeatedly (breaking to the main 
01320     stack loop after each call) until the return value dereferences to a NUL
01321     byte.  Save the return value as the new starting *data pointer otherwise.
01322     
01323     This function is aliased to TCPPutString on non-PIC18 platforms.
01324   ***************************************************************************/
01325 #if defined(__18CXX)
01326 ROM BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE* data)
01327 {
01328     return data + TCPPutROMArray(hTCP, data, strlenpgm((ROM char*)data));
01329 }
01330 #endif
01331 
01332 /*****************************************************************************
01333   Function:
01334     WORD TCPGetTxFIFOFull(TCP_SOCKET hTCP)
01335 
01336   Description:
01337     Determines how many bytes are pending in the TCP TX FIFO.
01338 
01339   Precondition:
01340     TCP is initialized.
01341 
01342   Parameters:
01343     hTCP - The socket to check.
01344 
01345   Returns:
01346     Number of bytes pending to be flushed in the TCP TX FIFO.
01347   ***************************************************************************/
01348 WORD TCPGetTxFIFOFull(TCP_SOCKET hTCP)
01349 {
01350     WORD wDataLen;
01351     WORD wFIFOSize;
01352 
01353     SyncTCBStub(hTCP);
01354 
01355     // Calculate total usable FIFO size
01356     wFIFOSize = MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1;
01357 
01358     // Find out how many data bytes are free in the TX FIFO
01359     wDataLen = TCPIsPutReady(hTCP);
01360 
01361     return wFIFOSize - wDataLen;
01362 }
01363 
01364 
01365 
01366 /****************************************************************************
01367   Section:
01368     Receive Functions
01369   ***************************************************************************/
01370 
01371 /*****************************************************************************
01372   Function:
01373     void TCPDiscard(TCP_SOCKET hTCP)
01374 
01375   Description:
01376     Discards any pending data in the TCP RX FIFO.
01377 
01378   Precondition:
01379     TCP is initialized.
01380 
01381   Parameters:
01382     hTCP - The socket whose RX FIFO is to be cleared.
01383 
01384   Returns:
01385     None
01386   ***************************************************************************/
01387 void TCPDiscard(TCP_SOCKET hTCP)
01388 {
01389     if(TCPIsGetReady(hTCP))
01390     {
01391         SyncTCBStub(hTCP);
01392     
01393         // Delete all data in the RX buffer
01394         MyTCBStub.rxTail = MyTCBStub.rxHead;
01395     
01396         // Send a Window update message to the remote node
01397         SendTCP(ACK, SENDTCP_RESET_TIMERS);
01398     }
01399 }
01400 
01401 
01402 /*****************************************************************************
01403   Function:
01404     void WORD TCPIsGetReady(TCP_SOCKET hTCP)
01405 
01406   Summary:
01407     Determines how many bytes can be read from the TCP RX buffer.
01408 
01409   Description:
01410     Call this function to determine how many bytes can be read from the 
01411     TCP RX buffer.  If this function returns zero, the application must 
01412     return to the main stack loop before continuing in order to wait for
01413     more data to arrive.
01414 
01415   Precondition:
01416     TCP is initialized.
01417 
01418   Parameters:
01419     hTCP - The socket to check.
01420 
01421   Returns:
01422     The number of bytes available to be read from the TCP RX buffer.
01423   ***************************************************************************/
01424 WORD TCPIsGetReady(TCP_SOCKET hTCP)
01425 {
01426     SyncTCBStub(hTCP);
01427         
01428     if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
01429         return MyTCBStub.rxHead - MyTCBStub.rxTail;
01430     else
01431         return (MyTCBStub.bufferEnd - MyTCBStub.rxTail + 1) + (MyTCBStub.rxHead - MyTCBStub.bufferRxStart);
01432 }
01433 
01434 
01435 /*****************************************************************************
01436   Function:
01437     BOOL TCPGet(TCP_SOCKET hTCP, BYTE* byte)
01438 
01439   Description:
01440     Retrieves a single byte to a TCP socket.
01441 
01442   Precondition:
01443     TCP is initialized.
01444 
01445   Parameters:
01446     hTCP - The socket from which to read.
01447     byte - Pointer to location in which the read byte should be stored.
01448 
01449   Return Values:
01450     TRUE - A byte was read from the buffer.
01451     FALSE - The buffer was empty, or the socket is not connected.
01452   ***************************************************************************/
01453 BOOL TCPGet(TCP_SOCKET hTCP, BYTE* byte)
01454 {
01455     WORD wGetReadyCount;
01456 
01457     // See if there is any data which can be read
01458     wGetReadyCount = TCPIsGetReady(hTCP);
01459     if(wGetReadyCount == 0u)
01460         return FALSE;
01461 
01462     SyncTCBStub(hTCP);
01463     
01464     if(byte)
01465         TCPRAMCopy((PTR_BASE)byte, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, 1);
01466     if(++MyTCBStub.rxTail > MyTCBStub.bufferEnd)
01467         MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
01468 
01469     // Send a window update if we've run out of data
01470     if(wGetReadyCount == 1u)
01471     {
01472         MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
01473     }
01474     // If not already enabled, start a timer so a window 
01475     // update will get sent to the remote node at some point
01476     else if(!MyTCBStub.Flags.bTimer2Enabled)
01477     {
01478         MyTCBStub.Flags.bTimer2Enabled = TRUE;
01479         MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
01480     }
01481 
01482 
01483     return TRUE;
01484 }
01485 
01486 
01487 /*****************************************************************************
01488   Function:
01489     WORD TCPGetArray(TCP_SOCKET hTCP, BYTE* data, WORD len)
01490 
01491   Description:
01492     Reads an array from a TCP socket.
01493 
01494   Precondition:
01495     TCP is initialized.
01496 
01497   Parameters:
01498     hTCP - The socket from which data is to be read.
01499     data - Pointer to the array to store data that was read.
01500     len  - Number of bytes to be read.
01501 
01502   Returns:
01503     The number of bytes read from the socket.  If less than len, the
01504     buffer became empty or the socket is not conected.
01505   ***************************************************************************/
01506 WORD TCPGetArray(TCP_SOCKET hTCP, BYTE* buffer, WORD len)
01507 {
01508     WORD wGetReadyCount;
01509     WORD RightLen = 0;
01510 
01511     // See if there is any data which can be read
01512     wGetReadyCount = TCPIsGetReady(hTCP);
01513     if(wGetReadyCount == 0u)
01514         return 0x0000u;
01515 
01516     SyncTCBStub(hTCP);
01517 
01518     // Make sure we don't try to read more data than is available
01519     if(len > wGetReadyCount)
01520         len = wGetReadyCount;
01521 
01522     // See if we need a two part get
01523     if(MyTCBStub.rxTail + len > MyTCBStub.bufferEnd)
01524     {
01525         RightLen = MyTCBStub.bufferEnd - MyTCBStub.rxTail + 1;
01526         if(buffer)
01527         {
01528             TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, RightLen);
01529             buffer += RightLen;
01530         }
01531         len -= RightLen;
01532         MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
01533     }
01534 
01535     if(buffer)
01536         TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, len);
01537     MyTCBStub.rxTail += len;
01538     len += RightLen;
01539 
01540     // Send a window update if we've run low on data
01541     if(wGetReadyCount - len <= len)
01542     {
01543         MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
01544     }
01545     else if(!MyTCBStub.Flags.bTimer2Enabled)
01546     // If not already enabled, start a timer so a window 
01547     // update will get sent to the remote node at some point
01548     {
01549         MyTCBStub.Flags.bTimer2Enabled = TRUE;
01550         MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
01551     }
01552 
01553     return len;
01554 }
01555 
01556 
01557 /*****************************************************************************
01558   Function:
01559     WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
01560 
01561   Description:
01562     Determines how many bytes are free in the RX FIFO.
01563 
01564   Precondition:
01565     TCP is initialized.
01566 
01567   Parameters:
01568     hTCP - The socket to check.
01569 
01570   Returns:
01571     The number of bytes free in the TCP RX FIFO.  If zero, no additional 
01572     data can be received until the application removes some data using one
01573     of the TCPGet family functions.
01574   ***************************************************************************/
01575 WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
01576 {
01577     WORD wDataLen;
01578     WORD wFIFOSize;
01579     
01580     SyncTCBStub(hTCP);
01581     
01582     // Calculate total usable FIFO size
01583     wFIFOSize = MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart;
01584 
01585     #if defined(STACK_USE_SSL)
01586     {
01587         PTR_BASE SSLtemp = MyTCBStub.rxHead;
01588 
01589         // Move SSL pointer to determine full buffer size
01590         if(MyTCBStub.sslStubID != SSL_INVALID_ID)
01591             MyTCBStub.rxHead = MyTCBStub.sslRxHead;
01592 
01593         // Find out how many data bytes are actually in the RX FIFO
01594         wDataLen = TCPIsGetReady(hTCP);
01595         
01596         // Move SSL pointer back to proper location (if we changed it)
01597         MyTCBStub.rxHead = SSLtemp;
01598     }
01599     #else
01600     {
01601         // Find out how many data bytes are actually in the RX FIFO
01602         wDataLen = TCPIsGetReady(hTCP);
01603     }
01604     #endif
01605     
01606     // Perform the calculation  
01607     return wFIFOSize - wDataLen;
01608 }
01609 
01610 
01611 
01612 /****************************************************************************
01613   Section:
01614     Search Functions
01615   ***************************************************************************/
01616 
01617 /*****************************************************************************
01618   Function:
01619     WORD TCPFindArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen, 
01620                         WORD wStart, WORD wSearchLen, BOOL bTextCompare)
01621 
01622   Summary:
01623     Searches for a string in the TCP RX buffer.
01624 
01625   Description:
01626     This function finds the first occurrance of an array of bytes in the
01627     TCP RX buffer.  It can be used by an application to abstract searches 
01628     out of their own application code.  For increased efficiency, the 
01629     function is capable of limiting the scope of search to a specific
01630     range of bytes.  It can also perform a case-insensitive search if
01631     required.
01632     
01633     For example, if the buffer contains "I love PIC MCUs!" and the search
01634     array is "love" with a length of 4, a value of 2 will be returned.
01635 
01636   Precondition:
01637     TCP is initialized.
01638 
01639   Parameters:
01640     hTCP - The socket to search within.
01641     cFindArray - The array of bytes to find in the buffer.
01642     wLen - Length of cFindArray.
01643     wStart - Zero-indexed starting position within the buffer.
01644     wSearchLen - Length from wStart to search in the buffer.
01645     bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
01646 
01647   Return Values:
01648     0xFFFF - Search array not found
01649     Otherwise - Zero-indexed position of the first occurrance
01650 
01651   Remarks:
01652     Since this function usually must transfer data from external storage
01653     to internal RAM for comparison, its performance degrades significantly
01654     when the buffer is full and the array is not found.  For better 
01655     performance, try to search for characters that are expected to exist or
01656     limit the scope of the search as much as possible.  The HTTP2 module, 
01657     for example, uses this function to parse headers.  However, it searches 
01658     for newlines, then the separating colon, then reads the header name to 
01659     RAM for final comparison.  This has proven to be significantly faster  
01660     than searching for full header name strings outright.
01661   ***************************************************************************/
01662 WORD TCPFindArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
01663 {
01664     PTR_BASE ptrRead;
01665     WORD wDataLen;
01666     WORD wBytesUntilWrap;
01667     PTR_BASE ptrLocation;
01668     WORD wLenStart;
01669     BYTE *cFindArrayStart;
01670     BYTE i, j, k;
01671     BOOL isFinding;
01672     BYTE buffer[32];
01673 
01674     if(wLen == 0u)
01675         return 0u;
01676 
01677     SyncTCBStub(hTCP);
01678 
01679     // Find out how many bytes are in the RX FIFO and return 
01680     // immediately if we won't possibly find a match
01681     wDataLen = TCPIsGetReady(hTCP) - wStart;
01682     if(wDataLen < wLen)
01683         return 0xFFFFu;
01684     if(wSearchLen && wDataLen > wSearchLen)
01685         wDataLen = wSearchLen;
01686 
01687     ptrLocation = MyTCBStub.rxTail + wStart;
01688     if(ptrLocation > MyTCBStub.bufferEnd)
01689         ptrLocation -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
01690     ptrRead = ptrLocation;
01691     wBytesUntilWrap = MyTCBStub.bufferEnd - ptrLocation + 1;
01692     ptrLocation = wStart;
01693     wLenStart = wLen;
01694     cFindArrayStart = cFindArray;
01695     j = *cFindArray++;
01696     isFinding = FALSE;
01697     if(bTextCompare)
01698     {
01699         if(j >= 'a' && j <= 'z')
01700             j += 'A'-'a';
01701     }
01702 
01703     // Search for the array
01704     while(1)
01705     {
01706         // Figure out how big of a chunk to read
01707         k = sizeof(buffer);
01708         if(k > wBytesUntilWrap)
01709             k = wBytesUntilWrap;
01710         if((WORD)k > wDataLen)
01711             k = wDataLen;
01712 
01713         // Read a chunk of data into the buffer
01714         TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, (WORD)k);
01715         ptrRead += k;
01716         wBytesUntilWrap -= k;
01717 
01718         if(wBytesUntilWrap == 0u)
01719         {
01720             ptrRead = MyTCBStub.bufferRxStart;
01721             wBytesUntilWrap = 0xFFFFu;
01722         }
01723 
01724         // Convert everything to uppercase
01725         if(bTextCompare)
01726         {
01727             for(i = 0; i < k; i++)
01728             {
01729                 if(buffer[i] >= 'a' && buffer[i] <= 'z')
01730                     buffer[i] += 'A'-'a';
01731 
01732                 if(j == buffer[i])
01733                 {
01734                     if(--wLen == 0u)
01735                         return ptrLocation-wLenStart + i + 1;
01736                     j = *cFindArray++;
01737                     isFinding = TRUE;
01738                     if(j >= 'a' && j <= 'z')
01739                         j += 'A'-'a';
01740                 }
01741                 else
01742                 {
01743                     wLen = wLenStart;
01744                     if(isFinding)
01745                     {
01746                         cFindArray = cFindArrayStart;
01747                         j = *cFindArray++;
01748                         if(j >= 'a' && j <= 'z')
01749                             j += 'A'-'a';
01750                         isFinding = FALSE;
01751                     }
01752                 }
01753             }
01754         }
01755         else    // Compare as is
01756         {
01757             for(i = 0; i < k; i++)
01758             {
01759                 if(j == buffer[i])
01760                 {
01761                     if(--wLen == 0)
01762                         return ptrLocation-wLenStart + i + 1;
01763                     j = *cFindArray++;
01764                     isFinding = TRUE;
01765                 }
01766                 else
01767                 {
01768                     wLen = wLenStart;
01769                     if(isFinding)
01770                     {
01771                         cFindArray = cFindArrayStart;
01772                         j = *cFindArray++;
01773                         isFinding = FALSE;
01774                     }
01775                 }
01776             }
01777         }
01778 
01779         // Check to see if it is impossible to find a match
01780         wDataLen -= k;
01781         if(wDataLen < wLen)
01782             return 0xFFFFu;
01783 
01784         ptrLocation += k;
01785     }
01786 }
01787 
01788 /*****************************************************************************
01789   Function:
01790     WORD TCPFindROMArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen, 
01791                         WORD wStart, WORD wSearchLen, BOOL bTextCompare)
01792 
01793   Summary:
01794     Searches for a ROM string in the TCP RX buffer.
01795 
01796   Description:
01797     This function finds the first occurrance of an array of bytes in the
01798     TCP RX buffer.  It can be used by an application to abstract searches 
01799     out of their own application code.  For increased efficiency, the 
01800     function is capable of limiting the scope of search to a specific
01801     range of bytes.  It can also perform a case-insensitive search if
01802     required.
01803     
01804     For example, if the buffer contains "I love PIC MCUs!" and the search
01805     array is "love" with a length of 4, a value of 2 will be returned.
01806 
01807   Precondition:
01808     TCP is initialized.
01809 
01810   Parameters:
01811     hTCP - The socket to search within.
01812     cFindArray - The array of bytes to find in the buffer.
01813     wLen - Length of cFindArray.
01814     wStart - Zero-indexed starting position within the buffer.
01815     wSearchLen - Length from wStart to search in the buffer.
01816     bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
01817 
01818   Return Values:
01819     0xFFFF - Search array not found
01820     Otherwise - Zero-indexed position of the first occurrance
01821 
01822   Remarks:
01823     Since this function usually must transfer data from external storage
01824     to internal RAM for comparison, its performance degrades significantly
01825     when the buffer is full and the array is not found.  For better 
01826     performance, try to search for characters that are expected to exist or
01827     limit the scope of the search as much as possible.  The HTTP2 module, 
01828     for example, uses this function to parse headers.  However, it searches 
01829     for newlines, then the separating colon, then reads the header name to 
01830     RAM for final comparison.  This has proven to be significantly faster  
01831     than searching for full header name strings outright.
01832     
01833     This function is aliased to TCPFindArrayEx on non-PIC18 platforms.
01834   ***************************************************************************/
01835 #if defined(__18CXX)
01836 WORD TCPFindROMArrayEx(TCP_SOCKET hTCP, ROM BYTE* cFindArray, WORD wLen, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
01837 {
01838     PTR_BASE ptrRead;
01839     WORD wDataLen;
01840     WORD wBytesUntilWrap;
01841     PTR_BASE ptrLocation;
01842     WORD wLenStart;
01843     ROM BYTE *cFindArrayStart;
01844     BYTE i, j, k;
01845     BOOL isFinding;
01846     BYTE buffer[32];
01847 
01848     if(wLen == 0u)
01849         return 0u;
01850 
01851     SyncTCBStub(hTCP);
01852 
01853     // Find out how many bytes are in the RX FIFO and return 
01854     // immediately if we won't possibly find a match
01855     wDataLen = TCPIsGetReady(hTCP) - wStart;
01856     if(wDataLen < wLen)
01857         return 0xFFFFu;
01858     if(wSearchLen && wDataLen > wSearchLen)
01859         wDataLen = wSearchLen;
01860 
01861     ptrLocation = MyTCBStub.rxTail + wStart;
01862     if(ptrLocation > MyTCBStub.bufferEnd)
01863         ptrLocation -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
01864     ptrRead = ptrLocation;
01865     wBytesUntilWrap = MyTCBStub.bufferEnd - ptrLocation + 1;
01866     ptrLocation = wStart;
01867     wLenStart = wLen;
01868     cFindArrayStart = cFindArray;
01869     j = *cFindArray++;
01870     isFinding = FALSE;
01871     if(bTextCompare)
01872     {
01873         if(j >= 'a' && j <= 'z')
01874             j += 'A'-'a';
01875     }
01876 
01877     // Search for the array
01878     while(1)
01879     {
01880         // Figure out how big of a chunk to read
01881         k = sizeof(buffer);
01882         if(k > wBytesUntilWrap)
01883             k = wBytesUntilWrap;
01884         if((WORD)k > wDataLen)
01885             k = wDataLen;
01886 
01887         // Read a chunk of data into the buffer
01888         TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, (WORD)k);
01889         ptrRead += k;
01890         wBytesUntilWrap -= k;
01891 
01892         if(wBytesUntilWrap == 0)
01893         {
01894             ptrRead = MyTCBStub.bufferRxStart;
01895             wBytesUntilWrap = 0xFFFFu;
01896         }
01897 
01898         // Convert everything to uppercase
01899         if(bTextCompare)
01900         {
01901             for(i = 0; i < k; i++)
01902             {
01903                 if(buffer[i] >= 'a' && buffer[i] <= 'z')
01904                     buffer[i] += 'A'-'a';
01905 
01906                 if(j == buffer[i])
01907                 {
01908                     if(--wLen == 0u)
01909                         return ptrLocation-wLenStart + i + 1;
01910                     j = *cFindArray++;
01911                     isFinding = TRUE;
01912                     if(j >= 'a' && j <= 'z')
01913                         j += 'A'-'a';
01914                 }
01915                 else
01916                 {
01917                     wLen = wLenStart;
01918                     if(isFinding)
01919                     {
01920                         cFindArray = cFindArrayStart;
01921                         j = *cFindArray++;
01922                         if(j >= 'a' && j <= 'z')
01923                             j += 'A'-'a';
01924                         isFinding = FALSE;
01925                     }
01926                 }
01927             }
01928         }
01929         else    // Compare as is
01930         {
01931             for(i = 0; i < k; i++)
01932             {
01933                 if(j == buffer[i])
01934                 {
01935                     if(--wLen == 0)
01936                         return ptrLocation-wLenStart + i + 1;
01937                     j = *cFindArray++;
01938                     isFinding = TRUE;
01939                 }
01940                 else
01941                 {
01942                     wLen = wLenStart;
01943                     if(isFinding)
01944                     {
01945                         cFindArray = cFindArrayStart;
01946                         j = *cFindArray++;
01947                         isFinding = FALSE;
01948                     }
01949                 }
01950             }
01951         }
01952 
01953         // Check to see if it is impossible to find a match
01954         wDataLen -= k;
01955         if(wDataLen < wLen)
01956             return 0xFFFFu;
01957 
01958         ptrLocation += k;
01959     }
01960 }
01961 #endif
01962 
01963 
01964 /*****************************************************************************
01965   Function:
01966     WORD TCPFindEx(TCP_SOCKET hTCP, BYTE cFind,
01967                         WORD wStart, WORD wSearchLen, BOOL bTextCompare)
01968 
01969   Summary:
01970     Searches for a byte in the TCP RX buffer.
01971 
01972   Description:
01973     This function finds the first occurrance of a byte in the TCP RX
01974     buffer.  It can be used by an application to abstract searches 
01975     out of their own application code.  For increased efficiency, the 
01976     function is capable of limiting the scope of search to a specific
01977     range of bytes.  It can also perform a case-insensitive search if
01978     required.
01979     
01980     For example, if the buffer contains "I love PIC MCUs!" and the cFind
01981     byte is ' ', a value of 1 will be returned.
01982 
01983   Precondition:
01984     TCP is initialized.
01985 
01986   Parameters:
01987     hTCP - The socket to search within.
01988     cFind - The byte to find in the buffer.
01989     wStart - Zero-indexed starting position within the buffer.
01990     wSearchLen - Length from wStart to search in the buffer.
01991     bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
01992 
01993   Return Values:
01994     0xFFFF - Search array not found
01995     Otherwise - Zero-indexed position of the first occurrance
01996 
01997   Remarks:
01998     Since this function usually must transfer data from external storage
01999     to internal RAM for comparison, its performance degrades significantly
02000     when the buffer is full and the array is not found.  For better 
02001     performance, try to search for characters that are expected to exist or
02002     limit the scope of the search as much as possible.  The HTTP2 module, 
02003     for example, uses this function to parse headers.  However, it searches 
02004     for newlines, then the separating colon, then reads the header name to 
02005     RAM for final comparison.  This has proven to be significantly faster  
02006     than searching for full header name strings outright.
02007   ***************************************************************************/
02008 WORD TCPFindEx(TCP_SOCKET hTCP, BYTE cFind, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
02009 {
02010     return TCPFindArrayEx(hTCP, &cFind, sizeof(cFind), wStart, wSearchLen, bTextCompare);
02011 }
02012 
02013 
02014 
02015 /****************************************************************************
02016   Section:
02017     Data Processing Functions
02018   ***************************************************************************/
02019 
02020 /*****************************************************************************
02021   Function:
02022     void TCPTick(void)
02023 
02024   Summary:
02025     Performs periodic TCP tasks.
02026 
02027   Description:
02028     This function performs any required periodic TCP tasks.  Each 
02029     socket's state machine is checked, and any elapsed timeout periods
02030     are handled.
02031 
02032   Precondition:
02033     TCP is initialized.
02034 
02035   Parameters:
02036     None
02037 
02038   Returns:
02039     None
02040   ***************************************************************************/
02041 void TCPTick(void)
02042 {
02043     TCP_SOCKET hTCP;
02044     BOOL bRetransmit;
02045     BOOL bCloseSocket;
02046     BYTE vFlags;
02047     WORD w;
02048 
02049     // Periodically all "not closed" sockets must perform timed operations
02050     for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
02051     {
02052         SyncTCBStub(hTCP);
02053         
02054         // Handle any SSL Processing and Message Transmission
02055         #if defined(STACK_USE_SSL)
02056         if(MyTCBStub.sslStubID != SSL_INVALID_ID)
02057         {
02058             // Handle any periodic tasks, such as RSA operations
02059             SSLPeriodic(hTCP, MyTCBStub.sslStubID);
02060             
02061             // If unsent data is waiting, transmit it as an application record
02062             if(MyTCBStub.sslTxHead != MyTCBStub.txHead && TCPSSLGetPendingTxSize(hTCP) != 0)
02063                 SSLTxRecord(hTCP, MyTCBStub.sslStubID, SSL_APPLICATION);
02064             
02065             // If an SSL message is requested, send it now
02066             if(MyTCBStub.sslReqMessage != SSL_NO_MESSAGE)
02067                 SSLTxMessage(hTCP, MyTCBStub.sslStubID, MyTCBStub.sslReqMessage);
02068         }
02069         #endif
02070         
02071         vFlags = 0x00;
02072         bRetransmit = FALSE;
02073         bCloseSocket = FALSE;
02074 
02075         // Transmit ASAP data if the medium is available
02076         if(MyTCBStub.Flags.bTXASAP || MyTCBStub.Flags.bTXASAPWithoutTimerReset)
02077         {
02078             if(MACIsTxReady())
02079             {
02080                 vFlags = ACK;
02081                 bRetransmit = MyTCBStub.Flags.bTXASAPWithoutTimerReset;
02082             }
02083         }
02084 
02085         // Perform any needed window updates and data transmissions
02086         if(MyTCBStub.Flags.bTimer2Enabled)
02087         {
02088             // See if the timeout has occured, and we need to send a new window update and pending data
02089             if((SHORT)(MyTCBStub.eventTime2 - (WORD)TickGetDiv256()) <= (SHORT)0)
02090                 vFlags = ACK;
02091         }
02092 
02093         // Process Delayed ACKnowledgement timer
02094         if(MyTCBStub.Flags.bDelayedACKTimerEnabled)
02095         {
02096             // See if the timeout has occured and delayed ACK needs to be sent
02097             if((SHORT)(MyTCBStub.OverlappedTimers.delayedACKTime - (WORD)TickGetDiv256()) <= (SHORT)0)
02098                 vFlags = ACK;
02099         }
02100         
02101         // Process TCP_CLOSE_WAIT timer
02102         if(MyTCBStub.smState == TCP_CLOSE_WAIT)
02103         {
02104             // Automatically close the socket on our end if the application 
02105             // fails to call TCPDisconnect() is a reasonable amount of time.
02106             if((SHORT)(MyTCBStub.OverlappedTimers.closeWaitTime - (WORD)TickGetDiv256()) <= (SHORT)0)
02107             {
02108                 vFlags = FIN | ACK;
02109                 MyTCBStub.smState = TCP_LAST_ACK;
02110             }
02111         }
02112 
02113         // Process listening server sockets that might have a SYN waiting in the SYNQueue[]
02114         #if TCP_SYN_QUEUE_MAX_ENTRIES
02115             if(MyTCBStub.smState == TCP_LISTEN)
02116             {
02117                 for(w = 0; w < TCP_SYN_QUEUE_MAX_ENTRIES; w++)
02118                 {
02119                     // Abort search if there are no more valid records
02120                     if(SYNQueue[w].wDestPort == 0u)
02121                         break;
02122                     
02123                     // Stop searching if this SYN queue entry can be used by this socket
02124                     #if defined(STACK_USE_SSL_SERVER)
02125                     if(SYNQueue[w].wDestPort == MyTCBStub.remoteHash.Val || SYNQueue[w].wDestPort == MyTCBStub.sslTxHead)
02126                     #else
02127                     if(SYNQueue[w].wDestPort == MyTCBStub.remoteHash.Val)
02128                     #endif
02129                     {
02130                         // Set up our socket and generate a reponse SYN+ACK packet
02131                         SyncTCB();
02132                         
02133                         #if defined(STACK_USE_SSL_SERVER)
02134                         // If this matches the SSL port, make sure that can be configured
02135                         // before continuing.  If not, break and leave this in the queue
02136                         if(SYNQueue[w].wDestPort == MyTCBStub.sslTxHead && !TCPStartSSLServer(hTCP))
02137                             break;
02138                         #endif
02139                         
02140                         memcpy((void*)&MyTCB.remote.niRemoteMACIP, (void*)&SYNQueue[w].niSourceAddress, sizeof(NODE_INFO));
02141                         MyTCB.remotePort.Val = SYNQueue[w].wSourcePort;
02142                         MyTCB.RemoteSEQ = SYNQueue[w].dwSourceSEQ + 1;
02143                         MyTCBStub.remoteHash.Val = (MyTCB.remote.niRemoteMACIP.IPAddr.w[1] + MyTCB.remote.niRemoteMACIP.IPAddr.w[0] + MyTCB.remotePort.Val) ^ MyTCB.localPort.Val;
02144                         vFlags = SYN | ACK;
02145                         MyTCBStub.smState = TCP_SYN_RECEIVED;
02146                         
02147                         // Delete this SYN from the SYNQueue and compact the SYNQueue[] array
02148                         TCPRAMCopy((PTR_BASE)&SYNQueue[w], TCP_PIC_RAM, (PTR_BASE)&SYNQueue[w+1], TCP_PIC_RAM, (TCP_SYN_QUEUE_MAX_ENTRIES-1u-w)*sizeof(TCP_SYN_QUEUE));
02149                         SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort = 0u;
02150     
02151                         break;
02152                     }
02153                 }
02154             }
02155         #endif
02156 
02157         if(vFlags)
02158             SendTCP(vFlags, bRetransmit ? 0 : SENDTCP_RESET_TIMERS);
02159 
02160         // The TCP_CLOSED, TCP_LISTEN, and sometimes the TCP_ESTABLISHED 
02161         // state don't need any timeout events, so see if the timer is enabled
02162         if(!MyTCBStub.Flags.bTimerEnabled)
02163         {
02164             #if defined(TCP_KEEP_ALIVE_TIMEOUT)
02165                 // Only the established state has any use for keep-alives
02166                 if(MyTCBStub.smState == TCP_ESTABLISHED)
02167                 {
02168                     // If timeout has not occured, do not do anything.
02169                     if((LONG)(TickGet() - MyTCBStub.eventTime) < (LONG)0)
02170                         continue;
02171         
02172                     // If timeout has occured and the connection appears to be dead (no 
02173                     // responses from remote node at all), close the connection so the 
02174                     // application doesn't sit around indefinitely with a useless socket 
02175                     // that it thinks is still open
02176                     if(MyTCBStub.Flags.vUnackedKeepalives == TCP_MAX_UNACKED_KEEP_ALIVES)
02177                     {
02178                         vFlags = MyTCBStub.Flags.bServer;
02179 
02180                         // Force an immediate FIN and RST transmission
02181                         // Double calling TCPDisconnect() will also place us 
02182                         // back in the listening state immediately if a server socket.
02183                         TCPDisconnect(hTCP);
02184                         TCPDisconnect(hTCP);
02185                         
02186                         // Prevent client mode sockets from getting reused by other applications.  
02187                         // The application must call TCPDisconnect() with the handle to free this 
02188                         // socket (and the handle associated with it)
02189                         if(!vFlags)
02190                             MyTCBStub.smState = TCP_CLOSED_BUT_RESERVED;
02191                         
02192                         continue;
02193                     }
02194                     
02195                     // Otherwise, if a timeout occured, simply send a keep-alive packet
02196                     SyncTCB();
02197                     SendTCP(ACK, SENDTCP_KEEP_ALIVE);
02198                     MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
02199                 }
02200             #endif
02201             continue;
02202         }
02203 
02204         // If timeout has not occured, do not do anything.
02205         if((LONG)(TickGet() - MyTCBStub.eventTime) < (LONG)0)
02206             continue;
02207 
02208         // Load up extended TCB information
02209         SyncTCB();
02210 
02211         // A timeout has occured.  Respond to this timeout condition
02212         // depending on what state this socket is in.
02213         switch(MyTCBStub.smState)
02214         {
02215             #if defined(STACK_CLIENT_MODE)
02216             #if defined(STACK_USE_DNS)
02217             case TCP_GET_DNS_MODULE:
02218                 if(DNSBeginUsage())
02219                 {
02220                     MyTCBStub.smState = TCP_DNS_RESOLVE;
02221                     #if defined(__C30__)
02222                         DNSResolve((BYTE*)(WORD)MyTCB.remote.dwRemoteHost, DNS_TYPE_A);
02223                     #else
02224                         if(MyTCB.flags.bRemoteHostIsROM)
02225                             DNSResolveROM((ROM BYTE*)MyTCB.remote.dwRemoteHost, DNS_TYPE_A);
02226                         else
02227                             DNSResolve((BYTE*)MyTCB.remote.dwRemoteHost, DNS_TYPE_A);
02228                     #endif
02229                 }
02230                 break;
02231                 
02232             case TCP_DNS_RESOLVE:
02233                 if(DNSIsResolved(&MyTCB.remote.niRemoteMACIP.IPAddr))
02234                 {
02235                     if(DNSEndUsage())
02236                     {
02237                         MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
02238                         MyTCBStub.remoteHash.Val = (MyTCB.remote.niRemoteMACIP.IPAddr.w[1]+MyTCB.remote.niRemoteMACIP.IPAddr.w[0] + MyTCB.remotePort.Val) ^ MyTCB.localPort.Val;
02239                         MyTCB.retryCount = 0;
02240                         MyTCB.retryInterval = (TICK_SECOND/4)/256;
02241                     }
02242                     else
02243                     {
02244                         MyTCBStub.eventTime = TickGet() + 10*TICK_SECOND;
02245                         MyTCBStub.smState = TCP_GET_DNS_MODULE;
02246                     }
02247                 }
02248                 break;
02249             #endif // #if defined(STACK_USE_DNS)
02250                 
02251             case TCP_GATEWAY_SEND_ARP:
02252                 // Obtain the MAC address associated with the server's IP address (either direct MAC address on same subnet, or the MAC address of the Gateway machine)
02253                 MyTCBStub.eventTime2 = TickGetDiv256();
02254                 ARPResolve(&MyTCB.remote.niRemoteMACIP.IPAddr);
02255                 MyTCBStub.smState = TCP_GATEWAY_GET_ARP;
02256                 break;
02257 
02258             case TCP_GATEWAY_GET_ARP:
02259                 // Wait for the MAC address to finish being obtained
02260                 if(!ARPIsResolved(&MyTCB.remote.niRemoteMACIP.IPAddr, &MyTCB.remote.niRemoteMACIP.MACAddr))
02261                 {
02262                     // Time out if too much time is spent in this state
02263                     // Note that this will continuously send out ARP 
02264                     // requests for an infinite time if the Gateway 
02265                     // never responds
02266                     if(TickGetDiv256() - MyTCBStub.eventTime2 > MyTCB.retryInterval)
02267                     {
02268                         // Exponentially increase timeout until we reach 6 attempts then stay constant
02269                         if(MyTCB.retryCount < 6)
02270                         {
02271                             MyTCB.retryCount++;
02272                             MyTCB.retryInterval <<= 1;
02273                         }
02274 
02275                         // Retransmit ARP request
02276                         MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
02277                     }
02278                     break;
02279                 }
02280                 
02281                 // Send out SYN connection request to remote node
02282                 // This automatically disables the Timer from 
02283                 // continuously firing for this socket
02284                 vFlags = SYN;
02285                 bRetransmit = FALSE;
02286                 MyTCBStub.smState = TCP_SYN_SENT;
02287                 break;
02288             #endif // #if defined(STACK_CLIENT_MODE)
02289             
02290             case TCP_SYN_SENT:
02291                 // Keep sending SYN until we hear from remote node.
02292                 // This may be for infinite time, in that case
02293                 // caller must detect it and do something.
02294                 vFlags = SYN;
02295                 bRetransmit = TRUE;
02296                 break;
02297     
02298             case TCP_SYN_RECEIVED:
02299                 // We must receive ACK before timeout expires.
02300                 // If not, resend SYN+ACK.
02301                 // Abort, if maximum attempts counts are reached.
02302                 if(MyTCB.retryCount < TCP_MAX_SYN_RETRIES)
02303                 {
02304                     vFlags = SYN | ACK;
02305                     bRetransmit = TRUE;
02306                 }
02307                 else
02308                 {
02309                     if(MyTCBStub.Flags.bServer)
02310                     {
02311                         vFlags = RST | ACK;
02312                         bCloseSocket = TRUE;
02313                     }
02314                     else
02315                     {
02316                         vFlags = SYN;
02317                     }
02318                 }
02319                 break;
02320     
02321             case TCP_ESTABLISHED:
02322             case TCP_CLOSE_WAIT:
02323                 // Retransmit any unacknowledged data
02324                 if(MyTCB.retryCount < TCP_MAX_RETRIES)
02325                 {
02326                     vFlags = ACK;
02327                     bRetransmit = TRUE;
02328                 }
02329                 else
02330                 {
02331                     // No response back for too long, close connection
02332                     // This could happen, for instance, if the communication 
02333                     // medium was lost
02334                     MyTCBStub.smState = TCP_FIN_WAIT_1;
02335                     vFlags = FIN | ACK;
02336                 }
02337                 break;
02338     
02339             case TCP_FIN_WAIT_1:
02340                 if(MyTCB.retryCount < TCP_MAX_RETRIES)
02341                 {
02342                     // Send another FIN
02343                     vFlags = FIN | ACK;
02344                     bRetransmit = TRUE;
02345                 }
02346                 else
02347                 {
02348                     // Close on our own, we can't seem to communicate 
02349                     // with the remote node anymore
02350                     vFlags = RST | ACK;
02351                     bCloseSocket = TRUE;
02352                 }
02353                 break;
02354     
02355             case TCP_FIN_WAIT_2:
02356                 // Close on our own, we can't seem to communicate 
02357                 // with the remote node anymore
02358                 vFlags = RST | ACK;
02359                 bCloseSocket = TRUE;
02360                 break;
02361 
02362             case TCP_CLOSING:
02363                 if(MyTCB.retryCount < TCP_MAX_RETRIES)
02364                 {
02365                     // Send another ACK+FIN (the FIN is retransmitted 
02366                     // automatically since it hasn't been acknowledged by 
02367                     // the remote node yet)
02368                     vFlags = ACK;
02369                     bRetransmit = TRUE;
02370                 }
02371                 else
02372                 {
02373                     // Close on our own, we can't seem to communicate 
02374                     // with the remote node anymore
02375                     vFlags = RST | ACK;
02376                     bCloseSocket = TRUE;
02377                 }
02378                 break;
02379     
02380 //          case TCP_TIME_WAIT:
02381 //              // Wait around for a while (2MSL) and then goto closed state
02382 //              bCloseSocket = TRUE;
02383 //              break;
02384 //          
02385 
02386             case TCP_LAST_ACK:
02387                 // Send some more FINs or close anyway
02388                 if(MyTCB.retryCount < TCP_MAX_RETRIES)
02389                 {
02390                     vFlags = FIN | ACK;
02391                     bRetransmit = TRUE;
02392                 }
02393                 else
02394                 {
02395                     vFlags = RST | ACK;
02396                     bCloseSocket = TRUE;
02397                 }
02398                 break;
02399             
02400             default:
02401                 break;
02402         }
02403 
02404         if(vFlags)
02405         {
02406             if(bRetransmit)
02407             {
02408                 // Set the appropriate retry time
02409                 MyTCB.retryCount++;
02410                 MyTCB.retryInterval <<= 1;
02411         
02412                 // Transmit all unacknowledged data over again
02413                 // Roll back unacknowledged TX tail pointer to cause retransmit to occur
02414                 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
02415                 if(MyTCB.txUnackedTail < MyTCBStub.txTail)
02416                     MyTCB.MySEQ -= (LONG)(SHORT)(MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
02417                 MyTCB.txUnackedTail = MyTCBStub.txTail;     
02418                 SendTCP(vFlags, 0);
02419             }
02420             else
02421                 SendTCP(vFlags, SENDTCP_RESET_TIMERS);
02422 
02423         }
02424         
02425         if(bCloseSocket)
02426             CloseSocket();
02427     }
02428     
02429     
02430     #if TCP_SYN_QUEUE_MAX_ENTRIES
02431         // Process SYN Queue entry timeouts
02432         for(w = 0; w < TCP_SYN_QUEUE_MAX_ENTRIES; w++)
02433         {
02434             // Abort search if there are no more valid records
02435             if(SYNQueue[w].wDestPort == 0u)
02436                 break;
02437             
02438             // See if this SYN has timed out
02439             if((WORD)TickGetDiv256() - SYNQueue[w].wTimestamp > (WORD)(TCP_SYN_QUEUE_TIMEOUT/256ull))
02440             {
02441                 // Delete this SYN from the SYNQueue and compact the SYNQueue[] array
02442                 TCPRAMCopy((PTR_BASE)&SYNQueue[w], TCP_PIC_RAM, (PTR_BASE)&SYNQueue[w+1], TCP_PIC_RAM, (TCP_SYN_QUEUE_MAX_ENTRIES-1u-w)*sizeof(TCP_SYN_QUEUE));
02443                 SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort = 0u;
02444     
02445                 // Since we deleted an entry, we need to roll back one 
02446                 // index so next loop will process the correct record
02447                 w--;    
02448             }
02449         }
02450     #endif
02451 }
02452 
02453 
02454 /*****************************************************************************
02455   Function:
02456     BOOL TCPProcess(NODE_INFO* remote, IP_ADDR* localIP, WORD len)
02457 
02458   Summary:
02459     Handles incoming TCP segments.
02460 
02461   Description:
02462     This function handles incoming TCP segments.  When a segment arrives, it
02463     is compared to open sockets using a hash of the remote port and IP.  
02464     On a match, the data is passed to HandleTCPSeg for further processing.
02465 
02466   Precondition:
02467     TCP is initialized and a TCP segment is ready in the MAC buffer.
02468 
02469   Parameters:
02470     remote - Remote NODE_INFO structure
02471     localIP - This stack's IP address (for header checking)
02472     len - Total length of the waiting TCP segment
02473 
02474   Return Values:
02475     TRUE - the segment was properly handled.
02476     FALSE - otherwise
02477   ***************************************************************************/
02478 BOOL TCPProcess(NODE_INFO* remote, IP_ADDR* localIP, WORD len)
02479 {
02480     TCP_HEADER      TCPHeader;
02481     PSEUDO_HEADER   pseudoHeader;
02482     WORD_VAL        checksum1;
02483     WORD_VAL        checksum2;
02484     BYTE            optionsSize;
02485 
02486     // Calculate IP pseudoheader checksum.
02487     pseudoHeader.SourceAddress      = remote->IPAddr;
02488     pseudoHeader.DestAddress        = *localIP;
02489     pseudoHeader.Zero               = 0x0;
02490     pseudoHeader.Protocol           = IP_PROT_TCP;
02491     pseudoHeader.Length             = len;
02492 
02493     SwapPseudoHeader(pseudoHeader);
02494 
02495     checksum1.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
02496         sizeof(pseudoHeader));
02497 
02498     // Now calculate TCP packet checksum in NIC RAM - should match
02499     // pesudo header checksum
02500     checksum2.Val = CalcIPBufferChecksum(len);
02501 
02502     // Compare checksums.
02503     if(checksum1.Val != checksum2.Val)
02504     {
02505         MACDiscardRx();
02506         return TRUE;
02507     }
02508 
02509 #if defined(DEBUG_GENERATE_RX_LOSS)
02510     // Throw RX packets away randomly
02511     if(rand() > DEBUG_GENERATE_RX_LOSS)
02512     {
02513         MACDiscardRx();
02514         return TRUE;
02515     }
02516 #endif
02517 
02518     // Retrieve TCP header.
02519     IPSetRxBuffer(0);
02520     MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
02521     SwapTCPHeader(&TCPHeader);
02522 
02523 
02524     // Skip over options to retrieve data bytes
02525     optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
02526         sizeof(TCPHeader));
02527     len = len - optionsSize - sizeof(TCPHeader);
02528 
02529     // Find matching socket.
02530     if(FindMatchingSocket(&TCPHeader, remote))
02531     {
02532         #if defined(STACK_USE_SSL)
02533         PTR_BASE prevRxHead = 0;
02534         // For SSL connections, show HandleTCPSeg() the full data buffer
02535         if(MyTCBStub.sslStubID != SSL_INVALID_ID)
02536         {
02537             prevRxHead = MyTCBStub.rxHead;
02538             MyTCBStub.rxHead = MyTCBStub.sslRxHead;
02539         }
02540         #endif
02541         
02542         HandleTCPSeg(&TCPHeader, len);
02543         
02544         #if defined(STACK_USE_SSL)
02545         if(MyTCBStub.sslStubID != SSL_INVALID_ID)
02546         {
02547             // Restore the buffer state
02548             MyTCBStub.sslRxHead = MyTCBStub.rxHead;
02549             MyTCBStub.rxHead = prevRxHead;
02550 
02551             // Process the new SSL data, using the currently loaded stub
02552             TCPSSLHandleIncoming(hCurrentTCP);
02553         }
02554         #endif
02555     }
02556 //  else
02557 //  {
02558 //      // \TODO: RFC 793 specifies that if the socket is closed 
02559 //      // and a segment arrives, we should send back a RST if 
02560 //      // the RST bit in the incoming packet is not set.  The 
02561 //      // code to respond with the RST packet and believable SEQ 
02562 //      // and ACK numbers needs to be implemented.
02563 //      //if(!TCPHeader.Flags.bits.flagRST)
02564 //      //  SendTCP(RST, SENDTCP_RESET_TIMERS);
02565 //  }
02566 
02567     // Finished with this packet, discard it and free the Ethernet RAM for new packets
02568     MACDiscardRx();
02569 
02570     return TRUE;
02571 }
02572 
02573 
02574 /*****************************************************************************
02575   Function:
02576     static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags)
02577 
02578   Summary:
02579     Transmits a TPC segment.
02580 
02581   Description:
02582     This function assembles and transmits a TCP segment, including any 
02583     pending data.  It also supports retransmissions, keep-alives, and 
02584     other packet types.
02585 
02586   Precondition:
02587     TCP is initialized.
02588 
02589   Parameters:
02590     vTCPFlags - Additional TCP flags to include
02591     vSendFlags - Any combinations of SENDTCP_* constants to modify the
02592                  transmit behavior or contents.
02593 
02594   Returns:
02595     None
02596   ***************************************************************************/
02597 static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags)
02598 {
02599     WORD_VAL        wVal;
02600     TCP_HEADER      header;
02601     TCP_OPTIONS     options;
02602     PSEUDO_HEADER   pseudoHeader;
02603     WORD            len;
02604     WORD            wEffectiveWindow;
02605     
02606     SyncTCB();
02607 
02608     // FINs must be handled specially
02609     if(vTCPFlags & FIN)
02610     {
02611         MyTCBStub.Flags.bTXFIN = 1;
02612         vTCPFlags &= ~FIN;
02613     }
02614 
02615     // Status will now be synched, disable automatic future 
02616     // status transmissions
02617     MyTCBStub.Flags.bTimer2Enabled = 0;
02618     MyTCBStub.Flags.bDelayedACKTimerEnabled = 0;
02619     MyTCBStub.Flags.bOneSegmentReceived = 0;
02620     MyTCBStub.Flags.bTXASAP = 0;
02621     MyTCBStub.Flags.bTXASAPWithoutTimerReset = 0;
02622     MyTCBStub.Flags.bHalfFullFlush = 0;
02623 
02624     //  Make sure that we can write to the MAC transmit area
02625     while(!IPIsTxReady());
02626 
02627     // Put all socket application data in the TX space
02628     if(vTCPFlags & (SYN | RST))
02629     {
02630         // Don't put any data in SYN and RST messages
02631         len = 0;
02632     }
02633     else
02634     {
02635         // Begin copying any application data over to the TX space
02636         if(MyTCBStub.txHead == MyTCB.txUnackedTail)
02637         {
02638             // All caught up on data TX, no real data for this packet
02639             len = 0;
02640 
02641             // If we are to transmit a FIN, make sure we can put one in this packet
02642             if(MyTCBStub.Flags.bTXFIN)
02643             {
02644                 if(MyTCB.remoteWindow)
02645                     vTCPFlags |= FIN;
02646             }
02647         }
02648         else if(MyTCBStub.txHead > MyTCB.txUnackedTail)
02649         {
02650             len = MyTCBStub.txHead - MyTCB.txUnackedTail;
02651             wEffectiveWindow = MyTCB.remoteWindow;
02652             if(MyTCB.txUnackedTail >= MyTCBStub.txTail)
02653                 wEffectiveWindow -= MyTCB.txUnackedTail - MyTCBStub.txTail;
02654             else
02655                 wEffectiveWindow -= (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart) - (MyTCBStub.txTail - MyTCB.txUnackedTail);
02656 
02657             if(len > wEffectiveWindow)
02658                 len = wEffectiveWindow;
02659 
02660             if(len > TCP_MAX_SEG_SIZE)
02661             {
02662                 len = TCP_MAX_SEG_SIZE;
02663                 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
02664             }
02665 
02666             // If we are to transmit a FIN, make sure we can put one in this packet
02667             if(MyTCBStub.Flags.bTXFIN)
02668             {
02669                 if((len != wEffectiveWindow) && (len != TCP_MAX_SEG_SIZE))
02670                     vTCPFlags |= FIN;
02671             }
02672 
02673             // Copy application data into the raw TX buffer
02674             TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), TCP_ETH_RAM, MyTCB.txUnackedTail, MyTCBStub.vMemoryMedium, len);
02675             MyTCB.txUnackedTail += len;
02676         }
02677         else
02678         {
02679             pseudoHeader.Length = MyTCBStub.bufferRxStart - MyTCB.txUnackedTail;
02680             len = pseudoHeader.Length + MyTCBStub.txHead - MyTCBStub.bufferTxStart;
02681 
02682             wEffectiveWindow = MyTCB.remoteWindow;
02683             if(MyTCB.txUnackedTail >= MyTCBStub.txTail)
02684                 wEffectiveWindow -= MyTCB.txUnackedTail - MyTCBStub.txTail;
02685             else
02686                 wEffectiveWindow -= (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart) - (MyTCBStub.txTail - MyTCB.txUnackedTail);
02687                 
02688             if(len > wEffectiveWindow)
02689                 len = wEffectiveWindow;
02690 
02691             if(len > TCP_MAX_SEG_SIZE)
02692             {
02693                 len = TCP_MAX_SEG_SIZE;
02694                 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
02695             }
02696 
02697             // If we are to transmit a FIN, make sure we can put one in this packet
02698             if(MyTCBStub.Flags.bTXFIN)
02699             {
02700                 if((len != wEffectiveWindow) && (len != TCP_MAX_SEG_SIZE))
02701                     vTCPFlags |= FIN;
02702             }
02703 
02704             if(pseudoHeader.Length > len)
02705                 pseudoHeader.Length = len;
02706 
02707             // Copy application data into the raw TX buffer
02708             TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), TCP_ETH_RAM, MyTCB.txUnackedTail, MyTCBStub.vMemoryMedium, pseudoHeader.Length);
02709             pseudoHeader.Length = len - pseudoHeader.Length;
02710     
02711             // Copy any left over chunks of application data over
02712             if(pseudoHeader.Length)
02713             {
02714                 TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER)+(MyTCBStub.bufferRxStart-MyTCB.txUnackedTail), TCP_ETH_RAM, MyTCBStub.bufferTxStart, MyTCBStub.vMemoryMedium, pseudoHeader.Length);
02715             }
02716 
02717             MyTCB.txUnackedTail += len;
02718             if(MyTCB.txUnackedTail >= MyTCBStub.bufferRxStart)
02719                 MyTCB.txUnackedTail -= MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart;
02720         }
02721     }
02722 
02723     // Ensure that all packets with data of some kind are 
02724     // retransmitted by TCPTick() until acknowledged
02725     // Pure ACK packets with no data are not ACKed back in TCP
02726     if(len || (vTCPFlags & (SYN | FIN)))
02727     {
02728         // Push (PSH) all data for enhanced responsiveness on 
02729         // the remote end, especially with GUIs
02730         if(len)
02731             vTCPFlags |= PSH;
02732 
02733         if(vSendFlags & SENDTCP_RESET_TIMERS)
02734         {
02735             MyTCB.retryCount = 0;
02736             MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
02737         }   
02738 
02739         MyTCBStub.eventTime = TickGet() + MyTCB.retryInterval;
02740         MyTCBStub.Flags.bTimerEnabled = 1;
02741     }
02742     else if(vSendFlags & SENDTCP_KEEP_ALIVE)
02743     {
02744         // Increment Keep Alive TX counter to handle disconnection if not response is returned
02745         MyTCBStub.Flags.vUnackedKeepalives++;
02746         
02747         // Generate a dummy byte
02748         MyTCB.MySEQ -= 1;
02749         len = 1;
02750     }
02751     else if(MyTCBStub.Flags.bTimerEnabled) 
02752     {
02753         // If we have data to transmit, but the remote RX window is zero, 
02754         // so we aren't transmitting any right now then make sure to not 
02755         // extend the retry counter or timer.  This will stall our TX 
02756         // with a periodic ACK sent to the remote node.
02757         if(!(vSendFlags & SENDTCP_RESET_TIMERS))
02758         {
02759             // Roll back retry counters since we can't send anything
02760             MyTCB.retryCount--;
02761             MyTCB.retryInterval >>= 1;
02762         }
02763     
02764         MyTCBStub.eventTime = TickGet() + MyTCB.retryInterval;
02765     }
02766     
02767 
02768     header.SourcePort           = MyTCB.localPort.Val;
02769     header.DestPort             = MyTCB.remotePort.Val;
02770     header.SeqNumber            = MyTCB.MySEQ;
02771     header.AckNumber            = MyTCB.RemoteSEQ;
02772     header.Flags.bits.Reserved2 = 0;
02773     header.DataOffset.Reserved3 = 0;
02774     header.Flags.byte           = vTCPFlags;
02775     header.UrgentPointer        = 0;
02776 
02777     // Update our send sequence number and ensure retransmissions 
02778     // of SYNs and FINs use the right sequence number
02779     MyTCB.MySEQ += (DWORD)len;
02780     if(vTCPFlags & SYN)
02781     {
02782         if(MyTCB.flags.bSYNSent)
02783             header.SeqNumber--;
02784         else
02785         {
02786             MyTCB.MySEQ++;
02787             MyTCB.flags.bSYNSent = 1;
02788         }
02789     }
02790     if(vTCPFlags & FIN)
02791     {
02792         if(MyTCB.flags.bFINSent)
02793             header.SeqNumber--;
02794         else
02795         {
02796             MyTCB.MySEQ++;
02797             MyTCB.flags.bFINSent = 1;
02798         }
02799     }
02800 
02801     // Calculate the amount of free space in the RX buffer area of this socket
02802     if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
02803         header.Window = (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart) - (MyTCBStub.rxHead - MyTCBStub.rxTail);
02804     else
02805         header.Window = MyTCBStub.rxTail - MyTCBStub.rxHead - 1;
02806 
02807     // Calculate the amount of free space in the MAC RX buffer area and adjust window if needed
02808     wVal.Val = MACGetFreeRxSize()-64;
02809     if((SHORT)wVal.Val < (SHORT)0)
02810         wVal.Val = 0;
02811     // Force the remote node to throttle back if we are running low on general RX buffer space
02812     if(header.Window > wVal.Val)
02813         header.Window = wVal.Val;
02814 
02815     SwapTCPHeader(&header);
02816 
02817 
02818     len += sizeof(header);
02819     header.DataOffset.Val   = sizeof(header) >> 2;
02820 
02821     // Insert the MSS (Maximum Segment Size) TCP option if this is SYN packet
02822     if(vTCPFlags & SYN)
02823     {
02824         len += sizeof(options);
02825         options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
02826         options.Length = 0x04;
02827 
02828         // Load MSS and swap to big endian
02829         options.MaxSegSize.Val = (((TCP_MAX_SEG_SIZE-4)&0x00FF)<<8) | (((TCP_MAX_SEG_SIZE-4)&0xFF00)>>8);
02830 
02831         header.DataOffset.Val   += sizeof(options) >> 2;
02832     }
02833 
02834     // Calculate IP pseudoheader checksum.
02835     // MODIFIX: Use the eWicht structure sIPConfig.
02836     pseudoHeader.SourceAddress  = sIPConfig.MyIPAddr;
02837     pseudoHeader.DestAddress    = MyTCB.remote.niRemoteMACIP.IPAddr;
02838     pseudoHeader.Zero           = 0x0;
02839     pseudoHeader.Protocol       = IP_PROT_TCP;
02840     pseudoHeader.Length         = len;
02841     SwapPseudoHeader(pseudoHeader);
02842     header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader));
02843 
02844     // Write IP header
02845     MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
02846     IPPutHeader(&MyTCB.remote.niRemoteMACIP, IP_PROT_TCP, len);
02847     MACPutArray((BYTE*)&header, sizeof(header));
02848     if(vTCPFlags & SYN)
02849         MACPutArray((BYTE*)&options, sizeof(options));
02850 
02851     // Update the TCP checksum
02852     MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER));
02853     wVal.Val = CalcIPBufferChecksum(len);
02854 #if defined(DEBUG_GENERATE_TX_LOSS)
02855     // Damage TCP checksums on TX packets randomly
02856     if(rand() > DEBUG_GENERATE_TX_LOSS)
02857     {
02858         wVal.Val++;
02859     }
02860 #endif
02861     MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 16);
02862     MACPutArray((BYTE*)&wVal, sizeof(WORD));
02863 
02864     // Physically start the packet transmission over the network
02865     MACFlush();
02866 }
02867 
02868 /*****************************************************************************
02869   Function:
02870     static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote)
02871 
02872   Summary:
02873     Finds a suitable socket for a TCP segment.
02874 
02875   Description:
02876     This function searches through the sockets and attempts to match one with
02877     a given TCP header and NODE_INFO structure.  If a socket is found, its 
02878     index is saved in hCurrentTCP and the associated MyTCBStub and MyTCB are
02879     loaded. Otherwise, INVALID_SOCKET is placed in hCurrentTCP.
02880     
02881   Precondition:
02882     TCP is initialized.
02883 
02884   Parameters:
02885     h - TCP header to be matched against
02886     remote - The remote node who sent this header
02887 
02888   Return Values:
02889     TRUE - A match was found and is loaded in hCurrentTCP
02890     FALSE - No suitable socket was found and hCurrentTCP is INVALID_SOCKET
02891   ***************************************************************************/
02892 static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote)
02893 {
02894     TCP_SOCKET hTCP;
02895     TCP_SOCKET partialMatch;
02896     WORD hash;
02897 
02898     // Prevent connections on invalid port 0
02899     if(h->DestPort == 0)
02900         return FALSE;
02901 
02902     partialMatch = INVALID_SOCKET;
02903     hash = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + h->SourcePort) ^ h->DestPort;
02904 
02905     // Loop through all sockets looking for a socket that is expecting this 
02906     // packet or can handle it.
02907     for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++ )
02908     {
02909         SyncTCBStub(hTCP);
02910 
02911         if(MyTCBStub.smState == TCP_CLOSED)
02912         {
02913             continue;
02914         }
02915         else if(MyTCBStub.smState == TCP_LISTEN)
02916         {// For listening ports, check if this is the correct port
02917             if(MyTCBStub.remoteHash.Val == h->DestPort)
02918                 partialMatch = hTCP;
02919             
02920             #if defined(STACK_USE_SSL_SERVER)
02921             // Check the SSL port as well for SSL Servers
02922             // 0 is defined as an invalid port number
02923             if(MyTCBStub.sslTxHead == h->DestPort)
02924                 partialMatch = hTCP;
02925             #endif
02926             
02927             continue;
02928         }
02929         else if(MyTCBStub.remoteHash.Val != hash)
02930         {// Ignore if the hash doesn't match
02931             continue;
02932         }
02933 
02934         SyncTCB();
02935         if( h->DestPort == MyTCB.localPort.Val &&
02936             h->SourcePort == MyTCB.remotePort.Val &&
02937             remote->IPAddr.Val == MyTCB.remote.niRemoteMACIP.IPAddr.Val)
02938         {
02939             return TRUE;
02940         }
02941     }
02942 
02943 
02944     // If there is a partial match, then a listening socket is currently 
02945     // available.  Set up the extended TCB with the info needed 
02946     // to establish a connection and return this socket to the 
02947     // caller.
02948     if(partialMatch != INVALID_SOCKET)
02949     {
02950         SyncTCBStub(partialMatch);
02951         SyncTCB();
02952     
02953         // For SSL ports, begin the SSL Handshake
02954         #if defined(STACK_USE_SSL_SERVER)
02955         if(MyTCBStub.sslTxHead == h->DestPort)
02956         {
02957             // Try to start an SSL session.  If no stubs are available,
02958             // we can't service this request right now, so ignore it.
02959             if(!TCPStartSSLServer(partialMatch))
02960                 partialMatch = INVALID_SOCKET;
02961         }
02962         #endif
02963     
02964         // Make sure the above check didn't fail (this is unfortunately 
02965         // redundant for non-SSL sockets).  Otherwise, fall out to below
02966         // and add to the SYN queue.
02967         if(partialMatch != INVALID_SOCKET)
02968         {
02969             MyTCBStub.remoteHash.Val = hash;
02970         
02971             memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
02972             MyTCB.remotePort.Val = h->SourcePort;
02973             MyTCB.localPort.Val = h->DestPort;
02974             MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
02975         
02976             // All done, and we have a match
02977             return TRUE;
02978         }
02979     }
02980 
02981     // No available sockets are listening on this port.  (Or, for
02982     // SSL requests, perhaps no SSL sessions were available.  However,
02983     // there may be a server socket which is currently busy but 
02984     // could handle this packet, so we should check.
02985     #if TCP_SYN_QUEUE_MAX_ENTRIES
02986     {
02987         WORD wQueueInsertPos;
02988         
02989         // See if this is a SYN packet
02990         if(!h->Flags.bits.flagSYN)
02991             return FALSE;
02992 
02993         // See if there is space in our SYN queue
02994         if(SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort)
02995             return FALSE;
02996         
02997         // See if we have this SYN already in our SYN queue.
02998         // If not already in the queue, find out where we 
02999         // should insert this SYN to the queue
03000         for(wQueueInsertPos = 0; wQueueInsertPos < TCP_SYN_QUEUE_MAX_ENTRIES; wQueueInsertPos++)
03001         {
03002             // Exit loop if we found a free record
03003             if(SYNQueue[wQueueInsertPos].wDestPort == 0u)
03004                 break;
03005 
03006             // Check if this SYN packet is already in the SYN queue
03007             if(SYNQueue[wQueueInsertPos].wDestPort != h->DestPort)
03008                 continue;
03009             if(SYNQueue[wQueueInsertPos].wSourcePort != h->SourcePort)
03010                 continue;
03011             if(SYNQueue[wQueueInsertPos].niSourceAddress.IPAddr.Val != remote->IPAddr.Val)
03012                 continue;
03013 
03014             // SYN matches SYN queue entry.  Update timestamp and do nothing.
03015             SYNQueue[wQueueInsertPos].wTimestamp = TickGetDiv256();
03016             return FALSE;
03017         }
03018         
03019         // Check to see if we have any server sockets which 
03020         // are currently connected, but could handle this SYN 
03021         // request at a later time if the client disconnects.
03022         for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
03023         {
03024             SyncTCBStub(hTCP);
03025             if(!MyTCBStub.Flags.bServer)
03026                 continue;
03027 
03028             SyncTCB();
03029             #if defined(STACK_USE_SSL_SERVER)
03030             if((MyTCB.localPort.Val != h->DestPort) && (MyTCB.localSSLPort.Val != h->DestPort))
03031             #else
03032             if(MyTCB.localPort.Val != h->DestPort)
03033             #endif
03034                 continue;
03035 
03036             // Generate the SYN queue entry
03037             memcpy((void*)&SYNQueue[wQueueInsertPos].niSourceAddress, (void*)remote, sizeof(NODE_INFO));
03038             SYNQueue[wQueueInsertPos].wSourcePort = h->SourcePort;
03039             SYNQueue[wQueueInsertPos].dwSourceSEQ = h->SeqNumber;
03040             SYNQueue[wQueueInsertPos].wDestPort = h->DestPort;
03041             SYNQueue[wQueueInsertPos].wTimestamp = TickGetDiv256();
03042 
03043             return FALSE;
03044         }
03045     }
03046     #endif
03047         
03048     return FALSE;
03049 
03050 }
03051 
03052 
03053 
03054 /*****************************************************************************
03055   Function:
03056     static void SwapTCPHeader(TCP_HEADER* header)
03057 
03058   Summary:
03059     Swaps endian-ness of a TCP header.
03060 
03061   Description:
03062     This function swaps the endian-ness of a given TCP header for comparison.
03063 
03064   Precondition:
03065     None
03066 
03067   Parameters:
03068     header - The TCP header that is to be swapped
03069 
03070   Returns:
03071     None
03072   ***************************************************************************/
03073 static void SwapTCPHeader(TCP_HEADER* header)
03074 {
03075     header->SourcePort      = swaps(header->SourcePort);
03076     header->DestPort        = swaps(header->DestPort);
03077     header->SeqNumber       = swapl(header->SeqNumber);
03078     header->AckNumber       = swapl(header->AckNumber);
03079     header->Window          = swaps(header->Window);
03080     header->Checksum        = swaps(header->Checksum);
03081     header->UrgentPointer   = swaps(header->UrgentPointer);
03082 }
03083 
03084 
03085 
03086 /*****************************************************************************
03087   Function:
03088     static void CloseSocket(void)
03089 
03090   Summary:
03091     Closes a TCP socket.
03092 
03093   Description:
03094     This function closes a TCP socket.  All socket state information is 
03095     reset, and any buffered bytes are discarded.  The socket is no longer
03096     accessible by the application after this point.
03097 
03098   Precondition:
03099     The TCPStub corresponding to the socket to be closed is synced.
03100 
03101   Parameters:
03102     None
03103 
03104   Returns:
03105     None
03106   ***************************************************************************/
03107 static void CloseSocket(void)
03108 {
03109     SyncTCB();
03110 
03111     MyTCBStub.remoteHash.Val = MyTCB.localPort.Val;
03112     MyTCBStub.txHead = MyTCBStub.bufferTxStart;
03113     MyTCBStub.txTail = MyTCBStub.bufferTxStart;
03114     MyTCBStub.rxHead = MyTCBStub.bufferRxStart;
03115     MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
03116     MyTCBStub.smState = MyTCBStub.Flags.bServer ? TCP_LISTEN : TCP_CLOSED;
03117     MyTCBStub.Flags.vUnackedKeepalives = 0;
03118     MyTCBStub.Flags.bTimerEnabled = 0;
03119     MyTCBStub.Flags.bTimer2Enabled = 0;
03120     MyTCBStub.Flags.bDelayedACKTimerEnabled = 0;
03121     MyTCBStub.Flags.bOneSegmentReceived = 0;
03122     MyTCBStub.Flags.bHalfFullFlush = 0;
03123     MyTCBStub.Flags.bTXASAP = 0;
03124     MyTCBStub.Flags.bTXASAPWithoutTimerReset = 0;
03125     MyTCBStub.Flags.bTXFIN = 0;
03126     MyTCBStub.Flags.bSocketReset = 1;
03127 
03128     #if defined(STACK_USE_SSL)
03129     // If SSL is active, then we need to close it
03130     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
03131     {
03132         SSLTerminate(MyTCBStub.sslStubID);
03133         MyTCBStub.sslStubID = SSL_INVALID_ID;
03134 
03135         // Swap the SSL port and local port back to proper values
03136         MyTCBStub.remoteHash.Val = MyTCB.localSSLPort.Val;
03137         MyTCB.localSSLPort.Val = MyTCB.localPort.Val;
03138         MyTCB.localPort.Val = MyTCBStub.remoteHash.Val;
03139     }
03140 
03141     // Reset the SSL buffer pointers
03142     MyTCBStub.sslRxHead = MyTCBStub.bufferRxStart;
03143     MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
03144     #endif
03145     
03146     #if defined(STACK_USE_SSL_SERVER)
03147     MyTCBStub.sslTxHead = MyTCB.localSSLPort.Val;
03148     #endif
03149 
03150     MyTCB.flags.bFINSent = 0;
03151     MyTCB.flags.bSYNSent = 0;
03152     MyTCB.flags.bRXNoneACKed1 = 0;
03153     MyTCB.flags.bRXNoneACKed2 = 0;
03154     MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
03155     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
03156     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
03157     MyTCB.sHoleSize = -1;
03158     MyTCB.remoteWindow = 1;
03159 }
03160 
03161 
03162 
03163 /*****************************************************************************
03164   Function:
03165     static void HandleTCPSeg(TCP_HEADER* h, WORD len)
03166 
03167   Summary:
03168     Processes an incoming TCP segment.
03169 
03170   Description:
03171     Once an incoming segment has been matched to a socket, this function
03172     performs the necessary processing with the data.  Depending on the 
03173     segment and the state, this may include copying data to the TCP buffer,
03174     re-assembling out-of order packets, continuing an initialization or 
03175     closing handshake, or closing the socket altogether.
03176 
03177   Precondition:
03178     TCP is initialized and the current TCP stub is already synced.
03179 
03180   Parameters:
03181     h - The TCP header for this packet
03182     len - The total buffer length of this segment
03183 
03184   Returns:
03185     None
03186   ***************************************************************************/
03187 static void HandleTCPSeg(TCP_HEADER* h, WORD len)
03188 {
03189     DWORD dwTemp;
03190     PTR_BASE wTemp;
03191     LONG lMissingBytes;
03192     WORD wMissingBytes;
03193     WORD wFreeSpace;
03194     BYTE localHeaderFlags;
03195     DWORD localAckNumber;
03196     DWORD localSeqNumber;
03197     WORD wSegmentLength;
03198     BOOL bSegmentAcceptable;
03199 
03200     // Cache a few variables in local RAM.  
03201     // PIC18s take a fair amount of code and execution time to 
03202     // dereference pointers frequently.
03203     localHeaderFlags = h->Flags.byte;
03204     localAckNumber = h->AckNumber;
03205     localSeqNumber = h->SeqNumber;
03206 
03207     // We received a packet, reset the keep alive timer and count
03208     #if defined(TCP_KEEP_ALIVE_TIMEOUT)
03209         MyTCBStub.Flags.vUnackedKeepalives = 0;
03210         if(!MyTCBStub.Flags.bTimerEnabled)
03211             MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
03212     #endif
03213 
03214     // Handle TCP_LISTEN and TCP_SYN_SENT states
03215     // Both of these states will return, so code following this 
03216     // state machine need not check explicitly for these two 
03217     // states.
03218     switch(MyTCBStub.smState)
03219     {
03220         case TCP_LISTEN:
03221             // First: check RST flag
03222             if(localHeaderFlags & RST)
03223             {
03224                 CloseSocket();  // Unbind remote IP address/port info
03225                 return;
03226             }
03227 
03228             // Second: check ACK flag, which would be invalid
03229             if(localHeaderFlags & ACK)
03230             {
03231                 // Use a believable sequence number and reset the remote node
03232                 MyTCB.MySEQ = localAckNumber;
03233                 SendTCP(RST, 0);
03234                 CloseSocket();  // Unbind remote IP address/port info
03235                 return;
03236             }
03237 
03238             // Third: check for SYN flag, which is what we're looking for
03239             if(localHeaderFlags & SYN)
03240             {
03241                 // We now have a sequence number for the remote node
03242                 MyTCB.RemoteSEQ = localSeqNumber + 1;
03243 
03244                 // Set Initial Send Sequence (ISS) number
03245                 // Nothing to do on this step... ISS already set in CloseSocket()
03246                 
03247                 // Respond with SYN + ACK
03248                 SendTCP(SYN | ACK, SENDTCP_RESET_TIMERS);
03249                 MyTCBStub.smState = TCP_SYN_RECEIVED;
03250             }
03251             else
03252             {
03253                 CloseSocket();  // Unbind remote IP address/port info
03254             }
03255 
03256             // Fourth: check for other text and control
03257             // Nothing to do since we don't support this
03258             return;
03259 
03260         case TCP_SYN_SENT:
03261             // Second: check the RST bit
03262             // This is out of order because this stack has no API for 
03263             // notifying the application that the connection seems to 
03264             // be failing.  Instead, the application must time out and 
03265             // the stack will just keep trying in the mean time.
03266             if(localHeaderFlags & RST)
03267                 return;
03268 
03269             // First: check ACK bit
03270             if(localHeaderFlags & ACK)
03271             {
03272                 if(localAckNumber != MyTCB.MySEQ)
03273                 {
03274                     // Send a RST packet with SEQ = SEG.ACK, but retain our SEQ 
03275                     // number for arivial of any other SYN+ACK packets
03276                     localSeqNumber = MyTCB.MySEQ;   // Save our original SEQ number
03277                     MyTCB.MySEQ = localAckNumber;   // Set SEQ = SEG.ACK
03278                     SendTCP(RST, SENDTCP_RESET_TIMERS);     // Send the RST
03279                     MyTCB.MySEQ = localSeqNumber;   // Restore original SEQ number
03280                     return;
03281                 }
03282             }
03283 
03284             // Third: check the security and precedence
03285             // No such feature in this stack.  We want to accept all connections.
03286 
03287             // Fourth: check the SYN bit
03288             if(localHeaderFlags & SYN)
03289             {
03290                 // We now have an initial sequence number and window size
03291                 MyTCB.RemoteSEQ = localSeqNumber + 1;
03292                 MyTCB.remoteWindow = h->Window;
03293 
03294                 if(localHeaderFlags & ACK)
03295                 {
03296                     SendTCP(ACK, SENDTCP_RESET_TIMERS);
03297                     MyTCBStub.smState = TCP_ESTABLISHED;
03298                     MyTCBStub.Flags.bTimerEnabled = 0;
03299                 }
03300                 else
03301                 {
03302                     SendTCP(SYN | ACK, SENDTCP_RESET_TIMERS);
03303                     MyTCBStub.smState = TCP_SYN_RECEIVED;
03304                 }
03305             }
03306 
03307             // Fifth: drop the segment if neither SYN or RST is set
03308             return;
03309 
03310         default:
03311             break;
03312     }
03313 
03314     //
03315     // First: check the sequence number
03316     //
03317     wSegmentLength = len;
03318     if(localHeaderFlags & FIN)
03319         wSegmentLength++;
03320     if(localHeaderFlags & SYN)
03321         wSegmentLength++;
03322 
03323     // Calculate the RX FIFO space
03324     if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
03325         wFreeSpace = (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart) - (MyTCBStub.rxHead - MyTCBStub.rxTail);
03326     else
03327         wFreeSpace = MyTCBStub.rxTail - MyTCBStub.rxHead - 1;
03328 
03329     // Calculate the number of bytes ahead of our head pointer this segment skips
03330     lMissingBytes = localSeqNumber - MyTCB.RemoteSEQ;
03331     wMissingBytes = (WORD)lMissingBytes;
03332     
03333     // Run TCP acceptability tests to verify that this packet has a valid sequence number
03334     bSegmentAcceptable = FALSE;
03335     if(wSegmentLength)
03336     {
03337         // Check to see if we have free space, and if so, if any of the data falls within the freespace
03338         if(wFreeSpace)
03339         {
03340             // RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
03341             if((lMissingBytes >= (LONG)0) && (wFreeSpace > lMissingBytes))
03342                 bSegmentAcceptable = TRUE;
03343             else
03344             {
03345                 // RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
03346                 if((lMissingBytes + (LONG)wSegmentLength > (LONG)0) && (lMissingBytes <= (LONG)(SHORT)(wFreeSpace - wSegmentLength)))
03347                     bSegmentAcceptable = TRUE;
03348             }
03349             
03350             if((lMissingBytes < (LONG)wFreeSpace) && ((SHORT)wMissingBytes + (SHORT)wSegmentLength > (SHORT)0))
03351                 bSegmentAcceptable = TRUE;
03352         }
03353         // Segments with data are not acceptable if we have no free space
03354     }
03355     else
03356     {
03357         // Zero length packets are acceptable if they fall within our free space window
03358         // SEG.SEQ = RCV.NXT
03359         if(lMissingBytes == 0)
03360         {
03361             bSegmentAcceptable = TRUE;
03362         }
03363         else
03364         {
03365             // RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
03366             if((lMissingBytes >= (LONG)0) && (wFreeSpace > lMissingBytes))
03367                 bSegmentAcceptable = TRUE;
03368         }
03369     }
03370     
03371     if(!bSegmentAcceptable)
03372     {
03373         // Unacceptable segment, drop it and respond appropriately
03374         if(!(localHeaderFlags & RST)) 
03375             SendTCP(ACK, SENDTCP_RESET_TIMERS);
03376         return;
03377     }
03378 
03379 
03380     //
03381     // Second: check the RST bit
03382     //
03383     //
03384     // Fourth: check the SYN bit
03385     //
03386     // Note, that since the third step is not implemented, we can 
03387     // combine this second and fourth step into a single operation.
03388     if(localHeaderFlags & (RST | SYN))
03389     {
03390         CloseSocket();
03391         return;
03392     }
03393 
03394     //
03395     // Third: check the security and precedence
03396     //
03397     // Feature not supported.  Let's process this segment.
03398 
03399     //
03400     // Fifth: check the ACK bit
03401     //
03402     if(!(localHeaderFlags & ACK))
03403         return;
03404 
03405     switch(MyTCBStub.smState)
03406     {
03407         case TCP_SYN_RECEIVED:
03408             if(localAckNumber != MyTCB.MySEQ)
03409             {
03410                 // Send a RST packet with SEQ = SEG.ACK, but retain our SEQ 
03411                 // number for arivial of any other correct packets
03412                 localSeqNumber = MyTCB.MySEQ;   // Save our original SEQ number
03413                 MyTCB.MySEQ = localAckNumber;   // Set SEQ = SEG.ACK
03414                 SendTCP(RST, SENDTCP_RESET_TIMERS);     // Send the RST
03415                 MyTCB.MySEQ = localSeqNumber;   // Restore original SEQ number
03416                 return;
03417             }
03418             MyTCBStub.smState = TCP_ESTABLISHED;
03419             // No break
03420 
03421         case TCP_ESTABLISHED:
03422         case TCP_FIN_WAIT_1:
03423         case TCP_FIN_WAIT_2:
03424         case TCP_CLOSE_WAIT:
03425         case TCP_CLOSING:
03426             // Calculate what the highest possible SEQ number in our TX FIFO is
03427             wTemp = MyTCBStub.txHead - MyTCB.txUnackedTail;
03428             if((SHORT)wTemp < (SHORT)0)
03429                 wTemp += MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
03430             dwTemp = MyTCB.MySEQ + (DWORD)wTemp;
03431 
03432             // Drop the packet if it ACKs something we haven't sent
03433             if((LONG)(dwTemp - localAckNumber) < (LONG)0)
03434             {
03435                 SendTCP(ACK, 0);
03436                 return;
03437             }
03438 
03439             // Throw away all ACKnowledged TX data:
03440             // Calculate what the last acknowledged sequence number was (ignoring any FINs we sent)
03441             dwTemp = MyTCB.MySEQ - (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
03442             if(MyTCB.txUnackedTail < MyTCBStub.txTail)
03443                 dwTemp -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
03444     
03445             // Calcluate how many bytes were ACKed with this packet
03446             dwTemp = localAckNumber - dwTemp;
03447             if(((LONG)(dwTemp) > (LONG)0) && (dwTemp <= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart))
03448             {
03449                 MyTCB.flags.bRXNoneACKed1 = 0;
03450                 MyTCB.flags.bRXNoneACKed2 = 0;
03451                 MyTCBStub.Flags.bHalfFullFlush = FALSE;
03452     
03453                 // Bytes ACKed, free up the TX FIFO space
03454                 wTemp = MyTCBStub.txTail;
03455                 MyTCBStub.txTail += dwTemp;
03456                 if(MyTCB.txUnackedTail >= wTemp)
03457                 {
03458                     if(MyTCB.txUnackedTail < MyTCBStub.txTail)
03459                     {
03460                         MyTCB.MySEQ += MyTCBStub.txTail - MyTCB.txUnackedTail;
03461                         MyTCB.txUnackedTail = MyTCBStub.txTail;
03462                     }
03463                 }
03464                 else
03465                 {
03466                     wTemp = MyTCB.txUnackedTail + (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
03467                     if(wTemp < MyTCBStub.txTail)
03468                     {
03469                         MyTCB.MySEQ += MyTCBStub.txTail - wTemp;
03470                         MyTCB.txUnackedTail = MyTCBStub.txTail;
03471                     }
03472                 }
03473                 if(MyTCBStub.txTail >= MyTCBStub.bufferRxStart)
03474                     MyTCBStub.txTail -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
03475                 if(MyTCB.txUnackedTail >= MyTCBStub.bufferRxStart)
03476                     MyTCB.txUnackedTail -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
03477             }
03478             else
03479             {
03480                 // See if we have outstanding TX data that is waiting for an ACK
03481                 if(MyTCBStub.txTail != MyTCB.txUnackedTail)
03482                 {
03483                     if(MyTCB.flags.bRXNoneACKed1)
03484                     {
03485                         if(MyTCB.flags.bRXNoneACKed2)
03486                         {
03487                             // Set up to perform a fast retransmission
03488                             // Roll back unacknowledged TX tail pointer to cause retransmit to occur
03489                             MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
03490                             if(MyTCB.txUnackedTail < MyTCBStub.txTail)
03491                                 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
03492                             MyTCB.txUnackedTail = MyTCBStub.txTail;
03493                             MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
03494                         }
03495                         MyTCB.flags.bRXNoneACKed2 = 1;
03496                     }
03497                     MyTCB.flags.bRXNoneACKed1 = 1;
03498                 }
03499             }
03500 
03501             // No need to keep our retransmit timer going if we have nothing that needs ACKing anymore
03502             if(MyTCBStub.txTail == MyTCBStub.txHead)
03503             {
03504                 // Make sure there isn't a "FIN byte in our TX FIFO"
03505                 if(MyTCBStub.Flags.bTXFIN == 0)
03506                 {
03507                     MyTCBStub.Flags.bTimerEnabled = 0;
03508                 }
03509                 else
03510                 {
03511                     // "Throw away" FIN byte from our TX FIFO if it has been ACKed
03512                     if(MyTCB.MySEQ == localAckNumber)
03513                     {
03514                         MyTCBStub.Flags.bTimerEnabled = 0;
03515                         MyTCBStub.Flags.bTXFIN = 0;
03516                         MyTCB.flags.bFINSent = 0;   
03517                     }
03518                 }
03519             }
03520 
03521             // Update the local stored copy of the RemoteWindow
03522             // If previously we had a zero window, and now we don't 
03523             // immediately send whatever was pending
03524             if((MyTCB.remoteWindow == 0u) && h->Window)
03525                 MyTCBStub.Flags.bTXASAP = 1;
03526             MyTCB.remoteWindow = h->Window;
03527 
03528             // A couple of states must do all of the TCP_ESTABLISHED stuff, but also a little more
03529             if(MyTCBStub.smState == TCP_FIN_WAIT_1)
03530             {
03531                 // Check to see if our FIN has been ACKnowledged
03532                 if(MyTCB.MySEQ == localAckNumber)
03533                 {
03534                     // Reset our timer for forced closure if the remote node 
03535                     // doesn't send us a FIN in a timely manner.
03536                     MyTCBStub.eventTime = TickGet() + TCP_FIN_WAIT_2_TIMEOUT;
03537                     MyTCBStub.Flags.bTimerEnabled = 1;
03538                     MyTCBStub.smState = TCP_FIN_WAIT_2;
03539                 }
03540             }
03541             else if(MyTCBStub.smState == TCP_FIN_WAIT_2)
03542             {
03543                 // RFC noncompliance:
03544                 // The remote node should not keep sending us data 
03545                 // indefinitely after we send a FIN to it.  
03546                 // However, some bad stacks may still keep sending 
03547                 // us data indefinitely after ACKing our FIN.  To 
03548                 // prevent this from locking up our socket, let's 
03549                 // send a RST right now and close forcefully on 
03550                 // our side.
03551                 if(!(localHeaderFlags & FIN))
03552                 {
03553                     MyTCB.MySEQ = localAckNumber;   // Set SEQ = SEG.ACK
03554                     SendTCP(RST | ACK, 0);
03555                     CloseSocket();
03556                     return;
03557                 }
03558             }
03559             else if(MyTCBStub.smState == TCP_CLOSING)
03560             {
03561                 // Check to see if our FIN has been ACKnowledged
03562                 if(MyTCB.MySEQ == localAckNumber)
03563                 {
03564                     // RFC not recommended: We should be going to 
03565                     // the TCP_TIME_WAIT state right here and 
03566                     // starting a 2MSL timer, but since we have so 
03567                     // few precious sockets, we can't afford to 
03568                     // leave a socket waiting around doing nothing 
03569                     // for a long time.  If the remote node does 
03570                     // not recieve this ACK, it'll have to figure 
03571                     // out on it's own that the connection is now 
03572                     // closed.
03573                     CloseSocket();
03574                 }
03575 
03576                 return;
03577             }
03578 
03579             break;
03580 
03581         case TCP_LAST_ACK:
03582             // Check to see if our FIN has been ACKnowledged
03583             if(MyTCB.MySEQ == localAckNumber)
03584                 CloseSocket();
03585             return;
03586 
03587 //      case TCP_TIME_WAIT:
03588 //          // Nothing is supposed to arrive here.  If it does, reset the quiet timer.
03589 //          SendTCP(ACK, SENDTCP_RESET_TIMERS);
03590 //          return;
03591 
03592         default:
03593             break;
03594     }
03595 
03596     //
03597     // Sixth: Check the URG bit
03598     //
03599     // Urgent packets are not supported in this stack, so we
03600     // will throw them away instead
03601     if(localHeaderFlags & URG)
03602         return;
03603 
03604     //
03605     // Seventh: Process the segment text
03606     //
03607     // Throw data away if in a state that doesn't accept data
03608     if(MyTCBStub.smState == TCP_CLOSE_WAIT)
03609         return;
03610     if(MyTCBStub.smState == TCP_CLOSING)
03611         return;
03612     if(MyTCBStub.smState == TCP_LAST_ACK)
03613         return;
03614 //  if(MyTCBStub.smState == TCP_TIME_WAIT)
03615 //      return;
03616 
03617     // Copy any valid segment data into our RX FIFO, if any
03618     if(len)
03619     {
03620         // See if there are bytes we must skip
03621         if((SHORT)wMissingBytes <= 0)
03622         {
03623             // Position packet read pointer to start of useful data area.
03624             IPSetRxBuffer((h->DataOffset.Val << 2) - wMissingBytes);
03625             len += wMissingBytes;       
03626     
03627             // Truncate packets that would overflow our TCP RX FIFO
03628             // and request a retransmit by sending a duplicate ACK
03629             if(len > wFreeSpace)
03630                 len = wFreeSpace;
03631     
03632             MyTCB.RemoteSEQ += (DWORD)len;
03633         
03634             // Copy the application data from the packet into the socket RX FIFO
03635             // See if we need a two part copy (spans bufferEnd->bufferRxStart)
03636             if(MyTCBStub.rxHead + len > MyTCBStub.bufferEnd)
03637             {
03638                 wTemp = MyTCBStub.bufferEnd - MyTCBStub.rxHead + 1;
03639                 TCPRAMCopy(MyTCBStub.rxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, wTemp);
03640                 TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len - wTemp);
03641                 MyTCBStub.rxHead = MyTCBStub.bufferRxStart + (len - wTemp);
03642             }
03643             else
03644             {
03645                 TCPRAMCopy(MyTCBStub.rxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
03646                 MyTCBStub.rxHead += len;
03647             }
03648         
03649             // See if we have a hole and other data waiting already in the RX FIFO
03650             if(MyTCB.sHoleSize != -1)
03651             {
03652                 MyTCB.sHoleSize -= len;
03653                 wTemp = MyTCB.wFutureDataSize + MyTCB.sHoleSize;
03654         
03655                 // See if we just closed up a hole, and if so, advance head pointer
03656                 if((SHORT)wTemp < (SHORT)0)
03657                 {
03658                     MyTCB.sHoleSize = -1;
03659                 }
03660                 else if(MyTCB.sHoleSize <= 0)
03661                 {
03662                     MyTCB.RemoteSEQ += wTemp;
03663                     MyTCBStub.rxHead += wTemp;
03664                     if(MyTCBStub.rxHead > MyTCBStub.bufferEnd)
03665                         MyTCBStub.rxHead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;                          
03666                     MyTCB.sHoleSize = -1;
03667                 }
03668             }
03669         } // This packet is out of order or we lost a packet, see if we can generate a hole to accomodate it
03670         else if((SHORT)wMissingBytes > 0)
03671         {
03672             // Truncate packets that would overflow our TCP RX FIFO
03673             if(len + wMissingBytes > wFreeSpace)
03674                 len = wFreeSpace - wMissingBytes;
03675         
03676             // Position packet read pointer to start of useful data area.
03677             IPSetRxBuffer(h->DataOffset.Val << 2);
03678     
03679             // See if we need a two part copy (spans bufferEnd->bufferRxStart)
03680             if(MyTCBStub.rxHead + wMissingBytes + len > MyTCBStub.bufferEnd)
03681             {
03682                 // Calculate number of data bytes to copy before wraparound
03683                 wTemp = MyTCBStub.bufferEnd - MyTCBStub.rxHead + 1 - wMissingBytes;
03684                 if((SHORT)wTemp >= 0)
03685                 {
03686                     TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, wTemp);
03687                     TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len - wTemp);
03688                 }
03689                 else
03690                 {
03691                     TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes - (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1), MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
03692                 }
03693             }
03694             else
03695             {
03696                 TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
03697             }
03698         
03699             // Record the hole is here
03700             if(MyTCB.sHoleSize == -1)
03701             {
03702                 MyTCB.sHoleSize = wMissingBytes;
03703                 MyTCB.wFutureDataSize = len;
03704             }
03705             else
03706             {
03707                 // We already have a hole, see if we can shrink the hole 
03708                 // or extend the future data size
03709                 if(wMissingBytes < (WORD)MyTCB.sHoleSize)
03710                 {
03711                     if((wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize) || (wMissingBytes + len < (WORD)MyTCB.sHoleSize))
03712                         MyTCB.wFutureDataSize = len;
03713                     else
03714                         MyTCB.wFutureDataSize = (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize - wMissingBytes;
03715                     MyTCB.sHoleSize = wMissingBytes;
03716                 }
03717                 else if(wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize)
03718                 {
03719                     // Make sure that there isn't a second hole between 
03720                     // our future data and this TCP segment's future data
03721                     if(wMissingBytes <= (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize)
03722                         MyTCB.wFutureDataSize += wMissingBytes + len - (WORD)MyTCB.sHoleSize - MyTCB.wFutureDataSize;
03723                 }
03724                 
03725             }
03726         }
03727     }
03728 
03729     // Send back an ACK of the data (+SYN | FIN) we just received, 
03730     // if any.  To minimize bandwidth waste, we are implementing 
03731     // the delayed acknowledgement algorithm here, only sending 
03732     // back an immediate ACK if this is the second segment received.  
03733     // Otherwise, a 200ms timer will cause the ACK to be transmitted.
03734     if(wSegmentLength)
03735     {
03736         // For non-established sockets, let's delete all data in 
03737         // the RX buffer immediately after receiving it.  This is 
03738         // not really how TCP was intended to operate since a 
03739         // socket cannot receive any response after it sends a FIN,
03740         // but our TCP application API doesn't readily accomodate
03741         // receiving data after calling TCPDisconnect(), which 
03742         // invalidates the application TCP handle.  By deleting all 
03743         // data, we'll ensure that the RX window is nonzero and 
03744         // the remote node will be able to send us a FIN response, 
03745         // which needs an RX window of at least 1.
03746         if(MyTCBStub.smState != TCP_ESTABLISHED)
03747             MyTCBStub.rxTail = MyTCBStub.rxHead;
03748 
03749         if(MyTCBStub.Flags.bOneSegmentReceived)
03750         {
03751             SendTCP(ACK, SENDTCP_RESET_TIMERS);
03752             SyncTCB();
03753             // bOneSegmentReceived is cleared in SendTCP(), so no need here
03754         }
03755         else
03756         {
03757             MyTCBStub.Flags.bOneSegmentReceived = TRUE; 
03758         
03759             // Do not send an ACK immediately back.  Instead, we will 
03760             // perform delayed acknowledgements.  To do this, we will 
03761             // just start a timer
03762             if(!MyTCBStub.Flags.bDelayedACKTimerEnabled)
03763             {
03764                 MyTCBStub.Flags.bDelayedACKTimerEnabled = 1;
03765                 MyTCBStub.OverlappedTimers.delayedACKTime = (WORD)TickGetDiv256() + (WORD)((TCP_DELAYED_ACK_TIMEOUT)>>8);
03766             }
03767         }
03768     }
03769 
03770     //
03771     // Eighth: check the FIN bit
03772     //
03773     if(localHeaderFlags & FIN)
03774     {
03775         // Note: Since we don't have a good means of storing "FIN bytes" 
03776         // in our TCP RX FIFO, we must ensure that FINs are processed 
03777         // in-order.
03778         if(MyTCB.RemoteSEQ + 1 == localSeqNumber + (DWORD)wSegmentLength)
03779         {
03780             // FINs are treated as one byte of data for ACK sequencing
03781             MyTCB.RemoteSEQ++;
03782             
03783             switch(MyTCBStub.smState)
03784             {
03785                 case TCP_SYN_RECEIVED:
03786                     // RFC in exact: Our API has no need for the user 
03787                     // to explicitly close a socket that never really 
03788                     // got opened fully in the first place, so just 
03789                     // transmit a FIN automatically and jump to 
03790                     // TCP_LAST_ACK
03791                     MyTCBStub.smState = TCP_LAST_ACK;
03792                     SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
03793                     return;
03794 
03795                 case TCP_ESTABLISHED:
03796                     // Go to TCP_CLOSE_WAIT state
03797                     MyTCBStub.smState = TCP_CLOSE_WAIT;
03798                     
03799                     // For legacy applications that don't call 
03800                     // TCPDisconnect() as needed and expect the TCP/IP 
03801                     // Stack to automatically close sockets when the 
03802                     // remote node sends a FIN, let's start a timer so 
03803                     // that we will eventually close the socket automatically
03804                     MyTCBStub.OverlappedTimers.closeWaitTime = (WORD)TickGetDiv256() + (WORD)((TCP_CLOSE_WAIT_TIMEOUT)>>8);
03805                     break;
03806     
03807                 case TCP_FIN_WAIT_1:
03808                     if(MyTCB.MySEQ == localAckNumber)
03809                     {
03810                         // RFC not recommended: We should be going to 
03811                         // the TCP_TIME_WAIT state right here and 
03812                         // starting a 2MSL timer, but since we have so 
03813                         // few precious sockets, we can't afford to 
03814                         // leave a socket waiting around doing nothing 
03815                         // for a long time.  If the remote node does 
03816                         // not recieve this ACK, it'll have to figure 
03817                         // out on it's own that the connection is now 
03818                         // closed.
03819                         SendTCP(ACK, 0);
03820                         CloseSocket();
03821                         return;
03822                     }
03823                     else
03824                     {
03825                         MyTCBStub.smState = TCP_CLOSING;
03826                     }
03827                     break;
03828     
03829                 case TCP_FIN_WAIT_2:
03830                     // RFC not recommended: We should be going to 
03831                     // the TCP_TIME_WAIT state right here and 
03832                     // starting a 2MSL timer, but since we have so 
03833                     // few precious sockets, we can't afford to 
03834                     // leave a socket waiting around doing nothing 
03835                     // for a long time.  If the remote node does 
03836                     // not recieve this ACK, it'll have to figure 
03837                     // out on it's own that the connection is now 
03838                     // closed.
03839                     SendTCP(ACK, 0);
03840                     CloseSocket();
03841                     return;
03842 
03843                 default:
03844                     break;
03845             }
03846 
03847             // Acknowledge receipt of FIN
03848             SendTCP(ACK, SENDTCP_RESET_TIMERS);
03849         }
03850     }
03851 }
03852 
03853 /****************************************************************************
03854   Section:
03855     Buffer Management Functions
03856   ***************************************************************************/
03857 
03858 /*****************************************************************************
03859   Function:
03860     BOOL TCPAdjustFIFOSize(TCP_SOCKET hTCP, WORD wMinRXSize, 
03861                             WORD wMinTXSize, BYTE vFlags)
03862 
03863   Summary:
03864     Adjusts the relative sizes of the RX and TX buffers.
03865 
03866   Description:
03867     This function can be used to adjust the relative sizes of the RX and
03868     TX FIFO depending on the immediate needs of an application.  Since a 
03869     larger FIFO can allow more data to be sent in a given packet, adjusting 
03870     the relative sizes on the fly can allow for optimal transmission speed 
03871     for one-sided application protocols.  For example, HTTP typically 
03872     begins by receiving large amounts of data from the client, then switches
03873     to serving large amounts of data back.  Adjusting the FIFO at these 
03874     points can increase performance substantially.  Once the FIFO is
03875     adjusted, a window update is sent.
03876     
03877     If neither or both of TCP_ADJUST_GIVE_REST_TO_TX and 
03878     TCP_ADJUST_GIVE_REST_TO_RX are set, the function distributes the
03879     remaining space equally.
03880     
03881     Received data can be preserved as long as the buffer is expanding and 
03882     has not wrapped.
03883 
03884   Precondition:
03885     TCP is initialized.
03886 
03887   Parameters:
03888     hTCP        - The socket to be adjusted
03889     wMinRXSize  - Minimum number of byte for the RX FIFO
03890     wMinTXSize  - Minimum number of bytes for the RX FIFO
03891     vFlags      - Any combination of TCP_ADJUST_GIVE_REST_TO_RX, 
03892                   TCP_ADJUST_GIVE_REST_TO_TX, TCP_ADJUST_PRESERVE_RX.
03893                   TCP_ADJUST_PRESERVE_TX is not currently supported.
03894 
03895   Return Values:
03896     TRUE - The FIFOs were adjusted successfully
03897     FALSE - Minimum RX, Minimum TX, or flags couldn't be accommodated and
03898             therefore the socket was left unchanged.
03899 
03900   Side Effects:
03901     Any unacknowledged or untransmitted data in the TX FIFO is always
03902     deleted.
03903 
03904   Remarks:
03905     At least one byte must always be allocated to the RX buffer so that
03906     a FIN can be received.  The function automatically corrects for this.
03907   ***************************************************************************/
03908 BOOL TCPAdjustFIFOSize(TCP_SOCKET hTCP, WORD wMinRXSize, WORD wMinTXSize, BYTE vFlags)
03909 {
03910     PTR_BASE ptrTemp, ptrHead;
03911     WORD wTXAllocation;
03912     
03913     // Load up info on this socket
03914     SyncTCBStub(hTCP);
03915 
03916     // RX has to be at least 1 byte to receive SYN and FIN bytes 
03917     // from the remote node, even if they aren't stored in the RX FIFO
03918     if(wMinRXSize == 0u)
03919         wMinRXSize = 1;
03920         
03921     // SSL connections need to be able to send or receive at least 
03922     // a full Alert record, MAC, and FIN
03923     #if defined(STACK_USE_SSL)
03924     if(TCPIsSSL(hTCP) && wMinRXSize < 25)
03925         wMinRXSize = 25;
03926     if(TCPIsSSL(hTCP) && wMinTXSize < 25)
03927         wMinTXSize = 25;
03928     #endif
03929     
03930     // Make sure space is available for minimums
03931     ptrTemp = MyTCBStub.bufferEnd - MyTCBStub.bufferTxStart - 1;
03932     if(wMinRXSize + wMinTXSize > ptrTemp)
03933         return FALSE;
03934 
03935     SyncTCB();
03936 
03937     // Set both allocation flags if none set
03938     if(!(vFlags & (TCP_ADJUST_GIVE_REST_TO_TX | TCP_ADJUST_GIVE_REST_TO_RX)))
03939         vFlags |= TCP_ADJUST_GIVE_REST_TO_TX | TCP_ADJUST_GIVE_REST_TO_RX;
03940         
03941 
03942     // Allocate minimums
03943     wTXAllocation = wMinTXSize;
03944     ptrTemp -= wMinRXSize + wMinTXSize;
03945 
03946     // Allocate extra
03947     if(vFlags & TCP_ADJUST_GIVE_REST_TO_TX)
03948     {
03949         if(vFlags & TCP_ADJUST_GIVE_REST_TO_RX)
03950         {
03951             // Do a 50%/50% split with any odd byte always going to the RX FIFO
03952             wTXAllocation += ptrTemp>>1;
03953         }
03954         else
03955         {
03956             wTXAllocation += ptrTemp;
03957         }
03958     }
03959 
03960     // Calculate new bufferRxStart pointer
03961     ptrTemp = MyTCBStub.bufferTxStart + wTXAllocation + 1;
03962 
03963     // Find the head pointer to use
03964     ptrHead = MyTCBStub.rxHead;
03965     #if defined(STACK_USE_SSL)
03966     if(TCPIsSSL(hTCP))
03967         ptrHead = MyTCBStub.sslRxHead;
03968     #endif
03969     
03970     // If there's out-of-order data pending, adjust the head pointer to compensate
03971     if(MyTCB.sHoleSize != -1)
03972     {
03973         ptrHead += MyTCB.sHoleSize + MyTCB.wFutureDataSize;
03974         if(ptrHead > MyTCBStub.bufferEnd)
03975             ptrHead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
03976     }
03977 
03978     // Determine if resizing will lose any RX data
03979     if(MyTCBStub.rxTail < ptrHead)
03980     {
03981         if(ptrTemp > MyTCBStub.rxTail)
03982         {
03983             if(vFlags & TCP_ADJUST_PRESERVE_RX)
03984                 return FALSE;
03985             else
03986             {
03987                 MyTCBStub.rxTail = ptrTemp;
03988                 MyTCBStub.rxHead = ptrTemp;
03989 
03990                 #if defined(STACK_USE_SSL)
03991                 MyTCBStub.sslRxHead = ptrTemp;
03992                 #endif
03993             }
03994         }
03995     }
03996     else if(MyTCBStub.rxTail > ptrHead)
03997     {
03998         if(ptrTemp > MyTCBStub.bufferRxStart)
03999         {
04000             if(vFlags & TCP_ADJUST_PRESERVE_RX)
04001                 return FALSE;
04002             else
04003             {
04004                 MyTCBStub.rxTail = ptrTemp;
04005                 MyTCBStub.rxHead = ptrTemp;
04006                 
04007                 #if defined(STACK_USE_SSL)
04008                 MyTCBStub.sslRxHead = ptrTemp;
04009                 #endif
04010             }
04011         }
04012     }
04013     else
04014     {
04015         // No data to preserve, but we may need to move 
04016         // the pointers to stay in the RX space
04017         MyTCBStub.rxTail = ptrTemp;
04018         MyTCBStub.rxHead = ptrTemp;
04019         
04020         #if defined(STACK_USE_SSL)
04021         MyTCBStub.sslRxHead = ptrTemp;
04022         #endif
04023     }
04024     
04025     // If we need to preserve data that wrapped in the ring, we must copy
04026     if(ptrHead < MyTCBStub.rxTail && (vFlags & TCP_ADJUST_PRESERVE_RX))
04027     {
04028         TCPRAMCopy(ptrTemp, MyTCBStub.vMemoryMedium, 
04029             MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium,
04030             ptrHead - MyTCBStub.bufferRxStart);
04031 
04032         // Move the pointers if they were in front of the tail
04033         #if defined(STACK_USE_SSL)
04034         if(TCPIsSSL(hTCP) && MyTCBStub.sslRxHead < MyTCBStub.rxTail)
04035             MyTCBStub.sslRxHead -= MyTCBStub.bufferRxStart - ptrTemp;
04036         #endif
04037         if(MyTCBStub.rxHead < MyTCBStub.rxTail)
04038             MyTCBStub.rxHead -= MyTCBStub.bufferRxStart - ptrTemp;
04039     }
04040     
04041     // Move the RX buffer pointer - it's the one that divides the two
04042     MyTCBStub.bufferRxStart = ptrTemp;
04043 
04044     // Empty the TX buffer
04045     MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
04046     MyTCBStub.txTail = MyTCBStub.bufferTxStart;
04047     MyTCBStub.txHead = MyTCBStub.bufferTxStart;
04048     
04049     #if defined(STACK_USE_SSL)
04050     if(TCPIsSSL(hTCP))
04051         MyTCBStub.sslTxHead = MyTCBStub.txHead + 5;
04052     #endif
04053     
04054     // Send a window update to notify remote node of change
04055     if(MyTCBStub.smState == TCP_ESTABLISHED)
04056         SendTCP(ACK, SENDTCP_RESET_TIMERS);
04057 
04058     return TRUE;
04059 
04060 }
04061 
04062 /*****************************************************************************
04063   Function:
04064     static void TCPRAMCopy(PTR_BASE ptrDest, BYTE vDestType, PTR_BASE ptrSource, 
04065                             BYTE vSourceType, WORD wLength)
04066 
04067   Summary:
04068     Copies data to/from various memory mediums.
04069 
04070   Description:
04071     This function copies data between memory mediums (PIC RAM, SPI
04072     RAM, and Ethernet buffer RAM).
04073 
04074   Precondition:
04075     TCP is initialized.
04076 
04077   Parameters:
04078     ptrDest     - Address to write to
04079     vDestType   - Destination meidum (TCP_PIC_RAM, TCP_ETH_RAM, TCP_SPI_RAM)
04080     ptrSource   - Address to copy from
04081     vSourceType - Source medium (TCP_PIC_RAM, TCP_ETH_RAM, or TCP_SPI_RAM)
04082     wLength     - Number of bytes to copy
04083 
04084   Returns:
04085     None
04086 
04087   Remarks:
04088     Copying to a destination region that overlaps with the source address 
04089     is supported only if the destination start address is at a lower memory 
04090     address (closer to 0x0000) than the source pointer.
04091   ***************************************************************************/
04092 static void TCPRAMCopy(PTR_BASE ptrDest, BYTE vDestType, PTR_BASE ptrSource, BYTE vSourceType, WORD wLength)
04093 {
04094     #if defined(SPIRAM_CS_TRIS)
04095     BYTE vBuffer[16];
04096     WORD w;
04097     #endif
04098         
04099     switch(vSourceType)
04100     {
04101         case TCP_PIC_RAM:
04102             switch(vDestType)
04103             {
04104                 case TCP_PIC_RAM:
04105                     memcpy((void*)(BYTE*)ptrDest, (void*)(BYTE*)ptrSource, wLength);
04106                     break;
04107     
04108                 case TCP_ETH_RAM:
04109                     if(!((WORD_VAL*)&ptrDest)->bits.b15)
04110                         MACSetWritePtr((WORD)ptrDest);
04111                     MACPutArray((BYTE*)ptrSource, wLength);
04112                     break;
04113     
04114                 #if defined(SPIRAM_CS_TRIS)
04115                 case TCP_SPI_RAM:
04116                     SPIRAMPutArray(ptrDest, (BYTE*)ptrSource, wLength);
04117                     break;
04118                 #endif
04119             }
04120             break;
04121     
04122         case TCP_ETH_RAM:
04123             switch(vDestType)
04124             {
04125                 case TCP_PIC_RAM:
04126                     if(!((WORD_VAL*)&ptrSource)->bits.b15)
04127                         MACSetReadPtr(ptrSource);
04128                     MACGetArray((BYTE*)ptrDest, wLength);
04129                     break;
04130     
04131                 case TCP_ETH_RAM:
04132                     MACMemCopyAsync(ptrDest, ptrSource, wLength);
04133                     while(!MACIsMemCopyDone());
04134                     break;
04135     
04136                 #if defined(SPIRAM_CS_TRIS)
04137                 case TCP_SPI_RAM:
04138                     if(!((WORD_VAL*)&ptrSource)->bits.b15)
04139                         MACSetReadPtr(ptrSource);
04140                     w = sizeof(vBuffer);
04141                     while(wLength)
04142                     {
04143                         if(w > wLength)
04144                             w = wLength;
04145                         
04146                         // Read and write a chunk   
04147                         MACGetArray(vBuffer, w);
04148                         SPIRAMPutArray(ptrDest, vBuffer, w);
04149                         ptrDest += w;
04150                         wLength -= w;
04151                     }
04152                     break;
04153                 #endif
04154             }
04155             break;
04156     
04157         #if defined(SPIRAM_CS_TRIS)
04158         case TCP_SPI_RAM:
04159             switch(vDestType)
04160             {
04161                 case TCP_PIC_RAM:
04162                     SPIRAMGetArray(ptrSource, (BYTE*)ptrDest, wLength);
04163                     break;
04164     
04165                 case TCP_ETH_RAM:
04166                     if(!((WORD_VAL*)&ptrDest)->bits.b15)
04167                         MACSetWritePtr(ptrDest);
04168                     w = sizeof(vBuffer);
04169                     while(wLength)
04170                     {
04171                         if(w > wLength)
04172                             w = wLength;
04173                         
04174                         // Read and write a chunk   
04175                         SPIRAMGetArray(ptrSource, vBuffer, w);
04176                         ptrSource += w;
04177                         MACPutArray(vBuffer, w);
04178                         wLength -= w;
04179                     }
04180                     break;
04181     
04182                 case TCP_SPI_RAM:
04183                     // Copy all of the data over in chunks
04184                     w = sizeof(vBuffer);
04185                     while(wLength)
04186                     {
04187                         if(w > wLength)
04188                             w = wLength;
04189                             
04190                         SPIRAMGetArray(ptrSource, vBuffer, w);
04191                         SPIRAMPutArray(ptrDest, vBuffer, w);
04192                         ptrSource += w;
04193                         ptrDest += w;
04194                         wLength -= w;
04195                     }
04196                     break;
04197             }
04198             break;
04199         #endif          
04200     }
04201 }
04202 
04203 /*****************************************************************************
04204   Function:
04205     static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource, 
04206                                 WORD wLength)
04207 
04208   Summary:
04209     Copies data to/from various memory mediums.
04210 
04211   Description:
04212     This function copies data between memory mediums (PIC RAM, SPI
04213     RAM, and Ethernet buffer RAM).  This function is to be used when 
04214     copying from ROM.
04215 
04216   Precondition:
04217     TCP is initialized.
04218 
04219   Parameters:
04220     wDest       - Address to write to
04221     wDestType   - Destination meidum (TCP_PIC_RAM, TCP_ETH_RAM, TCP_SPI_RAM)
04222     wSource     - Address to copy from
04223     wLength     - Number of bytes to copy
04224 
04225   Returns:
04226     None
04227 
04228   Remarks:
04229     Copying to a destination region that overlaps with the source address 
04230     is supported only if the destination start address is at a lower memory 
04231     address (closer to 0x0000) than the source pointer.
04232     
04233     This function is aliased to TCPRAMCopy on non-PIC18 platforms.
04234   ***************************************************************************/
04235 #if defined(__18CXX)
04236 static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource, WORD wLength)
04237 {
04238     BYTE vBuffer[16];
04239     WORD w;
04240     
04241     switch(wDestType)
04242     {
04243         case TCP_PIC_RAM:
04244             memcpypgm2ram((void*)(BYTE*)wDest, (ROM void*)wSource, wLength);
04245             break;
04246     
04247         case TCP_ETH_RAM:
04248             if(!((WORD_VAL*)&wDest)->bits.b15)
04249                 MACSetWritePtr(wDest);
04250             w = sizeof(vBuffer);
04251             while(wLength)
04252             {
04253                 if(w > wLength)
04254                     w = wLength;
04255                 
04256                 // Read and write a chunk   
04257                 memcpypgm2ram(vBuffer, (ROM void*)wSource, w);
04258                 MACPutArray(vBuffer, w);
04259                 wSource += w;
04260                 wLength -= w;
04261             }
04262             break;
04263     
04264         #if defined(SPIRAM_CS_TRIS)
04265         case TCP_SPI_RAM:
04266             w = sizeof(vBuffer);
04267             while(wLength)
04268             {
04269                 if(w > wLength)
04270                     w = wLength;
04271                 
04272                 // Read and write a chunk   
04273                 memcpypgm2ram(vBuffer, (ROM void*)wSource, w);
04274                 SPIRAMPutArray(wDest, vBuffer, w);
04275                 wDest += w;
04276                 wSource += w;
04277                 wLength -= w;
04278             }
04279             break;
04280         #endif
04281     }
04282 }
04283 #endif
04284 
04285 /****************************************************************************
04286   Section:
04287     SSL Functions
04288   ***************************************************************************/
04289 
04290 /*****************************************************************************
04291   Function:
04292     BOOL TCPStartSSLClient(TCP_SOCKET hTCP, BYTE* host)
04293 
04294   Summary:
04295     Begins an SSL client session.
04296 
04297   Description:
04298     This function escalates the current connection to an SSL secured 
04299     connection by initiating an SSL client handshake.
04300 
04301   Precondition:
04302     TCP is initialized and hTCP is already connected.
04303 
04304   Parameters:
04305     hTCP        - TCP connection to secure
04306     host        - Expected host name on certificate (currently ignored)
04307 
04308   Return Values:
04309     TRUE        - an SSL connection was initiated
04310     FALSE       - Insufficient SSL resources (stubs) were available
04311 
04312   Remarks:
04313     The host parameter is currently ignored and is not validated.
04314   ***************************************************************************/
04315 #if defined(STACK_USE_SSL_CLIENT)
04316 BOOL TCPStartSSLClient(TCP_SOCKET hTCP, BYTE* host)
04317 {
04318     BYTE i;
04319     
04320     SyncTCBStub(hTCP);
04321     
04322     // Make sure SSL is not established already
04323     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
04324         return FALSE;
04325     
04326     // Try to start the session
04327     MyTCBStub.sslStubID = SSLStartSession(hTCP);
04328     
04329     // Make sure a session stub was obtained
04330     if(MyTCBStub.sslStubID == SSL_INVALID_ID)
04331         return FALSE;
04332 
04333     // Mark connection as handshaking and return
04334     MyTCBStub.sslReqMessage = SSL_CLIENT_HELLO;
04335     MyTCBStub.sslRxHead = MyTCBStub.rxHead;
04336     MyTCBStub.sslTxHead = MyTCBStub.txHead;
04337     MyTCBStub.Flags.bSSLHandshaking = 1;
04338     for(i = 0; i < 5; i++)
04339     {// Skip first 5 bytes in TX for the record header
04340         if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
04341             MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
04342     }
04343     return TRUE;
04344 }
04345 #endif // SSL Client
04346 
04347 /*****************************************************************************
04348   Function:
04349     BOOL TCPStartSSLServer(TCP_SOCKET hTCP)
04350 
04351   Summary:
04352     Begins an SSL server session.
04353 
04354   Description:
04355     This function sets up an SSL server session when a new connection is
04356     established on an SSL port.
04357 
04358   Precondition:
04359     TCP is initialized and hTCP is already connected.
04360 
04361   Parameters:
04362     hTCP        - TCP connection to secure
04363 
04364   Return Values:
04365     TRUE        - an SSL connection was initiated
04366     FALSE       - Insufficient SSL resources (stubs) were available
04367   ***************************************************************************/
04368 #if defined(STACK_USE_SSL_SERVER)
04369 BOOL TCPStartSSLServer(TCP_SOCKET hTCP)
04370 {
04371     BYTE i;
04372     
04373     SyncTCBStub(hTCP);
04374     SyncTCB();
04375     
04376     // Make sure SSL is not established already
04377     if(MyTCBStub.sslStubID != SSL_INVALID_ID)
04378         return TRUE;
04379     
04380     // Try to start the session
04381     MyTCBStub.sslStubID = SSLStartSession(hTCP);
04382     
04383     // Make sure a session stub was obtained
04384     if(MyTCBStub.sslStubID == SSL_INVALID_ID)
04385         return FALSE;
04386 
04387     // Swap the localPort and localSSLPort
04388     MyTCBStub.remoteHash.Val = MyTCB.localPort.Val;
04389     MyTCB.localPort.Val = MyTCB.localSSLPort.Val;
04390     MyTCB.localSSLPort.Val = MyTCBStub.remoteHash.Val;  
04391 
04392     // Mark connection as handshaking and return
04393     MyTCBStub.sslReqMessage = SSL_NO_MESSAGE;
04394     MyTCBStub.sslRxHead = MyTCBStub.rxHead;
04395     MyTCBStub.sslTxHead = MyTCBStub.txHead;
04396     MyTCBStub.Flags.bSSLHandshaking = 1;
04397     for(i = 0; i < 5; i++)
04398     {// Skip first 5 bytes in TX for the record header
04399         if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
04400             MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
04401     }
04402     return TRUE;
04403 }
04404 #endif // SSL Client
04405 
04406 /*****************************************************************************
04407   Function:
04408     BOOL TCPAddSSLListener(TCP_SOCKET hTCP, WORD port)
04409 
04410   Summary:
04411     Listens for SSL connection on a specific port.
04412 
04413   Description:
04414     This function adds an additional listening port to a TCP connection.  
04415     Connections made on this alternate port will be secured via SSL.
04416 
04417   Precondition:
04418     TCP is initialized and hTCP is listening.
04419 
04420   Parameters:
04421     hTCP        - TCP connection to secure
04422     port        - SSL port to listen on
04423 
04424   Return Values:
04425     TRUE        - SSL port was added.
04426     FALSE       - The socket was not a listening socket.
04427   ***************************************************************************/
04428 #if defined(STACK_USE_SSL_SERVER)
04429 BOOL TCPAddSSLListener(TCP_SOCKET hTCP, WORD port)
04430 {
04431     SyncTCBStub(hTCP);
04432     
04433     if(MyTCBStub.smState != TCP_LISTEN)
04434         return FALSE;
04435     
04436     SyncTCB();
04437     
04438     MyTCB.localSSLPort.Val = port;
04439     MyTCBStub.sslTxHead = port;
04440 
04441     return TRUE;
04442 }
04443 #endif // SSL Server
04444 
04445 /*****************************************************************************
04446   Function:
04447     BOOL TCPRequestSSLMessage(TCP_SOCKET hTCP, BYTE msg)
04448 
04449   Summary:
04450     Requests an SSL message to be transmitted.
04451 
04452   Description:
04453     This function is called to request that a specific SSL message be
04454     transmitted.  This message should only be called by the SSL module.
04455     
04456   Precondition:
04457     TCP is initialized.
04458 
04459   Parameters:
04460     hTCP        - TCP connection to use
04461     msg         - One of the SSL_MESSAGE types to transmit.
04462 
04463   Return Values:
04464     TRUE        - The message was requested.
04465     FALSE       - Another message is already pending transmission.
04466   ***************************************************************************/
04467 #if defined(STACK_USE_SSL)
04468 BOOL TCPRequestSSLMessage(TCP_SOCKET hTCP, BYTE msg)
04469 {
04470     SyncTCBStub(hTCP);
04471     
04472     if(msg == SSL_NO_MESSAGE || MyTCBStub.sslReqMessage == SSL_NO_MESSAGE)
04473     {
04474         MyTCBStub.sslReqMessage = msg;
04475         return TRUE;
04476     }
04477     
04478     return FALSE;
04479 }
04480 #endif // SSL
04481 
04482 /*****************************************************************************
04483   Function:
04484     BOOL TCPSSLIsHandshaking(TCP_SOCKET hTCP)
04485 
04486   Summary:
04487     Determines if an SSL session is still handshaking.
04488 
04489   Description:
04490     Call this function after calling TCPStartSSLClient until FALSE is
04491     returned.  Then your application may continue with its normal data
04492     transfer (which is now secured).
04493     
04494   Precondition:
04495     TCP is initialized and hTCP is connected.
04496 
04497   Parameters:
04498     hTCP        - TCP connection to check
04499 
04500   Return Values:
04501     TRUE        - SSL handshake is still progressing
04502     FALSE       - SSL handshake has completed
04503   ***************************************************************************/
04504 #if defined(STACK_USE_SSL)
04505 BOOL TCPSSLIsHandshaking(TCP_SOCKET hTCP)
04506 {
04507     SyncTCBStub(hTCP);
04508     return MyTCBStub.Flags.bSSLHandshaking; 
04509 }
04510 #endif // SSL
04511 
04512 /*****************************************************************************
04513   Function:
04514     BOOL TCPIsSSL(TCP_SOCKET hTCP)
04515 
04516   Summary:
04517     Determines if a TCP connection is secured with SSL.
04518 
04519   Description:
04520     Call this function to determine whether or not a TCP connection is 
04521     secured with SSL.
04522     
04523   Precondition:
04524     TCP is initialized and hTCP is connected.
04525 
04526   Parameters:
04527     hTCP        - TCP connection to check
04528 
04529   Return Values:
04530     TRUE        - Connection is secured via SSL
04531     FALSE       - Connection is not secured
04532   ***************************************************************************/
04533 #if defined(STACK_USE_SSL)
04534 BOOL TCPIsSSL(TCP_SOCKET hTCP)
04535 {
04536     SyncTCBStub(hTCP);
04537     
04538     if(MyTCBStub.sslStubID == SSL_INVALID_ID)
04539         return FALSE;
04540     
04541     return TRUE;
04542 }
04543 #endif // SSL
04544 
04545 /*****************************************************************************
04546   Function:
04547     void TCPSSLHandshakeComplete(TCP_SOCKET hTCP)
04548 
04549   Summary:
04550     Clears the SSL handshake flag.
04551 
04552   Description:
04553     This function clears the flag indicating that an SSL handshake is
04554     complete.
04555     
04556   Precondition:
04557     TCP is initialized and hTCP is connected.
04558 
04559   Parameters:
04560     hTCP        - TCP connection to set
04561 
04562   Returns:
04563     None
04564 
04565   Remarks:
04566     This function should never be called by an application.  It is used 
04567     only by the SSL module itself.
04568   ***************************************************************************/
04569 #if defined(STACK_USE_SSL)
04570 void TCPSSLHandshakeComplete(TCP_SOCKET hTCP)
04571 {
04572     SyncTCBStub(hTCP);
04573     MyTCBStub.Flags.bSSLHandshaking = 0;
04574 }
04575 #endif // SSL
04576 
04577 /*****************************************************************************
04578   Function:
04579     void TCPSSLDecryptMAC(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx,
04580                             WORD len, BOOL inPlace)
04581 
04582   Summary:
04583     Decrypts and MACs data arriving via SSL.
04584 
04585   Description:
04586     This function decrypts data in the TCP buffer, calculates the MAC over
04587     the data, and optionally moves it to a new location within the buffer.  
04588     It is called to help process incoming SSL records.
04589     
04590   Precondition:
04591     TCP is initialized, hTCP is connected, and ctx's Sbox is loaded.
04592 
04593   Parameters:
04594     hTCP        - TCP connection to decrypt in
04595     ctx         - ARCFOUR encryption context to use
04596     len         - Number of bytes to crypt
04597     inPlace     - TRUE to write back in place, FALSE to write at end of
04598                     currently visible data.
04599 
04600   Returns:
04601     None
04602 
04603   Remarks:
04604     This function should never be called by an application.  It is used 
04605     only by the SSL module itself.
04606   ***************************************************************************/
04607 #if defined(STACK_USE_SSL)
04608 void TCPSSLDecryptMAC(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, WORD len, BOOL inPlace)
04609 {
04610     PTR_BASE wSrc, wDest, wBlockLen, wTemp;
04611     BYTE buffer[32];
04612     
04613     // Set up the pointers
04614     SyncTCBStub(hTCP);
04615     wSrc = MyTCBStub.rxTail;
04616     if(inPlace)
04617         wDest = wSrc;
04618     else
04619         wDest = MyTCBStub.sslRxHead;
04620     
04621     // Handle 32 bytes at a time
04622     while(len)
04623     {
04624         // Determine how many bytes we can read
04625         wBlockLen = sizeof(buffer);
04626         if(wBlockLen > len) // Don't do more than we should
04627             wBlockLen = len;
04628         
04629         // Read those bytes to a buffer
04630         if(wSrc + wBlockLen > MyTCBStub.bufferEnd)
04631         {// Two part read
04632             wTemp = MyTCBStub.bufferEnd - wSrc + 1;
04633             TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, wSrc, MyTCBStub.vMemoryMedium, wTemp);
04634             TCPRAMCopy((PTR_BASE)buffer+wTemp, TCP_PIC_RAM, MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, wBlockLen - wTemp);
04635             wSrc = MyTCBStub.bufferRxStart + wBlockLen - wTemp;
04636         }
04637         else
04638         {
04639             TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, wSrc, MyTCBStub.vMemoryMedium, wBlockLen);
04640             wSrc += wBlockLen;
04641         }
04642         
04643         // Decrypt and hash
04644         ARCFOURCrypt(ctx, buffer, wBlockLen);
04645         SSLMACAdd(buffer, wBlockLen);
04646         
04647         // Write decrypted bytes back
04648         if(wDest + wBlockLen > MyTCBStub.bufferEnd)
04649         {// Two part write
04650             wTemp = MyTCBStub.bufferEnd - wDest + 1;
04651             TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, wTemp);
04652             TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer+wTemp, TCP_PIC_RAM, wBlockLen - wTemp);
04653             wDest = MyTCBStub.bufferRxStart + wBlockLen - wTemp;
04654         }
04655         else
04656         {
04657             TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, wBlockLen);
04658             wDest += wBlockLen;
04659         }
04660         
04661         // Update the length remaining
04662         len -= wBlockLen;
04663     }
04664     
04665     // If not in place, update the sslRxHead pointer
04666     if(!inPlace)
04667     {
04668         MyTCBStub.sslRxHead = wDest;
04669         MyTCBStub.rxTail = wSrc;
04670     }
04671     
04672 }   
04673 #endif // SSL
04674 
04675 /*****************************************************************************
04676   Function:
04677     void TCPSSLInPlaceMACEncrypt(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, 
04678                                     BYTE* MACSecret, WORD len)
04679 
04680   Summary:
04681     Encrypts and MACs data in place in the TCP TX buffer.
04682 
04683   Description:
04684     This function encrypts data in the TCP buffer while calcuating a MAC.  
04685     When encryption is finished, the MAC is appended to the buffer and 
04686     the record will be ready to transmit.
04687     
04688   Precondition:
04689     TCP is initialized, hTCP is connected, and ctx's Sbox is loaded.
04690 
04691   Parameters:
04692     hTCP        - TCP connection to encrypt in
04693     ctx         - ARCFOUR encryption context to use
04694     MACSecret   - MAC encryption secret to use
04695     len         - Number of bytes to crypt
04696 
04697   Returns:
04698     None
04699 
04700   Remarks:
04701     This function should never be called by an application.  It is used 
04702     only by the SSL module itself.
04703   ***************************************************************************/
04704 #if defined(STACK_USE_SSL)
04705 void TCPSSLInPlaceMACEncrypt(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, BYTE* MACSecret, WORD len)
04706 {
04707     PTR_BASE pos;
04708     WORD blockLen;
04709     BYTE buffer[32];
04710     
04711     // Set up the pointers
04712     SyncTCBStub(hTCP);
04713     pos = MyTCBStub.txHead;
04714     for(blockLen = 0; blockLen < 5; blockLen++)
04715     {// Skips first 5 bytes for the header
04716         if(++pos >= MyTCBStub.bufferRxStart)
04717             pos = MyTCBStub.bufferTxStart;
04718     }
04719     
04720     // Handle 32 bytes at a time
04721     while(len)
04722     {
04723         // Determine how many bytes we can read
04724         blockLen = sizeof(buffer);
04725         if(blockLen > len) // Don't do more than we should
04726             blockLen = len;
04727         if(blockLen > MyTCBStub.bufferRxStart - pos) // Don't pass the end
04728             blockLen = MyTCBStub.bufferRxStart - pos;
04729         
04730         // Read those bytes to a buffer
04731         TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, pos, MyTCBStub.vMemoryMedium, blockLen);
04732         
04733         // Hash and encrypt
04734         SSLMACAdd(buffer, blockLen);
04735         ARCFOURCrypt(ctx, buffer, blockLen);
04736         
04737         // Put them back
04738         TCPRAMCopy(pos, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, blockLen);
04739         
04740         // Update the pointers
04741         pos += blockLen;
04742         len -= blockLen;
04743         if(pos >= MyTCBStub.bufferRxStart)
04744             pos = MyTCBStub.bufferTxStart;
04745     }
04746     
04747     // Calculate and add the MAC
04748     SSLMACCalc(MACSecret, buffer);
04749     ARCFOURCrypt(ctx, buffer, 16);
04750 
04751     // Write the MAC to the TX FIFO
04752     // Can't use TCPPutArray here because TCPIsPutReady() saves 16 bytes for the MAC
04753     // TCPPut* functions use this to prevent writing too much data.  Therefore, the
04754     // functionality is duplicated here.
04755     
04756     len = 16;
04757     blockLen = 0;
04758     // See if we need a two part put
04759     if(MyTCBStub.sslTxHead + len >= MyTCBStub.bufferRxStart)
04760     {
04761         blockLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
04762         TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, blockLen);
04763         len -= blockLen;
04764         MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
04765     }
04766     
04767     TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&buffer[blockLen], TCP_PIC_RAM, len);
04768     MyTCBStub.sslTxHead += len;
04769 
04770 }   
04771 #endif // SSL
04772 
04773 /*****************************************************************************
04774   Function:
04775     void TCPSSLPutRecordHeader(TCP_SOCKET hTCP, BYTE* hdr, BOOL recDone)
04776 
04777   Summary:
04778     Writes an SSL record header and sends an SSL record.
04779 
04780   Description:
04781     This function writes an SSL record header to the pending TCP SSL data, 
04782     then indicates that the data is ready to be sent by moving the txHead
04783     pointer.
04784     
04785     If the record is complete, set recDone to TRUE.  The sslTxHead 
04786     pointer will be moved forward 5 bytes to leave space for a future 
04787     record header.  If the record is only partially sent, use FALSE and
04788     to leave the pointer where it is so that more data can be added
04789     to the record.  Partial records can only be used for the 
04790     SERVER_CERTIFICATE handshake message.
04791     
04792   Precondition:
04793     TCP is initialized, and hTCP is connected with an active SSL session.
04794 
04795   Parameters:
04796     hTCP        - TCP connection to write the header and transmit with
04797     hdr         - Record header (5 bytes) to send or NULL to just 
04798                   move the pointerctx
04799     recDone     - TRUE if the record is done, FALSE otherwise
04800 
04801   Returns:
04802     None
04803 
04804   Remarks:
04805     This function should never be called by an application.  It is used 
04806     only by the SSL module itself.
04807   ***************************************************************************/
04808 #if defined(STACK_USE_SSL)
04809 void TCPSSLPutRecordHeader(TCP_SOCKET hTCP, BYTE* hdr, BOOL recDone)
04810 {
04811     BYTE i;
04812     
04813     // Set up the pointers
04814     SyncTCBStub(hTCP);
04815     
04816     // Write the header if needed
04817     if(hdr)
04818     {// This is a new record, so insert the header
04819         for(i = 0; i < 5; i++)
04820         {
04821             TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)hdr+i, TCP_PIC_RAM, sizeof(BYTE));
04822             if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
04823                 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
04824         }
04825     }
04826     
04827     // Move the txHead pointer to indicate what data is ready
04828     // Also, flush just the header, then all the data.  This shotguns two 
04829     // packets down the line, therefore causing immediate ACKs by the 
04830     // remote node.  Reconnect handshakes are as much as 60% faster now.
04831     TCPFlush(hTCP);
04832     MyTCBStub.txHead = MyTCBStub.sslTxHead;
04833     TCPFlush(hTCP);
04834     
04835     // If this record is done, move the sslTxHead forward
04836     // to accomodate the next record header
04837     if(recDone)
04838     {
04839         for(i = 0; i < 5; i++)
04840         {// Skip first 5 bytes in TX for the record header
04841             if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
04842                 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
04843         }
04844     }
04845 }   
04846 #endif // SSL
04847 
04848 /*****************************************************************************
04849   Function:
04850     WORD TCPSSLGetPendingTxSize(TCP_SOCKET hTCP)
04851 
04852   Summary:
04853     Determines how many bytes are pending for a future SSL record.
04854 
04855   Description:
04856     This function determines how many bytes are pending for a future SSL
04857     record.
04858     
04859   Precondition:
04860     TCP is initialized, and hTCP is connected with an active SSL connection.
04861 
04862   Parameters:
04863     hTCP        - TCP connection to check
04864 
04865   Returns:
04866     None
04867   ***************************************************************************/
04868 #if defined(STACK_USE_SSL)
04869 WORD TCPSSLGetPendingTxSize(TCP_SOCKET hTCP)
04870 {
04871     SyncTCBStub(hTCP);
04872 
04873     // Non-SSL connections have no pending SSL data
04874     //if(MyTCBStub.sslStubID == SSL_INVALID_ID)
04875     //  return 0;
04876             
04877     // Determine how many bytes are waiting to be written in this record
04878     if(MyTCBStub.sslTxHead > MyTCBStub.txHead)
04879         return MyTCBStub.sslTxHead - MyTCBStub.txHead - 5;
04880     else
04881         return (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.txHead - MyTCBStub.sslTxHead - 1) - 5;
04882 }
04883 #endif
04884 
04885 
04886 /*****************************************************************************
04887   Function:
04888     void TCPSSLHandleIncoming(TCP_SOCKET hTCP)
04889 
04890   Summary:
04891     Hands newly arrive TCP data to the SSL module for processing.
04892 
04893   Description:
04894     This function processes incoming TCP data as an SSL record and 
04895     performs any necessary repositioning and decrypting.
04896     
04897   Precondition:
04898     TCP is initialized, and hTCP is connected with an active SSL session.
04899 
04900   Parameters:
04901     hTCP        - TCP connection to handle incoming data on
04902 
04903   Returns:
04904     None
04905 
04906   Remarks:
04907     This function should never be called by an application.  It is used 
04908     only by the SSL module itself.
04909   ***************************************************************************/
04910 #if defined(STACK_USE_SSL)
04911 void TCPSSLHandleIncoming(TCP_SOCKET hTCP)
04912 {
04913     PTR_BASE prevRxTail, prevRxHead, wSrc, wDest;
04914     WORD wToMove, wLen;
04915     
04916     // Sync the stub
04917     SyncTCBStub(hTCP);
04918 
04919     // If new data is waiting
04920     if(MyTCBStub.sslRxHead != MyTCBStub.rxHead)
04921     {
04922         // Sync the TCP so we can check the hole size
04923         SyncTCB();
04924         
04925         // Reconfigure pointers for SSL use
04926         prevRxTail = MyTCBStub.rxTail;
04927         prevRxHead = MyTCBStub.rxHead;
04928         MyTCBStub.rxTail = MyTCBStub.rxHead;
04929         MyTCBStub.rxHead = MyTCBStub.sslRxHead;
04930         MyTCBStub.sslRxHead = prevRxHead;
04931         
04932         // Handle incoming data
04933         SSLRxRecord(hTCP, MyTCBStub.sslStubID);
04934         
04935         // If a MAC or new record header arrived, we now have a 
04936         // hole in our TCP buffer.  Remaining data should be 
04937         // moved forward to fill the hole, but optimizations are
04938         // possible in some cases.
04939         if(prevRxHead == MyTCBStub.rxTail)
04940         {// Didn't read anything, so nothing to move
04941             MyTCBStub.sslRxHead = MyTCBStub.rxHead;
04942             MyTCBStub.rxTail = prevRxTail;
04943             MyTCBStub.rxHead = prevRxHead;
04944         }
04945         else if(MyTCBStub.rxTail == MyTCBStub.rxHead && MyTCB.sHoleSize == -1)
04946         {// Nothing left out there, so just roll them back
04947             MyTCBStub.rxTail = prevRxTail;
04948             MyTCBStub.rxHead = MyTCBStub.sslRxHead;
04949         }
04950         else if(prevRxTail == prevRxHead)
04951         {// No previous data, so just roll forward
04952             MyTCBStub.sslRxHead = MyTCBStub.rxHead;
04953             MyTCBStub.rxHead = MyTCBStub.rxTail;
04954         }   
04955         else    
04956         {// Need to move data to fill the hole
04957             if(MyTCB.sHoleSize == -1)
04958             {// Just need to move pending SSL data
04959                 wToMove = TCPIsGetReady(hTCP);
04960             }
04961             else
04962             {// A TCP hole exists, so move all data
04963                 wToMove = TCPIsGetReady(hTCP) + MyTCB.sHoleSize + MyTCB.wFutureDataSize;
04964             }
04965             
04966             // Start with the destination as the sslHead and source as rxTail
04967             wDest = MyTCBStub.sslRxHead;
04968             wSrc = MyTCBStub.rxTail;
04969             
04970             // If data exists between the end of the buffer and 
04971             // the destination, then move it forward
04972             if(wSrc > wDest)
04973             {
04974                 wLen = MyTCBStub.bufferEnd - wSrc + 1;
04975                 if(wLen > wToMove)
04976                     wLen = wToMove;
04977                 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, 
04978                            wSrc, MyTCBStub.vMemoryMedium, wLen);
04979                 wDest += wLen;
04980                 wSrc = MyTCBStub.bufferRxStart;
04981                 wToMove -= wLen;
04982             }
04983             
04984             // If data remains to be moved, fill in to end of buffer
04985             if(wToMove > 0)
04986             {
04987                 wLen = MyTCBStub.bufferEnd - wDest + 1;
04988                 if(wLen > wToMove)
04989                     wLen = wToMove;
04990                 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, 
04991                            wSrc, MyTCBStub.vMemoryMedium, wLen);
04992                 wToMove -= wLen;
04993                 wDest += wLen;
04994                 wSrc += wLen;
04995                 if(wDest > MyTCBStub.bufferEnd)
04996                     wDest = MyTCBStub.bufferRxStart;
04997             }
04998             
04999             // If data still remains, copy from from front + len to front
05000             if(wToMove > 0)
05001             {
05002                 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium,
05003                            wSrc, MyTCBStub.vMemoryMedium, wToMove);
05004                 wDest += wToMove;
05005             }
05006                             
05007             // Restore pointers to the right positions
05008             MyTCBStub.rxTail = prevRxTail;
05009             MyTCBStub.rxHead = MyTCBStub.sslRxHead;
05010             MyTCBStub.sslRxHead = wDest;
05011         }
05012                 
05013     }
05014 
05015 }   
05016 #endif
05017 

Generated on Sun Nov 27 20:02:39 2011 for eWicht by  doxygen 1.5.5