xref: /unit/src/nxt_conn_write.c (revision 1577:604db78b62f9)
162Sigor@sysoev.ru 
262Sigor@sysoev.ru /*
362Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
462Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
562Sigor@sysoev.ru  */
662Sigor@sysoev.ru 
762Sigor@sysoev.ru #include <nxt_main.h>
862Sigor@sysoev.ru 
962Sigor@sysoev.ru 
1062Sigor@sysoev.ru static void nxt_conn_write_timer_handler(nxt_task_t *task, void *obj,
1162Sigor@sysoev.ru     void *data);
121403Smax.romanov@nginx.com static ssize_t nxt_conn_io_sendfile(nxt_task_t *task, nxt_sendbuf_t *sb);
131403Smax.romanov@nginx.com static ssize_t nxt_sendfile(int fd, int s, off_t pos, size_t size);
1462Sigor@sysoev.ru 
1562Sigor@sysoev.ru 
1662Sigor@sysoev.ru void
nxt_conn_io_write(nxt_task_t * task,void * obj,void * data)1762Sigor@sysoev.ru nxt_conn_io_write(nxt_task_t *task, void *obj, void *data)
1862Sigor@sysoev.ru {
1962Sigor@sysoev.ru     ssize_t             ret;
2062Sigor@sysoev.ru     nxt_buf_t           *b;
2162Sigor@sysoev.ru     nxt_conn_t          *c;
2262Sigor@sysoev.ru     nxt_sendbuf_t       sb;
2362Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2462Sigor@sysoev.ru 
2562Sigor@sysoev.ru     c = obj;
2662Sigor@sysoev.ru 
27979Sigor@sysoev.ru     nxt_debug(task, "conn write fd:%d er:%d bl:%d",
28979Sigor@sysoev.ru               c->socket.fd, c->socket.error, c->block_write);
2962Sigor@sysoev.ru 
30979Sigor@sysoev.ru     if (c->socket.error != 0 || c->block_write) {
31726Sigor@sysoev.ru         goto error;
32726Sigor@sysoev.ru     }
33726Sigor@sysoev.ru 
3462Sigor@sysoev.ru     if (!c->socket.write_ready || c->write == NULL) {
3562Sigor@sysoev.ru         return;
3662Sigor@sysoev.ru     }
3762Sigor@sysoev.ru 
3862Sigor@sysoev.ru     engine = task->thread->engine;
3962Sigor@sysoev.ru 
4062Sigor@sysoev.ru     c->socket.write_handler = nxt_conn_io_write;
4162Sigor@sysoev.ru     c->socket.error_handler = c->write_state->error_handler;
4262Sigor@sysoev.ru 
4362Sigor@sysoev.ru     b = c->write;
4462Sigor@sysoev.ru 
4562Sigor@sysoev.ru     sb.socket = c->socket.fd;
4662Sigor@sysoev.ru     sb.error = 0;
4762Sigor@sysoev.ru     sb.sent = 0;
4862Sigor@sysoev.ru     sb.size = 0;
4962Sigor@sysoev.ru     sb.buf = b;
50771Sigor@sysoev.ru #if (NXT_TLS)
51771Sigor@sysoev.ru     sb.tls = c->u.tls;
52771Sigor@sysoev.ru #endif
5362Sigor@sysoev.ru     sb.limit = 10 * 1024 * 1024;
5462Sigor@sysoev.ru     sb.ready = 1;
5562Sigor@sysoev.ru     sb.sync = 0;
5662Sigor@sysoev.ru 
5762Sigor@sysoev.ru     do {
58771Sigor@sysoev.ru         ret = c->io->sendbuf(task, &sb);
5962Sigor@sysoev.ru 
6062Sigor@sysoev.ru         c->socket.write_ready = sb.ready;
6162Sigor@sysoev.ru         c->socket.error = sb.error;
6262Sigor@sysoev.ru 
6362Sigor@sysoev.ru         if (ret < 0) {
6462Sigor@sysoev.ru             /* ret == NXT_AGAIN || ret == NXT_ERROR. */
6562Sigor@sysoev.ru             break;
6662Sigor@sysoev.ru         }
6762Sigor@sysoev.ru 
6862Sigor@sysoev.ru         sb.sent += ret;
6962Sigor@sysoev.ru         sb.limit -= ret;
7062Sigor@sysoev.ru 
7162Sigor@sysoev.ru         b = nxt_sendbuf_update(b, ret);
7262Sigor@sysoev.ru 
7362Sigor@sysoev.ru         if (b == NULL) {
7462Sigor@sysoev.ru             nxt_fd_event_block_write(engine, &c->socket);
7562Sigor@sysoev.ru             break;
7662Sigor@sysoev.ru         }
7762Sigor@sysoev.ru 
7862Sigor@sysoev.ru         sb.buf = b;
7962Sigor@sysoev.ru 
8062Sigor@sysoev.ru         if (!c->socket.write_ready) {
8162Sigor@sysoev.ru             ret = NXT_AGAIN;
8262Sigor@sysoev.ru             break;
8362Sigor@sysoev.ru         }
8462Sigor@sysoev.ru 
8562Sigor@sysoev.ru     } while (sb.limit != 0);
8662Sigor@sysoev.ru 
87494Spluknet@nginx.com     nxt_debug(task, "event conn: %z sent:%O", ret, sb.sent);
8862Sigor@sysoev.ru 
8962Sigor@sysoev.ru     if (sb.sent != 0) {
9062Sigor@sysoev.ru         if (c->write_state->timer_autoreset) {
9162Sigor@sysoev.ru             nxt_timer_disable(engine, &c->write_timer);
9262Sigor@sysoev.ru         }
9362Sigor@sysoev.ru     }
9462Sigor@sysoev.ru 
9562Sigor@sysoev.ru     if (ret != NXT_ERROR) {
9662Sigor@sysoev.ru 
9762Sigor@sysoev.ru         if (sb.limit == 0) {
9862Sigor@sysoev.ru             /*
9962Sigor@sysoev.ru              * Postpone writing until next event poll to allow to
10062Sigor@sysoev.ru              * process other recevied events and to get new events.
10162Sigor@sysoev.ru              */
10262Sigor@sysoev.ru             c->write_timer.handler = nxt_conn_write_timer_handler;
10362Sigor@sysoev.ru             nxt_timer_add(engine, &c->write_timer, 0);
10462Sigor@sysoev.ru 
10562Sigor@sysoev.ru         } else if (ret == NXT_AGAIN) {
10662Sigor@sysoev.ru             /*
10762Sigor@sysoev.ru              * SSL libraries can require to toggle either write or read
10862Sigor@sysoev.ru              * event if renegotiation occurs during SSL write operation.
109771Sigor@sysoev.ru              * This case is handled on the c->io->send() level.  Timer
11062Sigor@sysoev.ru              * can be set here because it should be set only for write
11162Sigor@sysoev.ru              * direction.
11262Sigor@sysoev.ru              */
11362Sigor@sysoev.ru             nxt_conn_timer(engine, c, c->write_state, &c->write_timer);
11462Sigor@sysoev.ru 
11562Sigor@sysoev.ru             if (nxt_fd_event_is_disabled(c->socket.write)) {
11662Sigor@sysoev.ru                 nxt_fd_event_enable_write(engine, &c->socket);
11762Sigor@sysoev.ru             }
11862Sigor@sysoev.ru         }
11962Sigor@sysoev.ru     }
12062Sigor@sysoev.ru 
12162Sigor@sysoev.ru     if (ret == 0 || sb.sent != 0) {
122726Sigor@sysoev.ru         /*
123726Sigor@sysoev.ru          * ret == 0 means a sync buffer was processed.
124726Sigor@sysoev.ru          * ret == NXT_ERROR is ignored here if some data was sent,
125726Sigor@sysoev.ru          * the error will be handled on the next nxt_conn_write() call.
126726Sigor@sysoev.ru          */
12762Sigor@sysoev.ru         c->sent += sb.sent;
12862Sigor@sysoev.ru         nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler,
12962Sigor@sysoev.ru                            task, c, data);
130726Sigor@sysoev.ru         return;
13162Sigor@sysoev.ru     }
13262Sigor@sysoev.ru 
133792Sigor@sysoev.ru     if (ret != NXT_ERROR) {
134792Sigor@sysoev.ru         return;
135792Sigor@sysoev.ru     }
136726Sigor@sysoev.ru 
137726Sigor@sysoev.ru     nxt_fd_event_block_write(engine, &c->socket);
13862Sigor@sysoev.ru 
139726Sigor@sysoev.ru error:
140726Sigor@sysoev.ru 
141726Sigor@sysoev.ru     nxt_work_queue_add(c->write_work_queue, c->write_state->error_handler,
142726Sigor@sysoev.ru                        task, c, data);
14362Sigor@sysoev.ru }
14462Sigor@sysoev.ru 
14562Sigor@sysoev.ru 
14662Sigor@sysoev.ru static void
nxt_conn_write_timer_handler(nxt_task_t * task,void * obj,void * data)14762Sigor@sysoev.ru nxt_conn_write_timer_handler(nxt_task_t *task, void *obj, void *data)
14862Sigor@sysoev.ru {
14962Sigor@sysoev.ru     nxt_conn_t   *c;
15062Sigor@sysoev.ru     nxt_timer_t  *timer;
15162Sigor@sysoev.ru 
15262Sigor@sysoev.ru     timer = obj;
15362Sigor@sysoev.ru 
154768Svbart@nginx.com     nxt_debug(task, "conn write timer");
15562Sigor@sysoev.ru 
15662Sigor@sysoev.ru     c = nxt_write_timer_conn(timer);
15762Sigor@sysoev.ru     c->delayed = 0;
15862Sigor@sysoev.ru 
15962Sigor@sysoev.ru     c->io->write(task, c, c->socket.data);
16062Sigor@sysoev.ru }
16162Sigor@sysoev.ru 
16262Sigor@sysoev.ru 
16362Sigor@sysoev.ru ssize_t
nxt_conn_io_sendbuf(nxt_task_t * task,nxt_sendbuf_t * sb)16462Sigor@sysoev.ru nxt_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb)
16562Sigor@sysoev.ru {
16662Sigor@sysoev.ru     nxt_uint_t    niov;
16762Sigor@sysoev.ru     struct iovec  iov[NXT_IOBUF_MAX];
16862Sigor@sysoev.ru 
16962Sigor@sysoev.ru     niov = nxt_sendbuf_mem_coalesce0(task, sb, iov, NXT_IOBUF_MAX);
17062Sigor@sysoev.ru 
17162Sigor@sysoev.ru     if (niov == 0 && sb->sync) {
17262Sigor@sysoev.ru         return 0;
17362Sigor@sysoev.ru     }
17462Sigor@sysoev.ru 
1751403Smax.romanov@nginx.com     if (niov == 0 && nxt_buf_is_file(sb->buf)) {
1761403Smax.romanov@nginx.com         return nxt_conn_io_sendfile(task, sb);
1771403Smax.romanov@nginx.com     }
1781403Smax.romanov@nginx.com 
17962Sigor@sysoev.ru     return nxt_conn_io_writev(task, sb, iov, niov);
18062Sigor@sysoev.ru }
18162Sigor@sysoev.ru 
18262Sigor@sysoev.ru 
1831403Smax.romanov@nginx.com static ssize_t
nxt_conn_io_sendfile(nxt_task_t * task,nxt_sendbuf_t * sb)1841403Smax.romanov@nginx.com nxt_conn_io_sendfile(nxt_task_t *task, nxt_sendbuf_t *sb)
1851403Smax.romanov@nginx.com {
1861403Smax.romanov@nginx.com     size_t     size;
1871403Smax.romanov@nginx.com     ssize_t    n;
1881403Smax.romanov@nginx.com     nxt_buf_t  *b;
1891403Smax.romanov@nginx.com     nxt_err_t  err;
1901403Smax.romanov@nginx.com 
1911403Smax.romanov@nginx.com     b = sb->buf;
1921403Smax.romanov@nginx.com 
1931403Smax.romanov@nginx.com     for ( ;; ) {
1941403Smax.romanov@nginx.com         size = b->file_end - b->file_pos;
1951403Smax.romanov@nginx.com 
1961403Smax.romanov@nginx.com         n = nxt_sendfile(b->file->fd, sb->socket, b->file_pos, size);
1971403Smax.romanov@nginx.com 
1981403Smax.romanov@nginx.com         err = (n == -1) ? nxt_errno : 0;
1991403Smax.romanov@nginx.com 
2001403Smax.romanov@nginx.com         nxt_debug(task, "sendfile(%FD, %d, @%O, %uz): %z",
2011403Smax.romanov@nginx.com                   b->file->fd, sb->socket, b->file_pos, size, n);
2021403Smax.romanov@nginx.com 
2031403Smax.romanov@nginx.com         if (n > 0) {
2041403Smax.romanov@nginx.com             if (n < (ssize_t) size) {
2051403Smax.romanov@nginx.com                 sb->ready = 0;
2061403Smax.romanov@nginx.com             }
2071403Smax.romanov@nginx.com 
2081403Smax.romanov@nginx.com             return n;
2091403Smax.romanov@nginx.com         }
2101403Smax.romanov@nginx.com 
2111403Smax.romanov@nginx.com         if (nxt_slow_path(n == 0)) {
2121403Smax.romanov@nginx.com             nxt_alert(task, "sendfile() reported that file was truncated at %O",
2131403Smax.romanov@nginx.com                       b->file_pos);
2141403Smax.romanov@nginx.com 
2151403Smax.romanov@nginx.com             return NXT_ERROR;
2161403Smax.romanov@nginx.com         }
2171403Smax.romanov@nginx.com 
2181403Smax.romanov@nginx.com         /* n == -1 */
2191403Smax.romanov@nginx.com 
2201403Smax.romanov@nginx.com         switch (err) {
2211403Smax.romanov@nginx.com 
2221403Smax.romanov@nginx.com         case NXT_EAGAIN:
2231403Smax.romanov@nginx.com             sb->ready = 0;
2241403Smax.romanov@nginx.com             nxt_debug(task, "sendfile() %E", err);
2251403Smax.romanov@nginx.com 
2261403Smax.romanov@nginx.com             return NXT_AGAIN;
2271403Smax.romanov@nginx.com 
2281403Smax.romanov@nginx.com         case NXT_EINTR:
2291403Smax.romanov@nginx.com             nxt_debug(task, "sendfile() %E", err);
2301403Smax.romanov@nginx.com             continue;
2311403Smax.romanov@nginx.com 
2321403Smax.romanov@nginx.com         default:
2331403Smax.romanov@nginx.com             sb->error = err;
2341403Smax.romanov@nginx.com             nxt_log(task, nxt_socket_error_level(err),
2351403Smax.romanov@nginx.com                     "sendfile(%FD, %d, @%O, %uz) failed %E",
2361403Smax.romanov@nginx.com                     b->file->fd, sb->socket, b->file_pos, size, err);
2371403Smax.romanov@nginx.com 
2381403Smax.romanov@nginx.com             return NXT_ERROR;
2391403Smax.romanov@nginx.com         }
2401403Smax.romanov@nginx.com     }
2411403Smax.romanov@nginx.com }
2421403Smax.romanov@nginx.com 
2431403Smax.romanov@nginx.com 
2441403Smax.romanov@nginx.com static ssize_t
nxt_sendfile(int fd,int s,off_t pos,size_t size)2451403Smax.romanov@nginx.com nxt_sendfile(int fd, int s, off_t pos, size_t size)
2461403Smax.romanov@nginx.com {
2471403Smax.romanov@nginx.com     ssize_t  res;
2481403Smax.romanov@nginx.com 
2491576Smax.romanov@nginx.com #if (NXT_HAVE_MACOSX_SENDFILE)
2501576Smax.romanov@nginx.com 
2511403Smax.romanov@nginx.com     off_t sent = size;
2521403Smax.romanov@nginx.com 
2531403Smax.romanov@nginx.com     int rc = sendfile(fd, s, pos, &sent, NULL, 0);
2541403Smax.romanov@nginx.com 
2551403Smax.romanov@nginx.com     res = (rc == 0 || sent > 0) ? sent : -1;
2561403Smax.romanov@nginx.com 
2571576Smax.romanov@nginx.com #elif (NXT_HAVE_FREEBSD_SENDFILE)
2581576Smax.romanov@nginx.com 
2591403Smax.romanov@nginx.com     off_t sent = 0;
2601403Smax.romanov@nginx.com 
2611403Smax.romanov@nginx.com     int rc = sendfile(fd, s, pos, size, NULL, &sent, 0);
2621403Smax.romanov@nginx.com 
2631403Smax.romanov@nginx.com     res = (rc == 0 || sent > 0) ? sent : -1;
2641576Smax.romanov@nginx.com 
2651576Smax.romanov@nginx.com #elif (NXT_HAVE_LINUX_SENDFILE)
2661576Smax.romanov@nginx.com 
2671576Smax.romanov@nginx.com     res = sendfile(s, fd, &pos, size);
2681403Smax.romanov@nginx.com 
2691576Smax.romanov@nginx.com #else
2701576Smax.romanov@nginx.com 
271*1577Smax.romanov@nginx.com     int    err;
272*1577Smax.romanov@nginx.com     void   *map;
273*1577Smax.romanov@nginx.com     off_t  page_off;
274*1577Smax.romanov@nginx.com 
275*1577Smax.romanov@nginx.com     page_off = pos % nxt_pagesize;
276*1577Smax.romanov@nginx.com 
277*1577Smax.romanov@nginx.com     map = nxt_mem_mmap(NULL, size + page_off, PROT_READ, MAP_SHARED, fd,
278*1577Smax.romanov@nginx.com                        pos - page_off);
279*1577Smax.romanov@nginx.com     if (nxt_slow_path(map == MAP_FAILED)) {
280*1577Smax.romanov@nginx.com         return -1;
281*1577Smax.romanov@nginx.com     }
282*1577Smax.romanov@nginx.com 
283*1577Smax.romanov@nginx.com     res = write(s, nxt_pointer_to(map, page_off), size);
284*1577Smax.romanov@nginx.com 
285*1577Smax.romanov@nginx.com     /* Backup and restore errno to catch socket errors in the upper level. */
286*1577Smax.romanov@nginx.com     err = errno;
287*1577Smax.romanov@nginx.com     nxt_mem_munmap(map, size + page_off);
288*1577Smax.romanov@nginx.com     errno = err;
2891576Smax.romanov@nginx.com 
2901403Smax.romanov@nginx.com #endif
2911403Smax.romanov@nginx.com 
2921403Smax.romanov@nginx.com     return res;
2931403Smax.romanov@nginx.com }
2941403Smax.romanov@nginx.com 
2951403Smax.romanov@nginx.com 
29662Sigor@sysoev.ru ssize_t
nxt_conn_io_writev(nxt_task_t * task,nxt_sendbuf_t * sb,struct iovec * iov,nxt_uint_t niov)29762Sigor@sysoev.ru nxt_conn_io_writev(nxt_task_t *task, nxt_sendbuf_t *sb, struct iovec *iov,
29862Sigor@sysoev.ru     nxt_uint_t niov)
29962Sigor@sysoev.ru {
30062Sigor@sysoev.ru     ssize_t    n;
30162Sigor@sysoev.ru     nxt_err_t  err;
30262Sigor@sysoev.ru 
30362Sigor@sysoev.ru     if (niov == 1) {
30462Sigor@sysoev.ru         /* Disposal of surplus kernel iovec copy-in operation. */
30562Sigor@sysoev.ru         return nxt_conn_io_send(task, sb, iov[0].iov_base, iov[0].iov_len);
30662Sigor@sysoev.ru     }
30762Sigor@sysoev.ru 
30862Sigor@sysoev.ru     for ( ;; ) {
30962Sigor@sysoev.ru         n = writev(sb->socket, iov, niov);
31062Sigor@sysoev.ru 
31162Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
31262Sigor@sysoev.ru 
313494Spluknet@nginx.com         nxt_debug(task, "writev(%d, %ui): %z", sb->socket, niov, n);
31462Sigor@sysoev.ru 
31562Sigor@sysoev.ru         if (n > 0) {
31662Sigor@sysoev.ru             return n;
31762Sigor@sysoev.ru         }
31862Sigor@sysoev.ru 
31962Sigor@sysoev.ru         /* n == -1 */
32062Sigor@sysoev.ru 
32162Sigor@sysoev.ru         switch (err) {
32262Sigor@sysoev.ru 
32362Sigor@sysoev.ru         case NXT_EAGAIN:
32462Sigor@sysoev.ru             sb->ready = 0;
32562Sigor@sysoev.ru             nxt_debug(task, "writev() %E", err);
32662Sigor@sysoev.ru 
32762Sigor@sysoev.ru             return NXT_AGAIN;
32862Sigor@sysoev.ru 
32962Sigor@sysoev.ru         case NXT_EINTR:
33062Sigor@sysoev.ru             nxt_debug(task, "writev() %E", err);
33162Sigor@sysoev.ru             continue;
33262Sigor@sysoev.ru 
33362Sigor@sysoev.ru         default:
33462Sigor@sysoev.ru             sb->error = err;
33562Sigor@sysoev.ru             nxt_log(task, nxt_socket_error_level(err),
33662Sigor@sysoev.ru                     "writev(%d, %ui) failed %E", sb->socket, niov, err);
33762Sigor@sysoev.ru 
33862Sigor@sysoev.ru             return NXT_ERROR;
33962Sigor@sysoev.ru         }
34062Sigor@sysoev.ru     }
34162Sigor@sysoev.ru }
34262Sigor@sysoev.ru 
34362Sigor@sysoev.ru 
34462Sigor@sysoev.ru ssize_t
nxt_conn_io_send(nxt_task_t * task,nxt_sendbuf_t * sb,void * buf,size_t size)34562Sigor@sysoev.ru nxt_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, size_t size)
34662Sigor@sysoev.ru {
34762Sigor@sysoev.ru     ssize_t    n;
34862Sigor@sysoev.ru     nxt_err_t  err;
34962Sigor@sysoev.ru 
35062Sigor@sysoev.ru     for ( ;; ) {
35162Sigor@sysoev.ru         n = send(sb->socket, buf, size, 0);
35262Sigor@sysoev.ru 
35362Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
35462Sigor@sysoev.ru 
35562Sigor@sysoev.ru         nxt_debug(task, "send(%d, %p, %uz): %z", sb->socket, buf, size, n);
35662Sigor@sysoev.ru 
35762Sigor@sysoev.ru         if (n > 0) {
35862Sigor@sysoev.ru             return n;
35962Sigor@sysoev.ru         }
36062Sigor@sysoev.ru 
36162Sigor@sysoev.ru         /* n == -1 */
36262Sigor@sysoev.ru 
36362Sigor@sysoev.ru         switch (err) {
36462Sigor@sysoev.ru 
36562Sigor@sysoev.ru         case NXT_EAGAIN:
36662Sigor@sysoev.ru             sb->ready = 0;
36762Sigor@sysoev.ru             nxt_debug(task, "send() %E", err);
36862Sigor@sysoev.ru 
36962Sigor@sysoev.ru             return NXT_AGAIN;
37062Sigor@sysoev.ru 
37162Sigor@sysoev.ru         case NXT_EINTR:
37262Sigor@sysoev.ru             nxt_debug(task, "send() %E", err);
37362Sigor@sysoev.ru             continue;
37462Sigor@sysoev.ru 
37562Sigor@sysoev.ru         default:
37662Sigor@sysoev.ru             sb->error = err;
37762Sigor@sysoev.ru             nxt_log(task, nxt_socket_error_level(err),
37862Sigor@sysoev.ru                     "send(%d, %p, %uz) failed %E", sb->socket, buf, size, err);
37962Sigor@sysoev.ru 
38062Sigor@sysoev.ru             return NXT_ERROR;
38162Sigor@sysoev.ru         }
38262Sigor@sysoev.ru     }
38362Sigor@sysoev.ru }
38462Sigor@sysoev.ru 
38562Sigor@sysoev.ru 
38662Sigor@sysoev.ru /* Obsolete interfaces. */
38762Sigor@sysoev.ru 
38862Sigor@sysoev.ru size_t
nxt_event_conn_write_limit(nxt_conn_t * c)38962Sigor@sysoev.ru nxt_event_conn_write_limit(nxt_conn_t *c)
39062Sigor@sysoev.ru {
39162Sigor@sysoev.ru     ssize_t                 limit, correction;
39262Sigor@sysoev.ru     nxt_event_write_rate_t  *rate;
39362Sigor@sysoev.ru 
39462Sigor@sysoev.ru     rate = c->rate;
39562Sigor@sysoev.ru 
39662Sigor@sysoev.ru     if (rate == NULL) {
39762Sigor@sysoev.ru         return c->max_chunk;
39862Sigor@sysoev.ru     }
39962Sigor@sysoev.ru 
40062Sigor@sysoev.ru     limit = rate->limit;
40162Sigor@sysoev.ru     correction = limit - (size_t) rate->average;
40262Sigor@sysoev.ru 
40362Sigor@sysoev.ru     nxt_debug(c->socket.task, "event conn correction:%z average:%0.3f",
40462Sigor@sysoev.ru               correction, rate->average);
40562Sigor@sysoev.ru 
40662Sigor@sysoev.ru     limit += correction;
40762Sigor@sysoev.ru 
40862Sigor@sysoev.ru     if (limit <= 0) {
40962Sigor@sysoev.ru         return 0;
41062Sigor@sysoev.ru     }
41162Sigor@sysoev.ru 
41262Sigor@sysoev.ru     if (rate->limit_after != 0) {
41362Sigor@sysoev.ru         limit += rate->limit_after;
41462Sigor@sysoev.ru         limit = nxt_min((size_t) limit, rate->max_limit);
41562Sigor@sysoev.ru     }
41662Sigor@sysoev.ru 
41762Sigor@sysoev.ru     return nxt_min((size_t) limit, c->max_chunk);
41862Sigor@sysoev.ru }
41962Sigor@sysoev.ru 
42062Sigor@sysoev.ru 
42162Sigor@sysoev.ru nxt_bool_t
nxt_event_conn_write_delayed(nxt_event_engine_t * engine,nxt_conn_t * c,size_t sent)42262Sigor@sysoev.ru nxt_event_conn_write_delayed(nxt_event_engine_t *engine, nxt_conn_t *c,
42362Sigor@sysoev.ru     size_t sent)
42462Sigor@sysoev.ru {
42562Sigor@sysoev.ru     return 0;
42662Sigor@sysoev.ru }
42762Sigor@sysoev.ru 
42862Sigor@sysoev.ru 
42962Sigor@sysoev.ru ssize_t
nxt_event_conn_io_sendbuf(nxt_conn_t * c,nxt_buf_t * b,size_t limit)43062Sigor@sysoev.ru nxt_event_conn_io_sendbuf(nxt_conn_t *c, nxt_buf_t *b, size_t limit)
43162Sigor@sysoev.ru {
43262Sigor@sysoev.ru     nxt_uint_t              niob;
43362Sigor@sysoev.ru     struct iovec            iob[NXT_IOBUF_MAX];
43462Sigor@sysoev.ru     nxt_sendbuf_coalesce_t  sb;
43562Sigor@sysoev.ru 
43662Sigor@sysoev.ru     sb.buf = b;
43762Sigor@sysoev.ru     sb.iobuf = iob;
43862Sigor@sysoev.ru     sb.nmax = NXT_IOBUF_MAX;
43962Sigor@sysoev.ru     sb.sync = 0;
44062Sigor@sysoev.ru     sb.size = 0;
44162Sigor@sysoev.ru     sb.limit = limit;
44262Sigor@sysoev.ru 
44362Sigor@sysoev.ru     niob = nxt_sendbuf_mem_coalesce(c->socket.task, &sb);
44462Sigor@sysoev.ru 
44562Sigor@sysoev.ru     if (niob == 0 && sb.sync) {
44662Sigor@sysoev.ru         return 0;
44762Sigor@sysoev.ru     }
44862Sigor@sysoev.ru 
44962Sigor@sysoev.ru     return nxt_event_conn_io_writev(c, iob, niob);
45062Sigor@sysoev.ru }
45162Sigor@sysoev.ru 
45262Sigor@sysoev.ru 
45362Sigor@sysoev.ru ssize_t
nxt_event_conn_io_writev(nxt_conn_t * c,nxt_iobuf_t * iob,nxt_uint_t niob)45462Sigor@sysoev.ru nxt_event_conn_io_writev(nxt_conn_t *c, nxt_iobuf_t *iob, nxt_uint_t niob)
45562Sigor@sysoev.ru {
45662Sigor@sysoev.ru     ssize_t    n;
45762Sigor@sysoev.ru     nxt_err_t  err;
45862Sigor@sysoev.ru 
45962Sigor@sysoev.ru     if (niob == 1) {
46062Sigor@sysoev.ru         /* Disposal of surplus kernel iovec copy-in operation. */
46162Sigor@sysoev.ru         return nxt_event_conn_io_send(c, iob->iov_base, iob->iov_len);
46262Sigor@sysoev.ru     }
46362Sigor@sysoev.ru 
46462Sigor@sysoev.ru     for ( ;; ) {
46562Sigor@sysoev.ru         n = writev(c->socket.fd, iob, niob);
46662Sigor@sysoev.ru 
46762Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
46862Sigor@sysoev.ru 
469494Spluknet@nginx.com         nxt_debug(c->socket.task, "writev(%d, %ui): %z", c->socket.fd, niob, n);
47062Sigor@sysoev.ru 
47162Sigor@sysoev.ru         if (n > 0) {
47262Sigor@sysoev.ru             return n;
47362Sigor@sysoev.ru         }
47462Sigor@sysoev.ru 
47562Sigor@sysoev.ru         /* n == -1 */
47662Sigor@sysoev.ru 
47762Sigor@sysoev.ru         switch (err) {
47862Sigor@sysoev.ru 
47962Sigor@sysoev.ru         case NXT_EAGAIN:
48062Sigor@sysoev.ru             nxt_debug(c->socket.task, "writev() %E", err);
48162Sigor@sysoev.ru             c->socket.write_ready = 0;
48262Sigor@sysoev.ru             return NXT_AGAIN;
48362Sigor@sysoev.ru 
48462Sigor@sysoev.ru         case NXT_EINTR:
48562Sigor@sysoev.ru             nxt_debug(c->socket.task, "writev() %E", err);
48662Sigor@sysoev.ru             continue;
48762Sigor@sysoev.ru 
48862Sigor@sysoev.ru         default:
48962Sigor@sysoev.ru             c->socket.error = err;
49062Sigor@sysoev.ru             nxt_log(c->socket.task, nxt_socket_error_level(err),
49162Sigor@sysoev.ru                     "writev(%d, %ui) failed %E", c->socket.fd, niob, err);
49262Sigor@sysoev.ru             return NXT_ERROR;
49362Sigor@sysoev.ru         }
49462Sigor@sysoev.ru     }
49562Sigor@sysoev.ru }
49662Sigor@sysoev.ru 
49762Sigor@sysoev.ru 
49862Sigor@sysoev.ru ssize_t
nxt_event_conn_io_send(nxt_conn_t * c,void * buf,size_t size)49962Sigor@sysoev.ru nxt_event_conn_io_send(nxt_conn_t *c, void *buf, size_t size)
50062Sigor@sysoev.ru {
50162Sigor@sysoev.ru     ssize_t    n;
50262Sigor@sysoev.ru     nxt_err_t  err;
50362Sigor@sysoev.ru 
50462Sigor@sysoev.ru     for ( ;; ) {
50562Sigor@sysoev.ru         n = send(c->socket.fd, buf, size, 0);
50662Sigor@sysoev.ru 
50762Sigor@sysoev.ru         err = (n == -1) ? nxt_socket_errno : 0;
50862Sigor@sysoev.ru 
50962Sigor@sysoev.ru         nxt_debug(c->socket.task, "send(%d, %p, %uz): %z",
51062Sigor@sysoev.ru                   c->socket.fd, buf, size, n);
51162Sigor@sysoev.ru 
51262Sigor@sysoev.ru         if (n > 0) {
51362Sigor@sysoev.ru             return n;
51462Sigor@sysoev.ru         }
51562Sigor@sysoev.ru 
51662Sigor@sysoev.ru         /* n == -1 */
51762Sigor@sysoev.ru 
51862Sigor@sysoev.ru         switch (err) {
51962Sigor@sysoev.ru 
52062Sigor@sysoev.ru         case NXT_EAGAIN:
52162Sigor@sysoev.ru             nxt_debug(c->socket.task, "send() %E", err);
52262Sigor@sysoev.ru             c->socket.write_ready = 0;
52362Sigor@sysoev.ru             return NXT_AGAIN;
52462Sigor@sysoev.ru 
52562Sigor@sysoev.ru         case NXT_EINTR:
52662Sigor@sysoev.ru             nxt_debug(c->socket.task, "send() %E", err);
52762Sigor@sysoev.ru             continue;
52862Sigor@sysoev.ru 
52962Sigor@sysoev.ru         default:
53062Sigor@sysoev.ru             c->socket.error = err;
53162Sigor@sysoev.ru             nxt_log(c->socket.task, nxt_socket_error_level(err),
53262Sigor@sysoev.ru                     "send(%d, %p, %uz) failed %E",
53362Sigor@sysoev.ru                     c->socket.fd, buf, size, err);
53462Sigor@sysoev.ru             return NXT_ERROR;
53562Sigor@sysoev.ru         }
53662Sigor@sysoev.ru     }
53762Sigor@sysoev.ru }
538