libcli/smb: add helpers to parse client/server smb3 encryption algorithms into struct...
[Samba.git] / source3 / lib / sendfile.c
blobd3effaf30aa4537d24741c59db3dbc4afefd9839
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"
27 #include "system/filesys.h"
29 #if defined(LINUX_SENDFILE_API)
31 #include <sys/sendfile.h>
33 #ifndef MSG_MORE
34 #define MSG_MORE 0x8000
35 #endif
37 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
39 size_t total=0;
40 ssize_t ret = -1;
41 size_t hdr_len = 0;
42 int old_flags = 0;
43 bool socket_flags_changed = false;
46 * Send the header first.
47 * Use MSG_MORE to cork the TCP output until sendfile is called.
50 if (header) {
51 hdr_len = header->length;
52 while (total < hdr_len) {
53 ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
54 if (ret == -1) {
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);
65 if (ret == -1) {
66 goto out;
68 socket_flags_changed = true;
69 continue;
71 goto out;
73 total += ret;
77 total = count;
78 while (total) {
79 ssize_t nwritten;
80 do {
81 nwritten = sendfile(tofd, fromfd, &offset, total);
82 } while (nwritten == -1 && errno == EINTR);
83 if (nwritten == -1) {
84 if (errno == EAGAIN || errno == EWOULDBLOCK) {
85 if (socket_flags_changed) {
87 * We're already in blocking
88 * mode. This is an error.
90 ret = -1;
91 goto out;
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
99 * non-blocking mode.
101 old_flags = fcntl(tofd, F_GETFL, 0);
102 ret = set_blocking(tofd, true);
103 if (ret == -1) {
104 goto out;
106 socket_flags_changed = true;
107 continue;
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. */
121 ret = -1;
122 goto out;
124 if (nwritten == 0) {
126 * EOF, return a short read
128 ret = hdr_len + (count - total);
129 goto out;
131 total -= nwritten;
134 ret = count + hdr_len;
136 out:
138 if (socket_flags_changed) {
139 int saved_errno;
140 int err;
142 if (ret == -1) {
143 saved_errno = errno;
145 /* Restore the old state of the socket. */
146 err = fcntl(tofd, F_SETFL, old_flags);
147 if (err == -1) {
148 return -1;
150 if (ret == -1) {
151 errno = saved_errno;
155 return ret;
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)
168 int sfvcnt;
169 size_t total, xferred;
170 struct sendfilevec vec[2];
171 ssize_t hdr_len = 0;
172 int old_flags = 0;
173 ssize_t ret = -1;
174 bool socket_flags_changed = false;
176 if (header) {
177 sfvcnt = 2;
179 vec[0].sfv_fd = SFV_FD_SELF;
180 vec[0].sfv_flag = 0;
181 vec[0].sfv_off = (off_t)header->data;
182 vec[0].sfv_len = hdr_len = header->length;
184 vec[1].sfv_fd = fromfd;
185 vec[1].sfv_flag = 0;
186 vec[1].sfv_off = offset;
187 vec[1].sfv_len = count;
189 } else {
190 sfvcnt = 1;
192 vec[0].sfv_fd = fromfd;
193 vec[0].sfv_flag = 0;
194 vec[0].sfv_off = offset;
195 vec[0].sfv_len = count;
198 total = count + hdr_len;
200 while (total) {
201 ssize_t nwritten;
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.
208 xferred = 0;
210 nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
211 if (nwritten == -1 && errno == EINTR) {
212 if (xferred == 0)
213 continue; /* Nothing written yet. */
214 else
215 nwritten = xferred;
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
225 * non-blocking mode.
227 old_flags = fcntl(tofd, F_GETFL, 0);
228 ret = set_blocking(tofd, true);
229 if (ret == -1) {
230 goto out;
232 socket_flags_changed = true;
233 continue;
235 ret = -1;
236 goto out;
238 if (nwritten == 0) {
239 ret = -1;
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 */
255 vec[0] = vec[1];
256 sfvcnt = 1;
257 } else {
258 vec[0].sfv_off += nwritten;
259 vec[0].sfv_len -= nwritten;
261 total -= nwritten;
263 ret = count + hdr_len;
265 out:
267 if (socket_flags_changed) {
268 int saved_errno;
269 int err;
271 if (ret == -1) {
272 saved_errno = errno;
274 /* Restore the old state of the socket. */
275 err = fcntl(tofd, F_SETFL, old_flags);
276 if (err == -1) {
277 return -1;
279 if (ret == -1) {
280 errno = saved_errno;
284 return ret;
287 #elif defined(HPUX_SENDFILE_API)
289 #include <sys/socket.h>
290 #include <sys/uio.h>
292 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
294 size_t total=0;
295 struct iovec hdtrl[2];
296 size_t hdr_len = 0;
297 int old_flags = 0;
298 ssize_t ret = -1;
299 bool socket_flags_changed = false;
301 if (header) {
302 /* Set up the header/trailer iovec. */
303 hdtrl[0].iov_base = (void *)header->data;
304 hdtrl[0].iov_len = hdr_len = header->length;
305 } else {
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;
312 total = count;
313 while (total + hdtrl[0].iov_len) {
314 ssize_t nwritten;
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.
323 do {
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
333 * non-blocking mode.
335 old_flags = fcntl(tofd, F_GETFL, 0);
336 ret = set_blocking(tofd, true);
337 if (ret == -1) {
338 goto out;
340 socket_flags_changed = true;
341 continue;
343 ret = -1;
344 goto out;
346 if (nwritten == 0) {
347 ret = -1; /* I think we're at EOF here... */
348 goto out;
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;
363 } else {
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;
367 nwritten = 0;
370 total -= nwritten;
371 offset += nwritten;
373 ret = count + hdr_len;
375 out:
377 if (socket_flags_changed) {
378 int saved_errno;
379 int err;
381 if (ret == -1) {
382 saved_errno = errno;
384 /* Restore the old state of the socket. */
385 err = fcntl(tofd, F_SETFL, old_flags);
386 if (err == -1) {
387 return -1;
389 if (ret == -1) {
390 errno = saved_errno;
394 return ret;
397 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
399 #include <sys/types.h>
400 #include <sys/socket.h>
401 #include <sys/uio.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};
408 int old_flags = 0;
410 off_t nwritten;
411 ssize_t ret = -1;
412 bool socket_flags_changed = false;
414 if (header) {
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;
423 while (count != 0) {
425 nwritten = count;
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);
430 #else
431 ret = sendfile(fromfd, tofd, offset, count, &sf_header, &nwritten, 0);
432 #endif
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
440 * non-blocking mode.
442 old_flags = fcntl(tofd, F_GETFL, 0);
443 ret = set_blocking(tofd, true);
444 if (ret == -1) {
445 goto out;
447 socket_flags_changed = true;
448 continue;
450 /* Send failed, we are toast. */
451 ret = -1;
452 goto out;
455 if (nwritten == 0) {
456 /* EOF of offset is after EOF. */
457 break;
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;
466 } else {
467 /* Partial header was sent. */
468 io_header.iov_len -= nwritten;
469 io_header.iov_base =
470 ((uint8_t *)io_header.iov_base) + nwritten;
471 nwritten = 0;
475 offset += nwritten;
476 count -= nwritten;
479 ret = nwritten;
481 out:
483 if (socket_flags_changed) {
484 int saved_errno;
485 int err;
487 if (ret == -1) {
488 saved_errno = errno;
490 /* Restore the old state of the socket. */
491 err = fcntl(tofd, F_SETFL, old_flags);
492 if (err == -1) {
493 return -1;
495 if (ret == -1) {
496 errno = saved_errno;
500 return ret;
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;
513 int old_flags = 0;
514 ssize_t ret = -1;
515 bool socket_flags_changed = false;
517 /* Set up the header/trailer struct params. */
518 if (header) {
519 hdtrl.header_data = header->data;
520 hdtrl.header_length = header->length;
521 } else {
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 ) {
534 Return Value
536 There are three possible return values from send_file:
538 Value Description
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.
548 do {
549 ret = send_file(&tofd, &hdtrl, 0);
550 } while ((ret == 1) || (ret == -1 && errno == EINTR));
551 if ( ret == -1 ) {
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
558 * non-blocking mode.
560 old_flags = fcntl(tofd, F_GETFL, 0);
561 ret = set_blocking(tofd, true);
562 if (ret == -1) {
563 goto out;
565 socket_flags_changed = true;
566 continue;
568 goto out;
572 ret = count + header->length;
574 out:
576 if (socket_flags_changed) {
577 int saved_errno;
578 int err;
580 if (ret == -1) {
581 saved_errno = errno;
583 /* Restore the old state of the socket. */
584 err = fcntl(tofd, F_SETFL, old_flags);
585 if (err == -1) {
586 return -1;
588 if (ret == -1) {
589 errno = saved_errno;
593 return ret;
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. */
602 errno = ENOSYS;
603 return -1;
605 #endif