📄 sock.c
字号:
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockDisconnect: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// If connection required, this call is invalid
if( ps->StateFlags & SS_CONNREQUIRED )
return( EINVAL );
// Make sure we are connected
if( !(ps->StateFlags & (SS_ISCONNECTED | SS_ISCONNECTING)) )
return( ENOTCONN );
// Disconnect (back to idle)
ps->StateFlags &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_CLOSING);
// Revert to strict bindings
ps->dwLIP = ps->dwBIP;
ps->LPort = ps->BPort;
ps->dwFIP = 0;
ps->FPort = 0;
// Toss any cached route
if( ps->hRoute )
{
RtDeRef( ps->hRoute );
ps->hRoute = 0;
}
return( 0 );
}
//--------------------------------------------------------------------
// SockBind()
//
// Bind Address and Port to Socket
//--------------------------------------------------------------------
int SockBind( HANDLE h, PSA pName )
{
SOCK *ps = (SOCK *)h;
int error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockBind: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// The only obvious error is that we're already bound
// Note: Even AF_TASK type sockets will have an "IP" (Socket Id)
if( ps->LPort || !pName )
return( EINVAL );
error = SockPcbBind( ps, pName->sin_addr.s_addr, pName->sin_port );
if( !error )
{
ps->dwBIP = ps->dwLIP;
ps->BPort = ps->LPort;
}
return( error );
}
//--------------------------------------------------------------------
// SockGetName
//
// Get Local and/or Peer Address and Port of Socket
//--------------------------------------------------------------------
int SockGetName( HANDLE h, PSA pSockName, PSA pPeerName)
{
SOCK *ps = (SOCK *)h;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockGetName: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
if( pSockName )
{
pSockName->sin_len = sizeof( SA );
pSockName->sin_family = (UINT8)ps->Family;
pSockName->sin_port = ps->LPort;
pSockName->sin_addr.s_addr = ps->dwLIP;
}
if( pPeerName )
{
pPeerName->sin_len = sizeof( SA );
pPeerName->sin_family = (UINT8)ps->Family;
pPeerName->sin_port = ps->FPort;
pPeerName->sin_addr.s_addr = ps->dwFIP;
}
return( 0 );
}
//--------------------------------------------------------------------
// SockListen()
//
// Listen for socket connections
//--------------------------------------------------------------------
int SockListen( HANDLE h, int maxcon )
{
SOCK *ps = (SOCK *)h;
int error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockListen: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// To listen, we must be connection oriented
if( !(ps->StateFlags & SS_CONNREQUIRED) )
return( EOPNOTSUPP );
// We also can't already be connected
if( ps->StateFlags & (SS_ISCONNECTED | SS_ISCONNECTING) )
return( EISCONN );
// Call the protocol to start the listening process
if( !(error = SockPrListen(ps)) )
{
// Success - Setup our state change
// Set the listen bit
ps->OptionFlags |= SO_ACCEPTCONN;
// Once listening, there's no way to stop. Hence, we
// can free the socket buffers
if( ps->hSBRx )
SBFree( ps->hSBRx );
if( ps->hSBTx )
SBFree( ps->hSBTx );
ps->hSBRx = ps->hSBTx = 0;
// Bound maxcon and set
if( maxcon < 0 )
maxcon = 0;
if( maxcon > SOCK_MAXCONNECT )
maxcon = SOCK_MAXCONNECT;
ps->ConnMax = maxcon;
}
return( error );
}
//--------------------------------------------------------------------
// SockAccept()
//
// Accept a socket connection from a listening socket
//--------------------------------------------------------------------
int SockAccept( HANDLE h, HANDLE hFd, HANDLE *phSock )
{
SOCK *ps = (SOCK *)h;
SOCK *psRet;
int error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockAccept: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// If not accepting, then we can't listen
if( !(ps->OptionFlags & SO_ACCEPTCONN) )
return( EINVAL );
// If no connections available and we're non-blocking, then
// return
if( !ps->pReady && (ps->StateFlags & SS_NBIO) )
return( EWOULDBLOCK );
// While we don't have a connection, spin
while( !ps->pReady && !ps->ErrorPending )
{
// If we're full, signal an error
if( ps->StateFlags & SS_CANTRCVMORE )
{
ps->ErrorPending = ECONNABORTED;
break;
}
// Wait forever (until wake)
FDWaitEvent( ps->hFd, FD_EVENT_READ, 0 );
}
// Return Error if Error
if( ps->ErrorPending )
{
error = ps->ErrorPending;
ps->ErrorPending = 0;
return( error );
}
// Unchain the next socket
psRet = ps->pReady;
ps->pReady = psRet->pReady;
psRet->pReady = 0;
psRet->pParent = 0;
psRet->StateFlags &= ~SS_READYQ;
ps->ConnTotal--;
// Set owning file desc.
psRet->hFd = hFd;
*phSock = (HANDLE)psRet;
return(0);
}
//--------------------------------------------------------------------
// SockSet()
//
// Set Socket Parameter Value
//--------------------------------------------------------------------
int SockSet(HANDLE hSock, int Type, int Prop, void *pbuf, int size)
{
SOCK *ps = (SOCK *)hSock;
int value,error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockSet: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Check size and pointer, just to be safe
if( size && !pbuf )
return( EINVAL );
//
// We also handle IPPROTO_IP and IPROTO_TCP
//
if( Type != SOL_SOCKET )
{
if( Type == IPPROTO_TCP )
{
if( ps->SockProt == SOCKPROT_TCP )
return( TcpPrSetOption( hSock, ps->hTP, Prop, pbuf, size ) );
else
return( EINVAL );
}
if( Type == IPPROTO_IP )
{
if( Prop != IP_OPTIONS )
{
if( size != sizeof(int) )
return( EINVAL );
value = *(int *)pbuf;
}
// Set Property
switch( Prop )
{
case IP_TOS:
ps->IpTos = (uint)value;
break;
case IP_TTL:
ps->IpTtl = (uint)value;
break;
case IP_HDRINCL:
// Only RAW sockets support this option
if( ps->SockProt != SOCKPROT_RAW )
return( EINVAL );
if( value )
ps->IpFlags |= SOCK_IP_HDRINCL;
else
ps->IpFlags &= ~SOCK_IP_HDRINCL;
break;
case IP_OPTIONS:
// Connection oriented sockets do not support options
if( (ps->StateFlags & SS_CONNREQUIRED) || size > 40 )
return( EINVAL );
ps->IpOptSize = (size + 3) & ~3;
if( ps->IpOptSize )
mmCopy( ps->IpOptions, pbuf, ps->IpOptSize );
break;
}
}
return( 0 );
}
//
// Socket Properties
//
//
// Handle the structure based first
//
switch( Prop )
{
case SO_LINGER:
{
struct linger *pl = (struct linger *)pbuf;
if( size != sizeof(struct linger) )
return( EINVAL );
if( pl->l_onoff )
ps->OptionFlags |= SO_LINGER;
else
ps->OptionFlags &= ~SO_LINGER;
ps->dwLingerTime = (UINT32)pl->l_linger * 1000;
return(0);
}
case SO_SNDTIMEO:
case SO_RCVTIMEO:
{
struct timeval *ptv = (struct timeval *)pbuf;
UINT32 dwTime;
if( size != sizeof(struct timeval) )
return( EINVAL );
dwTime = (UINT32)ptv->tv_sec*1000l;
dwTime += (UINT32)ptv->tv_usec;
if( Prop == SO_SNDTIMEO )
ps->dwTxTimeout = dwTime;
else
ps->dwRxTimeout = dwTime;
return(0);
}
case SO_IFDEVICE:
{
HANDLE h;
// Only DGRAM sockets can use the IFDEVICE option
if( !(ps->StateFlags & SS_ADDR) || size != sizeof(uint) )
return( EINVAL );
h = IFIndexGetHandle( *(uint *)pbuf );
if( !h || (ExecHType(h) != HTYPE_ETH) )
return( EINVAL );
ps->hIFTx = h;
return(0);
}
}
// For the remainder, the property value is an int
if( size < sizeof(int) )
return( EINVAL );
value = *(int *)pbuf;
switch( Prop )
{
case SO_BLOCKING:
if( value )
ps->StateFlags &= ~SS_NBIO;
else
ps->StateFlags |= SS_NBIO;
break;
case SO_DEBUG:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_USELOOPBACK:
case SO_BROADCAST:
case SO_REUSEADDR:
case SO_REUSEPORT:
case SO_OOBINLINE:
case SO_TIMESTAMP:
if( value )
ps->OptionFlags |= (uint)Prop;
else
ps->OptionFlags &= (uint)~Prop;
break;
case SO_SNDBUF:
if( value > SOCK_BUFMAX )
error = ENOBUFS;
break;
case SO_RCVBUF:
if( value > SOCK_BUFMAX )
error = ENOBUFS;
break;
case SO_SNDLOWAT:
if( ps->hSBTx )
SBSetMin( ps->hSBTx, value );
break;
case SO_RCVLOWAT:
if( ps->hSBRx )
SBSetMin( ps->hSBRx, value );
break;
case SO_ERROR:
ps->ErrorPending = value;
break;
default:
error = ENOPROTOOPT;
break;
}
return(error);
}
//--------------------------------------------------------------------
// SockGet()
//
// Get Socket Parameter Value
//--------------------------------------------------------------------
int SockGet(HANDLE hSock, int Type, int Prop, void *pbuf, int *psize)
{
SOCK *ps = (SOCK *)hSock;
int error = 0;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockGet: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Check pointers, just to be safe
if( !psize || !pbuf )
return( EINVAL );
//
// We also handle IPPROTO_IP and IPROTO_TCP
//
if( Type != SOL_SOCKET )
{
if( Type == IPPROTO_TCP )
{
if( ps->SockProt == SOCKPROT_TCP )
return( TcpPrGetOption( hSock, ps->hTP, Prop, pbuf, psize ) );
else
return( EINVAL );
}
if( Type == IPPROTO_IP )
{
if( Prop != IP_OPTIONS )
{
if( *psize < sizeof(int) )
return( EINVAL );
*psize = sizeof(int);
}
switch( Prop )
{
case IP_TOS:
*(int *)pbuf = (int)ps->IpTos;
return(0);
case IP_TTL:
*(int *)pbuf = (int)ps->IpTtl;
return(0);
case IP_HDRINCL:
if( ps->IpFlags & SOCK_IP_HDRINCL )
*(int *)pbuf = 1;
else
*(int *)pbuf = 0;
return(0);
case IP_OPTIONS:
if( *psize < (int)ps->IpOptSize )
return( EINVAL );
*psize = (int)ps->IpOptSize;
mmCopy( pbuf, ps->IpOptions, ps->IpOptSize );
return(0);
}
}
return( EINVAL );
}
//
// Socket Properties
//
//
// Handle the structure based first
//
switch( Prop )
{
case SO_LINGER:
{
struct linger *pl = (struct linger *)pbuf;
if( *psize < sizeof( struct linger ) )
return( EINVAL );
*psize = sizeof( struct linger );
if( ps->OptionFlags & SO_LINGER )
pl->l_onoff = 1;
else
pl->l_onoff = 0;
pl->l_linger = (int)(ps->dwLingerTime/1000);
return(0);
}
case SO_SNDTIMEO:
case SO_RCVTIMEO:
{
struct timeval *ptv = (struct timeval *)pbuf;
if( *psize < sizeof(struct timeval) )
return( EINVAL );
*psize = sizeof( struct timeval );
if( Prop == SO_SNDTIMEO )
{
ptv->tv_sec = ps->dwTxTimeout / 1000;
ptv->tv_usec = ps->dwTxTimeout % 1000;
}
else
{
ptv->tv_sec = ps->dwRxTimeout / 1000;
ptv->tv_usec = ps->dwRxTimeout % 1000;
}
return(0);
}
case SO_IFDEVICE:
{
if( *psize < sizeof( uint ) )
return( EINVAL );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -