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
nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t * c,nxt_buf_t * b,size_t limit)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_debug(c->socket.task, "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_debug(c->socket.task, "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(c->socket.task, nxt_socket_error_level(err),
71 "sendfilev(%d, %D) failed %E", c->socket.fd, nsfv, err);
72
73 return NXT_ERROR;
74 }
75
76 nxt_debug(c->socket.task, "sendfilev() %E", err);
77
78 return sent;
79 }
80
81 if ((nxt_off_t) sent < size) {
82 c->socket.write_ready = 0;
83 }
84
85 return sent;
86 }
87
88
89 static size_t
nxt_solaris_buf_coalesce(nxt_buf_t * b,sendfilevec_t * sfv,int32_t * nsfv,nxt_bool_t * sync,size_t limit)90 nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv,
91 nxt_bool_t *sync, size_t limit)
92 {
93 size_t size, total;
94 nxt_fd_t fd, last_fd;
95 nxt_int_t i;
96 nxt_off_t pos, last_pos;
97
98 i = -1;
99 last_fd = -1;
100 last_pos = 0;
101 total = 0;
102
103 for (total = 0; b != NULL && total < limit; b = b->next) {
104
105 if (nxt_buf_is_file(b)) {
106
107 fd = b->file->fd;
108 pos = b->file_pos;
109 size = b->file_end - pos;
110
111 if (size == 0) {
112 continue;
113 }
114
115 if (total + size > limit) {
116 size = limit - total;
117 }
118
119 } else if (nxt_buf_is_mem(b)) {
120
121 fd = SFV_FD_SELF;
122 pos = (uintptr_t) b->mem.pos;
123 size = b->mem.free - b->mem.pos;
124
125 if (size == 0) {
126 continue;
127 }
128
129 if (total + size > limit) {
130 size = limit - total;
131 }
132
133 } else {
134 *sync = 1;
135 continue;
136 }
137
138 if (size == 0) {
139 break;
140 }
141
142 if (fd != last_fd || pos != last_pos) {
143
144 if (++i >= NXT_IOBUF_MAX) {
145 goto done;
146 }
147
148 sfv[i].sfv_fd = fd;
149 sfv[i].sfv_flag = 0;
150 sfv[i].sfv_off = pos;
151 sfv[i].sfv_len = size;
152
153 } else {
154 sfv[i].sfv_len += size;
155 }
156
157 total += size;
158 last_pos = pos + size;
159 last_fd = fd;
160 }
161
162 i++;
163
164 done:
165
166 *nsfv = i;
167
168 return total;
169 }
170