-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathunix_socket_syncio.c
More file actions
10748 lines (8905 loc) · 343 KB
/
Copy pathunix_socket_syncio.c
File metadata and controls
10748 lines (8905 loc) · 343 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* %CopyrightBegin%
*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright Ericsson AB 2022-2026. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* %CopyrightEnd%
*
* ----------------------------------------------------------------------
* Purpose : UNIX version of synchronous I/O backend.
* ----------------------------------------------------------------------
*
* essio = ESock Synchronous I/O
*
*
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef ESOCK_ENABLE
/* If we HAVE_SCTP_H and Solaris, we need to define the following in
* order to get SCTP working:
*/
#if (defined(HAVE_SCTP_H) && defined(__sun) && defined(__SVR4))
#define SOLARIS10 1
/* WARNING: This is not quite correct, it may also be Solaris 11! */
#define _XPG4_2
#define __EXTENSIONS__
#endif
#ifdef HAVE_SENDFILE
#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
#include <sys/sendfile.h>
#elif defined(__FreeBSD__) || defined(__DragonFly__)
/* Need to define __BSD_VISIBLE in order to expose prototype
* of sendfile in sys/socket.h
*/
#define __BSD_VISIBLE 1
#endif
#endif
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
#endif
#include "sys.h"
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <net/if.h>
/* SCTP support -- currently for UNIX platforms only: */
#undef HAVE_SCTP
#define ASSOC_ID_LEN 4
#if defined(HAVE_SCTP_H)
#include <netinet/sctp.h>
/* SCTP Socket API Draft from version 11 on specifies that netinet/sctp.h must
* explicitly define HAVE_SCTP in case when SCTP is supported, but Solaris 10
* still apparently uses Draft 10, and does not define that symbol, so we have
* to define it explicitly:
*/
#ifndef HAVE_SCTP
# define HAVE_SCTP
#endif
/* These changed in draft 11, so SOLARIS10 uses the old MSG_* */
#if ! HAVE_DECL_SCTP_UNORDERED
# define SCTP_UNORDERED MSG_UNORDERED
#endif
#if ! HAVE_DECL_SCTP_ADDR_OVER
# define SCTP_ADDR_OVER MSG_ADDR_OVER
#endif
#if ! HAVE_DECL_SCTP_ABORT
# define SCTP_ABORT MSG_ABORT
#endif
#if ! HAVE_DECL_SCTP_EOF
# define SCTP_EOF MSG_EOF
#endif
/* More Solaris 10 fixes: */
#if ! HAVE_DECL_SCTP_CLOSED && HAVE_DECL_SCTPS_IDLE
# define SCTP_CLOSED SCTPS_IDLE
# undef HAVE_DECL_SCTP_CLOSED
# define HAVE_DECL_SCTP_CLOSED 1
#endif
#if ! HAVE_DECL_SCTP_BOUND && HAVE_DECL_SCTPS_BOUND
# define SCTP_BOUND SCTPS_BOUND
# undef HAVE_DECL_SCTP_BOUND
# define HAVE_DECL_SCTP_BOUND 1
#endif
#if ! HAVE_DECL_SCTP_LISTEN && HAVE_DECL_SCTPS_LISTEN
# define SCTP_LISTEN SCTPS_LISTEN
# undef HAVE_DECL_SCTP_LISTEN
# define HAVE_DECL_SCTP_LISTEN 1
#endif
#if ! HAVE_DECL_SCTP_COOKIE_WAIT && HAVE_DECL_SCTPS_COOKIE_WAIT
# define SCTP_COOKIE_WAIT SCTPS_COOKIE_WAIT
# undef HAVE_DECL_SCTP_COOKIE_WAIT
# define HAVE_DECL_SCTP_COOKIE_WAIT 1
#endif
#if ! HAVE_DECL_SCTP_COOKIE_ECHOED && HAVE_DECL_SCTPS_COOKIE_ECHOED
# define SCTP_COOKIE_ECHOED SCTPS_COOKIE_ECHOED
# undef HAVE_DECL_SCTP_COOKIE_ECHOED
# define HAVE_DECL_SCTP_COOKIE_ECHOED 1
#endif
#if ! HAVE_DECL_SCTP_ESTABLISHED && HAVE_DECL_SCTPS_ESTABLISHED
# define SCTP_ESTABLISHED SCTPS_ESTABLISHED
# undef HAVE_DECL_SCTP_ESTABLISHED
# define HAVE_DECL_SCTP_ESTABLISHED 1
#endif
#if ! HAVE_DECL_SCTP_SHUTDOWN_PENDING && HAVE_DECL_SCTPS_SHUTDOWN_PENDING
# define SCTP_SHUTDOWN_PENDING SCTPS_SHUTDOWN_PENDING
# undef HAVE_DECL_SCTP_SHUTDOWN_PENDING
# define HAVE_DECL_SCTP_SHUTDOWN_PENDING 1
#endif
#if ! HAVE_DECL_SCTP_SHUTDOWN_SENT && HAVE_DECL_SCTPS_SHUTDOWN_SENT
# define SCTP_SHUTDOWN_SENT SCTPS_SHUTDOWN_SENT
# undef HAVE_DECL_SCTP_SHUTDOWN_SENT
# define HAVE_DECL_SCTP_SHUTDOWN_SENT 1
#endif
#if ! HAVE_DECL_SCTP_SHUTDOWN_RECEIVED && HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED
# define SCTP_SHUTDOWN_RECEIVED SCTPS_SHUTDOWN_RECEIVED
# undef HAVE_DECL_SCTP_SHUTDOWN_RECEIVED
# define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED 1
#endif
#if ! HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT && HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT
# define SCTP_SHUTDOWN_ACK_SENT SCTPS_SHUTDOWN_ACK_SENT
# undef HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT
# define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT 1
#endif
/* New spelling in lksctp 2.6.22 or maybe even earlier:
* adaption -> adaptation
*/
#if !defined(SCTP_ADAPTATION_LAYER) && defined (SCTP_ADAPTION_LAYER)
# define SCTP_ADAPTATION_LAYER SCTP_ADAPTION_LAYER
# define SCTP_ADAPTATION_INDICATION SCTP_ADAPTION_INDICATION
# define sctp_adaptation_event sctp_adaption_event
# define sctp_setadaptation sctp_setadaption
# define sn_adaptation_event sn_adaption_event
# define sai_adaptation_ind sai_adaption_ind
# define ssb_adaptation_ind ssb_adaption_ind
# define sctp_adaptation_layer_event sctp_adaption_layer_event
#endif
/* Have Static SCTP */
#if defined(HAVE_SCTP_BINDX) || \
defined(HAVE_SCTP_PEELOFF) || \
defined(HAVE_SCTP_GETLADDRS) || defined(HAVE_SCTP_FREELADDRS) || \
defined(HAVE_SCTP_GETPADDRS) || defined(HAVE_SCTP_FREEPADDRS) || \
defined(HAVE_SCTP_CONNECTX)
#define HAVE_STATIC_SCTP TRUE
#endif
#endif /* #if defined(HAVE_SCTP_H) */
#include "prim_socket_int.h"
#include "socket_util.h"
#include "socket_io.h"
#include "socket_syncio.h"
#include "socket_tarray.h"
#include "prim_file_nif_dyncall.h"
/* ======================================================================== *
* Socket wrappers *
* ======================================================================== *
*/
#ifdef HAS_ACCEPT4
// We have to figure out what the flags are...
#define sock_accept(s, addr, len) \
accept4((s), (addr), (len), (SOCK_CLOEXEC))
#else
#define sock_accept(s, addr, len) accept((s), (addr), (len))
#endif
#define sock_bind(s, addr, len) bind((s), (addr), (len))
#define sock_bindx(s, addr, acnt, a) \
ctrl.sctp.bindx((s), (addr), (acnt), (a))
#define sock_ensure_bindx(e) \
if (ctrl.sctp.bindx == NULL) \
return enif_raise_exception((e), MKA((e), "notsup"));
#define sock_close(s) close((s))
/* Adaptive read buffer: double on a filled buffer, halve back towards
* the configured size once an EWMA of the read sizes falls below a
* quarter of it.
*/
#define ESSIO_RECV_ADAPT_BUFFER_MAX (1 << 18)
#define ESSIO_RECV_ADAPT_EWMA_SHIFT 3
// #define sock_close_event(e) /* do nothing */
#define sock_connect(s, addr, len) connect((s), (addr), (len))
#define sock_connectx(s, addrs, acnt, aidp) \
ctrl.sctp.connectx((s), (addrs), (acnt), (aidp))
#define sock_ensure_connectx(e) \
if (ctrl.sctp.connectx == NULL) \
return enif_raise_exception((e), MKA((e), "notsup"));
#define sock_errno() errno
// #define sock_listen(s, b) listen((s), (b))
// #define sock_name(s, addr, len) getsockname((s), (addr), (len))
#define sock_names(s, aid, ap) ctrl.sctp.getladdrs((s), (aid), (ap))
#define sock_ensure_names(e) \
if (ctrl.sctp.getladdrs == NULL) \
return enif_raise_exception((e), MKA((e), "notsup"));
#define sock_ntohs(x) ntohs((x))
#define sock_htonl(x) htonl((x))
#define sock_open(domain, type, proto) socket((domain), (type), (proto))
#define sock_peeloff(s, aid) ctrl.sctp.peeloff((s), (aid))
#define sock_ensure_peeloff(E) \
if (ctrl.sctp.peeloff == NULL) \
return enif_raise_exception((E), MKA((E), "notsup"))
#define sock_peer(s, addr, len) getpeername((s), (addr), (len))
#define sock_peers(s, aid, ap) ctrl.sctp.getpaddrs((s), (aid), (ap))
#define sock_ensure_peers(e) \
if (ctrl.sctp.getpaddrs == NULL) \
return enif_raise_exception((e), MKA((e), "notsup"));
#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag))
#define sock_recvfrom(s,buf,blen,flag,addr,alen) \
recvfrom((s),(buf),(blen),(flag),(addr),(alen))
#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag))
#ifdef HAVE_RECVMMSG
#define sock_recvmmsg(s,mmsghdr,vlen,flag,timeout) \
recvmmsg((s),(mmsghdr),(vlen),(flag),(timeout))
#endif
#define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag))
#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag))
#ifdef HAVE_SENDMMSG
#define sock_sendmmsg(s,mmsghdr,vlen,flag) \
sendmmsg((s),(mmsghdr),(vlen),(flag))
#endif
#define sock_sendto(s,buf,blen,flag,addr,alen) \
sendto((s),(buf),(blen),(flag),(addr),(alen))
#define sock_sendv(s,iov,iovcnt) writev((s), (iov), (iovcnt))
#define sock_shutdown(s, how) shutdown((s), (how))
/* Maximum number of messages for sendmmsg/recvmmsg operations.
* This limit prevents excessive resource usage and ensures scheduler
* responsiveness. The Linux kernel's UIO_MAXIOV is typically 1024.
* For batches larger than this, callers should use multiple calls
* from the Erlang layer.
*/
#define ESOCK_MMSG_MAX 1024
/* =================================================================== *
* *
* Various essio macros *
* *
* =================================================================== */
/* Global socket debug */
#define SGDBG( proto ) ESOCK_DBG_PRINTF( ctrl.dbg , proto )
/* =================================================================== *
* *
* Local types *
* *
* =================================================================== */
typedef struct {
/* If we "have" sctp, this is TRUE otherwise FALSE */
BOOLEAN_T have;
/* If we do *not* "have" sctp, all these function pointers are set to NULL */
#if defined(HAVE_SCTP)
int (*bindx) (int sd,
struct sockaddr *addrs,
int addrcnt,
int flags);
int (*connectx) (int sd,
const struct sockaddr *addrs,
int addrcnt,
sctp_assoc_t *id);
int (*peeloff) (int sd,
sctp_assoc_t assoc_id);
int (*getpaddrs) (int sd,
sctp_assoc_t id,
struct sockaddr **addrs);
void (*freepaddrs) (struct sockaddr *addrs);
int (*getladdrs) (int sd,
sctp_assoc_t id,
struct sockaddr **addrs);
void (*freeladdrs) (struct sockaddr *addrs);
#else
/* In this case we also do not have the SCTP types so we need "dummy" defs */
int (*bindx) (int sd,
void *addrs,
int addrcnt,
int flags);
int (*connectx) (int sd,
const void *addrs,
int addrcnt,
int *id);
int (*peeloff) (int sd,
int assoc_id);
int (*getpaddrs) (int sd,
int id,
void **addrs);
void (*freepaddrs) (int *addrs);
int (*getladdrs) (int sd,
int id,
void **addrs);
void (*freeladdrs) (void *addrs);
#endif
} ESSIOSctp;
typedef struct {
/* Misc stuff */
BOOLEAN_T dbg;
BOOLEAN_T sockDbg;
ESSIOSctp sctp;
} ESSIOControl;
/* ======================================================================== *
* Function Forwards *
* ======================================================================== *
*/
static BOOLEAN_T open_todup(ErlNifEnv* env,
ERL_NIF_TERM eopts);
static BOOLEAN_T open_which_domain(SOCKET sock, int* domain);
static BOOLEAN_T open_which_type(SOCKET sock, int* type);
static BOOLEAN_T open_get_domain(ErlNifEnv* env,
ERL_NIF_TERM eopts,
int* domain);
static BOOLEAN_T open_get_type(ErlNifEnv* env,
ERL_NIF_TERM eopts,
int* type);
static BOOLEAN_T open_get_protocol(ErlNifEnv* env,
ERL_NIF_TERM eopts,
int* protocol);
#ifdef HAVE_SETNS
static BOOLEAN_T open_get_netns(ErlNifEnv* env,
ERL_NIF_TERM opts,
char** netns);
static BOOLEAN_T change_network_namespace(BOOLEAN_T dbg,
char* netns, int* cns, int* err);
static BOOLEAN_T restore_network_namespace(BOOLEAN_T dbg,
int ns, SOCKET sock, int* err);
#endif
static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err);
static ERL_NIF_TERM essio_cancel_accept_current(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM essio_cancel_accept_waiting(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM opRef,
const ErlNifPid* selfP);
static ERL_NIF_TERM essio_cancel_send_current(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM essio_cancel_send_waiting(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM opRef,
const ErlNifPid* selfP);
static ERL_NIF_TERM essio_cancel_recv_current(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM essio_cancel_recv_waiting(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM opRef,
const ErlNifPid* selfP);
static ERL_NIF_TERM essio_accept_listening_error(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM accRef,
ErlNifPid caller,
int save_errno);
static ERL_NIF_TERM essio_accept_listening_accept(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid caller);
static ERL_NIF_TERM essio_accept_accepting_current(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM ref);
static
ERL_NIF_TERM essio_accept_accepting_current_accept(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
SOCKET accSock);
static
ERL_NIF_TERM essio_accept_accepting_current_error(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM opRef,
int save_errno);
static ERL_NIF_TERM essio_accept_accepting_other(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM ref,
ErlNifPid caller);
static ERL_NIF_TERM essio_accept_busy_retry(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM accRef,
ErlNifPid* pidP);
static BOOLEAN_T essio_accept_accepted(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid pid,
ERL_NIF_TERM* result);
static ERL_NIF_TERM essio_info_sctp(ErlNifEnv* env);
static BOOLEAN_T send_check_writer(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM ref,
ERL_NIF_TERM* checkResult);
static ERL_NIF_TERM send_check_result(ErlNifEnv* env,
ESockDescriptor* descP,
ssize_t send_result,
ssize_t dataSize,
BOOLEAN_T dataInTail,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM sendRef);
static ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
ESockDescriptor* descP,
ssize_t written,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
ESockDescriptor* descP,
int saveErrno,
ERL_NIF_TERM sockRef);
static void send_error_waiting_writers(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM reason);
static ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
ESockDescriptor* descP,
ssize_t written,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM sendRef);
static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eCMsg,
char* cmsgHdrBufP,
size_t cmsgHdrBufLen,
size_t* cmsgHdrBufUsed);
static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eCMsg,
char* bufP,
size_t rem,
size_t* used);
static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
ERL_NIF_TERM eType,
ERL_NIF_TERM eValue,
char* dataP,
size_t dataLen,
size_t* dataUsedP);
static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env,
ESockDescriptor* descP,
int level,
ERL_NIF_TERM eType,
ERL_NIF_TERM eData,
char* dataP,
size_t dataLen,
size_t* dataUsedP);
static void encode_msg(ErlNifEnv* env,
ESockDescriptor* descP,
ssize_t read,
struct msghdr* msgHdrP,
ErlNifBinary* dataBufP,
ErlNifBinary* ctrlBufP,
ERL_NIF_TERM* eMsg);
static void encode_cmsgs(ErlNifEnv* env,
ESockDescriptor* descP,
ErlNifBinary* cmsgBinP,
struct msghdr* msgHdrP,
ERL_NIF_TERM* eCMsg);
static ERL_NIF_TERM esock_encode_msg_flags_convert2sctp(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM flags);
#if defined(HAVE_SENDFILE)
static int essio_sendfile(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
off_t offset,
size_t* countP,
int* errP);
static ERL_NIF_TERM essio_sendfile_errno(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
int err);
static ERL_NIF_TERM essio_sendfile_error(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM reason);
static ERL_NIF_TERM essio_sendfile_select(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM sendRef,
size_t count);
static ERL_NIF_TERM essio_sendfile_ok(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
size_t count);
#endif
static BOOLEAN_T recv_alloc_buf(size_t size,
ErlNifBinary *bufP);
static BOOLEAN_T recv_create_bin(ErlNifBinary *bufP,
size_t size,
ErlNifBinary *binP);
static BOOLEAN_T recv_check_entry(ErlNifEnv *env,
ESockDescriptor *descP,
ERL_NIF_TERM recvRef,
ERL_NIF_TERM *retP);
static BOOLEAN_T recv_check_result(ErlNifEnv *env,
ESockDescriptor *descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ssize_t readResult,
int saveErrno,
ERL_NIF_TERM *retP);
static ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ssize_t len,
ErlNifBinary *bufP);
static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ErlNifBinary *bufP);
static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ErlNifBinary *bufP);
static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
int saveErrno);
static ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
int saveErrno);
static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM recv_check_select(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ERL_NIF_TERM msg);
static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
ssize_t len,
ErlNifBinary *bufP);
static void recv_init_current_reader(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM recvRef);
static void recv_update_current_reader(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef);
static void recv_error_current_reader(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM reason);
#if defined(HAVE_SCTP)
static ERL_NIF_TERM essio_addrs_encode(ErlNifEnv* env,
ESockDescriptor* descP,
int n,
struct sockaddr* sa);
#endif
static ERL_NIF_TERM essio_ioctl_gifconf(ErlNifEnv* env,
ESockDescriptor* descP);
/* esock_ioctl_fionread */
#if defined(FIONREAD)
#define IOCTL_FIONREAD_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionread)
#else
#define IOCTL_FIONREAD_FUNC2_DEF
#endif
/* esock_ioctl_fionwrite */
#if defined(FIONWRITE)
#define IOCTL_FIONWRITE_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionwrite)
#else
#define IOCTL_FIONWRITE_FUNC2_DEF
#endif
/* esock_ioctl_fionspace */
#if defined(FIONSPACE)
#define IOCTL_FIONSPACE_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionspace)
#else
#define IOCTL_FIONSPACE_FUNC2_DEF
#endif
/* esock_ioctl_siocatmark */
#if defined(SIOCATMARK)
#define IOCTL_SIOCATMARK_FUNC2_DEF IOCTL_GET_FUNC2_DEF(siocatmark)
#else
#define IOCTL_SIOCATMARK_FUNC2_DEF
#endif
#define IOCTL_GET_FUNCS2_DEF \
IOCTL_FIONREAD_FUNC2_DEF; \
IOCTL_FIONWRITE_FUNC2_DEF; \
IOCTL_FIONSPACE_FUNC2_DEF; \
IOCTL_SIOCATMARK_FUNC2_DEF;
#define IOCTL_GET_FUNC2_DEF(F) \
static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \
ESockDescriptor* descP)
IOCTL_GET_FUNCS2_DEF
#undef IOCTL_GET_FUNC2_DEF
#if defined(SIOCGIFNAME)
static ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eidx);
#endif
/* esock_ioctl_gifindex */
#if defined(SIOCGIFINDEX)
#define IOCTL_GIFINDEX_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifindex)
#else
#define IOCTL_GIFINDEX_FUNC3_DEF
#endif
/* esock_ioctl_gifflags */
#if defined(SIOCGIFFLAGS)
#define IOCTL_GIFFLAGS_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifflags)
#else
#define IOCTL_GIFFLAGS_FUNC3_DEF
#endif
/* esock_ioctl_gifaddr */
#if defined(SIOCGIFADDR)
#define IOCTL_GIFADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifaddr)
#else
#define IOCTL_GIFADDR_FUNC3_DEF
#endif
/* esock_ioctl_gifdstaddr */
#if defined(SIOCGIFDSTADDR)
#define IOCTL_GIFDSTADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifdstaddr)
#else
#define IOCTL_GIFDSTADDR_FUNC3_DEF
#endif
/* esock_ioctl_gifbrdaddr */
#if defined(SIOCGIFBRDADDR)
#define IOCTL_GIFBRDADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifbrdaddr)
#else
#define IOCTL_GIFBRDADDR_FUNC3_DEF
#endif
/* esock_ioctl_gifnetmask */
#if defined(SIOCGIFNETMASK)
#define IOCTL_GIFNETMASK_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifnetmask)
#else
#define IOCTL_GIFNETMASK_FUNC3_DEF
#endif
/* esock_ioctl_gifmtu */
#if defined(SIOCGIFMTU)
#define IOCTL_GIFMTU_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifmtu)
#else
#define IOCTL_GIFMTU_FUNC3_DEF
#endif
/* esock_ioctl_gifhwaddr */
#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR)
#define IOCTL_GIFHWADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifhwaddr)
#else
#define IOCTL_GIFHWADDR_FUNC3_DEF
#endif
/* esock_ioctl_gifenaddr */
#if defined(SIOCGENADDR) && defined(ESOCK_USE_ENADDR)
#define IOCTL_GENADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(genaddr)
#else
#define IOCTL_GENADDR_FUNC3_DEF
#endif
/* esock_ioctl_gifmap */
#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP)
#define IOCTL_GIFMAP_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifmap)
#else
#define IOCTL_GIFMAP_FUNC3_DEF
#endif
/* esock_ioctl_giftxqlen */
#if defined(SIOCGIFTXQLEN)
#define IOCTL_GIFTXQLEN_FUNC3_DEF IOCTL_GET_FUNC3_DEF(giftxqlen)
#else
#define IOCTL_GIFTXQLEN_FUNC3_DEF
#endif
#define IOCTL_GET_FUNCS3_DEF \
IOCTL_GIFINDEX_FUNC3_DEF; \
IOCTL_GIFFLAGS_FUNC3_DEF; \
IOCTL_GIFADDR_FUNC3_DEF; \
IOCTL_GIFDSTADDR_FUNC3_DEF; \
IOCTL_GIFBRDADDR_FUNC3_DEF; \
IOCTL_GIFNETMASK_FUNC3_DEF; \
IOCTL_GIFMTU_FUNC3_DEF; \
IOCTL_GIFHWADDR_FUNC3_DEF; \
IOCTL_GENADDR_FUNC3_DEF; \
IOCTL_GIFMAP_FUNC3_DEF; \
IOCTL_GIFTXQLEN_FUNC3_DEF;
#define IOCTL_GET_FUNC3_DEF(F) \
static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \
ESockDescriptor* descP, \
ERL_NIF_TERM ename)
IOCTL_GET_FUNCS3_DEF
#undef IOCTL_GET_FUNC3_DEF
/* esock_ioctl_sifflags */
#if defined(SIOCSIFFLAGS)
#define IOCTL_SIFFLAGS_FUNC_DEF IOCTL_SET_FUNC_DEF(sifflags)
#else
#define IOCTL_SIFFLAGS_FUNC_DEF
#endif
/* esock_ioctl_sifaddr */
#if defined(SIOCSIFADDR)
#define IOCTL_SIFADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifaddr)
#else
#define IOCTL_SIFADDR_FUNC_DEF
#endif
/* esock_ioctl_sifdstaddr */
#if defined(SIOCSIFDSTADDR)
#define IOCTL_SIFDSTADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifdstaddr)
#else
#define IOCTL_SIFDSTADDR_FUNC_DEF
#endif
/* esock_ioctl_sifbrdaddr */
#if defined(SIOCSIFBRDADDR)
#define IOCTL_SIFBRDADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifbrdaddr)
#else
#define IOCTL_SIFBRDADDR_FUNC_DEF
#endif
/* esock_ioctl_sifnetmask */
#if defined(SIOCSIFNETMASK)
#define IOCTL_SIFNETMASK_FUNC_DEF IOCTL_SET_FUNC_DEF(sifnetmask)
#else
#define IOCTL_SIFNETMASK_FUNC_DEF
#endif
/* esock_ioctl_sifmtu */
#if defined(SIOCSIFMTU)
#define IOCTL_SIFMTU_FUNC_DEF IOCTL_SET_FUNC_DEF(sifmtu)
#else
#define IOCTL_SIFMTU_FUNC_DEF
#endif
/* esock_ioctl_siftxqlen */
#if defined(SIOCSIFTXQLEN)
#define IOCTL_SIFTXQLEN_FUNC_DEF IOCTL_SET_FUNC_DEF(siftxqlen)
#else
#define IOCTL_SIFTXQLEN_FUNC_DEF
#endif
/* esock_ioctl_sifhwaddr */
#if defined(SIOCSIFHWADDR)
#define IOCTL_SIFHWADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifhwaddr)
#else
#define IOCTL_SIFHWADDR_FUNC_DEF
#endif
#define IOCTL_SET_FUNCS_DEF \
IOCTL_SIFFLAGS_FUNC_DEF; \
IOCTL_SIFADDR_FUNC_DEF; \
IOCTL_SIFDSTADDR_FUNC_DEF; \
IOCTL_SIFBRDADDR_FUNC_DEF; \
IOCTL_SIFNETMASK_FUNC_DEF; \
IOCTL_SIFMTU_FUNC_DEF; \
IOCTL_SIFTXQLEN_FUNC_DEF; \
IOCTL_SIFHWADDR_FUNC_DEF;
#define IOCTL_SET_FUNC_DEF(F) \
static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \
ESockDescriptor* descP, \
ERL_NIF_TERM ename, \
ERL_NIF_TERM evalue)
IOCTL_SET_FUNCS_DEF
#undef IOCTL_SET_FUNC_DEF
static ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env,
ESockDescriptor* descP,
struct ifconf* ifcP);
static ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env,
ESockDescriptor* descP,
struct ifreq* ifrP);
static ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env,
char* name);
static ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env,
struct sockaddr* sa);
static ERL_NIF_TERM make_ifreq(ErlNifEnv* env,
ERL_NIF_TERM name,
ERL_NIF_TERM key2,
ERL_NIF_TERM val2);
#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP)
static ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env,
ESockDescriptor* descP,
struct ifmap* mapP);
#endif
#if (defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR))
static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env,
ESockDescriptor* descP,
struct sockaddr* addrP);
#endif
#if (defined(SIOCGENADDR) && defined(ESOCK_USE_ENADDR))
static ERL_NIF_TERM encode_ioctl_enaddr(ErlNifEnv* env,
ESockDescriptor* descP,
char* addrP);
#endif
static ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env,
ESockDescriptor* descP,
struct sockaddr* addrP);
static ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env,
ESockDescriptor* descP,
short flags);
#if defined(SIOCSIFFLAGS)
static BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eflags,
short* flags);
#endif
static BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eaddr,
ESockAddress* addr);
#if defined(SIOCSIFHWADDR)
static
BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eaddr,
ESockAddress* addr);
#endif
#if defined(SIOCSIFMTU)
static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM emtu,
int* mtu);
#endif
#if defined(SIOCSIFTXQLEN)
static BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM etxqlen,
int* txqlen);
#endif
#if defined(SIOCSIFTXQLEN)
static BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eivalue,
int* ivalue);
#endif
static ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env,
ESockDescriptor* descP,
int ivalue);
static ERL_NIF_TERM encode_ioctl_bvalue(ErlNifEnv* env,
ESockDescriptor* descP,
int bvalue);
/*
static void essio_down_ctrl(ErlNifEnv* env,
ESockDescriptor* descP,
const ErlNifPid* pidP);
*/
static void essio_down_acceptor(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pidP,
const ErlNifMonitor* monP);
static void essio_down_writer(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pidP,
const ErlNifMonitor* monP);
static void essio_down_reader(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pidP,
const ErlNifMonitor* monP);
static BOOLEAN_T do_stop(ErlNifEnv* env,
ESockDescriptor* descP);
static void essio_sctp_init(void);
#if !defined(HAVE_SCTP)
static void essio_sctp_init_false(void);
#endif
static void essio_encode_sctp_notification(ErlNifEnv* env,
ESockDescriptor* descP,
ErlNifBinary* binP,
ERL_NIF_TERM* eEvent);
#if defined(HAVE_SCTP)
#if defined(HAVE_STATIC_SCTP)
static void essio_sctp_init_static(void);
#else
static void essio_sctp_init_dynamic(void);
#endif
#if defined(SCTP_ASSOC_CHANGE)
static void essio_encode_sctp_notif_assoc_change(ErlNifEnv* env,
ESockDescriptor* descP,
struct sctp_assoc_change* acp,
ERL_NIF_TERM* eEvent);
#endif
#if defined(SCTP_ASSOC_CHANGE) || defined(SCTP_REMOTE_ERROR) || defined(SCTP_SEND_FAILED) || defined(SCTP_SEND_FAILED_EVENT)
static ERL_NIF_TERM essio_encode_sctp_operation_error(ErlNifEnv* env,
ESockDescriptor* descP,
uint16_t error);
#endif
#if defined(SCTP_PEER_ADDR_CHANGE)
static void essio_encode_sctp_notif_paddr_change(ErlNifEnv* env,
ESockDescriptor* descP,
struct sctp_paddr_change* p,
ERL_NIF_TERM* eEvent);
static void essio_encode_sockaddr_storage(ErlNifEnv* env,
ESockDescriptor* descP,
struct sockaddr_storage* addr,
ERL_NIF_TERM* eaddr);
#endif
#if defined(SCTP_SEND_FAILED)
static void essio_encode_sctp_notif_send_failed(ErlNifEnv* env,
ESockDescriptor* descP,
struct sctp_send_failed* p,
ERL_NIF_TERM* eEvent);
static ERL_NIF_TERM essio_encode_sctp_notif_send_failed_flags(ErlNifEnv* env,
ESockDescriptor* descP,
unsigned int flags);
#endif
#if defined(SCTP_SEND_FAILED) || defined(SCTP_SEND_FAILED_EVENT)
static ERL_NIF_TERM essio_encode_sctp_send_failed_flags(ErlNifEnv* env,
ESockDescriptor* descP,
unsigned int flags);
#endif
#if defined(SCTP_REMOTE_ERROR)
static void essio_encode_sctp_notif_remote_error(ErlNifEnv* env,
ESockDescriptor* descP,
struct sctp_remote_error* p,
ERL_NIF_TERM* eEvent);
static void essio_encode_sctp_notif_remote_causes(ErlNifEnv* env,
char* chunkP,
int chunkTLen,
ERL_NIF_TERM* eRCauses);
#endif