xref: /unit/src/nxt_solaris_sendfilev.c (revision 0:a63ceefd6ab0)
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