📄 sock.c
字号:
*psize = sizeof( uint );
if( !ps->hIFTx )
*(uint *)pbuf = 0;
else
*(uint *)pbuf = IFGetIndex( ps->hIFTx );
return(0);
}
}
// For the remainder, the property value is an int
if( *psize < sizeof(int) )
return( EINVAL );
*psize = sizeof(int);
switch( Prop )
{
case SO_BLOCKING:
if( ps->StateFlags & SS_NBIO )
*(int *)pbuf = 0;
else
*(int *)pbuf = 1;
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( ps->OptionFlags & (uint)Prop )
*(int *)pbuf = 1;
else
*(int *)pbuf = 0;
break;
case SO_SNDBUF:
if( ps->hSBTx )
*(int *)pbuf = (int)SBGetMax( ps->hSBTx );
else
*(int *)pbuf = SOCK_BUFMAX;
break;
case SO_RCVBUF:
if( ps->hSBRx )
*(int *)pbuf = (int)SBGetMax( ps->hSBRx );
else
*(int *)pbuf = SOCK_BUFMAX;
break;
case SO_SNDLOWAT:
if( ps->hSBTx )
*(int *)pbuf = (int)SBGetMin( ps->hSBTx );
else
*(int *)pbuf = SOCK_BUFMINRX;
break;
case SO_RCVLOWAT:
if( ps->hSBRx )
*(int *)pbuf = (int)SBGetMin( ps->hSBRx );
else
*(int *)pbuf = SOCK_BUFMINRX;
break;
case SO_ERROR:
*(int *)pbuf = ps->ErrorPending;
break;
case SO_TYPE:
*(int *)pbuf = (int)ps->SockType;
break;
default:
error = ENOPROTOOPT;
break;
}
return(error);
}
//--------------------------------------------------------------------
// SockRecv
//
// Receive data from a socket. Optionally fill in the Peer name.
//--------------------------------------------------------------------
int SockRecv
(
HANDLE h,
char *pBuf,
INT32 size,
int flags,
PSA pPeer,
INT32 *pRetSize
)
{
SOCK *ps = (SOCK *)h;
int retry = 1;
int error = 0;
INT32 Total = 0;
INT32 SizeCopy = 0;
IPN dwIPFrom;
uint PortFrom;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockRecv: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Check for a moron
if( ps->OptionFlags & SO_ACCEPTCONN )
return( EINVAL );
// Check for a null read
if( !size )
goto rx_complete;
// Check the OOB flag
if( flags & MSG_OOB )
{
// MSG_OOB Specified
// If in OOBINLINE mode, this flag is illegal, or
// If stocket is not in OOB mode, it is illegal
if( (ps->OptionFlags & SO_OOBINLINE) ||
!(ps->StateFlags & SS_OOBACTIVE) )
return( EINVAL );
// If we don't have the OOB data yet, then we have a blocking
// situation
if( !(ps->StateFlags & SS_OOBDATAVALID) )
return( EWOULDBLOCK );
// We have the OOB Data ready - Complete the recv call
*pBuf = ps->OOBData;
SizeCopy = 1;
// Clear the OOB mode if not PEEKING
if( !(flags & MSG_PEEK) )
ps->StateFlags &= ~(SS_OOBACTIVE | SS_OOBDATAVALID);
goto rx_complete;
}
rx_restart:
// ATOMIC socket types get one shot at this...
if( ps->StateFlags & SS_ATOMIC )
retry = 0;
// Get the total bytes available
Total = SBGetTotal(ps->hSBRx);
// Return a pending error if available
if( ps->ErrorPending )
{
// Don't eat the error if we're returning data
if( !SizeCopy )
{
error = ps->ErrorPending;
ps->ErrorPending = 0;
}
// But don't get more data this time
Total = 0;
goto rx_dontblock;
}
// Check for blocking condition
if( !Total )
{
//
// Check all non-blocking conditions first
//
// Assume we can't block
retry = 0;
// Don't block if the socket is no longer connected (this is
// actually an error condition)
if( (ps->StateFlags & SS_CONNREQUIRED) &&
!(ps->StateFlags & (SS_ISCONNECTED|SS_ISCONNECTING)) )
{
error = ENOTCONN;
goto rx_dontblock;
}
// Don't block if the receiver is shut down
if( ps->StateFlags & SS_CANTRCVMORE )
{
error = EPIPE;
goto rx_dontblock;
}
// Don't block if there was an overriding request not to block
if( flags & MSG_DONTWAIT )
goto rx_dontblock;
// Don't block on NBIO if there was NO overriding request to block
if( !(flags & MSG_WAITALL) && (ps->StateFlags & SS_NBIO) )
goto rx_dontblock;
// If we copied the minimum and WAITALL is not set, then don't block
// the minimum. (If ATOMIC, SizeCopy will be zero.)
if( SizeCopy >= SBGetMin(ps->hSBRx) && !(flags&MSG_WAITALL) )
goto rx_dontblock;
// Finally, the blocking code
// If we get a file event, then try the loop again
if( FDWaitEvent( ps->hFd, FD_EVENT_READ, ps->dwRxTimeout ) )
{
retry = 1;
goto rx_restart;
}
}
rx_dontblock:
// Check for FATAL blocking condition
if( !Total && !SizeCopy )
{
if( !error )
error = EWOULDBLOCK;
return( error );
}
// Get how much data to copy
// Adjust to buffer size
if( size < (Total+SizeCopy) )
Total = size-SizeCopy;
// Don't cross an OOB mark
if( (ps->StateFlags & SS_OOBACTIVE) && ps->OOBMark && Total > ps->OOBMark )
{
retry = 0;
Total = ps->OOBMark;
}
if( Total )
{
if( flags & MSG_PEEK )
Total = SBRead( ps->hSBRx, Total, 0, (UINT8 *)(pBuf+SizeCopy),
&dwIPFrom, &PortFrom, 1 );
else
{
Total = SBRead( ps->hSBRx, Total, 0, (UINT8 *)(pBuf+SizeCopy),
&dwIPFrom, &PortFrom, 0 );
if( ps->StateFlags & SS_OOBACTIVE )
{
// Clear the OOB mode if at the mark
if( !ps->OOBMark )
ps->StateFlags &= ~(SS_OOBACTIVE | SS_OOBDATAVALID);
// Otherwise, move us towards the mark
else
ps->OOBMark -= Total;
}
}
if( pPeer )
{
// Get Peer Data from Socket
pPeer->sin_len = sizeof( SA );
pPeer->sin_family = (UINT8)ps->Family;
if( ps->StateFlags & SS_ADDR )
{
pPeer->sin_port = PortFrom;
pPeer->sin_addr.s_addr = dwIPFrom;
}
else
{
pPeer->sin_port = ps->FPort;
pPeer->sin_addr.s_addr = ps->dwFIP;
}
}
// Record that we received this data
SizeCopy += Total;
// Notify the protocol of status change
SockPrRecv( ps );
}
// Try and get all the data if possible
if( retry && size > SizeCopy )
goto rx_restart;
rx_complete:
*pRetSize = SizeCopy;
if( SizeCopy )
return(0);
return(error);
}
//--------------------------------------------------------------------
// SockRecvNC
//
// Receive data from a socket without copy.
// Optionally fill in the Peer name.
//--------------------------------------------------------------------
int SockRecvNC( HANDLE h, int flags, PSA pPeer, HANDLE *phFrag )
{
SOCK *ps = (SOCK *)h;
int error = 0;
INT32 Total = 0;
IPN dwIPFrom;
uint PortFrom;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockRecv: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Check for a moron
if( ps->OptionFlags & SO_ACCEPTCONN )
return( EINVAL );
// Check the OOB and PEEK flag
if( flags & (MSG_OOB|MSG_PEEK) )
return( EINVAL );
// Must be ATOMIC socket
if( !(ps->StateFlags & SS_ATOMICREAD) )
return( EINVAL );
rx_restart:
// Get the total bytes available
Total = SBGetTotal(ps->hSBRx);
// Return a pending error if available
if( ps->ErrorPending )
{
error = ps->ErrorPending;
ps->ErrorPending = 0;
Total = 0;
goto rx_dontblock;
}
// Check for blocking condition
if( !Total )
{
//
// Check all non-blocking conditions first
//
// Don't block if the socket is no longer connected (this is
// actually an error condition)
if( (ps->StateFlags & SS_CONNREQUIRED) &&
!(ps->StateFlags & (SS_ISCONNECTED|SS_ISCONNECTING)) )
{
error = ENOTCONN;
goto rx_dontblock;
}
// Don't block if the receiver is shut down
if( ps->StateFlags & SS_CANTRCVMORE )
{
error = EPIPE;
goto rx_dontblock;
}
// Don't block if there was an overriding request not to block
if( flags & MSG_DONTWAIT )
goto rx_dontblock;
// Don't block on NBIO if there was NO overriding request to block
if( !(flags & MSG_WAITALL) && (ps->StateFlags & SS_NBIO) )
goto rx_dontblock;
// Finally, the blocking code
// If we get a file event, then try the loop again
if( FDWaitEvent( ps->hFd, FD_EVENT_READ, ps->dwRxTimeout ) )
goto rx_restart;
}
rx_dontblock:
// Check for FATAL blocking condition
if( !Total )
{
if( !error )
error = EWOULDBLOCK;
return( error );
}
// We don't support OOB on this type of read, so clear any OOB mark
if( ps->StateFlags & SS_OOBACTIVE )
ps->StateFlags &= ~(SS_OOBACTIVE | SS_OOBDATAVALID);
if( Total )
{
*phFrag = SBReadNC( ps->hSBRx, &dwIPFrom, &PortFrom );
if( pPeer )
{
// Get Peer Data from Socket
pPeer->sin_len = sizeof( SA );
pPeer->sin_family = (UINT8)ps->Family;
if( ps->StateFlags & SS_ADDR )
{
pPeer->sin_port = PortFrom;
pPeer->sin_addr.s_addr = dwIPFrom;
}
else
{
pPeer->sin_port = ps->FPort;
pPeer->sin_addr.s_addr = ps->dwFIP;
}
}
// Notify the protocol of status change
SockPrRecv( ps );
}
if( Total )
return(0);
return(error);
}
//--------------------------------------------------------------------
// SockSend()
//
// Send data to a socket.
//--------------------------------------------------------------------
int SockSend
(
HANDLE h,
char *pBuf,
INT32 size,
int flags,
INT32 *pRetSize
)
{
SOCK *ps = (SOCK *)h;
int DontRoute = 0, error = 0;
INT32 SizeCopy = 0;
INT32 AddCopy;
#ifdef _STRONG_CHECKING
if( ps->Type != HTYPE_SOCK )
{
DbgPrintf(DBG_ERROR,"SockRecv: HTYPE %04x",ps->Type);
return( ENOTSOCK );
}
#endif
// Set a flag to see if we should temporarily add SO_DONTROUTE
if( (flags & MSG_DONTROUTE) && (ps->StateFlags & SS_ATOMICWRITE) &&
!(ps->OptionFlags & SO_DONTROUTE) )
DontRoute = 1;
//
// This routine doesn't actually enqueue any data, since "how"
// the data is queued is dependent on the protocol.
//
// Since in a reduced memory stack (i.e.: us), it is possible to
// run out of memory before buffer limits are reached, we don't
// even bother to check memory status. The protocol returns the
// number of bytes consumed, and hence, when to block.
//
while( SizeCopy < size )
{
//
// Check error conditions in our loop since the error may
// occur while we're sending
//
// Return any pending error
if( ps->ErrorPending )
{
error = ps->ErrorPending;
ps->ErrorPending = 0;
break;
}
// Must be connected - our upper layer ALWAYS connects on a UDP
// sendto().
if( !(ps->StateFlags & SS_ISCONNECTED) )
{
error = ENOTCONN;
break;
}
// Can't send if send shutdown
if( ps->StateFlags & SS_CANTSENDMORE )
{
error = ESHUTDOWN;
break;
}
// Send the Data
if( DontRoute )
ps->OptionFlags |= SO_DONTROUTE;
if( flags & MSG_OOB )
error = SockPrSendOOB( ps, (UINT8 *)(pBuf+SizeCopy),
size-SizeCopy, &AddCopy );
else
error = SockPrSend( ps, (UINT8 *)(pBuf+SizeCopy),
size-SizeCopy, &AddCopy );
if( DontRoute )
ps->OptionFlags &= ~SO_DONTROUTE;
// Mark what we did copy
SizeCopy += AddCopy;
// Break out now on an error condition
if( error )
break;
// If we're ATOMIC, we sent what we could - leave now
if( ps->StateFlags & SS_ATOMICWRITE )
break;
// Check blocking condition
if( SizeCopy < size && !AddCopy )
{
// We need to block (protocol did not handle the data )
// Can't block a non-blocking socket
// If we timeout, we have an error and break the loop
if( (ps->StateFlags & SS_NBIO) || (flags & MSG_DONTWAIT) ||
!FDWaitEvent( ps->hFd, FD_EVENT_WRITE, ps->dwTxTimeout ) )
{
error = EWOULDBLOCK;
break;
}
}
}
*pRetSize = SizeCopy;
return( error );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -