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