1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2018-2021. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 *
20 * ----------------------------------------------------------------------
21 * Purpose : The NIF (C) part of the socket interface
22 *
23 * All of the nif-functions which are part of the API has two parts.
24 * The first function is called 'nif_<something>', e.g. nif_open.
25 * This does the initial validation and argument processing and then
26 * calls the function that does the actual work. This is called
27 * 'esock_<something>'.
28 * ----------------------------------------------------------------------
29 *
30 *
31 * This is just a code snippet in case there is need of extra debugging
32 *
33 * esock_dbg_printf("DEMONP", "[%d] %s: %T\r\n",
34 * descP->sock, slogan,
35 * esock_make_monitor_term(env, &mon));
36 *
37 */
38
39 #define STATIC_ERLANG_NIF 1
40
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 /* If we HAVE_SCTP_H and Solaris, we need to define the following in
47 * order to get SCTP working:
48 */
49 #if (defined(HAVE_SCTP_H) && defined(__sun) && defined(__SVR4))
50 #define SOLARIS10 1
51 /* WARNING: This is not quite correct, it may also be Solaris 11! */
52 #define _XPG4_2
53 #define __EXTENSIONS__
54 #endif
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <stddef.h>
59 #include <ctype.h>
60 #include <sys/types.h>
61 #include <errno.h>
62 #include <stdint.h>
63 #include <limits.h>
64
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68 #ifdef HAVE_SYS_UIO_H
69 #include <sys/uio.h>
70 #endif
71
72 #ifdef HAVE_NET_IF_DL_H
73 #include <net/if_dl.h>
74 #endif
75
76 #ifdef HAVE_IFADDRS_H
77 #include <ifaddrs.h>
78 #endif
79
80 #ifdef HAVE_NETPACKET_PACKET_H
81 #include <netpacket/packet.h>
82 #endif
83
84 #ifdef HAVE_SENDFILE
85 #if defined(__linux__) || (defined(__sun) && defined(__SVR4))
86 #include <sys/sendfile.h>
87 #elif defined(__FreeBSD__) || defined(__DragonFly__)
88 /* Need to define __BSD_VISIBLE in order to expose prototype
89 * of sendfile in sys/socket.h
90 */
91 #define __BSD_VISIBLE 1
92 #endif
93 #endif
94
95 #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
96 #define __DARWIN__ 1
97 #endif
98
99
100 #ifdef __WIN32__
101 /* ---------------------------------------------------------------------- *
102 * *
103 * Start of __WIN32__ section *
104 * *
105 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
106
107
108 #define STRNCASECMP strncasecmp
109 #define INCL_WINSOCK_API_TYPEDEFS 1
110
111 #ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
112 #include <winsock2.h>
113 #endif
114 #include <windows.h>
115 #include <Ws2tcpip.h>
116
117 /* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h
118 * to define the right structures. It needs to be set to WINXP (or LONGHORN)
119 * for IPV6 to work and it's set lower by default, so we need to change it.
120 */
121 #ifdef HAVE_SDKDDKVER_H
122 # include <sdkddkver.h>
123 # ifdef NTDDI_VERSION
124 # undef NTDDI_VERSION
125 # endif
126 # define NTDDI_VERSION NTDDI_WINXP
127 #endif
128 #include <iphlpapi.h>
129
130 #undef WANT_NONBLOCKING
131 #include "sys.h"
132
133
134 /* AND HERE WE MAY HAVE A BUNCH OF DEFINES....SEE INET DRIVER.... */
135
136
137 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *
138 * *
139 * End of __WIN32__ section *
140 * *
141 * ---------------------------------------------------------------------- */
142 #else /* #ifdef __WIN32__ */
143 /* ---------------------------------------------------------------------- *
144 * *
145 * Start of non-__WIN32__ section a.k.a UNIX section *
146 * *
147 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
148
149
150 #include <sys/time.h>
151 #ifdef NETDB_H_NEEDS_IN_H
152 #include <netinet/in.h>
153 #endif
154 #include <netdb.h>
155
156 #include <sys/socket.h>
157 #include <netinet/in.h>
158
159 #ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H
160 #include <rpc/types.h>
161 #endif
162
163 #include <netinet/ip.h>
164 #include <netinet/tcp.h>
165 #include <netinet/udp.h>
166 #include <arpa/inet.h>
167
168 #include <sys/param.h>
169 #ifdef HAVE_ARPA_NAMESER_H
170 #include <arpa/nameser.h>
171 #endif
172
173 #ifdef HAVE_SYS_SOCKIO_H
174 #include <sys/sockio.h>
175 #endif
176
177 #ifdef HAVE_SYS_IOCTL_H
178 #include <sys/ioctl.h>
179 #endif
180
181 #include <net/if.h>
182
183 #ifdef HAVE_SCHED_H
184 #include <sched.h>
185 #endif
186
187 #ifdef HAVE_SETNS_H
188 #include <setns.h>
189 #endif
190 #ifdef HAVE_LINUX_ERRQUEUE_H
191 #include <linux/types.h> /* On some (I assume) "old" linux, *
192 * for example SLES 10 SP1, this is *
193 * not (explicitly) included by the *
194 * errqueue file. And for some reason *
195 * configure does not detect this. *
196 * So, to simplify, we include here. */
197 #include <linux/errqueue.h>
198 #include <linux/icmp.h>
199 #include <linux/icmpv6.h>
200 #endif
201
202 #define HAVE_UDP
203
204 /* SCTP support -- currently for UNIX platforms only: */
205 #undef HAVE_SCTP
206 #if defined(HAVE_SCTP_H)
207
208 #include <netinet/sctp.h>
209
210 /* SCTP Socket API Draft from version 11 on specifies that netinet/sctp.h must
211 explicitly define HAVE_SCTP in case when SCTP is supported, but Solaris 10
212 still apparently uses Draft 10, and does not define that symbol, so we have
213 to define it explicitly:
214 */
215 #ifndef HAVE_SCTP
216 # define HAVE_SCTP
217 #endif
218
219 /* These changed in draft 11, so SOLARIS10 uses the old MSG_* */
220 #if ! HAVE_DECL_SCTP_UNORDERED
221 # define SCTP_UNORDERED MSG_UNORDERED
222 #endif
223 #if ! HAVE_DECL_SCTP_ADDR_OVER
224 # define SCTP_ADDR_OVER MSG_ADDR_OVER
225 #endif
226 #if ! HAVE_DECL_SCTP_ABORT
227 # define SCTP_ABORT MSG_ABORT
228 #endif
229 #if ! HAVE_DECL_SCTP_EOF
230 # define SCTP_EOF MSG_EOF
231 #endif
232
233 /* More Solaris 10 fixes: */
234 #if ! HAVE_DECL_SCTP_CLOSED && HAVE_DECL_SCTPS_IDLE
235 # define SCTP_CLOSED SCTPS_IDLE
236 # undef HAVE_DECL_SCTP_CLOSED
237 # define HAVE_DECL_SCTP_CLOSED 1
238 #endif
239 #if ! HAVE_DECL_SCTP_BOUND && HAVE_DECL_SCTPS_BOUND
240 # define SCTP_BOUND SCTPS_BOUND
241 # undef HAVE_DECL_SCTP_BOUND
242 # define HAVE_DECL_SCTP_BOUND 1
243 #endif
244 #if ! HAVE_DECL_SCTP_LISTEN && HAVE_DECL_SCTPS_LISTEN
245 # define SCTP_LISTEN SCTPS_LISTEN
246 # undef HAVE_DECL_SCTP_LISTEN
247 # define HAVE_DECL_SCTP_LISTEN 1
248 #endif
249 #if ! HAVE_DECL_SCTP_COOKIE_WAIT && HAVE_DECL_SCTPS_COOKIE_WAIT
250 # define SCTP_COOKIE_WAIT SCTPS_COOKIE_WAIT
251 # undef HAVE_DECL_SCTP_COOKIE_WAIT
252 # define HAVE_DECL_SCTP_COOKIE_WAIT 1
253 #endif
254 #if ! HAVE_DECL_SCTP_COOKIE_ECHOED && HAVE_DECL_SCTPS_COOKIE_ECHOED
255 # define SCTP_COOKIE_ECHOED SCTPS_COOKIE_ECHOED
256 # undef HAVE_DECL_SCTP_COOKIE_ECHOED
257 # define HAVE_DECL_SCTP_COOKIE_ECHOED 1
258 #endif
259 #if ! HAVE_DECL_SCTP_ESTABLISHED && HAVE_DECL_SCTPS_ESTABLISHED
260 # define SCTP_ESTABLISHED SCTPS_ESTABLISHED
261 # undef HAVE_DECL_SCTP_ESTABLISHED
262 # define HAVE_DECL_SCTP_ESTABLISHED 1
263 #endif
264 #if ! HAVE_DECL_SCTP_SHUTDOWN_PENDING && HAVE_DECL_SCTPS_SHUTDOWN_PENDING
265 # define SCTP_SHUTDOWN_PENDING SCTPS_SHUTDOWN_PENDING
266 # undef HAVE_DECL_SCTP_SHUTDOWN_PENDING
267 # define HAVE_DECL_SCTP_SHUTDOWN_PENDING 1
268 #endif
269 #if ! HAVE_DECL_SCTP_SHUTDOWN_SENT && HAVE_DECL_SCTPS_SHUTDOWN_SENT
270 # define SCTP_SHUTDOWN_SENT SCTPS_SHUTDOWN_SENT
271 # undef HAVE_DECL_SCTP_SHUTDOWN_SENT
272 # define HAVE_DECL_SCTP_SHUTDOWN_SENT 1
273 #endif
274 #if ! HAVE_DECL_SCTP_SHUTDOWN_RECEIVED && HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED
275 # define SCTP_SHUTDOWN_RECEIVED SCTPS_SHUTDOWN_RECEIVED
276 # undef HAVE_DECL_SCTP_SHUTDOWN_RECEIVED
277 # define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED 1
278 #endif
279 #if ! HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT && HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT
280 # define SCTP_SHUTDOWN_ACK_SENT SCTPS_SHUTDOWN_ACK_SENT
281 # undef HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT
282 # define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT 1
283 #endif
284 /* New spelling in lksctp 2.6.22 or maybe even earlier:
285 * adaption -> adaptation
286 */
287 #if !defined(SCTP_ADAPTATION_LAYER) && defined (SCTP_ADAPTION_LAYER)
288 # define SCTP_ADAPTATION_LAYER SCTP_ADAPTION_LAYER
289 # define SCTP_ADAPTATION_INDICATION SCTP_ADAPTION_INDICATION
290 # define sctp_adaptation_event sctp_adaption_event
291 # define sctp_setadaptation sctp_setadaption
292 # define sn_adaptation_event sn_adaption_event
293 # define sai_adaptation_ind sai_adaption_ind
294 # define ssb_adaptation_ind ssb_adaption_ind
295 # define sctp_adaptation_layer_event sctp_adaption_layer_event
296 #endif
297
298 /*
299 * We *may* need this stuff later when we *fully* implement support for SCTP
300 *
301
302 #if defined(__GNUC__) && defined(HAVE_SCTP_BINDX)
303 static typeof(sctp_bindx) *esock_sctp_bindx = NULL;
304 #else
305 static int (*esock_sctp_bindx)
306 (int sd, struct sockaddr *addrs, int addrcnt, int flags) = NULL;
307 #endif
308
309 #if defined(__GNUC__) && defined(HAVE_SCTP_PEELOFF)
310 static typeof(sctp_peeloff) *esock_sctp_peeloff = NULL;
311 #else
312 static int (*esock_sctp_peeloff)
313 (int sd, sctp_assoc_t assoc_id) = NULL;
314 #endif
315
316 #if defined(__GNUC__) && defined(HAVE_SCTP_GETLADDRS)
317 static typeof(sctp_getladdrs) *esock_sctp_getladdrs = NULL;
318 #else
319 static int (*esock_sctp_getladdrs)
320 (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
321 #endif
322
323 #if defined(__GNUC__) && defined(HAVE_SCTP_FREELADDRS)
324 static typeof(sctp_freeladdrs) *esock_sctp_freeladdrs = NULL;
325 #else
326 static void (*esock_sctp_freeladdrs)(struct sockaddr *addrs) = NULL;
327 #endif
328
329 #if defined(__GNUC__) && defined(HAVE_SCTP_GETPADDRS)
330 static typeof(sctp_getpaddrs) *esock_sctp_getpaddrs = NULL;
331 #else
332 static int (*esock_sctp_getpaddrs)
333 (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
334 #endif
335
336 #if defined(__GNUC__) && defined(HAVE_SCTP_FREEPADDRS)
337 static typeof(sctp_freepaddrs) *esock_sctp_freepaddrs = NULL;
338 #else
339 static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
340 #endif
341
342 */
343
344 #endif /* #if defined(HAVE_SCTP_H) */
345
346
347 #ifndef WANT_NONBLOCKING
348 #define WANT_NONBLOCKING
349 #endif
350 #include "sys.h"
351
352 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *
353 * *
354 * End of non-__WIN32__ section a.k.a UNIX section *
355 * *
356 * ---------------------------------------------------------------------- */
357 #endif /* #ifdef __WIN32__ #else */
358
359
360
361 #include <erl_nif.h>
362
363 #include "socket_dbg.h"
364 #include "socket_tarray.h"
365 #include "socket_int.h"
366 #include "socket_util.h"
367 #include "prim_file_nif_dyncall.h"
368
369 #if defined(ERTS_INLINE)
370 # define ESOCK_INLINE ERTS_INLINE
371 #else
372 # if defined(__GNUC__)
373 # define ESOCK_INLINE __inline__
374 # elif defined(__WIN32__)
375 # define ESOCK_INLINE __inline
376 # else
377 # define ESOCK_INLINE
378 # endif
379 #endif
380
381
382 #if defined(SOL_IPV6) || defined(IPPROTO_IPV6)
383 #define HAVE_IPV6
384 #endif
385
386 /* Debug stuff... */
387 #define ESOCK_GLOBAL_DEBUG_DEFAULT FALSE
388 #define ESOCK_DEBUG_DEFAULT FALSE
389
390 /* Counters and stuff (Don't know where to send this stuff anyway) */
391 #define ESOCK_NIF_IOW_DEFAULT FALSE
392
393
394 #ifdef __WIN32__
395
396 //#define INVALID_HANDLE from Windows header file
397 //typedef void *HANDLE from Windows header file
398 //#define INVALID_SOCKET from Windows header file
399 //typedef void *SOCKET from Windows header file
400 #define INVALID_EVENT NULL
401
402 #else
403
404 #define INVALID_HANDLE (-1)
405 typedef int HANDLE;
406 #define INVALID_SOCKET (-1)
407 typedef int SOCKET; /* A subset of HANDLE */
408 #define INVALID_EVENT INVALID_HANDLE
409
410 #endif
411
412
413 /* ==============================================================================
414 * The ESOCK_IS_ERROR macro below is used for portability reasons.
415 * While POSIX specifies that errors from socket-related system calls
416 * should be indicated with a -1 return value, some users have experienced
417 * non-Windows OS kernels that return negative values other than -1.
418 * While one can argue that such kernels are technically broken, comparing
419 * against values less than 0 covers their out-of-spec return values without
420 * imposing incorrect semantics on systems that manage to correctly return -1
421 * for errors, thus increasing Erlang's portability.
422 */
423 #ifdef __WIN32__
424 #define ESOCK_IS_ERROR(val) ((val) == INVALID_SOCKET)
425 #else
426 #define ESOCK_IS_ERROR(val) ((val) < 0)
427 #endif
428
429
430 /* *** Misc macros and defines *** */
431
432 /* This macro exist on some (linux) platforms */
433 #if !defined(IPTOS_TOS_MASK)
434 #define IPTOS_TOS_MASK 0x1E
435 #endif
436 #if !defined(IPTOS_TOS)
437 #define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
438 #endif
439
440
441 #if defined(TCP_CA_NAME_MAX)
442 #define ESOCK_OPT_TCP_CONGESTION_NAME_MAX TCP_CA_NAME_MAX
443 #else
444 /* This is really excessive, but just in case... */
445 #define ESOCK_OPT_TCP_CONGESTION_NAME_MAX 256
446 #endif
447
448
449 #if defined(TCP_CONGESTION) || defined(SO_BINDTODEVICE)
450 #define USE_GETOPT_STR_OPT
451 #define USE_SETOPT_STR_OPT
452 #endif
453
454
455
456 /* *** Socket state defs *** */
457
458 #define ESOCK_STATE_BOUND 0x0001 /* readState */
459 #define ESOCK_STATE_LISTENING 0x0002 /* readState */
460 #define ESOCK_STATE_ACCEPTING 0x0004 /* readState */
461 #define ESOCK_STATE_CONNECTING 0x0010 /* writeState */
462 #define ESOCK_STATE_CONNECTED 0x0020 /* writeState */
463
464 /* This is set in either readState or writeState
465 * so it has to be read from both.
466 * Means that the socket has been used in select,
467 * so select_stop is required. */
468 #define ESOCK_STATE_SELECTED 0x0100 /* readState or writeState */
469
470 /* These are set in both readState and writeState
471 * so they can be read from either. */
472 #define ESOCK_STATE_CLOSING 0x0200 /* readState and writeState */
473
474 #define ESOCK_STATE_CLOSED 0x0400 /* readState and writeState */
475 //
476 #define ESOCK_STATE_DTOR 0x8000
477
478 #define IS_CLOSED(st) \
479 (((st) & ESOCK_STATE_CLOSED) != 0)
480
481 #define IS_CLOSING(st) \
482 (((st) & ESOCK_STATE_CLOSING) != 0)
483
484 #define IS_OPEN(st) \
485 (((st) & (ESOCK_STATE_CLOSED | ESOCK_STATE_CLOSING)) == 0)
486
487 #define IS_SELECTED(d) \
488 ((((d)->readState | (d)->writeState) & ESOCK_STATE_SELECTED) != 0)
489
490
491 #define ESOCK_GET_RESOURCE(ENV, REF, RES) \
492 enif_get_resource((ENV), (REF), esocks, (RES))
493
494 #define ESOCK_RECV_BUFFER_COUNT_DEFAULT 0
495 #define ESOCK_RECV_BUFFER_SIZE_DEFAULT 8192
496 #define ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024
497 #define ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024
498
499 #define ESOCK_DESC_PATTERN_CREATED 0x03030303
500 #define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0
501
502 /*
503 typedef union {
504 struct {
505 // 0 = not open, 1 = open
506 unsigned int open:1;
507 // 0 = not conn, 1 = connecting, 2 = connected
508 unsigned int connect:2;
509 // unsigned int connecting:1;
510 // unsigned int connected:1;
511 // 0 = not listen, 1 = listening, 2 = accepting
512 unsigned int listen:2;
513 // unsigned int listening:1;
514 // unsigned int accepting:1;
515 / * Room for more... * /
516 } flags;
517 unsigned int field; // Make it easy to reset all flags...
518 } SocketState;
519 */
520
521 /*----------------------------------------------------------------------------
522 * Interface constants.
523 *
524 * The set of elements should be the same as for the type
525 * msg_flag() in socket.erl.
526 */
527
528 static const struct msg_flag {
529 int flag;
530 ERL_NIF_TERM *name;
531 } msg_flags[] = {
532
533 {
534 #ifdef MSG_CMSG_CLOEXEC
535 MSG_CMSG_CLOEXEC,
536 #else
537 0,
538 #endif
539 &esock_atom_cmsg_cloexec},
540
541 {
542 #ifdef MSG_CONFIRM
543 MSG_CONFIRM,
544 #else
545 0,
546 #endif
547 &esock_atom_confirm},
548
549 {
550 #ifdef MSG_CTRUNC
551 MSG_CTRUNC,
552 #else
553 0,
554 #endif
555 &esock_atom_ctrunc},
556
557 {
558 #ifdef MSG_DONTROUTE
559 MSG_DONTROUTE,
560 #else
561 0,
562 #endif
563 &esock_atom_dontroute},
564
565 {
566 #ifdef MSG_EOR
567 MSG_EOR,
568 #else
569 0,
570 #endif
571 &esock_atom_eor},
572
573 {
574 #ifdef MSG_ERRQUEUE
575 MSG_ERRQUEUE,
576 #else
577 0,
578 #endif
579 &esock_atom_errqueue},
580
581 {
582 #ifdef MSG_MORE
583 MSG_MORE,
584 #else
585 0,
586 #endif
587 &esock_atom_more},
588
589 {
590 #ifdef MSG_NOSIGNAL
591 MSG_NOSIGNAL,
592 #else
593 0,
594 #endif
595 &esock_atom_nosignal},
596
597 {
598 #ifdef MSG_OOB
599 MSG_OOB,
600 #else
601 0,
602 #endif
603 &esock_atom_oob},
604
605 {
606 #ifdef MSG_PEEK
607 MSG_PEEK,
608 #else
609 0,
610 #endif
611 &esock_atom_peek},
612
613 {
614 #ifdef MSG_TRUNC
615 MSG_TRUNC,
616 #else
617 0,
618 #endif
619 &esock_atom_trunc}
620 };
621
622
623
624 /* level 'otp' options */
625 #define ESOCK_OPT_OTP_DEBUG 1001
626 #define ESOCK_OPT_OTP_IOW 1002
627 #define ESOCK_OPT_OTP_CTRL_PROC 1003
628 #define ESOCK_OPT_OTP_RCVBUF 1004
629 //#define ESOCK_OPT_OTP_SNDBUF 1005
630 #define ESOCK_OPT_OTP_RCVCTRLBUF 1006
631 #define ESOCK_OPT_OTP_SNDCTRLBUF 1007
632 #define ESOCK_OPT_OTP_FD 1008
633 #define ESOCK_OPT_OTP_META 1009
634 #define ESOCK_OPT_OTP_USE_REGISTRY 1010
635 /**/
636 #define ESOCK_OPT_OTP_DOMAIN 1999 // INTERNAL AND ONLY GET
637 #if 0
638 #define ESOCK_OPT_OTP_TYPE 1998 // INTERNAL AND ONLY GET
639 #define ESOCK_OPT_OTP_PROTOCOL 1997 // INTERNAL AND ONLY GET
640 #define ESOCK_OPT_OTP_DTP 1996 // INTERNAL AND ONLY GET
641 #endif
642
643
644 /*--------------------------------------------------------------------------*/
645
646
647 /* We should *eventually* use this instead of hard-coding the size (to 1) */
648 #define ESOCK_RECVMSG_IOVEC_SZ 1
649
650
651 /* =================================================================== *
652 * *
653 * Various esockmacros *
654 * *
655 * =================================================================== */
656
657 /* Global socket debug */
658 #define SGDBG( proto ) ESOCK_DBG_PRINTF( data.dbg , proto )
659 /* Socket specific debug */
660 #define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto )
661 #define SSDBG2( __DBG__ , proto ) ESOCK_DBG_PRINTF( (__DBG__) , proto )
662
663 #define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \
664 do { \
665 if (cnt_inc((CNT), (INC))) { \
666 esock_send_wrap_msg((__E__), (__D__), (SF), (ACNT)); \
667 } \
668 } while (0)
669
670
671 /* =================================================================== *
672 * *
673 * Basic socket operations *
674 * *
675 * =================================================================== */
676
677 #ifdef __WIN32__
678 /* ---------------------------------------------------------------------- *
679 * *
680 * Start of __WIN32__ section *
681 * *
682 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
683
684 /* *** Windows macros *** */
685
686 #define sock_accept(s, addr, len) \
687 make_noninheritable_handle(accept((s), (addr), (len)))
688 #define sock_bind(s, addr, len) bind((s), (addr), (len))
689 #define sock_close(s) closesocket((s))
690 #define sock_close_event(e) WSACloseEvent(e)
691 #define sock_connect(s, addr, len) connect((s), (addr), (len))
692 #define sock_create_event(s) WSACreateEvent()
693 #define sock_errno() WSAGetLastError()
694 #define sock_getopt(s,l,o,v,ln) getsockopt((s),(l),(o),(v),(ln))
695 #define sock_htons(x) htons((x))
696 #define sock_htonl(x) htonl((x))
697 #define sock_listen(s, b) listen((s), (b))
698 #define sock_name(s, addr, len) getsockname((s), (addr), (len))
699 #define sock_ntohs(x) ntohs((x))
700 #define sock_open(domain, type, proto) \
701 make_noninheritable_handle(socket((domain), (type), (proto)))
702 #define sock_peer(s, addr, len) getpeername((s), (addr), (len))
703 #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag))
704 #define sock_recvfrom(s,buf,blen,flag,addr,alen) \
705 recvfrom((s),(buf),(blen),(flag),(addr),(alen))
706 #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag))
707 #define sock_sendto(s,buf,blen,flag,addr,alen) \
708 sendto((s),(buf),(blen),(flag),(addr),(alen))
709 #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln))
710 #define sock_shutdown(s, how) shutdown((s), (how))
711
712
713 #define SET_BLOCKING(s) ioctlsocket(s, FIONBIO, &zero_value)
714 #define SET_NONBLOCKING(s) ioctlsocket(s, FIONBIO, &one_value)
715 static unsigned long zero_value = 0;
716 static unsigned long one_value = 1;
717
718
719 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *
720 * *
721 * End of __WIN32__ section *
722 * *
723 * ---------------------------------------------------------------------- */
724 #else /* #ifdef __WIN32__ */
725 /* ---------------------------------------------------------------------- *
726 * *
727 * Start of non-__WIN32__ section a.k.a UNIX section *
728 * *
729 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
730
731
732 #ifdef HAS_ACCEPT4
733 // We have to figure out what the flags are...
734 #define sock_accept(s, addr, len) accept4((s), (addr), (len), (SOCK_CLOEXEC))
735 #else
736 #define sock_accept(s, addr, len) accept((s), (addr), (len))
737 #endif
738 #define sock_bind(s, addr, len) bind((s), (addr), (len))
739 #define sock_close(s) close((s))
740 #define sock_close_event(e) /* do nothing */
741 #define sock_connect(s, addr, len) connect((s), (addr), (len))
742 #define sock_create_event(s) (s) /* return file descriptor */
743 #define sock_errno() errno
744 #define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l))
745 #define sock_htons(x) htons((x))
746 #define sock_htonl(x) htonl((x))
747 #define sock_listen(s, b) listen((s), (b))
748 #define sock_name(s, addr, len) getsockname((s), (addr), (len))
749 #define sock_ntohs(x) ntohs((x))
750 #define sock_open(domain, type, proto) socket((domain), (type), (proto))
751 #define sock_peer(s, addr, len) getpeername((s), (addr), (len))
752 #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag))
753 #define sock_recvfrom(s,buf,blen,flag,addr,alen) \
754 recvfrom((s),(buf),(blen),(flag),(addr),(alen))
755 #define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag))
756 #define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag))
757 #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag))
758 #define sock_sendto(s,buf,blen,flag,addr,alen) \
759 sendto((s),(buf),(blen),(flag),(addr),(alen))
760 #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln))
761 #define sock_shutdown(s, how) shutdown((s), (how))
762
763
764 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *
765 * *
766 * End of non-__WIN32__ section a.k.a UNIX section *
767 * *
768 * ---------------------------------------------------------------------- */
769 #endif /* #ifdef __WIN32__ #else */
770
771
772 /* We can use the IPv4 def for this since the beginning
773 * is the same for INET and INET6 */
774 #define which_address_port(sap) \
775 ((((sap)->in4.sin_family == AF_INET) || \
776 ((sap)->in4.sin_family == AF_INET6)) ? \
777 ((sap)->in4.sin_port) : -1)
778
779
780 typedef struct {
781 ErlNifMonitor mon;
782 BOOLEAN_T isActive;
783 } ESockMonitor;
784
785 typedef struct {
786 ErlNifPid pid; // PID of the requesting process
787 ESockMonitor mon; // Monitor to the requesting process
788
789 /* We need an environment for the copy of the ref we store here.
790 * We will also use this environment for any messages we send
791 * (with the ref in it). Such as the select message (used in the
792 * select call) or the abort message.
793 */
794 ErlNifEnv* env;
795 ERL_NIF_TERM ref; // The (unique) reference (ID) of the request
796 } ESockRequestor;
797
798 typedef struct{
799 // Holding the socket level 'otp' option 'meta' term
800 ErlNifEnv* env;
801 ERL_NIF_TERM ref;
802 } ESockMeta;
803
804 typedef struct esock_request_queue_element {
805 struct esock_request_queue_element* nextP;
806 ESockRequestor data;
807 } ESockRequestQueueElement;
808
809 typedef struct {
810 ESockRequestQueueElement* first;
811 ESockRequestQueueElement* last;
812 } ESockRequestQueue;
813
814
815 /*** The point of this is primarily testing ***/
816 /*
817 #if defined(ESOCK_COUNTER_SIZE)
818 #undef ESOCK_COUNTER_SIZE
819 // #define ESOCK_COUNTER_SIZE 16
820 // #define ESOCK_COUNTER_SIZE 24
821 // #define ESOCK_COUNTER_SIZE 32
822 // #define ESOCK_COUNTER_SIZE 48
823 // #define ESOCK_COUNTER_SIZE 64
824
825 #endif
826 */
827
828 #if ESOCK_COUNTER_SIZE == 16
829
830 typedef Uint16 ESockCounter;
831 #define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFF)
832 #define MKCNT(ENV, CNT) MKUI((ENV), (CNT))
833 #define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((CNT)))
834 #define ESOCK_COUNTER_FORMAT_STR "%u"
835
836 #elif ESOCK_COUNTER_SIZE == 24
837
838 typedef Uint32 ESockCounter;
839 #define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFF)
840 #define MKCNT(ENV, CNT) MKUI((ENV), (CNT))
841 #define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT)))
842 #define ESOCK_COUNTER_FORMAT_STR "%lu"
843
844 #elif ESOCK_COUNTER_SIZE == 32
845
846 typedef Uint32 ESockCounter;
847 #define ESOCK_COUNTER_MAX (~((ESockCounter) 0))
848 #define MKCNT(ENV, CNT) MKUI((ENV), (CNT))
849 #define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT)))
850 #define ESOCK_COUNTER_FORMAT_STR "%lu"
851
852 #elif ESOCK_COUNTER_SIZE == 48
853
854 typedef Uint64 ESockCounter;
855 #define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFFFFFFFF)
856 #define MKCNT(ENV, CNT) MKUI64((ENV), (CNT))
857 #define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT)))
858 #define ESOCK_COUNTER_FORMAT_STR "%llu"
859
860 #elif ESOCK_COUNTER_SIZE == 64
861
862 typedef Uint64 ESockCounter;
863 #define ESOCK_COUNTER_MAX (~((ESockCounter) 0))
864 #define MKCNT(ENV, CNT) MKUI64((ENV), (CNT))
865 #define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT)))
866 #define ESOCK_COUNTER_FORMAT_STR "%llu"
867
868 #else
869
870 #error "Invalid counter size"
871
872 #endif
873
874 // static const ESockCounter esock_counter_max = ESOCK_COUNTER_MAX;
875
876 #ifdef HAVE_SENDFILE
877
878 typedef struct {
879 ESockCounter cnt; // Calls to OS sendfile()
880 ESockCounter byteCnt; // Bytes sent with sendfile
881 ESockCounter fails; // Failed sendfile operations
882 ESockCounter max; // Largest sendfile operation
883 ESockCounter maxCnt; // Counter for ="=
884 ESockCounter pkg; // Sendfile chunks
885 ESockCounter pkgMax; // Largest sendfile chunk
886 ESockCounter tries; // Started sendfile operations
887 ESockCounter waits; // Select's during sendfile
888 } ESockSendfileCounters;
889 static ESockSendfileCounters initESockSendfileCounters =
890 {0, 0, 0, 0, 0, 0, 0, 0, 0};
891
892 #endif
893
894
895 typedef struct {
896 /*
897 * +++ This is a way to, possibly, detect memory overrides "and stuff" +++
898 *
899 * We have two patterns. One is set when the descriptor is created
900 * (allocated) and one is set when the descriptor is dtor'ed.
901 */
902 Uint32 pattern;
903
904 /* +++ Stuff "about" the socket +++ */
905
906 /* "Constant" - set when socket is created and never changed */
907 int domain;
908 int type;
909 int protocol;
910
911 /* The state is partly for debugging, decisions are made often
912 * based on other variables. The state is divided in
913 * a readState half and a writeState half that can be
914 * OR:ed together to create the complete state.
915 * The halves are locked by their corresponding lock.
916 */
917
918 /* +++ Write stuff +++ */
919 ErlNifMutex* writeMtx;
920 /**/
921 unsigned int writeState; // For debugging
922 ESockRequestor currentWriter;
923 ESockRequestor* currentWriterP; // NULL or ¤tWriter
924 ESockRequestQueue writersQ;
925 ESockCounter writePkgCnt;
926 ESockCounter writePkgMax;
927 ESockCounter writePkgMaxCnt;
928 ESockCounter writeByteCnt;
929 ESockCounter writeTries;
930 ESockCounter writeWaits;
931 ESockCounter writeFails;
932 #ifdef HAVE_SENDFILE
933 HANDLE sendfileHandle;
934 ESockSendfileCounters* sendfileCountersP;
935 #endif
936 /* +++ Connector +++ */
937 ESockRequestor connector;
938 ESockRequestor* connectorP; // NULL or &connector
939 /* +++ Config stuff +++ */
940 size_t wCtrlSz; // Write control buffer size
941 ESockMeta meta; // Level 'otp' option 'meta' term
942
943 /* +++ Read stuff +++ */
944 ErlNifMutex* readMtx;
945 /**/
946 unsigned int readState; // For debugging
947 ESockRequestor currentReader;
948 ESockRequestor* currentReaderP; // NULL or ¤tReader
949 ESockRequestQueue readersQ;
950 ErlNifBinary rbuffer; // DO WE NEED THIS
951 Uint32 readCapacity; // DO WE NEED THIS
952 ESockCounter readPkgCnt;
953 ESockCounter readPkgMax;
954 ESockCounter readPkgMaxCnt;
955 ESockCounter readByteCnt;
956 ESockCounter readTries;
957 ESockCounter readWaits;
958 ESockCounter readFails;
959 /* +++ Accept stuff +++ */
960 ESockRequestor currentAcceptor;
961 ESockRequestor* currentAcceptorP; // NULL or ¤tAcceptor
962 ESockRequestQueue acceptorsQ;
963 ESockCounter accSuccess;
964 ESockCounter accTries;
965 ESockCounter accWaits;
966 ESockCounter accFails;
967 /* +++ Config stuff +++ */
968 size_t rBufSz; // Read buffer size (when data length = 0)
969 /* rNum and rNumCnt are used (together with rBufSz) when calling the recv
970 * function with the Length argument set to 0 (zero).
971 * If rNum is 0 (zero), then rNumCnt is not used and only *one* read will
972 * be done. Also, when get'ing the value of the option (rcvbuf) with
973 * getopt, the value will be reported as an integer. If the rNum has a
974 * value greater then 0 (zero), then it will instead be reported as {N, BufSz}.
975 */
976 unsigned int rNum; // recv: Number of reads using rBufSz
977 unsigned int rNumCnt; // recv: Current number of reads (so far)
978 size_t rCtrlSz; // Read control buffer size
979
980 /* Locked by readMtx and writeMtx combined for writing,
981 * which means only one of them is required for reading
982 */
983 /* +++ Close stuff +++ */
984 ErlNifPid closerPid;
985 ESockMonitor closerMon;
986 ErlNifEnv* closeEnv;
987 ERL_NIF_TERM closeRef;
988 /* +++ Inform On (counter) Wrap +++ */
989 BOOLEAN_T iow;
990 /* +++ Controller (owner) process +++ */
991 ErlNifPid ctrlPid;
992 ESockMonitor ctrlMon;
993 /* +++ The actual socket +++ */
994 SOCKET sock;
995 ErlNifEvent event;
996 SOCKET origFD; // A 'socket' created from this FD
997 BOOLEAN_T closeOnClose; // Have we dup'ed or not
998 /* +++ The dbg flag for SSDBG +++ */
999 BOOLEAN_T dbg;
1000 BOOLEAN_T useReg;
1001
1002 /* Lock order: readMtx, writeMtx, cntMtx
1003 */
1004 } ESockDescriptor;
1005
1006
1007 /* Global stuff.
1008 */
1009 typedef struct {
1010 /* These are for debugging, testing and the like */
1011 // ERL_NIF_TERM version;
1012 // ERL_NIF_TERM buildDate;
1013
1014 /* XXX Should be locked but too awkward and small gain */
1015 BOOLEAN_T dbg;
1016 BOOLEAN_T useReg;
1017
1018 /* Registry stuff */
1019 ErlNifPid regPid; /* Constant - not locked */
1020
1021 /* IOV_MAX. Constant - not locked */
1022 int iov_max;
1023
1024 /* XXX
1025 * Should be locked but too awkward for no gain since it is not used yet
1026 */
1027 BOOLEAN_T iow; // Where do we send this? Subscription?
1028
1029 ErlNifMutex* protocolsMtx;
1030
1031 ErlNifMutex* cntMtx; /* Locks the below */
1032 /* Its extreme overkill to have these counters be 64-bit,
1033 * but since the other counters are, it's much simpler to
1034 * let these be 64-bit also.
1035 */
1036 ESockCounter numSockets;
1037 ESockCounter numTypeStreams;
1038 ESockCounter numTypeDGrams;
1039 ESockCounter numTypeSeqPkgs;
1040 ESockCounter numDomainInet;
1041 ESockCounter numDomainInet6;
1042 ESockCounter numDomainLocal;
1043 ESockCounter numProtoIP;
1044 ESockCounter numProtoTCP;
1045 ESockCounter numProtoUDP;
1046 ESockCounter numProtoSCTP;
1047 //
1048 BOOLEAN_T sockDbg;
1049 } ESockData;
1050
1051
1052 /* ----------------------------------------------------------------------
1053 * F o r w a r d s
1054 * ----------------------------------------------------------------------
1055 */
1056
1057
1058 extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */
1059
1060
1061 /* All the nif "callback" functions for the socket API has
1062 * the exact same API:
1063 *
1064 * nif_<funcname>(ErlNifEnv* env,
1065 * int argc,
1066 * const ERL_NIF_TERM argv[]);
1067 *
1068 * So, to simplify, use some macro magic to define those.
1069 *
1070 * These are the functions making up the "official" API.
1071 * Basically, these functions does some preliminary checks and argument
1072 * extractions and then call the functions called 'n<funcname>', which
1073 * does the actual work. Except for the info function.
1074 *
1075 * nif_info
1076 * nif_command
1077 * nif_supports
1078 * nif_open
1079 * nif_bind
1080 * nif_connect
1081 * nif_listen
1082 * nif_accept
1083 * nif_send
1084 * nif_sendto
1085 * nif_sendmsg
1086 * nif_sendfile
1087 * nif_recv
1088 * nif_recvfrom
1089 * nif_recvmsg
1090 * nif_close
1091 * nif_shutdown
1092 * nif_setopt
1093 * nif_getopt
1094 * nif_sockname
1095 * nif_peername
1096 * nif_finalize_close
1097 * nif_cancel
1098 */
1099
1100 #define ESOCK_NIF_FUNCS \
1101 ESOCK_NIF_FUNC_DEF(info); \
1102 ESOCK_NIF_FUNC_DEF(command); \
1103 ESOCK_NIF_FUNC_DEF(supports); \
1104 ESOCK_NIF_FUNC_DEF(open); \
1105 ESOCK_NIF_FUNC_DEF(bind); \
1106 ESOCK_NIF_FUNC_DEF(connect); \
1107 ESOCK_NIF_FUNC_DEF(listen); \
1108 ESOCK_NIF_FUNC_DEF(accept); \
1109 ESOCK_NIF_FUNC_DEF(send); \
1110 ESOCK_NIF_FUNC_DEF(sendto); \
1111 ESOCK_NIF_FUNC_DEF(sendmsg); \
1112 ESOCK_NIF_FUNC_DEF(recv); \
1113 ESOCK_NIF_FUNC_DEF(recvfrom); \
1114 ESOCK_NIF_FUNC_DEF(recvmsg); \
1115 ESOCK_NIF_FUNC_DEF(close); \
1116 ESOCK_NIF_FUNC_DEF(shutdown); \
1117 ESOCK_NIF_FUNC_DEF(setopt); \
1118 ESOCK_NIF_FUNC_DEF(getopt); \
1119 ESOCK_NIF_FUNC_DEF(sockname); \
1120 ESOCK_NIF_FUNC_DEF(peername); \
1121 ESOCK_NIF_FUNC_DEF(finalize_close); \
1122 ESOCK_NIF_FUNC_DEF(cancel);
1123
1124 #define ESOCK_NIF_FUNC_DEF(F) \
1125 static ERL_NIF_TERM nif_##F(ErlNifEnv* env, \
1126 int argc, \
1127 const ERL_NIF_TERM argv[]);
1128 ESOCK_NIF_FUNCS
1129 #undef ESOCK_NIF_FUNC_DEF
1130
1131
1132 #ifndef __WIN32__
1133 /* ---------------------------------------------------------------------- *
1134 * *
1135 * *
1136 * Start of non-__WIN32__ section a.k.a UNIX section *
1137 * *
1138 * *
1139 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
1140
1141 /* And here comes the functions that does the actual work (for the most part) */
1142
1143 static ERL_NIF_TERM esock_command(ErlNifEnv* env,
1144 ERL_NIF_TERM command,
1145 ERL_NIF_TERM cdata);
1146 static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env,
1147 ERL_NIF_TERM cdata);
1148 static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env,
1149 ERL_NIF_TERM cdata);
1150 static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env,
1151 ERL_NIF_TERM cdata);
1152
1153 static ERL_NIF_TERM esock_global_info(ErlNifEnv* env);
1154 static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
1155 ESockDescriptor* descP);
1156 static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env,
1157 ESockDescriptor* descP);
1158 static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env,
1159 ESockDescriptor* descP);
1160 static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
1161 ESockDescriptor* descP);
1162 static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env,
1163 ESockDescriptor* descP);
1164 static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env,
1165 unsigned int state);
1166 #define ESOCK_SOCKET_INFO_REQ_FUNCS \
1167 ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \
1168 ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \
1169 ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors);
1170
1171 #define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \
1172 static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \
1173 ESockDescriptor* descP);
1174 ESOCK_SOCKET_INFO_REQ_FUNCS
1175 #undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF
1176
1177 static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env,
1178 ESockDescriptor* descP,
1179 ESockRequestor* currentRequestorP,
1180 ESockRequestQueue* q);
1181
1182 static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env);
1183 static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key);
1184
1185 static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env);
1186 static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env);
1187 static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env);
1188
1189 static ERL_NIF_TERM esock_open2(ErlNifEnv* env,
1190 int fd,
1191 ERL_NIF_TERM eextra);
1192 static BOOLEAN_T esock_open2_todup(ErlNifEnv* env,
1193 ERL_NIF_TERM eextra);
1194 static BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env,
1195 ERL_NIF_TERM eopts,
1196 int* domain);
1197 static BOOLEAN_T esock_open2_get_type(ErlNifEnv* env,
1198 ERL_NIF_TERM eopt,
1199 int* type);
1200 static ERL_NIF_TERM esock_open4(ErlNifEnv* env,
1201 int domain,
1202 int type,
1203 int protocol,
1204 ERL_NIF_TERM eopts);
1205 static BOOLEAN_T esock_open_is_debug(ErlNifEnv* env,
1206 ERL_NIF_TERM eextra,
1207 BOOLEAN_T dflt);
1208 static BOOLEAN_T esock_open_use_registry(ErlNifEnv* env,
1209 ERL_NIF_TERM eextra,
1210 BOOLEAN_T dflt);
1211 static BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain);
1212 static BOOLEAN_T esock_open_which_type(SOCKET sock, int* type);
1213 static BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto);
1214
1215 static ERL_NIF_TERM esock_bind(ErlNifEnv* env,
1216 ESockDescriptor* descP,
1217 ESockAddress* sockAddrP,
1218 SOCKLEN_T addrLen);
1219 static ERL_NIF_TERM esock_connect(ErlNifEnv* env,
1220 ESockDescriptor* descP,
1221 ERL_NIF_TERM sockRef,
1222 ERL_NIF_TERM connRef,
1223 ESockAddress* addrP,
1224 SOCKLEN_T addrLen);
1225 static ERL_NIF_TERM esock_listen(ErlNifEnv* env,
1226 ESockDescriptor* descP,
1227 int backlog);
1228 static ERL_NIF_TERM esock_accept(ErlNifEnv* env,
1229 ESockDescriptor* descP,
1230 ERL_NIF_TERM sockRef,
1231 ERL_NIF_TERM ref);
1232 static ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
1233 ESockDescriptor* descP,
1234 ERL_NIF_TERM sockRef,
1235 ERL_NIF_TERM accRef,
1236 ErlNifPid caller,
1237 int save_errno);
1238 static ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
1239 ESockDescriptor* descP,
1240 ERL_NIF_TERM sockRef,
1241 SOCKET accSock,
1242 ErlNifPid caller);
1243 static ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env,
1244 ESockDescriptor* descP,
1245 ERL_NIF_TERM sockRef,
1246 ERL_NIF_TERM ref);
1247 static ERL_NIF_TERM
1248 esock_accept_accepting_current_accept(ErlNifEnv* env,
1249 ESockDescriptor* descP,
1250 ERL_NIF_TERM sockRef,
1251 SOCKET accSock);
1252 static ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
1253 ESockDescriptor* descP,
1254 ERL_NIF_TERM sockRef,
1255 ERL_NIF_TERM opRef,
1256 int save_errno);
1257 static ERL_NIF_TERM esock_accept_accepting_other(ErlNifEnv* env,
1258 ESockDescriptor* descP,
1259 ERL_NIF_TERM ref,
1260 ErlNifPid caller);
1261 static ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
1262 ESockDescriptor* descP,
1263 ERL_NIF_TERM sockRef,
1264 ERL_NIF_TERM accRef,
1265 ErlNifPid* pidP);
1266 static BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
1267 ESockDescriptor* descP,
1268 ERL_NIF_TERM sockRef,
1269 SOCKET accSock,
1270 ErlNifPid pid,
1271 ERL_NIF_TERM* result);
1272 static ERL_NIF_TERM esock_send(ErlNifEnv* env,
1273 ESockDescriptor* descP,
1274 ERL_NIF_TERM sockRef,
1275 ERL_NIF_TERM sendRef,
1276 ErlNifBinary* dataP,
1277 int flags);
1278 static ERL_NIF_TERM esock_sendto(ErlNifEnv* env,
1279 ESockDescriptor* descP,
1280 ERL_NIF_TERM sockRef,
1281 ERL_NIF_TERM sendRef,
1282 ErlNifBinary* dataP,
1283 int flags,
1284 ESockAddress* toAddrP,
1285 SOCKLEN_T toAddrLen);
1286 static ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
1287 ESockDescriptor* descP,
1288 ERL_NIF_TERM sockRef,
1289 ERL_NIF_TERM sendRef,
1290 ERL_NIF_TERM eMsg,
1291 int flags,
1292 ERL_NIF_TERM eIOV);
1293
1294 #ifdef HAVE_SENDFILE
1295 static ERL_NIF_TERM
1296 esock_sendfile_start(ErlNifEnv *env,
1297 ESockDescriptor *descP,
1298 ERL_NIF_TERM sockRef,
1299 ERL_NIF_TERM sendRef,
1300 off_t offset,
1301 size_t count,
1302 ERL_NIF_TERM fRef);
1303 static ERL_NIF_TERM
1304 esock_sendfile_cont(ErlNifEnv *env,
1305 ESockDescriptor *descP,
1306 ERL_NIF_TERM sockRef,
1307 ERL_NIF_TERM sendRef,
1308 off_t offset,
1309 size_t count);
1310 static ERL_NIF_TERM
1311 esock_sendfile_deferred_close(ErlNifEnv *env,
1312 ESockDescriptor *descP);
1313 static int
1314 esock_sendfile(ErlNifEnv *env,
1315 ESockDescriptor *descP,
1316 ERL_NIF_TERM sockRef,
1317 off_t offset,
1318 size_t *count,
1319 int *errP);
1320 static ERL_NIF_TERM
1321 esock_sendfile_error(ErlNifEnv *env,
1322 ESockDescriptor *descP,
1323 ERL_NIF_TERM sockRef,
1324 ERL_NIF_TERM reason);
1325 static ERL_NIF_TERM
1326 esock_sendfile_errno(ErlNifEnv *env,
1327 ESockDescriptor *descP,
1328 ERL_NIF_TERM sockRef,
1329 int err);
1330 static ERL_NIF_TERM
1331 esock_sendfile_ok(ErlNifEnv *env,
1332 ESockDescriptor *descP,
1333 ERL_NIF_TERM sockRef,
1334 size_t count);
1335 static ERL_NIF_TERM
1336 esock_sendfile_select(ErlNifEnv *env,
1337 ESockDescriptor *descP,
1338 ERL_NIF_TERM sockRef,
1339 ERL_NIF_TERM sendRef,
1340 size_t count);
1341 #endif // #ifdef HAVE_SENDFILE
1342
1343 static ERL_NIF_TERM esock_recv(ErlNifEnv* env,
1344 ESockDescriptor* descP,
1345 ERL_NIF_TERM sendRef,
1346 ERL_NIF_TERM recvRef,
1347 ssize_t len,
1348 int flags);
1349 static ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
1350 ESockDescriptor* descP,
1351 ERL_NIF_TERM sockRef,
1352 ERL_NIF_TERM recvRef,
1353 ssize_t bufSz,
1354 int flags);
1355 static ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
1356 ESockDescriptor* descP,
1357 ERL_NIF_TERM sockRef,
1358 ERL_NIF_TERM recvRef,
1359 ssize_t bufLen,
1360 ssize_t ctrlLen,
1361 int flags);
1362 static ERL_NIF_TERM esock_close(ErlNifEnv* env,
1363 ESockDescriptor* descP);
1364 static BOOLEAN_T esock_do_stop(ErlNifEnv* env,
1365 ESockDescriptor* descP);
1366 static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env,
1367 ESockDescriptor* descP,
1368 int how);
1369
1370
1371 /* Set OTP level options */
1372 static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
1373 ESockDescriptor* descP,
1374 int eOpt,
1375 ERL_NIF_TERM eVal);
1376 /* *** esock_setopt_otp_debug ***
1377 * *** esock_setopt_otp_iow ***
1378 * *** esock_setopt_otp_ctrl_proc ***
1379 * *** esock_setopt_otp_rcvbuf ***
1380 * *** esock_setopt_otp_rcvctrlbuf ***
1381 * *** esock_setopt_otp_sndctrlbuf ***
1382 * *** esock_setopt_otp_meta ***
1383 * *** esock_setopt_otp_use_registry ***
1384 */
1385 #define ESOCK_SETOPT_OTP_FUNCS \
1386 ESOCK_SETOPT_OTP_FUNC_DEF(debug); \
1387 ESOCK_SETOPT_OTP_FUNC_DEF(iow); \
1388 ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \
1389 ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \
1390 ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
1391 ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf); \
1392 ESOCK_SETOPT_OTP_FUNC_DEF(meta); \
1393 ESOCK_SETOPT_OTP_FUNC_DEF(use_registry);
1394 #define ESOCK_SETOPT_OTP_FUNC_DEF(F) \
1395 static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \
1396 ESockDescriptor* descP, \
1397 ERL_NIF_TERM eVal)
1398 ESOCK_SETOPT_OTP_FUNCS
1399 #undef ESOCK_SETOPT_OTP_FUNC_DEF
1400
1401 /* Set native options */
1402 static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env,
1403 ESockDescriptor* descP,
1404 int level,
1405 int opt,
1406 ERL_NIF_TERM eVal);
1407 static ERL_NIF_TERM esock_setopt(ErlNifEnv* env,
1408 ESockDescriptor* descP,
1409 int level,
1410 int opt,
1411 ERL_NIF_TERM eVal);
1412
1413 /* *** Handling set of socket options for level = socket *** */
1414
1415 #if defined(SO_BINDTODEVICE)
1416 static ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env,
1417 ESockDescriptor* descP,
1418 int level,
1419 int opt,
1420 ERL_NIF_TERM eVal);
1421 #endif
1422
1423 #if defined(SO_LINGER)
1424 static
1425 ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env,
1426 ESockDescriptor* descP,
1427 int level,
1428 int opt,
1429 ERL_NIF_TERM eVal);
1430 static
1431 ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env,
1432 ESockDescriptor* descP,
1433 int level,
1434 int opt);
1435 #endif
1436
1437 #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
1438 static ERL_NIF_TERM esock_setopt_msfilter(ErlNifEnv* env,
1439 ESockDescriptor* descP,
1440 int level,
1441 int opt,
1442 ERL_NIF_TERM eVal);
1443 static BOOLEAN_T decode_msfilter_mode(ErlNifEnv* env,
1444 ERL_NIF_TERM eVal,
1445 Uint32* mode);
1446 #endif
1447 #if defined(IP_MTU_DISCOVER)
1448 static ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env,
1449 ESockDescriptor* descP,
1450 int level,
1451 int opt,
1452 ERL_NIF_TERM eVal);
1453 #endif
1454 #if defined(IP_MULTICAST_IF)
1455 static ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env,
1456 ESockDescriptor* descP,
1457 int level,
1458 int opt,
1459 ERL_NIF_TERM eVal);
1460 #endif
1461
1462 #if defined(IP_TOS)
1463 static ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env,
1464 ESockDescriptor* descP,
1465 int level,
1466 int opt,
1467 ERL_NIF_TERM eVal);
1468 #endif
1469
1470 #if defined(IP_DROP_MEMBERSHIP) || defined(IP_ADD_MEMBERSHIP)
1471 static
1472 ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env,
1473 ESockDescriptor* descP,
1474 int level,
1475 int opt,
1476 ERL_NIF_TERM eVal);
1477 #endif
1478 #if defined(IP_ADD_SOURCE_MEMBERSHIP) || defined(IP_DROP_SOURCE_MEMBERSHIP) || defined(IP_BLOCK_SOURCE) || defined(IP_UNBLOCK_SOURCE)
1479 static
1480 ERL_NIF_TERM esock_setopt_in_update_source(ErlNifEnv* env,
1481 ESockDescriptor* descP,
1482 int level,
1483 int opt,
1484 ERL_NIF_TERM eVal);
1485 #endif
1486
1487
1488 /* *** Handling set of socket options for level = ipv6 *** */
1489 #if defined(HAVE_IPV6)
1490
1491 #if defined(IPV6_ADDRFORM)
1492 static ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env,
1493 ESockDescriptor* descP,
1494 int level,
1495 int opt,
1496 ERL_NIF_TERM eVal);
1497 #endif
1498 #if defined(IPV6_MTU_DISCOVER)
1499 static ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env,
1500 ESockDescriptor* descP,
1501 int level,
1502 int opt,
1503 ERL_NIF_TERM eVal);
1504 #endif
1505 #if defined(IPV6_MULTICAST_HOPS)
1506 static ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env,
1507 ESockDescriptor* descP,
1508 int level,
1509 int opt,
1510 ERL_NIF_TERM eVal);
1511 #endif
1512
1513 #if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
1514 static ERL_NIF_TERM
1515 esock_setopt_in6_update_membership(ErlNifEnv* env,
1516 ESockDescriptor* descP,
1517 int level,
1518 int opt,
1519 ERL_NIF_TERM eVal);
1520 #endif
1521
1522 #endif // defined(HAVE_IPV6)
1523
1524
1525 #if defined(TCP_CONGESTION)
1526 static ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env,
1527 ESockDescriptor* descP,
1528 int level,
1529 int opt,
1530 ERL_NIF_TERM eVal);
1531 #endif
1532
1533
1534 #if defined(HAVE_SCTP)
1535
1536 #if defined(SCTP_ASSOCINFO)
1537 static ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env,
1538 ESockDescriptor* descP,
1539 int level,
1540 int opt,
1541 ERL_NIF_TERM eVal);
1542 #endif
1543 #if defined(SCTP_EVENTS)
1544 static ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env,
1545 ESockDescriptor* descP,
1546 int level,
1547 int opt,
1548 ERL_NIF_TERM eVal);
1549 static int esock_setopt_sctp_event(ErlNifEnv *env,
1550 ERL_NIF_TERM eMap,
1551 ERL_NIF_TERM eKey,
1552 BOOLEAN_T *failure);
1553 #endif
1554 #if defined(SCTP_INITMSG)
1555 static ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env,
1556 ESockDescriptor* descP,
1557 int level,
1558 int opt,
1559 ERL_NIF_TERM eVal);
1560 #endif
1561 #if defined(SCTP_RTOINFO)
1562 static ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env,
1563 ESockDescriptor* descP,
1564 int level,
1565 int opt,
1566 ERL_NIF_TERM eVal);
1567 #endif
1568
1569 #endif // defined(HAVE_SCTP)
1570
1571
1572 static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
1573 ESockDescriptor* descP,
1574 int eOpt);
1575 /* *** esock_getopt_otp_debug ***
1576 * *** esock_getopt_otp_iow ***
1577 * *** esock_getopt_otp_ctrl_proc ***
1578 * *** esock_getopt_otp_rcvbuf ***
1579 * *** esock_getopt_otp_rcvctrlbuf ***
1580 * *** esock_getopt_otp_sndctrlbuf ***
1581 * *** esock_getopt_otp_fd ***
1582 * *** esock_getopt_otp_meta ***
1583 * *** esock_getopt_otp_use_registry ***
1584 * *** esock_getopt_otp_domain ***
1585 * *** //esock_getopt_otp_type ***
1586 * *** //esock_getopt_otp_protocol ***
1587 * *** //esock_getopt_otp_dtp ***
1588 */
1589 #define ESOCK_GETOPT_OTP_FUNCS \
1590 ESOCK_GETOPT_OTP_FUNC_DEF(debug); \
1591 ESOCK_GETOPT_OTP_FUNC_DEF(iow); \
1592 ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \
1593 ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \
1594 ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
1595 ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \
1596 ESOCK_GETOPT_OTP_FUNC_DEF(fd); \
1597 ESOCK_GETOPT_OTP_FUNC_DEF(meta); \
1598 ESOCK_GETOPT_OTP_FUNC_DEF(use_registry); \
1599 ESOCK_GETOPT_OTP_FUNC_DEF(domain);
1600 #if 0
1601 ESOCK_GETOPT_OTP_FUNC_DEF(type); \
1602 ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \
1603 ESOCK_GETOPT_OTP_FUNC_DEF(dtp);
1604 #endif
1605 #define ESOCK_GETOPT_OTP_FUNC_DEF(F) \
1606 static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \
1607 ESockDescriptor* descP)
1608 ESOCK_GETOPT_OTP_FUNCS
1609 #undef ESOCK_GETOPT_OTP_FUNC_DEF
1610
1611 static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env,
1612 ESockDescriptor* descP,
1613 int level,
1614 int opt,
1615 ERL_NIF_TERM valueSpec);
1616 static ERL_NIF_TERM esock_getopt(ErlNifEnv* env,
1617 ESockDescriptor* descP,
1618 int level,
1619 int opt);
1620
1621 #if defined(SO_BINDTODEVICE)
1622 static ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env,
1623 ESockDescriptor* descP,
1624 int level,
1625 int opt);
1626 #endif
1627 #if defined(SO_DOMAIN)
1628 static ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env,
1629 ESockDescriptor* descP,
1630 int level,
1631 int opt);
1632 #endif
1633
1634 #if defined(SO_TYPE)
1635 static
1636 ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env,
1637 ESockDescriptor* descP,
1638 int level,
1639 int opt);
1640 #endif
1641
1642 #if defined(SO_PROTOCOL)
1643 static
1644 ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env,
1645 ESockDescriptor* descP,
1646 int level,
1647 int opt);
1648 #endif
1649
1650 #if defined(IP_MTU_DISCOVER)
1651 static ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env,
1652 ESockDescriptor* descP,
1653 int level,
1654 int opt);
1655 #endif
1656 #if defined(IP_MULTICAST_IF)
1657 static ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env,
1658 ESockDescriptor* descP,
1659 int level,
1660 int opt);
1661 #endif
1662 #if defined(IP_TOS)
1663 static ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env,
1664 ESockDescriptor* descP,
1665 int level,
1666 int opt);
1667 #endif
1668
1669
1670 #if defined(HAVE_IPV6)
1671
1672 #if defined(IPV6_MTU_DISCOVER)
1673 static ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env,
1674 ESockDescriptor* descP,
1675 int level,
1676 int opt);
1677 #endif
1678
1679 #endif // defined(HAVE_IPV6)
1680
1681 #if defined(IP_PKTOPTIONS) || defined(IPV6_PKTOPTIONS)
1682 static ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env,
1683 ESockDescriptor* descP,
1684 int level,
1685 int opt);
1686 #endif
1687
1688 #if defined(TCP_CONGESTION)
1689 static ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env,
1690 ESockDescriptor* descP,
1691 int level,
1692 int opt);
1693 #endif
1694
1695
1696 #if defined(HAVE_SCTP)
1697
1698 #if defined(SCTP_ASSOCINFO)
1699 static ERL_NIF_TERM esock_getopt_sctp_associnfo(ErlNifEnv* env,
1700 ESockDescriptor* descP,
1701 int level,
1702 int opt);
1703 #endif
1704 #if defined(SCTP_INITMSG)
1705 static ERL_NIF_TERM esock_getopt_sctp_initmsg(ErlNifEnv* env,
1706 ESockDescriptor* descP,
1707 int level,
1708 int opt);
1709 #endif
1710 #if defined(SCTP_RTOINFO)
1711 static ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env,
1712 ESockDescriptor* descP,
1713 int level,
1714 int opt);
1715 #endif
1716
1717 #endif // defined(HAVE_SCTP)
1718
1719
1720 static ERL_NIF_TERM esock_sockname(ErlNifEnv* env,
1721 ESockDescriptor* descP);
1722 static ERL_NIF_TERM esock_peername(ErlNifEnv* env,
1723 ESockDescriptor* descP);
1724 static ERL_NIF_TERM esock_cancel(ErlNifEnv* env,
1725 ESockDescriptor* descP,
1726 ERL_NIF_TERM op,
1727 ERL_NIF_TERM sockRef,
1728 ERL_NIF_TERM opRef);
1729 static ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env,
1730 ESockDescriptor* descP,
1731 ERL_NIF_TERM opRef);
1732 static ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env,
1733 ESockDescriptor* descP,
1734 ERL_NIF_TERM sockRef,
1735 ERL_NIF_TERM opRef);
1736 static ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
1737 ESockDescriptor* descP,
1738 ERL_NIF_TERM sockRef);
1739 static ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env,
1740 ESockDescriptor* descP,
1741 ERL_NIF_TERM opRef,
1742 const ErlNifPid* selfP);
1743 static ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env,
1744 ESockDescriptor* descP,
1745 ERL_NIF_TERM sockRef,
1746 ERL_NIF_TERM opRef);
1747 static ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env,
1748 ESockDescriptor* descP,
1749 ERL_NIF_TERM sockRef);
1750 static ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env,
1751 ESockDescriptor* descP,
1752 ERL_NIF_TERM opRef,
1753 const ErlNifPid* selfP);
1754 static ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env,
1755 ESockDescriptor* descP,
1756 ERL_NIF_TERM sockRef,
1757 ERL_NIF_TERM opRef);
1758 static ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
1759 ESockDescriptor* descP,
1760 ERL_NIF_TERM sockRef);
1761 static ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env,
1762 ESockDescriptor* descP,
1763 ERL_NIF_TERM opRef,
1764 const ErlNifPid* selfP);
1765 static ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env,
1766 ESockDescriptor* descP,
1767 ERL_NIF_TERM opRef);
1768 static ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env,
1769 ESockDescriptor* descP,
1770 ERL_NIF_TERM opRef);
1771 static ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env,
1772 ESockDescriptor* descP,
1773 ERL_NIF_TERM opRef,
1774 int smode,
1775 int rmode);
1776
1777 #if defined(USE_SETOPT_STR_OPT)
1778 static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env,
1779 ESockDescriptor* descP,
1780 int level,
1781 int opt,
1782 int max,
1783 ERL_NIF_TERM eVal);
1784 #endif
1785 static ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env,
1786 ESockDescriptor* descP,
1787 int level,
1788 int opt,
1789 ERL_NIF_TERM eVal);
1790 static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env,
1791 ESockDescriptor* descP,
1792 int level,
1793 int opt,
1794 ERL_NIF_TERM eVal);
1795 #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \
1796 && defined(ESOCK_USE_RCVSNDTIMEO)
1797 static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env,
1798 ESockDescriptor* descP,
1799 int level,
1800 int opt,
1801 ERL_NIF_TERM eVal);
1802 #endif
1803 static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env,
1804 ESockDescriptor* descP,
1805 int level,
1806 int opt,
1807 void* optVal,
1808 socklen_t optLen);
1809
1810 #if defined(USE_GETOPT_STR_OPT)
1811 static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env,
1812 ESockDescriptor* descP,
1813 int level,
1814 int opt,
1815 int max,
1816 BOOLEAN_T stripNUL);
1817 #endif
1818 static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env,
1819 ESockDescriptor* descP,
1820 int level,
1821 int opt);
1822 static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env,
1823 ESockDescriptor* descP,
1824 int level,
1825 int opt);
1826 static BOOLEAN_T esock_getopt_int(SOCKET sock,
1827 int level,
1828 int opt,
1829 int* valP);
1830 static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env,
1831 ESockDescriptor* descP,
1832 int level,
1833 int opt,
1834 SOCKOPTLEN_T valueSz);
1835 static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env,
1836 ESockDescriptor* descP,
1837 int level,
1838 int opt,
1839 ErlNifBinary* binP);
1840 #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \
1841 && defined(ESOCK_USE_RCVSNDTIMEO)
1842 static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env,
1843 ESockDescriptor* descP,
1844 int level,
1845 int opt);
1846 #endif
1847
1848
1849
1850 /* ------------------------------------------------------------------------
1851 * Socket option tables and handling
1852 */
1853
1854 struct ESockOpt
1855 {
1856 int opt; // Option number
1857
1858 // Function to set option
1859 ERL_NIF_TERM (*setopt)
1860 (ErlNifEnv *env, ESockDescriptor *descP,
1861 int level, int opt, ERL_NIF_TERM eVal);
1862
1863 // Function to get option
1864 ERL_NIF_TERM (*getopt)
1865 (ErlNifEnv *env, ESockDescriptor *descP,
1866 int level, int opt);
1867
1868 ERL_NIF_TERM *nameP; // Pointer to option name atom
1869 };
1870
1871 // qsort and bsearch helper
cmpESockOpt(const void * vpa,const void * vpb)1872 static int cmpESockOpt(const void *vpa, const void *vpb) {
1873 struct ESockOpt *a, *b;
1874 a = (struct ESockOpt *) vpa;
1875 b = (struct ESockOpt *) vpb;
1876 return a->opt < b->opt ? -1 : (a->opt > b->opt ? 1 : 0);
1877 }
1878
1879
1880 /* SO_* options -------------------------------------------------------- */
1881
1882 static struct ESockOpt optLevelSocket[] =
1883 {
1884 {
1885 #ifdef SO_ACCEPTCONN
1886 SO_ACCEPTCONN,
1887 esock_setopt_bool_opt, esock_getopt_bool_opt,
1888 #else
1889 0, NULL, NULL,
1890 #endif
1891 &esock_atom_acceptconn},
1892
1893 {0, NULL, NULL, &esock_atom_acceptfilter},
1894
1895 {
1896 #ifdef SO_BINDTODEVICE
1897 SO_BINDTODEVICE,
1898 esock_setopt_so_bindtodevice, esock_getopt_so_bindtodevice,
1899 #else
1900 0, NULL, NULL,
1901 #endif
1902 &esock_atom_bindtodevice},
1903
1904 {
1905 #ifdef SO_BROADCAST
1906 SO_BROADCAST,
1907 esock_setopt_bool_opt, esock_getopt_bool_opt,
1908 #else
1909 0, NULL, NULL,
1910 #endif
1911 &esock_atom_broadcast},
1912
1913 {0, NULL, NULL, &esock_atom_busy_poll},
1914
1915 {
1916 #ifdef SO_DEBUG
1917 SO_DEBUG,
1918 esock_setopt_int_opt, esock_getopt_int_opt,
1919 #else
1920 0, NULL, NULL,
1921 #endif
1922 &esock_atom_debug},
1923
1924 {
1925 #ifdef SO_DOMAIN
1926 SO_DOMAIN,
1927 NULL, esock_getopt_sock_domain,
1928 #else
1929 0, NULL, NULL,
1930 #endif
1931 &esock_atom_domain},
1932
1933 {
1934 #ifdef SO_DONTROUTE
1935 SO_DONTROUTE,
1936 esock_setopt_bool_opt, esock_getopt_bool_opt,
1937 #else
1938 0, NULL, NULL,
1939 #endif
1940 &esock_atom_dontroute},
1941
1942 {0, NULL, NULL, &esock_atom_error},
1943
1944 {
1945 #ifdef SO_KEEPALIVE
1946 SO_KEEPALIVE,
1947 esock_setopt_bool_opt, esock_getopt_bool_opt,
1948 #else
1949 0, NULL, NULL,
1950 #endif
1951 &esock_atom_keepalive},
1952
1953 {
1954 #ifdef SO_LINGER
1955 SO_LINGER,
1956 esock_setopt_linger, esock_getopt_linger,
1957 #else
1958 0, NULL, NULL,
1959 #endif
1960 &esock_atom_linger},
1961
1962 {0, NULL, NULL, &esock_atom_mark},
1963
1964 {
1965 #ifdef SO_OOBINLINE
1966 SO_OOBINLINE,
1967 esock_setopt_bool_opt, esock_getopt_bool_opt,
1968 #else
1969 0, NULL, NULL,
1970 #endif
1971 &esock_atom_oobinline},
1972
1973 {
1974 #ifdef SO_PASSCRED
1975 SO_PASSCRED,
1976 esock_setopt_bool_opt, esock_getopt_bool_opt,
1977 #else
1978 0, NULL, NULL,
1979 #endif
1980 &esock_atom_passcred},
1981
1982 {
1983 #ifdef SO_PEEK_OFF
1984 SO_PEEK_OFF,
1985 esock_setopt_int_opt, esock_getopt_int_opt,
1986 #else
1987 0, NULL, NULL,
1988 #endif
1989 &esock_atom_peek_off},
1990
1991 {0, NULL, NULL, &esock_atom_peercred},
1992
1993 {
1994 #ifdef SO_PRIORITY
1995 SO_PRIORITY,
1996 esock_setopt_int_opt, esock_getopt_int_opt,
1997 #else
1998 0, NULL, NULL,
1999 #endif
2000 &esock_atom_priority},
2001
2002 {
2003 #ifdef SO_PROTOCOL
2004 SO_PROTOCOL,
2005 NULL, esock_getopt_sock_protocol,
2006 #else
2007 0, NULL, NULL,
2008 #endif
2009 &esock_atom_protocol},
2010
2011 {
2012 #ifdef SO_RCVBUF
2013 SO_RCVBUF,
2014 esock_setopt_int_opt, esock_getopt_int_opt,
2015 #else
2016 0, NULL, NULL,
2017 #endif
2018 &esock_atom_rcvbuf},
2019
2020 {0, NULL, NULL, &esock_atom_rcvbufforce},
2021
2022 {
2023 #ifdef SO_RCVLOWAT
2024 SO_RCVLOWAT,
2025 esock_setopt_int_opt, esock_getopt_int_opt,
2026 #else
2027 0, NULL, NULL,
2028 #endif
2029 &esock_atom_rcvlowat},
2030
2031 {
2032 #if defined(SO_RCVTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO)
2033 SO_RCVTIMEO,
2034 esock_setopt_timeval_opt, esock_getopt_timeval_opt,
2035 #else
2036 0, NULL, NULL,
2037 #endif
2038 &esock_atom_rcvtimeo},
2039
2040 {
2041 #ifdef SO_REUSEADDR
2042 SO_REUSEADDR,
2043 esock_setopt_bool_opt, esock_getopt_bool_opt,
2044 #else
2045 0, NULL, NULL,
2046 #endif
2047 &esock_atom_reuseaddr},
2048
2049 {
2050 #ifdef SO_REUSEPORT
2051 SO_REUSEPORT,
2052 esock_setopt_bool_opt, esock_getopt_bool_opt,
2053 #else
2054 0, NULL, NULL,
2055 #endif
2056 &esock_atom_reuseport},
2057
2058 {0, NULL, NULL, &esock_atom_rxq_ovfl},
2059 {0, NULL, NULL, &esock_atom_setfib},
2060
2061 {
2062 #ifdef SO_SNDBUF
2063 SO_SNDBUF,
2064 esock_setopt_int_opt, esock_getopt_int_opt,
2065 #else
2066 0, NULL, NULL,
2067 #endif
2068 &esock_atom_sndbuf},
2069
2070 {0, NULL, NULL, &esock_atom_sndbufforce},
2071
2072 {
2073 #ifdef SO_SNDLOWAT
2074 SO_SNDLOWAT,
2075 esock_setopt_int_opt, esock_getopt_int_opt,
2076 #else
2077 0, NULL, NULL,
2078 #endif
2079 &esock_atom_sndlowat},
2080
2081 {
2082 #if defined(SO_SNDTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO)
2083 SO_SNDTIMEO,
2084 esock_setopt_timeval_opt, esock_getopt_timeval_opt,
2085 #else
2086 0, NULL, NULL,
2087 #endif
2088 &esock_atom_sndtimeo},
2089
2090 {
2091 #ifdef SO_TIMESTAMP
2092 SO_TIMESTAMP,
2093 esock_setopt_bool_opt, esock_getopt_bool_opt,
2094 #else
2095 0, NULL, NULL,
2096 #endif
2097 &esock_atom_timestamp},
2098
2099 {
2100 #ifdef SO_TYPE
2101 SO_TYPE,
2102 NULL, esock_getopt_sock_type,
2103 #else
2104 0, NULL, NULL,
2105 #endif
2106 &esock_atom_type}
2107 };
2108
2109
2110 /* IP_* options -------------------------------------------------------- */
2111
2112 static struct ESockOpt optLevelIP[] =
2113 {
2114 {
2115 #ifdef IP_ADD_MEMBERSHIP
2116 IP_ADD_MEMBERSHIP,
2117 esock_setopt_in_update_membership, NULL,
2118 #else
2119 0, NULL, NULL,
2120 #endif
2121 &esock_atom_add_membership},
2122
2123 {
2124 #ifdef IP_ADD_SOURCE_MEMBERSHIP
2125 IP_ADD_SOURCE_MEMBERSHIP,
2126 esock_setopt_in_update_source, NULL,
2127 #else
2128 0, NULL, NULL,
2129 #endif
2130 &esock_atom_add_source_membership},
2131
2132 {
2133 #ifdef IP_BLOCK_SOURCE
2134 IP_BLOCK_SOURCE,
2135 esock_setopt_in_update_source, NULL,
2136 #else
2137 0, NULL, NULL,
2138 #endif
2139 &esock_atom_block_source},
2140
2141 {0, NULL, NULL, &esock_atom_dontfrag},
2142
2143 {
2144 #ifdef IP_DROP_MEMBERSHIP
2145 IP_DROP_MEMBERSHIP,
2146 esock_setopt_in_update_membership, NULL,
2147 #else
2148 0, NULL, NULL,
2149 #endif
2150 &esock_atom_drop_membership},
2151
2152 {
2153 #ifdef IP_DROP_SOURCE_MEMBERSHIP
2154 IP_DROP_SOURCE_MEMBERSHIP,
2155 esock_setopt_in_update_source, NULL,
2156 #else
2157 0, NULL, NULL,
2158 #endif
2159 &esock_atom_drop_source_membership},
2160
2161 {
2162 #ifdef IP_FREEBIND
2163 IP_FREEBIND,
2164 esock_setopt_bool_opt, esock_getopt_bool_opt,
2165 #else
2166 0, NULL, NULL,
2167 #endif
2168 &esock_atom_freebind},
2169
2170 {
2171 #ifdef IP_HDRINCL
2172 IP_HDRINCL,
2173 esock_setopt_bool_opt, esock_getopt_bool_opt,
2174 #else
2175 0, NULL, NULL,
2176 #endif
2177 &esock_atom_hdrincl},
2178
2179 {
2180 #ifdef IP_MINTTL
2181 IP_MINTTL,
2182 esock_setopt_int_opt, esock_getopt_int_opt,
2183 #else
2184 0, NULL, NULL,
2185 #endif
2186 &esock_atom_minttl},
2187
2188 {
2189 #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
2190 IP_MSFILTER,
2191 esock_setopt_msfilter, NULL,
2192 #else
2193 0, NULL, NULL,
2194 #endif
2195 &esock_atom_msfilter},
2196
2197 {
2198 #ifdef IP_MTU
2199 IP_MTU,
2200 NULL, esock_getopt_int_opt,
2201 #else
2202 0, NULL, NULL,
2203 #endif
2204 &esock_atom_mtu},
2205
2206 {
2207 #ifdef IP_MTU_DISCOVER
2208 IP_MTU_DISCOVER,
2209 esock_setopt_ip_mtu_discover, esock_getopt_ip_mtu_discover,
2210 #else
2211 0, NULL, NULL,
2212 #endif
2213 &esock_atom_mtu_discover},
2214
2215 {
2216 #ifdef IP_MULTICAST_ALL
2217 IP_MULTICAST_ALL,
2218 esock_setopt_bool_opt, esock_getopt_bool_opt,
2219 #else
2220 0, NULL, NULL,
2221 #endif
2222 &esock_atom_multicast_all},
2223
2224 {
2225 #ifdef IP_MULTICAST_IF
2226 IP_MULTICAST_IF,
2227 esock_setopt_multicast_if, esock_getopt_multicast_if,
2228 #else
2229 0, NULL, NULL,
2230 #endif
2231 &esock_atom_multicast_if},
2232
2233 {
2234 #ifdef IP_MULTICAST_LOOP
2235 IP_MULTICAST_LOOP,
2236 esock_setopt_bool_opt, esock_getopt_bool_opt,
2237 #else
2238 0, NULL, NULL,
2239 #endif
2240 &esock_atom_multicast_loop},
2241
2242 {
2243 #ifdef IP_MULTICAST_TTL
2244 IP_MULTICAST_TTL,
2245 esock_setopt_int_opt, esock_getopt_int_opt,
2246 #else
2247 0, NULL, NULL,
2248 #endif
2249 &esock_atom_multicast_ttl},
2250
2251 {
2252 #ifdef IP_NODEFRAG
2253 IP_NODEFRAG,
2254 esock_setopt_bool_opt, esock_getopt_bool_opt,
2255 #else
2256 0, NULL, NULL,
2257 #endif
2258 &esock_atom_nodefrag},
2259
2260 {0, NULL, NULL, &esock_atom_options},
2261
2262 {
2263 #ifdef IP_PKTINFO
2264 IP_PKTINFO,
2265 esock_setopt_bool_opt, esock_getopt_bool_opt,
2266 #else
2267 0, NULL, NULL,
2268 #endif
2269 &esock_atom_pktinfo},
2270
2271 {
2272 #ifdef IP_PKTOPTIONS
2273 IP_PKTOPTIONS,
2274 NULL, esock_getopt_pktoptions,
2275 #else
2276 0, NULL, NULL,
2277 #endif
2278 &esock_atom_pktoptions},
2279
2280 {
2281 #ifdef IP_RECVDSTADDR
2282 IP_RECVDSTADDR,
2283 esock_setopt_bool_opt, esock_getopt_bool_opt,
2284 #else
2285 0, NULL, NULL,
2286 #endif
2287 &esock_atom_recvdstaddr},
2288
2289 {
2290 #ifdef IP_RECVERR
2291 IP_RECVERR,
2292 esock_setopt_bool_opt, esock_getopt_bool_opt,
2293 #else
2294 0, NULL, NULL,
2295 #endif
2296 &esock_atom_recverr},
2297
2298 {
2299 #ifdef IP_RECVIF
2300 IP_RECVIF,
2301 esock_setopt_bool_opt, esock_getopt_bool_opt,
2302 #else
2303 0, NULL, NULL,
2304 #endif
2305 &esock_atom_recvif},
2306
2307 {
2308 #ifdef IP_RECVOPTS
2309 IP_RECVOPTS,
2310 esock_setopt_bool_opt, esock_getopt_bool_opt,
2311 #else
2312 0, NULL, NULL,
2313 #endif
2314 &esock_atom_recvopts},
2315
2316 {
2317 #ifdef IP_RECVORIGDSTADDR
2318 IP_RECVORIGDSTADDR,
2319 esock_setopt_bool_opt, esock_getopt_bool_opt,
2320 #else
2321 0, NULL, NULL,
2322 #endif
2323 &esock_atom_recvorigdstaddr},
2324
2325 {
2326 #ifdef IP_RECVTOS
2327 IP_RECVTOS,
2328 esock_setopt_bool_opt, esock_getopt_bool_opt,
2329 #else
2330 0, NULL, NULL,
2331 #endif
2332 &esock_atom_recvtos},
2333
2334 {
2335 #ifdef IP_RECVTTL
2336 IP_RECVTTL,
2337 esock_setopt_bool_opt, esock_getopt_bool_opt,
2338 #else
2339 0, NULL, NULL,
2340 #endif
2341 &esock_atom_recvttl},
2342
2343 {
2344 #ifdef IP_RETOPTS
2345 IP_RETOPTS,
2346 esock_setopt_bool_opt, esock_getopt_bool_opt,
2347 #else
2348 0, NULL, NULL,
2349 #endif
2350 &esock_atom_retopts},
2351
2352 {
2353 #ifdef IP_ROUTER_ALERT
2354 IP_ROUTER_ALERT,
2355 esock_setopt_int_opt, esock_getopt_int_opt,
2356 #else
2357 0, NULL, NULL,
2358 #endif
2359 &esock_atom_router_alert},
2360
2361 {
2362 #ifdef IP_SENDSRCADDR
2363 IP_SENDSRCADDR,
2364 esock_setopt_bool_opt, esock_getopt_bool_opt,
2365 #else
2366 0, NULL, NULL,
2367 #endif
2368 &esock_atom_sendsrcaddr},
2369
2370 {
2371 #ifdef IP_TOS
2372 IP_TOS,
2373 esock_setopt_tos, esock_getopt_tos,
2374 #else
2375 0, NULL, NULL,
2376 #endif
2377 &esock_atom_tos},
2378
2379 {
2380 #ifdef IP_TRANSPARENT
2381 IP_TRANSPARENT,
2382 esock_setopt_bool_opt, esock_getopt_bool_opt,
2383 #else
2384 0, NULL, NULL,
2385 #endif
2386 &esock_atom_transparent},
2387
2388 {
2389 #ifdef IP_TTL
2390 IP_TTL,
2391 esock_setopt_int_opt, esock_getopt_int_opt,
2392 #else
2393 0, NULL, NULL,
2394 #endif
2395 &esock_atom_ttl},
2396
2397 {
2398 #ifdef IP_UNBLOCK_SOURCE
2399 IP_UNBLOCK_SOURCE,
2400 esock_setopt_in_update_source, NULL,
2401 #else
2402 0, NULL, NULL,
2403 #endif
2404 &esock_atom_unblock_source}
2405
2406 };
2407
2408 /* IPV6_* options ------------------------------------------------------ */
2409
2410 #ifdef HAVE_IPV6
2411 static struct ESockOpt optLevelIPV6[] =
2412 {
2413
2414 {
2415 #ifdef IPV6_ADDRFORM
2416 IPV6_ADDRFORM,
2417 esock_setopt_addrform, NULL,
2418 #else
2419 0, NULL, NULL,
2420 #endif
2421 &esock_atom_addrform},
2422
2423 {
2424 #ifdef IPV6_ADD_MEMBERSHIP
2425 IPV6_ADD_MEMBERSHIP,
2426 esock_setopt_in6_update_membership, NULL,
2427 #else
2428 0, NULL, NULL,
2429 #endif
2430 &esock_atom_add_membership},
2431
2432 {
2433 #ifdef IPV6_AUTHHDR
2434 IPV6_AUTHHDR,
2435 esock_setopt_bool_opt, esock_getopt_bool_opt,
2436 #else
2437 0, NULL, NULL,
2438 #endif
2439 &esock_atom_authhdr},
2440
2441 {0, NULL, NULL, &esock_atom_auth_level},
2442 {0, NULL, NULL, &esock_atom_checksum},
2443
2444 {
2445 #ifdef IPV6_DROP_MEMBERSHIP
2446 IPV6_DROP_MEMBERSHIP,
2447 esock_setopt_in6_update_membership, NULL,
2448 #else
2449 0, NULL, NULL,
2450 #endif
2451 &esock_atom_drop_membership},
2452
2453 {
2454 #if defined(IPV6_DSTOPTS)
2455 IPV6_DSTOPTS,
2456 esock_setopt_bool_opt, esock_getopt_bool_opt,
2457 #else
2458 0, NULL, NULL,
2459 #endif
2460 &esock_atom_dstopts},
2461
2462 {0, NULL, NULL, &esock_atom_esp_network_level},
2463 {0, NULL, NULL, &esock_atom_esp_trans_level},
2464 {0, NULL, NULL, &esock_atom_faith},
2465
2466 {
2467 #ifdef IPV6_FLOWINFO
2468 IPV6_FLOWINFO,
2469 esock_setopt_bool_opt, esock_getopt_bool_opt,
2470 #else
2471 0, NULL, NULL,
2472 #endif
2473 &esock_atom_flowinfo},
2474
2475 {
2476 #ifdef IPV6_HOPLIMIT
2477 IPV6_HOPLIMIT,
2478 esock_setopt_bool_opt, esock_getopt_bool_opt,
2479 #else
2480 0, NULL, NULL,
2481 #endif
2482 &esock_atom_hoplimit},
2483
2484 {
2485 #ifdef IPV6_HOPOPTS
2486 IPV6_HOPOPTS,
2487 esock_setopt_bool_opt, esock_getopt_bool_opt,
2488 #else
2489 0, NULL, NULL,
2490 #endif
2491 &esock_atom_hopopts},
2492
2493 {0, NULL, NULL, &esock_atom_ipcomp_level},
2494 {0, NULL, NULL, &esock_atom_join_group},
2495 {0, NULL, NULL, &esock_atom_leave_group},
2496
2497 {
2498 #ifdef IPV6_MTU
2499 IPV6_MTU,
2500 esock_setopt_int_opt, esock_getopt_int_opt,
2501 #else
2502 0, NULL, NULL,
2503 #endif
2504 &esock_atom_mtu},
2505
2506 {
2507 #ifdef IPV6_MTU_DISCOVER
2508 IPV6_MTU_DISCOVER,
2509 esock_setopt_ipv6_mtu_discover, esock_getopt_ipv6_mtu_discover,
2510 #else
2511 0, NULL, NULL,
2512 #endif
2513 &esock_atom_mtu_discover},
2514
2515 {
2516 #ifdef IPV6_MULTICAST_HOPS
2517 IPV6_MULTICAST_HOPS,
2518 esock_setopt_hops, esock_getopt_int_opt,
2519 #else
2520 0, NULL, NULL,
2521 #endif
2522 &esock_atom_multicast_hops},
2523
2524 {
2525 #ifdef IPV6_MULTICAST_IF
2526 IPV6_MULTICAST_IF,
2527 esock_setopt_int_opt, esock_getopt_int_opt,
2528 #else
2529 0, NULL, NULL,
2530 #endif
2531 &esock_atom_multicast_if},
2532
2533 {
2534 #ifdef IPV6_MULTICAST_LOOP
2535 IPV6_MULTICAST_LOOP,
2536 esock_setopt_bool_opt, esock_getopt_bool_opt,
2537 #else
2538 0, NULL, NULL,
2539 #endif
2540 &esock_atom_multicast_loop},
2541
2542 {0, NULL, NULL, &esock_atom_portrange},
2543
2544 {
2545 #ifdef IPV6_PKTOPTIONS
2546 IPV6_PKTOPTIONS,
2547 NULL, esock_getopt_pktoptions,
2548 #else
2549 0, NULL, NULL,
2550 #endif
2551 &esock_atom_pktoptions},
2552
2553 {
2554 #ifdef IPV6_RECVERR
2555 IPV6_RECVERR,
2556 esock_setopt_bool_opt, esock_getopt_bool_opt,
2557 #else
2558 0, NULL, NULL,
2559 #endif
2560 &esock_atom_recverr},
2561
2562 {
2563 #ifdef IPV6_RECVHOPLIMIT
2564 IPV6_RECVHOPLIMIT,
2565 esock_setopt_bool_opt, esock_getopt_bool_opt,
2566 #else
2567 0, NULL, NULL,
2568 #endif
2569 &esock_atom_recvhoplimit},
2570
2571 {
2572 #if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
2573 #if defined(IPV6_RECVPKTINFO)
2574 IPV6_RECVPKTINFO,
2575 #else
2576 IPV6_PKTINFO,
2577 #endif
2578 esock_setopt_bool_opt, esock_getopt_bool_opt,
2579 #else
2580 0, NULL, NULL,
2581 #endif
2582 &esock_atom_recvpktinfo},
2583
2584 {
2585 #ifdef IPV6_RECVTCLASS
2586 IPV6_RECVTCLASS,
2587 esock_setopt_bool_opt, esock_getopt_bool_opt,
2588 #else
2589 0, NULL, NULL,
2590 #endif
2591 &esock_atom_recvtclass},
2592
2593 {
2594 #ifdef IPV6_ROUTER_ALERT
2595 IPV6_ROUTER_ALERT,
2596 esock_setopt_int_opt, esock_getopt_int_opt,
2597 #else
2598 0, NULL, NULL,
2599 #endif
2600 &esock_atom_router_alert},
2601
2602 {
2603 #ifdef IPV6_RTHDR
2604 IPV6_RTHDR,
2605 esock_setopt_bool_opt, esock_getopt_bool_opt,
2606 #else
2607 0, NULL, NULL,
2608 #endif
2609 &esock_atom_rthdr},
2610
2611 {
2612 #ifdef IPV6_TCLASS
2613 IPV6_TCLASS,
2614 esock_setopt_int_opt, esock_getopt_int_opt,
2615 #else
2616 0, NULL, NULL,
2617 #endif
2618 &esock_atom_tclass},
2619
2620 {
2621 #ifdef IPV6_UNICAST_HOPS
2622 IPV6_UNICAST_HOPS,
2623 esock_setopt_hops, esock_getopt_int_opt,
2624 #else
2625 0, NULL, NULL,
2626 #endif
2627 &esock_atom_unicast_hops},
2628
2629 {0, NULL, NULL, &esock_atom_use_min_mtu},
2630
2631 {
2632 #ifdef IPV6_V6ONLY
2633 IPV6_V6ONLY,
2634 esock_setopt_bool_opt, esock_getopt_bool_opt,
2635 #else
2636 0, NULL, NULL,
2637 #endif
2638 &esock_atom_v6only}
2639
2640 };
2641 #endif // #ifdef HAVE_IPV6
2642
2643
2644 /* SCTP_* options ------------------------------------------------------ */
2645
2646 #ifdef HAVE_SCTP
2647 static struct ESockOpt optLevelSCTP[] =
2648 {
2649
2650 {0, NULL, NULL, &esock_atom_adaption_layer},
2651
2652 {
2653 #ifdef SCTP_ASSOCINFO
2654 SCTP_ASSOCINFO,
2655 esock_setopt_sctp_associnfo, esock_getopt_sctp_associnfo,
2656 #else
2657 0, NULL, NULL,
2658 #endif
2659 &esock_atom_associnfo},
2660
2661 {0, NULL, NULL, &esock_atom_auth_active_key},
2662 {0, NULL, NULL, &esock_atom_auth_chunk},
2663 {0, NULL, NULL, &esock_atom_auth_delete_key},
2664 {0, NULL, NULL, &esock_atom_auth_key},
2665
2666 {
2667 #ifdef SCTP_AUTOCLOSE
2668 SCTP_AUTOCLOSE,
2669 esock_setopt_int_opt, esock_getopt_int_opt,
2670 #else
2671 0, NULL, NULL,
2672 #endif
2673 &esock_atom_autoclose},
2674
2675 {0, NULL, NULL, &esock_atom_context},
2676 {0, NULL, NULL, &esock_atom_default_send_params},
2677 {0, NULL, NULL, &esock_atom_delayed_ack_time},
2678
2679 {
2680 #ifdef SCTP_DISABLE_FRAGMENTS
2681 SCTP_DISABLE_FRAGMENTS,
2682 esock_setopt_bool_opt, esock_getopt_bool_opt,
2683 #else
2684 0, NULL, NULL,
2685 #endif
2686 &esock_atom_disable_fragments},
2687
2688 {0, NULL, NULL, &esock_atom_hmac_ident},
2689
2690 {
2691 #ifdef SCTP_EVENTS
2692 SCTP_EVENTS,
2693 esock_setopt_sctp_events, NULL,
2694 #else
2695 0, NULL, NULL,
2696 #endif
2697 &esock_atom_events},
2698
2699 {0, NULL, NULL, &esock_atom_explicit_eor},
2700 {0, NULL, NULL, &esock_atom_fragment_interleave},
2701 {0, NULL, NULL, &esock_atom_get_peer_addr_info},
2702
2703 {
2704 #ifdef SCTP_INITMSG
2705 SCTP_INITMSG,
2706 esock_setopt_sctp_initmsg, esock_getopt_sctp_initmsg,
2707 #else
2708 0, NULL, NULL,
2709 #endif
2710 &esock_atom_initmsg},
2711
2712 {0, NULL, NULL, &esock_atom_i_want_mapped_v4_addr},
2713 {0, NULL, NULL, &esock_atom_local_auth_chunks},
2714
2715 {
2716 #ifdef SCTP_MAXSEG
2717 SCTP_MAXSEG,
2718 esock_setopt_int_opt, esock_getopt_int_opt,
2719 #else
2720 0, NULL, NULL,
2721 #endif
2722 &esock_atom_maxseg},
2723
2724 {0, NULL, NULL, &esock_atom_maxburst},
2725
2726 {
2727 #ifdef SCTP_NODELAY
2728 SCTP_NODELAY,
2729 esock_setopt_bool_opt, esock_getopt_bool_opt,
2730 #else
2731 0, NULL, NULL,
2732 #endif
2733 &esock_atom_nodelay},
2734
2735 {0, NULL, NULL, &esock_atom_partial_delivery_point},
2736 {0, NULL, NULL, &esock_atom_peer_addr_params},
2737 {0, NULL, NULL, &esock_atom_peer_auth_chunks},
2738 {0, NULL, NULL, &esock_atom_primary_addr},
2739 {0, NULL, NULL, &esock_atom_reset_streams},
2740
2741 {
2742 #ifdef SCTP_RTOINFO
2743 SCTP_RTOINFO,
2744 esock_setopt_sctp_rtoinfo, esock_getopt_sctp_rtoinfo,
2745 #else
2746 0, NULL, NULL,
2747 #endif
2748 &esock_atom_rtoinfo},
2749
2750 {0, NULL, NULL, &esock_atom_set_peer_primary_addr},
2751 {0, NULL, NULL, &esock_atom_status},
2752 {0, NULL, NULL, &esock_atom_use_ext_recvinfo}
2753
2754 };
2755 #endif // #ifdef HAVE_SCTP
2756
2757 /* TCP_* options ------------------------------------------------------- */
2758
2759 static struct ESockOpt optLevelTCP[] =
2760 {
2761
2762 {
2763 #ifdef TCP_CONGESTION
2764 TCP_CONGESTION,
2765 esock_setopt_tcp_congestion, esock_getopt_tcp_congestion,
2766 #else
2767 0, NULL, NULL,
2768 #endif
2769 &esock_atom_congestion},
2770
2771 {
2772 #ifdef TCP_CORK
2773 TCP_CORK,
2774 esock_setopt_bool_opt, esock_getopt_bool_opt,
2775 #else
2776 0, NULL, NULL,
2777 #endif
2778 &esock_atom_cork},
2779
2780 {0, NULL, NULL, &esock_atom_info},
2781 {0, NULL, NULL, &esock_atom_keepcnt},
2782 {0, NULL, NULL, &esock_atom_keepidle},
2783 {0, NULL, NULL, &esock_atom_keepintvl},
2784
2785 {
2786 #ifdef TCP_MAXSEG
2787 TCP_MAXSEG,
2788 esock_setopt_int_opt, esock_getopt_int_opt,
2789 #else
2790 0, NULL, NULL,
2791 #endif
2792 &esock_atom_maxseg},
2793
2794 {0, NULL, NULL, &esock_atom_md5sig},
2795
2796 {
2797 #ifdef TCP_NODELAY
2798 TCP_NODELAY,
2799 esock_setopt_bool_opt, esock_getopt_bool_opt,
2800 #else
2801 0, NULL, NULL,
2802 #endif
2803 &esock_atom_nodelay},
2804
2805 {0, NULL, NULL, &esock_atom_noopt},
2806 {0, NULL, NULL, &esock_atom_nopush},
2807 {0, NULL, NULL, &esock_atom_syncnt},
2808 {0, NULL, NULL, &esock_atom_user_timeout}
2809
2810 };
2811
2812
2813 /* UDP_* options ------------------------------------------------------- */
2814
2815 static struct ESockOpt optLevelUDP[] =
2816 {
2817
2818 {
2819 #ifdef UDP_CORK
2820 UDP_CORK,
2821 esock_setopt_bool_opt, esock_getopt_bool_opt,
2822 #else
2823 0, NULL, NULL,
2824 #endif
2825 &esock_atom_cork}
2826
2827 };
2828
2829 /* Option levels table ------------------------------------------------- */
2830
2831 struct ESockOptLevel
2832 {
2833 int level; // Level number
2834
2835 size_t num; // Number of options
2836
2837 struct ESockOpt *opts; // Options table
2838 };
2839
2840 // qsort and bsearch helper
cmpESockOptLevel(const void * vpa,const void * vpb)2841 static int cmpESockOptLevel(const void *vpa, const void *vpb) {
2842 struct ESockOptLevel *a, *b;
2843 a = (struct ESockOptLevel*) vpa;
2844 b = (struct ESockOptLevel*) vpb;
2845 return a->level < b->level ? -1 : (a->level > b->level ? 1 : 0);
2846 }
2847
2848 #define OPT_LEVEL(Level, Opts) {(Level), NUM(Opts), (Opts)}
2849
2850 /* Table --------------------------------------------------------------- */
2851
2852 static struct ESockOptLevel optLevels[] =
2853 {
2854 OPT_LEVEL(SOL_SOCKET, optLevelSocket),
2855
2856 #ifdef SOL_IP
2857 OPT_LEVEL(SOL_IP, optLevelIP),
2858 #else
2859 OPT_LEVEL(IPPROTO_IP, optLevelIP),
2860 #endif
2861
2862 #ifdef HAVE_IPV6
2863 #ifdef SOL_IPV6
2864 OPT_LEVEL(SOL_IPV6, optLevelIPV6),
2865 #else
2866 OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6),
2867 #endif
2868 #endif // #ifdef HAVE_IPV6
2869
2870 #ifdef HAVE_SCTP
2871 OPT_LEVEL(IPPROTO_SCTP, optLevelSCTP),
2872 #endif // #ifdef HAVE_SCTP
2873
2874 OPT_LEVEL(IPPROTO_UDP, optLevelUDP),
2875 OPT_LEVEL(IPPROTO_TCP, optLevelTCP)
2876 };
2877
2878 #undef OPT_LEVEL
2879
2880 /* Tables init (sorting) ----------------------------------------------- */
2881
2882 #define ESOCK_SORT_TABLE(Array, Cmp) \
2883 qsort((Array), NUM(Array), sizeof(*(Array)), (Cmp))
2884
initOpts(void)2885 static void initOpts(void) {
2886 ESOCK_SORT_TABLE(optLevelSocket, cmpESockOpt);
2887 ESOCK_SORT_TABLE(optLevelIP, cmpESockOpt);
2888 #ifdef HAVE_IPV6
2889 ESOCK_SORT_TABLE(optLevelIPV6, cmpESockOpt);
2890 #endif
2891 #ifdef HAVE_SCTP
2892 ESOCK_SORT_TABLE(optLevelSCTP, cmpESockOpt);
2893 #endif
2894 ESOCK_SORT_TABLE(optLevelTCP, cmpESockOpt);
2895 ESOCK_SORT_TABLE(optLevelUDP, cmpESockOpt);
2896 ESOCK_SORT_TABLE(optLevels, cmpESockOptLevel);
2897 }
2898
2899 /* Option lookup in tables --------------------------------------------- */
2900
lookupOpt(int level,int opt)2901 static struct ESockOpt *lookupOpt(int level, int opt) {
2902 struct ESockOptLevel levelKey, *levelP;
2903 struct ESockOpt optKey;
2904
2905 sys_memzero((char *) &levelKey, sizeof(levelKey));
2906 levelKey.level = level;
2907 levelP =
2908 bsearch(&levelKey, optLevels, NUM(optLevels), sizeof(*optLevels),
2909 cmpESockOptLevel);
2910 if (levelP == NULL)
2911 return NULL;
2912
2913 sys_memzero((char *) &optKey, sizeof(optKey));
2914 optKey.opt = opt;
2915 return
2916 bsearch(&optKey, levelP->opts, levelP->num, sizeof(*levelP->opts),
2917 cmpESockOpt);
2918 }
2919
2920 /* --------------------------------------------------------------------- */
2921
2922
2923
2924 static BOOLEAN_T send_check_writer(ErlNifEnv* env,
2925 ESockDescriptor* descP,
2926 ERL_NIF_TERM ref,
2927 ERL_NIF_TERM* checkResult);
2928 static ERL_NIF_TERM send_check_result(ErlNifEnv* env,
2929 ESockDescriptor* descP,
2930 ssize_t send_result,
2931 ssize_t dataSize,
2932 BOOLEAN_T dataInTail,
2933 ERL_NIF_TERM sockRef,
2934 ERL_NIF_TERM sendRef);
2935 static ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
2936 ESockDescriptor* descP,
2937 ssize_t written,
2938 ERL_NIF_TERM sockRef);
2939 static ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
2940 ESockDescriptor* descP,
2941 int saveErrno,
2942 ERL_NIF_TERM sockRef);
2943 static void send_error_waiting_writers(ErlNifEnv* env,
2944 ESockDescriptor* descP,
2945 ERL_NIF_TERM sockRef,
2946 ERL_NIF_TERM reason);
2947 static ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
2948 ESockDescriptor* descP,
2949 ssize_t written,
2950 ERL_NIF_TERM sockRef,
2951 ERL_NIF_TERM sendRef);
2952 static BOOLEAN_T recv_check_reader(ErlNifEnv* env,
2953 ESockDescriptor* descP,
2954 ERL_NIF_TERM ref,
2955 ERL_NIF_TERM* checkResult);
2956 static void recv_init_current_reader(ErlNifEnv* env,
2957 ESockDescriptor* descP,
2958 ERL_NIF_TERM ref);
2959 static void recv_update_current_reader(ErlNifEnv* env,
2960 ESockDescriptor* descP,
2961 ERL_NIF_TERM sockRef);
2962 static void recv_error_current_reader(ErlNifEnv* env,
2963 ESockDescriptor* descP,
2964 ERL_NIF_TERM sockRef,
2965 ERL_NIF_TERM reason);
2966 static ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
2967 ESockDescriptor* descP,
2968 ssize_t read,
2969 ssize_t toRead,
2970 int saveErrno,
2971 ErlNifBinary* bufP,
2972 ERL_NIF_TERM sockRef,
2973 ERL_NIF_TERM recvRef);
2974 static ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
2975 ESockDescriptor* descP,
2976 ssize_t read,
2977 ssize_t toRead,
2978 ErlNifBinary* bufP,
2979 ERL_NIF_TERM sockRef,
2980 ERL_NIF_TERM recvRef);
2981 static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
2982 ESockDescriptor* descP,
2983 ssize_t read,
2984 ErlNifBinary* bufP,
2985 ERL_NIF_TERM sockRef,
2986 ERL_NIF_TERM recvRef);
2987 static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
2988 ESockDescriptor* descP,
2989 ssize_t read,
2990 ErlNifBinary* bufP,
2991 ERL_NIF_TERM sockRef);
2992 static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
2993 ESockDescriptor* descP,
2994 int saveErrno,
2995 ErlNifBinary* buf1P,
2996 ErlNifBinary* buf2P,
2997 ERL_NIF_TERM sockRef,
2998 ERL_NIF_TERM recvRef);
2999 static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env,
3000 ESockDescriptor* descP,
3001 ERL_NIF_TERM sockRef,
3002 ERL_NIF_TERM recvRef);
3003 static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
3004 ESockDescriptor* descP,
3005 ssize_t read,
3006 ssize_t toRead,
3007 ErlNifBinary* bufP,
3008 ERL_NIF_TERM sockRef,
3009 ERL_NIF_TERM recvRef);
3010 static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
3011 ESockDescriptor* descP,
3012 ssize_t read,
3013 ErlNifBinary* bufP,
3014 ERL_NIF_TERM sockRef);
3015 static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
3016 ESockDescriptor* descP,
3017 ssize_t read,
3018 ErlNifBinary* bufP,
3019 ERL_NIF_TERM sockRef,
3020 ERL_NIF_TERM recvRef);
3021 static ERL_NIF_TERM recv_check_retry(ErlNifEnv* env,
3022 ESockDescriptor* descP,
3023 ERL_NIF_TERM sockRef,
3024 ERL_NIF_TERM recvRef);
3025 static ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env,
3026 ESockDescriptor* descP,
3027 int saveErrno,
3028 ERL_NIF_TERM sockRef);
3029 static ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
3030 ESockDescriptor* descP,
3031 ssize_t read,
3032 int saveErrno,
3033 ErlNifBinary* bufP,
3034 ESockAddress* fromAddrP,
3035 SOCKLEN_T fromAddrLen,
3036 ERL_NIF_TERM sockRef,
3037 ERL_NIF_TERM recvRef);
3038 static ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
3039 ESockDescriptor* descP,
3040 ssize_t read,
3041 int saveErrno,
3042 struct msghdr* msgHdrP,
3043 ErlNifBinary* dataBufP,
3044 ErlNifBinary* ctrlBufP,
3045 ERL_NIF_TERM sockRef,
3046 ERL_NIF_TERM recvRef);
3047 static ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
3048 ESockDescriptor* descP,
3049 ssize_t read,
3050 struct msghdr* msgHdrP,
3051 ErlNifBinary* dataBufP,
3052 ErlNifBinary* ctrlBufP,
3053 ERL_NIF_TERM sockRef);
3054
3055 static ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env,
3056 ESockDescriptor* descP);
3057 static int esock_close_socket(ErlNifEnv* env,
3058 ESockDescriptor* descP,
3059 BOOLEAN_T unlock);
3060
3061 static void encode_msg(ErlNifEnv* env,
3062 ESockDescriptor* descP,
3063 ssize_t read,
3064 struct msghdr* msgHdrP,
3065 ErlNifBinary* dataBufP,
3066 ErlNifBinary* ctrlBufP,
3067 ERL_NIF_TERM* eSockAddr);
3068 static void encode_cmsgs(ErlNifEnv* env,
3069 ESockDescriptor* descP,
3070 ErlNifBinary* cmsgBinP,
3071 struct msghdr* msgHdrP,
3072 ERL_NIF_TERM* eCMsg);
3073 static BOOLEAN_T encode_cmsg(ErlNifEnv* env,
3074 int level,
3075 int type,
3076 unsigned char* dataP,
3077 size_t dataLen,
3078 ERL_NIF_TERM* eType,
3079 ERL_NIF_TERM* eData);
3080 static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env,
3081 ESockDescriptor* descP,
3082 ERL_NIF_TERM eCMsg,
3083 char* cmsgHdrBufP,
3084 size_t cmsgHdrBufLen,
3085 size_t* cmsgHdrBufUsed);
3086 static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env,
3087 ESockDescriptor* descP,
3088 ERL_NIF_TERM eCMsg,
3089 char* bufP,
3090 size_t rem,
3091 size_t* used);
3092 static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env,
3093 ESockDescriptor* descP,
3094 int level,
3095 ERL_NIF_TERM eType,
3096 ERL_NIF_TERM eValue,
3097 char* dataP,
3098 size_t dataLen,
3099 size_t* dataUsedP);
3100 static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env,
3101 ESockDescriptor* descP,
3102 int level,
3103 ERL_NIF_TERM eType,
3104 ERL_NIF_TERM eData,
3105 char* dataP,
3106 size_t dataLen,
3107 size_t* dataUsedP);
3108 static void *init_cmsghdr(struct cmsghdr* cmsgP,
3109 size_t rem,
3110 size_t size,
3111 size_t* usedP);
3112 static void encode_msg_flags(ErlNifEnv* env,
3113 ESockDescriptor* descP,
3114 int msgFlags,
3115 ERL_NIF_TERM* flags);
3116 #if defined(IP_TOS)
3117 static BOOLEAN_T decode_ip_tos(ErlNifEnv* env,
3118 ERL_NIF_TERM eVal,
3119 int* val);
3120 #endif
3121 #if defined(IP_MTU_DISCOVER)
3122 static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env,
3123 ERL_NIF_TERM eVal,
3124 int* val);
3125 #endif
3126 #if defined(IP_MTU_DISCOVER)
3127 static void encode_ip_pmtudisc(ErlNifEnv* env,
3128 int val,
3129 ERL_NIF_TERM* eVal);
3130 #endif
3131 #if defined(IPV6_MTU_DISCOVER)
3132 static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env,
3133 ERL_NIF_TERM eVal,
3134 int* val);
3135 #endif
3136 #if defined(IPV6_MTU_DISCOVER)
3137 static void encode_ipv6_pmtudisc(ErlNifEnv* env,
3138 int val,
3139 ERL_NIF_TERM* eVal);
3140 #endif
3141 #if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS)
3142 static
3143 BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val);
3144 #endif
3145
3146 /*
3147 static BOOLEAN_T decode_bool(ErlNifEnv* env,
3148 ERL_NIF_TERM eVal,
3149 BOOLEAN_T* val);
3150 */
3151 // static void encode_bool(BOOLEAN_T val, ERL_NIF_TERM* eVal);
3152 static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val);
3153
3154 #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO)
3155 static BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env,
3156 ERL_NIF_TERM eVal,
3157 sctp_assoc_t* val);
3158 static ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env,
3159 sctp_assoc_t val);
3160 #endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO)
3161
3162 static void esock_stop_handle_current(ErlNifEnv* env,
3163 const char* role,
3164 ESockDescriptor* descP,
3165 ERL_NIF_TERM sockRef,
3166 ESockRequestor* reqP);
3167 static void inform_waiting_procs(ErlNifEnv* env,
3168 const char* role,
3169 ESockDescriptor* descP,
3170 ERL_NIF_TERM sockRef,
3171 ESockRequestQueue* q,
3172 ERL_NIF_TERM reason);
3173
3174 static int socket_setopt(int sock,
3175 int level,
3176 int opt,
3177 const void* optVal,
3178 const socklen_t optLen);
3179
3180 static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err);
3181
3182 static ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event);
3183
3184
3185 static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how);
3186 #ifdef HAVE_SETNS
3187 static BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env,
3188 ERL_NIF_TERM opts,
3189 char** netns);
3190 static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err);
3191 static BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err);
3192 #endif
3193
3194 static BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc);
3195 static void cnt_dec(ESockCounter* cnt, ESockCounter dec);
3196
3197 static void inc_socket(int domain, int type, int protocol);
3198 static void dec_socket(int domain, int type, int protocol);
3199
3200
3201
3202 /* *** activate_next_acceptor ***
3203 * *** activate_next_writer ***
3204 * *** activate_next_reader ***
3205 *
3206 * All the activate-next functions for acceptor, writer and reader
3207 * have exactly the same API, so we apply some macro magic to simplify.
3208 * They simply operates on dufferent data structures.
3209 *
3210 */
3211
3212 #define ACTIVATE_NEXT_FUNCS_DEFS \
3213 ACTIVATE_NEXT_FUNC_DEF(acceptor) \
3214 ACTIVATE_NEXT_FUNC_DEF(writer) \
3215 ACTIVATE_NEXT_FUNC_DEF(reader)
3216
3217 #define ACTIVATE_NEXT_FUNC_DEF(F) \
3218 static BOOLEAN_T activate_next_##F(ErlNifEnv* env, \
3219 ESockDescriptor* descP, \
3220 ERL_NIF_TERM sockRef);
3221 ACTIVATE_NEXT_FUNCS_DEFS
3222 #undef ACTIVATE_NEXT_FUNC_DEF
3223
3224 /* *** acceptor_search4pid | writer_search4pid | reader_search4pid ***
3225 * *** acceptor_push | writer_push | reader_push ***
3226 * *** acceptor_pop | writer_pop | reader_pop ***
3227 * *** acceptor_unqueue | writer_unqueue | reader_unqueue ***
3228 *
3229 * All the queue operator functions (search4pid, push, pop
3230 * and unqueue) for acceptor, writer and reader has exactly
3231 * the same API, so we apply some macro magic to simplify.
3232 */
3233
3234 #define ESOCK_OPERATOR_FUNCS_DEFS \
3235 ESOCK_OPERATOR_FUNCS_DEF(acceptor) \
3236 ESOCK_OPERATOR_FUNCS_DEF(writer) \
3237 ESOCK_OPERATOR_FUNCS_DEF(reader)
3238
3239 #define ESOCK_OPERATOR_FUNCS_DEF(O) \
3240 static BOOLEAN_T O##_search4pid(ErlNifEnv* env, \
3241 ESockDescriptor* descP, \
3242 ErlNifPid* pid); \
3243 static void O##_push(ErlNifEnv* env, \
3244 ESockDescriptor* descP, \
3245 ErlNifPid pid, \
3246 ERL_NIF_TERM ref); \
3247 static BOOLEAN_T O##_pop(ErlNifEnv* env, \
3248 ESockDescriptor* descP, \
3249 ESockRequestor* reqP); \
3250 static BOOLEAN_T O##_unqueue(ErlNifEnv* env, \
3251 ESockDescriptor* descP, \
3252 ERL_NIF_TERM* refP, \
3253 const ErlNifPid* pidP);
3254 ESOCK_OPERATOR_FUNCS_DEFS
3255 #undef ESOCK_OPERATOR_FUNCS_DEF
3256
3257 static BOOLEAN_T requestor_pop(ESockRequestQueue* q,
3258 ESockRequestor* reqP);
3259
3260 static void requestor_init(ESockRequestor* reqP);
3261 static void requestor_release(const char* slogan,
3262 ErlNifEnv* env,
3263 ESockDescriptor* descP,
3264 ESockRequestor* reqP);
3265
3266 static BOOLEAN_T qsearch4pid(ErlNifEnv* env,
3267 ESockRequestQueue* q,
3268 ErlNifPid* pid);
3269 static void qpush(ESockRequestQueue* q,
3270 ESockRequestQueueElement* e);
3271 static ESockRequestQueueElement* qpop(ESockRequestQueue* q);
3272 static BOOLEAN_T qunqueue(ErlNifEnv* env,
3273 ESockDescriptor* descP,
3274 const char* slogan,
3275 ESockRequestQueue* q,
3276 ERL_NIF_TERM* refP,
3277 const ErlNifPid* pidP);
3278
3279 static int esock_monitor(const char* slogan,
3280 ErlNifEnv* env,
3281 ESockDescriptor* descP,
3282 const ErlNifPid* pid,
3283 ESockMonitor* mon);
3284 static int esock_demonitor(const char* slogan,
3285 ErlNifEnv* env,
3286 ESockDescriptor* descP,
3287 ESockMonitor* monP);
3288 static void esock_monitor_init(ESockMonitor* mon);
3289 static ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env,
3290 const ESockMonitor* monP);
3291 static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP,
3292 const ErlNifMonitor* mon);
3293
3294
3295
3296 static void esock_down_ctrl(ErlNifEnv* env,
3297 ESockDescriptor* descP,
3298 const ErlNifPid* pidP);
3299 static void esock_down_acceptor(ErlNifEnv* env,
3300 ESockDescriptor* descP,
3301 ERL_NIF_TERM sockRef,
3302 const ErlNifPid* pidP,
3303 const ErlNifMonitor* monP);
3304 static void esock_down_writer(ErlNifEnv* env,
3305 ESockDescriptor* descP,
3306 ERL_NIF_TERM sockRef,
3307 const ErlNifPid* pidP,
3308 const ErlNifMonitor* monP);
3309 static void esock_down_reader(ErlNifEnv* env,
3310 ESockDescriptor* descP,
3311 ERL_NIF_TERM sockRef,
3312 const ErlNifPid* pidP,
3313 const ErlNifMonitor* monP);
3314
3315 static void esock_send_reg_add_msg(ErlNifEnv* env,
3316 ESockDescriptor* descP,
3317 ERL_NIF_TERM sockRef);
3318 static void esock_send_reg_del_msg(ErlNifEnv* env,
3319 ESockDescriptor* descP,
3320 ERL_NIF_TERM sockRef);
3321
3322 static void esock_send_wrap_msg(ErlNifEnv* env,
3323 ESockDescriptor* descP,
3324 ERL_NIF_TERM sockRef,
3325 ERL_NIF_TERM cnt);
3326 static void esock_send_close_msg(ErlNifEnv* env,
3327 ESockDescriptor* descP,
3328 ErlNifPid* pid);
3329 #ifdef HAVE_SENDFILE
3330 static void
3331 esock_send_sendfile_deferred_close_msg(ErlNifEnv* env,
3332 ESockDescriptor* descP);
3333 #endif
3334 static void esock_send_abort_msg(ErlNifEnv* env,
3335 ESockDescriptor* descP,
3336 ERL_NIF_TERM sockRef,
3337 ESockRequestor* reqP,
3338 ERL_NIF_TERM reason);
3339 static BOOLEAN_T esock_send_msg(ErlNifEnv* env,
3340 ErlNifPid* pid,
3341 ERL_NIF_TERM msg,
3342 ErlNifEnv* msgEnv);
3343
3344 static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env,
3345 ERL_NIF_TERM sockRef);
3346 static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env,
3347 ERL_NIF_TERM sockRef);
3348 static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env,
3349 ERL_NIF_TERM tag,
3350 ERL_NIF_TERM sockRef);
3351 static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env,
3352 ERL_NIF_TERM sockRef,
3353 ERL_NIF_TERM opRef,
3354 ERL_NIF_TERM reason);
3355 static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env,
3356 ERL_NIF_TERM sockRef,
3357 ERL_NIF_TERM cnt);
3358 static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env,
3359 ERL_NIF_TERM sockRef,
3360 ERL_NIF_TERM closeRef);
3361 static ERL_NIF_TERM mk_select_msg(ErlNifEnv* env,
3362 ERL_NIF_TERM sockRef,
3363 ERL_NIF_TERM selectRef);
3364 static ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env,
3365 ERL_NIF_TERM sockRef,
3366 ERL_NIF_TERM tag,
3367 ERL_NIF_TERM info);
3368 static ERL_NIF_TERM mk_socket(ErlNifEnv* env,
3369 ERL_NIF_TERM sockRef);
3370
3371 static int esock_select_read(ErlNifEnv* env,
3372 ErlNifEvent event,
3373 void* obj,
3374 const ErlNifPid* pidP,
3375 ERL_NIF_TERM sockRef,
3376 ERL_NIF_TERM selectRef);
3377 static int esock_select_write(ErlNifEnv* env,
3378 ErlNifEvent event,
3379 void* obj,
3380 const ErlNifPid* pidP,
3381 ERL_NIF_TERM sockRef,
3382 ERL_NIF_TERM selectRef);
3383 static int esock_select_stop(ErlNifEnv* env,
3384 ErlNifEvent event,
3385 void* obj);
3386 static int esock_select_cancel(ErlNifEnv* env,
3387 ErlNifEvent event,
3388 enum ErlNifSelectFlags mode,
3389 void* obj);
3390
3391 static char* extract_debug_filename(ErlNifEnv* env,
3392 ERL_NIF_TERM map);
3393
3394
3395 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *
3396 * *
3397 * *
3398 * End of non-__WIN32__ section a.k.a UNIX section *
3399 * *
3400 * *
3401 * ---------------------------------------------------------------------- */
3402 #endif // #ifndef __WIN32__
3403
3404
3405 /*
3406 #if defined(HAS_AF_LOCAL) || defined(SO_BINDTODEVICE)
3407 static size_t my_strnlen(const char *s, size_t maxlen);
3408 #endif
3409 */
3410
3411 static void esock_dtor(ErlNifEnv* env, void* obj);
3412 static void esock_stop(ErlNifEnv* env,
3413 void* obj,
3414 ErlNifEvent fd,
3415 int is_direct_call);
3416 static void esock_down(ErlNifEnv* env,
3417 void* obj,
3418 const ErlNifPid* pidP,
3419 const ErlNifMonitor* monP);
3420
3421 static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
3422
3423
3424
3425 #if HAVE_IN6
3426 # if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
3427 # if HAVE_DECL_IN6ADDR_ANY_INIT
3428 static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
3429 # else
3430 static const struct in6_addr in6addr_any =
3431 { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
3432 # endif /* HAVE_IN6ADDR_ANY_INIT */
3433 # endif /* ! HAVE_DECL_IN6ADDR_ANY */
3434
3435 # if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
3436 # if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
3437 static const struct in6_addr in6addr_loopback =
3438 { { IN6ADDR_LOOPBACK_INIT } };
3439 # else
3440 static const struct in6_addr in6addr_loopback =
3441 { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
3442 # endif /* HAVE_IN6ADDR_LOOPBACk_INIT */
3443 # endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
3444 #endif /* HAVE_IN6 */
3445
3446
3447
3448 /* *** Global atoms ***
3449 * Note that when an (global) atom is added here, it must also be added
3450 * in the socket_int.h file!
3451 */
3452 #define GLOBAL_ATOMS \
3453 GLOBAL_ATOM_DECL(abort); \
3454 GLOBAL_ATOM_DECL(accept); \
3455 GLOBAL_ATOM_DECL(acceptconn); \
3456 GLOBAL_ATOM_DECL(acceptfilter); \
3457 GLOBAL_ATOM_DECL(adaption_layer); \
3458 GLOBAL_ATOM_DECL(addr); \
3459 GLOBAL_ATOM_DECL(addrform); \
3460 GLOBAL_ATOM_DECL(add_membership); \
3461 GLOBAL_ATOM_DECL(add_source_membership); \
3462 GLOBAL_ATOM_DECL(any); \
3463 GLOBAL_ATOM_DECL(associnfo); \
3464 GLOBAL_ATOM_DECL(authhdr); \
3465 GLOBAL_ATOM_DECL(auth_active_key); \
3466 GLOBAL_ATOM_DECL(auth_asconf); \
3467 GLOBAL_ATOM_DECL(auth_chunk); \
3468 GLOBAL_ATOM_DECL(auth_delete_key); \
3469 GLOBAL_ATOM_DECL(auth_key); \
3470 GLOBAL_ATOM_DECL(auth_level); \
3471 GLOBAL_ATOM_DECL(autoclose); \
3472 GLOBAL_ATOM_DECL(bad_data); \
3473 GLOBAL_ATOM_DECL(bindtodevice); \
3474 GLOBAL_ATOM_DECL(block_source); \
3475 GLOBAL_ATOM_DECL(broadcast); \
3476 GLOBAL_ATOM_DECL(busy_poll); \
3477 GLOBAL_ATOM_DECL(checksum); \
3478 GLOBAL_ATOM_DECL(close); \
3479 GLOBAL_ATOM_DECL(cmsg_cloexec); \
3480 GLOBAL_ATOM_DECL(command); \
3481 GLOBAL_ATOM_DECL(confirm); \
3482 GLOBAL_ATOM_DECL(congestion); \
3483 GLOBAL_ATOM_DECL(connect); \
3484 GLOBAL_ATOM_DECL(context); \
3485 GLOBAL_ATOM_DECL(cork); \
3486 GLOBAL_ATOM_DECL(credentials); \
3487 GLOBAL_ATOM_DECL(ctrl); \
3488 GLOBAL_ATOM_DECL(ctrunc); \
3489 GLOBAL_ATOM_DECL(data); \
3490 GLOBAL_ATOM_DECL(debug); \
3491 GLOBAL_ATOM_DECL(default); \
3492 GLOBAL_ATOM_DECL(default_send_params); \
3493 GLOBAL_ATOM_DECL(delayed_ack_time); \
3494 GLOBAL_ATOM_DECL(dgram); \
3495 GLOBAL_ATOM_DECL(disable_fragments); \
3496 GLOBAL_ATOM_DECL(domain); \
3497 GLOBAL_ATOM_DECL(dontfrag); \
3498 GLOBAL_ATOM_DECL(dontroute); \
3499 GLOBAL_ATOM_DECL(drop_membership); \
3500 GLOBAL_ATOM_DECL(drop_source_membership); \
3501 GLOBAL_ATOM_DECL(dstopts); \
3502 GLOBAL_ATOM_DECL(egp); \
3503 GLOBAL_ATOM_DECL(enotsup); \
3504 GLOBAL_ATOM_DECL(eor); \
3505 GLOBAL_ATOM_DECL(error); \
3506 GLOBAL_ATOM_DECL(errqueue); \
3507 GLOBAL_ATOM_DECL(esp_network_level); \
3508 GLOBAL_ATOM_DECL(esp_trans_level); \
3509 GLOBAL_ATOM_DECL(events); \
3510 GLOBAL_ATOM_DECL(explicit_eor); \
3511 GLOBAL_ATOM_DECL(faith); \
3512 GLOBAL_ATOM_DECL(false); \
3513 GLOBAL_ATOM_DECL(family); \
3514 GLOBAL_ATOM_DECL(fastroute); \
3515 GLOBAL_ATOM_DECL(flags); \
3516 GLOBAL_ATOM_DECL(flowinfo); \
3517 GLOBAL_ATOM_DECL(fragment_interleave); \
3518 GLOBAL_ATOM_DECL(freebind); \
3519 GLOBAL_ATOM_DECL(get_peer_addr_info); \
3520 GLOBAL_ATOM_DECL(hatype); \
3521 GLOBAL_ATOM_DECL(hdrincl); \
3522 GLOBAL_ATOM_DECL(hmac_ident); \
3523 GLOBAL_ATOM_DECL(hoplimit); \
3524 GLOBAL_ATOM_DECL(hopopts); \
3525 GLOBAL_ATOM_DECL(host); \
3526 GLOBAL_ATOM_DECL(icmp); \
3527 GLOBAL_ATOM_DECL(icmp6); \
3528 GLOBAL_ATOM_DECL(ifindex); \
3529 GLOBAL_ATOM_DECL(igmp); \
3530 GLOBAL_ATOM_DECL(inet); \
3531 GLOBAL_ATOM_DECL(inet6); \
3532 GLOBAL_ATOM_DECL(info); \
3533 GLOBAL_ATOM_DECL(initmsg); \
3534 GLOBAL_ATOM_DECL(invalid); \
3535 GLOBAL_ATOM_DECL(integer_range); \
3536 GLOBAL_ATOM_DECL(iov); \
3537 GLOBAL_ATOM_DECL(ip); \
3538 GLOBAL_ATOM_DECL(ipcomp_level); \
3539 GLOBAL_ATOM_DECL(ipip); \
3540 GLOBAL_ATOM_DECL(ipv6); \
3541 GLOBAL_ATOM_DECL(i_want_mapped_v4_addr); \
3542 GLOBAL_ATOM_DECL(join_group); \
3543 GLOBAL_ATOM_DECL(keepalive); \
3544 GLOBAL_ATOM_DECL(keepcnt); \
3545 GLOBAL_ATOM_DECL(keepidle); \
3546 GLOBAL_ATOM_DECL(keepintvl); \
3547 GLOBAL_ATOM_DECL(kernel); \
3548 GLOBAL_ATOM_DECL(leave_group); \
3549 GLOBAL_ATOM_DECL(level); \
3550 GLOBAL_ATOM_DECL(linger); \
3551 GLOBAL_ATOM_DECL(local); \
3552 GLOBAL_ATOM_DECL(local_auth_chunks); \
3553 GLOBAL_ATOM_DECL(loopback); \
3554 GLOBAL_ATOM_DECL(lowdelay); \
3555 GLOBAL_ATOM_DECL(mark); \
3556 GLOBAL_ATOM_DECL(maxburst); \
3557 GLOBAL_ATOM_DECL(maxseg); \
3558 GLOBAL_ATOM_DECL(md5sig); \
3559 GLOBAL_ATOM_DECL(mincost); \
3560 GLOBAL_ATOM_DECL(minttl); \
3561 GLOBAL_ATOM_DECL(more); \
3562 GLOBAL_ATOM_DECL(msfilter); \
3563 GLOBAL_ATOM_DECL(mtu); \
3564 GLOBAL_ATOM_DECL(mtu_discover); \
3565 GLOBAL_ATOM_DECL(multicast); \
3566 GLOBAL_ATOM_DECL(multicast_all); \
3567 GLOBAL_ATOM_DECL(multicast_hops); \
3568 GLOBAL_ATOM_DECL(multicast_if); \
3569 GLOBAL_ATOM_DECL(multicast_loop); \
3570 GLOBAL_ATOM_DECL(multicast_ttl); \
3571 GLOBAL_ATOM_DECL(nodelay); \
3572 GLOBAL_ATOM_DECL(nodefrag); \
3573 GLOBAL_ATOM_DECL(noopt); \
3574 GLOBAL_ATOM_DECL(nopush); \
3575 GLOBAL_ATOM_DECL(nosignal); \
3576 GLOBAL_ATOM_DECL(not_found); \
3577 GLOBAL_ATOM_DECL(not_owner); \
3578 GLOBAL_ATOM_DECL(ok); \
3579 GLOBAL_ATOM_DECL(oob); \
3580 GLOBAL_ATOM_DECL(oobinline); \
3581 GLOBAL_ATOM_DECL(options); \
3582 GLOBAL_ATOM_DECL(origdstaddr); \
3583 GLOBAL_ATOM_DECL(otherhost); \
3584 GLOBAL_ATOM_DECL(outgoing); \
3585 GLOBAL_ATOM_DECL(packet); \
3586 GLOBAL_ATOM_DECL(partial_delivery_point); \
3587 GLOBAL_ATOM_DECL(passcred); \
3588 GLOBAL_ATOM_DECL(path); \
3589 GLOBAL_ATOM_DECL(peek); \
3590 GLOBAL_ATOM_DECL(peek_off); \
3591 GLOBAL_ATOM_DECL(peer_addr_params); \
3592 GLOBAL_ATOM_DECL(peer_auth_chunks); \
3593 GLOBAL_ATOM_DECL(peercred); \
3594 GLOBAL_ATOM_DECL(pktinfo); \
3595 GLOBAL_ATOM_DECL(pktoptions); \
3596 GLOBAL_ATOM_DECL(pkttype); \
3597 GLOBAL_ATOM_DECL(port); \
3598 GLOBAL_ATOM_DECL(portrange); \
3599 GLOBAL_ATOM_DECL(primary_addr); \
3600 GLOBAL_ATOM_DECL(priority); \
3601 GLOBAL_ATOM_DECL(protocol); \
3602 GLOBAL_ATOM_DECL(raw); \
3603 GLOBAL_ATOM_DECL(rcvbuf); \
3604 GLOBAL_ATOM_DECL(rcvbufforce); \
3605 GLOBAL_ATOM_DECL(rcvlowat); \
3606 GLOBAL_ATOM_DECL(rcvtimeo); \
3607 GLOBAL_ATOM_DECL(rdm); \
3608 GLOBAL_ATOM_DECL(recv); \
3609 GLOBAL_ATOM_DECL(recvdstaddr); \
3610 GLOBAL_ATOM_DECL(recverr); \
3611 GLOBAL_ATOM_DECL(recvfrom); \
3612 GLOBAL_ATOM_DECL(recvhoplimit); \
3613 GLOBAL_ATOM_DECL(recvif); \
3614 GLOBAL_ATOM_DECL(recvmsg); \
3615 GLOBAL_ATOM_DECL(recvopts); \
3616 GLOBAL_ATOM_DECL(recvorigdstaddr); \
3617 GLOBAL_ATOM_DECL(recvpktinfo); \
3618 GLOBAL_ATOM_DECL(recvtclass); \
3619 GLOBAL_ATOM_DECL(recvtos); \
3620 GLOBAL_ATOM_DECL(recvttl); \
3621 GLOBAL_ATOM_DECL(reliability); \
3622 GLOBAL_ATOM_DECL(reset_streams); \
3623 GLOBAL_ATOM_DECL(retopts); \
3624 GLOBAL_ATOM_DECL(reuseaddr); \
3625 GLOBAL_ATOM_DECL(reuseport); \
3626 GLOBAL_ATOM_DECL(rights); \
3627 GLOBAL_ATOM_DECL(router_alert); \
3628 GLOBAL_ATOM_DECL(rthdr); \
3629 GLOBAL_ATOM_DECL(rtoinfo); \
3630 GLOBAL_ATOM_DECL(rxq_ovfl); \
3631 GLOBAL_ATOM_DECL(scope_id); \
3632 GLOBAL_ATOM_DECL(sctp); \
3633 GLOBAL_ATOM_DECL(sec); \
3634 GLOBAL_ATOM_DECL(select_failed); \
3635 GLOBAL_ATOM_DECL(select_sent); \
3636 GLOBAL_ATOM_DECL(send); \
3637 GLOBAL_ATOM_DECL(sendmsg); \
3638 GLOBAL_ATOM_DECL(sendsrcaddr); \
3639 GLOBAL_ATOM_DECL(sendto); \
3640 GLOBAL_ATOM_DECL(seqpacket); \
3641 GLOBAL_ATOM_DECL(setfib); \
3642 GLOBAL_ATOM_DECL(set_peer_primary_addr); \
3643 GLOBAL_ATOM_DECL(socket); \
3644 GLOBAL_ATOM_DECL(sndbuf); \
3645 GLOBAL_ATOM_DECL(sndbufforce); \
3646 GLOBAL_ATOM_DECL(sndlowat); \
3647 GLOBAL_ATOM_DECL(sndtimeo); \
3648 GLOBAL_ATOM_DECL(spec_dst); \
3649 GLOBAL_ATOM_DECL(status); \
3650 GLOBAL_ATOM_DECL(stream); \
3651 GLOBAL_ATOM_DECL(syncnt); \
3652 GLOBAL_ATOM_DECL(tclass); \
3653 GLOBAL_ATOM_DECL(tcp); \
3654 GLOBAL_ATOM_DECL(throughput); \
3655 GLOBAL_ATOM_DECL(timestamp); \
3656 GLOBAL_ATOM_DECL(tos); \
3657 GLOBAL_ATOM_DECL(transparent); \
3658 GLOBAL_ATOM_DECL(true); \
3659 GLOBAL_ATOM_DECL(trunc); \
3660 GLOBAL_ATOM_DECL(ttl); \
3661 GLOBAL_ATOM_DECL(type); \
3662 GLOBAL_ATOM_DECL(udp); \
3663 GLOBAL_ATOM_DECL(unblock_source); \
3664 GLOBAL_ATOM_DECL(undefined); \
3665 GLOBAL_ATOM_DECL(unicast_hops); \
3666 GLOBAL_ATOM_DECL(unspec); \
3667 GLOBAL_ATOM_DECL(usec); \
3668 GLOBAL_ATOM_DECL(user); \
3669 GLOBAL_ATOM_DECL(user_timeout); \
3670 GLOBAL_ATOM_DECL(use_ext_recvinfo); \
3671 GLOBAL_ATOM_DECL(use_min_mtu); \
3672 GLOBAL_ATOM_DECL(v6only)
3673
3674
3675 /* *** Global error reason atoms *** */
3676 #define GLOBAL_ERROR_REASON_ATOMS \
3677 GLOBAL_ATOM_DECL(eagain); \
3678 GLOBAL_ATOM_DECL(einval)
3679
3680
3681 #define GLOBAL_ATOM_DECL(A) ERL_NIF_TERM esock_atom_##A
3682 GLOBAL_ATOMS;
3683 GLOBAL_ERROR_REASON_ATOMS;
3684 #undef GLOBAL_ATOM_DECL
3685 ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
3686
3687 /* *** Local atoms *** */
3688 #define LOCAL_ATOMS \
3689 LOCAL_ATOM_DECL(accepting); \
3690 LOCAL_ATOM_DECL(acc_success); \
3691 LOCAL_ATOM_DECL(acc_fails); \
3692 LOCAL_ATOM_DECL(acc_tries); \
3693 LOCAL_ATOM_DECL(acc_waits); \
3694 LOCAL_ATOM_DECL(adaptation_layer); \
3695 LOCAL_ATOM_DECL(add); \
3696 LOCAL_ATOM_DECL(addr_unreach); \
3697 LOCAL_ATOM_DECL(address); \
3698 LOCAL_ATOM_DECL(adm_prohibited); \
3699 LOCAL_ATOM_DECL(already); \
3700 LOCAL_ATOM_DECL(association); \
3701 LOCAL_ATOM_DECL(assoc_id); \
3702 LOCAL_ATOM_DECL(authentication); \
3703 LOCAL_ATOM_DECL(boolean); \
3704 LOCAL_ATOM_DECL(bound); \
3705 LOCAL_ATOM_DECL(bufsz); \
3706 LOCAL_ATOM_DECL(close); \
3707 LOCAL_ATOM_DECL(closed); \
3708 LOCAL_ATOM_DECL(closing); \
3709 LOCAL_ATOM_DECL(code); \
3710 LOCAL_ATOM_DECL(connected); \
3711 LOCAL_ATOM_DECL(connecting); \
3712 LOCAL_ATOM_DECL(cookie_life); \
3713 LOCAL_ATOM_DECL(counter_wrap); \
3714 LOCAL_ATOM_DECL(counters); \
3715 LOCAL_ATOM_DECL(ctype); \
3716 LOCAL_ATOM_DECL(data_io); \
3717 LOCAL_ATOM_DECL(data_size); \
3718 LOCAL_ATOM_DECL(debug_filename); \
3719 LOCAL_ATOM_DECL(del); \
3720 LOCAL_ATOM_DECL(dest_unreach); \
3721 LOCAL_ATOM_DECL(do); \
3722 LOCAL_ATOM_DECL(dont); \
3723 LOCAL_ATOM_DECL(dtor); \
3724 LOCAL_ATOM_DECL(dup); \
3725 LOCAL_ATOM_DECL(efile); \
3726 LOCAL_ATOM_DECL(exclude); \
3727 LOCAL_ATOM_DECL(false); \
3728 LOCAL_ATOM_DECL(frag_needed); \
3729 LOCAL_ATOM_DECL(host_unknown); \
3730 LOCAL_ATOM_DECL(host_unreach); \
3731 LOCAL_ATOM_DECL(how); \
3732 LOCAL_ATOM_DECL(in4_sockaddr); \
3733 LOCAL_ATOM_DECL(in6_sockaddr); \
3734 LOCAL_ATOM_DECL(include); \
3735 LOCAL_ATOM_DECL(initial); \
3736 LOCAL_ATOM_DECL(interface); \
3737 LOCAL_ATOM_DECL(integer); \
3738 LOCAL_ATOM_DECL(iov_max); \
3739 LOCAL_ATOM_DECL(iow); \
3740 LOCAL_ATOM_DECL(listening); \
3741 LOCAL_ATOM_DECL(local_rwnd); \
3742 LOCAL_ATOM_DECL(max); \
3743 LOCAL_ATOM_DECL(max_attempts); \
3744 LOCAL_ATOM_DECL(max_init_timeo); \
3745 LOCAL_ATOM_DECL(max_instreams); \
3746 LOCAL_ATOM_DECL(asocmaxrxt); \
3747 LOCAL_ATOM_DECL(min); \
3748 LOCAL_ATOM_DECL(missing); \
3749 LOCAL_ATOM_DECL(mode); \
3750 LOCAL_ATOM_DECL(msg); \
3751 LOCAL_ATOM_DECL(msg_flags); \
3752 LOCAL_ATOM_DECL(multiaddr); \
3753 LOCAL_ATOM_DECL(net_unknown); \
3754 LOCAL_ATOM_DECL(net_unreach); \
3755 LOCAL_ATOM_DECL(netns); \
3756 LOCAL_ATOM_DECL(none); \
3757 LOCAL_ATOM_DECL(noroute); \
3758 LOCAL_ATOM_DECL(not_neighbour); \
3759 LOCAL_ATOM_DECL(null); \
3760 LOCAL_ATOM_DECL(num_acceptors); \
3761 LOCAL_ATOM_DECL(num_cnt_bits); \
3762 LOCAL_ATOM_DECL(num_dinet); \
3763 LOCAL_ATOM_DECL(num_dinet6); \
3764 LOCAL_ATOM_DECL(num_dlocal); \
3765 LOCAL_ATOM_DECL(num_outstreams); \
3766 LOCAL_ATOM_DECL(number_peer_destinations); \
3767 LOCAL_ATOM_DECL(num_pip); \
3768 LOCAL_ATOM_DECL(num_psctp); \
3769 LOCAL_ATOM_DECL(num_ptcp); \
3770 LOCAL_ATOM_DECL(num_pudp); \
3771 LOCAL_ATOM_DECL(num_readers); \
3772 LOCAL_ATOM_DECL(num_sockets); \
3773 LOCAL_ATOM_DECL(num_tdgrams); \
3774 LOCAL_ATOM_DECL(num_tseqpkgs); \
3775 LOCAL_ATOM_DECL(num_tstreams); \
3776 LOCAL_ATOM_DECL(num_writers); \
3777 LOCAL_ATOM_DECL(offender); \
3778 LOCAL_ATOM_DECL(onoff); \
3779 LOCAL_ATOM_DECL(options); \
3780 LOCAL_ATOM_DECL(origin); \
3781 LOCAL_ATOM_DECL(otp); \
3782 LOCAL_ATOM_DECL(otp_socket_option);\
3783 LOCAL_ATOM_DECL(owner); \
3784 LOCAL_ATOM_DECL(partial_delivery); \
3785 LOCAL_ATOM_DECL(peer_error); \
3786 LOCAL_ATOM_DECL(peer_rwnd); \
3787 LOCAL_ATOM_DECL(pkt_toobig); \
3788 LOCAL_ATOM_DECL(policy_fail); \
3789 LOCAL_ATOM_DECL(port_unreach); \
3790 LOCAL_ATOM_DECL(prim_file); \
3791 LOCAL_ATOM_DECL(probe); \
3792 LOCAL_ATOM_DECL(protocols); \
3793 LOCAL_ATOM_DECL(rcvctrlbuf); \
3794 LOCAL_ATOM_DECL(read); \
3795 LOCAL_ATOM_DECL(read_byte); \
3796 LOCAL_ATOM_DECL(read_fails); \
3797 LOCAL_ATOM_DECL(read_pkg); \
3798 LOCAL_ATOM_DECL(read_pkg_max); \
3799 LOCAL_ATOM_DECL(read_tries); \
3800 LOCAL_ATOM_DECL(read_waits); \
3801 LOCAL_ATOM_DECL(read_write); \
3802 LOCAL_ATOM_DECL(registry); \
3803 LOCAL_ATOM_DECL(reject_route); \
3804 LOCAL_ATOM_DECL(remote); \
3805 LOCAL_ATOM_DECL(rstates); \
3806 LOCAL_ATOM_DECL(select); \
3807 LOCAL_ATOM_DECL(selected); \
3808 LOCAL_ATOM_DECL(sender_dry); \
3809 LOCAL_ATOM_DECL(send_failure); \
3810 LOCAL_ATOM_DECL(sendfile); \
3811 LOCAL_ATOM_DECL(sendfile_byte); \
3812 LOCAL_ATOM_DECL(sendfile_deferred_close); \
3813 LOCAL_ATOM_DECL(sendfile_fails); \
3814 LOCAL_ATOM_DECL(sendfile_max); \
3815 LOCAL_ATOM_DECL(sendfile_pkg); \
3816 LOCAL_ATOM_DECL(sendfile_pkg_max); \
3817 LOCAL_ATOM_DECL(sendfile_tries); \
3818 LOCAL_ATOM_DECL(sendfile_waits); \
3819 LOCAL_ATOM_DECL(shutdown); \
3820 LOCAL_ATOM_DECL(slist); \
3821 LOCAL_ATOM_DECL(sndctrlbuf); \
3822 LOCAL_ATOM_DECL(sockaddr); \
3823 LOCAL_ATOM_DECL(socket_debug); \
3824 LOCAL_ATOM_DECL(socket_level); \
3825 LOCAL_ATOM_DECL(socket_option); \
3826 LOCAL_ATOM_DECL(sourceaddr); \
3827 LOCAL_ATOM_DECL(state); \
3828 LOCAL_ATOM_DECL(time_exceeded); \
3829 LOCAL_ATOM_DECL(timeout); \
3830 LOCAL_ATOM_DECL(true); \
3831 LOCAL_ATOM_DECL(txstatus); \
3832 LOCAL_ATOM_DECL(txtime); \
3833 LOCAL_ATOM_DECL(use_registry); \
3834 LOCAL_ATOM_DECL(value); \
3835 LOCAL_ATOM_DECL(want); \
3836 LOCAL_ATOM_DECL(write); \
3837 LOCAL_ATOM_DECL(write_byte); \
3838 LOCAL_ATOM_DECL(write_fails); \
3839 LOCAL_ATOM_DECL(write_pkg); \
3840 LOCAL_ATOM_DECL(write_pkg_max); \
3841 LOCAL_ATOM_DECL(write_tries); \
3842 LOCAL_ATOM_DECL(write_waits); \
3843 LOCAL_ATOM_DECL(wstates); \
3844 LOCAL_ATOM_DECL(zero); \
3845 LOCAL_ATOM_DECL(zerocopy)
3846
3847 /* Local error reason atoms */
3848 #define LOCAL_ERROR_REASON_ATOMS \
3849 LOCAL_ATOM_DECL(select_read); \
3850 LOCAL_ATOM_DECL(select_write)
3851
3852 #define LOCAL_ATOM_DECL(LA) static ERL_NIF_TERM atom_##LA
3853 LOCAL_ATOMS;
3854 LOCAL_ERROR_REASON_ATOMS;
3855 #undef LOCAL_ATOM_DECL
3856
3857
3858 /* *** Sockets *** */
3859 static ErlNifResourceType* esocks;
3860 static ErlNifResourceTypeInit esockInit = {
3861 esock_dtor,
3862 esock_stop,
3863 (ErlNifResourceDown*) esock_down
3864 };
3865
3866 // Initiated when the nif is loaded
3867 static ESockData data;
3868
3869
3870 /* These two (inline) functions are primarily intended for debugging,
3871 * that is, to make it easy to add debug printouts.
3872 */
esock_free_env(const char * slogan,ErlNifEnv * env)3873 static ESOCK_INLINE void esock_free_env(const char* slogan, ErlNifEnv* env)
3874 {
3875 SGDBG( ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) );
3876 // esock_dbg_printf("SOCK ENV", "free - %s: 0x%lX\r\n", slogan, env);
3877
3878 if (env != NULL) enif_free_env(env);
3879 }
3880
3881
esock_alloc_env(const char * slogan)3882 static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan)
3883 {
3884 ErlNifEnv* env;
3885
3886 ESOCK_ASSERT( (env = enif_alloc_env()) != NULL);
3887
3888 SGDBG( ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) );
3889 // esock_dbg_printf("SOCK ENV", "alloc - %s: 0x%lX\r\n", slogan, env);
3890
3891 return env;
3892 }
3893
3894
3895 /* ----------------------------------------------------------------------
3896 * N I F F u n c t i o n s
3897 * ----------------------------------------------------------------------
3898 *
3899 * Utility and admin functions:
3900 * ----------------------------
3901 * nif_info/0
3902 * nif_command/1
3903 * nif_supports/1
3904 *
3905 * The "proper" socket functions:
3906 * ------------------------------
3907 * nif_open(FD, Extra)
3908 * nif_open(Domain, Type, Protocol, Extra)
3909 * nif_bind(Sock, LocalAddr)
3910 * nif_connect(Sock, SockAddr)
3911 * nif_listen(Sock, Backlog)
3912 * nif_accept(LSock, Ref)
3913 * nif_send(Sock, SendRef, Data, Flags)
3914 * nif_sendto(Sock, SendRef, Data, Dest, Flags)
3915 * nif_sendmsg(Sock, SendRef, Msg, Flags)
3916 * nif_sendfile(Sock, SendRef, Offset, Count, InFileRef)
3917 * nif_sendfile(Sock, SendRef, Offset, Count)
3918 * nif_sendfile(Sock)
3919 * nif_recv(Sock, Length, Flags, RecvRef)
3920 * nif_recvfrom(Sock, RecvRef, BufSz, Flags)
3921 * nif_recvmsg(Sock, RecvRef, BufSz, CtrlSz, Flags)
3922 * nif_close(Sock)
3923 * nif_shutdown(Sock, How)
3924 * nif_sockname(Sock)
3925 * nif_peername(Sock)
3926 *
3927 * And some functions to manipulate and retrieve socket options:
3928 * -------------------------------------------------------------
3929 * nif_setopt/5
3930 * nif_getopt/3,4
3931 *
3932 * And some utility functions:
3933 * -------------------------------------------------------------
3934 *
3935 * And some socket admin functions:
3936 * -------------------------------------------------------------
3937 * nif_cancel(Sock, Ref)
3938 */
3939
3940
3941 /* ----------------------------------------------------------------------
3942 * nif_info
3943 *
3944 * Description:
3945 * This is currently just a placeholder...
3946 */
3947
3948 static
nif_info(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])3949 ERL_NIF_TERM nif_info(ErlNifEnv* env,
3950 int argc,
3951 const ERL_NIF_TERM argv[])
3952 {
3953 #ifdef __WIN32__
3954 return enif_raise_exception(env, MKA(env, "notsup"));
3955 #else
3956 ERL_NIF_TERM info;
3957 ESockDescriptor* descP;
3958
3959 SGDBG( ("SOCKET", "nif_info -> entry with %d args\r\n", argc) );
3960
3961 if (argc == 0)
3962 return esock_global_info(env);
3963
3964 ESOCK_ASSERT( argc == 1 );
3965
3966 if (!ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
3967 return enif_make_badarg(env);
3968 }
3969
3970 MLOCK(descP->readMtx);
3971 MLOCK(descP->writeMtx);
3972
3973 SSDBG( descP, ("SOCKET", "nif_info(%T) {%d,0x%X} -> get socket info\r\n",
3974 argv[0], descP->sock,
3975 descP->readState | descP->writeState) );
3976
3977 info = esock_socket_info(env, descP);
3978
3979 SSDBG( descP, ("SOCKET", "nif_info(%T) -> get socket info done with"
3980 "\r\n info: %T"
3981 "\r\n", argv[0], info) );
3982
3983 MUNLOCK(descP->writeMtx);
3984 MUNLOCK(descP->readMtx);
3985
3986 return info;
3987 #endif
3988 }
3989
3990
3991 /*
3992 * This function return a property list containing "global" info.
3993 *
3994 * Note that we also include something in the counter list that is not
3995 * actually a counter, the num_cnt_bits. This is the "size" of each counter,
3996 * in number of bits: 16 | 24 | 32 | 48 | 64.
3997 */
3998 #ifndef __WIN32__
3999 static
esock_global_info(ErlNifEnv * env)4000 ERL_NIF_TERM esock_global_info(ErlNifEnv* env)
4001 {
4002 ERL_NIF_TERM
4003 numBits, numSockets, numTypeDGrams, numTypeStreams,
4004 numTypeSeqPkgs, numDomLocal, numDomInet, numDomInet6,
4005 numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP,
4006 sockDbg, iovMax, dbg, useReg, iow;
4007
4008 MLOCK(data.cntMtx);
4009 numBits = MKUI(env, ESOCK_COUNTER_SIZE);
4010 numSockets = MKUI(env, data.numSockets);
4011 numTypeDGrams = MKUI(env, data.numTypeDGrams);
4012 numTypeStreams = MKUI(env, data.numTypeStreams);
4013 numTypeSeqPkgs = MKUI(env, data.numTypeSeqPkgs);
4014 numDomLocal = MKUI(env, data.numDomainLocal);
4015 numDomInet = MKUI(env, data.numDomainInet);
4016 numDomInet6 = MKUI(env, data.numDomainInet6);
4017 numProtoIP = MKUI(env, data.numProtoIP);
4018 numProtoTCP = MKUI(env, data.numProtoTCP);
4019 numProtoUDP = MKUI(env, data.numProtoUDP);
4020 numProtoSCTP = MKUI(env, data.numProtoSCTP);
4021 sockDbg = BOOL2ATOM(data.sockDbg);
4022 MUNLOCK(data.cntMtx);
4023
4024 iovMax = MKI(env, data.iov_max);
4025 dbg = BOOL2ATOM(data.dbg);
4026 useReg = BOOL2ATOM(data.useReg);
4027 iow = BOOL2ATOM(data.iow);
4028
4029 {
4030 ERL_NIF_TERM gcntVals[] =
4031 {numBits,
4032 numSockets,
4033 numTypeDGrams, numTypeStreams, numTypeSeqPkgs,
4034 numDomLocal, numDomInet, numDomInet6,
4035 numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP};
4036 ERL_NIF_TERM gcntKeys[] =
4037 {atom_num_cnt_bits,
4038 atom_num_sockets,
4039 atom_num_tdgrams, atom_num_tstreams, atom_num_tseqpkgs,
4040 atom_num_dlocal, atom_num_dinet, atom_num_dinet6,
4041 atom_num_pip, atom_num_ptcp, atom_num_pudp, atom_num_psctp};
4042 unsigned int numGCntVals = NUM(gcntVals);
4043 unsigned int numGCntKeys = NUM(gcntKeys);
4044 ERL_NIF_TERM gcnt;
4045
4046 ESOCK_ASSERT( numGCntKeys == numGCntVals );
4047 ESOCK_ASSERT( MKMA(env, gcntKeys, gcntVals, numGCntKeys, &gcnt) );
4048
4049 {
4050 ERL_NIF_TERM
4051 keys[] = {esock_atom_debug,
4052 atom_socket_debug,
4053 atom_use_registry,
4054 atom_iow,
4055 atom_counters,
4056 atom_iov_max},
4057 vals[] = {dbg,
4058 sockDbg,
4059 useReg,
4060 iow,
4061 gcnt,
4062 iovMax},
4063 info;
4064 unsigned int
4065 numKeys = NUM(keys),
4066 numVals = NUM(vals);
4067
4068 ESOCK_ASSERT( numKeys == numVals );
4069 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) );
4070
4071 return info;
4072 }
4073 }
4074 }
4075 #endif // #ifndef __WIN32__
4076
4077
4078 /*
4079 * This function return a property *map*. The properties are:
4080 * domain: The domain of the socket
4081 * type: The type of the socket
4082 * protocol: The protocol of the socket
4083 * owner: Controlling process (owner) of the socket)
4084 * rstates: Socket read state(s)
4085 * wstates: Socket write state(s)
4086 * counters: A list of each socket counter and there current values
4087 * readers: The number of current and waiting readers
4088 * writers: The number of current and waiting writers
4089 * acceptors: The number of current and waiting acceptors
4090 */
4091 #ifndef __WIN32__
4092 static
esock_socket_info(ErlNifEnv * env,ESockDescriptor * descP)4093 ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
4094 ESockDescriptor* descP)
4095 {
4096 ERL_NIF_TERM domain = esock_socket_info_domain(env, descP);
4097 ERL_NIF_TERM type = esock_socket_info_type(env, descP);
4098 ERL_NIF_TERM protocol = MKI(env, descP->protocol);
4099 ERL_NIF_TERM ctrlPid = MKPID(env, &descP->ctrlPid);
4100 ERL_NIF_TERM rstates = esock_socket_info_state(env, descP->readState);
4101 ERL_NIF_TERM wstates = esock_socket_info_state(env, descP->writeState);
4102 ERL_NIF_TERM ctype = esock_socket_info_ctype(env, descP);
4103 ERL_NIF_TERM counters = esock_socket_info_counters(env, descP);
4104 ERL_NIF_TERM readers = esock_socket_info_readers(env, descP);
4105 ERL_NIF_TERM writers = esock_socket_info_writers(env, descP);
4106 ERL_NIF_TERM acceptors = esock_socket_info_acceptors(env, descP);
4107
4108 {
4109 ERL_NIF_TERM keys[]
4110 = {esock_atom_domain,
4111 esock_atom_type,
4112 esock_atom_protocol,
4113 atom_owner,
4114 atom_rstates,
4115 atom_wstates,
4116 atom_ctype,
4117 atom_counters,
4118 atom_num_readers,
4119 atom_num_writers,
4120 atom_num_acceptors};
4121 ERL_NIF_TERM vals[]
4122 = {domain,
4123 type,
4124 protocol,
4125 ctrlPid,
4126 rstates,
4127 wstates,
4128 ctype,
4129 counters,
4130 readers,
4131 writers,
4132 acceptors};
4133 ERL_NIF_TERM info;
4134 unsigned int numKeys = NUM(keys);
4135 unsigned int numVals = NUM(vals);
4136
4137 SSDBG( descP, ("SOCKET", "esock_socket_info -> "
4138 "\r\n numKeys: %d"
4139 "\r\n numVals: %d"
4140 "\r\n", numKeys, numVals) );
4141
4142 ESOCK_ASSERT( numKeys == numVals );
4143 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) );
4144
4145 return info;
4146 }
4147 }
4148 #endif // #ifndef __WIN32__
4149
4150
4151 /*
4152 * Encode the socket domain
4153 */
4154 #ifndef __WIN32__
4155 static
esock_socket_info_domain(ErlNifEnv * env,ESockDescriptor * descP)4156 ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env,
4157 ESockDescriptor* descP)
4158 {
4159 int domain = descP->domain;
4160 ERL_NIF_TERM edomain;
4161
4162 esock_encode_domain(env, domain, &edomain);
4163 return edomain;
4164 }
4165 #endif // #ifndef __WIN32__
4166
4167
4168 /*
4169 * Encode the socket type
4170 */
4171 #ifndef __WIN32__
4172 static
esock_socket_info_type(ErlNifEnv * env,ESockDescriptor * descP)4173 ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env,
4174 ESockDescriptor* descP)
4175 {
4176 int type = descP->type;
4177 ERL_NIF_TERM etype;
4178
4179 esock_encode_type(env, type, &etype);
4180
4181 return etype;
4182 }
4183 #endif // #ifndef __WIN32__
4184
4185
4186 /*
4187 * Encode the socket "create type"
4188 * That is "show" how this socket was created:
4189 *
4190 * normal | fromfd | {fromfd, integer()}
4191 */
4192 #ifndef __WIN32__
4193 static
esock_socket_info_ctype(ErlNifEnv * env,ESockDescriptor * descP)4194 ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env,
4195 ESockDescriptor* descP)
4196 {
4197 ERL_NIF_TERM ctype;
4198
4199 SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> entry with"
4200 "\r\n origFD: %d"
4201 "\r\n closeOnClose: %s"
4202 "\r\n", descP->sock,
4203 descP->origFD, B2S(descP->closeOnClose)) );
4204
4205 if (descP->origFD > 0) {
4206 /* Created from other FD */
4207 if (descP->closeOnClose) {
4208 /* We *have* dup'ed: {fromfd, integer()} */
4209 ctype = MKT2(env, MKA(env, "fromfd"), MKI(env, descP->origFD));
4210 } else {
4211 /* We have *not* dup'ed: fromfd */
4212 ctype = MKA(env, "fromfd");
4213 }
4214 } else {
4215 /* Normal socket */
4216 ctype = MKA(env, "normal");
4217 }
4218
4219 SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> done:"
4220 "\r\n ctype: %T"
4221 "\r\n", descP->sock, ctype) );
4222
4223 return ctype;
4224 }
4225 #endif // #ifndef __WIN32__
4226
4227
4228 /*
4229 * Encode the socket "state"
4230 * That is "show" how this socket was created:
4231 *
4232 * normal | fromfd | {fromfd, integer()}
4233 */
4234 #ifndef __WIN32__
4235 static
esock_socket_info_state(ErlNifEnv * env,unsigned int state)4236 ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env,
4237 unsigned int state)
4238 {
4239 SocketTArray estate = TARRAY_CREATE(10);
4240 ERL_NIF_TERM estateList;
4241
4242
4243 if ((state & ESOCK_STATE_BOUND) != 0) {
4244 /*
4245 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> bound"
4246 "\r\n", descP->sock) );
4247 */
4248 TARRAY_ADD(estate, atom_bound);
4249 }
4250
4251 if ((state & ESOCK_STATE_LISTENING) != 0) {
4252 /*
4253 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> listening"
4254 "\r\n", descP->sock) );
4255 */
4256 TARRAY_ADD(estate, atom_listening);
4257 }
4258
4259 if ((state & ESOCK_STATE_ACCEPTING) != 0) {
4260 /*
4261 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> accepting"
4262 "\r\n", descP->sock) );
4263 */
4264 TARRAY_ADD(estate, atom_accepting);
4265 }
4266
4267 if ((state & ESOCK_STATE_CONNECTING) != 0) {
4268 /*
4269 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connecting"
4270 "\r\n", descP->sock) );
4271 */
4272 TARRAY_ADD(estate, atom_connecting);
4273 }
4274
4275 if ((state & ESOCK_STATE_CONNECTED) != 0) {
4276 /*
4277 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connected"
4278 "\r\n", descP->sock) );
4279 */
4280 TARRAY_ADD(estate, atom_connected);
4281 }
4282
4283 if ((state & ESOCK_STATE_SELECTED) != 0) {
4284 /*
4285 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> selected"
4286 "\r\n", descP->sock) );
4287 */
4288 TARRAY_ADD(estate, atom_selected);
4289 }
4290
4291 if ((state & ESOCK_STATE_CLOSING) != 0) {
4292 /*
4293 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closing"
4294 "\r\n", descP->sock) );
4295 */
4296 TARRAY_ADD(estate, atom_closing);
4297 }
4298
4299 if ((state & ESOCK_STATE_CLOSED) != 0) {
4300 /*
4301 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closed"
4302 "\r\n", descP->sock) );
4303 */
4304 TARRAY_ADD(estate, atom_closed);
4305 }
4306
4307 if ((state & ESOCK_STATE_DTOR) != 0) {
4308 /*
4309 SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> dror"
4310 "\r\n", descP->sock) );
4311 */
4312 TARRAY_ADD(estate, atom_dtor);
4313 }
4314
4315 TARRAY_TOLIST(estate, env, &estateList);
4316
4317 return estateList;
4318 }
4319 #endif // #ifndef __WIN32__
4320
4321
4322 /*
4323 * Collect all counters for a socket.
4324 */
4325 #ifndef __WIN32__
4326 static
esock_socket_info_counters(ErlNifEnv * env,ESockDescriptor * descP)4327 ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
4328 ESockDescriptor* descP)
4329 {
4330 ERL_NIF_TERM keys[] = {atom_read_byte,
4331 atom_read_fails,
4332 atom_read_pkg,
4333 atom_read_pkg_max,
4334 atom_read_tries,
4335 atom_read_waits,
4336 atom_write_byte,
4337 atom_write_fails,
4338 atom_write_pkg,
4339 atom_write_pkg_max,
4340 atom_write_tries,
4341 atom_write_waits,
4342 atom_acc_success,
4343 atom_acc_fails,
4344 atom_acc_tries,
4345 atom_acc_waits};
4346 unsigned int numKeys = NUM(keys);
4347 ERL_NIF_TERM vals[] = {MKCNT(env, descP->readByteCnt),
4348 MKCNT(env, descP->readFails),
4349 MKCNT(env, descP->readPkgCnt),
4350 MKCNT(env, descP->readPkgMax),
4351 MKCNT(env, descP->readTries),
4352 MKCNT(env, descP->readWaits),
4353 MKCNT(env, descP->writeByteCnt),
4354 MKCNT(env, descP->writeFails),
4355 MKCNT(env, descP->writePkgCnt),
4356 MKCNT(env, descP->writePkgMax),
4357 MKCNT(env, descP->writeTries),
4358 MKCNT(env, descP->writeWaits),
4359 MKCNT(env, descP->accSuccess),
4360 MKCNT(env, descP->accFails),
4361 MKCNT(env, descP->accTries),
4362 MKCNT(env, descP->accWaits)};
4363 unsigned int numVals = NUM(vals);
4364 ERL_NIF_TERM cnts;
4365
4366 SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> "
4367 "\r\n numKeys: %d"
4368 "\r\n numVals: %d"
4369 "\r\n", numKeys, numVals) );
4370
4371 ESOCK_ASSERT( numKeys == numVals );
4372 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &cnts) );
4373
4374 #ifdef HAVE_SENDFILE
4375 if (descP->sendfileCountersP != NULL) {
4376 ESockSendfileCounters *cP = descP->sendfileCountersP;
4377 ERL_NIF_TERM m,
4378 sfKeys[] =
4379 {atom_sendfile,
4380 atom_sendfile_byte,
4381 atom_sendfile_fails,
4382 atom_sendfile_max,
4383 atom_sendfile_pkg,
4384 atom_sendfile_pkg_max,
4385 atom_sendfile_tries,
4386 atom_sendfile_waits},
4387 sfVals[] =
4388 {MKUI(env, cP->cnt),
4389 MKUI(env, cP->byteCnt),
4390 MKUI(env, cP->fails),
4391 MKUI(env, cP->max),
4392 MKUI(env, cP->pkg),
4393 MKUI(env, cP->pkgMax),
4394 MKUI(env, cP->tries),
4395 MKUI(env, cP->waits)};
4396 size_t n, numSfKeys = NUM(sfKeys);
4397
4398 ESOCK_ASSERT( numSfKeys == NUM(sfVals) );
4399 for (n = 0; n < numSfKeys; n++) {
4400 ESOCK_ASSERT( enif_make_map_put(env, cnts,
4401 sfKeys[n], sfVals[n],
4402 &m) );
4403 cnts = m;
4404 }
4405 }
4406 #endif
4407
4408 SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> done with"
4409 "\r\n cnts: %T"
4410 "\r\n", cnts) );
4411
4412 return cnts;
4413 }
4414 #endif // #ifndef __WIN32__
4415
4416
4417
4418 /* ----------------------------------------------------------------------
4419 * nif_command
4420 *
4421 * Description:
4422 * This function is intended to handle "various" commands. That is,
4423 * commands and operations that are not part of the socket API proper.
4424 * It's a map with two attributes command and (command) data:
4425 * #{command :: atom(), data :: term()}
4426 *
4427 * Currently it handles setting:
4428 *
4429 * Command Data
4430 * ------- ----
4431 * (global) debug boolean()
4432 * socket_debug boolean()
4433 * use_registry boolean()
4434 *
4435 */
4436
4437 static
nif_command(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])4438 ERL_NIF_TERM nif_command(ErlNifEnv* env,
4439 int argc,
4440 const ERL_NIF_TERM argv[])
4441 {
4442 #ifdef __WIN32__
4443 return enif_raise_exception(env, MKA(env, "notsup"));
4444 #else
4445 ERL_NIF_TERM command, cdata, result;
4446
4447 ESOCK_ASSERT( argc == 1 );
4448
4449 SGDBG( ("SOCKET", "nif_command -> entry with %d args\r\n", argc) );
4450
4451 if (! GET_MAP_VAL(env, argv[0], esock_atom_command, &command)) {
4452 SGDBG( ("SOCKET",
4453 "nif_command -> field not found: command\r\n") );
4454 return enif_make_badarg(env);
4455 }
4456 if (! GET_MAP_VAL(env, argv[0], esock_atom_data, &cdata)) {
4457 SGDBG( ("SOCKET",
4458 "nif_command -> field not found: data\r\n") );
4459 return enif_make_badarg(env);
4460 }
4461
4462 SGDBG( ("SOCKET", "nif_command -> "
4463 "\r\n command: %T"
4464 "\r\n cdata: %T"
4465 "\r\n", command, cdata) );
4466
4467 result = esock_command(env, command, cdata);
4468
4469 SGDBG( ("SOCKET", "nif_command -> done with result: "
4470 "\r\n %T"
4471 "\r\n", result) );
4472
4473 return result;
4474
4475 #endif // #ifdef __WIN32__ #else
4476 }
4477
4478
4479 #ifndef __WIN32__
4480 static
4481 ERL_NIF_TERM
esock_command(ErlNifEnv * env,ERL_NIF_TERM command,ERL_NIF_TERM cdata)4482 esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata)
4483 {
4484 int cmp;
4485
4486 SGDBG( ("SOCKET", "esock_command -> entry with %T\r\n", command) );
4487
4488 cmp = COMPARE(command, atom_socket_debug);
4489 if (cmp == 0) {
4490 return esock_command_socket_debug(env, cdata);
4491 } else if (cmp < 0) {
4492 if (COMPARE(command, esock_atom_debug) == 0)
4493 return esock_command_debug(env, cdata);
4494 } else { // 0 < cmp
4495 if (COMPARE(command, atom_use_registry) == 0)
4496 return esock_command_use_socket_registry(env, cdata);
4497 }
4498
4499 SGDBG( ("SOCKET", "esock_command -> invalid command: %T\r\n",
4500 command) );
4501
4502 return esock_raise_invalid(env, MKT2(env, esock_atom_command, command));
4503 }
4504 #endif // #ifndef __WIN32__
4505
4506
4507 #ifndef __WIN32__
4508 static
esock_command_debug(ErlNifEnv * env,ERL_NIF_TERM cdata)4509 ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM cdata)
4510 {
4511 ERL_NIF_TERM result;
4512
4513 /* The data *should* be a boolean() */
4514 if (esock_decode_bool(cdata, &data.dbg))
4515 result = esock_atom_ok;
4516 else
4517 result =
4518 esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata));
4519
4520 return result;
4521 }
4522 #endif // #ifndef __WIN32__
4523
4524
4525 #ifndef __WIN32__
4526 static
esock_command_socket_debug(ErlNifEnv * env,ERL_NIF_TERM cdata)4527 ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata)
4528 {
4529 BOOLEAN_T dbg;
4530
4531 /* The data *should* be a boolean() */
4532 if (! esock_decode_bool(cdata, &dbg))
4533 return
4534 esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata));
4535
4536 MLOCK(data.cntMtx);
4537 data.sockDbg = dbg;
4538 MUNLOCK(data.cntMtx);
4539
4540 return esock_atom_ok;;
4541 }
4542 #endif // #ifndef __WIN32__
4543
4544
4545 #ifndef __WIN32__
4546 static
esock_command_use_socket_registry(ErlNifEnv * env,ERL_NIF_TERM cdata)4547 ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env,
4548 ERL_NIF_TERM cdata)
4549 {
4550 BOOLEAN_T useReg = FALSE;
4551
4552 /* The data *should* be a boolean() */
4553 if (! esock_decode_bool(cdata, &useReg))
4554 return
4555 esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata));
4556
4557 MLOCK(data.cntMtx);
4558 data.useReg = useReg;
4559 MUNLOCK(data.cntMtx);
4560
4561 return esock_atom_ok;;
4562 }
4563 #endif
4564
4565
4566
4567
4568 /* *** esock_socket_info_readers ***
4569 * *** esock_socket_info_writers ***
4570 * *** esock_socket_info_acceptors ***
4571 *
4572 * Calculate how many readers | writers | acceptors we have for this socket.
4573 * Current requestor + any waiting requestors (of the type).
4574 *
4575 */
4576
4577 #ifndef __WIN32__
4578
4579 #define ESOCK_INFO_REQ_FUNCS \
4580 ESOCK_INFO_REQ_FUNC_DECL(readers, currentReaderP, readersQ) \
4581 ESOCK_INFO_REQ_FUNC_DECL(writers, currentWriterP, writersQ) \
4582 ESOCK_INFO_REQ_FUNC_DECL(acceptors, currentAcceptorP, acceptorsQ)
4583
4584 #define ESOCK_INFO_REQ_FUNC_DECL(F, CRP, Q) \
4585 static \
4586 ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \
4587 ESockDescriptor* descP) \
4588 { \
4589 return socket_info_reqs(env, descP, descP->CRP, &descP->Q); \
4590 }
4591 ESOCK_INFO_REQ_FUNCS
4592 #undef ESOCK_INFO_REQ_FUNC_DECL
4593
4594 static
socket_info_reqs(ErlNifEnv * env,ESockDescriptor * descP,ESockRequestor * currentRequestorP,ESockRequestQueue * q)4595 ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env,
4596 ESockDescriptor* descP,
4597 ESockRequestor* currentRequestorP,
4598 ESockRequestQueue* q)
4599 {
4600 ESockRequestQueueElement* tmp;
4601 ERL_NIF_TERM info;
4602 unsigned int cnt = 0;
4603
4604 if (currentRequestorP != NULL) {
4605 // We have an active requestor!
4606 cnt++;
4607
4608 // And add all the waiting requestors
4609 tmp = q->first;
4610 while (tmp != NULL) {
4611 cnt++;
4612 tmp = tmp->nextP;
4613 }
4614 }
4615
4616 info = MKUI(env, cnt);
4617
4618 SSDBG( descP, ("SOCKET", "socket_info_reqs -> done with"
4619 "\r\n info: %T"
4620 "\r\n", info) );
4621
4622 return info;
4623 }
4624
4625 #endif // #ifndef __WIN32__
4626
4627
4628 /* ----------------------------------------------------------------------
4629 * nif_supports
4630 *
4631 * Description:
4632 * This function is intended to answer the question: "Is X supported?"
4633 * Currently three keys are "supported": options | sctp | ipv6
4634 * That results in a list of all *known options* (known by us) and if
4635 * the platform supports (OS) it or not.
4636 *
4637 * Key
4638 * ---
4639 * (arity 0) [{sctp, boolean()},
4640 * {ipv6, boolean()},
4641 * {local, boolean()},
4642 * {netns, boolean()},
4643 * {sendfile, boolean()}]
4644 *
4645 * msg_flags [{MsgFlag, boolean()}]
4646 * protocols [{[Protocol | Aliases], integer()}],
4647 * options [{socket, [{Opt, boolean()} | Opt]} |
4648 * {ProtoNum::integer(), [{Opt, boolean()} | Opt]}]
4649 */
4650
4651 static
nif_supports(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])4652 ERL_NIF_TERM nif_supports(ErlNifEnv* env,
4653 int argc,
4654 const ERL_NIF_TERM argv[])
4655 {
4656 #ifdef __WIN32__
4657 return enif_raise_exception(env, MKA(env, "notsup"));
4658 #else
4659
4660 SGDBG( ("SOCKET", "nif_supports -> entry with %d args\r\n", argc) );
4661
4662 /* Extract arguments and perform preliminary validation */
4663
4664 if (argc == 0)
4665 return esock_supports_0(env);
4666
4667 ESOCK_ASSERT( argc == 1 );
4668
4669 return esock_supports_1(env, argv[0]);
4670 #endif
4671 }
4672
4673 /* esock_supports - what features do we support?
4674 *
4675 * This gives information about what features actually
4676 * work on the current platform.
4677 */
4678 #ifndef __WIN32__
4679 static
esock_supports_0(ErlNifEnv * env)4680 ERL_NIF_TERM esock_supports_0(ErlNifEnv* env)
4681 {
4682 SocketTArray opts = TARRAY_CREATE(8);
4683 ERL_NIF_TERM is_supported, opts_list;
4684
4685 SGDBG( ("SOCKET", "esock_supports_0 -> entry\r\n") );
4686
4687 #if defined(HAVE_SCTP)
4688 is_supported = esock_atom_true;
4689 #else
4690 is_supported = esock_atom_false;
4691 #endif
4692 TARRAY_ADD(opts, MKT2(env, esock_atom_sctp, is_supported));
4693
4694 /* Is this (test) really sufficient for testing if we support IPv6? */
4695 #if defined(HAVE_IPV6)
4696 is_supported = esock_atom_true;
4697 #else
4698 is_supported = esock_atom_false;
4699 #endif
4700 TARRAY_ADD(opts, MKT2(env, esock_atom_ipv6, is_supported));
4701
4702 #if defined(AF_LOCAL)
4703 is_supported = esock_atom_true;
4704 #else
4705 is_supported = esock_atom_false;
4706 #endif
4707 TARRAY_ADD(opts, MKT2(env, esock_atom_local, is_supported));
4708
4709 #if defined(HAVE_SETNS)
4710 is_supported = esock_atom_true;
4711 #else
4712 is_supported = esock_atom_false;
4713 #endif
4714 TARRAY_ADD(opts, MKT2(env, atom_netns, is_supported));
4715
4716 #if defined(HAVE_SENDFILE)
4717 is_supported = esock_atom_true;
4718 #else
4719 is_supported = esock_atom_false;
4720 #endif
4721 TARRAY_ADD(opts, MKT2(env, atom_sendfile, is_supported));
4722
4723 TARRAY_TOLIST(opts, env, &opts_list);
4724 return opts_list;
4725 }
4726 #endif // #ifndef __WIN32__
4727
4728 #ifndef __WIN32__
4729 static
esock_supports_1(ErlNifEnv * env,ERL_NIF_TERM key)4730 ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key)
4731 {
4732 ERL_NIF_TERM result;
4733
4734 SGDBG( ("SOCKET",
4735 "esock_supports_1 -> entry"
4736 "\r\n key: %T"
4737 "\r\n", key) );
4738
4739 if (COMPARE(key, atom_msg_flags) == 0)
4740 result = esock_supports_msg_flags(env);
4741 else if (COMPARE(key, atom_protocols) == 0)
4742 result = esock_supports_protocols(env);
4743 else if (COMPARE(key, atom_options) == 0)
4744 result = esock_supports_options(env);
4745 else
4746 result = MKEL(env);
4747
4748 return result;
4749 }
4750 #endif // #ifndef __WIN32__
4751
4752
4753
4754 #ifndef __WIN32__
4755
esock_supports_msg_flags(ErlNifEnv * env)4756 static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env) {
4757 size_t n;
4758 ERL_NIF_TERM result;
4759
4760 result = MKEL(env);
4761 for (n = 0; n < NUM(msg_flags); n++) {
4762 result =
4763 MKC(env,
4764 MKT2(env,
4765 *(msg_flags[n].name),
4766 MKI(env, msg_flags[n].flag)),
4767 result);
4768 }
4769
4770 return result;
4771 }
4772
4773 #endif // #ifndef __WIN32__
4774
4775
4776 #ifndef __WIN32__
4777 static
esock_supports_protocols(ErlNifEnv * env)4778 ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env)
4779 {
4780 ERL_NIF_TERM protocols;
4781 struct protoent *pe;
4782 int stayopen;
4783
4784 protocols = MKEL(env);
4785
4786 #if defined(HAVE_GETPROTOENT) && \
4787 defined(HAVE_SETPROTOENT) && \
4788 defined(HAVE_ENDPROTOENT)
4789
4790 MLOCK(data.protocolsMtx);
4791 stayopen = TRUE;
4792 setprotoent(stayopen);
4793 while ((pe = getprotoent()) != NULL) {
4794 ERL_NIF_TERM names;
4795 char **aliases;
4796
4797 names = MKEL(env);
4798 for (aliases = pe->p_aliases; *aliases != NULL; aliases++)
4799 names = MKC(env, MKA(env, *aliases), names);
4800 names = MKC(env, MKA(env, pe->p_name), names);
4801
4802 protocols =
4803 MKC(env, MKT2(env, names, MKI(env, pe->p_proto)), protocols);
4804 }
4805 endprotoent();
4806 MUNLOCK(data.protocolsMtx);
4807
4808 #endif
4809
4810 /* Defaults for known protocols in case getprotoent()
4811 * does not work or does not exist. Prepended to the list
4812 * so a subsequent maps:from_list/2 will take the default
4813 * only when there is nothing from getprotoent().
4814 */
4815
4816 protocols =
4817 MKC(env,
4818 MKT2(env,
4819 MKL1(env, esock_atom_ip),
4820 MKI(env,
4821 #ifdef SOL_IP
4822 SOL_IP
4823 #else
4824 IPPROTO_IP
4825 #endif
4826 )),
4827 protocols);
4828
4829 #ifdef HAVE_IPV6
4830 protocols =
4831 MKC(env,
4832 MKT2(env,
4833 MKL1(env, esock_atom_ipv6),
4834 MKI(env,
4835 #ifdef SOL_IPV6
4836 SOL_IPV6
4837 #else
4838 IPPROTO_IPV6
4839 #endif
4840 )),
4841 protocols);
4842 #endif
4843
4844 protocols =
4845 MKC(env,
4846 MKT2(env, MKL1(env, esock_atom_tcp), MKI(env, IPPROTO_TCP)),
4847 protocols);
4848
4849 protocols =
4850 MKC(env,
4851 MKT2(env, MKL1(env, esock_atom_udp), MKI(env, IPPROTO_UDP)),
4852 protocols);
4853
4854 #ifdef HAVE_SCTP
4855 protocols =
4856 MKC(env,
4857 MKT2(env, MKL1(env, esock_atom_sctp), MKI(env, IPPROTO_SCTP)),
4858 protocols);
4859 #endif
4860
4861 return protocols;
4862 }
4863 #endif // #ifndef __WIN32__
4864
4865
4866
4867 #ifndef __WIN32__
4868
4869 static
esock_supports_options(ErlNifEnv * env)4870 ERL_NIF_TERM esock_supports_options(ErlNifEnv* env)
4871 {
4872 ERL_NIF_TERM levels;
4873 size_t n;
4874
4875 levels = MKEL(env);
4876
4877 for (n = 0; n < NUM(optLevels); n++) {
4878 ERL_NIF_TERM options;
4879 size_t m;
4880 struct ESockOptLevel *levelP;
4881
4882 options = MKEL(env);
4883 levelP = optLevels + n;
4884 for (m = 0; m < levelP->num; m++) {
4885 struct ESockOpt *optP;
4886
4887 optP = levelP->opts + m;
4888 if (optP->setopt == NULL && optP->getopt == NULL) {
4889 options = MKC(env, *optP->nameP, options);
4890 } else {
4891 options =
4892 MKC(env,
4893 MKT2(env, *optP->nameP, MKI(env, optP->opt)),
4894 options);
4895 }
4896 }
4897 levels =
4898 MKC(env,
4899 MKT2(env,
4900 esock_encode_level(env, levelP->level), options),
4901 levels);
4902 }
4903
4904 return levels;
4905 }
4906
4907 #endif // #ifndef __WIN32__
4908
4909
4910
4911 /* ----------------------------------------------------------------------
4912 * nif_open
4913 *
4914 * Description:
4915 * Create an endpoint for communication.
4916 * This function "exist" in two variants.
4917 * One with two args and onewith four.
4918 *
4919 * Arguments (2):
4920 * FD - File Descriptor (of an already open socket).
4921 * Extra - A map with extra options.
4922 * The options are:
4923 * [M] dup - boolean() - Shall the fd be dup'ed or not.
4924 * [O] bound - boolean() - Is the fd already bound.
4925 * [O] domain - domain() - We may not be able to retrieve
4926 * this on all platforms, and in
4927 * *those* cases this *must* be
4928 * provided.
4929 * [O] type - type() - We may not be able to retrieve
4930 * this on all platforms, and in
4931 * *those* cases this *must* be
4932 * provided.
4933 * [O] proto - protocol() - We may not be able to retrieve
4934 * this on all platforms, and in
4935 * *those* cases this *must* be
4936 * provided.
4937 * [O] use_registry - boolean() - Shall we use the socket
4938 * registry for this socket.
4939 * Arguments (4):
4940 * Domain - The domain, for example 'inet'
4941 * Type - Type of socket, for example 'stream'
4942 * Protocol - The protocol, for example 'tcp'
4943 * Extra - A map with "obscure" options.
4944 * Currently the only allowed option are:
4945 * netns - string() - Network namespace. *Only*
4946 * allowed on linux!
4947 * use_registry - boolean() - Shall we use the socket
4948 * registry for this socket.
4949 *
4950 */
4951 static
nif_open(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])4952 ERL_NIF_TERM nif_open(ErlNifEnv* env,
4953 int argc,
4954 const ERL_NIF_TERM argv[])
4955 {
4956 #ifdef __WIN32__
4957 return enif_raise_exception(env, MKA(env, "notsup"));
4958 #else
4959 ERL_NIF_TERM result;
4960
4961 SGDBG( ("SOCKET", "nif_open -> "
4962 "\r\n argc: %d"
4963 "\r\n", argc) );
4964
4965 if (argc == 2) {
4966 int fd;
4967 ERL_NIF_TERM eopts;
4968
4969 if (! GET_INT(env, argv[0], &fd)) {
4970 if (IS_INTEGER(env, argv[0]))
4971 return esock_make_error_integer_range(env, argv[0]);
4972 else
4973 return enif_make_badarg(env);
4974 }
4975 if (! IS_MAP(env, argv[1])) {
4976 return enif_make_badarg(env);
4977 }
4978 eopts = argv[1];
4979
4980 SGDBG( ("SOCKET", "nif_open -> "
4981 "\r\n FD: %d"
4982 "\r\n eopts: %T"
4983 "\r\n", fd, eopts) );
4984
4985 MLOCK(data.cntMtx);
4986 result = esock_open2(env, fd, eopts);
4987 MUNLOCK(data.cntMtx);
4988
4989 } else {
4990 ERL_NIF_TERM edomain, etype, eopts;
4991 int domain, type, proto;
4992
4993 ESOCK_ASSERT( argc == 4 );
4994
4995 /* Extract arguments and perform preliminary validation */
4996
4997 if (! GET_INT(env, argv[2], &proto)) {
4998 if (IS_INTEGER(env, argv[2]))
4999 return esock_make_error_integer_range(env, argv[2]);
5000 else
5001 return enif_make_badarg(env);
5002 }
5003 if (! IS_MAP(env, argv[3])) {
5004 return enif_make_badarg(env);
5005 }
5006 edomain = argv[0];
5007 etype = argv[1];
5008 eopts = argv[3];
5009
5010 SGDBG( ("SOCKET", "nif_open -> "
5011 "\r\n edomain: %T"
5012 "\r\n etype: %T"
5013 "\r\n proto: %T"
5014 "\r\n eopts: %T"
5015 "\r\n", argv[0], argv[1], argv[2], eopts) );
5016
5017 if (esock_decode_domain(env, edomain, &domain) == 0) {
5018 SGDBG( ("SOCKET",
5019 "nif_open -> invalid domain: %d\r\n", edomain) );
5020 return esock_make_invalid(env, esock_atom_domain);
5021 }
5022
5023 if (! esock_decode_type(env, etype, &type)) {
5024 SGDBG( ("SOCKET",
5025 "nif_open -> invalid type: %d\r\n", etype) );
5026 return esock_make_invalid(env, esock_atom_type);
5027 }
5028
5029 MLOCK(data.cntMtx);
5030 result = esock_open4(env, domain, type, proto, eopts);
5031 MUNLOCK(data.cntMtx);
5032 }
5033
5034 SGDBG( ("SOCKET", "nif_open -> done with result: "
5035 "\r\n %T"
5036 "\r\n", result) );
5037
5038 return result;
5039
5040 #endif // #ifdef __WIN32__ #else
5041 }
5042
5043
5044 /* esock_open - create an endpoint (from an existing fd) for communication
5045 *
5046 * Assumes the input has been validated.
5047 *
5048 * Normally we want debugging on (individual) sockets to be controlled
5049 * by the sockets own debug flag. But since we don't even have a socket
5050 * yet, we must use the global debug flag.
5051 */
5052 #ifndef __WIN32__
5053 static
esock_open2(ErlNifEnv * env,int fd,ERL_NIF_TERM eopts)5054 ERL_NIF_TERM esock_open2(ErlNifEnv* env,
5055 int fd,
5056 ERL_NIF_TERM eopts)
5057 {
5058 BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg);
5059 BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg);
5060 ESockDescriptor* descP;
5061 ERL_NIF_TERM sockRef;
5062 int domain, type, protocol;
5063 int save_errno = 0;
5064 BOOLEAN_T closeOnClose;
5065 SOCKET sock;
5066 ErlNifEvent event;
5067 ErlNifPid self;
5068
5069 /* Keep track of the creator
5070 * This should not be a problem, but just in case
5071 * the *open* function is used with the wrong kind
5072 * of environment...
5073 */
5074 ESOCK_ASSERT( enif_self(env, &self) != NULL );
5075
5076 SSDBG2( dbg,
5077 ("SOCKET", "esock_open2 -> entry with"
5078 "\r\n fd: %d"
5079 "\r\n eopts: %T"
5080 "\r\n", fd, eopts) );
5081
5082 /*
5083 * Before we do anything else, we try to retrieve domain, type and protocol
5084 * This information is either present in the eopts map or if not we need
5085 * to "get" it from the system (getsockopt).
5086 * Note that its not possible to get all of these on all platoforms,
5087 * and in those cases the user *must* provide us with them (eopts).
5088 *
5089 * We try the system first (since its more reliable) and if that fails
5090 * we check the eopts map. If neither one works, we *give up*!
5091 */
5092
5093 if (! esock_open_which_domain(fd, &domain)) {
5094 SSDBG2( dbg,
5095 ("SOCKET",
5096 "esock_open2 -> failed get domain from system\r\n") );
5097
5098 if (! esock_open2_get_domain(env, eopts, &domain)) {
5099 return esock_make_invalid(env, esock_atom_domain);
5100 }
5101 }
5102
5103 if (! esock_open_which_type(fd, &type)) {
5104 SSDBG2( dbg,
5105 ("SOCKET", "esock_open2 -> failed get type from system\r\n") );
5106
5107 if (! esock_open2_get_type(env, eopts, &type))
5108 return esock_make_invalid(env, esock_atom_type);
5109 }
5110
5111 if (! esock_open_which_protocol(fd, &protocol)) {
5112 SSDBG2( dbg,
5113 ("SOCKET",
5114 "esock_open2 -> failed get protocol from system\r\n") );
5115
5116 if (! esock_extract_int_from_map(env, eopts,
5117 esock_atom_protocol, &protocol)) {
5118 SSDBG2( dbg,
5119 ("SOCKET",
5120 "esock_open2 -> trying protocol 0\r\n") );
5121 protocol = 0;
5122 }
5123 }
5124
5125
5126 SSDBG2( dbg,
5127 ("SOCKET", "esock_open2 -> "
5128 "\r\n domain: %d"
5129 "\r\n type: %d"
5130 "\r\n protocol: %d"
5131 "\r\n", domain, type, protocol) );
5132
5133
5134 if (esock_open2_todup(env, eopts)) {
5135 /* We shall dup the socket */
5136 if (ESOCK_IS_ERROR(sock = dup(fd))) {
5137 save_errno = sock_errno();
5138
5139 SSDBG2( dbg,
5140 ("SOCKET",
5141 "esock_open2 -> dup failed: %d\r\n",
5142 save_errno) );
5143
5144 return esock_make_error_errno(env, save_errno);
5145 }
5146 closeOnClose = TRUE;
5147 } else {
5148 sock = fd;
5149 closeOnClose = FALSE;
5150 }
5151
5152 event = sock;
5153
5154 SET_NONBLOCKING(sock);
5155
5156 /* Create and initiate the socket "descriptor" */
5157 descP = alloc_descriptor(sock, event);
5158 descP->ctrlPid = self;
5159 descP->domain = domain;
5160 descP->type = type;
5161 descP->protocol = protocol;
5162 descP->closeOnClose = closeOnClose;
5163 descP->origFD = fd;
5164
5165 /* Check if we are already connected, if so change state */
5166 {
5167 ESockAddress remote;
5168 SOCKLEN_T addrLen = sizeof(remote);
5169 sys_memzero((char *) &remote, addrLen);
5170 if (sock_peer(descP->sock,
5171 (struct sockaddr*) &remote,
5172 &addrLen) == 0) {
5173 SSDBG2( dbg, ("SOCKET", "esock_open2 -> connected\r\n") );
5174 descP->writeState |= ESOCK_STATE_CONNECTED;
5175 } else {
5176 SSDBG2( dbg, ("SOCKET", "esock_open2 -> not connected\r\n") );
5177 }
5178 }
5179
5180 /* And create the 'socket' resource */
5181 sockRef = enif_make_resource(env, descP);
5182 enif_release_resource(descP);
5183
5184 ESOCK_ASSERT( MONP("esock_open2 -> ctrl",
5185 env, descP,
5186 &descP->ctrlPid,
5187 &descP->ctrlMon) == 0 );
5188
5189 descP->dbg = dbg;
5190 descP->useReg = useReg;
5191 inc_socket(domain, type, protocol);
5192
5193 /* And finally (maybe) update the registry.
5194 * Shall we keep track of the fact that this socket is created elsewhere?
5195 */
5196 if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef);
5197
5198 SSDBG2( dbg,
5199 ("SOCKET", "esock_open2 -> done: %T\r\n", sockRef) );
5200
5201 return esock_make_ok2(env, sockRef);
5202 }
5203 #endif // #ifndef __WIN32__
5204
5205
5206 /* The eextra contains a boolean 'dup' key. Defaults to TRUE.
5207 */
5208 #ifndef __WIN32__
5209 static
esock_open2_todup(ErlNifEnv * env,ERL_NIF_TERM eextra)5210 BOOLEAN_T esock_open2_todup(ErlNifEnv* env, ERL_NIF_TERM eextra)
5211 {
5212 return esock_get_bool_from_map(env, eextra, atom_dup, TRUE);
5213 }
5214 #endif // #ifndef __WIN32__
5215
5216 /* The eextra contains an integer 'domain' key.
5217 */
5218 #ifndef __WIN32__
5219 static
esock_open2_get_domain(ErlNifEnv * env,ERL_NIF_TERM eopts,int * domain)5220 BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env,
5221 ERL_NIF_TERM eopts, int* domain)
5222 {
5223 ERL_NIF_TERM edomain;
5224
5225 SGDBG( ("SOCKET", "esock_open2_get_domain -> entry with"
5226 "\r\n eopts: %T"
5227 "\r\n", eopts) );
5228
5229 if (!GET_MAP_VAL(env, eopts,
5230 esock_atom_domain, &edomain))
5231 return FALSE;
5232
5233 if (esock_decode_domain(env, edomain, domain) == 0)
5234 return FALSE;
5235
5236 return TRUE;
5237 }
5238 #endif // #ifndef __WIN32__
5239
5240 /* The eextra contains an integer 'type' key.
5241 */
5242 #ifndef __WIN32__
5243 static
esock_open2_get_type(ErlNifEnv * env,ERL_NIF_TERM eopts,int * type)5244 BOOLEAN_T esock_open2_get_type(ErlNifEnv* env,
5245 ERL_NIF_TERM eopts, int* type)
5246 {
5247 ERL_NIF_TERM etype;
5248
5249 SGDBG( ("SOCKET", "esock_open2_get_type -> entry with"
5250 "\r\n eopts: %T"
5251 "\r\n", eopts) );
5252
5253 if (! GET_MAP_VAL(env, eopts, esock_atom_type, &etype))
5254 return FALSE;
5255
5256 if (! esock_decode_type(env, etype, type))
5257 return FALSE;
5258
5259 return TRUE;
5260 }
5261 #endif // #ifndef __WIN32__
5262
5263
5264 /* esock_open4 - create an endpoint for communication
5265 *
5266 * Assumes the input has been validated.
5267 *
5268 * Normally we want debugging on (individual) sockets to be controlled
5269 * by the sockets own debug flag. But since we don't even have a socket
5270 * yet, we must use the global debug flag.
5271 */
5272 #ifndef __WIN32__
5273 static
esock_open4(ErlNifEnv * env,int domain,int type,int protocol,ERL_NIF_TERM eopts)5274 ERL_NIF_TERM esock_open4(ErlNifEnv* env,
5275 int domain,
5276 int type,
5277 int protocol,
5278 ERL_NIF_TERM eopts)
5279 {
5280 BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg);
5281 BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg);
5282 ESockDescriptor* descP;
5283 ERL_NIF_TERM sockRef;
5284 int proto = protocol, save_errno;
5285 SOCKET sock;
5286 ErlNifEvent event;
5287 char* netns;
5288 #ifdef HAVE_SETNS
5289 int current_ns = 0;
5290 #endif
5291 ErlNifPid self;
5292
5293 /* Keep track of the creator
5294 * This should not be a problem, but just in case
5295 * the *open* function is used with the wrong kind
5296 * of environment...
5297 */
5298 ESOCK_ASSERT( enif_self(env, &self) != NULL );
5299
5300 SSDBG2( dbg,
5301 ("SOCKET", "esock_open4 -> entry with"
5302 "\r\n domain: %d"
5303 "\r\n type: %d"
5304 "\r\n protocol: %d"
5305 "\r\n eopts: %T"
5306 "\r\n", domain, type, protocol, eopts) );
5307
5308
5309 #ifdef HAVE_SETNS
5310 if (esock_open4_get_netns(env, eopts, &netns)) {
5311 SGDBG( ("SOCKET", "nif_open -> namespace: %s\r\n", netns) );
5312 }
5313 #else
5314 netns = NULL;
5315 #endif
5316
5317
5318 #ifdef HAVE_SETNS
5319 if ((netns != NULL) &&
5320 (! change_network_namespace(netns, ¤t_ns, &save_errno))) {
5321 FREE(netns);
5322 return esock_make_error_errno(env, save_errno);
5323 }
5324 #endif
5325
5326 if (ESOCK_IS_ERROR(sock = sock_open(domain, type, proto))) {
5327 if (netns != NULL) FREE(netns);
5328 return esock_make_error_errno(env, sock_errno());
5329 }
5330
5331 SSDBG2( dbg, ("SOCKET", "esock_open -> open success: %d\r\n", sock) );
5332
5333
5334 /* NOTE that if the protocol = 0 (default) and the domain is not
5335 * local (AF_LOCAL) we need to explicitly get the protocol here!
5336 */
5337
5338 if (proto == 0)
5339 (void) esock_open_which_protocol(sock, &proto);
5340
5341 #ifdef HAVE_SETNS
5342 if (netns != NULL) {
5343 FREE(netns);
5344 if (! restore_network_namespace(current_ns, sock, &save_errno))
5345 return esock_make_error_errno(env, save_errno);
5346 }
5347 #endif
5348
5349
5350 if ((event = sock_create_event(sock)) == INVALID_EVENT) {
5351 save_errno = sock_errno();
5352 (void) sock_close(sock);
5353 return esock_make_error_errno(env, save_errno);
5354 }
5355
5356 SSDBG2( dbg, ("SOCKET", "esock_open4 -> event success: %d\r\n", event) );
5357
5358 SET_NONBLOCKING(sock);
5359
5360
5361 /* Create and initiate the socket "descriptor" */
5362 descP = alloc_descriptor(sock, event);
5363 descP->ctrlPid = self;
5364 descP->domain = domain;
5365 descP->type = type;
5366 descP->protocol = proto;
5367
5368 sockRef = enif_make_resource(env, descP);
5369 enif_release_resource(descP);
5370
5371 ESOCK_ASSERT( MONP("esock_open -> ctrl",
5372 env, descP,
5373 &descP->ctrlPid,
5374 &descP->ctrlMon) == 0 );
5375
5376 descP->dbg = dbg;
5377 descP->useReg = useReg;
5378 inc_socket(domain, type, protocol);
5379
5380 /* And finally (maybe) update the registry */
5381 if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef);
5382
5383 return esock_make_ok2(env, sockRef);
5384 }
5385 #endif // #ifndef __WIN32__
5386
5387 /* The eextra map "may" contain a boolean 'debug' key.
5388 */
5389 #ifndef __WIN32__
5390 static
esock_open_is_debug(ErlNifEnv * env,ERL_NIF_TERM eextra,BOOLEAN_T dflt)5391 BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, ERL_NIF_TERM eextra,
5392 BOOLEAN_T dflt)
5393 {
5394 return esock_get_bool_from_map(env, eextra, esock_atom_debug, dflt);
5395 }
5396 #endif // #ifndef __WIN32__
5397
5398
5399 #ifndef __WIN32__
5400 static
esock_open_use_registry(ErlNifEnv * env,ERL_NIF_TERM eextra,BOOLEAN_T dflt)5401 BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, ERL_NIF_TERM eextra,
5402 BOOLEAN_T dflt)
5403 {
5404 return esock_get_bool_from_map(env, eextra, atom_use_registry, dflt);
5405 }
5406 #endif
5407
5408
5409 #ifndef __WIN32__
5410 static
esock_open_which_domain(SOCKET sock,int * domain)5411 BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain)
5412 {
5413 #if defined(SO_DOMAIN)
5414 if (esock_getopt_int(sock, SOL_SOCKET, SO_DOMAIN, domain))
5415 return TRUE;
5416 #endif
5417 return FALSE;
5418 }
5419 #endif // #ifndef __WIN32__
5420
5421
5422 #ifndef __WIN32__
5423 static
esock_open_which_type(SOCKET sock,int * type)5424 BOOLEAN_T esock_open_which_type(SOCKET sock, int* type)
5425 {
5426 #if defined(SO_TYPE)
5427 if (esock_getopt_int(sock, SOL_SOCKET, SO_TYPE, type))
5428 return TRUE;
5429 #endif
5430 return FALSE;
5431 }
5432 #endif // #ifndef __WIN32__
5433
5434
5435 #ifndef __WIN32__
5436 static
esock_open_which_protocol(SOCKET sock,int * proto)5437 BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto)
5438 {
5439 #if defined(SO_PROTOCOL)
5440 if (esock_getopt_int(sock, SOL_SOCKET, SO_PROTOCOL, proto))
5441 return TRUE;
5442 #endif
5443 return FALSE;
5444 }
5445 #endif // #ifndef __WIN32__
5446
5447
5448
5449 #ifdef HAVE_SETNS
5450
5451
5452 /* We should really have another API, so that we can return errno... */
5453
5454 /* *** change network namespace ***
5455 * Retreive the current namespace and set the new.
5456 * Return result and previous namespace if successfull.
5457 */
5458 #ifndef __WIN32__
5459 static
change_network_namespace(char * netns,int * cns,int * err)5460 BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err)
5461 {
5462 int save_errno;
5463 int current_ns = 0;
5464 int new_ns = 0;
5465
5466 SGDBG( ("SOCKET", "change_network_namespace -> entry with"
5467 "\r\n new ns: %s"
5468 "\r\n", netns) );
5469
5470 current_ns = open("/proc/self/ns/net", O_RDONLY);
5471 if (ESOCK_IS_ERROR(current_ns)) {
5472 *err = sock_errno();
5473 return FALSE;
5474 }
5475 new_ns = open(netns, O_RDONLY);
5476 if (ESOCK_IS_ERROR(new_ns)) {
5477 save_errno = sock_errno();
5478 (void) close(current_ns);
5479 *err = save_errno;
5480 return FALSE;
5481 }
5482 if (setns(new_ns, CLONE_NEWNET) != 0) {
5483 save_errno = sock_errno();
5484 (void) close(new_ns);
5485 (void) close(current_ns);
5486 *err = save_errno;
5487 return FALSE;
5488 } else {
5489 (void) close(new_ns);
5490 *cns = current_ns;
5491 return TRUE;
5492 }
5493 }
5494 #endif // #ifndef __WIN32__
5495
5496
5497 /* *** restore network namespace ***
5498 * Restore the previous namespace (see above).
5499 */
5500 #ifndef __WIN32__
5501 static
restore_network_namespace(int ns,SOCKET sock,int * err)5502 BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err)
5503 {
5504 SGDBG( ("SOCKET", "restore_network_namespace -> entry with"
5505 "\r\n ns: %d"
5506 "\r\n", ns) );
5507
5508 if (setns(ns, CLONE_NEWNET) != 0) {
5509 /* XXX Failed to restore network namespace.
5510 * What to do? Tidy up and return an error...
5511 * Note that the thread now might still be in the namespace.
5512 * Can this even happen? Should the emulator be aborted?
5513 */
5514 int save_errno = sock_errno();
5515 (void) close(sock);
5516 (void) close(ns);
5517 *err = save_errno;
5518 return FALSE;
5519 } else {
5520 (void) close(ns);
5521 return TRUE;
5522 }
5523 }
5524 #endif // #ifndef __WIN32__
5525
5526
5527 #endif // ifdef HAVE_SETNS
5528
5529
5530
5531 /* ----------------------------------------------------------------------
5532 * nif_bind
5533 *
5534 * Description:
5535 * Bind a name to a socket.
5536 *
5537 * Arguments:
5538 * [0] Socket (ref) - Points to the socket descriptor.
5539 * [1] LocalAddr - Local address is a sockaddr map ( socket:sockaddr() ).
5540 */
5541 static
nif_bind(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])5542 ERL_NIF_TERM nif_bind(ErlNifEnv* env,
5543 int argc,
5544 const ERL_NIF_TERM argv[])
5545 {
5546 #ifdef __WIN32__
5547 return enif_raise_exception(env, MKA(env, "notsup"));
5548 #else
5549 ESockDescriptor* descP;
5550 ERL_NIF_TERM eSockAddr, ret;
5551 ESockAddress sockAddr;
5552 SOCKLEN_T addrLen;
5553
5554 ESOCK_ASSERT( argc == 2 );
5555
5556 SGDBG( ("SOCKET", "nif_bind -> entry with argc: %d\r\n", argc) );
5557
5558 /* Extract arguments and perform preliminary validation */
5559
5560 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
5561 return enif_make_badarg(env);
5562 }
5563 eSockAddr = argv[1];
5564
5565 if (! esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen))
5566 return esock_make_invalid(env, atom_sockaddr);
5567
5568 MLOCK(descP->readMtx);
5569
5570 SSDBG( descP,
5571 ("SOCKET", "nif_bind(%T) {%d,0x%X} ->"
5572 "\r\n SockAddr: %T"
5573 "\r\n",
5574 argv[0], descP->sock, descP->readState,
5575 eSockAddr) );
5576
5577 ret = esock_bind(env, descP, &sockAddr, addrLen);
5578
5579 SSDBG( descP, ("SOCKET", "nif_bind(%T) -> done with"
5580 "\r\n ret: %T"
5581 "\r\n", argv[0], ret) );
5582
5583 MUNLOCK(descP->readMtx);
5584
5585 return ret;
5586 #endif // #ifdef __WIN32__ #else
5587 }
5588
5589
5590 #ifndef __WIN32__
5591 static
esock_bind(ErlNifEnv * env,ESockDescriptor * descP,ESockAddress * sockAddrP,SOCKLEN_T addrLen)5592 ERL_NIF_TERM esock_bind(ErlNifEnv* env,
5593 ESockDescriptor* descP,
5594 ESockAddress* sockAddrP,
5595 SOCKLEN_T addrLen)
5596 {
5597 if (! IS_OPEN(descP->readState))
5598 return esock_make_error(env, atom_closed);
5599
5600 if (sock_bind(descP->sock, &sockAddrP->sa, addrLen) < 0) {
5601 return esock_make_error_errno(env, sock_errno());
5602 }
5603
5604 descP->readState |= ESOCK_STATE_BOUND;
5605
5606 return esock_atom_ok;
5607 }
5608 #endif // #ifndef __WIN32__
5609
5610
5611
5612 /* ----------------------------------------------------------------------
5613 * nif_connect
5614 *
5615 * Description:
5616 * Initiate a connection on a socket
5617 *
5618 * Arguments:
5619 * Socket (ref) - Points to the socket descriptor.
5620 * Optional arguments:
5621 * ConnectRef - Ref for the connection
5622 * SockAddr - Socket Address of "remote" host.
5623 * This is sockaddr(), which is either
5624 * sockaddr_in4 or sockaddr_in6.
5625 */
5626 static
nif_connect(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])5627 ERL_NIF_TERM nif_connect(ErlNifEnv* env,
5628 int argc,
5629 const ERL_NIF_TERM argv[])
5630 {
5631 #ifdef __WIN32__
5632 return enif_raise_exception(env, MKA(env, "notsup"));
5633 #else
5634 ESockDescriptor* descP;
5635 ERL_NIF_TERM res, sockRef, connRef;
5636 ESockAddress addr, *addrP;
5637 SOCKLEN_T addrLen;
5638
5639 ESOCK_ASSERT( argc >= 1 );
5640
5641 SGDBG( ("SOCKET", "nif_connect -> entry with argc: %d\r\n", argc) );
5642
5643 /* Extract arguments and perform preliminary validation */
5644
5645 sockRef = argv[0];
5646 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP))
5647 return enif_make_badarg(env);
5648
5649 if (argc == 3) {
5650 ERL_NIF_TERM eSockAddr = argv[2];
5651
5652 connRef = argv[1];
5653 if (! enif_is_ref(env, connRef))
5654 return enif_make_badarg(env);
5655
5656 if (! esock_decode_sockaddr(env, eSockAddr, &addr, &addrLen))
5657 return esock_make_invalid(env, atom_sockaddr);
5658 addrP = &addr;
5659
5660 MLOCK(descP->writeMtx);
5661
5662 SSDBG( descP,
5663 ("SOCKET", "nif_connect(%T), {%d0x%X} ->"
5664 "\r\n ConnRef: %T"
5665 "\r\n SockAddr: %T"
5666 "\r\n",
5667 sockRef, descP->sock, descP->writeState,
5668 connRef, eSockAddr) );
5669 } else {
5670
5671 ESOCK_ASSERT( argc == 1 );
5672
5673 connRef = esock_atom_undefined;
5674 addrP = NULL;
5675 addrLen = 0;
5676
5677 MLOCK(descP->writeMtx);
5678
5679 SSDBG( descP,
5680 ("SOCKET", "nif_connect(%T), {%d,0x%X} ->"
5681 "\r\n",
5682 sockRef, descP->sock, descP->writeState
5683 ) );
5684 }
5685
5686 res = esock_connect(env, descP, sockRef, connRef, addrP, addrLen);
5687
5688 SSDBG( descP, ("SOCKET", "nif_connect(%T) -> done with"
5689 "\r\n res: %T"
5690 "\r\n", sockRef, res) );
5691
5692 MUNLOCK(descP->writeMtx);
5693
5694 return res;
5695
5696 #endif // #ifdef __WIN32__ #else
5697 }
5698
5699
5700 #ifndef __WIN32__
5701 static
esock_connect(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM connRef,ESockAddress * addrP,SOCKLEN_T addrLen)5702 ERL_NIF_TERM esock_connect(ErlNifEnv* env,
5703 ESockDescriptor* descP,
5704 ERL_NIF_TERM sockRef,
5705 ERL_NIF_TERM connRef,
5706 ESockAddress* addrP,
5707 SOCKLEN_T addrLen)
5708 {
5709 int save_errno;
5710 ErlNifPid self;
5711
5712 ESOCK_ASSERT( enif_self(env, &self) != NULL );
5713
5714 /*
5715 * Verify that we are in the proper state
5716 */
5717
5718 if (! IS_OPEN(descP->writeState))
5719 return esock_make_error(env, atom_closed);
5720
5721 /* Connect and Write uses the same select flag
5722 * so they can not be simultaneous
5723 */
5724 if (descP->currentWriterP != NULL)
5725 return esock_make_error_invalid(env, atom_state);
5726
5727 if (descP->connectorP != NULL) {
5728 /* Connect in progress */
5729
5730 if (COMPARE_PIDS(&self, &descP->connector.pid) != 0) {
5731 /* Other process has connect in progress */
5732 if (addrP != NULL) {
5733 return esock_make_error(env, atom_already);
5734 } else {
5735 /* This is a bad call sequence
5736 * - connect without an address is only allowed
5737 * for the connecting process
5738 */
5739 return esock_raise_invalid(env, atom_state);
5740 }
5741 }
5742
5743 /* Finalize after received select message */
5744
5745 requestor_release("esock_connect finalize -> connected",
5746 env, descP, &descP->connector);
5747 descP->connectorP = NULL;
5748 descP->writeState &= ~ESOCK_STATE_CONNECTING;
5749
5750 if (! verify_is_connected(descP, &save_errno)) {
5751 return esock_make_error_errno(env, save_errno);
5752 }
5753
5754 descP->writeState |= ESOCK_STATE_CONNECTED;
5755
5756 return esock_atom_ok;
5757 }
5758
5759 /* No connect in progress */
5760
5761 if (addrP == NULL)
5762 /* This is a bad call sequence
5763 * - connect without an address is only allowed when
5764 * a connect is in progress, after getting the select message
5765 */
5766 return esock_raise_invalid(env, atom_state);
5767
5768 /* Initial connect call, with address */
5769
5770 if (sock_connect(descP->sock, (struct sockaddr*) addrP, addrLen) == 0) {
5771 /* Success already! */
5772 SSDBG( descP, ("SOCKET", "esock_connect {%d} -> connected\r\n",
5773 descP->sock) );
5774
5775 descP->writeState |= ESOCK_STATE_CONNECTED;
5776
5777 return esock_atom_ok;
5778 }
5779
5780 /* Connect returned error */
5781 save_errno = sock_errno();
5782
5783 switch (save_errno) {
5784
5785 case ERRNO_BLOCK: /* Winsock2 */
5786 case EINPROGRESS: /* Unix & OSE!! */
5787 SSDBG( descP,
5788 ("SOCKET", "esock_connect {%d} -> would block => select\r\n",
5789 descP->sock) );
5790 {
5791 int sres;
5792
5793 if ((sres =
5794 esock_select_write(env, descP->sock, descP, NULL,
5795 sockRef, connRef)) < 0)
5796 return
5797 enif_raise_exception(env,
5798 MKT2(env, atom_select_write,
5799 MKI(env, sres)));
5800 /* Initiate connector */
5801 descP->connector.pid = self;
5802 ESOCK_ASSERT( MONP("esock_connect -> conn",
5803 env, descP,
5804 &self, &descP->connector.mon) == 0 );
5805 descP->connector.env = esock_alloc_env("connector");
5806 descP->connector.ref = CP_TERM(descP->connector.env, connRef);
5807 descP->connectorP = &descP->connector;
5808 descP->writeState |=
5809 (ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
5810
5811 return atom_select;
5812 }
5813 break;
5814
5815 default:
5816 SSDBG( descP,
5817 ("SOCKET", "esock_connect {%d} -> error: %d\r\n",
5818 descP->sock, save_errno) );
5819
5820 return esock_make_error_errno(env, save_errno);
5821
5822 } // switch(save_errno)
5823 }
5824 #endif // #ifndef __WIN32__
5825
5826
5827
5828 /* *** verify_is_connected ***
5829 * Check if a connection has been established.
5830 */
5831 #ifndef __WIN32__
5832 static
verify_is_connected(ESockDescriptor * descP,int * err)5833 BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err)
5834 {
5835 /*
5836 * *** This is strange ***
5837 *
5838 * This *should* work on Windows NT too, but doesn't.
5839 * An bug in Winsock 2.0 for Windows NT?
5840 *
5841 * See "Unix Netwok Programming", "The Sockets Networking API",
5842 * W.R.Stevens, Volume 1, third edition, 16.4 Nonblocking 'connect',
5843 * before Interrupted 'connect' (p 412) for a discussion about
5844 * Unix portability and non blocking connect.
5845 */
5846
5847 int error = 0;
5848
5849 #ifdef SO_ERROR
5850 if (! esock_getopt_int(descP->sock, SOL_SOCKET, SO_ERROR, &error)) {
5851 // Solaris does it this way according to W.R.Stevens
5852 error = sock_errno();
5853 }
5854 #elif 1
5855 char buf[0];
5856 if (ESOCK_IS_ERROR(read(descP->sock, buf, sizeof(buf)))) {
5857 error = sock_errno();
5858 }
5859 #else
5860 /* This variant probably returns wrong error value
5861 * ENOTCONN instead of the actual connect error
5862 */
5863 ESockAddress remote;
5864 SOCKLEN_T addrLen = sizeof(remote);
5865 sys_memzero((char *) &remote, addrLen);
5866 if (sock_peer(descP->sock,
5867 (struct sockaddr*) &remote, &addrLen)) < 0) {
5868 error = sock_errno();
5869 }
5870 #endif
5871
5872 if (error != 0) {
5873 *err = error;
5874 return FALSE;
5875 }
5876 return TRUE;
5877 }
5878 #endif // #ifndef __WIN32__
5879
5880
5881
5882 /* ----------------------------------------------------------------------
5883 * nif_listen
5884 *
5885 * Description:
5886 * Listen for connections on a socket.
5887 *
5888 * Arguments:
5889 * Socket (ref) - Points to the socket descriptor.
5890 * Backlog - The maximum length to which the queue of pending
5891 * connections for socket may grow.
5892 */
5893 static
nif_listen(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])5894 ERL_NIF_TERM nif_listen(ErlNifEnv* env,
5895 int argc,
5896 const ERL_NIF_TERM argv[])
5897 {
5898 #ifdef __WIN32__
5899 return enif_raise_exception(env, MKA(env, "notsup"));
5900 #else
5901 ESockDescriptor* descP;
5902 int backlog;
5903 ERL_NIF_TERM ret;
5904
5905 ESOCK_ASSERT( argc == 2 );
5906
5907 SGDBG( ("SOCKET", "nif_listen -> entry with argc: %d\r\n", argc) );
5908
5909 /* Extract arguments and perform preliminary validation */
5910
5911 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
5912 return enif_make_badarg(env);
5913 }
5914 if (! GET_INT(env, argv[1], &backlog)) {
5915 if (IS_INTEGER(env, argv[1]))
5916 return esock_make_error_integer_range(env, argv[1]);
5917 else
5918 return enif_make_badarg(env);
5919 }
5920
5921 MLOCK(descP->readMtx);
5922
5923 SSDBG( descP,
5924 ("SOCKET", "nif_listen(%T), {%d,0x%X} ->"
5925 "\r\n backlog: %d"
5926 "\r\n",
5927 argv[0], descP->sock, descP->readState,
5928 backlog) );
5929
5930 ret = esock_listen(env, descP, backlog);
5931
5932 SSDBG( descP, ("SOCKET", "nif_listen(%T) -> done with"
5933 "\r\n ret: %T"
5934 "\r\n", argv[0], ret) );
5935
5936 MUNLOCK(descP->readMtx);
5937
5938 return ret;
5939 #endif // #ifdef __WIN32__ #else
5940 }
5941
5942
5943
5944 #ifndef __WIN32__
5945 static
esock_listen(ErlNifEnv * env,ESockDescriptor * descP,int backlog)5946 ERL_NIF_TERM esock_listen(ErlNifEnv* env,
5947 ESockDescriptor* descP,
5948 int backlog)
5949 {
5950
5951 /*
5952 * Verify that we are in the proper state
5953 */
5954
5955 if (! IS_OPEN(descP->readState))
5956 return esock_make_error(env, atom_closed);
5957
5958 /*
5959 * And attempt to make socket listening
5960 */
5961
5962 if ((sock_listen(descP->sock, backlog)) < 0)
5963 return esock_make_error_errno(env, sock_errno());
5964
5965 descP->readState |= ESOCK_STATE_LISTENING;
5966
5967 return esock_atom_ok;
5968
5969 }
5970 #endif // #ifndef __WIN32__
5971
5972
5973
5974 /* ----------------------------------------------------------------------
5975 * nif_accept
5976 *
5977 * Description:
5978 * Accept a connection on a socket.
5979 *
5980 * Arguments:
5981 * Socket (ref) - Points to the socket descriptor.
5982 * Request ref - Unique "id" of this request
5983 * (used for the select, if none is in queue).
5984 */
5985 static
nif_accept(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])5986 ERL_NIF_TERM nif_accept(ErlNifEnv* env,
5987 int argc,
5988 const ERL_NIF_TERM argv[])
5989 {
5990 #ifdef __WIN32__
5991 return enif_raise_exception(env, MKA(env, "notsup"));
5992 #else
5993
5994 ESockDescriptor* descP;
5995 ERL_NIF_TERM sockRef, ref, res;
5996
5997 ESOCK_ASSERT( argc == 2 );
5998
5999 SGDBG( ("SOCKET", "nif_accept -> entry with argc: %d\r\n", argc) );
6000
6001 /* Extract arguments and perform preliminary validation */
6002
6003 sockRef = argv[0];
6004 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
6005 return enif_make_badarg(env);
6006 }
6007 ref = argv[1];
6008
6009 MLOCK(descP->readMtx);
6010
6011 SSDBG( descP,
6012 ("SOCKET", "nif_accept%T), {%d,0x%X} ->"
6013 "\r\n ReqRef: %T"
6014 "\r\n Current Acceptor addr: %p"
6015 "\r\n Current Acceptor pid: %T"
6016 "\r\n Current Acceptor mon: %T"
6017 "\r\n Current Acceptor env: 0x%lX"
6018 "\r\n Current Acceptor ref: %T"
6019 "\r\n",
6020 sockRef, descP->sock, descP->readState,
6021 ref,
6022 descP->currentAcceptorP,
6023 descP->currentAcceptor.pid,
6024 esock_make_monitor_term(env, &descP->currentAcceptor.mon),
6025 descP->currentAcceptor.env,
6026 descP->currentAcceptor.ref) );
6027
6028 res = esock_accept(env, descP, sockRef, ref);
6029
6030 SSDBG( descP, ("SOCKET", "nif_accept(%T) -> done with"
6031 "\r\n res: %T"
6032 "\r\n", sockRef, res) );
6033
6034 MUNLOCK(descP->readMtx);
6035
6036 return res;
6037
6038 #endif // #ifdef __WIN32__ #else
6039 }
6040
6041
6042 #ifndef __WIN32__
6043 static
esock_accept(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM accRef)6044 ERL_NIF_TERM esock_accept(ErlNifEnv* env,
6045 ESockDescriptor* descP,
6046 ERL_NIF_TERM sockRef,
6047 ERL_NIF_TERM accRef)
6048 {
6049 ErlNifPid caller;
6050
6051 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
6052
6053 if (! IS_OPEN(descP->readState))
6054 return esock_make_error(env, atom_closed);
6055
6056 /* Accept and Read uses the same select flag
6057 * so they can not be simultaneous
6058 */
6059 if (descP->currentReaderP != NULL)
6060 return esock_make_error_invalid(env, atom_state);
6061
6062 if (descP->currentAcceptorP == NULL) {
6063 SOCKET accSock;
6064
6065 /* We have no active acceptor (and therefore no acceptors in queue)
6066 */
6067
6068 SSDBG( descP, ("SOCKET", "esock_accept {%d} -> try accept\r\n",
6069 descP->sock) );
6070
6071 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1);
6072
6073 accSock = sock_accept(descP->sock, NULL, NULL);
6074
6075 if (ESOCK_IS_ERROR(accSock)) {
6076 int save_errno;
6077
6078 save_errno = sock_errno();
6079
6080 return esock_accept_listening_error(env, descP, sockRef,
6081 accRef, caller, save_errno);
6082 } else {
6083 /* We got an incoming connection */
6084 return
6085 esock_accept_listening_accept(env, descP, sockRef,
6086 accSock, caller);
6087 }
6088 } else {
6089
6090 /* We have an active acceptor and possibly acceptors waiting in queue.
6091 * If the pid of the calling process is not the pid of the
6092 * "current process", push the requester onto the (acceptor) queue.
6093 */
6094
6095 SSDBG( descP, ("SOCKET", "esock_accept_accepting -> check: "
6096 "is caller current acceptor:"
6097 "\r\n Caller: %T"
6098 "\r\n Current: %T"
6099 "\r\n", caller, descP->currentAcceptor.pid) );
6100
6101 if (COMPARE_PIDS(&descP->currentAcceptor.pid, &caller) == 0) {
6102
6103 SSDBG( descP,
6104 ("SOCKET",
6105 "esock_accept_accepting {%d} -> current acceptor\r\n",
6106 descP->sock) );
6107
6108 return esock_accept_accepting_current(env, descP, sockRef, accRef);
6109
6110 } else {
6111
6112 /* Not the "current acceptor", so (maybe) push onto queue */
6113
6114 SSDBG( descP,
6115 ("SOCKET",
6116 "esock_accept_accepting {%d} -> *not* current acceptor\r\n",
6117 descP->sock) );
6118
6119 return esock_accept_accepting_other(env, descP, accRef, caller);
6120 }
6121 }
6122 }
6123 #endif // #ifndef __WIN32__
6124
6125 /* *** esock_accept_listening_error ***
6126 *
6127 * The accept call resultet in an error - handle it.
6128 * There are only two cases:
6129 * 1) BLOCK => Attempt a "retry"
6130 * 2) Other => Return the value (converted to an atom)
6131 */
6132 #ifndef __WIN32__
6133 static
esock_accept_listening_error(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM accRef,ErlNifPid caller,int save_errno)6134 ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
6135 ESockDescriptor* descP,
6136 ERL_NIF_TERM sockRef,
6137 ERL_NIF_TERM accRef,
6138 ErlNifPid caller,
6139 int save_errno)
6140 {
6141 ERL_NIF_TERM res;
6142
6143 if (save_errno == ERRNO_BLOCK ||
6144 save_errno == EAGAIN) {
6145
6146 /* *** Try again later *** */
6147
6148 SSDBG( descP,
6149 ("SOCKET",
6150 "esock_accept_listening_error {%d} -> would block\r\n",
6151 descP->sock) );
6152
6153 descP->currentAcceptor.pid = caller;
6154 ESOCK_ASSERT( MONP("esock_accept_listening -> current acceptor",
6155 env, descP,
6156 &descP->currentAcceptor.pid,
6157 &descP->currentAcceptor.mon) == 0 );
6158 ESOCK_ASSERT( descP->currentAcceptor.env == NULL );
6159 descP->currentAcceptor.env = esock_alloc_env("current acceptor");
6160 descP->currentAcceptor.ref =
6161 CP_TERM(descP->currentAcceptor.env, accRef);
6162 descP->currentAcceptorP = &descP->currentAcceptor;
6163 res = esock_accept_busy_retry(env, descP, sockRef, accRef, NULL);
6164 } else {
6165 SSDBG( descP,
6166 ("SOCKET",
6167 "esock_accept_listening {%d} -> errno: %d\r\n",
6168 descP->sock, save_errno) );
6169
6170 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1);
6171
6172 res = esock_make_error_errno(env, save_errno);
6173 }
6174
6175 return res;
6176 }
6177 #endif // #ifndef __WIN32__
6178
6179
6180 /* *** esock_accept_listening_accept ***
6181 *
6182 * The accept call was successful (accepted) - handle the new connection.
6183 */
6184 #ifndef __WIN32__
6185 static
esock_accept_listening_accept(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,SOCKET accSock,ErlNifPid caller)6186 ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
6187 ESockDescriptor* descP,
6188 ERL_NIF_TERM sockRef,
6189 SOCKET accSock,
6190 ErlNifPid caller)
6191 {
6192 ERL_NIF_TERM res;
6193
6194 esock_accept_accepted(env, descP, sockRef, accSock, caller, &res);
6195
6196 return res;
6197 }
6198 #endif // #ifndef __WIN32__
6199
6200
6201 /* *** esock_accept_accepting_current ***
6202 * Handles when the current acceptor makes another attempt.
6203 */
6204 #ifndef __WIN32__
6205 static
esock_accept_accepting_current(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM accRef)6206 ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env,
6207 ESockDescriptor* descP,
6208 ERL_NIF_TERM sockRef,
6209 ERL_NIF_TERM accRef)
6210 {
6211 SOCKET accSock;
6212 int save_errno;
6213 ERL_NIF_TERM res;
6214
6215 SSDBG( descP,
6216 ("SOCKET",
6217 "esock_accept_accepting_current {%d} -> try accept\r\n",
6218 descP->sock) );
6219
6220 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1);
6221
6222 accSock = sock_accept(descP->sock, NULL, NULL);
6223
6224 if (ESOCK_IS_ERROR(accSock)) {
6225
6226 save_errno = sock_errno();
6227
6228 res = esock_accept_accepting_current_error(env, descP, sockRef,
6229 accRef, save_errno);
6230 } else {
6231
6232 res = esock_accept_accepting_current_accept(env, descP, sockRef,
6233 accSock);
6234 }
6235
6236 return res;
6237 }
6238 #endif // #ifndef __WIN32__
6239
6240
6241 /* *** esock_accept_accepting_current_accept ***
6242 * Handles when the current acceptor succeeded in its accept call -
6243 * handle the new connection.
6244 */
6245 #ifndef __WIN32__
6246 static
esock_accept_accepting_current_accept(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,SOCKET accSock)6247 ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env,
6248 ESockDescriptor* descP,
6249 ERL_NIF_TERM sockRef,
6250 SOCKET accSock)
6251 {
6252 ERL_NIF_TERM res;
6253
6254 SSDBG( descP,
6255 ("SOCKET",
6256 "esock_accept_accepting_current_accept {%d}"
6257 "\r\n", descP->sock) );
6258
6259 if (esock_accept_accepted(env, descP, sockRef, accSock,
6260 descP->currentAcceptor.pid, &res)) {
6261
6262 if (!activate_next_acceptor(env, descP, sockRef)) {
6263
6264 SSDBG( descP,
6265 ("SOCKET",
6266 "esock_accept_accepting_current_accept {%d} ->"
6267 " no more acceptors"
6268 "\r\n", descP->sock) );
6269
6270 descP->readState &= ~ESOCK_STATE_ACCEPTING;
6271
6272 descP->currentAcceptorP = NULL;
6273 }
6274
6275 }
6276
6277 return res;
6278 }
6279 #endif // #ifndef __WIN32__
6280
6281
6282 /* *** esock_accept_accepting_current_error ***
6283 * The accept call of current acceptor resultet in an error - handle it.
6284 * There are only two cases:
6285 * 1) BLOCK => Attempt a "retry"
6286 * 2) Other => Return the value (converted to an atom)
6287 */
6288 #ifndef __WIN32__
6289 static
esock_accept_accepting_current_error(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef,int save_errno)6290 ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
6291 ESockDescriptor* descP,
6292 ERL_NIF_TERM sockRef,
6293 ERL_NIF_TERM opRef,
6294 int save_errno)
6295 {
6296 ERL_NIF_TERM res, reason;
6297
6298 if (save_errno == ERRNO_BLOCK ||
6299 save_errno == EAGAIN) {
6300
6301 /*
6302 * Just try again, no real error, just a ghost trigger from poll,
6303 */
6304
6305 SSDBG( descP,
6306 ("SOCKET",
6307 "esock_accept_accepting_current_error {%d} -> "
6308 "would block: try again\r\n", descP->sock) );
6309
6310 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_waits, &descP->accWaits, 1);
6311
6312 res = esock_accept_busy_retry(env, descP, sockRef, opRef,
6313 &descP->currentAcceptor.pid);
6314
6315 } else {
6316 ESockRequestor req;
6317
6318 SSDBG( descP,
6319 ("SOCKET",
6320 "esock_accept_accepting_current_error {%d} -> "
6321 "error: %d\r\n", descP->sock, save_errno) );
6322
6323 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1);
6324
6325 requestor_release("esock_accept_accepting_current_error",
6326 env, descP, &descP->currentAcceptor);
6327
6328 reason = MKA(env, erl_errno_id(save_errno));
6329 res = esock_make_error(env, reason);
6330
6331 req.env = NULL;
6332 while (acceptor_pop(env, descP, &req)) {
6333 SSDBG( descP,
6334 ("SOCKET",
6335 "esock_accept_accepting_current_error {%d} -> abort %T\r\n",
6336 descP->sock, req.pid) );
6337
6338 esock_send_abort_msg(env, descP, sockRef, &req, reason);
6339
6340 (void) DEMONP("esock_accept_accepting_current_error -> "
6341 "pop'ed writer",
6342 env, descP, &req.mon);
6343 }
6344 descP->currentAcceptorP = NULL;
6345 }
6346
6347 return res;
6348 }
6349 #endif // #ifndef __WIN32__
6350
6351
6352 /* *** esock_accept_accepting_other ***
6353 * Handles when the another acceptor makes an attempt, which
6354 * results (maybe) in the request beeing pushed onto the
6355 * acceptor queue.
6356 */
6357 #ifndef __WIN32__
6358 ERL_NIF_TERM
esock_accept_accepting_other(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM ref,ErlNifPid caller)6359 esock_accept_accepting_other(ErlNifEnv* env,
6360 ESockDescriptor* descP,
6361 ERL_NIF_TERM ref,
6362 ErlNifPid caller)
6363 {
6364 if (! acceptor_search4pid(env, descP, &caller)) {
6365 acceptor_push(env, descP, caller, ref);
6366 return atom_select;
6367 } else {
6368 /* Acceptor already in queue */
6369 return esock_raise_invalid(env, atom_state);
6370 }
6371 }
6372 #endif // #ifndef __WIN32__
6373
6374
6375 /* *** esock_accept_busy_retry ***
6376 *
6377 * Perform a retry select. If successful, set nextState.
6378 */
6379 #ifndef __WIN32__
6380 static
esock_accept_busy_retry(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM accRef,ErlNifPid * pidP)6381 ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
6382 ESockDescriptor* descP,
6383 ERL_NIF_TERM sockRef,
6384 ERL_NIF_TERM accRef,
6385 ErlNifPid* pidP)
6386 {
6387 int sres;
6388 ERL_NIF_TERM res;
6389
6390 if ((sres = esock_select_read(env, descP->sock, descP, pidP,
6391 sockRef, accRef)) < 0) {
6392
6393 ESOCK_ASSERT( DEMONP("esock_accept_busy_retry - select failed",
6394 env, descP, &descP->currentAcceptor.mon) == 0);
6395 /* It is very unlikely that a next acceptor will be able
6396 * to do anything succesful, but we will clean the queue
6397 */
6398 if (!activate_next_acceptor(env, descP, sockRef)) {
6399 SSDBG( descP,
6400 ("SOCKET",
6401 "esock_accept_busy_retry {%d} -> no more acceptors\r\n",
6402 descP->sock) );
6403
6404 descP->readState &= ~ESOCK_STATE_ACCEPTING;
6405
6406 descP->currentAcceptorP = NULL;
6407 }
6408
6409 res =
6410 enif_raise_exception(env,
6411 MKT2(env, atom_select_read,
6412 MKI(env, sres)));
6413 } else {
6414 descP->readState |=
6415 (ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED);
6416 res = atom_select;
6417 }
6418
6419 return res;
6420 }
6421 #endif // #ifndef __WIN32__
6422
6423
6424 /* *** esock_accept_accepted ***
6425 *
6426 * Generic function handling a successful accept.
6427 */
6428 #ifndef __WIN32__
6429 static
esock_accept_accepted(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,SOCKET accSock,ErlNifPid pid,ERL_NIF_TERM * result)6430 BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
6431 ESockDescriptor* descP,
6432 ERL_NIF_TERM sockRef,
6433 SOCKET accSock,
6434 ErlNifPid pid,
6435 ERL_NIF_TERM* result)
6436 {
6437 ESockDescriptor* accDescP;
6438 ErlNifEvent accEvent;
6439 ERL_NIF_TERM accRef;
6440 int save_errno;
6441
6442 /*
6443 * We got one
6444 */
6445
6446 ESOCK_CNT_INC(env, descP, sockRef, atom_acc_success, &descP->accSuccess, 1);
6447
6448 if ((accEvent = sock_create_event(accSock)) == INVALID_EVENT) {
6449 save_errno = sock_errno();
6450 (void) sock_close(accSock);
6451 *result = esock_make_error_errno(env, save_errno);
6452 return FALSE;
6453 }
6454
6455 accDescP = alloc_descriptor(accSock, accEvent);
6456 accDescP->domain = descP->domain;
6457 accDescP->type = descP->type;
6458 accDescP->protocol = descP->protocol;
6459
6460 MLOCK(descP->writeMtx);
6461
6462 accDescP->rBufSz = descP->rBufSz; // Inherit buffer size
6463 accDescP->rNum = descP->rNum; // Inherit buffer uses
6464 accDescP->rNumCnt = 0;
6465 accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size
6466 accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size
6467 accDescP->iow = descP->iow; // Inherit iow
6468 accDescP->dbg = descP->dbg; // Inherit debug flag
6469 accDescP->useReg = descP->useReg; // Inherit useReg flag
6470 inc_socket(accDescP->domain, accDescP->type, accDescP->protocol);
6471
6472 accRef = enif_make_resource(env, accDescP);
6473 enif_release_resource(accDescP);
6474
6475 accDescP->ctrlPid = pid;
6476 /* pid has actually been compared equal to self()
6477 * in this code path just a little while ago
6478 */
6479 ESOCK_ASSERT( MONP("esock_accept_accepted -> ctrl",
6480 env, accDescP,
6481 &accDescP->ctrlPid,
6482 &accDescP->ctrlMon) == 0 );
6483
6484 SET_NONBLOCKING(accDescP->sock);
6485
6486 descP->writeState |= ESOCK_STATE_CONNECTED;
6487
6488 MUNLOCK(descP->writeMtx);
6489
6490 /* And finally (maybe) update the registry */
6491 if (descP->useReg) esock_send_reg_add_msg(env, descP, accRef);
6492
6493 *result = esock_make_ok2(env, accRef);
6494
6495 return TRUE;
6496 }
6497 #endif // #ifndef __WIN32__
6498
6499
6500
6501 /* ----------------------------------------------------------------------
6502 * nif_send
6503 *
6504 * Description:
6505 * Send a message on a socket
6506 *
6507 * Arguments:
6508 * Socket (ref) - Points to the socket descriptor.
6509 * Bin - The data to send as a binary()
6510 * Flags - Send flags as an integer()
6511 * SendRef - A unique id reference() for this (send) request.
6512 */
6513
6514 static
nif_send(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])6515 ERL_NIF_TERM nif_send(ErlNifEnv* env,
6516 int argc,
6517 const ERL_NIF_TERM argv[])
6518 {
6519 #ifdef __WIN32__
6520 return enif_raise_exception(env, MKA(env, "notsup"));
6521 #else
6522 ESockDescriptor* descP;
6523 ERL_NIF_TERM sockRef, sendRef;
6524 ErlNifBinary sndData;
6525 int flags;
6526 ERL_NIF_TERM res;
6527
6528 ESOCK_ASSERT( argc == 4 );
6529
6530 SGDBG( ("SOCKET", "nif_send -> entry with argc: %d\r\n", argc) );
6531
6532 sockRef = argv[0]; // We need this in case we send in case we send abort
6533 sendRef = argv[3];
6534
6535 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
6536 SGDBG( ("SOCKET", "nif_send -> get resource failed\r\n") );
6537 return enif_make_badarg(env);
6538 }
6539
6540 /* Extract arguments and perform preliminary validation */
6541
6542 if ((! enif_is_ref(env, sendRef)) ||
6543 (! GET_BIN(env, argv[1], &sndData))) {
6544 SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") );
6545 return enif_make_badarg(env);
6546 }
6547 if (! GET_INT(env, argv[2], &flags)) {
6548 SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") );
6549 if (IS_INTEGER(env, argv[2]))
6550 return esock_make_error_integer_range(env, argv[2]);
6551 else
6552 return enif_make_badarg(env);
6553 }
6554 MLOCK(descP->writeMtx);
6555
6556 SSDBG( descP,
6557 ("SOCKET", "nif_send(%T), {%d,0x%X} ->"
6558 "\r\n SendRef: %T"
6559 "\r\n Data size: %u"
6560 "\r\n flags: 0x%X"
6561 "\r\n",
6562 sockRef, descP->sock, descP->writeState,
6563 sendRef, sndData.size, flags) );
6564
6565 /* We need to handle the case when another process tries
6566 * to write at the same time.
6567 * If the current write could not write its entire package
6568 * this time (resulting in an select). The write of the
6569 * other process must be made to wait until current
6570 * is done!
6571 */
6572
6573 res = esock_send(env, descP, sockRef, sendRef, &sndData, flags);
6574
6575 SSDBG( descP, ("SOCKET", "nif_send(%T) -> done with"
6576 "\r\n res: %T"
6577 "\r\n", sockRef, res) );
6578
6579 MUNLOCK(descP->writeMtx);
6580
6581 SGDBG( ("SOCKET", "nif_send -> done with result: "
6582 "\r\n %T"
6583 "\r\n", res) );
6584 return res;
6585
6586 #endif // #ifdef __WIN32__ #else
6587 }
6588
6589
6590
6591 /* *** esock_send ***
6592 *
6593 * Do the actual send.
6594 * Do some initial writer checks, do the actual send and then
6595 * analyze the result. If we are done, another writer may be
6596 * scheduled (if there is one in the writer queue).
6597 */
6598 #ifndef __WIN32__
6599 static
esock_send(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM sendRef,ErlNifBinary * sndDataP,int flags)6600 ERL_NIF_TERM esock_send(ErlNifEnv* env,
6601 ESockDescriptor* descP,
6602 ERL_NIF_TERM sockRef,
6603 ERL_NIF_TERM sendRef,
6604 ErlNifBinary* sndDataP,
6605 int flags)
6606 {
6607 ssize_t send_result;
6608 ERL_NIF_TERM writerCheck;
6609
6610 if (! IS_OPEN(descP->writeState))
6611 return esock_make_error(env, atom_closed);
6612
6613 /* Connect and Write uses the same select flag
6614 * so they can not be simultaneous
6615 */
6616 if (descP->connectorP != NULL)
6617 return esock_make_error_invalid(env, atom_state);
6618
6619 send_result = (ssize_t) sndDataP->size;
6620 if ((size_t) send_result != sndDataP->size)
6621 return esock_make_error_invalid(env, atom_data_size);
6622
6623 /* Ensure that we either have no current writer or we are it,
6624 * or enqueue this process if there is a current writer */
6625 if (! send_check_writer(env, descP, sendRef, &writerCheck)) {
6626 SSDBG( descP, ("SOCKET", "esock_send {%d} -> writer check failed: "
6627 "\r\n %T\r\n", descP->sock, writerCheck) );
6628 return writerCheck;
6629 }
6630
6631 ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
6632
6633 send_result =
6634 sock_send(descP->sock, sndDataP->data, sndDataP->size, flags);
6635
6636 return send_check_result(env, descP,
6637 send_result, sndDataP->size, FALSE,
6638 sockRef, sendRef);
6639
6640 }
6641 #endif // #ifndef __WIN32__
6642
6643
6644
6645 /* ----------------------------------------------------------------------
6646 * nif_sendto
6647 *
6648 * Description:
6649 * Send a message on a socket
6650 *
6651 * Arguments:
6652 * Socket (ref) - Points to the socket descriptor.
6653 * Bin - The data to send as a binary()
6654 * Dest - Destination (socket) address.
6655 * Flags - Send flags as an integer().
6656 * SendRef - A unique id reference() for this (send) request.
6657 */
6658
6659 static
nif_sendto(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])6660 ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
6661 int argc,
6662 const ERL_NIF_TERM argv[])
6663 {
6664 #ifdef __WIN32__
6665 return enif_raise_exception(env, MKA(env, "notsup"));
6666 #else
6667 ESockDescriptor* descP;
6668 ERL_NIF_TERM sockRef, sendRef;
6669 ErlNifBinary sndData;
6670 int flags;
6671 ERL_NIF_TERM eSockAddr;
6672 ESockAddress remoteAddr;
6673 SOCKLEN_T remoteAddrLen;
6674 ERL_NIF_TERM res;
6675
6676 ESOCK_ASSERT( argc == 5 );
6677
6678 SGDBG( ("SOCKET", "nif_sendto -> entry with argc: %d\r\n", argc) );
6679
6680 sockRef = argv[0]; // We need this in case we send abort (to the caller)
6681 sendRef = argv[4];
6682
6683 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
6684 SGDBG( ("SOCKET", "nif_sendto -> get resource failed\r\n") );
6685 return enif_make_badarg(env);
6686 }
6687
6688 /* Extract arguments and perform preliminary validation */
6689
6690 if ((! enif_is_ref(env, sendRef)) ||
6691 (! GET_BIN(env, argv[1], &sndData))) {
6692 SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") );
6693 return enif_make_badarg(env);
6694 }
6695 if (! GET_INT(env, argv[3], &flags)) {
6696 SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") );
6697 if (IS_INTEGER(env, argv[3]))
6698 return esock_make_error_integer_range(env, argv[3]);
6699 else
6700 return enif_make_badarg(env);
6701 }
6702 eSockAddr = argv[2];
6703 if (! esock_decode_sockaddr(env, eSockAddr,
6704 &remoteAddr,
6705 &remoteAddrLen)) {
6706 SSDBG( descP,
6707 ("SOCKET",
6708 "nif_sendto(%T), {%d} -> sockaddr decode failed \r\n",
6709 sockRef, descP->sock) );
6710
6711 return esock_make_invalid(env, atom_sockaddr);
6712 }
6713
6714 MLOCK(descP->writeMtx);
6715
6716 SSDBG( descP,
6717 ("SOCKET", "nif_sendto(%T), {%d,0x%X} ->"
6718 "\r\n sendRef: %T"
6719 "\r\n Data size: %u"
6720 "\r\n eSockAddr: %T"
6721 "\r\n flags: 0x%X"
6722 "\r\n",
6723 sockRef, descP->sock, descP->readState,
6724 sendRef, sndData.size, eSockAddr, flags) );
6725
6726 res = esock_sendto(env, descP, sockRef, sendRef, &sndData, flags,
6727 &remoteAddr, remoteAddrLen);
6728
6729 SSDBG( descP, ("SOCKET", "nif_sendto(%T) -> done with"
6730 "\r\n res: %T"
6731 "\r\n", sockRef, res) );
6732
6733 MUNLOCK(descP->writeMtx);
6734
6735 return res;
6736
6737 #endif // if defined(__WIN32__)
6738 }
6739
6740
6741 #ifndef __WIN32__
6742 static
esock_sendto(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM sendRef,ErlNifBinary * dataP,int flags,ESockAddress * toAddrP,SOCKLEN_T toAddrLen)6743 ERL_NIF_TERM esock_sendto(ErlNifEnv* env,
6744 ESockDescriptor* descP,
6745 ERL_NIF_TERM sockRef,
6746 ERL_NIF_TERM sendRef,
6747 ErlNifBinary* dataP,
6748 int flags,
6749 ESockAddress* toAddrP,
6750 SOCKLEN_T toAddrLen)
6751 {
6752 ssize_t sendto_result;
6753 ERL_NIF_TERM writerCheck;
6754
6755 if (! IS_OPEN(descP->writeState))
6756 return esock_make_error(env, atom_closed);
6757
6758 /* Connect and Write uses the same select flag
6759 * so they can not be simultaneous
6760 */
6761 if (descP->connectorP != NULL)
6762 return esock_make_error_invalid(env, atom_state);
6763
6764 sendto_result = (ssize_t) dataP->size;
6765 if ((size_t) sendto_result != dataP->size)
6766 return esock_make_error_invalid(env, atom_data_size);
6767
6768 /* Ensure that we either have no current writer or we are it,
6769 * or enqueue this process if there is a current writer */
6770 if (! send_check_writer(env, descP, sendRef, &writerCheck)) {
6771 SSDBG( descP, ("SOCKET", "esock_sendto {%d} -> writer check failed: "
6772 "\r\n %T\r\n", descP->sock, writerCheck) );
6773 return writerCheck;
6774 }
6775
6776 ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
6777
6778 if (toAddrP != NULL) {
6779 sendto_result =
6780 sock_sendto(descP->sock,
6781 dataP->data, dataP->size, flags,
6782 &toAddrP->sa, toAddrLen);
6783 } else {
6784 sendto_result =
6785 sock_sendto(descP->sock,
6786 dataP->data, dataP->size, flags,
6787 NULL, 0);
6788 }
6789
6790 return send_check_result(env, descP, sendto_result, dataP->size, FALSE,
6791 sockRef, sendRef);
6792 }
6793 #endif // #ifndef __WIN32__
6794
6795
6796
6797 /* ----------------------------------------------------------------------
6798 * nif_sendmsg
6799 *
6800 * Description:
6801 * Send a message on a socket
6802 *
6803 * Arguments:
6804 * Socket (ref) - Points to the socket descriptor.
6805 * Msg - Message - map() with data and (maybe) control and dest
6806 * Flags - Send flags as an integer().
6807 * SendRef - A unique id reference() for this (send) request.
6808 */
6809
6810 static
nif_sendmsg(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])6811 ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
6812 int argc,
6813 const ERL_NIF_TERM argv[])
6814 {
6815 #ifdef __WIN32__
6816 return enif_raise_exception(env, MKA(env, "notsup"));
6817 #else
6818 ERL_NIF_TERM res, sockRef, sendRef, eMsg, eIOV;
6819 ESockDescriptor* descP;
6820 int flags;
6821
6822 ESOCK_ASSERT( argc == 5 );
6823
6824 SGDBG( ("SOCKET", "nif_sendmsg -> entry with argc: %d\r\n", argc) );
6825
6826 sockRef = argv[0]; // We need this in case we send abort (to the caller)
6827 eMsg = argv[1];
6828 sendRef = argv[3];
6829 eIOV = argv[4];
6830
6831 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
6832 SGDBG( ("SOCKET", "nif_sendmsg -> get resource failed\r\n") );
6833 return enif_make_badarg(env);
6834 }
6835
6836 /* Extract arguments and perform preliminary validation */
6837
6838 if ((! enif_is_ref(env, sendRef)) ||
6839 (! IS_MAP(env, eMsg))) {
6840 SSDBG( descP, ("SOCKET", "nif_sendmsg -> argv decode failed\r\n") );
6841 return enif_make_badarg(env);
6842 }
6843 if (! GET_INT(env, argv[2], &flags)) {
6844 if (IS_INTEGER(env, argv[2]))
6845 return esock_make_error_integer_range(env, argv[2]);
6846 else
6847 return enif_make_badarg(env);
6848 }
6849
6850 MLOCK(descP->writeMtx);
6851
6852 SSDBG( descP,
6853 ("SOCKET", "nif_sendmsg(%T), {%d,0x%X} ->"
6854 "\r\n SendRef: %T"
6855 "\r\n flags: 0x%X"
6856 "\r\n",
6857 sockRef, descP->sock, descP->writeState,
6858 sendRef, flags) );
6859
6860 res = esock_sendmsg(env, descP, sockRef, sendRef, eMsg, flags, eIOV);
6861
6862 MUNLOCK(descP->writeMtx);
6863
6864 SSDBG( descP, ("SOCKET", "nif_sendmsg(%T) -> done with"
6865 "\r\n res: %T"
6866 "\r\n", sockRef, res) );
6867
6868 return res;
6869
6870 #endif // #ifdef __WIN32__ #else
6871 }
6872
6873
6874 #ifndef __WIN32__
6875 static
esock_sendmsg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM sendRef,ERL_NIF_TERM eMsg,int flags,ERL_NIF_TERM eIOV)6876 ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
6877 ESockDescriptor* descP,
6878 ERL_NIF_TERM sockRef,
6879 ERL_NIF_TERM sendRef,
6880 ERL_NIF_TERM eMsg,
6881 int flags,
6882 ERL_NIF_TERM eIOV)
6883 {
6884 ERL_NIF_TERM res, eAddr, eCtrl;
6885 ESockAddress addr;
6886 struct msghdr msgHdr;
6887 ErlNifIOVec *iovec = NULL;
6888 char* ctrlBuf;
6889 size_t ctrlBufLen, ctrlBufUsed;
6890 ssize_t dataSize, sendmsg_result;
6891 ERL_NIF_TERM writerCheck, tail;
6892
6893 if (! IS_OPEN(descP->writeState))
6894 return esock_make_error(env, atom_closed);
6895
6896 /* Connect and Write uses the same select flag
6897 * so they can not be simultaneous
6898 */
6899 if (descP->connectorP != NULL)
6900 return esock_make_error_invalid(env, atom_state);
6901
6902 /* Ensure that we either have no current writer or we are it,
6903 * or enqueue this process if there is a current writer */
6904 if (! send_check_writer(env, descP, sendRef, &writerCheck)) {
6905 SSDBG( descP,
6906 ("SOCKET", "esock_sendmsg {%d} -> writer check failed: "
6907 "\r\n %T\r\n", descP->sock, writerCheck) );
6908 return writerCheck;
6909 }
6910
6911 /* Initiate the .name and .namelen fields depending on if
6912 * we have an address or not
6913 */
6914 if (! GET_MAP_VAL(env, eMsg, esock_atom_addr, &eAddr)) {
6915
6916 SSDBG( descP, ("SOCKET",
6917 "esock_sendmsg {%d} -> no address\r\n", descP->sock) );
6918
6919 msgHdr.msg_name = NULL;
6920 msgHdr.msg_namelen = 0;
6921 } else {
6922 msgHdr.msg_name = (void*) &addr;
6923 msgHdr.msg_namelen = sizeof(addr);
6924 sys_memzero((char *) msgHdr.msg_name, msgHdr.msg_namelen);
6925
6926 SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->"
6927 "\r\n address: %T"
6928 "\r\n", descP->sock, eAddr) );
6929
6930 if (! esock_decode_sockaddr(env, eAddr,
6931 msgHdr.msg_name,
6932 &msgHdr.msg_namelen)) {
6933 SSDBG( descP, ("SOCKET",
6934 "esock_sendmsg {%d} -> invalid address\r\n",
6935 descP->sock) );
6936 return esock_make_invalid(env, esock_atom_addr);
6937 }
6938 }
6939
6940 /* Extract the *mandatory* 'iov', which must be an erlang:iovec(),
6941 * from which we take at most IOV_MAX binaries
6942 */
6943 if ((! enif_inspect_iovec(NULL, data.iov_max, eIOV, &tail, &iovec))) {
6944 SSDBG( descP, ("SOCKET",
6945 "esock_sendmsg {%d} -> not an iov\r\n",
6946 descP->sock) );
6947
6948 return esock_make_invalid(env, esock_atom_iov);
6949 }
6950
6951 SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->"
6952 "\r\n iovcnt: %lu"
6953 "\r\n tail: %s"
6954 "\r\n", descP->sock,
6955 (unsigned long) iovec->iovcnt,
6956 B2S(! enif_is_empty_list(env, tail))) );
6957
6958 /* We now have an allocated iovec */
6959
6960 eCtrl = esock_atom_undefined;
6961 ctrlBufLen = 0;
6962 ctrlBuf = NULL;
6963
6964 if (iovec->iovcnt > data.iov_max) {
6965 if (descP->type == SOCK_STREAM) {
6966 iovec->iovcnt = data.iov_max;
6967 } else {
6968 /* We can not send the whole packet in one sendmsg() call */
6969 SSDBG( descP, ("SOCKET",
6970 "esock_sendmsg {%d} -> iovcnt > iov_max\r\n",
6971 descP->sock) );
6972 res = esock_make_invalid(env, esock_atom_iov);
6973 goto done_free_iovec;
6974 }
6975 }
6976
6977 dataSize = 0;
6978 {
6979 ERL_NIF_TERM h, t;
6980 ErlNifBinary bin;
6981 size_t i;
6982
6983 /* Find out if there is remaining data in the tail.
6984 * Skip empty binaries otherwise break.
6985 * If 'tail' after loop exit is the empty list
6986 * there was no more data. Otherwise there is more
6987 * data or the 'iov' is invalid.
6988 */
6989 for (;;) {
6990 if (enif_get_list_cell(env, tail, &h, &t) &&
6991 enif_inspect_binary(env, h, &bin) &&
6992 (bin.size == 0)) {
6993 tail = t;
6994 continue;
6995 } else
6996 break;
6997 }
6998
6999 if ((! enif_is_empty_list(env, tail)) &&
7000 (descP->type != SOCK_STREAM)) {
7001 /* We can not send the whole packet in one sendmsg() call */
7002 SSDBG( descP, ("SOCKET",
7003 "esock_sendmsg {%d} -> invalid tail\r\n",
7004 descP->sock) );
7005 res = esock_make_invalid(env, esock_atom_iov);
7006 goto done_free_iovec;
7007 }
7008
7009 /* Calculate the data size */
7010
7011 for (i = 0; i < iovec->iovcnt; i++) {
7012 size_t len = iovec->iov[i].iov_len;
7013 dataSize += len;
7014 if (dataSize < len) {
7015 /* Overflow */
7016 SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> Overflow"
7017 "\r\n i: %lu"
7018 "\r\n len: %lu"
7019 "\r\n dataSize: %ld"
7020 "\r\n", descP->sock, (unsigned long) i,
7021 (unsigned long) len, (long) dataSize) );
7022 res = esock_make_invalid(env, esock_atom_iov);
7023 goto done_free_iovec;
7024 }
7025 }
7026 }
7027 SSDBG( descP,
7028 ("SOCKET",
7029 "esock_sendmsg {%d} ->"
7030 "\r\n iov length: %lu"
7031 "\r\n data size: %u"
7032 "\r\n",
7033 descP->sock,
7034 (unsigned long) iovec->iovcnt, (long) dataSize) );
7035
7036 msgHdr.msg_iovlen = iovec->iovcnt;
7037 msgHdr.msg_iov = iovec->iov;
7038
7039 /* Extract the *optional* 'ctrl' */
7040 if (GET_MAP_VAL(env, eMsg, esock_atom_ctrl, &eCtrl)) {
7041 ctrlBufLen = descP->wCtrlSz;
7042 ctrlBuf = (char*) MALLOC(ctrlBufLen);
7043 ESOCK_ASSERT( ctrlBuf != NULL );
7044 }
7045 SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> optional ctrl: "
7046 "\r\n ctrlBuf: %p"
7047 "\r\n ctrlBufLen: %lu"
7048 "\r\n eCtrl: %T"
7049 "\r\n", descP->sock,
7050 ctrlBuf, (unsigned long) ctrlBufLen, eCtrl) );
7051
7052 /* Decode the ctrl and initiate that part of the msghdr.
7053 */
7054 if (ctrlBuf != NULL) {
7055 if (! decode_cmsghdrs(env, descP,
7056 eCtrl,
7057 ctrlBuf, ctrlBufLen, &ctrlBufUsed)) {
7058 SSDBG( descP, ("SOCKET",
7059 "esock_sendmsg {%d} -> invalid ctrl\r\n",
7060 descP->sock) );
7061 res = esock_make_invalid(env, esock_atom_ctrl);
7062 goto done_free_iovec;
7063 }
7064 } else {
7065 ctrlBufUsed = 0;
7066 }
7067 msgHdr.msg_control = ctrlBuf;
7068 msgHdr.msg_controllen = ctrlBufUsed;
7069
7070 /* The msg_flags field is not used when sending,
7071 * but zero it just in case */
7072 msgHdr.msg_flags = 0;
7073
7074 ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
7075
7076 /* And now, try to send the message */
7077 sendmsg_result = sock_sendmsg(descP->sock, &msgHdr, flags);
7078
7079 res = send_check_result(env, descP, sendmsg_result, dataSize,
7080 (! enif_is_empty_list(env, tail)),
7081 sockRef, sendRef);
7082
7083 done_free_iovec:
7084 enif_free_iovec(iovec);
7085 if (ctrlBuf != NULL) FREE(ctrlBuf);
7086
7087 SSDBG( descP,
7088 ("SOCKET", "esock_sendmsg {%d} ->"
7089 "\r\n %T\r\n", descP->sock, res) );
7090 return res;
7091 }
7092 #endif // #ifndef __WIN32__
7093
7094
7095
7096 #ifdef FOOBAR
7097
7098 /* ----------------------------------------------------------------------
7099 * nif_writev / nif_sendv
7100 *
7101 * Description:
7102 * Send a message (vector) on a socket
7103 *
7104 * Arguments:
7105 * Socket (ref) - Points to the socket descriptor.
7106 * SendRef - A unique id for this (send) request.
7107 * Data - A vector of binaries
7108 * Flags - Send flags.
7109 */
7110
7111 static
nwritev(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sendRef,ERL_NIF_TERM data)7112 ERL_NIF_TERM nwritev(ErlNifEnv* env,
7113 ESockDescriptor* descP,
7114 ERL_NIF_TERM sendRef,
7115 ERL_NIF_TERM data)
7116 {
7117 ERL_NIF_TERM tail;
7118 ErlNifIOVec vec;
7119 ErlNifIOVec* iovec = &vec;
7120 SysIOVec* sysiovec;
7121 int save_errno;
7122 int iovcnt, n;
7123
7124 if (! enif_inspect_iovec(env, MAX_VSZ, data, &tail, &iovec))
7125 return enif_make_badarg(env);
7126
7127 if (enif_ioq_size(descP->outQ) > 0) {
7128 /* If the I/O queue contains data we enqueue the iovec
7129 * and then peek the data to write out of the queue.
7130 */
7131 if (!enif_ioq_enqv(q, iovec, 0))
7132 return -3;
7133
7134 sysiovec = enif_ioq_peek(descP->outQ, &iovcnt);
7135
7136 } else {
7137 /* If the I/O queue is empty we skip the trip through it. */
7138 iovcnt = iovec->iovcnt;
7139 sysiovec = iovec->iov;
7140 }
7141
7142 /* Attempt to write the data */
7143 n = writev(fd, sysiovec, iovcnt);
7144 saved_errno = errno;
7145
7146 if (enif_ioq_size(descP->outQ) == 0) {
7147 /* If the I/O queue was initially empty we enqueue any
7148 remaining data into the queue for writing later. */
7149 if (n >= 0 && !enif_ioq_enqv(descP->outQ, iovec, n))
7150 return -3;
7151 } else {
7152 /* Dequeue any data that was written from the queue. */
7153 if (n > 0 && !enif_ioq_deq(descP->outQ, n, NULL))
7154 return -4;
7155 }
7156 /* return n, which is either number of bytes written or -1 if
7157 some error happened */
7158 errno = saved_errno;
7159 return n;
7160 }
7161
7162 #endif // #ifdef FOOBAR
7163
7164
7165
7166 /* ----------------------------------------------------------------------
7167 * nif_sendfile/1,4,5
7168 *
7169 * Description:
7170 * Send a file on a socket
7171 *
7172 * Arguments:
7173 * Socket (ref) - Points to the socket descriptor.
7174 *
7175 * SendRef - A unique id reference() for this (send) request.
7176 *
7177 * Offset - File offset to start from.
7178 * Count - The number of bytes to send.
7179 *
7180 * InFileRef - A file NIF resource.
7181 */
7182
7183 static ERL_NIF_TERM
nif_sendfile(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])7184 nif_sendfile(ErlNifEnv* env,
7185 int argc,
7186 const ERL_NIF_TERM argv[])
7187 {
7188 #if defined(__WIN32__) || !defined(HAVE_SENDFILE)
7189 return enif_raise_exception(env, MKA(env, "notsup"));
7190 #else
7191 ESockDescriptor *descP;
7192 ERL_NIF_TERM sockRef, res;
7193
7194 SGDBG( ("SOCKET", "nif_sendfile -> entry with argc: %d\r\n", argc) );
7195
7196 if (argc < 1) {
7197 SGDBG( ("SOCKET", "nif_sendfile -> argc < 1\r\n") );
7198 return enif_make_badarg(env);
7199 }
7200 sockRef = argv[0];
7201 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) (&descP))) {
7202 SGDBG( ("SOCKET", "nif_sendfile -> get resource failed\r\n") );
7203 return enif_make_badarg(env);
7204 }
7205
7206 if (argc < 2) { // argc == 1
7207
7208 MLOCK(descP->writeMtx);
7209
7210 SSDBG( descP,
7211 ("SOCKET", "nif_sendfile(%T), {%d,%d,0x%X} ->"
7212 "\r\n",
7213 sockRef,
7214 descP->sock, descP->sendfileHandle, descP->writeState) );
7215
7216 res = esock_sendfile_deferred_close(env, descP);
7217
7218 } else {
7219 ERL_NIF_TERM sendRef;
7220 ErlNifSInt64 offset64;
7221 ErlNifUInt64 count64u;
7222 off_t offset;
7223 size_t count;
7224 BOOLEAN_T a2ok;
7225
7226 ESOCK_ASSERT( argc >= 4 );
7227
7228 sendRef = argv[1];
7229 if ((! enif_is_ref(env, sendRef))) {
7230 SSDBG( descP,
7231 ("SOCKET", "nif_sendfile -> argv[1] decode failed\r\n") );
7232 return enif_make_badarg(env);
7233 }
7234
7235 if ((! (a2ok = GET_INT64(env, argv[2], &offset64))) ||
7236 (! GET_UINT64(env, argv[3], &count64u))) {
7237 if ((! IS_INTEGER(env, argv[3])) ||
7238 (! IS_INTEGER(env, argv[3])))
7239 return enif_make_badarg(env);
7240 if (! a2ok)
7241 return esock_make_error_integer_range(env, argv[2]);
7242 else
7243 return esock_make_error_integer_range(env, argv[3]);
7244 }
7245 offset = (off_t) offset64;
7246 if (offset64 != (ErlNifSInt64) offset)
7247 return esock_make_error_integer_range(env, argv[2]);
7248 count = (size_t) count64u;
7249 if (count64u != (ErlNifUInt64) count)
7250 return esock_make_error_integer_range(env, argv[3]);
7251
7252 if (argc == 4) {
7253
7254 MLOCK(descP->writeMtx);
7255
7256 SSDBG( descP,
7257 ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->"
7258 "\r\n sendRef: %T"
7259 "\r\n offset: %ld"
7260 "\r\n count: %ld"
7261 "\r\n",
7262 sockRef, descP->sock, descP->readState,
7263 sendRef, (long) offset, (long) count) );
7264
7265 res =
7266 esock_sendfile_cont(env, descP, sockRef, sendRef,
7267 offset, count);
7268 } else {
7269 ERL_NIF_TERM fRef;
7270
7271 ESOCK_ASSERT( argc == 5 );
7272
7273 fRef = argv[4];
7274 if ((! enif_is_ref(env, fRef)))
7275 return enif_make_badarg(env);
7276
7277 MLOCK(descP->writeMtx);
7278
7279 SSDBG( descP,
7280 ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->"
7281 "\r\n sendRef: %T"
7282 "\r\n offset: %ld"
7283 "\r\n count: %ld"
7284 "\r\n fRef: %T"
7285 "\r\n",
7286 sockRef, descP->sock, descP->readState,
7287 sendRef, (long) offset, (long) count, fRef) );
7288
7289 res =
7290 esock_sendfile_start(env, descP, sockRef, sendRef,
7291 offset, count, fRef);
7292 }
7293 }
7294
7295 SSDBG( descP, ("SOCKET", "nif_sendfile(%T) -> done with"
7296 "\r\n res: %T"
7297 "\r\n", sockRef, res) );
7298
7299 MUNLOCK(descP->writeMtx);
7300
7301 return res;
7302
7303 #endif // #if defined(__WIN32__) || !defined(HAVE_SENDFILE)
7304 }
7305
7306 #ifndef __WIN32__
7307 #ifdef HAVE_SENDFILE
7308
7309 /* Start a sendfile() operation
7310 */
7311 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)7312 esock_sendfile_start(ErlNifEnv *env,
7313 ESockDescriptor *descP,
7314 ERL_NIF_TERM sockRef,
7315 ERL_NIF_TERM sendRef,
7316 off_t offset,
7317 size_t count,
7318 ERL_NIF_TERM fRef) {
7319 ERL_NIF_TERM writerCheck;
7320 ssize_t res;
7321 int err;
7322
7323 SSDBG( descP, ("SOCKET",
7324 "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n"
7325 " fRef: %T\r\n"
7326 " offset: %lu\r\n"
7327 " count: %lu\r\n",
7328 sockRef, descP->sock, sendRef,
7329 fRef, (unsigned long) offset, (unsigned long) count) );
7330
7331 if (! IS_OPEN(descP->writeState)) {
7332 return esock_make_error(env, atom_closed);
7333 }
7334
7335 /* Connect and Write uses the same select flag
7336 * so they can not be simultaneous
7337 */
7338 if (descP->connectorP != NULL) {
7339 return esock_make_error_invalid(env, atom_state);
7340 }
7341
7342 /* Ensure that we either have no current writer or we are it,
7343 * or enqueue this process if there is a current writer
7344 */
7345 if (! send_check_writer(env, descP, sendRef, &writerCheck)) {
7346 SSDBG( descP, ("SOCKET",
7347 "esock_sendfile_start {%d} -> writer check failed: "
7348 "\r\n %T\r\n", descP->sock, writerCheck) );
7349
7350 /* Returns 'select' if current process got enqueued,
7351 * or exception invalid state if current process already
7352 * was enqueued
7353 */
7354 return writerCheck;
7355 }
7356
7357 if (descP->sendfileHandle != INVALID_HANDLE)
7358 return esock_make_error_invalid(env, atom_state);
7359
7360 /* Get a dup:ed file handle from prim_file_nif
7361 * through a NIF dyncall
7362 */
7363 {
7364 struct prim_file_nif_dyncall_dup dc_dup;
7365
7366 dc_dup.op = prim_file_nif_dyncall_dup;
7367 dc_dup.result = EINVAL; // should not be needed
7368
7369 /* Request the handle */
7370 if (enif_dynamic_resource_call(env,
7371 atom_prim_file, atom_efile, fRef,
7372 &dc_dup)
7373 != 0) {
7374 return
7375 esock_sendfile_error(env, descP, sockRef,
7376 MKT2(env, esock_atom_invalid,
7377 atom_efile));
7378 }
7379 if (dc_dup.result != 0) {
7380 return
7381 esock_sendfile_errno(env, descP, sockRef, dc_dup.result);
7382 }
7383 descP->sendfileHandle = dc_dup.handle;
7384 }
7385
7386 SSDBG( descP, ("SOCKET",
7387 "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n"
7388 " sendfileHandle: %d\r\n",
7389 sockRef, descP->sock, sendRef,
7390 descP->sendfileHandle) );
7391
7392 if (descP->sendfileCountersP == NULL) {
7393 descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters));
7394 *descP->sendfileCountersP = initESockSendfileCounters;
7395 }
7396
7397 ESOCK_CNT_INC(env, descP, sockRef,
7398 atom_sendfile_tries, &descP->sendfileCountersP->tries, 1);
7399 descP->sendfileCountersP->maxCnt = 0;
7400
7401 res = esock_sendfile(env, descP, sockRef, offset, &count, &err);
7402
7403 if (res < 0) { // Terminal error
7404
7405 (void) close(descP->sendfileHandle);
7406 descP->sendfileHandle = INVALID_HANDLE;
7407
7408 return esock_sendfile_errno(env, descP, sockRef, err);
7409
7410 } else if (res > 0) { // Retry by select
7411
7412 if (descP->currentWriterP == NULL) {
7413 int mon_res;
7414
7415 /* Register writer as current */
7416 ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL );
7417 mon_res =
7418 MONP("sendfile -> current writer",
7419 env, descP,
7420 &descP->currentWriter.pid,
7421 &descP->currentWriter.mon);
7422 ESOCK_ASSERT( mon_res >= 0 );
7423
7424 if (mon_res > 0) {
7425 /* Caller died already, can happen for dirty NIFs */
7426
7427 (void) close(descP->sendfileHandle);
7428 descP->sendfileHandle = INVALID_HANDLE;
7429
7430 return
7431 esock_sendfile_error(env, descP, sockRef,
7432 MKT2(env,
7433 esock_atom_invalid,
7434 esock_atom_not_owner));
7435 }
7436 ESOCK_ASSERT( descP->currentWriter.env == NULL );
7437 descP->currentWriter.env = esock_alloc_env("current-writer");
7438 descP->currentWriter.ref =
7439 CP_TERM(descP->currentWriter.env, sendRef);
7440 descP->currentWriterP = &descP->currentWriter;
7441 }
7442 // else current writer is already registered by requestor_pop()
7443
7444 return esock_sendfile_select(env, descP, sockRef, sendRef, count);
7445
7446 } else { // res == 0: Done
7447 return esock_sendfile_ok(env, descP, sockRef, count);
7448 }
7449 }
7450
7451 /* Continue an ongoing sendfile operation
7452 */
7453 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)7454 esock_sendfile_cont(ErlNifEnv *env,
7455 ESockDescriptor *descP,
7456 ERL_NIF_TERM sockRef,
7457 ERL_NIF_TERM sendRef,
7458 off_t offset,
7459 size_t count) {
7460 ErlNifPid caller;
7461 ssize_t res;
7462 int err;
7463
7464 SSDBG( descP, ("SOCKET",
7465 "esock_sendfile_cont(%T) {%d} -> sendRef: %T\r\n",
7466 sockRef, descP->sock, sendRef) );
7467
7468 if (! IS_OPEN(descP->writeState))
7469 return esock_make_error(env, atom_closed);
7470
7471 /* Connect and Write uses the same select flag
7472 * so they can not be simultaneous
7473 */
7474 if (descP->connectorP != NULL)
7475 return esock_make_error_invalid(env, atom_state);
7476
7477 /* Verify that this process has a sendfile operation in progress */
7478 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
7479 if ((descP->currentWriterP == NULL) ||
7480 (descP->sendfileHandle == INVALID_HANDLE) ||
7481 (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0)) {
7482 //
7483 return esock_raise_invalid(env, atom_state);
7484 }
7485
7486 res = esock_sendfile(env, descP, sockRef, offset, &count, &err);
7487
7488 if (res < 0) { // Terminal error
7489
7490 (void) close(descP->sendfileHandle);
7491 descP->sendfileHandle = INVALID_HANDLE;
7492
7493 return esock_sendfile_errno(env, descP, sockRef, err);
7494
7495 } else if (res > 0) { // Retry by select
7496
7497 /* Overwrite current writer registration */
7498 enif_clear_env(descP->currentWriter.env);
7499 descP->currentWriter.ref =
7500 CP_TERM(descP->currentWriter.env, sendRef);
7501
7502 return esock_sendfile_select(env, descP, sockRef, sendRef, count);
7503
7504 } else { // res == 0: Done
7505 return esock_sendfile_ok(env, descP, sockRef, count);
7506 }
7507 }
7508
7509 /* Deferred close of the dup:ed file descriptor
7510 */
7511 static ERL_NIF_TERM
esock_sendfile_deferred_close(ErlNifEnv * env,ESockDescriptor * descP)7512 esock_sendfile_deferred_close(ErlNifEnv *env,
7513 ESockDescriptor *descP) {
7514 if (descP->sendfileHandle == INVALID_HANDLE)
7515 return esock_make_error_invalid(env, atom_state);
7516
7517 (void) close(descP->sendfileHandle);
7518 descP->sendfileHandle = INVALID_HANDLE;
7519
7520 return esock_atom_ok;
7521 }
7522
7523 /* Platform independent sendfile() function
7524 *
7525 * Return < 0 for terminal error
7526 * 0 for done
7527 * > 0 for retry with select
7528 */
7529 static int
esock_sendfile(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,off_t offset,size_t * countP,int * errP)7530 esock_sendfile(ErlNifEnv *env,
7531 ESockDescriptor *descP,
7532 ERL_NIF_TERM sockRef,
7533 off_t offset,
7534 size_t *countP,
7535 int *errP) {
7536
7537 size_t pkgSize = 0; // Total sent in this call
7538
7539 SSDBG( descP, ("SOCKET",
7540 "esock_sendfile(%T) {%d,%d}\r\n",
7541 sockRef, descP->sock, descP->sendfileHandle) );
7542
7543 for (;;) {
7544 size_t chunk_size = (size_t) 0x20000000UL; // 0.5 GB
7545 size_t bytes_sent;
7546 ssize_t res;
7547 int error;
7548
7549 /* *countP == 0 means send the whole file - use chunk size */
7550 if ((*countP > 0) && (*countP < chunk_size))
7551 chunk_size = *countP;
7552
7553 {
7554 /* Platform dependent code:
7555 * update and check offset, set and check bytes_sent, and
7556 * set res to >= 0 and error to 0, or
7557 * set res to < 0 and error to sock_errno()
7558 */
7559 #if defined (__linux__)
7560
7561 off_t prev_offset;
7562
7563 prev_offset = offset;
7564 res =
7565 sendfile(descP->sock, descP->sendfileHandle,
7566 &offset, chunk_size);
7567 error = (res < 0) ? sock_errno() : 0;
7568
7569 ESOCK_ASSERT( offset >= prev_offset );
7570 ESOCK_ASSERT( (off_t) chunk_size >= (offset - prev_offset) );
7571 bytes_sent = (size_t) (offset - prev_offset);
7572
7573 SSDBG( descP,
7574 ("SOCKET",
7575 "esock_sendfile(%T) {%d,%d}"
7576 "\r\n res: %d"
7577 "\r\n bytes_sent: %lu"
7578 "\r\n error: %d"
7579 "\r\n",
7580 sockRef, descP->sock, descP->sendfileHandle,
7581 res, (unsigned long) bytes_sent, error) );
7582
7583 #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__DARWIN__)
7584
7585 off_t sbytes;
7586
7587 #if defined(__DARWIN__)
7588 sbytes = (off_t) chunk_size;
7589 res = (ssize_t)
7590 sendfile(descP->sendfileHandle, descP->sock, offset,
7591 &sbytes, NULL, 0);
7592 #else
7593 sbytes = 0;
7594 res = (ssize_t)
7595 sendfile(descP->sendfileHandle, descP->sock, offset,
7596 chunk_size, NULL, &sbytes, 0);
7597 #endif
7598 error = (res < 0) ? sock_errno() : 0;
7599
7600 /* For an error return, we do not dare trust that sbytes is set
7601 * unless the error is ERRNO_BLOCK or EINTR
7602 * - the man page is to vague
7603 */
7604 if ((res < 0) && (error != ERRNO_BLOCK) && (error != EINTR)) {
7605 sbytes = 0;
7606 } else {
7607 ESOCK_ASSERT( sbytes >= 0 );
7608 ESOCK_ASSERT( (off_t) chunk_size >= sbytes );
7609 ESOCK_ASSERT( offset + sbytes >= offset );
7610 offset += sbytes;
7611 }
7612 bytes_sent = (size_t) sbytes;
7613
7614 SSDBG( descP,
7615 ("SOCKET",
7616 "esock_sendfile(%T) {%d,%d}"
7617 "\r\n res: %d"
7618 "\r\n bytes_sent: %lu"
7619 "\r\n error: %d"
7620 "\r\n",
7621 sockRef, descP->sock, descP->sendfileHandle,
7622 res, (unsigned long) bytes_sent, error) );
7623
7624 #elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV)
7625
7626 sendfilevec_t sfvec[1];
7627
7628 sfvec[0].sfv_fd = descP->sendfileHandle;
7629 sfvec[0].sfv_flag = 0;
7630 sfvec[0].sfv_off = offset;
7631 sfvec[0].sfv_len = chunk_size;
7632
7633 res = sendfilev(descP->sock, sfvec, NUM(sfvec), &bytes_sent);
7634 error = (res < 0) ? sock_errno() : 0;
7635
7636 SSDBG( descP,
7637 ("SOCKET",
7638 "esock_sendfile(%T) {%d,%d}"
7639 "\r\n res: %d"
7640 "\r\n bytes_sent: %lu"
7641 "\r\n error: %d"
7642 "\r\n",
7643 sockRef, descP->sock, descP->sendfileHandle,
7644 res, (unsigned long) bytes_sent, error) );
7645
7646 if ((res < 0) && (error == EINVAL)) {
7647 /* On e.b SunOS 5.10 using sfv_len > file size
7648 * lands here - we regard this as a succesful send.
7649 * All other causes for EINVAL are avoided,
7650 * except for .sfv_fd not seekable, which would
7651 * give bytes_sent == 0 that we would interpret
7652 * as end of file, which is kind of true.
7653 */
7654 res = 0;
7655 }
7656 ESOCK_ASSERT( chunk_size >= bytes_sent );
7657 ESOCK_ASSERT( offset + bytes_sent >= offset );
7658 offset += bytes_sent;
7659
7660 #else
7661 #error "Unsupported sendfile syscall; update configure test."
7662 #endif
7663
7664 ESOCK_CNT_INC(env, descP, sockRef,
7665 atom_sendfile, &descP->sendfileCountersP->cnt, 1);
7666
7667 if (bytes_sent != 0) {
7668
7669 pkgSize += bytes_sent;
7670
7671 ESOCK_CNT_INC(env, descP, sockRef,
7672 atom_sendfile_pkg,
7673 &descP->sendfileCountersP->pkg,
7674 1);
7675 ESOCK_CNT_INC(env, descP, sockRef,
7676 atom_sendfile_byte,
7677 &descP->sendfileCountersP->byteCnt,
7678 bytes_sent);
7679
7680 if (pkgSize > descP->sendfileCountersP->pkgMax)
7681 descP->sendfileCountersP->pkgMax = pkgSize;
7682 if ((descP->sendfileCountersP->maxCnt += bytes_sent)
7683 > descP->sendfileCountersP->max)
7684 descP->sendfileCountersP->max =
7685 descP->sendfileCountersP->maxCnt;
7686 }
7687
7688 /* *countP == 0 means send whole file */
7689 if (*countP > 0) {
7690
7691 *countP -= bytes_sent;
7692
7693 if (*countP == 0) { // All sent
7694 *countP = pkgSize;
7695 return 0;
7696 }
7697 }
7698
7699 if (res < 0) {
7700 if (error == ERRNO_BLOCK) {
7701 *countP = pkgSize;
7702 return 1;
7703 }
7704 if (error == EINTR)
7705 continue;
7706 *errP = error;
7707 return -1;
7708 }
7709
7710 if (bytes_sent == 0) { // End of input file
7711 *countP = pkgSize;
7712 return 0;
7713 }
7714 }
7715 } // for (;;)
7716 }
7717
7718 static ERL_NIF_TERM
esock_sendfile_errno(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,int err)7719 esock_sendfile_errno(ErlNifEnv *env,
7720 ESockDescriptor *descP,
7721 ERL_NIF_TERM sockRef,
7722 int err) {
7723 ERL_NIF_TERM reason;
7724
7725 reason = MKA(env, erl_errno_id(err));
7726 return esock_sendfile_error(env, descP, sockRef, reason);
7727 }
7728
7729 static ERL_NIF_TERM
esock_sendfile_error(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM reason)7730 esock_sendfile_error(ErlNifEnv *env,
7731 ESockDescriptor *descP,
7732 ERL_NIF_TERM sockRef,
7733 ERL_NIF_TERM reason) {
7734
7735 if (descP->sendfileCountersP == NULL) {
7736 descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters));
7737 *descP->sendfileCountersP = initESockSendfileCounters;
7738 }
7739
7740 ESOCK_CNT_INC(env, descP, sockRef,
7741 atom_sendfile_fails,
7742 &descP->sendfileCountersP->fails, 1);
7743
7744 SSDBG( descP, ("SOCKET",
7745 "esock_sendfile_error(%T) {%d} -> error: %T\r\n",
7746 sockRef, descP->sock, reason) );
7747
7748 /* XXX Should we have special treatment for EINVAL,
7749 * such as to only fail current operation and activate
7750 * the next from the queue?
7751 */
7752
7753 if (descP->currentWriterP != NULL) {
7754
7755 (void) DEMONP("esock_sendfile_error",
7756 env, descP, &descP->currentWriter.mon);
7757
7758 /* Fail all queued writers */
7759 requestor_release("esock_sendfile_error",
7760 env, descP, &descP->currentWriter);
7761 send_error_waiting_writers(env, descP, sockRef, reason);
7762 descP->currentWriterP = NULL;
7763
7764 }
7765
7766 return esock_make_error(env, reason);
7767 }
7768
7769 static ERL_NIF_TERM
esock_sendfile_select(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM sendRef,size_t count)7770 esock_sendfile_select(ErlNifEnv *env,
7771 ESockDescriptor *descP,
7772 ERL_NIF_TERM sockRef,
7773 ERL_NIF_TERM sendRef,
7774 size_t count) {
7775 int sres;
7776
7777 /* Select write for this process */
7778 sres =
7779 esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef);
7780 if (sres < 0) {
7781 ERL_NIF_TERM reason;
7782
7783 /* Internal select error */
7784 (void) DEMONP("esock_sendfile_select - failed",
7785 env, descP, &descP->currentWriter.mon);
7786
7787 /* Fail all queued writers */
7788 reason = MKT2(env, atom_select_write, MKI(env, sres));
7789 requestor_release("esock_sendfile_select_fail",
7790 env, descP, &descP->currentWriter);
7791 send_error_waiting_writers(env, descP, sockRef, reason);
7792 descP->currentWriterP = NULL;
7793
7794 (void) close(descP->sendfileHandle);
7795 descP->sendfileHandle = INVALID_HANDLE;
7796
7797 return enif_raise_exception(env, reason);
7798
7799 } else {
7800 ErlNifUInt64 bytes_sent;
7801
7802 SSDBG( descP,
7803 ("SOCKET", "esock_sendfile_select(%T) {%d} -> "
7804 "sendRef (%T)\r\n"
7805 "count: %lu\r\n",
7806 sockRef, descP->sock, sendRef, (unsigned long) count) );
7807
7808 ESOCK_CNT_INC(env, descP, sockRef,
7809 atom_sendfile_waits,
7810 &descP->sendfileCountersP->waits,
7811 1);
7812 descP->writeState |= ESOCK_STATE_SELECTED;
7813 bytes_sent = (ErlNifUInt64) count;
7814
7815 return MKT2(env, atom_select, MKUI64(env, bytes_sent));
7816 }
7817 }
7818
7819 static ERL_NIF_TERM
esock_sendfile_ok(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,size_t count)7820 esock_sendfile_ok(ErlNifEnv *env,
7821 ESockDescriptor *descP,
7822 ERL_NIF_TERM sockRef,
7823 size_t count) {
7824 ErlNifUInt64 bytes_sent64u;
7825
7826 SSDBG( descP,
7827 ("SOCKET", "esock_sendfile_ok(%T) {%d} -> "
7828 "everything written (%lu) - done\r\n",
7829 sockRef, descP->sock, (unsigned long) count) );
7830
7831 if (descP->currentWriterP != NULL) {
7832
7833 (void) DEMONP("esock_sendfile_ok -> current writer",
7834 env, descP, &descP->currentWriter.mon);
7835
7836 /*
7837 * Ok, this write is done maybe activate the next (if any)
7838 */
7839 if (! activate_next_writer(env, descP, sockRef)) {
7840
7841 SSDBG( descP,
7842 ("SOCKET",
7843 "esock_sendfile_ok(%T) {%d} -> no more writers\r\n",
7844 sockRef, descP->sock) );
7845
7846 descP->currentWriterP = NULL;
7847 }
7848 }
7849
7850 descP->writePkgMaxCnt = 0;
7851 bytes_sent64u = (ErlNifUInt64) count;
7852
7853 (void) close(descP->sendfileHandle);
7854 descP->sendfileHandle = INVALID_HANDLE;
7855
7856 return esock_make_ok2(env, MKUI64(env, bytes_sent64u));
7857 }
7858
7859 #endif // #ifdef HAVE_SENDFILE
7860 #endif // #ifndef __WIN32__
7861
7862
7863
7864 /* ----------------------------------------------------------------------
7865 * nif_recv
7866 *
7867 * Description:
7868 * Receive a message on a socket.
7869 * Normally used only on a connected socket!
7870 * If we are trying to read > 0 bytes, then that is what we do.
7871 * But if we have specified 0 bytes, then we want to read
7872 * whatever is in the buffers (everything it got).
7873 *
7874 * Arguments:
7875 * Socket (ref) - NIF resource reference() to the socket descriptor.
7876 * Length - The number of bytes to receive; integer().
7877 * Flags - Receive flags; integer().
7878 * RecvRef - A unique reference() id for this (send) request | 'poll'
7879 */
7880
7881 static
nif_recv(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])7882 ERL_NIF_TERM nif_recv(ErlNifEnv* env,
7883 int argc,
7884 const ERL_NIF_TERM argv[])
7885 {
7886 #ifdef __WIN32__
7887 return enif_raise_exception(env, MKA(env, "notsup"));
7888 #else
7889 ESockDescriptor* descP;
7890 ERL_NIF_TERM sockRef, recvRef;
7891 ErlNifUInt64 elen;
7892 ssize_t len; /* ssize_t due to the return type of recv() */
7893 int flags;
7894 ERL_NIF_TERM res;
7895 BOOLEAN_T a1ok;
7896
7897 ESOCK_ASSERT( argc == 4 );
7898
7899 sockRef = argv[0]; // We need this in case we send abort (to the caller)
7900 recvRef = argv[3];
7901
7902 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
7903 return enif_make_badarg(env);
7904 }
7905
7906 if ((! enif_is_ref(env, recvRef)) &&
7907 (COMPARE(recvRef, atom_zero) != 0)) {
7908 return enif_make_badarg(env);
7909 }
7910 if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) ||
7911 (! GET_INT(env, argv[2], &flags))) {
7912 if ((! IS_INTEGER(env, argv[1])) ||
7913 (! IS_INTEGER(env, argv[2])))
7914 return enif_make_badarg(env);
7915
7916 if (! a1ok)
7917 return esock_make_error_integer_range(env, argv[1]);
7918 return
7919 esock_make_error_integer_range(env, argv[2]);
7920 }
7921 len = (ssize_t) elen;
7922 if (elen != (ErlNifUInt64) len)
7923 return esock_make_error_integer_range(env, elen);
7924
7925 MLOCK(descP->readMtx);
7926
7927 SSDBG( descP,
7928 ("SOCKET", "nif_recv(%T), {%d,0x%X} ->"
7929 "\r\n recvRef: %T"
7930 "\r\n len: %ld"
7931 "\r\n flags: 0x%X"
7932 "\r\n",
7933 sockRef, descP->sock, descP->readState,
7934 recvRef, (long) len, flags) );
7935
7936 /* We need to handle the case when another process tries
7937 * to receive at the same time.
7938 * If the current recv could not read its entire package
7939 * this time (resulting in an select). The read of the
7940 * other process must be made to wait until current
7941 * is done!
7942 */
7943
7944 res = esock_recv(env, descP, sockRef, recvRef, len, flags);
7945
7946 SSDBG( descP, ("SOCKET", "nif_recv(%T) -> done"
7947 "\r\n", sockRef) );
7948
7949 MUNLOCK(descP->readMtx);
7950
7951 return res;
7952
7953 #endif // #ifdef __WIN32__ #else
7954 }
7955
7956
7957 /* The (read) buffer handling should be optimized!
7958 * But for now we make it easy for ourselves by
7959 * allocating a binary (of the specified or default
7960 * size) and then throwing it away...
7961 */
7962 #ifndef __WIN32__
7963 static
esock_recv(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef,ssize_t len,int flags)7964 ERL_NIF_TERM esock_recv(ErlNifEnv* env,
7965 ESockDescriptor* descP,
7966 ERL_NIF_TERM sockRef,
7967 ERL_NIF_TERM recvRef,
7968 ssize_t len,
7969 int flags)
7970 {
7971 ssize_t read;
7972 ErlNifBinary buf;
7973 ERL_NIF_TERM readerCheck;
7974 int save_errno;
7975 size_t bufSz = (len != 0 ? len : descP->rBufSz);
7976
7977 SSDBG( descP, ("SOCKET", "esock_recv {%d} -> entry with"
7978 "\r\n count,size: (%ld:%u:%lu)"
7979 "\r\n", descP->sock,
7980 (long) len, descP->rNumCnt, (unsigned long) bufSz) );
7981
7982 if (! IS_OPEN(descP->readState))
7983 return esock_make_error(env, atom_closed);
7984
7985 /* Accept and Read uses the same select flag
7986 * so they can not be simultaneous
7987 */
7988 if (descP->currentAcceptorP != NULL)
7989 return esock_make_error_invalid(env, atom_state);
7990
7991 /* Ensure that we either have no current reader or that we are it,
7992 * or enqueue this process if there is a current reader */
7993 if (! recv_check_reader(env, descP, recvRef, &readerCheck)) {
7994 SSDBG( descP,
7995 ("SOCKET", "esock_recv {%d} -> reader check failed: "
7996 "\r\n %T\r\n", descP->sock, readerCheck) );
7997 return readerCheck;
7998 }
7999
8000 /* Allocate a buffer:
8001 * Either as much as we want to read or (if zero (0)) use the "default"
8002 * size (what has been configured).
8003 */
8004 ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) );
8005
8006 // If it fails (read = -1), we need errno...
8007 SSDBG( descP, ("SOCKET", "esock_recv {%d} -> try read (%lu)\r\n",
8008 descP->sock, (unsigned long) buf.size) );
8009
8010 ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
8011
8012 read = sock_recv(descP->sock, buf.data, buf.size, flags);
8013 if (ESOCK_IS_ERROR(read)) {
8014 save_errno = sock_errno();
8015 } else {
8016 save_errno = 0; // The value does not actually matter in this case
8017 }
8018
8019 SSDBG( descP, ("SOCKET",
8020 "esock_recv {%d} -> read: %ld (%d)\r\n",
8021 descP->sock, (long) read, save_errno) );
8022
8023 return recv_check_result(env, descP, read, len, save_errno,
8024 &buf, sockRef, recvRef);
8025 }
8026 #endif // #ifndef __WIN32__
8027
8028
8029
8030 /* ----------------------------------------------------------------------
8031 * nif_recvfrom
8032 *
8033 * Description:
8034 * Receive a message on a socket.
8035 * Normally used only on a (un-) connected socket!
8036 * If a buffer size = 0 is specified, then the we will use the default
8037 * buffer size for this socket (whatever has been configured).
8038 *
8039 * Arguments:
8040 * Socket (ref) - NIF resource reference() to the socket descriptor.
8041 * BufSz - integer() ize of the buffer
8042 * into which we put the received message.
8043 * Flags - Receive flags; integer().
8044 * RecvRef - A unique reference() id for this recv request.
8045 *
8046 * <KOLLA>
8047 *
8048 * How do we handle if the peek flag is set? We need to basically keep
8049 * track of if we expect any data from the read. Regardless of the
8050 * number of bytes we try to read.
8051 *
8052 * </KOLLA>
8053 */
8054
8055 static
nif_recvfrom(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])8056 ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
8057 int argc,
8058 const ERL_NIF_TERM argv[])
8059 {
8060 #ifdef __WIN32__
8061 return enif_raise_exception(env, MKA(env, "notsup"));
8062 #else
8063 ESockDescriptor* descP;
8064 ERL_NIF_TERM sockRef, recvRef;
8065 ErlNifUInt64 elen;
8066 ssize_t len; /* ssize_t due to the return type of recvfrom() */
8067 int flags;
8068 ERL_NIF_TERM res;
8069 BOOLEAN_T a1ok;
8070
8071 ESOCK_ASSERT( argc == 4 );
8072
8073 SGDBG( ("SOCKET", "nif_recvfrom -> entry with argc: %d\r\n", argc) );
8074
8075 sockRef = argv[0]; // We need this in case we send abort (to the caller)
8076 recvRef = argv[3];
8077
8078 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
8079 return enif_make_badarg(env);
8080 }
8081
8082 /* Extract arguments and perform preliminary validation */
8083
8084 if ((! enif_is_ref(env, recvRef)) &&
8085 (COMPARE(recvRef, atom_zero) != 0)) {
8086 return enif_make_badarg(env);
8087 }
8088
8089 if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) ||
8090 (! GET_INT(env, argv[2], &flags))) {
8091 if ((! IS_INTEGER(env, argv[1])) ||
8092 (! IS_INTEGER(env, argv[2])))
8093 return enif_make_badarg(env);
8094
8095 if (! a1ok)
8096 return esock_make_error_integer_range(env, argv[1]);
8097 return
8098 esock_make_error_integer_range(env, argv[2]);
8099 }
8100 len = (ssize_t) elen;
8101 if (elen != (ErlNifUInt64) len)
8102 return esock_make_error_integer_range(env, elen);
8103
8104 MLOCK(descP->readMtx);
8105
8106 SSDBG( descP,
8107 ("SOCKET", "nif_recvfrom(%T), {%d,0x%X} ->"
8108 "\r\n recvRef: %T"
8109 "\r\n len: %ld"
8110 "\r\n flags: 0x%X"
8111 "\r\n",
8112 sockRef, descP->sock, descP->readState,
8113 recvRef, (long) len, flags) );
8114
8115 /* <KOLLA>
8116 * We need to handle the case when another process tries
8117 * to receive at the same time.
8118 * If the current recv could not read its entire package
8119 * this time (resulting in an select). The read of the
8120 * other process must be made to wait until current
8121 * is done!
8122 * Basically, we need a read queue!
8123 *
8124 * A 'reading' field (boolean), which is set if we did
8125 * not manage to read the entire message and reset every
8126 * time we do.
8127 * </KOLLA>
8128 */
8129
8130 res = esock_recvfrom(env, descP, sockRef, recvRef, len, flags);
8131
8132 SSDBG( descP, ("SOCKET", "nif_recvfrom(%T) -> done"
8133 "\r\n", sockRef) );
8134
8135 MUNLOCK(descP->readMtx);
8136
8137 return res;
8138 #endif // #ifdef __WIN32__ #else
8139 }
8140
8141
8142 /* The (read) buffer handling *must* be optimized!
8143 * But for now we make it easy for ourselves by
8144 * allocating a binary (of the specified or default
8145 * size) and then throwing it away...
8146 */
8147 #ifndef __WIN32__
8148 static
esock_recvfrom(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef,ssize_t len,int flags)8149 ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
8150 ESockDescriptor* descP,
8151 ERL_NIF_TERM sockRef,
8152 ERL_NIF_TERM recvRef,
8153 ssize_t len,
8154 int flags)
8155 {
8156 ESockAddress fromAddr;
8157 SOCKLEN_T addrLen;
8158 ssize_t read;
8159 int save_errno;
8160 ErlNifBinary buf;
8161 ERL_NIF_TERM readerCheck;
8162 size_t bufSz = (len != 0 ? len : descP->rBufSz);
8163
8164 SSDBG( descP, ("SOCKET", "esock_recvfrom {%d} -> entry with"
8165 "\r\n bufSz: %d"
8166 "\r\n", descP->sock, bufSz) );
8167
8168 if (! IS_OPEN(descP->readState))
8169 return esock_make_error(env, atom_closed);
8170
8171 /* Accept and Read uses the same select flag
8172 * so they can not be simultaneous
8173 */
8174 if (descP->currentAcceptorP != NULL)
8175 return esock_make_error_invalid(env, atom_state);
8176
8177 /* Ensure that we either have no current reader or that we are it,
8178 * or enqueue this process if there is a current reader */
8179 if (! recv_check_reader(env, descP, recvRef, &readerCheck)) {
8180 SSDBG( descP,
8181 ("SOCKET", "esock_recv {%d} -> reader check failed: "
8182 "\r\n %T\r\n", descP->sock, readerCheck) );
8183 return readerCheck;
8184 }
8185
8186 /* Allocate a buffer:
8187 * Either as much as we want to read or (if zero (0)) use the "default"
8188 * size (what has been configured).
8189 */
8190 ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) );
8191
8192 ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
8193
8194 addrLen = sizeof(fromAddr);
8195 sys_memzero((char*) &fromAddr, addrLen);
8196
8197 read = sock_recvfrom(descP->sock, buf.data, buf.size, flags,
8198 &fromAddr.sa, &addrLen);
8199 if (ESOCK_IS_ERROR(read))
8200 save_errno = sock_errno();
8201 else
8202 save_errno = 0; // The value does not actually matter in this case
8203
8204 return recvfrom_check_result(env, descP, read, save_errno,
8205 &buf, &fromAddr, addrLen,
8206 sockRef, recvRef);
8207 }
8208 #endif // #ifndef __WIN32__
8209
8210
8211
8212 /* ----------------------------------------------------------------------
8213 * nif_recvmsg
8214 *
8215 * Description:
8216 * Receive a message on a socket.
8217 * Normally used only on a (un-) connected socket!
8218 * If a buffer size = 0 is specified, then we will use the default
8219 * buffer size for this socket (whatever has been configured).
8220 * If ctrl (buffer) size = 0 is specified, then the default ctrl
8221 * (buffer) size is used (1024).
8222 *
8223 * Arguments:
8224 * Socket (ref) - NIF resource reference() to the socket descriptor.
8225 * BufSz - Size of the buffer into which we put the received message;
8226 * integer().
8227 * CtrlSz - Size of the ctrl (buffer) into which we put the received
8228 * ancillary data; integer().
8229 * Flags - Receive flags; integer().
8230 * RecvRef - A unique reference() id for this (send) request.
8231 *
8232 * <KOLLA>
8233 *
8234 * How do we handle if the peek flag is set? We need to basically keep
8235 * track of if we expect any data from the read. Regardless of the
8236 * number of bytes we try to read.
8237 *
8238 * </KOLLA>
8239 */
8240
8241 static
nif_recvmsg(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])8242 ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
8243 int argc,
8244 const ERL_NIF_TERM argv[])
8245 {
8246 #ifdef __WIN32__
8247 return enif_raise_exception(env, MKA(env, "notsup"));
8248 #else
8249 ESockDescriptor* descP;
8250 ERL_NIF_TERM sockRef, recvRef;
8251 ErlNifUInt64 eBufSz, eCtrlSz;
8252 ssize_t bufSz, ctrlSz;
8253 int flags;
8254 ERL_NIF_TERM res;
8255 BOOLEAN_T a1ok, a2ok;
8256
8257 ESOCK_ASSERT( argc == 5 );
8258
8259 SGDBG( ("SOCKET", "nif_recvmsg -> entry with argc: %d\r\n", argc) );
8260
8261 sockRef = argv[0]; // We need this in case we send abort (to the caller)
8262 recvRef = argv[4];
8263
8264 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
8265 return enif_make_badarg(env);
8266 }
8267
8268 /* Extract arguments and perform preliminary validation */
8269
8270 if ((! enif_is_ref(env, recvRef)) &&
8271 (COMPARE(recvRef, atom_zero) != 0)) {
8272 return enif_make_badarg(env);
8273 }
8274
8275 if ((! (a1ok = GET_UINT64(env, argv[1], &eBufSz))) ||
8276 (! (a2ok = GET_UINT64(env, argv[2], &eCtrlSz))) ||
8277 (! GET_INT(env, argv[3], &flags))) {
8278 if ((! IS_INTEGER(env, argv[1])) ||
8279 (! IS_INTEGER(env, argv[2])) ||
8280 (! IS_INTEGER(env, argv[3])))
8281 return enif_make_badarg(env);
8282
8283 if (! a1ok)
8284 return esock_make_error_integer_range(env, argv[1]);
8285 if (! a2ok)
8286 return esock_make_error_integer_range(env, argv[2]);
8287 return
8288 esock_make_error_integer_range(env, argv[3]);
8289 }
8290
8291 bufSz = (ssize_t) eBufSz;
8292 if (eBufSz != (ErlNifUInt64) bufSz)
8293 return esock_make_error_integer_range(env, eBufSz);
8294
8295 ctrlSz = (ssize_t) eCtrlSz;
8296 if (eCtrlSz != (ErlNifUInt64) ctrlSz)
8297 return esock_make_error_integer_range(env, eCtrlSz);
8298
8299 MLOCK(descP->readMtx);
8300
8301 SSDBG( descP,
8302 ("SOCKET", "nif_recvmsg(%T), {%d,0x%X} ->"
8303 "\r\n recvRef: %T"
8304 "\r\n bufSz: %ld"
8305 "\r\n ctrlSz: %ld"
8306 "\r\n flags: 0x%X"
8307 "\r\n",
8308 sockRef, descP->sock, descP->readState,
8309 recvRef, (long) bufSz, (long) ctrlSz, flags) );
8310
8311 /* <KOLLA>
8312 *
8313 * We need to handle the case when another process tries
8314 * to receive at the same time.
8315 * If the current recv could not read its entire package
8316 * this time (resulting in an select). The read of the
8317 * other process must be made to wait until current
8318 * is done!
8319 * Basically, we need a read queue!
8320 *
8321 * A 'reading' field (boolean), which is set if we did
8322 * not manage to read the entire message and reset every
8323 * time we do.
8324 *
8325 * </KOLLA>
8326 */
8327
8328 res = esock_recvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags);
8329
8330 SSDBG( descP, ("SOCKET", "nif_recvmsg(%T) -> done"
8331 "\r\n", sockRef) );
8332
8333 MUNLOCK(descP->readMtx);
8334
8335 return res;
8336 #endif // #ifdef __WIN32__ #else
8337 }
8338
8339
8340 /* The (read) buffer handling *must* be optimized!
8341 * But for now we make it easy for ourselves by
8342 * allocating a binary (of the specified or default
8343 * size) and then throwing it away...
8344 */
8345 #ifndef __WIN32__
8346 static
esock_recvmsg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef,ssize_t bufLen,ssize_t ctrlLen,int flags)8347 ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
8348 ESockDescriptor* descP,
8349 ERL_NIF_TERM sockRef,
8350 ERL_NIF_TERM recvRef,
8351 ssize_t bufLen,
8352 ssize_t ctrlLen,
8353 int flags)
8354 {
8355 SOCKLEN_T addrLen;
8356 ssize_t read;
8357 int save_errno;
8358 size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz);
8359 size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz);
8360 struct msghdr msgHdr;
8361 struct iovec iov[1]; // Shall we always use 1?
8362 ErlNifBinary data[1]; // Shall we always use 1?
8363 ErlNifBinary ctrl;
8364 ERL_NIF_TERM readerCheck;
8365 ESockAddress addr;
8366
8367 SSDBG( descP, ("SOCKET", "esock_recvmsg {%d} -> entry with"
8368 "\r\n bufSz: %lu (%ld)"
8369 "\r\n ctrlSz: %ld (%ld)"
8370 "\r\n", descP->sock,
8371 (unsigned long) bufSz, (long) bufLen,
8372 (unsigned long) ctrlSz, (long) ctrlLen) );
8373
8374 if (! IS_OPEN(descP->readState))
8375 return esock_make_error(env, atom_closed);
8376
8377 /* Accept and Read uses the same select flag
8378 * so they can not be simultaneous
8379 */
8380 if (descP->currentAcceptorP != NULL)
8381 return esock_make_error_invalid(env, atom_state);
8382
8383 /* Ensure that we either have no current reader or that we are it,
8384 * or enqueue this process if there is a current reader */
8385 if (! recv_check_reader(env, descP, recvRef, &readerCheck)) {
8386 SSDBG( descP,
8387 ("SOCKET", "esock_recv {%d} -> reader check failed: "
8388 "\r\n %T\r\n", descP->sock, readerCheck) );
8389 return readerCheck;
8390 }
8391
8392 /*
8393 for (i = 0; i < sizeof(buf); i++) {
8394 ESOCK_ASSERT( ALLOC_BIN(bifSz, &buf[i]) );
8395 iov[i].iov_base = buf[i].data;
8396 iov[i].iov_len = buf[i].size;
8397 }
8398 */
8399
8400 /* Allocate the (msg) data buffer:
8401 */
8402 ESOCK_ASSERT( ALLOC_BIN(bufSz, &data[0]) );
8403
8404 /* Allocate the ctrl (buffer):
8405 */
8406 ESOCK_ASSERT( ALLOC_BIN(ctrlSz, &ctrl) );
8407
8408 ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
8409
8410 addrLen = sizeof(addr);
8411 sys_memzero((char*) &addr, addrLen);
8412 sys_memzero((char*) &msgHdr, sizeof(msgHdr));
8413
8414 iov[0].iov_base = data[0].data;
8415 iov[0].iov_len = data[0].size;
8416
8417 msgHdr.msg_name = &addr;
8418 msgHdr.msg_namelen = addrLen;
8419 msgHdr.msg_iov = iov;
8420 msgHdr.msg_iovlen = 1; // Should use a constant or calculate...
8421 msgHdr.msg_control = ctrl.data;
8422 msgHdr.msg_controllen = ctrl.size;
8423
8424 read = sock_recvmsg(descP->sock, &msgHdr, flags);
8425 if (ESOCK_IS_ERROR(read))
8426 save_errno = sock_errno();
8427 else
8428 save_errno = 0; // The value does not actually matter in this case
8429
8430 return recvmsg_check_result(env, descP, read, save_errno,
8431 &msgHdr,
8432 data, // Needed for iov encode
8433 &ctrl, // Needed for ctrl header encode
8434 sockRef, recvRef);
8435 }
8436 #endif // #ifndef __WIN32__
8437
8438
8439
8440 /* ----------------------------------------------------------------------
8441 * nif_close
8442 *
8443 * Description:
8444 * Close a (socket) file descriptor.
8445 *
8446 * Arguments:
8447 * Socket (ref) - Points to the socket descriptor.
8448 */
8449
8450 static
nif_close(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])8451 ERL_NIF_TERM nif_close(ErlNifEnv* env,
8452 int argc,
8453 const ERL_NIF_TERM argv[])
8454 {
8455 #ifdef __WIN32__
8456 return enif_raise_exception(env, MKA(env, "notsup"));
8457 #else
8458 ESockDescriptor* descP;
8459 ERL_NIF_TERM res;
8460
8461 ESOCK_ASSERT( argc == 1 );
8462
8463 SGDBG( ("SOCKET", "nif_close -> entry with argc: %d\r\n", argc) );
8464
8465 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
8466 return enif_make_badarg(env);
8467 }
8468
8469 MLOCK(descP->readMtx);
8470 MLOCK(descP->writeMtx);
8471
8472 SSDBG( descP,
8473 ("SOCKET", "nif_close(%T), {%d,0x%X}\r\n",
8474 argv[0], descP->sock, descP->readState) );
8475
8476 res = esock_close(env, descP);
8477
8478 MUNLOCK(descP->writeMtx);
8479 MUNLOCK(descP->readMtx);
8480
8481 SSDBG( descP, ("SOCKET", "nif_close(%T) -> done"
8482 "\r\n res: %T"
8483 "\r\n", argv[0], res) );
8484
8485 return res;
8486 #endif // #ifdef __WIN32__ #else
8487 }
8488
8489
8490 #ifndef __WIN32__
8491 static
esock_close(ErlNifEnv * env,ESockDescriptor * descP)8492 ERL_NIF_TERM esock_close(ErlNifEnv* env,
8493 ESockDescriptor* descP)
8494 {
8495 if (! IS_OPEN(descP->readState)) {
8496 /* A bit of cheeting; maybe not closed yet - do we need a queue? */
8497 return esock_make_error(env, atom_closed);
8498 }
8499
8500 /* Store the PID of the caller,
8501 * since we need to inform it when we
8502 * (that is, the stop callback function)
8503 * completes.
8504 */
8505 ESOCK_ASSERT( enif_self(env, &descP->closerPid) != NULL );
8506
8507 /* If the caller is not the owner; monitor the caller,
8508 * since we should complete this operation even if the caller dies
8509 * (for whatever reason).
8510 */
8511 if (COMPARE_PIDS(&descP->closerPid, &descP->ctrlPid) != 0) {
8512
8513 ESOCK_ASSERT( MONP("esock_close_check -> closer",
8514 env, descP,
8515 &descP->closerPid,
8516 &descP->closerMon) == 0 );
8517 }
8518
8519 /* Prepare for closing the socket */
8520 descP->readState |= ESOCK_STATE_CLOSING;
8521 descP->writeState |= ESOCK_STATE_CLOSING;
8522 if (esock_do_stop(env, descP)) {
8523 // esock_stop() has been scheduled - wait for it
8524 SSDBG( descP,
8525 ("SOCKET", "esock_close {%d} -> stop was scheduled\r\n",
8526 descP->sock) );
8527
8528 // Create closeRef for the close msg that esock_stop() will send
8529 descP->closeEnv = esock_alloc_env("esock_close_do - close-env");
8530 descP->closeRef = MKREF(descP->closeEnv);
8531
8532 return esock_make_ok2(env, CP_TERM(env, descP->closeRef));
8533 } else {
8534 // The socket may be closed - tell caller to finalize
8535 SSDBG( descP,
8536 ("SOCKET",
8537 "esock_close {%d} -> stop was called\r\n",
8538 descP->sock) );
8539
8540 return esock_atom_ok;
8541 }
8542 }
8543 #endif // #ifndef __WIN32__
8544
8545
8546 #ifndef __WIN32__
8547 /* Prepare for close - return whether stop is scheduled
8548 */
8549 static
esock_do_stop(ErlNifEnv * env,ESockDescriptor * descP)8550 BOOLEAN_T esock_do_stop(ErlNifEnv* env,
8551 ESockDescriptor* descP) {
8552 BOOLEAN_T ret;
8553 int sres;
8554 ERL_NIF_TERM sockRef;
8555
8556 sockRef = enif_make_resource(env, descP);
8557
8558 if (IS_SELECTED(descP)) {
8559 ESOCK_ASSERT( (sres = esock_select_stop(env, descP->sock, descP))
8560 >= 0 );
8561 if ((sres & ERL_NIF_SELECT_STOP_CALLED) != 0) {
8562 /* The socket is no longer known by the select machinery
8563 * - it may be closed
8564 */
8565 ret = FALSE;
8566 } else {
8567 ESOCK_ASSERT( (sres & ERL_NIF_SELECT_STOP_SCHEDULED) != 0 );
8568 /* esock_stop() is scheduled
8569 * - socket may be removed by esock_stop() or later
8570 */
8571 ret = TRUE;
8572 }
8573 } else {
8574 sres = 0;
8575 /* The socket has never been used in the select machinery
8576 * - it may be closed
8577 */
8578 ret = FALSE;
8579 }
8580
8581 /* +++++++ Current and waiting Writers +++++++ */
8582
8583 if (descP->currentWriterP != NULL) {
8584
8585 /* We have a current Writer; was it deselected?
8586 */
8587
8588 if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) {
8589
8590 /* The current Writer will not get a select message
8591 * - send it an abort message
8592 */
8593
8594 esock_stop_handle_current(env,
8595 "writer",
8596 descP, sockRef, &descP->currentWriter);
8597 }
8598
8599 /* Inform the waiting Writers (in the same way) */
8600
8601 SSDBG( descP,
8602 ("SOCKET",
8603 "esock_do_stop {%d} -> handle waiting writer(s)\r\n",
8604 descP->sock) );
8605
8606 inform_waiting_procs(env, "writer",
8607 descP, sockRef, &descP->writersQ, atom_closed);
8608
8609 descP->currentWriterP = NULL;
8610 }
8611
8612 /* +++++++ Connector +++++++
8613 * Note that there should not be Writers and a Connector
8614 * at the same time so the check for if the
8615 * current Writer/Connecter was deselected is only correct
8616 * under that assumption
8617 */
8618
8619 if (descP->connectorP != NULL) {
8620
8621 /* We have a Connector; was it deselected?
8622 */
8623
8624 if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) {
8625
8626 /* The Connector will not get a select message
8627 * - send it an abort message
8628 */
8629
8630 esock_stop_handle_current(env,
8631 "connector",
8632 descP, sockRef, &descP->connector);
8633 }
8634
8635 descP->connectorP = NULL;
8636 }
8637
8638 /* +++++++ Current and waiting Readers +++++++ */
8639
8640 if (descP->currentReaderP != NULL) {
8641
8642 /* We have a current Reader; was it deselected?
8643 */
8644
8645 if (sres & ERL_NIF_SELECT_READ_CANCELLED) {
8646
8647 /* The current Reader will not get a select message
8648 * - send it an abort message
8649 */
8650
8651 esock_stop_handle_current(env,
8652 "reader",
8653 descP, sockRef, &descP->currentReader);
8654 }
8655
8656 /* Inform the Readers (in the same way) */
8657
8658 SSDBG( descP,
8659 ("SOCKET",
8660 "esock_do_stop {%d} -> handle waiting reader(s)\r\n",
8661 descP->sock) );
8662
8663 inform_waiting_procs(env, "writer",
8664 descP, sockRef, &descP->readersQ, atom_closed);
8665
8666 descP->currentReaderP = NULL;
8667 }
8668
8669 /* +++++++ Current and waiting Acceptors +++++++
8670 *
8671 * Note that there should not be Readers and Acceptors
8672 * at the same time so the check for if the
8673 * current Reader/Acceptor was deselected is only correct
8674 * under that assumption
8675 */
8676
8677 if (descP->currentAcceptorP != NULL) {
8678
8679 /* We have a current Acceptor; was it deselected?
8680 */
8681
8682 if (sres & ERL_NIF_SELECT_READ_CANCELLED) {
8683
8684 /* The current Acceptor will not get a select message
8685 * - send it an abort message
8686 */
8687
8688 esock_stop_handle_current(env,
8689 "acceptor",
8690 descP, sockRef, &descP->currentAcceptor);
8691 }
8692
8693 /* Inform the waiting Acceptor (in the same way) */
8694
8695 SSDBG( descP,
8696 ("SOCKET",
8697 "esock_do_stop {%d} -> handle waiting acceptors(s)\r\n",
8698 descP->sock) );
8699
8700 inform_waiting_procs(env, "acceptor",
8701 descP, sockRef, &descP->acceptorsQ, atom_closed);
8702
8703 descP->currentAcceptorP = NULL;
8704 }
8705
8706 return ret;
8707 }
8708 #endif // #ifndef __WIN32__
8709
8710
8711
8712 /* ----------------------------------------------------------------------
8713 * nif_finalize_close
8714 *
8715 * Description:
8716 * Perform the actual socket close!
8717 * Note that this function is executed in a dirty scheduler.
8718 *
8719 * Arguments:
8720 * Socket (ref) - Points to the socket descriptor.
8721 */
8722 static
nif_finalize_close(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])8723 ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env,
8724 int argc,
8725 const ERL_NIF_TERM argv[])
8726 {
8727 ESockDescriptor* descP;
8728 ERL_NIF_TERM result;
8729 #ifdef __WIN32__
8730 return enif_raise_exception(env, MKA(env, "notsup"));
8731 #else
8732
8733 /* Extract arguments and perform preliminary validation */
8734
8735 ESOCK_ASSERT( argc == 1 );
8736
8737 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
8738 return enif_make_badarg(env);
8739 }
8740
8741 MLOCK(descP->readMtx);
8742 MLOCK(descP->writeMtx);
8743
8744 SSDBG( descP,
8745 ("SOCKET", "nif_finalize_close(%T), {%d,0x%X}\r\n",
8746 argv[0], descP->sock, descP->readState) );
8747
8748 result = esock_finalize_close(env, descP);
8749
8750 SSDBG( descP, ("SOCKET", "nif_finalize_close(%T) -> done with"
8751 "\r\n result: %T"
8752 "\r\n", argv[0], result) );
8753
8754 MUNLOCK(descP->writeMtx);
8755 MUNLOCK(descP->readMtx);
8756
8757 return result;
8758 #endif // #ifdef __WIN32__ #else
8759 }
8760
8761
8762 /* *** esock_finalize_close ***
8763 * Perform the final step in the socket close.
8764 */
8765 #ifndef __WIN32__
8766 static
esock_finalize_close(ErlNifEnv * env,ESockDescriptor * descP)8767 ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env,
8768 ESockDescriptor* descP)
8769 {
8770 int err;
8771 ErlNifPid self;
8772 #ifdef HAVE_SENDFILE
8773 HANDLE sendfileHandle;
8774 #endif
8775
8776 ESOCK_ASSERT( enif_self(env, &self) != NULL );
8777
8778 if (IS_CLOSED(descP->readState))
8779 return esock_make_error(env, atom_closed);
8780
8781 if (! IS_CLOSING(descP->readState)) {
8782 // esock_close() has not been called
8783 return esock_raise_invalid(env, atom_state);
8784 }
8785
8786 if (IS_SELECTED(descP) && (descP->closeEnv != NULL)) {
8787 // esock_stop() is scheduled but has not been called
8788 return esock_raise_invalid(env, atom_state);
8789 }
8790
8791 if (COMPARE_PIDS(&descP->closerPid, &self) != 0) {
8792 // This process is not the closer
8793 return esock_raise_invalid(env, atom_state);
8794 }
8795
8796 // Close the socket
8797
8798 /* Stop monitoring the closer.
8799 * Demonitoring may fail since this is a dirty NIF
8800 * - the caller may have died already.
8801 */
8802 enif_set_pid_undefined(&descP->closerPid);
8803 if (descP->closerMon.isActive) {
8804 (void) DEMONP("esock_finalize_close -> closer",
8805 env, descP, &descP->closerMon);
8806 }
8807
8808 /* Stop monitoring the owner */
8809 enif_set_pid_undefined(&descP->ctrlPid);
8810 (void) DEMONP("esock_finalize_close -> ctrl",
8811 env, descP, &descP->ctrlMon);
8812 /* Not impossible to still get a esock_down() call from a
8813 * just triggered owner monitor down
8814 */
8815
8816 #ifdef HAVE_SENDFILE
8817 sendfileHandle = descP->sendfileHandle;
8818 descP->sendfileHandle = INVALID_HANDLE;
8819 #endif
8820
8821 /* This nif is executed in a dirty scheduler just so that
8822 * it can "hang" (whith minumum effect on the VM) while the
8823 * kernel writes our buffers. IF we have set the linger option
8824 * for this ({true, integer() > 0}). For this to work we must
8825 * be blocking...
8826 */
8827 SET_BLOCKING(descP->sock);
8828 err = esock_close_socket(env, descP, TRUE);
8829
8830 #ifdef HAVE_SENDFILE
8831 if (sendfileHandle != INVALID_HANDLE) {
8832 (void) close(descP->sendfileHandle);
8833 }
8834 #endif
8835
8836 if (err != 0) {
8837 if (err == ERRNO_BLOCK) {
8838 /* Not all data in the buffers where sent,
8839 * make sure the caller gets this.
8840 */
8841 return esock_make_error(env, atom_timeout);
8842 } else {
8843 return esock_make_error_errno(env, err);
8844 }
8845 }
8846
8847 return esock_atom_ok;
8848 }
8849 #endif // #ifndef __WIN32__
8850
8851
8852 #ifndef __WIN32__
esock_close_socket(ErlNifEnv * env,ESockDescriptor * descP,BOOLEAN_T unlock)8853 static int esock_close_socket(ErlNifEnv* env,
8854 ESockDescriptor* descP,
8855 BOOLEAN_T unlock) {
8856 int err = 0;
8857 SOCKET sock = descP->sock;
8858 ERL_NIF_TERM sockRef;
8859
8860 /* This code follows Linux's advice to assume that after calling
8861 * close(2), the file descriptor may be reused, so assuming
8862 * that it can be used for anything such as retrying
8863 * to close is bad behaviour, although odd platforms
8864 * such as HP-UX requires a retry after EINTR
8865 */
8866
8867 /* First update the state so no other thread will try
8868 * to close the socket, then we will close it,
8869 * possibly when being scheduled in during
8870 * finalize_close
8871 */
8872 descP->sock = INVALID_SOCKET;
8873 descP->event = INVALID_EVENT;
8874 descP->readState |= ESOCK_STATE_CLOSED;
8875 descP->writeState |= ESOCK_STATE_CLOSED;
8876 dec_socket(descP->domain, descP->type, descP->protocol);
8877
8878 /* +++++++ Clear the meta option +++++++ */
8879 enif_clear_env(descP->meta.env);
8880 descP->meta.ref = esock_atom_undefined;
8881
8882 sock_close_event(descP->event);
8883 if (descP->closeOnClose) {
8884 if (unlock) {
8885 MUNLOCK(descP->writeMtx);
8886 MUNLOCK(descP->readMtx);
8887 }
8888 if (sock_close(sock) != 0)
8889 err = sock_errno();
8890 if (unlock) {
8891 MLOCK(descP->readMtx);
8892 MLOCK(descP->writeMtx);
8893 }
8894 }
8895
8896 if (err != 0) {
8897 SSDBG( descP,
8898 ("SOCKET", "esock_close_socket {%d} -> %d\r\n",
8899 sock, err) );
8900 }
8901
8902 /* (maybe) Update the registry */
8903 if (descP->useReg) {
8904 sockRef = enif_make_resource(env, descP);
8905 esock_send_reg_del_msg(env, descP, sockRef);
8906 }
8907
8908 return err;
8909 }
8910 #endif // #ifndef __WIN32__
8911
8912
8913 /* ----------------------------------------------------------------------
8914 * nif_shutdown
8915 *
8916 * Description:
8917 * Disable sends and/or receives on a socket.
8918 *
8919 * Arguments:
8920 * [0] Socket (ref) - Points to the socket descriptor.
8921 * [1] How - What will be shutdown.
8922 */
8923
8924 static
nif_shutdown(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])8925 ERL_NIF_TERM nif_shutdown(ErlNifEnv* env,
8926 int argc,
8927 const ERL_NIF_TERM argv[])
8928 {
8929 #ifdef __WIN32__
8930 return enif_raise_exception(env, MKA(env, "notsup"));
8931 #else
8932 ESockDescriptor* descP;
8933 ERL_NIF_TERM ehow, res;
8934 int how;
8935
8936 ESOCK_ASSERT( argc == 2 );
8937
8938 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
8939 return enif_make_badarg(env);
8940 }
8941 ehow = argv[1];
8942
8943 if (! ehow2how(ehow, &how))
8944 return esock_raise_invalid(env,
8945 MKT2(env, atom_how, ehow));
8946
8947 MLOCK(descP->readMtx);
8948 MLOCK(descP->writeMtx);
8949
8950 SSDBG( descP,
8951 ("SOCKET", "nif_shutdown(%T), {%d,0x%X} ->"
8952 "\r\n how: %d"
8953 "\r\n",
8954 argv[0], descP->sock, descP->readState | descP->writeState,
8955 how) );
8956
8957 res = esock_shutdown(env, descP, how);
8958
8959 MUNLOCK(descP->writeMtx);
8960 MUNLOCK(descP->readMtx);
8961
8962 SSDBG( descP, ("SOCKET", "nif_shutdown(%T) -> done with"
8963 "\r\n res: %T"
8964 "\r\n", argv[0], res) );
8965
8966 return res;
8967 #endif // #ifdef __WIN32__ #else
8968 }
8969
8970
8971
8972 #ifndef __WIN32__
8973 static
esock_shutdown(ErlNifEnv * env,ESockDescriptor * descP,int how)8974 ERL_NIF_TERM esock_shutdown(ErlNifEnv* env,
8975 ESockDescriptor* descP,
8976 int how)
8977 {
8978 if (! IS_OPEN(descP->readState))
8979 return esock_make_error(env, atom_closed);
8980
8981 if (sock_shutdown(descP->sock, how) == 0)
8982 return esock_atom_ok;
8983 else
8984 return esock_make_error_errno(env, sock_errno());
8985 }
8986 #endif // #ifndef __WIN32__
8987
8988
8989
8990 /* ----------------------------------------------------------------------
8991 * nif_setopt
8992 *
8993 * Description:
8994 * Set socket option.
8995 * It is possible to use a native mode value where we do not use
8996 * any assumption about how to encode the value but instead
8997 * use the value's type to select encoding.
8998 *
8999 * Arguments:
9000 * Socket (ref) - Points to the socket descriptor.
9001 * Level - Level of the socket option.
9002 * Opt - The socket option.
9003 * Value - Value of the socket option.
9004 * NativeValue - If 0 Value type has to match our encoding function,
9005 * if not 0 type selects encoding.
9006 */
9007
9008 static
nif_setopt(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])9009 ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
9010 int argc,
9011 const ERL_NIF_TERM argv[])
9012 {
9013 #ifdef __WIN32__
9014 return enif_raise_exception(env, MKA(env, "notsup"));
9015 #else
9016 ESockDescriptor* descP = NULL;
9017 int level, opt, nativeValue;
9018 ERL_NIF_TERM eVal;
9019
9020 ESOCK_ASSERT( argc == 5 );
9021
9022 SGDBG( ("SOCKET", "nif_setopt -> entry with argc: %d\r\n", argc) );
9023
9024 /* Extract arguments and perform preliminary validation */
9025
9026 if ((! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) ||
9027 (! GET_INT(env, argv[4], &nativeValue))) {
9028 //
9029 SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") );
9030 return enif_make_badarg(env);
9031 }
9032 if (! GET_INT(env, argv[2], &opt)) {
9033 SSDBG( descP,
9034 ("SOCKET", "nif_setopt -> failed initial arg check\r\n") );
9035 if (! IS_INTEGER(env, argv[2]))
9036 return enif_make_badarg(env);
9037 else
9038 return esock_make_error_integer_range(env, argv[2]);
9039 }
9040 eVal = argv[3];
9041
9042 if (esock_decode_level(env, argv[1], &level)) {
9043 if (nativeValue == 0)
9044 return esock_setopt(env, descP, level, opt, eVal);
9045 else
9046 return esock_setopt_native(env, descP, level, opt, eVal);
9047 }
9048
9049 if (COMPARE(argv[1], atom_otp) == 0) {
9050 if (nativeValue == 0) {
9051 return esock_setopt_otp(env, descP, opt, eVal);
9052 } else {
9053 SSDBG( descP, ("SOCKET", "nif_setopt -> failed arg check\r\n") );
9054 return enif_make_badarg(env);
9055 }
9056 }
9057
9058 SGDBG( ("SOCKET", "nif_setopt -> failed arg check\r\n") );
9059
9060 if (IS_INTEGER(env, argv[1]))
9061 return esock_make_error_integer_range(env, argv[1]);
9062 else
9063 return enif_make_badarg(env);
9064 #endif // #ifdef __WIN32__ #else
9065 }
9066
9067
9068 /* esock_setopt_otp - Handle OTP (level) options
9069 */
9070 #ifndef __WIN32__
9071 static
esock_setopt_otp(ErlNifEnv * env,ESockDescriptor * descP,int eOpt,ERL_NIF_TERM eVal)9072 ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
9073 ESockDescriptor* descP,
9074 int eOpt,
9075 ERL_NIF_TERM eVal)
9076 {
9077 ERL_NIF_TERM result;
9078
9079 switch (eOpt) {
9080 case ESOCK_OPT_OTP_DEBUG:
9081 MLOCK(descP->readMtx);
9082 MLOCK(descP->writeMtx);
9083 result = esock_setopt_otp_debug(env, descP, eVal);
9084 MUNLOCK(descP->writeMtx);
9085 MUNLOCK(descP->readMtx);
9086 break;
9087
9088 case ESOCK_OPT_OTP_IOW:
9089 MLOCK(descP->readMtx);
9090 MLOCK(descP->writeMtx);
9091 result = esock_setopt_otp_iow(env, descP, eVal);
9092 MUNLOCK(descP->writeMtx);
9093 MUNLOCK(descP->readMtx);
9094 break;
9095
9096 case ESOCK_OPT_OTP_CTRL_PROC:
9097 MLOCK(descP->readMtx);
9098 MLOCK(descP->writeMtx);
9099 result = esock_setopt_otp_ctrl_proc(env, descP, eVal);
9100 MUNLOCK(descP->writeMtx);
9101 MUNLOCK(descP->readMtx);
9102 break;
9103
9104 case ESOCK_OPT_OTP_RCVBUF:
9105 MLOCK(descP->readMtx);
9106 result = esock_setopt_otp_rcvbuf(env, descP, eVal);
9107 MUNLOCK(descP->readMtx);
9108 break;
9109
9110 case ESOCK_OPT_OTP_RCVCTRLBUF:
9111 MLOCK(descP->readMtx);
9112 result = esock_setopt_otp_rcvctrlbuf(env, descP, eVal);
9113 MUNLOCK(descP->readMtx);
9114 break;
9115
9116 case ESOCK_OPT_OTP_SNDCTRLBUF:
9117 MLOCK(descP->writeMtx);
9118 result = esock_setopt_otp_sndctrlbuf(env, descP, eVal);
9119 MUNLOCK(descP->writeMtx);
9120 break;
9121
9122 case ESOCK_OPT_OTP_META:
9123 MLOCK(descP->writeMtx);
9124 result = esock_setopt_otp_meta(env, descP, eVal);
9125 MUNLOCK(descP->writeMtx);
9126 break;
9127
9128 case ESOCK_OPT_OTP_USE_REGISTRY:
9129 MLOCK(descP->writeMtx);
9130 result = esock_setopt_otp_use_registry(env, descP, eVal);
9131 MUNLOCK(descP->writeMtx);
9132 break;
9133
9134 default:
9135 MLOCK(descP->writeMtx);
9136 SSDBG( descP,
9137 ("SOCKET", "esock_setopt_otp {%d} -> invalid with"
9138 "\r\n eOpt: %d"
9139 "\r\n eVal: %T"
9140 "\r\n", descP->sock, eOpt, eVal) );
9141 MUNLOCK(descP->writeMtx);
9142
9143 /* This is an internal error - prim_inet gave us junk */
9144 result =
9145 esock_raise_invalid(env,
9146 MKT2(env,
9147 atom_otp_socket_option,
9148 MKI(env, eOpt)));
9149 break;
9150 }
9151
9152 return result;
9153 }
9154 #endif // #ifndef __WIN32__
9155
9156
9157
9158 /* esock_setopt_otp_debug - Handle the OTP (level) debug options
9159 */
9160 #ifndef __WIN32__
9161 static
esock_setopt_otp_debug(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9162 ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env,
9163 ESockDescriptor* descP,
9164 ERL_NIF_TERM eVal)
9165 {
9166 if (! IS_OPEN(descP->writeState)) {
9167 SSDBG( descP,
9168 ("SOCKET", "esock_setopt_otp_debug {%d} -> closed\r\n",
9169 descP->sock) );
9170 return esock_make_error(env, atom_closed);
9171 }
9172
9173 if (! esock_decode_bool(eVal, &descP->dbg))
9174 return esock_make_invalid(env, atom_value);
9175
9176 SSDBG( descP,
9177 ("SOCKET", "esock_setopt_otp_debug {%d} -> ok"
9178 "\r\n eVal: %T"
9179 "\r\n", descP->sock, eVal) );
9180
9181 return esock_atom_ok;
9182 }
9183 #endif // #ifndef __WIN32__
9184
9185
9186 /* esock_setopt_otp_iow - Handle the OTP (level) iow options
9187 */
9188 #ifndef __WIN32__
9189 static
esock_setopt_otp_iow(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9190 ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env,
9191 ESockDescriptor* descP,
9192 ERL_NIF_TERM eVal)
9193 {
9194 if (! IS_OPEN(descP->writeState)) {
9195 SSDBG( descP,
9196 ("SOCKET", "esock_setopt_otp_iow {%d} -> closed\r\n",
9197 descP->sock) );
9198 return esock_make_error(env, atom_closed);
9199 }
9200
9201 if (! esock_decode_bool(eVal, &descP->iow))
9202 return esock_make_invalid(env, atom_value);
9203
9204 SSDBG( descP,
9205 ("SOCKET", "esock_setopt_otp_iow {%d} -> ok"
9206 "\r\n eVal: %T"
9207 "\r\n", descP->sock, eVal) );
9208
9209 return esock_atom_ok;
9210 }
9211 #endif // #ifndef __WIN32__
9212
9213
9214 /* esock_setopt_otp_ctrl_proc - Handle the OTP (level)
9215 * controlling_process options
9216 */
9217 #ifndef __WIN32__
9218 static
esock_setopt_otp_ctrl_proc(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9219 ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env,
9220 ESockDescriptor* descP,
9221 ERL_NIF_TERM eVal)
9222 {
9223 ErlNifPid caller, newCtrlPid;
9224 int xres;
9225
9226 SSDBG( descP,
9227 ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> entry"
9228 "\r\n eVal: %T"
9229 "\r\n", descP->sock, eVal) );
9230
9231 if (! IS_OPEN(descP->writeState)) {
9232 SSDBG( descP,
9233 ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> closed\r\n",
9234 descP->sock) );
9235 return esock_make_error(env, atom_closed);
9236 }
9237
9238 /* Ensure that caller is (current) controlling process */
9239 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
9240 if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) {
9241 SSDBG( descP, ("SOCKET",
9242 "esock_setopt_otp_ctrl_proc -> not owner (%T)\r\n",
9243 descP->ctrlPid) );
9244 return esock_make_error_invalid(env, esock_atom_not_owner);
9245 }
9246
9247 /* Ensure that the new controller is a local process */
9248 if (!GET_LPID(env, eVal, &newCtrlPid)) {
9249 esock_warning_msg("Failed get pid of new controlling process\r\n");
9250 return esock_make_invalid(env, atom_value);
9251 }
9252
9253 if ((xres = DEMONP("esock_setopt_otp_ctrl_proc -> (old) ctrl",
9254 env, descP, &descP->ctrlMon)) != 0) {
9255 /* There is a legitimate reason for this is; the current
9256 * process was just killed from a different thread
9257 */
9258 esock_warning_msg("Failed demonitor (%d) "
9259 "old controlling process %T (%T)\r\n",
9260 xres, descP->ctrlPid, descP->ctrlMon);
9261 }
9262
9263 descP->ctrlPid = newCtrlPid;
9264
9265 if ((xres =
9266 MONP("esock_setopt_otp_ctrl_proc -> (new) ctrl",
9267 env, descP, &descP->ctrlPid, &descP->ctrlMon)) != 0) {
9268
9269 ESOCK_ASSERT( 0 < xres );
9270 /* Indicates that we do not have a DOWN callback,
9271 * which is preposterous
9272 */
9273
9274 /* We know newCtrlPid is not 'undefined' so
9275 * it must be dead already
9276 * - pretend the controlling process change went well
9277 * and then the monitor went down
9278 */
9279 SSDBG( descP,
9280 ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> DOWN"
9281 "\r\n xres: %d"
9282 "\r\n", descP->sock, xres) );
9283
9284 enif_set_pid_undefined(&descP->ctrlPid);
9285
9286 esock_down_ctrl(env, descP, &newCtrlPid);
9287
9288 descP->readState |= ESOCK_STATE_CLOSING;
9289 descP->writeState |= ESOCK_STATE_CLOSING;
9290
9291 } else {
9292 SSDBG( descP,
9293 ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> ok"
9294 "\r\n", descP->sock) );
9295 }
9296
9297 return esock_atom_ok;
9298 }
9299 #endif // #ifndef __WIN32__
9300
9301
9302 /* esock_setopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
9303 * The (otp) rcvbuf option is provided as:
9304 *
9305 * BufSz :: default | pos_integer() |
9306 * {N :: pos_integer(), Sz :: default | pos_integer()}
9307 *
9308 * Where N is the max number of reads.
9309 */
9310 #ifndef __WIN32__
9311 static
esock_setopt_otp_rcvbuf(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9312 ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env,
9313 ESockDescriptor* descP,
9314 ERL_NIF_TERM eVal)
9315 {
9316 const ERL_NIF_TERM* t; // The array of the elements of the tuple
9317 int tsz; // The size of the tuple - should be 2
9318 unsigned int n;
9319 size_t bufSz;
9320 ssize_t z;
9321
9322 SSDBG( descP,
9323 ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> entry"
9324 "\r\n eVal: %T"
9325 "\r\n", descP->sock, eVal) );
9326
9327 if (! IS_OPEN(descP->readState)) {
9328 SSDBG( descP,
9329 ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> done closed\r\n",
9330 descP->sock) );
9331 return esock_make_error(env, atom_closed);
9332 }
9333
9334 if (esock_decode_bufsz(env,
9335 eVal,
9336 ESOCK_RECV_BUFFER_SIZE_DEFAULT,
9337 &bufSz)) {
9338 n = 0; // Reported as an integer buffer size by getopt
9339 } else {
9340 if ((! GET_TUPLE(env, eVal, &tsz, &t)) ||
9341 (tsz != 2) ||
9342 (! GET_UINT(env, t[0], &n)) ||
9343 (n == 0) ||
9344 (! esock_decode_bufsz(env, t[1],
9345 ESOCK_RECV_BUFFER_SIZE_DEFAULT,
9346 &bufSz))) {
9347 SSDBG( descP,
9348 ("SOCKET",
9349 "esock_setopt_otp_rcvbuf {%d} -> done invalid\r\n",
9350 descP->sock) );
9351 return esock_make_invalid(env, atom_value);
9352 }
9353 }
9354 // We do not want a buffer size that does not fit in ssize_t
9355 z = bufSz;
9356 if (bufSz != (size_t) z)
9357 return esock_make_invalid(env, atom_value);
9358
9359 descP->rNum = n;
9360 descP->rBufSz = bufSz;
9361
9362 SSDBG( descP,
9363 ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> ok"
9364 "\r\n", descP->sock) );
9365
9366 return esock_atom_ok;
9367 }
9368 #endif // #ifndef __WIN32__
9369
9370
9371 /* esock_setopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
9372 */
9373 #ifndef __WIN32__
9374 static
esock_setopt_otp_rcvctrlbuf(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9375 ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env,
9376 ESockDescriptor* descP,
9377 ERL_NIF_TERM eVal)
9378 {
9379 size_t val;
9380
9381 SSDBG( descP,
9382 ("SOCKET", "esock_setopt_otp_recvctrlbuf {%d} -> entry"
9383 "\r\n eVal: %T"
9384 "\r\n", descP->sock, eVal) );
9385
9386 if (! IS_OPEN(descP->readState)) {
9387 SSDBG( descP,
9388 ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> done closed\r\n",
9389 descP->sock) );
9390 return esock_make_error(env, atom_closed);
9391 }
9392
9393 if (! esock_decode_bufsz(env,
9394 eVal,
9395 ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT,
9396 &val)) {
9397 SSDBG( descP,
9398 ("SOCKET",
9399 "esock_setopt_otp_rcvctrlbuf {%d} -> done invalid\r\n",
9400 descP->sock) );
9401 return esock_make_invalid(env, atom_value);
9402 }
9403
9404 descP->rCtrlSz = val;
9405
9406 SSDBG( descP,
9407 ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> ok"
9408 "\r\n", descP->sock) );
9409
9410 return esock_atom_ok;
9411 }
9412 #endif // #ifndef __WIN32__
9413
9414
9415 /* esock_setopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
9416 */
9417 #ifndef __WIN32__
9418 static
esock_setopt_otp_sndctrlbuf(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9419 ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env,
9420 ESockDescriptor* descP,
9421 ERL_NIF_TERM eVal)
9422 {
9423 size_t val;
9424
9425 SSDBG( descP,
9426 ("SOCKET", "esock_setopt_otp_sndvctrlbuf {%d} -> entry"
9427 "\r\n eVal: %T"
9428 "\r\n", descP->sock, eVal) );
9429
9430 if (! IS_OPEN(descP->writeState)) {
9431 SSDBG( descP,
9432 ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> done closed\r\n",
9433 descP->sock) );
9434 return esock_make_error(env, atom_closed);
9435 }
9436
9437 if (! esock_decode_bufsz(env,
9438 eVal,
9439 ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT,
9440 &val)) {
9441 SSDBG( descP,
9442 ("SOCKET",
9443 "esock_setopt_otp_sndctrlbuf {%d} -> done invalid\r\n",
9444 descP->sock) );
9445 return esock_make_invalid(env, atom_value);
9446 }
9447
9448 descP->wCtrlSz = val;
9449
9450 SSDBG( descP,
9451 ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> ok"
9452 "\r\n", descP->sock) );
9453
9454 return esock_atom_ok;
9455 }
9456 #endif // #ifndef __WIN32__
9457
9458
9459 /* esock_setopt_otp_meta - Handle the OTP (level) meta options
9460 */
9461 #ifndef __WIN32__
9462 static
esock_setopt_otp_meta(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9463 ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env,
9464 ESockDescriptor* descP,
9465 ERL_NIF_TERM eVal)
9466 {
9467 ErlNifPid caller;
9468
9469 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
9470
9471 SSDBG( descP,
9472 ("SOCKET", "esock_setopt_otp_meta {%d} -> entry"
9473 "\r\n eVal: %T"
9474 "\r\n", descP->sock, eVal) );
9475
9476 if (! IS_OPEN(descP->writeState)) {
9477 SSDBG( descP,
9478 ("SOCKET", "esock_setopt_otp_meta {%d} -> done closed\r\n",
9479 descP->sock) );
9480 return esock_make_error(env, atom_closed);
9481 }
9482
9483 if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) {
9484 SSDBG( descP, ("SOCKET",
9485 "esock_setopt_otp_meta -> not owner (%T)\r\n",
9486 descP->ctrlPid) );
9487 return esock_make_error_invalid(env, esock_atom_not_owner);
9488 }
9489
9490 enif_clear_env(descP->meta.env);
9491 descP->meta.ref = CP_TERM(descP->meta.env, eVal);
9492
9493 SSDBG( descP,
9494 ("SOCKET", "esock_setopt_otp_meta {%d} -> ok"
9495 "\r\n", descP->sock) );
9496
9497 return esock_atom_ok;
9498 }
9499 #endif // #ifndef __WIN32__
9500
9501
9502 /* esock_setopt_otp_use_registry - Handle the OTP (level) use_registry option
9503 */
9504 #ifndef __WIN32__
9505 static
esock_setopt_otp_use_registry(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eVal)9506 ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env,
9507 ESockDescriptor* descP,
9508 ERL_NIF_TERM eVal)
9509 {
9510 BOOLEAN_T useReg = FALSE;
9511
9512 if (! IS_OPEN(descP->writeState)) {
9513 SSDBG( descP,
9514 ("SOCKET", "esock_setopt_otp_use_registry {%d} -> closed\r\n",
9515 descP->sock) );
9516 return esock_make_error(env, atom_closed);
9517 }
9518
9519 if (! esock_decode_bool(eVal, &useReg))
9520 return esock_make_invalid(env, atom_value);
9521
9522 /* We only allow turning this on! */
9523 if (! useReg)
9524 return esock_make_invalid(env, atom_value);
9525
9526 if (!descP->useReg) {
9527 ERL_NIF_TERM sockRef = enif_make_resource(env, descP);
9528
9529 descP->useReg = useReg;
9530 esock_send_reg_add_msg(env, descP, sockRef);
9531 }
9532
9533 SSDBG( descP,
9534 ("SOCKET", "esock_setopt_otp_use_registry {%d} -> ok"
9535 "\r\n eVal: %T"
9536 "\r\n", descP->sock, eVal) );
9537
9538 return esock_atom_ok;
9539 }
9540 #endif // #ifndef __WIN32__
9541
9542
9543 /* The option has *not* been encoded. Instead it has been provided
9544 * in "native mode" (value is a binary, an integer or a boolean).
9545 */
9546 #ifndef __WIN32__
9547 static
esock_setopt_native(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9548 ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env,
9549 ESockDescriptor* descP,
9550 int level,
9551 int opt,
9552 ERL_NIF_TERM eVal)
9553 {
9554 ErlNifBinary binary;
9555 int integer;
9556 BOOLEAN_T boolean;
9557 ERL_NIF_TERM result;
9558
9559 MLOCK(descP->writeMtx);
9560
9561 SSDBG( descP,
9562 ("SOCKET", "esock_setopt_native {%d} -> entry"
9563 "\r\n level: %d"
9564 "\r\n opt: %d"
9565 "\r\n eVal: %T"
9566 "\r\n", descP->sock,
9567 level, opt, eVal) );
9568
9569 if (! IS_OPEN(descP->writeState)) {
9570 SSDBG( descP,
9571 ("SOCKET", "esock_setopt_native {%d} -> done closed\r\n",
9572 descP->sock) );
9573
9574 MUNLOCK(descP->writeMtx);
9575 return esock_make_error(env, atom_closed);
9576 }
9577
9578 if (GET_BIN(env, eVal, &binary)) {
9579 result = esock_setopt_level_opt(env, descP, level, opt,
9580 binary.data, binary.size);
9581 } else if (GET_INT(env, eVal, &integer)) {
9582 result = esock_setopt_level_opt(env, descP, level, opt,
9583 &integer, sizeof(integer));
9584 } else if (esock_decode_bool(eVal, &boolean)) {
9585 integer = boolean ? 1 : 0;
9586 result = esock_setopt_level_opt(env, descP, level, opt,
9587 &integer, sizeof(integer));
9588 } else {
9589 result = esock_make_error_invalid(env, atom_value);
9590 }
9591
9592 SSDBG( descP,
9593 ("SOCKET", "esock_setopt_native {%d} -> done when"
9594 "\r\n result: %T"
9595 "\r\n", descP->sock, result) );
9596
9597 MUNLOCK(descP->writeMtx);
9598 return result;
9599 }
9600 #endif // #ifndef __WIN32__
9601
9602
9603 /* esock_setopt - A "proper" level (option) has been specified,
9604 * and we have an value of known encoding
9605 */
9606 #ifndef __WIN32__
9607 static
esock_setopt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9608 ERL_NIF_TERM esock_setopt(ErlNifEnv* env,
9609 ESockDescriptor* descP,
9610 int level,
9611 int opt,
9612 ERL_NIF_TERM eVal)
9613 {
9614 ERL_NIF_TERM result;
9615 const struct ESockOpt *optP;
9616
9617 MLOCK(descP->writeMtx);
9618
9619 SSDBG( descP,
9620 ("SOCKET", "esock_setopt {%d} -> entry with"
9621 "\r\n level: %d"
9622 "\r\n opt: %d"
9623 "\r\n eVal: %T"
9624 "\r\n", descP->sock, level, opt, eVal) );
9625
9626 if (! IS_OPEN(descP->writeState)) {
9627 SSDBG( descP,
9628 ("SOCKET", "esock_setopt {%d} -> done closed\r\n",
9629 descP->sock) );
9630
9631 MUNLOCK(descP->writeMtx);
9632 return esock_make_error(env, atom_closed);
9633 }
9634
9635 optP = lookupOpt(level, opt);
9636
9637 if (optP == NULL) {
9638
9639 result = esock_make_invalid(env, atom_socket_option);
9640
9641 SSDBG( descP,
9642 ("SOCKET",
9643 "esock_setopt {%d} -> unknown option\r\n",
9644 descP->sock) );
9645
9646 } else if (optP->setopt == NULL) {
9647
9648 result = esock_make_invalid(env, atom_socket_option);
9649
9650 SSDBG( descP,
9651 ("SOCKET",
9652 "esock_setopt {%d} -> opt not settable\r\n",
9653 descP->sock) );
9654
9655 } else {
9656
9657 result = (optP->setopt)(env, descP, level, opt, eVal);
9658
9659 SSDBG( descP,
9660 ("SOCKET", "esock_setopt {%d} -> done when"
9661 "\r\n result: %T"
9662 "\r\n", descP->sock, result) );
9663 }
9664
9665 MUNLOCK(descP->writeMtx);
9666 return result;
9667 }
9668 #endif // #ifndef __WIN32__
9669
9670
9671 #ifndef __WIN32__
9672 #if defined(SO_BINDTODEVICE)
9673 static
esock_setopt_so_bindtodevice(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9674 ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env,
9675 ESockDescriptor* descP,
9676 int level,
9677 int opt,
9678 ERL_NIF_TERM eVal)
9679 {
9680 return esock_setopt_str_opt(env, descP, level, opt, IFNAMSIZ, eVal);
9681 }
9682 #endif
9683 #endif // #ifndef __WIN32__
9684
9685
9686 #ifndef __WIN32__
9687 #if defined(SO_LINGER)
9688 static
esock_setopt_linger(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9689 ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env,
9690 ESockDescriptor* descP,
9691 int level,
9692 int opt,
9693 ERL_NIF_TERM eVal)
9694 {
9695 ERL_NIF_TERM eOnOff, eLinger;
9696 BOOLEAN_T onOff;
9697 struct linger val;
9698
9699 sys_memzero(&val, sizeof(val));
9700
9701 if ((! GET_MAP_VAL(env, eVal, atom_onoff, &eOnOff)) ||
9702 (! GET_MAP_VAL(env, eVal, esock_atom_linger, &eLinger))) {
9703
9704 if (COMPARE(eVal, esock_atom_abort) == 0) {
9705 val.l_onoff = 1;
9706 val.l_linger = 0;
9707 return esock_setopt_level_opt(env, descP, level, opt,
9708 &val, sizeof(val));
9709 } else
9710 return esock_make_invalid(env, atom_value);
9711 }
9712
9713 if ((! esock_decode_bool(eOnOff, &onOff)) ||
9714 (! GET_INT(env, eLinger, &val.l_linger)) ||
9715 (val.l_linger < 0)) {
9716 return esock_make_invalid(env, atom_value);
9717 }
9718 val.l_onoff = onOff ? 1 : 0;
9719
9720 return esock_setopt_level_opt(env, descP, level, opt,
9721 &val, sizeof(val));
9722 }
9723 #endif
9724 #endif // #ifndef __WIN32__
9725
9726
9727
9728 #ifndef __WIN32__
9729 #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
9730
9731 /* esock_setopt_msfilter - Level IP MSFILTER option
9732 *
9733 * The value can be *either* the atom 'null' or a map of type ip_msfilter().
9734 */
9735 static
esock_setopt_msfilter(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9736 ERL_NIF_TERM esock_setopt_msfilter(ErlNifEnv* env,
9737 ESockDescriptor* descP,
9738 int level,
9739 int opt,
9740 ERL_NIF_TERM eVal)
9741 {
9742 ERL_NIF_TERM result;
9743
9744 if (COMPARE(eVal, atom_null) == 0) {
9745 return
9746 esock_setopt_level_opt(env, descP, level, opt, NULL, 0);
9747 } else {
9748 struct ip_msfilter* msfP;
9749 Uint32 msfSz;
9750 ERL_NIF_TERM eMultiAddr, eInterface, eFMode, eSList, elem, tail;
9751 unsigned int slistLen, idx;
9752
9753 if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) ||
9754 (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) ||
9755 (! GET_MAP_VAL(env, eVal, atom_mode, &eFMode)) ||
9756 (! GET_MAP_VAL(env, eVal, atom_slist, &eSList)))
9757 goto invalid;
9758
9759 /* We start (decoding) with the slist, since without it we don't
9760 * really know how much (memory) to allocate.
9761 */
9762 if (! GET_LIST_LEN(env, eSList, &slistLen))
9763 goto invalid;
9764
9765 msfSz = IP_MSFILTER_SIZE(slistLen);
9766 msfP = MALLOC(msfSz);
9767 ESOCK_ASSERT( msfP != NULL );
9768
9769 if ((! esock_decode_in_addr(env, eMultiAddr,
9770 &msfP->imsf_multiaddr)) ||
9771 (! esock_decode_in_addr(env, eInterface,
9772 &msfP->imsf_interface)) ||
9773 (! decode_msfilter_mode(env, eFMode,
9774 (Uint32*) &msfP->imsf_fmode)))
9775 goto free_invalid;
9776
9777 /* And finally, extract the source addresses */
9778 msfP->imsf_numsrc = slistLen;
9779 for (idx = 0; idx < slistLen; idx++) {
9780 ESOCK_ASSERT( GET_LIST_ELEM(env, eSList, &elem, &tail) );
9781 if (! esock_decode_in_addr(env, elem,
9782 &msfP->imsf_slist[idx]))
9783 goto free_invalid;
9784 eSList = tail;
9785 }
9786
9787 /* And now, finally, set the option */
9788 result = esock_setopt_level_opt(env, descP, level, opt,
9789 msfP, msfSz);
9790
9791 FREE(msfP);
9792 return result;
9793
9794 free_invalid:
9795 FREE(msfP);
9796 invalid:
9797 return esock_make_invalid(env, atom_value);
9798 }
9799
9800 }
9801
9802 static
decode_msfilter_mode(ErlNifEnv * env,ERL_NIF_TERM eVal,Uint32 * mode)9803 BOOLEAN_T decode_msfilter_mode(ErlNifEnv* env,
9804 ERL_NIF_TERM eVal,
9805 Uint32* mode)
9806 {
9807 BOOLEAN_T result;
9808
9809 if (COMPARE(eVal, atom_include) == 0) {
9810 *mode = MCAST_INCLUDE;
9811 result = TRUE;
9812 } else if (COMPARE(eVal, atom_exclude) == 0) {
9813 *mode = MCAST_EXCLUDE;
9814 result = TRUE;
9815 } else {
9816 result = FALSE;
9817 }
9818
9819 return result;
9820 }
9821
9822 #endif // #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
9823 #endif // #ifndef __WIN32__
9824
9825
9826 /* esock_setopt_ip_mtu_discover - Level IP MTU_DISCOVER option
9827 *
9828 * The value is an atom of the type ip_pmtudisc().
9829 */
9830 #ifndef __WIN32__
9831 #if defined(IP_MTU_DISCOVER)
9832 static
esock_setopt_ip_mtu_discover(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9833 ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env,
9834 ESockDescriptor* descP,
9835 int level,
9836 int opt,
9837 ERL_NIF_TERM eVal)
9838 {
9839 int val;
9840
9841 if (! decode_ip_pmtudisc(env, eVal, &val))
9842 return esock_make_invalid(env, atom_value);
9843 else
9844 return esock_setopt_level_opt(env, descP, level, opt,
9845 &val, sizeof(val));
9846 }
9847 #endif // #if defined(IP_MTU_DISCOVER)
9848 #endif // #ifndef __WIN32__
9849
9850
9851
9852 /* esock_setopt_multicast_if - Level IP MULTICAST_IF option
9853 *
9854 * The value is either the atom 'any' or a 4-tuple.
9855 */
9856 #ifndef __WIN32__
9857 #if defined(IP_MULTICAST_IF)
9858 static
esock_setopt_multicast_if(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9859 ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env,
9860 ESockDescriptor* descP,
9861 int level,
9862 int opt,
9863 ERL_NIF_TERM eVal)
9864 {
9865 ERL_NIF_TERM result;
9866 struct in_addr ifAddr;
9867
9868 if (! esock_decode_in_addr(env, eVal, &ifAddr)) {
9869 result = esock_make_invalid(env, atom_value);
9870 } else {
9871 result =
9872 esock_setopt_level_opt(env, descP, level, opt,
9873 &ifAddr, sizeof(ifAddr));
9874 }
9875
9876 return result;
9877 }
9878 #endif
9879 #endif // #ifndef __WIN32__
9880
9881 /* esock_setopt_tos - Level IP TOS option
9882 */
9883 #ifndef __WIN32__
9884 #if defined(IP_TOS)
9885 static
esock_setopt_tos(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9886 ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env,
9887 ESockDescriptor* descP,
9888 int level,
9889 int opt,
9890 ERL_NIF_TERM eVal)
9891 {
9892 ERL_NIF_TERM result;
9893 int val;
9894
9895 if (decode_ip_tos(env, eVal, &val)) {
9896 result =
9897 esock_setopt_level_opt(env, descP, level, opt,
9898 &val, sizeof(val));
9899 } else {
9900 result = esock_make_invalid(env, atom_value);
9901 }
9902
9903 return result;
9904 }
9905 #endif
9906 #endif // #ifndef __WIN32__
9907
9908
9909
9910
9911 /* The value is a map with two attributes: multiaddr and interface.
9912 * The attribute 'multiaddr' is always a 4-tuple (IPv4 address).
9913 * The attribute 'interface' is either the atom 'any' or a 4-tuple
9914 * (IPv4 address).
9915 */
9916 #ifndef __WIN32__
9917 #if defined(IP_ADD_MEMBERSHIP) || defined(IP_DROP_MEMBERSHIP)
9918 static
esock_setopt_in_update_membership(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9919 ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env,
9920 ESockDescriptor* descP,
9921 int level,
9922 int opt,
9923 ERL_NIF_TERM eVal)
9924 {
9925 ERL_NIF_TERM eMultiAddr, eInterface;
9926 struct ip_mreq mreq;
9927
9928 if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) {
9929 SSDBG( descP,
9930 ("SOCKET", "esock_setopt_in_update_membership -> "
9931 "failed get multiaddr (map) attribute\r\n") );
9932 goto invalid;
9933 }
9934
9935 if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) {
9936 SSDBG( descP,
9937 ("SOCKET", "esock_setopt_in_update_membership -> "
9938 "failed get interface (map) attribute\r\n") );
9939 goto invalid;
9940 }
9941
9942 if (! esock_decode_in_addr(env,
9943 eMultiAddr,
9944 &mreq.imr_multiaddr)) {
9945 SSDBG( descP,
9946 ("SOCKET", "esock_setopt_in_update_membership -> "
9947 "failed decode multiaddr %T\r\n", eMultiAddr) );
9948 goto invalid;
9949 }
9950
9951 if (! esock_decode_in_addr(env,
9952 eInterface,
9953 &mreq.imr_interface)) {
9954 SSDBG( descP,
9955 ("SOCKET", "esock_setopt_in_update_membership -> "
9956 "failed decode interface %T\r\n", eInterface) );
9957 goto invalid;
9958 }
9959
9960 return esock_setopt_level_opt(env, descP, level, opt,
9961 &mreq, sizeof(mreq));
9962
9963 invalid:
9964 return esock_make_invalid(env, atom_value);
9965 }
9966 #endif
9967 #endif // #ifndef __WIN32__
9968
9969
9970 /* The value is a map with three attributes: multiaddr, interface and
9971 * sourceaddr.
9972 * The attribute 'multiaddr' is always a 4-tuple (IPv4 address).
9973 * The attribute 'interface' is always a 4-tuple (IPv4 address).
9974 * The attribute 'sourceaddr' is always a 4-tuple (IPv4 address).
9975 * (IPv4 address).
9976 */
9977 #ifndef __WIN32__
9978 #if defined(IP_ADD_SOURCE_MEMBERSHIP) || \
9979 defined(IP_DROP_SOURCE_MEMBERSHIP) || \
9980 defined(IP_BLOCK_SOURCE) || \
9981 defined(IP_UNBLOCK_SOURCE)
9982 static
esock_setopt_in_update_source(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)9983 ERL_NIF_TERM esock_setopt_in_update_source(ErlNifEnv* env,
9984 ESockDescriptor* descP,
9985 int level,
9986 int opt,
9987 ERL_NIF_TERM eVal)
9988 {
9989 ERL_NIF_TERM eMultiAddr, eInterface, eSourceAddr;
9990 struct ip_mreq_source mreq;
9991
9992 if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) ||
9993 (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) ||
9994 (! GET_MAP_VAL(env, eVal, atom_sourceaddr, &eSourceAddr)) ||
9995 (! esock_decode_in_addr(env,
9996 eMultiAddr,
9997 &mreq.imr_multiaddr)) ||
9998 (! esock_decode_in_addr(env,
9999 eInterface,
10000 &mreq.imr_interface)) ||
10001 (! esock_decode_in_addr(env,
10002 eSourceAddr,
10003 &mreq.imr_sourceaddr)))
10004 goto invalid;
10005
10006 return esock_setopt_level_opt(env, descP, level, opt,
10007 &mreq, sizeof(mreq));
10008 invalid:
10009 return esock_make_invalid(env, atom_value);
10010 }
10011 #endif
10012 #endif // #ifndef __WIN32__
10013
10014
10015
10016 #if defined(HAVE_IPV6)
10017
10018
10019
10020 #ifndef __WIN32__
10021 #if defined(IPV6_ADDRFORM)
10022 static
esock_setopt_addrform(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10023 ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env,
10024 ESockDescriptor* descP,
10025 int level,
10026 int opt,
10027 ERL_NIF_TERM eVal)
10028 {
10029 int domain;
10030
10031 SSDBG( descP,
10032 ("SOCKET", "esock_setopt_addrform -> entry with"
10033 "\r\n eVal: %T"
10034 "\r\n", eVal) );
10035
10036 if (esock_decode_domain(env, eVal, &domain) == 0)
10037 return esock_make_invalid(env, atom_value);
10038
10039 SSDBG( descP, ("SOCKET",
10040 "esock_setopt_addrform -> try set opt to %d\r\n",
10041 domain) );
10042
10043 return esock_setopt_level_opt(env, descP, level, opt,
10044 &domain, sizeof(domain));
10045 }
10046 #endif
10047 #endif // #ifndef __WIN32__
10048
10049
10050
10051 /* esock_setopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
10052 *
10053 * The value is an atom of the type ipv6_pmtudisc().
10054 */
10055 #ifndef __WIN32__
10056 #if defined(IPV6_MTU_DISCOVER)
10057 static
esock_setopt_ipv6_mtu_discover(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10058 ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env,
10059 ESockDescriptor* descP,
10060 int level,
10061 int opt,
10062 ERL_NIF_TERM eVal)
10063 {
10064 int val;
10065
10066 if (! decode_ipv6_pmtudisc(env, eVal, &val))
10067 return esock_make_invalid(env, atom_value);
10068
10069 return esock_setopt_level_opt(env, descP, level, opt,
10070 &val, sizeof(val));
10071 }
10072 #endif
10073 #endif // #ifndef __WIN32__
10074
10075
10076 #ifndef __WIN32__
10077 #if defined(IPV6_MULTICAST_HOPS)
10078 static
esock_setopt_hops(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10079 ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env,
10080 ESockDescriptor* descP,
10081 int level,
10082 int opt,
10083 ERL_NIF_TERM eVal)
10084 {
10085 int hops;
10086
10087 if (! decode_hops(env, eVal, &hops))
10088 return esock_make_invalid(env, atom_value);
10089
10090 return esock_setopt_level_opt(env, descP, level, opt,
10091 &hops, sizeof(hops));
10092 }
10093 #endif
10094 #endif // #ifndef __WIN32__
10095
10096
10097 #ifndef __WIN32__
10098 #if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
10099 static
esock_setopt_in6_update_membership(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10100 ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env,
10101 ESockDescriptor* descP,
10102 int level,
10103 int opt,
10104 ERL_NIF_TERM eVal)
10105 {
10106 ERL_NIF_TERM eMultiAddr, eInterface;
10107 struct ipv6_mreq mreq;
10108
10109 if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) {
10110 SSDBG( descP,
10111 ("SOCKET", "esock_setopt_in6_update_membership -> "
10112 "failed get multiaddr (map) attribute\r\n") );
10113 goto invalid;
10114 }
10115
10116 if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) {
10117 SSDBG( descP,
10118 ("SOCKET", "esock_setopt_in6_update_membership -> "
10119 "failed get interface (map) attribute\r\n") );
10120 goto invalid;
10121 }
10122
10123 if (! esock_decode_in6_addr(env,
10124 eMultiAddr,
10125 &mreq.ipv6mr_multiaddr)) {
10126 SSDBG( descP,
10127 ("SOCKET", "esock_setopt_in6_update_membership -> "
10128 "failed decode multiaddr %T\r\n", eMultiAddr) );
10129 goto invalid;
10130 }
10131
10132 if (! GET_UINT(env, eInterface, &mreq.ipv6mr_interface)) {
10133 SSDBG( descP,
10134 ("SOCKET", "esock_setopt_in6_update_membership -> "
10135 "failed decode interface %T\r\n", eInterface) );
10136 goto invalid;
10137 }
10138
10139 return esock_setopt_level_opt(env, descP, level, opt,
10140 &mreq, sizeof(mreq));
10141
10142 invalid:
10143 return esock_make_invalid(env, atom_value);
10144 }
10145 #endif
10146 #endif // #ifndef __WIN32__
10147
10148
10149 #endif // defined(HAVE_IPV6)
10150
10151
10152
10153
10154 /* esock_setopt_tcp_congestion - Level TCP CONGESTION option
10155 */
10156 #ifndef __WIN32__
10157 #if defined(TCP_CONGESTION)
10158 static
esock_setopt_tcp_congestion(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10159 ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env,
10160 ESockDescriptor* descP,
10161 int level,
10162 int opt,
10163 ERL_NIF_TERM eVal)
10164 {
10165 int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1;
10166
10167 return esock_setopt_str_opt(env, descP, level, opt, max, eVal);
10168 }
10169 #endif
10170 #endif // #ifndef __WIN32__
10171
10172
10173
10174 #if defined(HAVE_SCTP)
10175
10176
10177
10178 /* esock_setopt_sctp_associnfo - Level SCTP ASSOCINFO option
10179 */
10180 #ifndef __WIN32__
10181 #if defined(SCTP_ASSOCINFO)
10182 static
esock_setopt_sctp_associnfo(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10183 ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env,
10184 ESockDescriptor* descP,
10185 int level,
10186 int opt,
10187 ERL_NIF_TERM eVal)
10188 {
10189 ERL_NIF_TERM eAssocId, eMaxRxt, eNumPeerDests;
10190 ERL_NIF_TERM ePeerRWND, eLocalRWND, eCookieLife;
10191 struct sctp_assocparams assocParams;
10192 unsigned int ui;
10193
10194 SSDBG( descP,
10195 ("SOCKET", "esock_setopt_sctp_associnfo -> entry with"
10196 "\r\n eVal: %T"
10197 "\r\n", eVal) );
10198
10199 // It must be a map
10200 if (! IS_MAP(env, eVal))
10201 goto invalid;
10202
10203 SSDBG( descP,
10204 ("SOCKET",
10205 "esock_setopt_sctp_associnfo -> extract attributes\r\n") );
10206
10207 if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) ||
10208 (! GET_MAP_VAL(env, eVal, atom_asocmaxrxt, &eMaxRxt)) ||
10209 (! GET_MAP_VAL(env, eVal, atom_number_peer_destinations,
10210 &eNumPeerDests)) ||
10211 (! GET_MAP_VAL(env, eVal, atom_peer_rwnd, &ePeerRWND)) ||
10212 (! GET_MAP_VAL(env, eVal, atom_local_rwnd, &eLocalRWND)) ||
10213 (! GET_MAP_VAL(env, eVal, atom_cookie_life, &eCookieLife)))
10214 goto invalid;
10215
10216 SSDBG( descP,
10217 ("SOCKET",
10218 "esock_setopt_sctp_associnfo -> decode attributes\r\n") );
10219
10220 if (! decode_sctp_assoc_t(env, eAssocId, &assocParams.sasoc_assoc_id))
10221 goto invalid;
10222
10223 /*
10224 * We should really make sure this is ok in erlang (to ensure that
10225 * the values (max-rxt and num-peer-dests) fits in 16-bits).
10226 * The value should be a 16-bit unsigned int...
10227 * Both sasoc_asocmaxrxt and sasoc_number_peer_destinations.
10228 */
10229
10230 if (! GET_UINT(env, eMaxRxt, &ui))
10231 goto invalid;
10232 assocParams.sasoc_asocmaxrxt = (Uint16) ui;
10233
10234 if (! GET_UINT(env, eNumPeerDests, &ui))
10235 goto invalid;
10236 assocParams.sasoc_number_peer_destinations = (Uint16) ui;
10237
10238 if (! GET_UINT(env, ePeerRWND, &ui))
10239 goto invalid;
10240 assocParams.sasoc_peer_rwnd = (Uint32) ui;
10241
10242 if (! GET_UINT(env, eLocalRWND, &ui))
10243 goto invalid;
10244 assocParams.sasoc_local_rwnd = (Uint32) ui;
10245
10246 if (! GET_UINT(env, eCookieLife, &ui))
10247 goto invalid;
10248 assocParams.sasoc_cookie_life = (Uint32) ui;
10249
10250 SSDBG( descP,
10251 ("SOCKET",
10252 "esock_setopt_sctp_associnfo -> set associnfo option\r\n") );
10253
10254 return esock_setopt_level_opt(env, descP, level, opt,
10255 &assocParams, sizeof(assocParams));
10256
10257 invalid:
10258 return esock_make_invalid(env, atom_value);
10259 }
10260 #endif
10261 #endif // #ifndef __WIN32__
10262
10263
10264 /* esock_setopt_sctp_events - Level SCTP EVENTS option
10265 */
10266 #ifndef __WIN32__
10267 #if defined(SCTP_EVENTS)
10268 static
esock_setopt_sctp_events(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10269 ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env,
10270 ESockDescriptor* descP,
10271 int level,
10272 int opt,
10273 ERL_NIF_TERM eVal)
10274 {
10275 struct sctp_event_subscribe events;
10276 BOOLEAN_T error;
10277
10278 SSDBG( descP,
10279 ("SOCKET", "esock_setopt_sctp_events {%d} -> entry with"
10280 "\r\n eVal: %T"
10281 "\r\n", descP->sock, eVal) );
10282
10283 // It must be a map
10284 if (! IS_MAP(env, eVal))
10285 goto invalid;
10286
10287 SSDBG( descP,
10288 ("SOCKET",
10289 "esock_setopt_sctp_events {%d} -> decode attributes\r\n",
10290 descP->sock) );
10291
10292 error = FALSE;
10293
10294 events.sctp_data_io_event =
10295 esock_setopt_sctp_event(env, eVal, atom_data_io, &error);
10296 events.sctp_association_event =
10297 esock_setopt_sctp_event(env, eVal, atom_association, &error);
10298 events.sctp_address_event =
10299 esock_setopt_sctp_event(env, eVal, atom_address, &error);
10300 events.sctp_send_failure_event =
10301 esock_setopt_sctp_event(env, eVal, atom_send_failure, &error);
10302 events.sctp_peer_error_event =
10303 esock_setopt_sctp_event(env, eVal, atom_peer_error, &error);
10304 events.sctp_shutdown_event =
10305 esock_setopt_sctp_event(env, eVal, atom_shutdown, &error);
10306 events.sctp_partial_delivery_event =
10307 esock_setopt_sctp_event(env, eVal, atom_partial_delivery, &error);
10308 events.sctp_adaptation_layer_event =
10309 esock_setopt_sctp_event(env, eVal, atom_adaptation_layer, &error);
10310
10311 #if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_AUTHENTICATION_EVENT)
10312 events.sctp_authentication_event =
10313 esock_setopt_sctp_event(env, eVal, atom_authentication, &error);
10314 #endif
10315
10316 #if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SENDER_DRY_EVENT)
10317 events.sctp_sender_dry_event =
10318 esock_setopt_sctp_event(env, eVal, atom_sender_dry, &error);
10319 #endif
10320
10321 if (error) {
10322 goto invalid;
10323 } else {
10324 ERL_NIF_TERM result;
10325
10326 result = esock_setopt_level_opt(env, descP, level, opt,
10327 &events, sizeof(events));
10328 SSDBG( descP,
10329 ("SOCKET",
10330 "esock_setopt_sctp_events {%d} -> set events -> %T\r\n",
10331 descP->sock, result) );
10332
10333 return result;
10334 }
10335
10336 invalid:
10337 SSDBG( descP,
10338 ("SOCKET",
10339 "esock_setopt_sctp_events {%d} -> invalid\r\n",
10340 descP->sock) );
10341
10342 return esock_make_invalid(env, atom_value);
10343 }
10344
10345 /* Return the value to make use of automatic type casting.
10346 * Set *error if something goes wrong.
10347 */
esock_setopt_sctp_event(ErlNifEnv * env,ERL_NIF_TERM eMap,ERL_NIF_TERM eKey,BOOLEAN_T * error)10348 static int esock_setopt_sctp_event(ErlNifEnv *env,
10349 ERL_NIF_TERM eMap,
10350 ERL_NIF_TERM eKey,
10351 BOOLEAN_T *error)
10352 {
10353 ERL_NIF_TERM eVal;
10354 BOOLEAN_T val;
10355
10356 if (GET_MAP_VAL(env, eMap, eKey, &eVal))
10357 if (esock_decode_bool(eVal, &val))
10358 return (int) val;
10359
10360 *error = TRUE;
10361 return 0;
10362 }
10363 #endif
10364 #endif // #ifndef __WIN32__
10365
10366
10367 /* esock_setopt_sctp_initmsg - Level SCTP INITMSG option
10368 */
10369 #ifndef __WIN32__
10370 #if defined(SCTP_INITMSG)
10371 static
esock_setopt_sctp_initmsg(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10372 ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env,
10373 ESockDescriptor* descP,
10374 int level,
10375 int opt,
10376 ERL_NIF_TERM eVal)
10377 {
10378 ERL_NIF_TERM eNumOut, eMaxIn, eMaxAttempts, eMaxInitTO;
10379 struct sctp_initmsg initMsg;
10380 unsigned int tmp;
10381
10382 SSDBG( descP,
10383 ("SOCKET", "esock_setopt_sctp_initmsg -> entry with"
10384 "\r\n eVal: %T"
10385 "\r\n", eVal) );
10386
10387 // It must be a map
10388 if (! IS_MAP(env, eVal))
10389 goto invalid;
10390
10391 SSDBG( descP,
10392 ("SOCKET",
10393 "esock_setopt_sctp_initmsg -> extract attributes\r\n") );
10394
10395 if ((! GET_MAP_VAL(env, eVal, atom_num_outstreams, &eNumOut)) ||
10396 (! GET_MAP_VAL(env, eVal, atom_max_instreams, &eMaxIn)) ||
10397 (! GET_MAP_VAL(env, eVal, atom_max_attempts, &eMaxAttempts)) ||
10398 (! GET_MAP_VAL(env, eVal, atom_max_init_timeo, &eMaxInitTO)))
10399 goto invalid;
10400
10401 SSDBG( descP,
10402 ("SOCKET",
10403 "esock_setopt_sctp_initmsg -> decode attributes\r\n") );
10404
10405 if (! GET_UINT(env, eNumOut, &tmp))
10406 goto invalid;
10407 initMsg.sinit_num_ostreams = (Uint16) tmp;
10408
10409 if (! GET_UINT(env, eMaxIn, &tmp))
10410 goto invalid;
10411 initMsg.sinit_max_instreams = (Uint16) tmp;
10412
10413 if (! GET_UINT(env, eMaxAttempts, &tmp))
10414 goto invalid;
10415 initMsg.sinit_max_attempts = (Uint16) tmp;
10416
10417 if (! GET_UINT(env, eMaxInitTO, &tmp))
10418 goto invalid;
10419 initMsg.sinit_max_init_timeo = (Uint16) tmp;
10420
10421 SSDBG( descP,
10422 ("SOCKET",
10423 "esock_setopt_sctp_initmsg -> set initmsg option\r\n") );
10424
10425 return esock_setopt_level_opt(env, descP, level, opt,
10426 &initMsg, sizeof(initMsg));
10427
10428 invalid:
10429 return esock_make_invalid(env, atom_value);
10430 }
10431 #endif
10432 #endif // #ifndef __WIN32__
10433
10434
10435 /* esock_setopt_sctp_rtoinfo - Level SCTP RTOINFO option
10436 */
10437 #ifndef __WIN32__
10438 #if defined(SCTP_RTOINFO)
10439 static
esock_setopt_sctp_rtoinfo(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10440 ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env,
10441 ESockDescriptor* descP,
10442 int level,
10443 int opt,
10444 ERL_NIF_TERM eVal)
10445 {
10446 ERL_NIF_TERM eAssocId, eInitial, eMax, eMin;
10447 struct sctp_rtoinfo rtoInfo;
10448
10449 SSDBG( descP,
10450 ("SOCKET", "esock_setopt_sctp_rtoinfo -> entry with"
10451 "\r\n eVal: %T"
10452 "\r\n", eVal) );
10453
10454 // It must be a map
10455 if (! IS_MAP(env, eVal))
10456 goto invalid;
10457
10458 SSDBG( descP,
10459 ("SOCKET",
10460 "esock_setopt_sctp_rtoinfo -> extract attributes\r\n") );
10461
10462 if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) ||
10463 (! GET_MAP_VAL(env, eVal, atom_initial, &eInitial)) ||
10464 (! GET_MAP_VAL(env, eVal, atom_max, &eMax)) ||
10465 (! GET_MAP_VAL(env, eVal, atom_min, &eMin)))
10466 goto invalid;
10467
10468 SSDBG( descP,
10469 ("SOCKET",
10470 "esock_setopt_sctp_rtoinfo -> decode attributes\r\n") );
10471
10472 if (! decode_sctp_assoc_t(env, eAssocId, &rtoInfo.srto_assoc_id))
10473 goto invalid;
10474
10475 if ((! GET_UINT(env, eInitial, &rtoInfo.srto_initial)) ||
10476 (! GET_UINT(env, eMax, &rtoInfo.srto_max)) ||
10477 (! GET_UINT(env, eMin, &rtoInfo.srto_min)))
10478 goto invalid;
10479
10480 SSDBG( descP,
10481 ("SOCKET",
10482 "esock_setopt_sctp_rtoinfo -> set associnfo option\r\n") );
10483
10484 return esock_setopt_level_opt(env, descP, level, opt,
10485 &rtoInfo, sizeof(rtoInfo));
10486
10487 invalid:
10488 return esock_make_invalid(env, atom_value);
10489 }
10490 #endif
10491 #endif // #ifndef __WIN32__
10492
10493
10494
10495 #endif // defined(HAVE_SCTP)
10496
10497
10498
10499
10500 /* esock_setopt_bool_opt - set an option that has an (integer) bool value
10501 */
10502 #ifndef __WIN32__
10503 static
esock_setopt_bool_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10504 ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env,
10505 ESockDescriptor* descP,
10506 int level,
10507 int opt,
10508 ERL_NIF_TERM eVal)
10509 {
10510 BOOLEAN_T val;
10511 int ival;
10512
10513 if (! esock_decode_bool(eVal, &val))
10514 return esock_make_invalid(env, atom_value);
10515
10516 ival = (val) ? 1 : 0;
10517 return esock_setopt_level_opt(env, descP, level, opt,
10518 &ival, sizeof(ival));
10519 }
10520 #endif // #ifndef __WIN32__
10521
10522
10523 /* esock_setopt_int_opt - set an option that has an integer value
10524 */
10525 #ifndef __WIN32__
10526 static
esock_setopt_int_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10527 ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env,
10528 ESockDescriptor* descP,
10529 int level,
10530 int opt,
10531 ERL_NIF_TERM eVal)
10532 {
10533 ERL_NIF_TERM result;
10534 int val;
10535
10536 if (GET_INT(env, eVal, &val)) {
10537 result =
10538 esock_setopt_level_opt(env, descP, level, opt,
10539 &val, sizeof(val));
10540 } else {
10541 result = esock_make_invalid(env, atom_value);
10542 }
10543 return result;
10544 }
10545 #endif // #ifndef __WIN32__
10546
10547
10548 /* esock_setopt_str_opt - set an option that has an string value
10549 */
10550 #ifndef __WIN32__
10551 #if defined(USE_SETOPT_STR_OPT)
10552 static
esock_setopt_str_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,int max,ERL_NIF_TERM eVal)10553 ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env,
10554 ESockDescriptor* descP,
10555 int level,
10556 int opt,
10557 int max,
10558 ERL_NIF_TERM eVal)
10559 {
10560 ERL_NIF_TERM result;
10561 int optLen;
10562 char* val = MALLOC(max);
10563
10564 ESOCK_ASSERT( val != NULL );
10565
10566 if ((optLen = GET_STR(env, eVal, val, max)) > 0) {
10567 optLen--;
10568
10569 result =
10570 esock_setopt_level_opt(env, descP, level, opt,
10571 val, optLen);
10572 } else {
10573 result = esock_make_invalid(env, atom_value);
10574 }
10575
10576 FREE(val);
10577
10578 return result;
10579 }
10580 #endif
10581 #endif // #ifndef __WIN32__
10582
10583
10584 /* esock_setopt_timeval_opt - set an option that has an (timeval) bool value
10585 */
10586 #ifndef __WIN32__
10587 #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \
10588 && defined(ESOCK_USE_RCVSNDTIMEO)
10589 static
esock_setopt_timeval_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM eVal)10590 ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env,
10591 ESockDescriptor* descP,
10592 int level,
10593 int opt,
10594 ERL_NIF_TERM eVal)
10595 {
10596 ERL_NIF_TERM result;
10597 struct timeval timeVal;
10598
10599 SSDBG( descP,
10600 ("SOCKET", "esock_setopt_timeval_opt -> entry with"
10601 "\r\n eVal: %T"
10602 "\r\n", eVal) );
10603
10604 if (! esock_decode_timeval(env, eVal, &timeVal))
10605 return esock_make_invalid(env, atom_value);
10606
10607 SSDBG( descP,
10608 ("SOCKET", "esock_setopt_timeval_opt -> set timeval option\r\n") );
10609
10610 result =
10611 esock_setopt_level_opt(env, descP, level, opt,
10612 &timeVal, sizeof(timeVal));
10613
10614 SSDBG( descP,
10615 ("SOCKET", "esock_setopt_timeval_opt -> done with"
10616 "\r\n result: %T"
10617 "\r\n", result) );
10618
10619 return result;
10620
10621 }
10622 #endif
10623 #endif // #ifndef __WIN32__
10624
10625
10626 #ifndef __WIN32__
esock_setopt_level_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,void * optVal,socklen_t optLen)10627 static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env,
10628 ESockDescriptor* descP,
10629 int level,
10630 int opt,
10631 void* optVal,
10632 socklen_t optLen)
10633 {
10634 if (socket_setopt(descP->sock, level, opt, optVal, optLen))
10635 return esock_make_error_errno(env, sock_errno());
10636 else
10637 return esock_atom_ok;
10638 }
10639 #endif // #ifndef __WIN32__
10640
10641
10642 /* +++ socket_setopt +++
10643 *
10644 * <Per H @ Tail-f>
10645 * The original code here had problems that possibly
10646 * only occur if you abuse it for non-INET sockets, but anyway:
10647 * a) If the getsockopt for SO_PRIORITY or IP_TOS failed, the actual
10648 * requested setsockopt was never even attempted.
10649 * b) If {get,set}sockopt for one of IP_TOS and SO_PRIORITY failed,
10650 * but ditto for the other worked and that was actually the requested
10651 * option, failure was still reported to erlang.
10652 * </Per H @ Tail-f>
10653 *
10654 * <PaN>
10655 * The relations between SO_PRIORITY, TOS and other options
10656 * is not what you (or at least I) would expect...:
10657 * If TOS is set after priority, priority is zeroed.
10658 * If any other option is set after tos, tos might be zeroed.
10659 * Therefore, save tos and priority. If something else is set,
10660 * restore both after setting, if tos is set, restore only
10661 * prio and if prio is set restore none... All to keep the
10662 * user feeling socket options are independent.
10663 * </PaN>
10664 */
10665 #ifndef __WIN32__
10666 static
socket_setopt(int sock,int level,int opt,const void * optVal,const socklen_t optLen)10667 int socket_setopt(int sock, int level, int opt,
10668 const void* optVal, const socklen_t optLen)
10669 {
10670 int res;
10671
10672 #if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY)
10673 int tmpIValPRIO = 0;
10674 int tmpIValTOS = 0;
10675 int resPRIO;
10676 int resTOS;
10677 SOCKOPTLEN_T tmpArgSzPRIO = sizeof(tmpIValPRIO);
10678 SOCKOPTLEN_T tmpArgSzTOS = sizeof(tmpIValTOS);
10679
10680 resPRIO = sock_getopt(sock, SOL_SOCKET, SO_PRIORITY,
10681 &tmpIValPRIO, &tmpArgSzPRIO);
10682 resTOS = sock_getopt(sock, SOL_IP, IP_TOS,
10683 &tmpIValTOS, &tmpArgSzTOS);
10684
10685 res = sock_setopt(sock, level, opt, optVal, optLen);
10686 if (res == 0) {
10687
10688 /* Ok, now we *maybe* need to "maybe" restore PRIO and TOS...
10689 * maybe, possibly, ...
10690 */
10691
10692 if (opt != SO_PRIORITY) {
10693 if ((opt != IP_TOS) && (resTOS == 0)) {
10694 resTOS = sock_setopt(sock, SOL_IP, IP_TOS,
10695 (void *) &tmpIValTOS,
10696 tmpArgSzTOS);
10697 res = resTOS;
10698 }
10699 if ((res == 0) && (resPRIO == 0)) {
10700 resPRIO = sock_setopt(sock, SOL_SOCKET, SO_PRIORITY,
10701 &tmpIValPRIO,
10702 tmpArgSzPRIO);
10703
10704 /* Some kernels set a SO_PRIORITY by default
10705 * that you are not permitted to reset,
10706 * silently ignore this error condition.
10707 */
10708
10709 if ((resPRIO != 0) && (sock_errno() == EPERM)) {
10710 res = 0;
10711 } else {
10712 res = resPRIO;
10713 }
10714 }
10715 }
10716 }
10717
10718 #else
10719
10720 res = sock_setopt(sock, level, opt, optVal, optLen);
10721
10722 #endif
10723
10724 return res;
10725 }
10726 #endif // #ifndef __WIN32__
10727
10728
10729
10730 /* ----------------------------------------------------------------------
10731 * nif_getopt
10732 *
10733 * Description:
10734 * Get socket option.
10735 * Its possible to use a ValueSpec to select
10736 * how the value should be decoded.
10737 *
10738 * Arguments:
10739 * Socket (ref) - Points to the socket descriptor.
10740 * Level (int) - Protocol level, encoded or native
10741 * Opt (int) - Option, encoded or native
10742 * ValueSpec (term) - How to decode the value [optional]
10743 */
10744
10745 static
nif_getopt(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])10746 ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
10747 int argc,
10748 const ERL_NIF_TERM argv[])
10749 {
10750 #ifdef __WIN32__
10751 return enif_raise_exception(env, MKA(env, "notsup"));
10752 #else
10753 ESockDescriptor* descP;
10754 int level, opt;
10755
10756 ESOCK_ASSERT( (argc == 3) || (argc == 4) );
10757
10758 SGDBG( ("SOCKET", "nif_getopt -> entry with argc: %d\r\n", argc) );
10759
10760 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
10761 SGDBG( ("SOCKET", "nif_getopt -> failed initial args check\r\n") );
10762 return enif_make_badarg(env);
10763 }
10764
10765 if (! GET_INT(env, argv[2], &opt)) {
10766 SSDBG( descP,
10767 ("SOCKET", "nif_getopt -> failed initial args check\r\n") );
10768 if (! IS_INTEGER(env, argv[2]))
10769 return enif_make_badarg(env);
10770 else
10771 return esock_make_error_integer_range(env, argv[2]);
10772 }
10773
10774 if (esock_decode_level(env, argv[1], &level)) {
10775 if (argc == 4) {
10776 ERL_NIF_TERM valueSpec = argv[3];
10777 return esock_getopt_native(env, descP, level, opt, valueSpec);
10778 } else {
10779 return esock_getopt(env, descP, level, opt);
10780 }
10781 }
10782
10783 if ((COMPARE(argv[1], atom_otp) == 0) &&
10784 (argc == 3)) {
10785 return esock_getopt_otp(env, descP, opt) ;
10786 }
10787
10788 SGDBG( ("SOCKET", "nif_getopt -> failed args check\r\n") );
10789 if (IS_INTEGER(env, argv[1]))
10790 return esock_make_error_integer_range(env, argv[1]);
10791 else
10792 return enif_make_badarg(env);
10793
10794 #endif // #ifdef __WIN32__ #else
10795 }
10796
10797
10798
10799 /* esock_getopt_otp - Handle OTP (level) options
10800 */
10801 #ifndef __WIN32__
10802 static
esock_getopt_otp(ErlNifEnv * env,ESockDescriptor * descP,int eOpt)10803 ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
10804 ESockDescriptor* descP,
10805 int eOpt)
10806 {
10807 ERL_NIF_TERM result;
10808
10809 SSDBG( descP,
10810 ("SOCKET", "esock_getopt_otp -> entry with"
10811 "\r\n eOpt: %d"
10812 "\r\n", eOpt) );
10813
10814 switch (eOpt) {
10815 case ESOCK_OPT_OTP_DEBUG:
10816 MLOCK(descP->readMtx);
10817 result = esock_getopt_otp_debug(env, descP);
10818 MUNLOCK(descP->readMtx);
10819 break;
10820
10821 case ESOCK_OPT_OTP_IOW:
10822 MLOCK(descP->readMtx);
10823 result = esock_getopt_otp_iow(env, descP);
10824 MUNLOCK(descP->readMtx);
10825 break;
10826
10827 case ESOCK_OPT_OTP_CTRL_PROC:
10828 MLOCK(descP->readMtx);
10829 result = esock_getopt_otp_ctrl_proc(env, descP);
10830 MUNLOCK(descP->readMtx);
10831 break;
10832
10833 case ESOCK_OPT_OTP_RCVBUF:
10834 MLOCK(descP->readMtx);
10835 result = esock_getopt_otp_rcvbuf(env, descP);
10836 MUNLOCK(descP->readMtx);
10837 break;
10838
10839 case ESOCK_OPT_OTP_RCVCTRLBUF:
10840 MLOCK(descP->readMtx);
10841 result = esock_getopt_otp_rcvctrlbuf(env, descP);
10842 MUNLOCK(descP->readMtx);
10843 break;
10844
10845 case ESOCK_OPT_OTP_SNDCTRLBUF:
10846 MLOCK(descP->writeMtx);
10847 result = esock_getopt_otp_sndctrlbuf(env, descP);
10848 MUNLOCK(descP->writeMtx);
10849 break;
10850
10851 case ESOCK_OPT_OTP_FD:
10852 MLOCK(descP->readMtx);
10853 result = esock_getopt_otp_fd(env, descP);
10854 MUNLOCK(descP->readMtx);
10855 break;
10856
10857 case ESOCK_OPT_OTP_META:
10858 MLOCK(descP->writeMtx);
10859 result = esock_getopt_otp_meta(env, descP);
10860 MUNLOCK(descP->writeMtx);
10861 break;
10862
10863 case ESOCK_OPT_OTP_USE_REGISTRY:
10864 MLOCK(descP->readMtx);
10865 result = esock_getopt_otp_use_registry(env, descP);
10866 MUNLOCK(descP->readMtx);
10867 break;
10868
10869 /* *** INTERNAL *** */
10870 case ESOCK_OPT_OTP_DOMAIN:
10871 MLOCK(descP->readMtx);
10872 result = esock_getopt_otp_domain(env, descP);
10873 MUNLOCK(descP->readMtx);
10874 break;
10875
10876 #if 0
10877 case ESOCK_OPT_OTP_TYPE:
10878 MLOCK(descP->readMtx);
10879 result = esock_getopt_otp_type(env, descP);
10880 MUNLOCK(descP->readMtx);
10881 break;
10882
10883 case ESOCK_OPT_OTP_PROTOCOL:
10884 MLOCK(descP->readMtx);
10885 result = esock_getopt_otp_protocol(env, descP);
10886 MUNLOCK(descP->readMtx);
10887 break;
10888
10889 case ESOCK_OPT_OTP_DTP:
10890 MLOCK(descP->readMtx);
10891 result = esock_getopt_otp_dtp(env, descP);
10892 MUNLOCK(descP->readMtx);
10893 break;
10894 #endif
10895
10896 default:
10897 MLOCK(descP->readMtx);
10898 SSDBG( descP,
10899 ("SOCKET", "esock_getopt_otp {%d} -> invalid with"
10900 "\r\n eOpt: %d"
10901 "\r\n", descP->sock, eOpt) );
10902 MUNLOCK(descP->readMtx);
10903
10904 /* This is an internal error - prim_inet gave us junk */
10905 result =
10906 esock_raise_invalid(env,
10907 MKT2(env,
10908 atom_otp_socket_option,
10909 MKI(env, eOpt)));
10910 break;
10911 }
10912
10913 return result;
10914 }
10915 #endif // #ifndef __WIN32__
10916
10917 /* esock_getopt_otp_debug - Handle the OTP (level) debug option
10918 */
10919 #ifndef __WIN32__
10920 static
esock_getopt_otp_debug(ErlNifEnv * env,ESockDescriptor * descP)10921 ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env,
10922 ESockDescriptor* descP)
10923 {
10924 ERL_NIF_TERM eVal;
10925
10926 if (! IS_OPEN(descP->readState)) {
10927 SSDBG( descP,
10928 ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n",
10929 descP->sock) );
10930 return esock_make_error(env, atom_closed);
10931 }
10932
10933 eVal = esock_encode_bool(descP->dbg);
10934
10935 return esock_make_ok2(env, eVal);
10936 }
10937 #endif // #ifndef __WIN32__
10938
10939 /* esock_getopt_otp_iow - Handle the OTP (level) iow option
10940 */
10941 #ifndef __WIN32__
10942 static
esock_getopt_otp_iow(ErlNifEnv * env,ESockDescriptor * descP)10943 ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env,
10944 ESockDescriptor* descP)
10945 {
10946 ERL_NIF_TERM eVal;
10947
10948 if (! IS_OPEN(descP->readState)) {
10949 SSDBG( descP,
10950 ("SOCKET", "esock_getopt_otp_iow {%d} -> done closed\r\n",
10951 descP->sock) );
10952 return esock_make_error(env, atom_closed);
10953 }
10954
10955 eVal = esock_encode_bool(descP->iow);
10956
10957 SSDBG( descP,
10958 ("SOCKET", "esock_getopt_otp_iow {%d} ->"
10959 "\r\n eVal: %T"
10960 "\r\n", descP->sock, eVal) );
10961
10962 return esock_make_ok2(env, eVal);
10963 }
10964 #endif // #ifndef __WIN32__
10965
10966
10967 /* esock_getopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option
10968 */
10969 #ifndef __WIN32__
10970 static
esock_getopt_otp_ctrl_proc(ErlNifEnv * env,ESockDescriptor * descP)10971 ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env,
10972 ESockDescriptor* descP)
10973 {
10974 ERL_NIF_TERM eVal;
10975
10976 if (! IS_OPEN(descP->readState)) {
10977 SSDBG( descP,
10978 ("SOCKET",
10979 "esock_getopt_otp_ctrl_proc {%d} -> done closed\r\n",
10980 descP->sock) );
10981 return esock_make_error(env, atom_closed);
10982 }
10983
10984 eVal = MKPID(env, &descP->ctrlPid);
10985
10986 SSDBG( descP,
10987 ("SOCKET", "esock_getopt_otp_ctrlProc {%d} ->"
10988 "\r\n eVal: %T"
10989 "\r\n", descP->sock, eVal) );
10990
10991 return esock_make_ok2(env, eVal);
10992 }
10993 #endif // #ifndef __WIN32__
10994
10995
10996 /* esock_getopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
10997 */
10998 #ifndef __WIN32__
10999 static
esock_getopt_otp_rcvbuf(ErlNifEnv * env,ESockDescriptor * descP)11000 ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env,
11001 ESockDescriptor* descP)
11002 {
11003 ERL_NIF_TERM eVal;
11004
11005 if (! IS_OPEN(descP->readState)) {
11006 SSDBG( descP,
11007 ("SOCKET", "esock_getopt_otp_rcvbuf {%d} -> done closed\r\n",
11008 descP->sock) );
11009 return esock_make_error(env, atom_closed);
11010 }
11011
11012 if (descP->rNum == 0) {
11013 eVal = MKUL(env, (unsigned long) descP->rBufSz);
11014 } else {
11015 eVal = MKT2(env,
11016 MKI(env, descP->rNum),
11017 MKUL(env, (unsigned long) descP->rBufSz));
11018 }
11019
11020 SSDBG( descP,
11021 ("SOCKET", "esock_getopt_otp_rcvbuf {%d} ->"
11022 "\r\n eVal: %T"
11023 "\r\n", descP->sock, eVal) );
11024
11025 return esock_make_ok2(env, eVal);
11026 }
11027 #endif // #ifndef __WIN32__
11028
11029
11030 /* esock_getopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
11031 */
11032 #ifndef __WIN32__
11033 static
esock_getopt_otp_rcvctrlbuf(ErlNifEnv * env,ESockDescriptor * descP)11034 ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env,
11035 ESockDescriptor* descP)
11036 {
11037 ERL_NIF_TERM eVal;
11038
11039 if (! IS_OPEN(descP->readState)) {
11040 SSDBG( descP,
11041 ("SOCKET",
11042 "esock_getopt_otp_rcvctrlbuf {%d} -> done closed\r\n",
11043 descP->sock) );
11044 return esock_make_error(env, atom_closed);
11045 }
11046
11047 eVal = MKUL(env, (unsigned long) descP->rCtrlSz);
11048
11049 SSDBG( descP,
11050 ("SOCKET", "esock_getopt_otp_rcvctrlbuf {%d} ->"
11051 "\r\n eVal: %T"
11052 "\r\n", descP->sock, eVal) );
11053
11054 return esock_make_ok2(env, eVal);
11055 }
11056 #endif // #ifndef __WIN32__
11057
11058
11059 /* esock_getopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
11060 */
11061 #ifndef __WIN32__
11062 static
esock_getopt_otp_sndctrlbuf(ErlNifEnv * env,ESockDescriptor * descP)11063 ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env,
11064 ESockDescriptor* descP)
11065 {
11066 ERL_NIF_TERM eVal;
11067
11068 if (! IS_OPEN(descP->writeState)) {
11069 SSDBG( descP,
11070 ("SOCKET",
11071 "esock_getopt_otp_sndctrlbuf {%d} -> done closed\r\n",
11072 descP->sock) );
11073 return esock_make_error(env, atom_closed);
11074 }
11075
11076 eVal = MKUL(env, (unsigned long) descP->wCtrlSz);
11077
11078 SSDBG( descP,
11079 ("SOCKET", "esock_getopt_otp_sndctrlbuf {%d} ->"
11080 "\r\n eVal: %T"
11081 "\r\n", descP->sock, eVal) );
11082
11083 return esock_make_ok2(env, eVal);
11084 }
11085 #endif // #ifndef __WIN32__
11086
11087
11088 /* esock_getopt_otp_fd - Handle the OTP (level) fd option
11089 */
11090 #ifndef __WIN32__
11091 static
esock_getopt_otp_fd(ErlNifEnv * env,ESockDescriptor * descP)11092 ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env,
11093 ESockDescriptor* descP)
11094 {
11095 ERL_NIF_TERM eVal;
11096
11097 if (! IS_OPEN(descP->readState)) {
11098 SSDBG( descP,
11099 ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n",
11100 descP->sock) );
11101 return esock_make_error(env, atom_closed);
11102 }
11103
11104 eVal = MKI(env, descP->sock);
11105
11106 SSDBG( descP,
11107 ("SOCKET", "esock_getopt_otp_fd {%d} ->"
11108 "\r\n eVal: %T"
11109 "\r\n", descP->sock, eVal) );
11110
11111 return esock_make_ok2(env, eVal);
11112 }
11113 #endif // #ifndef __WIN32__
11114
11115
11116 /* esock_getopt_otp_meta - Handle the OTP (level) meta option
11117 */
11118 #ifndef __WIN32__
11119 static
esock_getopt_otp_meta(ErlNifEnv * env,ESockDescriptor * descP)11120 ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env,
11121 ESockDescriptor* descP)
11122 {
11123 ERL_NIF_TERM eVal;
11124
11125 if (! IS_OPEN(descP->writeState)) {
11126 SSDBG( descP,
11127 ("SOCKET", "esock_getopt_otp_meta {%d} -> done closed\r\n",
11128 descP->sock) );
11129 return esock_make_error(env, atom_closed);
11130 }
11131
11132 eVal = CP_TERM(env, descP->meta.ref);
11133
11134 SSDBG( descP,
11135 ("SOCKET", "esock_getopt_otp_meta {%d} ->"
11136 "\r\n eVal: %T"
11137 "\r\n", descP->sock, eVal) );
11138
11139 return esock_make_ok2(env, eVal);
11140 }
11141 #endif // #ifndef __WIN32__
11142
11143
11144 /* esock_getopt_otp_use_registry - Handle the OTP (level) use_registry option
11145 */
11146 #ifndef __WIN32__
11147 static
esock_getopt_otp_use_registry(ErlNifEnv * env,ESockDescriptor * descP)11148 ERL_NIF_TERM esock_getopt_otp_use_registry(ErlNifEnv* env,
11149 ESockDescriptor* descP)
11150 {
11151 ERL_NIF_TERM eVal = esock_encode_bool(descP->useReg);
11152
11153 return esock_make_ok2(env, eVal);
11154 }
11155 #endif
11156
11157
11158 /*
11159 * esock_getopt_otp_domain - Handle the OTP (level) domain option
11160 */
11161 #ifndef __WIN32__
11162 static
esock_getopt_otp_domain(ErlNifEnv * env,ESockDescriptor * descP)11163 ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env,
11164 ESockDescriptor* descP)
11165 {
11166 ERL_NIF_TERM domain, result;
11167
11168 if (! IS_OPEN(descP->readState)) {
11169 SSDBG( descP,
11170 ("SOCKET", "esock_getopt_otp_domain {%d} -> done closed\r\n",
11171 descP->sock) );
11172 return esock_make_error(env, atom_closed);
11173 }
11174
11175 esock_encode_domain(env, descP->domain, &domain);
11176 result = esock_make_ok2(env, domain);
11177
11178 SSDBG( descP,
11179 ("SOCKET", "esock_getopt_otp_domain {%d} ->"
11180 "\r\n result: %T"
11181 "\r\n", descP->sock, result) );
11182
11183 return result;
11184 }
11185 #endif // #ifndef __WIN32__
11186
11187
11188
11189 #if 0
11190
11191 /*
11192 * esock_getopt_otp_type - Handle the OTP (level) type options.
11193 */
11194 #ifndef __WIN32__
11195 static
11196 ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env,
11197 ESockDescriptor* descP)
11198 {
11199 ERL_NIF_TERM type, result;
11200
11201 if (! IS_OPEN(descP->readState)) {
11202 SSDBG( descP,
11203 ("SOCKET", "esock_getopt_otp_type {%d} -> done closed\r\n",
11204 descP->sock) );
11205 return esock_make_error(env, atom_closed);
11206 }
11207
11208 esock_encode_type(env, descP->type, &type);
11209 result = esock_make_ok2(env, type);
11210
11211 SSDBG( descP,
11212 ("SOCKET", "esock_getopt_otp_type {%d} ->"
11213 "\r\n result: %T"
11214 "\r\n", descP->sock, result) );
11215
11216 return result;
11217 }
11218 #endif // #ifndef __WIN32__
11219
11220
11221 /*
11222 * esock_getopt_otp_protocol - Handle the OTP (level) protocol options.
11223 */
11224 #ifndef __WIN32__
11225 static
11226 ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env,
11227 ESockDescriptor* descP)
11228 {
11229 ERL_NIF_TERM protocol, result;
11230
11231 if (! IS_OPEN(descP->readState)) {
11232 SSDBG( descP,
11233 ("SOCKET", "esock_getopt_otp_protocol {%d} -> done closed\r\n",
11234 descP->sock) );
11235 return esock_make_error(env, atom_closed);
11236 }
11237
11238 protocol = MKI(env, descP->protocol);
11239 result = esock_make_ok2(env, protocol);
11240
11241 SSDBG( descP,
11242 ("SOCKET", "esock_getopt_otp_protocol {%d} ->"
11243 "\r\n result: %T"
11244 "\r\n", descP->sock, result) );
11245
11246 return result;
11247 }
11248 #endif // #ifndef __WIN32__
11249
11250
11251 /*
11252 * esock_getopt_otp_dtp - Handle the OTP (level) type options.
11253 */
11254 #ifndef __WIN32__
11255 static
11256 ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env,
11257 ESockDescriptor* descP)
11258 {
11259 ERL_NIF_TERM domain, type, protocol, dtp, result;
11260
11261 if (! IS_OPEN(descP->readState)) {
11262 SSDBG( descP,
11263 ("SOCKET", "esock_getopt_otp_dtp {%d} -> done closed\r\n",
11264 descP->sock) );
11265 return esock_make_error(env, atom_closed);
11266 }
11267
11268 esock_encode_domain(env, descP->domain, &domain);
11269 esock_encode_type(env, descP->type, &type);
11270 protocol = MKI(env, descP->protocol);
11271 dtp = MKT3(env, domain, type, protocol);
11272 result = esock_make_ok2(env, dtp);
11273
11274 SSDBG( descP,
11275 ("SOCKET", "esock_getopt_otp_dtp {%d} ->"
11276 "\r\n result: %T"
11277 "\r\n", descP->sock, result) );
11278
11279 return result;
11280 }
11281 #endif // #ifndef __WIN32__
11282
11283
11284 #endif // #if 0
11285
11286
11287 /* How to decode the value is specified with valueSpec
11288 */
11289 #ifndef __WIN32__
11290 static
esock_getopt_native(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ERL_NIF_TERM valueSpec)11291 ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env,
11292 ESockDescriptor* descP,
11293 int level,
11294 int opt,
11295 ERL_NIF_TERM valueSpec)
11296 {
11297 ERL_NIF_TERM result;
11298 SOCKOPTLEN_T valueSz;
11299 int sz;
11300 ErlNifBinary bin;
11301
11302 MLOCK(descP->readMtx);
11303
11304 SSDBG( descP,
11305 ("SOCKET", "esock_getopt_native {%d} -> entry"
11306 "\r\n level: %d"
11307 "\r\n opt: %d"
11308 "\r\n valueSpec: %T"
11309 "\r\n", descP->sock,
11310 level, opt, valueSpec) );
11311
11312 if (! IS_OPEN(descP->readState)) {
11313 SSDBG( descP,
11314 ("SOCKET", "esock_getopt_native {%d} -> done closed\r\n",
11315 descP->sock) );
11316 MUNLOCK(descP->readMtx);
11317 return esock_make_error(env, atom_closed);
11318 }
11319
11320 /* <KOLLA>
11321 * We could make it possible to specify more types,
11322 * such as string, NUL terminated or not, etc...
11323 * </KOLLA>
11324 */
11325
11326 if (GET_INT(env, valueSpec, &sz)) {
11327 valueSz = (SOCKOPTLEN_T) sz;
11328 if ((int) valueSz == sz) {
11329 SSDBG( descP,
11330 ("SOCKET", "esock_getopt_native {%d} -> binary size"
11331 "\r\n valueSz: %d"
11332 "\r\n", descP->sock, sz) );
11333 result =
11334 esock_getopt_size_opt(env, descP, level, opt, valueSz);
11335 } else {
11336 result = esock_make_invalid(env, atom_value);
11337 }
11338 } else if (COMPARE(valueSpec, atom_integer) == 0) {
11339 SSDBG( descP,
11340 ("SOCKET", "esock_getopt_native {%d} -> integer"
11341 "\r\n", descP->sock) );
11342 result = esock_getopt_int_opt(env, descP, level, opt);
11343 } else if (COMPARE(valueSpec, atom_boolean) == 0) {
11344 SSDBG( descP,
11345 ("SOCKET", "esock_getopt_native {%d} -> boolean"
11346 "\r\n", descP->sock) );
11347 result = esock_getopt_bool_opt(env, descP, level, opt);
11348 } else if (enif_inspect_binary(env, valueSpec, &bin)) {
11349 SSDBG( descP,
11350 ("SOCKET", "esock_getopt_native {%d} -> binary"
11351 "\r\n size: %lu"
11352 "\r\n", descP->sock, (unsigned long) bin.size) );
11353 result = esock_getopt_bin_opt(env, descP, level, opt, &bin);
11354 } else {
11355 result = esock_make_invalid(env, atom_value);
11356 }
11357
11358 SSDBG( descP,
11359 ("SOCKET", "esock_getopt_native {%d} -> done when"
11360 "\r\n result: %T"
11361 "\r\n", descP->sock, result) );
11362
11363 MUNLOCK(descP->readMtx);
11364 return result;
11365 }
11366 #endif // #ifndef __WIN32__
11367
11368
11369 /* esock_getopt - An option that we know how to decode
11370 */
11371 #ifndef __WIN32__
11372 static
esock_getopt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11373 ERL_NIF_TERM esock_getopt(ErlNifEnv* env,
11374 ESockDescriptor* descP,
11375 int level,
11376 int opt)
11377 {
11378 ERL_NIF_TERM result;
11379 const struct ESockOpt *optP;
11380
11381 MLOCK(descP->readMtx);
11382
11383 SSDBG( descP,
11384 ("SOCKET", "esock_getopt {%d} -> entry with"
11385 "\r\n level: %d"
11386 "\r\n opt: %d"
11387 "\r\n", descP->sock, level, opt) );
11388
11389 if (! IS_OPEN(descP->readState)) {
11390 SSDBG( descP,
11391 ("SOCKET", "esock_getopt {%d} -> done closed\r\n",
11392 descP->sock) );
11393 MUNLOCK(descP->readMtx);
11394 return esock_make_error(env, atom_closed);
11395 }
11396
11397 optP = lookupOpt(level, opt);
11398
11399 if (optP == NULL) {
11400
11401 result = esock_make_invalid(env, atom_socket_option);
11402
11403 SSDBG( descP,
11404 ("SOCKET", "esock_getopt {%d} -> unknown option\r\n",
11405 descP->sock) );
11406
11407 } else if (optP->getopt == NULL) {
11408
11409 result = esock_make_invalid(env, atom_socket_option);
11410
11411 SSDBG( descP,
11412 ("SOCKET", "esock_getopt {%d} -> opt not gettable\r\n",
11413 descP->sock) );
11414
11415 } else {
11416
11417 result = (optP->getopt)(env, descP, level, opt);
11418
11419 SSDBG( descP,
11420 ("SOCKET", "esock_getopt {%d} -> done when"
11421 "\r\n result: %T"
11422 "\r\n", descP->sock, result) );
11423 }
11424
11425 MUNLOCK(descP->readMtx);
11426 return result;
11427 }
11428 #endif // #ifndef __WIN32__
11429
11430
11431 #ifndef __WIN32__
11432 #if defined(SO_BINDTODEVICE)
11433 static
esock_getopt_so_bindtodevice(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11434 ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env,
11435 ESockDescriptor* descP,
11436 int level,
11437 int opt)
11438 {
11439 return esock_getopt_str_opt(env, descP, level, opt, IFNAMSIZ+1, FALSE);
11440 }
11441 #endif
11442 #endif // #ifndef __WIN32__
11443
11444
11445 #ifndef __WIN32__
11446 #if defined(SO_DOMAIN)
11447 static
esock_getopt_sock_domain(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11448 ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env,
11449 ESockDescriptor* descP,
11450 int level,
11451 int opt)
11452 {
11453 int val;
11454 ERL_NIF_TERM result;
11455
11456 if (! esock_getopt_int(descP->sock, level, opt, &val)) {
11457 result = esock_make_error_errno(env, sock_errno());
11458 } else {
11459 ERL_NIF_TERM domain;
11460 esock_encode_domain(env, val, &domain);
11461 result = esock_make_ok2(env, domain);
11462 }
11463
11464 return result;
11465 }
11466 #endif
11467 #endif // #ifndef __WIN32__
11468
11469
11470 #ifndef __WIN32__
11471 #if defined(SO_LINGER)
11472 static
esock_getopt_linger(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11473 ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env,
11474 ESockDescriptor* descP,
11475 int level,
11476 int opt)
11477 {
11478 ERL_NIF_TERM result;
11479 struct linger val;
11480 SOCKOPTLEN_T valSz = sizeof(val);
11481 int res;
11482
11483 sys_memzero((void *) &val, sizeof(val));
11484
11485 res = sock_getopt(descP->sock, level, opt, &val, &valSz);
11486
11487 if (res != 0) {
11488 result = esock_make_error_errno(env, sock_errno());
11489 } else {
11490 ERL_NIF_TERM
11491 lOnOff = ((val.l_onoff != 0) ? atom_true : atom_false),
11492 lSecs = MKI(env, val.l_linger),
11493 keys[] = {atom_onoff, esock_atom_linger},
11494 vals[] = {lOnOff, lSecs},
11495 linger;
11496 size_t numKeys = NUM(keys);
11497
11498 ESOCK_ASSERT( numKeys == NUM(vals) );
11499 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &linger) );
11500
11501 result = esock_make_ok2(env, linger);
11502 }
11503
11504 return result;
11505 }
11506 #endif
11507 #endif // #ifndef __WIN32__
11508
11509
11510
11511 #ifndef __WIN32__
11512 #if defined(SO_TYPE)
11513 static
esock_getopt_sock_type(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11514 ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env,
11515 ESockDescriptor* descP,
11516 int level,
11517 int opt)
11518 {
11519 ERL_NIF_TERM result;
11520 int val;
11521
11522 if (! esock_getopt_int(descP->sock, level, opt, &val)) {
11523 result = esock_make_error_errno(env, sock_errno());
11524 } else {
11525 ERL_NIF_TERM type;
11526 esock_encode_type(env, val, &type);
11527 result = esock_make_ok2(env, type);
11528 }
11529
11530 return result;
11531 }
11532 #endif
11533 #endif // #ifndef __WIN32__
11534
11535
11536 #ifndef __WIN32__
11537 #if defined(SO_PROTOCOL)
11538 static
esock_getopt_sock_protocol(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11539 ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env,
11540 ESockDescriptor* descP,
11541 int level,
11542 int opt)
11543 {
11544 ERL_NIF_TERM result;
11545 int val;
11546
11547 if (! esock_getopt_int(descP->sock, level, opt, &val)) {
11548 result = esock_make_error_errno(env, sock_errno());
11549 } else {
11550 ERL_NIF_TERM protocol;
11551
11552 protocol =
11553 #ifdef AF_LOCAL
11554 /* For AF_LOCAL, the protocols table value for 0 is wrong */
11555 (val == 0) && (descP->domain == AF_LOCAL) ?
11556 esock_atom_default :
11557 /* It is correct for AF_INET and hopefully for AF_INET6,
11558 * but for future additions it is an open question
11559 */
11560 #endif
11561 MKI(env, val);
11562
11563 result = esock_make_ok2(env, protocol);
11564 }
11565
11566 return result;
11567 }
11568 #endif
11569 #endif // #ifndef __WIN32__
11570
11571
11572 #ifndef __WIN32__
11573 /* esock_getopt_ip_mtu_discover - Level IP MTU_DISCOVER option
11574 */
11575 #if defined(IP_MTU_DISCOVER)
11576 static
esock_getopt_ip_mtu_discover(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11577 ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env,
11578 ESockDescriptor* descP,
11579 int level,
11580 int opt)
11581 {
11582 ERL_NIF_TERM result;
11583 int mtuDisc;
11584
11585 if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) {
11586 result = esock_make_error_errno(env, sock_errno());
11587 } else {
11588 ERL_NIF_TERM eMtuDisc;
11589 encode_ip_pmtudisc(env, mtuDisc, &eMtuDisc);
11590 result = esock_make_ok2(env, eMtuDisc);
11591 }
11592
11593 return result;
11594
11595 }
11596 #endif
11597 #endif // #ifndef __WIN32__
11598
11599
11600 /* esock_getopt_multicast_if - Level IP MULTICAST_IF option
11601 */
11602 #ifndef __WIN32__
11603 #if defined(IP_MULTICAST_IF)
11604 static
esock_getopt_multicast_if(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11605 ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env,
11606 ESockDescriptor* descP,
11607 int level,
11608 int opt)
11609 {
11610 ERL_NIF_TERM result;
11611 ERL_NIF_TERM eAddr;
11612 struct in_addr ifAddr;
11613 SOCKOPTLEN_T ifAddrSz = sizeof(ifAddr);
11614 int res;
11615
11616 sys_memzero((void *) &ifAddr, ifAddrSz);
11617
11618 res = sock_getopt(descP->sock, level, opt, &ifAddr, &ifAddrSz);
11619
11620 if (res != 0) {
11621 result = esock_make_error_errno(env, sock_errno());
11622 } else {
11623 esock_encode_in_addr(env, &ifAddr, &eAddr);
11624 result = esock_make_ok2(env, eAddr);
11625 }
11626
11627 return result;
11628
11629 }
11630 #endif
11631 #endif // #ifndef __WIN32__
11632
11633
11634 /* esock_getopt_tos - Level IP TOS option
11635 */
11636 #ifndef __WIN32__
11637 #if defined(IP_TOS)
11638 static
esock_getopt_tos(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11639 ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env,
11640 ESockDescriptor* descP,
11641 int level,
11642 int opt)
11643 {
11644 ERL_NIF_TERM result;
11645 int val = 0;
11646
11647 if (! esock_getopt_int(descP->sock, level, opt, &val)) {
11648 result = esock_make_error_errno(env, sock_errno());
11649 } else {
11650 result = esock_make_ok2(env, encode_ip_tos(env, val));
11651 }
11652
11653 return result;
11654 }
11655 #endif
11656 #endif // #ifndef __WIN32__
11657
11658
11659 #if defined(HAVE_IPV6)
11660
11661
11662 /* esock_getopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
11663 */
11664 #ifndef __WIN32__
11665 #if defined(IPV6_MTU_DISCOVER)
11666 static
esock_getopt_ipv6_mtu_discover(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11667 ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env,
11668 ESockDescriptor* descP,
11669 int level,
11670 int opt)
11671 {
11672 ERL_NIF_TERM result;
11673 int mtuDisc;
11674
11675 if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) {
11676 result = esock_make_error_errno(env, sock_errno());
11677 } else {
11678 ERL_NIF_TERM eMtuDisc;
11679 encode_ipv6_pmtudisc(env, mtuDisc, &eMtuDisc);
11680 result = esock_make_ok2(env, eMtuDisc);
11681 }
11682
11683 return result;
11684
11685 }
11686 #endif
11687 #endif // #ifndef __WIN32__
11688
11689
11690 #endif // defined(HAVE_IPV6)
11691
11692
11693
11694 /* esock_getopt_tcp_congestion - Level TCP CONGESTION option
11695 */
11696 #ifndef __WIN32__
11697 #if defined(TCP_CONGESTION)
11698 static
esock_getopt_tcp_congestion(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11699 ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env,
11700 ESockDescriptor* descP,
11701 int level,
11702 int opt)
11703 {
11704 int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1;
11705
11706 return esock_getopt_str_opt(env, descP, level, opt, max, TRUE);
11707 }
11708 #endif
11709 #endif // #ifndef __WIN32__
11710
11711
11712
11713 #if defined(HAVE_SCTP)
11714
11715
11716
11717 /* esock_getopt_sctp_associnfo - Level SCTP ASSOCINFO option
11718 *
11719 * <KOLLA>
11720 *
11721 * We should really specify which association this relates to,
11722 * as it is now we get assoc-id = 0. If this socket is an
11723 * association (and not an endpoint) then it will have an
11724 * assoc id. But since the sctp support at present is "limited",
11725 * we leave it for now.
11726 * What do we do if this is an endpoint? Invalid op? Or just leave
11727 * it for the OS?
11728 *
11729 * </KOLLA>
11730 */
11731 #ifndef __WIN32__
11732 #if defined(SCTP_ASSOCINFO)
11733 static
esock_getopt_sctp_associnfo(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11734 ERL_NIF_TERM esock_getopt_sctp_associnfo(ErlNifEnv* env,
11735 ESockDescriptor* descP,
11736 int level,
11737 int opt)
11738 {
11739 ERL_NIF_TERM result;
11740 struct sctp_assocparams val;
11741 SOCKOPTLEN_T valSz = sizeof(val);
11742 int res;
11743
11744 sys_memzero((char*) &val, valSz);
11745 res = sock_getopt(descP->sock, level, opt, &val, &valSz);
11746
11747 if (res != 0) {
11748 result = esock_make_error_errno(env, sock_errno());
11749 } else {
11750 ERL_NIF_TERM eAssocParams;
11751 ERL_NIF_TERM keys[] = {atom_assoc_id,
11752 atom_asocmaxrxt,
11753 atom_number_peer_destinations,
11754 atom_peer_rwnd,
11755 atom_local_rwnd,
11756 atom_cookie_life};
11757 ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.sasoc_assoc_id),
11758 MKUI(env, val.sasoc_asocmaxrxt),
11759 MKUI(env, val.sasoc_number_peer_destinations),
11760 MKUI(env, val.sasoc_peer_rwnd),
11761 MKUI(env, val.sasoc_local_rwnd),
11762 MKUI(env, val.sasoc_cookie_life)};
11763 size_t numKeys = NUM(keys);
11764
11765 ESOCK_ASSERT( numKeys == NUM(vals) );
11766 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eAssocParams) );
11767 result = esock_make_ok2(env, eAssocParams);
11768 }
11769
11770 return result;
11771 }
11772 #endif
11773 #endif // #ifndef __WIN32__
11774
11775
11776
11777
11778 /* esock_getopt_sctp_initmsg - Level SCTP INITMSG option
11779 *
11780 */
11781 #ifndef __WIN32__
11782 #if defined(SCTP_INITMSG)
11783 static
esock_getopt_sctp_initmsg(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11784 ERL_NIF_TERM esock_getopt_sctp_initmsg(ErlNifEnv* env,
11785 ESockDescriptor* descP,
11786 int level,
11787 int opt)
11788 {
11789 ERL_NIF_TERM result;
11790 struct sctp_initmsg val;
11791 SOCKOPTLEN_T valSz = sizeof(val);
11792 int res;
11793
11794 sys_memzero((char*) &val, valSz);
11795 res = sock_getopt(descP->sock, level, opt, &val, &valSz);
11796
11797 if (res != 0) {
11798 result = esock_make_error_errno(env, sock_errno());
11799 } else {
11800 ERL_NIF_TERM eInitMsg;
11801 ERL_NIF_TERM keys[] = {atom_num_outstreams, atom_max_instreams,
11802 atom_max_attempts, atom_max_init_timeo};
11803 ERL_NIF_TERM vals[] = {MKUI(env, val.sinit_num_ostreams),
11804 MKUI(env, val.sinit_max_instreams),
11805 MKUI(env, val.sinit_max_attempts),
11806 MKUI(env, val.sinit_max_init_timeo)};
11807 unsigned int numKeys = NUM(keys);
11808 unsigned int numVals = NUM(vals);
11809
11810 ESOCK_ASSERT( numKeys == numVals );
11811 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eInitMsg) );
11812 result = esock_make_ok2(env, eInitMsg);
11813 }
11814
11815 return result;
11816 }
11817 #endif
11818 #endif // #ifndef __WIN32__
11819
11820
11821 /* esock_getopt_sctp_rtoinfo - Level SCTP ASSOCINFO option
11822 *
11823 * <KOLLA>
11824 *
11825 * We should really specify which association this relates to,
11826 * as it is now we get assoc-id = 0. If this socket is an
11827 * association (and not an endpoint) then it will have an
11828 * assoc id (we can assume). But since the sctp support at
11829 * present is "limited", we leave it for now.
11830 * What do we do if this is an endpoint? Invalid op?
11831 *
11832 * </KOLLA>
11833 */
11834 #ifndef __WIN32__
11835 #if defined(SCTP_RTOINFO)
11836 static
esock_getopt_sctp_rtoinfo(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11837 ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env,
11838 ESockDescriptor* descP,
11839 int level,
11840 int opt)
11841 {
11842 ERL_NIF_TERM result;
11843 struct sctp_rtoinfo val;
11844 SOCKOPTLEN_T valSz = sizeof(val);
11845 int res;
11846
11847 sys_memzero((char*) &val, valSz);
11848 res = sock_getopt(descP->sock, level, opt, &val, &valSz);
11849
11850 if (res != 0) {
11851 result = esock_make_error_errno(env, sock_errno());
11852 } else {
11853 ERL_NIF_TERM eRTOInfo;
11854 ERL_NIF_TERM keys[] = {atom_assoc_id, atom_initial, atom_max, atom_min};
11855 ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.srto_assoc_id),
11856 MKUI(env, val.srto_initial),
11857 MKUI(env, val.srto_max),
11858 MKUI(env, val.srto_min)};
11859 unsigned int numKeys = NUM(keys);
11860 unsigned int numVals = NUM(vals);
11861
11862 ESOCK_ASSERT( numKeys == numVals );
11863 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eRTOInfo) );
11864 result = esock_make_ok2(env, eRTOInfo);
11865 }
11866
11867 return result;
11868 }
11869 #endif
11870 #endif // #ifndef __WIN32__
11871
11872
11873
11874 #endif // defined(HAVE_SCTP)
11875
11876
11877
11878 /* esock_getopt_bool_opt - get an (integer) bool option
11879 */
11880 #ifndef __WIN32__
11881 static
esock_getopt_bool_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11882 ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env,
11883 ESockDescriptor* descP,
11884 int level,
11885 int opt)
11886 {
11887 ERL_NIF_TERM result;
11888 int val = 0;
11889
11890 if (! esock_getopt_int(descP->sock, level, opt, &val)) {
11891 result = esock_make_error_errno(env, sock_errno());
11892 } else {
11893 ERL_NIF_TERM bval = ((val) ? atom_true : atom_false);
11894
11895 result = esock_make_ok2(env, bval);
11896 }
11897 return result;
11898 }
11899 #endif // #ifndef __WIN32__
11900
11901
11902 /* esock_getopt_int_opt - get an integer option
11903 */
11904 #ifndef __WIN32__
11905 static
esock_getopt_int_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)11906 ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env,
11907 ESockDescriptor* descP,
11908 int level,
11909 int opt)
11910 {
11911 int val;
11912
11913 if (! esock_getopt_int(descP->sock, level, opt, &val))
11914 return esock_make_error_errno(env, sock_errno());
11915
11916 return esock_make_ok2(env, MKI(env, val));
11917 }
11918 #endif // #ifndef __WIN32__
11919
11920
11921
11922 /* esock_getopt_int - get an integer option
11923 */
11924 #ifndef __WIN32__
11925 static
esock_getopt_int(SOCKET sock,int level,int opt,int * valP)11926 BOOLEAN_T esock_getopt_int(SOCKET sock,
11927 int level,
11928 int opt,
11929 int* valP)
11930 {
11931 int val = 0;
11932 SOCKOPTLEN_T valSz = sizeof(val);
11933
11934 if (sock_getopt(sock, level, opt, &val, &valSz) != 0)
11935 return FALSE;
11936
11937 *valP = val;
11938 return TRUE;
11939 }
11940 #endif // #ifndef __WIN32__
11941
11942
11943
11944 #ifndef __WIN32__
11945 static
esock_getopt_size_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,SOCKOPTLEN_T valueSz)11946 ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env,
11947 ESockDescriptor* descP,
11948 int level,
11949 int opt,
11950 SOCKOPTLEN_T valueSz)
11951 {
11952 ERL_NIF_TERM result;
11953 int res;
11954
11955 if (valueSz == 0) {
11956 res = sock_getopt(descP->sock, level, opt, NULL, NULL);
11957 if (res != 0)
11958 result = esock_make_error_errno(env, sock_errno());
11959 else
11960 result = esock_atom_ok;
11961 } else {
11962 SOCKOPTLEN_T vsz = valueSz;
11963 ErlNifBinary val;
11964
11965 ESOCK_ASSERT( ALLOC_BIN(vsz, &val) );
11966 sys_memzero(val.data, val.size);
11967 res = sock_getopt(descP->sock, level, opt, val.data, &vsz);
11968 if (res != 0) {
11969 result = esock_make_error_errno(env, sock_errno());
11970 FREE_BIN(&val);
11971 } else {
11972
11973 /* Did we use all of the buffer? */
11974 if (vsz == val.size) {
11975 result = esock_make_ok2(env, MKBIN(env, &val));
11976
11977 } else {
11978
11979 ERL_NIF_TERM tmp;
11980
11981 tmp = MKBIN(env, &val);
11982 tmp = MKSBIN(env, tmp, 0, vsz);
11983
11984 result = esock_make_ok2(env, tmp);
11985 }
11986 }
11987 }
11988
11989 return result;
11990 }
11991 #endif // #ifndef __WIN32__
11992
11993
11994 #ifndef __WIN32__
11995 static
esock_getopt_bin_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,ErlNifBinary * binP)11996 ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env,
11997 ESockDescriptor* descP,
11998 int level,
11999 int opt,
12000 ErlNifBinary* binP)
12001 {
12002 ERL_NIF_TERM result;
12003 int res;
12004 SOCKOPTLEN_T vsz;
12005 ErlNifBinary val;
12006
12007 vsz = (SOCKOPTLEN_T) binP->size;
12008 if (SZT(vsz) != binP->size) {
12009 result = esock_make_error_invalid(env, atom_data_size);
12010 } else {
12011 ESOCK_ASSERT( ALLOC_BIN(vsz, &val) );
12012 sys_memcpy(val.data, binP->data, vsz);
12013 res = sock_getopt(descP->sock, level, opt, val.data, &vsz);
12014 if (res != 0) {
12015 result = esock_make_error_errno(env, sock_errno());
12016 FREE_BIN(&val);
12017 } else {
12018
12019 /* Did we use all of the buffer? */
12020 if (vsz == val.size) {
12021 result = esock_make_ok2(env, MKBIN(env, &val));
12022
12023 } else {
12024
12025 ERL_NIF_TERM tmp;
12026
12027 tmp = MKBIN(env, &val);
12028 tmp = MKSBIN(env, tmp, 0, vsz);
12029
12030 result = esock_make_ok2(env, tmp);
12031 }
12032 }
12033 }
12034
12035 return result;
12036 }
12037 #endif // #ifndef __WIN32__
12038
12039
12040 /* esock_getopt_timeval_opt - get an timeval option
12041 */
12042 #ifndef __WIN32__
12043 #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \
12044 && defined(ESOCK_USE_RCVSNDTIMEO)
12045 static
esock_getopt_timeval_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)12046 ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env,
12047 ESockDescriptor* descP,
12048 int level,
12049 int opt)
12050 {
12051 ERL_NIF_TERM result;
12052 struct timeval val;
12053 SOCKOPTLEN_T valSz = sizeof(val);
12054 int res;
12055
12056 sys_memzero((char*) &val, valSz);
12057 res = sock_getopt(descP->sock, level, opt, &val, &valSz);
12058
12059 if (res != 0) {
12060 result = esock_make_error_errno(env, sock_errno());
12061 } else {
12062 ERL_NIF_TERM eTimeVal;
12063
12064 esock_encode_timeval(env, &val, &eTimeVal);
12065 result = esock_make_ok2(env, eTimeVal);
12066 }
12067
12068 return result;
12069 }
12070 #endif
12071 #endif // #ifndef __WIN32__
12072
12073
12074 #ifndef __WIN32__
12075 #if defined(IP_PKTOPTIONS) || defined(IPV6_PKTOPTIONS)
12076
12077 /* Calculate CMSG_NXTHDR without having a struct msghdr*.
12078 * CMSG_LEN only caters for alignment for start of data.
12079 * To get how much to advance we need to use CMSG_SPACE
12080 * on the payload length. To get the payload length we
12081 * take the calculated cmsg->cmsg_len and subtract the
12082 * header length. To get the header length we use
12083 * the pointer difference from the cmsg start pointer
12084 * to the CMSG_DATA(cmsg) pointer.
12085 *
12086 * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3)
12087 * may return 0 as the cmsg_len if the cmsg is to be ignored.
12088 */
12089 #define LEN_CMSG_DATA(__CMSG__) \
12090 ((__CMSG__)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \
12091 (__CMSG__)->cmsg_len - ((char*)CMSG_DATA(__CMSG__) - (char*)(__CMSG__)))
12092 #define NEXT_CMSG_HDR(__CMSG__) \
12093 ((struct cmsghdr*)(((char*)(__CMSG__)) + CMSG_SPACE(LEN_CMSG_DATA(__CMSG__))))
12094
12095 static
esock_getopt_pktoptions(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt)12096 ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env,
12097 ESockDescriptor* descP,
12098 int level,
12099 int opt)
12100 {
12101 ERL_NIF_TERM result, ePktOpts;
12102 int res;
12103 ErlNifBinary cmsgs;
12104 SOCKOPTLEN_T sz = (SOCKOPTLEN_T) descP->rCtrlSz;
12105 SocketTArray cmsghdrs = TARRAY_CREATE(16);
12106 ERL_NIF_TERM ctrlBuf;
12107
12108 ESOCK_ASSERT( ALLOC_BIN(sz, &cmsgs) );
12109
12110 sys_memzero(cmsgs.data, cmsgs.size);
12111 sz = cmsgs.size; // Make no assumption about the size
12112 res = sock_getopt(descP->sock, level, opt, cmsgs.data, &sz);
12113
12114 if (res != 0) {
12115 result = esock_make_error_errno(env, sock_errno());
12116 } else {
12117 struct cmsghdr* currentP;
12118 struct cmsghdr* endOfBuf;
12119
12120 ctrlBuf = MKBIN(env, &cmsgs); // The *entire* binary
12121
12122 for (endOfBuf = (struct cmsghdr*)(cmsgs.data + cmsgs.size),
12123 currentP = (struct cmsghdr*)(cmsgs.data);
12124 (currentP != NULL) && (currentP < endOfBuf);
12125 currentP = NEXT_CMSG_HDR(currentP)) {
12126 unsigned char* dataP = UCHARP(CMSG_DATA(currentP));
12127 size_t dataPos = dataP - cmsgs.data;
12128 size_t dataLen = (UCHARP(currentP) + currentP->cmsg_len) - dataP;
12129
12130 SSDBG( descP,
12131 ("SOCKET", "esock_getopt_pktoptions {%d} -> cmsg header data: "
12132 "\r\n currentP: 0x%lX"
12133 "\r\n level: %d"
12134 "\r\n data: %d"
12135 "\r\n len: %d [0x%lX]"
12136 "\r\n dataP: 0x%lX"
12137 "\r\n dataPos: %d"
12138 "\r\n dataLen: %d [0x%lX]"
12139 "\r\n", descP->sock,
12140 currentP,
12141 currentP->cmsg_level,
12142 currentP->cmsg_type,
12143 currentP->cmsg_len, currentP->cmsg_len,
12144 dataP,
12145 dataPos,
12146 dataLen, dataLen) );
12147
12148 /*
12149 * Check that this is within the allocated buffer...
12150 * The 'next control message header' is a bit adhoc,
12151 * so this check is a bit...
12152 */
12153 if ((dataPos > cmsgs.size) ||
12154 (dataLen > cmsgs.size) ||
12155 ((dataPos + dataLen) > ((size_t)endOfBuf))) {
12156 break;
12157 } else {
12158 ERL_NIF_TERM cmsgHdr;
12159 ERL_NIF_TERM keys[] = {esock_atom_level,
12160 esock_atom_type,
12161 esock_atom_data,
12162 atom_value};
12163 ERL_NIF_TERM vals[NUM(keys)];
12164 size_t numKeys = NUM(keys);
12165 BOOLEAN_T haveValue;
12166
12167 vals[0] = esock_encode_level(env, currentP->cmsg_level);
12168 vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen);
12169
12170 haveValue = encode_cmsg(env,
12171 currentP->cmsg_level,
12172 currentP->cmsg_type,
12173 dataP, dataLen, &vals[1], &vals[3]);
12174
12175 SSDBG( descP,
12176 ("SOCKET", "esock_getopt_pktoptions {%d} -> "
12177 "\r\n %T: %T"
12178 "\r\n %T: %T"
12179 "\r\n %T: %T"
12180 "\r\n", descP->sock,
12181 keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) );
12182
12183 if (haveValue) {
12184 SSDBG( descP,
12185 ("SOCKET", "esock_getopt_pktoptions {%d} -> "
12186 "\r\n %T: %T"
12187 "\r\n", descP->sock, keys[3], vals[3]) );
12188 }
12189
12190 /* Guard agains cut-and-paste errors */
12191 ESOCK_ASSERT( numKeys == NUM(vals) );
12192
12193 /* Make control message header map */
12194 ESOCK_ASSERT( MKMA(env, keys, vals,
12195 numKeys - (haveValue ? 0 : 1), &cmsgHdr) );
12196
12197 SSDBG( descP,
12198 ("SOCKET", "esock_getopt_pktoptions {%d} -> header processed: "
12199 "\r\n %T"
12200 "\r\n", descP->sock, cmsgHdr) );
12201
12202 /* And finally add it to the list... */
12203 TARRAY_ADD(cmsghdrs, cmsgHdr);
12204 }
12205 }
12206
12207 SSDBG( descP,
12208 ("SOCKET", "esock_getopt_pktoptions {%d} -> "
12209 "cmsg headers processed when"
12210 "\r\n TArray Size: %d"
12211 "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) );
12212
12213 /* The tarray is populated - convert it to a list */
12214 TARRAY_TOLIST(cmsghdrs, env, &ePktOpts);
12215
12216 result = esock_make_ok2(env, ePktOpts);
12217 }
12218
12219 FREE_BIN(&cmsgs);
12220
12221 return result;
12222 }
12223 #endif
12224 #endif // #ifndef __WIN32__
12225
12226
12227
12228
12229 /* esock_getopt_str_opt - get a string option
12230 *
12231 * We provide the max size of the string. This is the
12232 * size of the buffer we allocate for the value.
12233 * The actual size of the (read) value will be communicated
12234 * in the valSz variable.
12235 */
12236 #ifndef __WIN32__
12237 #if defined(USE_GETOPT_STR_OPT)
12238 static
esock_getopt_str_opt(ErlNifEnv * env,ESockDescriptor * descP,int level,int opt,int max,BOOLEAN_T stripNUL)12239 ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env,
12240 ESockDescriptor* descP,
12241 int level,
12242 int opt,
12243 int max,
12244 BOOLEAN_T stripNUL)
12245 {
12246 ERL_NIF_TERM result;
12247 char* val = MALLOC(max);
12248 SOCKOPTLEN_T valSz = max;
12249 int res;
12250
12251 ESOCK_ASSERT( val != NULL );
12252
12253 sys_memzero(val, max);
12254 res = sock_getopt(descP->sock, level, opt, val, &valSz);
12255
12256 if (res != 0) {
12257 result = esock_make_error_errno(env, sock_errno());
12258 } else {
12259 if (stripNUL &&
12260 valSz > 0 &&
12261 val[valSz - 1] == '\0') valSz--;
12262
12263 result = esock_make_ok2(env, MKSL(env, val, valSz));
12264 }
12265 FREE(val);
12266
12267 return result;
12268 }
12269 #endif // if defined(USE_GETOPT_STR_OPT)
12270 #endif // #ifndef __WIN32__
12271
12272
12273
12274 /* ----------------------------------------------------------------------
12275 * nif_sockname - get socket name
12276 *
12277 * Description:
12278 * Returns the current address to which the socket is bound.
12279 *
12280 * Arguments:
12281 * Socket (ref) - Points to the socket descriptor.
12282 */
12283
12284 static
nif_sockname(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])12285 ERL_NIF_TERM nif_sockname(ErlNifEnv* env,
12286 int argc,
12287 const ERL_NIF_TERM argv[])
12288 {
12289 #ifdef __WIN32__
12290 return enif_raise_exception(env, MKA(env, "notsup"));
12291 #else
12292 ESockDescriptor* descP;
12293 ERL_NIF_TERM res;
12294
12295 ESOCK_ASSERT( argc == 1 );
12296
12297 SGDBG( ("SOCKET", "nif_sockname -> entry with argc: %d\r\n", argc) );
12298
12299 /* Extract arguments and perform preliminary validation */
12300
12301 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
12302 return enif_make_badarg(env);
12303 }
12304
12305 MLOCK(descP->readMtx);
12306
12307 SSDBG( descP,
12308 ("SOCKET", "nif_sockname(%T) {%d}"
12309 "\r\n", argv[0], descP->sock) );
12310
12311 res = esock_sockname(env, descP);
12312
12313 SSDBG( descP,
12314 ("SOCKET", "nif_sockname(%T) {%d} -> done with res = %T\r\n",
12315 argv[0], descP->sock, res) );
12316
12317 MUNLOCK(descP->readMtx);
12318
12319 return res;
12320 #endif // #ifdef __WIN32__ #else
12321 }
12322
12323
12324
12325 #ifndef __WIN32__
12326 static
esock_sockname(ErlNifEnv * env,ESockDescriptor * descP)12327 ERL_NIF_TERM esock_sockname(ErlNifEnv* env,
12328 ESockDescriptor* descP)
12329 {
12330 ESockAddress sa;
12331 ESockAddress* saP = &sa;
12332 SOCKLEN_T sz = sizeof(ESockAddress);
12333
12334 if (! IS_OPEN(descP->readState))
12335 return esock_make_error(env, atom_closed);
12336
12337 sys_memzero((char*) saP, sz);
12338 if (sock_name(descP->sock, (struct sockaddr*) saP, &sz) < 0) {
12339 return esock_make_error_errno(env, sock_errno());
12340 } else {
12341 ERL_NIF_TERM esa;
12342
12343 esock_encode_sockaddr(env, saP, sz, &esa);
12344 return esock_make_ok2(env, esa);
12345 }
12346 }
12347 #endif // #ifndef __WIN32__
12348
12349
12350
12351
12352 /* ----------------------------------------------------------------------
12353 * nif_peername - get name of the connected peer socket
12354 *
12355 * Description:
12356 * Returns the address of the peer connected to the socket.
12357 *
12358 * Arguments:
12359 * Socket (ref) - Points to the socket descriptor.
12360 */
12361
12362 static
nif_peername(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])12363 ERL_NIF_TERM nif_peername(ErlNifEnv* env,
12364 int argc,
12365 const ERL_NIF_TERM argv[])
12366 {
12367 #ifdef __WIN32__
12368 return enif_raise_exception(env, MKA(env, "notsup"));
12369 #else
12370 ESockDescriptor* descP;
12371 ERL_NIF_TERM res;
12372
12373 ESOCK_ASSERT( argc == 1 );
12374
12375 SGDBG( ("SOCKET", "nif_peername -> entry with argc: %d\r\n", argc) );
12376
12377 /* Extract arguments and perform preliminary validation */
12378
12379 if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
12380 return enif_make_badarg(env);
12381 }
12382
12383 MLOCK(descP->readMtx);
12384
12385 SSDBG( descP,
12386 ("SOCKET", "nif_peername(%T) {%d}"
12387 "\r\n", argv[0], descP->sock) );
12388
12389 res = esock_peername(env, descP);
12390
12391 SSDBG( descP,
12392 ("SOCKET", "nif_peername(%T) {%d} -> done with res = %T\r\n",
12393 argv[0], descP->sock, res) );
12394
12395 MUNLOCK(descP->readMtx);
12396
12397 return res;
12398 #endif // #ifdef __WIN32__ #else
12399 }
12400
12401
12402
12403 #ifndef __WIN32__
12404 static
esock_peername(ErlNifEnv * env,ESockDescriptor * descP)12405 ERL_NIF_TERM esock_peername(ErlNifEnv* env,
12406 ESockDescriptor* descP)
12407 {
12408 ESockAddress sa;
12409 ESockAddress* saP = &sa;
12410 SOCKLEN_T sz = sizeof(ESockAddress);
12411
12412 if (! IS_OPEN(descP->readState))
12413 return esock_make_error(env, atom_closed);
12414
12415 sys_memzero((char*) saP, sz);
12416 if (sock_peer(descP->sock, (struct sockaddr*) saP, &sz) < 0) {
12417 return esock_make_error_errno(env, sock_errno());
12418 } else {
12419 ERL_NIF_TERM esa;
12420
12421 esock_encode_sockaddr(env, saP, sz, &esa);
12422 return esock_make_ok2(env, esa);
12423 }
12424 }
12425 #endif // #ifndef __WIN32__
12426
12427
12428
12429 /* ----------------------------------------------------------------------
12430 * nif_cancel
12431 *
12432 * Description:
12433 * Cancel a previous select!
12434 *
12435 * Arguments:
12436 * Socket (ref) - Points to the socket descriptor.
12437 * Operation (atom) - What kind of operation (accept, send, ...) is to be cancelled
12438 * Ref (ref) - Unique id for the operation
12439 */
12440 static
nif_cancel(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])12441 ERL_NIF_TERM nif_cancel(ErlNifEnv* env,
12442 int argc,
12443 const ERL_NIF_TERM argv[])
12444 {
12445 #ifdef __WIN32__
12446 return enif_raise_exception(env, MKA(env, "notsup"));
12447 #else
12448 ESockDescriptor* descP;
12449 ERL_NIF_TERM op, sockRef, opRef;
12450
12451 ESOCK_ASSERT( argc == 3 );
12452
12453 SGDBG( ("SOCKET", "nif_cancel -> entry with argc: %d\r\n", argc) );
12454
12455 /* Extract arguments and perform preliminary validation */
12456
12457 sockRef = argv[0];
12458 if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
12459 return enif_make_badarg(env);
12460 }
12461 op = argv[1];
12462 opRef = argv[2];
12463 if ((! IS_ATOM(env, op)) ||
12464 (! enif_is_ref(env, opRef))) {
12465 return enif_make_badarg(env);
12466 }
12467
12468 return esock_cancel(env, descP, op, sockRef, opRef);
12469
12470 #endif // #ifdef __WIN32__ #else
12471 }
12472
12473
12474 #ifndef __WIN32__
12475 static
esock_cancel(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM op,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef)12476 ERL_NIF_TERM esock_cancel(ErlNifEnv* env,
12477 ESockDescriptor* descP,
12478 ERL_NIF_TERM op,
12479 ERL_NIF_TERM sockRef,
12480 ERL_NIF_TERM opRef)
12481 {
12482 int cmp;
12483
12484 /* <KOLLA>
12485 *
12486 * Do we really need all these variants? Should it not be enough with:
12487 *
12488 * connect | accept | send | recv
12489 *
12490 * </KOLLA>
12491 */
12492
12493 /* Hand crafted binary search */
12494 if ((cmp = COMPARE(op, esock_atom_recvmsg)) == 0)
12495 return esock_cancel_recv(env, descP, sockRef, opRef);
12496 if (cmp < 0) {
12497 if ((cmp = COMPARE(op, esock_atom_recv)) == 0)
12498 return esock_cancel_recv(env, descP, sockRef, opRef);
12499 if (cmp < 0) {
12500 if (COMPARE(op, esock_atom_connect) == 0)
12501 return esock_cancel_connect(env, descP, opRef);
12502 if (COMPARE(op, esock_atom_accept) == 0)
12503 return esock_cancel_accept(env, descP, sockRef, opRef);
12504 } else {
12505 if (COMPARE(op, esock_atom_recvfrom) == 0)
12506 return esock_cancel_recv(env, descP, sockRef, opRef);
12507 }
12508 } else {
12509 if ((cmp = COMPARE(op, esock_atom_sendmsg)) == 0)
12510 return esock_cancel_send(env, descP, sockRef, opRef);
12511 if (cmp < 0) {
12512 if (COMPARE(op, esock_atom_send) == 0)
12513 return esock_cancel_send(env, descP, sockRef, opRef);
12514 if (COMPARE(op, atom_sendfile) == 0)
12515 return esock_cancel_send(env, descP, sockRef, opRef);
12516 } else {
12517 if (COMPARE(op, esock_atom_sendto) == 0)
12518 return esock_cancel_send(env, descP, sockRef, opRef);
12519 }
12520 }
12521
12522 {
12523 ERL_NIF_TERM result;
12524 const char *reason;
12525
12526 MLOCK(descP->readMtx);
12527 MLOCK(descP->writeMtx);
12528
12529 if (! IS_OPEN(descP->readState)) {
12530 result = esock_make_error(env, atom_closed);
12531 reason = "closed";
12532 } else {
12533 result = enif_make_badarg(env);
12534 reason = "badarg";
12535 }
12536
12537 SSDBG( descP,
12538 ("SOCKET", "esock_cancel(%T), {%d,0x%X} -> %s"
12539 "\r\n",
12540 sockRef, descP->sock,
12541 descP->readState | descP->writeState, reason) );
12542
12543 MUNLOCK(descP->writeMtx);
12544 MUNLOCK(descP->readMtx);
12545
12546 return result;
12547 }
12548 }
12549 #endif // #ifndef __WIN32__
12550
12551
12552
12553 /* *** esock_cancel_connect ***
12554 *
12555 *
12556 */
12557 #ifndef __WIN32__
12558 static
esock_cancel_connect(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef)12559 ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env,
12560 ESockDescriptor* descP,
12561 ERL_NIF_TERM opRef)
12562 {
12563 ERL_NIF_TERM res;
12564 ErlNifPid self;
12565
12566 ESOCK_ASSERT( enif_self(env, &self) != NULL );
12567
12568 MLOCK(descP->writeMtx);
12569
12570 if (! IS_OPEN(descP->writeState)) {
12571
12572 res = esock_make_error(env, atom_closed);
12573
12574 } else if ((descP->connectorP == NULL) ||
12575 (COMPARE_PIDS(&self, &descP->connector.pid) != 0) ||
12576 (COMPARE(opRef, descP->connector.ref) != 0)) {
12577
12578 res = esock_atom_not_found;
12579
12580 } else {
12581
12582 res = esock_cancel_write_select(env, descP, opRef);
12583 requestor_release("esock_cancel_connect",
12584 env, descP, &descP->connector);
12585 descP->connectorP = NULL;
12586 descP->writeState &= ~ESOCK_STATE_CONNECTING;
12587 }
12588
12589 SSDBG( descP,
12590 ("SOCKET",
12591 "esock_cancel_connect {%d,0x%X} ->"
12592 "\r\n opRef: %T"
12593 "\r\n res: %T"
12594 "\r\n",
12595 descP->sock, descP->writeState,
12596 opRef, res) );
12597
12598 MUNLOCK(descP->writeMtx);
12599
12600 return res;
12601 }
12602 #endif // #ifndef __WIN32__
12603
12604
12605 /* *** esock_cancel_accept ***
12606 *
12607 * We have two different cases:
12608 * *) Its the current acceptor
12609 * Cancel the select!
12610 * We need to activate one of the waiting acceptors.
12611 * *) Its one of the acceptors ("waiting") in the queue
12612 * Simply remove the acceptor from the queue.
12613 *
12614 */
12615 #ifndef __WIN32__
12616 static
esock_cancel_accept(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef)12617 ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env,
12618 ESockDescriptor* descP,
12619 ERL_NIF_TERM sockRef,
12620 ERL_NIF_TERM opRef)
12621 {
12622 ERL_NIF_TERM res;
12623
12624 MLOCK(descP->readMtx);
12625
12626 SSDBG( descP,
12627 ("SOCKET",
12628 "esock_cancel_accept(%T), {%d,0x%X} ->"
12629 "\r\n opRef: %T"
12630 "\r\n %s"
12631 "\r\n",
12632 sockRef, descP->sock, descP->readState,
12633 opRef,
12634 ((descP->currentAcceptorP == NULL)
12635 ? "without acceptor" : "with acceptor")) );
12636
12637 if (! IS_OPEN(descP->readState)) {
12638
12639 res = esock_make_error(env, atom_closed);
12640
12641 } else if (descP->currentAcceptorP == NULL) {
12642
12643 res = esock_atom_not_found;
12644
12645 } else {
12646 ErlNifPid self;
12647
12648 ESOCK_ASSERT( enif_self(env, &self) != NULL );
12649
12650 if (COMPARE_PIDS(&self, &descP->currentAcceptor.pid) == 0) {
12651 if (COMPARE(opRef, descP->currentAcceptor.ref) == 0)
12652 res = esock_cancel_accept_current(env, descP, sockRef);
12653 else
12654 res = esock_atom_not_found;
12655 } else {
12656 res = esock_cancel_accept_waiting(env, descP, opRef, &self);
12657 }
12658 }
12659
12660 SSDBG( descP,
12661 ("SOCKET", "esock_cancel_accept(%T) -> done with result:"
12662 "\r\n %T"
12663 "\r\n", sockRef, res) );
12664
12665 MUNLOCK(descP->readMtx);
12666
12667 return res;
12668 }
12669 #endif // #ifndef __WIN32__
12670
12671
12672 /* The current acceptor process has an ongoing select we first must
12673 * cancel. Then we must re-activate the "first" (the first
12674 * in the acceptor queue).
12675 */
12676 #ifndef __WIN32__
12677 static
esock_cancel_accept_current(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)12678 ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
12679 ESockDescriptor* descP,
12680 ERL_NIF_TERM sockRef)
12681 {
12682 ERL_NIF_TERM res;
12683
12684 ESOCK_ASSERT( DEMONP("esock_cancel_accept_current -> current acceptor",
12685 env, descP, &descP->currentAcceptor.mon) == 0);
12686 res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref);
12687
12688 SSDBG( descP,
12689 ("SOCKET",
12690 "esock_cancel_accept_current(%T) {%d} -> cancel res: %T"
12691 "\r\n", sockRef, descP->sock, res) );
12692
12693 if (!activate_next_acceptor(env, descP, sockRef)) {
12694
12695 SSDBG( descP,
12696 ("SOCKET",
12697 "esock_cancel_accept_current(%T) {%d} -> "
12698 "no more acceptors\r\n",
12699 sockRef, descP->sock) );
12700
12701 descP->readState &= ~ESOCK_STATE_ACCEPTING;
12702
12703 descP->currentAcceptorP = NULL;
12704 }
12705
12706 return res;
12707 }
12708 #endif // #ifndef __WIN32__
12709
12710
12711 /* These processes have not performed a select, so we can simply
12712 * remove them from the acceptor queue.
12713 */
12714 #ifndef __WIN32__
12715 static
esock_cancel_accept_waiting(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef,const ErlNifPid * selfP)12716 ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env,
12717 ESockDescriptor* descP,
12718 ERL_NIF_TERM opRef,
12719 const ErlNifPid* selfP)
12720 {
12721 /* unqueue request from (acceptor) queue */
12722
12723 if (acceptor_unqueue(env, descP, &opRef, selfP)) {
12724 return esock_atom_ok;
12725 } else {
12726 return esock_atom_not_found;
12727 }
12728 }
12729 #endif // #ifndef __WIN32__
12730
12731
12732
12733 /* *** esock_cancel_send ***
12734 *
12735 * Cancel a send operation.
12736 * Its either the current writer or one of the waiting writers.
12737 */
12738 #ifndef __WIN32__
12739 static
esock_cancel_send(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef)12740 ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env,
12741 ESockDescriptor* descP,
12742 ERL_NIF_TERM sockRef,
12743 ERL_NIF_TERM opRef)
12744 {
12745 ERL_NIF_TERM res;
12746
12747 MLOCK(descP->writeMtx);
12748
12749 SSDBG( descP,
12750 ("SOCKET",
12751 "esock_cancel_send(%T), {%d,0x%X} -> entry with"
12752 "\r\n opRef: %T"
12753 "\r\n %s"
12754 "\r\n",
12755 sockRef, descP->sock, descP->writeState,
12756 opRef,
12757 ((descP->currentWriterP == NULL)
12758 ? "without writer" : "with writer")) );
12759
12760 if (! IS_OPEN(descP->writeState)) {
12761
12762 res = esock_make_error(env, atom_closed);
12763
12764 } else if (descP->currentWriterP == NULL) {
12765
12766 res = esock_atom_not_found;
12767
12768 } else {
12769 ErlNifPid self;
12770
12771 ESOCK_ASSERT( enif_self(env, &self) != NULL );
12772
12773 if (COMPARE_PIDS(&self, &descP->currentWriter.pid) == 0) {
12774 if (COMPARE(opRef, descP->currentWriter.ref) == 0)
12775 res = esock_cancel_send_current(env, descP, sockRef);
12776 else
12777 res = esock_atom_not_found;
12778 } else {
12779 res = esock_cancel_send_waiting(env, descP, opRef, &self);
12780 }
12781 }
12782
12783 SSDBG( descP,
12784 ("SOCKET", "esock_cancel_send(%T) {%d} -> done with result:"
12785 "\r\n %T"
12786 "\r\n", sockRef, descP->sock, res) );
12787
12788 MUNLOCK(descP->writeMtx);
12789
12790 return res;
12791 }
12792 #endif // #ifndef __WIN32__
12793
12794
12795
12796 /* The current writer process has an ongoing select we first must
12797 * cancel. Then we must re-activate the "first" (the first
12798 * in the writer queue).
12799 */
12800 #ifndef __WIN32__
12801 static
esock_cancel_send_current(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)12802 ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env,
12803 ESockDescriptor* descP,
12804 ERL_NIF_TERM sockRef)
12805 {
12806 ERL_NIF_TERM res;
12807
12808 ESOCK_ASSERT( DEMONP("esock_cancel_send_current -> current writer",
12809 env, descP, &descP->currentWriter.mon) == 0);
12810 res = esock_cancel_write_select(env, descP, descP->currentWriter.ref);
12811
12812 SSDBG( descP,
12813 ("SOCKET", "esock_cancel_send_current(%T) {%d} -> cancel res: %T"
12814 "\r\n", sockRef, descP->sock, res) );
12815
12816 if (!activate_next_writer(env, descP, sockRef)) {
12817 SSDBG( descP,
12818 ("SOCKET",
12819 "esock_cancel_send_current(%T) {%d} -> no more writers"
12820 "\r\n", sockRef, descP->sock) );
12821
12822 descP->currentWriterP = NULL;
12823 }
12824
12825 return res;
12826 }
12827 #endif // #ifndef __WIN32__
12828
12829
12830 /* These processes have not performed a select, so we can simply
12831 * remove them from the writer queue.
12832 */
12833 #ifndef __WIN32__
12834 static
esock_cancel_send_waiting(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef,const ErlNifPid * selfP)12835 ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env,
12836 ESockDescriptor* descP,
12837 ERL_NIF_TERM opRef,
12838 const ErlNifPid* selfP)
12839 {
12840 /* unqueue request from (writer) queue */
12841
12842 if (writer_unqueue(env, descP, &opRef, selfP)) {
12843 return esock_atom_ok;
12844 } else {
12845 return esock_atom_not_found;
12846 }
12847 }
12848 #endif // #ifndef __WIN32__
12849
12850
12851
12852 /* *** esock_cancel_recv ***
12853 *
12854 * Cancel a read operation.
12855 * Its either the current reader or one of the waiting readers.
12856 */
12857 #ifndef __WIN32__
12858 static
esock_cancel_recv(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef)12859 ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env,
12860 ESockDescriptor* descP,
12861 ERL_NIF_TERM sockRef,
12862 ERL_NIF_TERM opRef)
12863 {
12864 ERL_NIF_TERM res;
12865
12866 MLOCK(descP->readMtx);
12867
12868 SSDBG( descP,
12869 ("SOCKET",
12870 "esock_cancel_recv(%T), {%d,0x%X} -> entry with"
12871 "\r\n opRef: %T"
12872 "\r\n %s"
12873 "\r\n",
12874 sockRef, descP->sock, descP->readState,
12875 opRef,
12876 ((descP->currentReaderP == NULL)
12877 ? "without reader" : "with reader")) );
12878
12879 if (! IS_OPEN(descP->readState)) {
12880
12881 res = esock_make_error(env, atom_closed);
12882
12883 } else if (descP->currentReaderP == NULL) {
12884
12885 res = esock_atom_not_found;
12886
12887 } else {
12888 ErlNifPid self;
12889
12890 ESOCK_ASSERT( enif_self(env, &self) != NULL );
12891
12892 if (COMPARE_PIDS(&self, &descP->currentReader.pid) == 0) {
12893 if (COMPARE(opRef, descP->currentReader.ref) == 0)
12894 res = esock_cancel_recv_current(env, descP, sockRef);
12895 else
12896 res = esock_atom_not_found;
12897 } else {
12898 res = esock_cancel_recv_waiting(env, descP, opRef, &self);
12899 }
12900 }
12901
12902 SSDBG( descP,
12903 ("SOCKET", "esock_cancel_recv(%T) {%d} -> done with result:"
12904 "\r\n %T"
12905 "\r\n", sockRef, descP->sock, res) );
12906
12907 MUNLOCK(descP->readMtx);
12908
12909 return res;
12910 }
12911 #endif // #ifndef __WIN32__
12912
12913
12914 /* The current reader process has an ongoing select we first must
12915 * cancel. Then we must re-activate the "first" (the first
12916 * in the reader queue).
12917 */
12918 #ifndef __WIN32__
12919 static
esock_cancel_recv_current(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)12920 ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
12921 ESockDescriptor* descP,
12922 ERL_NIF_TERM sockRef)
12923 {
12924 ERL_NIF_TERM res;
12925
12926 ESOCK_ASSERT( DEMONP("esock_cancel_recv_current -> current reader",
12927 env, descP, &descP->currentReader.mon) == 0);
12928 res = esock_cancel_read_select(env, descP, descP->currentReader.ref);
12929
12930 SSDBG( descP,
12931 ("SOCKET", "esock_cancel_recv_current(%T) {%d} -> cancel res: %T"
12932 "\r\n", sockRef, descP->sock, res) );
12933
12934 if (! activate_next_reader(env, descP, sockRef)) {
12935 SSDBG( descP,
12936 ("SOCKET",
12937 "esock_cancel_recv_current(%T) {%d} -> no more readers"
12938 "\r\n", sockRef, descP->sock) );
12939
12940 descP->currentReaderP = NULL;
12941 }
12942
12943 return res;
12944 }
12945 #endif // #ifndef __WIN32__
12946
12947
12948 /* These processes have not performed a select, so we can simply
12949 * remove them from the reader queue.
12950 */
12951 #ifndef __WIN32__
12952 static
esock_cancel_recv_waiting(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef,const ErlNifPid * selfP)12953 ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env,
12954 ESockDescriptor* descP,
12955 ERL_NIF_TERM opRef,
12956 const ErlNifPid* selfP)
12957 {
12958 /* unqueue request from (reader) queue */
12959
12960 if (reader_unqueue(env, descP, &opRef, selfP)) {
12961 return esock_atom_ok;
12962 } else {
12963 return esock_atom_not_found;
12964 }
12965 }
12966 #endif // #ifndef __WIN32__
12967
12968
12969
12970 #ifndef __WIN32__
12971 static
esock_cancel_read_select(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef)12972 ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env,
12973 ESockDescriptor* descP,
12974 ERL_NIF_TERM opRef)
12975 {
12976 return esock_cancel_mode_select(env, descP, opRef,
12977 ERL_NIF_SELECT_READ,
12978 ERL_NIF_SELECT_READ_CANCELLED);
12979 }
12980 #endif // #ifndef __WIN32__
12981
12982
12983 #ifndef __WIN32__
12984 static
esock_cancel_write_select(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef)12985 ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env,
12986 ESockDescriptor* descP,
12987 ERL_NIF_TERM opRef)
12988 {
12989 return esock_cancel_mode_select(env, descP, opRef,
12990 ERL_NIF_SELECT_WRITE,
12991 ERL_NIF_SELECT_WRITE_CANCELLED);
12992 }
12993 #endif // #ifndef __WIN32__
12994
12995
12996 #ifndef __WIN32__
12997 static
esock_cancel_mode_select(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM opRef,int smode,int rmode)12998 ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env,
12999 ESockDescriptor* descP,
13000 ERL_NIF_TERM opRef,
13001 int smode,
13002 int rmode)
13003 {
13004 /* Assumes cancelling only one mode */
13005
13006 int selectRes = esock_select_cancel(env, descP->sock, smode, descP);
13007
13008 if (selectRes >= 0) {
13009 /* Success */
13010 if ((selectRes & rmode) != 0) {
13011 /* Was cancelled */
13012 return esock_atom_ok;
13013 } else {
13014 /* Has already sent the message */
13015 return esock_atom_select_sent;
13016 }
13017 } else {
13018 /* Stopped? */
13019 SSDBG( descP,
13020 ("SOCKET",
13021 "esock_cancel_mode_select {%d} -> failed: %d (0x%lX)"
13022 "\r\n", descP->sock, selectRes, selectRes) );
13023
13024 return esock_atom_not_found;
13025 }
13026 }
13027 #endif // #ifndef __WIN32__
13028
13029
13030
13031 /* ----------------------------------------------------------------------
13032 * U t i l i t y F u n c t i o n s
13033 * ----------------------------------------------------------------------
13034 */
13035
13036 /* *** send_check_writer ***
13037 *
13038 * Checks if we have a current writer and if that is us.
13039 * If not (current writer), then we must be made to wait
13040 * for our turn. This is done by pushing us unto the writer queue.
13041 */
13042 #ifndef __WIN32__
13043 static
send_check_writer(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM ref,ERL_NIF_TERM * checkResult)13044 BOOLEAN_T send_check_writer(ErlNifEnv* env,
13045 ESockDescriptor* descP,
13046 ERL_NIF_TERM ref,
13047 ERL_NIF_TERM* checkResult)
13048 {
13049 if (descP->currentWriterP != NULL) {
13050 ErlNifPid caller;
13051
13052 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
13053
13054 if (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0) {
13055 /* Not the "current writer", so (maybe) push onto queue */
13056
13057 SSDBG( descP,
13058 ("SOCKET",
13059 "send_check_writer {%d} -> not (current) writer"
13060 "\r\n ref: %T"
13061 "\r\n", descP->sock, ref) );
13062
13063 if (! writer_search4pid(env, descP, &caller)) {
13064 writer_push(env, descP, caller, ref);
13065 *checkResult = atom_select;
13066 } else {
13067 /* Writer already in queue */
13068 *checkResult = esock_raise_invalid(env, atom_state);
13069 }
13070
13071 SSDBG( descP,
13072 ("SOCKET",
13073 "send_check_writer {%d} -> queue (push) result: %T\r\n"
13074 "\r\n ref: %T"
13075 "\r\n", descP->sock, *checkResult, ref) );
13076
13077 return FALSE;
13078 }
13079 }
13080
13081 // Does not actually matter in this case, but ...
13082 *checkResult = esock_atom_ok;
13083
13084 return TRUE;
13085 }
13086 #endif // #ifndef __WIN32__
13087
13088
13089 /* *** send_check_result ***
13090 *
13091 * Check the result of a socket send (send, sendto and sendmsg) call.
13092 * If a "complete" send has been made, the next (waiting) writer will be
13093 * scheduled (if there is one).
13094 * If we did not manage to send the entire package, make another select,
13095 * so that we can be informed when we can make another try (to send the rest),
13096 * and return with the amount we actually managed to send (its up to the caller
13097 * (that is the erlang code) to figure out hust much is left to send).
13098 * If the write fail, we give up and return with the appropriate error code.
13099 *
13100 * What about the remaining writers!!
13101 *
13102 */
13103 #ifndef __WIN32__
13104 static
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)13105 ERL_NIF_TERM send_check_result(ErlNifEnv* env,
13106 ESockDescriptor* descP,
13107 ssize_t send_result,
13108 ssize_t dataSize,
13109 BOOLEAN_T dataInTail,
13110 ERL_NIF_TERM sockRef,
13111 ERL_NIF_TERM sendRef)
13112 {
13113 ERL_NIF_TERM res;
13114 BOOLEAN_T send_error;
13115 int err;
13116
13117 send_error = ESOCK_IS_ERROR(send_result);
13118 err = send_error ? sock_errno() : 0;
13119
13120 SSDBG( descP,
13121 ("SOCKET", "send_check_result(%T) {%d} -> entry with"
13122 "\r\n send_result: %ld"
13123 "\r\n dataSize: %ld"
13124 "\r\n err: %d"
13125 "\r\n sendRef: %T"
13126 "\r\n", sockRef, descP->sock,
13127 (long) send_result, (long) dataSize, err, sendRef) );
13128
13129 if (send_error) {
13130 /* Some kind of send failure - check what kind */
13131 if ((err != EAGAIN) && (err != EINTR)) {
13132 res = send_check_fail(env, descP, err, sockRef);
13133 } else {
13134 /* Ok, try again later */
13135
13136 SSDBG( descP,
13137 ("SOCKET",
13138 "send_check_result(%T) {%d} -> try again"
13139 "\r\n", sockRef, descP->sock) );
13140
13141 res = send_check_retry(env, descP, -1, sockRef, sendRef);
13142 }
13143 } else {
13144 ssize_t written = send_result;
13145 ESOCK_ASSERT( dataSize >= written );
13146
13147 if (written < dataSize) {
13148 /* Not the entire package */
13149 SSDBG( descP,
13150 ("SOCKET",
13151 "send_check_result(%T) {%d} -> "
13152 "not entire package written (%d of %d)"
13153 "\r\n", sockRef, descP->sock,
13154 written, dataSize) );
13155
13156 res = send_check_retry(env, descP, written, sockRef, sendRef);
13157 } else if (dataInTail) {
13158 /* Not the entire package */
13159 SSDBG( descP,
13160 ("SOCKET",
13161 "send_check_result(%T) {%d} -> "
13162 "not entire package written (%d but data in tail)"
13163 "\r\n", sockRef, descP->sock,
13164 written) );
13165
13166 res =
13167 send_check_retry(env, descP, written, sockRef,
13168 esock_atom_iov);
13169 } else {
13170 res = send_check_ok(env, descP, written, sockRef);
13171 }
13172 }
13173
13174 SSDBG( descP,
13175 ("SOCKET",
13176 "send_check_result(%T) {%d} -> done:"
13177 "\r\n res: %T"
13178 "\r\n", sockRef, descP->sock,
13179 res) );
13180
13181 return res;
13182 }
13183 #endif // #ifndef __WIN32__
13184
13185
13186 /* *** send_check_ok ***
13187 *
13188 * Processing done upon successful send.
13189 */
13190 #ifndef __WIN32__
13191 static
send_check_ok(ErlNifEnv * env,ESockDescriptor * descP,ssize_t written,ERL_NIF_TERM sockRef)13192 ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
13193 ESockDescriptor* descP,
13194 ssize_t written,
13195 ERL_NIF_TERM sockRef)
13196 {
13197 ESOCK_CNT_INC(env, descP, sockRef,
13198 atom_write_pkg, &descP->writePkgCnt, 1);
13199 ESOCK_CNT_INC(env, descP, sockRef,
13200 atom_write_byte, &descP->writeByteCnt, written);
13201 descP->writePkgMaxCnt += written;
13202 if (descP->writePkgMaxCnt > descP->writePkgMax)
13203 descP->writePkgMax = descP->writePkgMaxCnt;
13204 descP->writePkgMaxCnt = 0;
13205
13206 SSDBG( descP,
13207 ("SOCKET", "send_check_ok(%T) {%d} -> "
13208 "everything written (%ld) - done\r\n",
13209 sockRef, descP->sock, written) );
13210
13211 if (descP->currentWriterP != NULL) {
13212 ESOCK_ASSERT( DEMONP("send_check_ok -> current writer",
13213 env, descP, &descP->currentWriter.mon) == 0);
13214 }
13215 /*
13216 * Ok, this write is done maybe activate the next (if any)
13217 */
13218 if (!activate_next_writer(env, descP, sockRef)) {
13219
13220 SSDBG( descP,
13221 ("SOCKET", "send_check_ok(%T) {%d} -> no more writers\r\n",
13222 sockRef, descP->sock) );
13223
13224 descP->currentWriterP = NULL;
13225 }
13226
13227 return esock_atom_ok;
13228 }
13229 #endif // #ifndef __WIN32__
13230
13231
13232 /* *** send_check_failure ***
13233 *
13234 * Processing done upon failed send.
13235 * An actual failure - we (and everyone waiting) give up.
13236 */
13237 #ifndef __WIN32__
13238 static
send_check_fail(ErlNifEnv * env,ESockDescriptor * descP,int saveErrno,ERL_NIF_TERM sockRef)13239 ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
13240 ESockDescriptor* descP,
13241 int saveErrno,
13242 ERL_NIF_TERM sockRef)
13243 {
13244 ERL_NIF_TERM reason;
13245
13246 ESOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1);
13247
13248 SSDBG( descP, ("SOCKET", "send_check_fail(%T) {%d} -> error: %d\r\n",
13249 sockRef, descP->sock, saveErrno) );
13250
13251 reason = MKA(env, erl_errno_id(saveErrno));
13252
13253 if (saveErrno != EINVAL) {
13254
13255 /*
13256 * We assume that anything other then einval (invalid input)
13257 * is basically fatal (=> all waiting sends are aborted)
13258 */
13259
13260 if (descP->currentWriterP != NULL) {
13261
13262 requestor_release("send_check_fail",
13263 env, descP, &descP->currentWriter);
13264
13265 send_error_waiting_writers(env, descP, sockRef, reason);
13266
13267 descP->currentWriterP = NULL;
13268 }
13269 }
13270 return esock_make_error(env, reason);
13271 }
13272 #endif // #ifndef __WIN32__
13273
13274
13275 /* *** send_error_waiting_writers ***
13276 *
13277 * Process all waiting writers when a fatal error has occured.
13278 * All waiting writers will be "aborted", that is a
13279 * nif_abort message will be sent (with ref and reason).
13280 */
13281 #ifndef __WIN32__
13282 static
send_error_waiting_writers(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM reason)13283 void send_error_waiting_writers(ErlNifEnv* env,
13284 ESockDescriptor* descP,
13285 ERL_NIF_TERM sockRef,
13286 ERL_NIF_TERM reason)
13287 {
13288 ESockRequestor req;
13289
13290 req.env = NULL; /* read by writer_pop before free */
13291 while (writer_pop(env, descP, &req)) {
13292 SSDBG( descP,
13293 ("SOCKET",
13294 "send_error_waiting_writers(%T) {%d} -> abort"
13295 "\r\n pid: %T"
13296 "\r\n reason: %T"
13297 "\r\n",
13298 sockRef, descP->sock, &req.pid, reason) );
13299
13300 esock_send_abort_msg(env, descP, sockRef, &req, reason);
13301
13302 (void) DEMONP("send_error_waiting_writers -> pop'ed writer",
13303 env, descP, &req.mon);
13304 }
13305 }
13306 #endif // #ifndef __WIN32__
13307
13308
13309 /* *** send_check_retry ***
13310 *
13311 * Processing done upon uncomplete or blocked send.
13312 *
13313 * We failed to write the *entire* packet (anything less
13314 * then size of the packet, which is 0 <= written < sizeof
13315 * packet, so schedule the rest for later.
13316 */
13317 #ifndef __WIN32__
13318 static
send_check_retry(ErlNifEnv * env,ESockDescriptor * descP,ssize_t written,ERL_NIF_TERM sockRef,ERL_NIF_TERM sendRef)13319 ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
13320 ESockDescriptor* descP,
13321 ssize_t written,
13322 ERL_NIF_TERM sockRef,
13323 ERL_NIF_TERM sendRef)
13324 {
13325 int sres;
13326 ERL_NIF_TERM res;
13327
13328 SSDBG( descP,
13329 ("SOCKET",
13330 "send_check_retry(%T) {%d} -> %ld"
13331 "\r\n", sockRef, descP->sock, (long) written) );
13332
13333 if (written >= 0) {
13334 descP->writePkgMaxCnt += written;
13335
13336 if (descP->type != SOCK_STREAM) {
13337 /* Partial write for packet oriented socket
13338 * - done with packet
13339 */
13340 if (descP->writePkgMaxCnt > descP->writePkgMax)
13341 descP->writePkgMax = descP->writePkgMaxCnt;
13342 descP->writePkgMaxCnt = 0;
13343
13344 ESOCK_CNT_INC(env, descP, sockRef,
13345 atom_write_pkg, &descP->writePkgCnt, 1);
13346 ESOCK_CNT_INC(env, descP, sockRef,
13347 atom_write_byte, &descP->writeByteCnt, written);
13348
13349 if (descP->currentWriterP != NULL) {
13350 ESOCK_ASSERT( DEMONP("send_check_retry -> current writer",
13351 env, descP,
13352 &descP->currentWriter.mon) == 0);
13353 }
13354 /*
13355 * Ok, this write is done maybe activate the next (if any)
13356 */
13357 if (!activate_next_writer(env, descP, sockRef)) {
13358
13359 SSDBG( descP,
13360 ("SOCKET",
13361 "send_check_retry(%T) {%d} -> no more writers\r\n",
13362 sockRef, descP->sock) );
13363
13364 descP->currentWriterP = NULL;
13365 }
13366
13367 return esock_make_ok2(env, MKI64(env, written));
13368 } /* else partial write for stream socket */
13369 } /* else send would have blocked */
13370
13371 /* Register this process as current writer */
13372
13373 if (descP->currentWriterP == NULL) {
13374 /* Register writer as current */
13375
13376 ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL );
13377 ESOCK_ASSERT( MONP("send_check_retry -> current writer",
13378 env, descP,
13379 &descP->currentWriter.pid,
13380 &descP->currentWriter.mon) == 0 );
13381 ESOCK_ASSERT( descP->currentWriter.env == NULL );
13382
13383 descP->currentWriter.env = esock_alloc_env("current-writer");
13384 descP->currentWriter.ref =
13385 CP_TERM(descP->currentWriter.env, sendRef);
13386 descP->currentWriterP = &descP->currentWriter;
13387 } else {
13388 /* Overwrite current writer registration */
13389 enif_clear_env(descP->currentWriter.env);
13390 descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef);
13391 }
13392
13393 if (COMPARE(sendRef, esock_atom_iov) == 0) {
13394 ESOCK_ASSERT( written >= 0 );
13395 /* IOV iteration - do not select */
13396 return MKT2(env, esock_atom_iov, MKI64(env, written));
13397 }
13398
13399 /* Select write for this process */
13400
13401 sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef);
13402
13403 if (sres < 0) {
13404 ERL_NIF_TERM reason;
13405
13406 /* Internal select error */
13407 ESOCK_ASSERT( DEMONP("send_check_retry - select error",
13408 env, descP, &descP->currentWriter.mon) == 0);
13409
13410 /* Fail all queued writers */
13411 reason = MKT2(env, atom_select_write, MKI(env, sres));
13412 requestor_release("send_check_retry - select error",
13413 env, descP, &descP->currentWriter);
13414 send_error_waiting_writers(env, descP, sockRef, reason);
13415 descP->currentWriterP = NULL;
13416
13417 res =
13418 enif_raise_exception(env,
13419 MKT2(env, atom_select_write,
13420 MKI(env, sres)));
13421
13422 } else {
13423 ESOCK_CNT_INC(env, descP, sockRef, atom_write_waits,
13424 &descP->writeWaits, 1);
13425
13426 descP->writeState |= ESOCK_STATE_SELECTED;
13427
13428 if (written >= 0) {
13429 /* Partial write success */
13430 res = MKT2(env, atom_select, MKI64(env, written));
13431 } else {
13432 /* No write - try again */
13433 res = atom_select;
13434 }
13435 }
13436
13437 return res;
13438 }
13439 #endif // #ifndef __WIN32__
13440
13441
13442 /* *** recv_check_reader ***
13443 *
13444 * Checks if we have a current reader and if that is us. If not,
13445 * then we must be made to wait for our turn. This is done by pushing
13446 * us unto the reader queue.
13447 * Note that we do *not* actually initiate the currentReader structure
13448 * here, since we do not actually know yet if we need to! We do that in
13449 * the [recv|recvfrom|recvmsg]_check_result function.
13450 */
13451 #ifndef __WIN32__
13452 static
recv_check_reader(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM ref,ERL_NIF_TERM * checkResult)13453 BOOLEAN_T recv_check_reader(ErlNifEnv* env,
13454 ESockDescriptor* descP,
13455 ERL_NIF_TERM ref,
13456 ERL_NIF_TERM* checkResult)
13457 {
13458 if (descP->currentReaderP != NULL) {
13459 ErlNifPid caller;
13460
13461 ESOCK_ASSERT( enif_self(env, &caller) != NULL );
13462
13463 if (COMPARE_PIDS(&descP->currentReader.pid, &caller) != 0) {
13464 /* Not the "current reader", so (maybe) push onto queue */
13465
13466 SSDBG( descP,
13467 ("SOCKET",
13468 "recv_check_reader {%d} -> not (current) reader"
13469 "\r\n ref: %T"
13470 "\r\n", descP->sock, ref) );
13471
13472 if (! reader_search4pid(env, descP, &caller)) {
13473 if (COMPARE(ref, atom_zero) == 0)
13474 goto done_ok;
13475 reader_push(env, descP, caller, ref);
13476 *checkResult = atom_select;
13477 } else {
13478 /* Reader already in queue */
13479 *checkResult = esock_raise_invalid(env, atom_state);
13480 }
13481
13482 SSDBG( descP,
13483 ("SOCKET",
13484 "recv_check_reader {%d} -> queue (push) result: %T\r\n",
13485 descP->sock, *checkResult) );
13486
13487 return FALSE;
13488 }
13489 }
13490
13491 done_ok:
13492 // Does not actually matter in this case, but ...
13493 *checkResult = esock_atom_ok;
13494 return TRUE;
13495 }
13496 #endif // #ifndef __WIN32__
13497
13498
13499 /* *** recv_init_current_reader ***
13500 *
13501 * Initiate (maybe) the currentReader structure of the descriptor.
13502 * Including monitoring the calling process.
13503 */
13504 #ifndef __WIN32__
13505 static
recv_init_current_reader(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM recvRef)13506 void recv_init_current_reader(ErlNifEnv* env,
13507 ESockDescriptor* descP,
13508 ERL_NIF_TERM recvRef)
13509 {
13510 if (descP->currentReaderP == NULL) {
13511
13512 ESOCK_ASSERT( enif_self(env, &descP->currentReader.pid) != NULL );
13513
13514 ESOCK_ASSERT( MONP("recv_init_current_reader -> current reader",
13515 env, descP,
13516 &descP->currentReader.pid,
13517 &descP->currentReader.mon) == 0);
13518 ESOCK_ASSERT(!descP->currentReader.env);
13519
13520 descP->currentReader.env = esock_alloc_env("current-reader");
13521 descP->currentReader.ref =
13522 CP_TERM(descP->currentReader.env, recvRef);
13523 descP->currentReaderP = &descP->currentReader;
13524 } else {
13525
13526 /*
13527 * This is a retry:
13528 * We have done, for instance, recv(Sock, X), but only received Y < X.
13529 * We then call recv again with size = X-Y. So, we then get a new ref.
13530 *
13531 * Make use of the existing environment
13532 */
13533
13534 enif_clear_env(descP->currentReader.env);
13535 descP->currentReader.ref = CP_TERM(descP->currentReader.env, recvRef);
13536 }
13537 }
13538 #endif // #ifndef __WIN32__
13539
13540
13541 /* *** recv_update_current_reader ***
13542 *
13543 * Demonitors the current reader process and pop's the reader queue.
13544 * If there is a waiting (reader) process, then it will be assigned
13545 * as the new current reader and a new (read) select will be done.
13546 */
13547 #ifndef __WIN32__
13548 static void
recv_update_current_reader(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)13549 recv_update_current_reader(ErlNifEnv* env,
13550 ESockDescriptor* descP,
13551 ERL_NIF_TERM sockRef)
13552 {
13553 if (descP->currentReaderP != NULL) {
13554
13555 ESOCK_ASSERT( DEMONP("recv_update_current_reader",
13556 env, descP, &descP->currentReader.mon) == 0);
13557
13558 if (! activate_next_reader(env, descP, sockRef)) {
13559
13560 SSDBG( descP,
13561 ("SOCKET",
13562 "recv_update_current_reader(%T) {%d} -> no more readers\r\n",
13563 sockRef, descP->sock) );
13564
13565 descP->currentReaderP = NULL;
13566 }
13567 }
13568 }
13569 #endif // #ifndef __WIN32__
13570
13571
13572 /* *** recv_error_current_reader ***
13573 *
13574 * Process the current reader and any waiting readers
13575 * when a read (fatal) error has occured.
13576 * All waiting readers will be "aborted", that is a
13577 * nif_abort message will be sent (with ref and reason).
13578 */
13579 #ifndef __WIN32__
13580 static
recv_error_current_reader(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM reason)13581 void recv_error_current_reader(ErlNifEnv* env,
13582 ESockDescriptor* descP,
13583 ERL_NIF_TERM sockRef,
13584 ERL_NIF_TERM reason)
13585 {
13586 if (descP->currentReaderP != NULL) {
13587 ESockRequestor req;
13588
13589 requestor_release("recv_error_current_reader",
13590 env, descP, &descP->currentReader);
13591
13592 req.env = NULL; /* read by reader_pop before free */
13593 while (reader_pop(env, descP, &req)) {
13594
13595 SSDBG( descP,
13596 ("SOCKET", "recv_error_current_reader(%T) {%d} -> abort"
13597 "\r\n pid: %T"
13598 "\r\n reason %T"
13599 "\r\n", sockRef, descP->sock,
13600 req.pid, reason) );
13601
13602 esock_send_abort_msg(env, descP, sockRef, &req, reason);
13603
13604 ESOCK_ASSERT( DEMONP("recv_error_current_reader -> pop'ed reader",
13605 env, descP, &req.mon) == 0);
13606 }
13607
13608 descP->currentReaderP = NULL;
13609 }
13610 }
13611 #endif // #ifndef __WIN32__
13612
13613
13614 /* *** recv_check_result ***
13615 *
13616 * Process the result of a call to recv.
13617 */
13618 #ifndef __WIN32__
13619 static
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)13620 ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
13621 ESockDescriptor* descP,
13622 ssize_t read,
13623 ssize_t toRead,
13624 int saveErrno,
13625 ErlNifBinary* bufP,
13626 ERL_NIF_TERM sockRef,
13627 ERL_NIF_TERM recvRef)
13628 {
13629 ERL_NIF_TERM res;
13630
13631 SSDBG( descP,
13632 ("SOCKET", "recv_check_result(%T) {%d} -> entry with"
13633 "\r\n read: %ld"
13634 "\r\n toRead: %ld"
13635 "\r\n saveErrno: %d"
13636 "\r\n recvRef: %T"
13637 "\r\n", sockRef, descP->sock,
13638 (long) read, (long) toRead, saveErrno, recvRef) );
13639
13640
13641 /* <KOLLA>
13642 *
13643 * We need to handle read = 0 for other type(s) (DGRAM) when
13644 * its actually valid to read 0 bytes.
13645 *
13646 * </KOLLA>
13647 */
13648
13649 if ((read == 0) && (descP->type == SOCK_STREAM)) {
13650 ERL_NIF_TERM reason = atom_closed;
13651 res = esock_make_error(env, reason);
13652
13653 ESOCK_CNT_INC(env, descP, sockRef,
13654 atom_read_fails, &descP->readFails, 1);
13655
13656 /*
13657 * When a stream socket peer has performed an orderly shutdown,
13658 * the return value will be 0 (the traditional "end-of-file" return).
13659 *
13660 * *We* do never actually try to read 0 bytes!
13661 *
13662 * We must also notify any waiting readers!
13663 */
13664
13665 recv_error_current_reader(env, descP, sockRef, reason);
13666
13667 FREE_BIN(bufP);
13668
13669 } else {
13670
13671 /* There is a special case: If the provided 'to read' value is
13672 * zero (0) (only for type =/= stream).
13673 * That means that we read as much as we can, using the default
13674 * read buffer size.
13675 */
13676
13677 if (bufP->size == read) {
13678
13679 /* +++ We filled the buffer +++ */
13680
13681 SSDBG( descP,
13682 ("SOCKET",
13683 "recv_check_result(%T) {%d} -> [%lu] filled the buffer\r\n",
13684 sockRef, descP->sock, (unsigned long) bufP->size) );
13685
13686 res = recv_check_full(env, descP, read, toRead, bufP,
13687 sockRef, recvRef);
13688
13689 } else if (read < 0) {
13690
13691 /* +++ Error handling +++ */
13692
13693 res = recv_check_fail(env, descP, saveErrno, bufP, NULL,
13694 sockRef, recvRef);
13695
13696 } else {
13697
13698 /* +++ We did not fill the buffer +++ */
13699
13700 SSDBG( descP,
13701 ("SOCKET",
13702 "recv_check_result(%T) {%d} -> [%lu] "
13703 "did not fill the buffer (%ld)\r\n",
13704 sockRef, descP->sock, (unsigned long) bufP->size,
13705 (long) read) );
13706
13707 res = recv_check_partial(env, descP, read, toRead, bufP,
13708 sockRef, recvRef);
13709 }
13710 }
13711
13712 return res;
13713 }
13714 #endif // #ifndef __WIN32__
13715
13716
13717 /* *** recv_check_full ***
13718 *
13719 * This function is called if we filled the allocated buffer.
13720 * But are we done yet?
13721 *
13722 * toRead = 0 means: Give me everything you have => maybe
13723 * toRead > 0 means: Yes
13724 */
13725 #ifndef __WIN32__
13726 static
recv_check_full(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ssize_t toRead,ErlNifBinary * bufP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)13727 ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
13728 ESockDescriptor* descP,
13729 ssize_t read,
13730 ssize_t toRead,
13731 ErlNifBinary* bufP,
13732 ERL_NIF_TERM sockRef,
13733 ERL_NIF_TERM recvRef)
13734 {
13735 ERL_NIF_TERM res;
13736
13737 if ((toRead == 0) &&
13738 (descP->type == SOCK_STREAM)) {
13739
13740 /* +++ Give us everything you have got => *
13741 * (maybe) needs to continue +++ */
13742
13743 /* Send up each chunk of data for each of the read
13744 * and let the erlang code assemble it: {more, Bin}
13745 * (when complete it should return {ok, Bin}).
13746 * We need to read atleast one more time to be sure if its
13747 * done...
13748 *
13749 * Also, we need to check if the rNumCnt has reached its max (rNum),
13750 * in which case we will assume the read to be done!
13751 */
13752
13753 SSDBG( descP,
13754 ("SOCKET", "recv_check_full(%T) {%d} -> shall we continue reading?"
13755 "\r\n read: %ld"
13756 "\r\n rNum: %u"
13757 "\r\n rNumCnt: %u"
13758 "\r\n", sockRef, descP->sock,
13759 (unsigned long) read, descP->rNum, descP->rNumCnt) );
13760
13761 res = recv_check_full_maybe_done(env, descP, read, bufP,
13762 sockRef, recvRef);
13763
13764 } else {
13765
13766 /* +++ We got exactly as much as we requested => We are done +++ */
13767
13768 SSDBG( descP,
13769 ("SOCKET",
13770 "recv_check_full(%T) {%d} -> [%ld] "
13771 "we got exactly what we could fit\r\n",
13772 sockRef, descP->sock, (long) toRead) );
13773
13774 res = recv_check_full_done(env, descP, read, bufP, sockRef);
13775
13776 }
13777
13778 return res;
13779
13780 }
13781 #endif // #ifndef __WIN32__
13782
13783
13784 /* *** recv_check_full_maybe_done ***
13785 *
13786 * Send up each chunk of data for each of the read
13787 * and let the erlang code assemble it: {more, Bin}
13788 * (when complete it should return {ok, Bin}).
13789 * We need to read at least one more time to be sure if its
13790 * done...
13791 *
13792 * Also, we need to check if the rNumCnt has reached its max (rNum),
13793 * in which case we will assume the read to be done!
13794 */
13795 #ifndef __WIN32__
13796 static
recv_check_full_maybe_done(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ErlNifBinary * bufP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)13797 ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
13798 ESockDescriptor* descP,
13799 ssize_t read,
13800 ErlNifBinary* bufP,
13801 ERL_NIF_TERM sockRef,
13802 ERL_NIF_TERM recvRef)
13803 {
13804 ESOCK_CNT_INC(env, descP, sockRef,
13805 atom_read_byte, &descP->readByteCnt, read);
13806 descP->readPkgMaxCnt += read;
13807
13808 descP->rNumCnt++;
13809 if (descP->rNumCnt >= descP->rNum) {
13810
13811 descP->rNumCnt = 0;
13812
13813 ESOCK_CNT_INC(env, descP, sockRef,
13814 atom_read_pkg, &descP->readPkgCnt, 1);
13815 if (descP->readPkgMaxCnt > descP->readPkgMax)
13816 descP->readPkgMax = descP->readPkgMaxCnt;
13817 descP->readPkgMaxCnt = 0;
13818
13819 recv_update_current_reader(env, descP, sockRef);
13820
13821 /* This transfers "ownership" of the *allocated* binary to an
13822 * erlang term (no need for an explicit free).
13823 */
13824
13825 return esock_make_ok2(env, MKBIN(env, bufP));
13826
13827 }
13828
13829 /* Yes, we *do* need to continue reading */
13830
13831 recv_init_current_reader(env, descP, recvRef);
13832
13833 /* This transfers "ownership" of the *allocated* binary to an
13834 * erlang term (no need for an explicit free).
13835 */
13836
13837 SSDBG( descP,
13838 ("SOCKET",
13839 "recv_check_full_maybe_done(%T) {%d} -> [%lu] "
13840 "we are done for now - read more\r\n",
13841 sockRef, descP->sock, (unsigned long)bufP->size) );
13842
13843 return MKT2(env, esock_atom_more, MKBIN(env, bufP));
13844 }
13845 #endif // #ifndef __WIN32__
13846
13847
13848 /* *** recv_check_full_done ***
13849 *
13850 * A successful recv and we filled the buffer.
13851 */
13852 #ifndef __WIN32__
13853 static
recv_check_full_done(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ErlNifBinary * bufP,ERL_NIF_TERM sockRef)13854 ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
13855 ESockDescriptor* descP,
13856 ssize_t read,
13857 ErlNifBinary* bufP,
13858 ERL_NIF_TERM sockRef)
13859 {
13860 ERL_NIF_TERM data;
13861
13862 ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
13863 ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
13864 &descP->readByteCnt, read);
13865
13866 descP->readPkgMaxCnt += read;
13867 if (descP->readPkgMaxCnt > descP->readPkgMax)
13868 descP->readPkgMax = descP->readPkgMaxCnt;
13869 descP->readPkgMaxCnt = 0;
13870
13871 recv_update_current_reader(env, descP, sockRef);
13872
13873 /* This transfers "ownership" of the *allocated* binary to an
13874 * erlang term (no need for an explicit free).
13875 */
13876 data = MKBIN(env, bufP);
13877
13878 return esock_make_ok2(env, data);
13879 }
13880 #endif // #ifndef __WIN32__
13881
13882
13883 /* *** recv_check_fail ***
13884 *
13885 * Handle recv failure.
13886 */
13887 #ifndef __WIN32__
13888 static
recv_check_fail(ErlNifEnv * env,ESockDescriptor * descP,int saveErrno,ErlNifBinary * buf1P,ErlNifBinary * buf2P,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)13889 ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
13890 ESockDescriptor* descP,
13891 int saveErrno,
13892 ErlNifBinary* buf1P,
13893 ErlNifBinary* buf2P,
13894 ERL_NIF_TERM sockRef,
13895 ERL_NIF_TERM recvRef)
13896 {
13897 ERL_NIF_TERM res;
13898
13899 FREE_BIN(buf1P);
13900 if (buf2P != NULL) FREE_BIN(buf2P);
13901
13902 if (saveErrno == ECONNRESET) {
13903
13904 /* +++ Oops - closed +++ */
13905
13906 SSDBG( descP,
13907 ("SOCKET",
13908 "recv_check_fail(%T) {%d} -> econnreset: closed"
13909 "\r\n recvRef: %T"
13910 "\r\n", sockRef, descP->sock, recvRef) );
13911
13912 // This is a bit overkill (to count here), but just in case...
13913 ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails,
13914 &descP->readFails, 1);
13915
13916 res = recv_check_fail_econnreset(env, descP, sockRef, recvRef);
13917
13918 } else if ((saveErrno == ERRNO_BLOCK) ||
13919 (saveErrno == EAGAIN)) {
13920
13921 SSDBG( descP,
13922 ("SOCKET",
13923 "recv_check_fail(%T) {%d} -> eagain"
13924 "\r\n recvRef: %T"
13925 "\r\n", sockRef, descP->sock, recvRef) );
13926
13927 if (COMPARE(recvRef, atom_zero) == 0)
13928 res = esock_atom_ok;
13929 else
13930 res = recv_check_retry(env, descP, sockRef, recvRef);
13931
13932 } else {
13933
13934 SSDBG( descP,
13935 ("SOCKET",
13936 "recv_check_fail(%T) {%d} -> errno: %d\r\n"
13937 "\r\n recvRef: %T"
13938 "\r\n", sockRef, descP->sock, saveErrno, recvRef) );
13939
13940 ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails,
13941 &descP->readFails, 1);
13942
13943 res = recv_check_fail_gen(env, descP, saveErrno, sockRef);
13944 }
13945
13946 return res;
13947 }
13948 #endif // #ifndef __WIN32__
13949
13950
13951 /* *** recv_check_fail_econnreset ***
13952 *
13953 * We detected that the socket was closed wile reading.
13954 * Inform current and waiting readers.
13955 */
13956 #ifndef __WIN32__
13957 static
recv_check_fail_econnreset(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)13958 ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env,
13959 ESockDescriptor* descP,
13960 ERL_NIF_TERM sockRef,
13961 ERL_NIF_TERM recvRef)
13962 {
13963 ERL_NIF_TERM reason = MKA(env, erl_errno_id(ECONNRESET));
13964 ERL_NIF_TERM res = esock_make_error(env, reason);
13965
13966 /* <KOLLA>
13967 *
13968 * IF THE CURRENT PROCESS IS *NOT* THE CONTROLLING
13969 * PROCESS, WE NEED TO INFORM IT!!!
13970 *
13971 * ALL WAITING PROCESSES MUST ALSO GET THE ERROR!!
13972 * HANDLED BY THE STOP (CALLBACK) FUNCTION?
13973 *
13974 * SINCE THIS IS A REMOTE CLOSE, WE DON'T NEED TO WAIT
13975 * FOR OUTPUT TO BE WRITTEN (NO ONE WILL READ), JUST
13976 * ABORT THE SOCKET REGARDLESS OF LINGER???
13977 *
13978 * </KOLLA>
13979 */
13980
13981 recv_error_current_reader(env, descP, sockRef, reason);
13982
13983 return res;
13984 }
13985 #endif // #ifndef __WIN32__
13986
13987
13988 /* *** recv_check_retry ***
13989 *
13990 * The recv call would have blocked, so retry.
13991 */
13992 #ifndef __WIN32__
13993 static
recv_check_retry(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)13994 ERL_NIF_TERM recv_check_retry(ErlNifEnv* env,
13995 ESockDescriptor* descP,
13996 ERL_NIF_TERM sockRef,
13997 ERL_NIF_TERM recvRef)
13998 {
13999 int sres;
14000 ERL_NIF_TERM res;
14001
14002 descP->rNumCnt = 0;
14003 recv_init_current_reader(env, descP, recvRef);
14004
14005 SSDBG( descP,
14006 ("SOCKET",
14007 "recv_check_retry(%T) {%d} -> SELECT for more"
14008 "\r\n recvRef: %T"
14009 "\r\n", sockRef, descP->sock, recvRef) );
14010
14011 if ((sres = esock_select_read(env, descP->sock, descP, NULL,
14012 sockRef, recvRef)) < 0) {
14013 /* Unlikely that any next reader will have better luck,
14014 * but why not give them a shot - the queue will be cleared
14015 */
14016 recv_update_current_reader(env, descP, sockRef);
14017
14018 res =
14019 enif_raise_exception(env,
14020 MKT2(env, atom_select_read,
14021 MKI(env, sres)));
14022 } else {
14023 descP->readState |= ESOCK_STATE_SELECTED;
14024 res = atom_select;
14025 }
14026
14027 return res;
14028 }
14029 #endif // #ifndef __WIN32__
14030
14031
14032 /* *** recv_check_fail_gen ***
14033 *
14034 * The recv call had a "general" failure.
14035 */
14036 #ifndef __WIN32__
14037 static
recv_check_fail_gen(ErlNifEnv * env,ESockDescriptor * descP,int saveErrno,ERL_NIF_TERM sockRef)14038 ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env,
14039 ESockDescriptor* descP,
14040 int saveErrno,
14041 ERL_NIF_TERM sockRef)
14042 {
14043 ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno));
14044
14045 recv_error_current_reader(env, descP, sockRef, reason);
14046
14047 return esock_make_error(env, reason);
14048 }
14049 #endif // #ifndef __WIN32__
14050
14051
14052 /* *** recv_check_partial ***
14053 *
14054 * Handle a sucessful recv which only partly filled the specified buffer.
14055 */
14056 #ifndef __WIN32__
14057 static
recv_check_partial(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ssize_t toRead,ErlNifBinary * bufP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)14058 ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
14059 ESockDescriptor* descP,
14060 ssize_t read,
14061 ssize_t toRead,
14062 ErlNifBinary* bufP,
14063 ERL_NIF_TERM sockRef,
14064 ERL_NIF_TERM recvRef)
14065 {
14066 ERL_NIF_TERM res;
14067
14068 if ((toRead == 0) ||
14069 (descP->type != SOCK_STREAM) ||
14070 (COMPARE(recvRef, atom_zero) == 0)) {
14071
14072 /* +++ We got it all, but since we +++
14073 * +++ did not fill the buffer, we +++
14074 * +++ must split it into a sub-binary. +++
14075 */
14076
14077 SSDBG( descP,
14078 ("SOCKET",
14079 "recv_check_partial(%T) {%d} -> [%ld] split buffer"
14080 "\r\n recvRef: %T"
14081 "\r\n", sockRef, descP->sock, (long) toRead,
14082 recvRef) );
14083
14084 res = recv_check_partial_done(env, descP, read, bufP, sockRef);
14085
14086 } else {
14087 /* A stream socket with specified read size
14088 * and not a polling read, we got a partial read
14089 * - return a select result to initiate a retry
14090 */
14091
14092 SSDBG( descP,
14093 ("SOCKET",
14094 "recv_check_partial(%T) {%d} -> [%ld]"
14095 " only part of message - expect more"
14096 "\r\n recvRef: %T"
14097 "\r\n", sockRef, descP->sock, (long) toRead,
14098 recvRef) );
14099
14100 res =
14101 recv_check_partial_part(env, descP, read,
14102 bufP, sockRef, recvRef);
14103 }
14104
14105 return res;
14106 }
14107 #endif // #ifndef __WIN32__
14108
14109
14110 /* *** recv_check_partial_done ***
14111 *
14112 * A successful but only partial recv, which fulfilled the required read.
14113 */
14114 #ifndef __WIN32__
14115 static
recv_check_partial_done(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ErlNifBinary * bufP,ERL_NIF_TERM sockRef)14116 ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
14117 ESockDescriptor* descP,
14118 ssize_t read,
14119 ErlNifBinary* bufP,
14120 ERL_NIF_TERM sockRef)
14121 {
14122 ERL_NIF_TERM data;
14123
14124 descP->rNumCnt = 0;
14125 ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
14126 ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
14127 &descP->readByteCnt, read);
14128
14129 descP->readPkgMaxCnt += read;
14130 if (descP->readPkgMaxCnt > descP->readPkgMax)
14131 descP->readPkgMax = descP->readPkgMaxCnt;
14132 descP->readPkgMaxCnt = 0;
14133
14134 recv_update_current_reader(env, descP, sockRef);
14135
14136 /* This transfers "ownership" of the *allocated* binary to an
14137 * erlang term (no need for an explicit free).
14138 */
14139 data = MKBIN(env, bufP);
14140 data = MKSBIN(env, data, 0, read);
14141
14142 SSDBG( descP,
14143 ("SOCKET", "recv_check_partial_done(%T) {%d} -> [%ld] done\r\n",
14144 sockRef, descP->sock, (long) read) );
14145
14146 return esock_make_ok2(env, data);
14147 }
14148 #endif // #ifndef __WIN32__
14149
14150
14151 /* *** recv_check_partial_part ***
14152 *
14153 * A successful but only partial recv, which only partly fulfilled
14154 * the required read.
14155 */
14156 #ifndef __WIN32__
14157 static
recv_check_partial_part(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,ErlNifBinary * bufP,ERL_NIF_TERM sockRef,ERL_NIF_TERM recvRef)14158 ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
14159 ESockDescriptor* descP,
14160 ssize_t read,
14161 ErlNifBinary* bufP,
14162 ERL_NIF_TERM sockRef,
14163 ERL_NIF_TERM recvRef)
14164 {
14165 ERL_NIF_TERM res;
14166 int sres;
14167
14168 ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
14169 &descP->readByteCnt, read);
14170
14171 recv_init_current_reader(env, descP, recvRef);
14172
14173 /* SELECT for more data */
14174
14175 sres = esock_select_read(env, descP->sock, descP, NULL,
14176 sockRef, recvRef);
14177 if (sres < 0) {
14178 /* Unlikely that any next reader will have better luck,
14179 * but why not give them a shot - the queue will be cleared
14180 */
14181 recv_update_current_reader(env, descP, sockRef);
14182
14183 res =
14184 enif_raise_exception(env,
14185 MKT2(env, atom_select_read,
14186 MKI(env, sres)));
14187 } else {
14188 ERL_NIF_TERM data;
14189
14190 descP->readState |= ESOCK_STATE_SELECTED;
14191 data = MKBIN(env, bufP);
14192 data = MKSBIN(env, data, 0, read);
14193 res = MKT2(env, atom_select, data);
14194 }
14195
14196 /* This transfers "ownership" of the *allocated* binary to an
14197 * erlang term (no need for an explicit free).
14198 */
14199 return res;
14200 }
14201 #endif // #ifndef __WIN32__
14202
14203
14204
14205
14206 /* The recvfrom function delivers one (1) message. If our buffer
14207 * is too small, the message will be truncated. So, regardless
14208 * if we filled the buffer or not, we have got what we are going
14209 * to get regarding this message.
14210 */
14211 #ifndef __WIN32__
14212 static
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)14213 ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
14214 ESockDescriptor* descP,
14215 ssize_t read,
14216 int saveErrno,
14217 ErlNifBinary* bufP,
14218 ESockAddress* fromAddrP,
14219 SOCKLEN_T fromAddrLen,
14220 ERL_NIF_TERM sockRef,
14221 ERL_NIF_TERM recvRef)
14222 {
14223 ERL_NIF_TERM data, res;
14224
14225 SSDBG( descP,
14226 ("SOCKET", "recvfrom_check_result(%T) {%d} -> entry with"
14227 "\r\n read: %ld"
14228 "\r\n saveErrno: %d"
14229 "\r\n recvRef: %T"
14230 "\r\n", sockRef, descP->sock,
14231 (long) read, saveErrno, recvRef) );
14232
14233 /* <KOLLA>
14234 *
14235 * We need to handle read = 0 for non_stream socket type(s) when
14236 * its actually valid to read 0 bytes.
14237 *
14238 * </KOLLA>
14239 */
14240
14241 if ((read == 0) && (descP->type == SOCK_STREAM)) {
14242
14243 /*
14244 * When a stream socket peer has performed an orderly shutdown,
14245 * the return value will be 0 (the traditional "end-of-file" return).
14246 *
14247 * *We* do never actually try to read 0 bytes!
14248 */
14249
14250 ESOCK_CNT_INC(env, descP, sockRef,
14251 atom_read_fails, &descP->readFails, 1);
14252
14253 FREE_BIN(bufP);
14254
14255 return esock_make_error(env, atom_closed);
14256 }
14257
14258 if (read < 0) {
14259
14260 /* +++ Error handling +++ */
14261
14262 res = recv_check_fail(env, descP, saveErrno, bufP, NULL,
14263 sockRef, recvRef);
14264
14265 } else {
14266
14267 /* +++ We sucessfully got a message - time to encode the address +++ */
14268
14269 ERL_NIF_TERM eSockAddr;
14270
14271 esock_encode_sockaddr(env,
14272 fromAddrP, fromAddrLen,
14273 &eSockAddr);
14274
14275 if (read == bufP->size) {
14276
14277 data = MKBIN(env, bufP);
14278
14279 } else {
14280
14281 /* +++ We got a chunk of data but +++
14282 * +++ since we did not fill the +++
14283 * +++ buffer, we must split it +++
14284 * +++ into a sub-binary. +++
14285 */
14286
14287 data = MKBIN(env, bufP);
14288 data = MKSBIN(env, data, 0, read);
14289 }
14290
14291 ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg,
14292 &descP->readPkgCnt, 1);
14293 ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
14294 &descP->readByteCnt, read);
14295
14296 recv_update_current_reader(env, descP, sockRef);
14297
14298 res = esock_make_ok2(env, MKT2(env, eSockAddr, data));
14299
14300 }
14301
14302 return res;
14303
14304 }
14305 #endif // #ifndef __WIN32__
14306
14307
14308
14309 /* *** recvmsg_check_result ***
14310 *
14311 * The recvmsg function delivers one (1) message. If our buffer
14312 * is to small, the message will be truncated. So, regardless
14313 * if we filled the buffer or not, we have got what we are going
14314 * to get regarding this message.
14315 */
14316 #ifndef __WIN32__
14317 static
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)14318 ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
14319 ESockDescriptor* descP,
14320 ssize_t read,
14321 int saveErrno,
14322 struct msghdr* msgHdrP,
14323 ErlNifBinary* dataBufP,
14324 ErlNifBinary* ctrlBufP,
14325 ERL_NIF_TERM sockRef,
14326 ERL_NIF_TERM recvRef)
14327 {
14328 ERL_NIF_TERM res;
14329
14330 SSDBG( descP,
14331 ("SOCKET", "recvmsg_check_result(%T) {%d} -> entry with"
14332 "\r\n read: %ld"
14333 "\r\n saveErrno: %d"
14334 "\r\n recvRef: %T"
14335 "\r\n", sockRef, descP->sock,
14336 (long) read, saveErrno, recvRef) );
14337
14338
14339 /* <KOLLA>
14340 *
14341 * We need to handle read = 0 for non_stream socket type(s) when
14342 * its actually valid to read 0 bytes.
14343 *
14344 * </KOLLA>
14345 */
14346
14347 if ((read == 0) && (descP->type == SOCK_STREAM)) {
14348
14349 /*
14350 * When a stream socket peer has performed an orderly shutdown,
14351 * the return value will be 0 (the traditional "end-of-file" return).
14352 *
14353 * *We* do never actually try to read 0 bytes!
14354 */
14355
14356 ESOCK_CNT_INC(env, descP, sockRef,
14357 atom_read_fails, &descP->readFails, 1);
14358
14359 FREE_BIN(dataBufP); FREE_BIN(ctrlBufP);
14360
14361 return esock_make_error(env, atom_closed);
14362 }
14363
14364
14365 if (read < 0) {
14366
14367 /* +++ Error handling +++ */
14368
14369 res = recv_check_fail(env, descP, saveErrno, dataBufP, ctrlBufP,
14370 sockRef, recvRef);
14371
14372 } else {
14373
14374 /* +++ We sucessfully got a message - time to encode it +++ */
14375
14376 res = recvmsg_check_msg(env, descP, read, msgHdrP,
14377 dataBufP, ctrlBufP, sockRef);
14378
14379 }
14380
14381 return res;
14382
14383 }
14384 #endif // #ifndef __WIN32__
14385
14386
14387 /* *** recvmsg_check_msg ***
14388 *
14389 * We successfully read one message. Time to process.
14390 */
14391 #ifndef __WIN32__
14392 static
recvmsg_check_msg(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,struct msghdr * msgHdrP,ErlNifBinary * dataBufP,ErlNifBinary * ctrlBufP,ERL_NIF_TERM sockRef)14393 ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
14394 ESockDescriptor* descP,
14395 ssize_t read,
14396 struct msghdr* msgHdrP,
14397 ErlNifBinary* dataBufP,
14398 ErlNifBinary* ctrlBufP,
14399 ERL_NIF_TERM sockRef)
14400 {
14401 ERL_NIF_TERM eMsg;
14402
14403 /*
14404 * <KOLLA>
14405 *
14406 * The return value of recvmsg is the *total* number of bytes
14407 * that where successfully read. This data has been put into
14408 * the *IO vector*.
14409 *
14410 * </KOLLA>
14411 */
14412
14413 encode_msg(env, descP,
14414 read, msgHdrP, dataBufP, ctrlBufP,
14415 &eMsg);
14416
14417 SSDBG( descP,
14418 ("SOCKET", "recvmsg_check_result(%T) {%d} -> ok\r\n",
14419 sockRef, descP->sock) );
14420
14421 ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
14422 ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
14423 &descP->readByteCnt, read);
14424
14425 recv_update_current_reader(env, descP, sockRef);
14426
14427 return esock_make_ok2(env, eMsg);
14428 }
14429 #endif // #ifndef __WIN32__
14430
14431
14432 /* +++ encode_msg +++
14433 *
14434 * Encode a msg() (recvmsg). In erlang its represented as
14435 * a map, which has a specific set of attributes:
14436 *
14437 * addr (source address) - sockaddr()
14438 * iov - [binary()]
14439 * ctrl - [cmsg()]
14440 * flags - msg_flags()
14441 */
14442 #ifndef __WIN32__
14443 static
encode_msg(ErlNifEnv * env,ESockDescriptor * descP,ssize_t read,struct msghdr * msgHdrP,ErlNifBinary * dataBufP,ErlNifBinary * ctrlBufP,ERL_NIF_TERM * eSockAddr)14444 void encode_msg(ErlNifEnv* env,
14445 ESockDescriptor* descP,
14446 ssize_t read,
14447 struct msghdr* msgHdrP,
14448 ErlNifBinary* dataBufP,
14449 ErlNifBinary* ctrlBufP,
14450 ERL_NIF_TERM* eSockAddr)
14451 {
14452 ERL_NIF_TERM addr, iov, ctrl, flags;
14453
14454 SSDBG( descP,
14455 ("SOCKET", "encode_msg {%d} -> entry with"
14456 "\r\n read: %ld"
14457 "\r\n", descP->sock, (long) read) );
14458
14459 /* The address is not used if we are connected (unless, maybe,
14460 * family is 'local'), so check (length = 0) before we try to encodel
14461 */
14462 if (msgHdrP->msg_namelen != 0) {
14463 esock_encode_sockaddr(env,
14464 (ESockAddress*) msgHdrP->msg_name,
14465 msgHdrP->msg_namelen,
14466 &addr);
14467 } else {
14468 addr = esock_atom_undefined;
14469 }
14470
14471 SSDBG( descP,
14472 ("SOCKET", "encode_msg {%d} -> encode iov"
14473 "\r\n msg_iovlen: %lu"
14474 "\r\n",
14475 descP->sock,
14476 (unsigned long) msgHdrP->msg_iovlen) );
14477
14478 esock_encode_iov(env, read,
14479 msgHdrP->msg_iov, msgHdrP->msg_iovlen, dataBufP,
14480 &iov);
14481
14482 SSDBG( descP,
14483 ("SOCKET",
14484 "encode_msg {%d} -> try encode cmsgs\r\n",
14485 descP->sock) );
14486
14487 encode_cmsgs(env, descP, ctrlBufP, msgHdrP, &ctrl);
14488
14489 SSDBG( descP,
14490 ("SOCKET",
14491 "encode_msg {%d} -> try encode flags\r\n",
14492 descP->sock) );
14493
14494 encode_msg_flags(env, descP, msgHdrP->msg_flags, &flags);
14495
14496 SSDBG( descP,
14497 ("SOCKET", "encode_msg {%d} -> components encoded:"
14498 "\r\n addr: %T"
14499 "\r\n ctrl: %T"
14500 "\r\n flags: %T"
14501 "\r\n", descP->sock, addr, ctrl, flags) );
14502
14503 {
14504 ERL_NIF_TERM keys[] = {esock_atom_iov,
14505 esock_atom_ctrl,
14506 esock_atom_flags,
14507 esock_atom_addr};
14508 ERL_NIF_TERM vals[] = {iov, ctrl, flags, addr};
14509 size_t numKeys = NUM(keys);
14510
14511 ESOCK_ASSERT( numKeys == NUM(vals) );
14512
14513 SSDBG( descP,
14514 ("SOCKET",
14515 "encode_msg {%d} -> create map\r\n",
14516 descP->sock) );
14517
14518 if (msgHdrP->msg_namelen == 0)
14519 numKeys--; // No addr
14520 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eSockAddr) );
14521
14522 SSDBG( descP,
14523 ("SOCKET",
14524 "encode_msg {%d}-> map encoded\r\n",
14525 descP->sock) );
14526 }
14527
14528 SSDBG( descP,
14529 ("SOCKET", "encode_msg {%d} -> done\r\n", descP->sock) );
14530 }
14531 #endif // #ifndef __WIN32__
14532
14533
14534
14535 /* +++ encode_cmsgs +++
14536 *
14537 * Encode a list of cmsg(). There can be 0 or more cmsghdr "blocks".
14538 *
14539 * Our "problem" is that we have no idea how many control messages
14540 * we have.
14541 *
14542 * The cmsgHdrP arguments points to the start of the control data buffer,
14543 * an actual binary. Its the only way to create sub-binaries. So, what we
14544 * need to continue processing this is to turn that into an binary erlang
14545 * term (which can then in turn be turned into sub-binaries).
14546 *
14547 * We need the cmsgBufP (even though cmsgHdrP points to it) to be able
14548 * to create sub-binaries (one for each cmsg hdr).
14549 *
14550 * The TArray (term array) is created with the size of 128, which should
14551 * be enough. But if its not, then it will be automatically realloc'ed during
14552 * add. Once we are done adding hdr's to it, we convert the tarray to a list.
14553 */
14554 #ifndef __WIN32__
14555 static
encode_cmsgs(ErlNifEnv * env,ESockDescriptor * descP,ErlNifBinary * cmsgBinP,struct msghdr * msgHdrP,ERL_NIF_TERM * eCMsg)14556 void encode_cmsgs(ErlNifEnv* env,
14557 ESockDescriptor* descP,
14558 ErlNifBinary* cmsgBinP,
14559 struct msghdr* msgHdrP,
14560 ERL_NIF_TERM* eCMsg)
14561 {
14562 ERL_NIF_TERM ctrlBuf = MKBIN(env, cmsgBinP); // The *entire* binary
14563 SocketTArray cmsghdrs = TARRAY_CREATE(128);
14564 struct cmsghdr* firstP = CMSG_FIRSTHDR(msgHdrP);
14565 struct cmsghdr* currentP;
14566
14567 SSDBG( descP, ("SOCKET", "encode_cmsgs {%d} -> entry when"
14568 "\r\n msg ctrl len: %d"
14569 "\r\n (ctrl) firstP: 0x%lX"
14570 "\r\n", descP->sock,
14571 msgHdrP->msg_controllen, firstP) );
14572
14573 for (currentP = firstP;
14574 /*
14575 * In *old* versions of darwin, the CMSG_FIRSTHDR does not
14576 * check the msg_controllen, so we do it here.
14577 * We should really test this stuff during configure,
14578 * but for now, this will have to do.
14579 */
14580 #if defined(__DARWIN__)
14581 (msgHdrP->msg_controllen >= sizeof(struct cmsghdr)) &&
14582 (currentP != NULL);
14583 #else
14584 (currentP != NULL);
14585 #endif
14586 currentP = CMSG_NXTHDR(msgHdrP, currentP)) {
14587
14588 SSDBG( descP,
14589 ("SOCKET", "encode_cmsgs {%d} -> process cmsg header when"
14590 "\r\n TArray Size: %d"
14591 "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) );
14592
14593 /* MUST check this since on Linux the returned "cmsg" may actually
14594 * go too far!
14595 */
14596 if (((CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP)) >
14597 msgHdrP->msg_controllen) {
14598
14599 /* Ouch, fatal error - give up
14600 * We assume we cannot trust any data if this is wrong.
14601 */
14602
14603 SSDBG( descP,
14604 ("SOCKET", "encode_cmsgs {%d} -> check failed when: "
14605 "\r\n currentP: 0x%lX"
14606 "\r\n (current) cmsg_len: %d"
14607 "\r\n firstP: 0x%lX"
14608 "\r\n => %d"
14609 "\r\n msg ctrl len: %d"
14610 "\r\n", descP->sock,
14611 CHARP(currentP), currentP->cmsg_len, CHARP(firstP),
14612 (CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP),
14613 msgHdrP->msg_controllen) );
14614
14615 TARRAY_ADD(cmsghdrs, esock_atom_bad_data);
14616 break;
14617
14618 } else {
14619 unsigned char* dataP = UCHARP(CMSG_DATA(currentP));
14620 size_t dataPos = dataP - cmsgBinP->data;
14621 size_t dataLen =
14622 (UCHARP(currentP) + currentP->cmsg_len) - dataP;
14623 ERL_NIF_TERM
14624 cmsgHdr,
14625 keys[] =
14626 {esock_atom_level,
14627 esock_atom_type,
14628 esock_atom_data,
14629 atom_value},
14630 vals[NUM(keys)];
14631 size_t numKeys = NUM(keys);
14632 BOOLEAN_T have_value;
14633
14634 SSDBG( descP,
14635 ("SOCKET", "encode_cmsgs {%d} -> cmsg header data: "
14636 "\r\n dataPos: %d"
14637 "\r\n dataLen: %d"
14638 "\r\n", descP->sock, dataPos, dataLen) );
14639
14640 vals[0] = esock_encode_level(env, currentP->cmsg_level);
14641 vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen);
14642 have_value =
14643 encode_cmsg(env,
14644 currentP->cmsg_level,
14645 currentP->cmsg_type,
14646 dataP, dataLen, &vals[1], &vals[3]);
14647
14648 SSDBG( descP,
14649 ("SOCKET", "encode_cmsgs {%d} -> "
14650 "\r\n %T: %T"
14651 "\r\n %T: %T"
14652 "\r\n %T: %T"
14653 "\r\n", descP->sock,
14654 keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) );
14655 if (have_value)
14656 SSDBG( descP,
14657 ("SOCKET", "encode_cmsgs {%d} -> "
14658 "\r\n %T: %T"
14659 "\r\n", descP->sock, keys[3], vals[3]) );
14660
14661 /* Guard agains cut-and-paste errors */
14662 ESOCK_ASSERT( numKeys == NUM(vals) );
14663 ESOCK_ASSERT( MKMA(env, keys, vals,
14664 numKeys - (have_value ? 0 : 1), &cmsgHdr) );
14665
14666 /* And finally add it to the list... */
14667 TARRAY_ADD(cmsghdrs, cmsgHdr);
14668 }
14669 }
14670
14671 SSDBG( descP,
14672 ("SOCKET", "encode_cmsgs {%d} -> cmsg headers processed when"
14673 "\r\n TArray Size: %d"
14674 "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) );
14675
14676 /* The tarray is populated - convert it to a list */
14677 TARRAY_TOLIST(cmsghdrs, env, eCMsg);
14678 }
14679 #endif // #ifndef __WIN32__
14680
14681
14682
14683 #ifndef __WIN32__
14684 #ifdef SCM_TIMESTAMP
14685 static
esock_cmsg_encode_timeval(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14686 BOOLEAN_T esock_cmsg_encode_timeval(ErlNifEnv *env,
14687 unsigned char *data,
14688 size_t dataLen,
14689 ERL_NIF_TERM *eResult) {
14690 struct timeval* timeP = (struct timeval *) data;
14691
14692 if (dataLen < sizeof(*timeP))
14693 return FALSE;
14694
14695 esock_encode_timeval(env, timeP, eResult);
14696 return TRUE;
14697 }
14698
esock_cmsg_decode_timeval(ErlNifEnv * env,ERL_NIF_TERM eValue,struct cmsghdr * cmsgP,size_t rem,size_t * usedP)14699 static BOOLEAN_T esock_cmsg_decode_timeval(ErlNifEnv *env,
14700 ERL_NIF_TERM eValue,
14701 struct cmsghdr *cmsgP,
14702 size_t rem,
14703 size_t *usedP)
14704 {
14705 struct timeval time, *timeP;
14706
14707 if (! esock_decode_timeval(env, eValue, &time))
14708 return FALSE;
14709
14710 if ((timeP = init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL)
14711 return FALSE;
14712
14713 *timeP = time;
14714 return TRUE;
14715 }
14716 #endif
14717 #endif
14718
14719
14720 #ifndef __WIN32__
14721 #if defined(IP_TOS) || defined(IP_RECVTOS)
14722 static
esock_cmsg_encode_ip_tos(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14723 BOOLEAN_T esock_cmsg_encode_ip_tos(ErlNifEnv *env,
14724 unsigned char *data,
14725 size_t dataLen,
14726 ERL_NIF_TERM *eResult)
14727 {
14728 unsigned char tos;
14729
14730 if (dataLen < sizeof(tos))
14731 return FALSE;
14732
14733 tos = *data;
14734
14735 *eResult = encode_ip_tos(env, tos);
14736 return TRUE;
14737 }
14738
esock_cmsg_decode_ip_tos(ErlNifEnv * env,ERL_NIF_TERM eValue,struct cmsghdr * cmsgP,size_t rem,size_t * usedP)14739 static BOOLEAN_T esock_cmsg_decode_ip_tos(ErlNifEnv *env,
14740 ERL_NIF_TERM eValue,
14741 struct cmsghdr *cmsgP,
14742 size_t rem,
14743 size_t *usedP)
14744 {
14745 int tos, *tosP;
14746
14747 if (! decode_ip_tos(env, eValue, &tos))
14748 return FALSE;
14749
14750 if ((tosP = init_cmsghdr(cmsgP, rem, sizeof(*tosP), usedP)) == NULL)
14751 return FALSE;
14752
14753 *tosP = tos;
14754 return TRUE;
14755 }
14756 #endif // #ifdef IP_TOS
14757 #endif // #ifdef __WIN32__
14758
14759 #ifndef __WIN32__
14760 #if defined(IP_TTL) || \
14761 defined(IPV6_HOPLIMIT) || \
14762 defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS)
14763 static
esock_cmsg_encode_int(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14764 BOOLEAN_T esock_cmsg_encode_int(ErlNifEnv *env,
14765 unsigned char *data,
14766 size_t dataLen,
14767 ERL_NIF_TERM *eResult) {
14768 int value;
14769
14770 if (dataLen < sizeof(value))
14771 return FALSE;
14772
14773 value = *((int *) data);
14774 *eResult = MKI(env, value);
14775 return TRUE;
14776 }
14777
esock_cmsg_decode_int(ErlNifEnv * env,ERL_NIF_TERM eValue,struct cmsghdr * cmsgP,size_t rem,size_t * usedP)14778 static BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv *env,
14779 ERL_NIF_TERM eValue,
14780 struct cmsghdr *cmsgP,
14781 size_t rem,
14782 size_t *usedP)
14783 {
14784 int value, *valueP;
14785
14786 if (! GET_INT(env, eValue, &value))
14787 return FALSE;
14788
14789 if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL)
14790 return FALSE;
14791
14792 *valueP = value;
14793 return TRUE;
14794 }
14795 #endif
14796 #endif
14797
14798
14799 #ifndef __WIN32__
esock_cmsg_decode_bool(ErlNifEnv * env,ERL_NIF_TERM eValue,struct cmsghdr * cmsgP,size_t rem,size_t * usedP)14800 static BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv *env,
14801 ERL_NIF_TERM eValue,
14802 struct cmsghdr *cmsgP,
14803 size_t rem,
14804 size_t *usedP)
14805 {
14806 BOOLEAN_T v;
14807 int *valueP;
14808
14809 if (! esock_decode_bool(eValue, &v))
14810 return FALSE;
14811
14812 if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL)
14813 return FALSE;
14814
14815 *valueP = v? 1 : 0;
14816 return TRUE;
14817 }
14818 #endif
14819
14820
14821 #ifndef __WIN32__
14822 #ifdef IP_RECVTTL
14823 static
esock_cmsg_encode_uchar(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14824 BOOLEAN_T esock_cmsg_encode_uchar(ErlNifEnv *env,
14825 unsigned char *data,
14826 size_t dataLen,
14827 ERL_NIF_TERM *eResult) {
14828 unsigned char value;
14829
14830 if (dataLen < sizeof(value))
14831 return FALSE;
14832
14833 value = *data;
14834 *eResult = MKUI(env, value);
14835 return TRUE;
14836 }
14837 #endif
14838 #endif
14839
14840 #ifndef __WIN32__
14841 #ifdef IP_PKTINFO
14842 static
esock_cmsg_encode_in_pktinfo(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14843 BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env,
14844 unsigned char *data,
14845 size_t dataLen,
14846 ERL_NIF_TERM *eResult) {
14847 struct in_pktinfo* pktInfoP = (struct in_pktinfo*) data;
14848 ERL_NIF_TERM ifIndex;
14849 ERL_NIF_TERM specDst, addr;
14850
14851 if (dataLen < sizeof(*pktInfoP))
14852 return FALSE;
14853
14854 ifIndex = MKUI(env, pktInfoP->ipi_ifindex);
14855 esock_encode_in_addr(env, &pktInfoP->ipi_spec_dst, &specDst);
14856 esock_encode_in_addr(env, &pktInfoP->ipi_addr, &addr);
14857
14858 {
14859 ERL_NIF_TERM keys[] = {esock_atom_ifindex,
14860 esock_atom_spec_dst,
14861 esock_atom_addr};
14862 ERL_NIF_TERM vals[] = {ifIndex, specDst, addr};
14863 unsigned int numKeys = NUM(keys);
14864 unsigned int numVals = NUM(vals);
14865
14866 ESOCK_ASSERT( numKeys == numVals );
14867 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eResult) );
14868 }
14869 return TRUE;
14870 }
14871 #endif
14872 #endif
14873
14874 #ifndef __WIN32__
14875 #ifdef IP_ORIGDSTADDR
14876 static
esock_cmsg_encode_sockaddr(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)14877 BOOLEAN_T esock_cmsg_encode_sockaddr(ErlNifEnv *env,
14878 unsigned char *data,
14879 size_t dataLen,
14880 ERL_NIF_TERM *eResult) {
14881 SOCKLEN_T addrLen = (SOCKLEN_T) dataLen;
14882
14883 if (addrLen != dataLen)
14884 return FALSE;
14885
14886 esock_encode_sockaddr(env,
14887 (ESockAddress*) data,
14888 addrLen,
14889 eResult);
14890 return TRUE;
14891 }
14892 #endif
14893 #endif
14894
14895 #ifndef __WIN32__
14896 #ifdef HAVE_LINUX_ERRQUEUE_H
14897 #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
14898 /* +++ encode_cmsg_encode_recverr +++
14899 *
14900 * Encode the extended socker error in the data part of the cmsg().
14901 *
14902 */
14903 static
esock_cmsg_encode_recverr(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eCMsgData)14904 BOOLEAN_T esock_cmsg_encode_recverr(ErlNifEnv *env,
14905 unsigned char *data,
14906 size_t dataLen,
14907 ERL_NIF_TERM *eCMsgData)
14908 {
14909 struct sock_extended_err *sock_err = (struct sock_extended_err *) data;
14910 struct sockaddr *offender;
14911 BOOLEAN_T have_offender = FALSE;
14912 ERL_NIF_TERM
14913 ee_errno, ee_origin, ee_type, ee_code, ee_info, ee_data,
14914 eSockAddr;
14915
14916 if (dataLen < sizeof(*sock_err))
14917 return FALSE;
14918
14919 offender = SO_EE_OFFENDER(sock_err);
14920 ee_errno = MKA(env, erl_errno_id(sock_err->ee_errno));
14921 ee_info = MKI(env, sock_err->ee_info);
14922 ee_data = MKI(env, sock_err->ee_data);
14923
14924 switch (sock_err->ee_origin) {
14925 #if defined(SO_EE_ORIGIN_NONE)
14926 case SO_EE_ORIGIN_NONE:
14927 ee_origin = atom_none;
14928 ee_type = MKI(env, sock_err->ee_type);
14929 ee_code = MKI(env, sock_err->ee_code);
14930 break;
14931 #endif
14932
14933 #if defined(SO_EE_ORIGIN_LOCAL)
14934 case SO_EE_ORIGIN_LOCAL:
14935 ee_origin = esock_atom_local;
14936 ee_type = MKI(env, sock_err->ee_type);
14937 ee_code = MKI(env, sock_err->ee_code);
14938 break;
14939 #endif
14940
14941 #if defined(SO_EE_ORIGIN_ICMP)
14942 case SO_EE_ORIGIN_ICMP:
14943 ee_origin = esock_atom_icmp;
14944 switch (sock_err->ee_type) {
14945
14946 #if defined(ICMP_DEST_UNREACH)
14947 case ICMP_DEST_UNREACH:
14948 ee_type = atom_dest_unreach;
14949 switch (sock_err->ee_code) {
14950
14951 #if defined(ICMP_NET_UNREACH)
14952 case ICMP_NET_UNREACH:
14953 ee_code = atom_net_unreach;
14954 break;
14955 #endif
14956
14957 #if defined(ICMP_HOST_UNREACH)
14958 case ICMP_HOST_UNREACH:
14959 ee_code = atom_host_unreach;
14960 break;
14961 #endif
14962
14963 #if defined(ICMP_PORT_UNREACH)
14964 case ICMP_PORT_UNREACH:
14965 ee_code = atom_port_unreach;
14966 break;
14967 #endif
14968
14969 #if defined(ICMP_FRAG_NEEDED)
14970 case ICMP_FRAG_NEEDED:
14971 ee_code = atom_frag_needed;
14972 break;
14973 #endif
14974
14975 #if defined(ICMP_NET_UNKNOWN)
14976 case ICMP_NET_UNKNOWN:
14977 ee_code = atom_net_unknown;
14978 break;
14979 #endif
14980
14981 #if defined(ICMP_HOST_UNKNOWN)
14982 case ICMP_HOST_UNKNOWN:
14983 ee_code = atom_host_unknown;
14984 break;
14985 #endif
14986
14987 default:
14988 ee_code = MKI(env, sock_err->ee_code);
14989 break;
14990 }
14991 break;
14992 #endif // ICMP_DEST_UNREACH
14993
14994 #if defined(ICMP_TIME_EXCEEDED)
14995 case ICMP_TIME_EXCEEDED:
14996 ee_type = atom_time_exceeded;
14997 ee_code = MKI(env, sock_err->ee_code);
14998 break;
14999 #endif
15000
15001 default:
15002 ee_type = MKI(env, sock_err->ee_type);
15003 ee_code = MKI(env, sock_err->ee_code);
15004 break;
15005 }
15006 break;
15007 #endif // SO_EE_ORIGIN_ICMP
15008
15009 #if defined(SO_EE_ORIGIN_ICMP6)
15010 case SO_EE_ORIGIN_ICMP6:
15011 ee_origin = esock_atom_icmp6;
15012 switch (sock_err->ee_type) {
15013
15014 #if defined(ICMPV6_DEST_UNREACH)
15015 case ICMPV6_DEST_UNREACH:
15016 ee_type = atom_dest_unreach;
15017 switch (sock_err->ee_code) {
15018
15019 #if defined(ICMPV6_NOROUTE)
15020 case ICMPV6_NOROUTE:
15021 ee_code = atom_noroute;
15022 break;
15023 #endif
15024 #if defined(ICMPV6_ADM_PROHIBITED)
15025 case ICMPV6_ADM_PROHIBITED:
15026 ee_code = atom_adm_prohibited;
15027 break;
15028 #endif
15029
15030 #if defined(ICMPV6_NOT_NEIGHBOUR)
15031 case ICMPV6_NOT_NEIGHBOUR:
15032 ee_code = atom_not_neighbour;
15033 break;
15034 #endif
15035
15036 #if defined(ICMPV6_ADDR_UNREACH)
15037 case ICMPV6_ADDR_UNREACH:
15038 ee_code = atom_addr_unreach;
15039 break;
15040 #endif
15041
15042 #if defined(ICMPV6_PORT_UNREACH)
15043 case ICMPV6_PORT_UNREACH:
15044 ee_code = atom_port_unreach;
15045 break;
15046 #endif
15047
15048 #if defined(ICMPV6_POLICY_FAIL)
15049 case ICMPV6_POLICY_FAIL:
15050 ee_code = atom_policy_fail;
15051 break;
15052 #endif
15053
15054 #if defined(ICMPV6_REJECT_ROUTE)
15055 case ICMPV6_REJECT_ROUTE:
15056 ee_code = atom_reject_route;
15057 break;
15058 #endif
15059
15060 default:
15061 ee_code = MKI(env, sock_err->ee_code);
15062 break;
15063 }
15064 break;
15065 #endif // ICMPV6_DEST_UNREACH
15066
15067 #if defined(ICMPV6_PKT_TOOBIG)
15068 case ICMPV6_PKT_TOOBIG:
15069 ee_type = atom_pkt_toobig;
15070 ee_code = MKI(env, sock_err->ee_code);
15071 break;
15072 #endif
15073
15074 #if defined(ICMPV6_TIME_EXCEED)
15075 case ICMPV6_TIME_EXCEED:
15076 ee_type = atom_time_exceeded;
15077 ee_code = MKI(env, sock_err->ee_code);
15078 break;
15079 #endif
15080
15081 default:
15082 ee_type = MKI(env, sock_err->ee_type);
15083 ee_code = MKI(env, sock_err->ee_code);
15084 break;
15085 }
15086 break;
15087 #endif // SO_EE_ORIGIN_ICMP6
15088
15089 #if defined(SO_EE_ORIGIN_TXSTATUS)
15090 case SO_EE_ORIGIN_TXSTATUS:
15091 ee_origin = atom_txstatus;
15092 ee_type = MKI(env, sock_err->ee_type);
15093 ee_code = MKI(env, sock_err->ee_code);
15094 break;
15095 #endif
15096
15097 #if defined(SO_EE_ORIGIN_ZEROCOPY)
15098 case SO_EE_ORIGIN_ZEROCOPY:
15099 ee_origin = atom_zerocopy;
15100 ee_type = MKI(env, sock_err->ee_type);
15101 ee_code = MKI(env, sock_err->ee_code);
15102 break;
15103 #endif
15104
15105 #if defined(SO_EE_ORIGIN_TXTIME)
15106 case SO_EE_ORIGIN_TXTIME:
15107 ee_origin = atom_txtime;
15108 ee_type = MKI(env, sock_err->ee_type);
15109 ee_code = MKI(env, sock_err->ee_code);
15110 break;
15111 #endif
15112
15113 default:
15114 ee_origin = MKI(env, sock_err->ee_origin);
15115 ee_type = MKI(env, sock_err->ee_type);
15116 ee_code = MKI(env, sock_err->ee_code);
15117 break;
15118 }
15119
15120 have_offender = CHARP(sock_err) + dataLen > CHARP(offender);
15121 if (have_offender) {
15122 esock_encode_sockaddr(env,
15123 (ESockAddress *)offender,
15124 (CHARP(sock_err) + dataLen ) - CHARP(offender),
15125 &eSockAddr);
15126 } else {
15127 eSockAddr = esock_atom_undefined;
15128 }
15129
15130 {
15131 ERL_NIF_TERM keys[] = {esock_atom_error,
15132 atom_origin,
15133 esock_atom_type,
15134 atom_code,
15135 esock_atom_info,
15136 esock_atom_data,
15137 atom_offender};
15138 ERL_NIF_TERM vals[] = {ee_errno,
15139 ee_origin,
15140 ee_type,
15141 ee_code,
15142 ee_info,
15143 ee_data,
15144 eSockAddr};
15145 unsigned int numKeys = NUM(keys);
15146 unsigned int numVals = NUM(vals);
15147
15148 ESOCK_ASSERT( numKeys == numVals );
15149 if (! have_offender) numKeys--;
15150 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eCMsgData) );
15151 }
15152 return TRUE;
15153 }
15154 #endif // #if defined(IP_RECVERR) || defined(IPV6_RECVERR)
15155 #endif // #ifdef HAVE_LINUX_ERRQUEUE_H
15156 #endif // #ifndef __WIN32__
15157
15158 #ifndef __WIN32__
15159 #ifdef IPV6_PKTINFO
15160 static
esock_cmsg_encode_in6_pktinfo(ErlNifEnv * env,unsigned char * data,size_t dataLen,ERL_NIF_TERM * eResult)15161 BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env,
15162 unsigned char *data,
15163 size_t dataLen,
15164 ERL_NIF_TERM *eResult) {
15165 struct in6_pktinfo* pktInfoP = (struct in6_pktinfo*) data;
15166 ERL_NIF_TERM ifIndex, addr;
15167
15168 if (dataLen < sizeof(*pktInfoP))
15169 return FALSE;
15170 ifIndex = MKI(env, pktInfoP->ipi6_ifindex);
15171 esock_encode_in6_addr(env, &pktInfoP->ipi6_addr, &addr);
15172 {
15173 ERL_NIF_TERM keys[] = {esock_atom_addr, esock_atom_ifindex};
15174 ERL_NIF_TERM vals[] = {addr, ifIndex};
15175 unsigned int numKeys = NUM(keys);
15176 unsigned int numVals = NUM(vals);
15177
15178 ESOCK_ASSERT( numKeys == numVals );
15179 ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eResult) );
15180 }
15181 return TRUE;
15182 }
15183 #endif
15184 #endif
15185
15186
15187
15188 #ifndef __WIN32__
15189
15190 struct ESockCmsgSpec {
15191 int type; // Message type
15192
15193 // Function to encode into erlang term
15194 BOOLEAN_T (* encode)
15195 (ErlNifEnv *env, unsigned char *data, size_t dataLen,
15196 ERL_NIF_TERM *eResult);
15197
15198 // Function to decode from erlang term
15199 BOOLEAN_T (* decode)
15200 (ErlNifEnv *env, ERL_NIF_TERM eValue,
15201 struct cmsghdr *cmsgP, size_t rem, size_t *usedP);
15202
15203 ERL_NIF_TERM *nameP; // Pointer to option name atom
15204 };
15205
cmpESockCmsgSpec(const void * vpa,const void * vpb)15206 static int cmpESockCmsgSpec(const void *vpa, const void *vpb) {
15207 struct ESockCmsgSpec *a, *b;
15208 a = (struct ESockCmsgSpec *) vpa;
15209 b = (struct ESockCmsgSpec *) vpb;
15210 return COMPARE(*(a->nameP), *(b->nameP));
15211 }
15212
15213 static struct ESockCmsgSpec
15214 cmsgLevelSocket[] =
15215 {
15216 #if defined(SCM_CREDENTIALS)
15217 {SCM_CREDENTIALS, NULL, NULL,
15218 &esock_atom_credentials},
15219 #elif defined(SCM_CREDS)
15220 {SCM_CREDS, NULL, NULL,
15221 &esock_atom_credentials},
15222 #endif
15223
15224 #if defined(SCM_RIGHTS)
15225 {SCM_RIGHTS, NULL, NULL,
15226 &esock_atom_rights},
15227 #endif
15228
15229 #if defined(SCM_TIMESTAMP)
15230 {SCM_TIMESTAMP,
15231 &esock_cmsg_encode_timeval, esock_cmsg_decode_timeval,
15232 &esock_atom_timestamp},
15233 #endif
15234 },
15235
15236 cmsgLevelIP[] =
15237 {
15238 #if defined(IP_TOS)
15239 {IP_TOS, esock_cmsg_encode_ip_tos, esock_cmsg_decode_ip_tos,
15240 &esock_atom_tos},
15241 #endif
15242
15243 #if defined(IP_TTL)
15244 {IP_TTL, esock_cmsg_encode_int, esock_cmsg_decode_int,
15245 &esock_atom_ttl},
15246 #endif
15247
15248 #if defined(IP_RECVTTL)
15249 {IP_RECVTTL, esock_cmsg_encode_uchar, NULL,
15250 &esock_atom_recvttl},
15251 #endif
15252
15253 #if defined(IP_PKTINFO)
15254 {IP_PKTINFO, esock_cmsg_encode_in_pktinfo, NULL,
15255 &esock_atom_pktinfo},
15256 #endif
15257
15258 #if defined(IP_ORIGDSTADDR)
15259 {IP_ORIGDSTADDR, esock_cmsg_encode_sockaddr, NULL,
15260 &esock_atom_origdstaddr},
15261 #endif
15262
15263 #if defined(IP_RECVTOS)
15264 {IP_RECVTOS, esock_cmsg_encode_ip_tos, NULL,
15265 &esock_atom_recvtos},
15266 #endif
15267
15268 #if defined(IP_RECVERR)
15269 {IP_RECVERR,
15270 #if defined(HAVE_LINUX_ERRQUEUE_H)
15271 esock_cmsg_encode_recverr,
15272 #else
15273 NULL,
15274 #endif
15275 NULL,
15276 &esock_atom_recverr},
15277 #endif
15278 };
15279
15280 #ifdef HAVE_IPV6
15281 static struct ESockCmsgSpec cmsgLevelIPv6[] =
15282 {
15283 #if defined(IPV6_PKTINFO)
15284 {IPV6_PKTINFO, esock_cmsg_encode_in6_pktinfo, NULL,
15285 &esock_atom_pktinfo},
15286 #endif
15287
15288 #if defined(IPV6_HOPLIMIT)
15289 {IPV6_HOPLIMIT, esock_cmsg_encode_int, esock_cmsg_decode_int,
15290 &esock_atom_hoplimit},
15291 #endif
15292
15293 #if defined(IPV6_TCLASS)
15294 {IPV6_TCLASS, esock_cmsg_encode_int, esock_cmsg_decode_int,
15295 &esock_atom_tclass},
15296 #endif
15297
15298 #if defined(IPV6_RECVTCLASS)
15299 {IPV6_RECVTCLASS, esock_cmsg_encode_int, NULL,
15300 &esock_atom_recvtclass},
15301 #endif
15302
15303 #if defined(IPV6_RECVERR)
15304 {IPV6_RECVERR,
15305 #if defined(HAVE_LINUX_ERRQUEUE_H)
15306 esock_cmsg_encode_recverr,
15307 #else
15308 NULL,
15309 #endif
15310 NULL,
15311 &esock_atom_recverr},
15312 #endif
15313 };
15314 #endif // #ifdef HAVE_IPV6
15315
initCmsgTables(void)15316 static void initCmsgTables(void) {
15317 ESOCK_SORT_TABLE(cmsgLevelSocket, cmpESockCmsgSpec);
15318 ESOCK_SORT_TABLE(cmsgLevelIP, cmpESockCmsgSpec);
15319 #ifdef HAVE_IPV6
15320 ESOCK_SORT_TABLE(cmsgLevelIPv6, cmpESockCmsgSpec);
15321 #endif
15322 }
15323
lookupCmsgTable(int level,size_t * num)15324 static struct ESockCmsgSpec *lookupCmsgTable(int level, size_t *num) {
15325 switch (level) {
15326
15327 case SOL_SOCKET:
15328 *num = NUM(cmsgLevelSocket);
15329 return cmsgLevelSocket;
15330
15331 #ifdef SOL_IP
15332 case SOL_IP:
15333 #else
15334 case IPPROTO_IP:
15335 #endif
15336 *num = NUM(cmsgLevelIP);
15337 return cmsgLevelIP;
15338
15339 #ifdef HAVE_IPV6
15340 #ifdef SOL_IPV6
15341 case SOL_IPV6:
15342 #else
15343 case IPPROTO_IPV6:
15344 #endif
15345 *num = NUM(cmsgLevelIPv6);
15346 return cmsgLevelIPv6;
15347 #endif
15348
15349 default:
15350 return NULL;
15351 }
15352 }
15353
lookupCmsgSpec(struct ESockCmsgSpec * table,size_t num,ERL_NIF_TERM eType)15354 static struct ESockCmsgSpec *lookupCmsgSpec(struct ESockCmsgSpec *table,
15355 size_t num,
15356 ERL_NIF_TERM eType) {
15357 struct ESockCmsgSpec key;
15358
15359 sys_memzero(CHARP(&key), sizeof(key));
15360 key.nameP = &eType;
15361 return bsearch(&key, table, num, sizeof(*table), cmpESockCmsgSpec);
15362 }
15363
15364 #endif // #ifdef __WIN32__
15365
15366
15367
15368 #ifndef __WIN32__
15369 static
encode_cmsg(ErlNifEnv * env,int level,int type,unsigned char * dataP,size_t dataLen,ERL_NIF_TERM * eType,ERL_NIF_TERM * eData)15370 BOOLEAN_T encode_cmsg(ErlNifEnv* env,
15371 int level,
15372 int type,
15373 unsigned char* dataP,
15374 size_t dataLen,
15375 ERL_NIF_TERM* eType,
15376 ERL_NIF_TERM* eData) {
15377 const struct ESockCmsgSpec *cmsgTable;
15378 size_t num;
15379
15380 if ((cmsgTable = lookupCmsgTable(level, &num)) != NULL) {
15381 size_t n;
15382
15383 /* Linear search for type number in level table
15384 */
15385 for (n = 0; n < num; n++) {
15386 if (cmsgTable[n].type == type) {
15387 /* Found the type number in the level table;
15388 * return the symbolic type (atom)
15389 * and try to encode the data
15390 */
15391
15392 *eType = *cmsgTable[n].nameP;
15393
15394 if (cmsgTable[n].encode != NULL)
15395 return cmsgTable[n].encode(env, dataP, dataLen, eData);
15396 else
15397 return FALSE;
15398 }
15399 }
15400 }
15401 /* No level table, or unknown type number in the table;
15402 * just return the type number as an erlang integer
15403 */
15404
15405
15406 *eType = MKI(env, type);
15407 return FALSE;
15408 }
15409 #endif
15410
15411
15412 #ifndef __WIN32__
15413 static
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)15414 BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env,
15415 ESockDescriptor* descP,
15416 int level,
15417 ERL_NIF_TERM eType,
15418 ERL_NIF_TERM eValue,
15419 char* bufP,
15420 size_t rem,
15421 size_t* usedP)
15422 {
15423 int type;
15424 struct cmsghdr *cmsgP = (struct cmsghdr *) bufP;
15425 struct ESockCmsgSpec *cmsgTable;
15426 struct ESockCmsgSpec *cmsgSpecP = NULL;
15427 size_t num = 0;
15428
15429 SSDBG( descP,
15430 ("SOCKET",
15431 "decode_cmsghdr_value {%d} -> entry \r\n"
15432 " eType: %T\r\n"
15433 " eValue: %T\r\n",
15434 descP->sock, eType, eValue) );
15435
15436 // We have decode functions only for symbolic (atom) types
15437 if (! IS_ATOM(env, eType)) {
15438 SSDBG( descP,
15439 ("SOCKET",
15440 "decode_cmsghdr_value {%d} -> FALSE:\r\n"
15441 " eType not an atom\r\n",
15442 descP->sock) );
15443 return FALSE;
15444 }
15445
15446 /* Try to look up the symbolic type
15447 */
15448 if (((cmsgTable = lookupCmsgTable(level, &num)) == NULL) ||
15449 ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL) ||
15450 (cmsgSpecP->decode == NULL)) {
15451 /* We found no table for this level,
15452 * we found no symbolic type in the level table,
15453 * or no decode function for this type
15454 */
15455
15456 SSDBG( descP,
15457 ("SOCKET",
15458 "decode_cmsghdr_value {%d} -> FALSE:\r\n"
15459 " cmsgTable: %p\r\n"
15460 " cmsgSpecP: %p\r\n",
15461 descP->sock, cmsgTable, cmsgSpecP) );
15462 return FALSE;
15463 }
15464
15465 if (! cmsgSpecP->decode(env, eValue, cmsgP, rem, usedP)) {
15466 // Decode function failed
15467 SSDBG( descP,
15468 ("SOCKET",
15469 "decode_cmsghdr_value {%d} -> FALSE:\r\n"
15470 " decode function failed\r\n",
15471 descP->sock) );
15472 return FALSE;
15473 }
15474
15475 // Succesful decode
15476
15477 type = cmsgSpecP->type;
15478
15479 SSDBG( descP,
15480 ("SOCKET",
15481 "decode_cmsghdr_value {%d} -> TRUE:\r\n"
15482 " level: %d\r\n"
15483 " type: %d\r\n",
15484 " *usedP: %lu\r\n",
15485 descP->sock, level, type, (unsigned long) *usedP) );
15486
15487 cmsgP->cmsg_level = level;
15488 cmsgP->cmsg_type = type;
15489 return TRUE;
15490 }
15491 #endif
15492
15493 #ifndef __WIN32__
15494 static
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)15495 BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env,
15496 ESockDescriptor* descP,
15497 int level,
15498 ERL_NIF_TERM eType,
15499 ERL_NIF_TERM eData,
15500 char* bufP,
15501 size_t rem,
15502 size_t* usedP)
15503 {
15504 int type;
15505 ErlNifBinary bin;
15506 struct cmsghdr *cmsgP = (struct cmsghdr *) bufP;
15507 struct ESockCmsgSpec *cmsgSpecP = NULL;
15508
15509 SSDBG( descP,
15510 ("SOCKET",
15511 "decode_cmsghdr_data {%d} -> entry \r\n"
15512 " eType: %T\r\n"
15513 " eData: %T\r\n",
15514 descP->sock, eType, eData) );
15515
15516 // Decode Type
15517 if (! GET_INT(env, eType, &type)) {
15518 struct ESockCmsgSpec *cmsgTable = NULL;
15519 size_t num = 0;
15520
15521 /* Try to look up the symbolic (atom) type
15522 */
15523 if ((! IS_ATOM(env, eType)) ||
15524 ((cmsgTable = lookupCmsgTable(level, &num)) == NULL) ||
15525 ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL)) {
15526 /* Type was not an atom,
15527 * we found no table for this level,
15528 * or we found no symbolic type in the level table
15529 */
15530
15531 SSDBG( descP,
15532 ("SOCKET",
15533 "decode_cmsghdr_data {%d} -> FALSE:\r\n"
15534 " cmsgTable: %p\r\n"
15535 " cmsgSpecP: %p\r\n",
15536 descP->sock, cmsgTable, cmsgSpecP) );
15537 return FALSE;
15538 }
15539
15540 type = cmsgSpecP->type;
15541 }
15542
15543 // Decode Data
15544 if (GET_BIN(env, eData, &bin)) {
15545 void *p;
15546
15547 p = init_cmsghdr(cmsgP, rem, bin.size, usedP);
15548 if (p == NULL) {
15549 /* No room for the data
15550 */
15551
15552 SSDBG( descP,
15553 ("SOCKET",
15554 "decode_cmsghdr_data {%d} -> FALSE:\r\n"
15555 " rem: %lu\r\n"
15556 " bin.size: %lu\r\n",
15557 descP->sock,
15558 (unsigned long) rem,
15559 (unsigned long) bin.size) );
15560 return FALSE;
15561 }
15562
15563 // Copy the binary data
15564 sys_memcpy(p, bin.data, bin.size);
15565
15566 } else if ((! esock_cmsg_decode_int(env, eData, cmsgP, rem, usedP)) &&
15567 (! esock_cmsg_decode_bool(env, eData, cmsgP, rem, usedP))) {
15568 SSDBG( descP,
15569 ("SOCKET",
15570 "decode_cmsghdr_data {%d} -> FALSE\r\n",
15571 descP->sock) );
15572 return FALSE;
15573 }
15574
15575 // Succesful decode
15576
15577 SSDBG( descP,
15578 ("SOCKET",
15579 "decode_cmsghdr_data {%d} -> TRUE:\r\n"
15580 " level: %d\r\n"
15581 " type: %d\r\n"
15582 " *usedP: %lu\r\n",
15583 descP->sock, level, type, (unsigned long) *usedP) );
15584
15585 cmsgP->cmsg_level = level;
15586 cmsgP->cmsg_type = type;
15587 return TRUE;
15588 }
15589 #endif
15590
15591 /* Clear the CMSG space and init the ->cmsg_len member,
15592 * return the position for the data, and the total used space
15593 */
15594 #ifndef __WIN32__
init_cmsghdr(struct cmsghdr * cmsgP,size_t rem,size_t size,size_t * usedP)15595 static void *init_cmsghdr(struct cmsghdr *cmsgP,
15596 size_t rem, // Remaining space
15597 size_t size, // Size of data
15598 size_t *usedP)
15599 {
15600 size_t space = CMSG_SPACE(size);
15601
15602 if (rem < space)
15603 return NULL; // Not enough space
15604
15605 sys_memzero(cmsgP, space);
15606 cmsgP->cmsg_len = CMSG_LEN(size);
15607
15608 *usedP = space;
15609 return CMSG_DATA(cmsgP);
15610 }
15611 #endif
15612
15613
15614 /* +++ decode_cmsghdrs +++
15615 *
15616 * Decode a list of cmsg(). There can be 0 or more "blocks".
15617 *
15618 * Each element can either be a (erlang) map that needs to be decoded,
15619 * or a (erlang) binary that just needs to be appended to the control
15620 * buffer.
15621 *
15622 * Our "problem" is that we have no idea much memory we actually need.
15623 *
15624 */
15625 #ifndef __WIN32__
15626 static
decode_cmsghdrs(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eCMsg,char * cmsgHdrBufP,size_t cmsgHdrBufLen,size_t * cmsgHdrBufUsed)15627 BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env,
15628 ESockDescriptor* descP,
15629 ERL_NIF_TERM eCMsg,
15630 char* cmsgHdrBufP,
15631 size_t cmsgHdrBufLen,
15632 size_t* cmsgHdrBufUsed)
15633 {
15634 ERL_NIF_TERM elem, tail, list;
15635 char* bufP;
15636 size_t rem, used, totUsed = 0;
15637 unsigned int len;
15638 int i;
15639
15640 SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> entry with"
15641 "\r\n eCMsg: %T"
15642 "\r\n cmsgHdrBufP: 0x%lX"
15643 "\r\n cmsgHdrBufLen: %d"
15644 "\r\n", descP->sock,
15645 eCMsg, cmsgHdrBufP, cmsgHdrBufLen) );
15646
15647 if (! GET_LIST_LEN(env, eCMsg, &len))
15648 return FALSE;
15649
15650 SSDBG( descP,
15651 ("SOCKET",
15652 "decode_cmsghdrs {%d} -> list length: %d\r\n",
15653 descP->sock, len) );
15654
15655 for (i = 0, list = eCMsg, rem = cmsgHdrBufLen, bufP = cmsgHdrBufP;
15656 i < len; i++) {
15657
15658 SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> process elem %d:"
15659 "\r\n (buffer) rem: %u"
15660 "\r\n (buffer) totUsed: %u"
15661 "\r\n", descP->sock, i, rem, totUsed) );
15662
15663 /* Extract the (current) head of the (cmsg hdr) list */
15664 if (! GET_LIST_ELEM(env, list, &elem, &tail))
15665 return FALSE;
15666
15667 used = 0; // Just in case...
15668 if (! decode_cmsghdr(env, descP, elem, bufP, rem, &used))
15669 return FALSE;
15670
15671 bufP = CHARP( ULONG(bufP) + used );
15672 rem = SZT( rem - used );
15673 list = tail;
15674 totUsed += used;
15675
15676 }
15677
15678 *cmsgHdrBufUsed = totUsed;
15679
15680 SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> done"
15681 "\r\n all %u ctrl headers processed"
15682 "\r\n totUsed = %lu\r\n",
15683 descP->sock, len, (unsigned long) totUsed) );
15684
15685 return TRUE;
15686 }
15687 #endif // #ifndef __WIN32__
15688
15689
15690 /* +++ decode_cmsghdr +++
15691 *
15692 * Decode one cmsg(). Put the "result" into the buffer and advance the
15693 * pointer (of the buffer) afterwards. Also update 'rem' accordingly.
15694 * But before the actual decode, make sure that there is enough room in
15695 * the buffer for the cmsg header (sizeof(*hdr) < rem).
15696 *
15697 * The eCMsg should be a map with three fields:
15698 *
15699 * level :: socket | protocol() | integer()
15700 * type :: atom() | integer()
15701 * What values are valid depend on the level
15702 * data :: binary() | integer() | boolean()
15703 * The type of the data depends on
15704 * or level and type, but can be a binary,
15705 * which means that the data is already coded.
15706 * value :: term() Which is a term matching the decode function
15707 */
15708 #ifndef __WIN32__
15709 static
decode_cmsghdr(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM eCMsg,char * bufP,size_t rem,size_t * used)15710 BOOLEAN_T decode_cmsghdr(ErlNifEnv* env,
15711 ESockDescriptor* descP,
15712 ERL_NIF_TERM eCMsg,
15713 char* bufP,
15714 size_t rem,
15715 size_t* used)
15716 {
15717 ERL_NIF_TERM eLevel, eType, eData, eValue;
15718 int level;
15719
15720 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> entry with"
15721 "\r\n eCMsg: %T"
15722 "\r\n", descP->sock, eCMsg) );
15723
15724 // Get 'level' field
15725 if (! GET_MAP_VAL(env, eCMsg, esock_atom_level, &eLevel))
15726 return FALSE;
15727 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eLevel: %T"
15728 "\r\n", descP->sock, eLevel) );
15729
15730 // Get 'type' field
15731 if (! GET_MAP_VAL(env, eCMsg, esock_atom_type, &eType))
15732 return FALSE;
15733 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eType: %T"
15734 "\r\n", descP->sock, eType) );
15735
15736 // Decode Level
15737 if (! esock_decode_level(env, eLevel, &level))
15738 return FALSE;
15739 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> level: %d\r\n",
15740 descP->sock, level) );
15741
15742 // Get 'data' field
15743 if (! GET_MAP_VAL(env, eCMsg, esock_atom_data, &eData)) {
15744
15745 // Get 'value' field
15746 if (! GET_MAP_VAL(env, eCMsg, atom_value, &eValue))
15747 return FALSE;
15748 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eValue: %T"
15749 "\r\n", descP->sock, eValue) );
15750
15751 // Decode Value
15752 if (! decode_cmsghdr_value(env, descP, level, eType, eValue,
15753 bufP, rem, used))
15754 return FALSE;
15755
15756 } else {
15757
15758 // Verify no 'value' field
15759 if (GET_MAP_VAL(env, eCMsg, atom_value, &eValue))
15760 return FALSE;
15761
15762 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eData: %T"
15763 "\r\n", descP->sock, eData) );
15764
15765 // Decode Data
15766 if (! decode_cmsghdr_data(env, descP, level, eType, eData,
15767 bufP, rem, used))
15768 return FALSE;
15769 }
15770
15771 SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> used: %lu\r\n",
15772 descP->sock, (unsigned long) *used) );
15773
15774 return TRUE;
15775 }
15776 #endif // #ifndef __WIN32__
15777
15778
15779
15780 /* +++ encode_msg_flags +++
15781 *
15782 * Encode a list of msg_flag().
15783 *
15784 */
15785 #ifndef __WIN32__
15786 static
encode_msg_flags(ErlNifEnv * env,ESockDescriptor * descP,int msgFlags,ERL_NIF_TERM * flags)15787 void encode_msg_flags(ErlNifEnv* env,
15788 ESockDescriptor* descP,
15789 int msgFlags,
15790 ERL_NIF_TERM* flags)
15791 {
15792 SSDBG( descP,
15793 ("SOCKET", "encode_msg_flags {%d} -> entry with"
15794 "\r\n msgFlags: %d (0x%lX)"
15795 "\r\n", descP->sock, msgFlags, msgFlags) );
15796
15797 if (msgFlags == 0) {
15798 *flags = MKEL(env);
15799 } else {
15800 size_t n;
15801 SocketTArray ta = TARRAY_CREATE(10); // Just to be on the safe side
15802
15803 for (n = 0; n < NUM(msg_flags); n++) {
15804 int f = msg_flags[n].flag;
15805 if ((f != 0) && ((msgFlags & f) == f)) {
15806 msgFlags &= ~f;
15807 TARRAY_ADD(ta, *(msg_flags[n].name));
15808 }
15809 if (msgFlags == 0) goto done;
15810 }
15811 /* Append remaining flags as an integer */
15812 if (msgFlags != 0)
15813 TARRAY_ADD(ta, MKI(env, msgFlags));
15814
15815 done:
15816 SSDBG( descP,
15817 ("SOCKET", "encode_msg_flags {%d} -> flags processed when"
15818 "\r\n TArray size: %d"
15819 "\r\n", descP->sock, TARRAY_SZ(ta)) );
15820
15821 TARRAY_TOLIST(ta, env, flags);
15822 }
15823 }
15824 #endif // #ifndef __WIN32__
15825
15826
15827 /* +++ decode the ip socket option TOS +++
15828 * The (ip) option can be provide in two ways:
15829 *
15830 * atom() | integer()
15831 *
15832 * When its an atom it can have the values:
15833 *
15834 * lowdelay | throughput | reliability | mincost
15835 *
15836 */
15837 #ifndef __WIN32__
15838 #if defined(IP_TOS)
15839 static
decode_ip_tos(ErlNifEnv * env,ERL_NIF_TERM eVal,int * val)15840 BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
15841 {
15842 BOOLEAN_T result = FALSE;
15843
15844 if (IS_ATOM(env, eVal)) {
15845
15846 if (COMPARE(eVal, esock_atom_lowdelay) == 0) {
15847 *val = IPTOS_LOWDELAY;
15848 result = TRUE;
15849 } else if (COMPARE(eVal, esock_atom_throughput) == 0) {
15850 *val = IPTOS_THROUGHPUT;
15851 result = TRUE;
15852 } else if (COMPARE(eVal, esock_atom_reliability) == 0) {
15853 *val = IPTOS_RELIABILITY;
15854 result = TRUE;
15855 #if defined(IPTOS_MINCOST)
15856 } else if (COMPARE(eVal, esock_atom_mincost) == 0) {
15857 *val = IPTOS_MINCOST;
15858 result = TRUE;
15859 #endif
15860 } else {
15861 *val = -1;
15862 result = FALSE;
15863 }
15864
15865 } else if (IS_NUM(env, eVal)) {
15866
15867 if (GET_INT(env, eVal, val)) {
15868 result = TRUE;
15869 } else {
15870 *val = -1;
15871 result = FALSE;
15872 }
15873
15874 } else {
15875 *val = -1;
15876 result = FALSE;
15877 }
15878
15879 return result;
15880 }
15881 #endif
15882 #endif // #ifndef __WIN32__
15883
15884
15885 /* +++ decode the ip socket option MTU_DISCOVER +++
15886 * The (ip) option can be provide in two ways:
15887 *
15888 * atom() | integer()
15889 *
15890 * When it's an atom it can have the values:
15891 *
15892 * want | dont | do | probe
15893 *
15894 */
15895 #ifndef __WIN32__
15896 #if defined(IP_MTU_DISCOVER)
15897 static
decode_ip_pmtudisc(ErlNifEnv * env,ERL_NIF_TERM eVal,int * val)15898 BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
15899 {
15900 if (IS_ATOM(env, eVal)) {
15901
15902 if (COMPARE(eVal, atom_want) == 0) {
15903 *val = IP_PMTUDISC_WANT;
15904 } else if (COMPARE(eVal, atom_dont) == 0) {
15905 *val = IP_PMTUDISC_DONT;
15906 } else if (COMPARE(eVal, atom_do) == 0) {
15907 *val = IP_PMTUDISC_DO;
15908 #if defined(IP_PMTUDISC_PROBE)
15909 } else if (COMPARE(eVal, atom_probe) == 0) {
15910 *val = IP_PMTUDISC_PROBE;
15911 #endif
15912 } else {
15913 return FALSE;
15914 }
15915
15916 } else if (! GET_INT(env, eVal, val)) {
15917 return FALSE;
15918 }
15919
15920 return TRUE;
15921 }
15922 #endif
15923 #endif // #ifndef __WIN32__
15924
15925
15926 #ifndef __WIN32__
15927 #if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS)
15928 static
decode_hops(ErlNifEnv * env,ERL_NIF_TERM eVal,int * val)15929 BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) {
15930 int hops;
15931
15932 if (! GET_INT(env, eVal, &hops)) {
15933 if (COMPARE(eVal, esock_atom_default) == 0) {
15934 *val = -1;
15935 return TRUE;
15936 }
15937 return FALSE;
15938 }
15939 if (hops < 0 || 255 < hops)
15940 return FALSE;
15941
15942 *val = hops;
15943 return TRUE;
15944 }
15945 #endif
15946 #endif // #ifndef __WIN32__
15947
15948
15949 /* +++ decode the ipv6 socket option MTU_DISCOVER +++
15950 * The (ip) option can be provide in two ways:
15951 *
15952 * atom() | integer()
15953 *
15954 * When its an atom it can have the values:
15955 *
15956 * want | dont | do | probe
15957 *
15958 */
15959 #ifndef __WIN32__
15960 #if defined(IPV6_MTU_DISCOVER)
15961 static
decode_ipv6_pmtudisc(ErlNifEnv * env,ERL_NIF_TERM eVal,int * val)15962 BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
15963 {
15964 if (IS_ATOM(env, eVal)) {
15965
15966 if (COMPARE(eVal, atom_want) == 0) {
15967 *val = IPV6_PMTUDISC_WANT;
15968 } else if (COMPARE(eVal, atom_dont) == 0) {
15969 *val = IPV6_PMTUDISC_DONT;
15970 } else if (COMPARE(eVal, atom_do) == 0) {
15971 *val = IPV6_PMTUDISC_DO;
15972 #if defined(IPV6_PMTUDISC_PROBE)
15973 } else if (COMPARE(eVal, atom_probe) == 0) {
15974 *val = IPV6_PMTUDISC_PROBE;
15975 #endif
15976 } else {
15977 return FALSE;
15978 }
15979
15980 } else if (! GET_INT(env, eVal, val)) {
15981 return FALSE;
15982 }
15983
15984 return TRUE;
15985 }
15986 #endif
15987 #endif // #ifndef __WIN32__
15988
15989
15990 /* +++ encode the ip socket option MTU_DISCOVER +++
15991 * The (ip) option can be provide in two ways:
15992 *
15993 * atom() | integer()
15994 *
15995 * If its one of the "known" values, it will be an atom:
15996 *
15997 * want | dont | do | probe
15998 *
15999 */
16000 #ifndef __WIN32__
16001 #if defined(IP_MTU_DISCOVER)
16002 static
encode_ip_pmtudisc(ErlNifEnv * env,int val,ERL_NIF_TERM * eVal)16003 void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal)
16004 {
16005 switch (val) {
16006 case IP_PMTUDISC_WANT:
16007 *eVal = atom_want;
16008 break;
16009
16010 case IP_PMTUDISC_DONT:
16011 *eVal = atom_dont;
16012 break;
16013
16014 case IP_PMTUDISC_DO:
16015 *eVal = atom_do;
16016 break;
16017
16018 #if defined(IP_PMTUDISC_PROBE)
16019 case IP_PMTUDISC_PROBE:
16020 *eVal = atom_probe;
16021 break;
16022 #endif
16023
16024 default:
16025 *eVal = MKI(env, val);
16026 break;
16027 }
16028
16029 return;
16030 }
16031 #endif
16032 #endif // #ifndef __WIN32__
16033
16034
16035 /* +++ encode the ipv6 socket option MTU_DISCOVER +++
16036 * The (ipv6) option can be provide in two ways:
16037 *
16038 * atom() | integer()
16039 *
16040 * If its one of the "known" values, it will be an atom:
16041 *
16042 * want | dont | do | probe
16043 *
16044 */
16045 #ifndef __WIN32__
16046 #if defined(IPV6_MTU_DISCOVER)
16047 static
encode_ipv6_pmtudisc(ErlNifEnv * env,int val,ERL_NIF_TERM * eVal)16048 void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal)
16049 {
16050 switch (val) {
16051 case IPV6_PMTUDISC_WANT:
16052 *eVal = atom_want;
16053 break;
16054
16055 case IPV6_PMTUDISC_DONT:
16056 *eVal = atom_dont;
16057 break;
16058
16059 case IPV6_PMTUDISC_DO:
16060 *eVal = atom_do;
16061 break;
16062
16063 #if defined(IPV6_PMTUDISC_PROBE)
16064 case IPV6_PMTUDISC_PROBE:
16065 *eVal = atom_probe;
16066 break;
16067 #endif
16068
16069 default:
16070 *eVal = MKI(env, val);
16071 break;
16072 }
16073
16074 return;
16075 }
16076 #endif
16077 #endif // #ifndef __WIN32__
16078
16079
16080 /* +++ encode the ip socket option tos +++
16081 * The (ip) option can be provide as:
16082 *
16083 * lowdelay | throughput | reliability | mincost | integer()
16084 *
16085 */
16086 #ifndef __WIN32__
16087 static
encode_ip_tos(ErlNifEnv * env,int val)16088 ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val)
16089 {
16090 ERL_NIF_TERM result;
16091
16092 switch (IPTOS_TOS(val)) {
16093 case IPTOS_LOWDELAY:
16094 result = esock_atom_lowdelay;
16095 break;
16096
16097 case IPTOS_THROUGHPUT:
16098 result = esock_atom_throughput;
16099 break;
16100
16101 case IPTOS_RELIABILITY:
16102 result = esock_atom_reliability;
16103 break;
16104
16105 #if defined(IPTOS_MINCOST)
16106 case IPTOS_MINCOST:
16107 result = esock_atom_mincost;
16108 break;
16109 #endif
16110
16111 default:
16112 result = MKI(env, val);
16113 break;
16114 }
16115
16116 return result;
16117 }
16118 #endif // #ifndef __WIN32__
16119
16120
16121 #ifndef __WIN32__
16122 #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO)
16123
16124 static
decode_sctp_assoc_t(ErlNifEnv * env,ERL_NIF_TERM eVal,sctp_assoc_t * val)16125 BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env,
16126 ERL_NIF_TERM eVal,
16127 sctp_assoc_t* val)
16128 {
16129 sctp_assoc_t assoc_id;
16130 int i;
16131 unsigned int ui;
16132
16133 /* Ensure that the assoc_id fits whether it is signed or unsigned
16134 */
16135 if (GET_INT(env, eVal, &i)) {
16136 assoc_id = (sctp_assoc_t) i;
16137 if ((int) assoc_id == i) {
16138 *val = assoc_id;
16139 return TRUE;
16140 }
16141 } else if (GET_UINT(env, eVal, &ui)) {
16142 assoc_id = (sctp_assoc_t) ui;
16143 if ((unsigned int) assoc_id == ui) {
16144 *val = assoc_id;
16145 return TRUE;
16146 }
16147 }
16148
16149 return FALSE;
16150 }
16151
16152 static
encode_sctp_assoc_t(ErlNifEnv * env,sctp_assoc_t val)16153 ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, sctp_assoc_t val)
16154 {
16155 unsigned int ui;
16156
16157 ui = (unsigned int) val;
16158 if ((sctp_assoc_t) ui == val)
16159 return MKUI(env, ui);
16160 else
16161 return MKI(env, val);
16162 }
16163
16164 #endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO)
16165 #endif // #ifdef __WIN32__
16166
16167
16168 /* *** alloc_descriptor ***
16169 *
16170 * Allocate and perform basic initialization of a socket descriptor.
16171 *
16172 */
16173 #ifndef __WIN32__
16174 static
alloc_descriptor(SOCKET sock,ErlNifEvent event)16175 ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event)
16176 {
16177 ESockDescriptor* descP;
16178 char buf[64]; /* Buffer used for building the mutex name */
16179
16180 ESOCK_ASSERT( (descP =
16181 enif_alloc_resource(esocks, sizeof(ESockDescriptor)))
16182 != NULL );
16183
16184 descP->pattern = ESOCK_DESC_PATTERN_CREATED;
16185
16186 requestor_init(&descP->connector);
16187 descP->connectorP = NULL;
16188
16189 sprintf(buf, "esock.w[%d]", sock);
16190 descP->writeMtx = MCREATE(buf);
16191 descP->writeState = 0;
16192 requestor_init(&descP->currentWriter);
16193 descP->currentWriterP = NULL; // currentWriter not used
16194 descP->writersQ.first = NULL;
16195 descP->writersQ.last = NULL;
16196
16197 descP->writePkgCnt = 0;
16198 descP->writePkgMax = 0;
16199 descP->writePkgMaxCnt = 0;
16200 descP->writeByteCnt = 0;
16201 descP->writeTries = 0;
16202 descP->writeWaits = 0;
16203 descP->writeFails = 0;
16204
16205 #ifdef HAVE_SENDFILE
16206 descP->sendfileHandle = INVALID_HANDLE;
16207 descP->sendfileCountersP = NULL;
16208 #endif
16209
16210 sprintf(buf, "esock.r[%d]", sock);
16211 descP->readMtx = MCREATE(buf);
16212 descP->readState = 0;
16213 requestor_init(&descP->currentReader);
16214 descP->currentReaderP = NULL; // currentReader not used
16215 descP->readersQ.first = NULL;
16216 descP->readersQ.last = NULL;
16217
16218 descP->readPkgCnt = 0;
16219 descP->readPkgMax = 0;
16220 descP->readPkgMaxCnt = 0;
16221 descP->readByteCnt = 0;
16222 descP->readTries = 0;
16223 descP->readWaits = 0;
16224 descP->readFails = 0;
16225
16226 sprintf(buf, "esock.acc[%d]", sock);
16227 requestor_init(&descP->currentAcceptor);
16228 descP->currentAcceptorP = NULL; // currentAcceptor not used
16229 descP->acceptorsQ.first = NULL;
16230 descP->acceptorsQ.last = NULL;
16231 descP->accSuccess = 0;
16232 descP->accFails = 0;
16233 descP->accTries = 0;
16234 descP->accWaits = 0;
16235
16236 sprintf(buf, "esock.close[%d]", sock);
16237 descP->closeEnv = NULL;
16238 descP->closeRef = esock_atom_undefined;
16239 enif_set_pid_undefined(&descP->closerPid);
16240 MON_INIT(&descP->closerMon);
16241
16242 sprintf(buf, "esock.cfg[%d]", sock);
16243 descP->rBufSz = ESOCK_RECV_BUFFER_SIZE_DEFAULT;
16244 descP->rNum = ESOCK_RECV_BUFFER_COUNT_DEFAULT;
16245 descP->rNumCnt = 0;
16246 descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT;
16247 descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT;
16248 descP->iow = FALSE;
16249 descP->dbg = ESOCK_DEBUG_DEFAULT; // Overwritten by caller
16250 descP->useReg = ESOCK_USE_SOCKET_REGISTRY; // Overwritten by caller
16251 descP->meta.env = esock_alloc_env("alloc_descriptor - "
16252 "meta-env");
16253 descP->meta.ref = esock_atom_undefined;
16254
16255 descP->sock = sock;
16256 descP->event = event;
16257 descP->origFD = INVALID_SOCKET;
16258 descP->closeOnClose = TRUE;
16259
16260 enif_set_pid_undefined(&descP->ctrlPid);
16261 MON_INIT(&descP->ctrlMon);
16262
16263 return descP;
16264 }
16265 #endif // #ifndef __WIN32__
16266
16267
16268 /* Decrement counters for when a socket is closed
16269 */
16270 #ifndef __WIN32__
16271 static
dec_socket(int domain,int type,int protocol)16272 void dec_socket(int domain, int type, int protocol)
16273 {
16274 MLOCK(data.cntMtx);
16275
16276 cnt_dec(&data.numSockets, 1);
16277
16278 /* *** Domain counter *** */
16279 if (domain == AF_INET)
16280 cnt_dec(&data.numDomainInet, 1);
16281 #if defined(HAVE_IN6) && defined(AF_INET6)
16282 else if (domain == AF_INET6)
16283 cnt_dec(&data.numDomainInet6, 1);
16284 #endif
16285 #ifdef HAS_AF_LOCAL
16286 else if (domain == AF_LOCAL)
16287 cnt_dec(&data.numDomainInet6, 1);
16288 #endif
16289
16290 /* *** Type counter *** */
16291 if (type == SOCK_STREAM)
16292 cnt_dec(&data.numTypeStreams, 1);
16293 else if (type == SOCK_DGRAM)
16294 cnt_dec(&data.numTypeDGrams, 1);
16295 #ifdef SOCK_SEQPACKET
16296 else if (type == SOCK_SEQPACKET)
16297 cnt_dec(&data.numTypeSeqPkgs, 1);
16298 #endif
16299
16300 /* *** Protocol counter *** */
16301 if (protocol == IPPROTO_IP)
16302 cnt_dec(&data.numProtoIP, 1);
16303 else if (protocol == IPPROTO_TCP)
16304 cnt_dec(&data.numProtoTCP, 1);
16305 else if (protocol == IPPROTO_UDP)
16306 cnt_dec(&data.numProtoUDP, 1);
16307 #if defined(HAVE_SCTP)
16308 else if (protocol == IPPROTO_SCTP)
16309 cnt_dec(&data.numProtoSCTP, 1);
16310 #endif
16311
16312 MUNLOCK(data.cntMtx);
16313 }
16314 #endif // #ifndef __WIN32__
16315
16316
16317 /* Increment counters for when a socket is opened
16318 */
16319 #ifndef __WIN32__
16320 static
inc_socket(int domain,int type,int protocol)16321 void inc_socket(int domain, int type, int protocol)
16322 {
16323 cnt_inc(&data.numSockets, 1);
16324
16325 /* *** Domain counter *** */
16326 if (domain == AF_INET)
16327 cnt_inc(&data.numDomainInet, 1);
16328 #if defined(HAVE_IN6) && defined(AF_INET6)
16329 else if (domain == AF_INET6)
16330 cnt_inc(&data.numDomainInet6, 1);
16331 #endif
16332 #ifdef HAS_AF_LOCAL
16333 else if (domain == AF_LOCAL)
16334 cnt_inc(&data.numDomainInet6, 1);
16335 #endif
16336
16337 /* *** Type counter *** */
16338 if (type == SOCK_STREAM)
16339 cnt_inc(&data.numTypeStreams, 1);
16340 else if (type == SOCK_DGRAM)
16341 cnt_inc(&data.numTypeDGrams, 1);
16342 #ifdef SOCK_SEQPACKET
16343 else if (type == SOCK_SEQPACKET)
16344 cnt_inc(&data.numTypeSeqPkgs, 1);
16345 #endif
16346
16347 /* *** Protocol counter *** */
16348 if (protocol == IPPROTO_IP)
16349 cnt_inc(&data.numProtoIP, 1);
16350 else if (protocol == IPPROTO_TCP)
16351 cnt_inc(&data.numProtoTCP, 1);
16352 else if (protocol == IPPROTO_UDP)
16353 cnt_inc(&data.numProtoUDP, 1);
16354 #if defined(HAVE_SCTP)
16355 else if (protocol == IPPROTO_SCTP)
16356 cnt_inc(&data.numProtoSCTP, 1);
16357 #endif
16358 }
16359 #endif // #ifndef __WIN32__
16360
16361
16362
16363 /* ----------------------------------------------------------------------
16364 * D e c o d e / E n c o d e F u n c t i o n s
16365 * ----------------------------------------------------------------------
16366 */
16367
16368 #ifndef __WIN32__
16369 #ifdef HAVE_SETNS
16370 /* esock_open4_get_netns - extract the netns field from the opts map
16371 */
16372 static
esock_open4_get_netns(ErlNifEnv * env,ERL_NIF_TERM opts,char ** netns)16373 BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env, ERL_NIF_TERM opts, char** netns)
16374 {
16375 ERL_NIF_TERM val;
16376 ErlNifBinary bin;
16377 char* buf;
16378
16379 /* The currently only supported extra option is: netns */
16380 if (!GET_MAP_VAL(env, opts, atom_netns, &val)) {
16381 *netns = NULL; // Just in case...
16382 return FALSE;
16383 }
16384
16385 /* The value should be a binary file name */
16386 if (! enif_inspect_binary(env, val, &bin)) {
16387 *netns = NULL; // Just in case...
16388 return FALSE;
16389 }
16390
16391 ESOCK_ASSERT( (buf = MALLOC(bin.size+1)) != NULL );
16392
16393 sys_memcpy(buf, bin.data, bin.size);
16394 buf[bin.size] = '\0';
16395 *netns = buf;
16396 return TRUE;
16397 }
16398 #endif
16399 #endif // #ifndef __WIN32__
16400
16401
16402 /* ehow2how - convert internal (erlang) "shutdown how" to
16403 * (proper) "shutdown how"
16404 */
16405 #ifndef __WIN32__
16406 static
ehow2how(ERL_NIF_TERM ehow,int * how)16407 BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how)
16408 {
16409 int cmp;
16410
16411 cmp = COMPARE(ehow, atom_read_write);
16412 if (cmp == 0)
16413 *how = SHUT_RDWR;
16414 else if (cmp < 0) {
16415 if (COMPARE(ehow, atom_read) == 0)
16416 *how = SHUT_RD;
16417 else
16418 return FALSE;
16419 } else {
16420 if (COMPARE(ehow, atom_write) == 0)
16421 *how = SHUT_WR;
16422 else
16423 return FALSE;
16424 }
16425
16426 return TRUE;
16427 }
16428 #endif // #ifndef __WIN32__
16429
16430
16431
16432 #ifndef __WIN32__
16433 #ifdef HAS_AF_LOCAL
16434 /* strnlen doesn't exist everywhere */
16435 /*
16436 static
16437 size_t my_strnlen(const char *s, size_t maxlen)
16438 {
16439 size_t i = 0;
16440 while (i < maxlen && s[i] != '\0')
16441 i++;
16442 return i;
16443 }
16444 */
16445 #endif
16446 #endif // #ifndef __WIN32__
16447
16448
16449
16450
16451 /* ===========================================================================
16452 *
16453 * Socket Registry message functions
16454 *
16455 * ===========================================================================
16456 */
16457
16458 /* Send a (socket) add message to the socket registry process.
16459 * We know that this process *is* alive since the VM would
16460 * terminate otherwise, so there is no need to test if
16461 * the sending fails.
16462 */
16463 #ifndef __WIN32__
16464 static
esock_send_reg_add_msg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)16465 void esock_send_reg_add_msg(ErlNifEnv* env,
16466 ESockDescriptor* descP,
16467 ERL_NIF_TERM sockRef)
16468 {
16469 ERL_NIF_TERM msg = mk_reg_add_msg(env, sockRef);
16470
16471 if (! esock_send_msg(env, &data.regPid, msg, NULL)) {
16472 SSDBG( descP,
16473 ("SOCKET",
16474 "esock_send_reg_add_msg(%T) {%d} failed ->"
16475 "\r\n regPid: %T"
16476 "\r\n",
16477 sockRef, descP->sock, MKPID(env, &data.regPid)) );
16478 }
16479 }
16480 #endif // #ifndef __WIN32__
16481
16482
16483
16484 /* Send a (socket) del message to the socket registry process.
16485 * We know that this process *is* alive since the VM would
16486 * terminate otherwise, so there is no need to test if
16487 * the sending fails.
16488 */
16489 #ifndef __WIN32__
16490 static
esock_send_reg_del_msg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef)16491 void esock_send_reg_del_msg(ErlNifEnv* env,
16492 ESockDescriptor* descP,
16493 ERL_NIF_TERM sockRef)
16494 {
16495 ERL_NIF_TERM msg = mk_reg_del_msg(env, sockRef);
16496
16497 if (! esock_send_msg(env, &data.regPid, msg, NULL)) {
16498 SSDBG( descP,
16499 ("SOCKET",
16500 "esock_send_reg_del_msg(%T) {%d} failed ->"
16501 "\r\n regPid: %T"
16502 "\r\n",
16503 sockRef, descP->sock, MKPID(env, &data.regPid)) );
16504 }
16505 }
16506 #endif // #ifndef __WIN32__
16507
16508
16509
16510
16511 /* ===========================================================================
16512 *
16513 * Socket user message functions
16514 *
16515 * ===========================================================================
16516 */
16517
16518 /* Send an counter wrap message to the controlling process:
16519 * A message in the form:
16520 *
16521 * {'$socket', Socket, counter_wrap, Counter :: atom()}
16522 *
16523 * This message will only be sent if the iow (Inform On Wrap) is TRUE.
16524 */
16525 #ifndef __WIN32__
16526 static
esock_send_wrap_msg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ERL_NIF_TERM cnt)16527 void esock_send_wrap_msg(ErlNifEnv* env,
16528 ESockDescriptor* descP,
16529 ERL_NIF_TERM sockRef,
16530 ERL_NIF_TERM cnt)
16531 {
16532 ERL_NIF_TERM msg = mk_wrap_msg(env, sockRef, cnt);
16533
16534 if (! esock_send_msg(env, &descP->ctrlPid, msg, NULL)) {
16535 SSDBG( descP,
16536 ("SOCKET",
16537 "esock_send_wrap_msg(%T) {%d} failed ->"
16538 "\r\n ctrlPid: %T"
16539 "\r\n cnt: %T"
16540 "\r\n",
16541 sockRef, descP->sock, MKPID(env, &descP->ctrlPid), cnt) );
16542 }
16543 }
16544 #endif // #ifndef __WIN32__
16545
16546
16547 /* Send an close message to the specified process:
16548 * A message in the form:
16549 *
16550 * {'$socket', Socket, close, CloseRef}
16551 *
16552 * This message is for processes that is waiting in the
16553 * erlang API (close-) function for the socket to be "closed"
16554 * (actually that the 'stop' callback function has been called).
16555 */
16556 #ifndef __WIN32__
16557 static
esock_send_close_msg(ErlNifEnv * env,ESockDescriptor * descP,ErlNifPid * pid)16558 void esock_send_close_msg(ErlNifEnv* env,
16559 ESockDescriptor* descP,
16560 ErlNifPid* pid)
16561 {
16562 ERL_NIF_TERM sockRef, msg;
16563
16564 sockRef = enif_make_resource(descP->closeEnv, descP);
16565 msg = mk_close_msg(descP->closeEnv, sockRef, descP->closeRef);
16566
16567 if (! esock_send_msg(env, pid, msg, descP->closeEnv)) {
16568 SSDBG( descP,
16569 ("SOCKET",
16570 "esock_send_close_msg(%T) {%d} failed ->"
16571 "\r\n pid: %T"
16572 "\r\n closeRef: %T"
16573 "\r\n",
16574 sockRef, descP->sock, MKPID(env, pid), descP->closeRef) );
16575 }
16576 }
16577 #ifdef HAVE_SENDFILE
16578 static void
esock_send_sendfile_deferred_close_msg(ErlNifEnv * env,ESockDescriptor * descP)16579 esock_send_sendfile_deferred_close_msg(ErlNifEnv* env,
16580 ESockDescriptor* descP)
16581 {
16582 ERL_NIF_TERM sockRef, msg;
16583 ErlNifPid *pid;
16584
16585 pid = &data.regPid;
16586 sockRef = enif_make_resource(env, descP);
16587 msg = mk_reg_msg(env, atom_sendfile_deferred_close, sockRef);
16588
16589 /* If this send should fail we have leaked a file descriptor
16590 * (intolerable), and if we try to close it here, on a regular
16591 * scheduler, it might hang "forever" due to e.g NFS
16592 * (out of the question), so terminating the VM
16593 * is the only viable option
16594 */
16595 ESOCK_ASSERT( esock_send_msg(env, pid, msg, NULL) );
16596 }
16597 #endif // #ifdef HAVE_SENDFILE
16598 #endif // #ifndef __WIN32__
16599
16600
16601 /* Send an abort message to the specified process:
16602 * A message in the form:
16603 *
16604 * {'$socket', Socket, abort, {RecvRef, Reason}}
16605 *
16606 * This message is for processes that is waiting in the
16607 * erlang API functions for a select message.
16608 */
16609 #ifndef __WIN32__
16610 static
esock_send_abort_msg(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ESockRequestor * reqP,ERL_NIF_TERM reason)16611 void esock_send_abort_msg(ErlNifEnv* env,
16612 ESockDescriptor* descP,
16613 ERL_NIF_TERM sockRef,
16614 ESockRequestor* reqP,
16615 ERL_NIF_TERM reason)
16616
16617
16618
16619
16620 {
16621 ERL_NIF_TERM msg;
16622
16623 msg =
16624 mk_abort_msg(reqP->env,
16625 /* sockRef not in env so copy */
16626 CP_TERM(reqP->env, sockRef), reqP->ref, reason);
16627
16628 if (! esock_send_msg(env, &reqP->pid, msg, reqP->env)) {
16629 SSDBG( descP,
16630 ("SOCKET",
16631 "esock_send_abort_msg(%T) {%d} failed ->"
16632 "\r\n pid: %T"
16633 "\r\n",
16634 sockRef, descP->sock, MKPID(env, &reqP->pid)) );
16635 }
16636 reqP->env = NULL;
16637 }
16638 #endif // #ifndef __WIN32__
16639
16640
16641 /* Send a message to the specified process.
16642 */
16643 #ifndef __WIN32__
16644 static
esock_send_msg(ErlNifEnv * env,ErlNifPid * pid,ERL_NIF_TERM msg,ErlNifEnv * msgEnv)16645 BOOLEAN_T esock_send_msg(ErlNifEnv* env,
16646 ErlNifPid* pid,
16647 ERL_NIF_TERM msg,
16648 ErlNifEnv* msgEnv)
16649 {
16650 int res = enif_send(env, pid, msgEnv, msg);
16651 esock_free_env("esock_msg_send - msg-env", msgEnv);
16652
16653 return !!res;
16654 }
16655 #endif // #ifndef __WIN32__
16656
16657
16658
16659 /* *** mk_reg_add_msg ***
16660 *
16661 * Construct a socket add message for the socket registry.
16662 *
16663 * {'$socket', add, Socket}
16664 *
16665 */
16666 #ifndef __WIN32__
16667 static
mk_reg_add_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef)16668 ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env,
16669 ERL_NIF_TERM sockRef)
16670 {
16671 return mk_reg_msg(env, atom_add, sockRef);
16672 }
16673 #endif // #ifndef __WIN32__
16674
16675
16676 /* *** mk_reg_del_msg ***
16677 *
16678 * Construct a socket del message for the socket registry.
16679 *
16680 * {'$socket', del, Socket}
16681 *
16682 */
16683 #ifndef __WIN32__
16684 static
mk_reg_del_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef)16685 ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env,
16686 ERL_NIF_TERM sockRef)
16687 {
16688 return mk_reg_msg(env, atom_del, sockRef);
16689 }
16690 #endif // #ifndef __WIN32__
16691
16692
16693 /* *** mk_reg_msg ***
16694 *
16695 * Construct a general message for the socket registry.
16696 * Tag is (at this time) either the atom 'add' or the atom 'del'.
16697 *
16698 * {'$socket', Tag, Socket}
16699 *
16700 */
16701 #ifndef __WIN32__
16702 static
mk_reg_msg(ErlNifEnv * env,ERL_NIF_TERM tag,ERL_NIF_TERM sockRef)16703 ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env,
16704 ERL_NIF_TERM tag,
16705 ERL_NIF_TERM sockRef)
16706 {
16707 ERL_NIF_TERM socket = mk_socket(env, sockRef);
16708
16709 return MKT3(env, esock_atom_socket_tag, tag, socket);
16710 }
16711 #endif // #ifndef __WIN32__
16712
16713
16714 /* *** mk_abort_msg ***
16715 *
16716 * Create the abort message, which has the following form:
16717 *
16718 * {'$socket', Socket, abort, {OpRef, Reason}}
16719 *
16720 * This message is for processes that are waiting in the
16721 * erlang API functions for a select (or this) message.
16722 */
16723 #ifndef __WIN32__
16724 static
mk_abort_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef,ERL_NIF_TERM opRef,ERL_NIF_TERM reason)16725 ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env,
16726 ERL_NIF_TERM sockRef,
16727 ERL_NIF_TERM opRef,
16728 ERL_NIF_TERM reason)
16729 {
16730 ERL_NIF_TERM info = MKT2(env, opRef, reason);
16731
16732 return mk_socket_msg(env, sockRef, esock_atom_abort, info);
16733 }
16734 #endif // #ifndef __WIN32__
16735
16736
16737 /* *** mk_wrap_msg ***
16738 *
16739 * Construct a counter wrap (socket) message. It has the form:
16740 *
16741 * {'$socket', Socket, counter_wrap, Counter}
16742 *
16743 */
16744 #ifndef __WIN32__
16745 static
mk_wrap_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef,ERL_NIF_TERM cnt)16746 ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env,
16747 ERL_NIF_TERM sockRef,
16748 ERL_NIF_TERM cnt)
16749 {
16750 return mk_socket_msg(env, sockRef, atom_counter_wrap, cnt);
16751 }
16752 #endif // #ifndef __WIN32__
16753
16754
16755 /* *** mk_close_msg ***
16756 *
16757 * Construct a close (socket) message. It has the form:
16758 *
16759 * {'$socket', Socket, close, closeRef}
16760 *
16761 */
16762 #ifndef __WIN32__
16763 static
mk_close_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef,ERL_NIF_TERM closeRef)16764 ERL_NIF_TERM mk_close_msg(ErlNifEnv* env,
16765 ERL_NIF_TERM sockRef,
16766 ERL_NIF_TERM closeRef)
16767 {
16768 return mk_socket_msg(env, sockRef, esock_atom_close, closeRef);
16769 }
16770 #endif // #ifndef __WIN32__
16771
16772
16773 /* *** mk_select_msg ***
16774 *
16775 * Construct a select (socket) message. It has the form:
16776 *
16777 * {'$socket', Socket, select, selectRef}
16778 *
16779 */
16780 #ifndef __WIN32__
16781 static
mk_select_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef,ERL_NIF_TERM selectRef)16782 ERL_NIF_TERM mk_select_msg(ErlNifEnv* env,
16783 ERL_NIF_TERM sockRef,
16784 ERL_NIF_TERM selectRef)
16785 {
16786 return mk_socket_msg(env, sockRef, atom_select, selectRef);
16787 }
16788 #endif // #ifndef __WIN32__
16789
16790
16791 /* *** mk_socket_msg ***
16792 *
16793 * Construct the socket message:
16794 *
16795 * {'$socket', Socket, Tag, Info}
16796 *
16797 * Socket :: socket:socket()
16798 * Tag :: atom()
16799 * Info :: term()
16800 *
16801 */
16802 #ifndef __WIN32__
16803 static
mk_socket_msg(ErlNifEnv * env,ERL_NIF_TERM sockRef,ERL_NIF_TERM tag,ERL_NIF_TERM info)16804 ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env,
16805 ERL_NIF_TERM sockRef,
16806 ERL_NIF_TERM tag,
16807 ERL_NIF_TERM info)
16808 {
16809 ERL_NIF_TERM socket = mk_socket(env, sockRef);
16810
16811 return MKT4(env, esock_atom_socket_tag, socket, tag, info);
16812 }
16813 #endif // #ifndef __WIN32__
16814
16815
16816 /* *** mk_socket ***
16817 *
16818 * Simple utility function that construct the socket tuple:
16819 *
16820 * socket:socket() :: {'$socket', SockRef :: reference()}
16821 */
16822 #ifndef __WIN32__
16823 static
mk_socket(ErlNifEnv * env,ERL_NIF_TERM sockRef)16824 ERL_NIF_TERM mk_socket(ErlNifEnv* env,
16825 ERL_NIF_TERM sockRef)
16826 {
16827 return MKT2(env, esock_atom_socket_tag, sockRef);
16828 }
16829 #endif // #ifndef __WIN32__
16830
16831
16832 /* ----------------------------------------------------------------------
16833 * S e l e c t W r a p p e r F u n c t i o n s
16834 * ----------------------------------------------------------------------
16835 */
16836
16837 /* *** esock_select_read ***
16838 *
16839 * Perform a read select. When the select is triggered, a 'select'
16840 * message (see mk_select_msg) will be sent.
16841 *
16842 * There are two ways to handle the select message:
16843 * 1) Create "your own" environment and create the message using it
16844 * and then pass it on to the select function.
16845 * 2) Or, to create the message using any available environment,
16846 * and then pass a NULL pointer to the select function.
16847 * This will have the effect that the select function will
16848 * create its own environment and then copy the message to it.
16849 * We choose the second alternative.
16850 */
16851 #ifndef __WIN32__
16852 static
esock_select_read(ErlNifEnv * env,ErlNifEvent event,void * obj,const ErlNifPid * pidP,ERL_NIF_TERM sockRef,ERL_NIF_TERM selectRef)16853 int esock_select_read(ErlNifEnv* env,
16854 ErlNifEvent event, // The file descriptor
16855 void* obj, // The socket descriptor object
16856 const ErlNifPid* pidP, // Destination
16857 ERL_NIF_TERM sockRef, // Socket
16858 ERL_NIF_TERM selectRef) // "ID" of the operation
16859 {
16860 ERL_NIF_TERM selectMsg = mk_select_msg(env, sockRef, selectRef);
16861
16862 return enif_select_read(env, event, obj, pidP, selectMsg, NULL);
16863
16864 }
16865 #endif // #ifndef __WIN32__
16866
16867
16868 /* *** esock_select_write ***
16869 *
16870 * Perform a write select. When the select is triggered, a 'select'
16871 * message (see mk_select_msg) will be sent.
16872 * The sockRef is copied to the msgEnv when the socket message is created,
16873 * so no need to do that here, but the selectRef needs to be copied.
16874 */
16875 #ifndef __WIN32__
16876 static
esock_select_write(ErlNifEnv * env,ErlNifEvent event,void * obj,const ErlNifPid * pidP,ERL_NIF_TERM sockRef,ERL_NIF_TERM selectRef)16877 int esock_select_write(ErlNifEnv* env,
16878 ErlNifEvent event, // The file descriptor
16879 void* obj, // The socket descriptor
16880 const ErlNifPid* pidP, // Destination
16881 ERL_NIF_TERM sockRef, // Socket
16882 ERL_NIF_TERM selectRef) // "ID" of the operation
16883 {
16884 ERL_NIF_TERM selectMsg = mk_select_msg(env, sockRef, selectRef);
16885
16886 return enif_select_write(env, event, obj, pidP, selectMsg, NULL);
16887 }
16888 #endif // #ifndef __WIN32__
16889
16890
16891 /* *** esock_select_stop ***
16892 *
16893 * WARNING: enif_select may call esock_stop directly
16894 * in which case deadlock is avoided by esock_stop that checks
16895 * if it got a direct call and then does not lock readMtx and writeMtx.
16896 *
16897 * So readMtx and writeMtx are supposed to be locked
16898 * when this function is called.
16899 */
16900 #ifndef __WIN32__
16901 static
esock_select_stop(ErlNifEnv * env,ErlNifEvent event,void * obj)16902 int esock_select_stop(ErlNifEnv* env,
16903 ErlNifEvent event,
16904 void* obj)
16905 {
16906 return enif_select(env, event, (ERL_NIF_SELECT_STOP), obj, NULL,
16907 esock_atom_undefined);
16908 }
16909 #endif // #ifndef __WIN32__
16910
16911 #ifndef __WIN32__
16912 static
esock_select_cancel(ErlNifEnv * env,ErlNifEvent event,enum ErlNifSelectFlags mode,void * obj)16913 int esock_select_cancel(ErlNifEnv* env,
16914 ErlNifEvent event,
16915 enum ErlNifSelectFlags mode,
16916 void* obj)
16917 {
16918 return enif_select(env, event, (ERL_NIF_SELECT_CANCEL | mode), obj, NULL,
16919 esock_atom_undefined);
16920 }
16921 #endif // #ifndef __WIN32__
16922
16923
16924 /* ----------------------------------------------------------------------
16925 * A c t i v a t e N e x t ( o p e r a t o r ) F u n c t i o n s
16926 * ----------------------------------------------------------------------
16927 */
16928
16929 /* *** activate_next_acceptor ***
16930 * *** activate_next_writer ***
16931 * *** activate_next_reader ***
16932 *
16933 * This functions pops the requestors queue and then selects until it
16934 * manages to successfully activate a requestor or the queue is empty.
16935 * Return value indicates if a new requestor was activated or not.
16936 */
16937
16938 #ifndef __WIN32__
16939
16940 #define ACTIVATE_NEXT_FUNCS \
16941 ACTIVATE_NEXT_FUNC_DECL(acceptor, read, currentAcceptor, acceptorsQ) \
16942 ACTIVATE_NEXT_FUNC_DECL(writer, write, currentWriter, writersQ) \
16943 ACTIVATE_NEXT_FUNC_DECL(reader, read, currentReader, readersQ)
16944
16945 #define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \
16946 static \
16947 BOOLEAN_T activate_next_##F(ErlNifEnv* env, \
16948 ESockDescriptor* descP, \
16949 ERL_NIF_TERM sockRef) \
16950 { \
16951 BOOLEAN_T popped, activated; \
16952 int sres; \
16953 ERL_NIF_TERM reason; \
16954 ESockRequestor* reqP = &descP->R; \
16955 ESockRequestQueue* q = &descP->Q; \
16956 \
16957 popped = FALSE; \
16958 do { \
16959 \
16960 if (requestor_pop(q, reqP)) { \
16961 \
16962 /* There was another one */ \
16963 \
16964 SSDBG( descP, \
16965 ("SOCKET", \
16966 "activate_next_" #F "(%T) {%d} ->" \
16967 " new (active) requestor: " \
16968 "\r\n pid: %T" \
16969 "\r\n ref: %T" \
16970 "\r\n", sockRef, descP->sock, \
16971 reqP->pid, reqP->ref) ); \
16972 \
16973 /* We need to copy req ref to 'env' */ \
16974 if ((sres = \
16975 esock_select_##S(env, descP->sock, descP, \
16976 &reqP->pid, sockRef, \
16977 CP_TERM(env, reqP->ref))) < 0) { \
16978 \
16979 /* We need to inform this process, reqP->pid, */ \
16980 /* that we failed to select, so we don't leave */ \
16981 /* it hanging. */ \
16982 /* => send abort */ \
16983 \
16984 reason = MKT2(env, \
16985 esock_atom_select_failed, \
16986 MKI(env, sres)); \
16987 esock_send_abort_msg(env, descP, sockRef, \
16988 reqP, reason); \
16989 \
16990 } else { \
16991 \
16992 descP->S##State |= ESOCK_STATE_SELECTED; \
16993 \
16994 /* Success: New requestor selected */ \
16995 popped = TRUE; \
16996 activated = TRUE; \
16997 \
16998 } \
16999 \
17000 } else { \
17001 \
17002 SSDBG( descP, \
17003 ("SOCKET", \
17004 "activate_next_" #F "(%T) {%d} ->" \
17005 " no more requestors\r\n", \
17006 sockRef, descP->sock) ); \
17007 \
17008 popped = TRUE; \
17009 activated = FALSE; \
17010 } \
17011 \
17012 } while (!popped); \
17013 \
17014 SSDBG( descP, \
17015 ("SOCKET", "activate_next_" #F "(%T) {%d} -> " \
17016 "done with %s\r\n", \
17017 sockRef, descP->sock, B2S(activated)) ); \
17018 \
17019 return activated; \
17020 }
17021 ACTIVATE_NEXT_FUNCS
17022 #undef ACTIVATE_NEXT_FUNC_DECL
17023
17024 #endif // #ifndef __WIN32__
17025
17026
17027 /* ----------------------------------------------------------------------
17028 * R e q u e s t o r Q u e u e F u n c t i o n s
17029 * ----------------------------------------------------------------------
17030 *
17031 * Since each of these functions (search4pid, push, pop and unqueue
17032 * are virtually identical for acceptors, writers and readers,
17033 * we make use of set of declaration macros.
17034 */
17035
17036 #ifndef __WIN32__
17037
17038 /* *** acceptor_search4pid ***
17039 * *** writer_search4pid ***
17040 * *** reader_search4pid ***
17041 *
17042 * Search for a pid in the requestor (acceptor, writer, or reader) queue.
17043 *
17044 */
17045
17046 #define REQ_SEARCH4PID_FUNCS \
17047 REQ_SEARCH4PID_FUNC_DECL(acceptor, acceptorsQ) \
17048 REQ_SEARCH4PID_FUNC_DECL(writer, writersQ) \
17049 REQ_SEARCH4PID_FUNC_DECL(reader, readersQ)
17050
17051 #define REQ_SEARCH4PID_FUNC_DECL(F, Q) \
17052 static \
17053 BOOLEAN_T F##_search4pid(ErlNifEnv* env, \
17054 ESockDescriptor* descP, \
17055 ErlNifPid* pid) \
17056 { \
17057 return qsearch4pid(env, &descP->Q, pid); \
17058 }
17059 REQ_SEARCH4PID_FUNCS
17060 #undef REQ_SEARCH4PID_FUNC_DECL
17061
17062 #endif // #ifndef __WIN32__
17063
17064
17065
17066 /* *** acceptor_push ***
17067 * *** writer_push ***
17068 * *** reader_push ***
17069 *
17070 * Push a requestor (acceptor, writer, or reader) onto its queue.
17071 * This happens when we already have a current request (of its type).
17072 *
17073 */
17074
17075 #ifndef __WIN32__
17076
17077 #define REQ_PUSH_FUNCS \
17078 REQ_PUSH_FUNC_DECL(acceptor, acceptorsQ) \
17079 REQ_PUSH_FUNC_DECL(writer, writersQ) \
17080 REQ_PUSH_FUNC_DECL(reader, readersQ)
17081
17082 #define REQ_PUSH_FUNC_DECL(F, Q) \
17083 static \
17084 void F##_push(ErlNifEnv* env, \
17085 ESockDescriptor* descP, \
17086 ErlNifPid pid, /* self() */ \
17087 ERL_NIF_TERM ref) \
17088 { \
17089 ESockRequestQueueElement *e; \
17090 ESockRequestor *reqP; \
17091 \
17092 ESOCK_ASSERT( (e = MALLOC(sizeof(ESockRequestQueueElement))) \
17093 != NULL ); \
17094 reqP = &e->data; \
17095 reqP->pid = pid; \
17096 ESOCK_ASSERT( MONP("reader_push -> " #F " request", \
17097 env, descP, &pid, &reqP->mon) == 0 ); \
17098 reqP->env = esock_alloc_env(#F "_push"); \
17099 reqP->ref = CP_TERM(reqP->env, ref); \
17100 \
17101 qpush(&descP->Q, e); \
17102 }
17103 REQ_PUSH_FUNCS
17104 #undef REQ_PUSH_FUNC_DECL
17105
17106 #endif // #ifndef __WIN32__
17107
17108
17109
17110 /* *** acceptor_pop ***
17111 * *** writer_pop ***
17112 * *** reader_pop ***
17113 *
17114 * Pop a requestor (acceptor, writer, or reader) from its queue.
17115 *
17116 */
17117
17118 #ifndef __WIN32__
17119
17120 #define REQ_POP_FUNCS \
17121 REQ_POP_FUNC_DECL(acceptor, acceptorsQ) \
17122 REQ_POP_FUNC_DECL(writer, writersQ) \
17123 REQ_POP_FUNC_DECL(reader, readersQ)
17124
17125 #define REQ_POP_FUNC_DECL(F, Q) \
17126 static \
17127 BOOLEAN_T F##_pop(ErlNifEnv* env, \
17128 ESockDescriptor* descP, \
17129 ESockRequestor* reqP) \
17130 { \
17131 return requestor_pop(&descP->Q, reqP); \
17132 }
17133 REQ_POP_FUNCS
17134 #undef REQ_POP_FUNC_DECL
17135
17136 #endif // #ifndef __WIN32__
17137
17138
17139
17140 /* *** acceptor_unqueue ***
17141 * *** writer_unqueue ***
17142 * *** reader_unqueue ***
17143 *
17144 * Remove a requestor (acceptor, writer, or reader) from its queue.
17145 *
17146 */
17147
17148 #ifndef __WIN32__
17149
17150 #define REQ_UNQUEUE_FUNCS \
17151 REQ_UNQUEUE_FUNC_DECL(acceptor, acceptorsQ) \
17152 REQ_UNQUEUE_FUNC_DECL(writer, writersQ) \
17153 REQ_UNQUEUE_FUNC_DECL(reader, readersQ)
17154
17155 #define REQ_UNQUEUE_FUNC_DECL(F, Q) \
17156 static \
17157 BOOLEAN_T F##_unqueue(ErlNifEnv* env, \
17158 ESockDescriptor* descP, \
17159 ERL_NIF_TERM* refP, \
17160 const ErlNifPid* pidP) \
17161 { \
17162 return qunqueue(env, descP, "qunqueue -> waiting " #F, \
17163 &descP->Q, refP, pidP); \
17164 }
17165 REQ_UNQUEUE_FUNCS
17166 #undef REQ_UNQUEUE_FUNC_DECL
17167
17168 #endif // #ifndef __WIN32__
17169
17170
17171
17172 /* *** requestor pop ***
17173 *
17174 * Pop an requestor from its queue.
17175 */
17176
17177 #ifndef __WIN32__
17178
17179 static
requestor_pop(ESockRequestQueue * q,ESockRequestor * reqP)17180 BOOLEAN_T requestor_pop(ESockRequestQueue* q,
17181 ESockRequestor* reqP)
17182 {
17183 ESockRequestQueueElement* e = qpop(q);
17184
17185 esock_free_env("requestor_pop", reqP->env);
17186
17187 if (e != NULL) {
17188 reqP->pid = e->data.pid;
17189 reqP->mon = e->data.mon;
17190 reqP->env = e->data.env;
17191 reqP->ref = e->data.ref;
17192 FREE(e);
17193 return TRUE;
17194 } else {
17195 /* Queue was empty */
17196 requestor_init(reqP);
17197 return FALSE;
17198 }
17199
17200 }
17201
requestor_init(ESockRequestor * reqP)17202 static void requestor_init(ESockRequestor* reqP) {
17203 enif_set_pid_undefined(&reqP->pid);
17204 MON_INIT(&reqP->mon);
17205 reqP->env = NULL;
17206 reqP->ref = esock_atom_undefined;
17207 }
17208
requestor_release(const char * slogan,ErlNifEnv * env,ESockDescriptor * descP,ESockRequestor * reqP)17209 static void requestor_release(const char* slogan,
17210 ErlNifEnv* env,
17211 ESockDescriptor* descP,
17212 ESockRequestor* reqP) {
17213
17214 enif_set_pid_undefined(&reqP->pid);
17215 (void) DEMONP(slogan, env, descP, &reqP->mon);
17216 esock_free_env(slogan, reqP->env);
17217 reqP->env = NULL;
17218 reqP->ref = esock_atom_undefined;
17219 }
17220 #endif // #ifndef __WIN32__
17221
17222
17223
17224 #ifndef __WIN32__
17225
17226 static
qsearch4pid(ErlNifEnv * env,ESockRequestQueue * q,ErlNifPid * pid)17227 BOOLEAN_T qsearch4pid(ErlNifEnv* env,
17228 ESockRequestQueue* q,
17229 ErlNifPid* pid)
17230 {
17231 ESockRequestQueueElement* tmp = q->first;
17232
17233 while (tmp != NULL) {
17234 if (COMPARE_PIDS(&tmp->data.pid, pid) == 0)
17235 return TRUE;
17236 else
17237 tmp = tmp->nextP;
17238 }
17239
17240 return FALSE;
17241 }
17242
17243 static
qpush(ESockRequestQueue * q,ESockRequestQueueElement * e)17244 void qpush(ESockRequestQueue* q,
17245 ESockRequestQueueElement* e)
17246 {
17247 if (q->first != NULL) {
17248 q->last->nextP = e;
17249 q->last = e;
17250 e->nextP = NULL;
17251 } else {
17252 q->first = e;
17253 q->last = e;
17254 e->nextP = NULL;
17255 }
17256 }
17257
17258 static
qpop(ESockRequestQueue * q)17259 ESockRequestQueueElement* qpop(ESockRequestQueue* q)
17260 {
17261 ESockRequestQueueElement* e = q->first;
17262
17263 if (e != NULL) {
17264 /* Atleast one element in the queue */
17265 if (e == q->last) {
17266 /* Only one element in the queue */
17267 q->first = q->last = NULL;
17268 } else {
17269 /* More than one element in the queue */
17270 q->first = e->nextP;
17271 }
17272 }
17273
17274 return e;
17275 }
17276 #endif // #ifndef __WIN32__
17277
17278
17279
17280 #ifndef __WIN32__
17281 static
qunqueue(ErlNifEnv * env,ESockDescriptor * descP,const char * slogan,ESockRequestQueue * q,ERL_NIF_TERM * refP,const ErlNifPid * pidP)17282 BOOLEAN_T qunqueue(ErlNifEnv* env,
17283 ESockDescriptor* descP,
17284 const char* slogan,
17285 ESockRequestQueue* q,
17286 ERL_NIF_TERM* refP,
17287 const ErlNifPid* pidP)
17288 {
17289 ESockRequestQueueElement* e = q->first;
17290 ESockRequestQueueElement* p = NULL;
17291
17292 /* Check if it was one of the waiting acceptor processes */
17293 while (e != NULL) {
17294 if (COMPARE_PIDS(&e->data.pid, pidP) == 0) {
17295 if ((refP != NULL) && (COMPARE(e->data.ref, *refP) != 0))
17296 return FALSE;
17297
17298 /* We have a match */
17299
17300 (void) DEMONP(slogan, env, descP, &e->data.mon);
17301
17302 if (p != NULL) {
17303 /* Not the first, but could be the last */
17304 if (q->last == e) {
17305 q->last = p;
17306 p->nextP = NULL;
17307 } else {
17308 p->nextP = e->nextP;
17309 }
17310
17311 } else {
17312 /* The first and could also be the last */
17313 if (q->last == e) {
17314 q->last = NULL;
17315 q->first = NULL;
17316 } else {
17317 q->first = e->nextP;
17318 }
17319 }
17320
17321 esock_free_env("qunqueue", e->data.env);
17322 FREE(e);
17323
17324 return TRUE;
17325 }
17326
17327 /* Try next */
17328 p = e;
17329 e = e->nextP;
17330 }
17331
17332 return FALSE;
17333 }
17334 #endif // #ifndef __WIN32__
17335
17336
17337
17338 /* ----------------------------------------------------------------------
17339 * C o u n t e r F u n c t i o n s
17340 * ----------------------------------------------------------------------
17341 */
17342
17343 #ifndef __WIN32__
17344
17345 static
cnt_inc(ESockCounter * cnt,ESockCounter inc)17346 BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc)
17347 {
17348 BOOLEAN_T wrap;
17349 ESockCounter max = ESOCK_COUNTER_MAX;
17350 ESockCounter current = *cnt;
17351
17352 if ((max - inc) >= current) {
17353 *cnt += inc;
17354 wrap = FALSE;
17355 } else {
17356 *cnt = inc - (max - current) - 1;
17357 wrap = TRUE;
17358 }
17359
17360 return (wrap);
17361 }
17362
17363 static
cnt_dec(ESockCounter * cnt,ESockCounter dec)17364 void cnt_dec(ESockCounter* cnt, ESockCounter dec)
17365 {
17366 ESockCounter current = *cnt;
17367
17368 if (dec > current)
17369 *cnt = 0; // The counter cannot be < 0 so this is the best we can do...
17370 else
17371 *cnt -= dec;
17372
17373 return;
17374 }
17375
17376 #endif // #ifndef __WIN32__
17377
17378
17379
17380
17381 /* ----------------------------------------------------------------------
17382 * M o n i t o r W r a p p e r F u n c t i o n s
17383 * ----------------------------------------------------------------------
17384 */
17385
17386 #ifndef __WIN32__
17387
17388 static
esock_monitor(const char * slogan,ErlNifEnv * env,ESockDescriptor * descP,const ErlNifPid * pid,ESockMonitor * monP)17389 int esock_monitor(const char* slogan,
17390 ErlNifEnv* env,
17391 ESockDescriptor* descP,
17392 const ErlNifPid* pid,
17393 ESockMonitor* monP)
17394 {
17395 int res;
17396
17397 SSDBG( descP, ("SOCKET",
17398 "esock_monitor {%d} [%T] %s: try monitor\r\n",
17399 descP->sock, esock_self(env), slogan) );
17400
17401 res = enif_monitor_process(env, descP, pid, &monP->mon);
17402
17403 if (res != 0) {
17404 monP->isActive = FALSE;
17405
17406 SSDBG( descP,
17407 ("SOCKET",
17408 "esock_monitor {%d} [%T] %s: monitor failed: %d\r\n",
17409 descP->sock, esock_self(env), slogan, res) );
17410 } else {
17411 monP->isActive = TRUE;
17412
17413 SSDBG( descP,
17414 ("SOCKET",
17415 "esock_monitor {%d} [%T] %s: monitor ok: %T\r\n",
17416 descP->sock, esock_self(env), slogan,
17417 esock_make_monitor_term(env, monP)) );
17418 }
17419
17420 return res;
17421 }
17422
17423 static
esock_demonitor(const char * slogan,ErlNifEnv * env,ESockDescriptor * descP,ESockMonitor * monP)17424 int esock_demonitor(const char* slogan,
17425 ErlNifEnv* env,
17426 ESockDescriptor* descP,
17427 ESockMonitor* monP)
17428 {
17429 int res;
17430
17431 if (! monP->isActive)
17432 return 1;
17433
17434 SSDBG( descP, ("SOCKET",
17435 "esock_demonitor {%d} [%T] %s: try demonitor %T\r\n",
17436 descP->sock, esock_self(env), slogan,
17437 esock_make_monitor_term(env, monP)) );
17438
17439 res = enif_demonitor_process(env, descP, &monP->mon);
17440 esock_monitor_init(monP);
17441
17442 if (res != 0) {
17443 SSDBG( descP,
17444 ("SOCKET",
17445 "esock_demonitor {%d}[%T] %s: demonitor failed: %d\r\n",
17446 descP->sock, esock_self(env), slogan, res) );
17447 }
17448
17449 return res;
17450 }
17451
17452 static
esock_monitor_init(ESockMonitor * monP)17453 void esock_monitor_init(ESockMonitor* monP)
17454 {
17455 monP->isActive = FALSE;
17456 }
17457
17458 static
esock_make_monitor_term(ErlNifEnv * env,const ESockMonitor * monP)17459 ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP)
17460 {
17461 if (monP->isActive)
17462 return enif_make_monitor_term(env, &monP->mon);
17463 else
17464 return esock_atom_undefined;
17465 }
17466
esock_monitor_eq(const ESockMonitor * monP,const ErlNifMonitor * mon)17467 static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP,
17468 const ErlNifMonitor* mon) {
17469 if (monP->isActive)
17470 return enif_compare_monitors(&monP->mon, mon) == 0;
17471 else
17472 return FALSE;
17473 }
17474
17475 #endif // #ifndef __WIN32__
17476
17477
17478
17479 /* ----------------------------------------------------------------------
17480 * C a l l b a c k F u n c t i o n s
17481 * ----------------------------------------------------------------------
17482 */
17483
17484
17485 #ifndef __WIN32__
free_request_queue(ESockRequestQueue * q)17486 static void free_request_queue(ESockRequestQueue* q)
17487 {
17488 while (q->first) {
17489 ESockRequestQueueElement* free_me = q->first;
17490 q->first = free_me->nextP;
17491 esock_free_env("dtor", free_me->data.env);
17492 FREE(free_me);
17493 }
17494 }
17495 #endif // #ifndef __WIN32__
17496
17497 /* =========================================================================
17498 * esock_dtor - Callback function for resource destructor
17499 *
17500 */
17501 static
esock_dtor(ErlNifEnv * env,void * obj)17502 void esock_dtor(ErlNifEnv* env, void* obj)
17503 {
17504 #ifndef __WIN32__
17505 ESockDescriptor* descP = (ESockDescriptor*) obj;
17506
17507 MLOCK(descP->readMtx);
17508 MLOCK(descP->writeMtx);
17509
17510 SGDBG( ("SOCKET", "dtor {%d,0x%X}\r\n",
17511 descP->sock, descP->readState | descP->writeState) );
17512
17513 if (IS_SELECTED(descP)) {
17514 /* We have used the socket in the select machinery,
17515 * so we must have closed it properly to get here
17516 */
17517 ESOCK_ASSERT( IS_CLOSED(descP->readState) );
17518 ESOCK_ASSERT( IS_CLOSED(descP->writeState) );
17519 ESOCK_ASSERT( descP->sock == INVALID_SOCKET );
17520 } else {
17521 /* The socket is only opened, should be safe to close nonblocking */
17522 (void) sock_close(descP->sock);
17523 descP->sock = INVALID_SOCKET;
17524 }
17525
17526 SGDBG( ("SOCKET", "dtor -> set state and pattern\r\n") );
17527 descP->readState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED);
17528 descP->writeState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED);
17529 descP->pattern = (ESOCK_DESC_PATTERN_DTOR | ESOCK_STATE_CLOSED);
17530
17531 esock_free_env("dtor reader", descP->currentReader.env);
17532 descP->currentReader.env = NULL;
17533
17534 esock_free_env("dtor writer", descP->currentWriter.env);
17535 descP->currentWriter.env = NULL;
17536
17537 esock_free_env("dtor acceptor", descP->currentAcceptor.env);
17538 descP->currentAcceptor.env = NULL;
17539
17540 SGDBG( ("SOCKET", "dtor -> try free readers request queue\r\n") );
17541 free_request_queue(&descP->readersQ);
17542
17543 SGDBG( ("SOCKET", "dtor -> try free writers request queue\r\n") );
17544 free_request_queue(&descP->writersQ);
17545
17546 SGDBG( ("SOCKET", "dtor -> try free acceptors request queue\r\n") );
17547 free_request_queue(&descP->acceptorsQ);
17548
17549 #ifdef HAVE_SENDFILE
17550 ESOCK_ASSERT( descP->sendfileHandle == INVALID_HANDLE );
17551 if (descP->sendfileCountersP != NULL) {
17552 FREE(descP->sendfileCountersP);
17553 descP->sendfileCountersP = NULL;
17554 }
17555 #endif
17556
17557 esock_free_env("dtor close env", descP->closeEnv);
17558 descP->closeEnv = NULL;
17559
17560 esock_free_env("dtor meta env", descP->meta.env);
17561 descP->meta.env = NULL;
17562
17563 MUNLOCK(descP->writeMtx);
17564 MUNLOCK(descP->readMtx);
17565
17566 SGDBG( ("SOCKET", "dtor -> try destroy read mutex\r\n") );
17567 MDESTROY(descP->readMtx); descP->readMtx = NULL;
17568
17569 SGDBG( ("SOCKET", "dtor -> try destroy write mutex\r\n") );
17570 MDESTROY(descP->writeMtx); descP->writeMtx = NULL;
17571
17572 SGDBG( ("SOCKET", "dtor -> done\r\n") );
17573 #endif // #ifndef __WIN32__
17574 }
17575
17576
17577 /* =========================================================================
17578 * esock_stop - Callback function for resource stop
17579 *
17580 * When the socket is stopped, we need to inform:
17581 *
17582 * * the controlling process
17583 * * the current writer and any waiting writers
17584 * * the current reader and any waiting readers
17585 * * the current acceptor and any waiting acceptor
17586 *
17587 * Also, make sure no process gets the message twice
17588 * (in case it is, for instance, both controlling process
17589 * and a writer).
17590 *
17591 */
17592 static
esock_stop(ErlNifEnv * env,void * obj,ErlNifEvent fd,int is_direct_call)17593 void esock_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, int is_direct_call)
17594 {
17595 #ifndef __WIN32__
17596 ESockDescriptor* descP = (ESockDescriptor*) obj;
17597
17598 if (is_direct_call) {
17599 return; // Nothing to do, caller gets ERL_NIF_SELECT_STOP_CALLED
17600 }
17601
17602 // This is a scheduled call, caller gets ERL_NIF_SELECT_STOP_SCHEDULED
17603 MLOCK(descP->readMtx);
17604 MLOCK(descP->writeMtx);
17605
17606 SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} -> when %s"
17607 "\r\n ctrlPid: %T"
17608 "\r\n closerPid: %T"
17609 "\r\ncounters:"
17610 "\r\n writePkgCnt: %lu"
17611 "\r\n writePkgMax: %lu"
17612 "\r\n writeByteCnt: %lu"
17613 "\r\n writeTries: %lu"
17614 "\r\n writeWaits: %lu"
17615 "\r\n writeFails: %lu"
17616 "\r\n readPkgCnt: %lu"
17617 "\r\n readPkgMax: %lu"
17618 "\r\n readByteCnt: %lu"
17619 "\r\n readTries: %lu"
17620 "\r\n readWaits: %lu"
17621 "\r\n accSuccess: %lu"
17622 "\r\n accTries: %lu"
17623 "\r\n accWaits: %lu"
17624 "\r\n accFails: %lu"
17625 "\r\n",
17626 descP->sock, fd,
17627 (is_direct_call) ? "called" : "scheduled",
17628 descP->ctrlPid,
17629 descP->closerPid,
17630 //
17631 (unsigned long) descP->writePkgCnt,
17632 (unsigned long) descP->writePkgMax,
17633 (unsigned long) descP->writeByteCnt,
17634 (unsigned long) descP->writeTries,
17635 (unsigned long) descP->writeWaits,
17636 (unsigned long) descP->writeFails,
17637 (unsigned long) descP->readPkgCnt,
17638 (unsigned long) descP->readPkgMax,
17639 (unsigned long) descP->readByteCnt,
17640 (unsigned long) descP->readTries,
17641 (unsigned long) descP->readWaits,
17642 //
17643 (unsigned long) descP->accSuccess,
17644 (unsigned long) descP->accTries,
17645 (unsigned long) descP->accWaits,
17646 (unsigned long) descP->accFails) );
17647
17648 #ifdef HAVE_SENDFILE
17649 if (descP->sendfileCountersP != NULL) {
17650 ESockSendfileCounters *cP = descP->sendfileCountersP;
17651
17652 SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} ->"
17653 "\r\nsendfileCounters:"
17654 "\r\n cnt: %lu"
17655 "\r\n byteCnt: %lu"
17656 "\r\n fails: %lu"
17657 "\r\n max: %lu"
17658 "\r\n pkg: %lu"
17659 "\r\n pkgMax %lu"
17660 "\r\n tries: %lu"
17661 "\r\n waits: %lu"
17662 "\r\n",
17663 descP->sock, fd,
17664 (unsigned long) cP->cnt,
17665 (unsigned long) cP->byteCnt,
17666 (unsigned long) cP->fails,
17667 (unsigned long) cP->max,
17668 (unsigned long) cP->pkg,
17669 (unsigned long) cP->pkgMax,
17670 (unsigned long) cP->tries,
17671 (unsigned long) cP->waits) );
17672 }
17673 #endif
17674
17675 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17676 *
17677 * Inform waiting Closer, or close socket
17678 *
17679 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17680 */
17681
17682 if (! enif_is_pid_undefined(&descP->closerPid)) {
17683 /* We have a waiting closer process after nif_close()
17684 * - send message to trigger nif_finalize_close()
17685 */
17686
17687 SSDBG( descP,
17688 ("SOCKET",
17689 "esock_stop {%d/%d} -> send close msg to %T\r\n",
17690 descP->sock, fd, MKPID(env, &descP->closerPid)) );
17691
17692 esock_send_close_msg(env, descP, &descP->closerPid);
17693 /* Message send frees closeEnv */
17694 descP->closeEnv = NULL;
17695 descP->closeRef = esock_atom_undefined;
17696 } else {
17697 int err;
17698
17699 /* We do not have a closer process
17700 * - have to do an unclean (non blocking) close */
17701
17702 #ifdef HAVE_SENDFILE
17703 if (descP->sendfileHandle != INVALID_HANDLE)
17704 esock_send_sendfile_deferred_close_msg(env, descP);
17705 #endif
17706
17707 err = esock_close_socket(env, descP, FALSE);
17708
17709 if (err != 0)
17710 esock_warning_msg("Failed closing socket without "
17711 "closer process: "
17712 "\r\n Controlling Process: %T"
17713 "\r\n Descriptor: %d"
17714 "\r\n Errno: %d (%T)"
17715 "\r\n",
17716 descP->ctrlPid, descP->sock,
17717 err, MKA(env, erl_errno_id(err)));
17718 }
17719
17720 SSDBG( descP,
17721 ("SOCKET",
17722 "esock_stop {%d/%d} -> done\r\n",
17723 descP->sock, fd) );
17724
17725 MUNLOCK(descP->writeMtx);
17726 MUNLOCK(descP->readMtx);
17727 #endif // #ifndef __WIN32__
17728 }
17729
17730
17731
17732 /* *** esock_stop_handle_current ***
17733 *
17734 * Handle current requestor (reader, writer or acceptor) during
17735 * socket stop.
17736 */
17737 #ifndef __WIN32__
17738 static
esock_stop_handle_current(ErlNifEnv * env,const char * role,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ESockRequestor * reqP)17739 void esock_stop_handle_current(ErlNifEnv* env,
17740 const char* role,
17741 ESockDescriptor* descP,
17742 ERL_NIF_TERM sockRef,
17743 ESockRequestor* reqP)
17744 {
17745 (void) DEMONP("esock_stop_handle_current", env, descP, &reqP->mon);
17746
17747 SSDBG( descP, ("SOCKET",
17748 "esock_stop_handle_current {%d} ->"
17749 " send abort message to current %s %T %T\r\n",
17750 descP->sock, role, reqP->pid, reqP->ref) );
17751
17752 esock_send_abort_msg(env, descP, sockRef, reqP, atom_closed);
17753
17754 enif_set_pid_undefined(&reqP->pid);
17755 reqP->ref = esock_atom_undefined;
17756 }
17757 #endif // #ifndef __WIN32__
17758
17759
17760
17761 /* This function traverse the queue and sends the specified
17762 * nif_abort message with the specified reason to each member,
17763 * and empty the queue.
17764 */
17765 #ifndef __WIN32__
17766 static
inform_waiting_procs(ErlNifEnv * env,const char * role,ESockDescriptor * descP,ERL_NIF_TERM sockRef,ESockRequestQueue * q,ERL_NIF_TERM reason)17767 void inform_waiting_procs(ErlNifEnv* env,
17768 const char* role,
17769 ESockDescriptor* descP,
17770 ERL_NIF_TERM sockRef,
17771 ESockRequestQueue* q,
17772 ERL_NIF_TERM reason)
17773 {
17774 ESockRequestQueueElement* currentP = q->first;
17775 ESockRequestQueueElement* nextP;
17776
17777 SSDBG( descP,
17778 ("SOCKET",
17779 "inform_waiting_procs -> handle waiting %s(s)\r\n", role) );
17780
17781 while (currentP != NULL) {
17782
17783 /* <KOLLA>
17784 *
17785 * Should we inform anyone if we fail to demonitor?
17786 * NOT SURE WHAT THAT WOULD REPRESENT AND IT IS NOT
17787 * IMPORTANT IN *THIS* CASE, BUT IT'S A FUNDAMENTAL OP...
17788 *
17789 * </KOLLA>
17790 */
17791
17792 SSDBG( descP,
17793 ("SOCKET",
17794 "inform_waiting_procs(%T) {%d} -> "
17795 "send abort message to waiting %s %T\r\n",
17796 sockRef, descP->sock,
17797 role, currentP->data.pid) );
17798
17799 esock_send_abort_msg(env, descP, sockRef, ¤tP->data, reason);
17800
17801 (void) DEMONP("inform_waiting_procs -> current 'request'",
17802 env, descP, ¤tP->data.mon);
17803
17804 nextP = currentP->nextP;
17805 FREE(currentP);
17806 currentP = nextP;
17807 }
17808
17809 q->first = NULL;
17810 q->last = NULL;
17811 }
17812 #endif // #ifndef __WIN32__
17813
17814
17815 /* =========================================================================
17816 * esock_down - Callback function for resource down (monitored processes)
17817 *
17818 */
17819 static
esock_down(ErlNifEnv * env,void * obj,const ErlNifPid * pidP,const ErlNifMonitor * monP)17820 void esock_down(ErlNifEnv* env,
17821 void* obj,
17822 const ErlNifPid* pidP,
17823 const ErlNifMonitor* monP)
17824 {
17825 #ifndef __WIN32__
17826 ESockDescriptor* descP = (ESockDescriptor*) obj;
17827
17828 MLOCK(descP->readMtx);
17829 MLOCK(descP->writeMtx);
17830
17831 SSDBG( descP, ("SOCKET", "esock_down {%d} -> entry with"
17832 "\r\n pid: %T"
17833 "\r\n Close: %s (%s)"
17834 "\r\n",
17835 descP->sock, MKPID(env, pidP),
17836 B2S(IS_CLOSED(descP->readState)),
17837 B2S(IS_CLOSING(descP->readState))) );
17838
17839 if (COMPARE_PIDS(&descP->closerPid, pidP) == 0) {
17840
17841 /* The closer process went down
17842 * - it will not call nif_finalize_close
17843 */
17844
17845 enif_set_pid_undefined(&descP->closerPid);
17846
17847 if (MON_EQ(&descP->closerMon, monP)) {
17848 MON_INIT(&descP->closerMon);
17849
17850 SSDBG( descP,
17851 ("SOCKET",
17852 "esock_down {%d} -> closer process exit\r\n",
17853 descP->sock) );
17854
17855 } else {
17856 // The owner is the closer so we used its monitor
17857
17858 ESOCK_ASSERT( MON_EQ(&descP->ctrlMon, monP) );
17859 MON_INIT(&descP->ctrlMon);
17860 enif_set_pid_undefined(&descP->ctrlPid);
17861
17862 SSDBG( descP,
17863 ("SOCKET",
17864 "esock_down {%d} -> closer controlling process exit\r\n",
17865 descP->sock) );
17866 }
17867
17868 /* Since the closer went down there was one,
17869 * hence esock_close() must have run or scheduled esock_stop(),
17870 * or the socket has never been selected upon
17871 */
17872
17873 if (descP->closeEnv == NULL) {
17874 int err;
17875
17876 /* Since there is no closeEnv,
17877 * esock_close() did not schedule esock_stop()
17878 * and is about to call esock_finalize_close() but died,
17879 * or esock_stop() has run, sent close_msg to the closer
17880 * and cleared ->closeEnv but the closer died
17881 * - we have to do an unclean (non blocking) socket close here
17882 */
17883
17884 #ifdef HAVE_SENDFILE
17885 if (descP->sendfileHandle != INVALID_HANDLE)
17886 esock_send_sendfile_deferred_close_msg(env, descP);
17887 #endif
17888
17889 err = esock_close_socket(env, descP, FALSE);
17890 if (err != 0)
17891 esock_warning_msg("Failed closing socket for terminating "
17892 "closer process: "
17893 "\r\n Closer Process: %T"
17894 "\r\n Descriptor: %d"
17895 "\r\n Errno: %d (%T)"
17896 "\r\n",
17897 MKPID(env, pidP), descP->sock,
17898 err, MKA(env, erl_errno_id(err)));
17899 } else {
17900 /* Since there is a closeEnv esock_stop() has not run yet
17901 * - when it finds that there is no closer process
17902 * it will close the socket and ignore the close_msg
17903 */
17904 esock_free_env("esock_down - close-env", descP->closeEnv);
17905 descP->closeEnv = NULL;
17906 descP->closeRef = esock_atom_undefined;
17907 }
17908
17909 } else if (MON_EQ(&descP->ctrlMon, monP)) {
17910 MON_INIT(&descP->ctrlMon);
17911 /* The owner went down */
17912 enif_set_pid_undefined(&descP->ctrlPid);
17913
17914 if (IS_OPEN(descP->readState)) {
17915 SSDBG( descP,
17916 ("SOCKET",
17917 "esock_down {%d} -> controller process exit"
17918 "\r\n initiate close\r\n",
17919 descP->sock) );
17920
17921 esock_down_ctrl(env, descP, pidP);
17922
17923 descP->readState |= ESOCK_STATE_CLOSING;
17924 descP->writeState |= ESOCK_STATE_CLOSING;
17925 } else {
17926 SSDBG( descP,
17927 ("SOCKET",
17928 "esock_down {%d} -> controller process exit"
17929 "\r\n already closed or closing\r\n",
17930 descP->sock) );
17931 }
17932
17933 } else if (descP->connectorP != NULL &&
17934 MON_EQ(&descP->connector.mon, monP)) {
17935 MON_INIT(&descP->connector.mon);
17936
17937 SSDBG( descP,
17938 ("SOCKET",
17939 "esock_down {%d} -> connector process exit\r\n",
17940 descP->sock) );
17941
17942 /* connectorP is only set during connection.
17943 * Forget all about the ongoing connection.
17944 * We might end up connected, but the process that initiated
17945 * the connection has died and will never know
17946 */
17947
17948 requestor_release("esock_down->connector",
17949 env, descP, &descP->connector);
17950 descP->connectorP = NULL;
17951 descP->writeState &= ~ESOCK_STATE_CONNECTING;
17952
17953 } else {
17954 ERL_NIF_TERM sockRef;
17955
17956 /* check all operation queue(s): acceptor, writer and reader.
17957 *
17958 * Is it really any point in doing this if the socket is closed?
17959 *
17960 */
17961
17962 sockRef = enif_make_resource(env, descP);
17963
17964 if (IS_CLOSED(descP->readState)) {
17965 SSDBG( descP,
17966 ("SOCKET",
17967 "esock_down(%T) {%d} -> stray down: %T\r\n",
17968 sockRef, descP->sock, pidP) );
17969 } else {
17970
17971 SSDBG( descP,
17972 ("SOCKET",
17973 "esock_down(%T) {%d} -> other process term\r\n",
17974 sockRef, descP->sock) );
17975
17976 if (descP->currentReaderP != NULL)
17977 esock_down_reader(env, descP, sockRef, pidP, monP);
17978 if (descP->currentAcceptorP != NULL)
17979 esock_down_acceptor(env, descP, sockRef, pidP, monP);
17980 if (descP->currentWriterP != NULL)
17981 esock_down_writer(env, descP, sockRef, pidP, monP);
17982 }
17983 }
17984
17985 MUNLOCK(descP->writeMtx);
17986 MUNLOCK(descP->readMtx);
17987
17988 SSDBG( descP, ("SOCKET", "esock_down -> done\r\n") );
17989
17990 #endif // #ifndef __WIN32__
17991 }
17992
17993
17994
17995 /* *** esock_down_ctrl ***
17996 *
17997 * Stop after a downed controller
17998 *
17999 */
18000 #ifndef __WIN32__
18001 static
esock_down_ctrl(ErlNifEnv * env,ESockDescriptor * descP,const ErlNifPid * pidP)18002 void esock_down_ctrl(ErlNifEnv* env,
18003 ESockDescriptor* descP,
18004 const ErlNifPid* pidP)
18005 {
18006 SSDBG( descP,
18007 ("SOCKET", "esock_down_ctrl {%d} ->"
18008 "\r\n Pid: %T"
18009 "\r\n", descP->sock, MKPID(env, pidP)) );
18010
18011 if (esock_do_stop(env, descP)) {
18012 /* esock_stop() is scheduled
18013 * - it has to close the socket
18014 */
18015 SSDBG( descP,
18016 ("SOCKET", "esock_down_ctrl {%d} -> stop was scheduled\r\n",
18017 descP->sock) );
18018 } else {
18019 int err;
18020
18021 /* Socket is not in the select machinery
18022 * so esock_stop() will not be called
18023 * - we have to do an unclean (non blocking) socket close here
18024 */
18025
18026 #ifdef HAVE_SENDFILE
18027 if (descP->sendfileHandle != INVALID_HANDLE)
18028 esock_send_sendfile_deferred_close_msg(env, descP);
18029 #endif
18030
18031 err = esock_close_socket(env, descP, FALSE);
18032 if (err != 0)
18033 esock_warning_msg("Failed closing socket for terminating "
18034 "owner process: "
18035 "\r\n Owner Process: %T"
18036 "\r\n Descriptor: %d"
18037 "\r\n Errno: %d (%T)"
18038 "\r\n",
18039 MKPID(env, pidP), descP->sock,
18040 err, MKA(env, erl_errno_id(err)));
18041 }
18042 }
18043 #endif // #ifndef __WIN32__
18044
18045
18046
18047 /* *** esock_down_acceptor ***
18048 *
18049 * Check and then handle a downed acceptor process.
18050 *
18051 */
18052 #ifndef __WIN32__
18053 static
esock_down_acceptor(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,const ErlNifPid * pidP,const ErlNifMonitor * monP)18054 void esock_down_acceptor(ErlNifEnv* env,
18055 ESockDescriptor* descP,
18056 ERL_NIF_TERM sockRef,
18057 const ErlNifPid* pidP,
18058 const ErlNifMonitor* monP)
18059 {
18060 if (MON_EQ(&descP->currentAcceptor.mon, monP)) {
18061 MON_INIT(&descP->currentAcceptor.mon);
18062
18063 SSDBG( descP,
18064 ("SOCKET",
18065 "esock_down_acceptor(%T) {%d} -> "
18066 "current acceptor - try activate next\r\n",
18067 sockRef, descP->sock) );
18068
18069 if (!activate_next_acceptor(env, descP, sockRef)) {
18070
18071 SSDBG( descP,
18072 ("SOCKET",
18073 "esock_down_acceptor(%T) {%d} -> no more writers\r\n",
18074 sockRef, descP->sock) );
18075
18076 descP->readState &= ~ESOCK_STATE_ACCEPTING;
18077
18078 descP->currentAcceptorP = NULL;
18079 }
18080
18081 } else {
18082
18083 /* Maybe unqueue one of the waiting acceptors */
18084
18085 SSDBG( descP,
18086 ("SOCKET",
18087 "esock_down_acceptor(%T) {%d} -> "
18088 "not current acceptor - maybe a waiting acceptor\r\n",
18089 sockRef, descP->sock) );
18090
18091 acceptor_unqueue(env, descP, NULL, pidP);
18092 }
18093 }
18094 #endif // #ifndef __WIN32__
18095
18096
18097 /* *** esock_down_writer ***
18098 *
18099 * Check and then handle a downed writer process.
18100 *
18101 */
18102 #ifndef __WIN32__
18103 static
esock_down_writer(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,const ErlNifPid * pidP,const ErlNifMonitor * monP)18104 void esock_down_writer(ErlNifEnv* env,
18105 ESockDescriptor* descP,
18106 ERL_NIF_TERM sockRef,
18107 const ErlNifPid* pidP,
18108 const ErlNifMonitor* monP)
18109 {
18110 if (MON_EQ(&descP->currentWriter.mon, monP)) {
18111 MON_INIT(&descP->currentWriter.mon);
18112
18113 SSDBG( descP,
18114 ("SOCKET",
18115 "esock_down_writer(%T) {%d} -> "
18116 "current writer - try activate next\r\n",
18117 sockRef, descP->sock) );
18118
18119 if (!activate_next_writer(env, descP, sockRef)) {
18120
18121 SSDBG( descP,
18122 ("SOCKET",
18123 "esock_down_writer(%T) {%d} -> no active writer\r\n",
18124 sockRef, descP->sock) );
18125
18126 descP->currentWriterP = NULL;
18127 }
18128
18129 } else {
18130
18131 /* Maybe unqueue one of the waiting writer(s) */
18132
18133 SSDBG( descP,
18134 ("SOCKET",
18135 "esock_down_writer(%T) {%d} -> "
18136 "not current writer - maybe a waiting writer\r\n",
18137 sockRef, descP->sock) );
18138
18139 writer_unqueue(env, descP, NULL, pidP);
18140 }
18141 }
18142 #endif // #ifndef __WIN32__
18143
18144
18145
18146
18147 /* *** esock_down_reader ***
18148 *
18149 * Check and then handle a downed reader process.
18150 *
18151 */
18152 #ifndef __WIN32__
18153 static
esock_down_reader(ErlNifEnv * env,ESockDescriptor * descP,ERL_NIF_TERM sockRef,const ErlNifPid * pidP,const ErlNifMonitor * monP)18154 void esock_down_reader(ErlNifEnv* env,
18155 ESockDescriptor* descP,
18156 ERL_NIF_TERM sockRef,
18157 const ErlNifPid* pidP,
18158 const ErlNifMonitor* monP)
18159 {
18160 if (MON_EQ(&descP->currentReader.mon, monP)) {
18161 MON_INIT(&descP->currentReader.mon);
18162
18163 SSDBG( descP,
18164 ("SOCKET",
18165 "esock_down_reader(%T) {%d} -> "
18166 "current reader - try activate next\r\n",
18167 sockRef, descP->sock) );
18168
18169 if (! activate_next_reader(env, descP, sockRef)) {
18170
18171 SSDBG( descP,
18172 ("SOCKET",
18173 "esock_down_reader(%T) {%d} -> no more readers\r\n",
18174 sockRef, descP->sock) );
18175
18176 descP->currentReaderP = NULL;
18177 }
18178
18179 } else {
18180
18181 /* Maybe unqueue one of the waiting reader(s) */
18182
18183 SSDBG( descP,
18184 ("SOCKET",
18185 "esock_down_reader(%T) {%d} -> "
18186 "not current reader - maybe a waiting reader\r\n",
18187 sockRef, descP->sock) );
18188
18189 reader_unqueue(env, descP, NULL, pidP);
18190 }
18191 }
18192 #endif // #ifndef __WIN32__
18193
18194
18195
18196 /* ----------------------------------------------------------------------
18197 * L o a d / u n l o a d / u p g r a d e F u n c t i o n s
18198 * ----------------------------------------------------------------------
18199 */
18200
18201 static
18202 ErlNifFunc esock_funcs[] =
18203 {
18204 // Some utility and support functions
18205 {"nif_info", 0, nif_info, 0},
18206 {"nif_info", 1, nif_info, 0},
18207 {"nif_supports", 0, nif_supports, 0},
18208 {"nif_supports", 1, nif_supports, 0},
18209 {"nif_command", 1, nif_command, 0},
18210
18211 // The proper "socket" interface
18212 {"nif_open", 2, nif_open, 0},
18213 {"nif_open", 4, nif_open, 0},
18214 {"nif_bind", 2, nif_bind, 0},
18215 {"nif_connect", 1, nif_connect, 0},
18216 {"nif_connect", 3, nif_connect, 0},
18217 {"nif_listen", 2, nif_listen, 0},
18218 {"nif_accept", 2, nif_accept, 0},
18219 {"nif_send", 4, nif_send, 0},
18220 {"nif_sendto", 5, nif_sendto, 0},
18221 {"nif_sendmsg", 5, nif_sendmsg, 0},
18222 {"nif_sendfile", 5, nif_sendfile, ERL_NIF_DIRTY_JOB_IO_BOUND},
18223 {"nif_sendfile", 4, nif_sendfile, ERL_NIF_DIRTY_JOB_IO_BOUND},
18224 {"nif_sendfile", 1, nif_sendfile, ERL_NIF_DIRTY_JOB_IO_BOUND},
18225 {"nif_recv", 4, nif_recv, 0},
18226 {"nif_recvfrom", 4, nif_recvfrom, 0},
18227 {"nif_recvmsg", 5, nif_recvmsg, 0},
18228 {"nif_close", 1, nif_close, 0},
18229 {"nif_shutdown", 2, nif_shutdown, 0},
18230 {"nif_setopt", 5, nif_setopt, 0},
18231 {"nif_getopt", 3, nif_getopt, 0},
18232 {"nif_getopt", 4, nif_getopt, 0},
18233 {"nif_sockname", 1, nif_sockname, 0},
18234 {"nif_peername", 1, nif_peername, 0},
18235
18236 /* Misc utility functions */
18237
18238 /* "Extra" functions to "complete" the socket interface.
18239 * For instance, the function nif_finalize_close
18240 * is called after the close *select* has "completed".
18241 */
18242 {"nif_cancel", 3, nif_cancel, 0},
18243 {"nif_finalize_close", 1, nif_finalize_close, ERL_NIF_DIRTY_JOB_IO_BOUND}
18244 };
18245
18246
18247 #ifndef __WIN32__
18248 static
extract_debug_filename(ErlNifEnv * env,ERL_NIF_TERM map)18249 char* extract_debug_filename(ErlNifEnv* env,
18250 ERL_NIF_TERM map)
18251 {
18252 /* See the functions above */
18253 ERL_NIF_TERM val;
18254 ErlNifBinary bin;
18255 char *filename;
18256
18257 if (! GET_MAP_VAL(env, map, atom_debug_filename, &val))
18258 return NULL;
18259
18260 if (! enif_inspect_binary(env, val, &bin))
18261 return NULL;
18262
18263 ESOCK_ASSERT( (filename = MALLOC(bin.size + 1)) != NULL );
18264
18265 sys_memcpy(filename, bin.data, bin.size);
18266 filename[bin.size] = '\0';
18267 return filename;
18268 }
18269 #endif // #ifndef __WIN32__
18270
18271
18272
18273 /* =======================================================================
18274 * load_info - A map of misc info (e.g global debug)
18275 */
18276
18277 static
on_load(ErlNifEnv * env,void ** priv_data,ERL_NIF_TERM load_info)18278 int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
18279 {
18280 /* +++ Local atoms and error reason atoms +++ */
18281 #define LOCAL_ATOM_DECL(A) atom_##A = MKA(env, #A)
18282 LOCAL_ATOMS;
18283 LOCAL_ERROR_REASON_ATOMS;
18284 #undef LOCAL_ATOM_DECL
18285
18286 /* Global atom(s) and error reason atom(s) */
18287 #define GLOBAL_ATOM_DECL(A) esock_atom_##A = MKA(env, #A)
18288 GLOBAL_ATOMS;
18289 GLOBAL_ERROR_REASON_ATOMS;
18290 #undef GLOBAL_ATOM_DECL
18291
18292 esock_atom_socket_tag = MKA(env, "$socket");
18293
18294 #ifndef __WIN32__
18295
18296 if (! esock_extract_pid_from_map(env, load_info,
18297 atom_registry,
18298 &data.regPid)) {
18299 enif_set_pid_undefined(&data.regPid);
18300 return 1; // Failure - no registry pid
18301 }
18302
18303 data.useReg =
18304 esock_get_bool_from_map(env, load_info,
18305 atom_use_registry,
18306 ESOCK_USE_SOCKET_REGISTRY);
18307
18308 data.iow =
18309 esock_get_bool_from_map(env, load_info,
18310 atom_iow,
18311 ESOCK_NIF_IOW_DEFAULT);
18312
18313 {
18314 char *debug_filename;
18315
18316 debug_filename = extract_debug_filename(env, load_info);
18317
18318 if (esock_dbg_init(debug_filename)) {
18319 // Pick up early debug flags only if debug_filename is ok
18320
18321 data.dbg =
18322 esock_get_bool_from_map(env, load_info,
18323 esock_atom_debug,
18324 ESOCK_GLOBAL_DEBUG_DEFAULT);
18325 data.sockDbg =
18326 esock_get_bool_from_map(env, load_info,
18327 atom_socket_debug,
18328 ESOCK_DEBUG_DEFAULT);
18329 }
18330
18331 if (debug_filename != NULL)
18332 FREE(debug_filename);
18333 }
18334
18335 data.protocolsMtx = MCREATE("esock.protocols");
18336
18337 /* +++ Global Counters +++ */
18338 data.cntMtx = MCREATE("esock.gcnt");
18339 data.numSockets = 0;
18340 data.numTypeDGrams = 0;
18341 data.numTypeStreams = 0;
18342 data.numTypeSeqPkgs = 0;
18343 data.numDomainLocal = 0;
18344 data.numDomainInet = 0;
18345 data.numDomainInet6 = 0;
18346 data.numProtoIP = 0;
18347 data.numProtoTCP = 0;
18348 data.numProtoUDP = 0;
18349 data.numProtoSCTP = 0;
18350
18351 initOpts();
18352 initCmsgTables();
18353
18354 data.iov_max =
18355 #if defined(NO_SYSCONF) || (! defined(_SC_IOV_MAX))
18356 # ifdef IOV_MAX
18357 IOV_MAX
18358 # else
18359 16
18360 # endif
18361 #else
18362 sysconf(_SC_IOV_MAX)
18363 #endif
18364 ;
18365 ESOCK_ASSERT( data.iov_max > 0 );
18366
18367 #endif // #ifndef __WIN32__
18368
18369 esocks = enif_open_resource_type_x(env,
18370 "sockets",
18371 &esockInit,
18372 ERL_NIF_RT_CREATE,
18373 NULL);
18374 return esocks != NULL ?
18375 0: // Success
18376 1; // Failure
18377 }
18378
18379 /*
18380 * MODULE: socket (the erlang API/interface module)
18381 * funcs: esock_funcs (defines the API of this nif)
18382 * load: on_load (load this nif)
18383 * upgrade: NULL (not used)
18384 * NULL: THIS IS NOT USED
18385 * unload: NULL (not used)
18386 */
18387 ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL)
18388