%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% header #include "dk3conf.h" #if DK3_HAVE_WINSOCK2_H #if !DK3_WINSOCK2_H_INCLUDED #define DK3_WINSOCK2_H_INCLUDED 1 #include #endif #endif #if DK3_HAVE_WS2TCPIP_H #if !DK3_WS2TCPIP_H_INCLUDED #define DK3_WS2TCPIP_H_INCLUDED #include #endif #endif #if DK3_HAVE_SYS_TYPES_H #include #endif #if DK3_HAVE_SYS_SOCKET_H #include #endif #if DK3_HAVE_SYS_UN_H #include #endif #include "dk3all.h" #if DK3_ON_WINDOWS /** Data type for network sockets. */ typedef SOCKET dk3_socket_t; #else /* if DK3_ON_WINDOWS */ /** Data type for network sockets. */ typedef int dk3_socket_t; #endif /* if DK3_ON_WINDOWS */ /** A socket set for listening or receiving datagrams. On systems with both IPv4 and IPv6 support we might listen on both the IPv4 and IPv6 address for TCP connection requests or UDP diagrams. So one socket is not sufficient. */ typedef struct { dk3_socket_t *pData; /**< Individual sockets. */ size_t szMax; /**< Allocated array size. */ size_t szUsed; /**< Sockets used in array. */ } dk3_socket_set_t; #if !DK3_HAVE_IN_ADDR /** IPv4 address (host address without port number). */ typedef struct in_addr IN_ADDR; #endif #if !DK3_HAVE_IN6_ADDR /** IPv6 address (host address without port number). */ typedef struct in6_addr IN6_ADDR; #endif /** Allowed IPv4 peer. */ typedef struct { IN_ADDR ad; /**< Network address. */ IN_ADDR ma; /**< Network mask. */ } dk3_peer_ip4_t; /** Allowed IPv6 peer. */ typedef struct { IN6_ADDR ad; /**< Network address. */ IN6_ADDR ma; /**< Network mask. */ } dk3_peer_ip6_t; /** Union containing either an IPv4 or an IPv6 allowed peer address. */ typedef union { dk3_peer_ip4_t ip4; /**< IPv4 allowed peer address. */ dk3_peer_ip6_t ip6; /**< IPv6 allowed peer address. */ } dk3_peer_allowed_data_t; /** Allowed peer address structure. */ typedef struct { int wh; /**< What is the type, 0=IPv4, 1=IPv6. */ dk3_peer_allowed_data_t d; /**< Address data. */ } dk3_peer_allowed_t; /** Socket address large enough to hold either IPv4 or IPv6 address. */ #if DK3_HAVE_STRUCT_SOCKADDR_STORAGE typedef struct sockaddr_storage dk3_sockaddr_storage_t; #else typedef struct { struct sockaddr_in ip4addr; /**< IPv4 address. */ #ifdef AF_INET6 struct sockaddr_in6 ip6addr; /**< IPv6 address. */ #endif } dk3_sockaddr_storage_t; #endif #ifdef __cplusplus extern "C" { #endif /** Bring socket subsystem up. On Windows systems this function initializes the WinSock DLL. On other systems this function does nothing and simply indicates success. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_up(int *ec, dk3_app_t *app); /** Bring socket subsystem down. On Windows systems this function cleans up after using the WinSock DLL. On other system this function does nothing and indicates success. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_down(int *ec, dk3_app_t *app); /** Convert IPv4 or IPv6 address to socket address. @param af Address family (AF_INET or AF_INET6). @param hn IP address, 8-bit char string. @param addr Address structure to fill, must be of type struct in_addr / IN_ADDR for af==AF_INET or struct in6_addr / IN6_ADDR for af==AF_INET6. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_inet_pton( int af, char const *hn, void *addr, int *ec, dk3_app_t *app ); /** Convert IPv4 or IPv6 address to socket address. @param af Address family (AF_INET or AF_INET6). @param hn IP address, portable string. @param addr Address structure to fill, must be of type struct in_addr / IN_ADDR for af==AF_INET or struct in6_addr / IN6_ADDR for af==AF_INET6. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_dkchar_inet_pton( int af, dkChar const *hn, void *addr, int *ec, dk3_app_t *app ); #if DK3_HAVE_STRUCT_SOCKADDR_UN /** Find current length of UNIX domain socket address (UNIX/Linux only). @param p Pointer to address. @return Address length. */ size_t dk3socket_un_length(struct sockaddr_un const *p); /** Create a UNIX domain listener socket (UNIX/Linux only). This is a server socket listening on a UNIX domain socket for incoming connection requests. @param fn File name, length must be less than 108. @param backlog Number of connection attempts in backlog. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid file descriptr on success, INVALID_SOCKET on error. */ dk3_socket_t dk3socket_un_listener(char const *fn, int backlog, int *ec, dk3_app_t *app); /** Create UNIX domain listener socket set (UNIX/Linux only). The returned set typically contains one socket. @param fn File name, length must be less than 108. @param backlog Number of connection attempts in backlog. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Pointer to new socket set on success, NULL on error. */ dk3_socket_set_t * dk3socket_un_listeners(char const *fn, int backlog, int *ec, dk3_app_t *app); /** Connect via UNIX domain socket. This function creates a client-side socket, connected to a server process. @param fn File name for socket. @param nsecs Timeout in seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ dk3_socket_t dk3socket_un_stream_client( char const *fn, long nsecs, long usecs, int *ec, dk3_app_t *app ); #endif /** Check socket for validity. @param so Socket to check. @return 1 if socket is valid, 0 for an invalid socket. */ int dk3socket_check(dk3_socket_t so); /** Return value to mark socket as invalid. @return Value to mark socket as invalid. */ dk3_socket_t dk3socket_invalid(void); /** Open a socket. This is a wrapper around the socket() function from the BSD socket API. @param af Address family. @param tp Socket type (stream or datagram). @param pr Socket protocol (typically 0). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return New socket on success, INVALID_SOCKET on error. */ dk3_socket_t dk3socket_open( int af, int tp, int pr, int *ec, dk3_app_t *app ); /** Open a TCP client socket and connect it to a server. If the @arg sh parameter is NULL, the function connects to the local host. @param sh Server host name, 8-bit character string. @param sp Server port. @param lp Local port number, 0 for any. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. On success the socket is ready to be used for sending and receiving data. */ dk3_socket_t dk3socket_open_net_stream_client( char const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ); /** Open a client socket and connect it to a server. If the @arg sh parameter is NULL, the function connects to the local host. @param sh Server host name, portable string. @param sp Server port. @param lp Local port number, 0 for any. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ dk3_socket_t dk3socket_dkchar_open_net_stream_client( dkChar const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ); /** Bind socket to local address. This function is a wrapper around the bind() function from the BSD sockets API. @param sock Socket to bind. @param pAddr Pointer to address buffer. @param szAddr Address buffer size. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_bind( dk3_socket_t sock, struct sockaddr const *pAddr, size_t szAddr, int *ec, dk3_app_t *app ); /** Connect a socket in known blocking/non-blocking state to a server. This is a wrapper around the connect() function from the BSD sockets API. @param so Socket to connect. @param pAddr Server address. @param szAddr Size of server address. @param secs Seconds in timeout (ignored if spnb==0). @param usecs Microseconds in timeout (ignored if spnb==0). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param str Descriptive string for server. @param spnb Flag: Use nb value. Note: The spnb flag is used on Windows systems only, on other systems we use fcntl() to check for blocking/non-blocking mode. @param nb Flag: Socket in non-blocking mode. Note: The nb flag is used on Windows systems only, on other systems we use fcntl() to check for blocking/non-blocking mode. @return 1 on success, 0 on error. */ int dk3socket_connect_spnb( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str, int spnb, int nb ); /** Connect a socket to a server. This is a wrapper around the connect() function from the BSD sockets API. @param so Socket to connect. @param pAddr Server address. @param szAddr Size of server address. @param secs Seconds in timeout (ignored on Windows). @param usecs Microseconds in timeout (ignored on Windows). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param str Descriptive string for server. @return 1 on success, 0 on error. */ int dk3socket_connect( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str ); /** Connect a socket in known blocking/non-blocking state to a server. This is a wrapper around the connect() function from the BSD sockets API. @param so Socket to connect. @param pAddr Server address. @param szAddr Size of server address. @param secs Seconds in timeout. @param usecs Microseconds in timeout. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param str Descriptive string for server. @param nb Flag: Socket in non-blocking mode. Note: The nb flag is used on Windows systems only, on other systems we use fcntl() to check for blocking/non-blocking mode. @return 1 on success, 0 on error. */ int dk3socket_connect_nb( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str, int nb ); /** Listen on a socket. This function is a wrapper around the listen() function from the BSD sockets API. @param so Socket to use for listening. @param bl Backlog (number of connection attempts queued). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_listen( dk3_socket_t so, int bl, int *ec, dk3_app_t *app ); /** Accept a new client connection. This is a wrapper around the accept() function from the BSD sockets API. @param ls Listener socket. @param pAddr Pointer to address buffer (may be NULL). @param pSzAddr Pointer to address size (in/out). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, -1 (INVALID_SOCKET) on error. */ dk3_socket_t dk3socket_accept( dk3_socket_t ls, struct sockaddr *pAddr, size_t *pSzAddr, int *ec, dk3_app_t *app ); /** Send data. Call dk3socket_send_attempt() multiple times if necessary. @param so Socket. @param bu Buffer pointer. @param sz Buffer size in bytes. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Number of bytes sent. */ int dk3socket_send( dk3_socket_t so, void const *bu, size_t sz, long secs, long usecs, int *ec, dk3_app_t *app ); /** Send datagram. This is a wrapper around the sendto() function from the BSD sockets API. @param so Socket. @param bu Buffer pointer. @param sz Buffer size in bytes. @param pAddr Pointer to destination address buffer. @param szAddr Size of destination address. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Number of bytes sent. */ int dk3socket_sendto( dk3_socket_t so, void const *bu, size_t sz, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app ); /** Receive data. This is a wrapper around the recv() function from the BSD sockets API. @param so Socket. @param bu Buffer pointer. @param sz Buffer size in bytes. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Number of bytes received. */ int dk3socket_recv( dk3_socket_t so, void *bu, size_t sz, long secs, long usecs, int *ec, dk3_app_t *app ); /** Receive datagram. This is a wrapper around the recvfrom() function from the BSD sockets API. @param so Socket. @param bu Buffer pointer. @param sz Buffer size in bytes. @param pAddr Pointer to address buffer for remote address. @param pSzAddr Pointer to address size (in/out). @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Number of bytes received. */ int dk3socket_recvfrom( dk3_socket_t so, void *bu, size_t sz, struct sockaddr *pAddr, size_t *pSzAddr, long secs, long usecs, int *ec, dk3_app_t *app ); /** Shut down a socket. This is a wrapper around the shutdown() function from the BSD sockets API. @param so Socket to shut down. @param sv Shutdown type DK3_TCPIP_SHUTDOWN_xxx, see @ref shutdownvalues. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_shutdown(dk3_socket_t so, int sv, int *ec, dk3_app_t *app); /** Prepare an IPv4 address for localhost. @param sp Socket address pointer. */ void dk3socket_ip4addr_set_localhost(struct sockaddr_in *sp); /** Convert IPv4 address to text buffer. @param dp Destination buffer pointer. @param szdp Size of destination buffer (number of dkChar). @param ia4 Address to convert. @return 1 on success, 0 on error. */ int dk3socket_ip4addr_to_text(dkChar *dp, size_t szdp, IN_ADDR const *ia4); #if DK3_HAVE_STRUCT_SOCKADDR_IN6 /** Prepare an IPv6 address for localhost (only if IPv6 support is available). @param sp Socket address pointer. */ void dk3socket_ip6addr_set_localhost(struct sockaddr_in6 *sp); /** Convert IPv6 address to text buffer. @param dp Destination buffer pointer. @param szdp Size of destination buffer (number of dkChar). @param ia6 Address to convert. @return 1 on success, 0 on error. */ int dk3socket_ip6addr_to_text(dkChar *dp, size_t szdp, IN6_ADDR const *ia6); #endif /** Convert IP address to dkChar text. @param dp Destination buffer pointer. @param szdp Size of @a dp (number of elements). @param ia Internet address (IPv4 or IPv6). @param sz Address length. @return 1 on success, 0 on error. */ int dk3socket_ipaddr_to_text(dkChar *dp, size_t szdp, void const *ia, size_t sz); /** Set re-use flag for socket. @param so Socket to modify. @param v New flag value (non-zero/zero). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_set_reuse(dk3_socket_t so, int v, int *ec, dk3_app_t *app); /** Set socket to non-blocking mode. @param so Socket to modify. @param v New non-block value (non-zero/zero). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_set_non_block(dk3_socket_t so, int v, int *ec, dk3_app_t *app); /** Retrieve non-block status for a socket. On Windows systems this function always returns an error, as ioctlsocket() can be used to set/reset non-blocking behaviour, but not to check it. @param so Socket to test. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 for non-blocking, 0 for blocking, -1 for error. */ int dk3socket_get_non_block(dk3_socket_t so, int *ec, dk3_app_t *app); /** Close socket. @param so Socket to close. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_close( dk3_socket_t so, int *ec, dk3_app_t *app ); /** Allocate memory for a socket set. @param sz Maximum number of sockets in set. @param ec Pointer to error code variable, may be NULL. @param app APplication structure for diagnostics, may be NULL. @return Pointer to new socket set on success, NULL on error. */ dk3_socket_set_t * dk3socket_set_new( size_t sz, int *ec, dk3_app_t *app ); /** Release memory for socket set. This function only releases memory, it does not close the sockets. @param ps Socket set to close. */ void dk3socket_set_delete(dk3_socket_set_t *ps); /** Close socket set (close all sockets, release memory). @param ps Socket set to close. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. */ void dk3socket_set_close(dk3_socket_set_t *ps, int *ec, dk3_app_t *app); /** Open a socket set to listen on a TCP port. On systems with IPv4 and IPv6 support we might need more than one socket to listen on both IPv4 and IPv6 addresses. @param portno TCP port number in host representation. @param backlog Listener backlog. @param fLocalOnly Flag: Listen on local loopback interfaces only. By default the socket set will listen on any address. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Pointer to new socket set on success, NULL on error. */ dk3_socket_set_t * dk3socket_listeners( unsigned short portno, int backlog, int fLocalOnly, int *ec, dk3_app_t *app ); /** Accept an incoming connection request on a listener socket set. @param ss Socket set. @param pAddr Buffer for peer address, may be NULL. @param pSzAddr Buffer for peer address size (in+out), may be NULL. When entering the function this parameter must be set to the available buffer size. On output it is set to the used buffer size on success. @param iAllowed Iterator through storage of allowed peer. @param skipDenied Continue silently after rejecting a denied client. addresses. The storage must have dk3socket_compare_peer() set as comparison function. @param nsecs Timeout in seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ dk3_socket_t dk3socket_set_accept( dk3_socket_set_t *ss, struct sockaddr *pAddr, size_t *pSzAddr, dk3_sto_it_t *iAllowed, int skipDenied, long nsecs, long usecs, int *ec, dk3_app_t *app ); /** Open a socket set for UDP traffic. On systems with both IPv4 and IPv6 addresses we might need more than one socket to listen on all addresses. @param portno TCP port number in host representation. @param fLocalOnly Flag: Listen on local loopback interfaces only. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Pointer to new socket set on success, NULL on error. */ dk3_socket_set_t * dk3socket_datagram_sockets( unsigned short portno, int fLocalOnly, int *ec, dk3_app_t *app ); /** Fill data for allowed peer (8-bit character text version). @param dp Destination peer data. @param sr Source string, typically from configuration file. The string contains an allowed client address, either IP address (preferred) or host name. Optionally you can add a network mask as IP address or number of bits. Use a slash to separate address and mask. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_set_peer( dk3_peer_allowed_t *dp, char const *sr, int *ec, dk3_app_t *app ); /** Fill data for allowed peer (portable text version). @param dp Destination peer data. @param sr Source string, typically from configuration file. The string contains an allowed client address, either IP address (preferred) or host name. Optionally you can add a network mask as IP address or number of bits. Use a slash to separate address and mask. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3socket_dkchar_set_peer( dk3_peer_allowed_t *dp, dkChar const *sr, int *ec, dk3_app_t *app ); /** Compare two allowed peer structures. You can use this function as comparison function for a dk3_sto_t containing information about all allowed clients. @param l Left peer object. @param r Right peer object. @param cr Comparison criteria (0=peer/peer, 1=peer/sockaddr). @return Comparison result. */ int dk3socket_compare_peer(void const *l, void const *r, int cr); /** Report error from opening a socket. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_socket(int *ec, dk3_app_t *app, int err); /** Report error from binding a socket. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. @param lat Local address as text, may be NULL. */ void dk3socket_error_bind(int *ec, dk3_app_t *app, int err, dkChar const *lat); /** Report error from connect attempt. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. @param str String describing connection target. */ void dk3socket_error_connect(int *ec, dk3_app_t *app, int err, dkChar const *str); /** Report error from listen attempt. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_listen(int *ec, dk3_app_t *app, int err); /** Report error from closing a socket. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_close(int *ec, dk3_app_t *app, int err); /** Report error from send attempt. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_send(int *ec, dk3_app_t *app, int err); /** Report error from receive attempt. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_recv(int *ec, dk3_app_t *app, int err); /** Report error from accepting a connection. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_accept(int *ec, dk3_app_t *app, int err); /** Report error from shutting down a socket. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_shutdown(int *ec, dk3_app_t *app, int err); /** Report error from inet_pton(). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_inet_pton(int *ec, dk3_app_t *app, int err); /** Report error from getaddrinfo(). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_getaddrinfo(int *ec, dk3_app_t *app, int err); /** Report error from gethostbyname(). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. @param hn Host name for error. */ void dk3socket_error_gethostbyname(int *ec, dk3_app_t *app, int err, char const *hn); /** Report error from setsockopt(). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_setsockopt(int *ec, dk3_app_t *app, int err); /** Report error from select(). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code to report. */ void dk3socket_error_select(int *ec, dk3_app_t *app, int err); /** Eat up input (for orderly release). @param so Socket to clean up. @param app Application structure for diagnostics, may be NULL. */ void dk3socket_eat_input(dk3_socket_t so, dk3_app_t *app); #ifdef __cplusplus } #endif #if !DK3_ON_WINDOWS #ifndef INVALID_SOCKET /** Invalid socket. */ #define INVALID_SOCKET (-1) #endif #endif %% module #include "dk3all.h" #include "dk3sock.h" $!trace-include #if DK3_HAVE_STRUCT_SOCKADDR_IN6 /** Value to initialize any address. */ static const IN6_ADDR dk3socket_ia6_addr_any = IN6ADDR_ANY_INIT; #endif $!trace-code static $!trace-code unsigned $!trace-code dk3socket_word_from_bytes(unsigned char u1, unsigned char u2) $!trace-code { $!trace-code unsigned back; $!trace-code back = (((unsigned)u1) << 8) & 0xFF00U; $!trace-code back |= ((unsigned)u2) & 0x00FFU; $!trace-code return back; $!trace-code } $!trace-code static $!trace-code void $!trace-code dk3socket_report_address(struct sockaddr *sa) $!trace-code { $!trace-code if(sa) { $!trace-code switch(sa->sa_family) { $!trace-code case AF_INET: { $!trace-code struct sockaddr_in *soin; $!trace-code unsigned long ul; $!trace-code unsigned short pn; $!trace-code soin = (struct sockaddr_in *)sa; $!trace-code ul = ntohl((soin->sin_addr).s_addr); $!trace-code pn = ntohs(soin->sin_port); $!trace-code if(dktrace_file()) { $!trace-code fprintf( $!trace-code dktrace_file(), $!trace-code "%lu.%lu.%lu.%lu:%u\n", $!trace-code ((ul >> 24) & 0x000000FFUL), $!trace-code ((ul >> 16) & 0x000000FFUL), $!trace-code ((ul >> 8) & 0x000000FFUL), $!trace-code ((ul ) & 0x000000FFUL), $!trace-code (unsigned)pn $!trace-code ); $!trace-code } $!trace-code } break; $!trace-code #if DK3_HAVE_STRUCT_SOCKADDR_IN6 $!trace-code case AF_INET6: { $!trace-code struct sockaddr_in6 *soin6; $!trace-code unsigned u1, u2, u3, u4, u5, u6, u7, u8; $!trace-code unsigned short pn; $!trace-code if(dktrace_file()) { $!trace-code u1 = u2 = u3 = u4 = u5 = u6 = u7 = u8 = 0; $!trace-code soin6 = (struct sockaddr_in6 *)sa; $!trace-code pn = ntohs(soin6->sin6_port); $!trace-code u1 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[0]), $!trace-code ((soin6->sin6_addr).s6_addr[1]) $!trace-code ); $!trace-code u2 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[2]), $!trace-code ((soin6->sin6_addr).s6_addr[3]) $!trace-code ); $!trace-code u3 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[4]), $!trace-code ((soin6->sin6_addr).s6_addr[5]) $!trace-code ); $!trace-code u4 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[6]), $!trace-code ((soin6->sin6_addr).s6_addr[7]) $!trace-code ); $!trace-code u5 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[8]), $!trace-code ((soin6->sin6_addr).s6_addr[9]) $!trace-code ); $!trace-code u6 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[10]), $!trace-code ((soin6->sin6_addr).s6_addr[11]) $!trace-code ); $!trace-code u7 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[12]), $!trace-code ((soin6->sin6_addr).s6_addr[13]) $!trace-code ); $!trace-code u8 = dk3socket_word_from_bytes( $!trace-code ((soin6->sin6_addr).s6_addr[14]), $!trace-code ((soin6->sin6_addr).s6_addr[15]) $!trace-code ); $!trace-code fprintf( $!trace-code dktrace_file(), $!trace-code "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x=%u\n", $!trace-code u1, u2, u3, u4, u5, u6, u7, u8, (unsigned)pn $!trace-code ); $!trace-code } $!trace-code } break; $!trace-code #endif $!trace-code } $!trace-code } $!trace-code } void dk3socket_set_delete(dk3_socket_set_t *ps) { if(ps) { dk3_release(ps->pData); ps->szMax = 0; ps->szUsed = 0; dk3_delete(ps); } } void dk3socket_set_close(dk3_socket_set_t *ps, int *ec, dk3_app_t *app) { dk3_socket_t *ptr; /* Current socket to close. */ size_t i; /* Index of current socket to close. */ if(ps) { if((ps->pData) && (ps->szUsed)) { ptr = ps->pData; for(i = 0; i < ps->szUsed; i++) { if(INVALID_SOCKET != (*ptr)) { dk3socket_close(*ptr, ec, app); *ptr = INVALID_SOCKET; } ptr++; } } dk3socket_set_delete(ps); } } dk3_socket_set_t * dk3socket_set_new( size_t sz, int *ec, dk3_app_t *app ) { dk3_socket_t *ptr; /* Current socket to initialize. */ dk3_socket_set_t *back = NULL; size_t i; /* Index of socket to initialize. */ if(sz) { back = dk3_new_app(dk3_socket_set_t,1,app); if(back) { back->pData = NULL; back->szMax = 0; back->szUsed = 0; back->pData = dk3_new_app(dk3_socket_t,sz,app); if(back->pData) { ptr = back->pData; for(i = 0; i < sz; i++) { *(ptr++) = INVALID_SOCKET; } back->szMax = sz; } else { dk3_delete(back); back = NULL; } } } return back; } int dk3socket_check(dk3_socket_t so) { int back = 0; if(INVALID_SOCKET != so) { back = 1; } return back; } /** Function names, used for error reporting on non-Windows systems. */ static dkChar const * const dk3socket_function_names[] = { $!string-table macro=dkT # # 0 # socket: # # 1 # bind: # # 2 # connect: # # 3 # listen: # # 4 # accept: # # 5 # send/sendto: # # 6 # recv/recvfrom: # # 7 # select: # # 8 # close: # # 9 # inet_pton: # # 10 # getaddrinfo: # # 11 # shutdown: # # 12 # setsockopt: # # 13 (empty string, intended) # # # 14 # fcntl: # # 15 # : # # 16 # %lu # # 17 # . # # 18 # %x # # 19 # %u@ $!end }; void dk3socket_error_socket(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 279); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem is down" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEAFNOSUPPORT: { $? "! address family not supported" if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 275); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 operation is running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEMFILE: { $? "! no more socket descriptors available" if(ec) { *ec = DK3_ERROR_TOO_MANY_OPEN_FILES; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 277); } } break; case WSAENOBUFS: { $? "! no more buffers available" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAEPROTONOSUPPORT: { $? "! protocol not supported" if(ec) { *ec = DK3_ERROR_PROTOCOL_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 278); } } break; case WSAEPROTOTYPE: { $? "! protocol doesnt match socket type" if(ec) { *ec = DK3_ERROR_ILLEGAL_PROTOCOL_FAMILY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 275); } } break; case WSAESOCKTNOSUPPORT: { $? "! socket type not supported by addr family" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 323); } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[0]); switch(err) { #ifdef EACCES case EACCES: { $? "! insufficient permissions" if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: { $? "! address family not supported" if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } } break; #endif #ifdef EINVAL case EINVAL: { $? "! unknown protocol family" if(ec) { *ec = DK3_ERROR_ILLEGAL_PROTOCOL_FAMILY; } } break; #endif #ifdef EMFILE case EMFILE: { $? "! process table overflow" if(ec) { *ec = DK3_ERROR_PROCESS_TABLE_OVERFLOW; } } break; #endif #ifdef ENFILE case ENFILE: { $? "! limit for open file descriptors reached" if(ec) { *ec = DK3_ERROR_TOO_MANY_OPEN_FILES; } } break; #endif #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: { $? "! protocol not supported" if(ec) { *ec = DK3_ERROR_PROTOCOL_NOT_SUPPORTED; } } break; #endif #ifdef EPROTOTYPE case EPROTOTYPE: { $? "! EPROTOTYPE" if(ec) { *ec = DK3_ERROR_ILLEGAL_PROTOCOL_FAMILY; } } break; #endif #ifdef ENOSR case ENOSR: { if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #if defined(ENOBUFS) && defined(ENOMEM) #if ENOBUFS == ENOMEM case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; case ENOMEM: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #else #if defined(ENOBUFS) case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else #if defined(ENOMEM) case ENOMEM: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #endif #endif } #endif } void dk3socket_error_bind(int *ec, dk3_app_t *app, int err, dkChar const *lat) { if(ec) { *ec = DK3_ERROR_BIND_FAILED; } if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 302, 303, lat); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem not available" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEACCES: { $? "! attempt to use broadcast addr" if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 324); } } break; case WSAEADDRINUSE: { $? "! address already in use" if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 293); } } break; case WSAEADDRNOTAVAIL: { $? "! address not valid for computer" if(ec) { *ec = DK3_ERROR_ADDRESS_NOT_AVAILABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 325); } } break; case WSAEFAULT: { $? "! adress wrong" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 operation running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEINVAL: { $? "! socket already bound to address" if(ec) { *ec = DK3_ERROR_ALREADY_BOUND; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 304);} } break; case WSAENOBUFS: { $? "! not enough buffers available" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAENOTSOCK: { $? "! not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[1]); switch(err) { #ifdef EACCES case EACCES: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #ifdef EADDRINUSE case EADDRINUSE: { $? "! EADDRINUSE" if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } } break; #endif #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: { $? "! EADDRNOTAVAIL" /* ERROR: Address not available on local machine */ if(ec) { *ec = DK3_ERROR_ADDRESS_NOT_AVAILABLE; } } break; #endif #ifdef ENOSR case ENOSR: { $? "! ENOSR" if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINVAL case EINVAL: { if(ec) { *ec = DK3_ERROR_ALREADY_BOUND; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EIO case EIO: { $? "! EIO" /* ERROR: I/O error while creating directory entry or inode */ if(ec) { *ec = DK3_ERROR_IO; } } break; #endif #ifdef EISDIR case EISDIR: { $? "! EISDIR" /* ERROR: NULL pathname */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EDESTADDRREQ #if EDESTADDRREQ != EISDIR case EDESTADDRREQ: { $? "! EDESTADDRREQ" /* ERROR: NULL pointer */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #endif #ifdef ELOOP case ELOOP: { $? "! ELOOP" /* ERROR: Too many symlinks in path */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOENT case ENOENT: { $? "! ENOENT" /* ERROR: Directory does not exist */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOTDIR case ENOTDIR: { $? "! ENOTDIR" /* ERROR: One of the path components is not a directory */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EROFS case EROFS: { $? "! EROFS" /* ERROR: Filesystem is read-only */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EFAULT case EFAULT: { $? "! EFAULT" /* ERROR: Address argument can not be accessed */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { $? "! EOPNOTSUPP" /* ERROR: Socket type does not support binding an address! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: { $? "! ENAMETOOLONG" /* ERROR: Path name too long! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #if defined(ENOBUFS) && defined(ENOMEM) #if ENOBUFS == ENOMEM case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; case ENOMEM: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #else #if defined(ENOBUFS) case ENOBUFS: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else #if defined(ENOMEM) case ENOMEM: { $? "! not enough memory" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #endif #endif #ifdef EISCONN case EISCONN: { $? "! EISCONN" /* ERROR: Socket already connected! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif } #endif } void dk3socket_error_connect(int *ec, dk3_app_t *app, int err, dkChar const *str) { if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { if(str) { dk3app_log_i3(app, DK3_LL_ERROR, 351, 352, str); } else { dk3app_log_i1(app, DK3_LL_ERROR, 282); } } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem is down" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEADDRINUSE: { $? "! local address already in use" if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 293); } } break; case WSAEINTR: { $? "! explicitly cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 operation running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEALREADY: { $? "! non-blocking connect in progress" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 295); } } break; case WSAEADDRNOTAVAIL: { $? "! invalid remote address" if(ec) { *ec = DK3_ERROR_ADDRESS_NOT_AVAILABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 325); } } break; case WSAEAFNOSUPPORT: { $? "! wrong address family for socket" if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 275); } } break; case WSAECONNREFUSED: { $? "! connection refused" if(ec) { *ec = DK3_ERROR_CONNECTION_REFUSED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 296); } } break; case WSAEFAULT: { $? "! incorrect remote address" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINVAL: { $? "! socket is listening" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEISCONN: { $? "! socket already connected" if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 297); } } break; case WSAENETUNREACH: { $? "! network unreachable" if(ec) { *ec = DK3_ERROR_NETWORK_UNREACHABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 298); } } break; case WSAEHOSTUNREACH: { $? "! remote host unreachable" if(ec) { *ec = DK3_ERROR_HOST_UNREACHABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 326); } } break; case WSAENOBUFS: { $? "! no more buffers available" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAENOTSOCK: { $? "! file descriptor is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAETIMEDOUT: { $? "! connect attempt timed out" if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } break; case WSAEWOULDBLOCK: { $? "! connect attempt continued in background" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case WSAEACCES: { $? "! can not connect to broadcast peer addr" if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 324); } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[2]); switch(err) { #if defined(EACCES) && defined(EPERM) #if EACCES == EPERM case EACCES: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break ; #else case EACCES: case EPERM: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #else #ifdef EACCES case EACCES: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #else #ifdef EPERM case EPERM: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #endif #endif #ifdef EADDRINUSE case EADDRINUSE: { if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } } break; #endif #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: { /* ERROR: Address not available on remote machine. */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: { if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } } break; #endif #if defined(EAGAIN) && defined(EWOULDBLOCK) #if EAGAIN == EWOULDBLOCK case EAGAIN: { if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #else case EAGAIN: { if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; case EWOULDBLOCK: { /* ERROR: Operation would block! */ if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #else #ifdef EAGAIN case EAGAIN: { if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef EWOULDBLOCK case EWOULDBLOCK: { /* ERROR: Operation would block! */ if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #endif #ifdef EALREADY case EALREADY: { if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } } break; #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ECONNREFUSED case ECONNREFUSED: { if(ec) { *ec = DK3_ERROR_CONNECTION_REFUSED; } } break; #endif #ifdef EFAULT case EFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINPROGRESS case EINPROGRESS: { if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EISCONN case EISCONN: { if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } } break; #endif #ifdef ENETUNREACH case ENETUNREACH: { if(ec) { *ec = DK3_ERROR_NETWORK_UNREACHABLE; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ETIMEDOUT case ETIMEDOUT: { if(ec) { *ec = DK3_ERROR_TIMEOUT; } } break; #endif #ifdef EINVAL case EINVAL: { /* ERROR: Address name length wrong */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EIO case EIO: { if(ec) { *ec = DK3_ERROR_IO; } } break; #endif #ifdef ELOOP case ELOOP: { /* ERROR: Too many symbolic links while translating path! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: { $? "! EHOSTUNREACH" /* ERROR: Remote host not available from this host! */ if(ec) { *ec = DK3_ERROR_HOST_UNREACHABLE; } } break; #endif #ifdef ENOENT case ENOENT: { $? "! ENOENT" /* ERROR: Component in path name does not exist! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOSR case ENOSR: { $? "! ENOSR" /* ERROR: Resources! */ if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef ENXIO case ENXIO: { $? "! ENXIO" /* ERROR: Server exited before completing connection! */ if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } } break; #endif #ifdef ENOTDIR case ENOTDIR: { $? "! ENOTDIR" /* Component of path prefix is not a directory! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EPROTOTYPE case EPROTOTYPE: { $? "! EPROTOTYPE" /* ERROR: Can not connect to datagram socket! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: { $? "! ENAMETOOLONG" /* ERROR: Path name too long! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ECONNRESET case ECONNRESET: { $? "! ECONNRESET" /* ERROR: Remote host reset connection request! */ if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } } break; #endif #ifdef ENETDOWN case ENETDOWN: { $? "! ENETDOWN" /* ERROR: Local network interface is down! */ if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { $? "! ENOBUFS" /* ERROR: No buffer space available */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { $? "! EOPNOTSUPP" /* ERROR: Socket is listening, cannot be connected! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif } #endif } void dk3socket_error_listen(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_LISTEN_FAILED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 283); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem is down" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEADDRINUSE: { $? "! local address already in use" if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 293); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEINVAL: { $? "! socket not yet bound to local address" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEISCONN: { $? "! socket already connected" if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 297); } } break; case WSAEMFILE: { $? "! no more file descriptors" if(ec) { *ec = DK3_ERROR_TOO_MANY_OPEN_FILES; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 277); } } break; case WSAENOBUFS: { $? "! no memory for buffers" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAENOTSOCK: { $? "! file descriptor is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEOPNOTSUPP: { $? "! socket type does not support listen" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[3]); switch(err) { #ifdef EADDRINUSE case EADDRINUSE: { if(ec) { *ec = DK3_ERROR_ADDR_IN_USE; } } break; #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EDESTADDRREQ case EDESTADDRREQ: { $? "! EDESTADDRREQ" /* ERROR: Socket must be bound before listening! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINVAL case EINVAL: { $? "! EINVAL" /* ERROR: Socket already connected or shut down! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EACCES case EACCES: { $? "! EACCES" /* ERROR: Insufficient privileges */ if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { $? "! ENOBUFS" /* ERROR: Insufficient resources! */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif } #endif } void dk3socket_error_accept(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_ACCEPT_FAILED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 317); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAECONNRESET: { $? "! canceled by client" if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; case WSAEFAULT: { $? "! address space to small" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINTR: { $? "! explicitly cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEINVAL: { $? "! socket is not listening" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEMFILE: { $? "! no more file descriptors" if(ec) { *ec = DK3_ERROR_TOO_MANY_OPEN_FILES; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 277); } } break; case WSAENETDOWN: { $? "! network subsystem failed" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAENOBUFS: { $? "! no memory for buffers" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAENOTSOCK: { $? "! fd is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEOPNOTSUPP: { $? "! socket is not connection-oriented" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEWOULDBLOCK: { $? "! socket non-blocking, op would block" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[4]); switch(err) { #if defined(EAGAIN) && defined(EWOULDBLOCK) #if EAGAIN == EWOULDBLOCK case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #else case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #else #ifdef EAGAIN case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #ifdef EWOULDBLOCK case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ECONNABORTED case ECONNABORTED: { if(ec) { *ec = DK3_ERROR_CONNECTION_ABORTED; } } break; #endif #ifdef EFAULT case EFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EINVAL case EINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EMFILE case EMFILE: { if(ec) { *ec = DK3_ERROR_PROCESS_TABLE_OVERFLOW; } } break; #endif #ifdef ENFILE case ENFILE: { if(ec) { *ec = DK3_ERROR_TOO_MANY_OPEN_FILES; } } break; #endif #if defined(ENOBUFS) && defined(ENOMEM) #if ENOBUFS == ENOMEM case ENOBUFS: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else case ENOBUFS: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #else #ifdef ENOBUFS case ENOBUFS: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ENOMEM case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EPROTO case EPROTO: { if(ec) { *ec = DK3_ERROR_NETWORK_PROTOCOL; } } break; #endif #ifdef EPERM case EPERM: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #ifdef ENODEV case ENODEV: { $? "! ENODEV" /* ERROR: Configuration files do not contain family and type */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOSR case ENOSR: { $? "! ENOSR" /* ERROR: Insufficient streams resources */ if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif } #endif } void dk3socket_error_send(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_DURING_WRITE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem not available" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEACCES: { $? "! attempt to send broadcast" if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 324); } } break; case WSAEINTR: { $? "! explicitly cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op in progress" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEFAULT: { $? "! buffer not in valid user space part" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAENETRESET: { $? "! connection reset by peer" if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; case WSAENOBUFS: { $? "! no buffer space available" if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAENOTCONN: { $? "! socket not connected" if(ec) { *ec = DK3_ERROR_SOCKET_NOT_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 316); } } break; case WSAENOTSOCK: { $? "! fd is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEOPNOTSUPP: { $? "! oob on non-stream or write on read-only" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAESHUTDOWN: { $? "! socket was already shut down" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEWOULDBLOCK: { $? "! operation would block" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case WSAEMSGSIZE: { $? "! message too large" if(ec) { *ec = DK3_ERROR_TOO_LARGE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 245); } } break; case WSAEHOSTUNREACH: { $? "! host unreachable" if(ec) { *ec = DK3_ERROR_HOST_UNREACHABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 326); } } break; case WSAEINVAL: { $? "! socket not completely set up" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAECONNABORTED: { $? "! connection aborted, i.e. timeout" if(ec) { *ec = DK3_ERROR_CONNECTION_ABORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 318); } } break; case WSAECONNRESET: { $? "! connection reset by peer" if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; case WSAETIMEDOUT: { $? "! operation timed out" if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } break; case WSAEADDRNOTAVAIL: { if(ec) { *ec = DK3_ERROR_ADDRESS_NOT_AVAILABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 325); } } break; case WSAEAFNOSUPPORT: { if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 275); } } break; case WSAEDESTADDRREQ: { if(ec) { *ec = DK3_ERROR_ADDRESS_REQUIRED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 308); } } break; case WSAENETUNREACH: { if(ec) { *ec = DK3_ERROR_NETWORK_UNREACHABLE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 298); } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[5]); switch(err) { #ifdef EACCES case EACCES: { if(ec) { *ec = DK3_ERROR_INSUFFICIENT_PERMISSIONS; } } break; #endif #if defined(EAGAIN) && defined(EWOULDBLOCK) #if EAGAIN == EWOULDBLOCK case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #else case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #else #ifdef EAGAIN case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #ifdef EWOULDBLOCK case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ECONNRESET case ECONNRESET: { if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } } break; #endif #ifdef EDESTADDRREQ case EDESTADDRREQ: { if(ec) { *ec = DK3_ERROR_ADDRESS_REQUIRED; } } break; #endif #ifdef EFAULT case EFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EINVAL case EINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EISCONN case EISCONN: { if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } } break; #endif #ifdef EISCON case EISCON: { $? "! EISCON" if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } } break; #endif #ifdef EMSGSIZE case EMSGSIZE: { if(ec) { *ec = DK3_ERROR_TOO_LARGE; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { if(ec) { *ec = DK3_ERROR_TOO_LARGE; } } break; #endif #ifdef ENOMEM case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ENOTCONN case ENOTCONN: { if(ec) { *ec = DK3_ERROR_ADDRESS_REQUIRED; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EPIPE case EPIPE: { if(ec) { *ec = DK3_ERROR_PIPE; } } break; #endif #ifdef ENOSR case ENOSR: { $? "! ENOSR" /* ERROR: Insufficient streams resources! */ if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef ECONNREFUSED case ECONNREFUSED: { $? "! ECONNREFUSED" /* ERROR: Connection refused by peer */ if(ec) { *ec = DK3_ERROR_CONNECTION_REFUSED; } } break; #endif #ifdef EIO case EIO: { $? "! EIO" if(ec) { *ec = DK3_ERROR_IO; } } break; #endif #ifdef ENETDOWN case ENETDOWN: { $? "! ENETDOWN" /* ERROR: Local network interface is down! */ if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } } break; #endif #ifdef ENETUNREACH case ENETUNREACH: { $? "! ENETUNREACH" /* ERROR: No route to network is present! */ if(ec) { *ec = DK3_ERROR_NETWORK_UNREACHABLE; } } break; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: { $? "! EAFNOSUPPORT" /* ERROR: Address can not be used with this socket! */ if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } } break; #endif #ifdef ELOOP case ELOOP: { $? "! ELOOP" /* ERROR: Too many symbolic links in path name! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: { $? "! ENAMETOOLONG" /* ERROR: Path name too long! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOENT case ENOENT: { $? "! ENOENT" /* COmponent in path name names nonexisting file or directory! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOTDIR case ENOTDIR: { $? "! ENOTDIR" /* ERROR: Component in path name is not a directory! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: { $? "! EHOSTUNREACH" /* ERROR: Host unreachable! */ if(ec) { *ec = DK3_ERROR_HOST_UNREACHABLE; } } break; #endif } #endif } void dk3socket_error_recv(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_DURING_READ; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 314); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEFAULT: { $? "! buf parameter wrong" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAENOTCONN: { $? "! not connected" if(ec) { *ec = DK3_ERROR_SOCKET_NOT_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 316); } } break; case WSAEINTR: { $? "! explicitly cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAENETRESET: { $? "! connection reset" if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; case WSAENOTSOCK: { $? "! fd is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEOPNOTSUPP: { $? "! OOB data only for streams" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAESHUTDOWN: { $? "! socket already shut down" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEWOULDBLOCK: { $? "! operation would block" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case WSAEMSGSIZE: { $? "! message too large" if(ec) { *ec = DK3_ERROR_TOO_LARGE; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 245); } } break; case WSAEINVAL: { $? "! wrong input parameters" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; case WSAEISCONN: { $? "! socket is connected" if(ec) { *ec = DK3_ERROR_ALREADY_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 297); } } break; case WSAECONNABORTED: { $? "! aborted due to timeout or failure" if(ec) { *ec = DK3_ERROR_CONNECTION_ABORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 318); } } break; case WSAETIMEDOUT: { $? "! timeout" if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } break; case WSAECONNRESET: { $? "! connection reset by peer" if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[6]); switch(err) { #if defined(EAGAIN) && defined(EWOULDBLOCK) #if EAGAIN == EWOULDBLOCK case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #else case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 306); } } break; case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #else #ifdef EAGAIN case EAGAIN: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #ifdef EWOULDBLOCK case EWOULDBLOCK: { if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; #endif #endif #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ECONNREFUSED case ECONNREFUSED: { if(ec) { *ec = DK3_ERROR_CONNECTION_REFUSED; } } break; #endif #ifdef EFAULT case EFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EINVAL case EINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOMEM case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ENOTCONN case ENOTCONN: { if(ec) { *ec = DK3_ERROR_ADDRESS_REQUIRED; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EIO case EIO: { $? "! EIO" if(ec) { *ec = DK3_ERROR_IO; } } break; #endif #ifdef ENOSR case ENOSR: { $? "! ENOSR" /* ERROR: Insufficient streams resources! */ if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef ESTALE case ESTALE: { $? "! ESTALE" /* ERROR: Stale NFS file handle! */ if(ec) { *ec = DK3_ERROR_STALE_NFS_FILE_HANDLE; } } break; #endif #ifdef ECONNRESET case ECONNRESET: { $? "! ECONNRESET" /* ERROR: Connection forcibly closed by peer! */ if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } } break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: { $? "! EOPNOTSUPP" /* ERROR: Specified flags are not supported! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { $? "! ENOBUFS" /* ERROR: Insufficient resources! */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ETIMEDOUT case ETIMEDOUT: { $? "! ETIMEDOUT" /* ERROR: Connection timed out! */ if(ec) { *ec = DK3_ERROR_TIMEOUT; } } break; #endif } #endif } void dk3socket_error_select(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 336); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAEFAULT: { $? "! failed to allocate resources" if(ec) { *ec = DK3_ERROR_RESOURCES; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 294); } } break; case WSAENETDOWN: { $? "! network subsystem not available" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEINVAL: { $? "! invalid timeout or all fdsets NULL" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINTR: { $? "! explicitly cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAENOTSOCK: { $? "! at least one file fd is not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[7]); switch(err) { #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EINVAL case EINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOMEM case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif } #endif } void dk3socket_error_close(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 280); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? "! Winsock not initialized" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem not available" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAENOTSOCK: { $? "! not a socket" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 op in progress" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEINTR: { $? "! explicitly canceled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; case WSAEWOULDBLOCK: { $? "! Operation would block" if(ec) { *ec = DK3_ERROR_WOULD_BLOCK; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[8]); switch(err) { #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINTR case EINTR: { if(ec) { *ec = DK3_ERROR_INTERRUPTED; } } break; #endif #ifdef EIO case EIO: { if(ec) { *ec = DK3_ERROR_IO; } } break; #endif #ifdef ENOLINK case ENOLINK: { $? "! ENOLINK" /* ERROR: Remote file descriptr, server not available! */ if(ec) { *ec = DK3_ERROR_STALE_NFS_FILE_HANDLE; } } break; #endif #ifdef ENOSPC case ENOSPC: { $? "! ENOSPC" /* ERROR: No free space left on device! */ if(ec) { *ec = DK3_ERROR_IO; } } break; #endif default: { if(ec) { *ec = DK3_ERROR_SYSTEM; } } break; } #endif } void dk3socket_error_inet_pton(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 337); } #if DK3_ON_WINDOWS switch(err) { case WSAEAFNOSUPPORT: { if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 275); } } break; case WSAEFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[9]); switch(err) { #ifdef EAFNOSUPPORT case EAFNOSUPPORT: { if(ec) { *ec = DK3_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED; } } break; #endif #ifdef ENOSPC case ENOSPC: { $? "! ENOSPC" /* ERROR: Inadequate result buffer size! */ if(ec) { *ec = DK3_ERROR_IO; } } break; #endif } #endif } void dk3socket_error_getaddrinfo(int *ec, dk3_app_t *app, int err) { #if (DK3_CHAR_SIZE == 1) && DK3_HAVE_STRERROR && (!DK3_ON_WINDOWS) dkChar const *msgarray[2]; #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE char const *oldlocale = NULL; char const *langptr = NULL; #endif #endif $? "+ dk3socket_error_getaddrinfo %d %s %s", err, TR_PTR(ec), TR_PTR(app) if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 338); } #if DK3_ON_WINDOWS switch(err) { case WSATRY_AGAIN: { if(ec) { *ec = DK3_ERROR_HOST_NOT_FOUND; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 289);} } break; case WSAEINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSANO_RECOVERY: { if(ec) { *ec = DK3_ERROR_HOST_NOT_FOUND; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 288);} } break; case WSAEAFNOSUPPORT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSA_NOT_ENOUGH_MEMORY: { if(ec) { *ec = DK3_ERROR_MEMORY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } break; case WSAHOST_NOT_FOUND: { if(ec) { *ec = DK3_ERROR_HOST_NOT_FOUND; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286);} } break; case WSATYPE_NOT_FOUND: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAESOCKTNOSUPPORT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else /* dk3sf_report_errno(app, err, dk3socket_function_names[10]); */ #if (DK3_CHAR_SIZE == 1) && DK3_HAVE_STRERROR && (!DK3_ON_WINDOWS) #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE langptr = getenv("LANG"); if(langptr) { oldlocale = setlocale(LC_MESSAGES, langptr); } #endif msgarray[0] = dk3socket_function_names[10]; errno = 0; msgarray[1] = gai_strerror(err); if(msgarray[1]) { if(0 == errno) { if(app) { dk3app_log_3( app, DK3_LL_ERROR, msgarray, 0, 1, dk3socket_function_names[13] ); } } } #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE if(langptr) { if(oldlocale) { setlocale(LC_MESSAGES, oldlocale); } } #endif #endif switch(err) { #ifdef EAI_ADDRFAMILY case EAI_ADDRFAMILY: { if(ec) { *ec =DK3_ERROR_HOST_NOT_FOUND; } } break; #endif #ifdef EAI_AGAIN case EAI_AGAIN: { if(ec) { *ec =DK3_ERROR_RESOURCES; } } break; #endif #ifdef EAI_BADFLAGS case EAI_BADFLAGS: { if(ec) { *ec =DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EAI_FAIL case EAI_FAIL: { if(ec) { *ec =DK3_ERROR_HOST_NOT_FOUND; } } break; #endif #ifdef EAI_FAMILY case EAI_FAMILY: { if(ec) { *ec =DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EAI_MEMORY case EAI_MEMORY: { if(ec) { *ec =DK3_ERROR_MEMORY; } } break; #endif #ifdef EAI_NODATA case EAI_NODATA: { if(ec) { *ec =DK3_ERROR_HOST_NOT_FOUND; } } break; #endif #ifdef EAI_NONAME case EAI_NONAME: { if(ec) { *ec =DK3_ERROR_HOST_NOT_FOUND; } } break; #endif #ifdef EAI_SERVICE case EAI_SERVICE: { if(ec) { *ec =DK3_ERROR_HOST_NOT_FOUND; } } break; #endif #ifdef EAI_SOCKTYPE case EAI_SOCKTYPE: { if(ec) { *ec =DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EAI_OVERFLOW case EAI_OVERFLOW: { if(ec) { *ec =DK3_ERROR_TOO_LARGE; } } break; #endif #ifdef EAI_SYSTEM case EAI_SYSTEM: { if(ec) { *ec =DK3_ERROR_SYSTEM; } } break; #endif } #endif $? "- dk3socket_error_getaddrinfo" } void dk3socket_error_gethostbyname(int *ec, dk3_app_t *app, int err, char const *hn) { if(app) { if(hn) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 284, 285, hn); #else dk3app_log_i1(app, DK3_LL_ERROR, 286); #endif } else { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } if(ec) { *ec = DK3_ERROR_HOST_NOT_FOUND; } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { $? ". Winsock not started" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? ". network subsystem down" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAHOST_NOT_FOUND: { $? ". no authorative answer host" } break; case WSATRY_AGAIN: { $? ". server failure or nonauthorative host not found" } break; case WSANO_RECOVERY: { $? ". nonrecoverable error" } break; case WSANO_DATA: { $? ". valid name, no data in record" } break; case WSAEINPROGRESS: { $? ". blocking winsock 1.1 call in progress" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEFAULT: { $? ". name not valid part of address space" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINTR: { $? ". blocking call was cancelled" if(ec) { *ec = DK3_ERROR_INTERRUPTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 281); } } break; } #else switch(err) { #ifdef HOST_NOT_FOUND case HOST_NOT_FOUND: { $? ". host is unknown" } break; #endif #ifdef TRY_AGAIN case TRY_AGAIN: { $? ". temporary error on authorative server" } break; #endif #ifdef NO_RECOVERY case NO_RECOVERY: { $? ". nonrecoverable name server error" } break; #endif #if defined(NO_DATA) && defined(NO_ADDRESS) #if NO_DATA == NO_ADDRESS case NO_DATA: { $? ". name valid but does not have IP address" } break; #else case NO_DATA: { $? ". name valid but does not have IP address" } break; case NO_ADDRESS: { $? ". name valid but does not have IP address" } break; #endif #else #ifdef NO_DATA case NO_DATA: { $? ". name valid but does not have IP address" } break; #endif #ifdef NO_ADDRESS case NO_ADDRESS: { $? ". name valid but does not have IP address" } break; #endif #endif } #endif } #if DK3_ON_WINDOWS /** Report error from bringing WinSock up (Windows only). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code from WSAStartUp. */ static void dk3socket_error_up(int *ec, dk3_app_t *app, int err) { /* ERROR: Failed to bring Windows sockets up. */ switch(err) { case WSASYSNOTREADY: { $? "! network subsystem not yet ready" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAVERNOTSUPPORTED: { $? "! Winsock version not supported here" if(ec) { *ec = DK3_ERROR_PROTOCOL_NOT_SUPPORTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 327); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 operation running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEPROCLIM: { $? "! too many processes use Winsock" if(ec) { *ec = DK3_ERROR_RESOURCES; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 328); } } break; case WSAEFAULT: { $? "! invalid wsaData pointer" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } } /** Report error from bringing WinSock down (Windows only). @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param err Error code from WSAStartUp. */ static void dk3socket_error_down(int *ec, dk3_app_t *app, int err) { /* ERROR: Failed to bring Winsock subsystem down! */ switch(err) { case WSANOTINITIALISED: { $? "! Winsock never brought up" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { $? "! network subsystem has failed" if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEINPROGRESS: { $? "! blocking Winsock 1.1 operation is running" if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; } } #endif void dk3socket_error_shutdown(int *ec, dk3_app_t *app, int err) { if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 315); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEINPROGRESS: { if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAENOTCONN: { if(ec) { *ec = DK3_ERROR_SOCKET_NOT_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 316); } } break; case WSAENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[11]); switch(err) { #ifdef EBADF case EBADF: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOMEM case ENOMEM: { if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ENOSR case ENOSR: { if(ec) { *ec = DK3_ERROR_RESOURCES; } } break; #endif #ifdef ENOTCONN case ENOTCONN: { if(ec) { *ec = DK3_ERROR_SOCKET_NOT_CONNECTED; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINVAL case EINVAL: { $? "! EINVAL" /* ERROR: how argument is invalid! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { $? "! ENOBUFS" /* ERROR: Insufficient resources! */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif } #endif } void dk3socket_error_setsockopt(int *ec, dk3_app_t *app, int err) { $? "+ dk3socket_error_setsockopt %d", err if(ec) { *ec = DK3_ERROR_IO; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 339); } #if DK3_ON_WINDOWS switch(err) { case WSANOTINITIALISED: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEINPROGRESS: { if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAEINVAL: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAENETRESET: { if(ec) { *ec = DK3_ERROR_CONNECTION_RESET; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 307); } } break; case WSAENOPROTOOPT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAENOTCONN: { if(ec) { *ec = DK3_ERROR_SOCKET_NOT_CONNECTED; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 316); } } break; case WSAENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } #else dk3sf_report_errno(app, err, dk3socket_function_names[12]); switch(err) { #if defined(ENOMEM) && defined(ENOBUFS) #if ENOMEM == ENOBUFS case ENOMEM: { $? "! ENOMEM" /* ERROR: Insufficient memory */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #else case ENOMEM: { $? "! ENOMEM" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; case ENOBUFS: { $? "! ENOBUFS" /* ERROR: Insufficient buffer resources. */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #else #ifdef ENOMEM case ENOMEM: { $? "! ENOMEM" if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #ifdef ENOBUFS case ENOBUFS: { $? "! ENOBUFS" /* */ if(ec) { *ec = DK3_ERROR_MEMORY; } } break; #endif #endif #ifdef EBADF case EBADF: { $? "! EBADF" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EFAULT case EFAULT: { $? "! EFAULT" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EINVAL case EINVAL: { $? " EINVAL" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOPROTOOPT case ENOPROTOOPT: { $? "! ENOPROTOOPT" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef ENOTSOCK case ENOTSOCK: { $? "! ENOTSOCK" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EDOM case EDOM: { $? "! EDOM" /* ERROR: Timeout values too big! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif #ifdef EISCONN case EISCONN: { $? "! EISCONN" /* ERROR: Socket already connected, too late to set option! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; #endif } #endif $? "- dk3socket_error_setsockopt" } void dk3socket_ip4addr_set_localhost(struct sockaddr_in *sp) { if(sp) { dk3mem_res((void *)sp, sizeof(struct sockaddr_in)); sp->sin_family = AF_INET; (sp->sin_addr).s_addr = htonl(0x7F000001UL); } } #if DK3_HAVE_STRUCT_SOCKADDR_IN6 void dk3socket_ip6addr_set_localhost(struct sockaddr_in6 *sp) { if(sp) { dk3mem_res((void *)sp, sizeof(struct sockaddr_in6)); sp->sin6_family = AF_INET6; sp->sin6_addr.s6_addr[15] = 0x01; } } int dk3socket_ip6addr_to_text(dkChar *dp, size_t szdp, IN6_ADDR const *ia6) { dkChar bu[32]; size_t i; size_t szx; int back = 0; unsigned char uc1; unsigned char uc2; unsigned short us; if((dp) && (szdp >= 40) && (ia6)) { back = 1; for(i = 0; i < 8; i++) { uc1 = ia6->s6_addr[2 * i]; uc2 = ia6->s6_addr[2 * i + 1]; us = (((unsigned short)uc1) << 8) & 0xFF00U; us |= (((unsigned short)uc2) & 0x00FFU); #if VERSION_BEFORE_20140716 dk3sf_sprintf3(bu,dk3socket_function_names[18],((int)us & 0xFFFF)); if(i) { dk3str_cat(dp, dk3socket_function_names[15]); dk3str_cat(dp, bu); } else { dk3str_cpy_not_overlapped(dp, bu); } #else if (dk3ma_um_to_hex_string(bu, DK3_SIZEOF(bu,dkChar), (dk3_um_t)us, 0)) { if(i) { szx = dk3str_len(dp) + dk3str_len(dk3socket_function_names[15]) + dk3str_len(bu); if (szx < szdp) { dk3str_cat(dp, dk3socket_function_names[15]); dk3str_cat(dp, bu); } else { back = 0; } } else { szx = dk3str_len(dp) + dk3str_len(bu); if (szx < szdp) { dk3str_cpy_not_overlapped(dp, bu); } else { back = 0; } } } #endif } } return back; } #endif int dk3socket_ip4addr_to_text(dkChar *dp, size_t szdp, IN_ADDR const *ia4) { #if VERSION_BEFORE_20140716 dkChar bu[32]; unsigned long ul; int back = 0; if((dp) && (szdp >= 16) && (ia4)) { ul = ntohl(ia4->s_addr); dk3sf_sprintf3(bu,dk3socket_function_names[16],((ul >> 24) & 0x000000FFUL)); dk3str_cpy_not_overlapped(dp, bu); dk3sf_sprintf3(bu,dk3socket_function_names[16],((ul >> 16) & 0x000000FFUL)); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu); dk3sf_sprintf3(bu,dk3socket_function_names[16],((ul >> 8) & 0x000000FFUL)); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu); dk3sf_sprintf3(bu,dk3socket_function_names[16],((ul ) & 0x000000FFUL)); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu); back = 1; } return back; #else dkChar bu1[32]; dkChar bu2[32]; dkChar bu3[32]; dkChar bu4[32]; size_t sz; unsigned long ul; int back = 0; if ((NULL != dp) && (16 <= szdp) && (ia4)) { ul = ntohl(ia4->s_addr); back = dk3ma_um_to_string( bu1, DK3_SIZEOF(bu1,dkChar), (dk3_um_t)((ul >> 24) & 0x000000FFUL) ); if (0 != back) { back = dk3ma_um_to_string( bu2, DK3_SIZEOF(bu2,dkChar), (dk3_um_t)((ul >> 16) & 0x000000FFUL) ); if (0 != back) { back = dk3ma_um_to_string( bu3, DK3_SIZEOF(bu3,dkChar), (dk3_um_t)((ul >> 8) & 0x000000FFUL) ); if (0 != back) { back = dk3ma_um_to_string( bu4, DK3_SIZEOF(bu4,dkChar), (dk3_um_t)(ul & 0x000000FFUL) ); if (0 != back) { back = 0; sz = dk3str_len(bu1) + dk3str_len(bu2) + dk3str_len(bu3) + dk3str_len(bu4) + 4; if (sz < szdp) { back = 1; dk3str_cpy_not_overlapped(dp, bu1); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu2); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu3); dk3str_cat(dp, dk3socket_function_names[17]); dk3str_cat(dp, bu4); } } } } } } return back; #endif } int dk3socket_ipaddr_to_text(dkChar *dp, size_t szdp, void const *ia, size_t sz) { dkChar mybu[64]; struct sockaddr const *soa; struct sockaddr_in const *so4; #ifdef AF_INET6 struct sockaddr_in6 const *so6; #endif dkChar *ptr; size_t sl; unsigned u; int back = 0; $? "+ dk3socket_ipaddr_to_text %u %u", (unsigned)sz, (unsigned)sizeof(struct sockaddr_in) if((dp) && (szdp) && (ia) && (sz)) { $? ". args ok" soa = (struct sockaddr const *)ia; if((AF_INET == soa->sa_family) && (sz == sizeof(struct sockaddr_in))) { so4 = (struct sockaddr_in const *)ia; $? ". in4" u = (unsigned)(ntohs(so4->sin_port)); #if VERSION_BEFORE_20140716 dk3sf_sprintf3(mybu, dk3socket_function_names[19], u); if((1 + dk3str_len(mybu)) < szdp) { dk3str_cpy_not_overlapped(dp, mybu); ptr = dp; while(*ptr) { ptr++; } sl = dk3str_len(dp); back = dk3socket_ip4addr_to_text(ptr, (szdp - sl), &(so4->sin_addr)); } #else if (dk3ma_um_to_string(mybu, DK3_SIZEOF(mybu,dkChar), (dk3_um_t)u)) { if((2 + dk3str_len(mybu)) < szdp) { dk3str_cpy_not_overlapped(dp, mybu); ptr = dp; while(*ptr) { ptr++; } *(ptr++) = dkT('@'); *ptr = dkT('\0'); sl = dk3str_len(dp); back = dk3socket_ip4addr_to_text(ptr, (szdp - sl), &(so4->sin_addr)); } } #endif } else { #ifdef AF_INET6 if((AF_INET6 == soa->sa_family) && (sz == sizeof(struct sockaddr_in6))) { so6 = (struct sockaddr_in6 const *)ia; $? ". in6" u = (unsigned)(ntohs(so6->sin6_port)); #if VERSION_BEFORE_20140716 dk3sf_sprintf3(mybu, dk3socket_function_names[19], u); if((1 + dk3str_len(mybu)) < szdp) { dk3str_cpy_not_overlapped(dp, mybu); ptr = dp; while(*ptr) { ptr++; } sl = dk3str_len(dp); back = dk3socket_ip6addr_to_text(ptr, (szdp - sl), &(so6->sin6_addr)); } #else if (dk3ma_um_to_string(mybu, DK3_SIZEOF(mybu,dkChar), (dk3_um_t)u)) { if((2 + dk3str_len(mybu)) < szdp) { dk3str_cpy_not_overlapped(dp, mybu); ptr = dp; while(*ptr) { ptr++; } *(ptr++) = dkT('@'); *ptr = dkT('\0'); sl = dk3str_len(dp); back = dk3socket_ip6addr_to_text(ptr,(szdp - sl),&(so6->sin6_addr)); } } #endif } else { #endif #ifdef AF_INET6 } #endif } } $? "- dk3socket_ipaddr_to_text %d", back return back; } /** Report success from listen(). @param app Application structure for diagnostics. @param so Socket. @param addr Local address we are listening on. @param szaddr Address size. */ static void dk3socket_report_listen_success( dk3_app_t *app, dk3_socket_t so, void *addr, size_t szaddr ) { dkChar bu[128]; dkChar sb[128]; int convres; /* Address conversion result. */ if(app) { if(dk3app_max_log_level(app) >= DK3_LL_PROGRESS) { convres = dk3socket_ipaddr_to_text( bu, DK3_SIZEOF(bu,dkChar), addr, szaddr ); if(convres) { #if VERSION_BEFORE_20140716 dk3sf_sprintf3(sb,dkT("%d"),((int)so)); dk3app_log_i5(app, DK3_LL_PROGRESS, 372, 373, 374, sb, bu); #else convres = dk3ma_im_to_string(sb, DK3_SIZEOF(sb,dkChar), (dk3_im_t)so); if (0 != convres) { dk3app_log_i5(app, DK3_LL_PROGRESS, 372, 373, 374, sb, bu); } #endif } } } } /** Report success from connect(). @param app Application structure for diagnostics. @param so Socket. @param addr Local address we are listening on. @param szaddr Address size. */ static void dk3socket_report_connect_success( dk3_app_t *app, dk3_socket_t so, void *addr, size_t szaddr ) { dkChar bu[128]; dkChar sb[128]; int convres; /* Address conversion result. */ if(app) { if(dk3app_max_log_level(app) >= DK3_LL_PROGRESS) { convres = dk3socket_ipaddr_to_text( bu, DK3_SIZEOF(bu,dkChar), addr, szaddr ); if(convres) { #if VERSION_BEFORE_20140716 dk3sf_sprintf3(sb,dkT("%d"),((int)so)); dk3app_log_i5(app, DK3_LL_PROGRESS, 375, 376, 377, sb, bu); #else convres = dk3ma_im_to_string(sb, DK3_SIZEOF(sb,dkChar), (dk3_im_t)so); if (0 != convres) { dk3app_log_i5(app, DK3_LL_PROGRESS, 375, 376, 377, sb, bu); } #endif } } } } /** Obtain last error code for sockets. @param ec Error code from errno. @return Result from WSAGetLastError() on Windows, ec on all other systems. */ static int dk3socket_error(int ec) { #if DK3_ON_WINDOWS int back; back = WSAGetLastError(); return back; #else return ec; #endif } dk3_socket_t dk3socket_open( int af, int tp, int pr, int *ec, dk3_app_t *app ) { dk3_socket_t back; int err; /* Error code. */ $? "+ dk3socket_open %d %d %d", af, tp, pr back = socket(af, tp, pr); if(INVALID_SOCKET == back) { err = dk3socket_error(errno); dk3socket_error_socket(ec, app, err); } $? "- dk3socket_open %d", (int)back return back; } int dk3socket_bind( dk3_socket_t sock, struct sockaddr const *pAddr, size_t szAddr, int *ec, dk3_app_t *app ) { dkChar bu[64]; /* Port number buffer. */ #if VERSION_BEFORE_20140716 dkChar *ptr; #endif dkChar *lat; /* Local address text. */ int res; /* Result from bind(). */ int err; /* Error code. */ int conr; /* Address conversion result. */ int back = 0; $? "+ dk3socket_bind %d", (int)sock if((INVALID_SOCKET != sock) && (pAddr) && (szAddr)) { res = bind(sock, pAddr, (int)szAddr); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); lat = NULL; switch(pAddr->sa_family) { #ifdef AF_UNIX case AF_UNIX: { #if DK3_CHAR_SIZE == 1 struct sockaddr_un *soun; soun = (struct sockaddr_un *)pAddr; lat = soun->sun_path; #endif } break; #endif case AF_INET: { #if VERSION_BEFORE_20140716 struct sockaddr_in *soin; unsigned u; soin = (struct sockaddr_in *)pAddr; u = (unsigned)(ntohs(soin->sin_port)); dk3sf_sprintf3(bu,dk3socket_function_names[19], u); ptr = bu; while(*ptr) { ptr++; } *(ptr++) = dkT('@'); *ptr = dkT('\0'); dk3socket_ip4addr_to_text( ptr, (DK3_SIZEOF(bu,dkChar) - dk3str_len(bu)), &(soin->sin_addr) ); lat = bu; #else conr = dk3socket_ipaddr_to_text( bu, DK3_SIZEOF(bu,dkChar), (void const *)pAddr, sizeof(struct sockaddr_in) ); if (0 != conr) { lat = bu; } #endif } break; #if defined(AF_INET6) && DK3_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6: { #if VERSION_BEFORE_20140716 struct sockaddr_in6 *soin6; unsigned u; soin6 = (struct sockaddr_in6 *)pAddr; u = (unsigned)(ntohs(soin6->sin6_port)); dk3sf_sprintf3(bu,dk3socket_function_names[19], u); ptr = bu; while(*ptr) { ptr++; } *(ptr++) = dkT('@'); *ptr = dkT('\0'); dk3socket_ip6addr_to_text( ptr, (DK3_SIZEOF(bu,dkChar) - dk3str_len(bu)), &(soin6->sin6_addr) ); lat = bu; #else conr = dk3socket_ipaddr_to_text( bu, DK3_SIZEOF(bu,dkChar), (void const *)pAddr, sizeof(struct sockaddr_in6) ); if (0 != conr) { lat = bu; } #endif } break; #endif } if (NULL != lat) { dk3socket_error_bind(ec, app, err, lat); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_bind %d", back return back; } #if DK3_ON_WINDOWS static void dk3socket_error_ioctlsocket_fionbio( int *ec, dk3_app_t *app, int err ) { if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 339); } switch(err) { case WSANOTINITIALISED: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 321); } } break; case WSAENETDOWN: { if(ec) { *ec = DK3_ERROR_NETWORK_SUBSYSTEM_NOT_READY; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 320); } } break; case WSAEINPROGRESS: { if(ec) { *ec = DK3_ERROR_IN_PROGRESS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 322); } } break; case WSAENOTSOCK: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; case WSAEFAULT: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } } /** Connect with timeout on Windows system. @param so Socket to connect. @param pAddr Pointer to address. @param szaddr Address size. @param secs Seconds for timeout. @param usecs Microseconds for timeout. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3socket_connect_windows_timeout( dk3_socket_t so, struct sockaddr const *pAddr, int szaddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str ) { fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int res; /* Operation result. */ int err; /* Error code. */ int back = 0; res = connect(so, pAddr, szaddr); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); switch(err) { /* ##### CHECK WHETHER ERROR CODE IS CORRECT! */ case WSAEINPROGRESS: { /* Still connecting, use select to wait. */ FD_ZERO(&wfds); FD_SET(so, &wfds); to.tv_sec = secs; to.tv_usec = usecs; res = select(((int)so + 1), NULL, &wfds, NULL, &to); if(SOCKET_ERROR != res) { if(FD_ISSET(so, &wfds)) { back = 1; } else { /* Timeout. */ if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { if(res == 0) { /* Timeout. */ if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } else { /* Error in select. */ if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } } break; default: { /* failed to connect. */ dk3socket_error_connect(ec, app, err, str); } break; } } return back; } #endif int dk3socket_connect_spnb( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str, int spnb, int nb ) { #if DK3_HAVE_SELECT && (!(DK3_ON_WINDOWS)) fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int oldmode; /* File mode before. */ int mustrestore = 0; /* Flag: Resotre old mode. */ #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int slo = 0; /* Size of option. */ #else socklen_t slo = 0; /* Size of option. */ #endif #endif int res; /* Operation result. */ int err; /* Error code. */ int back = 0; $? "+ dk3socket_connect %d", (int)so if((INVALID_SOCKET != so) && (pAddr) && (szAddr)) { if((secs) || (usecs)) { $? ". timeout" #if DK3_HAVE_SELECT #if DK3_ON_WINDOWS if(spnb) { $? ". nb specified" if(nb) { $? ". already non-blocking" /* Now attempt to connect */ back = dk3socket_connect_windows_timeout( so, pAddr, (int)szAddr, secs, usecs, ec, app, str ); } else { unsigned long xv; $? ". normal (blocking) mode" xv = 0x01010101UL; if(0 == ioctlsocket(so, FIONBIO, &xv)) { /* Now attempt to connect */ back = dk3socket_connect_windows_timeout( so, pAddr, (int)szAddr, secs, usecs, ec, app, str ); xv = 0UL; if(0 != ioctlsocket(so, FIONBIO, &xv)) { $? "! failed to restore" err = WSAGetLastError(); dk3socket_error_ioctlsocket_fionbio(ec, app, err); back = 0; } } else { $? "! failed to set to nonblocking" err = WSAGetLastError(); dk3socket_error_ioctlsocket_fionbio(ec, app, err); } } } else { $? ". nb not specified" res = connect(so, pAddr, (int)szAddr); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_connect(ec, app, err, str); } } #else mustrestore = 0; $? ". timeout unix" oldmode = fcntl(so, F_GETFL); if(!(oldmode & O_NONBLOCK)) { fcntl(so, F_SETFL, (oldmode | O_NONBLOCK)); mustrestore = 1; } res = connect(so, pAddr, (int)szAddr); if(0 == res) { $? ". connect" back = 1; } else { err = errno; switch(err) { case EINPROGRESS: { $? ". grant time" FD_ZERO(&wfds); FD_SET(so, &wfds); to.tv_sec = secs; to.tv_usec = usecs; res = select(((int)so + 1), NULL, &wfds, NULL, &to); #if DK3_ON_WINDOWS if(SOCKET_ERROR != res) #else if(res > 0) #endif { $? ". select" if(FD_ISSET(so, &wfds)) { $? ". FD_ISSET" if(FD_ISSET(so, &wfds)) { $? ". FD_ISSET" err = 0; slo = sizeof(int); res = getsockopt( so, SOL_SOCKET, SO_ERROR, (void *)(&err), &slo ); if(0 == res) { $? ". getsockopt" if(slo == sizeof(int)) { $? ". int found" if(0 == err) { $? ". success" back = 1; } else { $? "! error %d", err dk3socket_error_connect(ec, app, err, str); mustrestore = 0; } } else { $? "! size" /* ERROR: Not an int value from getsockopt */ if(ec) { *ec = DK3_ERROR_SOCKET_OPTIONS; } if(app) { dk3app_log_i1(app,DK3_LL_ERROR,282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 301); } mustrestore = 0; } } else { $? "! getsockopt" /* ERROR while reading socket option */ if(ec) { *ec = DK3_ERROR_SOCKET_OPTIONS; } if(app) { dk3app_log_i1(app,DK3_LL_ERROR,282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 301); } mustrestore = 0; } } else { $? "! FD_ISSET" /* TIMEOUT */ if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } mustrestore = 0; } } else { $? "! FD_ISSET" if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } mustrestore = 0; } } else { $? "! select" if(res == 0) { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } else { if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } mustrestore = 0; } } break; default: { $? "! connect %d", err dk3socket_error_connect(ec, app, err, str); mustrestore = 0; } break; } } if(mustrestore) { fcntl(so, F_SETFL, oldmode); } #endif #else res = connect(so, pAddr, (int)szAddr); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_connect(ec, app, err, str); } #endif } else { $? ". no timeout" res = connect(so, pAddr, (int)szAddr); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_connect(ec, app, err, str); } } if(back) { dk3socket_report_connect_success(app, so, (void *)pAddr, szAddr); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_connect %d", back return back; } int dk3socket_connect_nb( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str, int nb ) { int back; back = dk3socket_connect_spnb( so, pAddr, szAddr, secs, usecs, ec, app, str, 1, nb ); return back; } int dk3socket_connect( dk3_socket_t so, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *str ) { int back; back = dk3socket_connect_spnb( so, pAddr, szAddr, secs, usecs, ec, app, str, 0, 0 ); return back; } int dk3socket_listen( dk3_socket_t so, int bl, int *ec, dk3_app_t *app ) { int back = 0; int res; /* Operation result. */ int err; /* Error code. */ $? "+ dk3socket_listen %d", (int)so if(INVALID_SOCKET != so) { res = listen(so, bl); if(0 == res) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_listen(ec, app, err); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_listen %d", back return back; } dk3_socket_t dk3socket_accept( dk3_socket_t ls, struct sockaddr *pAddr, size_t *pSzAddr, int *ec, dk3_app_t *app ) { #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int addrsize = 0; #else socklen_t addrsize = 0; #endif dk3_socket_t back = INVALID_SOCKET; int err; if((pAddr) && (pSzAddr)) { #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) if(pSzAddr) { addrsize = (int)(*pSzAddr); } #else if(pSzAddr) { addrsize = (socklen_t)(*pSzAddr); } #endif } if(INVALID_SOCKET != ls) { back = accept(ls, pAddr, ((pAddr) ? &addrsize : NULL)); if((pAddr) && (pSzAddr)) { *pSzAddr = (size_t)addrsize; } if(INVALID_SOCKET == back) { err = dk3socket_error(errno); dk3socket_error_accept(ec, app, err); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } /** Send data. This is a wrapper around the send() function from the BSD sockets API. @param so Socket. @param bu Buffer pointer. @param sz Buffer size in bytes. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Number of bytes sent. */ static int dk3socket_send_attempt( dk3_socket_t so, void const *bu, size_t sz, long secs, long usecs, int *ec, dk3_app_t *app ) { int back = -1; int err; /* Error code. */ #if DK3_ON_WINDOWS || (!(DK3_HAVE_SSIZE_T)) int res; /* Operation result. */ #else ssize_t res; /* Operation result. */ #endif #if DK3_HAVE_SELECT || DK3_ON_WINDOWS fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ #endif $? "+ dk3socket_send_attempt %d %u", (int)so, (unsigned)sz if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS FD_ZERO(&wfds); FD_SET(so, &wfds); to.tv_sec = secs; to.tv_usec = usecs; selres = select(((int)so + 1), NULL, &wfds, NULL, &to); #if DK3_ON_WINDOWS if(selres != SOCKET_ERROR) #else if(selres > -1) #endif { if(selres > 0) { if(FD_ISSET(so,&wfds)) { #if DK3_ON_WINDOWS res = send(so, bu, (int)sz, 0); #else res = send(so, bu, sz, 0); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { err = dk3socket_error(errno); dk3socket_error_select(ec, app, err); } #else #if DK3_ON_WINDOWS res = send(so, bu, (int)sz, 0); #else res = send(so, bu, sz, 0); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } #endif } else { #if DK3_ON_WINDOWS res = send(so, bu, (int)sz, 0); #else res = send(so, bu, sz, 0); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_send_attempt %d", back return back; } int dk3socket_send( dk3_socket_t so, void const *bu, size_t sz, long secs, long usecs, int *ec, dk3_app_t *app ) { char const *ptr; int back = 0; int res; $? "+ dk3socket_send %d %u", (int)so, (unsigned)sz ptr = (char const *)bu; do { res = dk3socket_send_attempt(so,(void const *)ptr,sz,secs,usecs,ec,app); if(-1 < res) { back += res; ptr = &(ptr[res]); } } while((back < (int)sz) && (-1 < res)); $? "- dk3socket_send %d", back return back; } int dk3socket_recv( dk3_socket_t so, void *bu, size_t sz, long secs, long usecs, int *ec, dk3_app_t *app ) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS fd_set rfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ #if !DK3_ON_WINDOWS int oldmode; /* Block/nonblock mode. */ int mustrestore = 0; /* Must restore old mode. */ #endif #endif #if DK3_ON_WINDOWS || (!(DK3_HAVE_SSIZE_T)) int res; /* Operation result. */ #else ssize_t res; /* Operation result. */ #endif int err; /* Error code. */ int back = -1; $? "+ dk3socket_recv %d %u", (int)so, (unsigned)sz if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS FD_ZERO(&rfds); FD_SET(so,&rfds); to.tv_sec = secs; to.tv_usec = usecs; selres = select(((int)so + 1), &rfds, NULL, NULL, &to); #if DK3_ON_WINDOWS if(selres != SOCKET_ERROR) #else if(selres >= 0) #endif { if(selres > 0) { if(FD_ISSET(so,&rfds)) { #if DK3_ON_WINDOWS res = recv(so, bu, (int)sz, 0); #else mustrestore = 0; oldmode = fcntl(so, F_GETFL); if(!(oldmode & O_NONBLOCK)) { fcntl(so, F_SETFL, (oldmode | O_NONBLOCK)); mustrestore = 1; } res = recv(so, bu, sz, 0); #endif if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } #if !DK3_ON_WINDOWS if(mustrestore) { fcntl(so, F_SETFL, oldmode); } #endif } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { err = dk3socket_error(errno); dk3socket_error_select(ec, app, err); } #else #if DK3_ON_WINDOWS res = recv(so, bu, (int)sz, 0); #else res = recv(so, bu, sz, 0); #endif if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } #endif } else { #if DK3_ON_WINDOWS res = recv(so, bu, (int)sz, 0); #else res = recv(so, bu, sz, 0); #endif if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_recv %d", back return back; } int dk3socket_sendto( dk3_socket_t so, void const *bu, size_t sz, struct sockaddr const *pAddr, size_t szAddr, long secs, long usecs, int *ec, dk3_app_t *app ) { int back = -1; int err; /* Error code. */ #if DK3_ON_WINDOWS || (!(DK3_HAVE_SSIZE_T)) int res; /* Operation result. */ #else ssize_t res; /* Operation result. */ #endif #if DK3_HAVE_SELECT || DK3_ON_WINDOWS fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ #endif #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int myszaddr; #else socklen_t myszaddr; #endif $? "+ dk3socket_sendto %d %u", (int)so, (unsigned)sz #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) myszaddr = (int)szAddr; #else myszaddr = (socklen_t)szAddr; #endif if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS FD_ZERO(&wfds); FD_SET(so, &wfds); to.tv_sec = secs; to.tv_usec = usecs; selres = select(((int)so + 1), NULL, &wfds, NULL, &to); #if DK3_ON_WINDOWS if(selres != SOCKET_ERROR) #else if(selres > -1) #endif { if(selres > 0) { if(FD_ISSET(so,&wfds)) { #if DK3_ON_WINDOWS res = sendto(so, bu, (int)sz, 0, pAddr, myszaddr); #else res = sendto(so, bu, sz, 0, pAddr, myszaddr); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { err = dk3socket_error(errno); dk3socket_error_select(ec, app, err); } #else #if DK3_ON_WINDOWS res = sendto(so, bu, (int)sz, 0, pAddr, myszaddr); #else res = sendto(so, bu, sz, 0, pAddr, myszaddr); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } #endif } else { #if DK3_ON_WINDOWS res = sendto(so, bu, (int)sz, 0, pAddr, myszaddr); #else res = sendto(so, bu, sz, 0, pAddr, myszaddr); #endif if(res >= 0) { back = res; if((size_t)res < sz) { if(ec) { *ec = DK3_ERROR_MESSAGE_NOT_SENT_COMPLETELY; } if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 313); } } } else { err = dk3socket_error(errno); dk3socket_error_send(ec, app, err); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_sendto %d", back return back; } int dk3socket_recvfrom( dk3_socket_t so, void *bu, size_t sz, struct sockaddr *pAddr, size_t *pSzAddr, long secs, long usecs, int *ec, dk3_app_t *app ) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS fd_set rfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ #if !DK3_ON_WINDOWS int oldmode; /* Block/nonblock mode. */ int mustrestore; /* Flag: Restore old mode. */ #endif #endif #if DK3_ON_WINDOWS || (!(DK3_HAVE_SSIZE_T)) int res; /* Operation result. */ #else ssize_t res; /* Operation result. */ #endif int err; /* Error code. */ int back = -1; #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int myszaddr = 0; #else socklen_t myszaddr = 0; #endif $? "+ dk3socket_recvfrom %d %u", (int)so, (unsigned)sz #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) if((pAddr) && (pSzAddr)) { myszaddr = (int)(*pSzAddr); } #else if((pAddr) && (pSzAddr)) { myszaddr = (socklen_t)(*pSzAddr); } #endif if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { #if DK3_HAVE_SELECT || DK3_ON_WINDOWS FD_ZERO(&rfds); FD_SET(so,&rfds); to.tv_sec = secs; to.tv_usec = usecs; selres = select(((int)so + 1), &rfds, NULL, NULL, &to); #if DK3_ON_WINDOWS if(selres != SOCKET_ERROR) #else if(selres >= 0) #endif { if(selres > 0) { if(FD_ISSET(so,&rfds)) { #if DK3_ON_WINDOWS res = recvfrom(so,bu,(int)sz,0,pAddr,((pAddr) ? &myszaddr : NULL)); #else mustrestore = 0; oldmode = fcntl(so, F_GETFL); if(!(oldmode & O_NONBLOCK)) { fcntl(so, F_SETFL, (oldmode | O_NONBLOCK)); mustrestore = 1; } res = recvfrom(so, bu, sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); #endif if((pAddr) && (pSzAddr)) { *pSzAddr = (size_t)myszaddr; } if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } #if !DK3_ON_WINDOWS if(mustrestore) { fcntl(so, F_SETFL, oldmode); } #endif } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 305); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } else { err = dk3socket_error(errno); dk3socket_error_select(ec, app, err); } #else #if DK3_ON_WINDOWS res = recvfrom(so, bu, (int)sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); #else res = recvfrom(so, bu, sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); #endif if((pAddr) && (pSzAddr)) { *pSzAddr = (size_t)myszaddr; } if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } #endif } else { #if DK3_ON_WINDOWS res = recvfrom(so, bu, (int)sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); #else res = recvfrom(so, bu, sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); #endif if((pAddr) && (pSzAddr)) { *pSzAddr = (size_t)myszaddr; } if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(ec, app, err); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_recvfrom %d", back return back; } int dk3socket_close( dk3_socket_t so, int *ec, dk3_app_t *app ) { int res; /* Operation result. */ int err; /* Error code. */ int back = 0; $? "+ dk3socket_close %d", (int)so if(INVALID_SOCKET != so) { #if DK3_ON_WINDOWS res = closesocket(so); #else res = close(so); #endif if(0 == res) { back = 1; } else { /* ERROR: Failed to close socket! */ err = dk3socket_error(errno); dk3socket_error_close(ec, app, err); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_close %d", back return back; } dk3_socket_t dk3socket_invalid(void) { return INVALID_SOCKET; } int dk3socket_up(int *ec, dk3_app_t *app) { #if DK3_ON_WINDOWS int back = 0; int err; /* Error code. */ WORD wVersionRequested; /* Requested Winsock version. */ WSADATA wsaData; /* Result data. */ $? "+ dk3socket_up" wVersionRequested = MAKEWORD(2,0); err = WSAStartup(wVersionRequested, &wsaData); if(0 == err) { back = 1; } else { dk3socket_error_up(ec, app, err); } $? "- dk3socket_up %d", back return back; #else return 1; #endif } int dk3socket_down(int *ec, dk3_app_t *app) { #if DK3_ON_WINDOWS int back = 0; $? "+ dk3socket_down" if(0 == WSACleanup()) { back = 1; } else { dk3socket_error_down(ec, app, WSAGetLastError()); } $? "- dk3socket_down %d", back return back; #else return 1; #endif } int dk3socket_inet_pton(int af, char const *hn, void *addr, int *ec, dk3_app_t *app) { int back = 0; int res; /* Result from inet_pton(). */ $? "+ dk3socket_inet_pton \"%s\"", TR_STR(hn) #if DK3_ON_WINDOWS #if (!defined(NTDDI_VERSION)) || (NTDDI_VERSION >= NTDDI_VISTA) $? ". windows Vista+" res = InetPtonA(af, hn, addr); switch(res) { case 1: { back = 1; } break; case 0: { /* ERROR: Not an IP address! */ } break; case -1: { dk3socket_error_inet_pton(ec, app, WSAGetLastError()); } break; } #else if(AF_INET == af) { IN_ADDR *ia; unsigned long ul; ul = 0UL; if(dk3enc_c8_ipaddr_to_ul_app(hn, &ul, app)) { ia = (IN_ADDR *)addr; ia->s_addr = htonl(ul); back = 1; } else { /* ERROR: Not an IPv4 address! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } } #endif #else $? ". unix/linux" #if DK3_HAVE_INET_PTON $? ". DK3_HAVE_INET_PTON" res = inet_pton(af, hn, addr); switch(res) { case 1: { $? ". inet_pton" back = 1; } break; case 0: { $? "! not an IP address" /* ERROR: Not an IP address! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 348, 349, hn); #else dk3app_log_i1(app, DK3_LL_ERROR, 350); #endif } } break; case -1: { $? "! error from inet_pton" dk3socket_error_inet_pton(ec, app, errno); } break; } #else $? "! DK3_HAVE_INET_PTON" #if DK3_HAVE_INET_ATON $? ". DK3_HAVE_INET_ATON" if(AF_INET == af) { $? ". AF_INET" res = inet_aton(hn, (IN_ADDR *)addr); if(res) { $? ". inet_aton" back = 1; } else { $? "! inet_aton" /* ERROR: Not an IPv4 address! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 348, 349, hn); #else dk3app_log_i1(app, DK3_LL_ERROR, 350); #endif } } } else { #ifdef EAFNOSUPPORT dk3socket_error_inet_pton(ec, app, EAFNOSUPPORT); #endif } #else $? "! DK3_HAVE_INET_ATON" if(AF_INET == af) { IN_ADDR *ia; unsigned long ul; ul = 0UL; if(dk3enc_c8_ipaddr_to_ul_app(hn, &ul, app)) { $? ". dk3enc_c8_ipaddr_to_ul_app" ia = (IN_ADDR *)addr; ia->s_addr = htonl(ul); back = 1; } else { $? "! dk3enc_c8_ipaddr_to_ul_app" /* ERROR: Not an IPv4 address! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } } else { #ifdef EAFNOSUPPORT dk3socket_error_inet_pton(ec, app, EAFNOSUPPORT); #endif } #endif #endif #endif $? "- dk3socket_inet_pton %d", back return back; } int dk3socket_set_reuse(dk3_socket_t so, int v, int *ec, dk3_app_t *app) { int back = 0; int err; $? "+ dk3socket_set_reuse" if(INVALID_SOCKET != so) { #if DK3_HAVE_SETSOCKOPT && defined(SO_REUSEADDR) int opt; #if DK3_SIZEOF_INT > 2 #if DK3_SIZEOF_INT > 4 opt = ((v) ? 0x0101010101010101 : 0); #else opt = ((v) ? 0x01010101 : 0); #endif #else opt = ((v) ? 0x0101 : 0); #endif if(0 == setsockopt(so,SOL_SOCKET,SO_REUSEADDR,(void *)(&opt),sizeof(opt))) { $? ". setsockopt SO_REUSEADDR" #ifdef SO_REUSEPORT if(0 == setsockopt(so,SOL_SOCKET,SO_REUSEPORT,(void *)(&opt),sizeof(opt))) { $? ". setsockopt SO_REUSEPORT" back = 1; $? ". success" } else { $? "! setsockopt SO_REUSEPORT" /* ERROR: setsockopt failed! */ err = dk3socket_error(errno); dk3socket_error_setsockopt(ec, app, err); } #else back = 1; $? ". success" #endif } else { $? "! setsockopt SO_REUSEADDR" /* ERROR: setsockopt failed! */ err = dk3socket_error(errno); dk3socket_error_setsockopt(ec, app, err); } #else /* ERROR: SO_REUSEADDR NOT DEFINED */ $? "! no SO_REUSEADDR defined" #endif } else { $? "! invalid socket" /* ERROR: Not a valid socket! */ } $? "- dk3socket_set_reuse %d", back return back; } int dk3socket_shutdown(dk3_socket_t so, int sv, int *ec, dk3_app_t *app) { int back = 0; int err = 0; /* Error code. */ if(INVALID_SOCKET != so) { switch(sv) { case DK3_TCPIP_SHUTDOWN_READ: { #if DK3_ON_WINDOWS if(0 == shutdown(so, SD_RECEIVE)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } #else #ifdef SHUT_RD if(0 == shutdown(so, SHUT_RD)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #else if(0 == shutdown(so, 0)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #endif #endif } break; case DK3_TCPIP_SHUTDOWN_WRITE: { #if DK3_ON_WINDOWS if(0 == shutdown(so, SD_SEND)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } #else #ifdef SHUT_WR if(0 == shutdown(so, SHUT_WR)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #else if(0 == shutdown(so, 1)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #endif #endif } break; case DK3_TCPIP_SHUTDOWN_RW: { #if DK3_ON_WINDOWS if(0 == shutdown(so, SD_BOTH)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } #else #ifdef SHUT_RDWR if(0 == shutdown(so, SHUT_RDWR)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #else if(0 == shutdown(so, 2)) { back = 1; } else { err = dk3socket_error(errno); dk3socket_error_shutdown(ec, app, err); } #endif #endif } break; default: { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } break; } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } int dk3socket_set_non_block(dk3_socket_t so, int v, int *ec, dk3_app_t *app) { int back = 0; int err; if(INVALID_SOCKET != so) { #if DK3_ON_WINDOWS unsigned long xv; if(v) { xv = 0x01010101UL; } else { xv = 0UL; }; if(0 == ioctlsocket(so, FIONBIO, &xv)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_ioctlsocket_fionbio(ec, app, err); } #else int oldmode; oldmode = fcntl(so, F_GETFL); if(oldmode & O_NONBLOCK) { back = 1; } else { oldmode |= O_NONBLOCK; if(-1 != fcntl(so, F_SETFL, oldmode)) { back = 1; } else { err = dk3socket_error(errno); if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 339); } dk3sf_report_errno(app, err, dk3socket_function_names[14]); } } #endif } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } int dk3socket_get_non_block(dk3_socket_t so, int *ec, dk3_app_t *app) { int back = -1; if(INVALID_SOCKET != so) { #if DK3_ON_WINDOWS /* ERROR: No function implemented! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 353); } #else int oldmode; oldmode = fcntl(so, F_GETFL); if(oldmode & O_NONBLOCK) { back = 1; } else { back = 0; } #endif } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } #if DK3_HAVE_STRUCT_SOCKADDR_UN size_t dk3socket_un_length(struct sockaddr_un const *p) { size_t back = 0; if(p) { #ifdef SUN_LEN back = SUN_LEN(p) ; #else back = sizeof(struct sockaddr_un) - sizeof(p->sun_path) + strlen(p->sun_path); #endif } return back; } dk3_socket_t dk3socket_un_listener(char const *fn, int backlog, int *ec, dk3_app_t *app) { dk3_socket_t back = INVALID_SOCKET; struct sockaddr_un soun; #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int szs; #else socklen_t szs; #endif $? "+ dk3socket_un_listener \"%s\"", TR_STR(fn) if(fn) { if(strlen(fn) < 108) { back = dk3socket_open(AF_UNIX, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { (void)dk3socket_set_reuse(back, 1, ec, app); soun.sun_family = AF_UNIX; strcpy(soun.sun_path, fn); #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) szs = (int)dk3socket_un_length(&soun); #else szs = (socklen_t)dk3socket_un_length(&soun); #endif if(dk3socket_bind(back, (struct sockaddr *)(&soun), szs, ec, app)) { if(!dk3socket_listen(back, backlog, ec, app)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_un_listener %d", (int)back return back; } dk3_socket_set_t * dk3socket_un_listeners(char const *fn, int backlog, int *ec, dk3_app_t *app) { dk3_socket_set_t *back = NULL; dk3_socket_t fd; fd = dk3socket_un_listener(fn, backlog, ec, app); if(INVALID_SOCKET != fd) { back = dk3socket_set_new(1, ec, app); if(back) { *(back->pData) = fd; } else { dk3socket_close(fd, ec, app); } } return back; } dk3_socket_t dk3socket_un_stream_client( char const *fn, long nsecs, long usecs, int *ec, dk3_app_t *app ) { dk3_socket_t back = INVALID_SOCKET; struct sockaddr_un soun; size_t szs; int res; if(fn) { if(strlen(fn) < 108) { back = dk3socket_open(AF_UNIX, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { soun.sun_family = AF_UNIX; strcpy(soun.sun_path, fn); szs = dk3socket_un_length(&soun); res = dk3socket_connect( back, (struct sockaddr *)(&soun), szs, nsecs, usecs, ec, app, #if DK3_CHAR_SIZE == 1 fn #else NULL #endif ); if(!(res)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } else { /* ERROR: Socket name too long! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } #if DK3_CHAR_SIZE < 2 if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } #endif } } else { /* ERROR: Invalid arguments, missing file name! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } #endif #if DK3_HAVE_GETADDRINFO || DK3_ON_WINDOWS /* Section start: getaddrinfo(). */ /** Attempt to open a client socket. @param hai Server host address information. @param lai Client (local) host address information, may be NULL. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ static dk3_socket_t dk3socket_attempt_open_net_stream_client( struct addrinfo const *hai, struct addrinfo const *lai, long secs, long usecs, int *ec, dk3_app_t *app ) { struct addrinfo const *resc; /* Results for remote addresses. */ struct addrinfo const *resl; /* Results for local adddresses. */ struct sockaddr *soa; /* Remote socket address. */ struct sockaddr *sol; /* Local socket address. */ dk3_socket_t back = INVALID_SOCKET; int found; /* Flag: Address found. */ int connres; /* Result from bind()/connect(). */ $? "+ dk3socket_attempt_open_net_stream_client" found = 0; resc = hai; while((resc) && (INVALID_SOCKET == back)) { $? ". loop start" soa = resc->ai_addr; if(soa) { $? ". address" if(lai) { $? ". local address" resl = lai; $!trace-code dk3socket_report_address(soa); while((resl) && (INVALID_SOCKET == back)) { $? ". inner loop start" sol = resl->ai_addr; $!trace-code dk3socket_report_address(sol); if(sol) { $? ". local address" if(soa->sa_family == sol->sa_family) { $? ". families equal" switch(soa->sa_family) { case AF_INET: case AF_INET6: { $? ". known family" found = 1; switch(soa->sa_family) { case AF_INET6: { $? ". IPv6" back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); } break; default: { $? ". IPv4" back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); } break; } if(INVALID_SOCKET != back) { $? ". socket opened" (void)dk3socket_set_reuse(back, 1, NULL, NULL); connres = dk3socket_bind( back, sol, resl->ai_addrlen, ec, app ); if(connres) { $? ". bind ok" connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, NULL, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! bind" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! socket not opened" } } break; default: { $? "! unknown family" } break; } } else { $? "! family mismatch" /* Families do not match. */ } } else { $? "! sol" } resl = resl->ai_next; } } else { $? ". no local address" switch(soa->sa_family) { case AF_INET: { $? ". IPv4" found = 1; back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { $? ". open" connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, NULL, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } break; case AF_INET6: { $? ". IPv6" back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { $? ". open" connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, NULL, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } found = 1; } break; } } } else { $? "! soa" } resc = resc->ai_next; $? ". outer loop end" } $? "- dk3socket_attempt_open_net_stream_client %d", (int)back return back; } /** Connect to a remote address using one from a set of local addresses. @param af Address family for remote address. @param pAddr Remote address. @param szAddr Remote address length. @param resl Set of local addresses. @param secs Seconds for timeout. @param usecs Microseconds for timeout. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ static dk3_socket_t dk3socket_attempt_open_net_stream_for_local_address( int af, struct sockaddr const *pAddr, size_t szAddr, struct addrinfo const *resl, long secs, long usecs, int *ec, dk3_app_t *app ) { dk3_socket_t back = INVALID_SOCKET; struct addrinfo const *resc; /* Current address info struct. */ struct sockaddr *soa; /* Socket address. */ int found; /* Flag: Matching address found. */ int connres; /* Result from bind() and connect(). */ $? "+ dk3socket_attempt_open_net_stream_for_local_address" found = 0; resc = resl; while((resc) && (INVALID_SOCKET == back)) { $? ". loop start" soa = resc->ai_addr; if(soa) { $? ". soa" if(soa->sa_family == af) { $? ". family matches" switch(af) { case AF_INET: case AF_INET6: { $? ". known family" switch(soa->sa_family) { case AF_INET6: { $? ". IPv6" back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); } break; default: { $? ". IPv4" back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); } break; } if(INVALID_SOCKET != back) { $? ". open" (void)dk3socket_set_reuse(back, 1, NULL, NULL); connres = dk3socket_bind( back, soa, resc->ai_addrlen, ec, app ); if(connres) { $? ". bind" connres = dk3socket_connect_nb( back, pAddr, szAddr, secs, usecs, ec, app, NULL, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! bind" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! open" } } break; default: { $? "! unknown family" } break; } } else { $? "! family mismatch" } } else { $? "! soa" } resc = resc->ai_next; } $? "- dk3socket_attempt_open_net_stream_for_local_address %d", (int)back return back; } dk3_socket_t dk3socket_open_net_stream_client( char const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ) { char pbuf[64]; /* Server port number as text. */ char lbuf[64]; /* Local port number as text. */ IN_ADDR in4; /* IPv4 address. */ IN6_ADDR in6; /* IPv6 address. */ struct addrinfo hs; /* Remote hints. */ struct addrinfo hl; /* Local hints. */ struct addrinfo *ress; /* Server addresses. */ struct addrinfo *resl; /* Local addresses. */ struct sockaddr_in soin4; /* IPv4 socket address. */ struct sockaddr_in6 soin6; /* IPv6 socket address. */ int resgai = 0; /* Result from getaddrinfo(). */ int connres; /* Result from connect(). */ dk3_socket_t back = INVALID_SOCKET; $? "+ dk3socket_open_net_stream_client %s %u (getaddrinfo)", TR_STR(sh), (unsigned)sp if(sp) { $? ". sp" if(sh) { $? ". host name specified" ress = NULL; resl = NULL; /* Find local addresses. */ if(lp) { sprintf(lbuf, "%u", (unsigned)lp); dk3mem_res((void *)(&hl), sizeof(struct addrinfo)); hl.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hl.ai_family = AF_UNSPEC; hl.ai_socktype = SOCK_STREAM; hl.ai_protocol = 0; resgai = getaddrinfo(NULL, lbuf, &hl, &resl); $? ". resgai = %d", resgai } /* Continue only if local addresses are found or not needed. */ if(((resgai == 0) && (resl)) || (0 == lp)) { $? ". can continue" /* Test IPv4 address. */ resgai = dk3socket_inet_pton(AF_INET,sh,(void *)(&in4),NULL,NULL); if(1 == resgai) { $? ". inet_pton ok" dk3mem_res((void *)(&soin4), sizeof(struct sockaddr_in)); soin4.sin_family = AF_INET; soin4.sin_port = htons(sp); dk3mem_cpy( (void *)(&(soin4.sin_addr)), (void *)(&(in4)), sizeof(IN_ADDR) ); if(lp) { $? ". with local port" back = dk3socket_attempt_open_net_stream_for_local_address( AF_INET, (struct sockaddr *)(&soin4), sizeof(soin4), resl, secs, usecs, NULL, NULL ); } else { $? ". without local port" back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin4), sizeof(struct sockaddr_in), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { $? "! not connected" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } } else { $? ". inet_pton failed" } /* Test IPv6 address. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(INVALID_SOCKET == back) { resgai = dk3socket_inet_pton(AF_INET6,sh,(void *)(&in6),NULL,NULL); if(1 == resgai) { dk3mem_res((void *)(&soin6), sizeof(struct sockaddr_in6)); soin6.sin6_family = AF_INET6; soin6.sin6_port = htons(sp); dk3mem_cpy( (void *)(&(soin6.sin6_addr)), (void *)(&in6), sizeof(IN6_ADDR) ); if(lp) { back = dk3socket_attempt_open_net_stream_for_local_address( AF_INET6, (struct sockaddr *)(&soin6), sizeof(soin6), resl, secs, usecs, NULL, NULL ); } else { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } } } #endif /* Resolve host name. */ if(INVALID_SOCKET == back) { $? ". must resolve host name" sprintf(pbuf, "%u", (unsigned)sp); dk3mem_res((void *)(&hs), sizeof(struct addrinfo)); hs.ai_flags = AI_NUMERICSERV; hs.ai_family = AF_UNSPEC; /* Solaris man says: PF_UNSPEC */ hs.ai_socktype = SOCK_STREAM; hs.ai_protocol = 0; resgai = getaddrinfo(sh, pbuf, &hs, &ress); if((0 == resgai) && (ress)) { $? ". addresses found" back = dk3socket_attempt_open_net_stream_client( ress, ((lp) ? resl : NULL), secs, usecs, NULL, NULL ); } else { $? "! no address found" dk3socket_error_getaddrinfo(ec, app, resgai); } if(ress) { freeaddrinfo(ress); ress = NULL; } } } else { $? "! local addresses not found" } /* Release resources. */ if(resl) { freeaddrinfo(resl); resl = NULL; } } else { $? ". connect to localhost" /* Test IPv4 localhost */ back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip4addr_set_localhost(&soin4); soin4.sin_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&soin4), sizeof(soin4), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3socket_ip4addr_set_localhost(&soin4); soin4.sin_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin4), sizeof(soin4), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } /* Test IPv6 localhost */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(INVALID_SOCKET == back) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip6addr_set_localhost(&soin6); soin6.sin6_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&soin6), sizeof(soin6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } if(INVALID_SOCKET != back) { dk3socket_ip6addr_set_localhost(&soin6); soin6.sin6_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin6), sizeof(soin6), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } #endif } if(INVALID_SOCKET == back) { if(sh) { if(app) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 351, 352, sh); #else dk3app_log_i1(app, DK3_LL_ERROR, 282); #endif } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } } } } else { $? "! sp" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_open_net_stream_client %d", (int)back return back; } dk3_socket_set_t * dk3socket_listeners( unsigned short portno, int backlog, int fLocalOnly, int *ec, dk3_app_t *app ) { char pnb[32]; /* Port number buffer. */ struct addrinfo hi; /* Hints. */ struct addrinfo *ai; /* Result from getaddrinfo(). */ struct addrinfo *ap; /* Pointer to traverse ai. */ struct sockaddr *sa; /* Socket address in ap. */ dk3_socket_set_t *back = NULL; dk3_socket_t *sp; /* Pointer to current socket to init. */ size_t na; /* Number of addresses. */ dk3_socket_t so; /* Current socket to create. */ int res; /* Result from getaddrinfo(). */ if((portno) && (backlog > 0)) { dk3mem_res((void *)(&hi), sizeof(struct addrinfo)); sprintf(pnb, "%u", (unsigned)portno); hi.ai_family = AF_UNSPEC; hi.ai_socktype = SOCK_STREAM; hi.ai_flags = 0; hi.ai_protocol = 0; hi.ai_addrlen = 0; hi.ai_canonname = NULL; hi.ai_addr = NULL; hi.ai_next = NULL; if(!(fLocalOnly)) { hi.ai_flags = AI_PASSIVE; } hi.ai_flags |= AI_NUMERICSERV; ai = NULL; res = getaddrinfo(NULL, pnb, &hi, &ai); if(0 == res) { if(ai) { /* Find number of addresses. */ na = 0; ap = ai; while(ap) { na++; ap = ap->ai_next; } /* Allocate socket set. */ if(na > 0) { back = dk3socket_set_new(na, ec, app); } /* Create the listener sockets. */ if(back) { ap = ai; na = 0; sp = back->pData; while(ap) { $? ". attempting one address" sa = ap->ai_addr; $!trace-code dk3socket_report_address(sa); so = dk3socket_open(sa->sa_family, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != so) { (void)dk3socket_set_reuse(so, 1, ec, app); if(dk3socket_bind(so, sa, ap->ai_addrlen, NULL, NULL)) { if(dk3socket_listen(so, backlog, ec, app)) { *(sp++) = so; na++; dk3socket_report_listen_success(app, so, sa, ap->ai_addrlen); $!trace-code dk3socket_report_address(sa); } else { dk3socket_close(so, ec, app); } } else { dk3socket_close(so, ec, app); } } ap = ap->ai_next; } back->szUsed = na; } /* If no listener initialized, close socket set */ if(back) { if(!(na)) { dk3socket_set_close(back, ec, app); back = NULL; if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 364); } } } } else { /* ERROR: No addresses returned */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } } else { dk3socket_error_getaddrinfo(ec, app, res); } if(ai) { freeaddrinfo(ai); } } return back; } dk3_socket_set_t * dk3socket_datagram_sockets( unsigned short portno, int fLocalOnly, int *ec, dk3_app_t *app ) { char pnb[32]; /* Port number buffer. */ struct addrinfo hi; /* Hints. */ struct addrinfo *ai; /* Result from getaddrinfo(). */ struct addrinfo *ap; /* Pointer to traverse ai. */ struct sockaddr *sa; /* Socket address in ap. */ dk3_socket_set_t *back = NULL; dk3_socket_t *sp; /* Pointer to current socket to init. */ size_t na; /* Number of addresses. */ dk3_socket_t so; /* Current socket to create. */ int res; /* Result from getaddrinfo(). */ if(portno) { dk3mem_res((void *)(&hi), sizeof(struct addrinfo)); sprintf(pnb, "%u", (unsigned)portno); hi.ai_family = AF_UNSPEC; hi.ai_socktype = SOCK_STREAM; hi.ai_flags = 0; hi.ai_protocol = 0; hi.ai_addrlen = 0; hi.ai_canonname = NULL; hi.ai_addr = NULL; hi.ai_next = NULL; if(!(fLocalOnly)) { hi.ai_flags = AI_PASSIVE; } hi.ai_flags |= AI_NUMERICSERV; ai = NULL; res = getaddrinfo(NULL, pnb, &hi, &ai); if(0 == res) { if(ai) { /* Find number of addresses. */ na = 0; ap = ai; while(ap) { na++; ap = ap->ai_next; } /* Allocate socket set; */ if(na > 0) { back = dk3socket_set_new(na, ec, app); } /* Create the UDP sockets. */ if(back) { ap = ai; na = 0; sp = back->pData; while(ap) { sa = ap->ai_addr; so = dk3socket_open(sa->sa_family, SOCK_DGRAM, 0, ec, app); if(INVALID_SOCKET != so) { (void)dk3socket_set_reuse(so, 1, ec, app); if(dk3socket_bind(so, sa, ap->ai_addrlen, ec, app)) { *(sp++) = so; na++; } else { dk3socket_close(so, ec, app); } } ap = ap->ai_next; } } /* Close socket set if no socket created. */ if(back) { if(!(na)) { dk3socket_set_close(back, ec, app); back = NULL; } } } } else { dk3socket_error_getaddrinfo(ec, app, res); } if(ai) { freeaddrinfo(ai); } } return back; } /* Section end: getaddrinfo(). */ #else /* if DK3_HAVE_GETADDRINFO */ #if DK3_HAVE_GETHOSTBYNAME /* Section start: gethostbyname(). */ dk3_socket_t dk3socket_open_net_stream_client( char const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ) { #if DK3_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 sl6; /* Local IPv6 address. */ struct sockaddr_in6 sr6; /* Remote IPv6 address. */ IN6_ADDR in6; /* IPv6 address. */ #endif struct sockaddr_in sl4; /* Local IPv4 address. */ struct sockaddr_in sr4; /* Remote IPv4 address. */ IN_ADDR in4; /* IPv4 address. */ struct hostent *he; /* Result from gethostbyname(). */ char **addrptr; /* Address pointer. */ dk3_socket_t back = INVALID_SOCKET; int resgai; /* Result from getaddrinfo(). */ int connres; /* Result from bind()/connect(). */ int err; /* Error code from gethostbyname(). */ $? "+ dk3socket_open_net_stream_client %s %u (gethostbyname)", TR_STR(sh), (unsigned)sp if(sp) { if(sh) { $? ". remote host" /* Attempt IPv4 address. */ resgai = dk3socket_inet_pton(AF_INET, sh, &in4, NULL, NULL); if(1 == resgai) { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sl4), sizeof(struct sockaddr_in)); sl4.sin_family = AF_INET; sl4.sin_port = htons(lp); sl4.sin_addr.s_addr = INADDR_ANY; connres = dk3socket_bind( back, (struct sockaddr *)(&sl4), sizeof(sl4), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_res((void *)(&sr4), sizeof(sr4)); sr4.sin_family = AF_INET; sr4.sin_port = htons(sp); dk3mem_cpy( (void *)(&(sr4.sin_addr)), (void *)(&in4), sizeof(IN_ADDR) ); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr4), sizeof(sr4), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } /* Attempt IPv6 address. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(INVALID_SOCKET == back) { resgai = dk3socket_inet_pton(AF_INET6, sh, &in6, NULL, NULL); if(1 == resgai) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sl6), sizeof(struct sockaddr_in6)); sl6.sin6_family = AF_INET6; sl6.sin6_port = htons(lp); dk3mem_cpy( (void *)(&(sl6.sin6_addr)), (void *)(&dk3socket_ia6_addr_any), sizeof(IN6_ADDR) ); connres = dk3socket_bind( back, (struct sockaddr *)(&sl6), sizeof(struct sockaddr_in6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_res((void *)(&sr6), sizeof(struct sockaddr_in6)); sr6.sin6_family = AF_INET6; sr6.sin6_port = htons(sp); dk3mem_cpy( (void *)(&(sr6.sin6_addr)), (void *)(&in6), sizeof(IN6_ADDR) ); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } } #endif /* Host name resolution. */ if(INVALID_SOCKET == back) { he = gethostbyname(sh); if(he) { $? ". gethostbyname" if(AF_INET == he->h_addrtype) { if(4 == he->h_length) { if(he->h_addr_list) { addrptr = he->h_addr_list; while((INVALID_SOCKET == back) && (*addrptr)) { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sl4), sizeof(struct sockaddr_in)); sl4.sin_family = AF_INET; sl4.sin_port = htons(lp); sl4.sin_addr.s_addr = INADDR_ANY; connres = dk3socket_bind( back, (struct sockaddr *)(&sl4), sizeof(struct sockaddr_in), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_res((void *)(&sr4), sizeof(struct sockaddr_in)); sr4.sin_family = AF_INET; sr4.sin_port = htons(sp); dk3mem_cpy( (void *)(&(sr4.sin_addr)), (void *)(*addrptr), sizeof(IN_ADDR) ); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr4), sizeof(struct sockaddr_in), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } addrptr++; } } else { /* ERROR: No address list! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } } else { /* ERROR: Wrong address length */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } } else { #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(AF_INET6 == he->h_addrtype) { if(16 == he->h_length) { if(he->h_addr_list) { addrptr = he->h_addr_list; while((INVALID_SOCKET == back) && (*addrptr)) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sl6), sizeof(struct sockaddr_in6)); sl6.sin6_family = AF_INET6; sl6.sin6_port = htons(lp); dk3mem_cpy( (void *)(&(sl6.sin6_addr)), (void *)(&dk3socket_ia6_addr_any), sizeof(IN6_ADDR) ); connres = dk3socket_bind( back, (struct sockaddr *)(&sl6), sizeof(struct sockaddr_in6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_res((void *)(&sr6), sizeof(struct sockaddr_in6)); sr6.sin6_family = AF_INET6; sr6.sin6_port = htons(sp); dk3mem_cpy( (void *)(&(sr6.sin6_addr)), (void *)(*addrptr), sizeof(IN6_ADDR) ); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } addrptr++; } } else { /* ERROR: No address list! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } } else { /* ERROR: Illegal length! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } } else { } #endif } } else { /* ERROR: Host not found! */ err = dk3socket_error(h_errno); dk3socket_error_gethostbyname(ec, app, err, sh); } } } else { $? ". local host" /* Test IPv4 localhost */ back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip4addr_set_localhost(&sl4); sl4.sin_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&sl4), sizeof(struct sockaddr_in), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3socket_ip4addr_set_localhost(&sr4); sr4.sin_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr4), sizeof(sr4), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } /* Test IPv6 localhost */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(INVALID_SOCKET == back) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip6addr_set_localhost(&sl6); sl6.sin6_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&sl6), sizeof(struct sockaddr_in6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3socket_ip6addr_set_localhost(&sr6); sr6.sin6_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } #endif } if(INVALID_SOCKET == back) { if(sh) { if(app) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 351, 352, sh); #else dk3app_log_i1(app, DK3_LL_ERROR, 282); #endif } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_open_net_stream_client %d", back return back; } /* Section end: gethostbyname(). */ #else /* if DK3_HAVE_GETHOSTBYNAME */ /* Section start: No getaddrinfo(), no gethostbyname(). */ dk3_socket_t dk3socket_open_net_stream_client( char const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ) { #if DK3_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 sr6; /* Remote IPv6 address. */ struct sockaddr_in6 sl6; /* Local IPv6 address. */ IN6_ADDR in6; /* IPv6 address. */ #endif struct sockaddr_in srem; /* Remote IPv4 address. */ struct sockaddr_in sloc; /* Local IPv4 address. */ IN_ADDR in4; /* IPv4 address. */ dk3_socket_t back = INVALID_SOCKET; int connres; /* Result from bind()/connect(). */ $? "+ dk3socket_open_net_stream_client %s %u (no resolv)", TR_STR(sh), (unsigned)sp if(sp) { if(sh) { $? ". remote host connection" dk3mem_res((void *)(&srem), sizeof(struct sockaddr_in)); dk3mem_res((void *)(&in4), sizeof(IN_ADDR)); if(dk3socket_inet_pton(AF_INET, sh, (void *)(&in4), NULL, NULL)) { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sloc), sizeof(struct sockaddr_in)); sloc.sin_addr.s_addr = INADDR_ANY; sloc.sin_family = AF_INET; sloc.sin_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr const *)(&sloc), sizeof(struct sockaddr_in), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_res((void *)(&srem), sizeof(struct sockaddr_in)); dk3mem_cpy((void *)(&(srem.sin_addr)), (void *)(&in4), sizeof(IN_ADDR)); srem.sin_family = AF_INET; srem.sin_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&srem), sizeof(struct sockaddr_in), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } else { #if DK3_HAVE_STRUCT_SOCKADDR_IN6 dk3mem_res((void *)(&sr6), sizeof(struct sockaddr_in6)); dk3mem_res((void *)(&in6), sizeof(IN6_ADDR)); if(dk3socket_inet_pton(AF_INET6, sh, (void *)(&in6), NULL, NULL)) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3mem_res((void *)(&sl6), sizeof(struct sockaddr_in6)); dk3mem_cpy( (void *)(&(sl6.sin6_addr)), (void *)(&dk3socket_ia6_addr_any), sizeof(IN6_ADDR) ); sl6.sin6_family = AF_INET6; sl6.sin6_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&sl6), sizeof(struct sockaddr_in6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3mem_cpy( (void *)(&(sr6.sin6_addr)), (void *)(&in6), sizeof(IN6_ADDR) ); sr6.sin6_family = AF_INET6; sr6.sin6_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } else { /* ERROR: No an IPv6 address! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } } #else /* ERROR: Not an IPv4 address! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 286); } #endif } } else { $? ". locahost connection" back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if((lp) && (INVALID_SOCKET != back)) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip4addr_set_localhost(&srem); srem.sin_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr const *)(&srem), sizeof(struct sockaddr_in), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } if(INVALID_SOCKET != back) { dk3socket_ip4addr_set_localhost(&srem); srem.sin_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&srem), sizeof(struct sockaddr_in), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(INVALID_SOCKET == back) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if((lp) && (INVALID_SOCKET != back)) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip6addr_set_localhost(&sr6); sr6.sin6_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr const *)(&sr6), sizeof(struct sockaddr_in6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } if(INVALID_SOCKET != back) { dk3socket_ip6addr_set_localhost(&sr6); sr6.sin6_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&sr6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL, #if DK3_CHAR_SIZE == 1 sh, #else NULL, #endif 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } #endif } if(INVALID_SOCKET == back) { if(sh) { if(app) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 351, 352, sh); #else dk3app_log_i1(app, DK3_LL_ERROR, 282); #endif } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } } } } else { /* ERROR: No remote port! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_open_net_stream_client %d", (int)back return back; } /* Section end: No getaddrinfo(), no gethostbyname(). */ #endif /* if DK3_HAVE_GETHOSTBYNAME */ dk3_socket_set_t * dk3socket_listeners( unsigned short portno, int backlog, int fLocalOnly, int *ec, dk3_app_t *app ) { struct sockaddr_in ip4; /* Local IPv4 address. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 ip6; /* Local IPv6 address. */ #endif dk3_socket_t *sp; /* Pointer to current socket to init. */ dk3_socket_set_t *back = NULL; size_t szmax; /* Number of sockets in set. */ size_t na; /* Number of used sockets in set. */ dk3_socket_t so; /* Socket to create. */ $? "+ dk3socket_listeners port=%u backlog=%d local=%d", (unsigned)portno, backlog, fLocalOnly if((portno) && (portno > 0)) { szmax = 1; #if DK3_HAVE_STRUCT_SOCKADDR_IN6 szmax = 2; #endif back = dk3socket_set_new(szmax, ec, app); if(back) { sp = back->pData; na = 0; /* Attempt to bind IPv4 address. */ dk3mem_res((void *)(&ip4), sizeof(struct sockaddr_in)); if(fLocalOnly) { dk3socket_ip4addr_set_localhost(&ip4); } else { ip4.sin_family = AF_INET; ip4.sin_addr.s_addr = INADDR_ANY; } ip4.sin_port = htons(portno); so = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != so) { if(dk3socket_bind( so, (struct sockaddr *)(&ip4), sizeof(struct sockaddr_in), ec, app ) ) { if(dk3socket_listen(so, backlog, ec, app)) { *(sp++) = so; na++; dk3socket_report_listen_success( app, so, &ip4, sizeof(struct sockaddr_in) ); } else { dk3socket_close(so, ec, app); } } else { dk3socket_close(so, ec, app); } } #if DK3_HAVE_STRUCT_SOCKADDR_IN6 /* Attempt bo bind IPv6 address. */ dk3mem_res((void *)(&ip6), sizeof(struct sockaddr_in6)); if(fLocalOnly) { dk3socket_ip6addr_set_localhost(&ip6); } else { ip6.sin6_family = AF_INET6; dk3mem_cpy( (void *)(&(ip6.sin6_addr)), (void *)(&dk3socket_ia6_addr_any), sizeof(IN6_ADDR) ); } ip6.sin6_port = htons(portno); so = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != so) { if(dk3socket_bind( so, (struct sockaddr *)(&ip6), sizeof(struct sockaddr_in6), ec, app ) ) { if(dk3socket_listen(so, backlog, ec, app)) { *(sp++) = so; na++; dk3socket_report_listen_success( app, so, &ip6, sizeof(struct sockaddr_in6) ); } else { dk3socket_close(so, ec, app); } } else { dk3socket_close(so, ec, app); } } #endif /* If no address was bound, close the set. */ if(na) { back->szUsed = na; } else { dk3socket_set_close(back, ec, app); back = NULL; } $? ". na = %u", (unsigned)na } } $? "- dk3socket_listeners %s", TR_PTR(back) return back; } dk3_socket_set_t * dk3socket_datagram_sockets( unsigned short portno, int fLocalOnly, int *ec, dk3_app_t *app ) { struct sockaddr_in ip4; /* Local IPv4 address. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 ip6; /* Local IPv6 address. */ #endif dk3_socket_t *sp; /* Pointer to current socket to init. */ dk3_socket_set_t *back = NULL; size_t szmax; /* Number of sockets in set. */ size_t na; /* Number of used sockets in set. */ dk3_socket_t so; /* Socket to create. */ if(portno) { szmax = 1; #if DK3_HAVE_STRUCT_SOCKADDR_IN6 szmax = 2; #endif back = dk3socket_set_new(szmax, ec, app); if(back) { sp = back->pData; na = 0; /* Attempt to bind IPv4 address. */ dk3mem_res((void *)(&ip4), sizeof(struct sockaddr_in)); if(fLocalOnly) { dk3socket_ip4addr_set_localhost(&ip4); } else { ip4.sin_family = AF_INET; ip4.sin_addr.s_addr = INADDR_ANY; } ip4.sin_port = htons(portno); so = dk3socket_open(AF_INET, SOCK_DGRAM, 0, ec, app); if(INVALID_SOCKET != so) { if(dk3socket_bind( so, (struct sockaddr *)(&ip4), sizeof(struct sockaddr_in), ec, app ) ) { *(sp++) = so; na++; } else { dk3socket_close(so, ec, app); } } #if DK3_HAVE_STRUCT_SOCKADDR_IN6 /* Attempt bo bind IPv6 address. */ dk3mem_res((void *)(&ip6), sizeof(struct sockaddr_in6)); if(fLocalOnly) { dk3socket_ip6addr_set_localhost(&ip6); } else { ip6.sin6_family = AF_INET6; dk3mem_cpy( (void *)(&(ip6.sin6_addr)), (void *)(&dk3socket_ia6_addr_any), sizeof(IN6_ADDR) ); } ip6.sin6_port = htons(portno); so = dk3socket_open(AF_INET6, SOCK_DGRAM, 0, ec, app); if(INVALID_SOCKET != so) { if(dk3socket_bind( so, (struct sockaddr *)(&ip6), sizeof(struct sockaddr_in6), ec, app ) ) { *(sp++) = so; na++; } else { dk3socket_close(so, ec, app); } } #endif /* If no address was bound, close the set. */ if(na) { back->szUsed = na; } else { dk3socket_set_close(back, ec, app); back = NULL; } $? ". na = %u", (unsigned)na } } return back; } #endif /* if DK3_HAVE_GETADDRINFO */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 /** Bit patterns for use in dk3socket_ip6_fill_bits. */ static unsigned char const dk3socket_bits_in_byte[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /** Fill address bits in an IPv6 address beginning from MSB. This function is used to build a netmask. @param ap Address structure to modify. @param bits Number of bits to set. */ void dk3socket_ip6_fill_bits(IN6_ADDR *ap, unsigned bits) { int i; /* Current byte to process. */ int j; /* Current bit index. */ unsigned b; /* Number of bits still to process. */ $? "+ dk3socket_ip6_fill_bits %u", bits if(ap) { for(i = 0; i < 16; i++) { ap->s6_addr[i] = 0x00; } b = bits; if(b > 128) b = 128; i = 0; j = 0; while(b--) { ap->s6_addr[i] |= dk3socket_bits_in_byte[j]; j++; if(8 <= j) { j = 0; i++; } } } $? "- dk3socket_ip6_fill_bits" } #endif /** Fill address bits in an IPv4 address beginning from MSB. This function is used to build a netmask. @param ap Address structure to modify. @param bitno Number of bits to set. */ void dk3socket_ip4_fill_bits(IN_ADDR *ap, unsigned bitno) { $? "+ dk3socket_ip4_fill_bits %u", bitno if(ap) { unsigned long bits; unsigned long back; unsigned b; back = 0UL; bits = 0x80000000UL; b = bitno; if(b > 32) b = 32; while(b--) { back |= bits; bits = (bits >> 1); } ap->s_addr = htonl(back); $? ". back = %lx", back } $? "- dk3socket_ip4_fill_bits" } /** Set netmask part of allowed peer. @param dp Destination pointer (allowed peer). @param src Source text containing the network mask. @param app Application structure for diagnostics. @param is6 Flag: We are searching for IPv6 address. @return 1 on success, 0 on error. */ static int dknet_allowed_mask(dk3_peer_allowed_t *dp, char *src, dk3_app_t *app, int is6) { #if DK3_HAVE_STRUCT_SOCKADDR_IN6 IN6_ADDR ip6mask; /* IPv6 net mask. */ #endif IN_ADDR ip4mask; /* IPv4 net mask. */ unsigned u; /* Number of bits to set. */ int res; /* Operation result. */ int back = 0; #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(is6) { if(src) { if(dk3str_c8_chr(src, ':')) { res = dk3socket_inet_pton(AF_INET6,src,(void *)(&ip6mask),NULL,NULL); if(res) { back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 356); } } } else { if(sscanf(src, "%u", &u) == 1) { back = 1; dk3socket_ip6_fill_bits(&ip6mask, u); } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 355); } } } } else { back = 1; dk3socket_ip6_fill_bits(&((dp->d).ip6.ma), 128); } if(back) { dk3mem_cpy( (void *)(&((dp->d).ip6.ma)), (void *)(&ip6mask), sizeof(IN6_ADDR) ); } } else { #endif if(src) { if(dk3str_c8_chr(src, '.')) { res = dk3socket_inet_pton(AF_INET, src, (void *)(&ip4mask), NULL, NULL); if(res) { back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 354); } } } else { if(sscanf(src, "%u", &u) == 1) { back = 1; dk3socket_ip4_fill_bits(&ip4mask, u); } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 355); } } } } else { back = 1; ip4mask.s_addr = 0xFFFFFFFFUL; } if(back) { dk3mem_cpy( (void *)(&((dp->d).ip4.ma)), (void *)(&ip4mask), sizeof(IN_ADDR) ); } #if DK3_HAVE_STRUCT_SOCKADDR_IN6 } #endif return back; } int dk3socket_set_peer( dk3_peer_allowed_t *dp, char const *sr, int *ec, dk3_app_t *app ) { char bu[DK3_MAX_PATH]; /* Private copy of hostname. */ #if DK3_HAVE_GETADDRINFO struct addrinfo hints; /* Hints set. */ struct addrinfo *rgai; /* Result from getaddrinfo(). */ struct addrinfo *pai; /* Current address to check. */ #else #if DK3_HAVE_GETHOSTBYNAME struct hostent *heptr; /* Result from gethostbyname(). */ #endif #endif #if DK3_HAVE_STRUCT_SOCKADDR_IN6 IN6_ADDR ip6addr; /* IPv6 address. */ struct sockaddr_in6 *soin6; /* Socket address. */ #endif IN_ADDR ip4addr; /* IPv4 address. */ #if !(DK3_ON_WINDOWS || DK3_HAVE_GETADDRINFO) #if DK3_HAVE_GETHOSTBYNAME && DK3_HAVE_STRUCT_SOCKADDR_IN6 unsigned long *ulptr; /* Pointer to address. */ char **addrptr; /* Address pointer. */ #endif #endif struct sockaddr_in *soin; /* Socket address. */ char *maptr; /* Pointer to beginning of mask. */ #if 0 unsigned u; /* Number of bits in netmask. */ #endif int back = 0; int res; /* Result from inet_ntop(). */ int found; /* Flag: Host found. */ #if !(DK3_ON_WINDOWS || DK3_HAVE_GETADDRINFO) #if DK3_HAVE_GETHOSTBYNAME int err; /* Error code from gethostbyname() .*/ #endif #endif $? "+ dk3socket_set_peer \"%s\"", TR_STR(sr) if((dp) && (sr)) { $? ". args ok" found = 0; if(dk3str_c8_len(sr) < sizeof(bu)) { $? ". length" dk3str_c8_cpy_not_overlapped(bu, sr); maptr = dk3str_c8_chr(bu, '/'); if(maptr) { $? ". netmask part found" *(maptr++) = '\0'; maptr = dk3str_c8_start(maptr, NULL); } res = dk3socket_inet_pton(AF_INET, bu, (void *)(&ip4addr), NULL, NULL); if(res) { $? ". IPv4 address" found = 1; /* HAVE IPv4 address */ dp->wh = 0; dk3mem_cpy( (void *)(&((dp->d).ip4.ad)), (void *)(&ip4addr), sizeof(IN_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 0); } else { $? ". not an IPv4 address" #if DK3_HAVE_STRUCT_SOCKADDR_IN6 res = dk3socket_inet_pton(AF_INET6, bu, (void *)(&ip6addr), NULL, NULL); if(res) { $? ". IPv6 address" found = 1; dp->wh = 1; dk3mem_cpy( (void *)(&((dp->d).ip6.ad)), (void *)(&ip6addr), sizeof(IN6_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 1); } else { $? ". not an IPv6 address" } #endif } if(!(found)) { $? ". no address found yet" #if DK3_ON_WINDOWS || DK3_HAVE_GETADDRINFO $? ". use getaddrinfo" rgai = NULL; dk3mem_res((void *)(&hints), sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; res = getaddrinfo(bu, NULL, &hints, &rgai); if(0 == res) { $? ". getaddrinfo" if(rgai) { pai = rgai; while((0 == back) && (pai)) { $? ". one address found" if(AF_INET == pai->ai_family) { if(sizeof(struct sockaddr_in) == pai->ai_addrlen) { if(pai->ai_addr) { found = 1; dp->wh = 0; soin = (struct sockaddr_in *)(pai->ai_addr); dk3mem_cpy( (void *)(&((dp->d).ip4.ad)), (void *)(&(soin->sin_addr)), sizeof(IN_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 0); } } } else { $? ". not IPv4" #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(AF_INET6 == pai->ai_family) { $? ". IPv6" if(sizeof(struct sockaddr_in6) == pai->ai_addrlen) { $? ". address size ok" if(pai->ai_addr) { $? ". address" found = 1; dp->wh = 1; soin6 = (struct sockaddr_in6 *)(pai->ai_addr); dk3mem_cpy( (void *)(&((dp->d).ip6.ad)), (void *)(&(soin6->sin6_addr)), sizeof(IN6_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 1); } else { $? "! no address" } } else { $? "! wrong address size" } } else { $? "! any other address type" } #endif } pai = pai->ai_next; } } } else { $? "! getaddrinfo" dk3socket_error_getaddrinfo(ec, app, res); } if(rgai) { freeaddrinfo(rgai); } #else #if DK3_HAVE_GETHOSTBYNAME $? ". use gethostbyname" heptr = gethostbyname(bu); if(heptr) { if(AF_INET == heptr->h_addrtype) { $? ". IPv4" if(4 == heptr->h_length) { $? ". h_length" if(heptr->h_addr_list) { $? ". h_addr_list" addrptr = heptr->h_addr_list; ulptr = (unsigned long *)(*addrptr); if(ulptr) { dp->wh = 0; dk3mem_cpy( (void *)(&((dp->d).ip4.ad)), (void *)(ulptr), sizeof(IN_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 0); } } else { $? "! h_addr_list" } } else { $? "! h_length" } } else { $? ". not IPv4" #if DK3_HAVE_STRUCT_SOCKADDR_IN6 if(AF_INET6 == heptr->h_addrtype) { if(16 == heptr->h_length) { $? ". h_length" if(heptr->h_addr_list) { $? ". h_addr_list" addrptr = heptr->h_addr_list; ulptr = (unsigned long *)(*addrptr); if(ulptr) { $? ". ulptr" dp->wh = 0; dk3mem_cpy( (void *)(&((dp->d).ip6.ad)), (void *)(ulptr), sizeof(IN6_ADDR) ); back = dknet_allowed_mask(dp, maptr, app, 1); } else { $? "! ulptr" } } else { $? "! h_addr_list" } } else { $? "! h_length" } } #endif } } else { $? "! gethostbyname" err = dk3socket_error(h_errno); dk3socket_error_gethostbyname(ec, app, err, bu); } #else $? "! not getaddrinfo or gethostbyname function" /* ERROR: Host not an IP address, no address resolution */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 357); } #endif #endif } } else { $? "! length" /* ERROR: Source text too long! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 108); } } } else { $? "! args" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_set_peer %d", back return back; } int dk3socket_compare_peer(void const *l, void const *r, int cr) { char adbl[16]; char adbr[16]; dk3_peer_allowed_t const *pl; dk3_peer_allowed_t const *pr; struct sockaddr const *so; struct sockaddr_in const *soin; #if DK3_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 const *soin6; #endif unsigned long ull; unsigned long ulr; size_t i; int back = 0; if(l) { if(r) { pl = (dk3_peer_allowed_t const *)l; switch(cr) { case 1: { /* Compare address families. */ so = (struct sockaddr const *)r; switch(so->sa_family) { case AF_INET: { if(pl->wh) { back = 1; } } break; #if DK3_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6: { if(!(pl->wh)) { back = -1; } } break; #endif default: { back = -1; } break; } /* For matching address families compare addresses. */ if(0 == back) { if(pl->wh) { /* Compare IPv6. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 soin6 = (struct sockaddr_in6 const *)r; for(i = 0; i < 16; i++) { adbl[i] = ((pl->d).ip6.ad.s6_addr[i]) & ((pl->d).ip6.ma.s6_addr[i]); adbr[i] = ((soin6->sin6_addr).s6_addr[i]) & ((pl->d).ip6.ma.s6_addr[i]); } back = dk3mem_cmp((void *)adbl, (void *)adbr, 16); if(back < -1) back = -1; if(back > 1) back = 1; #endif } else { /* Compare IPv4. */ soin = (struct sockaddr_in const *)r; ull = ((pl->d).ip4.ad.s_addr) & ((pl->d).ip4.ma.s_addr); ulr = ((soin->sin_addr).s_addr) & ((pl->d).ip4.ma.s_addr); if(ull < ulr) { back = -1; } else { if(ull > ulr) { back = 1; } } } } } break; default: { pr = (dk3_peer_allowed_t const *)r; if(pl->wh > pr->wh) { back = 1; } else { if(pl->wh < pr->wh) { back = -1; } } if(0 == back) { switch(pl->wh) { case 1: { /* Compare IPv6 addresses. */ #if DK3_HAVE_STRUCT_SOCKADDR_IN6 back = dk3mem_cmp( (void *)(&((pl->d).ip6.ad)), (void *)(&((pr->d).ip6.ad)), sizeof(IN6_ADDR) ); if(back < -1) back = -1; if(back > 1) back = 1; #endif } break; default: { /* Compare IPv4 addresses. */ if((pl->d).ip4.ad.s_addr > (pr->d).ip4.ad.s_addr) { back = 1; } else { if((pl->d).ip4.ad.s_addr < (pr->d).ip4.ad.s_addr) { back = -1; } } } break; } } } break; } } else back = 1; } else { if(r) back = -1; } return back; } #if (DK3_CHAR_SIZE == 2) && DK3_ON_WINDOWS static dk3_socket_t dk3socket_dkchar_attempt_open_net_stream_for_local_address( int af, struct sockaddr const *pAddr, size_t szAddr, ADDRINFOW const *resl, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *hn ) { dk3_socket_t back = INVALID_SOCKET; ADDRINFOW const *resc; /* Current address. */ struct sockaddr *soa; /* Socket address. */ int found; /* Flag: Matching address found. */ int connres; /* Result from bind() and connect(). */ found = 0; resc = resl; while((resc) && (INVALID_SOCKET == back)) { soa = resc->ai_addr; if(soa) { if(soa->sa_family == af) { switch(af) { case AF_INET: case AF_INET6: { switch(soa->sa_family) { case AF_INET6: { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); } break; default: { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); } break; } if(INVALID_SOCKET != back) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); connres = dk3socket_bind( back, soa, resc->ai_addrlen, ec, app ); if(connres) { connres = dk3socket_connect_nb( back, pAddr, szAddr, secs, usecs, ec, app, hn, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! bind" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! socket" } } break; default: { $? "! unknown family" } break; } } else { $? "! family != af" } } else { $? "! soa" } resc = resc->ai_next; } return back; } /** Attempt to open a client socket. @param hai Server host address information. @param lai Client (local) host address information, may be NULL. @param secs Timeout seconds. @param usecs Timeout microseconds. @param ec Pointer to error code variable, may be NULL. @param app Application structure for diagnostics, may be NULL. @param sh Server host name. @return Valid socket on success, INVALID_SOCKET on error. */ static dk3_socket_t dk3socket_dkchar_attempt_open_net_stream_client( ADDRINFOW const *hai, ADDRINFOW const *lai, long secs, long usecs, int *ec, dk3_app_t *app, dkChar const *sh ) { ADDRINFOW const *resc; ADDRINFOW const *resl; struct sockaddr *soa; struct sockaddr *sol; dk3_socket_t back = INVALID_SOCKET; int found; int connres; $? "+ dk3socket_dkchar_attempt_open_net_stream_client" found = 0; resc = hai; while((resc) && (INVALID_SOCKET == back)) { $? ". loop start (have remote)" soa = resc->ai_addr; if(soa) { $? ". soa" if(lai) { resl = lai; while((resl) && (INVALID_SOCKET == back)) { sol = resl->ai_addr; if(sol) { if(soa->sa_family == sol->sa_family) { switch(soa->sa_family) { case AF_INET: case AF_INET6: { found = 1; switch(soa->sa_family) { case AF_INET6: { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); } break; default: { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); } break; } if(INVALID_SOCKET != back) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); connres = dk3socket_bind( back, sol, resl->ai_addrlen, ec, app ); if(connres) { connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, sh, 0 ); if(!(connres)) { $? "! connect" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! bind" dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! socket" } } break; default: { $? "! unknown family" } break; } } else { $? ". families dont match" } } else { $? "! sol" } resl = resl->ai_next; } } else { $? "No local addresses" switch(soa->sa_family) { case AF_INET: { found = 1; back = dk3socket_open(AF_INET, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, sh, 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } break; case AF_INET6: { found = 1; back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, ec, app); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, soa, resc->ai_addrlen, secs, usecs, ec, app, sh, 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } break; default: { } break; } } } else { $? "! soa" } resc = resc->ai_next; } $? "- dk3socket_dkchar_attempt_open_net_stream_client %d", (int)back return back; } /** Set netmask part of allowed peer. @param dp Destination pointer (allowed peer). @param src Source text containing the network mask. @param app Application structure for diagnostics. @param is6 Flag: We are searching for IPv6 address. @return 1 on success, 0 on error. */ static int dknet_dkchar_allowed_mask( dk3_peer_allowed_t *dp, dkChar *src, dk3_app_t *app, int is6 ) { IN6_ADDR ip6mask; /* IPv6 net mask. */ IN_ADDR ip4mask; /* IPv4 net mask. */ unsigned u; /* Number of bits to set. */ int res; /* Operation result. */ int back = 0; if(is6) { if(src) { if(dk3str_chr(src, dkT(':'))) { res = dk3socket_dkchar_inet_pton( AF_INET6, src, (void *)(&ip6mask), NULL, NULL ); if(res) { back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 356); } } } else { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(src, dkT("%u"), &u) == 1) #else if(dk3ma_ui_from_string(&u, src, NULL)) #endif { back = 1; dk3socket_ip6_fill_bits(&ip6mask, u); } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 355); } } } } else { back = 1; dk3socket_ip6_fill_bits(&((dp->d).ip6.ma), 128); } if(back) { dk3mem_cpy( (void *)(&((dp->d).ip6.ma)), (void *)(&ip6mask), sizeof(IN6_ADDR) ); } } else { if(src) { if(dk3str_chr(src, dkT('.'))) { res = dk3socket_dkchar_inet_pton( AF_INET, src, (void *)(&ip4mask), NULL, NULL ); if(res) { back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 354); } } } else { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(src, dkT("%u"), &u) == 1) #else if(dk3ma_ui_from_string(&u, src, NULL)) #endif { back = 1; dk3socket_ip4_fill_bits(&ip4mask, u); } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 355); } } } } else { back = 1; ip4mask.s_addr = 0xFFFFFFFFUL; } if(back) { dk3mem_cpy( (void *)(&((dp->d).ip4.ma)), (void *)(&ip4mask), sizeof(IN_ADDR) ); } } return back; } #endif dk3_socket_t dk3socket_dkchar_open_net_stream_client( dkChar const *sh, unsigned short sp, unsigned short lp, long secs, long usecs, int *ec, dk3_app_t *app ) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "No support for wide char socket functions!" #else #if DK3_ON_WINDOWS dkChar lbuf[64]; /* Server port text. */ dkChar pbuf[64]; /* Local port text. */ IN6_ADDR in6; /* IPv6 address. */ IN_ADDR in4; /* IPv4 address. */ dk3_socket_t back = INVALID_SOCKET; ADDRINFOW hs; ADDRINFOW hl; ADDRINFOW *ress = NULL; ADDRINFOW *resl = NULL; struct sockaddr_in soin4; struct sockaddr_in6 soin6; int resgai; int connres; $? "+ dk3socket_dkchar_open_net_stream_client" if(sp) { if(sh) { $? ". remote" ress = NULL; resl = NULL; resgai = 0; if(lp) { $? ". specific local p" #if VERSION_BEFORE_20140716 dk3sf_sprintf3(lbuf, dkT("%u"), (unsigned)lp); dk3mem_res((void *)(&hl), sizeof(ADDRINFOW)); hl.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hl.ai_family = AF_UNSPEC; hl.ai_socktype = SOCK_STREAM; hl.ai_protocol = 0; resgai = GetAddrInfoW(NULL, lbuf, &hl, &resl); #else if (dk3ma_um_to_string(lbuf, DK3_SIZEOF(lbuf,dkChar), (dk3_um_t)lp)) { dk3mem_res((void *)(&hl), sizeof(ADDRINFOW)); hl.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hl.ai_family = AF_UNSPEC; hl.ai_socktype = SOCK_STREAM; hl.ai_protocol = 0; resgai = GetAddrInfoW(NULL, lbuf, &hl, &resl); } #endif } if(((0 == resgai) && (resl)) || (0 == lp)) { resgai = dk3socket_dkchar_inet_pton( AF_INET, sh, (void *)(&in4), NULL, NULL ); if(1 == resgai) { dk3mem_res((void *)(&soin4), sizeof(struct sockaddr_in)); soin4.sin_family = AF_INET; soin4.sin_port = htons(sp); dk3mem_cpy( (void *)(&(soin4.sin_addr)), (void *)(&(in4)), sizeof(IN_ADDR) ); if(lp) { back = dk3socket_dkchar_attempt_open_net_stream_for_local_address( AF_INET, (struct sockaddr *)(&soin4), sizeof(soin4), resl, secs, usecs, NULL, NULL, sh ); } else { back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin4), sizeof(struct sockaddr_in), secs, usecs, NULL, NULL, sh, 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } else { $? "! socket" } } } else { $? ". inet_pton failed" } if(INVALID_SOCKET == back) { $? ". IPv6 attempt" resgai = dk3socket_dkchar_inet_pton( AF_INET6, sh, (void *)(&in6), NULL, NULL ); if(1 == resgai) { dk3mem_res((void *)(&soin6), sizeof(struct sockaddr_in6)); soin6.sin6_family = AF_INET6; soin6.sin6_port = htons(sp); dk3mem_cpy( (void *)(&(soin6.sin6_addr)), (void *)(&in6), sizeof(IN6_ADDR) ); if(lp) { back = dk3socket_dkchar_attempt_open_net_stream_for_local_address( AF_INET6, (struct sockaddr *)(&soin6), sizeof(soin6), resl, secs, usecs, NULL, NULL, sh ); } else { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin6), sizeof(struct sockaddr_in6), secs, usecs, NULL, NULL, sh,0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } } } if(INVALID_SOCKET == back) { $? ". name resolution" #if VERSION_BEFORE_20140716 dk3sf_sprintf3(pbuf, dkT("%u"), (unsigned)sp); dk3mem_res((void *)(&hs), sizeof(struct addrinfo)); hs.ai_flags = AI_NUMERICSERV; hs.ai_family = AF_UNSPEC; hs.ai_socktype = SOCK_STREAM; hs.ai_protocol = 0; resgai = GetAddrInfoW(sh, pbuf, &hs, &ress); if((0 == resgai) && (ress)) { $? ". addresses found" back = dk3socket_dkchar_attempt_open_net_stream_client( ress, ((lp) ? (resl) : NULL), secs, usecs, NULL, NULL, sh ); } else { $? "! GetAddrInfoW" dk3socket_error_getaddrinfo(ec, app, resgai); } if(ress) { FreeAddrInfoW(ress); ress = NULL; } #else if (dk3ma_um_to_string(pbuf, DK3_SIZEOF(pbuf,dkChar), (dk3_um_t)sp)) { dk3sf_sprintf3(pbuf, dkT("%u"), (unsigned)sp); dk3mem_res((void *)(&hs), sizeof(struct addrinfo)); hs.ai_flags = AI_NUMERICSERV; hs.ai_family = AF_UNSPEC; hs.ai_socktype = SOCK_STREAM; hs.ai_protocol = 0; resgai = GetAddrInfoW(sh, pbuf, &hs, &ress); if((0 == resgai) && (ress)) { $? ". addresses found" back = dk3socket_dkchar_attempt_open_net_stream_client( ress, ((lp) ? (resl) : NULL), secs, usecs, NULL, NULL, sh ); } else { $? "! GetAddrInfoW" dk3socket_error_getaddrinfo(ec, app, resgai); } if(ress) { FreeAddrInfoW(ress); ress = NULL; } } #endif } } else { /* ERROR: No local addresses found */ } if(resl) { FreeAddrInfoW(resl); resl = NULL; } } else { $? ". local" back = dk3socket_open(AF_INET, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { if(lp) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip4addr_set_localhost(&soin4); soin4.sin_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&soin4), sizeof(soin4), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } if(INVALID_SOCKET != back) { dk3socket_ip4addr_set_localhost(&soin4); soin4.sin_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin4), sizeof(soin4), secs, usecs, NULL, NULL, sh, 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } if(INVALID_SOCKET == back) { back = dk3socket_open(AF_INET6, SOCK_STREAM, 0, NULL, NULL); if(INVALID_SOCKET != back) { (void)dk3socket_set_reuse(back, 1, NULL, NULL); dk3socket_ip6addr_set_localhost(&soin6); soin6.sin6_port = htons(lp); connres = dk3socket_bind( back, (struct sockaddr *)(&soin6), sizeof(soin6), NULL, NULL ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } if(INVALID_SOCKET != back) { dk3socket_ip6addr_set_localhost(&soin6); soin6.sin6_port = htons(sp); connres = dk3socket_connect_nb( back, (struct sockaddr *)(&soin6), sizeof(soin6), secs, usecs, NULL, NULL, sh, 0 ); if(!(connres)) { dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; } } } } if(INVALID_SOCKET == back) { if(sh) { if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 351, 352, sh); } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 282); } } } } else { $? "! sp" /* ERROR: No server port specified! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_dkchar_open_net_stream_client %d", (int)back return back; #else #error "No support for wide char socket functions!" #endif #endif #else dk3_socket_t back; back = dk3socket_open_net_stream_client(sh, sp, lp, secs, usecs, ec, app); return back; #endif } int dk3socket_dkchar_inet_pton( int af, dkChar const *hn, void *addr, int *ec, dk3_app_t *app ) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "No support for wide char socket functions!" #else #if DK3_ON_WINDOWS #if (!defined(NTDDI_VERSION)) || (NTDDI_VERSION >= NTDDI_VISTA) int back = 0; int res; res = InetPtonW(af, hn, addr); switch(res) { case 1: { back = 1; } break; case 0: { /* ERROR: Not an IP address! */ } break; case -1: { dk3socket_error_inet_pton(ec, app, WSAGetLastError()); } break; } return back; #else char bu[128]; int back = 0; if(dk3str_c16_to_c8_simple_app(bu, sizeof(bu), hn, app)) { back = dk3socket_inet_pton(af, bu, addr, ec, app); } return back; #endif #else #error "No support for wide char socket functions!" #endif #endif #else int back; back = dk3socket_inet_pton(af, hn, addr, ec, app); return back; #endif } int dk3socket_dkchar_set_peer( dk3_peer_allowed_t *dp, dkChar const *sr, int *ec, dk3_app_t *app ) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "No support for wide char socket functions!" #else #if DK3_ON_WINDOWS dkChar bu[DK3_MAX_PATH]; ADDRINFOW hints; ADDRINFOW *rgai; ADDRINFOW *pai; IN6_ADDR ip6addr; struct sockaddr_in6 *soin6; IN_ADDR ip4addr; struct sockaddr_in *soin; dkChar *maptr; int res; int found; int back = 0; $? "+ dk3socket_dkchar_set_peer" if((dp) && (sr)) { found = 0; if(dk3str_len(sr) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, sr); maptr = dk3str_chr(bu, dkT('/')); if(maptr) { *(maptr++) = dkT('\0'); maptr = dk3str_start(maptr, NULL); } res = dk3socket_dkchar_inet_pton( AF_INET, bu, (void *)(&ip4addr), NULL, NULL ); if(res) { found = 1; dp->wh = 0; dk3mem_cpy( (void *)(&((dp->d).ip4.ad)), (void *)(&ip4addr), sizeof(IN_ADDR) ); back = dknet_dkchar_allowed_mask(dp, maptr, app, 0); } else { res = dk3socket_dkchar_inet_pton( AF_INET6, bu, (void *)(&ip6addr), NULL, NULL ); if(res) { found = 1; dp->wh = 1; dk3mem_cpy( (void *)(&((dp->d).ip6.ad)), (void *)(&ip6addr), sizeof(IN6_ADDR) ); back = dknet_dkchar_allowed_mask(dp, maptr, app, 1); } else { $? "! not a IPv6 address" } } if(!(found)) { rgai = NULL; dk3mem_res((void *)(&hints), sizeof(ADDRINFOW)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; res = GetAddrInfoW(bu, NULL, &hints, &rgai); if(0 == res) { if(rgai) { pai = rgai; while((0 == back) && (pai)) { switch(pai->ai_family) { case AF_INET: { if(sizeof(struct sockaddr_in) == pai->ai_addrlen) { if(pai->ai_addr) { found = 1; dp->wh = 0; soin = (struct sockaddr_in *)(pai->ai_addr); dk3mem_cpy( (void *)(&((dp->d).ip4.ad)), (void *)(&(soin->sin_addr)), sizeof(IN_ADDR) ); back = dknet_dkchar_allowed_mask(dp, maptr, app, 0); } } } break; case AF_INET6: { if(sizeof(struct sockaddr_in6) == pai->ai_addrlen) { if(pai->ai_addr) { found = 1; dp->wh = 1; soin6 = (struct sockaddr_in6 *)(pai->ai_addr); dk3mem_cpy( (void *)(&((dp->d).ip6.ad)), (void *)(&(soin6->sin6_addr)), sizeof(IN6_ADDR) ); back = dknet_dkchar_allowed_mask(dp, maptr, app, 1); } } } break; } pai = pai->ai_next; } } else { } } else { dk3socket_error_getaddrinfo(ec, app, res); } if(rgai) { FreeAddrInfoW(rgai); } } } else { /* ERROR: Host name too long! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 108); } } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_dkchar_set_peer %d", back return back; #else #error "No support for wide char socket functions!" #endif #endif #else int back; back = dk3socket_set_peer(dp, sr, ec, app); return back; #endif } dk3_socket_t dk3socket_set_accept( dk3_socket_set_t *ss, struct sockaddr *pAddr, size_t *pSzAddr, dk3_sto_it_t *iAllowed, int skipDenied, long nsecs, long usecs, int *ec, dk3_app_t *app ) { dkChar adbu[128]; /* Address text buffer. */ dkChar sobu[128]; /* Socket number buffer. */ dk3_sockaddr_storage_t sasto; /* Peer address. */ #if DK3_HAVE_SELECT || DK3_ON_WINDOWS struct timeval to; fd_set rfds; #endif void *pp; /* Peer pointer. */ size_t i; /* Listener index. */ dk3_socket_t lisock = INVALID_SOCKET; /* Listener socket. */ dk3_socket_t max = 0; /* Maximum socket number. */ dk3_socket_t back = INVALID_SOCKET; #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) int addrsize = 0; #else socklen_t addrsize = 0; #endif int mustSelect = 0; /* Flag: Must select(). */ int haveAny = 0; /* Flag: Have any listener. */ int ccloop = 0; /* Flag: Can continue loop. */ int adbures; /* Conversion result. */ $? "+ dk3socket_set_accept" dk3mem_res((void *)(&sasto), sizeof(sasto)); if(ss) { $? ". ss" if((ss->pData) && (ss->szUsed)) { $? ". data && szused" if(ss->szUsed > 1) { mustSelect = 1; } if((nsecs) || (usecs)) { mustSelect = 1; } do { ccloop = 0; to.tv_sec = nsecs; to.tv_usec = usecs; lisock = INVALID_SOCKET; #if DK3_ON_WINDOWS || (!(DK3_HAVE_SOCKLEN_T)) addrsize = (int)sizeof(sasto); #else addrsize = (socklen_t)sizeof(sasto); #endif to.tv_sec = nsecs; to.tv_usec = usecs; if(mustSelect) { $? ". select" #if DK3_HAVE_SELECT || DK3_ON_WINDOWS FD_ZERO(&rfds); for(i = 0; i < ss->szUsed; i++) { if(INVALID_SOCKET != (ss->pData)[i]) { FD_SET((ss->pData)[i],&rfds); haveAny = 1; $? ". check %d", (int)((ss->pData)[i]) if((ss->pData)[i] > max) { max = (ss->pData)[i]; } } } if(haveAny) { $? ". socket to check found, start select" haveAny = select( ((int)max + 1), &rfds, NULL, NULL, (((nsecs) || (usecs)) ? &to : NULL) ); $? ". select finished" #if DK3_ON_WINDOWS if(SOCKET_ERROR != haveAny) #else if(haveAny > 0) #endif { $? ". select %d", haveAny for(i = 0; (i < ss->szUsed) && (INVALID_SOCKET == lisock); i++) { if(INVALID_SOCKET != (ss->pData)[i]) { if(FD_ISSET((ss->pData)[i],&rfds)) { FD_CLR((ss->pData)[i],&rfds); lisock = (ss->pData)[i]; $? ". lisock ready %d", (int)lisock } } } } else { $? "! select" if(0 == haveAny) { /* Timeout */ $? "! timeout" if(ec) { *ec = DK3_ERROR_TIMEOUT; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 317); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } else { /* Failure */ $? "! select" if(ec) { *ec = DK3_ERROR_SYSTEM; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 317); } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 299); } } } } else { $? "! no listener to check" /* ERROR: No valid socket in set! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 359); } } #else $? ". no select function" if(1 == ss->szUsed) { $? ". just one socket, ignore timeout" lisock = *(ss->pData); /* Warning: Ignoring timeout! */ if(app) { dk3app_log_i1(app, DK3_LL_WARNING, 300); } } else { $? "! multiple sockets, not select" /* ERROR: No select function! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 358); } if(ec) { *ec = DK3_ERROR_NO_SELECT; } } #endif } else { $? ". no need to select" lisock = *(ss->pData); $? ". lisock without select %d", (int)(*(ss->pData)) } if(INVALID_SOCKET != lisock) { $? ". lisock %d, start accept", (int)lisock back = accept(lisock, (struct sockaddr *)(&sasto), &addrsize); $? ". accept finished" if(INVALID_SOCKET == back) { $? "! accept" dk3socket_error_accept(ec, app, dk3socket_error(errno)); } } if(INVALID_SOCKET != back) { $? ". accept" if(iAllowed) { pp = dk3sto_it_find_like(iAllowed, (void *)(&sasto), 1); if(!(pp)) { $? "! client not allowed" /* Not allowed to connect! */ dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; if(skipDenied) { ccloop = 1; } if(app) { if(dk3app_max_log_level(app) >= DK3_LL_PROGRESS) { adbures = dk3socket_ipaddr_to_text( adbu, DK3_SIZEOF(adbu,dkChar), (void *)(&sasto), addrsize ); if(adbures) { dk3app_log_i3(app, DK3_LL_PROGRESS, 362, 363, adbu); } } } } } } if(INVALID_SOCKET != back) { if((pAddr) && (pSzAddr)) { if(*pSzAddr >= (size_t)addrsize) { dk3mem_cpy((void *)pAddr, (void *)(&sasto), (size_t)addrsize); *pSzAddr = (size_t)addrsize; } else { $? "! address size buffer too small" /* Failed to save address! */ dk3socket_close(back, NULL, NULL); back = INVALID_SOCKET; /* Failed to save address size, buffer too small! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } } if(INVALID_SOCKET != back) { if(app) { if(dk3app_max_log_level(app) >= DK3_LL_PROGRESS) { adbures = dk3socket_ipaddr_to_text( adbu, DK3_SIZEOF(adbu,dkChar), (void *)(&sasto), addrsize ); if(adbures) { #if VERSION_BEFORE_20140716 dk3sf_sprintf3(sobu,dkT("%d"),((int)back)); dk3app_log_i5(app, DK3_LL_PROGRESS, 360, 361, 371, sobu, adbu); #else if ( dk3ma_im_to_string(sobu,DK3_SIZEOF(sobu,dkChar),(dk3_im_t)back) ) { dk3app_log_i5(app,DK3_LL_PROGRESS,360,361,371,sobu,adbu); } #endif } } } } } while((ccloop) && (INVALID_SOCKET == back)); } else { $? "! ss->pData or ss->szUsed wrong" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { /* ERROR: No usable socket in set! */ if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 359); } } } } else { $? "! ss" if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_set_accept %d", (int)back return back; } void dk3socket_eat_input(dk3_socket_t so, dk3_app_t *app) { char bu[4096]; int szrd; do { szrd = dk3socket_recv(so, bu, sizeof(bu), 0L, 0L, NULL, app); } while(szrd > 0); }