First cut at portable sendfile code. Only used in readX at the moment
[jra/samba/.git] / source3 / lib / sendfile.c
1 /*
2  Unix SMB/Netbios implementation.
3  Version 2.2.x / 3.0.x
4  sendfile implementations.
5  Copyright (C) Jeremy Allison 2002.
6
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 2 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.
15
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22  * This file handles the OS dependent sendfile implementations.
23  * The API is such that it returns -1 on error, else returns the
24  * number of bytes written.
25  */
26
27 #include "includes.h"
28
29 #if defined(LINUX_SENDFILE_API)
30
31 #include <sys/sendfile.h>
32
33 #ifndef MSG_MORE
34 #define MSG_MORE 0x8000
35 #endif
36
37 ssize_t sys_sendfile(int outfd, int infd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
38 {
39         size_t total=0;
40         ssize_t ret;
41
42         /*
43          * Send the header first.
44          * Use MSG_MORE to cork the TCP output until sendfile is called.
45          */
46
47         while (total < header->length) {
48                 ret = sys_send(outfd, header->data + total,header->length - total, MSG_MORE);
49                 if (ret == -1)
50                         return -1;
51                 total += ret;
52         }
53
54         total = count;
55         while (total) {
56                 ssize_t nwritten;
57                 do {
58 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(SENDFILE64)
59                         nwritten = sendfile64(outfd, infd, &offset, total);
60 #else
61                         nwritten = sendfile(outfd, infd, &offset, total);
62 #endif
63                 } while (nwritten == -1 && errno == EINTR);
64                 if (nwritten == -1)
65                         return -1;
66                 if (nwritten == 0)
67                         return -1; /* I think we're at EOF here... */
68                 total -= nwritten;
69         }
70         return count + header->length;
71 }
72
73 #elif defined(SOLARIS_SENDFILE_API)
74
75 ssize_t sys_sendfile(int outfd, int infd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
76 {
77 }
78
79 #elif defined(HPUX_SENDFILE_API)
80
81 #include <sys/socket.h>
82 #include <sys/uio.h>
83
84 ssize_t sys_sendfile(int outfd, int infd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
85 {
86         size_t total=0;
87         struct iovec hdtrl[2];
88
89         /* Set up the header/trailer iovec. */
90         hdtrl[0].iov_base = header->data;
91         hdtrl[0].iov_len = header->length;
92         hdtrl[1].iov_base = NULL;
93         hdtrl[1].iov_base = 0;
94
95         total = count;
96         while (total) {
97                 ssize_t nwritten;
98                 do {
99 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(SENDFILE64)
100                         nwritten = sendfile64(outfd, infd, &offset, total, &hdtrl, 0);
101 #else
102                         nwritten = sendfile(outfd, infd, &offset, total, &hdtrl, 0);
103 #endif
104                 } while (nwritten == -1 && errno == EINTR);
105                 if (nwritten == -1)
106                         return -1;
107                 total -= nwritten;
108         }
109         return count + header->length;
110 }
111
112 #elif defined(FREEBSD_SENDFILE_API)
113
114 #include <sys/types.h>
115 #include <sys/socket.h>
116 #include <sys/uio.h>
117
118 ssize_t sys_sendfile(int outfd, int infd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
119 {
120         size_t total=0;
121         struct sf_hdtr hdr;
122         struct iovec hdtrl;
123
124         hdr->headers = &hdtrl;
125         hdr->hdr_cnt = 1;
126         hdr->trailers = NULL;
127         hdr->trl_cnt = 0;
128
129         /* Set up the header iovec. */
130         hdtrl.iov_base = header->data;
131         hdtrl.iov_len = header->length;
132
133         total = count;
134         while (total) {
135                 ssize_t nwritten;
136                 do {
137 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(SENDFILE64)
138                         nwritten = sendfile64(outfd, infd, &offset, total, &hdr, NULL, 0);
139 #else
140                         nwritten = sendfile(outfd, infd, &offset, total, &hdr, NULL, 0);
141 #endif
142                 } while (nwritten == -1 && errno == EINTR);
143                 if (nwritten == -1)
144                         return -1;
145                 total -= nwritten;
146         }
147         return count + header->length;
148 }
149
150 #else /* No sendfile implementation. Return error. */
151
152 ssize_t sys_sendfile(int outfd, int infd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
153 {
154         /* No sendfile syscall. */
155         errno = ENOSYS;
156         return -1;
157 }
158 #endif