~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/network_io/win32/sendrecv.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * 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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
    rv = recvfrom(sock->socketdes, buf, (int)*len, flags, 
 
194
                  (struct sockaddr*)&from->sa, &from->salen);
 
195
    if (rv == SOCKET_ERROR) {
 
196
        (*len) = 0;
 
197
        return apr_get_netos_error();
 
198
    }
 
199
    (*len) = rv;
 
200
    if (rv == 0 && sock->type == SOCK_STREAM)
 
201
        return APR_EOF;
 
202
 
 
203
    return APR_SUCCESS;
 
204
}
 
205
 
 
206
 
 
207
static apr_status_t collapse_iovec(char **off, apr_size_t *len, 
 
208
                                   struct iovec *iovec, int numvec, 
 
209
                                   char *buf, apr_size_t buflen)
 
210
{
 
211
    if (numvec == 1) {
 
212
        *off = iovec[0].iov_base;
 
213
        *len = iovec[0].iov_len;
 
214
    }
 
215
    else {
 
216
        int i;
 
217
        for (i = 0; i < numvec; i++) {
 
218
            *len += iovec[i].iov_len;
 
219
        }
 
220
 
 
221
        if (*len > buflen) {
 
222
            *len = 0;
 
223
            return APR_INCOMPLETE;
 
224
        }
 
225
 
 
226
        *off = buf;
 
227
 
 
228
        for (i = 0; i < numvec; i++) {
 
229
            memcpy(buf, iovec[i].iov_base, iovec[i].iov_len);
 
230
            buf += iovec[i].iov_len;
 
231
        }
 
232
    }
 
233
    return APR_SUCCESS;
 
234
}
 
235
 
 
236
 
 
237
#if APR_HAS_SENDFILE
 
238
/*
 
239
 * apr_status_t apr_socket_sendfile(apr_socket_t *, apr_file_t *, apr_hdtr_t *, 
 
240
 *                                 apr_off_t *, apr_size_t *, apr_int32_t flags)
 
241
 *    Send a file from an open file descriptor to a socket, along with 
 
242
 *    optional headers and trailers
 
243
 * arg 1) The socket to which we're writing
 
244
 * arg 2) The open file from which to read
 
245
 * arg 3) A structure containing the headers and trailers to send
 
246
 * arg 4) Offset into the file where we should begin writing
 
247
 * arg 5) Number of bytes to send out of the file
 
248
 * arg 6) APR flags that are mapped to OS specific flags
 
249
 */
 
250
APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, 
 
251
                                              apr_file_t *file,
 
252
                                              apr_hdtr_t *hdtr,
 
253
                                              apr_off_t *offset,
 
254
                                              apr_size_t *len,
 
255
                                              apr_int32_t flags) 
 
256
{
 
257
    apr_status_t status = APR_SUCCESS;
 
258
    apr_status_t rv;
 
259
    apr_off_t curoff = *offset;
 
260
    DWORD dwFlags = 0;
 
261
    apr_size_t nbytes;
 
262
    TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL;
 
263
    int ptr = 0;
 
264
    apr_size_t bytes_to_send;   /* Bytes to send out of the file (not including headers) */
 
265
    int disconnected = 0;
 
266
    int sendv_trailers = 0;
 
267
    char hdtrbuf[4096];
 
268
 
 
269
    if (apr_os_level < APR_WIN_NT) {
 
270
        return APR_ENOTIMPL;
 
271
    }
 
272
 
 
273
    /* Use len to keep track of number of total bytes sent (including headers) */
 
274
    bytes_to_send = *len;
 
275
    *len = 0;
 
276
 
 
277
    /* Handle the goofy case of sending headers/trailers and a zero byte file */
 
278
    if (!bytes_to_send && hdtr) {
 
279
        if (hdtr->numheaders) {
 
280
            rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, 
 
281
                                  &nbytes);
 
282
            if (rv != APR_SUCCESS)
 
283
                return rv;
 
284
            *len += nbytes;
 
285
        }
 
286
        if (hdtr->numtrailers) {
 
287
            rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
 
288
                                  &nbytes);
 
289
            if (rv != APR_SUCCESS)
 
290
                return rv;
 
291
            *len += nbytes;
 
292
        }
 
293
        return APR_SUCCESS;
 
294
    }
 
295
 
 
296
    memset(&tfb, '\0', sizeof (tfb));
 
297
 
 
298
    /* Collapse the headers into a single buffer */
 
299
    if (hdtr && hdtr->numheaders) {
 
300
        apr_size_t head_length = tfb.HeadLength;
 
301
        ptfb = &tfb;
 
302
        nbytes = 0;
 
303
        rv = collapse_iovec((char **)&ptfb->Head, &head_length, 
 
304
                            hdtr->headers, hdtr->numheaders, 
 
305
                            hdtrbuf, sizeof(hdtrbuf));
 
306
 
 
307
        tfb.HeadLength = (DWORD)head_length;
 
308
 
 
309
        /* If not enough buffer, punt to sendv */
 
310
        if (rv == APR_INCOMPLETE) {
 
311
            rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes);
 
312
            if (rv != APR_SUCCESS)
 
313
                return rv;
 
314
            *len += nbytes;
 
315
            ptfb = NULL;
 
316
        }
 
317
    }
 
318
 
 
319
    /* Initialize the overlapped structure used on TransmitFile
 
320
     */
 
321
    if (!sock->overlapped) {
 
322
        sock->overlapped = apr_pcalloc(sock->pool, sizeof(OVERLAPPED));
 
323
        sock->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 
324
    }
 
325
    while (bytes_to_send) {
 
326
        DWORD xmitbytes;
 
327
 
 
328
        if (bytes_to_send > MAX_SEGMENT_SIZE) {
 
329
            xmitbytes = MAX_SEGMENT_SIZE;
 
330
        }
 
331
        else {
 
332
            /* Last call to TransmitFile() */
 
333
            xmitbytes = (DWORD)bytes_to_send;
 
334
            /* Collapse the trailers into a single buffer */
 
335
            if (hdtr && hdtr->numtrailers) {
 
336
                apr_size_t tail_length = tfb.TailLength;
 
337
                ptfb = &tfb;
 
338
                rv = collapse_iovec((char**) &ptfb->Tail, &tail_length,
 
339
                                    hdtr->trailers, hdtr->numtrailers,
 
340
                                    hdtrbuf + ptfb->HeadLength,
 
341
                                    sizeof(hdtrbuf) - ptfb->HeadLength);
 
342
 
 
343
                tfb.TailLength = (DWORD)tail_length;
 
344
 
 
345
                if (rv == APR_INCOMPLETE) {
 
346
                    /* If not enough buffer, punt to sendv, later */
 
347
                    sendv_trailers = 1;
 
348
                }
 
349
            }
 
350
            /* Disconnect the socket after last send */
 
351
            if ((flags & APR_SENDFILE_DISCONNECT_SOCKET)
 
352
                    && !sendv_trailers) {
 
353
                dwFlags |= TF_REUSE_SOCKET;
 
354
                dwFlags |= TF_DISCONNECT;
 
355
                disconnected = 1;
 
356
            }
 
357
        }
 
358
 
 
359
        sock->overlapped->Offset = (DWORD)(curoff);
 
360
#if APR_HAS_LARGE_FILES
 
361
        sock->overlapped->OffsetHigh = (DWORD)(curoff >> 32);
 
362
#endif  
 
363
        /* XXX BoundsChecker claims dwFlags must not be zero. */
 
364
        rv = TransmitFile(sock->socketdes,  /* socket */
 
365
                          file->filehand, /* open file descriptor of the file to be sent */
 
366
                          xmitbytes,      /* number of bytes to send. 0=send all */
 
367
                          0,              /* Number of bytes per send. 0=use default */
 
368
                          sock->overlapped,    /* OVERLAPPED structure */
 
369
                          ptfb,           /* header and trailer buffers */
 
370
                          dwFlags);       /* flags to control various aspects of TransmitFile */
 
371
        if (!rv) {
 
372
            status = apr_get_netos_error();
 
373
            if ((status == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) ||
 
374
                (status == APR_FROM_OS_ERROR(WSA_IO_PENDING))) 
 
375
            {
 
376
                rv = WaitForSingleObject(sock->overlapped->hEvent, 
 
377
                                         (DWORD)(sock->timeout >= 0 
 
378
                                                 ? sock->timeout_ms : INFINITE));
 
379
                if (rv == WAIT_OBJECT_0) {
 
380
                    status = APR_SUCCESS;
 
381
                    if (!disconnected) {
 
382
                        if (!WSAGetOverlappedResult(sock->socketdes,
 
383
                                                    sock->overlapped,
 
384
                                                    &xmitbytes,
 
385
                                                    FALSE,
 
386
                                                    &dwFlags)) {
 
387
                            status = apr_get_netos_error();
 
388
                        }
 
389
                        /* Ugly code alert: WSAGetOverlappedResult returns
 
390
                         * a count of all bytes sent. This loop only
 
391
                         * tracks bytes sent out of the file.
 
392
                         */
 
393
                        else if (ptfb) {
 
394
                            xmitbytes -= (ptfb->HeadLength + ptfb->TailLength);
 
395
                        }
 
396
                    }
 
397
                }
 
398
                else if (rv == WAIT_TIMEOUT) {
 
399
                    status = APR_FROM_OS_ERROR(WAIT_TIMEOUT);
 
400
                }
 
401
                else if (rv == WAIT_ABANDONED) {
 
402
                    /* Hummm... WAIT_ABANDONDED is not an error code. It is
 
403
                     * a return specific to the Win32 WAIT functions that
 
404
                     * indicates that a thread exited while holding a
 
405
                     * mutex. Should consider triggering an assert
 
406
                     * to detect the condition...
 
407
                     */
 
408
                    status = APR_FROM_OS_ERROR(WAIT_TIMEOUT);
 
409
                }
 
410
                else
 
411
                    status = apr_get_os_error();
 
412
            }
 
413
        }
 
414
        if (status != APR_SUCCESS)
 
415
            break;
 
416
 
 
417
        bytes_to_send -= xmitbytes;
 
418
        curoff += xmitbytes;
 
419
        *len += xmitbytes;
 
420
        /* Adjust len for any headers/trailers sent */
 
421
        if (ptfb) {
 
422
            *len += (ptfb->HeadLength + ptfb->TailLength);
 
423
            memset(&tfb, '\0', sizeof (tfb));
 
424
            ptfb = NULL;
 
425
        }
 
426
    }
 
427
 
 
428
    if (status == APR_SUCCESS) {
 
429
        if (sendv_trailers) {
 
430
            rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes);
 
431
            if (rv != APR_SUCCESS)
 
432
                return rv;
 
433
            *len += nbytes;
 
434
        }
 
435
 
 
436
    
 
437
        /* Mark the socket as disconnected, but do not close it.
 
438
         * Note: The application must have stored the socket prior to making
 
439
         * the call to apr_socket_sendfile in order to either reuse it 
 
440
         * or close it.
 
441
         */
 
442
        if (disconnected) {
 
443
            sock->disconnected = 1;
 
444
            sock->socketdes = INVALID_SOCKET;
 
445
        }
 
446
    }
 
447
 
 
448
    return status;
 
449
}
 
450
 
 
451
#endif
 
452