📄 tcp.c
字号:
{
#ifdef __SCO_VERSION__
struct sigaction act, oact;
/* Work around the broken SCO/UnixWare signal-handling, which sometimes
sends a nonblocking socket a SIGIO (thus killing the process) when
waiting in a select() (this may have been fixed by the switch to
blocking sockets necessitated by Winsock bugs with non-blocking
sockets, and will be fixed long-term when SCO's long death march
eventually ends). Since SIGIO is an alias for SIGPOLL, SCO doesn't
help by reporting this as a "polling alarm". To fix this we need to
catch and swallow SIGIOs */
memset( &act, 0, sizeof( act ) );
act.sa_handler = SIG_IGN;
sigemptyset( &act.sa_mask );
if( sigaction( SIGIO, &act, &oact ) < 0 )
{
/* This assumes that stderr is open, i.e. that we're not a daemon.
This should be the case, at least during the development/debugging
stage */
fprintf( stderr, "cryptlib: sigaction failed, errno = %d, "
"file = %s, line = %d.\n", errno, __FILE__, __LINE__ );
abort();
}
/* Check for handler override. */
if( oact.sa_handler != SIG_DFL && oact.sa_handler != SIG_IGN )
{
/* We overwrote the caller's handler, reinstate the old handler and
warn them about this */
fprintf( stderr, "Warning: Conflicting SIGIO handling detected in "
"UnixWare socket bug\n workaround, file " __FILE__
", line %d. This may cause\n false SIGIO/SIGPOLL "
"errors.\n", __LINE__ );
sigaction( SIGIO, &oact, &act );
}
#endif /* UnixWare/SCO */
/* Set up the socket pool state information */
return( initSocketPool() );
}
void netEndTCP( void )
{
/* Clean up the socket pool state information */
endSocketPool();
#ifdef __SCO_VERSION__
signal( SIGIO, SIG_DFL );
#endif /* UnixWare/SCO */
}
CHECK_RETVAL_BOOL \
static BOOLEAN transportOKFunction( void )
{
#if defined( __TANDEM_NSK__ ) || defined( __TANDEM_OSS__ )
static BOOLEAN transportOK = FALSE;
if( !transportOK )
{
SOCKET netSocket;
/* If the networking subsystem isn't enabled, attempting any network
operations will return ENOENT (which isn't a normal return code,
but is the least inappropriate thing to return). In order to
check this before we get deep into the networking code, we create
a test socket here to make sure that everything is OK. If the
network transport is unavailable, we re-try each time we're
called in case it's been enabled in the meantime */
netSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( !isBadSocket( netSocket ) )
{
closesocket( netSocket );
transportOK = TRUE;
}
}
return( transportOK );
#else
return( TRUE );
#endif /* OS-specific socket availability check */
}
#endif /* __WINDOWS__ */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Map of common error codes to strings. The error code supplied by the
caller is usually used as the return status code, however if a more
specific error code than the default is available it's specified via the
cryptSpecificCode member */
typedef struct {
const int errorCode; /* Native error code */
const int cryptSpecificCode;/* Specific cryptlib error code */
const BOOLEAN isFatal; /* Seriousness level */
BUFFER_FIXED( errorStringLength ) \
const char FAR_BSS *errorString;
const int errorStringLength;/* Error message */
} SOCKETERROR_INFO;
#ifdef __WINDOWS__
static const SOCKETERROR_INFO FAR_BSS socketErrorInfo[] = {
{ WSAECONNREFUSED, CRYPT_ERROR_PERMISSION, TRUE,
"WSAECONNREFUSED: The attempt to connect was rejected", 52 },
{ WSAEADDRNOTAVAIL, CRYPT_ERROR_NOTFOUND, TRUE,
"WSAEADDRNOTAVAIL: The remote address is not a valid address", 59 },
{ WSAECONNABORTED, CRYPT_OK, TRUE,
"WSAECONNABORTED: Connection was terminated due to a time-out or "
"other failure", 77 },
{ WSAECONNRESET, CRYPT_OK, TRUE,
"WSAECONNRESET: Connection was reset by the remote host executing "
"a close", 72 },
{ WSAEHOSTUNREACH, CRYPT_OK, TRUE,
"WSAEHOSTUNREACH: Remote host cannot be reached from this host at "
"this time", 74 },
{ WSAEMSGSIZE, CRYPT_ERROR_OVERFLOW, FALSE,
"WSAEMSGSIZE: Message is larger than the maximum supported by the "
"underlying transport", 85 },
{ WSAENETDOWN, CRYPT_OK, FALSE,
"WSAENETDOWN: The network subsystem has failed", 45 },
{ WSAENETRESET, CRYPT_OK, FALSE,
"WSAENETRESET: Connection was broken due to keep-alive detecting a "
"failure while operation was in progress", 105 },
{ WSAENETUNREACH, CRYPT_ERROR_NOTAVAIL, FALSE,
"WSAENETUNREACH: Network cannot be reached from this host at this "
"time", 69 },
{ WSAENOBUFS, CRYPT_ERROR_MEMORY, FALSE,
"WSAENOBUFS: No buffer space available", 37 },
{ WSAENOTCONN, CRYPT_OK, TRUE,
"WSAENOTCONN: Socket is not connected", 36 },
{ WSAETIMEDOUT, CRYPT_ERROR_TIMEOUT, FALSE,
"WSAETIMEDOUT: Function timed out before completion", 50 },
{ WSAHOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, FALSE,
"WSAHOST_NOT_FOUND: Host not found", 34 },
{ WSATRY_AGAIN, CRYPT_OK, FALSE,
"WSATRY_AGAIN: Host not found (non-authoritative)", 48 },
{ WSANO_ADDRESS, CRYPT_OK, FALSE,
"WSANO_ADDRESS: No address record available for this name", 56 },
{ WSANO_DATA, CRYPT_OK, FALSE,
"WSANO_DATA: Valid name, no data record of requested type", 56 },
{ CRYPT_ERROR }, { CRYPT_ERROR }
};
#define hostErrorInfo socketErrorInfo /* Winsock uses unified error codes */
#define TIMEOUT_ERROR WSAETIMEDOUT /* Code for timeout error */
#else
static const SOCKETERROR_INFO FAR_BSS socketErrorInfo[] = {
{ EADDRNOTAVAIL, CRYPT_ERROR_NOTFOUND, TRUE,
"EADDRNOTAVAIL: Specified address is not available from the local "
"machine", 72 },
{ ECONNREFUSED, CRYPT_ERROR_PERMISSION, TRUE,
"ECONNREFUSED: Attempt to connect was rejected", 45 },
{ EINTR, CRYPT_OK, FALSE,
"EINTR: Function was interrupted by a signal", 43 },
{ EMFILE, CRYPT_OK, FALSE,
"EMFILE: Per-process descriptor table is full", 44 },
#if !( defined( __PALMOS__ ) || defined( __SYMBIAN32__ ) )
{ ECONNABORTED, CRYPT_OK, TRUE,
"ECONNABORTED: Software caused connection abort", 46 },
#endif /* PalmOS || Symbian OS */
#ifndef __SYMBIAN32__
{ ECONNRESET, CRYPT_OK, TRUE,
"ECONNRESET: Connection was forcibly closed by remote host", 57 },
{ EMSGSIZE, CRYPT_ERROR_OVERFLOW, FALSE,
"EMSGSIZE: Message is too large to be sent all at once", 53 },
{ ENETUNREACH, CRYPT_OK, FALSE,
"ENETUNREACH: No route to the network or host is present", 55 },
{ ENOBUFS, CRYPT_ERROR_MEMORY, FALSE,
"ENOBUFS: Insufficient system resources available to complete the "
"call", 69 },
{ ENOTCONN, CRYPT_OK, TRUE,
"ENOTCONN: Socket is not connected", 33 },
#endif /* Symbian OS */
{ ETIMEDOUT, CRYPT_ERROR_TIMEOUT, FALSE,
"ETIMEDOUT: Function timed out before completion", 47 },
{ HOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, TRUE,
"HOST_NOT_FOUND: Not an official hostname or alias", 49 },
{ NO_ADDRESS, CRYPT_ERROR_NOTFOUND, TRUE,
"NO_ADDRESS: Name is valid but does not have an IP address at the "
"name server", 76 },
{ TRY_AGAIN, CRYPT_OK, FALSE,
"TRY_AGAIN: Local server did not receive a response from an "
"authoritative server", 79 },
{ CRYPT_ERROR }, { CRYPT_ERROR }
};
#define TIMEOUT_ERROR ETIMEDOUT /* Code for timeout error */
static const SOCKETERROR_INFO FAR_BSS hostErrorInfo[] = {
{ HOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, TRUE,
"HOST_NOT_FOUND: Host not found", 30 },
{ NO_ADDRESS, CRYPT_ERROR_NOTFOUND, TRUE,
"NO_ADDRESS: No address record available for this name", 53 },
{ NO_DATA, CRYPT_ERROR_NOTFOUND, TRUE,
"NO_DATA: Valid name, no data record of requested type", 53 },
{ TRY_AGAIN, CRYPT_OK, FALSE,
"TRY_AGAIN: Local server did not receive a response from an "
"authoritative server", 79 },
{ CRYPT_ERROR }, { CRYPT_ERROR }
};
#endif /* System-specific socket error codes */
/* Get and set the low-level error information from a socket- and host-
lookup-based error */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int mapError( NET_STREAM_INFO *netStream,
const BOOLEAN useHostErrorInfo,
IN_ERROR int status )
{
const SOCKETERROR_INFO *errorInfo = \
useHostErrorInfo ? hostErrorInfo : socketErrorInfo;
const int errorInfoSize = useHostErrorInfo ? \
FAILSAFE_ARRAYSIZE( hostErrorInfo, SOCKETERROR_INFO ) : \
FAILSAFE_ARRAYSIZE( socketErrorInfo, SOCKETERROR_INFO );
int i;
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
assert( cryptStatusError( status ) );
clearErrorString( &netStream->errorInfo );
for( i = 0; errorInfo[ i ].errorCode != CRYPT_ERROR && \
i < errorInfoSize; i++ )
{
if( errorInfo[ i ].errorCode == netStream->errorInfo.errorCode )
{
REQUIRES( errorInfo[ i ].errorStringLength > 16 && \
errorInfo[ i ].errorStringLength < 150 );
setErrorString( NETSTREAM_ERRINFO, errorInfo[ i ].errorString,
errorInfo[ i ].errorStringLength );
if( errorInfo[ i ].cryptSpecificCode != CRYPT_OK )
{
/* There's a more specific error code than the generic one
that we've been given available, use that instead */
status = errorInfo[ i ].cryptSpecificCode;
}
if( errorInfo[ i ].isFatal )
{
/* It's a fatal error, make it persistent for the stream */
netStream->persistentStatus = status;
}
break;
}
}
ENSURES( i < errorInfoSize );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int getSocketError( NET_STREAM_INFO *netStream,
IN_ERROR const int status )
{
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
REQUIRES( cryptStatusError( status ) );
/* Get the low-level error code and map it to an error string if
possible */
netStream->errorInfo.errorCode = getErrorCode();
return( mapError( netStream, FALSE, status ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int getHostError( NET_STREAM_INFO *netStream,
IN_ERROR const int status )
{
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
REQUIRES( cryptStatusError( status ) );
/* Get the low-level error code and map it to an error string if
possible */
netStream->errorInfo.errorCode = getHostErrorCode();
return( mapError( netStream, TRUE, status ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int setSocketError( INOUT NET_STREAM_INFO *netStream,
IN_BUFFER( errorMessageLength ) const char *errorMessage,
IN_LENGTH_ERRORMESSAGE const int errorMessageLength,
IN_ERROR const int status, const BOOLEAN isFatal )
{
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
assert( errorMessage != NULL );
REQUIRES( errorMessageLength > 16 && \
errorMessageLength < MAX_INTLENGTH );
REQUIRES( cryptStatusError( status ) );
/* Set a cryptlib-supplied socket error message. Since this doesn't
correspond to any system error, we clear the error code */
netStream->errorInfo.errorCode = 0;
setErrorString( NETSTREAM_ERRINFO, errorMessage, errorMessageLength );
if( isFatal )
{
/* It's a fatal error, make it persistent for the stream */
netStream->persistentStatus = status;
}
return( status );
}
#if defined( __BEOS__ ) && !defined( BONE_VERSION )
/* BeOS doesn't support checking for anything except readability in select()
and only supports one or two socket options so we define our own versions
of these functions that no-op out unsupported options */
#undef select /* Restore normal select() around the wrapper */
static int my_select( int socket_range, struct fd_set *read_bits,
struct fd_set *write_bits,
struct fd_set *exception_bits,
struct timeval *timeout )
{
/* BeOS doesn't support nonblocking connects, it always waits about a
minute for the connect and then times out, so it we get a wait on a
connecting socket we report it as being successful by exiting with
the fds as set by the caller and a successful return status */
if( read_bits != NULL && write_bits != NULL )
return( 1 );
/* If we're checking for writeability the best that we can do is to
always report the socket as writeable. Since the socket is a
blocking socket the data will (eventually) get written */
if( read_bits == NULL && write_bits != NULL )
{
if( exception_bits != NULL )
FD_ZERO( exception_bits );
return( 1 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -