1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru /* sendfile() has been introduced in MacOSX 10.5 (Leopard) */
11*0Sigor@sysoev.ru 
12*0Sigor@sysoev.ru #ifdef NXT_TEST_BUILD_MACOSX_SENDFILE
13*0Sigor@sysoev.ru 
14*0Sigor@sysoev.ru ssize_t nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b,
15*0Sigor@sysoev.ru     size_t limit);
16*0Sigor@sysoev.ru 
17*0Sigor@sysoev.ru static int nxt_sys_sendfile(int fd, int s, off_t offset, off_t *len,
18*0Sigor@sysoev.ru     struct sf_hdtr *hdtr, int flags)
19*0Sigor@sysoev.ru {
20*0Sigor@sysoev.ru     return -1;
21*0Sigor@sysoev.ru }
22*0Sigor@sysoev.ru 
23*0Sigor@sysoev.ru #else
24*0Sigor@sysoev.ru #define nxt_sys_sendfile  sendfile
25*0Sigor@sysoev.ru #endif
26*0Sigor@sysoev.ru 
27*0Sigor@sysoev.ru 
28*0Sigor@sysoev.ru ssize_t
29*0Sigor@sysoev.ru nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b,
30*0Sigor@sysoev.ru     size_t limit)
31*0Sigor@sysoev.ru {
32*0Sigor@sysoev.ru     size_t                  hd_size, file_size;
33*0Sigor@sysoev.ru     ssize_t                 n;
34*0Sigor@sysoev.ru     nxt_buf_t               *fb;
35*0Sigor@sysoev.ru     nxt_err_t               err;
36*0Sigor@sysoev.ru     nxt_off_t               sent;
37*0Sigor@sysoev.ru     nxt_uint_t              nhd, ntr;
38*0Sigor@sysoev.ru     struct iovec            hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX];
39*0Sigor@sysoev.ru     struct sf_hdtr          hdtr, *ht;
40*0Sigor@sysoev.ru     nxt_sendbuf_coalesce_t  sb;
41*0Sigor@sysoev.ru 
42*0Sigor@sysoev.ru     sb.buf = b;
43*0Sigor@sysoev.ru     sb.iobuf = hd;
44*0Sigor@sysoev.ru     sb.nmax = NXT_IOBUF_MAX;
45*0Sigor@sysoev.ru     sb.sync = 0;
46*0Sigor@sysoev.ru     sb.size = 0;
47*0Sigor@sysoev.ru     sb.limit = limit;
48*0Sigor@sysoev.ru 
49*0Sigor@sysoev.ru     nhd = nxt_sendbuf_mem_coalesce(&sb);
50*0Sigor@sysoev.ru 
51*0Sigor@sysoev.ru     if (nhd == 0 && sb.sync) {
52*0Sigor@sysoev.ru         return 0;
53*0Sigor@sysoev.ru     }
54*0Sigor@sysoev.ru 
55*0Sigor@sysoev.ru     if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) {
56*0Sigor@sysoev.ru         return nxt_event_conn_io_writev(c, hd, nhd);
57*0Sigor@sysoev.ru     }
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru     hd_size = sb.size;
60*0Sigor@sysoev.ru     fb = sb.buf;
61*0Sigor@sysoev.ru 
62*0Sigor@sysoev.ru     file_size = nxt_sendbuf_file_coalesce(&sb);
63*0Sigor@sysoev.ru 
64*0Sigor@sysoev.ru     if (file_size == 0) {
65*0Sigor@sysoev.ru         return nxt_event_conn_io_writev(c, hd, nhd);
66*0Sigor@sysoev.ru     }
67*0Sigor@sysoev.ru 
68*0Sigor@sysoev.ru     sb.iobuf = tr;
69*0Sigor@sysoev.ru 
70*0Sigor@sysoev.ru     ntr = nxt_sendbuf_mem_coalesce(&sb);
71*0Sigor@sysoev.ru 
72*0Sigor@sysoev.ru     /*
73*0Sigor@sysoev.ru      * Disposal of surplus kernel operations if there are no headers
74*0Sigor@sysoev.ru      * and trailers.  Besides sendfile() returns EINVAL if a sf_hdtr's
75*0Sigor@sysoev.ru      * count is 0, but corresponding pointer is not NULL.
76*0Sigor@sysoev.ru      */
77*0Sigor@sysoev.ru 
78*0Sigor@sysoev.ru     nxt_memzero(&hdtr, sizeof(struct sf_hdtr));
79*0Sigor@sysoev.ru     ht = NULL;
80*0Sigor@sysoev.ru 
81*0Sigor@sysoev.ru     if (nhd != 0) {
82*0Sigor@sysoev.ru         ht = &hdtr;
83*0Sigor@sysoev.ru         hdtr.headers = hd;
84*0Sigor@sysoev.ru         hdtr.hdr_cnt = nhd;
85*0Sigor@sysoev.ru     }
86*0Sigor@sysoev.ru 
87*0Sigor@sysoev.ru     if (ntr != 0) {
88*0Sigor@sysoev.ru         ht = &hdtr;
89*0Sigor@sysoev.ru         hdtr.trailers = tr;
90*0Sigor@sysoev.ru         hdtr.trl_cnt = ntr;
91*0Sigor@sysoev.ru     }
92*0Sigor@sysoev.ru 
93*0Sigor@sysoev.ru     /*
94*0Sigor@sysoev.ru      * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771).
95*0Sigor@sysoev.ru      * However this bug has never been fixed and instead of this it has been
96*0Sigor@sysoev.ru      * documented as a feature in MacOSX 10.7 (Lion) sendfile(2):
97*0Sigor@sysoev.ru      *
98*0Sigor@sysoev.ru      *   When a header or trailer is specified, the value of len argument
99*0Sigor@sysoev.ru      *   indicates the maximum number of bytes in the header and/or file
100*0Sigor@sysoev.ru      *   to be sent.  It does not control the trailer; if a trailer exists,
101*0Sigor@sysoev.ru      *   all of it will be sent.
102*0Sigor@sysoev.ru      */
103*0Sigor@sysoev.ru     sent = hd_size + file_size;
104*0Sigor@sysoev.ru 
105*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log,
106*0Sigor@sysoev.ru                   "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz",
107*0Sigor@sysoev.ru                   fb->file->fd, c->socket.fd, fb->file_pos, sent,
108*0Sigor@sysoev.ru                   nhd, ntr, hd_size);
109*0Sigor@sysoev.ru 
110*0Sigor@sysoev.ru     n = nxt_sys_sendfile(fb->file->fd, c->socket.fd,
111*0Sigor@sysoev.ru                          fb->file_pos, &sent, ht, 0);
112*0Sigor@sysoev.ru 
113*0Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
114*0Sigor@sysoev.ru 
115*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "sendfile(): %d sent:%O", n, sent);
116*0Sigor@sysoev.ru 
117*0Sigor@sysoev.ru     if (n == -1) {
118*0Sigor@sysoev.ru         switch (err) {
119*0Sigor@sysoev.ru 
120*0Sigor@sysoev.ru         case NXT_EAGAIN:
121*0Sigor@sysoev.ru             c->socket.write_ready = 0;
122*0Sigor@sysoev.ru             break;
123*0Sigor@sysoev.ru 
124*0Sigor@sysoev.ru         case NXT_EINTR:
125*0Sigor@sysoev.ru             break;
126*0Sigor@sysoev.ru 
127*0Sigor@sysoev.ru         default:
128*0Sigor@sysoev.ru             c->socket.error = err;
129*0Sigor@sysoev.ru             nxt_log_error(nxt_socket_error_level(err, c->socket.log_error),
130*0Sigor@sysoev.ru                           c->socket.log, "sendfile(%FD, %d, %O, %O) failed "
131*0Sigor@sysoev.ru                           "%E \"%FN\" hd:%ui tr:%ui", fb->file->fd,
132*0Sigor@sysoev.ru                           c->socket.fd, fb->file_pos, sent, err,
133*0Sigor@sysoev.ru                           fb->file->name, nhd, ntr);
134*0Sigor@sysoev.ru 
135*0Sigor@sysoev.ru             return NXT_ERROR;
136*0Sigor@sysoev.ru         }
137*0Sigor@sysoev.ru 
138*0Sigor@sysoev.ru         nxt_log_debug(c->socket.log, "sendfile() %E", err);
139*0Sigor@sysoev.ru 
140*0Sigor@sysoev.ru         return sent;
141*0Sigor@sysoev.ru     }
142*0Sigor@sysoev.ru 
143*0Sigor@sysoev.ru     if (sent == 0) {
144*0Sigor@sysoev.ru         nxt_log_error(NXT_LOG_ERR, c->socket.log,
145*0Sigor@sysoev.ru                       "file \"%FN\" was truncated while sendfile()",
146*0Sigor@sysoev.ru                       fb->file->name);
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru         return NXT_ERROR;
149*0Sigor@sysoev.ru     }
150*0Sigor@sysoev.ru 
151*0Sigor@sysoev.ru     if (sent < (nxt_off_t) sb.size) {
152*0Sigor@sysoev.ru         c->socket.write_ready = 0;
153*0Sigor@sysoev.ru     }
154*0Sigor@sysoev.ru 
155*0Sigor@sysoev.ru     return sent;
156*0Sigor@sysoev.ru }
157*0Sigor@sysoev.ru 
158*0Sigor@sysoev.ru 
159*0Sigor@sysoev.ru #if 0
160*0Sigor@sysoev.ru 
161*0Sigor@sysoev.ru typedef struct {
162*0Sigor@sysoev.ru     nxt_socket_t  socket;
163*0Sigor@sysoev.ru     nxt_err_t     error;
164*0Sigor@sysoev.ru 
165*0Sigor@sysoev.ru     uint8_t       write_ready;  /* 1 bit */
166*0Sigor@sysoev.ru     uint8_t       log_error;
167*0Sigor@sysoev.ru } nxt_sendbuf_t;
168*0Sigor@sysoev.ru 
169*0Sigor@sysoev.ru 
170*0Sigor@sysoev.ru ssize_t nxt_macosx_sendfile(nxt_thread_t *thr, nxt_sendbuf_t *sb, nxt_buf_t *b,
171*0Sigor@sysoev.ru     size_t limit);
172*0Sigor@sysoev.ru ssize_t nxt_writev(nxt_thread_t *thr, nxt_sendbuf_t *sb, nxt_iobuf_t *iob,
173*0Sigor@sysoev.ru     nxt_uint_t niob);
174*0Sigor@sysoev.ru ssize_t nxt_send(nxt_thread_t *thr, nxt_sendbuf_t *sb, void *buf, size_t size);
175*0Sigor@sysoev.ru 
176*0Sigor@sysoev.ru 
177*0Sigor@sysoev.ru ssize_t
178*0Sigor@sysoev.ru nxt_macosx_sendfile(nxt_thread_t *thr, nxt_sendbuf_t *sb, nxt_buf_t *b,
179*0Sigor@sysoev.ru     size_t limit)
180*0Sigor@sysoev.ru {
181*0Sigor@sysoev.ru     size_t                  hd_size, file_size;
182*0Sigor@sysoev.ru     ssize_t                 n;
183*0Sigor@sysoev.ru     nxt_buf_t               *buf;
184*0Sigor@sysoev.ru     nxt_err_t               err;
185*0Sigor@sysoev.ru     nxt_off_t               sent;
186*0Sigor@sysoev.ru     nxt_uint_t              nhd, ntr;
187*0Sigor@sysoev.ru     struct iovec            hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX];
188*0Sigor@sysoev.ru     struct sf_hdtr          hdtr, *ht;
189*0Sigor@sysoev.ru     nxt_sendbuf_coalesce_t  sbc;
190*0Sigor@sysoev.ru 
191*0Sigor@sysoev.ru     sbc.buf = b;
192*0Sigor@sysoev.ru     sbc.iobuf = hd;
193*0Sigor@sysoev.ru     sbc.nmax = NXT_IOBUF_MAX;
194*0Sigor@sysoev.ru     sbc.sync = 0;
195*0Sigor@sysoev.ru     sbc.size = 0;
196*0Sigor@sysoev.ru     sbc.limit = limit;
197*0Sigor@sysoev.ru 
198*0Sigor@sysoev.ru     nhd = nxt_sendbuf_mem_coalesce(&sbc);
199*0Sigor@sysoev.ru 
200*0Sigor@sysoev.ru     if (nhd == 0 && sbc.sync) {
201*0Sigor@sysoev.ru         return 0;
202*0Sigor@sysoev.ru     }
203*0Sigor@sysoev.ru 
204*0Sigor@sysoev.ru     if (sbc.buf == NULL || !nxt_buf_is_file(sbc.buf)) {
205*0Sigor@sysoev.ru         return nxt_writev(thr, sb, hd, nhd);
206*0Sigor@sysoev.ru     }
207*0Sigor@sysoev.ru 
208*0Sigor@sysoev.ru     hd_size = sbc.size;
209*0Sigor@sysoev.ru     buf = sbc.buf;
210*0Sigor@sysoev.ru 
211*0Sigor@sysoev.ru     file_size = nxt_sendbuf_file_coalesce(&sbc);
212*0Sigor@sysoev.ru 
213*0Sigor@sysoev.ru     if (file_size == 0) {
214*0Sigor@sysoev.ru         return nxt_writev(thr, sb, hd, nhd);
215*0Sigor@sysoev.ru     }
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru     sbc.iobuf = tr;
218*0Sigor@sysoev.ru 
219*0Sigor@sysoev.ru     ntr = nxt_sendbuf_mem_coalesce(&sbc);
220*0Sigor@sysoev.ru 
221*0Sigor@sysoev.ru     /*
222*0Sigor@sysoev.ru      * Disposal of surplus kernel operations if there are no headers
223*0Sigor@sysoev.ru      * and trailers.  Besides sendfile() returns EINVAL if a sf_hdtr's
224*0Sigor@sysoev.ru      * count is 0, but corresponding pointer is not NULL.
225*0Sigor@sysoev.ru      */
226*0Sigor@sysoev.ru 
227*0Sigor@sysoev.ru     nxt_memzero(&hdtr, sizeof(struct sf_hdtr));
228*0Sigor@sysoev.ru     ht = NULL;
229*0Sigor@sysoev.ru 
230*0Sigor@sysoev.ru     if (nhd != 0) {
231*0Sigor@sysoev.ru         ht = &hdtr;
232*0Sigor@sysoev.ru         hdtr.headers = hd;
233*0Sigor@sysoev.ru         hdtr.hdr_cnt = nhd;
234*0Sigor@sysoev.ru     }
235*0Sigor@sysoev.ru 
236*0Sigor@sysoev.ru     if (ntr != 0) {
237*0Sigor@sysoev.ru         ht = &hdtr;
238*0Sigor@sysoev.ru         hdtr.trailers = tr;
239*0Sigor@sysoev.ru         hdtr.trl_cnt = ntr;
240*0Sigor@sysoev.ru     }
241*0Sigor@sysoev.ru 
242*0Sigor@sysoev.ru     /*
243*0Sigor@sysoev.ru      * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771).
244*0Sigor@sysoev.ru      * However this bug has never been fixed and instead of this it has been
245*0Sigor@sysoev.ru      * documented as a feature in MacOSX 10.7 (Lion) sendfile(2):
246*0Sigor@sysoev.ru      *
247*0Sigor@sysoev.ru      *   When a header or trailer is specified, the value of len argument
248*0Sigor@sysoev.ru      *   indicates the maximum number of bytes in the header and/or file
249*0Sigor@sysoev.ru      *   to be sent.  It does not control the trailer; if a trailer exists,
250*0Sigor@sysoev.ru      *   all of it will be sent.
251*0Sigor@sysoev.ru      */
252*0Sigor@sysoev.ru     sent = hd_size + file_size;
253*0Sigor@sysoev.ru 
254*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz",
255*0Sigor@sysoev.ru                   buf->file->fd, sb->socket, buf->file_pos, sent,
256*0Sigor@sysoev.ru                   nhd, ntr, hd_size);
257*0Sigor@sysoev.ru 
258*0Sigor@sysoev.ru     n = nxt_sys_sendfile(buf->file->fd, sb->socket,
259*0Sigor@sysoev.ru                          buf->file_pos, &sent, ht, 0);
260*0Sigor@sysoev.ru 
261*0Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
262*0Sigor@sysoev.ru 
263*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "sendfile(): %d sent:%O", n, sent);
264*0Sigor@sysoev.ru 
265*0Sigor@sysoev.ru     if (n == -1) {
266*0Sigor@sysoev.ru         switch (err) {
267*0Sigor@sysoev.ru 
268*0Sigor@sysoev.ru         case NXT_EAGAIN:
269*0Sigor@sysoev.ru             sb->write_ready = 0;
270*0Sigor@sysoev.ru             break;
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru         case NXT_EINTR:
273*0Sigor@sysoev.ru             break;
274*0Sigor@sysoev.ru 
275*0Sigor@sysoev.ru         default:
276*0Sigor@sysoev.ru             sb->error = err;
277*0Sigor@sysoev.ru             nxt_log_error(nxt_socket_error_level(err, sb->log_error), thr->log,
278*0Sigor@sysoev.ru                           "sendfile(%FD, %d, %O, %O) failed %E \"%FN\" "
279*0Sigor@sysoev.ru                           "hd:%ui tr:%ui", buf->file->fd, sb->socket,
280*0Sigor@sysoev.ru                           buf->file_pos, sent, err, buf->file->name, nhd, ntr);
281*0Sigor@sysoev.ru 
282*0Sigor@sysoev.ru             return NXT_ERROR;
283*0Sigor@sysoev.ru         }
284*0Sigor@sysoev.ru 
285*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "sendfile() %E", err);
286*0Sigor@sysoev.ru 
287*0Sigor@sysoev.ru         return sent;
288*0Sigor@sysoev.ru     }
289*0Sigor@sysoev.ru 
290*0Sigor@sysoev.ru     if (sent == 0) {
291*0Sigor@sysoev.ru         nxt_log_error(NXT_LOG_ERR, thr->log,
292*0Sigor@sysoev.ru                       "file \"%FN\" was truncated while sendfile()",
293*0Sigor@sysoev.ru                       buf->file->name);
294*0Sigor@sysoev.ru 
295*0Sigor@sysoev.ru         return NXT_ERROR;
296*0Sigor@sysoev.ru     }
297*0Sigor@sysoev.ru 
298*0Sigor@sysoev.ru     if (sent < (nxt_off_t) sbc.size) {
299*0Sigor@sysoev.ru         sb->write_ready = 0;
300*0Sigor@sysoev.ru     }
301*0Sigor@sysoev.ru 
302*0Sigor@sysoev.ru     return sent;
303*0Sigor@sysoev.ru }
304*0Sigor@sysoev.ru 
305*0Sigor@sysoev.ru 
306*0Sigor@sysoev.ru ssize_t
307*0Sigor@sysoev.ru nxt_writev(nxt_thread_t *thr, nxt_sendbuf_t *sb, nxt_iobuf_t *iob,
308*0Sigor@sysoev.ru     nxt_uint_t niob)
309*0Sigor@sysoev.ru {
310*0Sigor@sysoev.ru     ssize_t    n;
311*0Sigor@sysoev.ru     nxt_err_t  err;
312*0Sigor@sysoev.ru 
313*0Sigor@sysoev.ru     if (niob == 1) {
314*0Sigor@sysoev.ru         /* Disposal of surplus kernel iovec copy-in operation. */
315*0Sigor@sysoev.ru         return nxt_send(thr, sb, iob->iov_base, iob->iov_len);
316*0Sigor@sysoev.ru     }
317*0Sigor@sysoev.ru 
318*0Sigor@sysoev.ru     for ( ;; ) {
319*0Sigor@sysoev.ru         n = writev(sb->socket, iob, niob);
320*0Sigor@sysoev.ru 
321*0Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
322*0Sigor@sysoev.ru 
323*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "writev(%d, %ui): %d", sb->socket, niob, n);
324*0Sigor@sysoev.ru 
325*0Sigor@sysoev.ru         if (n > 0) {
326*0Sigor@sysoev.ru             return n;
327*0Sigor@sysoev.ru         }
328*0Sigor@sysoev.ru 
329*0Sigor@sysoev.ru         /* n == -1 */
330*0Sigor@sysoev.ru 
331*0Sigor@sysoev.ru         switch (err) {
332*0Sigor@sysoev.ru 
333*0Sigor@sysoev.ru         case NXT_EAGAIN:
334*0Sigor@sysoev.ru             nxt_log_debug(thr->log, "writev() %E", err);
335*0Sigor@sysoev.ru             sb->write_ready = 0;
336*0Sigor@sysoev.ru             return NXT_AGAIN;
337*0Sigor@sysoev.ru 
338*0Sigor@sysoev.ru         case NXT_EINTR:
339*0Sigor@sysoev.ru             nxt_log_debug(thr->log, "writev() %E", err);
340*0Sigor@sysoev.ru             continue;
341*0Sigor@sysoev.ru 
342*0Sigor@sysoev.ru         default:
343*0Sigor@sysoev.ru             sb->error = err;
344*0Sigor@sysoev.ru             nxt_log_error(nxt_socket_error_level(err, sb->log_error), thr->log,
345*0Sigor@sysoev.ru                           "writev(%d, %ui) failed %E", sb->socket, niob, err);
346*0Sigor@sysoev.ru             return NXT_ERROR;
347*0Sigor@sysoev.ru         }
348*0Sigor@sysoev.ru     }
349*0Sigor@sysoev.ru }
350*0Sigor@sysoev.ru 
351*0Sigor@sysoev.ru 
352*0Sigor@sysoev.ru ssize_t
353*0Sigor@sysoev.ru nxt_send(nxt_thread_t *thr, nxt_sendbuf_t *sb, void *buf, size_t size)
354*0Sigor@sysoev.ru {
355*0Sigor@sysoev.ru     ssize_t    n;
356*0Sigor@sysoev.ru     nxt_err_t  err;
357*0Sigor@sysoev.ru 
358*0Sigor@sysoev.ru     for ( ;; ) {
359*0Sigor@sysoev.ru         n = send(sb->socket, buf, size, 0);
360*0Sigor@sysoev.ru 
361*0Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
362*0Sigor@sysoev.ru 
363*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "send(%d, %p, %uz): %z",
364*0Sigor@sysoev.ru                       sb->socket, buf, size, n);
365*0Sigor@sysoev.ru 
366*0Sigor@sysoev.ru         if (n > 0) {
367*0Sigor@sysoev.ru             return n;
368*0Sigor@sysoev.ru         }
369*0Sigor@sysoev.ru 
370*0Sigor@sysoev.ru         /* n == -1 */
371*0Sigor@sysoev.ru 
372*0Sigor@sysoev.ru         switch (err) {
373*0Sigor@sysoev.ru 
374*0Sigor@sysoev.ru         case NXT_EAGAIN:
375*0Sigor@sysoev.ru             nxt_log_debug(thr->log, "send() %E", err);
376*0Sigor@sysoev.ru             sb->write_ready = 0;
377*0Sigor@sysoev.ru             return NXT_AGAIN;
378*0Sigor@sysoev.ru 
379*0Sigor@sysoev.ru         case NXT_EINTR:
380*0Sigor@sysoev.ru             nxt_log_debug(thr->log, "send() %E", err);
381*0Sigor@sysoev.ru             continue;
382*0Sigor@sysoev.ru 
383*0Sigor@sysoev.ru         default:
384*0Sigor@sysoev.ru             sb->error = err;
385*0Sigor@sysoev.ru             nxt_log_error(nxt_socket_error_level(err, sb->log_error), thr->log,
386*0Sigor@sysoev.ru                           "send(%d, %p, %uz) failed %E",
387*0Sigor@sysoev.ru                           sb->socket, buf, size, err);
388*0Sigor@sysoev.ru             return NXT_ERROR;
389*0Sigor@sysoev.ru         }
390*0Sigor@sysoev.ru     }
391*0Sigor@sysoev.ru }
392*0Sigor@sysoev.ru 
393*0Sigor@sysoev.ru #endif
394