📄 sock.c
字号:
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// SOCK.C
//
// Object member functions for the Sock device object.
//
// These functions get access to the SOCK object structure and can
// adjust values, but usually call protocol functions for perform
// action.
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "sock.h"
//--------------------------------------------------------------------
// SockNew()
//
// Creates a socket
//--------------------------------------------------------------------
int SockNew( int Family, int Type, int Protocol, HANDLE hFd, HANDLE *phSock )
{
SOCK *ps;
int error = 0;
//
// Check to see is request makes sense
//
// AF_INET, SOCK_DGRAM: must use IPPROTO_UDP
// AF_INET, SOCK_STREAM: must use IPPROTO_TCP
// AF_INET, SOCK_RAW: protocol can be anything, including NULL
//
if( Family != AF_INET )
return( EPFNOSUPPORT );
if( Type == SOCK_DGRAM )
{
if( !Protocol )
Protocol = IPPROTO_UDP;
else if( Protocol != IPPROTO_UDP)
return( EPROTOTYPE );
}
else if( Type == SOCK_STREAM || Type == SOCK_STREAMNC )
{
if( !Protocol )
Protocol = IPPROTO_TCP;
else if( Protocol != IPPROTO_TCP )
return( EPROTOTYPE );
}
else if( Type != SOCK_RAW )
return( ESOCKTNOSUPPORT );
//
// If we got here, we have a legal socket request
//
// Attempt to allocate space for the socket
if( !(ps = mmAlloc(sizeof(SOCK))) )
{
DbgPrintf(DBG_WARN,"SockNew: OOM");
ExecLowResource();
error = ENOMEM;
goto socknew_done;
}
// Initialize what we can
mmZeroInit( ps, sizeof(SOCK) ); // Most Q's and counts init to Zero
ps->Type = HTYPE_SOCK;
ps->hFd = hFd; // Set handle to owning file desc.
ps->Family = (uint)Family; // INET or FILE
ps->SockType = (uint)Type; // STREAM, DGRAM or RAW
ps->Protocol = (uint)Protocol; // IP protocol # or NULL
ps->IpTtl = SOCK_TTL_DEFAULT;
ps->IpTos = SOCK_TOS_DEFAULT;
// Init default timeouts
ps->dwRxTimeout = SOCK_TIMEIO * 1000;
ps->dwTxTimeout = SOCK_TIMEIO * 1000;
// Allocate Rx socket buffer
if( Type == SOCK_STREAM )
ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_LINEAR );
else if( Type == SOCK_STREAMNC )
{
ps->StateFlags = SS_ATOMICREAD;
ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_HYBRID );
}
else
{
ps->StateFlags = SS_ATOMICREAD | SS_ATOMIC;
ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_ATOMIC );
}
if( !ps->hSBRx )
{
error = ENOMEM;
goto socknew_error;
}
// Finalize Socket Status
if( Type == SOCK_STREAM || Type == SOCK_STREAMNC )
{
ps->StateFlags |= SS_CONNREQUIRED;
ps->hSBTx = SBNew( SOCK_BUFMAX, SOCK_BUFMINTX, SB_MODE_LINEAR );
if( !ps->hSBTx )
{
error = ENOMEM;
goto socknew_error;
}
// Set the SockProt Type
ps->SockProt = SOCKPROT_TCP;
}
else
{
ps->StateFlags |= (SS_ADDR | SS_ATOMICWRITE);
ps->hSBTx = 0;
// Set the SockProt Type
if( Type == SOCK_DGRAM )
ps->SockProt = SOCKPROT_UDP;
else
ps->SockProt = SOCKPROT_RAW;
}
// Attach the socket to protocol processing
if( (error = SockPrAttach( ps )) )
goto socknew_error;
*phSock = (HANDLE)ps;
socknew_done:
// Return
return( error );
socknew_error:
ps->Type = 0;
// Free the Rx and Tx Buffers
if( ps->hSBRx )
SBFree( ps->hSBRx );
if( ps->hSBTx )
SBFree( ps->hSBTx );
// Free the socket
mmFree( ps );
// Return the error
return( error );
}
//--------------------------------------------------------------------
// SockClose()
//
// Close a socket
//--------------------------------------------------------------------
int SockClose( HANDLE h )
{
SOCK *ps = (SOCK *)h;
int error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockClose: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Abort any incoming connections to a "listening" socket
if( ps->OptionFlags & SO_ACCEPTCONN )
{
SOCK *psTemp;
while( ps->pPending )
{
// Dequeue the socket
psTemp = ps->pPending;
ps->pPending = psTemp->pPending;
psTemp->StateFlags &= ~SS_PENDINGQ;
// Abort the socket
SockIntAbort( psTemp );
}
while( ps->pReady )
{
// Dequeue the socket
psTemp = ps->pReady;
ps->pReady = psTemp->pReady;
psTemp->StateFlags &= ~SS_READYQ;
// Abort the socket
SockIntAbort( psTemp );
}
ps->ConnTotal = 0;
}
// If not connection oriented, we're done
if( !(ps->StateFlags & SS_CONNREQUIRED) )
goto close_drop;
// Disconnect any connections to the connection oriented socket
if( ps->StateFlags & SS_ISCONNECTED )
{
// Flush the input queue (we're not going to be reading)
SockShutdown( ps, FREAD );
// If linger is not set, we'll free the socket via our SockNotify
if( !(ps->OptionFlags & SO_LINGER) )
{
ps->StateFlags |= SS_CLOSING;
// Start Disconnect
return( SockPrDisconnect( ps ) );
}
// Since linger is set, we'll drop the socket now (after linger time)
ps->StateFlags |= SS_LINGERING;
error = SockPrDisconnect( ps );
if( error )
goto close_drop;
// Can't linger on non-blocking sockets
if( ps->StateFlags & SS_NBIO )
goto close_drop;
// If no linget time, drop now
if( !ps->dwLingerTime )
goto close_drop;
// Wait for the socket to disconnect
while( ps->StateFlags & SS_LINGERING )
{
// If we ever timeout, break out of this loop
if( !FDWaitEvent( ps->hFd, FD_EVENT_READ, ps->dwLingerTime ) )
break;
}
}
close_drop:
SockIntAbort( ps );
return( error );
}
//--------------------------------------------------------------------
// SockIntAbort()
//
// Close a socket - Called only internally to stack
//--------------------------------------------------------------------
void SockIntAbort( SOCK *ps )
{
// Detach the socket from protocol processing
SockPrDetach( ps );
// DeRef any held route
if( ps->hRoute )
RtDeRef( ps->hRoute );
// Free the Rx and Tx Buffers
if( ps->hSBRx )
SBFree( ps->hSBRx );
if( ps->hSBTx )
SBFree( ps->hSBTx );
// Free the sock memory
mmFree( ps );
}
//--------------------------------------------------------------------
// SockCheck()
//
// Check for socket read/write/except status
//--------------------------------------------------------------------
int SockCheck( HANDLE h, int IoType )
{
SOCK *ps = (SOCK *)h;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockCheck: HTYPE %04x",ps->Type);
return( 0 );
}
#endif
switch( IoType )
{
case SOCK_READ:
//
// Return TRUE if readable
//
if( ps->OptionFlags & SO_ACCEPTCONN )
{
if( ps->pReady || ps->ErrorPending )
return(1);
}
else
{
if( SBGetTotal(ps->hSBRx) >= SBGetMin(ps->hSBRx) ||
ps->StateFlags & SS_CANTRCVMORE || ps->ErrorPending )
return(1);
}
break;
case SOCK_WRITE:
//
// Return TRUE if writeable
//
// Listening sockets can never be written
// We return 1 so some Bozo won't sleep on it
// If error pending, then can write (will get error)
if( (ps->OptionFlags & SO_ACCEPTCONN) || ps->ErrorPending )
return(1);
// Verify we're connected
if( !(ps->StateFlags & SS_CONNREQUIRED) ||
(ps->StateFlags & SS_ISCONNECTED) )
{
// Writable "connected" cases
if( (ps->StateFlags & SS_CANTSENDMORE) ||
(ps->StateFlags & SS_ATOMICWRITE) ||
(SBGetSpace(ps->hSBTx) >= SBGetMin(ps->hSBTx)) )
return(1);
}
break;
case SOCK_EXCEPT:
// Return TRUE if OOB data present
if( ps->StateFlags & SS_OOBACTIVE )
return(1);
break;
}
return(0);
}
//--------------------------------------------------------------------
// SockShutdown()
//
// Shutdown Socket Connection
//--------------------------------------------------------------------
int SockShutdown( HANDLE h, int how )
{
SOCK *ps = (SOCK *)h;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockShutdown: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Shutdown Read
if( how & FREAD )
{
ps->StateFlags |= SS_CANTRCVMORE;
// Perform read flush
if( ps->hSBRx )
SBFlush( ps->hSBRx, 1 );
// Notify the protocol of status change
SockPrRecv( ps );
}
// Shutdown Write
if( how & FWRITE )
{
ps->StateFlags |= SS_CANTSENDMORE;
// If the socket is connection oriented, we should tell the
// peer that we're done sending data.
if( ps->StateFlags & SS_CONNREQUIRED )
SockPrDisconnect( ps );
}
return(0);
}
//--------------------------------------------------------------------
// SockConnect()
//
// Create Socket Connection
//--------------------------------------------------------------------
int SockConnect( HANDLE h, PSA pName )
{
SOCK *ps = (SOCK *)h;
int error = 0;
HANDLE hRt;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockConnect: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// If socket is "accepting", then it can't "connect"
if( ps->OptionFlags & SO_ACCEPTCONN )
{
error = EOPNOTSUPP;
goto SockConnectDone;
}
// We can have only one active connection
// If connection oriented, we can have only one active connection
if( ps->StateFlags & (SS_ISCONNECTED | SS_ISCONNECTING) )
{
// If connection oriented, we have an error condition
if( ps->StateFlags & SS_CONNREQUIRED )
{
error = EISCONN;
goto SockConnectDone;
}
// Otherwise, we'll disconnect first
if( error = SockDisconnect( h ) )
goto SockConnectDone;
}
// First create the socket side binding
//
// If we aren't bound to an IP, we'll just pick one. We try and pick
// the IP address of the egress device that matches the Ip network of
// the destination address.
//
// Note: If dwLIP is valid, then the port must also be valid
//
if( !ps->dwLIP )
{
UINT32 dwIPHost;
// If the socket has an egress device, then we'll use the
// IP address of that device
if( ps->hIFTx )
dwIPHost = BindIF2IPHost( ps->hIFTx );
// Else get the IP address that makes the most sense
else if( !(dwIPHost = BindIFNet2IPHost( 0, pName->sin_addr.s_addr )) )
{
// We don't have an IP address on the subnet of the destination,
// so try finding a route
// If the destination is a BCAST, we don't use a route. Otherwise;
// find the next hop for this destination. Search with cloning.
if( pName->sin_addr.s_addr != INADDR_ANY &&
pName->sin_addr.s_addr != INADDR_BROADCAST )
{
hRt = IPGetRoute( FLG_RTF_CLONE, pName->sin_addr.s_addr, 0 );
if( hRt )
{
dwIPHost = BindIF2IPHost( RtGetIF(hRt) );
RtDeRef(hRt);
}
}
// If all the nice methods failed, fall back and use any
// IP addr we can get our hands on...
if( !dwIPHost && !(dwIPHost = BindIF2IPHost( 0 )) )
{
// Here we have no IP addresses, plus the user did not
// specify an egress device. So we don't send out packets
// with 0.0.0.0 haphazardly, we'll error out instead
error = ENXIO;
goto SockConnectDone;
}
}
if( (error = SockPcbBind( h, dwIPHost, 0 )) )
goto SockConnectDone;
}
// Establish the PCB socket connection
if( (error = SockPcbConnect( h, pName->sin_addr.s_addr, pName->sin_port )) )
goto SockConnectDone;
// Make sure these are clear
ps->StateFlags &= ~(SS_CANTRCVMORE | SS_CANTSENDMORE);
// Validate a route for this connection
hRt = SockValidateRoute( ps );
// Non-Connection oriented socket just "connects"
if( !(ps->StateFlags & SS_CONNREQUIRED) )
{
// Easy case - just set to ISCONNECTED
ps->StateFlags |= SS_ISCONNECTED;
goto SockConnectDone;
}
// A connection oriented socket will not connect if we didn't find
// a route.
if( !hRt )
return( EHOSTUNREACH );
// Set ISCONNECTING flag (ISCONNECTED set via SockNotify)
ps->StateFlags |= SS_ISCONNECTING;
// Establish the protocol connection
error = SockPrConnect( ps );
// If no error and not connected and not non-blocking, we wait
while( !error && !ps->ErrorPending &&
!(ps->StateFlags & (SS_NBIO|SS_ISCONNECTED)) )
{
// If we ever time out, we have an error
if( !FDWaitEvent( ps->hFd, FD_EVENT_READ, SOCK_TIMECONNECT*1000 ) )
error = ETIMEDOUT;
}
if( ps->ErrorPending )
{
error = ps->ErrorPending;
ps->ErrorPending = 0;
}
if( error )
{
ps->StateFlags &= ~SS_ISCONNECTING;
SockPrDisconnect( ps );
}
SockConnectDone:
return( error );
}
//--------------------------------------------------------------------
// SockDisconnect()
//
// Disconnect a Socket
//--------------------------------------------------------------------
int SockDisconnect( HANDLE h )
{
SOCK *ps = (SOCK *)h;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -