/* * Copyright (C) Igor Sysoev * Copyright (C) NGINX, Inc. */ #include /* * sendfilev() has been introduced in Solaris 8 (7/01). * According to sendfilev(3EXT) it can write to: * * a file descriptor to a regular file or to a AF_NCA, AF_INET, or * AF_INET6 family type SOCK_STREAM socket that is open for writing. */ ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, nxt_bool_t *sync, size_t limit); ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit) { size_t sent; ssize_t n; int32_t nsfv; nxt_err_t err; nxt_off_t size; nxt_bool_t sync; sendfilevec_t sfv[NXT_IOBUF_MAX]; if (c->sendfile == 0) { /* AF_UNIX does not support sendfilev(). */ return nxt_event_conn_io_sendbuf(c, b, limit); } sync = 0; size = nxt_solaris_buf_coalesce(b, sfv, &nsfv, &sync, limit); nxt_debug(c->socket.task, "sendfilev(%d, %D)", c->socket.fd, nsfv); if (nsfv == 0 && sync) { return 0; } sent = 0; n = sendfilev(c->socket.fd, sfv, nsfv, &sent); err = (n == -1) ? nxt_errno : 0; nxt_debug(c->socket.task, "sendfilev(): %d sent:%uz", n, sent); if (n == -1) { switch (err) { case NXT_EAGAIN: c->socket.write_ready = 0; break; case NXT_EINTR: break; default: c->socket.error = err; nxt_log(c->socket.task, nxt_socket_error_level(err), "sendfilev(%d, %D) failed %E", c->socket.fd, nsfv, err); return NXT_ERROR; } nxt_debug(c->socket.task, "sendfilev() %E", err); return sent; } if ((nxt_off_t) sent < size) { c->socket.write_ready = 0; } return sent; } static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, nxt_bool_t *sync, size_t limit) { size_t size, total; nxt_fd_t fd, last_fd; nxt_int_t i; nxt_off_t pos, last_pos; i = -1; last_fd = -1; last_pos = 0; total = 0; for (total = 0; b != NULL && total < limit; b = b->next) { if (nxt_buf_is_file(b)) { fd = b->file->fd; pos = b->file_pos; size = b->file_end - pos; if (size == 0) { continue; } if (total + size > limit) { size = limit - total; } } else if (nxt_buf_is_mem(b)) { fd = SFV_FD_SELF; pos = (uintptr_t) b->mem.pos; size = b->mem.free - b->mem.pos; if (size == 0) { continue; } if (total + size > limit) { size = limit - total; } } else { *sync = 1; continue; } if (size == 0) { break; } if (fd != last_fd || pos != last_pos) { if (++i >= NXT_IOBUF_MAX) { goto done; } sfv[i].sfv_fd = fd; sfv[i].sfv_flag = 0; sfv[i].sfv_off = pos; sfv[i].sfv_len = size; } else { sfv[i].sfv_len += size; } total += size; last_pos = pos + size; last_fd = fd; } i++; done: *nsfv = i; return total; }