/src/unit/src/nxt_socketpair.c
Line | Count | Source (jump to first uncovered line) |
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 |
24 | | nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair) |
25 | 0 | { |
26 | 0 | if (nxt_slow_path(socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, pair) != 0)) { |
27 | 0 | nxt_alert(task, "socketpair() failed %E", nxt_errno); |
28 | 0 | return NXT_ERROR; |
29 | 0 | } |
30 | | |
31 | 0 | nxt_debug(task, "socketpair(): %d:%d", pair[0], pair[1]); |
32 | |
|
33 | 0 | if (nxt_slow_path(nxt_socket_nonblocking(task, pair[0]) != NXT_OK)) { |
34 | 0 | goto fail; |
35 | 0 | } |
36 | | |
37 | 0 | if (nxt_slow_path(fcntl(pair[0], F_SETFD, FD_CLOEXEC) == -1)) { |
38 | 0 | goto fail; |
39 | 0 | } |
40 | | |
41 | 0 | if (nxt_slow_path(nxt_socket_nonblocking(task, pair[1]) != NXT_OK)) { |
42 | 0 | goto fail; |
43 | 0 | } |
44 | | |
45 | 0 | if (nxt_slow_path(fcntl(pair[1], F_SETFD, FD_CLOEXEC) == -1)) { |
46 | 0 | goto fail; |
47 | 0 | } |
48 | | |
49 | 0 | #if NXT_HAVE_SOCKOPT_SO_PASSCRED |
50 | 0 | int enable_creds = 1; |
51 | |
|
52 | 0 | if (nxt_slow_path(setsockopt(pair[0], SOL_SOCKET, SO_PASSCRED, |
53 | 0 | &enable_creds, sizeof(enable_creds)) == -1)) |
54 | 0 | { |
55 | 0 | nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); |
56 | 0 | goto fail; |
57 | 0 | } |
58 | | |
59 | 0 | if (nxt_slow_path(setsockopt(pair[1], SOL_SOCKET, SO_PASSCRED, |
60 | 0 | &enable_creds, sizeof(enable_creds)) == -1)) |
61 | 0 | { |
62 | 0 | nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); |
63 | 0 | goto fail; |
64 | 0 | } |
65 | 0 | #endif |
66 | | |
67 | 0 | return NXT_OK; |
68 | | |
69 | 0 | fail: |
70 | |
|
71 | 0 | nxt_socketpair_close(task, pair); |
72 | |
|
73 | 0 | return NXT_ERROR; |
74 | 0 | } |
75 | | |
76 | | |
77 | | void |
78 | | nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair) |
79 | 0 | { |
80 | 0 | nxt_socket_close(task, pair[0]); |
81 | 0 | nxt_socket_close(task, pair[1]); |
82 | 0 | } |
83 | | |
84 | | |
85 | | ssize_t |
86 | | nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, |
87 | | nxt_uint_t niob) |
88 | 0 | { |
89 | 0 | ssize_t n; |
90 | 0 | nxt_err_t err; |
91 | 0 | nxt_send_oob_t oob; |
92 | |
|
93 | 0 | nxt_socket_msg_oob_init(&oob, fd); |
94 | |
|
95 | 0 | for ( ;; ) { |
96 | 0 | n = nxt_sendmsg(ev->fd, iob, niob, &oob); |
97 | |
|
98 | 0 | err = (n == -1) ? nxt_socket_errno : 0; |
99 | |
|
100 | 0 | nxt_debug(ev->task, "sendmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0], |
101 | 0 | fd[1], niob, n); |
102 | |
|
103 | 0 | if (n > 0) { |
104 | 0 | return n; |
105 | 0 | } |
106 | | |
107 | | /* n == -1 */ |
108 | | |
109 | 0 | switch (err) { |
110 | | |
111 | 0 | case NXT_EAGAIN: |
112 | 0 | nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd); |
113 | 0 | break; |
114 | | |
115 | | /* |
116 | | * Returned (at least on OSX) when trying to send many small messages. |
117 | | */ |
118 | 0 | case NXT_ENOBUFS: |
119 | 0 | nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd); |
120 | 0 | break; |
121 | | |
122 | 0 | case NXT_EINTR: |
123 | 0 | nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd); |
124 | 0 | continue; |
125 | | |
126 | 0 | default: |
127 | 0 | nxt_alert(ev->task, "sendmsg(%d, %FD, %FD, %ui) failed %E", |
128 | 0 | ev->fd, fd[0], fd[1], niob, err); |
129 | |
|
130 | 0 | return NXT_ERROR; |
131 | 0 | } |
132 | | |
133 | 0 | ev->write_ready = 0; |
134 | |
|
135 | 0 | return NXT_AGAIN; |
136 | 0 | } |
137 | 0 | } |
138 | | |
139 | | |
140 | | ssize_t |
141 | | nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob, |
142 | | void *oob) |
143 | 0 | { |
144 | 0 | ssize_t n; |
145 | 0 | nxt_err_t err; |
146 | |
|
147 | 0 | for ( ;; ) { |
148 | 0 | n = nxt_recvmsg(ev->fd, iob, niob, oob); |
149 | |
|
150 | 0 | err = (n == -1) ? nxt_socket_errno : 0; |
151 | |
|
152 | 0 | nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z", |
153 | 0 | ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n); |
154 | |
|
155 | 0 | if (n > 0) { |
156 | 0 | return n; |
157 | 0 | } |
158 | | |
159 | 0 | if (n == 0) { |
160 | 0 | ev->closed = 1; |
161 | 0 | ev->read_ready = 0; |
162 | |
|
163 | 0 | return n; |
164 | 0 | } |
165 | | |
166 | | /* n == -1 */ |
167 | | |
168 | 0 | switch (err) { |
169 | | |
170 | 0 | case NXT_EAGAIN: |
171 | 0 | nxt_debug(ev->task, "recvmsg(%d) not ready", ev->fd); |
172 | 0 | ev->read_ready = 0; |
173 | |
|
174 | 0 | return NXT_AGAIN; |
175 | | |
176 | 0 | case NXT_EINTR: |
177 | 0 | nxt_debug(ev->task, "recvmsg(%d) interrupted", ev->fd); |
178 | 0 | continue; |
179 | | |
180 | 0 | default: |
181 | 0 | nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E", |
182 | 0 | ev->fd, niob, err); |
183 | |
|
184 | 0 | return NXT_ERROR; |
185 | 0 | } |
186 | 0 | } |
187 | 0 | } |