📄 tcpprot.c
字号:
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// TCPPROT.C
//
// TCP Protocol Functions + Misc Functions
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "tcp.h"
//--------------------------------------------------------------------
// TcpPrAttach()
//
// Creates a new TCP side "socket"
//--------------------------------------------------------------------
int TcpPrAttach( HANDLE h, HANDLE *phTcp )
{
TCPPROT *pt;
// Allocate the TCP Protocol Control Block
if( !(pt = mmAlloc(sizeof(TCPPROT))) )
{
DbgPrintf(DBG_WARN,"TcpPrAttach: OOM");
ExecLowResource();
// Return the error
return( ENOMEM );
}
// Default init to zero
mmZeroInit( pt, sizeof(TCPPROT) );
// Initialize the TCP Protocol Control Block
pt->hSock = h;
pt->t_state = TSTATE_CLOSED;
pt->t_mss = TCP_MSS_DEFAULT;
pt->t_flags = TCP_TFLAGS_DEFAULT;
pt->t_srtt = TCPTV_SRTTBASE << TCP_FIXP_SHIFT;
pt->t_rttvar = TCPTV_RTTDFLT << TCP_FIXP_SHIFT;
pt->t_trtx = pt->t_rttvar >> (TCP_FIXP_SHIFT-1);
pt->snd_cwnd = TCP_MAXWIN;
// Get local copies of the SOCK buffers
pt->hSBRx = SockGetRx( h );
pt->hSBTx = SockGetTx( h );
// Initialize our handle in the SOCK object
*phTcp = (HANDLE)pt;
// Now we attach the Socket to our handler list
SockPcbAttach( h );
TcpTimeoutAdd( pt );
return(0);
}
//--------------------------------------------------------------------
// TcpPrDetach()
//
// Closes a TCP side "socket", detaches, and free resources
//--------------------------------------------------------------------
int TcpPrDetach( HANDLE hSock, HANDLE *phTcp, int fatal )
{
TCPPROT *pt = *(TCPPROT **)phTcp;
// Mark this so close doesn't notify the socket layer
pt->t_flags |= TF_DETACHED;
//
// We CLOSE an unconnected socket, but if something is in progress,
// use DROP. We are detaching, so can't do anything gracefully.
//
if( !fatal && pt->t_state >= TSTATE_SYNRCVD && pt->t_state != TSTATE_TIMEWAIT )
TcpDrop( pt, 0 ); // TcpDrop() calls TcpClose()
else
TcpClose( pt ); // Must call - frees some resources
//
// Detach the socket and free the TCP control
//
TcpTimeoutRemove( pt );
SockPcbDetach( hSock );
// Zap the TCP Proto Structure
*phTcp = 0;
mmFree( pt );
return(0);
}
//--------------------------------------------------------------------
// TcpPrListen()
//
// Called to mark TCP "socket" as a listening socket
//--------------------------------------------------------------------
int TcpPrListen( HANDLE h, HANDLE hTcp )
{
TCPPROT *pt = (TCPPROT *)hTcp;
(void)h;
// This really kills the socket as far as TCP is concerned.
// It simply becomes a "spawnable" mark in the PCB table
// Lets not take any chances on this...
pt->t_state = TSTATE_CLOSED;
// Also free held resources
if( pt->hFrag )
FragFree( pt->hFrag );
pt->hFrag = 0;
// Also zap the local copy of the buffer handles
pt->hSBRx = pt->hSBTx = 0;
return(0);
}
//--------------------------------------------------------------------
// TcpPrConnect()
//
// Request a connection for a TCP side socket
//--------------------------------------------------------------------
int TcpPrConnect( HANDLE h, HANDLE hTcp )
{
TCPPROT *pt = (TCPPROT *)hTcp;
int error = 0;
(void)h;
// Bump the stats
tcps.dwConnAttempt++;
// Set inititial send sequence number
pt->snd_una = pt->snd_nxt = pt->snd_max = pt->snd_up = pt->iss = tcp_iss;
tcp_iss += TCP_ISSINCR / 2;
// Send the SYN ("KeepAlive" timer is also our connection timeout timer)
pt->t_state = TSTATE_SYNSENT;
pt->dwTicksKeep = TCPTV_KEEP_INIT;
error = TcpOutput( hTcp );
return( error );
}
//--------------------------------------------------------------------
// TcpPrDisconnect()
//
// Disconnects a TCP side "socket" - performs "half close"
//--------------------------------------------------------------------
int TcpPrDisconnect( HANDLE h, HANDLE hTcp )
{
(void)h;
// Close the write side
TcpUsrClose( hTcp );
return(0);
}
//--------------------------------------------------------------------
// TcpPrRecv()
//
// Deal with Rx data being removed from buffer
//--------------------------------------------------------------------
int TcpPrRecv( HANDLE h, HANDLE hTcp )
{
(void)h;
// A read may cause us to readjust our window
return( TcpOutput( hTcp ) );
}
//--------------------------------------------------------------------
// TcpPrSend()
//
// Send data
//--------------------------------------------------------------------
int TcpPrSend( HANDLE h, HANDLE hTcp, UINT8 *pBuf, INT32 Size, INT32 *pRetSize )
{
TCPPROT *pt = (TCPPROT *)hTcp;
INT32 Space;
(void)h;
// Append as much data as possible to the output buffer
Space = SBGetSpace( pt->hSBTx );
if( Space < Size )
Size = Space;
// Copy out the data
if( Size )
Size = SBWrite( pt->hSBTx, Size, pBuf, 0 );
*pRetSize = Size;
// Data write may cause us to send data
if( Size )
return( TcpOutput( hTcp ) );
else
return( 0 );
}
//--------------------------------------------------------------------
// TcpPrSendOOB()
//
// Send data
//--------------------------------------------------------------------
int TcpPrSendOOB( HANDLE h, HANDLE hTcp, UINT8 *pBuf,
INT32 Size, INT32 *pRetSize )
{
TCPPROT *pt = (TCPPROT *)hTcp;
INT32 Space;
int error;
(void)h;
// Append as much data as possible to the output buffer
Space = SBGetSpace( pt->hSBTx );
if( Space < Size )
Size = Space;
// Copy out the data
if( Size )
Size = SBWrite( pt->hSBTx, Size, pBuf, 0 );
*pRetSize = Size;
// Update urgent pointer
pt->snd_up = pt->snd_una + SBGetTotal(pt->hSBTx);
// Data write may cause us to send data
error = TcpOutput(pt);
return( error );
}
//--------------------------------------------------------------------
// TcpPrInherit()
//
// Send data
//--------------------------------------------------------------------
void TcpPrInherit( HANDLE hParent, HANDLE hTcpParent,
HANDLE hChild, HANDLE hTcpChild )
{
TCPPROT *ptP = (TCPPROT *)hTcpParent;
TCPPROT *ptC = (TCPPROT *)hTcpChild;
(void)hParent;
(void)hChild;
ptC->t_flags |= ptP->t_flags & (TF_NOPUSH|TF_NOOPT|TF_NODELAY);
}
//--------------------------------------------------------------------
// TcpPrGetState()
//
// Return TCP State
//--------------------------------------------------------------------
uint TcpPrGetState( HANDLE hParent, HANDLE hTcp )
{
(void)hParent;
return( ((TCPPROT *)hTcp)->t_state );
}
//--------------------------------------------------------------------
// TcpPrSetOptions()
//
// Set TCP Options
//--------------------------------------------------------------------
int TcpPrSetOption(HANDLE h, HANDLE hTcp, int Prop, void *pBuf, int size)
{
TCPPROT *pt = (TCPPROT *)hTcp;
int value;
(void)h;
if( size != sizeof(int) || !pBuf )
return( EINVAL );
value = *(int *)pBuf;
switch( Prop )
{
case TCP_NODELAY:
if( value )
pt->t_flags |= TF_NODELAY;
else
pt->t_flags &= ~TF_NODELAY;
return( 0 );
case TCP_NOPUSH:
if( value )
pt->t_flags |= TF_NOPUSH;
else
pt->t_flags &= ~TF_NOPUSH;
return( 0 );
case TCP_NOOPT:
if( value )
pt->t_flags |= TF_NOOPT;
else
pt->t_flags &= ~TF_NOOPT;
return( 0 );
case TCP_MAXSEG:
if( (uint)value < pt->t_mss )
TcpValidateMetrics( pt, (uint)value );
return( 0 );
}
return( EINVAL );
}
//--------------------------------------------------------------------
// TcpPrGetOptions()
//
// Get TCP Options
//--------------------------------------------------------------------
int TcpPrGetOption(HANDLE h, HANDLE hTcp, int Prop, void *pBuf, int *psize)
{
TCPPROT *pt = (TCPPROT *)hTcp;
(void)h;
if( *psize < sizeof(int) )
return( EINVAL );
*psize = sizeof(int);
switch( Prop )
{
case TCP_NODELAY:
if( pt->t_flags & TF_NODELAY )
*(int *)pBuf = 1;
else
*(int *)pBuf = 0;
return( 0 );
case TCP_NOPUSH:
if( pt->t_flags & TF_NOPUSH )
*(int *)pBuf = 1;
else
*(int *)pBuf = 0;
return( 0 );
case TCP_NOOPT:
if( pt->t_flags & TF_NOOPT )
*(int *)pBuf = 1;
else
*(int *)pBuf = 0;
return( 0 );
case TCP_MAXSEG:
*(int *)pBuf = (int)pt->t_mss;
return( 0 );
}
return( EINVAL );
}
//--------------------------------------------------------------------
// TcpPrCtlError()
//
// Inform TCP of an error
//--------------------------------------------------------------------
void TcpPrCtlError( HANDLE h, HANDLE hTcp, uint Code, int Error )
{
TCPPROT *pt = (TCPPROT *)hTcp;
// Quench - close congestion window
if( Code == PRC_QUENCH )
pt->snd_cwnd = pt->t_mss;
else if( Error )
{
// Depending on state, we may ignore some errors
if( pt->t_state == TSTATE_ESTAB &&
( Error == EHOSTUNREACH || Error == EHOSTDOWN ) )
return;
if( pt->t_state<TSTATE_ESTAB && pt->t_rtxindex>3 && pt->t_softerror )
SockSetError( h, Error );
else
pt->t_softerror = Error;
SockNotify( h, SOCK_NOTIFY_ERROR );
}
}
//--------------------------------------------------------------------
//
// The following are protocol support functions
//
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// TcpDrop()
//
// Drops a TCP side "socket" with ABORT
//--------------------------------------------------------------------
void TcpDrop( TCPPROT *pt, int Error )
{
// Drop the connection with "ABORTED" error
if( pt->t_state >= TSTATE_SYNRCVD )
{
pt->t_state = TSTATE_CLOSED;
TcpOutput( pt );
tcps.dwDrops++;
}
else
tcps.dwConnDrops++;
// Change a TIMEOUT to the soft error if any, and set error code
if( Error == ETIMEDOUT && pt->t_softerror )
Error = pt->t_softerror;
SockSetError( pt->hSock, Error );
TcpClose( pt );
}
//--------------------------------------------------------------------
// TcpUsrClose()
//
// User requested close
//--------------------------------------------------------------------
void TcpUsrClose( TCPPROT *pt )
{
if( pt->t_state < TSTATE_ESTAB )
TcpClose( pt );
else if( pt->t_state < TSTATE_CLOSEWAIT )
{
pt->t_state = TSTATE_FINWAIT1;
TcpOutput( pt );
}
else if( pt->t_state == TSTATE_CLOSEWAIT )
{
pt->t_state = TSTATE_LASTACK;
TcpOutput( pt );
}
// Notify the Socket
if( pt->t_state >= TSTATE_FINWAIT2 )
SockNotify( pt->hSock, SOCK_NOTIFY_DISCONNECT );
}
//--------------------------------------------------------------------
// TcpClose()
//
// Closes down the TCP protocol block
//--------------------------------------------------------------------
void TcpClose( TCPPROT *pt )
{
pt->t_state = TSTATE_CLOSED;
// Free held resources
if( pt->hFrag )
FragFree( pt->hFrag );
pt->hFrag = 0;
// Notify the Socket (if not already detached)
if( !(pt->t_flags & TF_DETACHED) )
SockNotify( pt->hSock, SOCK_NOTIFY_CLOSED );
}
//--------------------------------------------------------------------
// TcpValidateMetrics
//
// Called to update TCP information based on socket route
// Returns current MSS to advertise
//--------------------------------------------------------------------
uint TcpValidateMetrics( TCPPROT *pt, uint rcvmss )
{
HANDLE hRoute;
uint ourmss;
// Validate the route plus any route related metrics (like t_mss)
if( !(hRoute = SockGetRoute( pt->hSock )) )
hRoute = SockValidateRoute( pt->hSock );
// Get our (best case) mss
if( !hRoute )
ourmss = TCP_MSS_DEFAULT_NR;
else
ourmss = RtGetMTU( hRoute );
// Take off IpHdr & TcpHdr
ourmss -= SockGetIpHdrSize(pt->hSock) + TCPHDR_SIZE;
// A previous write overrides us
if( (pt->t_flags & TF_RCVD_MSS) && pt->t_mss < ourmss )
ourmss = pt->t_mss;
// If we have received an mss, record it
if( rcvmss )
{
// Use the smallest of the valid mss values
pt->t_flags |= TF_RCVD_MSS;
if( rcvmss < ourmss )
pt->t_mss = rcvmss;
else
pt->t_mss = ourmss;
}
// If we have a valid (negotiated) mss, return it. Else,
// return what we'd like to advertise.
if( pt->t_flags & TF_RCVD_MSS )
return( pt->t_mss );
return( ourmss );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -