xref: /unit/src/nxt_socketpair.c (revision 1996:35873fa78fed)
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>
8*1996St.nateldemoura@f5.com #include <nxt_socket_msg.h>
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 nxt_int_t
nxt_socketpair_create(nxt_task_t * task,nxt_socket_t * pair)2413Sigor@sysoev.ru nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair)
250Sigor@sysoev.ru {
260Sigor@sysoev.ru     if (nxt_slow_path(socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, pair) != 0)) {
27564Svbart@nginx.com         nxt_alert(task, "socketpair() failed %E", nxt_errno);
280Sigor@sysoev.ru         return NXT_ERROR;
290Sigor@sysoev.ru     }
300Sigor@sysoev.ru 
3113Sigor@sysoev.ru     nxt_debug(task, "socketpair(): %d:%d", pair[0], pair[1]);
320Sigor@sysoev.ru 
3313Sigor@sysoev.ru     if (nxt_slow_path(nxt_socket_nonblocking(task, pair[0]) != NXT_OK)) {
340Sigor@sysoev.ru         goto fail;
350Sigor@sysoev.ru     }
360Sigor@sysoev.ru 
370Sigor@sysoev.ru     if (nxt_slow_path(fcntl(pair[0], F_SETFD, FD_CLOEXEC) == -1)) {
380Sigor@sysoev.ru         goto fail;
390Sigor@sysoev.ru     }
400Sigor@sysoev.ru 
4113Sigor@sysoev.ru     if (nxt_slow_path(nxt_socket_nonblocking(task, pair[1]) != NXT_OK)) {
420Sigor@sysoev.ru         goto fail;
430Sigor@sysoev.ru     }
440Sigor@sysoev.ru 
450Sigor@sysoev.ru     if (nxt_slow_path(fcntl(pair[1], F_SETFD, FD_CLOEXEC) == -1)) {
460Sigor@sysoev.ru         goto fail;
470Sigor@sysoev.ru     }
480Sigor@sysoev.ru 
49*1996St.nateldemoura@f5.com #if NXT_HAVE_SOCKOPT_SO_PASSCRED
50*1996St.nateldemoura@f5.com     int  enable_creds = 1;
51*1996St.nateldemoura@f5.com 
52*1996St.nateldemoura@f5.com     if (nxt_slow_path(setsockopt(pair[0], SOL_SOCKET, SO_PASSCRED,
53*1996St.nateldemoura@f5.com                       &enable_creds, sizeof(enable_creds)) == -1))
54*1996St.nateldemoura@f5.com     {
55*1996St.nateldemoura@f5.com         nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno);
56*1996St.nateldemoura@f5.com         goto fail;
57*1996St.nateldemoura@f5.com     }
58*1996St.nateldemoura@f5.com 
59*1996St.nateldemoura@f5.com     if (nxt_slow_path(setsockopt(pair[1], SOL_SOCKET, SO_PASSCRED,
60*1996St.nateldemoura@f5.com                       &enable_creds, sizeof(enable_creds)) == -1))
61*1996St.nateldemoura@f5.com     {
62*1996St.nateldemoura@f5.com         nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno);
63*1996St.nateldemoura@f5.com         goto fail;
64*1996St.nateldemoura@f5.com     }
65*1996St.nateldemoura@f5.com #endif
66*1996St.nateldemoura@f5.com 
670Sigor@sysoev.ru     return NXT_OK;
680Sigor@sysoev.ru 
690Sigor@sysoev.ru fail:
700Sigor@sysoev.ru 
7113Sigor@sysoev.ru     nxt_socketpair_close(task, pair);
720Sigor@sysoev.ru 
730Sigor@sysoev.ru     return NXT_ERROR;
740Sigor@sysoev.ru }
750Sigor@sysoev.ru 
760Sigor@sysoev.ru 
770Sigor@sysoev.ru void
nxt_socketpair_close(nxt_task_t * task,nxt_socket_t * pair)7813Sigor@sysoev.ru nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair)
790Sigor@sysoev.ru {
8013Sigor@sysoev.ru     nxt_socket_close(task, pair[0]);
8113Sigor@sysoev.ru     nxt_socket_close(task, pair[1]);
820Sigor@sysoev.ru }
830Sigor@sysoev.ru 
840Sigor@sysoev.ru 
850Sigor@sysoev.ru ssize_t
nxt_socketpair_send(nxt_fd_event_t * ev,nxt_fd_t * fd,nxt_iobuf_t * iob,nxt_uint_t niob)861553Smax.romanov@nginx.com nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob,
870Sigor@sysoev.ru     nxt_uint_t niob)
880Sigor@sysoev.ru {
89*1996St.nateldemoura@f5.com     ssize_t         n;
90*1996St.nateldemoura@f5.com     nxt_err_t       err;
91*1996St.nateldemoura@f5.com     nxt_send_oob_t  oob;
92*1996St.nateldemoura@f5.com 
93*1996St.nateldemoura@f5.com     nxt_socket_msg_oob_init(&oob, fd);
940Sigor@sysoev.ru 
950Sigor@sysoev.ru     for ( ;; ) {
96*1996St.nateldemoura@f5.com         n = nxt_sendmsg(ev->fd, iob, niob, &oob);
970Sigor@sysoev.ru 
980Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
990Sigor@sysoev.ru 
1001553Smax.romanov@nginx.com         nxt_debug(ev->task, "sendmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0],
1011553Smax.romanov@nginx.com                   fd[1], niob, n);
1020Sigor@sysoev.ru 
1030Sigor@sysoev.ru         if (n > 0) {
1040Sigor@sysoev.ru             return n;
1050Sigor@sysoev.ru         }
1060Sigor@sysoev.ru 
1070Sigor@sysoev.ru         /* n == -1 */
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru         switch (err) {
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru         case NXT_EAGAIN:
1121Sigor@sysoev.ru             nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd);
1131003Smax.romanov@nginx.com             break;
1141Sigor@sysoev.ru 
1151003Smax.romanov@nginx.com         /*
1161003Smax.romanov@nginx.com          * Returned (at least on OSX) when trying to send many small messages.
1171003Smax.romanov@nginx.com          */
1181003Smax.romanov@nginx.com         case NXT_ENOBUFS:
1191003Smax.romanov@nginx.com             nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd);
1201003Smax.romanov@nginx.com             break;
1210Sigor@sysoev.ru 
1220Sigor@sysoev.ru         case NXT_EINTR:
1231Sigor@sysoev.ru             nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd);
1240Sigor@sysoev.ru             continue;
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru         default:
1271553Smax.romanov@nginx.com             nxt_alert(ev->task, "sendmsg(%d, %FD, %FD, %ui) failed %E",
1281553Smax.romanov@nginx.com                       ev->fd, fd[0], fd[1], niob, err);
1291Sigor@sysoev.ru 
1300Sigor@sysoev.ru             return NXT_ERROR;
1310Sigor@sysoev.ru         }
1321003Smax.romanov@nginx.com 
1331003Smax.romanov@nginx.com         ev->write_ready = 0;
1341003Smax.romanov@nginx.com 
1351003Smax.romanov@nginx.com         return NXT_AGAIN;
1360Sigor@sysoev.ru     }
1370Sigor@sysoev.ru }
1380Sigor@sysoev.ru 
1390Sigor@sysoev.ru 
1400Sigor@sysoev.ru ssize_t
nxt_socketpair_recv(nxt_fd_event_t * ev,nxt_iobuf_t * iob,nxt_uint_t niob,void * oob)141*1996St.nateldemoura@f5.com nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob,
142*1996St.nateldemoura@f5.com     void *oob)
1430Sigor@sysoev.ru {
1440Sigor@sysoev.ru     ssize_t    n;
1450Sigor@sysoev.ru     nxt_err_t  err;
1460Sigor@sysoev.ru 
1470Sigor@sysoev.ru     for ( ;; ) {
148*1996St.nateldemoura@f5.com         n = nxt_recvmsg(ev->fd, iob, niob, oob);
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
1510Sigor@sysoev.ru 
152*1996St.nateldemoura@f5.com         nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z",
153*1996St.nateldemoura@f5.com                   ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n);
1540Sigor@sysoev.ru 
1550Sigor@sysoev.ru         if (n > 0) {
1560Sigor@sysoev.ru             return n;
1570Sigor@sysoev.ru         }
1580Sigor@sysoev.ru 
1590Sigor@sysoev.ru         if (n == 0) {
1600Sigor@sysoev.ru             ev->closed = 1;
1610Sigor@sysoev.ru             ev->read_ready = 0;
1621Sigor@sysoev.ru 
1630Sigor@sysoev.ru             return n;
1640Sigor@sysoev.ru         }
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru         /* n == -1 */
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru         switch (err) {
1690Sigor@sysoev.ru 
1700Sigor@sysoev.ru         case NXT_EAGAIN:
1711Sigor@sysoev.ru             nxt_debug(ev->task, "recvmsg(%d) not ready", ev->fd);
1720Sigor@sysoev.ru             ev->read_ready = 0;
1731Sigor@sysoev.ru 
1740Sigor@sysoev.ru             return NXT_AGAIN;
1750Sigor@sysoev.ru 
1760Sigor@sysoev.ru         case NXT_EINTR:
1771Sigor@sysoev.ru             nxt_debug(ev->task, "recvmsg(%d) interrupted", ev->fd);
1780Sigor@sysoev.ru             continue;
1790Sigor@sysoev.ru 
1800Sigor@sysoev.ru         default:
181*1996St.nateldemoura@f5.com             nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E",
182*1996St.nateldemoura@f5.com                       ev->fd, niob, err);
1831Sigor@sysoev.ru 
1840Sigor@sysoev.ru             return NXT_ERROR;
1850Sigor@sysoev.ru         }
1860Sigor@sysoev.ru     }
1870Sigor@sysoev.ru }
188