Apache HTTPD
sockets.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_network_io.h"
19#include "apr_general.h"
20#include "apr_lib.h"
21#include "apr_portable.h"
22#include "apr_strings.h"
23#include <string.h>
24#include "apr_arch_inherit.h"
25#include "apr_arch_misc.h"
26
27/* Borrow the definition of SOMAXCONN_HINT() from Windows SDK 8,
28 * in case the SDK we are building against doesn't have it.
29 */
30#ifndef SOMAXCONN_HINT
31#define SOMAXCONN_HINT(b) (-(b))
32#endif
33
34static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */
35
37{
39
40 if (thesocket->socketdes != INVALID_SOCKET) {
41 if (closesocket(thesocket->socketdes) == SOCKET_ERROR) {
42 return apr_get_netos_error();
43 }
44 thesocket->socketdes = INVALID_SOCKET;
45 }
46#if APR_HAS_SENDFILE
47 if (thesocket->overlapped) {
48 CloseHandle(thesocket->overlapped->hEvent);
49 thesocket->overlapped = NULL;
50 }
51#endif
52 return APR_SUCCESS;
53}
54
56{
57 sock->type = type;
61#if APR_HAVE_IPV6
62 /* hard-coded behavior for older Windows IPv6 */
65 }
66#endif
67}
69{
70 *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t));
71 (*new)->pool = p;
72 (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
73 sizeof(apr_sockaddr_t));
74 (*new)->local_addr->pool = p;
75
76 (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool,
77 sizeof(apr_sockaddr_t));
78 (*new)->remote_addr->pool = p;
79 (*new)->remote_addr_unknown = 1;
80
81 /* Create a pollset with room for one descriptor. */
82 /* ### check return codes */
83 (void) apr_pollset_create(&(*new)->pollset, 1, p, 0);
84}
85
92
94 int type, int protocol,
96{
97#if APR_HAVE_IPV6
98 int downgrade = (family == AF_UNSPEC);
99#endif
100
101 if (family == AF_UNSPEC) {
102#if APR_HAVE_IPV6
104#else
105 family = AF_INET;
106#endif
107 }
108
109 alloc_socket(new, cont);
110
111 /* For right now, we are not using socket groups. We may later.
112 * No flags to use when creating a socket, so use 0 for that parameter as well.
113 */
114 (*new)->socketdes = socket(family, type, protocol);
115#if APR_HAVE_IPV6
116 if ((*new)->socketdes == INVALID_SOCKET && downgrade) {
117 family = AF_INET;
118 (*new)->socketdes = socket(family, type, protocol);
119 }
120#endif
121
122 if ((*new)->socketdes == INVALID_SOCKET) {
123 return apr_get_netos_error();
124 }
125
126#ifdef WIN32
127 /* Socket handles are never truly inheritable, there are too many
128 * bugs associated. WSADuplicateSocket will copy them, but for our
129 * purposes, always transform the socket() created as a non-inherited
130 * handle
131 */
132#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE)
134 /* A different approach. Many users report errors such as
135 * (32538)An operation was attempted on something that is not
136 * a socket. : Parent: WSADuplicateSocket failed...
137 *
138 * This appears that the duplicated handle is no longer recognized
139 * as a socket handle. SetHandleInformation should overcome that
140 * problem by not altering the handle identifier. But this won't
141 * work on 9x - it's unsupported.
142 */
143 SetHandleInformation((HANDLE) (*new)->socketdes,
145 }
146#if APR_HAS_ANSI_FS
147 /* only if APR_HAS_ANSI_FS && APR_HAS_UNICODE_FS */
149#endif
150#endif
151#if APR_HAS_ANSI_FS || defined(_WIN32_WCE)
152 {
154 HANDLE dup;
155 if (DuplicateHandle(hProcess, (HANDLE) (*new)->socketdes, hProcess,
157 closesocket((*new)->socketdes);
158 (*new)->socketdes = (SOCKET) dup;
159 }
160 }
161#endif
162
163#endif /* def WIN32 */
164
166
167 (*new)->timeout = -1;
168 (*new)->disconnected = 0;
169
170 apr_pool_cleanup_register((*new)->pool, (void *)(*new),
172
173 return APR_SUCCESS;
174}
175
178{
179 int winhow = 0;
180
181#ifdef SD_RECEIVE
182 switch (how) {
183 case APR_SHUTDOWN_READ: {
185 break;
186 }
187 case APR_SHUTDOWN_WRITE: {
188 winhow = SD_SEND;
189 break;
190 }
192 winhow = SD_BOTH;
193 break;
194 }
195 default:
196 return APR_BADARG;
197 }
198#endif
199 if (shutdown(thesocket->socketdes, winhow) == 0) {
200 return APR_SUCCESS;
201 }
202 else {
203 return apr_get_netos_error();
204 }
205}
206
208{
211}
212
215{
216 if (bind(sock->socketdes,
217 (struct sockaddr *)&sa->sa,
218 sa->salen) == -1) {
219 return apr_get_netos_error();
220 }
221 else {
222 sock->local_addr = sa;
223 if (sock->local_addr->sa.sin.sin_port == 0) {
224 sock->local_port_unknown = 1; /* ephemeral port */
225 }
226 return APR_SUCCESS;
227 }
228}
229
232{
233 int backlog_val;
234
235 if (apr_os_level >= APR_WIN_8) {
236 /* Starting from Windows 8, listen() accepts a special SOMAXCONN_HINT()
237 * arg that allows setting the listen backlog value to a larger
238 * value than the predefined Winsock 2 limit (several hundred).
239 * https://blogs.msdn.microsoft.com/winsdk/2015/06/01/winsocks-listen-backlog-offers-more-flexibility-in-windows-8/
240 */
242 }
243 else {
245 }
246
248 return apr_get_netos_error();
249 else
250 return APR_SUCCESS;
251}
252
255{
256 SOCKET s;
257#if APR_HAVE_IPV6
258 struct sockaddr_storage sa;
259#else
260 struct sockaddr sa;
261#endif
262 int salen = sizeof(sock->remote_addr->sa);
263
264 /* Don't allocate the memory until after we call accept. This allows
265 us to work with nonblocking sockets. */
266 s = accept(sock->socketdes, (struct sockaddr *)&sa, &salen);
267 if (s == INVALID_SOCKET) {
268 return apr_get_netos_error();
269 }
270
271 alloc_socket(new, p);
272 set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM,
273 sock->protocol);
274
275 (*new)->timeout = -1;
276 (*new)->disconnected = 0;
277
278 (*new)->socketdes = s;
279 /* XXX next line looks bogus w.r.t. AF_INET6 support */
280 (*new)->remote_addr->salen = sizeof((*new)->remote_addr->sa);
281 memcpy (&(*new)->remote_addr->sa, &sa, salen);
282 *(*new)->local_addr = *sock->local_addr;
283 (*new)->remote_addr_unknown = 0;
284
285 /* The above assignment just overwrote the pool entry. Setting the local_addr
286 pool for the accepted socket back to what it should be. Otherwise all
287 allocations for this socket will come from a server pool that is not
288 freed until the process goes down.*/
289 (*new)->local_addr->pool = p;
290
291 /* fix up any pointers which are no longer valid */
292 if (sock->local_addr->sa.sin.sin_family == AF_INET) {
293 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr;
294 }
295#if APR_HAVE_IPV6
296 else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
297 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
298 }
299#endif
300 (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
302 /* not likely for a listening socket, but theoretically possible :) */
303 (*new)->local_port_unknown = 1;
304 }
305
306#if APR_TCP_NODELAY_INHERITED
309 }
310#endif /* TCP_NODELAY_INHERITED */
311#if APR_O_NONBLOCK_INHERITED
314 }
315#endif /* APR_O_NONBLOCK_INHERITED */
316
321 /* If the interface address inside the listening socket's local_addr wasn't
322 * up-to-date, we don't know local interface of the connected socket either.
323 *
324 * If the listening socket was not bound to a specific interface, we
325 * don't know the local_addr of the connected socket.
326 */
327 (*new)->local_interface_unknown = 1;
328 }
329
330 apr_pool_cleanup_register((*new)->pool, (void *)(*new),
332 return APR_SUCCESS;
333}
334
336{
337 int rc;
338 struct timeval tv, *tvptr;
340
341 /* wait for the connect to complete or timeout */
342 FD_ZERO(&wfdset);
344 FD_ZERO(&efdset);
346
347 if (sock->timeout < 0) {
348 tvptr = NULL;
349 }
350 else {
351 /* casts for winsock/timeval definition */
352 tv.tv_sec = (long)apr_time_sec(sock->timeout);
353 tv.tv_usec = (int)apr_time_usec(sock->timeout);
354 tvptr = &tv;
355 }
357 if (rc == SOCKET_ERROR) {
358 return apr_get_netos_error();
359 }
360 else if (!rc) {
362 }
363 /* Evaluate the efdset */
364 if (FD_ISSET(sock->socketdes, &efdset)) {
365 /* The connect failed. */
366 int rclen = sizeof(rc);
367 if (getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen)) {
368 return apr_get_netos_error();
369 }
370 return APR_FROM_OS_ERROR(rc);
371 }
372
373 return APR_SUCCESS;
374}
375
378{
379 apr_status_t rv;
380
381 if ((sock->socketdes == INVALID_SOCKET) || (!sock->local_addr)) {
382 return APR_ENOTSOCK;
383 }
384
385 if (connect(sock->socketdes, (const struct sockaddr *)&sa->sa.sin,
386 sa->salen) == SOCKET_ERROR) {
387 rv = apr_get_netos_error();
388 }
389 else {
390 rv = APR_SUCCESS;
391 }
392
394 if (sock->timeout == 0) {
395 /* Tell the app that the connect is in progress...
396 * Gotta play some games here. connect on Unix will return
397 * EINPROGRESS under the same circumstances that Windows
398 * returns WSAEWOULDBLOCK. Do some adhoc canonicalization...
399 */
401 }
402 else {
404 if (rv != APR_SUCCESS) {
405 return rv;
406 }
407 }
408 }
409
411 /* A real remote address was passed in. If the unspecified
412 * address was used, the actual remote addr will have to be
413 * determined using getpeername() if required. */
415
416 /* Copy the address structure details in. */
417 sock->remote_addr->sa = sa->sa;
419 /* Adjust ipaddr_ptr et al. */
421 }
422
423 if (sock->local_addr->sa.sin.sin_port == 0) {
424 /* connect() got us an ephemeral port */
426 }
430 /* not bound to specific local interface; connect() had to assign
431 * one for the socket
432 */
434 }
435
436 if (rv != APR_SUCCESS && rv != APR_FROM_OS_ERROR(WSAEISCONN)) {
437 return rv;
438 }
439
440 return APR_SUCCESS;
441}
442
444{
445 *type = sock->type;
446 return APR_SUCCESS;
447}
448
451{
453
454 *data = NULL;
455
456 while (cur) {
457 if (!strcmp(cur->key, key)) {
458 *data = cur->data;
459 break;
460 }
461 cur = cur->next;
462 }
463
464 return APR_SUCCESS;
465}
466
468 const char *key,
469 apr_status_t (*cleanup)(void *))
470{
472
473 new->key = apr_pstrdup(sock->pool, key);
474 new->data = data;
475 new->next = sock->userdata;
476 sock->userdata = new;
477
478 if (cleanup) {
480 }
481
482 return APR_SUCCESS;
483}
484
487{
489 return APR_SUCCESS;
490}
491
495{
498 (*apr_sock)->timeout = -1;
499 (*apr_sock)->disconnected = 0;
500 (*apr_sock)->socketdes = *os_sock_info->os_sock;
501 if (os_sock_info->local) {
502 memcpy(&(*apr_sock)->local_addr->sa.sin,
504 (*apr_sock)->local_addr->salen);
505 (*apr_sock)->local_addr->pool = cont;
506 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
507 (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port);
508 }
509 else {
510 (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1;
511 }
512 if (os_sock_info->remote) {
513 memcpy(&(*apr_sock)->remote_addr->sa.sin,
515 (*apr_sock)->remote_addr->salen);
516 (*apr_sock)->remote_addr->pool = cont;
517 /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */
518 (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port);
519 (*apr_sock)->remote_addr_unknown = 0;
520 }
521
522 apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock),
524
525 return APR_SUCCESS;
526}
527
531{
532 if ((*sock) == NULL) {
534 /* XXX figure out the actual socket type here */
535 /* *or* just decide that apr_os_sock_put() has to be told the family and type */
537 (*sock)->timeout = -1;
538 (*sock)->disconnected = 0;
539 }
540 (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
541 (*sock)->remote_addr_unknown = 1;
542 (*sock)->socketdes = *thesock;
543 return APR_SUCCESS;
544}
545
546
547/* Sockets cannot be inherited through the standard sockets
548 * inheritence. WSADuplicateSocket must be used.
549 * This is not trivial to implement.
550 */
551
553{
554 return APR_ENOTIMPL;
555}
556
558{
559 return APR_ENOTIMPL;
560}
561
#define FALSE
Definition abts.h:35
#define select
#define listen
#define accept
#define getsockopt
#define socket
#define shutdown
#define connect
#define bind
#define closesocket(sh)
#define GetCurrentProcess()
#define DuplicateHandle(h1, h2, h3, ph4, d1, b, d2)
#define CloseHandle(h)
APR Miscellaneous library routines.
APR general purpose library routines.
APR Network library.
APR Portability Routines.
APR Strings library.
#define APR_BADARG
Definition apr_errno.h:459
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOTSOCK
Definition apr_errno.h:744
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
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
void const char apr_status_t(* cleanup)(void *))
int type
apr_pool_t * cont
Definition apr_getopt.h:103
apr_sockaddr_t * sockaddr
int family
apr_socket_t * sock
apr_sockaddr_t * sa
apr_int32_t backlog
apr_shutdown_how_e how
int int int protocol
apr_shutdown_how_e
@ APR_SHUTDOWN_WRITE
@ APR_SHUTDOWN_READ
@ APR_SHUTDOWN_READWRITE
#define APR_POOL_IMPLEMENT_ACCESSOR(type)
Definition apr_pools.h:91
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int apr_os_sock_t
apr_os_sock_t * thesock
apr_os_sock_info_t * os_sock_info
#define APR_TCP_NODELAY
#define APR_SO_NONBLOCK
#define APR_IPV6_V6ONLY
const char * s
Definition apr_strings.h:95
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_usec(time)
Definition apr_time.h:66
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t)
Definition sockaddr.c:180
static void alloc_socket(apr_socket_t **new, apr_pool_t *p)
Definition sockets.c:58
static apr_status_t socket_cleanup(void *sock)
Definition sockets.c:33
static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol)
Definition sockets.c:50
apr_os_sock_t * os_sock
struct sockaddr * remote
struct sockaddr * local
union apr_sockaddr_t::@55 sa
apr_pool_t * pool
struct sockaddr_in sin
apr_int32_t family
apr_socklen_t salen
apr_pool_t * pool
sock_userdata_t * userdata
apr_interval_time_t timeout
apr_sockaddr_t * remote_addr
apr_sockaddr_t * local_addr
#define apr_is_option_set(skt, option)
#define apr_set_option(skt, option, on)
apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock)
Definition sockets.c:506
apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, apr_pool_t *connection_context)
Definition sockets.c:247
apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog)
Definition sockets.c:239
apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
Definition sockets.c:216
apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, apr_os_sock_info_t *os_sock_info, apr_pool_t *cont)
Definition sockets.c:512
apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, apr_pool_t *cont)
Definition sockets.c:550
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type)
Definition sockets.c:466
apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa)
Definition sockets.c:388
apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol)
Definition sockets.c:110
apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, apr_shutdown_how_e how)
Definition sockets.c:205
static char generic_inaddr_any[16]
Definition sockets.c:36
apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, int protocol, apr_pool_t *cont)
Definition sockets.c:116
apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock)
Definition sockets.c:472
apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, apr_status_t(*cleanup)(void *))
Definition sockets.c:489
#define ELSE_WIN_OS_IS_ANSI
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_8
@ APR_WIN_VISTA
#define IF_WIN_OS_IS_UNICODE
static apr_status_t wait_for_connect(apr_socket_t *sock)
Definition sockets.c:335
#define SOMAXCONN_HINT(b)
Definition sockets.c:31