Apache HTTPD
sendrecv.c
Go to the documentation of this file.
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
41{
42 apr_ssize_t rv;
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) {
58 *len = 0;
59 return lasterror;
60 }
61
62 *len = dwBytes;
63
64 return APR_SUCCESS;
65}
66
67
70{
71 apr_ssize_t rv;
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
82#else
83 rv = recv(sock->socketdes, wsaData.buf, wsaData.len, 0);
84 dwBytes = rv;
85#endif
86 if (rv == SOCKET_ERROR) {
88 *len = 0;
89 return lasterror;
90 }
91
92 *len = dwBytes;
93 return dwBytes == 0 ? APR_EOF : APR_SUCCESS;
94}
95
96
98 const struct iovec *vec,
100{
102 apr_ssize_t rv;
105 DWORD dwBytes = 0;
107
108 total_len = 0;
109 for (i = 0; i < in_vec; i++) {
110 apr_size_t iov_len = vec[i].iov_len;
112 /* WSASend() returns NumberOfBytesSent as DWORD, so the total size
113 should be less than that. */
114 return APR_EINVAL;
115 }
117 }
118
119 pWsaBuf = (in_vec <= WSABUF_ON_STACK) ? _alloca(sizeof(WSABUF) * (in_vec))
120 : malloc(sizeof(WSABUF) * (in_vec));
121 if (!pWsaBuf)
122 return APR_ENOMEM;
123
124 for (i = 0; i < in_vec; i++) {
125 pWsaBuf[i].buf = vec[i].iov_base;
126 pWsaBuf[i].len = (ULONG) vec[i].iov_len;
127 }
128#ifndef _WIN32_WCE
130 if (rv == SOCKET_ERROR) {
132 }
133#else
134 for (i = 0; i < in_vec; i++) {
135 rv = send(sock->socketdes, pWsaBuf[i].buf, pWsaBuf[i].len, 0);
136 if (rv == SOCKET_ERROR) {
138 break;
139 }
140 dwBytes += rv;
141 }
142#endif
144 free(pWsaBuf);
145
146 *nbytes = dwBytes;
147 return rc;
148}
149
150
153 apr_int32_t flags, const char *buf,
155{
156 apr_ssize_t rv;
157
158 rv = sendto(sock->socketdes, buf, (int)*len, flags,
159 (const struct sockaddr*)&where->sa,
160 where->salen);
161 if (rv == SOCKET_ERROR) {
162 *len = 0;
163 return apr_get_netos_error();
164 }
165
166 *len = rv;
167 return APR_SUCCESS;
168}
169
170
174 char *buf, apr_size_t *len)
175{
176 apr_ssize_t rv;
177
178 from->salen = sizeof(from->sa);
179
180 rv = recvfrom(sock->socketdes, buf, (int)*len, flags,
181 (struct sockaddr*)&from->sa, &from->salen);
182 if (rv == SOCKET_ERROR) {
183 (*len) = 0;
184 return apr_get_netos_error();
185 }
186
187 apr_sockaddr_vars_set(from, from->sa.sin.sin_family,
188 ntohs(from->sa.sin.sin_port));
189
190 (*len) = rv;
191 if (rv == 0 && sock->type == SOCK_STREAM)
192 return APR_EOF;
193
194 return APR_SUCCESS;
195}
196
197
198#if APR_HAS_SENDFILE
200 struct iovec *iovec, int numvec,
201 char *buf, apr_size_t buflen)
202{
203 if (numvec == 1) {
204 *off = iovec[0].iov_base;
205 *len = iovec[0].iov_len;
206 }
207 else {
208 int i;
209 for (i = 0; i < numvec; i++) {
210 *len += iovec[i].iov_len;
211 }
212
213 if (*len > buflen) {
214 *len = 0;
215 return APR_INCOMPLETE;
216 }
217
218 *off = buf;
219
220 for (i = 0; i < numvec; i++) {
222 buf += iovec[i].iov_len;
223 }
224 }
225 return APR_SUCCESS;
226}
227
228
229/*
230 * apr_status_t apr_socket_sendfile(apr_socket_t *, apr_file_t *, apr_hdtr_t *,
231 * apr_off_t *, apr_size_t *, apr_int32_t flags)
232 * Send a file from an open file descriptor to a socket, along with
233 * optional headers and trailers
234 * arg 1) The socket to which we're writing
235 * arg 2) The open file from which to read
236 * arg 3) A structure containing the headers and trailers to send
237 * arg 4) Offset into the file where we should begin writing
238 * arg 5) Number of bytes to send out of the file
239 * arg 6) APR flags that are mapped to OS specific flags
240 */
247{
249 apr_status_t rv;
251 DWORD dwFlags = 0;
254 apr_size_t bytes_to_send; /* Bytes to send out of the file (not including headers) */
255 int disconnected = 0;
256 int sendv_trailers = 0;
257 char hdtrbuf[4096];
260 DWORD dw;
261
262 if (apr_os_level < APR_WIN_NT) {
263 return APR_ENOTIMPL;
264 }
265
266 /* According to documentation TransmitFile() should not be used directly.
267 * Pointer to function should retrieved using WSAIoctl:
268 * https://docs.microsoft.com/en-gb/windows/win32/api/mswsock/nf-mswsock-transmitfile#remarks
269 */
273 &dw, NULL, NULL) == SOCKET_ERROR) {
274 return apr_get_os_error();
275 }
276
277 if (dw != sizeof(pfn_transmit_file)) {
278 return APR_EINVAL;
279 }
280
281 /* Use len to keep track of number of total bytes sent (including headers) */
283 *len = 0;
284
285 /* Handle the goofy case of sending headers/trailers and a zero byte file */
286 if (!bytes_to_send && hdtr) {
287 if (hdtr->numheaders) {
288 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders,
289 &nbytes);
290 if (rv != APR_SUCCESS)
291 return rv;
292 *len += nbytes;
293 }
294 if (hdtr->numtrailers) {
295 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
296 &nbytes);
297 if (rv != APR_SUCCESS)
298 return rv;
299 *len += nbytes;
300 }
301 return APR_SUCCESS;
302 }
303
304 memset(&tfb, '\0', sizeof (tfb));
305
306 /* Collapse the headers into a single buffer */
307 if (hdtr && hdtr->numheaders) {
308 apr_size_t head_length = tfb.HeadLength;
309 ptfb = &tfb;
310 nbytes = 0;
311 rv = collapse_iovec((char **)&ptfb->Head, &head_length,
312 hdtr->headers, hdtr->numheaders,
313 hdtrbuf, sizeof(hdtrbuf));
314
315 tfb.HeadLength = (DWORD)head_length;
316
317 /* If not enough buffer, punt to sendv */
318 if (rv == APR_INCOMPLETE) {
319 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes);
320 if (rv != APR_SUCCESS)
321 return rv;
322 *len += nbytes;
323 ptfb = NULL;
324 }
325 }
326
327 /* Initialize the overlapped structure used on TransmitFile
328 */
329 if (!sock->overlapped) {
330 sock->overlapped = apr_pcalloc(sock->pool, sizeof(OVERLAPPED));
331 sock->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
332 }
333 while (bytes_to_send) {
335
338 }
339 else {
340 /* Last call to TransmitFile() */
342 /* Collapse the trailers into a single buffer */
343 if (hdtr && hdtr->numtrailers) {
344 apr_size_t tail_length = tfb.TailLength;
345 ptfb = &tfb;
346 rv = collapse_iovec((char**) &ptfb->Tail, &tail_length,
347 hdtr->trailers, hdtr->numtrailers,
348 hdtrbuf + ptfb->HeadLength,
349 sizeof(hdtrbuf) - ptfb->HeadLength);
350
351 tfb.TailLength = (DWORD)tail_length;
352
353 if (rv == APR_INCOMPLETE) {
354 /* If not enough buffer, punt to sendv, later */
355 sendv_trailers = 1;
356 }
357 }
358 /* Disconnect the socket after last send */
360 && !sendv_trailers) {
361 dwFlags |= TF_REUSE_SOCKET;
362 dwFlags |= TF_DISCONNECT;
363 disconnected = 1;
364 }
365 }
366
367 sock->overlapped->Offset = (DWORD)(curoff);
368#if APR_HAS_LARGE_FILES
369 sock->overlapped->OffsetHigh = (DWORD)(curoff >> 32);
370#endif
371 /* XXX BoundsChecker claims dwFlags must not be zero. */
372 rv = pfn_transmit_file(sock->socketdes, /* socket */
373 file->filehand, /* open file descriptor of the file to be sent */
374 xmitbytes, /* number of bytes to send. 0=send all */
375 0, /* Number of bytes per send. 0=use default */
376 sock->overlapped, /* OVERLAPPED structure */
377 ptfb, /* header and trailer buffers */
378 dwFlags); /* flags to control various aspects of TransmitFile */
379 if (!rv) {
383 {
384 rv = WaitForSingleObject(sock->overlapped->hEvent,
385 (DWORD)(sock->timeout >= 0
386 ? sock->timeout_ms : INFINITE));
387 if (rv == WAIT_OBJECT_0) {
389 if (!disconnected) {
391 sock->overlapped,
392 &xmitbytes,
393 FALSE,
394 &dwFlags)) {
396 }
397 /* Ugly code alert: WSAGetOverlappedResult returns
398 * a count of all bytes sent. This loop only
399 * tracks bytes sent out of the file.
400 */
401 else if (ptfb) {
402 xmitbytes -= (ptfb->HeadLength + ptfb->TailLength);
403 }
404 }
405 }
406 else if (rv == WAIT_TIMEOUT) {
408 }
409 else if (rv == WAIT_ABANDONED) {
410 /* Hummm... WAIT_ABANDONDED is not an error code. It is
411 * a return specific to the Win32 WAIT functions that
412 * indicates that a thread exited while holding a
413 * mutex. Should consider triggering an assert
414 * to detect the condition...
415 */
417 }
418 else
420 }
421 }
422 if (status != APR_SUCCESS)
423 break;
424
426 curoff += xmitbytes;
427 *len += xmitbytes;
428 /* Adjust len for any headers/trailers sent */
429 if (ptfb) {
430 *len += (ptfb->HeadLength + ptfb->TailLength);
431 memset(&tfb, '\0', sizeof (tfb));
432 ptfb = NULL;
433 }
434 }
435
436 if (status == APR_SUCCESS) {
437 if (sendv_trailers) {
438 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes);
439 if (rv != APR_SUCCESS)
440 return rv;
441 *len += nbytes;
442 }
443
444
445 /* Mark the socket as disconnected, but do not close it.
446 * Note: The application must have stored the socket prior to making
447 * the call to apr_socket_sendfile in order to either reuse it
448 * or close it.
449 */
450 if (disconnected) {
451 sock->disconnected = 1;
453 }
454 }
455
456 return status;
457}
458
459#endif
460
const char apr_size_t len
Definition ap_regex.h:187
#define FALSE
Definition abts.h:35
#define recvfrom
#define sendto
#define recv
#define send
#define WaitForSingleObject(h, d)
APR Error Codes.
APR Miscellaneous library routines.
APR general purpose library routines.
APR Network library.
const unsigned char * buf
Definition util_md5.h:50
#define APR_EOF
Definition apr_errno.h:461
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINVAL
Definition apr_errno.h:711
const char apr_ssize_t int flags
Definition apr_encode.h:168
apr_redis_t * rc
Definition apr_redis.h:173
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
#define APR_FROM_OS_ERROR(e)
Definition apr_errno.h:1214
#define apr_get_netos_error()
Definition apr_errno.h:1222
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
void apr_size_t * nbytes
apr_seek_where_t where
const struct iovec * vec
apr_seek_where_t apr_off_t * offset
const char apr_file_t * file
apr_sockaddr_t * sockaddr
apr_socket_t * sock
apr_size_t buflen
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int int status
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t)
Definition sockaddr.c:180
union apr_sockaddr_t::@55 sa
struct sockaddr_in sin
apr_socklen_t salen
apr_pool_t * pool
apr_interval_time_t timeout
apr_int32_t disconnected
apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, apr_int32_t flags, const char *buf, apr_size_t *len)
Definition sendrecv.c:112
apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, apr_int32_t flags, char *buf, apr_size_t *len)
Definition sendrecv.c:146
apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, apr_size_t *len)
Definition sendrecv.c:30
apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec, apr_int32_t nvec, apr_size_t *len)
Definition sendrecv.c:194
apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
Definition sendrecv.c:70
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_NT
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName
#define MAX_SEGMENT_SIZE
Definition sendrecv.c:36
#define WSABUF_ON_STACK
Definition sendrecv.c:37