1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #include <nxt_main.h>
8 #include <nxt_socket_msg.h>
9
10 /*
11 * SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open
12 * sockets, Linux 2.6.4, FreeBSD 9.0, NetBSD 6.0, and OpenBSD 5.0.
13 */
14
15 /* SOCK_SEQPACKET is disabled to test SOCK_DGRAM on all platforms. */
16 #if (0 || NXT_HAVE_AF_UNIX_SOCK_SEQPACKET)
17 #define NXT_UNIX_SOCKET SOCK_SEQPACKET
18 #else
19 #define NXT_UNIX_SOCKET SOCK_DGRAM
20 #endif
21
22
23 nxt_int_t
nxt_socketpair_create(nxt_task_t * task,nxt_socket_t * pair)24 nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair)
25 {
26 if (nxt_slow_path(socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, pair) != 0)) {
27 nxt_alert(task, "socketpair() failed %E", nxt_errno);
28 return NXT_ERROR;
29 }
30
31 nxt_debug(task, "socketpair(): %d:%d", pair[0], pair[1]);
32
33 if (nxt_slow_path(nxt_socket_nonblocking(task, pair[0]) != NXT_OK)) {
34 goto fail;
35 }
36
37 if (nxt_slow_path(fcntl(pair[0], F_SETFD, FD_CLOEXEC) == -1)) {
38 goto fail;
39 }
40
41 if (nxt_slow_path(nxt_socket_nonblocking(task, pair[1]) != NXT_OK)) {
42 goto fail;
43 }
44
45 if (nxt_slow_path(fcntl(pair[1], F_SETFD, FD_CLOEXEC) == -1)) {
46 goto fail;
47 }
48
49 #if NXT_HAVE_SOCKOPT_SO_PASSCRED
50 int enable_creds = 1;
51
52 if (nxt_slow_path(setsockopt(pair[0], SOL_SOCKET, SO_PASSCRED,
53 &enable_creds, sizeof(enable_creds)) == -1))
54 {
55 nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno);
56 goto fail;
57 }
58
59 if (nxt_slow_path(setsockopt(pair[1], SOL_SOCKET, SO_PASSCRED,
60 &enable_creds, sizeof(enable_creds)) == -1))
61 {
62 nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno);
63 goto fail;
64 }
65 #endif
66
67 return NXT_OK;
68
69 fail:
70
71 nxt_socketpair_close(task, pair);
72
73 return NXT_ERROR;
74 }
75
76
77 void
nxt_socketpair_close(nxt_task_t * task,nxt_socket_t * pair)78 nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair)
79 {
80 nxt_socket_close(task, pair[0]);
81 nxt_socket_close(task, pair[1]);
82 }
83
84
85 ssize_t
nxt_socketpair_send(nxt_fd_event_t * ev,nxt_fd_t * fd,nxt_iobuf_t * iob,nxt_uint_t niob)86 nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob,
87 nxt_uint_t niob)
88 {
89 ssize_t n;
90 nxt_err_t err;
91 nxt_send_oob_t oob;
92
93 nxt_socket_msg_oob_init(&oob, fd);
94
95 for ( ;; ) {
96 n = nxt_sendmsg(ev->fd, iob, niob, &oob);
97
98 err = (n == -1) ? nxt_socket_errno : 0;
99
100 nxt_debug(ev->task, "sendmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0],
101 fd[1], niob, n);
102
103 if (n > 0) {
104 return n;
105 }
106
107 /* n == -1 */
108
109 switch (err) {
110
111 case NXT_EAGAIN:
112 nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd);
113 break;
114
115 /*
116 * Returned (at least on OSX) when trying to send many small messages.
117 */
118 case NXT_ENOBUFS:
119 nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd);
120 break;
121
122 case NXT_EINTR:
123 nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd);
124 continue;
125
126 default:
127 nxt_alert(ev->task, "sendmsg(%d, %FD, %FD, %ui) failed %E",
128 ev->fd, fd[0], fd[1], niob, err);
129
130 return NXT_ERROR;
131 }
132
133 ev->write_ready = 0;
134
135 return NXT_AGAIN;
136 }
137 }
138
139
140 ssize_t
nxt_socketpair_recv(nxt_fd_event_t * ev,nxt_iobuf_t * iob,nxt_uint_t niob,void * oob)141 nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob,
142 void *oob)
143 {
144 ssize_t n;
145 nxt_err_t err;
146
147 for ( ;; ) {
148 n = nxt_recvmsg(ev->fd, iob, niob, oob);
149
150 err = (n == -1) ? nxt_socket_errno : 0;
151
152 nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z",
153 ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n);
154
155 if (n > 0) {
156 return n;
157 }
158
159 if (n == 0) {
160 ev->closed = 1;
161 ev->read_ready = 0;
162
163 return n;
164 }
165
166 /* n == -1 */
167
168 switch (err) {
169
170 case NXT_EAGAIN:
171 nxt_debug(ev->task, "recvmsg(%d) not ready", ev->fd);
172 ev->read_ready = 0;
173
174 return NXT_AGAIN;
175
176 case NXT_EINTR:
177 nxt_debug(ev->task, "recvmsg(%d) interrupted", ev->fd);
178 continue;
179
180 default:
181 nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E",
182 ev->fd, niob, err);
183
184 return NXT_ERROR;
185 }
186 }
187 }
188