📄 net_tcp.c
字号:
/****************************************************************************
* *
* cryptlib TCP/IP Interface Routines *
* Copyright Peter Gutmann 1998-2001 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "stream.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../keymgmt/stream.h"
#else
#include "crypt.h"
#include "keymgmt/stream.h"
#endif /* Compiler-specific includes */
#ifdef NET_TCP
#if defined( __WINDOWS__ )
#include <winsock.h>
#elif defined( __UNIX__ )
#undef C_IN /* Defined via some versions of netdb.h */
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#if ( defined( sun ) && OSVERSION <= 4 ) || defined( __hpux ) || \
defined( __bsdi__ ) || defined( __FreeBSD__ ) || \
defined( __OpenBSD__ )
#include <netinet/in.h>
#endif /* SunOS 4.x || PHUX || *BSDs */
#include <arpa/inet.h>
#ifdef __SCO_VERSION__
#include <signal.h>
#ifndef SIGIO
#include <sys/signal.h>
#endif /* SIGIO not defined in signal.h - only from SCO */
#endif /* UnixWare/SCO */
#ifdef _AIX
#include <sys/select.h>
#endif /* Aches */
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#endif /* OS-specific includes and defines */
/* Portability defines */
#ifdef __WINDOWS__
#define isBadSocket( socket ) ( ( socket ) == INVALID_SOCKET )
#define isSocketError( status ) ( ( status ) == SOCKET_ERROR )
#define isBadAddress( address ) ( ( address ) == INADDR_NONE )
#define isNonblockWarning() ( WSAGetLastError() == WSAEWOULDBLOCK )
#define getErrorCode() WSAGetLastError()
#define getHostErrorCode() WSAGetLastError()
/* Windows doesn't define in_*_t's */
#define in_addr_t u_long
#define in_port_t u_short
#else
#define INVALID_SOCKET -1
#define isBadSocket( socket ) ( ( socket ) == -1 )
#define isSocketError( status ) ( ( status ) == -1 )
#define isBadAddress( address ) ( ( address ) == ( in_addr_t ) -1 )
#define isNonblockWarning() ( errno == EINPROGRESS )
#define getErrorCode() errno
#define getHostErrorCode() h_errno
/* Many older Unixen don't define the in_*_t's */
#if ( defined( sun ) && OSVERSION <= 4 ) || defined( __hpux ) || \
defined( __bsdi__ ) || defined( __FreeBSD__ ) || \
defined( __OpenBSD__ ) || defined( __linux__ )
#ifndef in_addr_t
#define in_addr_t u_long
#define in_port_t u_short
#endif /* in_addr_t */
#endif /* SunOS 4.x || PHUX || *BSDs || Linux */
/* PHUX generally doesn't define h_errno, we have to be careful here since
later versions may use macros to get around threading issues so we check
for the existence of a macro with the given name before defining our own
version */
#if defined( __hpux ) && !defined( h_errno )
/* Usually missing from netdb.h */
extern int h_errno;
#endif /* PHUX && !h_errno */
/* Windows uses a distinct socket handle type and requires the use of
separate closesocket() and ioctlsocket() functions because socket
handles aren't the same as standard Windows handles */
#define SOCKET int
#define closesocket close
#define ioctlsocket ioctl
#endif /* OS-specific portability defines */
/* The traditional way to set a descriptor to nonblocking mode was an
ioctl with FIONBIO, however Posix prefers the O_NONBLOCK flag for fcntl
so we use this if it's available */
#if defined( F_GETFL ) && defined( F_SETFL ) && defined( O_NONBLOCK )
#define setSocketNonblocking( socket ) \
{ \
int flags; \
\
fcntl( socket, F_GETFL, &flags ); \
fcntl( socket, F_SETFL, flags | O_NONBLOCK ); \
}
#else
#define setSocketNonblocking( socket ) \
{ \
long nonBlock = TRUE; \
\
ioctlsocket( socket, FIONBIO, &nonBlock ); \
}
#endif /* F_GETFL && F_SETFL && O_NONBLOCK */
/* For some connections which involve long-running sessions we need to be
able to gracefully recover from errors such as the remote process or
host crashing and restarting, which we can do by closing and re-opening
the connection. The various situations are:
Process crashes and restarts:
Write: Remote host sends a RST in response to an attempt to continue
a TCP session which it doesn't remember, which is reported
locally as the dreaded (if you ssh or NNTP to remote hosts a
lot) connection reset by peer error.
Read: Remote host sends a FIN, we read 0 bytes.
Network problem:
Write: Data is resent, if a read is pending it returns ETIMEDOUT,
otherwise write returns EPIPE or SIGPIPE (some
implementations may return ENETUNREACH or EHOSTUNREACH if
they receive the right ICMP information).
Read: See above, without the write sematics.
Host crashes and restarts:
Write: Looks like a network outage until host is restarted, then gets
an EPIPE/SIGPIPE.
Read: As for write, but gets a ECONNRESET.
The following macros check for error conditions which are currently
defined as recoverable, in the future we may want to address some of the
others listed above as well */
#ifdef __WINDOWS__
#define isRecoverableError( status ) ( ( status ) == WSAECONNRESET )
#else
#define isRecoverableError( status ) ( ( status ) == ECONNRESET )
#endif /* OS-specific status codes */
/****************************************************************************
* *
* Init/Shutdown Routines *
* *
****************************************************************************/
/* Dynamically bind in the networking code. This is required under
Windows (the Winsock DLLs) and Slowaris (which doesn't have sockets
support in libc) */
#if defined( __WINDOWS__ ) || ( defined( sun ) && OSVERSION > 4 )
/* Global function pointers. These are necessary because the functions need
to be dynamically linked since not all systems contain the necessary
libraries */
INSTANCE_HANDLE hTCP;
#ifdef __WINDOWS__
#ifdef WSAAPI
#define SOCKET_API WSAAPI
#else
#define SOCKET_API FAR PASCAL
#endif /* WSAAPI */
#else
#define SOCKET_API
#define FAR
#endif /* Different socket API calling conventions */
typedef SOCKET ( SOCKET_API *ACCEPT )( SOCKET s, struct sockaddr *addr,
int *addrlen );
typedef int ( SOCKET_API *BIND )( SOCKET s, const struct sockaddr FAR *addr,
int namelen );
typedef int ( SOCKET_API *CONNECT )( SOCKET s, const struct sockaddr *name,
int namelen );
typedef struct hostent FAR * ( SOCKET_API *GETHOSTBYNAME )( const char FAR * name );
typedef int ( SOCKET_API *GETSOCKOPT )( SOCKET s, int level, int optname,
char *optval, int FAR *optlen );
typedef u_long ( SOCKET_API *HTONL )( u_long hostlong );
typedef u_short ( SOCKET_API *HTONS )( u_short hostshort );
typedef unsigned long ( SOCKET_API *INET_ADDR )( const char FAR * cp );
typedef char FAR * ( SOCKET_API *INET_NTOA )( struct in_addr in );
typedef int ( SOCKET_API *LISTEN )( SOCKET s, int backlog );
typedef u_short ( SOCKET_API *NTOHS )( u_short netshort );
typedef int ( SOCKET_API *RECV )( SOCKET s, char *buf, int len, int flags );
typedef int ( SOCKET_API *SELECT )( int nfds, fd_set *readfds,
fd_set *writefds, fd_set *exceptfds,
const struct timeval *timeout );
typedef int ( SOCKET_API *SEND )( SOCKET s, const char *buf, int len,
int flags );
typedef int ( SOCKET_API *SETSOCKOPT )( SOCKET s, int level, int optname,
char *optval, int optlen );
typedef SOCKET ( SOCKET_API *SOCKETFN )( int af, int type, int protocol );
#ifdef __WINDOWS__
typedef int ( SOCKET_API *CLOSESOCKET )( SOCKET s );
typedef int ( SOCKET_API *IOCTLSOCKET )( SOCKET s, long cmd,
u_long FAR *argp );
typedef int ( SOCKET_API *WSACLEANUP )( void );
typedef int ( SOCKET_API *WSAGETLASTERROR )( void );
typedef int ( SOCKET_API *WSASTARTUP )( WORD wVersionRequested,
LPWSADATA lpWSAData );
typedef int ( SOCKET_API *FDISSETFN )( SOCKET, fd_set * );
#endif /* __WINDOWS__ */
static ACCEPT paccept = NULL;
static BIND pbind = NULL;
static CONNECT pconnect = NULL;
static GETHOSTBYNAME pgethostbyname = NULL;
static GETSOCKOPT pgetsockopt = NULL;
static HTONL phtonl = NULL;
static HTONS phtons = NULL;
static INET_ADDR pinet_addr = NULL;
static INET_NTOA pinet_ntoa = NULL;
static LISTEN plisten = NULL;
static NTOHS pntohs = NULL;
static RECV precv = NULL;
static SELECT pselect = NULL;
static SEND psend = NULL;
static SETSOCKOPT psetsockopt = NULL;
static SOCKETFN psocket = NULL;
#ifdef __WINDOWS__
static CLOSESOCKET pclosesocket = NULL;
static IOCTLSOCKET pioctlsocket = NULL;
static WSACLEANUP pWSACleanup = NULL;
static WSAGETLASTERROR pWSAGetLastError = NULL;
static WSASTARTUP pWSAStartup = NULL;
static FDISSETFN pFDISSETfn = NULL;
#endif /* __WINDOWS__ */
#if ( defined( sun ) && OSVERSION > 4 )
static int *h_errnoPtr;
#undef getHostErrorCode
#define getHostErrorCode() *h_errnoPtr
#undef htonl /* Slowaris has defines which conflict with our ones */
#undef htons
#undef ntohs
#endif /* Slowaris */
#define accept paccept
#define bind pbind
#define connect pconnect
#define gethostbyname pgethostbyname
#define getsockopt pgetsockopt
#define htonl phtonl
#define htons phtons
#define inet_addr pinet_addr
#define inet_ntoa pinet_ntoa
#define listen plisten
#define ntohs pntohs
#define recv precv
#define select pselect
#define send psend
#define setsockopt psetsockopt
#define socket psocket
#ifdef __WINDOWS__
#define closesocket pclosesocket
#define ioctlsocket pioctlsocket
#define WSACleanup pWSACleanup
#define WSAGetLastError pWSAGetLastError
#define WSAStartup pWSAStartup
#define __WSAFDIsSet pFDISSETfn
#endif /* __WINDOWS__ */
/* Dynamically load and unload any necessary TCP/IP libraries. Under Windows
the dynamic loading is complicated by the existence of Winsock 1 vs
Winsock 2, all recent systems will use Winsock 2 but we allow for Winsock 1
as well just in case, and for use on 16-bit systems */
#ifdef __WINDOWS__
#ifdef __WIN16__
#define TCP_LIBNAME "winsock.dll"
#else
#define TCP_LIBNAME "ws2_32.dll"
#define WINSOCK_OLD_LIBNAME "wsock32.dll"
#endif /* __WIN16__ */
#else
#define TCP_LIBNAME "libsocket.so"
#endif /* OS-specific TCP/IP library naming */
void netInitTCP( void )
{
STATIC_FN int initSocketPool( void );
#ifdef __WINDOWS__
WSADATA wsaData;
#ifdef __WIN16__
UINT errorMode;
#endif /* __WIN16__ */
#endif /* __WINDOWS__ */
/* Obtain a handle to the module containing the TCP/IP functions */
#ifdef __WINDOWS__
#ifdef __WIN16__
errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
hTCP = DynamicLoad( TCP_LIBNAME );
SetErrorMode( errorMode );
if( hTCP < HINSTANCE_ERROR )
{
hTCP = NULL_INSTANCE;
return;
}
#else
if( ( hTCP = DynamicLoad( TCP_LIBNAME ) ) == NULL_INSTANCE && \
( hTCP = DynamicLoad( WINSOCK_OLD_LIBNAME ) ) == NULL_INSTANCE )
return;
#endif /* Win16 vs Win32 */
#else
if( ( hTCP = DynamicLoad( TCP_LIBNAME ) ) == NULL_INSTANCE )
return;
#endif /* OS-specific dynamic load */
/* Now get pointers to the functions */
accept = ( ACCEPT ) DynamicBind( hTCP, "accept" );
bind = ( BIND ) DynamicBind( hTCP, "bind" );
connect = ( CONNECT ) DynamicBind( hTCP, "connect" );
gethostbyname = ( GETHOSTBYNAME ) DynamicBind( hTCP, "gethostbyname" );
getsockopt = ( GETSOCKOPT ) DynamicBind( hTCP, "getsockopt" );
htonl = ( HTONL ) DynamicBind( hTCP, "htonl" );
htons = ( HTONS ) DynamicBind( hTCP, "htons" );
inet_addr = ( INET_ADDR ) DynamicBind( hTCP, "inet_addr" );
inet_ntoa = ( INET_NTOA ) DynamicBind( hTCP, "inet_ntoa" );
listen = ( LISTEN ) DynamicBind( hTCP, "listen" );
ntohs = ( NTOHS ) DynamicBind( hTCP, "ntohs" );
recv = ( RECV ) DynamicBind( hTCP, "recv" );
select = ( SELECT ) DynamicBind( hTCP, "select" );
send = ( SEND ) DynamicBind( hTCP, "send" );
setsockopt = ( SETSOCKOPT ) DynamicBind( hTCP, "setsockopt" );
socket = ( SOCKETFN ) DynamicBind( hTCP, "socket" );
#ifdef __WINDOWS__
closesocket = ( CLOSESOCKET ) DynamicBind( hTCP, "closesocket" );
ioctlsocket = ( IOCTLSOCKET ) DynamicBind( hTCP, "ioctlsocket" );
WSACleanup = ( WSACLEANUP ) DynamicBind( hTCP, "WSACleanup" );
WSAGetLastError = ( WSAGETLASTERROR ) DynamicBind( hTCP, "WSAGetLastError" );
WSAStartup = ( WSASTARTUP ) DynamicBind( hTCP, "WSAStartup" );
__WSAFDIsSet = ( FDISSETFN ) DynamicBind( hTCP, "__WSAFDIsSet" );
#endif /* __WINDOWS__ */
#if ( defined( sun ) && OSVERSION > 4 )
h_errnoPtr = ( int * ) DynamicBind( hTCP, "h_errno" );
if( h_errnoPtr == NULL )
{
DynamicUnload( hTCP );
hTCP = NULL_INSTANCE;
return;
}
#endif /* Slowaris */
/* Make sure we got valid pointers for every TCP/IP function */
if( accept == NULL || bind == NULL || connect == NULL || \
gethostbyname == NULL || getsockopt == NULL || htonl == NULL || \
htons == NULL || inet_addr == NULL || inet_ntoa == NULL || \
listen == NULL || ntohs == NULL || recv == NULL || select == NULL || \
send == NULL || setsockopt == NULL || socket == NULL )
{
DynamicUnload( hTCP );
hTCP = NULL_INSTANCE;
return;
}
#ifdef __WINDOWS__
if( closesocket == NULL || ioctlsocket == NULL || WSACleanup == NULL || \
WSAGetLastError == NULL || WSAStartup == NULL || \
__WSAFDIsSet == NULL || \
( WSAStartup( 2, &wsaData ) && WSAStartup( 1, &wsaData ) ) )
{
DynamicUnload( hTCP );
hTCP = NULL_INSTANCE;
}
#endif /* __WINDOWS__ */
/* Set up the socket pool state information */
initSocketPool();
}
void netEndTCP( void )
{
STATIC_FN void endSocketPool( void );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -