10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru /* 110Sigor@sysoev.ru * SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open 120Sigor@sysoev.ru * sockets, Linux 2.6.4, FreeBSD 9.0, NetBSD 6.0, and OpenBSD 5.0. 130Sigor@sysoev.ru */ 140Sigor@sysoev.ru 150Sigor@sysoev.ru /* SOCK_SEQPACKET is disabled to test SOCK_DGRAM on all platforms. */ 160Sigor@sysoev.ru #if (0 || NXT_HAVE_AF_UNIX_SOCK_SEQPACKET) 170Sigor@sysoev.ru #define NXT_UNIX_SOCKET SOCK_SEQPACKET 180Sigor@sysoev.ru #else 190Sigor@sysoev.ru #define NXT_UNIX_SOCKET SOCK_DGRAM 200Sigor@sysoev.ru #endif 210Sigor@sysoev.ru 220Sigor@sysoev.ru 230Sigor@sysoev.ru static ssize_t nxt_sendmsg(nxt_socket_t s, nxt_fd_t fd, nxt_iobuf_t *iob, 240Sigor@sysoev.ru nxt_uint_t niob); 250Sigor@sysoev.ru static ssize_t nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, 260Sigor@sysoev.ru nxt_uint_t niob); 270Sigor@sysoev.ru 280Sigor@sysoev.ru 290Sigor@sysoev.ru nxt_int_t 300Sigor@sysoev.ru nxt_socketpair_create(nxt_socket_t *pair) 310Sigor@sysoev.ru { 320Sigor@sysoev.ru if (nxt_slow_path(socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, pair) != 0)) { 330Sigor@sysoev.ru nxt_thread_log_alert("socketpair() failed %E", nxt_errno); 340Sigor@sysoev.ru return NXT_ERROR; 350Sigor@sysoev.ru } 360Sigor@sysoev.ru 370Sigor@sysoev.ru nxt_thread_log_debug("socketpair(): %d:%d", pair[0], pair[1]); 380Sigor@sysoev.ru 390Sigor@sysoev.ru if (nxt_slow_path(nxt_socket_nonblocking(pair[0]) != NXT_OK)) { 400Sigor@sysoev.ru goto fail; 410Sigor@sysoev.ru } 420Sigor@sysoev.ru 430Sigor@sysoev.ru if (nxt_slow_path(fcntl(pair[0], F_SETFD, FD_CLOEXEC) == -1)) { 440Sigor@sysoev.ru goto fail; 450Sigor@sysoev.ru } 460Sigor@sysoev.ru 470Sigor@sysoev.ru if (nxt_slow_path(nxt_socket_nonblocking(pair[1]) != NXT_OK)) { 480Sigor@sysoev.ru goto fail; 490Sigor@sysoev.ru } 500Sigor@sysoev.ru 510Sigor@sysoev.ru if (nxt_slow_path(fcntl(pair[1], F_SETFD, FD_CLOEXEC) == -1)) { 520Sigor@sysoev.ru goto fail; 530Sigor@sysoev.ru } 540Sigor@sysoev.ru 550Sigor@sysoev.ru return NXT_OK; 560Sigor@sysoev.ru 570Sigor@sysoev.ru fail: 580Sigor@sysoev.ru 590Sigor@sysoev.ru nxt_socketpair_close(pair); 600Sigor@sysoev.ru 610Sigor@sysoev.ru return NXT_ERROR; 620Sigor@sysoev.ru } 630Sigor@sysoev.ru 640Sigor@sysoev.ru 650Sigor@sysoev.ru void 660Sigor@sysoev.ru nxt_socketpair_close(nxt_socket_t *pair) 670Sigor@sysoev.ru { 680Sigor@sysoev.ru nxt_socket_close(pair[0]); 690Sigor@sysoev.ru nxt_socket_close(pair[1]); 700Sigor@sysoev.ru } 710Sigor@sysoev.ru 720Sigor@sysoev.ru 730Sigor@sysoev.ru ssize_t 740Sigor@sysoev.ru nxt_socketpair_send(nxt_event_fd_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, 750Sigor@sysoev.ru nxt_uint_t niob) 760Sigor@sysoev.ru { 770Sigor@sysoev.ru ssize_t n; 780Sigor@sysoev.ru nxt_err_t err; 790Sigor@sysoev.ru 800Sigor@sysoev.ru for ( ;; ) { 810Sigor@sysoev.ru n = nxt_sendmsg(ev->fd, fd, iob, niob); 820Sigor@sysoev.ru 830Sigor@sysoev.ru err = (n == -1) ? nxt_socket_errno : 0; 840Sigor@sysoev.ru 85*1Sigor@sysoev.ru nxt_debug(ev->task, "sendmsg(%d, %FD, %ui): %z", ev->fd, fd, niob, n); 860Sigor@sysoev.ru 870Sigor@sysoev.ru if (n > 0) { 880Sigor@sysoev.ru return n; 890Sigor@sysoev.ru } 900Sigor@sysoev.ru 910Sigor@sysoev.ru /* n == -1 */ 920Sigor@sysoev.ru 930Sigor@sysoev.ru switch (err) { 940Sigor@sysoev.ru 950Sigor@sysoev.ru case NXT_EAGAIN: 96*1Sigor@sysoev.ru nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd); 970Sigor@sysoev.ru ev->write_ready = 0; 98*1Sigor@sysoev.ru 990Sigor@sysoev.ru return NXT_AGAIN; 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru case NXT_EINTR: 102*1Sigor@sysoev.ru nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd); 1030Sigor@sysoev.ru continue; 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru default: 106*1Sigor@sysoev.ru nxt_log(ev->task, NXT_LOG_CRIT, "sendmsg(%d, %FD, %ui) failed %E", 107*1Sigor@sysoev.ru ev->fd, fd, niob, err); 108*1Sigor@sysoev.ru 1090Sigor@sysoev.ru return NXT_ERROR; 1100Sigor@sysoev.ru } 1110Sigor@sysoev.ru } 1120Sigor@sysoev.ru } 1130Sigor@sysoev.ru 1140Sigor@sysoev.ru 1150Sigor@sysoev.ru ssize_t 1160Sigor@sysoev.ru nxt_socketpair_recv(nxt_event_fd_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, 1170Sigor@sysoev.ru nxt_uint_t niob) 1180Sigor@sysoev.ru { 1190Sigor@sysoev.ru ssize_t n; 1200Sigor@sysoev.ru nxt_err_t err; 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru for ( ;; ) { 1230Sigor@sysoev.ru n = nxt_recvmsg(ev->fd, fd, iob, niob); 1240Sigor@sysoev.ru 1250Sigor@sysoev.ru err = (n == -1) ? nxt_socket_errno : 0; 1260Sigor@sysoev.ru 127*1Sigor@sysoev.ru nxt_debug(ev->task, "recvmsg(%d, %FD, %ui): %z", ev->fd, *fd, niob, n); 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru if (n > 0) { 1300Sigor@sysoev.ru return n; 1310Sigor@sysoev.ru } 1320Sigor@sysoev.ru 1330Sigor@sysoev.ru if (n == 0) { 1340Sigor@sysoev.ru ev->closed = 1; 1350Sigor@sysoev.ru ev->read_ready = 0; 136*1Sigor@sysoev.ru 1370Sigor@sysoev.ru return n; 1380Sigor@sysoev.ru } 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru /* n == -1 */ 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru switch (err) { 1430Sigor@sysoev.ru 1440Sigor@sysoev.ru case NXT_EAGAIN: 145*1Sigor@sysoev.ru nxt_debug(ev->task, "recvmsg(%d) not ready", ev->fd); 1460Sigor@sysoev.ru ev->read_ready = 0; 147*1Sigor@sysoev.ru 1480Sigor@sysoev.ru return NXT_AGAIN; 1490Sigor@sysoev.ru 1500Sigor@sysoev.ru case NXT_EINTR: 151*1Sigor@sysoev.ru nxt_debug(ev->task, "recvmsg(%d) interrupted", ev->fd); 1520Sigor@sysoev.ru continue; 1530Sigor@sysoev.ru 1540Sigor@sysoev.ru default: 155*1Sigor@sysoev.ru nxt_log(ev->task, NXT_LOG_CRIT, "recvmsg(%d, %p, %ui) failed %E", 156*1Sigor@sysoev.ru ev->fd, fd, niob, err); 157*1Sigor@sysoev.ru 1580Sigor@sysoev.ru return NXT_ERROR; 1590Sigor@sysoev.ru } 1600Sigor@sysoev.ru } 1610Sigor@sysoev.ru } 1620Sigor@sysoev.ru 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru #if (NXT_HAVE_MSGHDR_MSG_CONTROL) 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru /* 1670Sigor@sysoev.ru * Linux, FreeBSD, Solaris X/Open sockets, 1680Sigor@sysoev.ru * MacOSX, NetBSD, AIX, HP-UX X/Open sockets. 1690Sigor@sysoev.ru */ 1700Sigor@sysoev.ru 1710Sigor@sysoev.ru static ssize_t 1720Sigor@sysoev.ru nxt_sendmsg(nxt_socket_t s, nxt_fd_t fd, nxt_iobuf_t *iob, nxt_uint_t niob) 1730Sigor@sysoev.ru { 1740Sigor@sysoev.ru struct msghdr msg; 1750Sigor@sysoev.ru union { 1760Sigor@sysoev.ru struct cmsghdr cm; 1770Sigor@sysoev.ru char space[CMSG_SPACE(sizeof(int))]; 1780Sigor@sysoev.ru } cmsg; 1790Sigor@sysoev.ru 1800Sigor@sysoev.ru msg.msg_name = NULL; 1810Sigor@sysoev.ru msg.msg_namelen = 0; 1820Sigor@sysoev.ru msg.msg_iov = iob; 1830Sigor@sysoev.ru msg.msg_iovlen = niob; 1840Sigor@sysoev.ru /* Flags are cleared just to suppress valgrind warning. */ 1850Sigor@sysoev.ru msg.msg_flags = 0; 1860Sigor@sysoev.ru 1870Sigor@sysoev.ru if (fd != -1) { 1880Sigor@sysoev.ru msg.msg_control = (caddr_t) &cmsg; 1890Sigor@sysoev.ru msg.msg_controllen = sizeof(cmsg); 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); 1920Sigor@sysoev.ru cmsg.cm.cmsg_level = SOL_SOCKET; 1930Sigor@sysoev.ru cmsg.cm.cmsg_type = SCM_RIGHTS; 1940Sigor@sysoev.ru 1950Sigor@sysoev.ru /* 1960Sigor@sysoev.ru * nxt_memcpy() is used instead of simple 1970Sigor@sysoev.ru * *(int *) CMSG_DATA(&cmsg.cm) = fd; 1980Sigor@sysoev.ru * because GCC 4.4 with -O2/3/s optimization may issue a warning: 1990Sigor@sysoev.ru * dereferencing type-punned pointer will break strict-aliasing rules 2000Sigor@sysoev.ru * 2010Sigor@sysoev.ru * Fortunately, GCC with -O1 compiles this nxt_memcpy() 2020Sigor@sysoev.ru * in the same simple assignment as in the code above. 2030Sigor@sysoev.ru */ 2040Sigor@sysoev.ru nxt_memcpy(CMSG_DATA(&cmsg.cm), &fd, sizeof(int)); 2050Sigor@sysoev.ru 2060Sigor@sysoev.ru } else { 2070Sigor@sysoev.ru msg.msg_control = NULL; 2080Sigor@sysoev.ru msg.msg_controllen = 0; 2090Sigor@sysoev.ru } 2100Sigor@sysoev.ru 2110Sigor@sysoev.ru return sendmsg(s, &msg, 0); 2120Sigor@sysoev.ru } 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru 2150Sigor@sysoev.ru static ssize_t 2160Sigor@sysoev.ru nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) 2170Sigor@sysoev.ru { 2180Sigor@sysoev.ru ssize_t n; 2190Sigor@sysoev.ru struct msghdr msg; 2200Sigor@sysoev.ru union { 2210Sigor@sysoev.ru struct cmsghdr cm; 2220Sigor@sysoev.ru char space[CMSG_SPACE(sizeof(int))]; 2230Sigor@sysoev.ru } cmsg; 2240Sigor@sysoev.ru 2250Sigor@sysoev.ru msg.msg_name = NULL; 2260Sigor@sysoev.ru msg.msg_namelen = 0; 2270Sigor@sysoev.ru msg.msg_iov = iob; 2280Sigor@sysoev.ru msg.msg_iovlen = niob; 2290Sigor@sysoev.ru msg.msg_control = (caddr_t) &cmsg; 2300Sigor@sysoev.ru msg.msg_controllen = sizeof(cmsg); 2310Sigor@sysoev.ru 2320Sigor@sysoev.ru *fd = -1; 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru n = recvmsg(s, &msg, 0); 2350Sigor@sysoev.ru 2360Sigor@sysoev.ru if (n > 0 2370Sigor@sysoev.ru && cmsg.cm.cmsg_len == CMSG_LEN(sizeof(int)) 2380Sigor@sysoev.ru && cmsg.cm.cmsg_level == SOL_SOCKET 2390Sigor@sysoev.ru && cmsg.cm.cmsg_type == SCM_RIGHTS) 2400Sigor@sysoev.ru { 2410Sigor@sysoev.ru /* (*fd) = *(int *) CMSG_DATA(&cmsg.cm); */ 2420Sigor@sysoev.ru nxt_memcpy(fd, CMSG_DATA(&cmsg.cm), sizeof(int)); 2430Sigor@sysoev.ru } 2440Sigor@sysoev.ru 2450Sigor@sysoev.ru return n; 2460Sigor@sysoev.ru } 2470Sigor@sysoev.ru 2480Sigor@sysoev.ru #else 2490Sigor@sysoev.ru 2500Sigor@sysoev.ru /* Solaris 4.3BSD sockets. */ 2510Sigor@sysoev.ru 2520Sigor@sysoev.ru static ssize_t 2530Sigor@sysoev.ru nxt_sendmsg(nxt_socket_t s, nxt_fd_t fd, nxt_iobuf_t *iob, nxt_uint_t niob) 2540Sigor@sysoev.ru { 2550Sigor@sysoev.ru struct msghdr msg; 2560Sigor@sysoev.ru 2570Sigor@sysoev.ru msg.msg_name = NULL; 2580Sigor@sysoev.ru msg.msg_namelen = 0; 2590Sigor@sysoev.ru msg.msg_iov = iob; 2600Sigor@sysoev.ru msg.msg_iovlen = niob; 2610Sigor@sysoev.ru 2620Sigor@sysoev.ru if (fd != -1) { 2630Sigor@sysoev.ru msg.msg_accrights = (caddr_t) &fd; 2640Sigor@sysoev.ru msg.msg_accrightslen = sizeof(int); 2650Sigor@sysoev.ru 2660Sigor@sysoev.ru } else { 2670Sigor@sysoev.ru msg.msg_accrights = NULL; 2680Sigor@sysoev.ru msg.msg_accrightslen = 0; 2690Sigor@sysoev.ru } 2700Sigor@sysoev.ru 2710Sigor@sysoev.ru return sendmsg(s, &msg, 0); 2720Sigor@sysoev.ru } 2730Sigor@sysoev.ru 2740Sigor@sysoev.ru 2750Sigor@sysoev.ru static ssize_t 2760Sigor@sysoev.ru nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) 2770Sigor@sysoev.ru { 2780Sigor@sysoev.ru struct msghdr msg; 2790Sigor@sysoev.ru 2800Sigor@sysoev.ru *fd = -1; 2810Sigor@sysoev.ru 2820Sigor@sysoev.ru msg.msg_name = NULL; 2830Sigor@sysoev.ru msg.msg_namelen = 0; 2840Sigor@sysoev.ru msg.msg_iov = iob; 2850Sigor@sysoev.ru msg.msg_iovlen = niob; 2860Sigor@sysoev.ru msg.msg_accrights = (caddr_t) fd; 2870Sigor@sysoev.ru msg.msg_accrightslen = sizeof(int); 2880Sigor@sysoev.ru 2890Sigor@sysoev.ru return recvmsg(s, &msg, 0); 2900Sigor@sysoev.ru } 2910Sigor@sysoev.ru 2920Sigor@sysoev.ru #endif 293