📄 tcp.h
字号:
subset of IPv6 defines further on */
#if defined( __BEOS__ ) && defined( BONE_VERSION )
#define IPv6
#endif /* BeOS with BONE */
/* IPv6 emulation functions used to provide a single consistent interface */
#ifndef IPv6
/* The addrinfo struct used by getaddrinfo() */
struct addrinfo {
int ai_flags; /* AI_PASSIVE, NI_NUMERICHOST */
int ai_family; /* PF_INET */
int ai_socktype; /* SOCK_STREAM */
int ai_protocol; /* IPPROTO_TCP */
size_t ai_addrlen; /* Length of ai_addr */
char *ai_canonname; /* CNAME for nodename */
ARRAY_FIXED( ai_addrlen ) \
struct sockaddr *ai_addr; /* IPv4 or IPv6 sockaddr */
struct addrinfo *ai_next; /* Next addrinfo structure list */
};
/* The generic sockaddr struct used to reserve storage for protocol-
specific sockaddr structs. This isn't quite right but since all
we're using it for is to reserve storage (we never actually look
inside it) it's OK to use here */
typedef char SOCKADDR_STORAGE[ 128 ];
/* getaddrinfo() flags and values */
#define AI_PASSIVE 0x1 /* Flag for hints are for getaddrinfo() */
/* getnameinfo() flags and values. We have to use slightly different
values for these under Windows because Windows uses different values
for these than anyone else, and even if we're not on an explicitly
IPv6-enabled system we could still end up dynamically pulling in the
required libraries, so we need to ensure that we're using the same flag
values that Windows does */
#ifdef __WINDOWS__
#define NI_NUMERICHOST 0x2 /* Return numeric form of host addr.*/
#define NI_NUMERICSERV 0x8 /* Return numeric form of host port */
#else
#define NI_NUMERICHOST 0x1 /* Return numeric form of host addr.*/
#define NI_NUMERICSERV 0x2 /* Return numeric form of host port */
#endif /* __WINDOWS__ */
/* If there's no getaddrinfo() available and we're not using dynamic
linking, use an emulation of the function */
#ifndef __WINDOWS__
#define getaddrinfo my_getaddrinfo
#define freeaddrinfo my_freeaddrinfo
#define getnameinfo my_getnameinfo
static int my_getaddrinfo( const char *nodename, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res );
static void my_freeaddrinfo( struct addrinfo *ai );
static int my_getnameinfo( const struct sockaddr *sa, SIZE_TYPE salen,
char *node, SIZE_TYPE nodelen,
char *service, SIZE_TYPE servicelen,
int flags );
/* Windows uses the Pascal calling convention for these functions, we
hide this behind a define that becomes a no-op on non-Windows
systems */
#define SOCKET_API
#endif /* __WINDOWS__ */
#endif /* IPv6 */
/* A subset of the above for BeOS with the BONE network stack. See the
full IPv6 version above for descriptions of the entries */
#if defined( __BEOS__ ) && defined( BONE_VERSION )
#undef IPv6 /* We really don't do IPv6 */
typedef char SOCKADDR_STORAGE[ 128 ];
#define getaddrinfo my_getaddrinfo
#define freeaddrinfo my_freeaddrinfo
#define getnameinfo my_getnameinfo
static int my_getaddrinfo( const char *nodename, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res );
static void my_freeaddrinfo( struct addrinfo *ai );
static int my_getnameinfo( const struct sockaddr *sa, SIZE_TYPE salen,
char *node, SIZE_TYPE nodelen,
char *service, SIZE_TYPE servicelen,
int flags );
#endif /* BeOS with BONE */
/* Values defined in some environments but not in others. T_SRV and
NS_SRVFIXEDSZ are used for DNS SRV lookups. Newer versions of bind use a
ns_t_srv enum for T_SRV but since we can't autodetect this via the
preprocessor we always define T_SRV ourselves */
#ifndef T_SRV
#define T_SRV 33
#endif /* !T_SRV */
#ifndef NS_SRVFIXEDSZ
#define NS_SRVFIXEDSZ ( NS_RRFIXEDSZ + 6 )
#endif /* !NS_SRVFIXEDSZ */
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0
#endif /* !AI_ADDRCONFIG */
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif /* !AI_NUMERICSERV */
/* gethostbyname is a problem function because the standard version is non-
thread-safe due to the use of static internal storage to contain the
returned host info. Some OSes (Windows, PHUX >= 11.0, OSF/1 >= 4.0,
Aches >= 4.3) don't have a problem with this because they use thread
local storage, but others either require the use of nonstandard _r
variants or simply don't handle it at all. To make it even more
entertaining, there are at least three different variations of the _r
form:
Linux (and glibc systems in general, but not BeOS with BONE):
int gethostbyname_r( const char *name, struct hostent *result_buf,
char *buf, size_t buflen, struct hostent **result,
int *h_errnop);
Slowaris >= 2.5.1, IRIX >= 6.5, QNX:
struct hostent *gethostbyname_r( const char *name,
struct hostent *result, char *buffer,
int buflen, int *h_errnop );
OSF/1, Aches (deprecated, see above):
int gethostbyname_r( const char *name, struct hostent *hptr,
struct hostent_data *hdptr );
To work around this mess, we define macros for thread-safe versions of
gethostbyname that can be retargeted to the appropriate function as
required */
#if defined( USE_THREADS ) && defined( __GLIBC__ ) && ( __GLIBC__ >= 2 ) && \
( !defined( __BEOS__ ) || !defined( BONE_VERSION ) )
#define gethostbyname_vars() \
char hostBuf[ 4096 ]; \
struct hostent hostEnt;
#define gethostbyname_threadsafe( hostName, hostEntPtr, hostErrno ) \
if( gethostbyname_r( hostName, &hostEnt, hostBuf, 4096, &hostEntPtr, &hostErrno ) < 0 ) \
hostEntPtr = NULL
#elif defined( USE_THREADS ) && \
( ( defined( sun ) && OSVERSION > 4 ) || \
( defined( __sgi ) && OSVERSION >= 6 ) || defined( __QNX__ ) )
#define gethostbyname_vars() \
char hostBuf[ 4096 ]; \
struct hostent hostEnt;
#define gethostbyname_threadsafe( hostName, hostEntPtr, hostErrno ) \
hostEntPtr = gethostbyname_r( hostName, &hostEnt, hostBuf, 4096, &hostErrno )
#else
#define gethostbyname_vars()
#define gethostbyname_threadsafe( hostName, hostEntPtr, hostErrno ) \
hostEntPtr = gethostbyname( hostName ); \
hostErrno = h_errno;
#endif /* Various gethostbyname variants */
/****************************************************************************
* *
* Non-blocking I/O 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.
Unfortunately if we haven't got the fcntl() interface available there's
no way to determine whether a socket is non-blocking or not, which is
particularly troublesome for Windows where we need to ensure that the
socket is blocking in order to avoid Winsock bugs with nonblocking
sockets. Although WSAIoctl() would appear to provide an interface for
obtaining the nonblocking status, it doesn't provide any more
functionality than ioctlsocket(), returning an error if we try and read
the FIONBIO value.
If we're just using this as a basic valid-socket check we could also use
( GetFileType( ( HANDLE ) stream->netSocket ) == FILE_TYPE_PIPE ) ? 0 : \
WSAEBADF to check that it's a socket, but there's a bug under all Win9x
versions for which GetFileType() on a socket returns FILE_TYPE_UNKNOWN,
so we can't reliably detect a socket with this. In any case though
ioctlsocket() will return WSAENOTSOCK if it's not a socket, so this is
covered by the default handling anyway.
The best that we can do in this case is to force the socket to be
blocking, which somewhat voids the guarantee that we leave the socket as
we found it, but OTOH if we've been passed an invalid socket the caller
will have to abort and fix the problem anyway, so changing the socket
state isn't such a big deal.
BeOS is even worse, not only is there no way to determine whether a
socket is blocking or not, it'll also quite happily perform socket
functions like setsockopt() on a file descriptor (for example stdout),
so we can't even use this as a check for socket validity as it is under
other OSes. Because of this the check socket function will always
indicate that something vaguely handle-like is a valid socket.
When we get the nonblocking status, if there's an error getting the
status we report it as a non-blocking socket, which results in the socket
being reported as invalid, the same as if it were a a genuine non-
blocking socket */
#if defined( F_GETFL ) && defined( F_SETFL ) && defined( O_NONBLOCK )
#define getSocketNonblockingStatus( socket, value ) \
{ \
value = fcntl( socket, F_GETFL, 0 ); \
value = ( isSocketError( value ) || ( value & O_NONBLOCK ) ) ? \
TRUE : FALSE; \
}
#define setSocketNonblocking( socket ) \
{ \
const int flags = fcntl( socket, F_GETFL, 0 ); \
fcntl( socket, F_SETFL, flags | O_NONBLOCK ); \
}
#define setSocketBlocking( socket ) \
{ \
const int flags = fcntl( socket, F_GETFL, 0 ); \
fcntl( socket, F_SETFL, flags & ~O_NONBLOCK ); \
}
#elif defined( FIONBIO )
#define getSocketNonblockingStatus( socket, value ) \
{ \
long nonBlock = FALSE; \
value = ioctlsocket( socket, FIONBIO, &nonBlock ); \
value = isSocketError( value ) ? TRUE : FALSE; \
}
#define setSocketNonblocking( socket ) \
{ \
long nonBlock = TRUE; \
ioctlsocket( socket, FIONBIO, &nonBlock ); \
}
#define setSocketBlocking( socket ) \
{ \
long nonBlock = FALSE; \
ioctlsocket( socket, FIONBIO, &nonBlock ); \
}
#elif defined( __AMX__ ) || defined( __BEOS__ )
#define getSocketNonblockingStatus( socket, value ) \
{ \
int nonBlock = FALSE; \
setsockopt( socket, SOL_SOCKET, SO_NONBLOCK, &nonBlock, sizeof( int ) ); \
}
#define setSocketNonblocking( socket ) \
{ \
int nonBlock = TRUE; \
setsockopt( socket, SOL_SOCKET, SO_NONBLOCK, &nonBlock, sizeof( int ) ); \
}
#define setSocketBlocking( socket ) \
{ \
int nonBlock = FALSE; \
setsockopt( socket, SOL_SOCKET, SO_NONBLOCK, &nonBlock, sizeof( int ) ); \
}
#elif defined( __SYMBIAN32__ )
/* Symbian OS doesn't support nonblocking I/O */
#define getSocketNonblockingStatus( socket, value ) value = 0
#define setSocketNonblocking( socket )
#define setSocketBlocking( socket )
#else
#error Need to create macros to handle nonblocking I/O
#endif /* Handling of blocking/nonblocking sockets */
/****************************************************************************
* *
* Misc.Functions and Defines *
* *
****************************************************************************/
/* DNS dynamic-binding init/shutdown functions */
#ifdef __WINDOWS__
CHECK_RETVAL \
int initDNS( const INSTANCE_HANDLE hTCP, const INSTANCE_HANDLE hAddr );
void endDNS( const INSTANCE_HANDLE hTCP );
#ifdef USE_DNSSRV
CHECK_RETVAL \
int initDNSSRV( const INSTANCE_HANDLE hTCP );
void endDNSSRV( const INSTANCE_HANDLE hTCP );
#else
#define initDNSSRV( hTCP ) CRYPT_ERROR
#define endDNSSRV( hTCP )
#endif /* USE_DNSSRV */
#endif /* __WINDOWS__ */
/* Prototypes for functions in dns.c */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int getAddressInfo( INOUT NET_STREAM_INFO *netStream,
OUT_PTR struct addrinfo **addrInfoPtrPtr,
IN_BUFFER( nameLen ) const char *name,
IN_LENGTH_DNS const int nameLen,
IN_PORT const int port, const BOOLEAN isServer );
STDC_NONNULL_ARG( ( 1 ) ) \
void freeAddressInfo( struct addrinfo *addrInfoPtr );
STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
void getNameInfo( const struct sockaddr *sockAddr,
OUT_BUFFER( addressMaxLen, *addressLen ) \
char *address, IN_LENGTH_DNS const int addressMaxLen,
OUT_LENGTH_DNS_Z int *addressLen,
OUT_PORT_Z int *port );
/* Prototypes for functions in dns_srv.c */
#ifdef USE_DNSSRV
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
int findHostInfo( INOUT NET_STREAM_INFO *netStream,
OUT_BUFFER_FIXED( hostNameMaxLen ) char *hostName,
IN_LENGTH_DNS const int hostNameMaxLen,
OUT_PORT_Z int *hostPort,
IN_BUFFER( nameLen ) const char *name,
IN_LENGTH_DNS const int nameLen );
#else
/* If there's no DNS support available in the OS there's not much that we
can do to handle automatic host detection. Setting hostPort as a side-
effect is necessary because the #define otherwise no-ops it out,
leading to declared-but-not-used warnings from some compilers */
#define findHostInfo( netStream, hostName, hostNameLen, hostPort, name, nameLen ) \
setSocketError( netStream, "DNS SRV services not available", 30, \
CRYPT_ERROR_NOTAVAIL, FALSE ); \
memset( hostName, 0, min( 16, hostNameLen ) ); \
*( hostPort ) = 0
#endif /* USE_DNSSRV */
/* Prototypes for functions in tcp.c */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int getSocketError( NET_STREAM_INFO *netStream, IN_ERROR const int status );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int getHostError( NET_STREAM_INFO *netStream, IN_ERROR const int 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 );
#endif /* USE_TCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -