2 Unix SMB/Netbios implementation.
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.
27 #include "system/filesys.h"
29 #if defined(LINUX_SENDFILE_API)
31 #include <sys/sendfile.h>
34 #define MSG_MORE 0x8000
37 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
43 bool socket_flags_changed
= false;
46 * Send the header first.
47 * Use MSG_MORE to cork the TCP output until sendfile is called.
51 hdr_len
= header
->length
;
52 while (total
< hdr_len
) {
53 ret
= sys_send(tofd
, header
->data
+ total
,hdr_len
- total
, MSG_MORE
);
55 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
57 * send() must complete before we can
58 * send any other outgoing data on the
59 * socket. Ensure socket is in blocking
60 * mode. For SMB2 by default the socket
61 * is in non-blocking mode.
63 old_flags
= fcntl(tofd
, F_GETFL
, 0);
64 ret
= set_blocking(tofd
, true);
68 socket_flags_changed
= true;
81 nwritten
= sendfile(tofd
, fromfd
, &offset
, total
);
82 } while (nwritten
== -1 && errno
== EINTR
);
84 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
85 if (socket_flags_changed
) {
87 * We're already in blocking
88 * mode. This is an error.
95 * Sendfile must complete before we can
96 * send any other outgoing data on the socket.
97 * Ensure socket is in blocking mode.
98 * For SMB2 by default the socket is in
101 old_flags
= fcntl(tofd
, F_GETFL
, 0);
102 ret
= set_blocking(tofd
, true);
106 socket_flags_changed
= true;
110 if (errno
== ENOSYS
|| errno
== EINVAL
) {
111 /* Ok - we're in a world of pain here. We just sent
112 * the header, but the sendfile failed. We have to
113 * emulate the sendfile at an upper layer before we
114 * disable it's use. So we do something really ugly.
115 * We set the errno to a strange value so we can detect
116 * this at the upper level and take care of it without
117 * layer violation. JRA.
119 errno
= EINTR
; /* Normally we can never return this. */
126 * EOF, return a short read
128 ret
= hdr_len
+ (count
- total
);
134 ret
= count
+ hdr_len
;
138 if (socket_flags_changed
) {
145 /* Restore the old state of the socket. */
146 err
= fcntl(tofd
, F_SETFL
, old_flags
);
158 #elif defined(SOLARIS_SENDFILE_API)
161 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
164 #include <sys/sendfile.h>
166 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
169 size_t total
, xferred
;
170 struct sendfilevec vec
[2];
174 bool socket_flags_changed
= false;
179 vec
[0].sfv_fd
= SFV_FD_SELF
;
181 vec
[0].sfv_off
= (off_t
)header
->data
;
182 vec
[0].sfv_len
= hdr_len
= header
->length
;
184 vec
[1].sfv_fd
= fromfd
;
186 vec
[1].sfv_off
= offset
;
187 vec
[1].sfv_len
= count
;
192 vec
[0].sfv_fd
= fromfd
;
194 vec
[0].sfv_off
= offset
;
195 vec
[0].sfv_len
= count
;
198 total
= count
+ hdr_len
;
204 * Although not listed in the API error returns, this is almost certainly
205 * a slow system call and will be interrupted by a signal with EINTR. JRA.
210 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
211 if (nwritten
== -1 && errno
== EINTR
) {
213 continue; /* Nothing written yet. */
218 if (nwritten
== -1) {
219 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
221 * Sendfile must complete before we can
222 * send any other outgoing data on the socket.
223 * Ensure socket is in blocking mode.
224 * For SMB2 by default the socket is in
227 old_flags
= fcntl(tofd
, F_GETFL
, 0);
228 ret
= set_blocking(tofd
, true);
232 socket_flags_changed
= true;
240 goto out
; /* I think we're at EOF here... */
244 * If this was a short (signal interrupted) write we may need
245 * to subtract it from the header data, or null out the header
246 * data altogether if we wrote more than vec[0].sfv_len bytes.
247 * We move vec[1].* to vec[0].* and set sfvcnt to 1
250 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
251 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
252 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
254 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
258 vec
[0].sfv_off
+= nwritten
;
259 vec
[0].sfv_len
-= nwritten
;
263 ret
= count
+ hdr_len
;
267 if (socket_flags_changed
) {
274 /* Restore the old state of the socket. */
275 err
= fcntl(tofd
, F_SETFL
, old_flags
);
287 #elif defined(HPUX_SENDFILE_API)
289 #include <sys/socket.h>
292 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
295 struct iovec hdtrl
[2];
299 bool socket_flags_changed
= false;
302 /* Set up the header/trailer iovec. */
303 hdtrl
[0].iov_base
= (void *)header
->data
;
304 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
306 hdtrl
[0].iov_base
= NULL
;
307 hdtrl
[0].iov_len
= hdr_len
= 0;
309 hdtrl
[1].iov_base
= NULL
;
310 hdtrl
[1].iov_len
= 0;
313 while (total
+ hdtrl
[0].iov_len
) {
317 * HPUX guarantees that if any data was written before
318 * a signal interrupt then sendfile returns the number of
319 * bytes written (which may be less than requested) not -1.
320 * nwritten includes the header data sent.
324 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
325 } while (nwritten
== -1 && errno
== EINTR
);
326 if (nwritten
== -1) {
327 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
329 * Sendfile must complete before we can
330 * send any other outgoing data on the socket.
331 * Ensure socket is in blocking mode.
332 * For SMB2 by default the socket is in
335 old_flags
= fcntl(tofd
, F_GETFL
, 0);
336 ret
= set_blocking(tofd
, true);
340 socket_flags_changed
= true;
347 ret
= -1; /* I think we're at EOF here... */
352 * If this was a short (signal interrupted) write we may need
353 * to subtract it from the header data, or null out the header
354 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
355 * We change nwritten to be the number of file bytes written.
358 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
359 if (nwritten
>= hdtrl
[0].iov_len
) {
360 nwritten
-= hdtrl
[0].iov_len
;
361 hdtrl
[0].iov_base
= NULL
;
362 hdtrl
[0].iov_len
= 0;
364 /* iov_base is defined as a void *... */
365 hdtrl
[0].iov_base
= (void *)(((char *)hdtrl
[0].iov_base
) + nwritten
);
366 hdtrl
[0].iov_len
-= nwritten
;
373 ret
= count
+ hdr_len
;
377 if (socket_flags_changed
) {
384 /* Restore the old state of the socket. */
385 err
= fcntl(tofd
, F_SETFL
, old_flags
);
397 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
399 #include <sys/types.h>
400 #include <sys/socket.h>
403 ssize_t
sys_sendfile(int tofd
, int fromfd
,
404 const DATA_BLOB
*header
, off_t offset
, size_t count
)
406 struct sf_hdtr sf_header
= {0};
407 struct iovec io_header
= {0};
412 bool socket_flags_changed
= false;
415 sf_header
.headers
= &io_header
;
416 sf_header
.hdr_cnt
= 1;
417 io_header
.iov_base
= header
->data
;
418 io_header
.iov_len
= header
->length
;
419 sf_header
.trailers
= NULL
;
420 sf_header
.trl_cnt
= 0;
426 #if defined(DARWIN_SENDFILE_API)
427 /* Darwin recycles nwritten as a value-result parameter, apart from that this
428 sendfile implementation is quite the same as the FreeBSD one */
429 ret
= sendfile(fromfd
, tofd
, offset
, &nwritten
, &sf_header
, 0);
431 ret
= sendfile(fromfd
, tofd
, offset
, count
, &sf_header
, &nwritten
, 0);
433 if (ret
== -1 && errno
!= EINTR
) {
434 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
436 * Sendfile must complete before we can
437 * send any other outgoing data on the socket.
438 * Ensure socket is in blocking mode.
439 * For SMB2 by default the socket is in
442 old_flags
= fcntl(tofd
, F_GETFL
, 0);
443 ret
= set_blocking(tofd
, true);
447 socket_flags_changed
= true;
450 /* Send failed, we are toast. */
456 /* EOF of offset is after EOF. */
460 if (sf_header
.hdr_cnt
) {
461 if (io_header
.iov_len
<= nwritten
) {
462 /* Entire header was sent. */
463 sf_header
.headers
= NULL
;
464 sf_header
.hdr_cnt
= 0;
465 nwritten
-= io_header
.iov_len
;
467 /* Partial header was sent. */
468 io_header
.iov_len
-= nwritten
;
470 ((uint8_t *)io_header
.iov_base
) + nwritten
;
483 if (socket_flags_changed
) {
490 /* Restore the old state of the socket. */
491 err
= fcntl(tofd
, F_SETFL
, old_flags
);
503 #elif defined(AIX_SENDFILE_API)
505 /* BEGIN AIX SEND_FILE */
507 /* Contributed by William Jojo <jojowil@hvcc.edu> */
508 #include <sys/socket.h>
510 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
512 struct sf_parms hdtrl
;
515 bool socket_flags_changed
= false;
517 /* Set up the header/trailer struct params. */
519 hdtrl
.header_data
= header
->data
;
520 hdtrl
.header_length
= header
->length
;
522 hdtrl
.header_data
= NULL
;
523 hdtrl
.header_length
= 0;
525 hdtrl
.trailer_data
= NULL
;
526 hdtrl
.trailer_length
= 0;
528 hdtrl
.file_descriptor
= fromfd
;
529 hdtrl
.file_offset
= offset
;
530 hdtrl
.file_bytes
= count
;
532 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
536 There are three possible return values from send_file:
540 -1 an error has occurred, errno contains the error code.
542 0 the command has completed successfully.
544 1 the command was completed partially, some data has been
545 transmitted but the command has to return for some reason,
546 for example, the command was interrupted by signals.
549 ret
= send_file(&tofd
, &hdtrl
, 0);
550 } while ((ret
== 1) || (ret
== -1 && errno
== EINTR
));
552 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
554 * Sendfile must complete before we can
555 * send any other outgoing data on the socket.
556 * Ensure socket is in blocking mode.
557 * For SMB2 by default the socket is in
560 old_flags
= fcntl(tofd
, F_GETFL
, 0);
561 ret
= set_blocking(tofd
, true);
565 socket_flags_changed
= true;
572 ret
= count
+ header
->length
;
576 if (socket_flags_changed
) {
583 /* Restore the old state of the socket. */
584 err
= fcntl(tofd
, F_SETFL
, old_flags
);
595 /* END AIX SEND_FILE */
597 #else /* No sendfile implementation. Return error. */
599 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
601 /* No sendfile syscall. */