diff options
Diffstat (limited to 'erts/emulator/nifs/common/prim_socket_int.h')
-rw-r--r-- | erts/emulator/nifs/common/prim_socket_int.h | 853 |
1 files changed, 853 insertions, 0 deletions
diff --git a/erts/emulator/nifs/common/prim_socket_int.h b/erts/emulator/nifs/common/prim_socket_int.h new file mode 100644 index 0000000000..9f753bf80b --- /dev/null +++ b/erts/emulator/nifs/common/prim_socket_int.h @@ -0,0 +1,853 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + * + * ---------------------------------------------------------------------- + * Purpose : "Global" Types and stuff for socket. + * ---------------------------------------------------------------------- + * + */ + +#ifndef PRIM_SOCKET_INT_H__ +#define PRIM_SOCKET_INT_H__ + +#include <erl_nif.h> +#include <sys.h> + +#include "socket_int.h" +#include "socket_dbg.h" + + +/* ********************************************************************* * + * SOCKET and HANDLE * + * ********************************************************************* * + */ + +#if defined(__WIN32__) + +#define INVALID_EVENT NULL +#define SOCKET_FORMAT_STR "%lld" + +#else + +#define INVALID_HANDLE (-1) +typedef int HANDLE; +#define INVALID_SOCKET (-1) +typedef int SOCKET; /* A subset of HANDLE */ +#define INVALID_EVENT INVALID_HANDLE +#define SOCKET_FORMAT_STR "%d" + +#endif + + +/* ********************************************************************* * + * Socket state defs and macros * + * ********************************************************************* * + */ + +#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_BOUND(st) \ + (((st) & ESOCK_STATE_BOUND) != 0) + +#define IS_CLOSED(st) \ + (((st) & ESOCK_STATE_CLOSED) != 0) + +#define IS_CLOSING(st) \ + (((st) & ESOCK_STATE_CLOSING) != 0) + +#define IS_ACCEPTING(st) \ + (((st) & ESOCK_STATE_ACCEPTING) != 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_DESC_PATTERN_CREATED 0x03030303 +#define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0 + + +/* ========================================================================== + * 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 * + * ********************************************************************* * + */ + +#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)) + + +/* ********************************************************************* * + * Counter type and related "things" * + * ********************************************************************* * + */ + +#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 + +#define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \ + do { \ + if (esock_cnt_inc((CNT), (INC))) { \ + esock_send_wrap_msg((__E__), (__D__), (SF), (ACNT)); \ + } \ + } while (0) + + + +/* ********************************************************************* * + * (Socket) Debug macros * + * ********************************************************************* * + */ + +#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto ) +#define SSDBG2( __DBG__ , proto ) ESOCK_DBG_PRINTF( (__DBG__) , proto ) + + +/* ********************************************************************* * + * Sendfile stuff * + * ********************************************************************* * + */ + +#if defined(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; + +#endif + + +/* ********************************************************************* * + * Monitor wrapper type * + * ********************************************************************* * + */ + +typedef struct { + ErlNifMonitor mon; + BOOLEAN_T isActive; +} ESockMonitor; + + + + +/* ********************************************************************* * + * The 'request' data structure * + * Each I/O request (write, read, accept, connect, ...) that cannot be * + * completed directly, is scheduled for later or asynchronous. * + * These requests are "pushed" into a request "queue". * + * In the case of the classic (unix) implementation, this is an actual * + * queue which also takes care of the order of the requests. * + * In case of the I/O Completion Port (windows), it is only used as an * + * database (we "push" into the list but we never "pop" from the list, * + * we search and delete). * + * ********************************************************************* * + */ + +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 + + /* The socket for which this request is made. + * A pointer to an *optional* data structure. This is intended for + * the 'overlapped' structure used by I/O Completion Port. + * A request scheduled by the I/O Completion Port can be 'cancelled' + * using the socket and the 'overlapped' data (provided when the + * operation was scheduled). + */ + SOCKET sock; + void* dataP; + +} ESockRequestor; + +typedef struct esock_request_queue_element { + struct esock_request_queue_element* nextP; + ESockRequestor data; +} ESockRequestQueueElement; + +typedef struct { + ESockRequestQueueElement* first; + ESockRequestQueueElement* last; +} ESockRequestQueue; + + + +/* ********************************************************************* * + * Holding the socket level 'otp' option 'meta' term * + * ********************************************************************* * + */ + +typedef struct{ + ErlNifEnv* env; + ERL_NIF_TERM ref; +} ESockMeta; + + + +/* ********************************************************************* * + * Control Message spec type * + * ********************************************************************* * + */ + +typedef struct { + 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 +} ESockCmsgSpec; + + +/*---------------------------------------------------------------------------- + * Interface types and constants. + * + * The set of elements should be the same as for the type + * msg_flag() in socket.erl. + */ +typedef struct { + int flag; + ERL_NIF_TERM* name; +} ESockFlag; + +extern const ESockFlag esock_msg_flags[]; +extern const int esock_msg_flags_length; +extern const ESockFlag esock_ioctl_flags[]; +extern const int esock_ioctl_flags_length; + + +/* ********************************************************************* * + * The socket nif global info * + * ********************************************************************* * + */ + +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; + BOOLEAN_T eei; + + /* 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; + + + +/* ********************************************************************* * + * The socket descriptor * + * ********************************************************************* * + */ + +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 +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* writer. + * The queue is intended for *waiting* writers. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentWriter; + ESockRequestor* currentWriterP; // NULL or ¤tWriter +#endif + 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 +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* reader. + * The queue is intended for *waiting* readers. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentReader; + ESockRequestor* currentReaderP; // NULL or ¤tReader +#endif + 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 +++ */ +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* acceptor. + * The queue is intended for *waiting* acceptors. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentAcceptor; + ESockRequestor* currentAcceptorP; // NULL or ¤tAcceptor +#endif + 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}. + * On Windows, rNum and rNumCnt is *not* used! + */ +#ifndef __WIN32__ + unsigned int rNum; // recv: Number of reads using rBufSz + unsigned int rNumCnt; // recv: Current number of reads (so far) +#endif + 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; + 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 + */ + +#if defined(ESOCK_DESCRIPTOR_FILLER) + char filler[1024]; +#endif + +} ESockDescriptor; + + + +/* ======================================================================== * + * What to do about this? * + * ======================================================================== * + */ + +extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ + + +/* ======================================================================== * + * Functions * + * ======================================================================== * + */ + +extern ESockDescriptor* esock_alloc_descriptor(SOCKET sock); +extern void esock_dealloc_descriptor(ErlNifEnv* env, + ESockDescriptor* descP); + +extern BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def); +extern BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def); +extern BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto); + +extern BOOLEAN_T esock_getopt_int(SOCKET sock, + int level, + int opt, + int* valP); + + +/* ** Socket Registry functions *** */ +extern void esock_send_reg_add_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +extern void esock_send_reg_del_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); + + +/* *** Message sending functions *** */ +extern void esock_send_simple_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +extern void esock_send_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestor* reqP, + ERL_NIF_TERM reason); +extern void esock_send_close_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid); +extern void esock_send_wrap_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); + + +/* ** Monitor functions *** */ +extern int esock_monitor(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pid, + ESockMonitor* mon); +extern int esock_demonitor(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockMonitor* monP); +extern void esock_monitor_init(ESockMonitor* mon); +extern ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, + const ESockMonitor* monP); +extern BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, + const ErlNifMonitor* mon); + + +/* *** Counter functions *** */ +extern BOOLEAN_T esock_cnt_inc(ESockCounter* cnt, ESockCounter inc); +extern void esock_cnt_dec(ESockCounter* cnt, ESockCounter dec); +extern void esock_inc_socket(int domain, int type, int protocol); +extern void esock_dec_socket(int domain, int type, int protocol); + + +/* *** Select functions *** */ +extern int esock_select_read(ErlNifEnv* env, + ErlNifEvent event, + void* obj, + const ErlNifPid* pidP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); +extern int esock_select_write(ErlNifEnv* env, + ErlNifEvent event, + void* obj, + const ErlNifPid* pidP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); +extern int esock_select_stop(ErlNifEnv* env, + ErlNifEvent event, + void* obj); +extern int esock_select_cancel(ErlNifEnv* env, + ErlNifEvent event, + enum ErlNifSelectFlags mode, + void* obj); +extern ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + int smode, + int rmode); + + +/* *** Request queue functions *** */ +extern void esock_free_request_queue(ESockRequestQueue* q); +extern BOOLEAN_T esock_requestor_pop(ESockRequestQueue* q, + ESockRequestor* reqP); + +extern void esock_requestor_init(ESockRequestor* reqP); +extern void esock_requestor_release(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockRequestor* reqP); + + +/* *** 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 + + +/* *** Environment wrapper functions *** + * These hould really be inline, but for now... + */ +extern void esock_clear_env(const char* slogan, ErlNifEnv* env); +extern void esock_free_env(const char* slogan, ErlNifEnv* env); +extern ErlNifEnv* esock_alloc_env(const char* slogan); + + +/* *** Control Message utility functions *** + */ +#ifndef __WIN32__ +extern void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, + size_t size, + size_t* usedP); +#if defined(IP_TTL) || \ + defined(IPV6_HOPLIMIT) || \ + defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS) +extern BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP); +#endif +extern BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP); +extern ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num); +extern ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType); + +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); +extern void esock_encode_msg_flags(ErlNifEnv* env, + ESockDescriptor* descP, + int msgFlags, + ERL_NIF_TERM* flags); +#endif + + +extern void esock_stop_handle_current(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestor* reqP); +extern void esock_inform_waiting_procs(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestQueue* q, + ERL_NIF_TERM reason); + + +/* *** Control Message 'stuff' *** + */ +extern void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, // Remaining space + size_t size, // Size of data + size_t* usedP); +extern ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num); +extern ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType); + +/* *** Sendfile 'stuff' *** + */ +#ifdef HAVE_SENDFILE + +extern ESockSendfileCounters initESockSendfileCounters; + +#endif + +/* *** message functions **** + */ +extern void esock_send_wrap_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); +extern BOOLEAN_T esock_send_msg(ErlNifEnv* env, + ErlNifPid* pid, + ERL_NIF_TERM msg, + ErlNifEnv* msgEnv); +extern ERL_NIF_TERM esock_mk_socket_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM tag, + ERL_NIF_TERM info); +extern ERL_NIF_TERM esock_mk_socket(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +#ifdef HAVE_SENDFILE +extern void esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, + ESockDescriptor* descP); +#endif + + +/* *** 'close' functions *** + */ +extern int esock_close_socket(ErlNifEnv* env, + ESockDescriptor* descP, + BOOLEAN_T unlock); + +#endif // PRIM_SOCKET_INT_H__ |