python/samba: Another object.next() to next(object) py2/py3 converstion
[Samba.git] / source3 / lib / sendfile.c
blob3d457bd6f132c416350f82535730b3dc6c4f26a0
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.2.x / 3.0.x
4 sendfile implementations.
5 Copyright (C) Jeremy Allison 2002.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * This file handles the OS dependent sendfile implementations.
22 * The API is such that it returns -1 on error, else returns the
23 * number of bytes written.
26 #include "includes.h"
28 #if defined(LINUX_SENDFILE_API)
30 #include <sys/sendfile.h>
32 #ifndef MSG_MORE
33 #define MSG_MORE 0x8000
34 #endif
36 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
38 size_t total=0;
39 ssize_t ret;
40 size_t hdr_len = 0;
43 * Send the header first.
44 * Use MSG_MORE to cork the TCP output until sendfile is called.
47 if (header) {
48 hdr_len = header->length;
49 while (total < hdr_len) {
50 ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
51 if (ret == -1)
52 return -1;
53 total += ret;
57 total = count;
58 while (total) {
59 ssize_t nwritten;
60 do {
61 nwritten = sendfile(tofd, fromfd, &offset, total);
62 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
63 if (nwritten == -1) {
64 if (errno == ENOSYS || errno == EINVAL) {
65 /* Ok - we're in a world of pain here. We just sent
66 * the header, but the sendfile failed. We have to
67 * emulate the sendfile at an upper layer before we
68 * disable it's use. So we do something really ugly.
69 * We set the errno to a strange value so we can detect
70 * this at the upper level and take care of it without
71 * layer violation. JRA.
73 errno = EINTR; /* Normally we can never return this. */
75 return -1;
77 if (nwritten == 0) {
79 * EOF, return a short read
81 return hdr_len + (count - total);
83 total -= nwritten;
85 return count + hdr_len;
88 #elif defined(SOLARIS_SENDFILE_API)
91 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
94 #include <sys/sendfile.h>
96 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
98 int sfvcnt;
99 size_t total, xferred;
100 struct sendfilevec vec[2];
101 ssize_t hdr_len = 0;
103 if (header) {
104 sfvcnt = 2;
106 vec[0].sfv_fd = SFV_FD_SELF;
107 vec[0].sfv_flag = 0;
108 vec[0].sfv_off = (off_t)header->data;
109 vec[0].sfv_len = hdr_len = header->length;
111 vec[1].sfv_fd = fromfd;
112 vec[1].sfv_flag = 0;
113 vec[1].sfv_off = offset;
114 vec[1].sfv_len = count;
116 } else {
117 sfvcnt = 1;
119 vec[0].sfv_fd = fromfd;
120 vec[0].sfv_flag = 0;
121 vec[0].sfv_off = offset;
122 vec[0].sfv_len = count;
125 total = count + hdr_len;
127 while (total) {
128 ssize_t nwritten;
131 * Although not listed in the API error returns, this is almost certainly
132 * a slow system call and will be interrupted by a signal with EINTR. JRA.
135 xferred = 0;
137 nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
138 if (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
139 if (xferred == 0)
140 continue; /* Nothing written yet. */
141 else
142 nwritten = xferred;
145 if (nwritten == -1)
146 return -1;
147 if (nwritten == 0)
148 return -1; /* I think we're at EOF here... */
151 * If this was a short (signal interrupted) write we may need
152 * to subtract it from the header data, or null out the header
153 * data altogether if we wrote more than vec[0].sfv_len bytes.
154 * We move vec[1].* to vec[0].* and set sfvcnt to 1
157 if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
158 vec[1].sfv_off += nwritten - vec[0].sfv_len;
159 vec[1].sfv_len -= nwritten - vec[0].sfv_len;
161 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
162 vec[0] = vec[1];
163 sfvcnt = 1;
164 } else {
165 vec[0].sfv_off += nwritten;
166 vec[0].sfv_len -= nwritten;
168 total -= nwritten;
170 return count + hdr_len;
173 #elif defined(HPUX_SENDFILE_API)
175 #include <sys/socket.h>
176 #include <sys/uio.h>
178 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
180 size_t total=0;
181 struct iovec hdtrl[2];
182 size_t hdr_len = 0;
184 if (header) {
185 /* Set up the header/trailer iovec. */
186 hdtrl[0].iov_base = (void *)header->data;
187 hdtrl[0].iov_len = hdr_len = header->length;
188 } else {
189 hdtrl[0].iov_base = NULL;
190 hdtrl[0].iov_len = hdr_len = 0;
192 hdtrl[1].iov_base = NULL;
193 hdtrl[1].iov_len = 0;
195 total = count;
196 while (total + hdtrl[0].iov_len) {
197 ssize_t nwritten;
200 * HPUX guarantees that if any data was written before
201 * a signal interrupt then sendfile returns the number of
202 * bytes written (which may be less than requested) not -1.
203 * nwritten includes the header data sent.
206 do {
207 nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
208 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
209 if (nwritten == -1)
210 return -1;
211 if (nwritten == 0)
212 return -1; /* I think we're at EOF here... */
215 * If this was a short (signal interrupted) write we may need
216 * to subtract it from the header data, or null out the header
217 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
218 * We change nwritten to be the number of file bytes written.
221 if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
222 if (nwritten >= hdtrl[0].iov_len) {
223 nwritten -= hdtrl[0].iov_len;
224 hdtrl[0].iov_base = NULL;
225 hdtrl[0].iov_len = 0;
226 } else {
227 /* iov_base is defined as a void *... */
228 hdtrl[0].iov_base = (void *)(((char *)hdtrl[0].iov_base) + nwritten);
229 hdtrl[0].iov_len -= nwritten;
230 nwritten = 0;
233 total -= nwritten;
234 offset += nwritten;
236 return count + hdr_len;
239 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
241 #include <sys/types.h>
242 #include <sys/socket.h>
243 #include <sys/uio.h>
245 ssize_t sys_sendfile(int tofd, int fromfd,
246 const DATA_BLOB *header, off_t offset, size_t count)
248 struct sf_hdtr sf_header = {0};
249 struct iovec io_header = {0};
251 off_t nwritten;
252 int ret;
254 if (header) {
255 sf_header.headers = &io_header;
256 sf_header.hdr_cnt = 1;
257 io_header.iov_base = header->data;
258 io_header.iov_len = header->length;
259 sf_header.trailers = NULL;
260 sf_header.trl_cnt = 0;
263 while (count != 0) {
265 nwritten = count;
266 #if defined(DARWIN_SENDFILE_API)
267 /* Darwin recycles nwritten as a value-result parameter, apart from that this
268 sendfile implementation is quite the same as the FreeBSD one */
269 ret = sendfile(fromfd, tofd, offset, &nwritten, &sf_header, 0);
270 #else
271 ret = sendfile(fromfd, tofd, offset, count, &sf_header, &nwritten, 0);
272 #endif
273 if (ret == -1 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
274 /* Send failed, we are toast. */
275 return -1;
278 if (nwritten == 0) {
279 /* EOF of offset is after EOF. */
280 break;
283 if (sf_header.hdr_cnt) {
284 if (io_header.iov_len <= nwritten) {
285 /* Entire header was sent. */
286 sf_header.headers = NULL;
287 sf_header.hdr_cnt = 0;
288 nwritten -= io_header.iov_len;
289 } else {
290 /* Partial header was sent. */
291 io_header.iov_len -= nwritten;
292 io_header.iov_base =
293 ((uint8_t *)io_header.iov_base) + nwritten;
294 nwritten = 0;
298 offset += nwritten;
299 count -= nwritten;
302 return nwritten;
305 #elif defined(AIX_SENDFILE_API)
307 /* BEGIN AIX SEND_FILE */
309 /* Contributed by William Jojo <jojowil@hvcc.edu> */
310 #include <sys/socket.h>
312 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
314 struct sf_parms hdtrl;
316 /* Set up the header/trailer struct params. */
317 if (header) {
318 hdtrl.header_data = header->data;
319 hdtrl.header_length = header->length;
320 } else {
321 hdtrl.header_data = NULL;
322 hdtrl.header_length = 0;
324 hdtrl.trailer_data = NULL;
325 hdtrl.trailer_length = 0;
327 hdtrl.file_descriptor = fromfd;
328 hdtrl.file_offset = offset;
329 hdtrl.file_bytes = count;
331 while ( hdtrl.file_bytes + hdtrl.header_length ) {
332 ssize_t ret;
335 Return Value
337 There are three possible return values from send_file:
339 Value Description
341 -1 an error has occurred, errno contains the error code.
343 0 the command has completed successfully.
345 1 the command was completed partially, some data has been
346 transmitted but the command has to return for some reason,
347 for example, the command was interrupted by signals.
349 do {
350 ret = send_file(&tofd, &hdtrl, 0);
351 } while ((ret == 1) || (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)));
352 if ( ret == -1 )
353 return -1;
356 return count + header->length;
358 /* END AIX SEND_FILE */
360 #else /* No sendfile implementation. Return error. */
362 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
364 /* No sendfile syscall. */
365 errno = ENOSYS;
366 return -1;
368 #endif