1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apr_arch_networkio.h"
18 #include "apr_errno.h"
19 #include "apr_general.h"
20 #include "apr_network_io.h"
21 #include "apr_lib.h"
22 #include "apr_arch_file_io.h"
23 #if APR_HAVE_TIME_H
24 #include <time.h>
25 #endif
26
27 /* MAX_SEGMENT_SIZE is the maximum amount of data that will be sent to a client
28 * in one call of TransmitFile. This number must be small enough to give the
29 * slowest client time to receive the data before the socket timeout triggers.
30 * The same problem can exist with apr_socket_send(). In that case, we rely on
31 * the application to adjust socket timeouts and max send segment
32 * sizes appropriately.
33 * For example, Apache will in most cases call apr_socket_send() with less
34 * than 8193 bytes.
35 */
36 #define MAX_SEGMENT_SIZE 65536
37 #define WSABUF_ON_STACK 50
38
apr_socket_send(apr_socket_t * sock,const char * buf,apr_size_t * len)39 APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf,
40 apr_size_t *len)
41 {
42 apr_ssize_t rv;
43 WSABUF wsaData;
44 int lasterror;
45 DWORD dwBytes = 0;
46
47 wsaData.len = (u_long)*len;
48 wsaData.buf = (char*) buf;
49
50 #ifndef _WIN32_WCE
51 rv = WSASend(sock->socketdes, &wsaData, 1, &dwBytes, 0, NULL, NULL);
52 #else
53 rv = send(sock->socketdes, wsaData.buf, wsaData.len, 0);
54 dwBytes = rv;
55 #endif
56 if (rv == SOCKET_ERROR) {
57 lasterror = apr_get_netos_error();
58 *len = 0;
59 return lasterror;
60 }
61
62 *len = dwBytes;
63
64 return APR_SUCCESS;
65 }
66
67
apr_socket_recv(apr_socket_t * sock,char * buf,apr_size_t * len)68 APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf,
69 apr_size_t *len)
70 {
71 apr_ssize_t rv;
72 WSABUF wsaData;
73 int lasterror;
74 DWORD dwBytes = 0;
75 DWORD flags = 0;
76
77 wsaData.len = (u_long)*len;
78 wsaData.buf = (char*) buf;
79
80 #ifndef _WIN32_WCE
81 rv = WSARecv(sock->socketdes, &wsaData, 1, &dwBytes, &flags, NULL, NULL);
82 #else
83 rv = recv(sock->socketdes, wsaData.buf, wsaData.len, 0);
84 dwBytes = rv;
85 #endif
86 if (rv == SOCKET_ERROR) {
87 lasterror = apr_get_netos_error();
88 *len = 0;
89 return lasterror;
90 }
91
92 *len = dwBytes;
93 return dwBytes == 0 ? APR_EOF : APR_SUCCESS;
94 }
95
96
apr_socket_sendv(apr_socket_t * sock,const struct iovec * vec,apr_int32_t in_vec,apr_size_t * nbytes)97 APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock,
98 const struct iovec *vec,
99 apr_int32_t in_vec, apr_size_t *nbytes)
100 {
101 apr_status_t rc = APR_SUCCESS;
102 apr_ssize_t rv;
103 apr_size_t cur_len;
104 apr_int32_t nvec = 0;
105 int i, j = 0;
106 DWORD dwBytes = 0;
107 WSABUF *pWsaBuf;
108
109 for (i = 0; i < in_vec; i++) {
110 cur_len = vec[i].iov_len;
111 nvec++;
112 while (cur_len > APR_DWORD_MAX) {
113 nvec++;
114 cur_len -= APR_DWORD_MAX;
115 }
116 }
117
118 pWsaBuf = (nvec <= WSABUF_ON_STACK) ? _alloca(sizeof(WSABUF) * (nvec))
119 : malloc(sizeof(WSABUF) * (nvec));
120 if (!pWsaBuf)
121 return APR_ENOMEM;
122
123 for (i = 0; i < in_vec; i++) {
124 char * base = vec[i].iov_base;
125 cur_len = vec[i].iov_len;
126
127 do {
128 if (cur_len > APR_DWORD_MAX) {
129 pWsaBuf[j].buf = base;
130 pWsaBuf[j].len = APR_DWORD_MAX;
131 cur_len -= APR_DWORD_MAX;
132 base += APR_DWORD_MAX;
133 }
134 else {
135 pWsaBuf[j].buf = base;
136 pWsaBuf[j].len = (DWORD)cur_len;
137 cur_len = 0;
138 }
139 j++;
140
141 } while (cur_len > 0);
142 }
143 #ifndef _WIN32_WCE
144 rv = WSASend(sock->socketdes, pWsaBuf, nvec, &dwBytes, 0, NULL, NULL);
145 if (rv == SOCKET_ERROR) {
146 rc = apr_get_netos_error();
147 }
148 #else
149 for (i = 0; i < nvec; i++) {
150 rv = send(sock->socketdes, pWsaBuf[i].buf, pWsaBuf[i].len, 0);
151 if (rv == SOCKET_ERROR) {
152 rc = apr_get_netos_error();
153 break;
154 }
155 dwBytes += rv;
156 }
157 #endif
158 if (nvec > WSABUF_ON_STACK)
159 free(pWsaBuf);
160
161 *nbytes = dwBytes;
162 return rc;
163 }
164
165
apr_socket_sendto(apr_socket_t * sock,apr_sockaddr_t * where,apr_int32_t flags,const char * buf,apr_size_t * len)166 APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock,
167 apr_sockaddr_t *where,
168 apr_int32_t flags, const char *buf,
169 apr_size_t *len)
170 {
171 apr_ssize_t rv;
172
173 rv = sendto(sock->socketdes, buf, (int)*len, flags,
174 (const struct sockaddr*)&where->sa,
175 where->salen);
176 if (rv == SOCKET_ERROR) {
177 *len = 0;
178 return apr_get_netos_error();
179 }
180
181 *len = rv;
182 return APR_SUCCESS;
183 }
184
185
apr_socket_recvfrom(apr_sockaddr_t * from,apr_socket_t * sock,apr_int32_t flags,char * buf,apr_size_t * len)186 APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from,
187 apr_socket_t *sock,
188 apr_int32_t flags,
189 char *buf, apr_size_t *len)
190 {
191 apr_ssize_t rv;
192
193 from->salen = sizeof(from->sa);
194
195 rv = recvfrom(sock->socketdes, buf, (int)*len, flags,
196 (struct sockaddr*)&from->sa, &from->salen);
197 if (rv == SOCKET_ERROR) {
198 (*len) = 0;
199 return apr_get_netos_error();
200 }
201
202 apr_sockaddr_vars_set(from, from->sa.sin.sin_family,
203 ntohs(from->sa.sin.sin_port));
204
205 (*len) = rv;
206 if (rv == 0 && sock->type == SOCK_STREAM)
207 return APR_EOF;
208
209 return APR_SUCCESS;
210 }
211
212
213 #if APR_HAS_SENDFILE
collapse_iovec(char ** off,apr_size_t * len,struct iovec * iovec,int numvec,char * buf,apr_size_t buflen)214 static apr_status_t collapse_iovec(char **off, apr_size_t *len,
215 struct iovec *iovec, int numvec,
216 char *buf, apr_size_t buflen)
217 {
218 if (numvec == 1) {
219 *off = iovec[0].iov_base;
220 *len = iovec[0].iov_len;
221 }
222 else {
223 int i;
224 for (i = 0; i < numvec; i++) {
225 *len += iovec[i].iov_len;
226 }
227
228 if (*len > buflen) {
229 *len = 0;
230 return APR_INCOMPLETE;
231 }
232
233 *off = buf;
234
235 for (i = 0; i < numvec; i++) {
236 memcpy(buf, iovec[i].iov_base, iovec[i].iov_len);
237 buf += iovec[i].iov_len;
238 }
239 }
240 return APR_SUCCESS;
241 }
242
243
244 /*
245 * apr_status_t apr_socket_sendfile(apr_socket_t *, apr_file_t *, apr_hdtr_t *,
246 * apr_off_t *, apr_size_t *, apr_int32_t flags)
247 * Send a file from an open file descriptor to a socket, along with
248 * optional headers and trailers
249 * arg 1) The socket to which we're writing
250 * arg 2) The open file from which to read
251 * arg 3) A structure containing the headers and trailers to send
252 * arg 4) Offset into the file where we should begin writing
253 * arg 5) Number of bytes to send out of the file
254 * arg 6) APR flags that are mapped to OS specific flags
255 */
apr_socket_sendfile(apr_socket_t * sock,apr_file_t * file,apr_hdtr_t * hdtr,apr_off_t * offset,apr_size_t * len,apr_int32_t flags)256 APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock,
257 apr_file_t *file,
258 apr_hdtr_t *hdtr,
259 apr_off_t *offset,
260 apr_size_t *len,
261 apr_int32_t flags)
262 {
263 apr_status_t status = APR_SUCCESS;
264 apr_status_t rv;
265 apr_off_t curoff = *offset;
266 DWORD dwFlags = 0;
267 apr_size_t nbytes;
268 TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL;
269 apr_size_t bytes_to_send; /* Bytes to send out of the file (not including headers) */
270 int disconnected = 0;
271 int sendv_trailers = 0;
272 char hdtrbuf[4096];
273
274 if (apr_os_level < APR_WIN_NT) {
275 return APR_ENOTIMPL;
276 }
277
278 /* Use len to keep track of number of total bytes sent (including headers) */
279 bytes_to_send = *len;
280 *len = 0;
281
282 /* Handle the goofy case of sending headers/trailers and a zero byte file */
283 if (!bytes_to_send && hdtr) {
284 if (hdtr->numheaders) {
285 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders,
286 &nbytes);
287 if (rv != APR_SUCCESS)
288 return rv;
289 *len += nbytes;
290 }
291 if (hdtr->numtrailers) {
292 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
293 &nbytes);
294 if (rv != APR_SUCCESS)
295 return rv;
296 *len += nbytes;
297 }
298 return APR_SUCCESS;
299 }
300
301 memset(&tfb, '\0', sizeof (tfb));
302
303 /* Collapse the headers into a single buffer */
304 if (hdtr && hdtr->numheaders) {
305 apr_size_t head_length = tfb.HeadLength;
306 ptfb = &tfb;
307 nbytes = 0;
308 rv = collapse_iovec((char **)&ptfb->Head, &head_length,
309 hdtr->headers, hdtr->numheaders,
310 hdtrbuf, sizeof(hdtrbuf));
311
312 tfb.HeadLength = (DWORD)head_length;
313
314 /* If not enough buffer, punt to sendv */
315 if (rv == APR_INCOMPLETE) {
316 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes);
317 if (rv != APR_SUCCESS)
318 return rv;
319 *len += nbytes;
320 ptfb = NULL;
321 }
322 }
323
324 /* Initialize the overlapped structure used on TransmitFile
325 */
326 if (!sock->overlapped) {
327 sock->overlapped = apr_pcalloc(sock->pool, sizeof(OVERLAPPED));
328 sock->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
329 }
330 while (bytes_to_send) {
331 DWORD xmitbytes;
332
333 if (bytes_to_send > MAX_SEGMENT_SIZE) {
334 xmitbytes = MAX_SEGMENT_SIZE;
335 }
336 else {
337 /* Last call to TransmitFile() */
338 xmitbytes = (DWORD)bytes_to_send;
339 /* Collapse the trailers into a single buffer */
340 if (hdtr && hdtr->numtrailers) {
341 apr_size_t tail_length = tfb.TailLength;
342 ptfb = &tfb;
343 rv = collapse_iovec((char**) &ptfb->Tail, &tail_length,
344 hdtr->trailers, hdtr->numtrailers,
345 hdtrbuf + ptfb->HeadLength,
346 sizeof(hdtrbuf) - ptfb->HeadLength);
347
348 tfb.TailLength = (DWORD)tail_length;
349
350 if (rv == APR_INCOMPLETE) {
351 /* If not enough buffer, punt to sendv, later */
352 sendv_trailers = 1;
353 }
354 }
355 /* Disconnect the socket after last send */
356 if ((flags & APR_SENDFILE_DISCONNECT_SOCKET)
357 && !sendv_trailers) {
358 dwFlags |= TF_REUSE_SOCKET;
359 dwFlags |= TF_DISCONNECT;
360 disconnected = 1;
361 }
362 }
363
364 sock->overlapped->Offset = (DWORD)(curoff);
365 #if APR_HAS_LARGE_FILES
366 sock->overlapped->OffsetHigh = (DWORD)(curoff >> 32);
367 #endif
368 /* XXX BoundsChecker claims dwFlags must not be zero. */
369 rv = TransmitFile(sock->socketdes, /* socket */
370 file->filehand, /* open file descriptor of the file to be sent */
371 xmitbytes, /* number of bytes to send. 0=send all */
372 0, /* Number of bytes per send. 0=use default */
373 sock->overlapped, /* OVERLAPPED structure */
374 ptfb, /* header and trailer buffers */
375 dwFlags); /* flags to control various aspects of TransmitFile */
376 if (!rv) {
377 status = apr_get_netos_error();
378 if ((status == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) ||
379 (status == APR_FROM_OS_ERROR(WSA_IO_PENDING)))
380 {
381 rv = WaitForSingleObject(sock->overlapped->hEvent,
382 (DWORD)(sock->timeout >= 0
383 ? sock->timeout_ms : INFINITE));
384 if (rv == WAIT_OBJECT_0) {
385 status = APR_SUCCESS;
386 if (!disconnected) {
387 if (!WSAGetOverlappedResult(sock->socketdes,
388 sock->overlapped,
389 &xmitbytes,
390 FALSE,
391 &dwFlags)) {
392 status = apr_get_netos_error();
393 }
394 /* Ugly code alert: WSAGetOverlappedResult returns
395 * a count of all bytes sent. This loop only
396 * tracks bytes sent out of the file.
397 */
398 else if (ptfb) {
399 xmitbytes -= (ptfb->HeadLength + ptfb->TailLength);
400 }
401 }
402 }
403 else if (rv == WAIT_TIMEOUT) {
404 status = APR_FROM_OS_ERROR(WAIT_TIMEOUT);
405 }
406 else if (rv == WAIT_ABANDONED) {
407 /* Hummm... WAIT_ABANDONDED is not an error code. It is
408 * a return specific to the Win32 WAIT functions that
409 * indicates that a thread exited while holding a
410 * mutex. Should consider triggering an assert
411 * to detect the condition...
412 */
413 status = APR_FROM_OS_ERROR(WAIT_TIMEOUT);
414 }
415 else
416 status = apr_get_os_error();
417 }
418 }
419 if (status != APR_SUCCESS)
420 break;
421
422 bytes_to_send -= xmitbytes;
423 curoff += xmitbytes;
424 *len += xmitbytes;
425 /* Adjust len for any headers/trailers sent */
426 if (ptfb) {
427 *len += (ptfb->HeadLength + ptfb->TailLength);
428 memset(&tfb, '\0', sizeof (tfb));
429 ptfb = NULL;
430 }
431 }
432
433 if (status == APR_SUCCESS) {
434 if (sendv_trailers) {
435 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes);
436 if (rv != APR_SUCCESS)
437 return rv;
438 *len += nbytes;
439 }
440
441
442 /* Mark the socket as disconnected, but do not close it.
443 * Note: The application must have stored the socket prior to making
444 * the call to apr_socket_sendfile in order to either reuse it
445 * or close it.
446 */
447 if (disconnected) {
448 sock->disconnected = 1;
449 sock->socketdes = INVALID_SOCKET;
450 }
451 }
452
453 return status;
454 }
455
456 #endif
457
458