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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
24 #if defined(BEOS) && !defined(BEOS_BONE)
25 #define close closesocket
28 static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */
30 static apr_status_t socket_cleanup(void *sock)
32 apr_socket_t *thesocket = sock;
34 if (close(thesocket->socketdes) == 0) {
35 thesocket->socketdes = -1;
43 static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol)
46 sock->protocol = protocol;
47 apr_sockaddr_vars_set(sock->local_addr, family, 0);
48 apr_sockaddr_vars_set(sock->remote_addr, family, 0);
50 #if defined(BEOS) && !defined(BEOS_BONE)
51 /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be
54 sock->netmask |= APR_TCP_NODELAY;
58 static void alloc_socket(apr_socket_t **new, apr_pool_t *p)
60 *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
62 (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->cntxt,
63 sizeof(apr_sockaddr_t));
64 (*new)->local_addr->pool = p;
65 (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->cntxt,
66 sizeof(apr_sockaddr_t));
67 (*new)->remote_addr->pool = p;
70 apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol)
72 *protocol = sock->protocol;
76 apr_status_t apr_socket_create_ex(apr_socket_t **new, int ofamily, int type,
77 int protocol, apr_pool_t *cont)
81 if (family == APR_UNSPEC) {
89 alloc_socket(new, cont);
91 (*new)->socketdes = socket(family, type, protocol);
94 if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) {
96 (*new)->socketdes = socket(family, type, protocol);
100 if ((*new)->socketdes < 0) {
103 set_socket_vars(*new, family, type, protocol);
105 (*new)->timeout = -1;
107 apr_pool_cleanup_register((*new)->cntxt, (void *)(*new), socket_cleanup,
112 apr_status_t apr_socket_create(apr_socket_t **new, int family, int type,
115 return apr_socket_create_ex(new, family, type, 0, cont);
118 apr_status_t apr_socket_shutdown(apr_socket_t *thesocket,
119 apr_shutdown_how_e how)
121 return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS;
124 apr_status_t apr_socket_close(apr_socket_t *thesocket)
126 return apr_pool_cleanup_run(thesocket->cntxt, thesocket, socket_cleanup);
129 apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
131 if (bind(sock->socketdes,
132 (struct sockaddr *)&sa->sa, sa->salen) == -1) {
136 sock->local_addr = sa;
137 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
138 if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */
139 sock->local_port_unknown = 1; /* kernel got us an ephemeral port */
145 apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog)
147 if (listen(sock->socketdes, backlog) == -1)
153 apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock,
154 apr_pool_t *connection_context)
156 alloc_socket(new, connection_context);
157 set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, sock->protocol);
160 (*new)->connected = 1;
162 (*new)->timeout = -1;
164 (*new)->socketdes = accept(sock->socketdes,
165 (struct sockaddr *)&(*new)->remote_addr->sa,
166 &(*new)->remote_addr->salen);
168 if ((*new)->socketdes < 0) {
172 if ((*new)->socketdes == 0) {
173 /* 0 is an invalid socket for TPF */
178 *(*new)->local_addr = *sock->local_addr;
180 /* The above assignment just overwrote the pool entry. Setting the local_addr
181 pool for the accepted socket back to what it should be. Otherwise all
182 allocations for this socket will come from a server pool that is not
183 freed until the process goes down.*/
184 (*new)->local_addr->pool = connection_context;
186 /* fix up any pointers which are no longer valid */
187 if (sock->local_addr->sa.sin.sin_family == AF_INET) {
188 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
191 else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
192 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
195 (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
196 if (sock->local_port_unknown) {
197 /* not likely for a listening socket, but theoretically possible :) */
198 (*new)->local_port_unknown = 1;
201 #if APR_TCP_NODELAY_INHERITED
202 if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) == 1) {
203 apr_set_option(&(*new)->netmask, APR_TCP_NODELAY, 1);
205 #endif /* TCP_NODELAY_INHERITED */
206 #if APR_O_NONBLOCK_INHERITED
207 if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) == 1) {
208 apr_set_option(&(*new)->netmask, APR_SO_NONBLOCK, 1);
210 #endif /* APR_O_NONBLOCK_INHERITED */
212 if (sock->local_interface_unknown ||
213 !memcmp(sock->local_addr->ipaddr_ptr,
215 sock->local_addr->ipaddr_len)) {
216 /* If the interface address inside the listening socket's local_addr wasn't
217 * up-to-date, we don't know local interface of the connected socket either.
219 * If the listening socket was not bound to a specific interface, we
220 * don't know the local_addr of the connected socket.
222 (*new)->local_interface_unknown = 1;
226 apr_pool_cleanup_register((*new)->cntxt, (void *)(*new), socket_cleanup,
231 apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa)
236 rc = connect(sock->socketdes,
237 (const struct sockaddr *)&sa->sa.sin,
239 } while (rc == -1 && errno == EINTR);
241 /* we can see EINPROGRESS the first time connect is called on a non-blocking
242 * socket; if called again, we can see EALREADY
244 if (rc == -1 && (errno == EINPROGRESS || errno == EALREADY) &&
245 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
246 rc = apr_wait_for_io_or_timeout(NULL, sock, 0);
247 if (rc != APR_SUCCESS) {
254 apr_socklen_t len = sizeof(error);
255 if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR,
256 (char *)&error, &len)) < 0) {
263 #endif /* SO_ERROR */
266 if (rc == -1 && errno != EISCONN) {
270 sock->remote_addr = sa;
271 if (sock->local_addr->port == 0) {
272 /* connect() got us an ephemeral port */
273 sock->local_port_unknown = 1;
275 if (!memcmp(sock->local_addr->ipaddr_ptr,
277 sock->local_addr->ipaddr_len)) {
278 /* not bound to specific local interface; connect() had to assign
281 sock->local_interface_unknown = 1;
289 apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock)
291 sock_userdata_t *cur = sock->userdata;
296 if (!strcmp(cur->key, key)) {
306 apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key,
307 apr_status_t (*cleanup) (void *))
309 sock_userdata_t *new = apr_palloc(sock->cntxt, sizeof(sock_userdata_t));
311 new->key = apr_pstrdup(sock->cntxt, key);
313 new->next = sock->userdata;
314 sock->userdata = new;
317 apr_pool_cleanup_register(sock->cntxt, data, cleanup, cleanup);
323 apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock)
325 *thesock = sock->socketdes;
329 apr_status_t apr_os_sock_make(apr_socket_t **apr_sock,
330 apr_os_sock_info_t *os_sock_info,
333 alloc_socket(apr_sock, cont);
334 #ifdef APR_ENABLE_FOR_1_0 /* no protocol field yet */
335 set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol);
337 set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, 0);
339 (*apr_sock)->timeout = -1;
340 (*apr_sock)->socketdes = *os_sock_info->os_sock;
341 if (os_sock_info->local) {
342 memcpy(&(*apr_sock)->local_addr->sa.sin,
344 (*apr_sock)->local_addr->salen);
345 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
346 (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
349 (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
351 if (os_sock_info->remote) {
353 (*apr_sock)->connected = 1;
355 memcpy(&(*apr_sock)->remote_addr->sa.sin,
356 os_sock_info->remote,
357 (*apr_sock)->remote_addr->salen);
358 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
359 (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
362 (*apr_sock)->remote_addr_unknown = 1;
365 (*apr_sock)->inherit = 0;
366 apr_pool_cleanup_register((*apr_sock)->cntxt, (void *)(*apr_sock),
367 socket_cleanup, socket_cleanup);
371 apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock,
374 /* XXX Bogus assumption that *sock points at anything legit */
375 if ((*sock) == NULL) {
376 alloc_socket(sock, cont);
377 /* XXX IPv6 figure out the family here! */
378 /* XXX figure out the actual socket type here */
379 /* *or* just decide that apr_os_sock_put() has to be told the family and type */
380 set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0);
381 (*sock)->timeout = -1;
383 (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
384 (*sock)->remote_addr_unknown = 1;
385 (*sock)->socketdes = *thesock;
389 APR_IMPLEMENT_INHERIT_SET(socket, inherit, cntxt, socket_cleanup)
391 APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, cntxt, socket_cleanup)
394 apr_status_t apr_shutdown(apr_socket_t *thesocket, apr_shutdown_how_e how)
396 return apr_socket_shutdown(thesocket, how);
400 apr_status_t apr_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
402 return apr_socket_bind(sock, sa);
406 apr_status_t apr_listen(apr_socket_t *sock, apr_int32_t backlog)
408 return apr_socket_listen(sock, backlog);
412 apr_status_t apr_accept(apr_socket_t **new, apr_socket_t *sock,
413 apr_pool_t *connection_context)
415 return apr_socket_accept(new, sock, connection_context);
419 apr_status_t apr_connect(apr_socket_t *sock, apr_sockaddr_t *sa)
421 return apr_socket_connect(sock, sa);