diff options
Diffstat (limited to 'erts/emulator/nifs/common/prim_socket_nif.c')
-rw-r--r-- | erts/emulator/nifs/common/prim_socket_nif.c | 12650 |
1 files changed, 2810 insertions, 9840 deletions
diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index 4ac0fc0966..9d6755387d 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2022. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,13 @@ * The first function is called 'nif_<something>', e.g. nif_open. * This does the initial validation and argument processing and then * calls the function that does the actual work. This is called - * 'esock_<something>', e.g. esock_open (actually esock_open2 or - * esock_open4). + * '<io-backend>_<something>', e.g. essio_open (actually + * essio_open_with_fd or essio_open_plain). * ---------------------------------------------------------------------- * * - * This is just a code snippet in case there is need of extra debugging + * This is just a code snippet example in case there is need of + * extra debugging: * * esock_dbg_printf("DEMONP", "[%d] %s: %T\r\n", * descP->sock, slogan, @@ -124,6 +125,10 @@ ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL) * * * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +#define ESOCK_CMSG_SPACE(l) WSA_CMSG_SPACE((l)) +#define ESOCK_CMSG_LEN(l) WSA_CMSG_LEN((l)) +#define ESOCK_CMSG_DATA(p) WSA_CMSG_DATA((p)) + #define STRNCASECMP strncasecmp #define INCL_WINSOCK_API_TYPEDEFS 1 @@ -166,6 +171,10 @@ ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL) * * * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +#define ESOCK_CMSG_SPACE(l) CMSG_SPACE((l)) +#define ESOCK_CMSG_LEN(l) CMSG_LEN((l)) +#define ESOCK_CMSG_DATA(p) CMSG_DATA((p)) + #include <sys/time.h> #ifdef NETDB_H_NEEDS_IN_H @@ -363,12 +372,12 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #endif /* #if defined(HAVE_SCTP_H) */ - #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING #endif #include "sys.h" + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * * * End of non-__WIN32__ section a.k.a UNIX section * @@ -384,6 +393,10 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #include "socket_tarray.h" #include "socket_int.h" #include "socket_util.h" +#include "prim_socket_int.h" +#include "socket_io.h" +#include "socket_asyncio.h" +#include "socket_syncio.h" #include "prim_file_nif_dyncall.h" #if defined(ERTS_INLINE) @@ -411,41 +424,6 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #define ESOCK_NIF_IOW_DEFAULT FALSE -#ifdef __WIN32__ - -//#define INVALID_HANDLE from Windows header file -//typedef void *HANDLE from Windows header file -//#define INVALID_SOCKET from Windows header file -//typedef void *SOCKET from Windows header file -#define INVALID_EVENT NULL - -#else - -#define INVALID_HANDLE (-1) -typedef int HANDLE; -#define INVALID_SOCKET (-1) -typedef int SOCKET; /* A subset of HANDLE */ -#define INVALID_EVENT INVALID_HANDLE - -#endif - - -/* ============================================================================== - * The ESOCK_IS_ERROR macro below is used for portability reasons. - * While POSIX specifies that errors from socket-related system calls - * should be indicated with a -1 return value, some users have experienced - * non-Windows OS kernels that return negative values other than -1. - * While one can argue that such kernels are technically broken, comparing - * against values less than 0 covers their out-of-spec return values without - * imposing incorrect semantics on systems that manage to correctly return -1 - * for errors, thus increasing Erlang's portability. - */ -#ifdef __WIN32__ -#define ESOCK_IS_ERROR(val) ((val) == INVALID_SOCKET) -#else -#define ESOCK_IS_ERROR(val) ((val) < 0) -#endif - /* *** Misc macros and defines *** */ @@ -473,73 +451,11 @@ typedef int SOCKET; /* A subset of HANDLE */ -/* *** Socket state defs *** */ - -#define ESOCK_STATE_BOUND 0x0001 /* readState */ -#define ESOCK_STATE_LISTENING 0x0002 /* readState */ -#define ESOCK_STATE_ACCEPTING 0x0004 /* readState */ -#define ESOCK_STATE_CONNECTING 0x0010 /* writeState */ -#define ESOCK_STATE_CONNECTED 0x0020 /* writeState */ - -/* This is set in either readState or writeState - * so it has to be read from both. - * Means that the socket has been used in select, - * so select_stop is required. */ -#define ESOCK_STATE_SELECTED 0x0100 /* readState or writeState */ - -/* These are set in both readState and writeState - * so they can be read from either. */ -#define ESOCK_STATE_CLOSING 0x0200 /* readState and writeState */ - -#define ESOCK_STATE_CLOSED 0x0400 /* readState and writeState */ -// -#define ESOCK_STATE_DTOR 0x8000 - -#define IS_CLOSED(st) \ - (((st) & ESOCK_STATE_CLOSED) != 0) - -#define IS_CLOSING(st) \ - (((st) & ESOCK_STATE_CLOSING) != 0) - -#define IS_OPEN(st) \ - (((st) & (ESOCK_STATE_CLOSED | ESOCK_STATE_CLOSING)) == 0) - -#define IS_SELECTED(d) \ - ((((d)->readState | (d)->writeState) & ESOCK_STATE_SELECTED) != 0) - - -#define ESOCK_GET_RESOURCE(ENV, REF, RES) \ - enif_get_resource((ENV), (REF), esocks, (RES)) - -#define ESOCK_MON2TERM(E, M) \ - esock_make_monitor_term((E), (M)) - #define ESOCK_RECV_BUFFER_COUNT_DEFAULT 0 #define ESOCK_RECV_BUFFER_SIZE_DEFAULT 8192 #define ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024 #define ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024 -#define ESOCK_DESC_PATTERN_CREATED 0x03030303 -#define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0 - -/* -typedef union { - struct { - // 0 = not open, 1 = open - unsigned int open:1; - // 0 = not conn, 1 = connecting, 2 = connected - unsigned int connect:2; - // unsigned int connecting:1; - // unsigned int connected:1; - // 0 = not listen, 1 = listening, 2 = accepting - unsigned int listen:2; - // unsigned int listening:1; - // unsigned int accepting:1; - / * Room for more... * / - } flags; - unsigned int field; // Make it easy to reset all flags... -} SocketState; -*/ /*---------------------------------------------------------------------------- * Interface constants. @@ -548,11 +464,7 @@ typedef union { * msg_flag() in socket.erl. */ -static const struct msg_flag { - int flag; - ERL_NIF_TERM *name; -} msg_flags[] = { - +const ESockFlag esock_msg_flags[] = { { #ifdef MSG_CMSG_CLOEXEC MSG_CMSG_CLOEXEC, @@ -641,13 +553,9 @@ static const struct msg_flag { #endif &esock_atom_trunc} }; +const int esock_msg_flags_length = NUM(esock_msg_flags); - -static const struct ioctl_flag { - int flag; - ERL_NIF_TERM *name; -} ioctl_flags[] = { - +const ESockFlag esock_ioctl_flags[] = { { #ifdef IFF_UP IFF_UP, @@ -917,6 +825,7 @@ static const struct ioctl_flag { #endif &esock_atom_nogroup} }; +const int esock_ioctl_flags_length = NUM(esock_ioctl_flags); @@ -955,16 +864,6 @@ static const struct ioctl_flag { /* Global socket debug */ #define SGDBG( proto ) ESOCK_DBG_PRINTF( data.dbg , proto ) -/* Socket specific debug */ -#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto ) -#define SSDBG2( __DBG__ , proto ) ESOCK_DBG_PRINTF( (__DBG__) , proto ) - -#define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \ - do { \ - if (cnt_inc((CNT), (INC))) { \ - esock_send_wrap_msg((__E__), (__D__), (SF), (ACNT)); \ - } \ - } while (0) /* =================================================================== * @@ -982,29 +881,29 @@ static const struct ioctl_flag { /* *** Windows macros *** */ -#define sock_accept(s, addr, len) \ - make_noninheritable_handle(accept((s), (addr), (len))) -#define sock_bind(s, addr, len) bind((s), (addr), (len)) +/* #define sock_accept(s, addr, len) \ + make_noninheritable_handle(accept((s), (addr), (len))) */ +// #define sock_bind(s, addr, len) bind((s), (addr), (len)) #define sock_close(s) closesocket((s)) -#define sock_close_event(e) WSACloseEvent(e) -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_create_event(s) WSACreateEvent() +// #define sock_close_event(e) WSACloseEvent(e) +// #define sock_connect(s, addr, len) connect((s), (addr), (len)) +// #define sock_create_event(s) WSACreateEvent() #define sock_errno() WSAGetLastError() #define sock_getopt(s,l,o,v,ln) getsockopt((s),(l),(o),(v),(ln)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) +// #define sock_htons(x) htons((x)) +// #define sock_htonl(x) htonl((x)) #define sock_listen(s, b) listen((s), (b)) #define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_open(domain, type, proto) \ - make_noninheritable_handle(socket((domain), (type), (proto))) +// #define sock_ntohs(x) ntohs((x)) +/* #define sock_open(domain, type, proto) \ + make_noninheritable_handle(socket((domain), (type), (proto))) */ #define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +// #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) +/* #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) */ +/* #define sock_sendto(s,buf,blen,flag,addr,alen) \ + sendto((s),(buf),(blen),(flag),(addr),(alen)) */ #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln)) #define sock_shutdown(s, how) shutdown((s), (how)) @@ -1028,34 +927,34 @@ static unsigned long one_value = 1; * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ -#ifdef HAS_ACCEPT4 +// #ifdef HAS_ACCEPT4 // We have to figure out what the flags are... -#define sock_accept(s, addr, len) accept4((s), (addr), (len), (SOCK_CLOEXEC)) -#else -#define sock_accept(s, addr, len) accept((s), (addr), (len)) -#endif -#define sock_bind(s, addr, len) bind((s), (addr), (len)) +// #define sock_accept(s, addr, len) accept4((s), (addr), (len), (SOCK_CLOEXEC)) +// #else +// #define sock_accept(s, addr, len) accept((s), (addr), (len)) +// #endif +// #define sock_bind(s, addr, len) bind((s), (addr), (len)) #define sock_close(s) close((s)) -#define sock_close_event(e) /* do nothing */ -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_create_event(s) (s) /* return file descriptor */ +// #define sock_close_event(e) /* do nothing */ +// #define sock_connect(s, addr, len) connect((s), (addr), (len)) +// #define sock_create_event(s) (s) /* return file descriptor */ #define sock_errno() errno #define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) +// #define sock_htons(x) htons((x)) +// #define sock_htonl(x) htonl((x)) #define sock_listen(s, b) listen((s), (b)) #define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_open(domain, type, proto) socket((domain), (type), (proto)) +// #define sock_ntohs(x) ntohs((x)) +// #define sock_open(domain, type, proto) socket((domain), (type), (proto)) #define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) -#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ - recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) -#define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag)) -#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) +// #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +/* #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ */ +/* recvfrom((s),(buf),(blen),(flag),(addr),(alen)) */ +// #define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) +// #define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag)) +// #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) +/* #define sock_sendto(s,buf,blen,flag,addr,alen) \ */ +/* sendto((s),(buf),(blen),(flag),(addr),(alen)) */ #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln)) #define sock_shutdown(s, how) shutdown((s), (how)) @@ -1068,284 +967,20 @@ static unsigned long one_value = 1; #endif /* #ifdef __WIN32__ #else */ -/* We can use the IPv4 def for this since the beginning - * is the same for INET and INET6 */ -#define which_address_port(sap) \ - ((((sap)->in4.sin_family == AF_INET) || \ - ((sap)->in4.sin_family == AF_INET6)) ? \ - ((sap)->in4.sin_port) : -1) - - -typedef struct { - ErlNifMonitor mon; - BOOLEAN_T isActive; -} ESockMonitor; - -typedef struct { - ErlNifPid pid; // PID of the requesting process - ESockMonitor mon; // Monitor to the requesting process - - /* We need an environment for the copy of the ref we store here. - * We will also use this environment for any messages we send - * (with the ref in it). Such as the select message (used in the - * select call) or the abort message. - */ - ErlNifEnv* env; - ERL_NIF_TERM ref; // The (unique) reference (ID) of the request -} ESockRequestor; - -typedef struct{ - // Holding the socket level 'otp' option 'meta' term - ErlNifEnv* env; - ERL_NIF_TERM ref; -} ESockMeta; - -typedef struct esock_request_queue_element { - struct esock_request_queue_element* nextP; - ESockRequestor data; -} ESockRequestQueueElement; - -typedef struct { - ESockRequestQueueElement* first; - ESockRequestQueueElement* last; -} ESockRequestQueue; - - -/*** The point of this is primarily testing ***/ -/* -#if defined(ESOCK_COUNTER_SIZE) -#undef ESOCK_COUNTER_SIZE -// #define ESOCK_COUNTER_SIZE 16 -// #define ESOCK_COUNTER_SIZE 24 -// #define ESOCK_COUNTER_SIZE 32 -// #define ESOCK_COUNTER_SIZE 48 -// #define ESOCK_COUNTER_SIZE 64 - -#endif -*/ - -#if ESOCK_COUNTER_SIZE == 16 - -typedef Uint16 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFF) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%u" - -#elif ESOCK_COUNTER_SIZE == 24 - -typedef Uint32 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFF) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%lu" - -#elif ESOCK_COUNTER_SIZE == 32 - -typedef Uint32 ESockCounter; -#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%lu" - -#elif ESOCK_COUNTER_SIZE == 48 - -typedef Uint64 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFFFFFFFF) -#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%llu" - -#elif ESOCK_COUNTER_SIZE == 64 - -typedef Uint64 ESockCounter; -#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) -#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%llu" - -#else - -#error "Invalid counter size" - -#endif - -// static const ESockCounter esock_counter_max = ESOCK_COUNTER_MAX; - #ifdef HAVE_SENDFILE -typedef struct { - ESockCounter cnt; // Calls to OS sendfile() - ESockCounter byteCnt; // Bytes sent with sendfile - ESockCounter fails; // Failed sendfile operations - ESockCounter max; // Largest sendfile operation - ESockCounter maxCnt; // Counter for ="= - ESockCounter pkg; // Sendfile chunks - ESockCounter pkgMax; // Largest sendfile chunk - ESockCounter tries; // Started sendfile operations - ESockCounter waits; // Select's during sendfile -} ESockSendfileCounters; -static ESockSendfileCounters initESockSendfileCounters = +ESockSendfileCounters initESockSendfileCounters = {0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif -typedef struct { - /* - * +++ This is a way to, possibly, detect memory overrides "and stuff" +++ - * - * We have two patterns. One is set when the descriptor is created - * (allocated) and one is set when the descriptor is dtor'ed. - */ - Uint32 pattern; - - /* +++ Stuff "about" the socket +++ */ - - /* "Constant" - set when socket is created and never changed */ - int domain; - int type; - int protocol; - - /* The state is partly for debugging, decisions are made often - * based on other variables. The state is divided in - * a readState half and a writeState half that can be - * OR:ed together to create the complete state. - * The halves are locked by their corresponding lock. - */ - - /* +++ Write stuff +++ */ - ErlNifMutex* writeMtx; - /**/ - unsigned int writeState; // For debugging - ESockRequestor currentWriter; - ESockRequestor* currentWriterP; // NULL or ¤tWriter - ESockRequestQueue writersQ; - ESockCounter writePkgCnt; - ESockCounter writePkgMax; - ESockCounter writePkgMaxCnt; - ESockCounter writeByteCnt; - ESockCounter writeTries; - ESockCounter writeWaits; - ESockCounter writeFails; -#ifdef HAVE_SENDFILE - HANDLE sendfileHandle; - ESockSendfileCounters* sendfileCountersP; -#endif - /* +++ Connector +++ */ - ESockRequestor connector; - ESockRequestor* connectorP; // NULL or &connector - /* +++ Config stuff +++ */ - size_t wCtrlSz; // Write control buffer size - ESockMeta meta; // Level 'otp' option 'meta' term - - /* +++ Read stuff +++ */ - ErlNifMutex* readMtx; - /**/ - unsigned int readState; // For debugging - ESockRequestor currentReader; - ESockRequestor* currentReaderP; // NULL or ¤tReader - ESockRequestQueue readersQ; - ErlNifBinary rbuffer; // DO WE NEED THIS - Uint32 readCapacity; // DO WE NEED THIS - ESockCounter readPkgCnt; - ESockCounter readPkgMax; - ESockCounter readPkgMaxCnt; - ESockCounter readByteCnt; - ESockCounter readTries; - ESockCounter readWaits; - ESockCounter readFails; - /* +++ Accept stuff +++ */ - ESockRequestor currentAcceptor; - ESockRequestor* currentAcceptorP; // NULL or ¤tAcceptor - ESockRequestQueue acceptorsQ; - ESockCounter accSuccess; - ESockCounter accTries; - ESockCounter accWaits; - ESockCounter accFails; - /* +++ Config stuff +++ */ - size_t rBufSz; // Read buffer size (when data length = 0) - /* rNum and rNumCnt are used (together with rBufSz) when calling the recv - * function with the Length argument set to 0 (zero). - * If rNum is 0 (zero), then rNumCnt is not used and only *one* read will - * be done. Also, when get'ing the value of the option (rcvbuf) with - * getopt, the value will be reported as an integer. If the rNum has a - * value greater then 0 (zero), then it will instead be reported as {N, BufSz}. - */ - unsigned int rNum; // recv: Number of reads using rBufSz - unsigned int rNumCnt; // recv: Current number of reads (so far) - size_t rCtrlSz; // Read control buffer size - - /* Locked by readMtx and writeMtx combined for writing, - * which means only one of them is required for reading - */ - /* +++ Close stuff +++ */ - ErlNifPid closerPid; - ESockMonitor closerMon; - ErlNifEnv* closeEnv; - ERL_NIF_TERM closeRef; - /* +++ Inform On (counter) Wrap +++ */ - BOOLEAN_T iow; - /* +++ Controller (owner) process +++ */ - ErlNifPid ctrlPid; - ESockMonitor ctrlMon; - /* +++ The actual socket +++ */ - SOCKET sock; - ErlNifEvent event; - SOCKET origFD; // A 'socket' created from this FD - BOOLEAN_T closeOnClose; // Have we dup'ed or not - /* +++ The dbg flag for SSDBG +++ */ - BOOLEAN_T dbg; - BOOLEAN_T useReg; - - /* Lock order: readMtx, writeMtx, cntMtx - */ -} ESockDescriptor; - - -/* Global stuff. - */ -typedef struct { - /* These are for debugging, testing and the like */ - // ERL_NIF_TERM version; - // ERL_NIF_TERM buildDate; - - /* XXX Should be locked but too awkward and small gain */ - BOOLEAN_T dbg; - BOOLEAN_T useReg; - - /* Registry stuff */ - ErlNifPid regPid; /* Constant - not locked */ - - /* IOV_MAX. Constant - not locked */ - int iov_max; - - /* XXX - * Should be locked but too awkward for no gain since it is not used yet - */ - BOOLEAN_T iow; // Where do we send this? Subscription? - - ErlNifMutex* protocolsMtx; - - ErlNifMutex* cntMtx; /* Locks the below */ - /* Its extreme overkill to have these counters be 64-bit, - * but since the other counters are, it's much simpler to - * let these be 64-bit also. - */ - ESockCounter numSockets; - ESockCounter numTypeStreams; - ESockCounter numTypeDGrams; - ESockCounter numTypeSeqPkgs; - ESockCounter numDomainInet; - ESockCounter numDomainInet6; - ESockCounter numDomainLocal; - ESockCounter numProtoIP; - ESockCounter numProtoTCP; - ESockCounter numProtoUDP; - ESockCounter numProtoSCTP; - // - BOOLEAN_T sockDbg; -} ESockData; +/* We can use the IPv4 def for this since the beginning + * is the same for INET and INET6 */ +#define which_address_port(sap) \ + ((((sap)->in4.sin_family == AF_INET) || \ + ((sap)->in4.sin_family == AF_INET6)) ? \ + ((sap)->in4.sin_port) : -1) /* ---------------------------------------------------------------------- @@ -1354,7 +989,6 @@ typedef struct { */ -extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ /* All the nif "callback" functions for the socket API has @@ -1430,247 +1064,133 @@ ESOCK_NIF_FUNCS #undef ESOCK_NIF_FUNC_DEF -#ifndef __WIN32__ -/* ---------------------------------------------------------------------- * - * * - * * - * Start of non-__WIN32__ section a.k.a UNIX section * - * * - * * - * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +/* ======================================================================= + * Socket specific backend 'synchronicity' functions. + * This type is used to create 'sync' function table. + * This table is initiated when the nif is loaded. + * Initially, its content will be hardcoded to: + * * Windows: async (esaio) + * * Other (unix): sync (essio) + * When we introduce async I/O for unix (io_uring or something similar) + * we may make it possible to choose (set a flag when the VM is started; + * --esock-io=<async|sync>). + */ -/* And here comes the functions that does the actual work (for the most part) */ +typedef struct { + ESockIOInit init; + ESockIOFinish finish; + + ESockIOInfo info; + ESockIOCommand cmd; + ESockIOSupports0 supports_0; + ESockIOSupports1 supports_1; + + ESockIOOpenWithFd open_with_fd; + ESockIOOpenPlain open_plain; + ESockIOBind bind; + + ESockIOConnect connect; + ESockIOListen listen; + ESockIOAccept accept; + + ESockIOSend send; + ESockIOSendTo sendto; + ESockIOSendMsg sendmsg; + ESockIOSendFileStart sendfile_start; + ESockIOSendFileContinue sendfile_cont; + ESockIOSendFileDeferredClose sendfile_dc; + + ESockIORecv recv; + ESockIORecvFrom recvfrom; + ESockIORecvMsg recvmsg; + + ESockIOClose close; + ESockIOFinClose fin_close; + ESockIOShutdown shutdown; + + ESockIOSockName sockname; + ESockIOPeerName peername; + + /* The various cancel operations */ + ESockIOCancelConnect cancel_connect; + ESockIOCancelAccept cancel_accept; + ESockIOCancelSend cancel_send; + ESockIOCancelRecv cancel_recv; + + /* Socket option callback functions */ + ESockIOSetopt setopt; + ESockIOSetoptNative setopt_native; + ESockIOSetoptOtp setopt_otp; + ESockIOGetopt getopt; + ESockIOGetoptNative getopt_native; + ESockIOGetoptOtp getopt_otp; + + /* Socket ioctl callback functions */ + ESockIOIoctl_2 ioctl_2; + ESockIOIoctl_3 ioctl_3; + ESockIOIoctl_4 ioctl_4; + + /* (socket) NIF resource callback functions */ + ESockIODTor dtor; + ESockIOStop stop; + ESockIODown down; + +} ESockIoBackend; -static ERL_NIF_TERM esock_command(ErlNifEnv* env, - ERL_NIF_TERM command, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_global_info(ErlNifEnv* env); -static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, - unsigned int state); -#define ESOCK_SOCKET_INFO_REQ_FUNCS \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors); +/* ------------------------------------------------------------------------ + * Socket option(s) and table(s) + */ -#define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ - ESockDescriptor* descP); -ESOCK_SOCKET_INFO_REQ_FUNCS -#undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF +struct ESockOpt +{ + int opt; // Option number -static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* currentRequestorP, - ESockRequestQueue* q); + // Function to set option + ERL_NIF_TERM (*setopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); -static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key); + // Function to get option + ERL_NIF_TERM (*getopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); -static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env); + ERL_NIF_TERM *nameP; // Pointer to option name atom +}; -static ERL_NIF_TERM esock_open2(ErlNifEnv* env, - int fd, - ERL_NIF_TERM eextra); -static BOOLEAN_T esock_open2_todup(ErlNifEnv* env, - ERL_NIF_TERM eextra); -static BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env, - ERL_NIF_TERM eopts, - int* domain); -static BOOLEAN_T esock_open2_get_type(ErlNifEnv* env, - ERL_NIF_TERM eopt, - int* type); -static ERL_NIF_TERM esock_open4(ErlNifEnv* env, - int domain, - int type, - int protocol, - ERL_NIF_TERM eopts); -static BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, - ERL_NIF_TERM eextra, - BOOLEAN_T dflt); -static BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, - ERL_NIF_TERM eextra, - BOOLEAN_T dflt); -static BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain); -static BOOLEAN_T esock_open_which_type(SOCKET sock, int* type); -static BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto); - -static ERL_NIF_TERM esock_bind(ErlNifEnv* env, - ESockDescriptor* descP, - ESockAddress* sockAddrP, - SOCKLEN_T addrLen); -static ERL_NIF_TERM esock_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM connRef, - ESockAddress* addrP, - SOCKLEN_T addrLen); -static ERL_NIF_TERM esock_listen(ErlNifEnv* env, - ESockDescriptor* descP, - int backlog); -static ERL_NIF_TERM esock_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref); -static ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid caller, - int save_errno); -static ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid caller); -static ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref); -static ERL_NIF_TERM -esock_accept_accepting_current_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock); -static ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - int save_errno); -static ERL_NIF_TERM esock_accept_accepting_other(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ErlNifPid caller); -static ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid* pidP); -static BOOLEAN_T esock_accept_accepted(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid pid, - ERL_NIF_TERM* result); -static ERL_NIF_TERM esock_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags); -static ERL_NIF_TERM esock_sendto(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags, - ESockAddress* toAddrP, - SOCKLEN_T toAddrLen); -static ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsg, - int flags, - ERL_NIF_TERM eIOV); -#ifdef HAVE_SENDFILE -static ERL_NIF_TERM -esock_sendfile_start(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count, - ERL_NIF_TERM fRef); -static ERL_NIF_TERM -esock_sendfile_cont(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count); -static ERL_NIF_TERM -esock_sendfile_deferred_close(ErlNifEnv *env, - ESockDescriptor *descP); -static int -esock_sendfile(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - off_t offset, - size_t *count, - int *errP); -static ERL_NIF_TERM -esock_sendfile_error(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM -esock_sendfile_errno(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - int err); -static ERL_NIF_TERM -esock_sendfile_ok(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - size_t count); -static ERL_NIF_TERM -esock_sendfile_select(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - size_t count); -#endif // #ifdef HAVE_SENDFILE +/* Option levels table*/ -static ERL_NIF_TERM esock_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags); -static ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufSz, - int flags); -static ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufLen, - ssize_t ctrlLen, - int flags); -static ERL_NIF_TERM esock_close(ErlNifEnv* env, - ESockDescriptor* descP); -static BOOLEAN_T esock_do_stop(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, - ESockDescriptor* descP, - int how); +struct ESockOptLevel +{ + int level; // Level number + + size_t num; // Number of options + struct ESockOpt *opts; // Options table + ERL_NIF_TERM *nameP; // Pointer to level name atom +}; + + + +/* First chunk of forwards...some of these are used in the options tables... */ + +/* Set native options */ +static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM valueSpec); /* Set OTP level options */ static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, ESockDescriptor* descP, @@ -1685,28 +1205,186 @@ static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, * *** esock_setopt_otp_meta *** * *** esock_setopt_otp_use_registry *** */ -#define ESOCK_SETOPT_OTP_FUNCS \ - ESOCK_SETOPT_OTP_FUNC_DEF(debug); \ - ESOCK_SETOPT_OTP_FUNC_DEF(iow); \ - ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \ - ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(meta); \ +#define ESOCK_SETOPT_OTP_FUNCS \ + ESOCK_SETOPT_OTP_FUNC_DEF(debug); \ + ESOCK_SETOPT_OTP_FUNC_DEF(iow); \ + ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \ + ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(meta); \ ESOCK_SETOPT_OTP_FUNC_DEF(use_registry); -#define ESOCK_SETOPT_OTP_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ +#define ESOCK_SETOPT_OTP_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ ERL_NIF_TERM eVal) ESOCK_SETOPT_OTP_FUNCS #undef ESOCK_SETOPT_OTP_FUNC_DEF -/* Set native options */ -static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal); +static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt); +/* *** esock_getopt_otp_debug *** + * *** esock_getopt_otp_iow *** + * *** esock_getopt_otp_ctrl_proc *** + * *** esock_getopt_otp_rcvbuf *** + * *** esock_getopt_otp_rcvctrlbuf *** + * *** esock_getopt_otp_sndctrlbuf *** + * *** esock_getopt_otp_fd *** + * *** esock_getopt_otp_meta *** + * *** esock_getopt_otp_use_registry *** + * *** esock_getopt_otp_domain *** + * *** //esock_getopt_otp_type *** + * *** //esock_getopt_otp_protocol *** + * *** //esock_getopt_otp_dtp *** + */ +#define ESOCK_GETOPT_OTP_FUNCS \ + ESOCK_GETOPT_OTP_FUNC_DEF(debug); \ + ESOCK_GETOPT_OTP_FUNC_DEF(iow); \ + ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \ + ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(fd); \ + ESOCK_GETOPT_OTP_FUNC_DEF(meta); \ + ESOCK_GETOPT_OTP_FUNC_DEF(use_registry); \ + ESOCK_GETOPT_OTP_FUNC_DEF(domain); +#if 0 +ESOCK_GETOPT_OTP_FUNC_DEF(type); \ +ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \ +ESOCK_GETOPT_OTP_FUNC_DEF(dtp); +#endif +#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) +ESOCK_GETOPT_OTP_FUNCS +#undef ESOCK_GETOPT_OTP_FUNC_DEF + +static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + void* optVal, + socklen_t optLen); +static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + SOCKOPTLEN_T valueSz); +static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ErlNifBinary* binP); + +static int socket_setopt(int sock, + int level, + int opt, + const void* optVal, + const socklen_t optLen); + +static int cmpESockOpt(const void *vpa, const void *vpb); +static int cmpESockOptLevel(const void *vpa, const void *vpb); +static struct ESockOpt *lookupOpt(int level, int opt); + + +static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key); + +static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env); + +#ifndef __WIN32__ +/* ---------------------------------------------------------------------- * + * * + * * + * Start of non-__WIN32__ section a.k.a UNIX section * + * * + * * + * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ + +/* *** esock_activate_next_acceptor *** + * *** esock_activate_next_writer *** + * *** esock_activate_next_reader *** + * + * All the activate-next functions for acceptor, writer and reader + * have exactly the same API, so we apply some macro magic to simplify. + * They simply operates on dufferent data structures. + * + */ + +#define ACTIVATE_NEXT_FUNCS_DEFS \ + ACTIVATE_NEXT_FUNC_DEF(acceptor) \ + ACTIVATE_NEXT_FUNC_DEF(writer) \ + ACTIVATE_NEXT_FUNC_DEF(reader) + +#define ACTIVATE_NEXT_FUNC_DEF(F) \ + extern BOOLEAN_T esock_activate_next_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM sockRef); +ACTIVATE_NEXT_FUNCS_DEFS +#undef ACTIVATE_NEXT_FUNC_DEF + +/* esock_acceptor_search4pid | esock_writer_search4pid | esock_reader_search4pid + * esock_acceptor_push | esock_writer_push | esock_reader_push + * esock_acceptor_pop | esock_writer_pop | esock_reader_pop + * esock_acceptor_unqueue | esock_writer_unqueue | esock_reader_unqueue + * + * All the queue operator functions (search4pid, push, pop + * and unqueue) for acceptor, writer and reader has exactly + * the same API, so we apply some macro magic to simplify. + */ + +#define ESOCK_OPERATOR_FUNCS_DEFS \ + ESOCK_OPERATOR_FUNCS_DEF(acceptor) \ + ESOCK_OPERATOR_FUNCS_DEF(writer) \ + ESOCK_OPERATOR_FUNCS_DEF(reader) + +#define ESOCK_OPERATOR_FUNCS_DEF(O) \ + extern BOOLEAN_T esock_##O##_search4pid(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid* pid); \ + extern void esock_##O##_push(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid pid, \ + ERL_NIF_TERM ref, \ + void* dataP); \ + extern BOOLEAN_T esock_##O##_pop(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ESockRequestor* reqP); \ + extern BOOLEAN_T esock_##O##_unqueue(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP); +ESOCK_OPERATOR_FUNCS_DEFS +#undef ESOCK_OPERATOR_FUNCS_DEF + +static ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); + + +/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * + * * + * * + * End of non-__WIN32__ section a.k.a UNIX section * + * * + * * + * ---------------------------------------------------------------------- */ +#endif // #ifndef __WIN32__ + + static ERL_NIF_TERM esock_setopt(ErlNifEnv* env, ESockDescriptor* descP, int level, @@ -1872,50 +1550,6 @@ static ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, #endif // defined(HAVE_SCTP) -static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, - ESockDescriptor* descP, - int eOpt); -/* *** esock_getopt_otp_debug *** - * *** esock_getopt_otp_iow *** - * *** esock_getopt_otp_ctrl_proc *** - * *** esock_getopt_otp_rcvbuf *** - * *** esock_getopt_otp_rcvctrlbuf *** - * *** esock_getopt_otp_sndctrlbuf *** - * *** esock_getopt_otp_fd *** - * *** esock_getopt_otp_meta *** - * *** esock_getopt_otp_use_registry *** - * *** esock_getopt_otp_domain *** - * *** //esock_getopt_otp_type *** - * *** //esock_getopt_otp_protocol *** - * *** //esock_getopt_otp_dtp *** - */ -#define ESOCK_GETOPT_OTP_FUNCS \ - ESOCK_GETOPT_OTP_FUNC_DEF(debug); \ - ESOCK_GETOPT_OTP_FUNC_DEF(iow); \ - ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \ - ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(fd); \ - ESOCK_GETOPT_OTP_FUNC_DEF(meta); \ - ESOCK_GETOPT_OTP_FUNC_DEF(use_registry); \ - ESOCK_GETOPT_OTP_FUNC_DEF(domain); -#if 0 - ESOCK_GETOPT_OTP_FUNC_DEF(type); \ - ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \ - ESOCK_GETOPT_OTP_FUNC_DEF(dtp); -#endif -#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \ - ESockDescriptor* descP) -ESOCK_GETOPT_OTP_FUNCS -#undef ESOCK_GETOPT_OTP_FUNC_DEF - -static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM valueSpec); static ERL_NIF_TERM esock_getopt(ErlNifEnv* env, ESockDescriptor* descP, int level, @@ -1952,9 +1586,9 @@ ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, #if defined(IP_MTU_DISCOVER) static ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); + ESockDescriptor* descP, + int level, + int opt); #endif #if defined(IP_MULTICAST_IF) static ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, @@ -2020,300 +1654,6 @@ static ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env, #endif // defined(HAVE_SCTP) -static ERL_NIF_TERM esock_sockname(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_peername(ErlNifEnv* env, - ESockDescriptor* descP); - -static ERL_NIF_TERM esock_ioctl1(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req); -static ERL_NIF_TERM esock_ioctl2(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM arg); -static ERL_NIF_TERM esock_ioctl3(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM ename, - ERL_NIF_TERM eval); -static ERL_NIF_TERM esock_ioctl_gifconf(ErlNifEnv* env, - ESockDescriptor* descP); -#if defined(SIOCGIFNAME) -static ERL_NIF_TERM esock_ioctl_gifname(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eidx); -#endif - -/* esock_ioctl_gifindex */ -#if defined(SIOCGIFINDEX) -#define IOCTL_GIFINDEX_FUNC_DEF IOCTL_GET_FUNC_DEF(gifindex) -#else -#define IOCTL_GIFINDEX_FUNC_DEF -#endif - -/* esock_ioctl_gifflags */ -#if defined(SIOCGIFFLAGS) -#define IOCTL_GIFFLAGS_FUNC_DEF IOCTL_GET_FUNC_DEF(gifflags) -#else -#define IOCTL_GIFFLAGS_FUNC_DEF -#endif - -/* esock_ioctl_gifaddr */ -#if defined(SIOCGIFADDR) -#define IOCTL_GIFADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifaddr) -#else -#define IOCTL_GIFADDR_FUNC_DEF -#endif - -/* esock_ioctl_gifdstaddr */ -#if defined(SIOCGIFDSTADDR) -#define IOCTL_GIFDSTADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifdstaddr) -#else -#define IOCTL_GIFDSTADDR_FUNC_DEF -#endif - -/* esock_ioctl_gifbrdaddr */ -#if defined(SIOCGIFBRDADDR) -#define IOCTL_GIFBRDADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifbrdaddr) -#else -#define IOCTL_GIFBRDADDR_FUNC_DEF -#endif - -/* esock_ioctl_gifnetmask */ -#if defined(SIOCGIFNETMASK) -#define IOCTL_GIFNETMASK_FUNC_DEF IOCTL_GET_FUNC_DEF(gifnetmask) -#else -#define IOCTL_GIFNETMASK_FUNC_DEF -#endif - -/* esock_ioctl_gifmtu */ -#if defined(SIOCGIFMTU) -#define IOCTL_GIFMTU_FUNC_DEF IOCTL_GET_FUNC_DEF(gifmtu) -#else -#define IOCTL_GIFMTU_FUNC_DEF -#endif - -/* esock_ioctl_gifhwaddr */ -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -#define IOCTL_GIFHWADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifhwaddr) -#else -#define IOCTL_GIFHWADDR_FUNC_DEF -#endif - -/* esock_ioctl_gifmap */ -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -#define IOCTL_GIFMAP_FUNC_DEF IOCTL_GET_FUNC_DEF(gifmap) -#else -#define IOCTL_GIFMAP_FUNC_DEF -#endif - -/* esock_ioctl_giftxqlen */ -#if defined(SIOCGIFTXQLEN) -#define IOCTL_GIFTXQLEN_FUNC_DEF IOCTL_GET_FUNC_DEF(giftxqlen) -#else -#define IOCTL_GIFTXQLEN_FUNC_DEF -#endif - -#define IOCTL_GET_FUNCS_DEF \ - IOCTL_GIFINDEX_FUNC_DEF; \ - IOCTL_GIFFLAGS_FUNC_DEF; \ - IOCTL_GIFADDR_FUNC_DEF; \ - IOCTL_GIFDSTADDR_FUNC_DEF; \ - IOCTL_GIFBRDADDR_FUNC_DEF; \ - IOCTL_GIFNETMASK_FUNC_DEF; \ - IOCTL_GIFMTU_FUNC_DEF; \ - IOCTL_GIFHWADDR_FUNC_DEF; \ - IOCTL_GIFMAP_FUNC_DEF; \ - IOCTL_GIFTXQLEN_FUNC_DEF; -#define IOCTL_GET_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_ioctl_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename) -IOCTL_GET_FUNCS_DEF -#undef IOCTL_GET_FUNC_DEF - -/* esock_ioctl_sifflags */ -#if defined(SIOCSIFFLAGS) -#define IOCTL_SIFFLAGS_FUNC_DEF IOCTL_SET_FUNC_DEF(sifflags) -#else -#define IOCTL_SIFFLAGS_FUNC_DEF -#endif - -/* esock_ioctl_sifaddr */ -#if defined(SIOCSIFADDR) -#define IOCTL_SIFADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifaddr) -#else -#define IOCTL_SIFADDR_FUNC_DEF -#endif - -/* esock_ioctl_sifdstaddr */ -#if defined(SIOCSIFDSTADDR) -#define IOCTL_SIFDSTADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifdstaddr) -#else -#define IOCTL_SIFDSTADDR_FUNC_DEF -#endif - -/* esock_ioctl_sifbrdaddr */ -#if defined(SIOCSIFBRDADDR) -#define IOCTL_SIFBRDADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifbrdaddr) -#else -#define IOCTL_SIFBRDADDR_FUNC_DEF -#endif - -/* esock_ioctl_sifnetmask */ -#if defined(SIOCSIFNETMASK) -#define IOCTL_SIFNETMASK_FUNC_DEF IOCTL_SET_FUNC_DEF(sifnetmask) -#else -#define IOCTL_SIFNETMASK_FUNC_DEF -#endif - -/* esock_ioctl_sifmtu */ -#if defined(SIOCSIFMTU) -#define IOCTL_SIFMTU_FUNC_DEF IOCTL_SET_FUNC_DEF(sifmtu) -#else -#define IOCTL_SIFMTU_FUNC_DEF -#endif - -/* esock_ioctl_siftxqlen */ -#if defined(SIOCSIFTXQLEN) -#define IOCTL_SIFTXQLEN_FUNC_DEF IOCTL_SET_FUNC_DEF(siftxqlen) -#else -#define IOCTL_SIFTXQLEN_FUNC_DEF -#endif - -#define IOCTL_SET_FUNCS_DEF \ - IOCTL_SIFFLAGS_FUNC_DEF; \ - IOCTL_SIFADDR_FUNC_DEF; \ - IOCTL_SIFDSTADDR_FUNC_DEF; \ - IOCTL_SIFBRDADDR_FUNC_DEF; \ - IOCTL_SIFNETMASK_FUNC_DEF; \ - IOCTL_SIFMTU_FUNC_DEF; \ - IOCTL_SIFTXQLEN_FUNC_DEF; -#define IOCTL_SET_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_ioctl_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename, \ - ERL_NIF_TERM evalue) -IOCTL_SET_FUNCS_DEF -#undef IOCTL_SET_FUNC_DEF - - -static ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifconf* ifcP); -static ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifreq* ifrP); -static ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, - char* name); -static ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, - struct sockaddr* sa); -static ERL_NIF_TERM make_ifreq(ErlNifEnv* env, - ERL_NIF_TERM name, - ERL_NIF_TERM key2, - ERL_NIF_TERM val2); -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -static ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifmap* mapP); -#endif -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP); -#endif -static ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP); -static ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - short flags); -#if defined(SIOCSIFFLAGS) -static BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eflags, - short* flags); -#endif -static BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eaddr, - ESockAddress* addr); -#if defined(SIOCSIFMTU) -static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM emtu, - int* mtu); -#endif -#if defined(SIOCSIFTXQLEN) -static BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM etxqlen, - int* txqlen); -#endif -#if defined(SIOCSIFTXQLEN) -static BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eivalue, - int* ivalue); -#endif -static ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - int ivalue); - -static ERL_NIF_TERM esock_cancel(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM op, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); -static ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); -static ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); -static ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - int smode, - int rmode); - #if defined(USE_SETOPT_STR_OPT) static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -2332,7 +1672,7 @@ static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, int level, int opt, ERL_NIF_TERM eVal); -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ && defined(ESOCK_USE_RCVSNDTIMEO) static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -2340,13 +1680,6 @@ static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, int opt, ERL_NIF_TERM eVal); #endif -static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - void* optVal, - socklen_t optLen); - #if defined(USE_GETOPT_STR_OPT) static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -2355,29 +1688,7 @@ static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, int max, BOOLEAN_T stripNUL); #endif -static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); -static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); -static BOOLEAN_T esock_getopt_int(SOCKET sock, - int level, - int opt, - int* valP); -static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - SOCKOPTLEN_T valueSz); -static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ErlNifBinary* binP); -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ && defined(ESOCK_USE_RCVSNDTIMEO) static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -2387,36 +1698,948 @@ static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, -/* ------------------------------------------------------------------------ - * Socket option tables and handling + + + + +static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, + ESockDescriptor* descP, + int how); +static ERL_NIF_TERM esock_sockname(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_peername(ErlNifEnv* env, + ESockDescriptor* descP); + +static ERL_NIF_TERM esock_command(ErlNifEnv* env, + ERL_NIF_TERM command, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, + ERL_NIF_TERM cdata); + +#define ESOCK_SOCKET_INFO_REQ_FUNCS \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors); + +#define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ + ESockDescriptor* descP); +ESOCK_SOCKET_INFO_REQ_FUNCS +#undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF + +static ERL_NIF_TERM esock_cancel(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM op, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +/* +static ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +*/ +static ERL_NIF_TERM esock_listen(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog); + +static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, + ESockDescriptor* descP, +#ifndef __WIN32__ + ESockRequestor* currentRequestorP, +#endif + ESockRequestQueue* q); + +static ERL_NIF_TERM esock_global_info(ErlNifEnv* env); +static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, + unsigned int state); +static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, + ESockDescriptor* descP); + +static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM closeRef); +static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, + ERL_NIF_TERM tag, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_simple_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); +static BOOLEAN_T qsearch4pid(ErlNifEnv* env, + ESockRequestQueue* q, + ErlNifPid* pid); +static unsigned int qlength(ESockRequestQueue* q); +static void qpush(ESockRequestQueue* q, + ESockRequestQueueElement* e); +static ESockRequestQueueElement* qpop(ESockRequestQueue* q); +static BOOLEAN_T qunqueue(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP); +static ESockRequestQueueElement* qget(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP); + +static char* extract_debug_filename(ErlNifEnv* env, + ERL_NIF_TERM map); + + +/* --------------------------------------------------------------------- */ + +#if defined(IP_TOS) +static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IP_MTU_DISCOVER) +static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IP_MTU_DISCOVER) +static void encode_ip_pmtudisc(ErlNifEnv* env, + int val, + ERL_NIF_TERM* eVal); +#endif +#if defined(IPV6_MTU_DISCOVER) +static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IPV6_MTU_DISCOVER) +static void encode_ipv6_pmtudisc(ErlNifEnv* env, + int val, + ERL_NIF_TERM* eVal); +#endif + +static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val); + +#if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) +static +BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val); +#endif + +#if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) +static BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env, + ERL_NIF_TERM eVal, + sctp_assoc_t* val); +static ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, + sctp_assoc_t val); +#endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) + + +static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how); + + +/* +#if defined(HAS_AF_LOCAL) || defined(SO_BINDTODEVICE) +static size_t my_strnlen(const char *s, size_t maxlen); +#endif +*/ + +static void esock_dtor(ErlNifEnv* env, void* obj); +static void esock_stop(ErlNifEnv* env, + void* obj, + ErlNifEvent fd, + int is_direct_call); +static void esock_down(ErlNifEnv* env, + void* obj, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +static void esock_on_halt(void* priv_data); + +static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + + + +#if HAVE_IN6 +# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY +# if HAVE_DECL_IN6ADDR_ANY_INIT +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; +# else +static const struct in6_addr in6addr_any = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +# endif /* HAVE_IN6ADDR_ANY_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_ANY */ + +# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK +# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT +static const struct in6_addr in6addr_loopback = + { { IN6ADDR_LOOPBACK_INIT } }; +# else +static const struct in6_addr in6addr_loopback = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ +#endif /* HAVE_IN6 */ + + + +/* *** Global atoms *** + * Note that when an (global) atom is added here, it must also be added + * in the socket_int.h file! */ +#define GLOBAL_ATOMS \ + GLOBAL_ATOM_DECL(abort); \ + GLOBAL_ATOM_DECL(accept); \ + GLOBAL_ATOM_DECL(acceptconn); \ + GLOBAL_ATOM_DECL(acceptfilter); \ + GLOBAL_ATOM_DECL(acc_success); \ + GLOBAL_ATOM_DECL(acc_fails); \ + GLOBAL_ATOM_DECL(acc_tries); \ + GLOBAL_ATOM_DECL(acc_waits); \ + GLOBAL_ATOM_DECL(adaption_layer); \ + GLOBAL_ATOM_DECL(addr); \ + GLOBAL_ATOM_DECL(addrform); \ + GLOBAL_ATOM_DECL(add_membership); \ + GLOBAL_ATOM_DECL(add_socket); \ + GLOBAL_ATOM_DECL(add_source_membership); \ + GLOBAL_ATOM_DECL(alen); \ + GLOBAL_ATOM_DECL(allmulti); \ + GLOBAL_ATOM_DECL(already); \ + GLOBAL_ATOM_DECL(any); \ + GLOBAL_ATOM_DECL(appletlk); \ + GLOBAL_ATOM_DECL(arcnet); \ + GLOBAL_ATOM_DECL(associnfo); \ + GLOBAL_ATOM_DECL(atm); \ + GLOBAL_ATOM_DECL(authhdr); \ + GLOBAL_ATOM_DECL(auth_active_key); \ + GLOBAL_ATOM_DECL(auth_asconf); \ + GLOBAL_ATOM_DECL(auth_chunk); \ + GLOBAL_ATOM_DECL(auth_delete_key); \ + GLOBAL_ATOM_DECL(auth_key); \ + GLOBAL_ATOM_DECL(auth_level); \ + GLOBAL_ATOM_DECL(autoclose); \ + GLOBAL_ATOM_DECL(automedia); \ + GLOBAL_ATOM_DECL(ax25); \ + GLOBAL_ATOM_DECL(bad_data); \ + GLOBAL_ATOM_DECL(base_addr); \ + GLOBAL_ATOM_DECL(bindtodevice); \ + GLOBAL_ATOM_DECL(block_source); \ + GLOBAL_ATOM_DECL(broadcast); \ + GLOBAL_ATOM_DECL(busy_poll); \ + GLOBAL_ATOM_DECL(cancel); \ + GLOBAL_ATOM_DECL(cantconfig); \ + GLOBAL_ATOM_DECL(chaos); \ + GLOBAL_ATOM_DECL(checksum); \ + GLOBAL_ATOM_DECL(close); \ + GLOBAL_ATOM_DECL(closed); \ + GLOBAL_ATOM_DECL(cmsg_cloexec); \ + GLOBAL_ATOM_DECL(command); \ + GLOBAL_ATOM_DECL(completion); \ + GLOBAL_ATOM_DECL(completion_status); \ + GLOBAL_ATOM_DECL(confirm); \ + GLOBAL_ATOM_DECL(congestion); \ + GLOBAL_ATOM_DECL(connect); \ + GLOBAL_ATOM_DECL(connected); \ + GLOBAL_ATOM_DECL(connecting); \ + GLOBAL_ATOM_DECL(context); \ + GLOBAL_ATOM_DECL(cork); \ + GLOBAL_ATOM_DECL(counters); \ + GLOBAL_ATOM_DECL(credentials); \ + GLOBAL_ATOM_DECL(ctrl); \ + GLOBAL_ATOM_DECL(ctrunc); \ + GLOBAL_ATOM_DECL(data); \ + GLOBAL_ATOM_DECL(data_size); \ + GLOBAL_ATOM_DECL(debug); \ + GLOBAL_ATOM_DECL(default); \ + GLOBAL_ATOM_DECL(default_send_params); \ + GLOBAL_ATOM_DECL(delayed_ack_time); \ + GLOBAL_ATOM_DECL(dgram); \ + GLOBAL_ATOM_DECL(disable_fragments); \ + GLOBAL_ATOM_DECL(dlci); \ + GLOBAL_ATOM_DECL(dma); \ + GLOBAL_ATOM_DECL(domain); \ + GLOBAL_ATOM_DECL(dontfrag); \ + GLOBAL_ATOM_DECL(dontroute); \ + GLOBAL_ATOM_DECL(dormant); \ + GLOBAL_ATOM_DECL(drop_membership); \ + GLOBAL_ATOM_DECL(drop_source_membership); \ + GLOBAL_ATOM_DECL(dstopts); \ + GLOBAL_ATOM_DECL(dup); \ + GLOBAL_ATOM_DECL(dying); \ + GLOBAL_ATOM_DECL(dynamic); \ + GLOBAL_ATOM_DECL(echo); \ + GLOBAL_ATOM_DECL(eether); \ + GLOBAL_ATOM_DECL(efile); \ + GLOBAL_ATOM_DECL(egp); \ + GLOBAL_ATOM_DECL(enotsup); \ + GLOBAL_ATOM_DECL(eor); \ + GLOBAL_ATOM_DECL(error); \ + GLOBAL_ATOM_DECL(errqueue); \ + GLOBAL_ATOM_DECL(esp_network_level); \ + GLOBAL_ATOM_DECL(esp_trans_level); \ + GLOBAL_ATOM_DECL(ether); \ + GLOBAL_ATOM_DECL(eui64); \ + GLOBAL_ATOM_DECL(events); \ + GLOBAL_ATOM_DECL(explicit_eor); \ + GLOBAL_ATOM_DECL(faith); \ + GLOBAL_ATOM_DECL(false); \ + GLOBAL_ATOM_DECL(family); \ + GLOBAL_ATOM_DECL(fastroute); \ + GLOBAL_ATOM_DECL(flags); \ + GLOBAL_ATOM_DECL(flowinfo); \ + GLOBAL_ATOM_DECL(fragment_interleave); \ + GLOBAL_ATOM_DECL(freebind); \ + GLOBAL_ATOM_DECL(frelay); \ + GLOBAL_ATOM_DECL(get_overlapped_result); \ + GLOBAL_ATOM_DECL(get_peer_addr_info); \ + GLOBAL_ATOM_DECL(hatype); \ + GLOBAL_ATOM_DECL(hdrincl); \ + GLOBAL_ATOM_DECL(hmac_ident); \ + GLOBAL_ATOM_DECL(hoplimit); \ + GLOBAL_ATOM_DECL(hopopts); \ + GLOBAL_ATOM_DECL(host); \ + GLOBAL_ATOM_DECL(icmp); \ + GLOBAL_ATOM_DECL(icmp6); \ + GLOBAL_ATOM_DECL(ieee802); \ + GLOBAL_ATOM_DECL(ieee1394); \ + GLOBAL_ATOM_DECL(ifindex); \ + GLOBAL_ATOM_DECL(igmp); \ + GLOBAL_ATOM_DECL(implink); \ + GLOBAL_ATOM_DECL(index); \ + GLOBAL_ATOM_DECL(inet); \ + GLOBAL_ATOM_DECL(inet6); \ + GLOBAL_ATOM_DECL(infiniband); \ + GLOBAL_ATOM_DECL(info); \ + GLOBAL_ATOM_DECL(initmsg); \ + GLOBAL_ATOM_DECL(invalid); \ + GLOBAL_ATOM_DECL(integer_range); \ + GLOBAL_ATOM_DECL(iov); \ + GLOBAL_ATOM_DECL(ip); \ + GLOBAL_ATOM_DECL(ipcomp_level); \ + GLOBAL_ATOM_DECL(ipip); \ + GLOBAL_ATOM_DECL(ipv6); \ + GLOBAL_ATOM_DECL(irq); \ + GLOBAL_ATOM_DECL(i_want_mapped_v4_addr); \ + GLOBAL_ATOM_DECL(join_group); \ + GLOBAL_ATOM_DECL(keepalive); \ + GLOBAL_ATOM_DECL(keepcnt); \ + GLOBAL_ATOM_DECL(keepidle); \ + GLOBAL_ATOM_DECL(keepintvl); \ + GLOBAL_ATOM_DECL(kernel); \ + GLOBAL_ATOM_DECL(knowsepoch); \ + GLOBAL_ATOM_DECL(leave_group); \ + GLOBAL_ATOM_DECL(level); \ + GLOBAL_ATOM_DECL(linger); \ + GLOBAL_ATOM_DECL(link); \ + GLOBAL_ATOM_DECL(link0); \ + GLOBAL_ATOM_DECL(link1); \ + GLOBAL_ATOM_DECL(link2); \ + GLOBAL_ATOM_DECL(local); \ + GLOBAL_ATOM_DECL(localtlk); \ + GLOBAL_ATOM_DECL(local_auth_chunks); \ + GLOBAL_ATOM_DECL(loopback); \ + GLOBAL_ATOM_DECL(lowdelay); \ + GLOBAL_ATOM_DECL(lower_up); \ + GLOBAL_ATOM_DECL(mark); \ + GLOBAL_ATOM_DECL(master); \ + GLOBAL_ATOM_DECL(maxburst); \ + GLOBAL_ATOM_DECL(maxseg); \ + GLOBAL_ATOM_DECL(md5sig); \ + GLOBAL_ATOM_DECL(mem_end); \ + GLOBAL_ATOM_DECL(mem_start); \ + GLOBAL_ATOM_DECL(metricom); \ + GLOBAL_ATOM_DECL(mincost); \ + GLOBAL_ATOM_DECL(minttl); \ + GLOBAL_ATOM_DECL(monitor); \ + GLOBAL_ATOM_DECL(more); \ + GLOBAL_ATOM_DECL(msfilter); \ + GLOBAL_ATOM_DECL(mtu); \ + GLOBAL_ATOM_DECL(mtu_discover); \ + GLOBAL_ATOM_DECL(multicast); \ + GLOBAL_ATOM_DECL(multicast_all); \ + GLOBAL_ATOM_DECL(multicast_hops); \ + GLOBAL_ATOM_DECL(multicast_if); \ + GLOBAL_ATOM_DECL(multicast_loop); \ + GLOBAL_ATOM_DECL(multicast_ttl); \ + GLOBAL_ATOM_DECL(name); \ + GLOBAL_ATOM_DECL(netns); \ + GLOBAL_ATOM_DECL(netrom); \ + GLOBAL_ATOM_DECL(nlen); \ + GLOBAL_ATOM_DECL(noarp); \ + GLOBAL_ATOM_DECL(nodelay); \ + GLOBAL_ATOM_DECL(nodefrag); \ + GLOBAL_ATOM_DECL(nogroup); \ + GLOBAL_ATOM_DECL(none); \ + GLOBAL_ATOM_DECL(noopt); \ + GLOBAL_ATOM_DECL(nopush); \ + GLOBAL_ATOM_DECL(nosignal); \ + GLOBAL_ATOM_DECL(notrailers); \ + GLOBAL_ATOM_DECL(not_bound); \ + GLOBAL_ATOM_DECL(not_found); \ + GLOBAL_ATOM_DECL(num_general_errors); \ + GLOBAL_ATOM_DECL(not_owner); \ + GLOBAL_ATOM_DECL(num_threads); \ + GLOBAL_ATOM_DECL(num_unexpected_accepts); \ + GLOBAL_ATOM_DECL(num_unexpected_connects); \ + GLOBAL_ATOM_DECL(num_unexpected_reads); \ + GLOBAL_ATOM_DECL(num_unexpected_writes); \ + GLOBAL_ATOM_DECL(num_unknown_cmds); \ + GLOBAL_ATOM_DECL(oactive); \ + GLOBAL_ATOM_DECL(ok); \ + GLOBAL_ATOM_DECL(oob); \ + GLOBAL_ATOM_DECL(oobinline); \ + GLOBAL_ATOM_DECL(options); \ + GLOBAL_ATOM_DECL(origdstaddr); \ + GLOBAL_ATOM_DECL(otherhost); \ + GLOBAL_ATOM_DECL(outgoing); \ + GLOBAL_ATOM_DECL(packet); \ + GLOBAL_ATOM_DECL(partial_delivery_point); \ + GLOBAL_ATOM_DECL(passcred); \ + GLOBAL_ATOM_DECL(path); \ + GLOBAL_ATOM_DECL(peek); \ + GLOBAL_ATOM_DECL(peek_off); \ + GLOBAL_ATOM_DECL(peer_addr_params); \ + GLOBAL_ATOM_DECL(peer_auth_chunks); \ + GLOBAL_ATOM_DECL(peercred); \ + GLOBAL_ATOM_DECL(pktinfo); \ + GLOBAL_ATOM_DECL(pktoptions); \ + GLOBAL_ATOM_DECL(pkttype); \ + GLOBAL_ATOM_DECL(pointopoint); \ + GLOBAL_ATOM_DECL(port); \ + GLOBAL_ATOM_DECL(portrange); \ + GLOBAL_ATOM_DECL(portsel); \ + GLOBAL_ATOM_DECL(ppromisc); \ + GLOBAL_ATOM_DECL(primary_addr); \ + GLOBAL_ATOM_DECL(prim_file); \ + GLOBAL_ATOM_DECL(priority); \ + GLOBAL_ATOM_DECL(promisc); \ + GLOBAL_ATOM_DECL(pronet); \ + GLOBAL_ATOM_DECL(protocol); \ + GLOBAL_ATOM_DECL(pup); \ + GLOBAL_ATOM_DECL(raw); \ + GLOBAL_ATOM_DECL(rcvbuf); \ + GLOBAL_ATOM_DECL(rcvbufforce); \ + GLOBAL_ATOM_DECL(rcvlowat); \ + GLOBAL_ATOM_DECL(rcvtimeo); \ + GLOBAL_ATOM_DECL(rdm); \ + GLOBAL_ATOM_DECL(read_byte); \ + GLOBAL_ATOM_DECL(read_fails); \ + GLOBAL_ATOM_DECL(read_pkg); \ + GLOBAL_ATOM_DECL(read_tries); \ + GLOBAL_ATOM_DECL(read_waits); \ + GLOBAL_ATOM_DECL(recv); \ + GLOBAL_ATOM_DECL(recvdstaddr); \ + GLOBAL_ATOM_DECL(recverr); \ + GLOBAL_ATOM_DECL(recvfrom); \ + GLOBAL_ATOM_DECL(recvhoplimit); \ + GLOBAL_ATOM_DECL(recvif); \ + GLOBAL_ATOM_DECL(recvmsg); \ + GLOBAL_ATOM_DECL(recvopts); \ + GLOBAL_ATOM_DECL(recvorigdstaddr); \ + GLOBAL_ATOM_DECL(recvpktinfo); \ + GLOBAL_ATOM_DECL(recvtclass); \ + GLOBAL_ATOM_DECL(recvtos); \ + GLOBAL_ATOM_DECL(recvttl); \ + GLOBAL_ATOM_DECL(reliability); \ + GLOBAL_ATOM_DECL(renaming); \ + GLOBAL_ATOM_DECL(reset_streams); \ + GLOBAL_ATOM_DECL(retopts); \ + GLOBAL_ATOM_DECL(reuseaddr); \ + GLOBAL_ATOM_DECL(reuseport); \ + GLOBAL_ATOM_DECL(rights); \ + GLOBAL_ATOM_DECL(router_alert); \ + GLOBAL_ATOM_DECL(rthdr); \ + GLOBAL_ATOM_DECL(rtoinfo); \ + GLOBAL_ATOM_DECL(running); \ + GLOBAL_ATOM_DECL(rxq_ovfl); \ + GLOBAL_ATOM_DECL(scope_id); \ + GLOBAL_ATOM_DECL(sctp); \ + GLOBAL_ATOM_DECL(sec); \ + GLOBAL_ATOM_DECL(select); \ + GLOBAL_ATOM_DECL(select_failed); \ + GLOBAL_ATOM_DECL(select_sent); \ + GLOBAL_ATOM_DECL(send); \ + GLOBAL_ATOM_DECL(sendfile); \ + GLOBAL_ATOM_DECL(sendfile_byte); \ + GLOBAL_ATOM_DECL(sendfile_deferred_close); \ + GLOBAL_ATOM_DECL(sendfile_fails); \ + GLOBAL_ATOM_DECL(sendfile_max); \ + GLOBAL_ATOM_DECL(sendfile_pkg); \ + GLOBAL_ATOM_DECL(sendfile_pkg_max); \ + GLOBAL_ATOM_DECL(sendfile_tries); \ + GLOBAL_ATOM_DECL(sendfile_waits); \ + GLOBAL_ATOM_DECL(sendmsg); \ + GLOBAL_ATOM_DECL(sendsrcaddr); \ + GLOBAL_ATOM_DECL(sendto); \ + GLOBAL_ATOM_DECL(seqpacket); \ + GLOBAL_ATOM_DECL(setfib); \ + GLOBAL_ATOM_DECL(set_peer_primary_addr); \ + GLOBAL_ATOM_DECL(simplex); \ + GLOBAL_ATOM_DECL(slave); \ + GLOBAL_ATOM_DECL(slen); \ + GLOBAL_ATOM_DECL(sndbuf); \ + GLOBAL_ATOM_DECL(sndbufforce); \ + GLOBAL_ATOM_DECL(sndlowat); \ + GLOBAL_ATOM_DECL(sndtimeo); \ + GLOBAL_ATOM_DECL(sockaddr); \ + GLOBAL_ATOM_DECL(socket); \ + GLOBAL_ATOM_DECL(spec_dst); \ + GLOBAL_ATOM_DECL(staticarp); \ + GLOBAL_ATOM_DECL(state); \ + GLOBAL_ATOM_DECL(status); \ + GLOBAL_ATOM_DECL(stream); \ + GLOBAL_ATOM_DECL(syncnt); \ + GLOBAL_ATOM_DECL(tclass); \ + GLOBAL_ATOM_DECL(tcp); \ + GLOBAL_ATOM_DECL(throughput); \ + GLOBAL_ATOM_DECL(timestamp); \ + GLOBAL_ATOM_DECL(tos); \ + GLOBAL_ATOM_DECL(transparent); \ + GLOBAL_ATOM_DECL(timeout); \ + GLOBAL_ATOM_DECL(true); \ + GLOBAL_ATOM_DECL(trunc); \ + GLOBAL_ATOM_DECL(ttl); \ + GLOBAL_ATOM_DECL(tunnel); \ + GLOBAL_ATOM_DECL(tunnel6); \ + GLOBAL_ATOM_DECL(txqlen); \ + GLOBAL_ATOM_DECL(type); \ + GLOBAL_ATOM_DECL(udp); \ + GLOBAL_ATOM_DECL(unblock_source); \ + GLOBAL_ATOM_DECL(undefined); \ + GLOBAL_ATOM_DECL(unicast_hops); \ + GLOBAL_ATOM_DECL(unknown); \ + GLOBAL_ATOM_DECL(unspec); \ + GLOBAL_ATOM_DECL(up); \ + GLOBAL_ATOM_DECL(update_accept_context); \ + GLOBAL_ATOM_DECL(update_connect_context); \ + GLOBAL_ATOM_DECL(usec); \ + GLOBAL_ATOM_DECL(user); \ + GLOBAL_ATOM_DECL(user_timeout); \ + GLOBAL_ATOM_DECL(use_ext_recvinfo); \ + GLOBAL_ATOM_DECL(use_min_mtu); \ + GLOBAL_ATOM_DECL(use_registry); \ + GLOBAL_ATOM_DECL(value); \ + GLOBAL_ATOM_DECL(void); \ + GLOBAL_ATOM_DECL(v6only); \ + GLOBAL_ATOM_DECL(write_byte); \ + GLOBAL_ATOM_DECL(write_fails); \ + GLOBAL_ATOM_DECL(write_pkg); \ + GLOBAL_ATOM_DECL(write_tries); \ + GLOBAL_ATOM_DECL(write_waits); \ + GLOBAL_ATOM_DECL(zero) -struct ESockOpt -{ - int opt; // Option number - // Function to set option - ERL_NIF_TERM (*setopt) - (ErlNifEnv *env, ESockDescriptor *descP, - int level, int opt, ERL_NIF_TERM eVal); - // Function to get option - ERL_NIF_TERM (*getopt) - (ErlNifEnv *env, ESockDescriptor *descP, - int level, int opt); +/* *** Global error reason atoms *** */ +#define GLOBAL_ERROR_REASON_ATOMS \ + GLOBAL_ATOM_DECL(create_accept_socket); \ + GLOBAL_ATOM_DECL(eagain); \ + GLOBAL_ATOM_DECL(einval); \ + GLOBAL_ATOM_DECL(select_read); \ + GLOBAL_ATOM_DECL(select_write) - ERL_NIF_TERM *nameP; // Pointer to option name atom + +#define GLOBAL_ATOM_DECL(A) ERL_NIF_TERM esock_atom_##A +GLOBAL_ATOMS; +GLOBAL_ERROR_REASON_ATOMS; +#undef GLOBAL_ATOM_DECL +ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket') + +/* *** Local atoms *** */ +#define LOCAL_ATOMS \ + LOCAL_ATOM_DECL(accepting); \ + LOCAL_ATOM_DECL(adaptation_layer); \ + LOCAL_ATOM_DECL(add); \ + LOCAL_ATOM_DECL(addr_unreach); \ + LOCAL_ATOM_DECL(address); \ + LOCAL_ATOM_DECL(adm_prohibited); \ + LOCAL_ATOM_DECL(association); \ + LOCAL_ATOM_DECL(assoc_id); \ + LOCAL_ATOM_DECL(authentication); \ + LOCAL_ATOM_DECL(boolean); \ + LOCAL_ATOM_DECL(bound); \ + LOCAL_ATOM_DECL(bufsz); \ + LOCAL_ATOM_DECL(close); \ + LOCAL_ATOM_DECL(closing); \ + LOCAL_ATOM_DECL(code); \ + LOCAL_ATOM_DECL(cookie_life); \ + LOCAL_ATOM_DECL(counter_wrap); \ + LOCAL_ATOM_DECL(ctype); \ + LOCAL_ATOM_DECL(data_io); \ + LOCAL_ATOM_DECL(debug_filename); \ + LOCAL_ATOM_DECL(del); \ + LOCAL_ATOM_DECL(dest_unreach); \ + LOCAL_ATOM_DECL(do); \ + LOCAL_ATOM_DECL(dont); \ + LOCAL_ATOM_DECL(dtor); \ + LOCAL_ATOM_DECL(eei); \ + LOCAL_ATOM_DECL(exclude); \ + LOCAL_ATOM_DECL(false); \ + LOCAL_ATOM_DECL(frag_needed); \ + LOCAL_ATOM_DECL(gifaddr); \ + LOCAL_ATOM_DECL(gifbrdaddr); \ + LOCAL_ATOM_DECL(gifconf); \ + LOCAL_ATOM_DECL(gifdstaddr); \ + LOCAL_ATOM_DECL(gifflags); \ + LOCAL_ATOM_DECL(gifhwaddr); \ + LOCAL_ATOM_DECL(gifindex); \ + LOCAL_ATOM_DECL(gifmap); \ + LOCAL_ATOM_DECL(gifmtu); \ + LOCAL_ATOM_DECL(gifname); \ + LOCAL_ATOM_DECL(gifnetmask); \ + LOCAL_ATOM_DECL(giftxqlen); \ + LOCAL_ATOM_DECL(host_unknown); \ + LOCAL_ATOM_DECL(host_unreach); \ + LOCAL_ATOM_DECL(how); \ + LOCAL_ATOM_DECL(in4_sockaddr); \ + LOCAL_ATOM_DECL(in6_sockaddr); \ + LOCAL_ATOM_DECL(include); \ + LOCAL_ATOM_DECL(initial); \ + LOCAL_ATOM_DECL(interface); \ + LOCAL_ATOM_DECL(integer); \ + LOCAL_ATOM_DECL(ioctl_flags); \ + LOCAL_ATOM_DECL(ioctl_requests); \ + LOCAL_ATOM_DECL(iov_max); \ + LOCAL_ATOM_DECL(iow); \ + LOCAL_ATOM_DECL(io_backend); \ + LOCAL_ATOM_DECL(io_num_threads); \ + LOCAL_ATOM_DECL(listening); \ + LOCAL_ATOM_DECL(local_rwnd); \ + LOCAL_ATOM_DECL(map); \ + LOCAL_ATOM_DECL(max); \ + LOCAL_ATOM_DECL(max_attempts); \ + LOCAL_ATOM_DECL(max_init_timeo); \ + LOCAL_ATOM_DECL(max_instreams); \ + LOCAL_ATOM_DECL(asocmaxrxt); \ + LOCAL_ATOM_DECL(min); \ + LOCAL_ATOM_DECL(missing); \ + LOCAL_ATOM_DECL(mode); \ + LOCAL_ATOM_DECL(msg); \ + LOCAL_ATOM_DECL(msg_flags); \ + LOCAL_ATOM_DECL(mtu); \ + LOCAL_ATOM_DECL(multiaddr); \ + LOCAL_ATOM_DECL(net_unknown); \ + LOCAL_ATOM_DECL(net_unreach); \ + LOCAL_ATOM_DECL(nogroup); \ + LOCAL_ATOM_DECL(none); \ + LOCAL_ATOM_DECL(noroute); \ + LOCAL_ATOM_DECL(not_neighbour); \ + LOCAL_ATOM_DECL(null); \ + LOCAL_ATOM_DECL(num_acceptors); \ + LOCAL_ATOM_DECL(num_cnt_bits); \ + LOCAL_ATOM_DECL(num_dinet); \ + LOCAL_ATOM_DECL(num_dinet6); \ + LOCAL_ATOM_DECL(num_dlocal); \ + LOCAL_ATOM_DECL(num_outstreams); \ + LOCAL_ATOM_DECL(number_peer_destinations); \ + LOCAL_ATOM_DECL(num_pip); \ + LOCAL_ATOM_DECL(num_psctp); \ + LOCAL_ATOM_DECL(num_ptcp); \ + LOCAL_ATOM_DECL(num_pudp); \ + LOCAL_ATOM_DECL(num_readers); \ + LOCAL_ATOM_DECL(num_sockets); \ + LOCAL_ATOM_DECL(num_tdgrams); \ + LOCAL_ATOM_DECL(num_tseqpkgs); \ + LOCAL_ATOM_DECL(num_tstreams); \ + LOCAL_ATOM_DECL(num_writers); \ + LOCAL_ATOM_DECL(offender); \ + LOCAL_ATOM_DECL(onoff); \ + LOCAL_ATOM_DECL(options); \ + LOCAL_ATOM_DECL(origin); \ + LOCAL_ATOM_DECL(otp); \ + LOCAL_ATOM_DECL(otp_socket_option);\ + LOCAL_ATOM_DECL(owner); \ + LOCAL_ATOM_DECL(partial_delivery); \ + LOCAL_ATOM_DECL(peer_error); \ + LOCAL_ATOM_DECL(peer_rwnd); \ + LOCAL_ATOM_DECL(pkt_toobig); \ + LOCAL_ATOM_DECL(policy_fail); \ + LOCAL_ATOM_DECL(port); \ + LOCAL_ATOM_DECL(port_unreach); \ + LOCAL_ATOM_DECL(probe); \ + LOCAL_ATOM_DECL(protocols); \ + LOCAL_ATOM_DECL(rcvctrlbuf); \ + LOCAL_ATOM_DECL(read); \ + LOCAL_ATOM_DECL(read_pkg_max); \ + LOCAL_ATOM_DECL(read_waits); \ + LOCAL_ATOM_DECL(read_write); \ + LOCAL_ATOM_DECL(registry); \ + LOCAL_ATOM_DECL(reject_route); \ + LOCAL_ATOM_DECL(remote); \ + LOCAL_ATOM_DECL(rstates); \ + LOCAL_ATOM_DECL(selected); \ + LOCAL_ATOM_DECL(sender_dry); \ + LOCAL_ATOM_DECL(send_failure); \ + LOCAL_ATOM_DECL(shutdown); \ + LOCAL_ATOM_DECL(sifaddr); \ + LOCAL_ATOM_DECL(sifbrdaddr); \ + LOCAL_ATOM_DECL(sifdstaddr); \ + LOCAL_ATOM_DECL(sifflags); \ + LOCAL_ATOM_DECL(sifmtu); \ + LOCAL_ATOM_DECL(sifnetmask); \ + LOCAL_ATOM_DECL(siftxqlen); \ + LOCAL_ATOM_DECL(slist); \ + LOCAL_ATOM_DECL(sndctrlbuf); \ + LOCAL_ATOM_DECL(socket_debug); \ + LOCAL_ATOM_DECL(socket_level); \ + LOCAL_ATOM_DECL(socket_option); \ + LOCAL_ATOM_DECL(sourceaddr); \ + LOCAL_ATOM_DECL(time_exceeded); \ + LOCAL_ATOM_DECL(true); \ + LOCAL_ATOM_DECL(txstatus); \ + LOCAL_ATOM_DECL(txtime); \ + LOCAL_ATOM_DECL(want); \ + LOCAL_ATOM_DECL(write); \ + LOCAL_ATOM_DECL(write_pkg_max); \ + LOCAL_ATOM_DECL(wstates); \ + LOCAL_ATOM_DECL(zerocopy) + +/* Local error reason atoms + * Keep this (commented) for future use... + */ +/* +#define LOCAL_ERROR_REASON_ATOMS \ + LOCAL_ATOM_DECL(select_read); \ + LOCAL_ATOM_DECL(select_write) +*/ +#define LOCAL_ATOM_DECL(LA) static ERL_NIF_TERM atom_##LA +LOCAL_ATOMS; +// LOCAL_ERROR_REASON_ATOMS; +#undef LOCAL_ATOM_DECL + +/* *** Sockets *** */ +static ErlNifResourceType* esocks; +static ErlNifResourceTypeInit esockInit = { + esock_dtor, + esock_stop, + (ErlNifResourceDown*) esock_down }; -// qsort and bsearch helper -static int cmpESockOpt(const void *vpa, const void *vpb) { - struct ESockOpt *a, *b; - a = (struct ESockOpt *) vpa; - b = (struct ESockOpt *) vpb; - return a->opt < b->opt ? -1 : (a->opt > b->opt ? 1 : 0); -} +// Initiated when the nif is loaded +static ESockData data; + +/* Jump table for the I/O backend (async or sync) */ +static ESockIoBackend io_backend = {0}; + + +/* This, the test for NULL), is temporary until we have a win stub */ +#define ESOCK_IO_INIT(NUMT) \ + ((io_backend.init != NULL) ? \ + io_backend.init((NUMT), &data) : ESOCK_IO_ERR_UNSUPPORTED) +#define ESOCK_IO_FIN() \ + ((io_backend.finish != NULL) ? \ + io_backend.finish() : ESOCK_IO_ERR_UNSUPPORTED) + +#define ESOCK_IO_INFO(ENV) \ + ((io_backend.info != NULL) ? \ + io_backend.info((ENV)) : MKEMA((ENV))) +#define ESOCK_IO_CMD(ENV, CMD, CDATA) \ + ((io_backend.cmd != NULL) ? \ + io_backend.cmd((ENV), (CMD), (CDATA)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SUPPORTS_0(ENV) \ + ((io_backend.supports_0 != NULL) ? \ + io_backend.supports_0((ENV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SUPPORTS_1(ENV, KEY) \ + ((io_backend.supports_1 != NULL) ? \ + io_backend.supports_1((ENV), (KEY)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) + +#define ESOCK_IO_OPEN_WITH_FD(ENV, FD, EOPTS) \ + ((io_backend.open_with_fd != NULL) ? \ + io_backend.open_with_fd((ENV), (FD), (EOPTS), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_OPEN_PLAIN(ENV, D, T, P, EOPTS) \ + ((io_backend.open_plain != NULL) ? \ + io_backend.open_plain((ENV), (D), \ + (T), (P), (EOPTS), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_BIND(ENV, D, SAP, AL) \ + ((io_backend.bind != NULL) ? \ + io_backend.bind((ENV), (D), (SAP), (AL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CONNECT(ENV, D, SR, CR, AP, AL) \ + ((io_backend.connect != NULL) ? \ + io_backend.connect((ENV), (D), \ + (SR), (CR), (AP), (AL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_LISTEN(ENV, D, BL) \ + ((io_backend.listen != NULL) ? \ + io_backend.listen((ENV), (D), (BL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_ACCEPT(ENV, D, SR, AR) \ + ((io_backend.accept != NULL) ? \ + io_backend.accept((ENV), (D), (SR), (AR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SEND(ENV, D, SR, RF, L, F) \ + ((io_backend.send != NULL) ? \ + io_backend.send((ENV), (D), \ + (SR), (RF), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDTO(ENV, D, \ + SOCKR, SENDR, \ + DP, F, TAP, TAL) \ + ((io_backend.sendto != NULL) ? \ + io_backend.sendto((ENV), (D), \ + (SOCKR), (SENDR), \ + (DP), (F), (TAP), (TAL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDMSG(ENV, D, \ + SOCKR, SENDR, EM, F, EIOV) \ + ((io_backend.sendmsg != NULL) ? \ + io_backend.sendmsg((ENV), (D), \ + (SOCKR), (SENDR), \ + (EM), (F), (EIOV), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_START(ENV, D, \ + SOR, SNR, \ + O, CN, FR) \ + ((io_backend.sendfile_start != NULL) ? \ + io_backend.sendfile_start((ENV), (D), \ + (SOR), (SNR), \ + (O), (CN), (FR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_CONT(ENV, D, \ + SOR, SNR, \ + O, CP) \ + ((io_backend.sendfile_cont != NULL) ? \ + io_backend.sendfile_cont((ENV), (D), \ + (SOR), (SNR), \ + (O), (CP)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_DC(ENV, D) \ + ((io_backend.sendfile_dc != NULL) ? \ + io_backend.sendfile_dc((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECV(ENV, D, \ + SR, RR, L, F) \ + ((io_backend.recv != NULL) ? \ + io_backend.recv((ENV), (D), \ + (SR), (RR), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECVFROM(ENV, D, \ + SR, RR, L, F) \ + ((io_backend.recvfrom != NULL) ? \ + io_backend.recvfrom((ENV), (D), \ + (SR), (RR), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECVMSG(ENV, D, \ + SR, RR, BL, CL, F) \ + ((io_backend.recvmsg != NULL) ? \ + io_backend.recvmsg((ENV), (D), \ + (SR), (RR), \ + (BL), (CL), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CLOSE(ENV, D) \ + ((io_backend.close != NULL) ? \ + io_backend.close((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_FIN_CLOSE(ENV, D) \ + ((io_backend.fin_close != NULL) ? \ + io_backend.fin_close((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SHUTDOWN(ENV, D, H) \ + ((io_backend.shutdown != NULL) ? \ + io_backend.shutdown((ENV), (D), (H)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SOCKNAME(ENV, D) \ + ((io_backend.sockname != NULL) ? \ + io_backend.sockname((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_PEERNAME(ENV, D) \ + ((io_backend.peername != NULL) ? \ + io_backend.peername((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_CONNECT(ENV, D, OR) \ + ((io_backend.cancel_connect != NULL) ? \ + io_backend.cancel_connect((ENV), (D), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_ACCEPT(ENV, D, SR, OR) \ + ((io_backend.cancel_accept != NULL) ? \ + io_backend.cancel_accept((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_SEND(ENV, D, SR, OR) \ + ((io_backend.cancel_send != NULL) ? \ + io_backend.cancel_send((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_RECV(ENV, D, SR, OR) \ + ((io_backend.cancel_recv != NULL) ? \ + io_backend.cancel_recv((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT(ENV, D, L, O, EV) \ + ((io_backend.setopt != NULL) ? \ + io_backend.setopt((ENV), (D), (L), (O), (EV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT_NATIVE(ENV, D, L, O, EV) \ + ((io_backend.setopt_native != NULL) ? \ + io_backend.setopt_native((ENV), (D), (L), (O), (EV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT_OTP(ENV, D, L, O) \ + ((io_backend.setopt_otp != NULL) ? \ + io_backend.setopt_otp((ENV), (D), (L), (O)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT(ENV, D, L, O) \ + ((io_backend.getopt != NULL) ? \ + io_backend.getopt((ENV), (D), (L), (O)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT_NATIVE(ENV, D, L, O, VS) \ + ((io_backend.getopt_native != NULL) ? \ + io_backend.getopt_native((ENV), (D), (L), (O), (VS)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT_OTP(ENV, D, EO) \ + ((io_backend.getopt_otp != NULL) ? \ + io_backend.getopt_otp((ENV), (D), (EO)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_2(ENV, D, R) \ + ((io_backend.ioctl_2 != NULL) ? \ + io_backend.ioctl_2((ENV), (D), (R)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_3(ENV, D, R, A) \ + ((io_backend.ioctl_3 != NULL) ? \ + io_backend.ioctl_3((ENV), (D), (R), (A)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_4(ENV, D, R, A1, A2) \ + ((io_backend.ioctl_4 != NULL) ? \ + io_backend.ioctl_4((ENV), (D), (R), (A1), (A2)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) + +#define ESOCK_IO_DTOR(ENV, D) \ + ((io_backend.dtor != NULL) ? \ + io_backend.dtor((ENV), (D)) : ((void) (D))) +#define ESOCK_IO_STOP(ENV, D) \ + ((io_backend.stop != NULL) ? \ + io_backend.stop((ENV), (D)) : ((void) (D))) +#define ESOCK_IO_DOWN(ENV, D, PP, MP) \ + ((io_backend.down != NULL) ? \ + io_backend.down((ENV), (D), (PP), (MP)) : ((void) (D))) + +/* ------------------------------------------------------------------------ + * Socket option tables and handling + */ + /* SO_* options -------------------------------------------------------- */ static struct ESockOpt optLevelSocket[] = @@ -3111,11 +3334,11 @@ static struct ESockOpt optLevelIPV6[] = { #if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) #if defined(IPV6_RECVPKTINFO) - IPV6_RECVPKTINFO, + IPV6_RECVPKTINFO, #else - IPV6_PKTINFO, + IPV6_PKTINFO, #endif - esock_setopt_bool_opt, esock_getopt_bool_opt, + esock_setopt_bool_opt, esock_getopt_bool_opt, #else 0, NULL, NULL, #endif @@ -3177,7 +3400,7 @@ static struct ESockOpt optLevelIPV6[] = #endif &esock_atom_v6only} - }; + }; #endif // #ifdef HAVE_IPV6 @@ -3366,60 +3589,53 @@ static struct ESockOpt optLevelUDP[] = }; -/* Option levels table ------------------------------------------------- */ -struct ESockOptLevel -{ - int level; // Level number - - size_t num; // Number of options - - struct ESockOpt *opts; // Options table -}; +/* Option levels utility macro */ -// qsort and bsearch helper -static int cmpESockOptLevel(const void *vpa, const void *vpb) { - struct ESockOptLevel *a, *b; - a = (struct ESockOptLevel*) vpa; - b = (struct ESockOptLevel*) vpb; - return a->level < b->level ? -1 : (a->level > b->level ? 1 : 0); -} +#define OPT_LEVEL(Level, Opts, Name) {(Level), NUM(Opts), (Opts), (Name)} -#define OPT_LEVEL(Level, Opts) {(Level), NUM(Opts), (Opts)} /* Table --------------------------------------------------------------- */ static struct ESockOptLevel optLevels[] = { - OPT_LEVEL(SOL_SOCKET, optLevelSocket), + OPT_LEVEL(SOL_SOCKET, optLevelSocket, &esock_atom_socket), +#ifndef __WIN32__ #ifdef SOL_IP - OPT_LEVEL(SOL_IP, optLevelIP), + OPT_LEVEL(SOL_IP, optLevelIP, &esock_atom_ip), +#else + OPT_LEVEL(IPPROTO_IP, optLevelIP, &esock_atom_ip), +#endif #else - OPT_LEVEL(IPPROTO_IP, optLevelIP), + OPT_LEVEL(IPPROTO_IP, optLevelIP, &esock_atom_ip), #endif #ifdef HAVE_IPV6 +#ifndef __WIN32__ #ifdef SOL_IPV6 - OPT_LEVEL(SOL_IPV6, optLevelIPV6), + OPT_LEVEL(SOL_IPV6, optLevelIPV6, &esock_atom_ipv6), +#else + OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6, &esock_atom_ipv6), +#endif #else - OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6), + OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6, &esock_atom_ipv6), #endif #endif // #ifdef HAVE_IPV6 #ifdef HAVE_SCTP - OPT_LEVEL(IPPROTO_SCTP, optLevelSCTP), + OPT_LEVEL(IPPROTO_SCTP, optLevelSCTP, &esock_atom_sctp), #endif // #ifdef HAVE_SCTP - OPT_LEVEL(IPPROTO_UDP, optLevelUDP), - OPT_LEVEL(IPPROTO_TCP, optLevelTCP) + OPT_LEVEL(IPPROTO_UDP, optLevelUDP, &esock_atom_udp), + OPT_LEVEL(IPPROTO_TCP, optLevelTCP, &esock_atom_tcp) }; #undef OPT_LEVEL /* Tables init (sorting) ----------------------------------------------- */ -#define ESOCK_SORT_TABLE(Array, Cmp) \ +#define ESOCK_SORT_TABLE(Array, Cmp) \ qsort((Array), NUM(Array), sizeof(*(Array)), (Cmp)) static void initOpts(void) { @@ -3436,1085 +3652,89 @@ static void initOpts(void) { ESOCK_SORT_TABLE(optLevels, cmpESockOptLevel); } + +/* ------------------------------------------------------------------------ + * Socket option tables and handling + */ + +// qsort and bsearch helper(s) +static +int cmpESockOpt(const void *vpa, const void *vpb) +{ + struct ESockOpt *a, *b; + a = (struct ESockOpt *) vpa; + b = (struct ESockOpt *) vpb; + return a->opt < b->opt ? -1 : (a->opt > b->opt ? 1 : 0); +} + +static +int cmpESockOptLevel(const void *vpa, const void *vpb) +{ + struct ESockOptLevel *a, *b; + a = (struct ESockOptLevel*) vpa; + b = (struct ESockOptLevel*) vpb; + return a->level < b->level ? -1 : (a->level > b->level ? 1 : 0); +} + /* Option lookup in tables --------------------------------------------- */ -static struct ESockOpt *lookupOpt(int level, int opt) { +static +struct ESockOpt *lookupOpt(int level, int opt) +{ struct ESockOptLevel levelKey, *levelP; struct ESockOpt optKey; sys_memzero((char *) &levelKey, sizeof(levelKey)); levelKey.level = level; - levelP = - bsearch(&levelKey, optLevels, NUM(optLevels), sizeof(*optLevels), - cmpESockOptLevel); + levelP = bsearch(&levelKey, optLevels, NUM(optLevels), sizeof(*optLevels), + cmpESockOptLevel); if (levelP == NULL) return NULL; sys_memzero((char *) &optKey, sizeof(optKey)); optKey.opt = opt; - return - bsearch(&optKey, levelP->opts, levelP->num, sizeof(*levelP->opts), - cmpESockOpt); + return bsearch(&optKey, levelP->opts, levelP->num, sizeof(*levelP->opts), + cmpESockOpt); } -/* --------------------------------------------------------------------- */ - - - -static BOOLEAN_T send_check_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult); -static ERL_NIF_TERM send_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t send_result, - ssize_t dataSize, - BOOLEAN_T dataInTail, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef); -static ERL_NIF_TERM send_check_ok(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM send_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef); -static void send_error_waiting_writers(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM send_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef); -static BOOLEAN_T recv_check_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult); -static void recv_init_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref); -static void recv_update_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static void recv_error_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM recv_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - int saveErrno, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ErlNifBinary* buf1P, - ErlNifBinary* buf2P, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - ErlNifBinary* bufP, - ESockAddress* fromAddrP, - SOCKLEN_T fromAddrLen, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef); - -static ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env, - ESockDescriptor* descP); -static int esock_close_socket(ErlNifEnv* env, - ESockDescriptor* descP, - BOOLEAN_T unlock); - -static void encode_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM* eSockAddr); -static void encode_cmsgs(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifBinary* cmsgBinP, - struct msghdr* msgHdrP, - ERL_NIF_TERM* eCMsg); -static BOOLEAN_T encode_cmsg(ErlNifEnv* env, - int level, - int type, - unsigned char* dataP, - size_t dataLen, - ERL_NIF_TERM* eType, - ERL_NIF_TERM* eData); -static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* cmsgHdrBufP, - size_t cmsgHdrBufLen, - size_t* cmsgHdrBufUsed); -static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* bufP, - size_t rem, - size_t* used); -static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eValue, - char* dataP, - size_t dataLen, - size_t* dataUsedP); -static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eData, - char* dataP, - size_t dataLen, - size_t* dataUsedP); -static void *init_cmsghdr(struct cmsghdr* cmsgP, - size_t rem, - size_t size, - size_t* usedP); -static void encode_msg_flags(ErlNifEnv* env, - ESockDescriptor* descP, - int msgFlags, - ERL_NIF_TERM* flags); -#if defined(IP_TOS) -static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IP_MTU_DISCOVER) -static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IP_MTU_DISCOVER) -static void encode_ip_pmtudisc(ErlNifEnv* env, - int val, - ERL_NIF_TERM* eVal); -#endif -#if defined(IPV6_MTU_DISCOVER) -static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IPV6_MTU_DISCOVER) -static void encode_ipv6_pmtudisc(ErlNifEnv* env, - int val, - ERL_NIF_TERM* eVal); -#endif -#if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) -static -BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val); -#endif - -/* -static BOOLEAN_T decode_bool(ErlNifEnv* env, - ERL_NIF_TERM eVal, - BOOLEAN_T* val); -*/ -// static void encode_bool(BOOLEAN_T val, ERL_NIF_TERM* eVal); -static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val); - -#if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) -static BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env, - ERL_NIF_TERM eVal, - sctp_assoc_t* val); -static ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, - sctp_assoc_t val); -#endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) - -static void esock_stop_handle_current(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestor* reqP); -static void inform_waiting_procs(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestQueue* q, - ERL_NIF_TERM reason); - -static int socket_setopt(int sock, - int level, - int opt, - const void* optVal, - const socklen_t optLen); - -static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err); - -static ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event); - - -static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how); -#ifdef HAVE_SETNS -static BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env, - ERL_NIF_TERM opts, - char** netns); -static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err); -static BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err); -#endif - -static BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc); -static void cnt_dec(ESockCounter* cnt, ESockCounter dec); - -static void inc_socket(int domain, int type, int protocol); -static void dec_socket(int domain, int type, int protocol); - - - -/* *** activate_next_acceptor *** - * *** activate_next_writer *** - * *** activate_next_reader *** - * - * All the activate-next functions for acceptor, writer and reader - * have exactly the same API, so we apply some macro magic to simplify. - * They simply operates on dufferent data structures. - * - */ - -#define ACTIVATE_NEXT_FUNCS_DEFS \ - ACTIVATE_NEXT_FUNC_DEF(acceptor) \ - ACTIVATE_NEXT_FUNC_DEF(writer) \ - ACTIVATE_NEXT_FUNC_DEF(reader) - -#define ACTIVATE_NEXT_FUNC_DEF(F) \ - static BOOLEAN_T activate_next_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM sockRef); -ACTIVATE_NEXT_FUNCS_DEFS -#undef ACTIVATE_NEXT_FUNC_DEF - -/* *** acceptor_search4pid | writer_search4pid | reader_search4pid *** - * *** acceptor_push | writer_push | reader_push *** - * *** acceptor_pop | writer_pop | reader_pop *** - * *** acceptor_unqueue | writer_unqueue | reader_unqueue *** - * - * All the queue operator functions (search4pid, push, pop - * and unqueue) for acceptor, writer and reader has exactly - * the same API, so we apply some macro magic to simplify. - */ - -#define ESOCK_OPERATOR_FUNCS_DEFS \ - ESOCK_OPERATOR_FUNCS_DEF(acceptor) \ - ESOCK_OPERATOR_FUNCS_DEF(writer) \ - ESOCK_OPERATOR_FUNCS_DEF(reader) - -#define ESOCK_OPERATOR_FUNCS_DEF(O) \ - static BOOLEAN_T O##_search4pid(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid* pid); \ - static void O##_push(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid pid, \ - ERL_NIF_TERM ref); \ - static BOOLEAN_T O##_pop(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ESockRequestor* reqP); \ - static BOOLEAN_T O##_unqueue(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM* refP, \ - const ErlNifPid* pidP); -ESOCK_OPERATOR_FUNCS_DEFS -#undef ESOCK_OPERATOR_FUNCS_DEF -static BOOLEAN_T requestor_pop(ESockRequestQueue* q, - ESockRequestor* reqP); -static void requestor_init(ESockRequestor* reqP); -static void requestor_release(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* reqP); - -static BOOLEAN_T qsearch4pid(ErlNifEnv* env, - ESockRequestQueue* q, - ErlNifPid* pid); -static void qpush(ESockRequestQueue* q, - ESockRequestQueueElement* e); -static ESockRequestQueueElement* qpop(ESockRequestQueue* q); -static BOOLEAN_T qunqueue(ErlNifEnv* env, - ESockDescriptor* descP, - const char* slogan, - ESockRequestQueue* q, - ERL_NIF_TERM* refP, - const ErlNifPid* pidP); - -static int esock_monitor(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pid, - ESockMonitor* mon); -static int esock_demonitor(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockMonitor* monP); -static void esock_monitor_init(ESockMonitor* mon); -static ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, - const ESockMonitor* monP); -static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, - const ErlNifMonitor* mon); - - - -static void esock_down_ctrl(ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pidP); -static void esock_down_acceptor(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); -static void esock_down_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); -static void esock_down_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); - -static void esock_send_reg_add_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static void esock_send_reg_del_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); - -static void esock_send_wrap_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM cnt); -static void esock_send_close_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifPid* pid); -#ifdef HAVE_SENDFILE -static void -esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, - ESockDescriptor* descP); -#endif -static void esock_send_abort_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestor* reqP, - ERL_NIF_TERM reason); -static BOOLEAN_T esock_send_msg(ErlNifEnv* env, - ErlNifPid* pid, - ERL_NIF_TERM msg, - ErlNifEnv* msgEnv); - -static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, - ERL_NIF_TERM tag, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM cnt); -static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM closeRef); -static ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM tag, - ERL_NIF_TERM info); -static ERL_NIF_TERM mk_socket(ErlNifEnv* env, - ERL_NIF_TERM sockRef); - -static int esock_select_read(ErlNifEnv* env, - ErlNifEvent event, - void* obj, - const ErlNifPid* pidP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static int esock_select_write(ErlNifEnv* env, - ErlNifEvent event, - void* obj, - const ErlNifPid* pidP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static int esock_select_stop(ErlNifEnv* env, - ErlNifEvent event, - void* obj); -static int esock_select_cancel(ErlNifEnv* env, - ErlNifEvent event, - enum ErlNifSelectFlags mode, - void* obj); - -static char* extract_debug_filename(ErlNifEnv* env, - ERL_NIF_TERM map); - - -/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * * - * * - * End of non-__WIN32__ section a.k.a UNIX section * - * * - * * - * ---------------------------------------------------------------------- */ -#endif // #ifndef __WIN32__ - - -/* -#if defined(HAS_AF_LOCAL) || defined(SO_BINDTODEVICE) -static size_t my_strnlen(const char *s, size_t maxlen); -#endif -*/ - -static void esock_dtor(ErlNifEnv* env, void* obj); -static void esock_stop(ErlNifEnv* env, - void* obj, - ErlNifEvent fd, - int is_direct_call); -static void esock_down(ErlNifEnv* env, - void* obj, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); - -static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); - - - -#if HAVE_IN6 -# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY -# if HAVE_DECL_IN6ADDR_ANY_INIT -static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; -# else -static const struct in6_addr in6addr_any = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; -# endif /* HAVE_IN6ADDR_ANY_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_ANY */ - -# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK -# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT -static const struct in6_addr in6addr_loopback = - { { IN6ADDR_LOOPBACK_INIT } }; -# else -static const struct in6_addr in6addr_loopback = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; -# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ -#endif /* HAVE_IN6 */ - - - -/* *** Global atoms *** - * Note that when an (global) atom is added here, it must also be added - * in the socket_int.h file! +/* These three (inline) functions are primarily intended for debugging, + * that is, to make it easy to add debug printouts. */ -#define GLOBAL_ATOMS \ - GLOBAL_ATOM_DECL(abort); \ - GLOBAL_ATOM_DECL(accept); \ - GLOBAL_ATOM_DECL(acceptconn); \ - GLOBAL_ATOM_DECL(acceptfilter); \ - GLOBAL_ATOM_DECL(adaption_layer); \ - GLOBAL_ATOM_DECL(addr); \ - GLOBAL_ATOM_DECL(addrform); \ - GLOBAL_ATOM_DECL(add_membership); \ - GLOBAL_ATOM_DECL(add_source_membership); \ - GLOBAL_ATOM_DECL(alen); \ - GLOBAL_ATOM_DECL(allmulti); \ - GLOBAL_ATOM_DECL(any); \ - GLOBAL_ATOM_DECL(appletlk); \ - GLOBAL_ATOM_DECL(arcnet); \ - GLOBAL_ATOM_DECL(associnfo); \ - GLOBAL_ATOM_DECL(atm); \ - GLOBAL_ATOM_DECL(authhdr); \ - GLOBAL_ATOM_DECL(auth_active_key); \ - GLOBAL_ATOM_DECL(auth_asconf); \ - GLOBAL_ATOM_DECL(auth_chunk); \ - GLOBAL_ATOM_DECL(auth_delete_key); \ - GLOBAL_ATOM_DECL(auth_key); \ - GLOBAL_ATOM_DECL(auth_level); \ - GLOBAL_ATOM_DECL(autoclose); \ - GLOBAL_ATOM_DECL(automedia); \ - GLOBAL_ATOM_DECL(ax25); \ - GLOBAL_ATOM_DECL(bad_data); \ - GLOBAL_ATOM_DECL(bindtodevice); \ - GLOBAL_ATOM_DECL(block_source); \ - GLOBAL_ATOM_DECL(broadcast); \ - GLOBAL_ATOM_DECL(busy_poll); \ - GLOBAL_ATOM_DECL(cantconfig); \ - GLOBAL_ATOM_DECL(chaos); \ - GLOBAL_ATOM_DECL(checksum); \ - GLOBAL_ATOM_DECL(close); \ - GLOBAL_ATOM_DECL(cmsg_cloexec); \ - GLOBAL_ATOM_DECL(command); \ - GLOBAL_ATOM_DECL(confirm); \ - GLOBAL_ATOM_DECL(congestion); \ - GLOBAL_ATOM_DECL(connect); \ - GLOBAL_ATOM_DECL(connected); \ - GLOBAL_ATOM_DECL(connecting); \ - GLOBAL_ATOM_DECL(context); \ - GLOBAL_ATOM_DECL(cork); \ - GLOBAL_ATOM_DECL(credentials); \ - GLOBAL_ATOM_DECL(ctrl); \ - GLOBAL_ATOM_DECL(ctrunc); \ - GLOBAL_ATOM_DECL(data); \ - GLOBAL_ATOM_DECL(debug); \ - GLOBAL_ATOM_DECL(default); \ - GLOBAL_ATOM_DECL(default_send_params); \ - GLOBAL_ATOM_DECL(delayed_ack_time); \ - GLOBAL_ATOM_DECL(dgram); \ - GLOBAL_ATOM_DECL(disable_fragments); \ - GLOBAL_ATOM_DECL(dlci); \ - GLOBAL_ATOM_DECL(domain); \ - GLOBAL_ATOM_DECL(dontfrag); \ - GLOBAL_ATOM_DECL(dontroute); \ - GLOBAL_ATOM_DECL(dormant); \ - GLOBAL_ATOM_DECL(drop_membership); \ - GLOBAL_ATOM_DECL(drop_source_membership); \ - GLOBAL_ATOM_DECL(dstopts); \ - GLOBAL_ATOM_DECL(dying); \ - GLOBAL_ATOM_DECL(dynamic); \ - GLOBAL_ATOM_DECL(echo); \ - GLOBAL_ATOM_DECL(eether); \ - GLOBAL_ATOM_DECL(egp); \ - GLOBAL_ATOM_DECL(enotsup); \ - GLOBAL_ATOM_DECL(eor); \ - GLOBAL_ATOM_DECL(error); \ - GLOBAL_ATOM_DECL(errqueue); \ - GLOBAL_ATOM_DECL(esp_network_level); \ - GLOBAL_ATOM_DECL(esp_trans_level); \ - GLOBAL_ATOM_DECL(ether); \ - GLOBAL_ATOM_DECL(eui64); \ - GLOBAL_ATOM_DECL(events); \ - GLOBAL_ATOM_DECL(explicit_eor); \ - GLOBAL_ATOM_DECL(faith); \ - GLOBAL_ATOM_DECL(false); \ - GLOBAL_ATOM_DECL(family); \ - GLOBAL_ATOM_DECL(fastroute); \ - GLOBAL_ATOM_DECL(flags); \ - GLOBAL_ATOM_DECL(flowinfo); \ - GLOBAL_ATOM_DECL(fragment_interleave); \ - GLOBAL_ATOM_DECL(freebind); \ - GLOBAL_ATOM_DECL(frelay); \ - GLOBAL_ATOM_DECL(get_peer_addr_info); \ - GLOBAL_ATOM_DECL(hatype); \ - GLOBAL_ATOM_DECL(hdrincl); \ - GLOBAL_ATOM_DECL(hmac_ident); \ - GLOBAL_ATOM_DECL(hoplimit); \ - GLOBAL_ATOM_DECL(hopopts); \ - GLOBAL_ATOM_DECL(host); \ - GLOBAL_ATOM_DECL(icmp); \ - GLOBAL_ATOM_DECL(icmp6); \ - GLOBAL_ATOM_DECL(ieee802); \ - GLOBAL_ATOM_DECL(ieee1394); \ - GLOBAL_ATOM_DECL(ifindex); \ - GLOBAL_ATOM_DECL(igmp); \ - GLOBAL_ATOM_DECL(implink); \ - GLOBAL_ATOM_DECL(index); \ - GLOBAL_ATOM_DECL(inet); \ - GLOBAL_ATOM_DECL(inet6); \ - GLOBAL_ATOM_DECL(infiniband); \ - GLOBAL_ATOM_DECL(info); \ - GLOBAL_ATOM_DECL(initmsg); \ - GLOBAL_ATOM_DECL(invalid); \ - GLOBAL_ATOM_DECL(integer_range); \ - GLOBAL_ATOM_DECL(iov); \ - GLOBAL_ATOM_DECL(ip); \ - GLOBAL_ATOM_DECL(ipcomp_level); \ - GLOBAL_ATOM_DECL(ipip); \ - GLOBAL_ATOM_DECL(ipv6); \ - GLOBAL_ATOM_DECL(i_want_mapped_v4_addr); \ - GLOBAL_ATOM_DECL(join_group); \ - GLOBAL_ATOM_DECL(keepalive); \ - GLOBAL_ATOM_DECL(keepcnt); \ - GLOBAL_ATOM_DECL(keepidle); \ - GLOBAL_ATOM_DECL(keepintvl); \ - GLOBAL_ATOM_DECL(kernel); \ - GLOBAL_ATOM_DECL(knowsepoch); \ - GLOBAL_ATOM_DECL(leave_group); \ - GLOBAL_ATOM_DECL(level); \ - GLOBAL_ATOM_DECL(linger); \ - GLOBAL_ATOM_DECL(link); \ - GLOBAL_ATOM_DECL(link0); \ - GLOBAL_ATOM_DECL(link1); \ - GLOBAL_ATOM_DECL(link2); \ - GLOBAL_ATOM_DECL(local); \ - GLOBAL_ATOM_DECL(localtlk); \ - GLOBAL_ATOM_DECL(local_auth_chunks); \ - GLOBAL_ATOM_DECL(loopback); \ - GLOBAL_ATOM_DECL(lowdelay); \ - GLOBAL_ATOM_DECL(lower_up); \ - GLOBAL_ATOM_DECL(mark); \ - GLOBAL_ATOM_DECL(master); \ - GLOBAL_ATOM_DECL(maxburst); \ - GLOBAL_ATOM_DECL(maxseg); \ - GLOBAL_ATOM_DECL(md5sig); \ - GLOBAL_ATOM_DECL(metricom); \ - GLOBAL_ATOM_DECL(mincost); \ - GLOBAL_ATOM_DECL(minttl); \ - GLOBAL_ATOM_DECL(monitor); \ - GLOBAL_ATOM_DECL(more); \ - GLOBAL_ATOM_DECL(msfilter); \ - GLOBAL_ATOM_DECL(mtu); \ - GLOBAL_ATOM_DECL(mtu_discover); \ - GLOBAL_ATOM_DECL(multicast); \ - GLOBAL_ATOM_DECL(multicast_all); \ - GLOBAL_ATOM_DECL(multicast_hops); \ - GLOBAL_ATOM_DECL(multicast_if); \ - GLOBAL_ATOM_DECL(multicast_loop); \ - GLOBAL_ATOM_DECL(multicast_ttl); \ - GLOBAL_ATOM_DECL(name); \ - GLOBAL_ATOM_DECL(netrom); \ - GLOBAL_ATOM_DECL(nlen); \ - GLOBAL_ATOM_DECL(noarp); \ - GLOBAL_ATOM_DECL(nodelay); \ - GLOBAL_ATOM_DECL(nodefrag); \ - GLOBAL_ATOM_DECL(nogroup); \ - GLOBAL_ATOM_DECL(none); \ - GLOBAL_ATOM_DECL(noopt); \ - GLOBAL_ATOM_DECL(nopush); \ - GLOBAL_ATOM_DECL(nosignal); \ - GLOBAL_ATOM_DECL(notrailers); \ - GLOBAL_ATOM_DECL(not_found); \ - GLOBAL_ATOM_DECL(not_owner); \ - GLOBAL_ATOM_DECL(oactive); \ - GLOBAL_ATOM_DECL(ok); \ - GLOBAL_ATOM_DECL(oob); \ - GLOBAL_ATOM_DECL(oobinline); \ - GLOBAL_ATOM_DECL(options); \ - GLOBAL_ATOM_DECL(origdstaddr); \ - GLOBAL_ATOM_DECL(otherhost); \ - GLOBAL_ATOM_DECL(outgoing); \ - GLOBAL_ATOM_DECL(packet); \ - GLOBAL_ATOM_DECL(partial_delivery_point); \ - GLOBAL_ATOM_DECL(passcred); \ - GLOBAL_ATOM_DECL(path); \ - GLOBAL_ATOM_DECL(peek); \ - GLOBAL_ATOM_DECL(peek_off); \ - GLOBAL_ATOM_DECL(peer_addr_params); \ - GLOBAL_ATOM_DECL(peer_auth_chunks); \ - GLOBAL_ATOM_DECL(peercred); \ - GLOBAL_ATOM_DECL(pktinfo); \ - GLOBAL_ATOM_DECL(pktoptions); \ - GLOBAL_ATOM_DECL(pkttype); \ - GLOBAL_ATOM_DECL(pointopoint); \ - GLOBAL_ATOM_DECL(port); \ - GLOBAL_ATOM_DECL(portrange); \ - GLOBAL_ATOM_DECL(portsel); \ - GLOBAL_ATOM_DECL(ppromisc); \ - GLOBAL_ATOM_DECL(primary_addr); \ - GLOBAL_ATOM_DECL(priority); \ - GLOBAL_ATOM_DECL(promisc); \ - GLOBAL_ATOM_DECL(pronet); \ - GLOBAL_ATOM_DECL(protocol); \ - GLOBAL_ATOM_DECL(pup); \ - GLOBAL_ATOM_DECL(raw); \ - GLOBAL_ATOM_DECL(rcvbuf); \ - GLOBAL_ATOM_DECL(rcvbufforce); \ - GLOBAL_ATOM_DECL(rcvlowat); \ - GLOBAL_ATOM_DECL(rcvtimeo); \ - GLOBAL_ATOM_DECL(rdm); \ - GLOBAL_ATOM_DECL(recv); \ - GLOBAL_ATOM_DECL(recvdstaddr); \ - GLOBAL_ATOM_DECL(recverr); \ - GLOBAL_ATOM_DECL(recvfrom); \ - GLOBAL_ATOM_DECL(recvhoplimit); \ - GLOBAL_ATOM_DECL(recvif); \ - GLOBAL_ATOM_DECL(recvmsg); \ - GLOBAL_ATOM_DECL(recvopts); \ - GLOBAL_ATOM_DECL(recvorigdstaddr); \ - GLOBAL_ATOM_DECL(recvpktinfo); \ - GLOBAL_ATOM_DECL(recvtclass); \ - GLOBAL_ATOM_DECL(recvtos); \ - GLOBAL_ATOM_DECL(recvttl); \ - GLOBAL_ATOM_DECL(reliability); \ - GLOBAL_ATOM_DECL(renaming); \ - GLOBAL_ATOM_DECL(reset_streams); \ - GLOBAL_ATOM_DECL(retopts); \ - GLOBAL_ATOM_DECL(reuseaddr); \ - GLOBAL_ATOM_DECL(reuseport); \ - GLOBAL_ATOM_DECL(rights); \ - GLOBAL_ATOM_DECL(router_alert); \ - GLOBAL_ATOM_DECL(rthdr); \ - GLOBAL_ATOM_DECL(rtoinfo); \ - GLOBAL_ATOM_DECL(running); \ - GLOBAL_ATOM_DECL(rxq_ovfl); \ - GLOBAL_ATOM_DECL(scope_id); \ - GLOBAL_ATOM_DECL(sctp); \ - GLOBAL_ATOM_DECL(sec); \ - GLOBAL_ATOM_DECL(select_failed); \ - GLOBAL_ATOM_DECL(select_sent); \ - GLOBAL_ATOM_DECL(send); \ - GLOBAL_ATOM_DECL(sendmsg); \ - GLOBAL_ATOM_DECL(sendsrcaddr); \ - GLOBAL_ATOM_DECL(sendto); \ - GLOBAL_ATOM_DECL(seqpacket); \ - GLOBAL_ATOM_DECL(setfib); \ - GLOBAL_ATOM_DECL(set_peer_primary_addr); \ - GLOBAL_ATOM_DECL(simplex); \ - GLOBAL_ATOM_DECL(slave); \ - GLOBAL_ATOM_DECL(slen); \ - GLOBAL_ATOM_DECL(sndbuf); \ - GLOBAL_ATOM_DECL(sndbufforce); \ - GLOBAL_ATOM_DECL(sndlowat); \ - GLOBAL_ATOM_DECL(sndtimeo); \ - GLOBAL_ATOM_DECL(socket); \ - GLOBAL_ATOM_DECL(spec_dst); \ - GLOBAL_ATOM_DECL(staticarp); \ - GLOBAL_ATOM_DECL(status); \ - GLOBAL_ATOM_DECL(stream); \ - GLOBAL_ATOM_DECL(syncnt); \ - GLOBAL_ATOM_DECL(tclass); \ - GLOBAL_ATOM_DECL(tcp); \ - GLOBAL_ATOM_DECL(throughput); \ - GLOBAL_ATOM_DECL(timestamp); \ - GLOBAL_ATOM_DECL(tos); \ - GLOBAL_ATOM_DECL(transparent); \ - GLOBAL_ATOM_DECL(true); \ - GLOBAL_ATOM_DECL(trunc); \ - GLOBAL_ATOM_DECL(ttl); \ - GLOBAL_ATOM_DECL(tunnel); \ - GLOBAL_ATOM_DECL(tunnel6); \ - GLOBAL_ATOM_DECL(type); \ - GLOBAL_ATOM_DECL(udp); \ - GLOBAL_ATOM_DECL(unblock_source); \ - GLOBAL_ATOM_DECL(undefined); \ - GLOBAL_ATOM_DECL(unicast_hops); \ - GLOBAL_ATOM_DECL(unspec); \ - GLOBAL_ATOM_DECL(up); \ - GLOBAL_ATOM_DECL(usec); \ - GLOBAL_ATOM_DECL(user); \ - GLOBAL_ATOM_DECL(user_timeout); \ - GLOBAL_ATOM_DECL(use_ext_recvinfo); \ - GLOBAL_ATOM_DECL(use_min_mtu); \ - GLOBAL_ATOM_DECL(void); \ - GLOBAL_ATOM_DECL(v6only) - - -/* *** Global error reason atoms *** */ -#define GLOBAL_ERROR_REASON_ATOMS \ - GLOBAL_ATOM_DECL(eagain); \ - GLOBAL_ATOM_DECL(einval) - - -#define GLOBAL_ATOM_DECL(A) ERL_NIF_TERM esock_atom_##A -GLOBAL_ATOMS; -GLOBAL_ERROR_REASON_ATOMS; -#undef GLOBAL_ATOM_DECL -ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket') -/* *** Local atoms *** */ -#define LOCAL_ATOMS \ - LOCAL_ATOM_DECL(accepting); \ - LOCAL_ATOM_DECL(acc_success); \ - LOCAL_ATOM_DECL(acc_fails); \ - LOCAL_ATOM_DECL(acc_tries); \ - LOCAL_ATOM_DECL(acc_waits); \ - LOCAL_ATOM_DECL(adaptation_layer); \ - LOCAL_ATOM_DECL(add); \ - LOCAL_ATOM_DECL(addr_unreach); \ - LOCAL_ATOM_DECL(address); \ - LOCAL_ATOM_DECL(adm_prohibited); \ - LOCAL_ATOM_DECL(already); \ - LOCAL_ATOM_DECL(association); \ - LOCAL_ATOM_DECL(assoc_id); \ - LOCAL_ATOM_DECL(authentication); \ - LOCAL_ATOM_DECL(base_addr); \ - LOCAL_ATOM_DECL(boolean); \ - LOCAL_ATOM_DECL(bound); \ - LOCAL_ATOM_DECL(bufsz); \ - LOCAL_ATOM_DECL(close); \ - LOCAL_ATOM_DECL(closed); \ - LOCAL_ATOM_DECL(closing); \ - LOCAL_ATOM_DECL(code); \ - LOCAL_ATOM_DECL(cookie_life); \ - LOCAL_ATOM_DECL(counter_wrap); \ - LOCAL_ATOM_DECL(counters); \ - LOCAL_ATOM_DECL(ctype); \ - LOCAL_ATOM_DECL(data_io); \ - LOCAL_ATOM_DECL(data_size); \ - LOCAL_ATOM_DECL(debug_filename); \ - LOCAL_ATOM_DECL(del); \ - LOCAL_ATOM_DECL(dest_unreach); \ - LOCAL_ATOM_DECL(dma); \ - LOCAL_ATOM_DECL(do); \ - LOCAL_ATOM_DECL(dont); \ - LOCAL_ATOM_DECL(dtor); \ - LOCAL_ATOM_DECL(dup); \ - LOCAL_ATOM_DECL(efile); \ - LOCAL_ATOM_DECL(exclude); \ - LOCAL_ATOM_DECL(false); \ - LOCAL_ATOM_DECL(frag_needed); \ - LOCAL_ATOM_DECL(gifaddr); \ - LOCAL_ATOM_DECL(gifbrdaddr); \ - LOCAL_ATOM_DECL(gifconf); \ - LOCAL_ATOM_DECL(gifdstaddr); \ - LOCAL_ATOM_DECL(gifflags); \ - LOCAL_ATOM_DECL(gifhwaddr); \ - LOCAL_ATOM_DECL(gifindex); \ - LOCAL_ATOM_DECL(gifmap); \ - LOCAL_ATOM_DECL(gifmtu); \ - LOCAL_ATOM_DECL(gifname); \ - LOCAL_ATOM_DECL(gifnetmask); \ - LOCAL_ATOM_DECL(giftxqlen); \ - LOCAL_ATOM_DECL(host_unknown); \ - LOCAL_ATOM_DECL(host_unreach); \ - LOCAL_ATOM_DECL(how); \ - LOCAL_ATOM_DECL(in4_sockaddr); \ - LOCAL_ATOM_DECL(in6_sockaddr); \ - LOCAL_ATOM_DECL(include); \ - LOCAL_ATOM_DECL(initial); \ - LOCAL_ATOM_DECL(interface); \ - LOCAL_ATOM_DECL(integer); \ - LOCAL_ATOM_DECL(ioctl_flags); \ - LOCAL_ATOM_DECL(ioctl_requests); \ - LOCAL_ATOM_DECL(iov_max); \ - LOCAL_ATOM_DECL(iow); \ - LOCAL_ATOM_DECL(irq); \ - LOCAL_ATOM_DECL(listening); \ - LOCAL_ATOM_DECL(local_rwnd); \ - LOCAL_ATOM_DECL(map); \ - LOCAL_ATOM_DECL(max); \ - LOCAL_ATOM_DECL(max_attempts); \ - LOCAL_ATOM_DECL(max_init_timeo); \ - LOCAL_ATOM_DECL(max_instreams); \ - LOCAL_ATOM_DECL(asocmaxrxt); \ - LOCAL_ATOM_DECL(mem_end); \ - LOCAL_ATOM_DECL(mem_start); \ - LOCAL_ATOM_DECL(min); \ - LOCAL_ATOM_DECL(missing); \ - LOCAL_ATOM_DECL(mode); \ - LOCAL_ATOM_DECL(msg); \ - LOCAL_ATOM_DECL(msg_flags); \ - LOCAL_ATOM_DECL(mtu); \ - LOCAL_ATOM_DECL(multiaddr); \ - LOCAL_ATOM_DECL(net_unknown); \ - LOCAL_ATOM_DECL(net_unreach); \ - LOCAL_ATOM_DECL(netns); \ - LOCAL_ATOM_DECL(nogroup); \ - LOCAL_ATOM_DECL(none); \ - LOCAL_ATOM_DECL(noroute); \ - LOCAL_ATOM_DECL(not_neighbour); \ - LOCAL_ATOM_DECL(null); \ - LOCAL_ATOM_DECL(num_acceptors); \ - LOCAL_ATOM_DECL(num_cnt_bits); \ - LOCAL_ATOM_DECL(num_dinet); \ - LOCAL_ATOM_DECL(num_dinet6); \ - LOCAL_ATOM_DECL(num_dlocal); \ - LOCAL_ATOM_DECL(num_outstreams); \ - LOCAL_ATOM_DECL(number_peer_destinations); \ - LOCAL_ATOM_DECL(num_pip); \ - LOCAL_ATOM_DECL(num_psctp); \ - LOCAL_ATOM_DECL(num_ptcp); \ - LOCAL_ATOM_DECL(num_pudp); \ - LOCAL_ATOM_DECL(num_readers); \ - LOCAL_ATOM_DECL(num_sockets); \ - LOCAL_ATOM_DECL(num_tdgrams); \ - LOCAL_ATOM_DECL(num_tseqpkgs); \ - LOCAL_ATOM_DECL(num_tstreams); \ - LOCAL_ATOM_DECL(num_writers); \ - LOCAL_ATOM_DECL(offender); \ - LOCAL_ATOM_DECL(onoff); \ - LOCAL_ATOM_DECL(options); \ - LOCAL_ATOM_DECL(origin); \ - LOCAL_ATOM_DECL(otp); \ - LOCAL_ATOM_DECL(otp_socket_option);\ - LOCAL_ATOM_DECL(owner); \ - LOCAL_ATOM_DECL(partial_delivery); \ - LOCAL_ATOM_DECL(peer_error); \ - LOCAL_ATOM_DECL(peer_rwnd); \ - LOCAL_ATOM_DECL(pkt_toobig); \ - LOCAL_ATOM_DECL(policy_fail); \ - LOCAL_ATOM_DECL(port); \ - LOCAL_ATOM_DECL(port_unreach); \ - LOCAL_ATOM_DECL(prim_file); \ - LOCAL_ATOM_DECL(probe); \ - LOCAL_ATOM_DECL(protocols); \ - LOCAL_ATOM_DECL(rcvctrlbuf); \ - LOCAL_ATOM_DECL(read); \ - LOCAL_ATOM_DECL(read_byte); \ - LOCAL_ATOM_DECL(read_fails); \ - LOCAL_ATOM_DECL(read_pkg); \ - LOCAL_ATOM_DECL(read_pkg_max); \ - LOCAL_ATOM_DECL(read_tries); \ - LOCAL_ATOM_DECL(read_waits); \ - LOCAL_ATOM_DECL(read_write); \ - LOCAL_ATOM_DECL(registry); \ - LOCAL_ATOM_DECL(reject_route); \ - LOCAL_ATOM_DECL(remote); \ - LOCAL_ATOM_DECL(rstates); \ - LOCAL_ATOM_DECL(select); \ - LOCAL_ATOM_DECL(selected); \ - LOCAL_ATOM_DECL(sender_dry); \ - LOCAL_ATOM_DECL(send_failure); \ - LOCAL_ATOM_DECL(sendfile); \ - LOCAL_ATOM_DECL(sendfile_byte); \ - LOCAL_ATOM_DECL(sendfile_deferred_close); \ - LOCAL_ATOM_DECL(sendfile_fails); \ - LOCAL_ATOM_DECL(sendfile_max); \ - LOCAL_ATOM_DECL(sendfile_pkg); \ - LOCAL_ATOM_DECL(sendfile_pkg_max); \ - LOCAL_ATOM_DECL(sendfile_tries); \ - LOCAL_ATOM_DECL(sendfile_waits); \ - LOCAL_ATOM_DECL(shutdown); \ - LOCAL_ATOM_DECL(sifaddr); \ - LOCAL_ATOM_DECL(sifbrdaddr); \ - LOCAL_ATOM_DECL(sifdstaddr); \ - LOCAL_ATOM_DECL(sifflags); \ - LOCAL_ATOM_DECL(sifmtu); \ - LOCAL_ATOM_DECL(sifnetmask); \ - LOCAL_ATOM_DECL(siftxqlen); \ - LOCAL_ATOM_DECL(slist); \ - LOCAL_ATOM_DECL(sndctrlbuf); \ - LOCAL_ATOM_DECL(sockaddr); \ - LOCAL_ATOM_DECL(socket_debug); \ - LOCAL_ATOM_DECL(socket_level); \ - LOCAL_ATOM_DECL(socket_option); \ - LOCAL_ATOM_DECL(sourceaddr); \ - LOCAL_ATOM_DECL(state); \ - LOCAL_ATOM_DECL(time_exceeded); \ - LOCAL_ATOM_DECL(timeout); \ - LOCAL_ATOM_DECL(true); \ - LOCAL_ATOM_DECL(txqlen); \ - LOCAL_ATOM_DECL(txstatus); \ - LOCAL_ATOM_DECL(txtime); \ - LOCAL_ATOM_DECL(use_registry); \ - LOCAL_ATOM_DECL(value); \ - LOCAL_ATOM_DECL(want); \ - LOCAL_ATOM_DECL(write); \ - LOCAL_ATOM_DECL(write_byte); \ - LOCAL_ATOM_DECL(write_fails); \ - LOCAL_ATOM_DECL(write_pkg); \ - LOCAL_ATOM_DECL(write_pkg_max); \ - LOCAL_ATOM_DECL(write_tries); \ - LOCAL_ATOM_DECL(write_waits); \ - LOCAL_ATOM_DECL(wstates); \ - LOCAL_ATOM_DECL(zero); \ - LOCAL_ATOM_DECL(zerocopy) - -/* Local error reason atoms */ -#define LOCAL_ERROR_REASON_ATOMS \ - LOCAL_ATOM_DECL(select_read); \ - LOCAL_ATOM_DECL(select_write) - -#define LOCAL_ATOM_DECL(LA) static ERL_NIF_TERM atom_##LA -LOCAL_ATOMS; -LOCAL_ERROR_REASON_ATOMS; -#undef LOCAL_ATOM_DECL +// static ESOCK_INLINE void esock_clear_env(const char* slogan, ErlNifEnv* env) +extern void esock_clear_env(const char* slogan, ErlNifEnv* env) +{ + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env clear - %s: 0x%lX\r\n", slogan, env) ); + SGDBG( ("SOCKET", "env clear - %s: 0x%lX\r\n", slogan, env) ); -/* *** Sockets *** */ -static ErlNifResourceType* esocks; -static ErlNifResourceTypeInit esockInit = { - esock_dtor, - esock_stop, - (ErlNifResourceDown*) esock_down -}; - -// Initiated when the nif is loaded -static ESockData data; + if (env != NULL) enif_clear_env(env); +} -/* These two (inline) functions are primarily intended for debugging, - * that is, to make it easy to add debug printouts. - */ -static ESOCK_INLINE void esock_free_env(const char* slogan, ErlNifEnv* env) +// static ESOCK_INLINE void esock_free_env(const char* slogan, ErlNifEnv* env) +extern void esock_free_env(const char* slogan, ErlNifEnv* env) { + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) ); + SGDBG( ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) ); - // esock_dbg_printf("SOCK ENV", "free - %s: 0x%lX\r\n", slogan, env); if (env != NULL) enif_free_env(env); } -static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan) +// static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan) +extern ErlNifEnv* esock_alloc_env(const char* slogan) { - ErlNifEnv* env; + ErlNifEnv* env = enif_alloc_env(); - ESOCK_ASSERT( (env = enif_alloc_env()) != NULL); + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) ); SGDBG( ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) ); - // esock_dbg_printf("SOCK ENV", "alloc - %s: 0x%lX\r\n", slogan, env); + + ESOCK_ASSERT( env != NULL ); return env; } @@ -4578,9 +3798,6 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM info; ESockDescriptor* descP; @@ -4612,7 +3829,6 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, MUNLOCK(descP->readMtx); return info; -#endif } @@ -4623,7 +3839,6 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, * actually a counter, the num_cnt_bits. This is the "size" of each counter, * in number of bits: 16 | 24 | 32 | 48 | 64. */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_global_info(ErlNifEnv* env) { @@ -4631,7 +3846,7 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env) numBits, numSockets, numTypeDGrams, numTypeStreams, numTypeSeqPkgs, numDomLocal, numDomInet, numDomInet6, numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP, - sockDbg, iovMax, dbg, useReg, iow; + sockDbg, iovMax, dbg, useReg, iow, eei; MLOCK(data.cntMtx); numBits = MKUI(env, ESOCK_COUNTER_SIZE); @@ -4647,6 +3862,7 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env) numProtoUDP = MKUI(env, data.numProtoUDP); numProtoSCTP = MKUI(env, data.numProtoSCTP); sockDbg = BOOL2ATOM(data.sockDbg); + eei = BOOL2ATOM(data.eei); MUNLOCK(data.cntMtx); iovMax = MKI(env, data.iov_max); @@ -4678,16 +3894,33 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env) ERL_NIF_TERM keys[] = {esock_atom_debug, atom_socket_debug, - atom_use_registry, + atom_eei, + esock_atom_use_registry, atom_iow, - atom_counters, - atom_iov_max}, + esock_atom_counters, + atom_iov_max, + atom_io_backend}, vals[] = {dbg, sockDbg, + eei, useReg, iow, gcnt, - iovMax}, + iovMax, + ESOCK_IO_INFO(env) + /* This mess is just a temporary hack + * and shall be replaced by a callback + * function (eventually). + * That function should return a 'term' (a map). + */ + /* +#ifdef __WIN32__ + MKA(env, "win_esaio") +#else + MKA(env, "unix_essio") +#endif + */ + }, info; unsigned int numKeys = NUM(keys), @@ -4700,7 +3933,6 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env) } } } -#endif // #ifndef __WIN32__ /* @@ -4716,7 +3948,6 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env) * writers: The number of current and waiting writers * acceptors: The number of current and waiting acceptors */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, ESockDescriptor* descP) @@ -4742,7 +3973,7 @@ ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, atom_rstates, atom_wstates, atom_ctype, - atom_counters, + esock_atom_counters, atom_num_readers, atom_num_writers, atom_num_acceptors}; @@ -4773,13 +4004,11 @@ ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, return info; } } -#endif // #ifndef __WIN32__ /* * Encode the socket domain */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, ESockDescriptor* descP) @@ -4790,13 +4019,11 @@ ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, esock_encode_domain(env, domain, &edomain); return edomain; } -#endif // #ifndef __WIN32__ /* * Encode the socket type */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, ESockDescriptor* descP) @@ -4808,16 +4035,14 @@ ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, return etype; } -#endif // #ifndef __WIN32__ /* * Encode the socket "create type" - * That is "show" how this socket was created: + * That is; "show" how this socket was created: * * normal | fromfd | {fromfd, integer()} */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, ESockDescriptor* descP) @@ -4830,7 +4055,7 @@ ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, "\r\n", descP->sock, descP->origFD, B2S(descP->closeOnClose)) ); - if (descP->origFD > 0) { + if (descP->origFD != INVALID_SOCKET) { /* Created from other FD */ if (descP->closeOnClose) { /* We *have* dup'ed: {fromfd, integer()} */ @@ -4850,16 +4075,12 @@ ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, return ctype; } -#endif // #ifndef __WIN32__ /* * Encode the socket "state" - * That is "show" how this socket was created: - * - * normal | fromfd | {fromfd, integer()} + * This is a list of atoms, one for each valid 'state' value. */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, unsigned int state) @@ -4929,12 +4150,12 @@ ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closed" "\r\n", descP->sock) ); */ - TARRAY_ADD(estate, atom_closed); + TARRAY_ADD(estate, esock_atom_closed); } if ((state & ESOCK_STATE_DTOR) != 0) { /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> dror" + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> dtor" "\r\n", descP->sock) ); */ TARRAY_ADD(estate, atom_dtor); @@ -4944,33 +4165,31 @@ ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, return estateList; } -#endif // #ifndef __WIN32__ /* * Collect all counters for a socket. */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, ESockDescriptor* descP) { - ERL_NIF_TERM keys[] = {atom_read_byte, - atom_read_fails, - atom_read_pkg, + ERL_NIF_TERM keys[] = {esock_atom_read_byte, + esock_atom_read_fails, + esock_atom_read_pkg, atom_read_pkg_max, - atom_read_tries, + esock_atom_read_tries, atom_read_waits, - atom_write_byte, - atom_write_fails, - atom_write_pkg, + esock_atom_write_byte, + esock_atom_write_fails, + esock_atom_write_pkg, atom_write_pkg_max, - atom_write_tries, - atom_write_waits, - atom_acc_success, - atom_acc_fails, - atom_acc_tries, - atom_acc_waits}; + esock_atom_write_tries, + esock_atom_write_waits, + esock_atom_acc_success, + esock_atom_acc_fails, + esock_atom_acc_tries, + esock_atom_acc_waits}; unsigned int numKeys = NUM(keys); ERL_NIF_TERM vals[] = {MKCNT(env, descP->readByteCnt), MKCNT(env, descP->readFails), @@ -5004,14 +4223,14 @@ ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, ESockSendfileCounters *cP = descP->sendfileCountersP; ERL_NIF_TERM m, sfKeys[] = - {atom_sendfile, - atom_sendfile_byte, - atom_sendfile_fails, - atom_sendfile_max, - atom_sendfile_pkg, - atom_sendfile_pkg_max, - atom_sendfile_tries, - atom_sendfile_waits}, + {esock_atom_sendfile, + esock_atom_sendfile_byte, + esock_atom_sendfile_fails, + esock_atom_sendfile_max, + esock_atom_sendfile_pkg, + esock_atom_sendfile_pkg_max, + esock_atom_sendfile_tries, + esock_atom_sendfile_waits}, sfVals[] = {MKUI(env, cP->cnt), MKUI(env, cP->byteCnt), @@ -5039,7 +4258,6 @@ ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, return cnts; } -#endif // #ifndef __WIN32__ @@ -5067,9 +4285,6 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM command, cdata, result; ESOCK_ASSERT( argc == 1 ); @@ -5089,10 +4304,10 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, SGDBG( ("SOCKET", "nif_command -> " "\r\n command: %T" - "\r\n cdata: %T" + "\r\n cdata: %T" "\r\n", command, cdata) ); - result = esock_command(env, command, cdata); + result = ESOCK_IO_CMD(env, command, cdata); SGDBG( ("SOCKET", "nif_command -> done with result: " "\r\n %T" @@ -5100,14 +4315,11 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, return result; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ static -ERL_NIF_TERM -esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) +ERL_NIF_TERM esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) { int cmp; @@ -5120,7 +4332,7 @@ esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) if (COMPARE(command, esock_atom_debug) == 0) return esock_command_debug(env, cdata); } else { // 0 < cmp - if (COMPARE(command, atom_use_registry) == 0) + if (COMPARE(command, esock_atom_use_registry) == 0) return esock_command_use_socket_registry(env, cdata); } @@ -5129,10 +4341,8 @@ esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) return esock_raise_invalid(env, MKT2(env, esock_atom_command, command)); } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) { @@ -5142,15 +4352,12 @@ ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) if (esock_decode_bool(cdata, &data.dbg)) result = esock_atom_ok; else - result = - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); + result = esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) { @@ -5158,8 +4365,7 @@ ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) /* The data *should* be a boolean() */ if (! esock_decode_bool(cdata, &dbg)) - return - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); + return esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); MLOCK(data.cntMtx); data.sockDbg = dbg; @@ -5167,10 +4373,8 @@ ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) return esock_atom_ok;; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, ERL_NIF_TERM cdata) @@ -5179,17 +4383,14 @@ ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, /* The data *should* be a boolean() */ if (! esock_decode_bool(cdata, &useReg)) - return - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); + return esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); MLOCK(data.cntMtx); data.useReg = useReg; MUNLOCK(data.cntMtx); - return esock_atom_ok;; + return esock_atom_ok; } -#endif - @@ -5199,14 +4400,14 @@ ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, * * Calculate how many readers | writers | acceptors we have for this socket. * Current requestor + any waiting requestors (of the type). - * + * Note that "Current requestor" is *not* used on Windows. */ #ifndef __WIN32__ #define ESOCK_INFO_REQ_FUNCS \ ESOCK_INFO_REQ_FUNC_DECL(readers, currentReaderP, readersQ) \ - ESOCK_INFO_REQ_FUNC_DECL(writers, currentWriterP, writersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(writers, currentWriterP, writersQ) \ ESOCK_INFO_REQ_FUNC_DECL(acceptors, currentAcceptorP, acceptorsQ) #define ESOCK_INFO_REQ_FUNC_DECL(F, CRP, Q) \ @@ -5216,32 +4417,49 @@ ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, { \ return socket_info_reqs(env, descP, descP->CRP, &descP->Q); \ } +#else + +#define ESOCK_INFO_REQ_FUNCS \ + ESOCK_INFO_REQ_FUNC_DECL(readers, readersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(writers, writersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(acceptors, acceptorsQ) + +#define ESOCK_INFO_REQ_FUNC_DECL(F, Q) \ + static \ + ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) \ + { \ + return socket_info_reqs(env, descP, &descP->Q); \ + } + +#endif + ESOCK_INFO_REQ_FUNCS #undef ESOCK_INFO_REQ_FUNC_DECL static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, ESockDescriptor* descP, +#ifndef __WIN32__ ESockRequestor* currentRequestorP, +#endif ESockRequestQueue* q) { - ESockRequestQueueElement* tmp; - ERL_NIF_TERM info; - unsigned int cnt = 0; + ERL_NIF_TERM info; + unsigned int cnt; +#ifdef __WIN32__ + cnt = 0; +#else if (currentRequestorP != NULL) { // We have an active requestor! - cnt++; - - // And add all the waiting requestors - tmp = q->first; - while (tmp != NULL) { - cnt++; - tmp = tmp->nextP; - } + cnt = 1; + } else { + cnt = 0; } +#endif - info = MKUI(env, cnt); + info = MKUI(env, cnt + qlength(q)); SSDBG( descP, ("SOCKET", "socket_info_reqs -> done with" "\r\n info: %T" @@ -5250,8 +4468,6 @@ ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, return info; } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- * nif_supports @@ -5281,29 +4497,28 @@ ERL_NIF_TERM nif_supports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else SGDBG( ("SOCKET", "nif_supports -> entry with %d args\r\n", argc) ); /* Extract arguments and perform preliminary validation */ if (argc == 0) - return esock_supports_0(env); + return ESOCK_IO_SUPPORTS_0(env); - ESOCK_ASSERT( argc == 1 ); + if (argc == 1) + return ESOCK_IO_SUPPORTS_1(env, argv[0]); + + return esock_make_error(env, esock_atom_einval); - return esock_supports_1(env, argv[0]); -#endif } + /* esock_supports - what features do we support? * * This gives information about what features actually * work on the current platform. */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env) { @@ -5339,21 +4554,21 @@ ERL_NIF_TERM esock_supports_0(ErlNifEnv* env) #else is_supported = esock_atom_false; #endif - TARRAY_ADD(opts, MKT2(env, atom_netns, is_supported)); + TARRAY_ADD(opts, MKT2(env, esock_atom_netns, is_supported)); #if defined(HAVE_SENDFILE) is_supported = esock_atom_true; #else is_supported = esock_atom_false; #endif - TARRAY_ADD(opts, MKT2(env, atom_sendfile, is_supported)); + TARRAY_ADD(opts, MKT2(env, esock_atom_sendfile, is_supported)); TARRAY_TOLIST(opts, env, &opts_list); return opts_list; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + + static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key) { @@ -5379,37 +4594,52 @@ ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key) return result; } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env) { size_t n; ERL_NIF_TERM result; result = MKEL(env); - for (n = 0; n < NUM(msg_flags); n++) { + for (n = 0; n < esock_msg_flags_length; n++) { result = MKC(env, MKT2(env, - *(msg_flags[n].name), - MKI(env, msg_flags[n].flag)), + *(esock_msg_flags[n].name), + MKI(env, esock_msg_flags[n].flag)), result); } return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env) { ERL_NIF_TERM protocols; +#ifndef __WIN32__ +#if defined(SOL_IP) + int protoIP = SOL_IP; +#else + int protoIP = IPPROTO_IP; +#endif +#else + int protoIP = IPPROTO_IP; +#endif +#if defined(HAVE_IPV6) +#ifndef __WIN32__ +#if defined(SOL_IPV6) + int protoIPV6 = SOL_IPV6; +#else + int protoIPV6 = IPPROTO_IPV6; +#endif +#else + int protoIPV6 = IPPROTO_IPV6; +#endif +#endif protocols = MKEL(env); @@ -5449,29 +4679,13 @@ ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env) protocols = MKC(env, - MKT2(env, - MKL1(env, esock_atom_ip), - MKI(env, -#ifdef SOL_IP - SOL_IP -#else - IPPROTO_IP -#endif - )), + MKT2(env, MKL1(env, esock_atom_ip), MKI(env, protoIP)), protocols); #ifdef HAVE_IPV6 protocols = MKC(env, - MKT2(env, - MKL1(env, esock_atom_ipv6), - MKI(env, -#ifdef SOL_IPV6 - SOL_IPV6 -#else - IPPROTO_IPV6 -#endif - )), + MKT2(env, MKL1(env, esock_atom_ipv6), MKI(env, protoIPV6)), protocols); #endif @@ -5494,11 +4708,9 @@ ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env) return protocols; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env) { @@ -5582,35 +4794,30 @@ ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env) return requests; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env) +static +ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env) { size_t n; ERL_NIF_TERM result; result = MKEL(env); - for (n = 0; n < NUM(ioctl_flags); n++) { + for (n = 0; n < esock_ioctl_flags_length; n++) { result = MKC(env, MKT2(env, - *(ioctl_flags[n].name), - MKI(env, ioctl_flags[n].flag)), + *(esock_ioctl_flags[n].name), + MKI(env, esock_ioctl_flags[n].flag)), result); } return result; } -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env) @@ -5650,7 +4857,6 @@ ERL_NIF_TERM esock_supports_options(ErlNifEnv* env) return levels; } -#endif // #ifndef __WIN32__ @@ -5699,9 +4905,6 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM result; SGDBG( ("SOCKET", "nif_open -> " @@ -5729,36 +4932,38 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, "\r\n", fd, eopts) ); MLOCK(data.cntMtx); - result = esock_open2(env, fd, eopts); + result = ESOCK_IO_OPEN_WITH_FD(env, fd, eopts); MUNLOCK(data.cntMtx); } else { - ERL_NIF_TERM edomain, etype, eopts; + ERL_NIF_TERM edomain, etype, eproto, eopts; int domain, type, proto; ESOCK_ASSERT( argc == 4 ); /* Extract arguments and perform preliminary validation */ - if (! GET_INT(env, argv[2], &proto)) { - if (IS_INTEGER(env, argv[2])) - return esock_make_error_integer_range(env, argv[2]); - else - return enif_make_badarg(env); - } - if (! IS_MAP(env, argv[3])) { - return enif_make_badarg(env); - } edomain = argv[0]; - etype = argv[1]; - eopts = argv[3]; + etype = argv[1]; + eproto = argv[2]; + eopts = argv[3]; SGDBG( ("SOCKET", "nif_open -> " "\r\n edomain: %T" "\r\n etype: %T" - "\r\n proto: %T" + "\r\n eproto: %T" "\r\n eopts: %T" - "\r\n", argv[0], argv[1], argv[2], eopts) ); + "\r\n", edomain, etype, eproto, eopts) ); + + if (! GET_INT(env, eproto, &proto)) { + if (IS_INTEGER(env, eproto)) + return esock_make_error_integer_range(env, eproto); + else + return enif_make_badarg(env); + } + if (! IS_MAP(env, argv[3])) { + return enif_make_badarg(env); + } if (esock_decode_domain(env, edomain, &domain) == 0) { SGDBG( ("SOCKET", @@ -5773,7 +4978,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, } MLOCK(data.cntMtx); - result = esock_open4(env, domain, type, proto, eopts); + result = ESOCK_IO_OPEN_PLAIN(env, domain, type, proto, eopts); MUNLOCK(data.cntMtx); } @@ -5783,403 +4988,26 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, return result; -#endif // #ifdef __WIN32__ #else -} - - -/* esock_open - create an endpoint (from an existing fd) for communication - * - * Assumes the input has been validated. - * - * Normally we want debugging on (individual) sockets to be controlled - * by the sockets own debug flag. But since we don't even have a socket - * yet, we must use the global debug flag. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_open2(ErlNifEnv* env, - int fd, - ERL_NIF_TERM eopts) -{ - BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg); - BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg); - ESockDescriptor* descP; - ERL_NIF_TERM sockRef; - int domain, type, protocol; - int save_errno = 0; - BOOLEAN_T closeOnClose; - SOCKET sock; - ErlNifEvent event; - ErlNifPid self; - - /* Keep track of the creator - * This should not be a problem, but just in case - * the *open* function is used with the wrong kind - * of environment... - */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> entry with" - "\r\n fd: %d" - "\r\n eopts: %T" - "\r\n", fd, eopts) ); - - /* - * Before we do anything else, we try to retrieve domain, type and protocol - * This information is either present in the eopts map or if not we need - * to "get" it from the system (getsockopt). - * Note that its not possible to get all of these on all platforms, - * and in those cases the user *must* provide us with them (eopts). - * - * We try the system first (since its more reliable) and if that fails - * we check the eopts map. If neither one works, we *give up*! - */ - - if (! esock_open_which_domain(fd, &domain)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> failed get domain from system\r\n") ); - - if (! esock_open2_get_domain(env, eopts, &domain)) { - return esock_make_invalid(env, esock_atom_domain); - } - } - - if (! esock_open_which_type(fd, &type)) { - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> failed get type from system\r\n") ); - - if (! esock_open2_get_type(env, eopts, &type)) - return esock_make_invalid(env, esock_atom_type); - } - - if (! esock_open_which_protocol(fd, &protocol)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> failed get protocol from system\r\n") ); - - if (! esock_extract_int_from_map(env, eopts, - esock_atom_protocol, &protocol)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> trying protocol 0\r\n") ); - protocol = 0; - } - } - - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> " - "\r\n domain: %d" - "\r\n type: %d" - "\r\n protocol: %d" - "\r\n", domain, type, protocol) ); - - - if (esock_open2_todup(env, eopts)) { - /* We shall dup the socket */ - if (ESOCK_IS_ERROR(sock = dup(fd))) { - save_errno = sock_errno(); - - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> dup failed: %d\r\n", - save_errno) ); - - return esock_make_error_errno(env, save_errno); - } - closeOnClose = TRUE; - } else { - sock = fd; - closeOnClose = FALSE; - } - - event = sock; - - SET_NONBLOCKING(sock); - - /* Create and initiate the socket "descriptor" */ - descP = alloc_descriptor(sock, event); - descP->ctrlPid = self; - descP->domain = domain; - descP->type = type; - descP->protocol = protocol; - descP->closeOnClose = closeOnClose; - descP->origFD = fd; - - /* Check if we are already connected, if so change state */ - { - ESockAddress remote; - SOCKLEN_T addrLen = sizeof(remote); - sys_memzero((char *) &remote, addrLen); - if (sock_peer(descP->sock, - (struct sockaddr*) &remote, - &addrLen) == 0) { - SSDBG2( dbg, ("SOCKET", "esock_open2 -> connected\r\n") ); - descP->writeState |= ESOCK_STATE_CONNECTED; - } else { - SSDBG2( dbg, ("SOCKET", "esock_open2 -> not connected\r\n") ); - } - } - - /* And create the 'socket' resource */ - sockRef = enif_make_resource(env, descP); - enif_release_resource(descP); - - ESOCK_ASSERT( MONP("esock_open2 -> ctrl", - env, descP, - &descP->ctrlPid, - &descP->ctrlMon) == 0 ); - - descP->dbg = dbg; - descP->useReg = useReg; - inc_socket(domain, type, protocol); - - /* And finally (maybe) update the registry. - * Shall we keep track of the fact that this socket is created elsewhere? - */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> done: %T\r\n", sockRef) ); - - return esock_make_ok2(env, sockRef); -} -#endif // #ifndef __WIN32__ - - -/* The eextra contains a boolean 'dup' key. Defaults to TRUE. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_todup(ErlNifEnv* env, ERL_NIF_TERM eextra) -{ - return esock_get_bool_from_map(env, eextra, atom_dup, TRUE); -} -#endif // #ifndef __WIN32__ - -/* The eextra contains an integer 'domain' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env, - ERL_NIF_TERM eopts, int* domain) -{ - ERL_NIF_TERM edomain; - - SGDBG( ("SOCKET", "esock_open2_get_domain -> entry with" - "\r\n eopts: %T" - "\r\n", eopts) ); - - if (!GET_MAP_VAL(env, eopts, - esock_atom_domain, &edomain)) - return FALSE; - - if (esock_decode_domain(env, edomain, domain) == 0) - return FALSE; - - return TRUE; -} -#endif // #ifndef __WIN32__ - -/* The eextra contains an integer 'type' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_get_type(ErlNifEnv* env, - ERL_NIF_TERM eopts, int* type) -{ - ERL_NIF_TERM etype; - - SGDBG( ("SOCKET", "esock_open2_get_type -> entry with" - "\r\n eopts: %T" - "\r\n", eopts) ); - - if (! GET_MAP_VAL(env, eopts, esock_atom_type, &etype)) - return FALSE; - - if (! esock_decode_type(env, etype, type)) - return FALSE; - - return TRUE; -} -#endif // #ifndef __WIN32__ - - -/* esock_open4 - create an endpoint for communication - * - * Assumes the input has been validated. - * - * Normally we want debugging on (individual) sockets to be controlled - * by the sockets own debug flag. But since we don't even have a socket - * yet, we must use the global debug flag. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_open4(ErlNifEnv* env, - int domain, - int type, - int protocol, - ERL_NIF_TERM eopts) -{ - BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg); - BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg); - ESockDescriptor* descP; - ERL_NIF_TERM sockRef; - int proto = protocol, save_errno; - SOCKET sock; - ErlNifEvent event; - char* netns; -#ifdef HAVE_SETNS - int current_ns = 0; -#endif - ErlNifPid self; - - /* Keep track of the creator - * This should not be a problem, but just in case - * the *open* function is used with the wrong kind - * of environment... - */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - SSDBG2( dbg, - ("SOCKET", "esock_open4 -> entry with" - "\r\n domain: %d" - "\r\n type: %d" - "\r\n protocol: %d" - "\r\n eopts: %T" - "\r\n", domain, type, protocol, eopts) ); - - -#ifdef HAVE_SETNS - if (esock_open4_get_netns(env, eopts, &netns)) { - SGDBG( ("SOCKET", "nif_open -> namespace: %s\r\n", netns) ); - } -#else - netns = NULL; -#endif - - -#ifdef HAVE_SETNS - if ((netns != NULL) && - (! change_network_namespace(netns, ¤t_ns, &save_errno))) { - FREE(netns); - return esock_make_error_errno(env, save_errno); - } -#endif - - if (ESOCK_IS_ERROR(sock = sock_open(domain, type, proto))) { - if (netns != NULL) FREE(netns); - return esock_make_error_errno(env, sock_errno()); - } - - SSDBG2( dbg, ("SOCKET", "esock_open -> open success: %d\r\n", sock) ); - - - /* NOTE that if the protocol = 0 (default) and the domain is not - * local (AF_LOCAL) we need to explicitly get the protocol here! - */ - - if (proto == 0) - (void) esock_open_which_protocol(sock, &proto); - -#ifdef HAVE_SETNS - if (netns != NULL) { - FREE(netns); - if (! restore_network_namespace(current_ns, sock, &save_errno)) - return esock_make_error_errno(env, save_errno); - } -#endif - - - if ((event = sock_create_event(sock)) == INVALID_EVENT) { - save_errno = sock_errno(); - (void) sock_close(sock); - return esock_make_error_errno(env, save_errno); - } - - SSDBG2( dbg, ("SOCKET", "esock_open4 -> event success: %d\r\n", event) ); - - SET_NONBLOCKING(sock); - - - /* Create and initiate the socket "descriptor" */ - descP = alloc_descriptor(sock, event); - descP->ctrlPid = self; - descP->domain = domain; - descP->type = type; - descP->protocol = proto; - - sockRef = enif_make_resource(env, descP); - enif_release_resource(descP); - - ESOCK_ASSERT( MONP("esock_open -> ctrl", - env, descP, - &descP->ctrlPid, - &descP->ctrlMon) == 0 ); - - descP->dbg = dbg; - descP->useReg = useReg; - inc_socket(domain, type, protocol); - - /* And finally (maybe) update the registry */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); - - return esock_make_ok2(env, sockRef); -} -#endif // #ifndef __WIN32__ - -/* The eextra map "may" contain a boolean 'debug' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, ERL_NIF_TERM eextra, - BOOLEAN_T dflt) -{ - return esock_get_bool_from_map(env, eextra, esock_atom_debug, dflt); } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, ERL_NIF_TERM eextra, - BOOLEAN_T dflt) +extern +BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def) { - return esock_get_bool_from_map(env, eextra, atom_use_registry, dflt); + return esock_get_bool_from_map(env, eopts, esock_atom_debug, def); } -#endif - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain) -{ -#if defined(SO_DOMAIN) - if (esock_getopt_int(sock, SOL_SOCKET, SO_DOMAIN, domain)) - return TRUE; -#endif - return FALSE; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_which_type(SOCKET sock, int* type) +extern +BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def) { -#if defined(SO_TYPE) - if (esock_getopt_int(sock, SOL_SOCKET, SO_TYPE, type)) - return TRUE; -#endif - return FALSE; + return esock_get_bool_from_map(env, eopts, esock_atom_use_registry, def); } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ -static +extern BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto) { #if defined(SO_PROTOCOL) @@ -6188,89 +5016,7 @@ BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto) #endif return FALSE; } -#endif // #ifndef __WIN32__ - - - -#ifdef HAVE_SETNS - - -/* We should really have another API, so that we can return errno... */ - -/* *** change network namespace *** - * Retrieve the current namespace and set the new. - * Return result and previous namespace if successful. - */ -#ifndef __WIN32__ -static -BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err) -{ - int save_errno; - int current_ns = 0; - int new_ns = 0; - - SGDBG( ("SOCKET", "change_network_namespace -> entry with" - "\r\n new ns: %s" - "\r\n", netns) ); - - current_ns = open("/proc/self/ns/net", O_RDONLY); - if (ESOCK_IS_ERROR(current_ns)) { - *err = sock_errno(); - return FALSE; - } - new_ns = open(netns, O_RDONLY); - if (ESOCK_IS_ERROR(new_ns)) { - save_errno = sock_errno(); - (void) close(current_ns); - *err = save_errno; - return FALSE; - } - if (setns(new_ns, CLONE_NEWNET) != 0) { - save_errno = sock_errno(); - (void) close(new_ns); - (void) close(current_ns); - *err = save_errno; - return FALSE; - } else { - (void) close(new_ns); - *cns = current_ns; - return TRUE; - } -} -#endif // #ifndef __WIN32__ - - -/* *** restore network namespace *** - * Restore the previous namespace (see above). - */ -#ifndef __WIN32__ -static -BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err) -{ - SGDBG( ("SOCKET", "restore_network_namespace -> entry with" - "\r\n ns: %d" - "\r\n", ns) ); - - if (setns(ns, CLONE_NEWNET) != 0) { - /* XXX Failed to restore network namespace. - * What to do? Tidy up and return an error... - * Note that the thread now might still be in the namespace. - * Can this even happen? Should the emulator be aborted? - */ - int save_errno = sock_errno(); - (void) close(sock); - (void) close(ns); - *err = save_errno; - return FALSE; - } else { - (void) close(ns); - return TRUE; - } -} -#endif // #ifndef __WIN32__ - -#endif // ifdef HAVE_SETNS @@ -6289,9 +5035,6 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM eSockAddr, ret; ESockAddress sockAddr; @@ -6309,7 +5052,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, eSockAddr = argv[1]; if (! esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) - return esock_make_invalid(env, atom_sockaddr); + return esock_make_invalid(env, esock_atom_sockaddr); MLOCK(descP->readMtx); @@ -6320,7 +5063,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, argv[0], descP->sock, descP->readState, eSockAddr) ); - ret = esock_bind(env, descP, &sockAddr, addrLen); + ret = ESOCK_IO_BIND(env, descP, &sockAddr, addrLen); SSDBG( descP, ("SOCKET", "nif_bind(%T) -> done with" "\r\n ret: %T" @@ -6329,32 +5072,9 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, MUNLOCK(descP->readMtx); return ret; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_bind(ErlNifEnv* env, - ESockDescriptor* descP, - ESockAddress* sockAddrP, - SOCKLEN_T addrLen) -{ - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - if (sock_bind(descP->sock, &sockAddrP->sa, addrLen) < 0) { - return esock_make_error_errno(env, sock_errno()); - } - - descP->readState |= ESOCK_STATE_BOUND; - - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ - - - /* ---------------------------------------------------------------------- * nif_connect * @@ -6374,9 +5094,6 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM res, sockRef, connRef; ESockAddress addr, *addrP; @@ -6400,14 +5117,14 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, return enif_make_badarg(env); if (! esock_decode_sockaddr(env, eSockAddr, &addr, &addrLen)) - return esock_make_invalid(env, atom_sockaddr); + return esock_make_invalid(env, esock_atom_sockaddr); addrP = &addr; MLOCK(descP->writeMtx); SSDBG( descP, ("SOCKET", "nif_connect(%T), {%d0x%X} ->" - "\r\n ConnRef: %T" + "\r\n ConnRef: %T" "\r\n SockAddr: %T" "\r\n", sockRef, descP->sock, descP->writeState, @@ -6417,7 +5134,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, ESOCK_ASSERT( argc == 1 ); connRef = esock_atom_undefined; - addrP = NULL; + addrP = NULL; addrLen = 0; MLOCK(descP->writeMtx); @@ -6429,7 +5146,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, ) ); } - res = esock_connect(env, descP, sockRef, connRef, addrP, addrLen); + res = ESOCK_IO_CONNECT(env, descP, sockRef, connRef, addrP, addrLen); SSDBG( descP, ("SOCKET", "nif_connect(%T) -> done with" "\r\n res: %T" @@ -6439,189 +5156,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, return res; -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM connRef, - ESockAddress* addrP, - SOCKLEN_T addrLen) -{ - int save_errno; - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - /* - * Verify that we are in the proper state - */ - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentWriterP != NULL) - return esock_make_error_invalid(env, atom_state); - - if (descP->connectorP != NULL) { - /* Connect in progress */ - - if (COMPARE_PIDS(&self, &descP->connector.pid) != 0) { - /* Other process has connect in progress */ - if (addrP != NULL) { - return esock_make_error(env, atom_already); - } else { - /* This is a bad call sequence - * - connect without an address is only allowed - * for the connecting process - */ - return esock_raise_invalid(env, atom_state); - } - } - - /* Finalize after received select message */ - - requestor_release("esock_connect finalize -> connected", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; - - if (! verify_is_connected(descP, &save_errno)) { - return esock_make_error_errno(env, save_errno); - } - - descP->writeState |= ESOCK_STATE_CONNECTED; - - return esock_atom_ok; - } - - /* No connect in progress */ - - if (addrP == NULL) - /* This is a bad call sequence - * - connect without an address is only allowed when - * a connect is in progress, after getting the select message - */ - return esock_raise_invalid(env, atom_state); - - /* Initial connect call, with address */ - - if (sock_connect(descP->sock, (struct sockaddr*) addrP, addrLen) == 0) { - /* Success already! */ - SSDBG( descP, ("SOCKET", "esock_connect {%d} -> connected\r\n", - descP->sock) ); - - descP->writeState |= ESOCK_STATE_CONNECTED; - - return esock_atom_ok; - } - - /* Connect returned error */ - save_errno = sock_errno(); - - switch (save_errno) { - - case ERRNO_BLOCK: /* Winsock2 */ - case EINPROGRESS: /* Unix & OSE!! */ - SSDBG( descP, - ("SOCKET", "esock_connect {%d} -> would block => select\r\n", - descP->sock) ); - { - int sres; - - if ((sres = - esock_select_write(env, descP->sock, descP, NULL, - sockRef, connRef)) < 0) - return - enif_raise_exception(env, - MKT2(env, atom_select_write, - MKI(env, sres))); - /* Initiate connector */ - descP->connector.pid = self; - ESOCK_ASSERT( MONP("esock_connect -> conn", - env, descP, - &self, &descP->connector.mon) == 0 ); - descP->connector.env = esock_alloc_env("connector"); - descP->connector.ref = CP_TERM(descP->connector.env, connRef); - descP->connectorP = &descP->connector; - descP->writeState |= - (ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); - - return atom_select; - } - break; - - default: - SSDBG( descP, - ("SOCKET", "esock_connect {%d} -> error: %d\r\n", - descP->sock, save_errno) ); - - return esock_make_error_errno(env, save_errno); - - } // switch(save_errno) -} -#endif // #ifndef __WIN32__ - - - -/* *** verify_is_connected *** - * Check if a connection has been established. - */ -#ifndef __WIN32__ -static -BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err) -{ - /* - * *** This is strange *** - * - * This *should* work on Windows NT too, but doesn't. - * An bug in Winsock 2.0 for Windows NT? - * - * See "Unix Netwok Programming", "The Sockets Networking API", - * W.R.Stevens, Volume 1, third edition, 16.4 Nonblocking 'connect', - * before Interrupted 'connect' (p 412) for a discussion about - * Unix portability and non blocking connect. - */ - - int error = 0; - -#ifdef SO_ERROR - if (! esock_getopt_int(descP->sock, SOL_SOCKET, SO_ERROR, &error)) { - // Solaris does it this way according to W.R.Stevens - error = sock_errno(); - } -#elif 1 - char buf[0]; - if (ESOCK_IS_ERROR(read(descP->sock, buf, sizeof(buf)))) { - error = sock_errno(); - } -#else - /* This variant probably returns wrong error value - * ENOTCONN instead of the actual connect error - */ - ESockAddress remote; - SOCKLEN_T addrLen = sizeof(remote); - sys_memzero((char *) &remote, addrLen); - if (sock_peer(descP->sock, - (struct sockaddr*) &remote, &addrLen)) < 0) { - error = sock_errno(); - } -#endif - - if (error != 0) { - *err = error; - return FALSE; - } - return TRUE; } -#endif // #ifndef __WIN32__ @@ -6641,9 +5176,6 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; int backlog; ERL_NIF_TERM ret; @@ -6673,7 +5205,7 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env, argv[0], descP->sock, descP->readState, backlog) ); - ret = esock_listen(env, descP, backlog); + ret = ESOCK_IO_LISTEN(env, descP, backlog); SSDBG( descP, ("SOCKET", "nif_listen(%T) -> done with" "\r\n ret: %T" @@ -6682,12 +5214,12 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env, MUNLOCK(descP->readMtx); return ret; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ +/* ======================================================================== + */ static ERL_NIF_TERM esock_listen(ErlNifEnv* env, ESockDescriptor* descP, @@ -6698,13 +5230,26 @@ ERL_NIF_TERM esock_listen(ErlNifEnv* env, * Verify that we are in the proper state */ + SSDBG( descP, + ("SOCKET", "esock_listen(%d) -> verify open\r\n", descP->sock) ); if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); + +#if defined(__WIN32__) + SSDBG( descP, + ("SOCKET", "esock_listen(%d) -> verify bound\r\n", descP->sock) ); + if (! IS_BOUND(descP->writeState)) + return esock_make_error(env, esock_atom_not_bound); +#endif /* * And attempt to make socket listening */ + SSDBG( descP, ("SOCKET", "esock_listen(%d) -> try listen with" + "\r\n backlog: %d" + "\r\n", descP->sock, backlog) ); + if ((sock_listen(descP->sock, backlog)) < 0) return esock_make_error_errno(env, sock_errno()); @@ -6713,7 +5258,6 @@ ERL_NIF_TERM esock_listen(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ @@ -6733,10 +5277,6 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; ERL_NIF_TERM sockRef, ref, res; @@ -6754,6 +5294,7 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, MLOCK(descP->readMtx); +#ifndef __WIN32__ SSDBG( descP, ("SOCKET", "nif_accept%T), {%d,0x%X} ->" "\r\n ReqRef: %T" @@ -6770,8 +5311,18 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, ESOCK_MON2TERM(env, &descP->currentAcceptor.mon), descP->currentAcceptor.env, descP->currentAcceptor.ref) ); +#else + SSDBG( descP, + ("SOCKET", "nif_accept%T), {%d,0x%X} ->" + "\r\n ReqRef: %T" + "\r\n First Acceptor addr: %p" + "\r\n", + sockRef, descP->sock, descP->readState, + ref, + descP->acceptorsQ.first) ); +#endif - res = esock_accept(env, descP, sockRef, ref); + res = ESOCK_IO_ACCEPT(env, descP, sockRef, ref); SSDBG( descP, ("SOCKET", "nif_accept(%T) -> done with" "\r\n res: %T" @@ -6781,492 +5332,7 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, return res; -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef) -{ - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentReaderP != NULL) - return esock_make_error_invalid(env, atom_state); - - if (descP->currentAcceptorP == NULL) { - SOCKET accSock; - - /* We have no active acceptor (and therefore no acceptors in queue) - */ - - SSDBG( descP, ("SOCKET", "esock_accept {%d} -> try accept\r\n", - descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1); - - accSock = sock_accept(descP->sock, NULL, NULL); - - if (ESOCK_IS_ERROR(accSock)) { - int save_errno; - - save_errno = sock_errno(); - - return esock_accept_listening_error(env, descP, sockRef, - accRef, caller, save_errno); - } else { - /* We got an incoming connection */ - return esock_accept_listening_accept(env, descP, sockRef, - accSock, caller); - } - } else { - - /* We have an active acceptor and possibly acceptors waiting in queue. - * If the pid of the calling process is not the pid of the - * "current process", push the requester onto the (acceptor) queue. - */ - - SSDBG( descP, ("SOCKET", "esock_accept_accepting -> check: " - "is caller current acceptor:" - "\r\n Caller: %T" - "\r\n Current: %T" - "\r\n Current Mon: %T" - "\r\n", - caller, - descP->currentAcceptor.pid, - ESOCK_MON2TERM(env, &descP->currentAcceptor.mon)) ); - - if (COMPARE_PIDS(&descP->currentAcceptor.pid, &caller) == 0) { - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting {%d} -> current acceptor" - "\r\n", descP->sock) ); - - return esock_accept_accepting_current(env, descP, sockRef, accRef); - - } else { - - /* Not the "current acceptor", so (maybe) push onto queue */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting {%d} -> *not* current acceptor\r\n", - descP->sock) ); - - return esock_accept_accepting_other(env, descP, accRef, caller); - } - } -} -#endif // #ifndef __WIN32__ - -/* *** esock_accept_listening_error *** - * - * The accept call resultet in an error - handle it. - * There are only two cases: - * 1) BLOCK => Attempt a "retry" - * 2) Other => Return the value (converted to an atom) - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid caller, - int save_errno) -{ - ERL_NIF_TERM res; - - if (save_errno == ERRNO_BLOCK || - save_errno == EAGAIN) { - - /* *** Try again later *** */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_listening_error {%d} -> would block - retry\r\n", - descP->sock) ); - - descP->currentAcceptor.pid = caller; - ESOCK_ASSERT( MONP("esock_accept_listening -> current acceptor", - env, descP, - &descP->currentAcceptor.pid, - &descP->currentAcceptor.mon) == 0 ); - ESOCK_ASSERT( descP->currentAcceptor.env == NULL ); - descP->currentAcceptor.env = esock_alloc_env("current acceptor"); - descP->currentAcceptor.ref = - CP_TERM(descP->currentAcceptor.env, accRef); - descP->currentAcceptorP = &descP->currentAcceptor; - - SSDBG( descP, - ("SOCKET", - "esock_accept_listening_error {%d} -> retry for: " - "\r\n Current Pid: %T" - "\r\n Current Mon: %T" - "\r\n", - descP->sock, - descP->currentAcceptor.pid, - ESOCK_MON2TERM(env, &descP->currentAcceptor.mon)) ); - - res = esock_accept_busy_retry(env, descP, sockRef, accRef, NULL); - } else { - - SSDBG( descP, - ("SOCKET", - "esock_accept_listening {%d} -> errno: %d\r\n", - descP->sock, save_errno) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1); - - res = esock_make_error_errno(env, save_errno); - } - - return res; } -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_listening_accept *** - * - * The accept call was successful (accepted) - handle the new connection. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid caller) -{ - ERL_NIF_TERM res; - - esock_accept_accepted(env, descP, sockRef, accSock, caller, &res); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current *** - * Handles when the current acceptor makes another attempt. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef) -{ - SOCKET accSock; - int save_errno; - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current {%d} -> try accept\r\n", - descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1); - - accSock = sock_accept(descP->sock, NULL, NULL); - - if (ESOCK_IS_ERROR(accSock)) { - - save_errno = sock_errno(); - - res = esock_accept_accepting_current_error(env, descP, sockRef, - accRef, save_errno); - } else { - - res = esock_accept_accepting_current_accept(env, descP, sockRef, - accSock); - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current_accept *** - * - * Handles when the current acceptor succeeded in its accept call - - * handle the new connection. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock) -{ - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_accept {%d}" - "\r\n", descP->sock) ); - - if (esock_accept_accepted(env, descP, sockRef, accSock, - descP->currentAcceptor.pid, &res)) { - - ESOCK_ASSERT( DEMONP("esock_accept_accepting_current_accept -> " - "current acceptor", - env, descP, &descP->currentAcceptor.mon) == 0); - - MON_INIT(&descP->currentAcceptor.mon); - - if (!activate_next_acceptor(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_accept {%d} ->" - " no more acceptors" - "\r\n", descP->sock) ); - - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current_error *** - * The accept call of current acceptor resultet in an error - handle it. - * There are only two cases: - * 1) BLOCK => Attempt a "retry" - * 2) Other => Return the value (converted to an atom) - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - int save_errno) -{ - ERL_NIF_TERM res, reason; - - if (save_errno == ERRNO_BLOCK || - save_errno == EAGAIN) { - - /* - * Just try again, no real error, just a ghost trigger from poll, - */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> " - "would block: try again\r\n", descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_waits, &descP->accWaits, 1); - - res = esock_accept_busy_retry(env, descP, sockRef, opRef, - &descP->currentAcceptor.pid); - - } else { - ESockRequestor req; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> " - "error: %d\r\n", descP->sock, save_errno) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1); - - requestor_release("esock_accept_accepting_current_error", - env, descP, &descP->currentAcceptor); - - reason = MKA(env, erl_errno_id(save_errno)); - res = esock_make_error(env, reason); - - req.env = NULL; - while (acceptor_pop(env, descP, &req)) { - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> abort %T\r\n", - descP->sock, req.pid) ); - - esock_send_abort_msg(env, descP, sockRef, &req, reason); - - (void) DEMONP("esock_accept_accepting_current_error -> " - "pop'ed writer", - env, descP, &req.mon); - } - descP->currentAcceptorP = NULL; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_other *** - * Handles when the another acceptor makes an attempt, which - * results (maybe) in the request being pushed onto the - * acceptor queue. - */ -#ifndef __WIN32__ -ERL_NIF_TERM -esock_accept_accepting_other(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ErlNifPid caller) -{ - if (! acceptor_search4pid(env, descP, &caller)) { - acceptor_push(env, descP, caller, ref); - return atom_select; - } else { - /* Acceptor already in queue */ - return esock_raise_invalid(env, atom_state); - } -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_busy_retry *** - * - * Perform a retry select. If successful, set nextState. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid* pidP) -{ - int sres; - ERL_NIF_TERM res; - - if ((sres = esock_select_read(env, descP->sock, descP, pidP, - sockRef, accRef)) < 0) { - - ESOCK_ASSERT( DEMONP("esock_accept_busy_retry - select failed", - env, descP, &descP->currentAcceptor.mon) == 0); - - MON_INIT(&descP->currentAcceptor.mon); - - /* It is very unlikely that a next acceptor will be able - * to do anything successful, but we will clean the queue - */ - - if (!activate_next_acceptor(env, descP, sockRef)) { - SSDBG( descP, - ("SOCKET", - "esock_accept_busy_retry {%d} -> no more acceptors\r\n", - descP->sock) ); - - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); - } else { - descP->readState |= - (ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); - res = atom_select; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepted *** - * - * Generic function handling a successful accept. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_accept_accepted(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid pid, - ERL_NIF_TERM* result) -{ - ESockDescriptor* accDescP; - ErlNifEvent accEvent; - ERL_NIF_TERM accRef; - int save_errno; - - /* - * We got one - */ - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_success, &descP->accSuccess, 1); - - if ((accEvent = sock_create_event(accSock)) == INVALID_EVENT) { - save_errno = sock_errno(); - (void) sock_close(accSock); - *result = esock_make_error_errno(env, save_errno); - return FALSE; - } - - accDescP = alloc_descriptor(accSock, accEvent); - accDescP->domain = descP->domain; - accDescP->type = descP->type; - accDescP->protocol = descP->protocol; - - MLOCK(descP->writeMtx); - - accDescP->rBufSz = descP->rBufSz; // Inherit buffer size - accDescP->rNum = descP->rNum; // Inherit buffer uses - accDescP->rNumCnt = 0; - accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size - accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size - accDescP->iow = descP->iow; // Inherit iow - accDescP->dbg = descP->dbg; // Inherit debug flag - accDescP->useReg = descP->useReg; // Inherit useReg flag - inc_socket(accDescP->domain, accDescP->type, accDescP->protocol); - - accRef = enif_make_resource(env, accDescP); - enif_release_resource(accDescP); - - accDescP->ctrlPid = pid; - /* pid has actually been compared equal to self() - * in this code path just a little while ago - */ - ESOCK_ASSERT( MONP("esock_accept_accepted -> ctrl", - env, accDescP, - &accDescP->ctrlPid, - &accDescP->ctrlMon) == 0 ); - - SET_NONBLOCKING(accDescP->sock); - - descP->writeState |= ESOCK_STATE_CONNECTED; - - MUNLOCK(descP->writeMtx); - - /* And finally (maybe) update the registry */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, accRef); - - *result = esock_make_ok2(env, accRef); - - return TRUE; -} -#endif // #ifndef __WIN32__ @@ -7288,9 +5354,6 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM sockRef, sendRef; ErlNifBinary sndData; @@ -7342,7 +5405,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env, * is done! */ - res = esock_send(env, descP, sockRef, sendRef, &sndData, flags); + res = ESOCK_IO_SEND(env, descP, sockRef, sendRef, &sndData, flags); SSDBG( descP, ("SOCKET", "nif_send(%T) -> done with" "\r\n res: %T" @@ -7353,65 +5416,10 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env, SGDBG( ("SOCKET", "nif_send -> done with result: " "\r\n %T" "\r\n", res) ); - return res; - -#endif // #ifdef __WIN32__ #else -} - - - -/* *** esock_send *** - * - * Do the actual send. - * Do some initial writer checks, do the actual send and then - * analyze the result. If we are done, another writer may be - * scheduled (if there is one in the writer queue). - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* sndDataP, - int flags) -{ - ssize_t send_result; - ERL_NIF_TERM writerCheck; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - send_result = (ssize_t) sndDataP->size; - if ((size_t) send_result != sndDataP->size) - return esock_make_error_invalid(env, atom_data_size); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", "esock_send {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - send_result = - sock_send(descP->sock, sndDataP->data, sndDataP->size, flags); - - return send_check_result(env, descP, - send_result, sndDataP->size, FALSE, - sockRef, sendRef); + return res; } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -7433,9 +5441,6 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM sockRef, sendRef; ErlNifBinary sndData; @@ -7480,7 +5485,7 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, "nif_sendto(%T), {%d} -> sockaddr decode failed \r\n", sockRef, descP->sock) ); - return esock_make_invalid(env, atom_sockaddr); + return esock_make_invalid(env, esock_atom_sockaddr); } MLOCK(descP->writeMtx); @@ -7495,8 +5500,8 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, sockRef, descP->sock, descP->readState, sendRef, sndData.size, eSockAddr, flags) ); - res = esock_sendto(env, descP, sockRef, sendRef, &sndData, flags, - &remoteAddr, remoteAddrLen); + res = ESOCK_IO_SENDTO(env, descP, sockRef, sendRef, &sndData, flags, + &remoteAddr, remoteAddrLen); SSDBG( descP, ("SOCKET", "nif_sendto(%T) -> done with" "\r\n res: %T" @@ -7506,66 +5511,9 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, return res; -#endif // if defined(__WIN32__) } -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_sendto(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags, - ESockAddress* toAddrP, - SOCKLEN_T toAddrLen) -{ - ssize_t sendto_result; - ERL_NIF_TERM writerCheck; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - sendto_result = (ssize_t) dataP->size; - if ((size_t) sendto_result != dataP->size) - return esock_make_error_invalid(env, atom_data_size); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", "esock_sendto {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - - if (toAddrP != NULL) { - sendto_result = - sock_sendto(descP->sock, - dataP->data, dataP->size, flags, - &toAddrP->sa, toAddrLen); - } else { - sendto_result = - sock_sendto(descP->sock, - dataP->data, dataP->size, flags, - NULL, 0); - } - - return send_check_result(env, descP, sendto_result, dataP->size, FALSE, - sockRef, sendRef); -} -#endif // #ifndef __WIN32__ - - - /* ---------------------------------------------------------------------- * nif_sendmsg * @@ -7577,6 +5525,7 @@ ERL_NIF_TERM esock_sendto(ErlNifEnv* env, * Msg - Message - map() with data and (maybe) control and dest * Flags - Send flags as an integer(). * SendRef - A unique id reference() for this (send) request. + * IOV - List of binaries */ static @@ -7584,9 +5533,6 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM res, sockRef, sendRef, eMsg, eIOV; ESockDescriptor* descP; int flags; @@ -7629,7 +5575,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, sockRef, descP->sock, descP->writeState, sendRef, flags) ); - res = esock_sendmsg(env, descP, sockRef, sendRef, eMsg, flags, eIOV); + res = ESOCK_IO_SENDMSG(env, descP, sockRef, sendRef, eMsg, flags, eIOV); MUNLOCK(descP->writeMtx); @@ -7639,231 +5585,9 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, return res; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsg, - int flags, - ERL_NIF_TERM eIOV) -{ - ERL_NIF_TERM res, eAddr, eCtrl; - ESockAddress addr; - struct msghdr msgHdr; - ErlNifIOVec *iovec = NULL; - char* ctrlBuf; - size_t ctrlBufLen, ctrlBufUsed; - ssize_t dataSize, sendmsg_result; - ERL_NIF_TERM writerCheck, tail; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_sendmsg {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - /* Initiate the .name and .namelen fields depending on if - * we have an address or not - */ - if (! GET_MAP_VAL(env, eMsg, esock_atom_addr, &eAddr)) { - - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> no address\r\n", descP->sock) ); - - msgHdr.msg_name = NULL; - msgHdr.msg_namelen = 0; - } else { - msgHdr.msg_name = (void*) &addr; - msgHdr.msg_namelen = sizeof(addr); - sys_memzero((char *) msgHdr.msg_name, msgHdr.msg_namelen); - - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n address: %T" - "\r\n", descP->sock, eAddr) ); - - if (! esock_decode_sockaddr(env, eAddr, - msgHdr.msg_name, - &msgHdr.msg_namelen)) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid address\r\n", - descP->sock) ); - return esock_make_invalid(env, esock_atom_addr); - } - } - - /* Extract the *mandatory* 'iov', which must be an erlang:iovec(), - * from which we take at most IOV_MAX binaries - */ - if ((! enif_inspect_iovec(NULL, data.iov_max, eIOV, &tail, &iovec))) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> not an iov\r\n", - descP->sock) ); - - return esock_make_invalid(env, esock_atom_iov); - } - - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n iovcnt: %lu" - "\r\n tail: %s" - "\r\n", descP->sock, - (unsigned long) iovec->iovcnt, - B2S(! enif_is_empty_list(env, tail))) ); - - /* We now have an allocated iovec */ - - eCtrl = esock_atom_undefined; - ctrlBufLen = 0; - ctrlBuf = NULL; - - if (iovec->iovcnt > data.iov_max) { - if (descP->type == SOCK_STREAM) { - iovec->iovcnt = data.iov_max; - } else { - /* We can not send the whole packet in one sendmsg() call */ - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> iovcnt > iov_max\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - } - - dataSize = 0; - { - ERL_NIF_TERM h, t; - ErlNifBinary bin; - size_t i; - - /* Find out if there is remaining data in the tail. - * Skip empty binaries otherwise break. - * If 'tail' after loop exit is the empty list - * there was no more data. Otherwise there is more - * data or the 'iov' is invalid. - */ - for (;;) { - if (enif_get_list_cell(env, tail, &h, &t) && - enif_inspect_binary(env, h, &bin) && - (bin.size == 0)) { - tail = t; - continue; - } else - break; - } - - if ((! enif_is_empty_list(env, tail)) && - (descP->type != SOCK_STREAM)) { - /* We can not send the whole packet in one sendmsg() call */ - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid tail\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - - /* Calculate the data size */ - - for (i = 0; i < iovec->iovcnt; i++) { - size_t len = iovec->iov[i].iov_len; - dataSize += len; - if (dataSize < len) { - /* Overflow */ - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> Overflow" - "\r\n i: %lu" - "\r\n len: %lu" - "\r\n dataSize: %ld" - "\r\n", descP->sock, (unsigned long) i, - (unsigned long) len, (long) dataSize) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - } - } - SSDBG( descP, - ("SOCKET", - "esock_sendmsg {%d} ->" - "\r\n iov length: %lu" - "\r\n data size: %u" - "\r\n", - descP->sock, - (unsigned long) iovec->iovcnt, (long) dataSize) ); - - msgHdr.msg_iovlen = iovec->iovcnt; - msgHdr.msg_iov = iovec->iov; - - /* Extract the *optional* 'ctrl' */ - if (GET_MAP_VAL(env, eMsg, esock_atom_ctrl, &eCtrl)) { - ctrlBufLen = descP->wCtrlSz; - ctrlBuf = (char*) MALLOC(ctrlBufLen); - ESOCK_ASSERT( ctrlBuf != NULL ); - } - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> optional ctrl: " - "\r\n ctrlBuf: %p" - "\r\n ctrlBufLen: %lu" - "\r\n eCtrl: %T" - "\r\n", descP->sock, - ctrlBuf, (unsigned long) ctrlBufLen, eCtrl) ); - - /* Decode the ctrl and initiate that part of the msghdr. - */ - if (ctrlBuf != NULL) { - if (! decode_cmsghdrs(env, descP, - eCtrl, - ctrlBuf, ctrlBufLen, &ctrlBufUsed)) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid ctrl\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_ctrl); - goto done_free_iovec; - } - } else { - ctrlBufUsed = 0; - } - msgHdr.msg_control = ctrlBuf; - msgHdr.msg_controllen = ctrlBufUsed; - - /* The msg_flags field is not used when sending, - * but zero it just in case */ - msgHdr.msg_flags = 0; - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - - /* And now, try to send the message */ - sendmsg_result = sock_sendmsg(descP->sock, &msgHdr, flags); - - res = send_check_result(env, descP, sendmsg_result, dataSize, - (! enif_is_empty_list(env, tail)), - sockRef, sendRef); - - done_free_iovec: - enif_free_iovec(iovec); - if (ctrlBuf != NULL) FREE(ctrlBuf); - - SSDBG( descP, - ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n %T\r\n", descP->sock, res) ); - return res; -} -#endif // #ifndef __WIN32__ - - #ifdef FOOBAR @@ -7957,7 +5681,7 @@ nif_sendfile(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) || !defined(HAVE_SENDFILE) +#if !defined(HAVE_SENDFILE) return enif_raise_exception(env, MKA(env, "notsup")); #else ESockDescriptor *descP; @@ -7985,7 +5709,7 @@ nif_sendfile(ErlNifEnv* env, sockRef, descP->sock, descP->sendfileHandle, descP->writeState) ); - res = esock_sendfile_deferred_close(env, descP); + res = ESOCK_IO_SENDFILE_DC(env, descP); } else { ERL_NIF_TERM sendRef; @@ -8034,9 +5758,9 @@ nif_sendfile(ErlNifEnv* env, sockRef, descP->sock, descP->readState, sendRef, (long) offset, (long) count) ); - res = - esock_sendfile_cont(env, descP, sockRef, sendRef, - offset, count); + res = ESOCK_IO_SENDFILE_CONT(env, descP, + sockRef, sendRef, + offset, count); } else { ERL_NIF_TERM fRef; @@ -8052,15 +5776,15 @@ nif_sendfile(ErlNifEnv* env, ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->" "\r\n sendRef: %T" "\r\n offset: %ld" - "\r\n count: %ld" + "\r\n count: %ld" "\r\n fRef: %T" "\r\n", sockRef, descP->sock, descP->readState, sendRef, (long) offset, (long) count, fRef) ); - res = - esock_sendfile_start(env, descP, sockRef, sendRef, - offset, count, fRef); + res = ESOCK_IO_SENDFILE_START(env, descP, + sockRef, sendRef, + offset, count, fRef); } } @@ -8072,565 +5796,9 @@ nif_sendfile(ErlNifEnv* env, return res; -#endif // #if defined(__WIN32__) || !defined(HAVE_SENDFILE) -} - -#ifndef __WIN32__ -#ifdef HAVE_SENDFILE - -/* Start a sendfile() operation - */ -static ERL_NIF_TERM -esock_sendfile_start(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count, - ERL_NIF_TERM fRef) { - ERL_NIF_TERM writerCheck; - ssize_t res; - int err; - - SSDBG( descP, ("SOCKET", - "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n" - " fRef: %T\r\n" - " offset: %lu\r\n" - " count: %lu\r\n", - sockRef, descP->sock, sendRef, - fRef, (unsigned long) offset, (unsigned long) count) ); - - if (! IS_OPEN(descP->writeState)) { - return esock_make_error(env, atom_closed); - } - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) { - return esock_make_error_invalid(env, atom_state); - } - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer - */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", - "esock_sendfile_start {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - - /* Returns 'select' if current process got enqueued, - * or exception invalid state if current process already - * was enqueued - */ - return writerCheck; - } - - if (descP->sendfileHandle != INVALID_HANDLE) - return esock_make_error_invalid(env, atom_state); - - /* Get a dup:ed file handle from prim_file_nif - * through a NIF dyncall - */ - { - struct prim_file_nif_dyncall_dup dc_dup; - - dc_dup.op = prim_file_nif_dyncall_dup; - dc_dup.result = EINVAL; // should not be needed - - /* Request the handle */ - if (enif_dynamic_resource_call(env, - atom_prim_file, atom_efile, fRef, - &dc_dup) - != 0) { - return - esock_sendfile_error(env, descP, sockRef, - MKT2(env, esock_atom_invalid, - atom_efile)); - } - if (dc_dup.result != 0) { - return - esock_sendfile_errno(env, descP, sockRef, dc_dup.result); - } - descP->sendfileHandle = dc_dup.handle; - } - - SSDBG( descP, ("SOCKET", - "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n" - " sendfileHandle: %d\r\n", - sockRef, descP->sock, sendRef, - descP->sendfileHandle) ); - - if (descP->sendfileCountersP == NULL) { - descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); - *descP->sendfileCountersP = initESockSendfileCounters; - } - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_tries, &descP->sendfileCountersP->tries, 1); - descP->sendfileCountersP->maxCnt = 0; - - res = esock_sendfile(env, descP, sockRef, offset, &count, &err); - - if (res < 0) { // Terminal error - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_sendfile_errno(env, descP, sockRef, err); - - } else if (res > 0) { // Retry by select - - if (descP->currentWriterP == NULL) { - int mon_res; - - /* Register writer as current */ - ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); - mon_res = - MONP("sendfile -> current writer", - env, descP, - &descP->currentWriter.pid, - &descP->currentWriter.mon); - ESOCK_ASSERT( mon_res >= 0 ); - - if (mon_res > 0) { - /* Caller died already, can happen for dirty NIFs */ - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return - esock_sendfile_error(env, descP, sockRef, - MKT2(env, - esock_atom_invalid, - esock_atom_not_owner)); - } - ESOCK_ASSERT( descP->currentWriter.env == NULL ); - descP->currentWriter.env = esock_alloc_env("current-writer"); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - descP->currentWriterP = &descP->currentWriter; - } - // else current writer is already registered by requestor_pop() - - return esock_sendfile_select(env, descP, sockRef, sendRef, count); - - } else { // res == 0: Done - return esock_sendfile_ok(env, descP, sockRef, count); - } -} - -/* Continue an ongoing sendfile operation - */ -static ERL_NIF_TERM -esock_sendfile_cont(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count) { - ErlNifPid caller; - ssize_t res; - int err; - - SSDBG( descP, ("SOCKET", - "esock_sendfile_cont(%T) {%d} -> sendRef: %T\r\n", - sockRef, descP->sock, sendRef) ); - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Verify that this process has a sendfile operation in progress */ - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - if ((descP->currentWriterP == NULL) || - (descP->sendfileHandle == INVALID_HANDLE) || - (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0)) { - // - return esock_raise_invalid(env, atom_state); - } - - res = esock_sendfile(env, descP, sockRef, offset, &count, &err); - - if (res < 0) { // Terminal error - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_sendfile_errno(env, descP, sockRef, err); - - } else if (res > 0) { // Retry by select - - /* Overwrite current writer registration */ - enif_clear_env(descP->currentWriter.env); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - - return esock_sendfile_select(env, descP, sockRef, sendRef, count); - - } else { // res == 0: Done - return esock_sendfile_ok(env, descP, sockRef, count); - } +#endif // !defined(HAVE_SENDFILE) } -/* Deferred close of the dup:ed file descriptor - */ -static ERL_NIF_TERM -esock_sendfile_deferred_close(ErlNifEnv *env, - ESockDescriptor *descP) { - if (descP->sendfileHandle == INVALID_HANDLE) - return esock_make_error_invalid(env, atom_state); - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_atom_ok; -} - -/* Platform independent sendfile() function - * - * Return < 0 for terminal error - * 0 for done - * > 0 for retry with select - */ -static int -esock_sendfile(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - off_t offset, - size_t *countP, - int *errP) { - - size_t pkgSize = 0; // Total sent in this call - - SSDBG( descP, ("SOCKET", - "esock_sendfile(%T) {%d,%d}\r\n", - sockRef, descP->sock, descP->sendfileHandle) ); - - for (;;) { - size_t chunk_size = (size_t) 0x20000000UL; // 0.5 GB - size_t bytes_sent; - ssize_t res; - int error; - - /* *countP == 0 means send the whole file - use chunk size */ - if ((*countP > 0) && (*countP < chunk_size)) - chunk_size = *countP; - - { - /* Platform dependent code: - * update and check offset, set and check bytes_sent, and - * set res to >= 0 and error to 0, or - * set res to < 0 and error to sock_errno() - */ -#if defined (__linux__) - - off_t prev_offset; - - prev_offset = offset; - res = - sendfile(descP->sock, descP->sendfileHandle, - &offset, chunk_size); - error = (res < 0) ? sock_errno() : 0; - - ESOCK_ASSERT( offset >= prev_offset ); - ESOCK_ASSERT( (off_t) chunk_size >= (offset - prev_offset) ); - bytes_sent = (size_t) (offset - prev_offset); - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - -#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__DARWIN__) - - off_t sbytes; - -#if defined(__DARWIN__) - sbytes = (off_t) chunk_size; - res = (ssize_t) - sendfile(descP->sendfileHandle, descP->sock, offset, - &sbytes, NULL, 0); -#else - sbytes = 0; - res = (ssize_t) - sendfile(descP->sendfileHandle, descP->sock, offset, - chunk_size, NULL, &sbytes, 0); -#endif - error = (res < 0) ? sock_errno() : 0; - - /* For an error return, we do not dare trust that sbytes is set - * unless the error is ERRNO_BLOCK or EINTR - * - the man page is to vague - */ - if ((res < 0) && (error != ERRNO_BLOCK) && (error != EINTR)) { - sbytes = 0; - } else { - ESOCK_ASSERT( sbytes >= 0 ); - ESOCK_ASSERT( (off_t) chunk_size >= sbytes ); - ESOCK_ASSERT( offset + sbytes >= offset ); - offset += sbytes; - } - bytes_sent = (size_t) sbytes; - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - -#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) - - sendfilevec_t sfvec[1]; - - sfvec[0].sfv_fd = descP->sendfileHandle; - sfvec[0].sfv_flag = 0; - sfvec[0].sfv_off = offset; - sfvec[0].sfv_len = chunk_size; - - res = sendfilev(descP->sock, sfvec, NUM(sfvec), &bytes_sent); - error = (res < 0) ? sock_errno() : 0; - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - - if ((res < 0) && (error == EINVAL)) { - /* On e.b SunOS 5.10 using sfv_len > file size - * lands here - we regard this as a successful send. - * All other causes for EINVAL are avoided, - * except for .sfv_fd not seekable, which would - * give bytes_sent == 0 that we would interpret - * as end of file, which is kind of true. - */ - res = 0; - } - ESOCK_ASSERT( chunk_size >= bytes_sent ); - ESOCK_ASSERT( offset + bytes_sent >= offset ); - offset += bytes_sent; - -#else -#error "Unsupported sendfile syscall; update configure test." -#endif - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile, &descP->sendfileCountersP->cnt, 1); - - if (bytes_sent != 0) { - - pkgSize += bytes_sent; - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_pkg, - &descP->sendfileCountersP->pkg, - 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_byte, - &descP->sendfileCountersP->byteCnt, - bytes_sent); - - if (pkgSize > descP->sendfileCountersP->pkgMax) - descP->sendfileCountersP->pkgMax = pkgSize; - if ((descP->sendfileCountersP->maxCnt += bytes_sent) - > descP->sendfileCountersP->max) - descP->sendfileCountersP->max = - descP->sendfileCountersP->maxCnt; - } - - /* *countP == 0 means send whole file */ - if (*countP > 0) { - - *countP -= bytes_sent; - - if (*countP == 0) { // All sent - *countP = pkgSize; - return 0; - } - } - - if (res < 0) { - if (error == ERRNO_BLOCK) { - *countP = pkgSize; - return 1; - } - if (error == EINTR) - continue; - *errP = error; - return -1; - } - - if (bytes_sent == 0) { // End of input file - *countP = pkgSize; - return 0; - } - } - } // for (;;) -} - -static ERL_NIF_TERM -esock_sendfile_errno(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - int err) { - ERL_NIF_TERM reason; - - reason = MKA(env, erl_errno_id(err)); - return esock_sendfile_error(env, descP, sockRef, reason); -} - -static ERL_NIF_TERM -esock_sendfile_error(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) { - - if (descP->sendfileCountersP == NULL) { - descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); - *descP->sendfileCountersP = initESockSendfileCounters; - } - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_fails, - &descP->sendfileCountersP->fails, 1); - - SSDBG( descP, ("SOCKET", - "esock_sendfile_error(%T) {%d} -> error: %T\r\n", - sockRef, descP->sock, reason) ); - - /* XXX Should we have special treatment for EINVAL, - * such as to only fail current operation and activate - * the next from the queue? - */ - - if (descP->currentWriterP != NULL) { - - (void) DEMONP("esock_sendfile_error", - env, descP, &descP->currentWriter.mon); - - /* Fail all queued writers */ - requestor_release("esock_sendfile_error", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; - - } - - return esock_make_error(env, reason); -} - -static ERL_NIF_TERM -esock_sendfile_select(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - size_t count) { - int sres; - - /* Select write for this process */ - sres = - esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); - if (sres < 0) { - ERL_NIF_TERM reason; - - /* Internal select error */ - (void) DEMONP("esock_sendfile_select - failed", - env, descP, &descP->currentWriter.mon); - - /* Fail all queued writers */ - reason = MKT2(env, atom_select_write, MKI(env, sres)); - requestor_release("esock_sendfile_select_fail", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return enif_raise_exception(env, reason); - - } else { - ErlNifUInt64 bytes_sent; - - SSDBG( descP, - ("SOCKET", "esock_sendfile_select(%T) {%d} -> " - "sendRef (%T)\r\n" - "count: %lu\r\n", - sockRef, descP->sock, sendRef, (unsigned long) count) ); - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_waits, - &descP->sendfileCountersP->waits, - 1); - descP->writeState |= ESOCK_STATE_SELECTED; - bytes_sent = (ErlNifUInt64) count; - - return MKT2(env, atom_select, MKUI64(env, bytes_sent)); - } -} - -static ERL_NIF_TERM -esock_sendfile_ok(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - size_t count) { - ErlNifUInt64 bytes_sent64u; - - SSDBG( descP, - ("SOCKET", "esock_sendfile_ok(%T) {%d} -> " - "everything written (%lu) - done\r\n", - sockRef, descP->sock, (unsigned long) count) ); - - if (descP->currentWriterP != NULL) { - - (void) DEMONP("esock_sendfile_ok -> current writer", - env, descP, &descP->currentWriter.mon); - - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (! activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_sendfile_ok(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - } - - descP->writePkgMaxCnt = 0; - bytes_sent64u = (ErlNifUInt64) count; - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_make_ok2(env, MKUI64(env, bytes_sent64u)); -} - -#endif // #ifdef HAVE_SENDFILE -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -8655,9 +5823,6 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM sockRef, recvRef; ErlNifUInt64 elen; @@ -8676,7 +5841,7 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env, } if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { + (COMPARE(recvRef, esock_atom_zero) != 0)) { return enif_make_badarg(env); } if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) || @@ -8713,7 +5878,7 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env, * is done! */ - res = esock_recv(env, descP, sockRef, recvRef, len, flags); + res = ESOCK_IO_RECV(env, descP, sockRef, recvRef, len, flags); SSDBG( descP, ("SOCKET", "nif_recv(%T) -> done" "\r\n", sockRef) ); @@ -8722,83 +5887,9 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env, return res; -#endif // #ifdef __WIN32__ #else } -/* The (read) buffer handling should be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags) -{ - ssize_t read; - ErlNifBinary buf; - ERL_NIF_TERM readerCheck; - int save_errno; - size_t bufSz = (len != 0 ? len : descP->rBufSz); - - SSDBG( descP, ("SOCKET", "esock_recv {%d} -> entry with" - "\r\n count,size: (%ld:%u:%lu)" - "\r\n", descP->sock, - (long) len, descP->rNumCnt, (unsigned long) bufSz) ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } - - /* Allocate a buffer: - * Either as much as we want to read or (if zero (0)) use the "default" - * size (what has been configured). - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); - - // If it fails (read = -1), we need errno... - SSDBG( descP, ("SOCKET", "esock_recv {%d} -> try read (%lu)\r\n", - descP->sock, (unsigned long) buf.size) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); - - read = sock_recv(descP->sock, buf.data, buf.size, flags); - if (ESOCK_IS_ERROR(read)) { - save_errno = sock_errno(); - } else { - save_errno = 0; // The value does not actually matter in this case - } - - SSDBG( descP, ("SOCKET", - "esock_recv {%d} -> read: %ld (%d)\r\n", - descP->sock, (long) read, save_errno) ); - - return recv_check_result(env, descP, read, len, save_errno, - &buf, sockRef, recvRef); -} -#endif // #ifndef __WIN32__ - - - /* ---------------------------------------------------------------------- * nif_recvfrom * @@ -8829,9 +5920,6 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM sockRef, recvRef; ErlNifUInt64 elen; @@ -8854,7 +5942,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, /* Extract arguments and perform preliminary validation */ if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { + (COMPARE(recvRef, esock_atom_zero) != 0)) { return enif_make_badarg(env); } @@ -8866,8 +5954,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, if (! a1ok) return esock_make_error_integer_range(env, argv[1]); - return - esock_make_error_integer_range(env, argv[2]); + return esock_make_error_integer_range(env, argv[2]); } len = (ssize_t) elen; if (elen != (ErlNifUInt64) len) @@ -8899,7 +5986,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, * </KOLLA> */ - res = esock_recvfrom(env, descP, sockRef, recvRef, len, flags); + res = ESOCK_IO_RECVFROM(env, descP, sockRef, recvRef, len, flags); SSDBG( descP, ("SOCKET", "nif_recvfrom(%T) -> done" "\r\n", sockRef) ); @@ -8907,77 +5994,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, MUNLOCK(descP->readMtx); return res; -#endif // #ifdef __WIN32__ #else -} - - -/* The (read) buffer handling *must* be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags) -{ - ESockAddress fromAddr; - SOCKLEN_T addrLen; - ssize_t read; - int save_errno; - ErlNifBinary buf; - ERL_NIF_TERM readerCheck; - size_t bufSz = (len != 0 ? len : descP->rBufSz); - - SSDBG( descP, ("SOCKET", "esock_recvfrom {%d} -> entry with" - "\r\n bufSz: %d" - "\r\n", descP->sock, bufSz) ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } - - /* Allocate a buffer: - * Either as much as we want to read or (if zero (0)) use the "default" - * size (what has been configured). - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); - - addrLen = sizeof(fromAddr); - sys_memzero((char*) &fromAddr, addrLen); - - read = sock_recvfrom(descP->sock, buf.data, buf.size, flags, - &fromAddr.sa, &addrLen); - if (ESOCK_IS_ERROR(read)) - save_errno = sock_errno(); - else - save_errno = 0; // The value does not actually matter in this case - - return recvfrom_check_result(env, descP, read, save_errno, - &buf, &fromAddr, addrLen, - sockRef, recvRef); } -#endif // #ifndef __WIN32__ @@ -9015,9 +6032,6 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM sockRef, recvRef; ErlNifUInt64 eBufSz, eCtrlSz; @@ -9040,7 +6054,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, /* Extract arguments and perform preliminary validation */ if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { + (COMPARE(recvRef, esock_atom_zero) != 0)) { return enif_make_badarg(env); } @@ -9097,7 +6111,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, * </KOLLA> */ - res = esock_recvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); + res = ESOCK_IO_RECVMSG(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); SSDBG( descP, ("SOCKET", "nif_recvmsg(%T) -> done" "\r\n", sockRef) ); @@ -9105,108 +6119,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, MUNLOCK(descP->readMtx); return res; -#endif // #ifdef __WIN32__ #else -} - - -/* The (read) buffer handling *must* be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufLen, - ssize_t ctrlLen, - int flags) -{ - SOCKLEN_T addrLen; - ssize_t read; - int save_errno; - size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz); - size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz); - struct msghdr msgHdr; - SysIOVec iov[1]; // Shall we always use 1? - ErlNifBinary data[1]; // Shall we always use 1? - ErlNifBinary ctrl; - ERL_NIF_TERM readerCheck; - ESockAddress addr; - - SSDBG( descP, ("SOCKET", "esock_recvmsg {%d} -> entry with" - "\r\n bufSz: %lu (%ld)" - "\r\n ctrlSz: %ld (%ld)" - "\r\n", descP->sock, - (unsigned long) bufSz, (long) bufLen, - (unsigned long) ctrlSz, (long) ctrlLen) ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } - - /* - for (i = 0; i < sizeof(buf); i++) { - ESOCK_ASSERT( ALLOC_BIN(bifSz, &buf[i]) ); - iov[i].iov_base = buf[i].data; - iov[i].iov_len = buf[i].size; - } - */ - - /* Allocate the (msg) data buffer: - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &data[0]) ); - - /* Allocate the ctrl (buffer): - */ - ESOCK_ASSERT( ALLOC_BIN(ctrlSz, &ctrl) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); - - addrLen = sizeof(addr); - sys_memzero((char*) &addr, addrLen); - sys_memzero((char*) &msgHdr, sizeof(msgHdr)); - - iov[0].iov_base = data[0].data; - iov[0].iov_len = data[0].size; - - msgHdr.msg_name = &addr; - msgHdr.msg_namelen = addrLen; - msgHdr.msg_iov = iov; - msgHdr.msg_iovlen = 1; // Should use a constant or calculate... - msgHdr.msg_control = ctrl.data; - msgHdr.msg_controllen = ctrl.size; - - read = sock_recvmsg(descP->sock, &msgHdr, flags); - if (ESOCK_IS_ERROR(read)) - save_errno = sock_errno(); - else - save_errno = 0; // The value does not actually matter in this case - - return recvmsg_check_result(env, descP, read, save_errno, - &msgHdr, - data, // Needed for iov encode - &ctrl, // Needed for ctrl header encode - sockRef, recvRef); } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -9224,9 +6137,6 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM res; @@ -9253,7 +6163,7 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env, descP->readState, descP->writeState, esock_self(env)) ); - res = esock_close(env, descP); + res = ESOCK_IO_CLOSE(env, descP); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); @@ -9263,230 +6173,7 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env, "\r\n", argv[0], res) ); return res; -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_close(ErlNifEnv* env, - ESockDescriptor* descP) -{ - if (! IS_OPEN(descP->readState)) { - /* A bit of cheeting; maybe not closed yet - do we need a queue? */ - return esock_make_error(env, atom_closed); - } - - /* Store the PID of the caller, - * since we need to inform it when we - * (that is, the stop callback function) - * completes. - */ - ESOCK_ASSERT( enif_self(env, &descP->closerPid) != NULL ); - - /* If the caller is not the owner; monitor the caller, - * since we should complete this operation even if the caller dies - * (for whatever reason). - */ - if (COMPARE_PIDS(&descP->closerPid, &descP->ctrlPid) != 0) { - - ESOCK_ASSERT( MONP("esock_close_check -> closer", - env, descP, - &descP->closerPid, - &descP->closerMon) == 0 ); - } - - /* Prepare for closing the socket */ - descP->readState |= ESOCK_STATE_CLOSING; - descP->writeState |= ESOCK_STATE_CLOSING; - if (esock_do_stop(env, descP)) { - // esock_stop() has been scheduled - wait for it - SSDBG( descP, - ("SOCKET", "esock_close {%d} -> stop was scheduled\r\n", - descP->sock) ); - - // Create closeRef for the close msg that esock_stop() will send - descP->closeEnv = esock_alloc_env("esock_close_do - close-env"); - descP->closeRef = MKREF(descP->closeEnv); - - return esock_make_ok2(env, CP_TERM(env, descP->closeRef)); - } else { - // The socket may be closed - tell caller to finalize - SSDBG( descP, - ("SOCKET", - "esock_close {%d} -> stop was called\r\n", - descP->sock) ); - - return esock_atom_ok; - } } -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -/* Prepare for close - return whether stop is scheduled - */ -static -BOOLEAN_T esock_do_stop(ErlNifEnv* env, - ESockDescriptor* descP) { - BOOLEAN_T ret; - int sres; - ERL_NIF_TERM sockRef; - - sockRef = enif_make_resource(env, descP); - - if (IS_SELECTED(descP)) { - ESOCK_ASSERT( (sres = esock_select_stop(env, descP->sock, descP)) - >= 0 ); - if ((sres & ERL_NIF_SELECT_STOP_CALLED) != 0) { - /* The socket is no longer known by the select machinery - * - it may be closed - */ - ret = FALSE; - } else { - ESOCK_ASSERT( (sres & ERL_NIF_SELECT_STOP_SCHEDULED) != 0 ); - /* esock_stop() is scheduled - * - socket may be removed by esock_stop() or later - */ - ret = TRUE; - } - } else { - sres = 0; - /* The socket has never been used in the select machinery - * - it may be closed - */ - ret = FALSE; - } - - /* +++++++ Current and waiting Writers +++++++ */ - - if (descP->currentWriterP != NULL) { - - /* We have a current Writer; was it deselected? - */ - - if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { - - /* The current Writer will not get a select message - * - send it an abort message - */ - - esock_stop_handle_current(env, - "writer", - descP, sockRef, &descP->currentWriter); - } - - /* Inform the waiting Writers (in the same way) */ - - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting writer(s)\r\n", - descP->sock) ); - - inform_waiting_procs(env, "writer", - descP, sockRef, &descP->writersQ, atom_closed); - - descP->currentWriterP = NULL; - } - - /* +++++++ Connector +++++++ - * Note that there should not be Writers and a Connector - * at the same time so the check for if the - * current Writer/Connecter was deselected is only correct - * under that assumption - */ - - if (descP->connectorP != NULL) { - - /* We have a Connector; was it deselected? - */ - - if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { - - /* The Connector will not get a select message - * - send it an abort message - */ - - esock_stop_handle_current(env, - "connector", - descP, sockRef, &descP->connector); - } - - descP->connectorP = NULL; - } - - /* +++++++ Current and waiting Readers +++++++ */ - - if (descP->currentReaderP != NULL) { - - /* We have a current Reader; was it deselected? - */ - - if (sres & ERL_NIF_SELECT_READ_CANCELLED) { - - /* The current Reader will not get a select message - * - send it an abort message - */ - - esock_stop_handle_current(env, - "reader", - descP, sockRef, &descP->currentReader); - } - - /* Inform the Readers (in the same way) */ - - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting reader(s)\r\n", - descP->sock) ); - - inform_waiting_procs(env, "writer", - descP, sockRef, &descP->readersQ, atom_closed); - - descP->currentReaderP = NULL; - } - - /* +++++++ Current and waiting Acceptors +++++++ - * - * Note that there should not be Readers and Acceptors - * at the same time so the check for if the - * current Reader/Acceptor was deselected is only correct - * under that assumption - */ - - if (descP->currentAcceptorP != NULL) { - - /* We have a current Acceptor; was it deselected? - */ - - if (sres & ERL_NIF_SELECT_READ_CANCELLED) { - - /* The current Acceptor will not get a select message - * - send it an abort message - */ - - esock_stop_handle_current(env, - "acceptor", - descP, sockRef, &descP->currentAcceptor); - } - - /* Inform the waiting Acceptor (in the same way) */ - - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting acceptors(s)\r\n", - descP->sock) ); - - inform_waiting_procs(env, "acceptor", - descP, sockRef, &descP->acceptorsQ, atom_closed); - - descP->currentAcceptorP = NULL; - } - - return ret; -} -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -9506,9 +6193,6 @@ ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env, { ESockDescriptor* descP; ERL_NIF_TERM result; -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else /* Extract arguments and perform preliminary validation */ @@ -9522,10 +6206,13 @@ ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env, MLOCK(descP->writeMtx); SSDBG( descP, - ("SOCKET", "nif_finalize_close(%T), {%d,0x%X}\r\n", - argv[0], descP->sock, descP->readState) ); + ("SOCKET", "nif_finalize_close(%T, %d) -> " + "\r\n ReadState: 0x%X" + "\r\n WriteState: 0x%X" + "\r\n", + argv[0], descP->sock, descP->readState, descP->writeState) ); - result = esock_finalize_close(env, descP); + result = ESOCK_IO_FIN_CLOSE(env, descP); SSDBG( descP, ("SOCKET", "nif_finalize_close(%T) -> done with" "\r\n result: %T" @@ -9535,104 +6222,14 @@ ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env, MUNLOCK(descP->readMtx); return result; -#endif // #ifdef __WIN32__ #else } -/* *** esock_finalize_close *** - * Perform the final step in the socket close. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env, - ESockDescriptor* descP) +extern +int esock_close_socket(ErlNifEnv* env, + ESockDescriptor* descP, + BOOLEAN_T unlock) { - int err; - ErlNifPid self; -#ifdef HAVE_SENDFILE - HANDLE sendfileHandle; -#endif - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - if (IS_CLOSED(descP->readState)) - return esock_make_error(env, atom_closed); - - if (! IS_CLOSING(descP->readState)) { - // esock_close() has not been called - return esock_raise_invalid(env, atom_state); - } - - if (IS_SELECTED(descP) && (descP->closeEnv != NULL)) { - // esock_stop() is scheduled but has not been called - return esock_raise_invalid(env, atom_state); - } - - if (COMPARE_PIDS(&descP->closerPid, &self) != 0) { - // This process is not the closer - return esock_raise_invalid(env, atom_state); - } - - // Close the socket - - /* Stop monitoring the closer. - * Demonitoring may fail since this is a dirty NIF - * - the caller may have died already. - */ - enif_set_pid_undefined(&descP->closerPid); - if (descP->closerMon.isActive) { - (void) DEMONP("esock_finalize_close -> closer", - env, descP, &descP->closerMon); - } - - /* Stop monitoring the owner */ - enif_set_pid_undefined(&descP->ctrlPid); - (void) DEMONP("esock_finalize_close -> ctrl", - env, descP, &descP->ctrlMon); - /* Not impossible to still get a esock_down() call from a - * just triggered owner monitor down - */ - -#ifdef HAVE_SENDFILE - sendfileHandle = descP->sendfileHandle; - descP->sendfileHandle = INVALID_HANDLE; -#endif - - /* This nif is executed in a dirty scheduler just so that - * it can "hang" (with minimum effect on the VM) while the - * kernel writes our buffers. IF we have set the linger option - * for this ({true, integer() > 0}). For this to work we must - * be blocking... - */ - SET_BLOCKING(descP->sock); - err = esock_close_socket(env, descP, TRUE); - -#ifdef HAVE_SENDFILE - if (sendfileHandle != INVALID_HANDLE) { - (void) close(descP->sendfileHandle); - } -#endif - - if (err != 0) { - if (err == ERRNO_BLOCK) { - /* Not all data in the buffers where sent, - * make sure the caller gets this. - */ - return esock_make_error(env, atom_timeout); - } else { - return esock_make_error_errno(env, err); - } - } - - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static int esock_close_socket(ErlNifEnv* env, - ESockDescriptor* descP, - BOOLEAN_T unlock) { int err = 0; SOCKET sock = descP->sock; ERL_NIF_TERM sockRef; @@ -9650,21 +6247,22 @@ static int esock_close_socket(ErlNifEnv* env, * finalize_close */ descP->sock = INVALID_SOCKET; - descP->event = INVALID_EVENT; descP->readState |= ESOCK_STATE_CLOSED; descP->writeState |= ESOCK_STATE_CLOSED; - dec_socket(descP->domain, descP->type, descP->protocol); + esock_dec_socket(descP->domain, descP->type, descP->protocol); /* +++++++ Clear the meta option +++++++ */ enif_clear_env(descP->meta.env); descP->meta.ref = esock_atom_undefined; - sock_close_event(descP->event); if (descP->closeOnClose) { if (unlock) { MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); } + SSDBG( descP, + ("SOCKET", "esock_close_socket(%d) -> " + "try socket close\r\n", sock) ); if (sock_close(sock) != 0) err = sock_errno(); if (unlock) { @@ -9675,8 +6273,8 @@ static int esock_close_socket(ErlNifEnv* env, if (err != 0) { SSDBG( descP, - ("SOCKET", "esock_close_socket {%d} -> %d\r\n", - sock, err) ); + ("SOCKET", "esock_close_socket(%d) -> %s (%d)\r\n", + sock, erl_errno_id(err), err) ); } /* (maybe) Update the registry */ @@ -9687,7 +6285,7 @@ static int esock_close_socket(ErlNifEnv* env, return err; } -#endif // #ifndef __WIN32__ + /* ---------------------------------------------------------------------- @@ -9706,9 +6304,6 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM ehow, res; int how; @@ -9734,7 +6329,7 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env, argv[0], descP->sock, descP->readState | descP->writeState, how) ); - res = esock_shutdown(env, descP, how); + res = ESOCK_IO_SHUTDOWN(env, descP, how); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); @@ -9744,26 +6339,25 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env, "\r\n", argv[0], res) ); return res; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ +/* ======================================================================== + */ static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, ESockDescriptor* descP, int how) { if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); if (sock_shutdown(descP->sock, how) == 0) return esock_atom_ok; else return esock_make_error_errno(env, sock_errno()); } -#endif // #ifndef __WIN32__ @@ -9790,64 +6384,73 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP = NULL; + ERL_NIF_TERM esock, elevel, eopt, eval, enval; int level, opt, nativeValue; - ERL_NIF_TERM eVal; ESOCK_ASSERT( argc == 5 ); - SGDBG( ("SOCKET", "nif_setopt -> entry with argc: %d\r\n", argc) ); + esock = argv[0]; + elevel = argv[1]; + eopt = argv[2]; + eval = argv[3]; + enval = argv[4]; + + SGDBG( ("SOCKET", + "nif_setopt -> entry with argc: %d" + "\r\n esock: %T" + "\r\n elevel: %T" + "\r\n eopt: %T" + "\r\n eval: %T" + "\r\n enval: %T" + "\r\n", argc, esock, elevel, eopt, eval, enval) ); /* Extract arguments and perform preliminary validation */ - if ((! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) || - (! GET_INT(env, argv[4], &nativeValue))) { - // + if ((! ESOCK_GET_RESOURCE(env, esock, (void**) &descP)) || + (! GET_INT(env, enval, &nativeValue))) { SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); return enif_make_badarg(env); } - if (! GET_INT(env, argv[2], &opt)) { + + if (! GET_INT(env, eopt, &opt)) { SSDBG( descP, ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); - if (! IS_INTEGER(env, argv[2])) + if (! IS_INTEGER(env, eopt)) return enif_make_badarg(env); else - return esock_make_error_integer_range(env, argv[2]); - } - eVal = argv[3]; - - if (esock_decode_level(env, argv[1], &level)) { - if (nativeValue == 0) - return esock_setopt(env, descP, level, opt, eVal); - else - return esock_setopt_native(env, descP, level, opt, eVal); + return esock_make_error_integer_range(env, eopt); } - if (COMPARE(argv[1], atom_otp) == 0) { + if (COMPARE(elevel, atom_otp) == 0) { if (nativeValue == 0) { - return esock_setopt_otp(env, descP, opt, eVal); + return ESOCK_IO_SETOPT_OTP(env, descP, opt, eval); } else { SSDBG( descP, ("SOCKET", "nif_setopt -> failed arg check\r\n") ); return enif_make_badarg(env); } } + if (esock_decode_level(env, elevel, &level)) { + if (nativeValue == 0) + return ESOCK_IO_SETOPT(env, descP, level, opt, eval); + else + return ESOCK_IO_SETOPT_NATIVE(env, descP, level, opt, eval); + } + SGDBG( ("SOCKET", "nif_setopt -> failed arg check\r\n") ); - if (IS_INTEGER(env, argv[1])) - return esock_make_error_integer_range(env, argv[1]); + if (IS_INTEGER(env, elevel)) + return esock_make_error_integer_range(env, elevel); else return enif_make_badarg(env); -#endif // #ifdef __WIN32__ #else + } /* esock_setopt_otp - Handle OTP (level) options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, ESockDescriptor* descP, @@ -9931,13 +6534,12 @@ ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ /* esock_setopt_otp_debug - Handle the OTP (level) debug options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env, ESockDescriptor* descP, @@ -9947,11 +6549,11 @@ ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_debug {%d} -> closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (! esock_decode_bool(eVal, &descP->dbg)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); SSDBG( descP, ("SOCKET", "esock_setopt_otp_debug {%d} -> ok" @@ -9960,12 +6562,12 @@ ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_iow - Handle the OTP (level) iow options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env, ESockDescriptor* descP, @@ -9975,11 +6577,11 @@ ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_iow {%d} -> closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (! esock_decode_bool(eVal, &descP->iow)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); SSDBG( descP, ("SOCKET", "esock_setopt_otp_iow {%d} -> ok" @@ -9988,13 +6590,13 @@ ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_ctrl_proc - Handle the OTP (level) * controlling_process options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, ESockDescriptor* descP, @@ -10012,7 +6614,7 @@ ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } /* Ensure that caller is (current) controlling process */ @@ -10027,7 +6629,7 @@ ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, /* Ensure that the new controller is a local process */ if (!GET_LPID(env, eVal, &newCtrlPid)) { esock_warning_msg("Failed get pid of new controlling process\r\n"); - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } if ((xres = DEMONP("esock_setopt_otp_ctrl_proc -> (old) ctrl", @@ -10063,7 +6665,12 @@ ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, enif_set_pid_undefined(&descP->ctrlPid); - esock_down_ctrl(env, descP, &newCtrlPid); + /* Shall we use an function pointer argument instead? */ +#ifndef __WIN32__ + essio_down_ctrl(env, descP, &newCtrlPid); +#else + esaio_down_ctrl(env, descP, &newCtrlPid); +#endif descP->readState |= ESOCK_STATE_CLOSING; descP->writeState |= ESOCK_STATE_CLOSING; @@ -10076,7 +6683,7 @@ ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option @@ -10086,8 +6693,9 @@ ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, * {N :: pos_integer(), Sz :: default | pos_integer()} * * Where N is the max number of reads. + * Note that on Windows the tuple variant is not allowed! */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, ESockDescriptor* descP, @@ -10095,7 +6703,9 @@ ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, { const ERL_NIF_TERM* t; // The array of the elements of the tuple int tsz; // The size of the tuple - should be 2 +#ifndef __WIN32__ unsigned int n; +#endif size_t bufSz; ssize_t z; @@ -10108,9 +6718,25 @@ ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); + } + + +#ifdef __WIN32__ + + if (!esock_decode_bufsz(env, + eVal, + ESOCK_RECV_BUFFER_SIZE_DEFAULT, + &bufSz)) { + SSDBG( descP, + ("SOCKET", + "esock_setopt_otp_rcvbuf(%d) -> done invalid\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); } +#else + if (esock_decode_bufsz(env, eVal, ESOCK_RECV_BUFFER_SIZE_DEFAULT, @@ -10122,21 +6748,25 @@ ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, (! GET_UINT(env, t[0], &n)) || (n == 0) || (! esock_decode_bufsz(env, t[1], - ESOCK_RECV_BUFFER_SIZE_DEFAULT, + ESOCK_RECV_BUFFER_SIZE_DEFAULT, &bufSz))) { SSDBG( descP, ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> done invalid\r\n", - descP->sock) ); - return esock_make_invalid(env, atom_value); + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); } } +#endif + // We do not want a buffer size that does not fit in ssize_t z = bufSz; if (bufSz != (size_t) z) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); +#ifndef __WIN32__ descP->rNum = n; +#endif descP->rBufSz = bufSz; SSDBG( descP, @@ -10145,12 +6775,12 @@ ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, ESockDescriptor* descP, @@ -10167,7 +6797,7 @@ ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (! esock_decode_bufsz(env, @@ -10178,7 +6808,7 @@ ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> done invalid\r\n", descP->sock) ); - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } descP->rCtrlSz = val; @@ -10189,12 +6819,12 @@ ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, ESockDescriptor* descP, @@ -10211,7 +6841,7 @@ ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (! esock_decode_bufsz(env, @@ -10222,7 +6852,7 @@ ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> done invalid\r\n", descP->sock) ); - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } descP->wCtrlSz = val; @@ -10233,12 +6863,12 @@ ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_meta - Handle the OTP (level) meta options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env, ESockDescriptor* descP, @@ -10257,7 +6887,7 @@ ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_meta {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) { @@ -10276,12 +6906,12 @@ ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* esock_setopt_otp_use_registry - Handle the OTP (level) use_registry option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env, ESockDescriptor* descP, @@ -10293,15 +6923,15 @@ ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_setopt_otp_use_registry {%d} -> closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (! esock_decode_bool(eVal, &useReg)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); /* We only allow turning this on! */ if (! useReg) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); if (!descP->useReg) { ERL_NIF_TERM sockRef = enif_make_resource(env, descP); @@ -10317,13 +6947,13 @@ ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env, return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* The option has *not* been encoded. Instead it has been provided * in "native mode" (value is a binary, an integer or a boolean). */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, ESockDescriptor* descP, @@ -10352,7 +6982,7 @@ ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, descP->sock) ); MUNLOCK(descP->writeMtx); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } if (GET_BIN(env, eVal, &binary)) { @@ -10366,7 +6996,7 @@ ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, result = esock_setopt_level_opt(env, descP, level, opt, &integer, sizeof(integer)); } else { - result = esock_make_error_invalid(env, atom_value); + result = esock_make_error_invalid(env, esock_atom_value); } SSDBG( descP, @@ -10377,13 +7007,13 @@ ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, MUNLOCK(descP->writeMtx); return result; } -#endif // #ifndef __WIN32__ + /* esock_setopt - A "proper" level (option) has been specified, * and we have an value of known encoding */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt(ErlNifEnv* env, ESockDescriptor* descP, @@ -10409,7 +7039,7 @@ ERL_NIF_TERM esock_setopt(ErlNifEnv* env, descP->sock) ); MUNLOCK(descP->writeMtx); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } optP = lookupOpt(level, opt); @@ -10445,10 +7075,8 @@ ERL_NIF_TERM esock_setopt(ErlNifEnv* env, MUNLOCK(descP->writeMtx); return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_BINDTODEVICE) static ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env, @@ -10460,10 +7088,8 @@ ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env, return esock_setopt_str_opt(env, descP, level, opt, IFNAMSIZ, eVal); } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_LINGER) static ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, @@ -10487,13 +7113,13 @@ ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, return esock_setopt_level_opt(env, descP, level, opt, &val, sizeof(val)); } else - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } if ((! esock_decode_bool(eOnOff, &onOff)) || - (! GET_INT(env, eLinger, &val.l_linger)) || + (! GET_INT(env, eLinger, (int*) &val.l_linger)) || (val.l_linger < 0)) { - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } val.l_onoff = onOff ? 1 : 0; @@ -10501,11 +7127,9 @@ ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, &val, sizeof(val)); } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) /* esock_setopt_msfilter - Level IP MSFILTER option @@ -10574,7 +7198,7 @@ ERL_NIF_TERM esock_setopt_msfilter(ErlNifEnv* env, free_invalid: FREE(msfP); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } } @@ -10600,14 +7224,12 @@ BOOLEAN_T decode_msfilter_mode(ErlNifEnv* env, } #endif // #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) -#endif // #ifndef __WIN32__ /* esock_setopt_ip_mtu_discover - Level IP MTU_DISCOVER option * * The value is an atom of the type ip_pmtudisc(). */ -#ifndef __WIN32__ #if defined(IP_MTU_DISCOVER) static ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env, @@ -10619,13 +7241,12 @@ ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env, int val; if (! decode_ip_pmtudisc(env, eVal, &val)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); else return esock_setopt_level_opt(env, descP, level, opt, &val, sizeof(val)); } #endif // #if defined(IP_MTU_DISCOVER) -#endif // #ifndef __WIN32__ @@ -10633,7 +7254,6 @@ ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env, * * The value is either the atom 'any' or a 4-tuple. */ -#ifndef __WIN32__ #if defined(IP_MULTICAST_IF) static ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env, @@ -10646,7 +7266,7 @@ ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env, struct in_addr ifAddr; if (! esock_decode_in_addr(env, eVal, &ifAddr)) { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } else { result = esock_setopt_level_opt(env, descP, level, opt, @@ -10656,11 +7276,11 @@ ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ + /* esock_setopt_tos - Level IP TOS option */ -#ifndef __WIN32__ + #if defined(IP_TOS) static ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env, @@ -10677,14 +7297,12 @@ ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env, esock_setopt_level_opt(env, descP, level, opt, &val, sizeof(val)); } else { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } return result; } #endif -#endif // #ifndef __WIN32__ - @@ -10693,7 +7311,7 @@ ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env, * The attribute 'interface' is either the atom 'any' or a 4-tuple * (IPv4 address). */ -#ifndef __WIN32__ + #if defined(IP_ADD_MEMBERSHIP) || defined(IP_DROP_MEMBERSHIP) static ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env, @@ -10741,10 +7359,9 @@ ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env, &mreq, sizeof(mreq)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ /* The value is a map with three attributes: multiaddr, interface and @@ -10754,7 +7371,7 @@ ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env, * The attribute 'sourceaddr' is always a 4-tuple (IPv4 address). * (IPv4 address). */ -#ifndef __WIN32__ + #if defined(IP_ADD_SOURCE_MEMBERSHIP) || \ defined(IP_DROP_SOURCE_MEMBERSHIP) || \ defined(IP_BLOCK_SOURCE) || \ @@ -10786,18 +7403,14 @@ ERL_NIF_TERM esock_setopt_in_update_source(ErlNifEnv* env, return esock_setopt_level_opt(env, descP, level, opt, &mreq, sizeof(mreq)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ #if defined(HAVE_IPV6) - - -#ifndef __WIN32__ #if defined(IPV6_ADDRFORM) static ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, @@ -10814,7 +7427,7 @@ ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, "\r\n", eVal) ); if (esock_decode_domain(env, eVal, &domain) == 0) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); SSDBG( descP, ("SOCKET", "esock_setopt_addrform -> try set opt to %d\r\n", @@ -10824,7 +7437,6 @@ ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, &domain, sizeof(domain)); } #endif -#endif // #ifndef __WIN32__ @@ -10832,7 +7444,7 @@ ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, * * The value is an atom of the type ipv6_pmtudisc(). */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env, @@ -10844,16 +7456,15 @@ ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env, int val; if (! decode_ipv6_pmtudisc(env, eVal, &val)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); return esock_setopt_level_opt(env, descP, level, opt, &val, sizeof(val)); } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + #if defined(IPV6_MULTICAST_HOPS) static ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env, @@ -10865,16 +7476,15 @@ ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env, int hops; if (! decode_hops(env, eVal, &hops)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); return esock_setopt_level_opt(env, descP, level, opt, &hops, sizeof(hops)); } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + #if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP) static ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env, @@ -10920,10 +7530,9 @@ ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env, &mreq, sizeof(mreq)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ #endif // defined(HAVE_IPV6) @@ -10933,7 +7542,6 @@ ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env, /* esock_setopt_tcp_congestion - Level TCP CONGESTION option */ -#ifndef __WIN32__ #if defined(TCP_CONGESTION) static ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env, @@ -10947,17 +7555,13 @@ ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env, return esock_setopt_str_opt(env, descP, level, opt, max, eVal); } #endif -#endif // #ifndef __WIN32__ - #if defined(HAVE_SCTP) - - /* esock_setopt_sctp_associnfo - Level SCTP ASSOCINFO option */ -#ifndef __WIN32__ + #if defined(SCTP_ASSOCINFO) static ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env, @@ -11035,15 +7639,15 @@ ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env, &assocParams, sizeof(assocParams)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ + /* esock_setopt_sctp_events - Level SCTP EVENTS option */ -#ifndef __WIN32__ + #if defined(SCTP_EVENTS) static ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env, @@ -11119,7 +7723,7 @@ ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env, "esock_setopt_sctp_events {%d} -> invalid\r\n", descP->sock) ); - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } /* Return the value to make use of automatic type casting. @@ -11141,12 +7745,12 @@ static int esock_setopt_sctp_event(ErlNifEnv *env, return 0; } #endif -#endif // #ifndef __WIN32__ + /* esock_setopt_sctp_initmsg - Level SCTP INITMSG option */ -#ifndef __WIN32__ + #if defined(SCTP_INITMSG) static ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env, @@ -11206,15 +7810,15 @@ ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env, &initMsg, sizeof(initMsg)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ + /* esock_setopt_sctp_rtoinfo - Level SCTP RTOINFO option */ -#ifndef __WIN32__ + #if defined(SCTP_RTOINFO) static ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, @@ -11265,12 +7869,9 @@ ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, &rtoInfo, sizeof(rtoInfo)); invalid: - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); } #endif -#endif // #ifndef __WIN32__ - - #endif // defined(HAVE_SCTP) @@ -11279,7 +7880,7 @@ ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, /* esock_setopt_bool_opt - set an option that has an (integer) bool value */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -11291,18 +7892,18 @@ ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, int ival; if (! esock_decode_bool(eVal, &val)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); ival = (val) ? 1 : 0; return esock_setopt_level_opt(env, descP, level, opt, &ival, sizeof(ival)); } -#endif // #ifndef __WIN32__ + /* esock_setopt_int_opt - set an option that has an integer value */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -11318,16 +7919,16 @@ ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, esock_setopt_level_opt(env, descP, level, opt, &val, sizeof(val)); } else { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } return result; } -#endif // #ifndef __WIN32__ + /* esock_setopt_str_opt - set an option that has an string value */ -#ifndef __WIN32__ + #if defined(USE_SETOPT_STR_OPT) static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, @@ -11350,7 +7951,7 @@ ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, esock_setopt_level_opt(env, descP, level, opt, val, optLen); } else { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } FREE(val); @@ -11358,12 +7959,12 @@ ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ + /* esock_setopt_timeval_opt - set an option that has an (timeval) bool value */ -#ifndef __WIN32__ + #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ && defined(ESOCK_USE_RCVSNDTIMEO) static @@ -11382,7 +7983,7 @@ ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, "\r\n", eVal) ); if (! esock_decode_timeval(env, eVal, &timeVal)) - return esock_make_invalid(env, atom_value); + return esock_make_invalid(env, esock_atom_value); SSDBG( descP, ("SOCKET", "esock_setopt_timeval_opt -> set timeval option\r\n") ); @@ -11400,10 +8001,8 @@ ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, ESockDescriptor* descP, int level, @@ -11416,7 +8015,7 @@ static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, else return esock_atom_ok; } -#endif // #ifndef __WIN32__ + /* +++ socket_setopt +++ @@ -11442,7 +8041,6 @@ static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, * user feeling socket options are independent. * </PaN> */ -#ifndef __WIN32__ static int socket_setopt(int sock, int level, int opt, const void* optVal, const socklen_t optLen) @@ -11503,7 +8101,6 @@ int socket_setopt(int sock, int level, int opt, return res; } -#endif // #ifndef __WIN32__ @@ -11527,58 +8124,67 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; + ERL_NIF_TERM esock, elevel, eopt, evspec; int level, opt; ESOCK_ASSERT( (argc == 3) || (argc == 4) ); - SGDBG( ("SOCKET", "nif_getopt -> entry with argc: %d\r\n", argc) ); + esock = argv[0]; + elevel = argv[1]; + eopt = argv[2]; + evspec = ((argc == 4) ? argv[3] : esock_atom_undefined); - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - SGDBG( ("SOCKET", "nif_getopt -> failed initial args check\r\n") ); + SGDBG( ("SOCKET", + "nif_getopt -> entry with argc: %d" + "\r\n esock: %T" + "\r\n elevel: %T" + "\r\n eopt: %T" + "\r\n evspec: %T" + "\r\n", argc, esock, elevel, eopt, evspec) ); + + if (! ESOCK_GET_RESOURCE(env, esock, (void**) &descP)) { + SGDBG( ("SOCKET", + "nif_getopt -> failed initial args check - sock\r\n") ); return enif_make_badarg(env); } - if (! GET_INT(env, argv[2], &opt)) { + if (! GET_INT(env, eopt, &opt)) { SSDBG( descP, - ("SOCKET", "nif_getopt -> failed initial args check\r\n") ); - if (! IS_INTEGER(env, argv[2])) + ("SOCKET", + "nif_getopt -> failed initial args check - opt\r\n") ); + if (! IS_INTEGER(env, eopt)) return enif_make_badarg(env); else - return esock_make_error_integer_range(env, argv[2]); + return esock_make_error_integer_range(env, eopt); + } + + if ((COMPARE(elevel, atom_otp) == 0) && + (argc == 3)) { + return ESOCK_IO_GETOPT_OTP(env, descP, opt) ; } - if (esock_decode_level(env, argv[1], &level)) { + if (esock_decode_level(env, elevel, &level)) { if (argc == 4) { - ERL_NIF_TERM valueSpec = argv[3]; - return esock_getopt_native(env, descP, level, opt, valueSpec); + return ESOCK_IO_GETOPT_NATIVE(env, descP, level, opt, evspec); } else { - return esock_getopt(env, descP, level, opt); + return ESOCK_IO_GETOPT(env, descP, level, opt); } } - if ((COMPARE(argv[1], atom_otp) == 0) && - (argc == 3)) { - return esock_getopt_otp(env, descP, opt) ; - } - SGDBG( ("SOCKET", "nif_getopt -> failed args check\r\n") ); - if (IS_INTEGER(env, argv[1])) - return esock_make_error_integer_range(env, argv[1]); + if (IS_INTEGER(env, elevel)) + return esock_make_error_integer_range(env, elevel); else return enif_make_badarg(env); -#endif // #ifdef __WIN32__ #else } /* esock_getopt_otp - Handle OTP (level) options */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, ESockDescriptor* descP, @@ -11692,11 +8298,11 @@ ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_debug - Handle the OTP (level) debug option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env, ESockDescriptor* descP) @@ -11707,18 +8313,18 @@ ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = esock_encode_bool(descP->dbg); return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_iow - Handle the OTP (level) iow option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env, ESockDescriptor* descP) @@ -11729,7 +8335,7 @@ ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_iow {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = esock_encode_bool(descP->iow); @@ -11741,12 +8347,12 @@ ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env, ESockDescriptor* descP) @@ -11758,7 +8364,7 @@ ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env, ("SOCKET", "esock_getopt_otp_ctrl_proc {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = MKPID(env, &descP->ctrlPid); @@ -11770,12 +8376,11 @@ ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ /* esock_getopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, ESockDescriptor* descP) @@ -11786,9 +8391,12 @@ ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_rcvbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } +#ifdef __WIN32__ + eVal = MKUL(env, (unsigned long) descP->rBufSz); +#else if (descP->rNum == 0) { eVal = MKUL(env, (unsigned long) descP->rBufSz); } else { @@ -11796,6 +8404,7 @@ ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, MKI(env, descP->rNum), MKUL(env, (unsigned long) descP->rBufSz)); } +#endif SSDBG( descP, ("SOCKET", "esock_getopt_otp_rcvbuf {%d} ->" @@ -11804,12 +8413,12 @@ ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env, ESockDescriptor* descP) @@ -11821,7 +8430,7 @@ ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env, ("SOCKET", "esock_getopt_otp_rcvctrlbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = MKUL(env, (unsigned long) descP->rCtrlSz); @@ -11833,12 +8442,12 @@ ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env, ESockDescriptor* descP) @@ -11850,7 +8459,7 @@ ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env, ("SOCKET", "esock_getopt_otp_sndctrlbuf {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = MKUL(env, (unsigned long) descP->wCtrlSz); @@ -11862,12 +8471,12 @@ ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_fd - Handle the OTP (level) fd option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env, ESockDescriptor* descP) @@ -11878,7 +8487,7 @@ ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = MKI(env, descP->sock); @@ -11890,12 +8499,12 @@ ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_meta - Handle the OTP (level) meta option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env, ESockDescriptor* descP) @@ -11906,7 +8515,7 @@ ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_meta {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } eVal = CP_TERM(env, descP->meta.ref); @@ -11918,12 +8527,12 @@ ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ + /* esock_getopt_otp_use_registry - Handle the OTP (level) use_registry option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_use_registry(ErlNifEnv* env, ESockDescriptor* descP) @@ -11932,13 +8541,13 @@ ERL_NIF_TERM esock_getopt_otp_use_registry(ErlNifEnv* env, return esock_make_ok2(env, eVal); } -#endif + /* * esock_getopt_otp_domain - Handle the OTP (level) domain option */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, ESockDescriptor* descP) @@ -11949,7 +8558,7 @@ ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_domain {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } esock_encode_domain(env, descP->domain, &domain); @@ -11962,7 +8571,6 @@ ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ @@ -11971,7 +8579,7 @@ ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, /* * esock_getopt_otp_type - Handle the OTP (level) type options. */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env, ESockDescriptor* descP) @@ -11982,7 +8590,7 @@ ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_type {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } esock_encode_type(env, descP->type, &type); @@ -11995,13 +8603,13 @@ ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ + /* * esock_getopt_otp_protocol - Handle the OTP (level) protocol options. */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env, ESockDescriptor* descP) @@ -12012,7 +8620,7 @@ ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_protocol {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } protocol = MKI(env, descP->protocol); @@ -12025,13 +8633,13 @@ ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ + /* * esock_getopt_otp_dtp - Handle the OTP (level) type options. */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, ESockDescriptor* descP) @@ -12042,7 +8650,7 @@ ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, SSDBG( descP, ("SOCKET", "esock_getopt_otp_dtp {%d} -> done closed\r\n", descP->sock) ); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } esock_encode_domain(env, descP->domain, &domain); @@ -12058,7 +8666,6 @@ ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ #endif // #if 0 @@ -12066,7 +8673,7 @@ ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, /* How to decode the value is specified with valueSpec */ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, ESockDescriptor* descP, @@ -12094,7 +8701,7 @@ ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, ("SOCKET", "esock_getopt_native {%d} -> done closed\r\n", descP->sock) ); MUNLOCK(descP->readMtx); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } /* <KOLLA> @@ -12113,7 +8720,7 @@ ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, result = esock_getopt_size_opt(env, descP, level, opt, valueSz); } else { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } } else if (COMPARE(valueSpec, atom_integer) == 0) { SSDBG( descP, @@ -12132,7 +8739,7 @@ ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, "\r\n", descP->sock, (unsigned long) bin.size) ); result = esock_getopt_bin_opt(env, descP, level, opt, &bin); } else { - result = esock_make_invalid(env, atom_value); + result = esock_make_invalid(env, esock_atom_value); } SSDBG( descP, @@ -12143,35 +8750,34 @@ ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, MUNLOCK(descP->readMtx); return result; } -#endif // #ifndef __WIN32__ + /* esock_getopt - An option that we know how to decode */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_getopt(ErlNifEnv* env, ESockDescriptor* descP, int level, int opt) { - ERL_NIF_TERM result; + ERL_NIF_TERM result; const struct ESockOpt *optP; MLOCK(descP->readMtx); SSDBG( descP, ("SOCKET", "esock_getopt {%d} -> entry with" - "\r\n level: %d" - "\r\n opt: %d" + "\r\n level: %d" + "\r\n opt: %d" "\r\n", descP->sock, level, opt) ); if (! IS_OPEN(descP->readState)) { SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> done closed\r\n", + ("SOCKET", "esock_getopt {%d} -> done when closed\r\n", descP->sock) ); MUNLOCK(descP->readMtx); - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); } optP = lookupOpt(level, opt); @@ -12205,10 +8811,8 @@ ERL_NIF_TERM esock_getopt(ErlNifEnv* env, MUNLOCK(descP->readMtx); return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_BINDTODEVICE) static ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env, @@ -12219,10 +8823,8 @@ ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env, return esock_getopt_str_opt(env, descP, level, opt, IFNAMSIZ+1, FALSE); } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_DOMAIN) static ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env, @@ -12244,10 +8846,8 @@ ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_LINGER) static ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env, @@ -12262,7 +8862,11 @@ ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env, sys_memzero((void *) &val, sizeof(val)); +#ifdef __WIN32__ + res = sock_getopt(descP->sock, level, opt, (char*) &val, &valSz); +#else res = sock_getopt(descP->sock, level, opt, &val, &valSz); +#endif if (res != 0) { result = esock_make_error_errno(env, sock_errno()); @@ -12284,11 +8888,9 @@ ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_TYPE) static ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env, @@ -12310,10 +8912,8 @@ ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(SO_PROTOCOL) static ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, @@ -12346,10 +8946,8 @@ ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ /* esock_getopt_ip_mtu_discover - Level IP MTU_DISCOVER option */ #if defined(IP_MTU_DISCOVER) @@ -12374,12 +8972,11 @@ ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env, } #endif -#endif // #ifndef __WIN32__ /* esock_getopt_multicast_if - Level IP MULTICAST_IF option */ -#ifndef __WIN32__ + #if defined(IP_MULTICAST_IF) static ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, @@ -12395,7 +8992,11 @@ ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, sys_memzero((void *) &ifAddr, ifAddrSz); +#ifdef __WIN32__ + res = sock_getopt(descP->sock, level, opt, (char*) &ifAddr, &ifAddrSz); +#else res = sock_getopt(descP->sock, level, opt, &ifAddr, &ifAddrSz); +#endif if (res != 0) { result = esock_make_error_errno(env, sock_errno()); @@ -12408,12 +9009,12 @@ ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, } #endif -#endif // #ifndef __WIN32__ + /* esock_getopt_tos - Level IP TOS option */ -#ifndef __WIN32__ + #if defined(IP_TOS) static ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env, @@ -12433,15 +9034,14 @@ ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env, return result; } #endif -#endif // #ifndef __WIN32__ -#if defined(HAVE_IPV6) +#if defined(HAVE_IPV6) /* esock_getopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env, @@ -12464,16 +9064,13 @@ ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env, } #endif -#endif // #ifndef __WIN32__ - #endif // defined(HAVE_IPV6) - /* esock_getopt_tcp_congestion - Level TCP CONGESTION option */ -#ifndef __WIN32__ + #if defined(TCP_CONGESTION) static ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env, @@ -12486,14 +9083,11 @@ ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env, return esock_getopt_str_opt(env, descP, level, opt, max, TRUE); } #endif -#endif // #ifndef __WIN32__ #if defined(HAVE_SCTP) - - /* esock_getopt_sctp_associnfo - Level SCTP ASSOCINFO option * * <KOLLA> @@ -12657,7 +9251,6 @@ ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env, /* esock_getopt_bool_opt - get an (integer) bool option */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -12676,12 +9269,10 @@ ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, } return result; } -#endif // #ifndef __WIN32__ /* esock_getopt_int_opt - get an integer option */ -#ifndef __WIN32__ static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -12695,14 +9286,12 @@ ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, return esock_make_ok2(env, MKI(env, val)); } -#endif // #ifndef __WIN32__ /* esock_getopt_int - get an integer option */ -#ifndef __WIN32__ -static +extern BOOLEAN_T esock_getopt_int(SOCKET sock, int level, int opt, @@ -12711,17 +9300,19 @@ BOOLEAN_T esock_getopt_int(SOCKET sock, int val = 0; SOCKOPTLEN_T valSz = sizeof(val); +#ifdef __WIN32__ + if (sock_getopt(sock, level, opt, (char*) &val, &valSz) != 0) +#else if (sock_getopt(sock, level, opt, &val, &valSz) != 0) +#endif return FALSE; *valP = val; return TRUE; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -12768,10 +9359,9 @@ ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, ESockDescriptor* descP, @@ -12786,7 +9376,7 @@ ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, vsz = (SOCKOPTLEN_T) binP->size; if (SZT(vsz) != binP->size) { - result = esock_make_error_invalid(env, atom_data_size); + result = esock_make_error_invalid(env, esock_atom_data_size); } else { ESOCK_ASSERT( ALLOC_BIN(vsz, &val) ); sys_memcpy(val.data, binP->data, vsz); @@ -12814,7 +9404,7 @@ ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, return result; } -#endif // #ifndef __WIN32__ + /* esock_getopt_timeval_opt - get an timeval option @@ -12866,11 +9456,11 @@ ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3) * may return 0 as the cmsg_len if the cmsg is to be ignored. */ -#define LEN_CMSG_DATA(__CMSG__) \ - ((__CMSG__)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \ - (__CMSG__)->cmsg_len - ((char*)CMSG_DATA(__CMSG__) - (char*)(__CMSG__))) -#define NEXT_CMSG_HDR(__CMSG__) \ - ((struct cmsghdr*)(((char*)(__CMSG__)) + CMSG_SPACE(LEN_CMSG_DATA(__CMSG__)))) +#define ESOCK_LEN_CMSG_DATA(__CMSG__) \ + ((__CMSG__)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \ + (__CMSG__)->cmsg_len - ((char*)ESOCK_CMSG_DATA(__CMSG__) - (char*)(__CMSG__))) +#define ESOCK_NEXT_CMSG_HDR(__CMSG__) \ + ((struct cmsghdr*)(((char*)(__CMSG__)) + ESOCK_CMSG_SPACE(ESOCK_LEN_CMSG_DATA(__CMSG__)))) static ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, @@ -12902,8 +9492,8 @@ ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, for (endOfBuf = (struct cmsghdr*)(cmsgs.data + cmsgs.size), currentP = (struct cmsghdr*)(cmsgs.data); (currentP != NULL) && (currentP < endOfBuf); - currentP = NEXT_CMSG_HDR(currentP)) { - unsigned char* dataP = UCHARP(CMSG_DATA(currentP)); + currentP = ESOCK_NEXT_CMSG_HDR(currentP)) { + unsigned char* dataP = UCHARP(ESOCK_CMSG_DATA(currentP)); size_t dataPos = dataP - cmsgs.data; size_t dataLen = (UCHARP(currentP) + currentP->cmsg_len) - dataP; @@ -12939,7 +9529,7 @@ ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, ERL_NIF_TERM keys[] = {esock_atom_level, esock_atom_type, esock_atom_data, - atom_value}; + esock_atom_value}; ERL_NIF_TERM vals[NUM(keys)]; size_t numKeys = NUM(keys); BOOLEAN_T haveValue; @@ -12947,10 +9537,10 @@ ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, vals[0] = esock_encode_level(env, currentP->cmsg_level); vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); - haveValue = encode_cmsg(env, - currentP->cmsg_level, - currentP->cmsg_type, - dataP, dataLen, &vals[1], &vals[3]); + haveValue = esock_encode_cmsg(env, + currentP->cmsg_level, + currentP->cmsg_type, + dataP, dataLen, &vals[1], &vals[3]); SSDBG( descP, ("SOCKET", "esock_getopt_pktoptions {%d} -> " @@ -13066,9 +9656,6 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM res; @@ -13088,7 +9675,7 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env, ("SOCKET", "nif_sockname(%T) {%d}" "\r\n", argv[0], descP->sock) ); - res = esock_sockname(env, descP); + res = ESOCK_IO_SOCKNAME(env, descP); SSDBG( descP, ("SOCKET", "nif_sockname(%T) {%d} -> done with res = %T\r\n", @@ -13097,22 +9684,27 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env, MUNLOCK(descP->readMtx); return res; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ +/* ======================================================================== + */ + static ERL_NIF_TERM esock_sockname(ErlNifEnv* env, ESockDescriptor* descP) { ESockAddress sa; ESockAddress* saP = &sa; +#ifdef __WIN32__ + int sz = sizeof(ESockAddress); +#else SOCKLEN_T sz = sizeof(ESockAddress); +#endif if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); SSDBG( descP, ("SOCKET", "esock_sockname {%d} -> open - try get sockname\r\n", @@ -13129,7 +9721,7 @@ ERL_NIF_TERM esock_sockname(ErlNifEnv* env, "got sockname - try decode\r\n", descP->sock) ); - esock_encode_sockaddr(env, saP, sz, &esa); + esock_encode_sockaddr(env, saP, (SOCKLEN_T) sz, &esa); SSDBG( descP, ("SOCKET", "esock_sockname {%d} -> decoded: " @@ -13139,8 +9731,6 @@ ERL_NIF_TERM esock_sockname(ErlNifEnv* env, return esock_make_ok2(env, esa); } } -#endif // #ifndef __WIN32__ - @@ -13159,9 +9749,6 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM res; @@ -13181,7 +9768,7 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env, ("SOCKET", "nif_peername(%T) {%d}" "\r\n", argv[0], descP->sock) ); - res = esock_peername(env, descP); + res = ESOCK_IO_PEERNAME(env, descP); SSDBG( descP, ("SOCKET", "nif_peername(%T) {%d} -> done with res = %T\r\n", @@ -13190,22 +9777,27 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env, MUNLOCK(descP->readMtx); return res; -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ +/* ======================================================================== + */ + static ERL_NIF_TERM esock_peername(ErlNifEnv* env, ESockDescriptor* descP) { ESockAddress sa; ESockAddress* saP = &sa; +#ifdef __WIN32__ + int sz = sizeof(ESockAddress); +#else SOCKLEN_T sz = sizeof(ESockAddress); +#endif if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + return esock_make_error_closed(env); SSDBG( descP, ("SOCKET", "esock_peername {%d} -> open - try get peername\r\n", @@ -13222,7 +9814,7 @@ ERL_NIF_TERM esock_peername(ErlNifEnv* env, "got peername - try decode\r\n", descP->sock) ); - esock_encode_sockaddr(env, saP, sz, &esa); + esock_encode_sockaddr(env, saP, (SOCKLEN_T) sz, &esa); SSDBG( descP, ("SOCKET", "esock_peername {%d} -> decoded: " @@ -13232,7 +9824,6 @@ ERL_NIF_TERM esock_peername(ErlNifEnv* env, return esock_make_ok2(env, esa); } } -#endif // #ifndef __WIN32__ @@ -13260,9 +9851,6 @@ ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM res; unsigned long req; @@ -13285,49 +9873,54 @@ ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, ("SOCKET", "nif_ioctl(%T) {%d} -> ioctl request %d" "\r\n", argv[0], descP->sock, req) ); + /* Is this really enough? Why not the write mutex also? */ MLOCK(descP->readMtx); if (! IS_OPEN(descP->readState)) { - res = esock_make_error(env, atom_closed); + res = esock_make_error_closed(env); } else { - if (argc == 2) { - - /* Only one request with this number of arguments: gifconf - * Socket and request (=gifconf) - */ - - /* Two arguments: Socket and get request */ - res = esock_ioctl1(env, descP, req); - - } else if (argc == 3) { - - /* (Currently) All *other* get requests has 3 arguments - * Socket, request and name/index - */ - - ERL_NIF_TERM earg = argv[2]; - - /* Two arguments: request and arg */ - res = esock_ioctl2(env, descP, req, earg); - - } else if (argc == 4) { - - /* (Currently) Set requests has 4 arguments - * Socket, request, name and value - */ - - ERL_NIF_TERM earg1 = argv[2]; // (currently) Name - ERL_NIF_TERM earg2 = argv[3]; // Value - - /* Three arguments: request, arg1 (name) and arg2 (value) */ - res = esock_ioctl3(env, descP, req, earg1, earg2); - - } else { - - res = esock_make_error(env, esock_atom_einval); - - } + switch (argc) { + case 2: + /* Only one request with this number of arguments: gifconf + * Socket and request (=gifconf) + */ + + /* Two arguments: socket and request */ + res = ESOCK_IO_IOCTL_2(env, descP, req); + break; + + case 3: + /* (Currently) All *other* get requests has 3 arguments + * Socket, request and name/index + */ + { + ERL_NIF_TERM earg = argv[2]; + + /* Three arguments: socket, request and arg */ + res = ESOCK_IO_IOCTL_3(env, descP, req, earg); + } + break; + + case 4: + /* (Currently) Set requests has 4 arguments + * Socket, request, name and value + */ + { + ERL_NIF_TERM earg1 = argv[2]; // (currently) Name + ERL_NIF_TERM earg2 = argv[3]; // Value + + res = ESOCK_IO_IOCTL_4(env, descP, req, earg1, earg2); + } + break; + + default: + /* This is just to protect against programming errors, + * since we have an assert above! + */ + res = esock_make_error(env, esock_atom_einval); + break; + } } MUNLOCK(descP->readMtx); @@ -13337,1132 +9930,8 @@ ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, argv[0], descP->sock, res) ); return res; -#endif // #ifdef __WIN32__ #else -} - - - -#ifndef __WIN32__ - -static -ERL_NIF_TERM esock_ioctl1(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req) -{ - switch (req) { - -#if defined(SIOCGIFCONF) - case SIOCGIFCONF: - return esock_ioctl_gifconf(env, descP); - break; -#endif - - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } - -} - - -/* The type and value of 'arg' depend on the request, - * which we have not yet "analyzed". - * - * Request arg arg type - * ------- ------- -------- - * gifname ifindex integer - * gifindex name string - * gifflags name string - * gifaddr name string - * gifdstaddr name string - * gifbdraddr name string - * gifnetmask name string - * gifmtu name string - * gifhwaddr name string - * gifmap name string - * giftxqlen name string - */ -static -ERL_NIF_TERM esock_ioctl2(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM arg) -{ - /* This for *get* requests */ - - switch (req) { - -#if defined(SIOCGIFNAME) - case SIOCGIFNAME: - return esock_ioctl_gifname(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFINDEX) - case SIOCGIFINDEX: - return esock_ioctl_gifindex(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFFLAGS) - case SIOCGIFFLAGS: - return esock_ioctl_gifflags(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFADDR) - case SIOCGIFADDR: - return esock_ioctl_gifaddr(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFDSTADDR) - case SIOCGIFDSTADDR: - return esock_ioctl_gifdstaddr(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFBRDADDR) - case SIOCGIFBRDADDR: - return esock_ioctl_gifbrdaddr(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFNETMASK) - case SIOCGIFNETMASK: - return esock_ioctl_gifnetmask(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFMTU) - case SIOCGIFMTU: - return esock_ioctl_gifmtu(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) - case SIOCGIFHWADDR: - return esock_ioctl_gifhwaddr(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) - case SIOCGIFMAP: - return esock_ioctl_gifmap(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFTXQLEN) - case SIOCGIFTXQLEN: - return esock_ioctl_giftxqlen(env, descP, arg); - break; -#endif - - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } - -} - - -/* The type and value of arg(s) depend on the request, - * which we have not yet "analyzed". - * - * Request arg1 arg1 type arg2 arg2 type - * ------- ------- --------- ------ --------- - * sifflags name string Flags #{IntFlag := boolean()} - * IntFlag is the native flag - * sifaddr name string Addr sockaddr() - * sifdstaddr name string DstAddr sockaddr() - * sifbrdaddr name string BrdAddr sockaddr() - * sifnetmask name string NetMask sockaddr() - * gifmtu name string MTU integer() - * sifhwaddr name string HwAddr sockaddr() - * giftxqlen name string Len integer() - */ -static -ERL_NIF_TERM esock_ioctl3(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM ename, - ERL_NIF_TERM eval) -{ - - switch (req) { - -#if defined(SIOCSIFFLAGS) - case SIOCSIFFLAGS: - return esock_ioctl_sifflags(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFADDR) - case SIOCSIFADDR: - return esock_ioctl_sifaddr(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFDSTADDR) - case SIOCSIFDSTADDR: - return esock_ioctl_sifdstaddr(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFBRDADDR) - case SIOCSIFBRDADDR: - return esock_ioctl_sifbrdaddr(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFNETMASK) - case SIOCSIFNETMASK: - return esock_ioctl_sifnetmask(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFMTU) - case SIOCSIFMTU: - return esock_ioctl_sifmtu(env, descP, ename, eval); - break; -#endif - -#if defined(SIOCSIFTXQLEN) - case SIOCSIFTXQLEN: - return esock_ioctl_siftxqlen(env, descP, ename, eval); - break; -#endif - - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } - -} - - -/* =========================================================================== - * The implemented (ioctl) get requests falls into three grops: - * - * 1) gifconf - Takes no argument other then the request - * 2) gifname - Takes the interface index (integer) as an argument - * 3) other - All other (get) requests takes the interface name (string) - * as the argument. - * - * The functions defined using the macros below are all in the third (3) - * group. - * - */ - -/* *** esock_ioctl_gifindex *** */ -#if defined(SIOCGIFINDEX) -#if defined(ESOCK_USE_IFINDEX) -#define IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_ifindex) -#elif defined(ESOCK_USE_INDEX) -#define IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_index) -#else -#define IOCTL_GIFINDEX_FUNC_DECL -#endif -#else -#define IOCTL_GIFINDEX_FUNC_DECL -#endif - -/* *** esock_ioctl_gifflags *** */ -#if defined(SIOCGIFFLAGS) -#define IOCTL_GIFFLAGS_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifflags, SIOCGIFFLAGS, flags, ifreq.ifr_flags) -#else -#define IOCTL_GIFFLAGS_FUNC_DECL -#endif - -/* *** esock_ioctl_gifaddr *** */ -#if defined(SIOCGIFADDR) -#define IOCTL_GIFADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifaddr, SIOCGIFADDR, ifraddr, &ifreq.ifr_addr) -#else -#define IOCTL_GIFADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_gifdstaddr *** */ -#if defined(SIOCGIFDSTADDR) -#define IOCTL_GIFDSTADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifdstaddr, SIOCGIFDSTADDR, ifraddr, &ifreq.ifr_dstaddr) -#else -#define IOCTL_GIFDSTADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_gifbrdaddr *** */ -#if defined(SIOCGIFBRDADDR) -#define IOCTL_GIFBRDADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifbrdaddr, SIOCGIFBRDADDR, ifraddr, &ifreq.ifr_broadaddr) -#else -#define IOCTL_GIFBRDADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_gifnetmask *** */ -#if defined(SIOCGIFNETMASK) -#ifdef __linux__ -#define IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_netmask) -#else -#define IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_addr) -#endif -#else -#define IOCTL_GIFNETMASK_FUNC_DECL -#endif - -/* *** esock_ioctl_gifmtu *** */ -#if defined(SIOCGIFMTU) -#define IOCTL_GIFMTU_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifmtu, SIOCGIFMTU, ivalue, ifreq.ifr_mtu) -#else -#define IOCTL_GIFMTU_FUNC_DECL -#endif - -/* *** esock_ioctl_gifhwaddr *** */ -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -#define IOCTL_GIFHWADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) -#else -#define IOCTL_GIFHWADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_gifmap *** */ -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -#define IOCTL_GIFMAP_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifmap, SIOCGIFMAP, ifrmap, &ifreq.ifr_map) -#else -#define IOCTL_GIFMAP_FUNC_DECL -#endif - -/* *** esock_ioctl_giftxqlen *** */ -#if defined(SIOCGIFTXQLEN) -#define IOCTL_GIFTXQLEN_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(giftxqlen, SIOCGIFTXQLEN, ivalue, ifreq.ifr_qlen) -#else -#define IOCTL_GIFTXQLEN_FUNC_DECL -#endif - -#define IOCTL_GET_FUNCS \ - IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GIFFLAGS_FUNC_DECL \ - IOCTL_GIFADDR_FUNC_DECL \ - IOCTL_GIFDSTADDR_FUNC_DECL \ - IOCTL_GIFBRDADDR_FUNC_DECL \ - IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GIFMTU_FUNC_DECL \ - IOCTL_GIFHWADDR_FUNC_DECL \ - IOCTL_GIFMAP_FUNC_DECL \ - IOCTL_GIFTXQLEN_FUNC_DECL - -#define IOCTL_GET_REQUEST_DECL(OR, R, EF, UV) \ - static \ - ERL_NIF_TERM esock_ioctl_##OR(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename) \ - { \ - ERL_NIF_TERM result; \ - struct ifreq ifreq; \ - char* ifn = NULL; \ - int nlen; \ - \ - SSDBG( descP, ("SOCKET", "esock_ioctl_" #OR " {%d} -> entry with" \ - "\r\n (e)Name: %T" \ - "\r\n", descP->sock, ename) ); \ - \ - if (!esock_decode_string(env, ename, &ifn)) \ - return enif_make_badarg(env); \ - \ - nlen = esock_strnlen(ifn, IFNAMSIZ); \ - \ - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ - sys_memcpy(ifreq.ifr_name, ifn, \ - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ - \ - SSDBG( descP, \ - ("SOCKET", \ - "esock_ioctl_" #OR " {%d} -> try ioctl\r\n", \ - descP->sock) ); \ - \ - if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ - int saveErrno = sock_errno(); \ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failure: " \ - "\r\n reason: %T (%d)" \ - "\r\n", descP->sock, reason, saveErrno) ); \ - \ - result = esock_make_error(env, reason); \ - \ - } else { \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> encode value\r\n", \ - descP->sock) ); \ - result = encode_ioctl_##EF(env, descP, UV); \ - } \ - \ - FREE(ifn); \ - \ - return result; \ - \ - } -IOCTL_GET_FUNCS -#undef IOCTL_GET_FUNCS - - -/* =========================================================================== - * The "rest" of the implemented (ioctl) get requests - * - * These (get) requests could not be 'generated' by the macros above. - */ - -static -ERL_NIF_TERM esock_ioctl_gifconf(ErlNifEnv* env, - ESockDescriptor* descP) -{ - struct ifconf ifc; - int ifc_len = 0; - int buflen = 100 * sizeof(struct ifreq); - char *buf = MALLOC(buflen); - ERL_NIF_TERM result; - - SSDBG( descP, ("SOCKET", "esock_ioctl_gifconf {%d} -> entry\r\n", descP->sock) ); - - for (;;) { - ifc.ifc_len = buflen; - ifc.ifc_buf = buf; - if (ioctl(descP->sock, SIOCGIFCONF, (char *) &ifc) < 0) { - int saveErrno = sock_errno(); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifconf {%d} -> failure: " - "\r\n errno: %d (%s)" - "\r\n", descP->sock, saveErrno, erl_errno_id(saveErrno)) ); - - if (saveErrno != EINVAL || ifc_len) { - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - FREE(buf); - return esock_make_error(env, reason); - } - } else { - if (ifc.ifc_len == ifc_len) break; /* buf large enough */ - ifc_len = ifc.ifc_len; - } - buflen += 10 * sizeof(struct ifreq); - buf = (char *) REALLOC(buf, buflen); - } - - result = encode_ioctl_ifconf(env, descP, &ifc); - - FREE(ifc.ifc_buf); - - return result; -} - - -#if defined(SIOCGIFNAME) -static -ERL_NIF_TERM esock_ioctl_gifname(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eidx) -{ - ERL_NIF_TERM result; - struct ifreq ifreq; - int index; - - SSDBG( descP, ("SOCKET", "esock_ioctl_gifname {%d} -> entry with" - "\r\n (e)Index: %T" - "\r\n", descP->sock, eidx) ); - - if (!GET_INT(env, eidx, &index)) - return enif_make_badarg(env); - - ifreq.ifr_ifindex = index; - - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> try ioctl\r\n", descP->sock) ); - - if (ioctl(descP->sock, SIOCGIFNAME, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> failure: " - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); - - result = esock_make_error(env, reason); - - } else { - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> encode name\r\n", - descP->sock) ); - - result = esock_make_ok2(env, encode_ioctl_ifreq_name(env, ifreq.ifr_name)); - } - - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> done with" - "\r\n result: %T" - "\r\n", - descP->sock, result) ); - - return result; - -} -#endif - - - - -/* =========================================================================== - * The implemented (ioctl) set requests: - * - */ - -/* *** esock_ioctl_sifaddr *** */ -#if defined(SIOCSIFADDR) -#define IOCTL_SIFADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifaddr, SIOCSIFADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_addr)) -#else -#define IOCTL_SIFADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_sifdstaddr *** */ -#if defined(SIOCSIFDSTADDR) -#define IOCTL_SIFDSTADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifdstaddr, SIOCSIFDSTADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_dstaddr)) -#else -#define IOCTL_SIFDSTADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_sifbrdaddr *** */ -#if defined(SIOCSIFBRDADDR) -#define IOCTL_SIFBRDADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifbrdaddr, SIOCSIFBRDADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_broadaddr)) -#else -#define IOCTL_SIFBRDADDR_FUNC_DECL -#endif - -/* *** esock_ioctl_sifnetmask *** */ -#if defined(SIOCSIFNETMASK) -#ifdef __linux__ -#define IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_netmask)) -#else -#define IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_addr)) -#endif -#else -#define IOCTL_SIFNETMASK_FUNC_DECL -#endif - -/* *** esock_ioctl_sifmtu *** - * On some platforms, MTU is an unsigned int - */ -#if defined(SIOCSIFMTU) -#define IOCTL_SIFMTU_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifmtu, SIOCSIFMTU, mtu, (int*) &ifreq.ifr_mtu) -#else -#define IOCTL_SIFMTU_FUNC_DECL -#endif - -/* *** esock_ioctl_siftxqlen *** */ -#if defined(SIOCSIFTXQLEN) -#define IOCTL_SIFTXQLEN_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(siftxqlen, SIOCSIFTXQLEN, txqlen, &ifreq.ifr_qlen) -#else -#define IOCTL_SIFTXQLEN_FUNC_DECL -#endif - -#define IOCTL_SET_FUNCS \ - IOCTL_SIFADDR_FUNC_DECL \ - IOCTL_SIFDSTADDR_FUNC_DECL \ - IOCTL_SIFBRDADDR_FUNC_DECL \ - IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SIFMTU_FUNC_DECL \ - IOCTL_SIFTXQLEN_FUNC_DECL - -#define IOCTL_SET_REQUEST_DECL(OR, R, DF, UVP) \ - static \ - ERL_NIF_TERM esock_ioctl_##OR(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename, \ - ERL_NIF_TERM evalue) \ - { \ - ERL_NIF_TERM result; \ - struct ifreq ifreq; \ - char* ifn = NULL; \ - int nlen; \ - \ - SSDBG( descP, ("SOCKET", "esock_ioctl_" #OR " {%d} -> entry with" \ - "\r\n (e)Name: %T" \ - "\r\n (e)Value: %T" \ - "\r\n", descP->sock, ename, evalue) ); \ - \ - if (!esock_decode_string(env, ename, &ifn)) { \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failed decode name" \ - "\r\n", descP->sock) ); \ - \ - return enif_make_badarg(env); \ - } \ - \ - if (! decode_ioctl_##DF(env, descP, evalue, UVP)) { \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failed decode addr" \ - "\r\n", descP->sock) ); \ - \ - return esock_make_invalid(env, atom_##DF); \ - } \ - \ - nlen = esock_strnlen(ifn, IFNAMSIZ); \ - \ - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ - sys_memcpy(ifreq.ifr_name, ifn, \ - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> try ioctl\r\n", \ - descP->sock) ); \ - \ - if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ - int saveErrno = sock_errno(); \ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failure: " \ - "\r\n reason: %T (%d)" \ - "\r\n", descP->sock, reason, saveErrno) ); \ - \ - result = esock_make_error(env, reason); \ - \ - } else { \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> " \ - "addr successfully set\r\n", \ - descP->sock) ); \ - result = esock_atom_ok; \ - } \ - \ - FREE(ifn); \ - \ - return result; \ - \ - } - -IOCTL_SET_FUNCS -#undef IOCTL_SET_FUNCS - - -/* =========================================================================== - * The "rest" of the implemented (ioctl) set requests - * - * These (set) requests could not be 'generated' by the macros above. - */ - -#if defined(SIOCSIFFLAGS) -static -ERL_NIF_TERM esock_ioctl_sifflags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ename, - ERL_NIF_TERM eflags) -{ - ERL_NIF_TERM result; - struct ifreq ifreq; - char* ifn = NULL; - int nlen; - - SSDBG( descP, ("SOCKET", "esock_ioctl_sifflags {%d} -> entry with" - "\r\n (e)Name: %T" - "\r\n (e)Flags: %T" - "\r\n", descP->sock, ename, eflags) ); - - if (!esock_decode_string(env, ename, &ifn)) { - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> failed decode name" - "\r\n", descP->sock) ); - - return enif_make_badarg(env); - } - - // Make sure the length of the string is valid! - nlen = esock_strnlen(ifn, IFNAMSIZ); - - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); // Just in case - sys_memcpy(ifreq.ifr_name, ifn, - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> try (get) ioctl\r\n", - descP->sock) ); - - if (ioctl(descP->sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> " - "failure: failed reading *current* flags" - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); - - result = esock_make_error(env, reason); - - } else { - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> (local) update flags\r\n", - descP->sock) ); - - if (decode_ioctl_flags(env, descP, eflags, &ifreq.ifr_flags)) { - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> try (set) ioctl\r\n", - descP->sock) ); - - if (ioctl(descP->sock, SIOCSIFFLAGS, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> failure: " - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); - - result = esock_make_error(env, reason); - - } else { - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> " - "updated flags successfully set\r\n", - descP->sock) ); - result = esock_atom_ok; - } - - /* We know that if esock_decode_string is successful, - * we have "some" form of string, and therefor memory - * has been allocated (and need to be freed)... */ - FREE(ifn); - - } else { - result = enif_make_badarg(env); - } - } - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> done with result: " - "\r\n %T" - "\r\n", - descP->sock, result) ); - - return result; - -} -#endif - - - -/* =========================================================================== - * ioctl utility functions - * - */ - -static -ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifconf* ifcP) -{ - ERL_NIF_TERM result; - unsigned int len = ((ifcP == NULL) ? 0 : - (ifcP->ifc_len / sizeof(struct ifreq))); - - SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> entry (when len = %d)\r\n", len) ); - - if (len > 0) { - ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); - unsigned int i = 0; - struct ifreq* p = ifcP->ifc_req; - - for (i = 0 ; i < len ; i++) { - SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> encode ifreq entry %d\r\n", i) ); - array[i] = encode_ioctl_ifconf_ifreq(env, descP, &p[i]); - } - - SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> all entries encoded\r\n", i) ); - - result = esock_make_ok2(env, MKLA(env, array, len)); - FREE(array); - - } else { - - result = esock_make_ok2(env, MKEL(env)); - - } - - return result; -} - - -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -static -ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifmap* mapP) -{ - ERL_NIF_TERM mapKeys[] = {atom_mem_start, - atom_mem_end, - atom_base_addr, - atom_irq, - atom_dma, - atom_port}; - ERL_NIF_TERM mapVals[] = {MKUL(env, mapP->mem_start), - MKUL(env, mapP->mem_end), - MKUI(env, mapP->base_addr), - MKUI(env, mapP->irq), - MKUI(env, mapP->dma), - MKUI(env, mapP->port)}; - unsigned int numMapKeys = NUM(mapKeys); - unsigned int numMapVals = NUM(mapVals); - ERL_NIF_TERM emap; - - ESOCK_ASSERT( numMapVals == numMapKeys ); - ESOCK_ASSERT( MKMA(env, mapKeys, mapVals, numMapKeys, &emap) ); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifrmap -> done with" - "\r\n Map: %T" - "\r\n", emap) ); - - return esock_make_ok2(env, emap);; } -#endif - -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -static -ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP) -{ - ERL_NIF_TERM eaddr; - SOCKLEN_T sz = sizeof(struct sockaddr); - - esock_encode_hwsockaddr(env, addrP, sz, &eaddr); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifraddr -> done with" - "\r\n Sock Addr: %T" - "\r\n", eaddr) ); - - return esock_make_ok2(env, eaddr);; -} -#endif - - -static -ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP) -{ - ERL_NIF_TERM eaddr; - - esock_encode_sockaddr(env, (ESockAddress*) addrP, -1, &eaddr); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifraddr -> done with" - "\r\n Sock Addr: %T" - "\r\n", eaddr) ); - - return esock_make_ok2(env, eaddr);; -} - - -static -ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - short flags) -{ - int i, flag, num = NUM(ioctl_flags); - ERL_NIF_TERM eflags, eflag; - SocketTArray ta = TARRAY_CREATE(20); // Just to be on the safe side - - if (flags == 0) { - eflags = MKEL(env); - } else { - for (i = 0; (i < num) && (flags != 0); i++) { - flag = ioctl_flags[i].flag; - if ((flag != 0) && ((flags & flag) == flag)) { - eflag = *(ioctl_flags[i].name); - flags &= ~flag; - - SSDBG( descP, ("SOCKET", "encode_ioctl_flags {%d} -> " - "\r\n i: %d" - "\r\n found flag: %T (%d)" - "\r\n remaining flags: %d" - "\r\n", descP->sock, i, eflag, flag, flags) ); - - TARRAY_ADD(ta, eflag); - } - } - if (flags != 0) { - - SSDBG( descP, ("SOCKET", "encode_ioctl_flags {%d} -> unknown flag(s): %d" - "\r\n", descP->sock, flags) ); - - TARRAY_ADD(ta, MKI(env, flags)); - } - - TARRAY_TOLIST(ta, env, &eflags); - } - - - SSDBG( descP, ("SOCKET", "encode_ioctl_flags -> done with" - "\r\n Flags: %T (%d)" - "\r\n", eflags, flags) ); - - return esock_make_ok2(env, eflags);; -} - - -static -BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eaddr, - ESockAddress* addr) -{ - SOCKLEN_T addrLen; - BOOLEAN_T result; - - result = esock_decode_sockaddr(env, eaddr, (ESockAddress*) addr, &addrLen); - - VOID(addrLen); - - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_sockaddr {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); - - return result; -} - - -static -BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM emtu, - int* mtu) -{ - BOOLEAN_T result; - - if (! GET_INT(env, emtu, mtu)) { - result = FALSE; - } else { - result = TRUE; - } - - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_mtu {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); - - return result; -} - - -#if defined(SIOCSIFTXQLEN) -static -BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM etxqlen, - int* txqlen) -{ - return decode_ioctl_ivalue(env, descP, etxqlen, txqlen); -} -#endif - -/* All uses of the function should be added. For instance: - * #if defined(SIOCGIFTXQLEN) || defined(FOOBAR) || defined(YXA) - */ -#if defined(SIOCGIFTXQLEN) -static -BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eivalue, - int* ivalue) -{ - BOOLEAN_T result; - - if (! GET_INT(env, eivalue, ivalue)) { - result = FALSE; - } else { - result = TRUE; - } - - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_ivalue {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); - - return result; -} -#endif - - -static -BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eflags, - short* flags) -{ - ERL_NIF_TERM key, value; - ErlNifMapIterator iter; - int tmpFlags = (int) *flags; // Current value - int flag; - - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> entry with" - "\r\n flags: %d" - "\r\n", - descP->sock, tmpFlags) ); - - enif_map_iterator_create(env, eflags, &iter, ERL_NIF_MAP_ITERATOR_FIRST); - - while (enif_map_iterator_get_pair(env, &iter, &key, &value)) { - - /* Convert key (eflag) to int */ - if (! GET_INT(env, key, &flag)) { - enif_map_iterator_destroy(env, &iter); - return FALSE; - } - - // Update flag - if (COMPARE(value, esock_atom_true) == 0) { - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> set %d\r\n", - descP->sock, flag) ); - tmpFlags |= flag; - } else { - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> reset %d\r\n", - descP->sock, flag) ); - tmpFlags &= ~flag; - } - - enif_map_iterator_next(env, &iter); - } - - enif_map_iterator_destroy(env, &iter); - - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> done with" - "\r\n (new) flags: %d" - "\r\n", - descP->sock, tmpFlags) ); - - *flags = (short) tmpFlags; - - return TRUE; -} - - -static -ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - int ivalue) -{ - ERL_NIF_TERM eivalue = MKI(env, ivalue); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ivalue -> done with" - "\r\n iValue: %T (%d)" - "\r\n", eivalue, ivalue) ); - - return esock_make_ok2(env, eivalue);; -} - -static -ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifreq* ifrP) -{ - ERL_NIF_TERM ename, eaddr; - - ESOCK_ASSERT( ifrP != NULL ); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> encode name\r\n") ); - ename = encode_ioctl_ifreq_name(env, ifrP->ifr_name); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> encode sockaddr\r\n") ); - eaddr = encode_ioctl_ifreq_sockaddr(env, &ifrP->ifr_addr); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> make ifreq map with" - "\r\n Name: %T" - "\r\n Sock Addr: %T" - "\r\n", ename, eaddr) ); - return make_ifreq(env, ename, esock_atom_addr, eaddr); -} - -static -ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, - char* name) -{ - return ((name == NULL) ? esock_atom_undefined : MKS(env, name)); -} - -static -ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, struct sockaddr* sa) -{ - ERL_NIF_TERM esa; - - if (sa != NULL) { - - esock_encode_sockaddr(env, (ESockAddress*) sa, -1, &esa); - - } else { - - esa = esock_atom_undefined; - - } - - return esa; -} - - -/* The ifreq structure *always* contain a name - * and *one* other element. The second element - * depend on the ioctl request. - */ -static -ERL_NIF_TERM make_ifreq(ErlNifEnv* env, - ERL_NIF_TERM name, - ERL_NIF_TERM key2, - ERL_NIF_TERM val2) -{ - ERL_NIF_TERM keys[2]; - ERL_NIF_TERM vals[2]; - ERL_NIF_TERM res; - - keys[0] = esock_atom_name; - vals[0] = name; - - keys[1] = key2; - vals[1] = val2; - - ESOCK_ASSERT( MKMA(env, keys, vals, NUM(keys), &res) ); - - return res; -} - -#endif // #ifndef __WIN32__ @@ -14474,7 +9943,8 @@ ERL_NIF_TERM make_ifreq(ErlNifEnv* env, * * Arguments: * Socket (ref) - Points to the socket descriptor. - * Operation (atom) - What kind of operation (accept, send, ...) is to be cancelled + * Operation (atom) - What kind of operation (accept, send, ...) + * is to be cancelled * Ref (ref) - Unique id for the operation */ static @@ -14482,9 +9952,6 @@ ERL_NIF_TERM nif_cancel(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; ERL_NIF_TERM op, sockRef, opRef; @@ -14507,11 +9974,9 @@ ERL_NIF_TERM nif_cancel(ErlNifEnv* env, return esock_cancel(env, descP, op, sockRef, opRef); -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ static ERL_NIF_TERM esock_cancel(ErlNifEnv* env, ESockDescriptor* descP, @@ -14519,7 +9984,8 @@ ERL_NIF_TERM esock_cancel(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM opRef) { - int cmp; + ERL_NIF_TERM result; + int cmp; /* <KOLLA> * @@ -14531,43 +9997,78 @@ ERL_NIF_TERM esock_cancel(ErlNifEnv* env, */ /* Hand crafted binary search */ - if ((cmp = COMPARE(op, esock_atom_recvmsg)) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); + if ((cmp = COMPARE(op, esock_atom_recvmsg)) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } if (cmp < 0) { - if ((cmp = COMPARE(op, esock_atom_recv)) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); + if ((cmp = COMPARE(op, esock_atom_recv)) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } if (cmp < 0) { - if (COMPARE(op, esock_atom_connect) == 0) - return esock_cancel_connect(env, descP, opRef); - if (COMPARE(op, esock_atom_accept) == 0) - return esock_cancel_accept(env, descP, sockRef, opRef); + if (COMPARE(op, esock_atom_connect) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_CONNECT(env, descP, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + if (COMPARE(op, esock_atom_accept) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_ACCEPT(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } } else { - if (COMPARE(op, esock_atom_recvfrom) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); + if (COMPARE(op, esock_atom_recvfrom) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } } } else { - if ((cmp = COMPARE(op, esock_atom_sendmsg)) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); + if ((cmp = COMPARE(op, esock_atom_sendmsg)) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } if (cmp < 0) { - if (COMPARE(op, esock_atom_send) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); - if (COMPARE(op, atom_sendfile) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); + if (COMPARE(op, esock_atom_send) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + if (COMPARE(op, esock_atom_sendfile) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } } else { - if (COMPARE(op, esock_atom_sendto) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); + if (COMPARE(op, esock_atom_sendto) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } } } { - ERL_NIF_TERM result; const char *reason; MLOCK(descP->readMtx); MLOCK(descP->writeMtx); if (! IS_OPEN(descP->readState)) { - result = esock_make_error(env, atom_closed); + result = esock_make_error_closed(env); reason = "closed"; } else { result = enif_make_badarg(env); @@ -14586,430 +10087,10 @@ ERL_NIF_TERM esock_cancel(ErlNifEnv* env, return result; } } -#endif // #ifndef __WIN32__ - -/* *** esock_cancel_connect *** - * - * - */ #ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef) -{ - ERL_NIF_TERM res; - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - MLOCK(descP->writeMtx); - - if (! IS_OPEN(descP->writeState)) { - - res = esock_make_error(env, atom_closed); - - } else if ((descP->connectorP == NULL) || - (COMPARE_PIDS(&self, &descP->connector.pid) != 0) || - (COMPARE(opRef, descP->connector.ref) != 0)) { - - res = esock_atom_not_found; - - } else { - - res = esock_cancel_write_select(env, descP, opRef); - requestor_release("esock_cancel_connect", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; - } - - SSDBG( descP, - ("SOCKET", - "esock_cancel_connect {%d,0x%X} ->" - "\r\n opRef: %T" - "\r\n res: %T" - "\r\n", - descP->sock, descP->writeState, - opRef, res) ); - - MUNLOCK(descP->writeMtx); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_cancel_accept *** - * - * We have two different cases: - * *) Its the current acceptor - * Cancel the select! - * We need to activate one of the waiting acceptors. - * *) Its one of the acceptors ("waiting") in the queue - * Simply remove the acceptor from the queue. - * - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) -{ - ERL_NIF_TERM res; - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_accept(%T), {%d,0x%X} ->" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->readState, - opRef, - ((descP->currentAcceptorP == NULL) - ? "without acceptor" : "with acceptor")) ); - - if (! IS_OPEN(descP->readState)) { - - res = esock_make_error(env, atom_closed); - - } else if (descP->currentAcceptorP == NULL) { - - res = esock_atom_not_found; - - } else { - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - if (COMPARE_PIDS(&self, &descP->currentAcceptor.pid) == 0) { - if (COMPARE(opRef, descP->currentAcceptor.ref) == 0) - res = esock_cancel_accept_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_accept_waiting(env, descP, opRef, &self); - } - } - - SSDBG( descP, - ("SOCKET", "esock_cancel_accept(%T) -> done with result:" - "\r\n %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->readMtx); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* The current acceptor process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the acceptor queue). - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_accept_current -> current acceptor", - env, descP, &descP->currentAcceptor.mon) == 0); - MON_INIT(&descP->currentAcceptor.mon); - res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_accept_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); - - if (!activate_next_acceptor(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_cancel_accept_current(%T) {%d} -> " - "no more acceptors\r\n", - sockRef, descP->sock) ); - - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* These processes have not performed a select, so we can simply - * remove them from the acceptor queue. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) -{ - /* unqueue request from (acceptor) queue */ - - if (acceptor_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; - } else { - return esock_atom_not_found; - } -} -#endif // #ifndef __WIN32__ - - - -/* *** esock_cancel_send *** - * - * Cancel a send operation. - * Its either the current writer or one of the waiting writers. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) -{ - ERL_NIF_TERM res; - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_send(%T), {%d,0x%X} -> entry with" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->writeState, - opRef, - ((descP->currentWriterP == NULL) - ? "without writer" : "with writer")) ); - - if (! IS_OPEN(descP->writeState)) { - - res = esock_make_error(env, atom_closed); - - } else if (descP->currentWriterP == NULL) { - - res = esock_atom_not_found; - - } else { - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - if (COMPARE_PIDS(&self, &descP->currentWriter.pid) == 0) { - if (COMPARE(opRef, descP->currentWriter.ref) == 0) - res = esock_cancel_send_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_send_waiting(env, descP, opRef, &self); - } - } - - SSDBG( descP, - ("SOCKET", "esock_cancel_send(%T) {%d} -> done with result:" - "\r\n %T" - "\r\n", sockRef, descP->sock, res) ); - - MUNLOCK(descP->writeMtx); - - return res; -} -#endif // #ifndef __WIN32__ - - - -/* The current writer process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the writer queue). - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_send_current -> current writer", - env, descP, &descP->currentWriter.mon) == 0); - res = esock_cancel_write_select(env, descP, descP->currentWriter.ref); - - SSDBG( descP, - ("SOCKET", "esock_cancel_send_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); - - if (!activate_next_writer(env, descP, sockRef)) { - SSDBG( descP, - ("SOCKET", - "esock_cancel_send_current(%T) {%d} -> no more writers" - "\r\n", sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* These processes have not performed a select, so we can simply - * remove them from the writer queue. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) -{ - /* unqueue request from (writer) queue */ - - if (writer_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; - } else { - return esock_atom_not_found; - } -} -#endif // #ifndef __WIN32__ - - - -/* *** esock_cancel_recv *** - * - * Cancel a read operation. - * Its either the current reader or one of the waiting readers. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) -{ - ERL_NIF_TERM res; - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_recv(%T), {%d,0x%X} -> entry with" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->readState, - opRef, - ((descP->currentReaderP == NULL) - ? "without reader" : "with reader")) ); - - if (! IS_OPEN(descP->readState)) { - - res = esock_make_error(env, atom_closed); - - } else if (descP->currentReaderP == NULL) { - - res = esock_atom_not_found; - - } else { - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - if (COMPARE_PIDS(&self, &descP->currentReader.pid) == 0) { - if (COMPARE(opRef, descP->currentReader.ref) == 0) - res = esock_cancel_recv_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_recv_waiting(env, descP, opRef, &self); - } - } - - SSDBG( descP, - ("SOCKET", "esock_cancel_recv(%T) {%d} -> done with result:" - "\r\n %T" - "\r\n", sockRef, descP->sock, res) ); - - MUNLOCK(descP->readMtx); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* The current reader process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the reader queue). - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_recv_current -> current reader", - env, descP, &descP->currentReader.mon) == 0); - res = esock_cancel_read_select(env, descP, descP->currentReader.ref); - - SSDBG( descP, - ("SOCKET", "esock_cancel_recv_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); - - if (! activate_next_reader(env, descP, sockRef)) { - SSDBG( descP, - ("SOCKET", - "esock_cancel_recv_current(%T) {%d} -> no more readers" - "\r\n", sockRef, descP->sock) ); - - descP->currentReaderP = NULL; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* These processes have not performed a select, so we can simply - * remove them from the reader queue. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) -{ - /* unqueue request from (reader) queue */ - - if (reader_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; - } else { - return esock_atom_not_found; - } -} -#endif // #ifndef __WIN32__ - - - -#ifndef __WIN32__ -static +extern ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM opRef) @@ -15022,10 +10103,10 @@ ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, #ifndef __WIN32__ -static +extern ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef) + ESockDescriptor* descP, + ERL_NIF_TERM opRef) { return esock_cancel_mode_select(env, descP, opRef, ERL_NIF_SELECT_WRITE, @@ -15035,7 +10116,7 @@ ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, #ifndef __WIN32__ -static +extern ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM opRef, @@ -15053,7 +10134,7 @@ ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, return esock_atom_ok; } else { /* Has already sent the message */ - return esock_atom_select_sent; + return esock_make_error(env, esock_atom_select_sent); } } else { /* Stopped? */ @@ -15062,7 +10143,7 @@ ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, "esock_cancel_mode_select {%d} -> failed: %d (0x%lX)" "\r\n", descP->sock, selectRes, selectRes) ); - return esock_atom_not_found; + return esock_make_error(env, esock_atom_not_found); } } #endif // #ifndef __WIN32__ @@ -15074,1654 +10155,95 @@ ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, * ---------------------------------------------------------------------- */ -/* *** send_check_writer *** - * - * Checks if we have a current writer and if that is us. - * If not (current writer), then we must be made to wait - * for our turn. This is done by pushing us unto the writer queue. - */ -#ifndef __WIN32__ -static -BOOLEAN_T send_check_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult) -{ - if (descP->currentWriterP != NULL) { - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - - if (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0) { - /* Not the "current writer", so (maybe) push onto queue */ - - SSDBG( descP, - ("SOCKET", - "send_check_writer {%d} -> not (current) writer" - "\r\n ref: %T" - "\r\n", descP->sock, ref) ); - - if (! writer_search4pid(env, descP, &caller)) { - writer_push(env, descP, caller, ref); - *checkResult = atom_select; - } else { - /* Writer already in queue */ - *checkResult = esock_raise_invalid(env, atom_state); - } - - SSDBG( descP, - ("SOCKET", - "send_check_writer {%d} -> queue (push) result: %T\r\n" - "\r\n ref: %T" - "\r\n", descP->sock, *checkResult, ref) ); - - return FALSE; - } - } - - // Does not actually matter in this case, but ... - *checkResult = esock_atom_ok; - - return TRUE; -} -#endif // #ifndef __WIN32__ - - -/* *** send_check_result *** - * - * Check the result of a socket send (send, sendto and sendmsg) call. - * If a "complete" send has been made, the next (waiting) writer will be - * scheduled (if there is one). - * If we did not manage to send the entire package, make another select, - * so that we can be informed when we can make another try (to send the rest), - * and return with the amount we actually managed to send (its up to the caller - * (that is the erlang code) to figure out hust much is left to send). - * If the write fail, we give up and return with the appropriate error code. - * - * What about the remaining writers!! - * - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM send_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t send_result, - ssize_t dataSize, - BOOLEAN_T dataInTail, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef) +extern +BOOLEAN_T esock_encode_cmsg(ErlNifEnv* env, + int level, + int type, + unsigned char* dataP, + size_t dataLen, + ERL_NIF_TERM* eType, + ERL_NIF_TERM* eData) { - ERL_NIF_TERM res; - BOOLEAN_T send_error; - int err; - - send_error = ESOCK_IS_ERROR(send_result); - err = send_error ? sock_errno() : 0; - - SSDBG( descP, - ("SOCKET", "send_check_result(%T) {%d} -> entry with" - "\r\n send_result: %ld" - "\r\n dataSize: %ld" - "\r\n err: %d" - "\r\n sendRef: %T" - "\r\n", sockRef, descP->sock, - (long) send_result, (long) dataSize, err, sendRef) ); - - if (send_error) { - /* Some kind of send failure - check what kind */ - if ((err != EAGAIN) && (err != EINTR)) { - res = send_check_fail(env, descP, err, sockRef); - } else { - /* Ok, try again later */ - - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> try again" - "\r\n", sockRef, descP->sock) ); - - res = send_check_retry(env, descP, -1, sockRef, sendRef); - } - } else { - ssize_t written = send_result; - ESOCK_ASSERT( dataSize >= written ); - - if (written < dataSize) { - /* Not the entire package */ - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> " - "not entire package written (%d of %d)" - "\r\n", sockRef, descP->sock, - written, dataSize) ); - - res = send_check_retry(env, descP, written, sockRef, sendRef); - } else if (dataInTail) { - /* Not the entire package */ - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> " - "not entire package written (%d but data in tail)" - "\r\n", sockRef, descP->sock, - written) ); - - res = - send_check_retry(env, descP, written, sockRef, - esock_atom_iov); - } else { - res = send_check_ok(env, descP, written, sockRef); - } - } - - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> done:" - "\r\n res: %T" - "\r\n", sockRef, descP->sock, - res) ); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** send_check_ok *** - * - * Processing done upon successful send. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM send_check_ok(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef) -{ - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_pkg, &descP->writePkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_byte, &descP->writeByteCnt, written); - descP->writePkgMaxCnt += written; - if (descP->writePkgMaxCnt > descP->writePkgMax) - descP->writePkgMax = descP->writePkgMaxCnt; - descP->writePkgMaxCnt = 0; - - SSDBG( descP, - ("SOCKET", "send_check_ok(%T) {%d} -> " - "everything written (%ld) - done\r\n", - sockRef, descP->sock, written) ); - - if (descP->currentWriterP != NULL) { - ESOCK_ASSERT( DEMONP("send_check_ok -> current writer", - env, descP, &descP->currentWriter.mon) == 0); - } - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (!activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", "send_check_ok(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ - - -/* *** send_check_failure *** - * - * Processing done upon failed send. - * An actual failure - we (and everyone waiting) give up. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM send_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM reason; - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1); - - SSDBG( descP, ("SOCKET", "send_check_fail(%T) {%d} -> error: %d\r\n", - sockRef, descP->sock, saveErrno) ); - - reason = MKA(env, erl_errno_id(saveErrno)); + const ESockCmsgSpec *cmsgTable; + size_t num; - if (saveErrno != EINVAL) { + if ((cmsgTable = esock_lookup_cmsg_table(level, &num)) != NULL) { + size_t n; - /* - * We assume that anything other then einval (invalid input) - * is basically fatal (=> all waiting sends are aborted) + /* Linear search for type number in level table */ + for (n = 0; n < num; n++) { + if (cmsgTable[n].type == type) { + /* Found the type number in the level table; + * return the symbolic type (atom) + * and try to encode the data + */ - if (descP->currentWriterP != NULL) { - - requestor_release("send_check_fail", - env, descP, &descP->currentWriter); - - send_error_waiting_writers(env, descP, sockRef, reason); - - descP->currentWriterP = NULL; - } - } - return esock_make_error(env, reason); -} -#endif // #ifndef __WIN32__ - - -/* *** send_error_waiting_writers *** - * - * Process all waiting writers when a fatal error has occurred. - * All waiting writers will be "aborted", that is a - * nif_abort message will be sent (with ref and reason). - */ -#ifndef __WIN32__ -static -void send_error_waiting_writers(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) -{ - ESockRequestor req; - - req.env = NULL; /* read by writer_pop before free */ - while (writer_pop(env, descP, &req)) { - SSDBG( descP, - ("SOCKET", - "send_error_waiting_writers(%T) {%d} -> abort" - "\r\n pid: %T" - "\r\n reason: %T" - "\r\n", - sockRef, descP->sock, &req.pid, reason) ); - - esock_send_abort_msg(env, descP, sockRef, &req, reason); - - (void) DEMONP("send_error_waiting_writers -> pop'ed writer", - env, descP, &req.mon); - } -} -#endif // #ifndef __WIN32__ - - -/* *** send_check_retry *** - * - * Processing done upon incomplete or blocked send. - * - * We failed to write the *entire* packet (anything less - * then size of the packet, which is 0 <= written < sizeof - * packet, so schedule the rest for later. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM send_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef) -{ - int sres; - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", - "send_check_retry(%T) {%d} -> %ld" - "\r\n", sockRef, descP->sock, (long) written) ); - - if (written >= 0) { - descP->writePkgMaxCnt += written; - - if (descP->type != SOCK_STREAM) { - /* Partial write for packet oriented socket - * - done with packet - */ - if (descP->writePkgMaxCnt > descP->writePkgMax) - descP->writePkgMax = descP->writePkgMaxCnt; - descP->writePkgMaxCnt = 0; - - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_pkg, &descP->writePkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_byte, &descP->writeByteCnt, written); - - if (descP->currentWriterP != NULL) { - ESOCK_ASSERT( DEMONP("send_check_retry -> current writer", - env, descP, - &descP->currentWriter.mon) == 0); - } - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (!activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "send_check_retry(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - - return esock_make_ok2(env, MKI64(env, written)); - } /* else partial write for stream socket */ - } /* else send would have blocked */ - - /* Register this process as current writer */ - - if (descP->currentWriterP == NULL) { - /* Register writer as current */ - - ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); - ESOCK_ASSERT( MONP("send_check_retry -> current writer", - env, descP, - &descP->currentWriter.pid, - &descP->currentWriter.mon) == 0 ); - ESOCK_ASSERT( descP->currentWriter.env == NULL ); - - descP->currentWriter.env = esock_alloc_env("current-writer"); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - descP->currentWriterP = &descP->currentWriter; - } else { - /* Overwrite current writer registration */ - enif_clear_env(descP->currentWriter.env); - descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef); - } - - if (COMPARE(sendRef, esock_atom_iov) == 0) { - ESOCK_ASSERT( written >= 0 ); - /* IOV iteration - do not select */ - return MKT2(env, esock_atom_iov, MKI64(env, written)); - } - - /* Select write for this process */ - - sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); - - if (sres < 0) { - ERL_NIF_TERM reason; - - /* Internal select error */ - ESOCK_ASSERT( DEMONP("send_check_retry - select error", - env, descP, &descP->currentWriter.mon) == 0); - - /* Fail all queued writers */ - reason = MKT2(env, atom_select_write, MKI(env, sres)); - requestor_release("send_check_retry - select error", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; - - res = - enif_raise_exception(env, - MKT2(env, atom_select_write, - MKI(env, sres))); - - } else { - ESOCK_CNT_INC(env, descP, sockRef, atom_write_waits, - &descP->writeWaits, 1); - - descP->writeState |= ESOCK_STATE_SELECTED; - - if (written >= 0) { - /* Partial write success */ - res = MKT2(env, atom_select, MKI64(env, written)); - } else { - /* No write - try again */ - res = atom_select; - } - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_reader *** - * - * Checks if we have a current reader and if that is us. If not, - * then we must be made to wait for our turn. This is done by pushing - * us unto the reader queue. - * Note that we do *not* actually initiate the currentReader structure - * here, since we do not actually know yet if we need to! We do that in - * the [recv|recvfrom|recvmsg]_check_result function. - */ -#ifndef __WIN32__ -static -BOOLEAN_T recv_check_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult) -{ - if (descP->currentReaderP != NULL) { - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - - if (COMPARE_PIDS(&descP->currentReader.pid, &caller) != 0) { - /* Not the "current reader", so (maybe) push onto queue */ + *eType = *cmsgTable[n].nameP; - SSDBG( descP, - ("SOCKET", - "recv_check_reader {%d} -> not (current) reader" - "\r\n ref: %T" - "\r\n", descP->sock, ref) ); - - if (! reader_search4pid(env, descP, &caller)) { - if (COMPARE(ref, atom_zero) == 0) - goto done_ok; - reader_push(env, descP, caller, ref); - *checkResult = atom_select; - } else { - /* Reader already in queue */ - *checkResult = esock_raise_invalid(env, atom_state); + if (cmsgTable[n].encode != NULL) + return cmsgTable[n].encode(env, dataP, dataLen, eData); + else + return FALSE; } - - SSDBG( descP, - ("SOCKET", - "recv_check_reader {%d} -> queue (push) result: %T\r\n", - descP->sock, *checkResult) ); - - return FALSE; - } - } - - done_ok: - // Does not actually matter in this case, but ... - *checkResult = esock_atom_ok; - return TRUE; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_init_current_reader *** - * - * Initiate (maybe) the currentReader structure of the descriptor. - * Including monitoring the calling process. - */ -#ifndef __WIN32__ -static -void recv_init_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM recvRef) -{ - if (descP->currentReaderP == NULL) { - - ESOCK_ASSERT( enif_self(env, &descP->currentReader.pid) != NULL ); - - ESOCK_ASSERT( MONP("recv_init_current_reader -> current reader", - env, descP, - &descP->currentReader.pid, - &descP->currentReader.mon) == 0); - ESOCK_ASSERT(!descP->currentReader.env); - - descP->currentReader.env = esock_alloc_env("current-reader"); - descP->currentReader.ref = - CP_TERM(descP->currentReader.env, recvRef); - descP->currentReaderP = &descP->currentReader; - } else { - - /* - * This is a retry: - * We have done, for instance, recv(Sock, X), but only received Y < X. - * We then call recv again with size = X-Y. So, we then get a new ref. - * - * Make use of the existing environment - */ - - enif_clear_env(descP->currentReader.env); - descP->currentReader.ref = CP_TERM(descP->currentReader.env, recvRef); - } -} -#endif // #ifndef __WIN32__ - - -/* *** recv_update_current_reader *** - * - * Demonitors the current reader process and pop's the reader queue. - * If there is a waiting (reader) process, then it will be assigned - * as the new current reader and a new (read) select will be done. - */ -#ifndef __WIN32__ -static void -recv_update_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) -{ - if (descP->currentReaderP != NULL) { - - ESOCK_ASSERT( DEMONP("recv_update_current_reader", - env, descP, &descP->currentReader.mon) == 0); - - if (! activate_next_reader(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "recv_update_current_reader(%T) {%d} -> no more readers\r\n", - sockRef, descP->sock) ); - - descP->currentReaderP = NULL; - } - } -} -#endif // #ifndef __WIN32__ - - -/* *** recv_error_current_reader *** - * - * Process the current reader and any waiting readers - * when a read (fatal) error has occurred. - * All waiting readers will be "aborted", that is a - * nif_abort message will be sent (with ref and reason). - */ -#ifndef __WIN32__ -static -void recv_error_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) -{ - if (descP->currentReaderP != NULL) { - ESockRequestor req; - - requestor_release("recv_error_current_reader", - env, descP, &descP->currentReader); - - req.env = NULL; /* read by reader_pop before free */ - while (reader_pop(env, descP, &req)) { - - SSDBG( descP, - ("SOCKET", "recv_error_current_reader(%T) {%d} -> abort" - "\r\n pid: %T" - "\r\n reason %T" - "\r\n", sockRef, descP->sock, - req.pid, reason) ); - - esock_send_abort_msg(env, descP, sockRef, &req, reason); - - ESOCK_ASSERT( DEMONP("recv_error_current_reader -> pop'ed reader", - env, descP, &req.mon) == 0); - } - - descP->currentReaderP = NULL; - } -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_result *** - * - * Process the result of a call to recv. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - int saveErrno, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", "recv_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n toRead: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, (long) toRead, saveErrno, recvRef) ); - - - /* <KOLLA> - * - * We need to handle read = 0 for other type(s) (DGRAM) when - * its actually valid to read 0 bytes. - * - * </KOLLA> - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { - ERL_NIF_TERM reason = atom_closed; - res = esock_make_error(env, reason); - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); - - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - * - * We must also notify any waiting readers! - */ - - recv_error_current_reader(env, descP, sockRef, reason); - - FREE_BIN(bufP); - - } else { - - /* There is a special case: If the provided 'to read' value is - * zero (0) (only for type =/= stream). - * That means that we read as much as we can, using the default - * read buffer size. - */ - - if (bufP->size == read) { - - /* +++ We filled the buffer +++ */ - - SSDBG( descP, - ("SOCKET", - "recv_check_result(%T) {%d} -> [%lu] filled the buffer\r\n", - sockRef, descP->sock, (unsigned long) bufP->size) ); - - res = recv_check_full(env, descP, read, toRead, bufP, - sockRef, recvRef); - - } else if (read < 0) { - - /* +++ Error handling +++ */ - - res = recv_check_fail(env, descP, saveErrno, bufP, NULL, - sockRef, recvRef); - - } else { - - /* +++ We did not fill the buffer +++ */ - - SSDBG( descP, - ("SOCKET", - "recv_check_result(%T) {%d} -> [%lu] " - "did not fill the buffer (%ld)\r\n", - sockRef, descP->sock, (unsigned long) bufP->size, - (long) read) ); - - res = recv_check_partial(env, descP, read, toRead, bufP, - sockRef, recvRef); } } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_full *** - * - * This function is called if we filled the allocated buffer. - * But are we done yet? - * - * toRead = 0 means: Give me everything you have => maybe - * toRead > 0 means: Yes - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_full(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - - if ((toRead == 0) && - (descP->type == SOCK_STREAM)) { - - /* +++ Give us everything you have got => * - * (maybe) needs to continue +++ */ - - /* Send up each chunk of data for each of the read - * and let the erlang code assemble it: {more, Bin} - * (when complete it should return {ok, Bin}). - * We need to read at least one more time to be sure if its - * done... - * - * Also, we need to check if the rNumCnt has reached its max (rNum), - * in which case we will assume the read to be done! - */ - - SSDBG( descP, - ("SOCKET", "recv_check_full(%T) {%d} -> shall we continue reading?" - "\r\n read: %ld" - "\r\n rNum: %u" - "\r\n rNumCnt: %u" - "\r\n", sockRef, descP->sock, - (unsigned long) read, descP->rNum, descP->rNumCnt) ); - - res = recv_check_full_maybe_done(env, descP, read, bufP, - sockRef, recvRef); - - } else { - - /* +++ We got exactly as much as we requested => We are done +++ */ - - SSDBG( descP, - ("SOCKET", - "recv_check_full(%T) {%d} -> [%ld] " - "we got exactly what we could fit\r\n", - sockRef, descP->sock, (long) toRead) ); - - res = recv_check_full_done(env, descP, read, bufP, sockRef); - - } - - return res; - -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_full_maybe_done *** - * - * Send up each chunk of data for each of the read - * and let the erlang code assemble it: {more, Bin} - * (when complete it should return {ok, Bin}). - * We need to read at least one more time to be sure if its - * done... - * - * Also, we need to check if the rNumCnt has reached its max (rNum), - * in which case we will assume the read to be done! - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_byte, &descP->readByteCnt, read); - descP->readPkgMaxCnt += read; - - descP->rNumCnt++; - if (descP->rNumCnt >= descP->rNum) { - - descP->rNumCnt = 0; - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_pkg, &descP->readPkgCnt, 1); - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; - - recv_update_current_reader(env, descP, sockRef); - - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - - return esock_make_ok2(env, MKBIN(env, bufP)); - - } - - /* Yes, we *do* need to continue reading */ - - recv_init_current_reader(env, descP, recvRef); - - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - - SSDBG( descP, - ("SOCKET", - "recv_check_full_maybe_done(%T) {%d} -> [%lu] " - "we are done for now - read more\r\n", - sockRef, descP->sock, (unsigned long)bufP->size) ); - - return MKT2(env, esock_atom_more, MKBIN(env, bufP)); -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_full_done *** - * - * A successful recv and we filled the buffer. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM data; - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - descP->readPkgMaxCnt += read; - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; - - recv_update_current_reader(env, descP, sockRef); - - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - data = MKBIN(env, bufP); - - return esock_make_ok2(env, data); -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_fail *** - * - * Handle recv failure. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ErlNifBinary* buf1P, - ErlNifBinary* buf2P, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - - FREE_BIN(buf1P); - if (buf2P != NULL) FREE_BIN(buf2P); - - if (saveErrno == ECONNRESET) { - - /* +++ Oops - closed +++ */ - - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> econnreset: closed" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); - - // This is a bit overkill (to count here), but just in case... - ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, - &descP->readFails, 1); - - res = recv_check_fail_econnreset(env, descP, sockRef, recvRef); - - } else if ((saveErrno == ERRNO_BLOCK) || - (saveErrno == EAGAIN)) { - - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> eagain" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); - - if (COMPARE(recvRef, atom_zero) == 0) - res = esock_atom_ok; - else - res = recv_check_retry(env, descP, sockRef, recvRef); - - } else { - - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> errno: %d\r\n" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, saveErrno, recvRef) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, - &descP->readFails, 1); - - res = recv_check_fail_gen(env, descP, saveErrno, sockRef); - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_fail_econnreset *** - * - * We detected that the socket was closed while reading. - * Inform current and waiting readers. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(ECONNRESET)); - ERL_NIF_TERM res = esock_make_error(env, reason); - - /* <KOLLA> - * - * IF THE CURRENT PROCESS IS *NOT* THE CONTROLLING - * PROCESS, WE NEED TO INFORM IT!!! - * - * ALL WAITING PROCESSES MUST ALSO GET THE ERROR!! - * HANDLED BY THE STOP (CALLBACK) FUNCTION? - * - * SINCE THIS IS A REMOTE CLOSE, WE DON'T NEED TO WAIT - * FOR OUTPUT TO BE WRITTEN (NO ONE WILL READ), JUST - * ABORT THE SOCKET REGARDLESS OF LINGER??? - * - * </KOLLA> + /* No level table, or unknown type number in the table; + * just return the type number as an erlang integer */ - recv_error_current_reader(env, descP, sockRef, reason); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_retry *** - * - * The recv call would have blocked, so retry. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - int sres; - ERL_NIF_TERM res; - - descP->rNumCnt = 0; - recv_init_current_reader(env, descP, recvRef); - - SSDBG( descP, - ("SOCKET", - "recv_check_retry(%T) {%d} -> SELECT for more" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); - - if ((sres = esock_select_read(env, descP->sock, descP, NULL, - sockRef, recvRef)) < 0) { - /* Unlikely that any next reader will have better luck, - * but why not give them a shot - the queue will be cleared - */ - recv_update_current_reader(env, descP, sockRef); - - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); - } else { - descP->readState |= ESOCK_STATE_SELECTED; - res = atom_select; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_fail_gen *** - * - * The recv call had a "general" failure. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - recv_error_current_reader(env, descP, sockRef, reason); + *eType = MKI(env, type); - return esock_make_error(env, reason); + return FALSE; } -#endif // #ifndef __WIN32__ -/* *** recv_check_partial *** +/* +++ esock_encode_msg_flags +++ * - * Handle a successful recv which only partly filled the specified buffer. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - - if ((toRead == 0) || - (descP->type != SOCK_STREAM) || - (COMPARE(recvRef, atom_zero) == 0)) { - - /* +++ We got it all, but since we +++ - * +++ did not fill the buffer, we +++ - * +++ must split it into a sub-binary. +++ - */ - - SSDBG( descP, - ("SOCKET", - "recv_check_partial(%T) {%d} -> [%ld] split buffer" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, (long) toRead, - recvRef) ); - - res = recv_check_partial_done(env, descP, read, bufP, sockRef); - - } else { - /* A stream socket with specified read size - * and not a polling read, we got a partial read - * - return a select result to initiate a retry - */ - - SSDBG( descP, - ("SOCKET", - "recv_check_partial(%T) {%d} -> [%ld]" - " only part of message - expect more" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, (long) toRead, - recvRef) ); - - res = - recv_check_partial_part(env, descP, read, - bufP, sockRef, recvRef); - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** recv_check_partial_done *** + * Encode a list of msg_flag(). * - * A successful but only partial recv, which fulfilled the required read. */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM data; - - descP->rNumCnt = 0; - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - descP->readPkgMaxCnt += read; - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; - - recv_update_current_reader(env, descP, sockRef); - - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); - - SSDBG( descP, - ("SOCKET", "recv_check_partial_done(%T) {%d} -> [%ld] done\r\n", - sockRef, descP->sock, (long) read) ); - - return esock_make_ok2(env, data); -} -#endif // #ifndef __WIN32__ - -/* *** recv_check_partial_part *** - * - * A successful but only partial recv, which only partly fulfilled - * the required read. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - int sres; - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - recv_init_current_reader(env, descP, recvRef); - - /* SELECT for more data */ - - sres = esock_select_read(env, descP->sock, descP, NULL, - sockRef, recvRef); - if (sres < 0) { - /* Unlikely that any next reader will have better luck, - * but why not give them a shot - the queue will be cleared - */ - recv_update_current_reader(env, descP, sockRef); - - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); - } else { - ERL_NIF_TERM data; - - descP->readState |= ESOCK_STATE_SELECTED; - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); - res = MKT2(env, atom_select, data); - } - - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - return res; -} -#endif // #ifndef __WIN32__ - - - - -/* The recvfrom function delivers one (1) message. If our buffer - * is too small, the message will be truncated. So, regardless - * if we filled the buffer or not, we have got what we are going - * to get regarding this message. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - ErlNifBinary* bufP, - ESockAddress* fromAddrP, - SOCKLEN_T fromAddrLen, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +extern +void esock_encode_msg_flags(ErlNifEnv* env, + ESockDescriptor* descP, + int msgFlags, + ERL_NIF_TERM* flags) { - ERL_NIF_TERM data, res; - SSDBG( descP, - ("SOCKET", "recvfrom_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, saveErrno, recvRef) ); - - /* <KOLLA> - * - * We need to handle read = 0 for non_stream socket type(s) when - * its actually valid to read 0 bytes. - * - * </KOLLA> - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { - - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - */ - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); - - FREE_BIN(bufP); - - return esock_make_error(env, atom_closed); - } - - if (read < 0) { - - /* +++ Error handling +++ */ - - res = recv_check_fail(env, descP, saveErrno, bufP, NULL, - sockRef, recvRef); + ("SOCKET", "encode_msg_flags {%d} -> entry with" + "\r\n msgFlags: %d (0x%lX)" + "\r\n", descP->sock, msgFlags, msgFlags) ); + if (msgFlags == 0) { + *flags = MKEL(env); } else { + size_t n; + SocketTArray ta = TARRAY_CREATE(10); // Just to be on the safe side - /* +++ We successfully got a message - time to encode the address +++ */ - - ERL_NIF_TERM eSockAddr; - - esock_encode_sockaddr(env, - fromAddrP, fromAddrLen, - &eSockAddr); - - if (read == bufP->size) { - - data = MKBIN(env, bufP); - - } else { - - /* +++ We got a chunk of data but +++ - * +++ since we did not fill the +++ - * +++ buffer, we must split it +++ - * +++ into a sub-binary. +++ - */ - - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); + for (n = 0; n < esock_msg_flags_length; n++) { + int f = esock_msg_flags[n].flag; + if ((f != 0) && ((msgFlags & f) == f)) { + msgFlags &= ~f; + TARRAY_ADD(ta, *(esock_msg_flags[n].name)); + } + if (msgFlags == 0) goto done; } + /* Append remaining flags as an integer */ + if (msgFlags != 0) + TARRAY_ADD(ta, MKI(env, msgFlags)); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, - &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - recv_update_current_reader(env, descP, sockRef); - - res = esock_make_ok2(env, MKT2(env, eSockAddr, data)); - - } - - return res; - -} -#endif // #ifndef __WIN32__ - - - -/* *** recvmsg_check_result *** - * - * The recvmsg function delivers one (1) message. If our buffer - * is to small, the message will be truncated. So, regardless - * if we filled the buffer or not, we have got what we are going - * to get regarding this message. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", "recvmsg_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, saveErrno, recvRef) ); - - - /* <KOLLA> - * - * We need to handle read = 0 for non_stream socket type(s) when - * its actually valid to read 0 bytes. - * - * </KOLLA> - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { - - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - */ - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); - - FREE_BIN(dataBufP); FREE_BIN(ctrlBufP); - - return esock_make_error(env, atom_closed); - } - - - if (read < 0) { - - /* +++ Error handling +++ */ - - res = recv_check_fail(env, descP, saveErrno, dataBufP, ctrlBufP, - sockRef, recvRef); - - } else { - - /* +++ We successfully got a message - time to encode it +++ */ - - res = recvmsg_check_msg(env, descP, read, msgHdrP, - dataBufP, ctrlBufP, sockRef); - - } - - return res; - -} -#endif // #ifndef __WIN32__ - - -/* *** recvmsg_check_msg *** - * - * We successfully read one message. Time to process. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM eMsg; - - /* - * <KOLLA> - * - * The return value of recvmsg is the *total* number of bytes - * that where successfully read. This data has been put into - * the *IO vector*. - * - * </KOLLA> - */ - - encode_msg(env, descP, - read, msgHdrP, dataBufP, ctrlBufP, - &eMsg); - - SSDBG( descP, - ("SOCKET", "recvmsg_check_result(%T) {%d} -> ok\r\n", - sockRef, descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - recv_update_current_reader(env, descP, sockRef); - - return esock_make_ok2(env, eMsg); -} -#endif // #ifndef __WIN32__ - - -/* +++ encode_msg +++ - * - * Encode a msg() (recvmsg). In erlang its represented as - * a map, which has a specific set of attributes: - * - * addr (source address) - sockaddr() - * iov - [binary()] - * ctrl - [cmsg()] - * flags - msg_flags() - */ -#ifndef __WIN32__ -static -void encode_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM* eSockAddr) -{ - ERL_NIF_TERM addr, iov, ctrl, flags; - - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> entry with" - "\r\n read: %ld" - "\r\n", descP->sock, (long) read) ); - - /* The address is not used if we are connected (unless, maybe, - * family is 'local'), so check (length = 0) before we try to encodel - */ - if (msgHdrP->msg_namelen != 0) { - esock_encode_sockaddr(env, - (ESockAddress*) msgHdrP->msg_name, - msgHdrP->msg_namelen, - &addr); - } else { - addr = esock_atom_undefined; - } - - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> encode iov" - "\r\n msg_iovlen: %lu" - "\r\n", - descP->sock, - (unsigned long) msgHdrP->msg_iovlen) ); - - esock_encode_iov(env, read, - msgHdrP->msg_iov, msgHdrP->msg_iovlen, dataBufP, - &iov); - - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> try encode cmsgs\r\n", - descP->sock) ); - - encode_cmsgs(env, descP, ctrlBufP, msgHdrP, &ctrl); - - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> try encode flags\r\n", - descP->sock) ); - - encode_msg_flags(env, descP, msgHdrP->msg_flags, &flags); - - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> components encoded:" - "\r\n addr: %T" - "\r\n ctrl: %T" - "\r\n flags: %T" - "\r\n", descP->sock, addr, ctrl, flags) ); - - { - ERL_NIF_TERM keys[] = {esock_atom_iov, - esock_atom_ctrl, - esock_atom_flags, - esock_atom_addr}; - ERL_NIF_TERM vals[] = {iov, ctrl, flags, addr}; - size_t numKeys = NUM(keys); - - ESOCK_ASSERT( numKeys == NUM(vals) ); - - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> create map\r\n", - descP->sock) ); - - if (msgHdrP->msg_namelen == 0) - numKeys--; // No addr - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eSockAddr) ); - - SSDBG( descP, - ("SOCKET", - "encode_msg {%d}-> map encoded\r\n", - descP->sock) ); - } - - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> done\r\n", descP->sock) ); -} -#endif // #ifndef __WIN32__ - - - -/* +++ encode_cmsgs +++ - * - * Encode a list of cmsg(). There can be 0 or more cmsghdr "blocks". - * - * Our "problem" is that we have no idea how many control messages - * we have. - * - * The cmsgHdrP arguments points to the start of the control data buffer, - * an actual binary. Its the only way to create sub-binaries. So, what we - * need to continue processing this is to turn that into an binary erlang - * term (which can then in turn be turned into sub-binaries). - * - * We need the cmsgBufP (even though cmsgHdrP points to it) to be able - * to create sub-binaries (one for each cmsg hdr). - * - * The TArray (term array) is created with the size of 128, which should - * be enough. But if its not, then it will be automatically realloc'ed during - * add. Once we are done adding hdr's to it, we convert the tarray to a list. - */ -#ifndef __WIN32__ -static -void encode_cmsgs(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifBinary* cmsgBinP, - struct msghdr* msgHdrP, - ERL_NIF_TERM* eCMsg) -{ - ERL_NIF_TERM ctrlBuf = MKBIN(env, cmsgBinP); // The *entire* binary - SocketTArray cmsghdrs = TARRAY_CREATE(128); - struct cmsghdr* firstP = CMSG_FIRSTHDR(msgHdrP); - struct cmsghdr* currentP; - - SSDBG( descP, ("SOCKET", "encode_cmsgs {%d} -> entry when" - "\r\n msg ctrl len: %d" - "\r\n (ctrl) firstP: 0x%lX" - "\r\n", descP->sock, - msgHdrP->msg_controllen, firstP) ); - - for (currentP = firstP; - /* - * In *old* versions of darwin, the CMSG_FIRSTHDR does not - * check the msg_controllen, so we do it here. - * We should really test this stuff during configure, - * but for now, this will have to do. - */ -#if defined(__DARWIN__) - (msgHdrP->msg_controllen >= sizeof(struct cmsghdr)) && - (currentP != NULL); -#else - (currentP != NULL); -#endif - currentP = CMSG_NXTHDR(msgHdrP, currentP)) { - + done: SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> process cmsg header when" - "\r\n TArray Size: %d" - "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); - - /* MUST check this since on Linux the returned "cmsg" may actually - * go too far! - */ - if (((CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP)) > - msgHdrP->msg_controllen) { - - /* Ouch, fatal error - give up - * We assume we cannot trust any data if this is wrong. - */ - - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> check failed when: " - "\r\n currentP: 0x%lX" - "\r\n (current) cmsg_len: %d" - "\r\n firstP: 0x%lX" - "\r\n => %d" - "\r\n msg ctrl len: %d" - "\r\n", descP->sock, - CHARP(currentP), currentP->cmsg_len, CHARP(firstP), - (CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP), - msgHdrP->msg_controllen) ); - - TARRAY_ADD(cmsghdrs, esock_atom_bad_data); - break; - - } else { - unsigned char* dataP = UCHARP(CMSG_DATA(currentP)); - size_t dataPos = dataP - cmsgBinP->data; - size_t dataLen = - (UCHARP(currentP) + currentP->cmsg_len) - dataP; - ERL_NIF_TERM - cmsgHdr, - keys[] = - {esock_atom_level, - esock_atom_type, - esock_atom_data, - atom_value}, - vals[NUM(keys)]; - size_t numKeys = NUM(keys); - BOOLEAN_T have_value; - - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> cmsg header data: " - "\r\n dataPos: %d" - "\r\n dataLen: %d" - "\r\n", descP->sock, dataPos, dataLen) ); - - vals[0] = esock_encode_level(env, currentP->cmsg_level); - vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); - have_value = - encode_cmsg(env, - currentP->cmsg_level, - currentP->cmsg_type, - dataP, dataLen, &vals[1], &vals[3]); + ("SOCKET", "encode_msg_flags {%d} -> flags processed when" + "\r\n TArray size: %d" + "\r\n", descP->sock, TARRAY_SZ(ta)) ); - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> " - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n", descP->sock, - keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); - if (have_value) - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> " - "\r\n %T: %T" - "\r\n", descP->sock, keys[3], vals[3]) ); - - /* Guard against cut-and-paste errors */ - ESOCK_ASSERT( numKeys == NUM(vals) ); - ESOCK_ASSERT( MKMA(env, keys, vals, - numKeys - (have_value ? 0 : 1), &cmsgHdr) ); - - /* And finally add it to the list... */ - TARRAY_ADD(cmsghdrs, cmsgHdr); - } + TARRAY_TOLIST(ta, env, flags); } - - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> cmsg headers processed when" - "\r\n TArray Size: %d" - "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); - - /* The tarray is populated - convert it to a list */ - TARRAY_TOLIST(cmsghdrs, env, eCMsg); } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ #ifdef SCM_TIMESTAMP static BOOLEAN_T esock_cmsg_encode_timeval(ErlNifEnv *env, @@ -16748,17 +10270,15 @@ static BOOLEAN_T esock_cmsg_decode_timeval(ErlNifEnv *env, if (! esock_decode_timeval(env, eValue, &time)) return FALSE; - if ((timeP = init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL) + if ((timeP = esock_init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL) return FALSE; *timeP = time; return TRUE; } #endif -#endif -#ifndef __WIN32__ #if defined(IP_TOS) || defined(IP_RECVTOS) static BOOLEAN_T esock_cmsg_encode_ip_tos(ErlNifEnv *env, @@ -16788,16 +10308,15 @@ static BOOLEAN_T esock_cmsg_decode_ip_tos(ErlNifEnv *env, if (! decode_ip_tos(env, eValue, &tos)) return FALSE; - if ((tosP = init_cmsghdr(cmsgP, rem, sizeof(*tosP), usedP)) == NULL) + if ((tosP = esock_init_cmsghdr(cmsgP, rem, sizeof(*tosP), usedP)) == NULL) return FALSE; *tosP = tos; return TRUE; } #endif // #ifdef IP_TOS -#endif // #ifdef __WIN32__ -#ifndef __WIN32__ + #if defined(IP_TTL) || \ defined(IPV6_HOPLIMIT) || \ defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS) @@ -16816,50 +10335,50 @@ BOOLEAN_T esock_cmsg_encode_int(ErlNifEnv *env, return TRUE; } -static BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) +extern +BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP) { int value, *valueP; if (! GET_INT(env, eValue, &value)) return FALSE; - if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL) + valueP = esock_init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP); + if (valueP == NULL) return FALSE; *valueP = value; return TRUE; } #endif -#endif -#ifndef __WIN32__ -static BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) +extern +BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP) { BOOLEAN_T v; - int *valueP; + int* valueP; if (! esock_decode_bool(eValue, &v)) return FALSE; - if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL) + if ((valueP = esock_init_cmsghdr(cmsgP, rem, + sizeof(*valueP), usedP)) == NULL) return FALSE; *valueP = v? 1 : 0; return TRUE; } -#endif -#ifndef __WIN32__ #ifdef IP_RECVTTL static BOOLEAN_T esock_cmsg_encode_uchar(ErlNifEnv *env, @@ -16876,15 +10395,15 @@ BOOLEAN_T esock_cmsg_encode_uchar(ErlNifEnv *env, return TRUE; } #endif -#endif -#ifndef __WIN32__ + #ifdef IP_PKTINFO static BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env, unsigned char *data, size_t dataLen, - ERL_NIF_TERM *eResult) { + ERL_NIF_TERM *eResult) +{ struct in_pktinfo* pktInfoP = (struct in_pktinfo*) data; ERL_NIF_TERM ifIndex; ERL_NIF_TERM specDst, addr; @@ -16893,14 +10412,23 @@ BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env, return FALSE; ifIndex = MKUI(env, pktInfoP->ipi_ifindex); +#ifndef __WIN32__ + /* On Windows, the field ipi_spec_dst does not exist */ esock_encode_in_addr(env, &pktInfoP->ipi_spec_dst, &specDst); +#endif esock_encode_in_addr(env, &pktInfoP->ipi_addr, &addr); { ERL_NIF_TERM keys[] = {esock_atom_ifindex, esock_atom_spec_dst, esock_atom_addr}; - ERL_NIF_TERM vals[] = {ifIndex, specDst, addr}; + ERL_NIF_TERM vals[] = {ifIndex, +#ifndef __WIN32__ + specDst, +#else + esock_atom_undefined, +#endif + addr}; unsigned int numKeys = NUM(keys); unsigned int numVals = NUM(vals); @@ -16910,7 +10438,7 @@ BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env, return TRUE; } #endif -#endif + #ifndef __WIN32__ #ifdef IP_ORIGDSTADDR @@ -16933,6 +10461,7 @@ BOOLEAN_T esock_cmsg_encode_sockaddr(ErlNifEnv *env, #endif #endif + #ifndef __WIN32__ #ifdef HAVE_LINUX_ERRQUEUE_H #if defined(IP_RECVERR) || defined(IPV6_RECVERR) @@ -17196,7 +10725,6 @@ BOOLEAN_T esock_cmsg_encode_recverr(ErlNifEnv *env, #endif // #ifdef HAVE_LINUX_ERRQUEUE_H #endif // #ifndef __WIN32__ -#ifndef __WIN32__ #ifdef IPV6_PKTINFO static BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env, @@ -17222,37 +10750,24 @@ BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env, return TRUE; } #endif -#endif - -#ifndef __WIN32__ - -struct ESockCmsgSpec { - int type; // Message type - - // Function to encode into erlang term - BOOLEAN_T (* encode) - (ErlNifEnv *env, unsigned char *data, size_t dataLen, - ERL_NIF_TERM *eResult); - - // Function to decode from erlang term - BOOLEAN_T (* decode) - (ErlNifEnv *env, ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, size_t rem, size_t *usedP); - - ERL_NIF_TERM *nameP; // Pointer to option name atom -}; static int cmpESockCmsgSpec(const void *vpa, const void *vpb) { - struct ESockCmsgSpec *a, *b; - a = (struct ESockCmsgSpec *) vpa; - b = (struct ESockCmsgSpec *) vpb; + ESockCmsgSpec *a, *b; + a = (ESockCmsgSpec *) vpa; + b = (ESockCmsgSpec *) vpb; return COMPARE(*(a->nameP), *(b->nameP)); } -static struct ESockCmsgSpec - cmsgLevelSocket[] = + +#if defined(SCM_CREDENTIALS) || defined(SCM_RIGHTS) || defined(SCM_TIMESTAMP) +#define HAVE_ESOCK_CMSG_SOCKET +#endif + + +#if defined(HAVE_ESOCK_CMSG_SOCKET) +static ESockCmsgSpec cmsgLevelSocket[] = { #if defined(SCM_CREDENTIALS) {SCM_CREDENTIALS, NULL, NULL, @@ -17272,9 +10787,10 @@ static struct ESockCmsgSpec &esock_cmsg_encode_timeval, esock_cmsg_decode_timeval, &esock_atom_timestamp}, #endif - }, + }; +#endif - cmsgLevelIP[] = +static ESockCmsgSpec cmsgLevelIP[] = { #if defined(IP_TOS) {IP_TOS, esock_cmsg_encode_ip_tos, esock_cmsg_decode_ip_tos, @@ -17319,7 +10835,7 @@ static struct ESockCmsgSpec }; #ifdef HAVE_IPV6 -static struct ESockCmsgSpec cmsgLevelIPv6[] = +static ESockCmsgSpec cmsgLevelIPv6[] = { #if defined(IPV6_PKTINFO) {IPV6_PKTINFO, esock_cmsg_encode_in6_pktinfo, NULL, @@ -17354,35 +10870,52 @@ static struct ESockCmsgSpec cmsgLevelIPv6[] = }; #endif // #ifdef HAVE_IPV6 -static void initCmsgTables(void) { +static void initCmsgTables(void) +{ +#if defined(HAVE_ESOCK_CMSG_SOCKET) ESOCK_SORT_TABLE(cmsgLevelSocket, cmpESockCmsgSpec); - ESOCK_SORT_TABLE(cmsgLevelIP, cmpESockCmsgSpec); +#endif + + ESOCK_SORT_TABLE(cmsgLevelIP, cmpESockCmsgSpec); + #ifdef HAVE_IPV6 - ESOCK_SORT_TABLE(cmsgLevelIPv6, cmpESockCmsgSpec); + ESOCK_SORT_TABLE(cmsgLevelIPv6, cmpESockCmsgSpec); #endif } -static struct ESockCmsgSpec *lookupCmsgTable(int level, size_t *num) { +extern +ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num) +{ switch (level) { +#if defined(HAVE_ESOCK_CMSG_SOCKET) case SOL_SOCKET: *num = NUM(cmsgLevelSocket); return cmsgLevelSocket; +#endif +#ifndef __WIN32__ #ifdef SOL_IP case SOL_IP: #else case IPPROTO_IP: #endif +#else + case IPPROTO_IP: +#endif *num = NUM(cmsgLevelIP); return cmsgLevelIP; #ifdef HAVE_IPV6 +#ifndef __WIN32__ #ifdef SOL_IPV6 case SOL_IPV6: #else case IPPROTO_IPV6: #endif +#else + case IPPROTO_IPV6: +#endif *num = NUM(cmsgLevelIPv6); return cmsgLevelIPv6; #endif @@ -17392,477 +10925,44 @@ static struct ESockCmsgSpec *lookupCmsgTable(int level, size_t *num) { } } -static struct ESockCmsgSpec *lookupCmsgSpec(struct ESockCmsgSpec *table, - size_t num, - ERL_NIF_TERM eType) { - struct ESockCmsgSpec key; +extern +ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType) +{ + ESockCmsgSpec key; sys_memzero(CHARP(&key), sizeof(key)); key.nameP = &eType; return bsearch(&key, table, num, sizeof(*table), cmpESockCmsgSpec); } -#endif // #ifdef __WIN32__ - - - -#ifndef __WIN32__ -static -BOOLEAN_T encode_cmsg(ErlNifEnv* env, - int level, - int type, - unsigned char* dataP, - size_t dataLen, - ERL_NIF_TERM* eType, - ERL_NIF_TERM* eData) { - const struct ESockCmsgSpec *cmsgTable; - size_t num; - - if ((cmsgTable = lookupCmsgTable(level, &num)) != NULL) { - size_t n; - - /* Linear search for type number in level table - */ - for (n = 0; n < num; n++) { - if (cmsgTable[n].type == type) { - /* Found the type number in the level table; - * return the symbolic type (atom) - * and try to encode the data - */ - - *eType = *cmsgTable[n].nameP; - - if (cmsgTable[n].encode != NULL) - return cmsgTable[n].encode(env, dataP, dataLen, eData); - else - return FALSE; - } - } - } - /* No level table, or unknown type number in the table; - * just return the type number as an erlang integer - */ - - - *eType = MKI(env, type); - return FALSE; -} -#endif - - -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eValue, - char* bufP, - size_t rem, - size_t* usedP) -{ - int type; - struct cmsghdr *cmsgP = (struct cmsghdr *) bufP; - struct ESockCmsgSpec *cmsgTable; - struct ESockCmsgSpec *cmsgSpecP = NULL; - size_t num = 0; - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> entry \r\n" - " eType: %T\r\n" - " eValue: %T\r\n", - descP->sock, eType, eValue) ); - - // We have decode functions only for symbolic (atom) types - if (! IS_ATOM(env, eType)) { - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " eType not an atom\r\n", - descP->sock) ); - return FALSE; - } - - /* Try to look up the symbolic type - */ - if (((cmsgTable = lookupCmsgTable(level, &num)) == NULL) || - ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL) || - (cmsgSpecP->decode == NULL)) { - /* We found no table for this level, - * we found no symbolic type in the level table, - * or no decode function for this type - */ - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " cmsgTable: %p\r\n" - " cmsgSpecP: %p\r\n", - descP->sock, cmsgTable, cmsgSpecP) ); - return FALSE; - } - - if (! cmsgSpecP->decode(env, eValue, cmsgP, rem, usedP)) { - // Decode function failed - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " decode function failed\r\n", - descP->sock) ); - return FALSE; - } - - // Successful decode - - type = cmsgSpecP->type; - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> TRUE:\r\n" - " level: %d\r\n" - " type: %d\r\n", - " *usedP: %lu\r\n", - descP->sock, level, type, (unsigned long) *usedP) ); - - cmsgP->cmsg_level = level; - cmsgP->cmsg_type = type; - return TRUE; -} -#endif - -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eData, - char* bufP, - size_t rem, - size_t* usedP) -{ - int type; - ErlNifBinary bin; - struct cmsghdr *cmsgP = (struct cmsghdr *) bufP; - struct ESockCmsgSpec *cmsgSpecP = NULL; - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> entry \r\n" - " eType: %T\r\n" - " eData: %T\r\n", - descP->sock, eType, eData) ); - - // Decode Type - if (! GET_INT(env, eType, &type)) { - struct ESockCmsgSpec *cmsgTable = NULL; - size_t num = 0; - - /* Try to look up the symbolic (atom) type - */ - if ((! IS_ATOM(env, eType)) || - ((cmsgTable = lookupCmsgTable(level, &num)) == NULL) || - ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL)) { - /* Type was not an atom, - * we found no table for this level, - * or we found no symbolic type in the level table - */ - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE:\r\n" - " cmsgTable: %p\r\n" - " cmsgSpecP: %p\r\n", - descP->sock, cmsgTable, cmsgSpecP) ); - return FALSE; - } - - type = cmsgSpecP->type; - } - - // Decode Data - if (GET_BIN(env, eData, &bin)) { - void *p; - - p = init_cmsghdr(cmsgP, rem, bin.size, usedP); - if (p == NULL) { - /* No room for the data - */ - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE:\r\n" - " rem: %lu\r\n" - " bin.size: %lu\r\n", - descP->sock, - (unsigned long) rem, - (unsigned long) bin.size) ); - return FALSE; - } - - // Copy the binary data - sys_memcpy(p, bin.data, bin.size); - - } else if ((! esock_cmsg_decode_int(env, eData, cmsgP, rem, usedP)) && - (! esock_cmsg_decode_bool(env, eData, cmsgP, rem, usedP))) { - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE\r\n", - descP->sock) ); - return FALSE; - } - // Successful decode - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> TRUE:\r\n" - " level: %d\r\n" - " type: %d\r\n" - " *usedP: %lu\r\n", - descP->sock, level, type, (unsigned long) *usedP) ); - - cmsgP->cmsg_level = level; - cmsgP->cmsg_type = type; - return TRUE; -} -#endif /* Clear the CMSG space and init the ->cmsg_len member, * return the position for the data, and the total used space */ -#ifndef __WIN32__ -static void *init_cmsghdr(struct cmsghdr *cmsgP, - size_t rem, // Remaining space - size_t size, // Size of data - size_t *usedP) +extern +void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, // Remaining space + size_t size, // Size of data + size_t* usedP) { - size_t space = CMSG_SPACE(size); + size_t space = ESOCK_CMSG_SPACE(size); + void* dataP; if (rem < space) return NULL; // Not enough space sys_memzero(cmsgP, space); - cmsgP->cmsg_len = CMSG_LEN(size); + cmsgP->cmsg_len = ESOCK_CMSG_LEN(size); *usedP = space; - return CMSG_DATA(cmsgP); -} -#endif - - -/* +++ decode_cmsghdrs +++ - * - * Decode a list of cmsg(). There can be 0 or more "blocks". - * - * Each element can either be a (erlang) map that needs to be decoded, - * or a (erlang) binary that just needs to be appended to the control - * buffer. - * - * Our "problem" is that we have no idea much memory we actually need. - * - */ -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* cmsgHdrBufP, - size_t cmsgHdrBufLen, - size_t* cmsgHdrBufUsed) -{ - ERL_NIF_TERM elem, tail, list; - char* bufP; - size_t rem, used, totUsed = 0; - unsigned int len; - int i; - - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> entry with" - "\r\n eCMsg: %T" - "\r\n cmsgHdrBufP: 0x%lX" - "\r\n cmsgHdrBufLen: %d" - "\r\n", descP->sock, - eCMsg, cmsgHdrBufP, cmsgHdrBufLen) ); - - if (! GET_LIST_LEN(env, eCMsg, &len)) - return FALSE; - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdrs {%d} -> list length: %d\r\n", - descP->sock, len) ); - - for (i = 0, list = eCMsg, rem = cmsgHdrBufLen, bufP = cmsgHdrBufP; - i < len; i++) { - - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> process elem %d:" - "\r\n (buffer) rem: %u" - "\r\n (buffer) totUsed: %u" - "\r\n", descP->sock, i, rem, totUsed) ); - - /* Extract the (current) head of the (cmsg hdr) list */ - if (! GET_LIST_ELEM(env, list, &elem, &tail)) - return FALSE; - - used = 0; // Just in case... - if (! decode_cmsghdr(env, descP, elem, bufP, rem, &used)) - return FALSE; - - bufP = CHARP( ULONG(bufP) + used ); - rem = SZT( rem - used ); - list = tail; - totUsed += used; - - } - - *cmsgHdrBufUsed = totUsed; - - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> done" - "\r\n all %u ctrl headers processed" - "\r\n totUsed = %lu\r\n", - descP->sock, len, (unsigned long) totUsed) ); - - return TRUE; -} -#endif // #ifndef __WIN32__ - - -/* +++ decode_cmsghdr +++ - * - * Decode one cmsg(). Put the "result" into the buffer and advance the - * pointer (of the buffer) afterwards. Also update 'rem' accordingly. - * But before the actual decode, make sure that there is enough room in - * the buffer for the cmsg header (sizeof(*hdr) < rem). - * - * The eCMsg should be a map with three fields: - * - * level :: socket | protocol() | integer() - * type :: atom() | integer() - * What values are valid depend on the level - * data :: binary() | integer() | boolean() - * The type of the data depends on - * or level and type, but can be a binary, - * which means that the data is already coded. - * value :: term() Which is a term matching the decode function - */ -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* bufP, - size_t rem, - size_t* used) -{ - ERL_NIF_TERM eLevel, eType, eData, eValue; - int level; - - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> entry with" - "\r\n eCMsg: %T" - "\r\n", descP->sock, eCMsg) ); - - // Get 'level' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_level, &eLevel)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eLevel: %T" - "\r\n", descP->sock, eLevel) ); - - // Get 'type' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_type, &eType)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eType: %T" - "\r\n", descP->sock, eType) ); - - // Decode Level - if (! esock_decode_level(env, eLevel, &level)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> level: %d\r\n", - descP->sock, level) ); - - // Get 'data' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_data, &eData)) { - - // Get 'value' field - if (! GET_MAP_VAL(env, eCMsg, atom_value, &eValue)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eValue: %T" - "\r\n", descP->sock, eValue) ); - - // Decode Value - if (! decode_cmsghdr_value(env, descP, level, eType, eValue, - bufP, rem, used)) - return FALSE; - - } else { + dataP = ESOCK_CMSG_DATA(cmsgP); - // Verify no 'value' field - if (GET_MAP_VAL(env, eCMsg, atom_value, &eValue)) - return FALSE; - - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eData: %T" - "\r\n", descP->sock, eData) ); - - // Decode Data - if (! decode_cmsghdr_data(env, descP, level, eType, eData, - bufP, rem, used)) - return FALSE; - } - - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> used: %lu\r\n", - descP->sock, (unsigned long) *used) ); - - return TRUE; -} -#endif // #ifndef __WIN32__ - - - -/* +++ encode_msg_flags +++ - * - * Encode a list of msg_flag(). - * - */ -#ifndef __WIN32__ -static -void encode_msg_flags(ErlNifEnv* env, - ESockDescriptor* descP, - int msgFlags, - ERL_NIF_TERM* flags) -{ - SSDBG( descP, - ("SOCKET", "encode_msg_flags {%d} -> entry with" - "\r\n msgFlags: %d (0x%lX)" - "\r\n", descP->sock, msgFlags, msgFlags) ); - - if (msgFlags == 0) { - *flags = MKEL(env); - } else { - size_t n; - SocketTArray ta = TARRAY_CREATE(10); // Just to be on the safe side - - for (n = 0; n < NUM(msg_flags); n++) { - int f = msg_flags[n].flag; - if ((f != 0) && ((msgFlags & f) == f)) { - msgFlags &= ~f; - TARRAY_ADD(ta, *(msg_flags[n].name)); - } - if (msgFlags == 0) goto done; - } - /* Append remaining flags as an integer */ - if (msgFlags != 0) - TARRAY_ADD(ta, MKI(env, msgFlags)); - - done: - SSDBG( descP, - ("SOCKET", "encode_msg_flags {%d} -> flags processed when" - "\r\n TArray size: %d" - "\r\n", descP->sock, TARRAY_SZ(ta)) ); - - TARRAY_TOLIST(ta, env, flags); - } + return dataP; } -#endif // #ifndef __WIN32__ /* +++ decode the ip socket option TOS +++ @@ -17874,8 +10974,10 @@ void encode_msg_flags(ErlNifEnv* env, * * lowdelay | throughput | reliability | mincost * + * + * For Windows, the Microsoft recommendation is: *Do not use* */ -#ifndef __WIN32__ + #if defined(IP_TOS) static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) @@ -17884,6 +10986,14 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) if (IS_ATOM(env, eVal)) { +#ifdef __WIN32__ + + /* See above */ + *val = -1; + result = FALSE; + +#else + if (COMPARE(eVal, esock_atom_lowdelay) == 0) { *val = IPTOS_LOWDELAY; result = TRUE; @@ -17898,11 +11008,14 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) *val = IPTOS_MINCOST; result = TRUE; #endif + } else { *val = -1; result = FALSE; } +#endif // ifdef __WIN32__ + } else if (IS_NUM(env, eVal)) { if (GET_INT(env, eVal, val)) { @@ -17920,7 +11033,7 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return result; } #endif -#endif // #ifndef __WIN32__ + /* +++ decode the ip socket option MTU_DISCOVER +++ @@ -17932,20 +11045,23 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) * * want | dont | do | probe * + * Note that on Windows, the 'want' value seems to not exist! */ -#ifndef __WIN32__ + #if defined(IP_MTU_DISCOVER) static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) { if (IS_ATOM(env, eVal)) { - if (COMPARE(eVal, atom_want) == 0) { - *val = IP_PMTUDISC_WANT; - } else if (COMPARE(eVal, atom_dont) == 0) { + if (COMPARE(eVal, atom_dont) == 0) { *val = IP_PMTUDISC_DONT; } else if (COMPARE(eVal, atom_do) == 0) { *val = IP_PMTUDISC_DO; +#if defined(IP_PMTUDISC_WANT) + } else if (COMPARE(eVal, atom_want) == 0) { + *val = IP_PMTUDISC_WANT; +#endif #if defined(IP_PMTUDISC_PROBE) } else if (COMPARE(eVal, atom_probe) == 0) { *val = IP_PMTUDISC_PROBE; @@ -17961,10 +11077,8 @@ BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return TRUE; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) static BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { @@ -17984,7 +11098,6 @@ BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { return TRUE; } #endif -#endif // #ifndef __WIN32__ /* +++ decode the ipv6 socket option MTU_DISCOVER +++ @@ -17996,20 +11109,33 @@ BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { * * want | dont | do | probe * + * Use same as IP on Windows!! */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) { if (IS_ATOM(env, eVal)) { - if (COMPARE(eVal, atom_want) == 0) { - *val = IPV6_PMTUDISC_WANT; - } else if (COMPARE(eVal, atom_dont) == 0) { +#ifdef __WIN32__ + /* On Windows, the IP-flags are used */ + if (COMPARE(eVal, atom_dont) == 0) { + *val = IP_PMTUDISC_DONT; + } else if (COMPARE(eVal, atom_do) == 0) { + *val = IP_PMTUDISC_DO; + } else if (COMPARE(eVal, atom_probe) == 0) { + *val = IP_PMTUDISC_PROBE; + } else { + return FALSE; + } +#else + if (COMPARE(eVal, atom_dont) == 0) { *val = IPV6_PMTUDISC_DONT; } else if (COMPARE(eVal, atom_do) == 0) { *val = IPV6_PMTUDISC_DO; + } else if (COMPARE(eVal, atom_want) == 0) { + *val = IPV6_PMTUDISC_WANT; #if defined(IPV6_PMTUDISC_PROBE) } else if (COMPARE(eVal, atom_probe) == 0) { *val = IPV6_PMTUDISC_PROBE; @@ -18017,6 +11143,7 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) } else { return FALSE; } +#endif } else if (! GET_INT(env, eVal, val)) { return FALSE; @@ -18025,7 +11152,6 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return TRUE; } #endif -#endif // #ifndef __WIN32__ /* +++ encode the ip socket option MTU_DISCOVER +++ @@ -18038,15 +11164,17 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) * want | dont | do | probe * */ -#ifndef __WIN32__ + #if defined(IP_MTU_DISCOVER) static void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) { switch (val) { +#if defined(IP_PMTUDISC_WANT) case IP_PMTUDISC_WANT: *eVal = atom_want; break; +#endif case IP_PMTUDISC_DONT: *eVal = atom_dont; @@ -18070,7 +11198,6 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) return; } #endif -#endif // #ifndef __WIN32__ /* +++ encode the ipv6 socket option MTU_DISCOVER +++ @@ -18082,30 +11209,47 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) * * want | dont | do | probe * + * Windows uses the IP-flags. */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) { switch (val) { +#if defined(IPV6_PMTUDISC_WANT) case IPV6_PMTUDISC_WANT: *eVal = atom_want; break; +#endif +#if defined(__WIN32__) + case IP_PMTUDISC_DONT: +#else case IPV6_PMTUDISC_DONT: +#endif *eVal = atom_dont; break; +#if defined(__WIN32__) + case IP_PMTUDISC_DO: +#else case IPV6_PMTUDISC_DO: +#endif *eVal = atom_do; break; +#if defined(__WIN32__) + case IP_PMTUDISC_PROBE: + *eVal = atom_probe; + break; +#else #if defined(IPV6_PMTUDISC_PROBE) case IPV6_PMTUDISC_PROBE: *eVal = atom_probe; break; #endif +#endif default: *eVal = MKI(env, val); @@ -18115,7 +11259,7 @@ void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) return; } #endif -#endif // #ifndef __WIN32__ + /* +++ encode the ip socket option tos +++ @@ -18124,24 +11268,30 @@ void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) * lowdelay | throughput | reliability | mincost | integer() * */ -#ifndef __WIN32__ + static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val) { ERL_NIF_TERM result; switch (IPTOS_TOS(val)) { +#if defined(IPTOS_LOWDELAY) case IPTOS_LOWDELAY: result = esock_atom_lowdelay; break; +#endif +#if defined(IPTOS_THROUGHPUT) case IPTOS_THROUGHPUT: result = esock_atom_throughput; break; +#endif +#if defined(IPTOS_RELIABILITY) case IPTOS_RELIABILITY: result = esock_atom_reliability; break; +#endif #if defined(IPTOS_MINCOST) case IPTOS_MINCOST: @@ -18156,10 +11306,9 @@ ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val) return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) static @@ -18203,20 +11352,19 @@ ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, sctp_assoc_t val) } #endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) -#endif // #ifdef __WIN32__ -/* *** alloc_descriptor *** + +/* *** esock_alloc_descriptor *** * * Allocate and perform basic initialization of a socket descriptor. * */ -#ifndef __WIN32__ -static -ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) +extern +ESockDescriptor* esock_alloc_descriptor(SOCKET sock) { ESockDescriptor* descP; - char buf[64]; /* Buffer used for building the mutex name */ + char buf[64]; /* Buffer used for building the mutex name(s) */ ESOCK_ASSERT( (descP = enif_alloc_resource(esocks, sizeof(ESockDescriptor))) @@ -18224,14 +11372,17 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->pattern = ESOCK_DESC_PATTERN_CREATED; - requestor_init(&descP->connector); + esock_requestor_init(&descP->connector); descP->connectorP = NULL; - sprintf(buf, "esock.w[%d]", sock); + sprintf(buf, "esock.w[" SOCKET_FORMAT_STR "]", sock); descP->writeMtx = MCREATE(buf); descP->writeState = 0; - requestor_init(&descP->currentWriter); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentWriter); descP->currentWriterP = NULL; // currentWriter not used +#endif descP->writersQ.first = NULL; descP->writersQ.last = NULL; @@ -18248,11 +11399,14 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->sendfileCountersP = NULL; #endif - sprintf(buf, "esock.r[%d]", sock); + sprintf(buf, "esock.r[" SOCKET_FORMAT_STR "]", sock); descP->readMtx = MCREATE(buf); descP->readState = 0; - requestor_init(&descP->currentReader); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentReader); descP->currentReaderP = NULL; // currentReader not used +#endif descP->readersQ.first = NULL; descP->readersQ.last = NULL; @@ -18264,9 +11418,12 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->readWaits = 0; descP->readFails = 0; - sprintf(buf, "esock.acc[%d]", sock); - requestor_init(&descP->currentAcceptor); + sprintf(buf, "esock.acc[" SOCKET_FORMAT_STR "]", sock); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentAcceptor); descP->currentAcceptorP = NULL; // currentAcceptor not used +#endif descP->acceptorsQ.first = NULL; descP->acceptorsQ.last = NULL; descP->accSuccess = 0; @@ -18274,130 +11431,162 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->accTries = 0; descP->accWaits = 0; - sprintf(buf, "esock.close[%d]", sock); + sprintf(buf, "esock.close[" SOCKET_FORMAT_STR "]", sock); descP->closeEnv = NULL; descP->closeRef = esock_atom_undefined; enif_set_pid_undefined(&descP->closerPid); MON_INIT(&descP->closerMon); - sprintf(buf, "esock.cfg[%d]", sock); + sprintf(buf, "esock.cfg[" SOCKET_FORMAT_STR "]", sock); descP->rBufSz = ESOCK_RECV_BUFFER_SIZE_DEFAULT; +#ifndef __WIN32__ descP->rNum = ESOCK_RECV_BUFFER_COUNT_DEFAULT; descP->rNumCnt = 0; +#endif descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT; descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT; descP->iow = FALSE; - descP->dbg = ESOCK_DEBUG_DEFAULT; // Overwritten by caller - descP->useReg = ESOCK_USE_SOCKET_REGISTRY; // Overwritten by caller - descP->meta.env = esock_alloc_env("alloc_descriptor - " + descP->dbg = ESOCK_DEBUG_DEFAULT; // Overwritten by caller + descP->useReg = ESOCK_USE_SOCKET_REGISTRY;// Overwritten by caller + descP->meta.env = esock_alloc_env("esock_alloc_descriptor - " "meta-env"); descP->meta.ref = esock_atom_undefined; descP->sock = sock; - descP->event = event; descP->origFD = INVALID_SOCKET; descP->closeOnClose = TRUE; enif_set_pid_undefined(&descP->ctrlPid); MON_INIT(&descP->ctrlMon); +#if defined(ESOCK_DESCRIPTOR_FILLER) + sys_memzero(descP->filler, sizeof(descP->filler)); +#endif + return descP; } -#endif // #ifndef __WIN32__ + + +/* This function is *only* called during 'open' after an + * descriptor has been allocated but before it has been used. + */ +extern +void esock_dealloc_descriptor(ErlNifEnv* env, + ESockDescriptor* descP) +{ + if (descP->writeMtx != NULL) { + MDESTROY(descP->writeMtx); + descP->writeMtx = NULL; + } + + if (descP->readMtx != NULL) { + MDESTROY(descP->readMtx); + descP->readMtx = NULL; + } + + if (descP->closeEnv != NULL) { + esock_free_env("dealloc descriptor", descP->closeEnv); + descP->closeEnv = NULL; + } + + if (descP->meta.env != NULL) { + esock_free_env("dealloc descriptor", descP->meta.env); + descP->meta.env = NULL; + } + +} + + /* Decrement counters for when a socket is closed */ -#ifndef __WIN32__ -static -void dec_socket(int domain, int type, int protocol) +extern +void esock_dec_socket(int domain, int type, int protocol) { MLOCK(data.cntMtx); - cnt_dec(&data.numSockets, 1); + esock_cnt_dec(&data.numSockets, 1); /* *** Domain counter *** */ if (domain == AF_INET) - cnt_dec(&data.numDomainInet, 1); + esock_cnt_dec(&data.numDomainInet, 1); #if defined(HAVE_IN6) && defined(AF_INET6) else if (domain == AF_INET6) - cnt_dec(&data.numDomainInet6, 1); + esock_cnt_dec(&data.numDomainInet6, 1); #endif -#ifdef HAS_AF_LOCAL +#if defined(HAS_AF_LOCAL) else if (domain == AF_LOCAL) - cnt_dec(&data.numDomainInet6, 1); + esock_cnt_dec(&data.numDomainInet6, 1); #endif /* *** Type counter *** */ if (type == SOCK_STREAM) - cnt_dec(&data.numTypeStreams, 1); + esock_cnt_dec(&data.numTypeStreams, 1); else if (type == SOCK_DGRAM) - cnt_dec(&data.numTypeDGrams, 1); -#ifdef SOCK_SEQPACKET + esock_cnt_dec(&data.numTypeDGrams, 1); +#if defined(SOCK_SEQPACKET) else if (type == SOCK_SEQPACKET) - cnt_dec(&data.numTypeSeqPkgs, 1); + esock_cnt_dec(&data.numTypeSeqPkgs, 1); #endif /* *** Protocol counter *** */ if (protocol == IPPROTO_IP) - cnt_dec(&data.numProtoIP, 1); + esock_cnt_dec(&data.numProtoIP, 1); else if (protocol == IPPROTO_TCP) - cnt_dec(&data.numProtoTCP, 1); + esock_cnt_dec(&data.numProtoTCP, 1); else if (protocol == IPPROTO_UDP) - cnt_dec(&data.numProtoUDP, 1); + esock_cnt_dec(&data.numProtoUDP, 1); #if defined(HAVE_SCTP) else if (protocol == IPPROTO_SCTP) - cnt_dec(&data.numProtoSCTP, 1); + esock_cnt_dec(&data.numProtoSCTP, 1); #endif MUNLOCK(data.cntMtx); } -#endif // #ifndef __WIN32__ /* Increment counters for when a socket is opened */ -#ifndef __WIN32__ -static -void inc_socket(int domain, int type, int protocol) +extern +void esock_inc_socket(int domain, int type, int protocol) { - cnt_inc(&data.numSockets, 1); + esock_cnt_inc(&data.numSockets, 1); /* *** Domain counter *** */ if (domain == AF_INET) - cnt_inc(&data.numDomainInet, 1); + esock_cnt_inc(&data.numDomainInet, 1); #if defined(HAVE_IN6) && defined(AF_INET6) else if (domain == AF_INET6) - cnt_inc(&data.numDomainInet6, 1); + esock_cnt_inc(&data.numDomainInet6, 1); #endif -#ifdef HAS_AF_LOCAL +#if defined(HAS_AF_LOCAL) else if (domain == AF_LOCAL) - cnt_inc(&data.numDomainInet6, 1); + esock_cnt_inc(&data.numDomainInet6, 1); #endif /* *** Type counter *** */ if (type == SOCK_STREAM) - cnt_inc(&data.numTypeStreams, 1); + esock_cnt_inc(&data.numTypeStreams, 1); else if (type == SOCK_DGRAM) - cnt_inc(&data.numTypeDGrams, 1); -#ifdef SOCK_SEQPACKET + esock_cnt_inc(&data.numTypeDGrams, 1); +#if defined(SOCK_SEQPACKET) else if (type == SOCK_SEQPACKET) - cnt_inc(&data.numTypeSeqPkgs, 1); + esock_cnt_inc(&data.numTypeSeqPkgs, 1); #endif /* *** Protocol counter *** */ if (protocol == IPPROTO_IP) - cnt_inc(&data.numProtoIP, 1); + esock_cnt_inc(&data.numProtoIP, 1); else if (protocol == IPPROTO_TCP) - cnt_inc(&data.numProtoTCP, 1); + esock_cnt_inc(&data.numProtoTCP, 1); else if (protocol == IPPROTO_UDP) - cnt_inc(&data.numProtoUDP, 1); + esock_cnt_inc(&data.numProtoUDP, 1); #if defined(HAVE_SCTP) else if (protocol == IPPROTO_SCTP) - cnt_inc(&data.numProtoSCTP, 1); + esock_cnt_inc(&data.numProtoSCTP, 1); #endif } -#endif // #ifndef __WIN32__ @@ -18406,44 +11595,10 @@ void inc_socket(int domain, int type, int protocol) * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ -#ifdef HAVE_SETNS -/* esock_open4_get_netns - extract the netns field from the opts map - */ -static -BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env, ERL_NIF_TERM opts, char** netns) -{ - ERL_NIF_TERM val; - ErlNifBinary bin; - char* buf; - - /* The currently only supported extra option is: netns */ - if (!GET_MAP_VAL(env, opts, atom_netns, &val)) { - *netns = NULL; // Just in case... - return FALSE; - } - - /* The value should be a binary file name */ - if (! enif_inspect_binary(env, val, &bin)) { - *netns = NULL; // Just in case... - return FALSE; - } - - ESOCK_ASSERT( (buf = MALLOC(bin.size+1)) != NULL ); - - sys_memcpy(buf, bin.data, bin.size); - buf[bin.size] = '\0'; - *netns = buf; - return TRUE; -} -#endif -#endif // #ifndef __WIN32__ - /* ehow2how - convert internal (erlang) "shutdown how" to * (proper) "shutdown how" */ -#ifndef __WIN32__ static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how) { @@ -18451,22 +11606,33 @@ BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how) cmp = COMPARE(ehow, atom_read_write); if (cmp == 0) +#ifdef __WIN32__ + *how = SD_BOTH; +#else *how = SHUT_RDWR; +#endif else if (cmp < 0) { if (COMPARE(ehow, atom_read) == 0) +#ifdef __WIN32__ + *how = SD_RECEIVE; +#else *how = SHUT_RD; +#endif else return FALSE; } else { if (COMPARE(ehow, atom_write) == 0) +#ifdef __WIN32__ + *how = SD_SEND; +#else *how = SHUT_WR; +#endif else return FALSE; } return TRUE; } -#endif // #ifndef __WIN32__ @@ -18501,8 +11667,7 @@ size_t my_strnlen(const char *s, size_t maxlen) * terminate otherwise, so there is no need to test if * the sending fails. */ -#ifndef __WIN32__ -static +extern void esock_send_reg_add_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef) @@ -18518,7 +11683,6 @@ void esock_send_reg_add_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &data.regPid)) ); } } -#endif // #ifndef __WIN32__ @@ -18527,8 +11691,7 @@ void esock_send_reg_add_msg(ErlNifEnv* env, * terminate otherwise, so there is no need to test if * the sending fails. */ -#ifndef __WIN32__ -static +extern void esock_send_reg_del_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef) @@ -18544,9 +11707,6 @@ void esock_send_reg_del_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &data.regPid)) ); } } -#endif // #ifndef __WIN32__ - - /* =========================================================================== @@ -18563,8 +11723,7 @@ void esock_send_reg_del_msg(ErlNifEnv* env, * * This message will only be sent if the iow (Inform On Wrap) is TRUE. */ -#ifndef __WIN32__ -static +extern void esock_send_wrap_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, @@ -18582,7 +11741,6 @@ void esock_send_wrap_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &descP->ctrlPid), cnt) ); } } -#endif // #ifndef __WIN32__ /* Send an close message to the specified process: @@ -18594,8 +11752,7 @@ void esock_send_wrap_msg(ErlNifEnv* env, * erlang API (close-) function for the socket to be "closed" * (actually that the 'stop' callback function has been called). */ -#ifndef __WIN32__ -static +extern void esock_send_close_msg(ErlNifEnv* env, ESockDescriptor* descP, ErlNifPid* pid) @@ -18615,17 +11772,20 @@ void esock_send_close_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, pid), descP->closeRef) ); } } + + + #ifdef HAVE_SENDFILE -static void -esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, - ESockDescriptor* descP) +extern +void esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, + ESockDescriptor* descP) { ERL_NIF_TERM sockRef, msg; ErlNifPid *pid; pid = &data.regPid; sockRef = enif_make_resource(env, descP); - msg = mk_reg_msg(env, atom_sendfile_deferred_close, sockRef); + msg = mk_reg_msg(env, esock_atom_sendfile_deferred_close, sockRef); /* If this send should fail we have leaked a file descriptor * (intolerable), and if we try to close it here, on a regular @@ -18636,7 +11796,6 @@ esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, ESOCK_ASSERT( esock_send_msg(env, pid, msg, NULL) ); } #endif // #ifdef HAVE_SENDFILE -#endif // #ifndef __WIN32__ /* Send an abort message to the specified process: @@ -18647,8 +11806,7 @@ esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, * This message is for processes that is waiting in the * erlang API functions for a select message. */ -#ifndef __WIN32__ -static +extern void esock_send_abort_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, @@ -18661,10 +11819,11 @@ void esock_send_abort_msg(ErlNifEnv* env, { ERL_NIF_TERM msg; - msg = - mk_abort_msg(reqP->env, - /* sockRef not in env so copy */ - CP_TERM(reqP->env, sockRef), reqP->ref, reason); + msg = mk_abort_msg(reqP->env, + /* sockRef not in env so copy */ + CP_TERM(reqP->env, sockRef), + reqP->ref, + CP_TERM(reqP->env, reason)); if (! esock_send_msg(env, &reqP->pid, msg, reqP->env)) { SSDBG( descP, @@ -18676,13 +11835,38 @@ void esock_send_abort_msg(ErlNifEnv* env, } reqP->env = NULL; } -#endif // #ifndef __WIN32__ + + +/* Send an *simple* abort message to the specified process: + * A message in the form: + * + * {'$socket', Socket, abort, Info} + * + */ +extern +void esock_send_simple_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + ERL_NIF_TERM msg = mk_simple_abort_msg(env, sockRef, reason); + + if (! esock_send_msg(env, pid, msg, NULL)) { + + SSDBG( descP, + ("SOCKET", + "esock_send_simple_abort_msg(%T) {%d} failed ->" + "\r\n pid: %T" + "\r\n", + sockRef, descP->sock, MKPID(env, pid)) ); + } +} /* Send a message to the specified process. */ -#ifndef __WIN32__ -static +extern BOOLEAN_T esock_send_msg(ErlNifEnv* env, ErlNifPid* pid, ERL_NIF_TERM msg, @@ -18693,7 +11877,6 @@ BOOLEAN_T esock_send_msg(ErlNifEnv* env, return !!res; } -#endif // #ifndef __WIN32__ @@ -18704,14 +11887,12 @@ BOOLEAN_T esock_send_msg(ErlNifEnv* env, * {'$socket', add, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef) { return mk_reg_msg(env, atom_add, sockRef); } -#endif // #ifndef __WIN32__ /* *** mk_reg_del_msg *** @@ -18721,14 +11902,12 @@ ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, * {'$socket', del, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef) { return mk_reg_msg(env, atom_del, sockRef); } -#endif // #ifndef __WIN32__ /* *** mk_reg_msg *** @@ -18739,17 +11918,31 @@ ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, * {'$socket', Tag, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, ERL_NIF_TERM tag, ERL_NIF_TERM sockRef) { - ERL_NIF_TERM socket = mk_socket(env, sockRef); + ERL_NIF_TERM socket = esock_mk_socket(env, sockRef); return MKT3(env, esock_atom_socket_tag, tag, socket); } -#endif // #ifndef __WIN32__ + + +/* *** mk_simple_abort_msg *** + * + * Create the simple abort message, which has the following form: + * + * {'$socket', Socket, abort, Info} + * + */ +static +ERL_NIF_TERM mk_simple_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + return esock_mk_socket_msg(env, sockRef, esock_atom_abort, reason); +} /* *** mk_abort_msg *** @@ -18761,7 +11954,6 @@ ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, * This message is for processes that are waiting in the * erlang API functions for a select (or this) message. */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, @@ -18770,9 +11962,8 @@ ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, { ERL_NIF_TERM info = MKT2(env, opRef, reason); - return mk_socket_msg(env, sockRef, esock_atom_abort, info); + return esock_mk_socket_msg(env, sockRef, esock_atom_abort, info); } -#endif // #ifndef __WIN32__ /* *** mk_wrap_msg *** @@ -18782,15 +11973,13 @@ ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, * {'$socket', Socket, counter_wrap, Counter} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM cnt) { - return mk_socket_msg(env, sockRef, atom_counter_wrap, cnt); + return esock_mk_socket_msg(env, sockRef, atom_counter_wrap, cnt); } -#endif // #ifndef __WIN32__ /* *** mk_close_msg *** @@ -18800,15 +11989,14 @@ ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, * {'$socket', Socket, close, closeRef} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM closeRef) { - return mk_socket_msg(env, sockRef, esock_atom_close, closeRef); + return esock_mk_socket_msg(env, sockRef, esock_atom_close, closeRef); } -#endif // #ifndef __WIN32__ + /* *** mk_select_msg *** @@ -18824,12 +12012,12 @@ ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM selectRef) { - return mk_socket_msg(env, sockRef, atom_select, selectRef); + return esock_mk_socket_msg(env, sockRef, esock_atom_select, selectRef); } #endif // #ifndef __WIN32__ -/* *** mk_socket_msg *** +/* *** esock_mk_socket_msg *** * * Construct the socket message: * @@ -18840,18 +12028,16 @@ ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, * Info :: term() * */ -#ifndef __WIN32__ -static -ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM tag, - ERL_NIF_TERM info) +extern +ERL_NIF_TERM esock_mk_socket_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM tag, + ERL_NIF_TERM info) { - ERL_NIF_TERM socket = mk_socket(env, sockRef); + ERL_NIF_TERM socket = esock_mk_socket(env, sockRef); return MKT4(env, esock_atom_socket_tag, socket, tag, info); } -#endif // #ifndef __WIN32__ /* *** mk_socket *** @@ -18860,14 +12046,12 @@ ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, * * socket:socket() :: {'$socket', SockRef :: reference()} */ -#ifndef __WIN32__ -static -ERL_NIF_TERM mk_socket(ErlNifEnv* env, - ERL_NIF_TERM sockRef) +extern +ERL_NIF_TERM esock_mk_socket(ErlNifEnv* env, + ERL_NIF_TERM sockRef) { return MKT2(env, esock_atom_socket_tag, sockRef); } -#endif // #ifndef __WIN32__ /* ---------------------------------------------------------------------- @@ -18890,7 +12074,7 @@ ERL_NIF_TERM mk_socket(ErlNifEnv* env, * We choose the second alternative. */ #ifndef __WIN32__ -static +extern int esock_select_read(ErlNifEnv* env, ErlNifEvent event, // The file descriptor void* obj, // The socket descriptor object @@ -18914,7 +12098,7 @@ int esock_select_read(ErlNifEnv* env, * so no need to do that here, but the selectRef needs to be copied. */ #ifndef __WIN32__ -static +extern int esock_select_write(ErlNifEnv* env, ErlNifEvent event, // The file descriptor void* obj, // The socket descriptor @@ -18938,8 +12122,7 @@ int esock_select_write(ErlNifEnv* env, * So readMtx and writeMtx are supposed to be locked * when this function is called. */ -#ifndef __WIN32__ -static +extern int esock_select_stop(ErlNifEnv* env, ErlNifEvent event, void* obj) @@ -18947,10 +12130,8 @@ int esock_select_stop(ErlNifEnv* env, return enif_select(env, event, (ERL_NIF_SELECT_STOP), obj, NULL, esock_atom_undefined); } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -static +extern int esock_select_cancel(ErlNifEnv* env, ErlNifEvent event, enum ErlNifSelectFlags mode, @@ -18959,7 +12140,7 @@ int esock_select_cancel(ErlNifEnv* env, return enif_select(env, event, (ERL_NIF_SELECT_CANCEL | mode), obj, NULL, esock_atom_undefined); } -#endif // #ifndef __WIN32__ + /* ---------------------------------------------------------------------- @@ -18967,9 +12148,9 @@ int esock_select_cancel(ErlNifEnv* env, * ---------------------------------------------------------------------- */ -/* *** activate_next_acceptor *** - * *** activate_next_writer *** - * *** activate_next_reader *** +/* *** esock_activate_next_acceptor *** + * *** esock_activate_next_writer *** + * *** esock_activate_next_reader *** * * This functions pops the requestors queue and then selects until it * manages to successfully activate a requestor or the queue is empty. @@ -18983,11 +12164,11 @@ int esock_select_cancel(ErlNifEnv* env, ACTIVATE_NEXT_FUNC_DECL(writer, write, currentWriter, writersQ) \ ACTIVATE_NEXT_FUNC_DECL(reader, read, currentReader, readersQ) -#define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \ - static \ - BOOLEAN_T activate_next_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM sockRef) \ +#define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \ + extern \ + BOOLEAN_T esock_activate_next_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM sockRef) \ { \ BOOLEAN_T popped, activated; \ int sres; \ @@ -18998,13 +12179,13 @@ int esock_select_cancel(ErlNifEnv* env, popped = FALSE; \ do { \ \ - if (requestor_pop(q, reqP)) { \ + if (esock_requestor_pop(q, reqP)) { \ \ /* There was another one */ \ \ SSDBG( descP, \ ("SOCKET", \ - "activate_next_" #F "(%T) {%d} ->" \ + "esock_activate_next_" #F "(%T) {%d} ->" \ " new (active) requestor: " \ "\r\n pid: %T" \ "\r\n ref: %T" \ @@ -19042,7 +12223,7 @@ int esock_select_cancel(ErlNifEnv* env, \ SSDBG( descP, \ ("SOCKET", \ - "activate_next_" #F "(%T) {%d} ->" \ + "esock_activate_next_" #F "(%T) {%d} ->" \ " no more requestors\r\n", \ sockRef, descP->sock) ); \ \ @@ -19053,7 +12234,7 @@ int esock_select_cancel(ErlNifEnv* env, } while (!popped); \ \ SSDBG( descP, \ - ("SOCKET", "activate_next_" #F "(%T) {%d} -> " \ + ("SOCKET", "esock_activate_next_" #F "(%T) {%d} -> " \ "done with %s\r\n", \ sockRef, descP->sock, B2S(activated)) ); \ \ @@ -19074,11 +12255,22 @@ ACTIVATE_NEXT_FUNCS * we make use of set of declaration macros. */ -#ifndef __WIN32__ -/* *** acceptor_search4pid *** - * *** writer_search4pid *** - * *** reader_search4pid *** +extern +void esock_free_request_queue(ESockRequestQueue* q) +{ + while (q->first) { + ESockRequestQueueElement* free_me = q->first; + q->first = free_me->nextP; + esock_free_env("dtor", free_me->data.env); + FREE(free_me); + } +} + + +/* *** esock_acceptor_search4pid *** + * *** esock_writer_search4pid *** + * *** esock_reader_search4pid *** * * Search for a pid in the requestor (acceptor, writer, or reader) queue. * @@ -19089,43 +12281,41 @@ ACTIVATE_NEXT_FUNCS REQ_SEARCH4PID_FUNC_DECL(writer, writersQ) \ REQ_SEARCH4PID_FUNC_DECL(reader, readersQ) -#define REQ_SEARCH4PID_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_search4pid(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid* pid) \ - { \ - return qsearch4pid(env, &descP->Q, pid); \ +#define REQ_SEARCH4PID_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_search4pid(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid* pid) \ + { \ + return qsearch4pid(env, &descP->Q, pid); \ } REQ_SEARCH4PID_FUNCS #undef REQ_SEARCH4PID_FUNC_DECL -#endif // #ifndef __WIN32__ -/* *** acceptor_push *** - * *** writer_push *** - * *** reader_push *** +/* *** esock_acceptor_push *** + * *** esock_writer_push *** + * *** esock_reader_push *** * * Push a requestor (acceptor, writer, or reader) onto its queue. * This happens when we already have a current request (of its type). * */ -#ifndef __WIN32__ - #define REQ_PUSH_FUNCS \ REQ_PUSH_FUNC_DECL(acceptor, acceptorsQ) \ REQ_PUSH_FUNC_DECL(writer, writersQ) \ REQ_PUSH_FUNC_DECL(reader, readersQ) #define REQ_PUSH_FUNC_DECL(F, Q) \ - static \ - void F##_push(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid pid, /* self() */ \ - ERL_NIF_TERM ref) \ + extern \ + void esock_##F##_push(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid pid, /* self() */ \ + ERL_NIF_TERM ref, \ + void* dataP) \ { \ ESockRequestQueueElement *e; \ ESockRequestor *reqP; \ @@ -19133,24 +12323,22 @@ REQ_SEARCH4PID_FUNCS ESOCK_ASSERT( (e = MALLOC(sizeof(ESockRequestQueueElement))) \ != NULL ); \ reqP = &e->data; \ - reqP->pid = pid; \ - ESOCK_ASSERT( MONP(#F "_push -> " #F " request", \ + reqP->dataP = dataP; \ + reqP->pid = pid; \ + ESOCK_ASSERT( MONP("esock_" #F "_push -> " #F " request", \ env, descP, &pid, &reqP->mon) == 0 ); \ - reqP->env = esock_alloc_env(#F "_push"); \ - reqP->ref = CP_TERM(reqP->env, ref); \ + reqP->env = esock_alloc_env("esock_" #F "_push"); \ + reqP->ref = CP_TERM(reqP->env, ref); \ \ qpush(&descP->Q, e); \ } REQ_PUSH_FUNCS #undef REQ_PUSH_FUNC_DECL -#endif // #ifndef __WIN32__ - - -/* *** acceptor_pop *** - * *** writer_pop *** - * *** reader_pop *** +/* *** esock_acceptor_pop *** + * *** esock_writer_pop *** + * *** esock_reader_pop *** * * Pop a requestor (acceptor, writer, or reader) from its queue. * @@ -19163,13 +12351,13 @@ REQ_PUSH_FUNCS REQ_POP_FUNC_DECL(writer, writersQ) \ REQ_POP_FUNC_DECL(reader, readersQ) -#define REQ_POP_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_pop(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ESockRequestor* reqP) \ - { \ - return requestor_pop(&descP->Q, reqP); \ +#define REQ_POP_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_pop(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ESockRequestor* reqP) \ + { \ + return esock_requestor_pop(&descP->Q, reqP); \ } REQ_POP_FUNCS #undef REQ_POP_FUNC_DECL @@ -19178,15 +12366,57 @@ REQ_POP_FUNCS -/* *** acceptor_unqueue *** - * *** writer_unqueue *** - * *** reader_unqueue *** +/* *** esock_acceptor_get *** + * *** esock_writer_get *** + * *** esock_reader_get *** * * Remove a requestor (acceptor, writer, or reader) from its queue. * */ -#ifndef __WIN32__ +#ifdef __WIN32__ + +#define REQ_GET_FUNCS \ + REQ_GET_FUNC_DECL(acceptor, acceptorsQ) \ + REQ_GET_FUNC_DECL(writer, writersQ) \ + REQ_GET_FUNC_DECL(reader, readersQ) + +#define REQ_GET_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_get(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP, \ + ESockRequestor* reqP) \ + { \ + ESockRequestQueueElement* elemP; \ + \ + elemP = qget(env, descP, "esock_" #F "_get ", \ + &descP->Q, refP, pidP); \ + if (elemP != NULL) { \ + reqP->pid = elemP->data.pid; \ + reqP->mon = elemP->data.mon; \ + reqP->env = elemP->data.env; \ + reqP->ref = elemP->data.ref; \ + reqP->dataP = elemP->data.dataP; \ + return TRUE; \ + } \ + return FALSE; \ + } +REQ_GET_FUNCS +#undef REQ_GET_FUNC_DECL + +#endif // #ifndef __WIN32__ + + + +/* *** esock_acceptor_unqueue *** + * *** esock_writer_unqueue *** + * *** esock_reader_unqueue *** + * + * Remove a requestor (acceptor, writer, or reader) from its queue. + * + */ #define REQ_UNQUEUE_FUNCS \ REQ_UNQUEUE_FUNC_DECL(acceptor, acceptorsQ) \ @@ -19194,11 +12424,11 @@ REQ_POP_FUNCS REQ_UNQUEUE_FUNC_DECL(reader, readersQ) #define REQ_UNQUEUE_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_unqueue(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM* refP, \ - const ErlNifPid* pidP) \ + extern \ + BOOLEAN_T esock_##F##_unqueue(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP) \ { \ return qunqueue(env, descP, "qunqueue -> waiting " #F, \ &descP->Q, refP, pidP); \ @@ -19206,63 +12436,62 @@ REQ_POP_FUNCS REQ_UNQUEUE_FUNCS #undef REQ_UNQUEUE_FUNC_DECL -#endif // #ifndef __WIN32__ - - /* *** requestor pop *** * * Pop an requestor from its queue. */ -#ifndef __WIN32__ - -static -BOOLEAN_T requestor_pop(ESockRequestQueue* q, - ESockRequestor* reqP) +extern +BOOLEAN_T esock_requestor_pop(ESockRequestQueue* q, + ESockRequestor* reqP) { ESockRequestQueueElement* e = qpop(q); esock_free_env("requestor_pop", reqP->env); if (e != NULL) { - reqP->pid = e->data.pid; - reqP->mon = e->data.mon; - reqP->env = e->data.env; - reqP->ref = e->data.ref; + reqP->pid = e->data.pid; + reqP->mon = e->data.mon; + reqP->env = e->data.env; + reqP->ref = e->data.ref; + reqP->dataP = e->data.dataP; FREE(e); return TRUE; } else { /* Queue was empty */ - requestor_init(reqP); + esock_requestor_init(reqP); return FALSE; } } -static void requestor_init(ESockRequestor* reqP) { +extern +void esock_requestor_init(ESockRequestor* reqP) +{ enif_set_pid_undefined(&reqP->pid); MON_INIT(&reqP->mon); - reqP->env = NULL; - reqP->ref = esock_atom_undefined; + reqP->env = NULL; + reqP->ref = esock_atom_undefined; + reqP->dataP = NULL; } -static void requestor_release(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* reqP) { - +extern +void esock_requestor_release(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockRequestor* reqP) +{ + reqP->dataP = NULL; enif_set_pid_undefined(&reqP->pid); (void) DEMONP(slogan, env, descP, &reqP->mon); + esock_clear_env(slogan, reqP->env); esock_free_env(slogan, reqP->env); reqP->env = NULL; reqP->ref = esock_atom_undefined; } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ static BOOLEAN_T qsearch4pid(ErlNifEnv* env, @@ -19282,6 +12511,22 @@ BOOLEAN_T qsearch4pid(ErlNifEnv* env, } static +unsigned int qlength(ESockRequestQueue* q) +{ + ESockRequestQueueElement* tmp; + unsigned int cnt = 0; + + tmp = q->first; + while (tmp != NULL) { + cnt++; + tmp = tmp->nextP; + } + + return cnt; +} + + +static void qpush(ESockRequestQueue* q, ESockRequestQueueElement* e) { @@ -19296,6 +12541,7 @@ void qpush(ESockRequestQueue* q, } } + static ESockRequestQueueElement* qpop(ESockRequestQueue* q) { @@ -19314,11 +12560,8 @@ ESockRequestQueueElement* qpop(ESockRequestQueue* q) return e; } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ static BOOLEAN_T qunqueue(ErlNifEnv* env, ESockDescriptor* descP, @@ -19327,19 +12570,40 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, ERL_NIF_TERM* refP, const ErlNifPid* pidP) { + ESockRequestQueueElement* e = qget(env, descP, slogan, q, refP, pidP); + + if (e != NULL) { + (void) DEMONP(slogan, env, descP, &e->data.mon); + esock_clear_env(slogan, e->data.env); + esock_free_env(slogan, e->data.env); + FREE(e); + + return TRUE; + } else { + return FALSE; + } +} + + +static +ESockRequestQueueElement* qget(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP) +{ ESockRequestQueueElement* e = q->first; ESockRequestQueueElement* p = NULL; - /* Check if it was one of the waiting acceptor processes */ + /* Check if it was one of the waiting requestor processes */ while (e != NULL) { if (COMPARE_PIDS(&e->data.pid, pidP) == 0) { if ((refP != NULL) && (COMPARE(e->data.ref, *refP) != 0)) - return FALSE; + return NULL; /* We have a match */ - (void) DEMONP(slogan, env, descP, &e->data.mon); - if (p != NULL) { /* Not the first, but could be the last */ if (q->last == e) { @@ -19359,10 +12623,7 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, } } - esock_free_env("qunqueue", e->data.env); - FREE(e); - - return TRUE; + return e; } /* Try next */ @@ -19370,9 +12631,8 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, e = e->nextP; } - return FALSE; + return NULL; } -#endif // #ifndef __WIN32__ @@ -19381,10 +12641,8 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ - -static -BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc) +extern +BOOLEAN_T esock_cnt_inc(ESockCounter* cnt, ESockCounter inc) { BOOLEAN_T wrap; ESockCounter max = ESOCK_COUNTER_MAX; @@ -19401,8 +12659,8 @@ BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc) return (wrap); } -static -void cnt_dec(ESockCounter* cnt, ESockCounter dec) +extern +void esock_cnt_dec(ESockCounter* cnt, ESockCounter dec) { ESockCounter current = *cnt; @@ -19414,9 +12672,6 @@ void cnt_dec(ESockCounter* cnt, ESockCounter dec) return; } -#endif // #ifndef __WIN32__ - - /* ---------------------------------------------------------------------- @@ -19424,9 +12679,7 @@ void cnt_dec(ESockCounter* cnt, ESockCounter dec) * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ - -static +extern int esock_monitor(const char* slogan, ErlNifEnv* env, ESockDescriptor* descP, @@ -19461,7 +12714,7 @@ int esock_monitor(const char* slogan, return res; } -static +extern int esock_demonitor(const char* slogan, ErlNifEnv* env, ESockDescriptor* descP, @@ -19490,13 +12743,13 @@ int esock_demonitor(const char* slogan, return res; } -static +extern void esock_monitor_init(ESockMonitor* monP) { monP->isActive = FALSE; } -static +extern ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP) { if (monP->isActive) @@ -19505,16 +12758,15 @@ ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP) return esock_atom_undefined; } -static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, - const ErlNifMonitor* mon) { +extern +BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, + const ErlNifMonitor* mon) { if (monP->isActive) return enif_compare_monitors(&monP->mon, mon) == 0; else return FALSE; } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -19523,18 +12775,6 @@ static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, */ -#ifndef __WIN32__ -static void free_request_queue(ESockRequestQueue* q) -{ - while (q->first) { - ESockRequestQueueElement* free_me = q->first; - q->first = free_me->nextP; - esock_free_env("dtor", free_me->data.env); - FREE(free_me); - } -} -#endif // #ifndef __WIN32__ - /* ========================================================================= * esock_dtor - Callback function for resource destructor * @@ -19542,79 +12782,30 @@ static void free_request_queue(ESockRequestQueue* q) static void esock_dtor(ErlNifEnv* env, void* obj) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; MLOCK(descP->readMtx); MLOCK(descP->writeMtx); - SGDBG( ("SOCKET", "dtor {%d,0x%X}\r\n", + SGDBG( ("SOCKET", "esock_dtor {%d,0x%X}\r\n", descP->sock, descP->readState | descP->writeState) ); - if (IS_SELECTED(descP)) { - /* We have used the socket in the select machinery, - * so we must have closed it properly to get here - */ - ESOCK_ASSERT( IS_CLOSED(descP->readState) ); - ESOCK_ASSERT( IS_CLOSED(descP->writeState) ); - ESOCK_ASSERT( descP->sock == INVALID_SOCKET ); - } else { - /* The socket is only opened, should be safe to close nonblocking */ - (void) sock_close(descP->sock); - descP->sock = INVALID_SOCKET; - } - - SGDBG( ("SOCKET", "dtor -> set state and pattern\r\n") ); - descP->readState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); - descP->writeState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); - descP->pattern = (ESOCK_DESC_PATTERN_DTOR | ESOCK_STATE_CLOSED); - - esock_free_env("dtor reader", descP->currentReader.env); - descP->currentReader.env = NULL; - - esock_free_env("dtor writer", descP->currentWriter.env); - descP->currentWriter.env = NULL; - - esock_free_env("dtor acceptor", descP->currentAcceptor.env); - descP->currentAcceptor.env = NULL; - - SGDBG( ("SOCKET", "dtor -> try free readers request queue\r\n") ); - free_request_queue(&descP->readersQ); - - SGDBG( ("SOCKET", "dtor -> try free writers request queue\r\n") ); - free_request_queue(&descP->writersQ); - - SGDBG( ("SOCKET", "dtor -> try free acceptors request queue\r\n") ); - free_request_queue(&descP->acceptorsQ); - -#ifdef HAVE_SENDFILE - ESOCK_ASSERT( descP->sendfileHandle == INVALID_HANDLE ); - if (descP->sendfileCountersP != NULL) { - FREE(descP->sendfileCountersP); - descP->sendfileCountersP = NULL; - } -#endif - - esock_free_env("dtor close env", descP->closeEnv); - descP->closeEnv = NULL; - - esock_free_env("dtor meta env", descP->meta.env); - descP->meta.env = NULL; + ESOCK_IO_DTOR(env, descP); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); - SGDBG( ("SOCKET", "dtor -> try destroy read mutex\r\n") ); + SGDBG( ("SOCKET", "esock_dtor -> try destroy read mutex\r\n") ); MDESTROY(descP->readMtx); descP->readMtx = NULL; - SGDBG( ("SOCKET", "dtor -> try destroy write mutex\r\n") ); + SGDBG( ("SOCKET", "esock_dtor -> try destroy write mutex\r\n") ); MDESTROY(descP->writeMtx); descP->writeMtx = NULL; - SGDBG( ("SOCKET", "dtor -> done\r\n") ); -#endif // #ifndef __WIN32__ + SGDBG( ("SOCKET", "esock_dtor -> done\r\n") ); } + /* ========================================================================= * esock_stop - Callback function for resource stop * @@ -19633,7 +12824,6 @@ void esock_dtor(ErlNifEnv* env, void* obj) static void esock_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, int is_direct_call) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; if (is_direct_call) { @@ -19686,97 +12876,26 @@ void esock_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, int is_direct_call) (unsigned long) descP->accWaits, (unsigned long) descP->accFails) ); -#ifdef HAVE_SENDFILE - if (descP->sendfileCountersP != NULL) { - ESockSendfileCounters *cP = descP->sendfileCountersP; - - SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} ->" - "\r\nsendfileCounters:" - "\r\n cnt: %lu" - "\r\n byteCnt: %lu" - "\r\n fails: %lu" - "\r\n max: %lu" - "\r\n pkg: %lu" - "\r\n pkgMax %lu" - "\r\n tries: %lu" - "\r\n waits: %lu" - "\r\n", - descP->sock, fd, - (unsigned long) cP->cnt, - (unsigned long) cP->byteCnt, - (unsigned long) cP->fails, - (unsigned long) cP->max, - (unsigned long) cP->pkg, - (unsigned long) cP->pkgMax, - (unsigned long) cP->tries, - (unsigned long) cP->waits) ); - } -#endif + ESOCK_IO_STOP(env, descP); - /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * - * Inform waiting Closer, or close socket - * - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - if (! enif_is_pid_undefined(&descP->closerPid)) { - /* We have a waiting closer process after nif_close() - * - send message to trigger nif_finalize_close() - */ - - SSDBG( descP, - ("SOCKET", - "esock_stop {%d/%d} -> send close msg to %T\r\n", - descP->sock, fd, MKPID(env, &descP->closerPid)) ); - - esock_send_close_msg(env, descP, &descP->closerPid); - /* Message send frees closeEnv */ - descP->closeEnv = NULL; - descP->closeRef = esock_atom_undefined; - } else { - int err; - - /* We do not have a closer process - * - have to do an unclean (non blocking) close */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); - - if (err != 0) - esock_warning_msg("Failed closing socket without " - "closer process: " - "\r\n Controlling Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - descP->ctrlPid, descP->sock, - err, MKA(env, erl_errno_id(err))); - } + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} -> done\r\n", descP->sock, fd) ); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); -#endif // #ifndef __WIN32__ } -/* *** esock_stop_handle_current *** +/* *** esock_stop_handle_currentalloc_desc *** * * Handle current requestor (reader, writer or acceptor) during * socket stop. */ -#ifndef __WIN32__ -static +extern void esock_stop_handle_current(ErlNifEnv* env, const char* role, ESockDescriptor* descP, @@ -19790,12 +12909,11 @@ void esock_stop_handle_current(ErlNifEnv* env, " send abort message to current %s %T %T\r\n", descP->sock, role, reqP->pid, reqP->ref) ); - esock_send_abort_msg(env, descP, sockRef, reqP, atom_closed); + esock_send_abort_msg(env, descP, sockRef, reqP, esock_atom_closed); enif_set_pid_undefined(&reqP->pid); reqP->ref = esock_atom_undefined; } -#endif // #ifndef __WIN32__ @@ -19803,14 +12921,13 @@ void esock_stop_handle_current(ErlNifEnv* env, * nif_abort message with the specified reason to each member, * and empty the queue. */ -#ifndef __WIN32__ -static -void inform_waiting_procs(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestQueue* q, - ERL_NIF_TERM reason) +extern +void esock_inform_waiting_procs(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestQueue* q, + ERL_NIF_TERM reason) { ESockRequestQueueElement* currentP = q->first; ESockRequestQueueElement* nextP; @@ -19850,7 +12967,6 @@ void inform_waiting_procs(ErlNifEnv* env, q->first = NULL; q->last = NULL; } -#endif // #ifndef __WIN32__ /* ========================================================================= @@ -19863,7 +12979,6 @@ void esock_down(ErlNifEnv* env, const ErlNifPid* pidP, const ErlNifMonitor* monP) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; MLOCK(descP->readMtx); @@ -19877,361 +12992,37 @@ void esock_down(ErlNifEnv* env, B2S(IS_CLOSED(descP->readState)), B2S(IS_CLOSING(descP->readState))) ); - if (COMPARE_PIDS(&descP->closerPid, pidP) == 0) { - - /* The closer process went down - * - it will not call nif_finalize_close - */ - - enif_set_pid_undefined(&descP->closerPid); - - if (MON_EQ(&descP->closerMon, monP)) { - MON_INIT(&descP->closerMon); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> closer process exit\r\n", - descP->sock) ); - - } else { - // The owner is the closer so we used its monitor - - ESOCK_ASSERT( MON_EQ(&descP->ctrlMon, monP) ); - MON_INIT(&descP->ctrlMon); - enif_set_pid_undefined(&descP->ctrlPid); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> closer controlling process exit\r\n", - descP->sock) ); - } - - /* Since the closer went down there was one, - * hence esock_close() must have run or scheduled esock_stop(), - * or the socket has never been selected upon - */ - - if (descP->closeEnv == NULL) { - int err; - - /* Since there is no closeEnv, - * esock_close() did not schedule esock_stop() - * and is about to call esock_finalize_close() but died, - * or esock_stop() has run, sent close_msg to the closer - * and cleared ->closeEnv but the closer died - * - we have to do an unclean (non blocking) socket close here - */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); - if (err != 0) - esock_warning_msg("Failed closing socket for terminating " - "closer process: " - "\r\n Closer Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - MKPID(env, pidP), descP->sock, - err, MKA(env, erl_errno_id(err))); - } else { - /* Since there is a closeEnv esock_stop() has not run yet - * - when it finds that there is no closer process - * it will close the socket and ignore the close_msg - */ - esock_free_env("esock_down - close-env", descP->closeEnv); - descP->closeEnv = NULL; - descP->closeRef = esock_atom_undefined; - } - - } else if (MON_EQ(&descP->ctrlMon, monP)) { - MON_INIT(&descP->ctrlMon); - /* The owner went down */ - enif_set_pid_undefined(&descP->ctrlPid); - - if (IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> controller process exit" - "\r\n initiate close\r\n", - descP->sock) ); - - esock_down_ctrl(env, descP, pidP); - - descP->readState |= ESOCK_STATE_CLOSING; - descP->writeState |= ESOCK_STATE_CLOSING; - } else { - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> controller process exit" - "\r\n already closed or closing\r\n", - descP->sock) ); - } - - } else if (descP->connectorP != NULL && - MON_EQ(&descP->connector.mon, monP)) { - MON_INIT(&descP->connector.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> connector process exit\r\n", - descP->sock) ); - - /* connectorP is only set during connection. - * Forget all about the ongoing connection. - * We might end up connected, but the process that initiated - * the connection has died and will never know - */ - - requestor_release("esock_down->connector", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; - - } else { - ERL_NIF_TERM sockRef; - - /* check all operation queue(s): acceptor, writer and reader. - * - * Is it really any point in doing this if the socket is closed? - * - */ - - sockRef = enif_make_resource(env, descP); - - if (IS_CLOSED(descP->readState)) { - SSDBG( descP, - ("SOCKET", - "esock_down(%T) {%d} -> stray down: %T\r\n", - sockRef, descP->sock, pidP) ); - } else { - - SSDBG( descP, - ("SOCKET", - "esock_down(%T) {%d} -> other process term\r\n", - sockRef, descP->sock) ); - - if (descP->currentReaderP != NULL) - esock_down_reader(env, descP, sockRef, pidP, monP); - if (descP->currentAcceptorP != NULL) - esock_down_acceptor(env, descP, sockRef, pidP, monP); - if (descP->currentWriterP != NULL) - esock_down_writer(env, descP, sockRef, pidP, monP); - } - } + ESOCK_IO_DOWN(env, descP, pidP, monP); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); SSDBG( descP, ("SOCKET", "esock_down -> done\r\n") ); -#endif // #ifndef __WIN32__ -} - - - -/* *** esock_down_ctrl *** - * - * Stop after a downed controller - * - */ -#ifndef __WIN32__ -static -void esock_down_ctrl(ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pidP) -{ - SSDBG( descP, - ("SOCKET", "esock_down_ctrl {%d} ->" - "\r\n Pid: %T" - "\r\n", descP->sock, MKPID(env, pidP)) ); - - if (esock_do_stop(env, descP)) { - /* esock_stop() is scheduled - * - it has to close the socket - */ - SSDBG( descP, - ("SOCKET", "esock_down_ctrl {%d} -> stop was scheduled\r\n", - descP->sock) ); - } else { - int err; - - /* Socket is not in the select machinery - * so esock_stop() will not be called - * - we have to do an unclean (non blocking) socket close here - */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); - if (err != 0) - esock_warning_msg("Failed closing socket for terminating " - "owner process: " - "\r\n Owner Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - MKPID(env, pidP), descP->sock, - err, MKA(env, erl_errno_id(err))); - } } -#endif // #ifndef __WIN32__ - - - -/* *** esock_down_acceptor *** - * - * Check and then handle a downed acceptor process. - * - */ -#ifndef __WIN32__ -static -void esock_down_acceptor(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) -{ - if (MON_EQ(&descP->currentAcceptor.mon, monP)) { - MON_INIT(&descP->currentAcceptor.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> " - "current acceptor - try activate next\r\n", - sockRef, descP->sock) ); - - if (!activate_next_acceptor(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - descP->readState &= ~ESOCK_STATE_ACCEPTING; - descP->currentAcceptorP = NULL; - } - } else { - - /* Maybe unqueue one of the waiting acceptors */ - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> " - "not current acceptor - maybe a waiting acceptor\r\n", - sockRef, descP->sock) ); - - acceptor_unqueue(env, descP, NULL, pidP); - } -} -#endif // #ifndef __WIN32__ - - -/* *** esock_down_writer *** - * - * Check and then handle a downed writer process. - * +/* + * The idea with this function is that it should call esock_io_finish + * and release anything allocated by the I/O backend (just to be a + * nice citizen). + * On Unix this currently a void operation, but on Windows it will be + * more substantial... + * So, this is currently just a placeholder. */ -#ifndef __WIN32__ static -void esock_down_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) +void esock_on_halt(void* priv_data) { - if (MON_EQ(&descP->currentWriter.mon, monP)) { - MON_INIT(&descP->currentWriter.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> " - "current writer - try activate next\r\n", - sockRef, descP->sock) ); - - if (!activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> no active writer\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - - } else { - - /* Maybe unqueue one of the waiting writer(s) */ - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> " - "not current writer - maybe a waiting writer\r\n", - sockRef, descP->sock) ); - - writer_unqueue(env, descP, NULL, pidP); - } -} -#endif // #ifndef __WIN32__ - - - - -/* *** esock_down_reader *** - * - * Check and then handle a downed reader process. - * - */ + // We do not *currently* use this (priv_data), so ignore #ifndef __WIN32__ -static -void esock_down_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) -{ - if (MON_EQ(&descP->currentReader.mon, monP)) { - MON_INIT(&descP->currentReader.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> " - "current reader - try activate next\r\n", - sockRef, descP->sock) ); - - if (! activate_next_reader(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> no more readers\r\n", - sockRef, descP->sock) ); - - descP->currentReaderP = NULL; - } + VOID(priv_data); +#else + VOIDP(priv_data); +#endif - } else { - - /* Maybe unqueue one of the waiting reader(s) */ - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> " - "not current reader - maybe a waiting reader\r\n", - sockRef, descP->sock) ); - - reader_unqueue(env, descP, NULL, pidP); - } + ESOCK_IO_FIN(); } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -20288,7 +13079,6 @@ ErlNifFunc esock_funcs[] = }; -#ifndef __WIN32__ static char* extract_debug_filename(ErlNifEnv* env, ERL_NIF_TERM map) @@ -20310,7 +13100,6 @@ char* extract_debug_filename(ErlNifEnv* env, filename[bin.size] = '\0'; return filename; } -#endif // #ifndef __WIN32__ @@ -20321,10 +13110,13 @@ char* extract_debug_filename(ErlNifEnv* env, static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + ErlNifSysInfo sysInfo; + unsigned int ioNumThreads, ioNumThreadsDef; + /* +++ Local atoms and error reason atoms +++ */ #define LOCAL_ATOM_DECL(A) atom_##A = MKA(env, #A) LOCAL_ATOMS; - LOCAL_ERROR_REASON_ATOMS; + // LOCAL_ERROR_REASON_ATOMS; #undef LOCAL_ATOM_DECL /* Global atom(s) and error reason atom(s) */ @@ -20335,8 +13127,6 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) esock_atom_socket_tag = MKA(env, "$socket"); -#ifndef __WIN32__ - if (! esock_extract_pid_from_map(env, load_info, atom_registry, &data.regPid)) { @@ -20344,16 +13134,26 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) return 1; // Failure - no registry pid } + /* --esock-disable-registry */ data.useReg = esock_get_bool_from_map(env, load_info, - atom_use_registry, + esock_atom_use_registry, ESOCK_USE_SOCKET_REGISTRY); + /* --esock-enable-iow */ data.iow = esock_get_bool_from_map(env, load_info, atom_iow, ESOCK_NIF_IOW_DEFAULT); + /* --enable-extended-error-info */ +#if defined(ESOCK_USE_EXTENDED_ERROR_INFO) + data.eei = TRUE; +#else + data.eei = FALSE; +#endif + + /* --esock-debug-file=<filename> */ { char *debug_filename; @@ -20392,9 +13192,37 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) data.numProtoUDP = 0; data.numProtoSCTP = 0; + initOpts(); initCmsgTables(); + + // #define ESOCK_DISPLAY_OPTION_TABLES 1 +#if defined(ESOCK_DISPLAY_OPTION_TABLES) + { + /* Display option table(s) after init */ + ESOCK_EPRINTF("\r\n[ESOCK] Option tables after init:\r\n"); + + for (int levelIdx = 0; levelIdx < NUM(optLevels); levelIdx++) { + int numOpts = optLevels[levelIdx].num; + int level = optLevels[levelIdx].level; + ERL_NIF_TERM lname = *optLevels[levelIdx].nameP; + struct ESockOpt* opts = optLevels[levelIdx].opts; + + ESOCK_EPRINTF("[ESOCK] [%d] Option table for level %T (%d) (%d options):\r\n", + levelIdx, lname, level, numOpts); + + for (int optIdx = 0; optIdx < numOpts; optIdx++) { + ESOCK_EPRINTF("[ESOCK] %T[%d]: %T -> %d\r\n", + lname, optIdx, lname, opts[optIdx].opt); + + } + ESOCK_EPRINTF("\r\n"); + } + } +#endif + + data.iov_max = #if defined(NO_SYSCONF) || (! defined(_SC_IOV_MAX)) # ifdef IOV_MAX @@ -20408,16 +13236,158 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) ; ESOCK_ASSERT( data.iov_max > 0 ); -#endif // #ifndef __WIN32__ + + /* This is (currently) intended for Windows use */ + enif_system_info(&sysInfo, sizeof(ErlNifSysInfo)); + + /* We should have a config options for this: + * --esock-num-io-threads=16 + * + * ESOCK_IO_NUM_THREADS + */ + ioNumThreadsDef = + (unsigned int) (sysInfo.scheduler_threads > 0) ? + 2*sysInfo.scheduler_threads : 2; + + ioNumThreads = esock_get_uint_from_map(env, load_info, + atom_io_num_threads, + ioNumThreadsDef); + +#ifdef __WIN32__ + + io_backend.init = esaio_init; + io_backend.finish = esaio_finish; + + io_backend.info = esaio_info; + io_backend.cmd = esock_command; + io_backend.supports_0 = esock_supports_0; + io_backend.supports_1 = esock_supports_1; + + io_backend.open_with_fd = NULL; + io_backend.open_plain = esaio_open_plain; + io_backend.bind = esaio_bind; + io_backend.connect = esaio_connect; + io_backend.listen = esock_listen; + io_backend.accept = esaio_accept; + io_backend.send = esaio_send; + io_backend.sendto = esaio_sendto; + io_backend.sendmsg = esaio_sendmsg; + io_backend.sendfile_start = NULL; + io_backend.sendfile_cont = NULL; + io_backend.sendfile_dc = NULL; + io_backend.recv = esaio_recv; + io_backend.recvfrom = esaio_recvfrom; + io_backend.recvmsg = esaio_recvmsg; + io_backend.close = esaio_close; + io_backend.fin_close = esaio_fin_close; + io_backend.shutdown = esock_shutdown; + io_backend.sockname = esock_sockname; + io_backend.peername = esock_peername; + io_backend.cancel_connect = esaio_cancel_connect; + io_backend.cancel_accept = esaio_cancel_accept; + io_backend.cancel_send = esaio_cancel_send; + io_backend.cancel_recv = esaio_cancel_recv; + + io_backend.setopt = esock_setopt; + io_backend.setopt_native = esock_setopt_native; + io_backend.setopt_otp = esock_setopt_otp; + io_backend.getopt = esock_getopt; + io_backend.getopt_native = esock_getopt_native; + io_backend.getopt_otp = esock_getopt_otp; + + io_backend.ioctl_2 = NULL; + io_backend.ioctl_3 = NULL; + io_backend.ioctl_4 = NULL; + + io_backend.dtor = esaio_dtor; + io_backend.stop = NULL; // esaio_stop; + io_backend.down = esaio_down; + +#else + + io_backend.init = essio_init; + io_backend.finish = essio_finish; + + io_backend.info = essio_info; + io_backend.cmd = esock_command; + io_backend.supports_0 = esock_supports_0; + io_backend.supports_1 = esock_supports_1; + + io_backend.open_with_fd = essio_open_with_fd; + io_backend.open_plain = essio_open_plain; + io_backend.bind = essio_bind; + io_backend.connect = essio_connect; + io_backend.listen = esock_listen; + io_backend.accept = essio_accept; + io_backend.send = essio_send; + io_backend.sendto = essio_sendto; + io_backend.sendmsg = essio_sendmsg; + io_backend.sendfile_start = essio_sendfile_start; + io_backend.sendfile_cont = essio_sendfile_cont; + io_backend.sendfile_dc = essio_sendfile_deferred_close; + io_backend.recv = essio_recv; + io_backend.recvfrom = essio_recvfrom; + io_backend.recvmsg = essio_recvmsg; + io_backend.close = essio_close; + io_backend.fin_close = essio_fin_close; + io_backend.shutdown = esock_shutdown; + io_backend.sockname = esock_sockname; + io_backend.peername = esock_peername; + io_backend.cancel_connect = essio_cancel_connect; + io_backend.cancel_accept = essio_cancel_accept; + io_backend.cancel_send = essio_cancel_send; + io_backend.cancel_recv = essio_cancel_recv; + + io_backend.setopt = esock_setopt; + io_backend.setopt_native = esock_setopt_native; + io_backend.setopt_otp = esock_setopt_otp; + io_backend.getopt = esock_getopt; + io_backend.getopt_native = esock_getopt_native; + io_backend.getopt_otp = esock_getopt_otp; + + io_backend.ioctl_2 = essio_ioctl2; + io_backend.ioctl_3 = essio_ioctl3; + io_backend.ioctl_4 = essio_ioctl4; + + io_backend.dtor = essio_dtor; + io_backend.stop = essio_stop; + io_backend.down = essio_down; + +#endif + + if (ESOCK_IO_INIT(ioNumThreads) != ESOCK_IO_OK) { + esock_error_msg("Failed initiating I/O backend"); + return 1; // Failure + } esocks = enif_open_resource_type_x(env, "sockets", &esockInit, ERL_NIF_RT_CREATE, NULL); - return esocks != NULL ? - 0: // Success - 1; // Failure + + if (esocks != NULL) { + int ores; + + // *Try* install on-halt (callback) function + if ((ores = enif_set_option(env, + ERL_NIF_OPT_ON_HALT, + esock_on_halt)) != 0) { + esock_error_msg("Failed installing 'on-halt' " + "callback function (%d)\r\n", ores); + return 1; // Failure + } + + // *Try* enable 'delay on halt' (none-fatal) + if ((ores = enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)) != 0) { + esock_error_msg("Failed enable 'on-halt' delay (%d)\r\n", ores); + } + + return 0; // Success + } else { + esock_error_msg("Failed open esock resource type\r\n"); + return 1; // Failure + } } /* |