Apache HTTPD
mod_proxy_wstunnel.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 "mod_proxy.h"
18#include "http_config.h"
19
20module AP_MODULE_DECLARE_DATA proxy_wstunnel_module;
21
26
28
30{
32 &proxy_wstunnel_module);
33
35 ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "check_trans fallback");
36 return DECLINED;
37 }
38
39 if (ap_cstr_casecmpn(url, "ws:", 3) != 0
40 && ap_cstr_casecmpn(url, "wss:", 4) != 0) {
41 return DECLINED;
42 }
43
44 if (!apr_table_get(r->headers_in, "Upgrade")) {
45 /* No Upgrade, let mod_proxy_http handle it (for instance).
46 * Note: anything but OK/DECLINED will do (i.e. bypass wstunnel w/o
47 * aborting the request), HTTP_UPGRADE_REQUIRED is documentary...
48 */
50 }
51
52 return OK;
53}
54
55/*
56 * Canonicalise http-like URLs.
57 * scheme is the scheme for the URL
58 * url is the URL starting with the first '/'
59 * def_port is the default port for this scheme.
60 */
62{
64 &proxy_wstunnel_module);
65 char *host, *path, sport[7];
66 char *search = NULL;
67 const char *err;
68 char *scheme;
70
72 ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "canon fallback");
73 return DECLINED;
74 }
75
76 /* ap_port_of_scheme() */
77 if (ap_cstr_casecmpn(url, "ws:", 3) == 0) {
78 url += 3;
79 scheme = "ws:";
81 }
82 else if (ap_cstr_casecmpn(url, "wss:", 4) == 0) {
83 url += 4;
84 scheme = "wss:";
86 }
87 else {
88 return DECLINED;
89 }
90
91 port = def_port;
92 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url);
93
94 /*
95 * do syntactic check.
96 * We break the URL into host, port, path, search
97 */
99 if (err) {
100 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02439) "error parsing URL %s: %s",
101 url, err);
102 return HTTP_BAD_REQUEST;
103 }
104
105 /*
106 * now parse path/search args, according to rfc1738:
107 * process the path. With proxy-nocanon set (by
108 * mod_proxy) we use the raw, unparsed uri
109 */
110 if (apr_table_get(r->notes, "proxy-nocanon")) {
111 path = url; /* this is the raw path */
112 }
113 else if (apr_table_get(r->notes, "proxy-noencode")) {
114 path = url; /* this is the encoded path already */
115 search = r->args;
116 }
117 else {
119 int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
120
122 r->proxyreq);
123 if (!path) {
124 return HTTP_BAD_REQUEST;
125 }
126 search = r->args;
127 }
128 /*
129 * If we have a raw control character or a ' ' in nocanon path or
130 * r->args, correct encoding was missed.
131 */
132 if (path == url && *ap_scan_vchar_obstext(path)) {
134 "To be forwarded path contains control "
135 "characters or spaces");
136 return HTTP_FORBIDDEN;
137 }
140 "To be forwarded query string contains control "
141 "characters or spaces");
142 return HTTP_FORBIDDEN;
143 }
144
145 if (port != def_port)
146 apr_snprintf(sport, sizeof(sport), ":%d", port);
147 else
148 sport[0] = '\0';
149
150 if (ap_strchr_c(host, ':')) {
151 /* if literal IPv6 address */
152 host = apr_pstrcat(r->pool, "[", host, "]", NULL);
153 }
154 r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "//", host, sport,
155 "/", path, (search) ? "?" : "",
156 (search) ? search : "", NULL);
157 return OK;
158}
159
160/*
161 * process the request and write the response.
162 */
164 proxy_conn_rec *conn,
165 proxy_worker *worker,
166 proxy_server_conf *conf,
167 apr_uri_t *uri,
168 char *url, char *server_portstr)
169{
170 apr_status_t rv;
173 const apr_pollfd_t *signalled;
177 apr_socket_t *sock = conn->sock;
179 char *buf;
180 apr_bucket_brigade *header_brigade;
181 apr_bucket *e;
182 char *old_cl_val = NULL;
183 char *old_te_val = NULL;
184 apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
185 apr_socket_t *client_socket = ap_get_conn_socket(c);
186 int done = 0, replied = 0;
187 const char *upgrade_method = *worker->s->upgrade ? worker->s->upgrade : "WebSocket";
188
189 header_brigade = apr_brigade_create(p, backconn->bucket_alloc);
190
191 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending request");
192
193 rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, conn,
194 worker, conf, uri, url, server_portstr,
195 &old_cl_val, &old_te_val);
196 if (rv != OK) {
197 return rv;
198 }
199
200 if (ap_cstr_casecmp(upgrade_method, "NONE") == 0) {
201 buf = apr_pstrdup(p, "Upgrade: WebSocket" CRLF "Connection: Upgrade" CRLF CRLF);
202 } else if (ap_cstr_casecmp(upgrade_method, "ANY") == 0) {
203 const char *upgrade;
204 upgrade = apr_table_get(r->headers_in, "Upgrade");
205 buf = apr_pstrcat(p, "Upgrade: ", upgrade, CRLF "Connection: Upgrade" CRLF CRLF, NULL);
206 } else {
207 buf = apr_pstrcat(p, "Upgrade: ", upgrade_method, CRLF "Connection: Upgrade" CRLF CRLF, NULL);
208 }
210 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
211 APR_BRIGADE_INSERT_TAIL(header_brigade, e);
212
213 if ((rv = ap_proxy_pass_brigade(backconn->bucket_alloc, r, conn, backconn,
214 header_brigade, 1)) != OK)
215 return rv;
216
217 apr_brigade_cleanup(header_brigade);
218
219 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()");
220
221 if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) {
223 "error apr_pollset_create()");
225 }
226
227#if 0
230 apr_socket_opt_set(client_socket, APR_SO_NONBLOCK, 1);
231 apr_socket_opt_set(client_socket, APR_SO_KEEPALIVE, 1);
232#endif
233
234 pollfd.p = p;
235 pollfd.desc_type = APR_POLL_SOCKET;
236 pollfd.reqevents = APR_POLLIN | APR_POLLHUP;
237 pollfd.desc.s = sock;
238 pollfd.client_data = NULL;
240
241 pollfd.desc.s = client_socket;
243
244 ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout");
245
246 r->output_filters = c->output_filters;
247 r->proto_output_filters = c->output_filters;
248 r->input_filters = c->input_filters;
249 r->proto_input_filters = c->input_filters;
250
251 /* This handler should take care of the entire connection; make it so that
252 * nothing else is attempted on the connection after returning. */
253 c->keepalive = AP_CONN_CLOSE;
254
255 do { /* Loop until done (one side closes the connection, or an error) */
257 if (rv != APR_SUCCESS) {
258 if (APR_STATUS_IS_EINTR(rv)) {
259 continue;
260 }
261 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()");
263 }
265 "woke from poll(), i=%d", pollcnt);
266
267 for (pi = 0; pi < pollcnt; pi++) {
268 const apr_pollfd_t *cur = &signalled[pi];
269
270 if (cur->desc.s == sock) {
272 if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
274 "sock was readable");
276 c,
277 header_brigade,
278 bb, "sock",
279 &replied,
281 0)
282 != APR_SUCCESS;
283 }
284 else if (pollevent & APR_POLLERR) {
286 "error on backconn");
287 backconn->aborted = 1;
288 done = 1;
289 }
290 else {
292 "unknown event on backconn %d", pollevent);
293 done = 1;
294 }
295 }
296 else if (cur->desc.s == client_socket) {
297 pollevent = cur->rtnevents;
298 if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
300 "client was readable");
302 backconn, bb,
303 header_brigade,
304 "client",
305 NULL,
307 0)
308 != APR_SUCCESS;
309 }
310 else if (pollevent & APR_POLLERR) {
312 "error on client conn");
313 c->aborted = 1;
314 done = 1;
315 }
316 else {
318 "unknown event on client conn %d", pollevent);
319 done = 1;
320 }
321 }
322 else {
324 "unknown socket in pollset");
325 done = 1;
326 }
327
328 }
329 } while (!done);
330
332 "finished with poll() - cleaning up");
333
334 if (!replied) {
335 return HTTP_BAD_GATEWAY;
336 }
337 else {
338 return OK;
339 }
340
341 return OK;
342}
343
344/*
345 */
347 proxy_server_conf *conf,
348 char *url, const char *proxyname,
350{
352 &proxy_wstunnel_module);
353 int status;
354 char server_portstr[32];
355 proxy_conn_rec *backend = NULL;
356 const char *upgrade;
357 char *scheme;
358 apr_pool_t *p = r->pool;
359 char *locurl = url;
360 apr_uri_t *uri;
361 int is_ssl = 0;
362
364 ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "handler fallback");
365 return DECLINED;
366 }
367
368 if (ap_cstr_casecmpn(url, "wss:", 4) == 0) {
369 scheme = "WSS";
370 is_ssl = 1;
371 }
372 else if (ap_cstr_casecmpn(url, "ws:", 3) == 0) {
373 scheme = "WS";
374 }
375 else {
377 "declining URL %s", url);
378 return DECLINED;
379 }
380 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "serving URL %s", url);
381
382 upgrade = apr_table_get(r->headers_in, "Upgrade");
383 if (!upgrade || !ap_proxy_worker_can_upgrade(p, worker, upgrade,
384 "WebSocket")) {
385 const char *worker_upgrade = *worker->s->upgrade ? worker->s->upgrade
386 : "WebSocket";
388 "require upgrade for URL %s "
389 "(Upgrade header is %s, expecting %s)",
390 url, upgrade ? upgrade : "missing", worker_upgrade);
391 apr_table_setn(r->err_headers_out, "Connection", "Upgrade");
394 }
395
396 uri = apr_palloc(p, sizeof(*uri));
397 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02451) "serving URL %s", url);
398
399 /* create space for state information */
400 status = ap_proxy_acquire_connection(scheme, &backend, worker, r->server);
401 if (status != OK) {
402 goto cleanup;
403 }
404
405 backend->is_ssl = is_ssl;
406 backend->close = 0;
407
408 /* Step One: Determine Who To Connect To */
409 status = ap_proxy_determine_connection(p, r, conf, worker, backend,
411 server_portstr,
412 sizeof(server_portstr));
413 if (status != OK) {
414 goto cleanup;
415 }
416
417 /* Step Two: Make the Connection */
418 if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
420 "failed to make connection to backend: %s",
421 backend->hostname);
423 goto cleanup;
424 }
425
426 /* Step Three: Create conn_rec */
427 status = ap_proxy_connection_create_ex(scheme, backend, r);
428 if (status != OK) {
429 goto cleanup;
430 }
431
432 /* Step Four: Process the Request */
433 status = proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl,
434 server_portstr);
435
436cleanup:
437 /* Do not close the socket */
438 if (backend) {
439 backend->close = 1;
440 ap_proxy_release_connection(scheme, backend, r->server);
441 }
442 return status;
443}
444
446{
447 proxyws_dir_conf *new =
449
450 new->fallback_to_proxy_http = 1;
451
452 return (void *) new;
453}
454
455static void *merge_proxyws_dir_config(apr_pool_t *p, void *vbase, void *vadd)
456{
458 *add = vadd, *base = vbase;
459
460 new->fallback_to_proxy_http = (add->fallback_to_proxy_http_set)
461 ? add->fallback_to_proxy_http
462 : base->fallback_to_proxy_http;
463 new->fallback_to_proxy_http_set = (add->fallback_to_proxy_http_set
464 || base->fallback_to_proxy_http_set);
465
466 return new;
467}
468
469static const char * proxyws_fallback_to_proxy_http(cmd_parms *cmd, void *conf, int arg)
470{
471 proxyws_dir_conf *dconf = conf;
472 dconf->fallback_to_proxy_http = !!arg;
474 return NULL;
475}
476
478 apr_pool_t *ptemp, server_rec *s)
479{
481 (ap_find_linked_module("mod_proxy_http.c") != NULL);
482
483 return OK;
484}
485
487{
488 AP_INIT_FLAG("ProxyWebsocketFallbackToProxyHttp",
490 "whether to let mod_proxy_http handle the upgrade and tunneling, "
491 "On by default"),
492
493 {NULL}
494};
495
504
507 create_proxyws_dir_config, /* create per-directory config structure */
508 merge_proxyws_dir_config, /* merge per-directory config structures */
509 NULL, /* create per-server config structure */
510 NULL, /* merge per-server config structures */
511 ws_proxy_cmds, /* command apr_table_t */
512 ws_proxy_hooks /* register hooks */
513};
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
static apr_pool_t * pconf
Definition event.c:441
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
ap_conf_vector_t * base
request_rec int int apr_table_t const char * path
request_rec * r
#define AP_IOBUFSIZE
Definition httpd.h:306
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define ap_xlate_proto_to_ascii(x, y)
Definition util_ebcdic.h:80
apr_status_t ap_remove_input_filter_byhandle(ap_filter_t *next, const char *handle)
#define ap_get_core_module_config(v)
Definition http_core.h:383
apr_socket_t * ap_get_conn_socket(conn_rec *c)
Definition core.c:5202
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define APLOG_INFO
Definition http_log.h:70
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_TRACE5
Definition http_log.h:76
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
const char apr_port_t port
Definition http_vhost.h:125
void * dummy
Definition http_vhost.h:62
const char * host
Definition http_vhost.h:124
void const char * arg
Definition http_vhost.h:63
#define CRLF
Definition httpd.h:724
#define APR_STATUS_IS_EINTR(s)
Definition apr_errno.h:1281
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_bucket * e
const char apr_ssize_t int flags
Definition apr_encode.h:168
const char * url
Definition apr_escape.h:120
const char *const const char *const * aszSucc
Definition apr_hooks.h:346
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
const char * uri
Definition apr_uri.h:159
#define ACCESS_CONF
#define RSRC_CONF
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_SERVICE_UNAVAILABLE
Definition httpd.h:538
#define HTTP_UPGRADE_REQUIRED
Definition httpd.h:530
#define HTTP_BAD_GATEWAY
Definition httpd.h:537
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define HTTP_FORBIDDEN
Definition httpd.h:511
int ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s)
apr_status_t ap_proxy_transfer_between_connections(request_rec *r, conn_rec *c_i, conn_rec *c_o, apr_bucket_brigade *bb_i, apr_bucket_brigade *bb_o, const char *name, int *sent, apr_off_t bsize, int flags)
char * ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, char **passwordp, char **hostp, apr_port_t *port)
Definition proxy_util.c:342
int ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s)
int ap_proxy_acquire_connection(const char *proxy_function, proxy_conn_rec **conn, proxy_worker *worker, server_rec *s)
char * ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, enum enctype t, int flags, int proxyreq)
Definition proxy_util.c:220
#define PROXY_CANONENC_NOENCODEDSLASHENCODING
Definition mod_proxy.h:81
int ap_proxy_worker_can_upgrade(apr_pool_t *p, const proxy_worker *worker, const char *upgrade, const char *dflt)
void proxy_hook_canon_handler(proxy_HOOK_canon_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3412
int ap_proxy_connection_create_ex(const char *proxy_function, proxy_conn_rec *conn, request_rec *r)
int ap_proxy_create_hdrbrgd(apr_pool_t *p, apr_bucket_brigade *header_brigade, request_rec *r, proxy_conn_rec *p_conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr, char **old_cl_val, char **old_te_val)
int ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, proxy_server_conf *conf, proxy_worker *worker, proxy_conn_rec *conn, apr_uri_t *uri, char **url, const char *proxyname, apr_port_t proxyport, char *server_portstr, int server_portstr_size)
void proxy_hook_scheme_handler(proxy_HOOK_scheme_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3406
void proxy_hook_check_trans(proxy_HOOK_check_trans_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3409
int ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, request_rec *r, proxy_conn_rec *p_conn, conn_rec *origin, apr_bucket_brigade *bb, int flush)
@ enc_path
Definition mod_proxy.h:76
#define STANDARD20_MODULE_STUFF
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
#define ap_strchr_c(s, c)
Definition httpd.h:2353
const char * ap_scan_vchar_obstext(const char *ptr)
Definition util.c:1674
int ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
Definition util.c:3559
@ AP_CONN_CLOSE
Definition httpd.h:1145
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void const char apr_status_t(* cleanup)(void *))
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_socket_t * sock
apr_uint16_t apr_port_t
@ APR_POLL_SOCKET
Definition apr_poll.h:93
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
#define APR_SO_KEEPALIVE
#define APR_SO_NONBLOCK
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
int int status
#define APR_POLLERR
Definition apr_poll.h:52
#define APR_POLLIN
Definition apr_poll.h:49
#define APR_POLLHUP
Definition apr_poll.h:53
Apache Configuration.
apr_pool_t * p
Definition md_event.c:32
Proxy Extension Module for Apache.
static void * create_proxyws_dir_config(apr_pool_t *p, char *dummy)
static int can_fallback_to_proxy_http
static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr)
static int proxy_wstunnel_canon(request_rec *r, char *url)
static const char * proxyws_fallback_to_proxy_http(cmd_parms *cmd, void *conf, int arg)
static void ws_proxy_hooks(apr_pool_t *p)
static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport)
static int proxy_wstunnel_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static const command_rec ws_proxy_cmds[]
static int proxy_wstunnel_check_trans(request_rec *r, const char *url)
static void * merge_proxyws_dir_config(apr_pool_t *p, void *vbase, void *vadd)
return NULL
Definition mod_so.c:359
static sed_label_t * search(sed_commands_t *commands)
Definition sed0.c:907
apr_int16_t rtnevents
Definition apr_poll.h:112
Structure to store things which are per connection.
Definition httpd.h:1152
Per-directory configuration.
Definition http_core.h:527
const char * hostname
Definition mod_proxy.h:275
apr_socket_t * sock
Definition mod_proxy.h:278
unsigned int is_ssl
Definition mod_proxy.h:283
unsigned int close
Definition mod_proxy.h:284
conn_rec * connection
Definition mod_proxy.h:270
proxy_worker_shared * s
Definition mod_proxy.h:505
unsigned int fallback_to_proxy_http_set
unsigned int fallback_to_proxy_http
A structure that represents the current request.
Definition httpd.h:845
struct ap_filter_t * output_filters
Definition httpd.h:1070
struct ap_filter_t * proto_input_filters
Definition httpd.h:1079
apr_table_t * notes
Definition httpd.h:985
apr_pool_t * pool
Definition httpd.h:847
char * filename
Definition httpd.h:1018
int proxyreq
Definition httpd.h:873
conn_rec * connection
Definition httpd.h:849
apr_table_t * err_headers_out
Definition httpd.h:981
struct ap_filter_t * proto_output_filters
Definition httpd.h:1076
struct ap_filter_t * input_filters
Definition httpd.h:1072
apr_table_t * headers_in
Definition httpd.h:976
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
char * args
Definition httpd.h:1026
A structure to store information for each virtual server.
Definition httpd.h:1322
static apr_pollset_t * pollset
Definition testpoll.c:41
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition sockopt.c:113