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

« back to all changes in this revision

Viewing changes to srclib/apr/network_io/unix/sockets.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_network_io.h"
 
19
#include "apr_strings.h"
 
20
#include "apr_support.h"
 
21
#include "apr_portable.h"
 
22
#include "apr_arch_inherit.h"
 
23
 
 
24
#ifdef BEOS_R5
 
25
#undef close
 
26
#define close closesocket
 
27
#endif /* BEOS_R5 */
 
28
 
 
29
static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */
 
30
 
 
31
static apr_status_t socket_cleanup(void *sock)
 
32
{
 
33
    apr_socket_t *thesocket = sock;
 
34
 
 
35
    if (close(thesocket->socketdes) == 0) {
 
36
        thesocket->socketdes = -1;
 
37
        return APR_SUCCESS;
 
38
    }
 
39
    else {
 
40
        return errno;
 
41
    }
 
42
}
 
43
 
 
44
static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol)
 
45
{
 
46
    sock->type = type;
 
47
    sock->protocol = protocol;
 
48
    apr_sockaddr_vars_set(sock->local_addr, family, 0);
 
49
    apr_sockaddr_vars_set(sock->remote_addr, family, 0);
 
50
    sock->options = 0;
 
51
#if defined(BEOS) && !defined(BEOS_BONE)
 
52
    /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be
 
53
     * switched off!
 
54
     */
 
55
    sock->options |= APR_TCP_NODELAY;
 
56
#endif
 
57
}
 
58
 
 
59
static void alloc_socket(apr_socket_t **new, apr_pool_t *p)
 
60
{
 
61
    *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
 
62
    (*new)->pool = p;
 
63
    (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
 
64
                                                       sizeof(apr_sockaddr_t));
 
65
    (*new)->local_addr->pool = p;
 
66
    (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
 
67
                                                        sizeof(apr_sockaddr_t));
 
68
    (*new)->remote_addr->pool = p;
 
69
    (*new)->remote_addr_unknown = 1;
 
70
#ifndef WAITIO_USES_POLL
 
71
    /* Create a pollset with room for one descriptor. */
 
72
    /* ### check return codes */
 
73
    (void) apr_pollset_create(&(*new)->pollset, 1, p, 0);
 
74
#endif
 
75
}
 
76
 
 
77
apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol)
 
78
{
 
79
    *protocol = sock->protocol;
 
80
    return APR_SUCCESS;
 
81
}
 
82
 
 
83
apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type,
 
84
                               int protocol, apr_pool_t *cont)
 
85
{
 
86
    int family = ofamily;
 
87
 
 
88
    if (family == APR_UNSPEC) {
 
89
#if APR_HAVE_IPV6
 
90
        family = APR_INET6;
 
91
#else
 
92
        family = APR_INET;
 
93
#endif
 
94
    }
 
95
 
 
96
    alloc_socket(new, cont);
 
97
 
 
98
#ifndef BEOS_R5
 
99
    (*new)->socketdes = socket(family, type, protocol);
 
100
#else
 
101
    /* For some reason BeOS R5 has an unconventional protocol numbering,
 
102
     * so we need to translate here. */
 
103
    switch (protocol) {
 
104
    case 0:
 
105
        (*new)->socketdes = socket(family, type, 0);
 
106
        break;
 
107
    case APR_PROTO_TCP:
 
108
        (*new)->socketdes = socket(family, type, IPPROTO_TCP);
 
109
        break;
 
110
    case APR_PROTO_UDP:
 
111
        (*new)->socketdes = socket(family, type, IPPROTO_UDP);
 
112
        break;
 
113
    case APR_PROTO_SCTP:
 
114
    default:
 
115
        errno = EPROTONOSUPPORT;
 
116
        (*new)->socketdes = -1;
 
117
        break;
 
118
    }
 
119
#endif /* BEOS_R5 */
 
120
 
 
121
#if APR_HAVE_IPV6
 
122
    if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) {
 
123
        family = APR_INET;
 
124
        (*new)->socketdes = socket(family, type, protocol);
 
125
    }
 
126
#endif
 
127
 
 
128
    if ((*new)->socketdes < 0) {
 
129
        return errno;
 
130
    }
 
131
    set_socket_vars(*new, family, type, protocol);
 
132
 
 
133
    (*new)->timeout = -1;
 
134
    (*new)->inherit = 0;
 
135
    apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
 
136
                              socket_cleanup);
 
137
 
 
138
    return APR_SUCCESS;
 
139
 
140
 
 
141
apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, 
 
142
                                 apr_shutdown_how_e how)
 
143
{
 
144
    return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS;
 
145
}
 
146
 
 
147
apr_status_t apr_socket_close(apr_socket_t *thesocket)
 
148
{
 
149
    return apr_pool_cleanup_run(thesocket->pool, thesocket, socket_cleanup);
 
150
}
 
151
 
 
152
apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
 
153
{
 
154
    if (bind(sock->socketdes, 
 
155
             (struct sockaddr *)&sa->sa, sa->salen) == -1) {
 
156
        return errno;
 
157
    }
 
158
    else {
 
159
        sock->local_addr = sa;
 
160
        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
 
161
        if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */
 
162
            sock->local_port_unknown = 1; /* kernel got us an ephemeral port */
 
163
        }
 
164
        return APR_SUCCESS;
 
165
    }
 
166
}
 
167
 
 
168
apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog)
 
169
{
 
170
    if (listen(sock->socketdes, backlog) == -1)
 
171
        return errno;
 
172
    else
 
173
        return APR_SUCCESS;
 
174
}
 
175
 
 
176
apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock,
 
177
                               apr_pool_t *connection_context)
 
178
{
 
179
    alloc_socket(new, connection_context);
 
180
    set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, sock->protocol);
 
181
 
 
182
#ifndef HAVE_POLL
 
183
    (*new)->connected = 1;
 
184
#endif
 
185
    (*new)->timeout = -1;
 
186
    
 
187
    (*new)->socketdes = accept(sock->socketdes, 
 
188
                               (struct sockaddr *)&(*new)->remote_addr->sa,
 
189
                               &(*new)->remote_addr->salen);
 
190
 
 
191
    if ((*new)->socketdes < 0) {
 
192
        return errno;
 
193
    }
 
194
#ifdef TPF
 
195
    if ((*new)->socketdes == 0) { 
 
196
        /* 0 is an invalid socket for TPF */
 
197
        return APR_EINTR;
 
198
    }
 
199
#endif
 
200
 
 
201
    (*new)->remote_addr_unknown = 0;
 
202
 
 
203
    *(*new)->local_addr = *sock->local_addr;
 
204
 
 
205
    /* The above assignment just overwrote the pool entry. Setting the local_addr 
 
206
       pool for the accepted socket back to what it should be.  Otherwise all 
 
207
       allocations for this socket will come from a server pool that is not
 
208
       freed until the process goes down.*/
 
209
    (*new)->local_addr->pool = connection_context;
 
210
 
 
211
    /* fix up any pointers which are no longer valid */
 
212
    if (sock->local_addr->sa.sin.sin_family == AF_INET) {
 
213
        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
 
214
    }
 
215
#if APR_HAVE_IPV6
 
216
    else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
 
217
        (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
 
218
    }
 
219
#endif
 
220
    (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
 
221
    if (sock->local_port_unknown) {
 
222
        /* not likely for a listening socket, but theoretically possible :) */
 
223
        (*new)->local_port_unknown = 1;
 
224
    }
 
225
 
 
226
#if APR_TCP_NODELAY_INHERITED
 
227
    if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) {
 
228
        apr_set_option(*new, APR_TCP_NODELAY, 1);
 
229
    }
 
230
#endif /* TCP_NODELAY_INHERITED */
 
231
#if APR_O_NONBLOCK_INHERITED
 
232
    if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) {
 
233
        apr_set_option(*new, APR_SO_NONBLOCK, 1);
 
234
    }
 
235
#endif /* APR_O_NONBLOCK_INHERITED */
 
236
 
 
237
    if (sock->local_interface_unknown ||
 
238
        !memcmp(sock->local_addr->ipaddr_ptr,
 
239
                generic_inaddr_any,
 
240
                sock->local_addr->ipaddr_len)) {
 
241
        /* If the interface address inside the listening socket's local_addr wasn't 
 
242
         * up-to-date, we don't know local interface of the connected socket either.
 
243
         *
 
244
         * If the listening socket was not bound to a specific interface, we
 
245
         * don't know the local_addr of the connected socket.
 
246
         */
 
247
        (*new)->local_interface_unknown = 1;
 
248
    }
 
249
 
 
250
    (*new)->inherit = 0;
 
251
    apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
 
252
                              socket_cleanup);
 
253
    return APR_SUCCESS;
 
254
}
 
255
 
 
256
apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa)
 
257
{
 
258
    int rc;        
 
259
 
 
260
    do {
 
261
        rc = connect(sock->socketdes,
 
262
                     (const struct sockaddr *)&sa->sa.sin,
 
263
                     sa->salen);
 
264
    } while (rc == -1 && errno == EINTR);
 
265
 
 
266
    /* we can see EINPROGRESS the first time connect is called on a non-blocking
 
267
     * socket; if called again, we can see EALREADY
 
268
     */
 
269
    if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
 
270
                   && (sock->timeout > 0)) {
 
271
        rc = apr_wait_for_io_or_timeout(NULL, sock, 0);
 
272
        if (rc != APR_SUCCESS) {
 
273
            return rc;
 
274
        }
 
275
 
 
276
#ifdef SO_ERROR
 
277
        {
 
278
            int error;
 
279
            apr_socklen_t len = sizeof(error);
 
280
            if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, 
 
281
                                 (char *)&error, &len)) < 0) {
 
282
                return errno;
 
283
            }
 
284
            if (error) {
 
285
                return error;
 
286
            }
 
287
        }
 
288
#endif /* SO_ERROR */
 
289
    }
 
290
 
 
291
    if (rc == -1 && errno != EISCONN) {
 
292
        return errno;
 
293
    }
 
294
 
 
295
    if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) {
 
296
        /* A real remote address was passed in.  If the unspecified
 
297
         * address was used, the actual remote addr will have to be
 
298
         * determined using getpeername() if required. */
 
299
        /* ### this should probably be a structure copy + fixup as per
 
300
         * _accept()'s handling of local_addr */
 
301
        sock->remote_addr = sa;
 
302
        sock->remote_addr_unknown = 0;
 
303
    }
 
304
 
 
305
    if (sock->local_addr->port == 0) {
 
306
        /* connect() got us an ephemeral port */
 
307
        sock->local_port_unknown = 1;
 
308
    }
 
309
    if (!memcmp(sock->local_addr->ipaddr_ptr,
 
310
                generic_inaddr_any,
 
311
                sock->local_addr->ipaddr_len)) {
 
312
        /* not bound to specific local interface; connect() had to assign
 
313
         * one for the socket
 
314
         */
 
315
        sock->local_interface_unknown = 1;
 
316
    }
 
317
#ifndef HAVE_POLL
 
318
    sock->connected=1;
 
319
#endif
 
320
    return APR_SUCCESS;
 
321
}
 
322
 
 
323
apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type)
 
324
{
 
325
    *type = sock->type;
 
326
    return APR_SUCCESS;
 
327
}
 
328
 
 
329
apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock)
 
330
{
 
331
    sock_userdata_t *cur = sock->userdata;
 
332
 
 
333
    *data = NULL;
 
334
 
 
335
    while (cur) {
 
336
        if (!strcmp(cur->key, key)) {
 
337
            *data = cur->data;
 
338
            break;
 
339
        }
 
340
        cur = cur->next;
 
341
    }
 
342
 
 
343
    return APR_SUCCESS;
 
344
}
 
345
 
 
346
apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key,
 
347
                                 apr_status_t (*cleanup) (void *))
 
348
{
 
349
    sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t));
 
350
 
 
351
    new->key = apr_pstrdup(sock->pool, key);
 
352
    new->data = data;
 
353
    new->next = sock->userdata;
 
354
    sock->userdata = new;
 
355
 
 
356
    if (cleanup) {
 
357
        apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup);
 
358
    }
 
359
 
 
360
    return APR_SUCCESS;
 
361
}
 
362
 
 
363
apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock)
 
364
{
 
365
    *thesock = sock->socketdes;
 
366
    return APR_SUCCESS;
 
367
}
 
368
 
 
369
apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, 
 
370
                              apr_os_sock_info_t *os_sock_info, 
 
371
                              apr_pool_t *cont)
 
372
{
 
373
    alloc_socket(apr_sock, cont);
 
374
    set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol);
 
375
    (*apr_sock)->timeout = -1;
 
376
    (*apr_sock)->socketdes = *os_sock_info->os_sock;
 
377
    if (os_sock_info->local) {
 
378
        memcpy(&(*apr_sock)->local_addr->sa.sin, 
 
379
               os_sock_info->local, 
 
380
               (*apr_sock)->local_addr->salen);
 
381
        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
 
382
        (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
 
383
    }
 
384
    else {
 
385
        (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
 
386
    }
 
387
    if (os_sock_info->remote) {
 
388
#ifndef HAVE_POLL
 
389
        (*apr_sock)->connected = 1;
 
390
#endif
 
391
        memcpy(&(*apr_sock)->remote_addr->sa.sin, 
 
392
               os_sock_info->remote,
 
393
               (*apr_sock)->remote_addr->salen);
 
394
        /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
 
395
        (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
 
396
    }
 
397
    else {
 
398
        (*apr_sock)->remote_addr_unknown = 1;
 
399
    }
 
400
        
 
401
    (*apr_sock)->inherit = 0;
 
402
    apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), 
 
403
                              socket_cleanup, socket_cleanup);
 
404
    return APR_SUCCESS;
 
405
}
 
406
 
 
407
apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, 
 
408
                           apr_pool_t *cont)
 
409
{
 
410
    /* XXX Bogus assumption that *sock points at anything legit */
 
411
    if ((*sock) == NULL) {
 
412
        alloc_socket(sock, cont);
 
413
        /* XXX IPv6 figure out the family here! */
 
414
        /* XXX figure out the actual socket type here */
 
415
        /* *or* just decide that apr_os_sock_put() has to be told the family and type */
 
416
        set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0);
 
417
        (*sock)->timeout = -1;
 
418
    }
 
419
    (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
 
420
    (*sock)->remote_addr_unknown = 1;
 
421
    (*sock)->socketdes = *thesock;
 
422
    return APR_SUCCESS;
 
423
}
 
424
 
 
425
APR_POOL_IMPLEMENT_ACCESSOR(socket)
 
426
 
 
427
APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup)
 
428
 
 
429
APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup)