static void test_atreadeof(abts_case *tc, void *data) { apr_status_t rv; apr_socket_t *sock; apr_socket_t *sock2; apr_proc_t proc; apr_size_t length = STRLEN; char datastr[STRLEN]; int atreadeof = -1; sock = setup_socket(tc); if (!sock) return; launch_child(tc, &proc, "write", p); rv = apr_socket_accept(&sock2, sock, p); APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); /* Check that the remote socket is still open */ rv = apr_socket_atreadeof(sock2, &atreadeof); APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #1", rv); ABTS_INT_EQUAL(tc, 0, atreadeof); memset(datastr, 0, STRLEN); apr_socket_recv(sock2, datastr, &length); /* Make sure that the server received the data we sent */ ABTS_STR_EQUAL(tc, DATASTR, datastr); ABTS_SIZE_EQUAL(tc, strlen(datastr), wait_child(tc, &proc)); /* The child is dead, so should be the remote socket */ rv = apr_socket_atreadeof(sock2, &atreadeof); APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #2", rv); ABTS_INT_EQUAL(tc, 1, atreadeof); rv = apr_socket_close(sock2); APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); launch_child(tc, &proc, "close", p); rv = apr_socket_accept(&sock2, sock, p); APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); /* The child closed the socket as soon as it could... */ rv = apr_socket_atreadeof(sock2, &atreadeof); APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #3", rv); if (!atreadeof) { /* ... but perhaps not yet; wait a moment */ apr_sleep(apr_time_from_msec(5)); rv = apr_socket_atreadeof(sock2, &atreadeof); APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #4", rv); } ABTS_INT_EQUAL(tc, 1, atreadeof); wait_child(tc, &proc); rv = apr_socket_close(sock2); APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); rv = apr_socket_close(sock); APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); }
void _reap_hportal(host_portal_t *hp, int quick) { host_connection_t *hc; apr_status_t value; int count; tbx_stack_move_to_top(hp->closed_que); while ((hc = (host_connection_t *)tbx_stack_get_current_data(hp->closed_que)) != NULL) { apr_thread_join(&value, hc->recv_thread); log_printf(5, "hp=%s ns=%d\n", hp->skey, tbx_ns_getid(hc->ns)); for (count=0; ((quick == 0) || (count < 2)); count++) { lock_hc(hc); //** Make sure that no one is running close_hc() while we're trying to close it if (hc->closing != 1) { //** Ok to to remove it unlock_hc(hc); tbx_stack_delete_current(hp->closed_que, 0, 0); destroy_host_connection(hc); break; } else { //** Got somone trying ot close it so wait a little bit unlock_hc(hc); apr_sleep(apr_time_from_msec(10)); } } tbx_stack_move_down(hp->closed_que); if (tbx_stack_get_current_data(hp->closed_que) == NULL) tbx_stack_move_to_top(hp->closed_que); //** Restart it needed } }
static void closed_connection(serf_connection_t *conn, void *closed_baton, apr_status_t why, apr_pool_t *pool) { s_baton_t *ctx = closed_baton; if (why) { /* justin says that error handling isn't done yet. hah. */ /* XXXXXX: review */ ap_log_rerror(APLOG_MARK, APLOG_ERR, why, ctx->r, APLOGNO(01120) "Closed Connection Error"); ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR; } if (mpm_supprts_serf) { ap_mpm_register_timed_callback(apr_time_from_msec(1), timed_cleanup_callback, ctx); } ctx->keep_reading = 0; }
static void justsleep(abts_case *tc, void *data) { apr_int32_t nsds; const apr_pollfd_t *hot_files; apr_pollset_t *pollset; apr_status_t rv; apr_time_t t1, t2; int i; apr_pollset_method_e methods[] = { APR_POLLSET_DEFAULT, APR_POLLSET_SELECT, APR_POLLSET_KQUEUE, APR_POLLSET_PORT, APR_POLLSET_EPOLL, APR_POLLSET_POLL}; nsds = 1; t1 = apr_time_now(); rv = apr_poll(NULL, 0, &nsds, apr_time_from_msec(200)); t2 = apr_time_now(); ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); ABTS_INT_EQUAL(tc, 0, nsds); ABTS_ASSERT(tc, "apr_poll() didn't sleep", (t2 - t1) > apr_time_from_msec(100)); for (i = 0; i < sizeof methods / sizeof methods[0]; i++) { rv = apr_pollset_create_ex(&pollset, 5, p, 0, methods[i]); if (rv != APR_ENOTIMPL) { ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); nsds = 1; t1 = apr_time_now(); rv = apr_pollset_poll(pollset, apr_time_from_msec(200), &nsds, &hot_files); t2 = apr_time_now(); ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); ABTS_INT_EQUAL(tc, 0, nsds); ABTS_ASSERT(tc, "apr_pollset_poll() didn't sleep", (t2 - t1) > apr_time_from_msec(100)); rv = apr_pollset_destroy(pollset); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); } rv = apr_pollcb_create_ex(&pollcb, 5, p, 0, methods[0]); if (rv != APR_ENOTIMPL) { ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); t1 = apr_time_now(); rv = apr_pollcb_poll(pollcb, apr_time_from_msec(200), NULL, NULL); t2 = apr_time_now(); ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); ABTS_ASSERT(tc, "apr_pollcb_poll() didn't sleep", (t2 - t1) > apr_time_from_msec(100)); /* no apr_pollcb_destroy() */ } } }
/** * A h2_mplx needs to be thread-safe *and* if will be called by * the h2_session thread *and* the h2_worker threads. Therefore: * - calls are protected by a mutex lock, m->lock * - the pool needs its own allocator, since apr_allocator_t are * not re-entrant. The separate allocator works without a * separate lock since we already protect h2_mplx itself. * Since HTTP/2 connections can be expected to live longer than * their HTTP/1 cousins, the separate allocator seems to work better * than protecting a shared h2_session one with an own lock. */ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, const h2_config *conf, apr_interval_time_t stream_timeout, h2_workers *workers) { apr_status_t status = APR_SUCCESS; apr_allocator_t *allocator = NULL; h2_mplx *m; AP_DEBUG_ASSERT(conf); status = apr_allocator_create(&allocator); if (status != APR_SUCCESS) { return NULL; } m = apr_pcalloc(parent, sizeof(h2_mplx)); if (m) { m->id = c->id; APR_RING_ELEM_INIT(m, link); m->c = c; apr_pool_create_ex(&m->pool, parent, NULL, allocator); if (!m->pool) { return NULL; } apr_pool_tag(m->pool, "h2_mplx"); apr_allocator_owner_set(allocator, m->pool); status = apr_thread_mutex_create(&m->lock, APR_THREAD_MUTEX_DEFAULT, m->pool); if (status != APR_SUCCESS) { h2_mplx_destroy(m); return NULL; } status = apr_thread_cond_create(&m->task_thawed, m->pool); if (status != APR_SUCCESS) { h2_mplx_destroy(m); return NULL; } m->bucket_alloc = apr_bucket_alloc_create(m->pool); m->max_streams = h2_config_geti(conf, H2_CONF_MAX_STREAMS); m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM); m->q = h2_iq_create(m->pool, m->max_streams); m->stream_ios = h2_io_set_create(m->pool); m->ready_ios = h2_io_set_create(m->pool); m->stream_timeout = stream_timeout; m->workers = workers; m->workers_max = workers->max_workers; m->workers_def_limit = 4; m->workers_limit = m->workers_def_limit; m->last_limit_change = m->last_idle_block = apr_time_now(); m->limit_change_interval = apr_time_from_msec(200); m->tx_handles_reserved = 0; m->tx_chunk_size = 4; m->spare_slaves = apr_array_make(m->pool, 10, sizeof(conn_rec*)); m->ngn_shed = h2_ngn_shed_create(m->pool, m->c, m->max_streams, m->stream_max_mem); h2_ngn_shed_set_ctx(m->ngn_shed , m); } return m; }
static int client(apr_pool_t *p, client_socket_mode_t socket_mode, const char *host, int start_server) { apr_status_t rv, tmprv; apr_socket_t *sock; char buf[120]; apr_file_t *f = NULL; apr_size_t len; apr_size_t expected_len; apr_off_t current_file_offset; apr_hdtr_t hdtr; struct iovec headers[3]; struct iovec trailers[3]; apr_size_t bytes_read; apr_pollset_t *pset; apr_int32_t nsocks; int connect_tries = 1; int i; int family; apr_sockaddr_t *destsa; apr_proc_t server; apr_interval_time_t connect_retry_interval = apr_time_from_msec(50); if (start_server) { spawn_server(p, &server); connect_tries = 5; /* give it a chance to start up */ } create_testfile(p, TESTFILE); rv = apr_file_open(&f, TESTFILE, APR_FOPEN_READ, 0, p); if (rv != APR_SUCCESS) { aprerr("apr_file_open()", rv); } if (!host) { host = "127.0.0.1"; } family = APR_INET; rv = apr_sockaddr_info_get(&destsa, host, family, TESTSF_PORT, 0, p); if (rv != APR_SUCCESS) { aprerr("apr_sockaddr_info_get()", rv); } while (connect_tries--) { apr_setup(p, &sock, &family); rv = apr_socket_connect(sock, destsa); if (connect_tries && APR_STATUS_IS_ECONNREFUSED(rv)) { apr_status_t tmprv = apr_socket_close(sock); if (tmprv != APR_SUCCESS) { aprerr("apr_socket_close()", tmprv); } apr_sleep(connect_retry_interval); connect_retry_interval *= 2; } else { break; } } if (rv != APR_SUCCESS) { aprerr("apr_socket_connect()", rv); } switch(socket_mode) { case BLK: /* leave it blocking */ break; case NONBLK: /* set it non-blocking */ rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); if (rv != APR_SUCCESS) { aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); } break; case TIMEOUT: /* set a timeout */ rv = apr_socket_timeout_set(sock, 100 * APR_USEC_PER_SEC); if (rv != APR_SUCCESS) { aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); exit(1); } break; default: assert(1 != 1); } printf("Sending the file...\n"); hdtr.headers = headers; hdtr.numheaders = 3; hdtr.headers[0].iov_base = HDR1; hdtr.headers[0].iov_len = strlen(hdtr.headers[0].iov_base); hdtr.headers[1].iov_base = HDR2; hdtr.headers[1].iov_len = strlen(hdtr.headers[1].iov_base); hdtr.headers[2].iov_base = malloc(HDR3_LEN); assert(hdtr.headers[2].iov_base); memset(hdtr.headers[2].iov_base, HDR3_CHAR, HDR3_LEN); hdtr.headers[2].iov_len = HDR3_LEN; hdtr.trailers = trailers; hdtr.numtrailers = 3; hdtr.trailers[0].iov_base = TRL1; hdtr.trailers[0].iov_len = strlen(hdtr.trailers[0].iov_base); hdtr.trailers[1].iov_base = TRL2; hdtr.trailers[1].iov_len = strlen(hdtr.trailers[1].iov_base); hdtr.trailers[2].iov_base = malloc(TRL3_LEN); memset(hdtr.trailers[2].iov_base, TRL3_CHAR, TRL3_LEN); assert(hdtr.trailers[2].iov_base); hdtr.trailers[2].iov_len = TRL3_LEN; expected_len = strlen(HDR1) + strlen(HDR2) + HDR3_LEN + strlen(TRL1) + strlen(TRL2) + TRL3_LEN + FILE_LENGTH; if (socket_mode == BLK) { current_file_offset = 0; len = FILE_LENGTH; rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &len, 0); if (rv != APR_SUCCESS) { aprerr("apr_socket_sendfile()", rv); } printf("apr_socket_sendfile() updated offset with %ld\n", (long int)current_file_offset); printf("apr_socket_sendfile() updated len with %ld\n", (long int)len); printf("bytes really sent: %" APR_SIZE_T_FMT "\n", expected_len); if (len != expected_len) { fprintf(stderr, "apr_socket_sendfile() didn't report the correct " "number of bytes sent!\n"); exit(1); } } else { /* non-blocking... wooooooo */ apr_size_t total_bytes_sent; apr_pollfd_t pfd; pset = NULL; rv = apr_pollset_create(&pset, 1, p, 0); assert(!rv); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLOUT; pfd.rtnevents = 0; pfd.desc.s = sock; pfd.client_data = NULL; rv = apr_pollset_add(pset, &pfd); assert(!rv); total_bytes_sent = 0; current_file_offset = 0; len = FILE_LENGTH; do { apr_size_t tmplen; tmplen = len; /* bytes remaining to send from the file */ printf("Calling apr_socket_sendfile()...\n"); printf("Headers (%d):\n", hdtr.numheaders); for (i = 0; i < hdtr.numheaders; i++) { printf("\t%ld bytes (%c)\n", (long)hdtr.headers[i].iov_len, *(char *)hdtr.headers[i].iov_base); } printf("File: %ld bytes from offset %ld\n", (long)tmplen, (long)current_file_offset); printf("Trailers (%d):\n", hdtr.numtrailers); for (i = 0; i < hdtr.numtrailers; i++) { printf("\t%ld bytes\n", (long)hdtr.trailers[i].iov_len); } rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &tmplen, 0); printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { assert(tmplen == 0); nsocks = 1; tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL); assert(!tmprv); assert(nsocks == 1); /* continue; */ } } total_bytes_sent += tmplen; /* Adjust hdtr to compensate for partially-written * data. */ /* First, skip over any header data which might have * been written. */ while (tmplen && hdtr.numheaders) { if (tmplen >= hdtr.headers[0].iov_len) { tmplen -= hdtr.headers[0].iov_len; --hdtr.numheaders; ++hdtr.headers; } else { hdtr.headers[0].iov_len -= tmplen; hdtr.headers[0].iov_base = (char*) hdtr.headers[0].iov_base + tmplen; tmplen = 0; } } /* Now, skip over any file data which might have been * written. */ if (tmplen <= len) { current_file_offset += tmplen; len -= tmplen; tmplen = 0; } else { tmplen -= len; len = 0; current_file_offset = 0; } /* Last, skip over any trailer data which might have * been written. */ while (tmplen && hdtr.numtrailers) { if (tmplen >= hdtr.trailers[0].iov_len) { tmplen -= hdtr.trailers[0].iov_len; --hdtr.numtrailers; ++hdtr.trailers; } else { hdtr.trailers[0].iov_len -= tmplen; hdtr.trailers[0].iov_base = (char *)hdtr.trailers[0].iov_base + tmplen; tmplen = 0; } } } while (total_bytes_sent < expected_len && (rv == APR_SUCCESS || (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT))); if (total_bytes_sent != expected_len) { fprintf(stderr, "client problem: sent %ld of %ld bytes\n", (long)total_bytes_sent, (long)expected_len); exit(1); } if (rv) { fprintf(stderr, "client problem: rv %d\n", rv); exit(1); } } current_file_offset = 0; rv = apr_file_seek(f, APR_CUR, ¤t_file_offset); if (rv != APR_SUCCESS) { aprerr("apr_file_seek()", rv); } printf("After apr_socket_sendfile(), the kernel file pointer is " "at offset %ld.\n", (long int)current_file_offset); rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE); if (rv != APR_SUCCESS) { aprerr("apr_socket_shutdown()", rv); } /* in case this is the non-blocking test, set socket timeout; * we're just waiting for EOF */ rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv != APR_SUCCESS) { aprerr("apr_socket_timeout_set()", rv); } bytes_read = 1; rv = apr_socket_recv(sock, buf, &bytes_read); if (rv != APR_EOF) { aprerr("apr_socket_recv() (expected APR_EOF)", rv); } if (bytes_read != 0) { fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" "but instead we read %ld bytes.\n", (long int)bytes_read); exit(1); } printf("client: apr_socket_sendfile() worked as expected!\n"); rv = apr_file_remove(TESTFILE, p); if (rv != APR_SUCCESS) { aprerr("apr_file_remove()", rv); } if (start_server) { apr_exit_why_e exitwhy; apr_size_t nbytes; char responsebuf[1024]; int exitcode; rv = apr_file_pipe_timeout_set(server.out, apr_time_from_sec(2)); if (rv != APR_SUCCESS) { aprerr("apr_file_pipe_timeout_set()", rv); } nbytes = sizeof(responsebuf); rv = apr_file_read(server.out, responsebuf, &nbytes); if (rv != APR_SUCCESS) { aprerr("apr_file_read() messages from server", rv); } printf("%.*s", (int)nbytes, responsebuf); rv = apr_proc_wait(&server, &exitcode, &exitwhy, APR_WAIT); if (rv != APR_CHILD_DONE) { aprerr("apr_proc_wait() (expected APR_CHILD_DONE)", rv); } if (exitcode != 0) { fprintf(stderr, "sendfile server returned %d\n", exitcode); exit(1); } } return 0; }
static apr_status_t handle_response(serf_request_t *request, serf_bucket_t *response, void *vbaton, apr_pool_t *pool) { apr_status_t rv; s_baton_t *ctx = vbaton; const char *data; apr_size_t len; serf_status_line sl; if (response == NULL) { ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } /* XXXXXXX: Create better error message. */ rv = serf_bucket_response_status(response, &sl); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { return APR_SUCCESS; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01121) "serf_bucket_response_status..."); ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR; if (mpm_supprts_serf) { ap_mpm_register_timed_callback(apr_time_from_msec(1), timed_cleanup_callback, ctx); } return rv; } /** * XXXXX: If I understood serf buckets better, it might be possible to not * copy all of the data here, and better stream it to the client. **/ do { apr_brigade_cleanup(ctx->tmpbb); rv = serf_bucket_read(response, AP_IOBUFSIZE, &data, &len); if (SERF_BUCKET_READ_ERROR(rv)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01122) "serf_bucket_read(response)"); return rv; } if (!ctx->done_headers) { serf_bucket_t *hdrs; serf_status_line line; /* TODO: improve */ serf_bucket_response_status(response, &line); ctx->r->status = line.code; hdrs = serf_bucket_response_get_headers(response); serf_bucket_headers_do(hdrs, copy_headers_out, ctx); ctx->done_headers = 1; } if (len > 0) { /* TODO: make APR bucket <-> serf bucket stuff more magical. */ apr_brigade_write(ctx->tmpbb, NULL, NULL, data, len); } if (APR_STATUS_IS_EOF(rv)) { ctx->keep_reading = 0; ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb); if (mpm_supprts_serf) { ap_mpm_register_timed_callback(apr_time_from_msec(1), timed_cleanup_callback, ctx); } return APR_EOF; } ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb); /* XXXX: Should we send a flush now? */ if (APR_STATUS_IS_EAGAIN(rv)) { return APR_SUCCESS; } } while (1); }