⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_tcp.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Clean up the socket pool state information */
	endSocketPool();

	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 */

BOOLEAN networkingOK( void )
	{
	return( hTCP != NULL_INSTANCE ? TRUE : FALSE );
	}
#else

void netInitTCP( void )
	{
	STATIC_FN int initSocketPool( void );

#ifdef __SCO_VERSION__
	void ( *disp )( int );

	/* 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().  Since SIGIO is an alias for SIGPOLL, SCO
	   eventually reports this as a "polling alarm" */
	disp = signal( SIGIO, SIG_IGN );
	if( disp != SIG_DFL && disp != SIG_IGN )
		{
		/* There was already a SIGIO handler present, reinstate the old
		   handler and warn the user that they need to take special steps
		   to manage this problem.  This is ugly, but it's better than
		   leaving a difficult-to-find problem where the user's SIGIO
		   handler is pre-empted by cryptlib */
		signal( SIGIO, disp );
		printf( "Conflicting SIGIO handling detected in UnixWare socket "
				"bug workaround,\nfile " __FILE__ ", line %d.\n", __LINE__ );
		}
#endif /* UnixWare/SCO */

	/* Set up the socket pool state information */
	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 */
	}

BOOLEAN networkingOK( void )
	{
	return( TRUE );
	}
#endif /* Windows and Unixen without socket support in libc (ie Slowaris) */

/****************************************************************************
*																			*
*						 		Utility Routines							*
*																			*
****************************************************************************/

/* Map of common error codes to strings */

typedef struct { const int errorCode; const char *errorString; } SOCKETERROR_INFO;

#ifdef __WINDOWS__

static const SOCKETERROR_INFO socketErrorInfo[] = {
	WSAECONNREFUSED, "WSAECONNREFUSED: The attempt to connect was rejected",
	WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL: The remote address is not a valid "
					  "address",
	WSAECONNABORTED, "WSAECONNABORTED: Connection was terminated due to a "
					 "time-out or other failure",
	WSAECONNRESET, "WSAECONNRESET: Connection was reset by the remote host "
				   "executing a close",
	WSAEHOSTUNREACH, "WSAEHOSTUNREACH: Remote host cannot be reached from "
					 "this host at this time",
	WSAEMSGSIZE, "WSAEMSGSIZE: Message is larger than the maximum supported "
				 "by the underlying transport",
	WSAENETDOWN, "WSAENETDOWN: The network subsystem has failed",
	WSAENETRESET, "WSAENETRESET: Connection was broken due to keep-alive "
				  "detecting a failure while operation was in progress",
	WSAENETUNREACH, "WSAENETUNREACH: Network cannot be reached from this "
					"host at this time",
	WSAENOBUFS, "WSAENOBUFS: No buffer space available",
	WSAENOTCONN, "WSAENOTCONN: Socket is not connected",
	WSAETIMEDOUT, "WSAETIMEDOUT: Function timed out before completion",
	WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND: Host not found",
	WSATRY_AGAIN, "WSATRY_AGAIN: Host not found (non-authoritative)",
	WSANO_DATA, "WSANO_DATA: Valid name, no data record of requested type",
	CRYPT_ERROR, NULL
	};
#define hostErrorInfo	socketErrorInfo		/* Winsock uses unified error codes */

#define TIMEOUT_ERROR	WSAETIMEDOUT		/* Code for timeout error */

#else

static const SOCKETERROR_INFO socketErrorInfo[] = {
	EADDRNOTAVAIL, "EADDRNOTAVAIL: Specified address is not available from "
				   "the local machine",
	ECONNREFUSED, "ECONNREFUSED: Attempt to connect was rejected",
	ECONNRESET, "ECONNRESET: Connection was forcibly closed by remote host",
	EINTR, "EINTR: Function was interrupted by a signal",
	EMFILE, "EMFILE: Per-process descriptor table is full",
	EMSGSIZE, "EMSGSIZE: Message is too large to be sent all at once",
	ENETUNREACH, "ENETUNREACH: No route to the network or host is present",
	ENOBUFS, "ENOBUFS: Insufficient system resources available to complete "
			 "the call",
	ENOTCONN, "ENOTCONN: Socket is not connected",
	ETIMEDOUT, "ETIMEDOUT: Function timed out before completion",
	HOST_NOT_FOUND, "HOST_NOT_FOUND: Not an official hostname or alias",
	NO_ADDRESS, "NO_ADDRESS: Name is valid but does not have an IP address "
				"at the name server",
	TRY_AGAIN, "TRY_AGAIN: Local server did not receive a response from an "
			   "authoritative server",
	CRYPT_ERROR, NULL
	};

#define TIMEOUT_ERROR	ETIMEDOUT			/* Code for timeout error */

static const SOCKETERROR_INFO hostErrorInfo[] = {
	HOST_NOT_FOUND, "HOST_NOT_FOUND: Host not found",
	NO_ADDRESS, "NO_ADDRESS: No address record available for this name",
	CRYPT_ERROR, NULL
	};
#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, const 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 );
			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 )
	{
	stream->errorCode = 0;
	strcpy( stream->errorMessage, errorMessage );

	return( status );
	}

/* Get a host's IP address */

int getIPAddress( STREAM *stream, BYTE *ipAddress, const char *name )
	{
	struct hostent *pHostent;

	/* If it's a dotted address, convert it to in_addr form and return it */
	if( isdigit( *name ) )
		{
		BYTE *addrPtr = ipAddress;
		in_addr_t address = inet_addr( name );

		if( isBadAddress( address ) )
			return( setSocketError( stream, "Bad IP address",
									CRYPT_ERROR_OPEN ) );
		mputLong( addrPtr, address );
		return( CRYPT_OK );
		}

	/* It's a host name, convert it to the in_addr form */
	pHostent = gethostbyname( name );
	if( pHostent == NULL || pHostent->h_length != 4 )
		return( getHostError( stream, CRYPT_ERROR_OPEN ) );
	memcpy( ipAddress, pHostent->h_addr_list[ 0 ], 4 );
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Network Socket Manager							*
*																			*
****************************************************************************/

/* cryptlib's separation kernel causes some problems with objects which use
   sockets both because it doesn't allow sharing of sockets (which is a
   problem because the Unix server programming model assumes that a single
   process will listen on a socket and fork off children to handle incoming
   connections, in fact the accept() function more or less forces you to do
   this whether you want to or not) and because when a thread is blocked in
   an object waiting on a socket there's no way to unblock it apart from
   killing the thread.  In order to work around this we maintain a socket
   pool which serves two functions:

	- Maintains a list of sockets which an object is listening on to allow a
	  listening socket to be reused rather than having to listen on a
	  socket and close it as soon as an incoming connection is made in
	  order to switch to the connected socket.

	- Allows sockets to be closed from another thread, which results in any
	  objects waiting on them being woken up and exiting.

   For now we limit the socket pool to a maximum of 256 sockets both as a
   safety feature to protect against runaway apps from and because cryptlib
   was never designed to function as a high-volume server application.  If
   necessary this can be changed to dynamically expand the pool size in the
   same way that the kernel dynamically expands its object table */

#define SOCKETPOOL_SIZE		256

typedef struct {
	SOCKET netSocket;		/* Socket handle */
	int port;				/* Port which socket is bound to */
	int refCount;			/* Reference count for socket */
	} SOCKET_INFO;

static SOCKET_INFO *socketInfo;
static const SOCKET_INFO socketInfoTemplate = \
				{ INVALID_SOCKET, CRYPT_ERROR, 0 };

/* Initialise and shut down the socket pool */

static int initSocketPool( void )
	{
	int i;

	/* Allocate and clear the socket pool */
	if( ( socketInfo = malloc( SOCKETPOOL_SIZE * sizeof( SOCKET_INFO ) ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	for( i = 0; i < SOCKETPOOL_SIZE; i++ )
		memcpy( &socketInfo[ i ], &socketInfoTemplate,
				sizeof( SOCKET_INFO ) );

	return( CRYPT_OK );
	}

static void endSocketPool( void )
	{
	free( socketInfo );
	}

/* Create/add and and remove a socket to/from the pool.  The difference
   between creating and adding a socket is that newSocket() creates and
   adds a completely new socket while addSocket() adds an externally-
   created (via accept()) socket */

static int newSocket( SOCKET *newSocket, const int port )
	{
	SOCKET netSocket;
	int i;

	/* Clear return value */
	*newSocket = INVALID_SOCKET;

	enterMutex( MUTEX_SOCKETPOOL );

	/* If this is a server socket (ie one bound to a specific port), check
	   to see whether there's already a socket bound to this port.  If there
	   is, return the existing socket rather than creating a new one */
	if( port != CRYPT_UNUSED )
		for( i = 0; i < SOCKETPOOL_SIZE; i++ )
			if( socketInfo[ i ].port == port )
				{
				socketInfo[ i ].refCount++;
				*newSocket = socketInfo[ i ].netSocket;
				exitMutex( MUTEX_SOCKETPOOL );

				/* The socket already exists, don't perform any further
				   initialisation with it */
				return( CRYPT_OK );
				}

	/* Create a new socket entry */
	for( i = 0; i < SOCKETPOOL_SIZE; i++ )
		if( socketInfo[ i ].port == CRYPT_ERROR )
			break;
	if( i == SOCKETPOOL_SIZE )
		return( CRYPT_ERROR_MEMORY );	/* Should never happen */
	if( isBadSocket( netSocket = socket( PF_INET, SOCK_STREAM, 0 ) ) )
		return( CRYPT_ERROR_OPEN );
	socketInfo[ i ].netSocket = netSocket;
	socketInfo[ i ].port = port;
	socketInfo[ i ].refCount = 0;
	*newSocket = netSocket;

	/* If we're creating a new server socket we can't unlock the socket info
	   yet because we need to bind it to a port before we do anything else
	   with it.  If we were to unlock the socket info, another thread could
	   perform an accept() on the incompletely set up socket, so we return
	   with the socket info still locked.  When the caller has finished
	   setting it up, they'll call newSocketDone() to signal that the socket
	   is ready for use */
	if( port != CRYPT_UNUSED )
		return( OK_SPECIAL );

	exitMutex( MUTEX_SOCKETPOOL );

	return( CRYPT_OK );
	}

static void newSocketDone( void )
	{
	/* The caller has finished setting up a new server socket, unlock the
	   socket info to allow others to access it */
	exitMutex( MUTEX_SOCKETPOOL );
	}

static int addSocket( const SOCKET netSocket )
	{
	int i;

	enterMutex( MUTEX_SOCKETPOOL );

	/* Add an existing socket entry */
	for( i = 0; i < SOCKETPOOL_SIZE; i++ )
		if( socketInfo[ i ].port == CRYPT_ERROR )
			break;
	if( i == SOCKETPOOL_SIZE )
		return( CRYPT_ERROR_MEMORY );	/* Should never happen */
	socketInfo[ i ].netSocket = netSocket;
	socketInfo[ i ].port = CRYPT_UNUSED;
	socketInfo[ i ].refCount = 0;

	exitMutex( MUTEX_SOCKETPOOL );

	return( CRYPT_OK );
	}

static void deleteSocket( const SOCKET netSocket )
	{
	int i;

	enterMutex( MUTEX_SOCKETPOOL );

	/* Find the entry for this socket in the pool.  There may not be one
	   present if the pool has received a shutdown signal and closed all
	   network sockets, so if we don't find it we exit normally */
	for( i = 0; i < SOCKETPOOL_SIZE; i++ )
		if( socketInfo[ i ].netSocket == netSocket )
			break;
	if( i == SOCKETPOOL_SIZE )
		{
		exitMutex( MUTEX_SOCKETPOOL );
		return;
		}

	/* Decrement the socket's reference count */
	socketInfo[ i ].refCount--;
	if( socketInfo[ i ].refCount < 0 )
		{
		/* If the reference count has reached zero, close the socket
		   and delete the pool entry */
		closesocket( socketInfo[ i ].netSocket );
		memcpy( &socketInfo[ i ], &socketInfoTemplate,
				sizeof( SOCKET_INFO ) );
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -