1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 /* 11 * sendfilev() has been introduced in Solaris 8 (7/01). 12 * According to sendfilev(3EXT) it can write to: 13 * 14 * a file descriptor to a regular file or to a AF_NCA, AF_INET, or 15 * AF_INET6 family type SOCK_STREAM socket that is open for writing. 16 */ 17 18 ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, 19 size_t limit); 20 static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, 21 int32_t *nsfv, nxt_bool_t *sync, size_t limit); 22 23 24 ssize_t 25 nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, 26 size_t limit) 27 { 28 size_t sent; 29 ssize_t n; 30 int32_t nsfv; 31 nxt_err_t err; 32 nxt_off_t size; 33 nxt_bool_t sync; 34 sendfilevec_t sfv[NXT_IOBUF_MAX]; 35 36 if (c->sendfile == 0) { 37 /* AF_UNIX does not support sendfilev(). */ 38 return nxt_event_conn_io_sendbuf(c, b, limit); 39 } 40 41 sync = 0; 42 43 size = nxt_solaris_buf_coalesce(b, sfv, &nsfv, &sync, limit); 44 45 nxt_log_debug(c->socket.log, "sendfilev(%d, %D)", c->socket.fd, nsfv); 46 47 if (nsfv == 0 && sync) { 48 return 0; 49 } 50 51 sent = 0; 52 n = sendfilev(c->socket.fd, sfv, nsfv, &sent); 53 54 err = (n == -1) ? nxt_errno : 0; 55 56 nxt_log_debug(c->socket.log, "sendfilev(): %d sent:%uz", n, sent); 57 58 if (n == -1) { 59 switch (err) { 60 61 case NXT_EAGAIN: 62 c->socket.write_ready = 0; 63 break; 64 65 case NXT_EINTR: 66 break; 67 68 default: 69 c->socket.error = err; 70 nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), 71 c->socket.log, "sendfilev(%d, %D) failed %E", 72 c->socket.fd, nsfv, err); 73 74 return NXT_ERROR; 75 } 76 77 nxt_log_debug(c->socket.log, "sendfilev() %E", err); 78 79 return sent; 80 } 81 82 if ((nxt_off_t) sent < size) { 83 c->socket.write_ready = 0; 84 } 85 86 return sent; 87 } 88 89 90 static size_t 91 nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, 92 nxt_bool_t *sync, size_t limit) 93 { 94 size_t size, total; 95 nxt_fd_t fd, last_fd; 96 nxt_int_t i; 97 nxt_off_t pos, last_pos; 98 99 i = -1; 100 last_fd = -1; 101 last_pos = 0; 102 total = 0; 103 104 for (total = 0; b != NULL && total < limit; b = b->next) { 105 106 if (nxt_buf_is_file(b)) { 107 108 fd = b->file->fd; 109 pos = b->file_pos; 110 size = b->file_end - pos; 111 112 if (size == 0) { 113 continue; 114 } 115 116 if (total + size > limit) { 117 size = limit - total; 118 } 119 120 } else if (nxt_buf_is_mem(b)) { 121 122 fd = SFV_FD_SELF; 123 pos = (uintptr_t) b->mem.pos; 124 size = b->mem.free - b->mem.pos; 125 126 if (size == 0) { 127 continue; 128 } 129 130 if (total + size > limit) { 131 size = limit - total; 132 } 133 134 } else { 135 *sync = 1; 136 continue; 137 } 138 139 if (size == 0) { 140 break; 141 } 142 143 if (fd != last_fd || pos != last_pos) { 144 145 if (++i >= NXT_IOBUF_MAX) { 146 goto done; 147 } 148 149 sfv[i].sfv_fd = fd; 150 sfv[i].sfv_flag = 0; 151 sfv[i].sfv_off = pos; 152 sfv[i].sfv_len = size; 153 154 } else { 155 sfv[i].sfv_len += size; 156 } 157 158 total += size; 159 last_pos = pos + size; 160 last_fd = fd; 161 } 162 163 i++; 164 165 done: 166 167 *nsfv = i; 168 169 return total; 170 } 171