📄 net_tcp.c
字号:
#endif /* __WINDOWS__ */
/* Set up the socket pool state information */
return( initSocketPool() );
}
void netEndTCP( void )
{
STATIC_FN void endSocketPool( void );
/* Clean up the socket pool state information */
endSocketPool();
if( hIPv6 != NULL_INSTANCE )
{
DynamicUnload( hIPv6 );
hIPv6 = NULL_INSTANCE;
}
if( hDNS != NULL_INSTANCE )
{
DynamicUnload( hDNS );
hDNS = NULL_INSTANCE;
}
if( hTCP != NULL_INSTANCE )
{
#ifdef __WINDOWS__
/* Wipe the Sheets Afterwards and Cleanup */
WSACleanup();
#endif /* __WINDOWS__ */
DynamicUnload( hTCP );
}
hTCP = NULL_INSTANCE;
}
/* Return the status of the network interface */
static BOOLEAN transportOKFunction( void )
{
return( hTCP != NULL_INSTANCE ? TRUE : FALSE );
}
#else
int netInitTCP( void )
{
STATIC_FN int initSocketPool( void );
#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). 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 )
{
STATIC_FN void endSocketPool( void );
/* Clean up the socket pool state information */
endSocketPool();
#ifdef __SCO_VERSION__
signal( SIGIO, SIG_DFL );
#endif /* UnixWare/SCO */
}
static BOOLEAN transportOKFunction( void )
{
return( TRUE );
}
#endif /* __WINDOWS__ */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Map of common error codes to strings */
typedef struct {
const int errorCode; /* Native error code */
const int cryptErrorCode; /* cryptlib error code */
const BOOLEAN isFatal; /* Seriousness level */
const char *errorString; /* Error message */
} SOCKETERROR_INFO;
#ifdef __WINDOWS__
static const FAR_BSS SOCKETERROR_INFO socketErrorInfo[] = {
{ WSAECONNREFUSED, CRYPT_ERROR_PERMISSION, TRUE,
"WSAECONNREFUSED: The attempt to connect was rejected" },
{ WSAEADDRNOTAVAIL, CRYPT_ERROR_NOTFOUND, TRUE,
"WSAEADDRNOTAVAIL: The remote address is not a valid address" },
{ WSAECONNABORTED, CRYPT_OK, TRUE,
"WSAECONNABORTED: Connection was terminated due to a time-out or "
"other failure" },
{ WSAECONNRESET, CRYPT_OK, TRUE,
"WSAECONNRESET: Connection was reset by the remote host executing "
"a close" },
{ WSAEHOSTUNREACH, CRYPT_OK, TRUE,
"WSAEHOSTUNREACH: Remote host cannot be reached from this host at "
"this time" },
{ WSAEMSGSIZE, CRYPT_ERROR_OVERFLOW, FALSE,
"WSAEMSGSIZE: Message is larger than the maximum supported by the "
"underlying transport" },
{ WSAENETDOWN, CRYPT_OK, FALSE,
"WSAENETDOWN: The network subsystem has failed" },
{ WSAENETRESET, CRYPT_OK, FALSE,
"WSAENETRESET: Connection was broken due to keep-alive detecting a "
"failure while operation was in progress" },
{ WSAENETUNREACH, CRYPT_ERROR_NOTAVAIL, FALSE,
"WSAENETUNREACH: Network cannot be reached from this host at this "
"time" },
{ WSAENOBUFS, CRYPT_ERROR_MEMORY, FALSE,
"WSAENOBUFS: No buffer space available" },
{ WSAENOTCONN, CRYPT_OK, TRUE,
"WSAENOTCONN: Socket is not connected" },
{ WSAETIMEDOUT, CRYPT_ERROR_TIMEOUT, FALSE,
"WSAETIMEDOUT: Function timed out before completion" },
{ WSAHOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, FALSE,
"WSAHOST_NOT_FOUND: Host not found" },
{ WSATRY_AGAIN, CRYPT_OK, FALSE,
"WSATRY_AGAIN: Host not found (non-authoritative)" },
{ WSANO_DATA, CRYPT_OK, FALSE,
"WSANO_DATA: Valid name, no data record of requested type" },
{ CRYPT_ERROR }
};
#define hostErrorInfo socketErrorInfo /* Winsock uses unified error codes */
#define TIMEOUT_ERROR WSAETIMEDOUT /* Code for timeout error */
#else
static const FAR_BSS SOCKETERROR_INFO socketErrorInfo[] = {
{ EADDRNOTAVAIL, CRYPT_ERROR_NOTFOUND, TRUE,
"EADDRNOTAVAIL: Specified address is not available from the local "
"machine" },
{ ECONNREFUSED, CRYPT_ERROR_PERMISSION, TRUE,
"ECONNREFUSED: Attempt to connect was rejected" },
{ EINTR, CRYPT_OK, FALSE,
"EINTR: Function was interrupted by a signal" },
{ EMFILE, CRYPT_OK, FALSE,
"EMFILE: Per-process descriptor table is full" },
#ifndef __SYMBIAN32__
{ ECONNRESET, CRYPT_OK, TRUE,
"ECONNRESET: Connection was forcibly closed by remote host" },
{ EMSGSIZE, CRYPT_ERROR_OVERFLOW, FALSE,
"EMSGSIZE: Message is too large to be sent all at once" },
{ ENETUNREACH, CRYPT_OK, FALSE,
"ENETUNREACH: No route to the network or host is present" },
{ ENOBUFS, CRYPT_ERROR_MEMORY, FALSE,
"ENOBUFS: Insufficient system resources available to complete the "
"call" },
{ ENOTCONN, CRYPT_OK, TRUE,
"ENOTCONN: Socket is not connected" },
#endif /* Symbian OS */
{ ETIMEDOUT, CRYPT_ERROR_TIMEOUT, FALSE,
"ETIMEDOUT: Function timed out before completion" },
{ HOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, TRUE,
"HOST_NOT_FOUND: Not an official hostname or alias" },
{ NO_ADDRESS, CRYPT_ERROR_NOTFOUND, TRUE,
"NO_ADDRESS: Name is valid but does not have an IP address at the "
"name server" },
{ TRY_AGAIN, CRYPT_OK, FALSE,
"TRY_AGAIN: Local server did not receive a response from an "
"authoritative server" },
{ CRYPT_ERROR }
};
#define TIMEOUT_ERROR ETIMEDOUT /* Code for timeout error */
static const FAR_BSS SOCKETERROR_INFO hostErrorInfo[] = {
{ HOST_NOT_FOUND, CRYPT_ERROR_NOTFOUND, TRUE,
"HOST_NOT_FOUND: Host not found" },
{ NO_ADDRESS, CRYPT_ERROR_NOTFOUND, TRUE,
"NO_ADDRESS: No address record available for this name" },
{ CRYPT_ERROR }
};
#endif /* System-specific socket error codes */
/* Get and set the low-level error information from a socket- and host-
lookup-based error */
static int mapError( STREAM *stream, const SOCKETERROR_INFO *errorInfo,
const int errorCode, int status )
{
int i;
*stream->errorMessage = '\0';
for( i = 0; errorInfo[ i ].errorCode != CRYPT_ERROR; i++ )
if( errorInfo[ i ].errorCode == stream->errorCode )
{
strcpy( stream->errorMessage, errorInfo[ i ].errorString );
if( errorInfo[ i ].cryptErrorCode != CRYPT_OK )
/* There's a more specific error code than the generic one
we've been given available, use that instead */
status = errorInfo[ i ].cryptErrorCode;
if( errorInfo[ i ].isFatal )
/* It's a fatal error, make it persistent for the stream */
stream->status = status;
break;
}
return( status );
}
static int getSocketError( STREAM *stream, const int status )
{
/* Get the low-level error code and map it to an error string if
possible */
stream->errorCode = getErrorCode();
return( mapError( stream, socketErrorInfo, stream->errorCode,
status ) );
}
static int getHostError( STREAM *stream, const int status )
{
/* Get the low-level error code and map it to an error string if
possible */
stream->errorCode = getHostErrorCode();
return( mapError( stream, hostErrorInfo, stream->errorCode,
status ) );
}
static int setSocketError( STREAM *stream, const char *errorMessage,
const int status, const BOOLEAN isFatal )
{
/* Set a cryptlib-supplied socket error message. Since this doesn't
correspond to any system error, we clear the error code */
stream->errorCode = 0;
strcpy( stream->errorMessage, errorMessage );
if( isFatal )
/* It's a fatal error, make it persistent for the stream */
stream->status = 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 );
/* Since BeOS doesn't support checking for writeability or errors, we
have to clear these values before we call select() so the caller
won't find anything still set when we return */
if( write_bits != NULL )
FD_ZERO( write_bits );
if( exception_bits != NULL )
FD_ZERO( exception_bits );
return( select( socket_range, read_bits, NULL, NULL, timeout ) );
}
#define select( sockets, readFD, writeFD, exceptFD, timeout ) \
my_select( sockets, readFD, writeFD, exceptFD, timeout )
static int my_setsockopt( int socket, int level, int option,
const void *data, uint size )
{
if( option != SO_NONBLOCK && option != SO_REUSEADDR )
return( 0 );
return( setsockopt( socket, level, option, data, size ) );
}
static int my_getsockopt( int socket, int level, int option,
void *data, uint *size )
{
BYTE buffer[ 8 ];
int count;
if( option != SO_ERROR )
return( 0 );
*( ( int * ) data ) = 0; /* Clear return status */
/* It's unclear whether the following setsockopt actually does anything
under BeOS or not. If it fails, the alternative below may work */
#if 1
return( setsockopt( socket, level, option, data, *size ) );
#else
count = recv( socket, buffer, 0, 0 );
printf( "recv( 0 ) = %d, errno = %d.\n", count, errno );
if( count < 0 )
*( ( int * ) data ) = errno;
#endif /* 1 */
}
#endif /* BeOS without BONE */
/* Emulation of IPv6 networking functions. We include these unconditionally
under Windows because with dynamic binding we can't be sure that they're
needed or not */
#if !defined( IPv6 ) || defined( __WINDOWS__ )
static int addAddrInfo( struct addrinfo *prevAddrInfoPtr,
struct addrinfo **addrInfoPtrPtr,
const void *address, const int port )
{
struct addrinfo *addrInfoPtr;
struct sockaddr_in *sockAddrPtr;
/* Allocate the new element, clear it, and set fixed fields for IPv4 */
if( ( addrInfoPtr = clAlloc( "addAddrInfo", \
sizeof( struct addrinfo ) ) ) == NULL || \
( sockAddrPtr = clAlloc( "addAddrInfo", \
sizeof( struct sockaddr ) ) ) == NULL )
{
if( addrInfoPtr != NULL )
clFree( "addAddrInfo", addrInfoPtr );
return( -1 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -