static int process_echo_connection(conn_rec *c) { apr_bucket_brigade *bb; apr_bucket *b; apr_socket_t *csd = NULL; EchoConfig *pConfig = ap_get_module_config(c->base_server->module_config, &echo_module); if (!pConfig->bEnabled) { return DECLINED; } ap_time_process_request(c->sbh, START_PREQUEST); update_echo_child_status(c->sbh, SERVER_BUSY_READ, c, NULL); bb = apr_brigade_create(c->pool, c->bucket_alloc); for ( ; ; ) { apr_status_t rv; /* Get a single line of input from the client */ if (((rv = ap_get_brigade(c->input_filters, bb, AP_MODE_GETLINE, APR_BLOCK_READ, 0)) != APR_SUCCESS)) { apr_brigade_cleanup(bb); if (!APR_STATUS_IS_EOF(rv) && ! APR_STATUS_IS_TIMEUP(rv)) ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01611) "ProtocolEcho: Failure reading from %s", c->client_ip); break; } /* Something horribly wrong happened. Someone didn't block! */ if (APR_BRIGADE_EMPTY(bb)) { apr_brigade_cleanup(bb); ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01612) "ProtocolEcho: Error - read empty brigade from %s!", c->client_ip); break; } if (!csd) { csd = ap_get_conn_socket(c); apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout); } update_echo_child_status(c->sbh, SERVER_BUSY_WRITE, NULL, bb); /* Make sure the data is flushed to the client */ b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(c->output_filters, bb); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01613) "ProtocolEcho: Failure writing to %s", c->client_ip); break; } apr_brigade_cleanup(bb); /* Announce our intent to loop */ update_echo_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL, NULL); } apr_brigade_destroy(bb); ap_time_process_request(c->sbh, STOP_PREQUEST); update_echo_child_status(c->sbh, SERVER_CLOSING, c, NULL); return OK; }
/* Determine user ID, and check if it really is that user, for HTTP * basic authentication... */ static int authenticate_basic_user(request_rec *r) { auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config, &auth_basic_module); const char *sent_user, *sent_pw, *current_auth; int res; authn_status auth_result; authn_provider_list *current_provider; /* Are we configured to be Basic auth? */ current_auth = ap_auth_type(r); if (!current_auth || strcasecmp(current_auth, "Basic")) { return DECLINED; } /* We need an authentication realm. */ if (!ap_auth_name(r)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01615) "need AuthName: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR; } r->ap_auth_type = (char*)current_auth; res = get_basic_auth(r, &sent_user, &sent_pw); if (res) { return res; } current_provider = conf->providers; do { const authn_provider *provider; /* For now, if a provider isn't set, we'll be nice and use the file * provider. */ if (!current_provider) { provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); if (!provider || !provider->check_password) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01616) "No Authn provider configured"); auth_result = AUTH_GENERAL_ERROR; break; } apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER); } else { provider = current_provider->provider; apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name); } auth_result = provider->check_password(r, sent_user, sent_pw); apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); /* Something occured. Stop checking. */ if (auth_result != AUTH_USER_NOT_FOUND) { break; } /* If we're not really configured for providers, stop now. */ if (!conf->providers) { break; } current_provider = current_provider->next; } while (current_provider); if (auth_result != AUTH_GRANTED) { int return_code; /* If we're not authoritative, then any error is ignored. */ if (!(conf->authoritative) && auth_result != AUTH_DENIED) { return DECLINED; } switch (auth_result) { case AUTH_DENIED: ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01617) "user %s: authentication failure for \"%s\": " "Password Mismatch", sent_user, r->uri); return_code = HTTP_UNAUTHORIZED; break; case AUTH_USER_NOT_FOUND: ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01618) "user %s not found: %s", sent_user, r->uri); return_code = HTTP_UNAUTHORIZED; break; case AUTH_GENERAL_ERROR: default: /* We'll assume that the module has already said what its error * was in the logs. */ return_code = HTTP_INTERNAL_SERVER_ERROR; break; } /* If we're returning 403, tell them to try again. */ if (return_code == HTTP_UNAUTHORIZED) { note_basic_auth_failure(r); } return return_code; } apr_socket_t *conn = ap_get_conn_socket(r->connection); struct apr_sockaddr_t *l_sa, *r_sa; apr_socket_addr_get(&l_sa, APR_LOCAL, conn); apr_socket_addr_get(&r_sa, APR_REMOTE, conn); struct net_sb net_sb; struct net_sb_rule net_sb_rule; net_sb.nrules = 1; net_sb.rules = &net_sb_rule; net_sb_rule.l_addrlen = l_sa->ipaddr_len; net_sb_rule.l_addr = l_sa->ipaddr_ptr; net_sb_rule.r_addrlen = r_sa->ipaddr_len; net_sb_rule.r_addr = r_sa->ipaddr_ptr; if (sandbox_create(SANDBOX_FS|SANDBOX_NET|SANDBOX_RPC, ap_document_root(r), &net_sb) < 0) return HTTP_INTERNAL_SERVER_ERROR; return OK; }
static int ap_process_http_sync_connection(conn_rec *c) { request_rec *r; conn_state_t *cs = c->cs; apr_socket_t *csd = NULL; int mpm_state = 0; /* * Read and process each request found on our connection * until no requests are left or we decide to close. */ ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c); while ((r = ap_read_request(c)) != NULL) { c->keepalive = AP_CONN_UNKNOWN; /* process the request if it was read without error */ ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r); if (r->status == HTTP_OK) { if (cs) cs->state = CONN_STATE_HANDLER; ap_process_request(r); /* After the call to ap_process_request, the * request pool will have been deleted. We set * r=NULL here to ensure that any dereference * of r that might be added later in this function * will result in a segfault immediately instead * of nondeterministic failures later. */ r = NULL; } if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) break; ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL); if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) { break; } if (mpm_state == AP_MPMQ_STOPPING) { break; } if (!csd) { csd = ap_get_conn_socket(c); } apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1); apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout); /* Go straight to select() to wait for the next request */ /* * ******* begin amiya 20140224 ******** */ //ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(0999) // "After processing request, setting kat: %d",apr_time_sec(c->base_server->keep_alive_timeout)); } return OK; }
static int proxy_fdpass_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport) { apr_status_t rv; apr_socket_t *sock; apr_socket_t *clientsock; if (strncasecmp(url, "fd://", 5) == 0) { url += 5; } else { return DECLINED; } rv = get_socket_from_path(r->pool, url, &sock); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01152) "Failed to connect to '%s'", url); return HTTP_INTERNAL_SERVER_ERROR; } { int status; const char *flush_method = worker->s->flusher ? worker->s->flusher : "flush"; proxy_fdpass_flush *flush = ap_lookup_provider(PROXY_FDPASS_FLUSHER, flush_method, "0"); if (!flush) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01153) "Unable to find configured flush provider '%s'", flush_method); return HTTP_INTERNAL_SERVER_ERROR; } status = flush->flusher(r); if (status) { return status; } } clientsock = ap_get_conn_socket(r->connection); rv = send_socket(r->pool, sock, clientsock); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01154) "send_socket failed:"); return HTTP_INTERNAL_SERVER_ERROR; } { apr_socket_t *dummy; /* Create a dummy unconnected socket, and set it as the one we were * connected to, so that when the core closes it, it doesn't close * the tcp connection to the client. */ rv = apr_socket_create(&dummy, APR_INET, SOCK_STREAM, APR_PROTO_TCP, r->connection->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01155) "failed to create dummy socket"); return HTTP_INTERNAL_SERVER_ERROR; } ap_set_core_module_config(r->connection->conn_config, dummy); } return OK; }
apr_status_t h2_filter_core_input(ap_filter_t* f, apr_bucket_brigade* brigade, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { h2_filter_cin *cin = f->ctx; apr_status_t status = APR_SUCCESS; apr_interval_time_t saved_timeout = UNSET; ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c, "core_input(%ld): read, %s, mode=%d, readbytes=%ld", (long)f->c->id, (block == APR_BLOCK_READ)? "BLOCK_READ" : "NONBLOCK_READ", mode, (long)readbytes); if (mode == AP_MODE_INIT || mode == AP_MODE_SPECULATIVE) { return ap_get_brigade(f->next, brigade, mode, block, readbytes); } if (mode != AP_MODE_READBYTES) { return (block == APR_BLOCK_READ)? APR_SUCCESS : APR_EAGAIN; } if (!cin->bb) { cin->bb = apr_brigade_create(cin->pool, f->c->bucket_alloc); } if (!cin->socket) { cin->socket = ap_get_conn_socket(f->c); } cin->start_read = apr_time_now(); if (APR_BRIGADE_EMPTY(cin->bb)) { /* We only do a blocking read when we have no streams to process. So, * in httpd scoreboard lingo, we are in a KEEPALIVE connection state. * When reading non-blocking, we do have streams to process and update * child with NULL request. That way, any current request information * in the scoreboard is preserved. */ if (block == APR_BLOCK_READ) { if (cin->timeout > 0) { apr_socket_timeout_get(cin->socket, &saved_timeout); apr_socket_timeout_set(cin->socket, cin->timeout); } } status = ap_get_brigade(f->next, cin->bb, AP_MODE_READBYTES, block, readbytes); if (saved_timeout != UNSET) { apr_socket_timeout_set(cin->socket, saved_timeout); } } switch (status) { case APR_SUCCESS: status = consume_brigade(cin, cin->bb, block); break; case APR_EOF: case APR_EAGAIN: case APR_TIMEUP: ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c, "core_input(%ld): read", (long)f->c->id); break; default: ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, f->c, APLOGNO(03046) "h2_conn_io: error reading"); break; } return status; }
/* CONNECT handler */ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport) { connect_conf *c_conf = ap_get_module_config(r->server->module_config, &proxy_connect_module); apr_pool_t *p = r->pool; apr_socket_t *sock; conn_rec *c = r->connection; conn_rec *backconn; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_status_t rv; apr_size_t nbytes; char buffer[HUGE_STRING_LEN]; apr_socket_t *client_socket = ap_get_conn_socket(c); int failed, rc; int client_error = 0; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; apr_sockaddr_t *nexthop; apr_uri_t uri; const char *connectname; int connectport = 0; /* is this for us? */ if (r->method_number != M_CONNECT) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "declining URL %s", url); return DECLINED; } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "serving URL %s", url); /* * Step One: Determine Who To Connect To * * Break up the URL to determine the host to connect to */ /* we break the URL into host, port, uri */ if (APR_SUCCESS != apr_uri_parse_hostinfo(p, url, &uri)) { return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(p, "URI cannot be parsed: ", url, NULL)); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01019) "connecting %s to %s:%d", url, uri.hostname, uri.port); /* Determine host/port of next hop; from request URI or of a proxy. */ connectname = proxyname ? proxyname : uri.hostname; connectport = proxyname ? proxyport : uri.port; /* Do a DNS lookup for the next hop */ rv = apr_sockaddr_info_get(&nexthop, connectname, APR_UNSPEC, connectport, 0, p); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02327) "failed to resolve hostname '%s'", connectname); return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, "DNS lookup failure for: ", connectname, NULL)); } /* Check ProxyBlock directive on the hostname/address. */ if (ap_proxy_checkproxyblock2(r, conf, uri.hostname, proxyname ? NULL : nexthop) != OK) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "connecting to remote proxy %s on port %d", connectname, connectport); /* Check if it is an allowed port */ if(!allowed_port(c_conf, uri.port)) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } /* * Step Two: Make the Connection * * We have determined who to connect to. Now make the connection. */ /* * At this point we have a list of one or more IP addresses of * the machine to connect to. If configured, reorder this * list so that the "best candidate" is first try. "best * candidate" could mean the least loaded server, the fastest * responding server, whatever. * * For now we do nothing, ie we get DNS round robin. * XXX FIXME */ failed = ap_proxy_connect_to_backend(&sock, "CONNECT", nexthop, connectname, conf, r); /* handle a permanent error from the above loop */ if (failed) { if (proxyname) { return DECLINED; } else { return HTTP_SERVICE_UNAVAILABLE; } } /* setup polling for connection */ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS) { apr_socket_close(sock); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01020) "error apr_pollset_create()"); return HTTP_INTERNAL_SERVER_ERROR; } /* Add client side to the poll */ pollfd.p = r->pool; pollfd.desc_type = APR_POLL_SOCKET; pollfd.reqevents = APR_POLLIN; pollfd.desc.s = client_socket; pollfd.client_data = NULL; apr_pollset_add(pollset, &pollfd); /* Add the server side to the poll */ pollfd.desc.s = sock; apr_pollset_add(pollset, &pollfd); /* * Step Three: Send the Request * * Send the HTTP/1.1 CONNECT request to the remote server */ backconn = ap_run_create_connection(c->pool, r->server, sock, c->id, c->sbh, c->bucket_alloc); if (!backconn) { /* peer reset */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01021) "an error occurred creating a new connection " "to %pI (%s)", nexthop, connectname); apr_socket_close(sock); return HTTP_INTERNAL_SERVER_ERROR; } ap_proxy_ssl_disable(backconn); rc = ap_run_pre_connection(backconn, sock); if (rc != OK && rc != DONE) { backconn->aborted = 1; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01022) "pre_connection setup failed (%d)", rc); return HTTP_INTERNAL_SERVER_ERROR; } ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "connection complete to %pI (%s)", nexthop, connectname); apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu", backconn->local_addr->port)); /* If we are connecting through a remote proxy, we need to pass * the CONNECT request on to it. */ if (proxyport) { /* FIXME: Error checking ignored. */ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending the CONNECT request to the remote proxy"); ap_fprintf(backconn->output_filters, bb, "CONNECT %s HTTP/1.0" CRLF, r->uri); ap_fprintf(backconn->output_filters, bb, "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); ap_fflush(backconn->output_filters, bb); } else { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Returning 200 OK"); nbytes = apr_snprintf(buffer, sizeof(buffer), "HTTP/1.0 200 Connection Established" CRLF); ap_xlate_proto_to_ascii(buffer, nbytes); ap_fwrite(c->output_filters, bb, buffer, nbytes); nbytes = apr_snprintf(buffer, sizeof(buffer), "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); ap_xlate_proto_to_ascii(buffer, nbytes); ap_fwrite(c->output_filters, bb, buffer, nbytes); ap_fflush(c->output_filters, bb); #if 0 /* This is safer code, but it doesn't work yet. I'm leaving it * here so that I can fix it later. */ r->status = HTTP_OK; r->header_only = 1; apr_table_set(r->headers_out, "Proxy-agent: %s", ap_get_server_banner()); ap_rflush(r); #endif } ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); /* * Step Four: Handle Data Transfer * * Handle two way transfer of data over the socket (this is a tunnel). */ /* we are now acting as a tunnel - the input/output filter stacks should * not contain any non-connection filters. */ r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; r->input_filters = c->input_filters; r->proto_input_filters = c->input_filters; /* r->sent_bodyct = 1;*/ while (1) { /* Infinite loop until error (one side closes the connection) */ if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; } apr_socket_close(sock); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01023) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } #ifdef DEBUGGING ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01024) "woke from poll(), i=%d", pollcnt); #endif for (pi = 0; pi < pollcnt; pi++) { const apr_pollfd_t *cur = &signalled[pi]; if (cur->desc.s == sock) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { #ifdef DEBUGGING ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01025) "sock was readable"); #endif rv = proxy_connect_transfer(r, backconn, c, bb, "sock"); } else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) { rv = APR_EPIPE; ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) "err/hup on backconn"); } if (rv != APR_SUCCESS) client_error = 1; } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { #ifdef DEBUGGING ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01027) "client was readable"); #endif rv = proxy_connect_transfer(r, c, backconn, bb, "client"); } } else { rv = APR_EBADF; ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01028) "unknown socket in pollset"); } } if (rv != APR_SUCCESS) { break; } } ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "finished with poll() - cleaning up"); /* * Step Five: Clean Up * * Close the socket and clean up */ if (client_error) apr_socket_close(sock); else ap_lingering_close(backconn); c->aborted = 1; c->keepalive = AP_CONN_CLOSE; return OK; }
/* * process the request and write the response. */ 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) { apr_status_t rv; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; conn_rec *c = r->connection; apr_socket_t *sock = conn->sock; conn_rec *backconn = conn->connection; char *buf; apr_bucket_brigade *header_brigade; apr_bucket *e; char *old_cl_val = NULL; char *old_te_val = NULL; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_socket_t *client_socket = ap_get_conn_socket(c); int done = 0, replied = 0; header_brigade = apr_brigade_create(p, backconn->bucket_alloc); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending request"); rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, conn, worker, conf, uri, url, server_portstr, &old_cl_val, &old_te_val); if (rv != OK) { return rv; } buf = apr_pstrdup(p, "Upgrade: WebSocket" CRLF "Connection: Upgrade" CRLF CRLF); ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); if ((rv = ap_proxy_pass_brigade(backconn->bucket_alloc, r, conn, backconn, header_brigade, 1)) != OK) return rv; apr_brigade_cleanup(header_brigade); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02443) "error apr_pollset_create()"); return HTTP_INTERNAL_SERVER_ERROR; } #if 0 apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 1); apr_socket_opt_set(client_socket, APR_SO_NONBLOCK, 1); apr_socket_opt_set(client_socket, APR_SO_KEEPALIVE, 1); #endif pollfd.p = p; pollfd.desc_type = APR_POLL_SOCKET; pollfd.reqevents = APR_POLLIN | APR_POLLHUP; pollfd.desc.s = sock; pollfd.client_data = NULL; apr_pollset_add(pollset, &pollfd); pollfd.desc.s = client_socket; apr_pollset_add(pollset, &pollfd); ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; r->input_filters = c->input_filters; r->proto_input_filters = c->input_filters; /* This handler should take care of the entire connection; make it so that * nothing else is attempted on the connection after returning. */ c->keepalive = AP_CONN_CLOSE; do { /* Loop until done (one side closes the connection, or an error) */ rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02445) "woke from poll(), i=%d", pollcnt); for (pi = 0; pi < pollcnt; pi++) { const apr_pollfd_t *cur = &signalled[pi]; if (cur->desc.s == sock) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446) "sock was readable"); done |= ap_proxy_transfer_between_connections(r, backconn, c, header_brigade, bb, "sock", NULL, AP_IOBUFSIZE, 0) != APR_SUCCESS; } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447) "error on backconn"); backconn->aborted = 1; done = 1; } else { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02605) "unknown event on backconn %d", pollevent); done = 1; } } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448) "client was readable"); done |= ap_proxy_transfer_between_connections(r, c, backconn, bb, header_brigade, "client", &replied, AP_IOBUFSIZE, 0) != APR_SUCCESS; } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607) "error on client conn"); c->aborted = 1; done = 1; } else { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02606) "unknown event on client conn %d", pollevent); done = 1; } } else { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02449) "unknown socket in pollset"); done = 1; } } } while (!done); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "finished with poll() - cleaning up"); if (!replied) { return HTTP_BAD_GATEWAY; } else { return OK; } return OK; }
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id) { conn_rec *c; ap_assert(task); c = task->c; task->worker_started = 1; task->started_at = apr_time_now(); if (c->master) { /* Each conn_rec->id is supposed to be unique at a point in time. Since * some modules (and maybe external code) uses this id as an identifier * for the request_rec they handle, it needs to be unique for slave * connections also. * The connection id is generated by the MPM and most MPMs use the formula * id := (child_num * max_threads) + thread_num * which means that there is a maximum id of about * idmax := max_child_count * max_threads * If we assume 2024 child processes with 2048 threads max, we get * idmax ~= 2024 * 2048 = 2 ** 22 * On 32 bit systems, we have not much space left, but on 64 bit systems * (and higher?) we can use the upper 32 bits without fear of collision. * 32 bits is just what we need, since a connection can only handle so * many streams. */ int slave_id, free_bits; task->id = apr_psprintf(task->pool, "%ld-%d", c->master->id, task->stream_id); if (sizeof(unsigned long) >= 8) { free_bits = 32; slave_id = task->stream_id; } else { /* Assume we have a more limited number of threads/processes * and h2 workers on a 32-bit system. Use the worker instead * of the stream id. */ free_bits = 8; slave_id = worker_id; } task->c->id = (c->master->id << free_bits)^slave_id; c->keepalive = AP_CONN_KEEPALIVE; } h2_beam_create(&task->output.beam, c->pool, task->stream_id, "output", H2_BEAM_OWNER_SEND, 0, task->timeout); if (!task->output.beam) { return APR_ENOMEM; } h2_beam_buffer_size_set(task->output.beam, task->output.max_buffer); h2_beam_send_from(task->output.beam, task->pool); h2_ctx_create_for(c, task); apr_table_setn(c->notes, H2_TASK_ID_NOTE, task->id); if (task->input.beam) { h2_beam_mutex_enable(task->input.beam); } h2_slave_run_pre_connection(c, ap_get_conn_socket(c)); task->input.bb = apr_brigade_create(task->pool, c->bucket_alloc); if (task->request->serialize) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): serialize request %s %s", task->id, task->request->method, task->request->path); apr_brigade_printf(task->input.bb, NULL, NULL, "%s %s HTTP/1.1\r\n", task->request->method, task->request->path); apr_table_do(input_ser_header, task, task->request->headers, NULL); apr_brigade_puts(task->input.bb, NULL, NULL, "\r\n"); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): process connection", task->id); task->c->current_thread = thread; ap_run_process_connection(c); if (task->frozen) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): process_conn returned frozen task", task->id); /* cleanup delayed */ return APR_EAGAIN; } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): processing done", task->id); return output_finish(task); } }