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
39APR_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
68APR_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
97APR_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
166APR_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
186APR_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
214static 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 */
256APR_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