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