1#include <errno.h>
  2#include <fcntl.h>
  3#include <netdb.h>
  4#include <sys/un.h>
  5#include <unistd.h>
  6
  7#include "include/pw_args.h"
  8#include "include/pwlib/netutils.h"
  9#include "include/pwlib/socket.h"
 10#include "include/pw_utf.h"
 11#include "src/pw_interfaces_internal.h"
 12#include "src/types/struct_internal.h"
 13
 14// status codes
 15uint16_t PW_ERROR_BAD_ADDRESS_FAMILY = 0;
 16uint16_t PW_ERROR_BAD_IP_ADDRESS = 0;
 17uint16_t PW_ERROR_BAD_PORT = 0;
 18uint16_t PW_ERROR_HOST_ADDRESS_EXPECTED = 0;
 19uint16_t PW_ERROR_ADDRESS_FAMILY_MISMATCH = 0;
 20uint16_t PW_ERROR_SOCKET_NAME_TOO_LONG = 0;
 21uint16_t PW_ERROR_MISSING_NETMASK = 0;
 22uint16_t PW_ERROR_BAD_NETMASK = 0;
 23uint16_t PW_ERROR_PORT_UNSPECIFIED = 0;
 24
 25// socket data
 26
 27typedef struct {
 28    int sock;
 29    int listen_backlog;  // 0: not listening
 30    uint16_t new_sock_type;  // for accept, to create socket of desired type
 31    bool own_fd;
 32
 33    // args the socket() was called with
 34    int domain;
 35    int type;
 36    int proto;
 37
 38    _PwValue local_addr;   // set when bind returns success
 39    _PwValue remote_addr;  // set when connect returns success or "in progress"
 40
 41} _PwSocket;
 42
 43#define get_this_socket(value)  _pw_get_this_struct_ptr(_PwSocket*, mthis, (value))
 44
 45static void close_socket(_PwSocket* s)
 46{
 47    if (s->sock != -1 && s->own_fd) {
 48        close(s->sock);
 49        s->sock = -1;
 50    }
 51    pw_destroy(&s->local_addr);
 52    pw_destroy(&s->remote_addr);
 53}
 54
 55/****************************************************************
 56 * SockAddr basic interface
 57 */
 58
 59uint16_t PwTypeId_SockAddr = 0;
 60
 61#define get_this_sockaddr(value)  _pw_get_this_struct_ptr(_PwSockAddrData*, mthis, (value))
 62
 63static bool sockaddr_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
 64{
 65    _PwSockAddrData* sa = get_this_sockaddr(self);
 66
 67    _pw_hash_uint64(ctx, self->type_id);
 68    _pw_hash_uint64(ctx, sa->addr.ss_family);
 69    switch (sa->addr.ss_family) {
 70        case AF_LOCAL: {
 71            char* path = ((struct sockaddr_un*) &sa->addr)->sun_path;
 72            for (;;) {
 73                unsigned char chr = *path++;
 74                if (chr == 0) {
 75                    break;
 76                }
 77                _pw_hash_uint64(ctx, chr);
 78            }
 79            break;
 80        }
 81        case AF_INET:
 82            _pw_hash_uint64(ctx, ((struct sockaddr_in*) &sa->addr)->sin_addr.s_addr);
 83            _pw_hash_uint64(ctx, ((struct sockaddr_in*) &sa->addr)->sin_port);
 84            break;
 85        case AF_INET6: {
 86            uint64_t* addr = (uint64_t*) &((struct sockaddr_in6*) &sa->addr)->sin6_addr;
 87            _pw_hash_uint64(ctx, *addr++);
 88            _pw_hash_uint64(ctx, *addr);
 89            _pw_hash_uint64(ctx, ((struct sockaddr_in6*) &sa->addr)->sin6_port);
 90            break;
 91        }
 92        default:
 93            break;
 94    }
 95    _pw_hash_uint64(ctx, sa->netmask);
 96    return true;
 97}
 98
 99static bool dump_sockaddr(FILE* fp, PwValuePtr sockaddr)
100{
101    _PwSockAddrData* sa = _pw_get_struct_ptr(sockaddr, PwTypeId_SockAddr);
102
103    const char* addr;
104    char addr_buf[1024];
105    in_port_t port = 0;
106    switch (sa->addr.ss_family) {
107        case AF_UNSPEC:
108            addr = "[unspecified]";
109            break;
110        case AF_LOCAL:
111            addr = ((struct sockaddr_un*) &sa->addr)->sun_path;
112            break;
113        case AF_INET:
114            port = ntohs(((struct sockaddr_in*) &sa->addr)->sin_port);
115            addr = inet_ntop(AF_INET, &((struct sockaddr_in*) &sa->addr)->sin_addr, addr_buf, sizeof(addr_buf));
116            break;
117        case AF_INET6:
118            port = ntohs(((struct sockaddr_in6*) &sa->addr)->sin6_port);
119            addr = inet_ntop(AF_INET6, &((struct sockaddr_in6*) &sa->addr)->sin6_addr, addr_buf, sizeof(addr_buf));
120            break;
121        default:
122            addr = "<not supported>";
123            break;
124    }
125    if (!addr) {
126        addr = "<error>";
127    }
128    if (port) {
129        if (sa->addr.ss_family == AF_INET6) {
130            fprintf(fp, " [%s]:%u", addr, port);
131        } else {
132            fprintf(fp, " %s:%u", addr, port);
133        }
134    } else {
135        fputc(' ', fp);
136        fputs(addr, fp);
137    }
138    if (sa->netmask) {
139        fprintf(fp, "/%u\n", sa->netmask);
140    } else {
141        fputc('\n', fp);
142    }
143    return true;
144}
145
146static bool sockaddr_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
147{
148    if (!pw_super(mthis, self, fp, indent, tail)) {
149        return false;
150    }
151    _pw_print_indent(fp, indent);
152    dump_sockaddr(fp, self);
153    return true;
154}
155
156static PwInterface_Basic sockaddr_basic_interface = {
157    .hash = { .func = sockaddr_hash },
158    .dump = { .func = sockaddr_dump }
159};
160
161/****************************************************************
162 * Socket type and basic intrerface
163 */
164
165uint16_t PwTypeId_Socket = 0;
166
167static bool socket_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
168{
169    if (!pw_super(mthis, result, ctor_args)) {
170        return false;
171    }
172
173    _PwSocket* s = get_this_socket(result);
174
175    PwSocketCtorArgs* args = pw_get_ctor_args(PwTypeId_Socket, ctor_args);
176
177    if (!args) {
178        // special case for internal use in accept method
179        s->sock = -1;
180        return true;
181    }
182
183    s->sock = socket(args->domain, args->type, args->protocol);
184    if (s->sock != -1) {
185
186        s->own_fd = true;
187        s->domain = args->domain;
188        s->type   = args->type;
189        s->proto  = args->protocol;
190
191        return true;
192    }
193    int _errno = errno;
194    if (!pw_super_call(destroy, mthis, result, nullptr)) { /* no op */ }
195    pw_set_status(PwErrno(_errno));
196    return false;
197}
198
199static bool socket_destroy(PwMethod_Basic_destroy* mthis, PwValuePtr self, _PwCompoundChain* tail)
200{
201    PwValuePtr value_seen = _pw_on_chain(self, tail);
202    if (value_seen) {
203        return true;
204    }
205    close_socket(get_this_socket(self));
206    return pw_super(mthis, self, nullptr);
207}
208
209static bool socket_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
210{
211    if (!pw_super(mthis, self, fp, indent, tail)) {
212        return false;
213    }
214
215    _PwSocket* s = get_this_socket(self);
216
217    // domain to string
218
219    char* domain;
220    char domain_other[32];
221    switch (s->domain) {
222        case AF_UNSPEC:  domain = "AF_UNSPEC"; break;
223        case AF_LOCAL:   domain = "AF_LOCAL"; break;
224        case AF_INET:    domain = "AF_INET"; break;
225        case AF_INET6:   domain = "AF_INET6"; break;
226        case AF_NETLINK: domain = "AF_NETLINK"; break;
227        case AF_PACKET:  domain = "AF_PACKET"; break;
228        default:
229            snprintf(domain_other, sizeof(domain_other), "AF_(%d)", s->domain);
230            domain = domain_other;
231            break;
232    }
233
234    // socket type to string
235
236    char* type;
237    char type_other[32];
238    char type_buf[80];
239    int t = s->type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
240    switch (t) {
241        case SOCK_STREAM: type = "SOCK_STREAM"; break;
242        case SOCK_DGRAM:  type = "SOCK_DGRAM"; break;
243        case SOCK_RAW:    type = "SOCK_RAW"; break;
244        default:
245            snprintf(type_other, sizeof(type_other), "SOCK_(%d)", t);
246            type = type_other;
247            break;
248    }
249    if (s->type & (SOCK_CLOEXEC | SOCK_NONBLOCK)) {
250        strcpy(type_buf, type);
251        strcat(type_buf, "{");
252        if (s->type & SOCK_CLOEXEC) {
253            strcat(type_buf, "SOCK_CLOEXEC");
254        }
255        if (s->type & SOCK_NONBLOCK) {
256            if (s->type & SOCK_CLOEXEC) {
257                strcat(type_buf, ",");
258            }
259            strcat(type_buf, "SOCK_NONBLOCK");
260        }
261        strcat(type_buf, "}");
262        type = type_buf;
263    }
264
265    // proto to string
266
267    char* protocol;
268    struct protoent proto;
269    struct protoent *proto_result;
270    char proto_buf[1024];
271    if (getprotobynumber_r(s->proto, &proto, proto_buf, sizeof(proto_buf), &proto_result) == 0) {
272        protocol = proto_result->p_name;
273    } else {
274        snprintf(proto_buf, sizeof(proto_buf), "%d", s->proto);
275        protocol = proto_buf;
276    }
277
278    // listen backlog to string
279
280    char* listening = "";
281    char listening_buf[128];
282    if (s->listen_backlog) {
283        snprintf(listening_buf, sizeof(listening_buf), ", listening (backlog=%d, new_type=%u)", s->listen_backlog, s->new_sock_type);
284        listening = listening_buf;
285    }
286
287    // dump
288
289    _pw_print_indent(fp, indent);
290    fprintf(fp, "socket(%s, %s, %s) fd=%d%s\n", domain, type, protocol, s->sock, listening);
291
292    if (pw_is_sockaddr(&s->local_addr)) {
293        _pw_print_indent(fp, indent);
294        fputs("Local address: ", fp);
295        dump_sockaddr(fp, &s->local_addr);
296    }
297    if (pw_is_sockaddr(&s->remote_addr)) {
298        _pw_print_indent(fp, indent);
299        fputs("Remote address: ", fp);
300        dump_sockaddr(fp, &s->remote_addr);
301    }
302    return true;
303}
304
305static PwInterface_Basic socket_basic_interface = {
306    .create  = { .func = socket_create },
307    .destroy = { .func = socket_destroy },
308    .dump    = { .func = socket_dump }
309};
310
311/****************************************************************
312 * Socket interface
313 */
314
315uint16_t PwInterfaceId_Socket = 0;
316
317[[nodiscard]] static bool make_address(int domain, PwValuePtr addr, socklen_t* ss_addr_size, PwValuePtr result)
318/*
319 * Helper function for bind and connect.
320 *
321 * If `addr` is SockAddr, clone it if address family matches domain.
322 * If `addr` is String, try to convert it to SockAddr.
323 *
324 * Write size of sockaddr atructure to `ss_addr_size`.
325 */
326{
327    *ss_addr_size = sizeof(struct sockaddr_storage);
328
329    if (pw_is_sockaddr(addr)) {
330        _PwSockAddrData* sa = _pw_get_struct_ptr(addr, PwTypeId_SockAddr);
331        if (sa->netmask != 0) {
332            pw_set_status(PwStatus(PW_ERROR_HOST_ADDRESS_EXPECTED));
333            return false;
334        }
335        if (sa->addr.ss_family != domain) {
336            pw_set_status(PwStatus(PW_ERROR_ADDRESS_FAMILY_MISMATCH));
337            return false;
338        }
339        pw_clone2(addr, result);
340        return true;
341    }
342
343    if (!pw_validate(addr, PwTypeId_String)) {
344        return false;
345    }
346
347    switch (domain) {
348        case AF_LOCAL: {
349            if (!pw_create(PwTypeId_SockAddr, result)) {
350                return false;
351            }
352
353            _PwSockAddrData* sa = _pw_get_struct_ptr(result, PwTypeId_SockAddr);
354            sa->addr.ss_family = AF_LOCAL;
355
356            unsigned len = pw_strlen_in_utf8(addr);
357            if (len >= sizeof(((struct sockaddr_un*)0)->sun_path)) {
358                pw_set_status(PwStatus(PW_ERROR_SOCKET_NAME_TOO_LONG));
359                return false;
360            }
361            pw_string_to_utf8(addr, ((struct sockaddr_un*) &sa->addr)->sun_path);
362            *ss_addr_size = offsetof(struct sockaddr_un, sun_path) + len + 1;
363            return true;
364        }
365        case AF_INET:
366        case AF_INET6:
367            return pw_parse_inet_address(addr, result);
368
369        default:
370            pw_panic("Address family %d is not supported yet\n", domain);
371    }
372}
373
374static bool socket_bind(PwMethod_Socket_bind* mthis, PwValuePtr self, PwValuePtr local_addr)
375{
376    _PwSocket* s = get_this_socket(self);
377
378    pw_destroy(&s->local_addr);
379
380    socklen_t addr_size;
381    PwValue addr = PW_NULL;
382    if (!make_address(s->domain, local_addr, &addr_size, &addr)) {
383        return false;
384    }
385
386    pw_move(&addr, &s->local_addr);
387    _PwSockAddrData* sa = _pw_get_struct_ptr(&s->local_addr, PwTypeId_SockAddr);
388
389    if (bind(s->sock, (struct sockaddr*) &sa->addr, addr_size) == 0) {
390        return true;
391    } else {
392        pw_set_status(PwErrno(errno));
393        return false;
394    }
395}
396
397static bool socket_reuse_addr(PwMethod_Socket_reuse_addr* mthis, PwValuePtr self, bool reuse)
398{
399    _PwSocket* s = get_this_socket(self);
400
401    int i = reuse;
402    if (setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) {
403        pw_set_status(PwErrno(errno));
404        return false;
405    } else {
406        return true;
407    }
408}
409
410static bool socket_listen(PwMethod_Socket_listen* mthis, PwValuePtr self, int backlog, uint16_t new_sock_type)
411{
412    _PwSocket* s = get_this_socket(self);
413
414    if (backlog == 0) {
415        backlog = 5;
416    }
417    if (new_sock_type == PwTypeId_Null) {
418        new_sock_type = self->type_id;
419    }
420    if (listen(s->sock, backlog) == -1) {
421        pw_set_status(PwErrno(errno));
422        return false;
423    }
424    s->listen_backlog = backlog;
425    s->new_sock_type = new_sock_type;
426    return true;
427}
428
429static bool socket_is_listening(PwMethod_Socket_is_listening* mthis, PwValuePtr self, bool* result)
430{
431    _PwSocket* s = get_this_socket(self);
432    *result = s->listen_backlog != 0;
433    return true;
434}
435
436static bool socket_accept(PwMethod_Socket_accept* mthis, PwValuePtr self, PwValuePtr result)
437{
438    _PwSocket* s_lsnr = get_this_socket(self);
439
440    // create uninitialized socket
441    if (!pw_create(s_lsnr->new_sock_type, result)) {
442        return false;
443    }
444
445    _PwSocket* s_new  = get_this_socket(result);
446
447    // initialize addresses for new socket
448    pw_clone2(&s_lsnr->local_addr, &s_new->local_addr);
449    if (!pw_create(PwTypeId_SockAddr, &s_new->remote_addr)) {
450        return false;
451    }
452
453    // get pointer to remote address structure
454    _PwSockAddrData* sa_remote = _pw_get_struct_ptr(&s_new->remote_addr, PwTypeId_SockAddr);
455
456    // call accept and initialize new socket and remote address
457    socklen_t addrlen = sizeof(sa_remote->addr);
458    s_new->sock = accept(s_lsnr->sock, (struct sockaddr*) &sa_remote->addr,  &addrlen);
459    if (s_new->sock < 0) {
460        pw_set_status(PwErrno(errno));
461        return false;
462    }
463    // initialize other fields (they are mainly for informational purposes)
464    s_new->domain = s_lsnr->domain;
465    s_new->type   = s_lsnr->type;
466    s_new->proto  = s_lsnr->proto;
467
468    return true;
469}
470
471static bool socket_connect(PwMethod_Socket_connect* mthis, PwValuePtr self, PwValuePtr remote_addr)
472{
473    _PwSocket* s = get_this_socket(self);
474
475    pw_destroy(&s->local_addr);
476
477    socklen_t addr_size;
478    PwValue addr = PW_NULL;
479    if (!make_address(s->domain, remote_addr, &addr_size, &addr)) {
480        return false;
481    }
482
483    pw_move(&addr, &s->remote_addr);
484    _PwSockAddrData* sa = _pw_get_struct_ptr(&s->remote_addr, PwTypeId_SockAddr);
485
486    int rc;
487    do {
488        rc = connect(s->sock, (struct sockaddr*) &sa->addr, sizeof(sa->addr));
489    } while (rc != 0 && errno == EINTR);
490
491    if (rc == 0) {
492        return true;
493    }
494    if (errno == EAGAIN && sa->addr.ss_family == AF_LOCAL) {
495        // make it consistent
496        errno = EINPROGRESS;
497    }
498    pw_set_status(PwErrno(errno));
499    return false;
500}
501
502static bool socket_shutdown(PwMethod_Socket_shutdown* mthis, PwValuePtr self, int how)
503{
504    _PwSocket* s = get_this_socket(self);
505
506    if (shutdown(s->sock, how) == 0) {
507        return true;
508    } else {
509        pw_set_status(PwErrno(errno));
510        return false;
511    }
512}
513
514static bool socket_get_socket_error(PwMethod_Socket_get_socket_error* mthis, PwValuePtr self, PwValuePtr result)
515{
516    _PwSocket* s = get_this_socket(self);
517    int err;
518    socklen_t len = sizeof(int);
519    if (getsockopt(s->sock,  SOL_SOCKET, SO_ERROR, (void*) &err, &len) == -1) {
520        fprintf(stderr, "%s:%d getsockopt: %s\n", __FILE__, __LINE__, strerror(errno));
521        return false;
522    }
523    pw_destroy(result);
524    if (err) {
525        *result = PwErrno(err);
526    } else {
527        *result = PwStatus(PW_SUCCESS);
528    }
529    return true;
530}
531
532static PwInterface_Socket socket_interface = {
533#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
534    PW_SOCKET_INTERFACE_METHODS
535#undef X
536};
537
538/****************************************************************
539 * Fd interface
540 */
541
542static bool socket_get_fd(PwMethod_Fd_get_fd* mthis, PwValuePtr self, int* result)
543{
544    *result = get_this_socket(self)->sock;
545    return true;
546}
547
548static bool socket_set_fd(PwMethod_Fd_set_fd* mthis, PwValuePtr self, int fd, bool move)
549{
550    _PwSocket* s = get_this_socket(self);
551
552    if (s->sock != -1) {
553        // fd already set
554        pw_set_status(PwStatus(PW_ERROR_FD_ALREADY_SET));
555        return false;
556    }
557    s->sock = fd;
558    s->own_fd = move;
559    return true;
560}
561
562static bool socket_close(PwMethod_Fd_close* mthis, PwValuePtr self)
563{
564    close_socket(get_this_socket(self));
565    return true;
566}
567
568static bool socket_set_nonblocking(PwMethod_Fd_set_nonblocking* mthis, PwValuePtr self, bool mode)
569{
570    _PwSocket* s = get_this_socket(self);
571
572    int flags = fcntl(s->sock, F_GETFL, 0);
573    if (mode) {
574        flags |= O_NONBLOCK;
575    } else {
576        flags &= ~O_NONBLOCK;
577    }
578    if (fcntl(s->sock, F_SETFL, flags) == -1) {
579        pw_set_status(PwErrno(errno));
580        return false;
581    } else {
582        return true;
583    }
584}
585
586static PwInterface_Fd socket_fd_interface = {
587#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
588    PW_FD_INTERFACE_METHODS
589#undef X
590};
591
592/****************************************************************
593 * Reader and writer interfaces
594 */
595
596static bool socket_read(PwMethod_Reader_read* mthis, PwValuePtr self, void* buffer, unsigned buffer_size, unsigned* bytes_read)
597{
598    _PwSocket* s = get_this_socket(self);
599
600    ssize_t result;
601    do {
602        result = read(s->sock, buffer, buffer_size);
603    } while (result < 0 && errno == EINTR);
604
605    if (result < 0) {
606        pw_set_status(PwErrno(errno));
607        return false;
608    } else {
609        *bytes_read = (unsigned) result;
610        return true;
611    }
612}
613
614static bool socket_write(PwMethod_Writer_write* mthis, PwValuePtr self, void* data, unsigned size, unsigned* bytes_written)
615{
616    _PwSocket* s = get_this_socket(self);
617
618    ssize_t result;
619    do {
620        result = write(s->sock, data, size);
621    } while (result < 0 && errno == EINTR);
622
623    if (result < 0) {
624        pw_set_status(PwErrno(errno));
625        return false;
626    } else {
627        *bytes_written = (unsigned) result;
628        return true;
629    }
630}
631
632static PwInterface_Reader socket_reader_interface = {
633#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
634    PW_READER_INTERFACE_METHODS
635#undef X
636};
637
638static PwInterface_Writer socket_writer_interface = {
639#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
640    PW_WRITER_INTERFACE_METHODS
641#undef X
642};
643
644/****************************************************************
645 * Initialization
646 */
647
648[[ gnu::constructor ]]
649void _pw_init_socket()
650{
651    // interface can be already registered
652    // basically. interfaces can be registered by any type in any order
653    if (PwInterfaceId_Socket == 0) {
654        _pw_init_interfaces();
655#       define X(name, ...) #name __VA_OPT__(,)
656        PwInterfaceId_Socket = pw_register_interface("Socket", PW_SOCKET_INTERFACE_METHODS, nullptr);
657#       undef X
658    }
659
660    if (PwTypeId_Socket != 0) {
661        return;
662    }
663
664    _pw_init_types();
665
666    // init statuses
667    PW_ERROR_BAD_ADDRESS_FAMILY = pw_define_status("BAD_ADDRESS_FAMILY");
668    PW_ERROR_BAD_IP_ADDRESS     = pw_define_status("BAD_IP_ADDRESS");
669    PW_ERROR_BAD_PORT           = pw_define_status("BAD_PORT");
670    PW_ERROR_HOST_ADDRESS_EXPECTED   = pw_define_status("HOST_ADDRESS_EXPECTED");
671    PW_ERROR_ADDRESS_FAMILY_MISMATCH = pw_define_status("ADDRESS_FAMILY_MISMATCH");
672    PW_ERROR_SOCKET_NAME_TOO_LONG    = pw_define_status("SOCKET_NAME_TOO_LONG");
673    PW_ERROR_MISSING_NETMASK    = pw_define_status("MISSING_NETMASK");
674    PW_ERROR_BAD_NETMASK        = pw_define_status("BAD_NETMASK");
675    PW_ERROR_PORT_UNSPECIFIED   = pw_define_status("PORT_UNSPECIFIED");
676
677    // init types
678
679    PwTypeId_SockAddr = pw_add_type2(
680        "SockAddr", _PwSockAddrData,
681        PW_PARENTS,
682            PwTypeId_Struct,
683        PW_INTERFACES,
684            PwInterfaceId_Basic, &sockaddr_basic_interface
685    );
686
687    PwTypeId_Socket = pw_add_type2(
688        "Socket", _PwSocket,
689        PW_PARENTS,
690            PwTypeId_Struct,
691        PW_INTERFACES,
692            PwInterfaceId_Basic,  &socket_basic_interface,
693            PwInterfaceId_Fd,     &socket_fd_interface,
694            PwInterfaceId_Socket, &socket_interface,
695            PwInterfaceId_Reader, &socket_reader_interface,
696            PwInterfaceId_Writer, &socket_writer_interface
697    );
698}