%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% module #include "dk3all.h" #include "dk3sock.h" $!trace-include #if DK3_ON_WINDOWS $!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 } $!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); } 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; } } 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); } 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; } } 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); } } 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; } } 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); } 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; } } 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); } 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; } } 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); } 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; } } 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); } 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; } } 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); } 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; } } 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); } 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; } } 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); } 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; } } 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; } 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; } } /** 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; } } 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); } 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; } } 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); } 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; } $? "- 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); } } int dk3socket_ip4addr_to_text(dkChar *dp, size_t szdp, IN_ADDR *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 *ia, size_t sz) { dkChar mybu[64]; struct sockaddr *soa; struct sockaddr_in *so4; 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 *)ia; if((AF_INET == soa->sa_family) && (sz == sizeof(struct sockaddr_in))) { so4 = (struct sockaddr_in *)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 (0 != 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 { } } $? "- 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 } } } } 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. */ dkChar *ptr; dkChar *lat; /* Local address text. */ int res; /* Result from bind(). */ int err; /* Error code. */ int back = 0; int conr = 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) { case AF_INET: { struct sockaddr_in *soin; unsigned u; soin = (struct sockaddr_in *)pAddr; u = (unsigned)(ntohs(soin->sin_port)); #if VERSION_BEFORE_20140716 dk3sf_sprintf3(bu,dk3socket_function_names[19], u); #else dk3ma_um_to_string(bu, DK3_SIZEOF(bu,dkChar), (dk3_um_t)u); #endif 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; } break; } dk3socket_error_bind(ec, app, err, lat); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } $? "- dk3socket_bind %d", back return back; } 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; } 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 ) { 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(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 { $? ". 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 ) { int addrsize = 0; dk3_socket_t back = INVALID_SOCKET; int err; if((pAddr) && (pSzAddr)) { if(pSzAddr) { addrsize = (int)(*pSzAddr); } } 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. */ int res; /* Operation result. */ fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ $? "+ dk3socket_send %d %u", (int)so, (unsigned)sz if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { 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(selres != SOCKET_ERROR) { if(selres > 0) { if(FD_ISSET(so,&wfds)) { res = send(so, bu, (int)sz, 0); 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 { res = send(so, bu, (int)sz, 0); 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 %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 ) { fd_set rfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ int res; /* Operation result. */ int err; /* Error code. */ int back = -1; $? "+ dk3socket_recv %d %u", (int)so, (unsigned)sz if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { 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(selres != SOCKET_ERROR) { if(selres > 0) { if(FD_ISSET(so,&rfds)) { res = recv(so, bu, (int)sz, 0); if(res >= 0) { back = res; } else { err = dk3socket_error(errno); dk3socket_error_recv(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 { res = recv(so, bu, (int)sz, 0); 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 *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. */ int res; /* Operation result. */ fd_set wfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ int myszaddr; $? "+ dk3socket_sendto %d %u", (int)so, (unsigned)sz myszaddr = (int)szAddr; if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { 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(selres != SOCKET_ERROR) { if(selres > 0) { if(FD_ISSET(so,&wfds)) { res = sendto(so, bu, (int)sz, 0, pAddr, myszaddr); 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 { res = sendto(so, bu, (int)sz, 0, pAddr, myszaddr); 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 ) { fd_set rfds; /* File descriptor set. */ struct timeval to; /* Timeout. */ int selres; /* Result from select(). */ int res; /* Operation result. */ int err; /* Error code. */ int back = -1; int myszaddr = 0; $? "+ dk3socket_recvfrom %d %u", (int)so, (unsigned)sz if((pAddr) && (pSzAddr)) { myszaddr = (int)(*pSzAddr); } if((INVALID_SOCKET != so) && (bu) && (sz)) { if((secs) || (usecs)) { 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(selres != SOCKET_ERROR) { if(selres > 0) { if(FD_ISSET(so,&rfds)) { res = recvfrom(so,bu,(int)sz,0,pAddr,((pAddr) ? &myszaddr : NULL)); 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_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 { res = recvfrom(so, bu, (int)sz, 0, pAddr, ((pAddr) ? &myszaddr : NULL)); 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) { res = closesocket(so); 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) { 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; } int dk3socket_down(int *ec, dk3_app_t *app) { int back = 0; $? "+ dk3socket_down" if(0 == WSACleanup()) { back = 1; } else { dk3socket_error_down(ec, app, WSAGetLastError()); } $? "- dk3socket_down %d", back return back; } 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 $? ". windows" 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 $? ". 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) { if(dk3enc_c8_ipaddr_to_ul_app(hn, (unsigned long *)addr, app)) { $? ". dk3enc_c8_ipaddr_to_ul_app" 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(0 == shutdown(so, SD_RECEIVE)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } } break; case DK3_TCPIP_SHUTDOWN_WRITE: { if(0 == shutdown(so, SD_SEND)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } } break; case DK3_TCPIP_SHUTDOWN_RW: { if(0 == shutdown(so, SD_BOTH)) { back = 1; } else { err = WSAGetLastError(); dk3socket_error_shutdown(ec, app, err); } } 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) { 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 { 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) { /* ERROR: No function implemented! */ if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 353); } } else { if(ec) { *ec = DK3_ERROR_INVALID_ARGS; } } return back; } /* 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 ) { 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; } } } /* 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 { } } 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; } } } 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; } 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. */ 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; 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 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. */ 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; 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 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; } /** 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) { IN_ADDR ip4mask; /* IPv4 net mask. */ unsigned u; /* Number of bits to set. */ int res; /* Operation result. */ int back = 0; 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) ); } 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. */ struct hostent *heptr; /* Result from gethostbyname(). */ IN_ADDR ip4addr; /* IPv4 address. */ unsigned long *ulptr; /* Pointer to address. */ char **addrptr; /* Address pointer. */ struct sockaddr_in *soin; /* Socket address. */ char *maptr; /* Pointer to beginning of mask. */ int back = 0; int res; /* Result from inet_ntop(). */ int found; /* Flag: Host found. */ int err; /* Error code from gethostbyname() .*/ $? "+ 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(!(found)) { $? ". no address found yet" $? ". 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" } } else { $? "! gethostbyname" err = dk3socket_error(h_errno); dk3socket_error_gethostbyname(ec, app, err, bu); } } } 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 *l, void *r, int cr) { char adbl[16]; char adbr[16]; dk3_peer_allowed_t *pl; dk3_peer_allowed_t *pr; struct sockaddr *so; struct sockaddr_in *soin; unsigned long ull; unsigned long ulr; size_t i; int back = 0; if(l) { if(r) { pl = (dk3_peer_allowed_t *)l; switch(cr) { case 1: { /* Compare address families. */ so = (struct sockaddr *)r; switch(so->sa_family) { case AF_INET: { if(pl->wh) { back = 1; } } break; default: { back = -1; } break; } /* For matching address families compare addresses. */ if(0 == back) { if(pl->wh) { /* Compare IPv6. */ } else { /* Compare IPv4. */ soin = (struct sockaddr_in *)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 *)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. */ } 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) 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 ) { IN_ADDR ip4mask; /* IPv4 net mask. */ unsigned u; /* Number of bits to set. */ int res; /* Operation result. */ int back = 0; 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(0 != dk3ma_u_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 /* ##### Complete rewrite, do not use getaddrinfo(). */ dkChar lbuf[64]; /* Server port text. */ dkChar pbuf[64]; /* Local port text. */ 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; 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 (0 != 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; #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 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; #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 /* ##### Complete rewrite, do not use getaddrinfo() */ 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 { } 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; } 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; #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. */ struct timeval to; fd_set rfds; 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; int addrsize = 0; 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; addrsize = (int)sizeof(sasto); to.tv_sec = nsecs; to.tv_usec = usecs; if(mustSelect) { $? ". select" 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(SOCKET_ERROR != haveAny) { $? ". 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 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); } #else #error "This module is for legacy Windows versions only!" #endif