/** Create interruptable pollset on top of APR pollset */ APT_DECLARE(apt_pollset_t*) apt_pollset_create(apr_uint32_t size, apr_pool_t *pool) { apt_pollset_t *pollset = apr_palloc(pool,sizeof(apt_pollset_t)); pollset->pool = pool; memset(&pollset->wakeup_pfd,0,sizeof(pollset->wakeup_pfd)); /* create pollset with max number of descriptors size+1, where +1 is builtin wakeup descriptor */ if(apr_pollset_create(&pollset->base,size+1,pool,0) != APR_SUCCESS) { return NULL; } /* create wakeup pipe */ if(apt_wakeup_pipe_create(pollset) != TRUE) { apr_pollset_destroy(pollset->base); return NULL; } /* add wakeup pipe to pollset */ if(apr_pollset_add(pollset->base,&pollset->wakeup_pfd) != APR_SUCCESS) { apt_wakeup_pipe_destroy(pollset); apr_pollset_destroy(pollset->base); return NULL; } return pollset; }
static apt_bool_t mrcp_client_agent_pollset_create(mrcp_connection_agent_t *agent) { apr_status_t status; /* create pollset */ status = apr_pollset_create(&agent->pollset, (apr_uint32_t)agent->max_connection_count + 1, agent->pool, 0); if(status != APR_SUCCESS) { apt_log(APT_PRIO_WARNING,"Failed to Create Pollset"); return FALSE; } /* create control socket */ if(mrcp_client_agent_control_socket_create(agent) != TRUE) { apt_log(APT_PRIO_WARNING,"Failed to Create Control Socket"); apr_pollset_destroy(agent->pollset); return FALSE; } /* add control socket to pollset */ agent->control_sock_pfd.desc_type = APR_POLL_SOCKET; agent->control_sock_pfd.reqevents = APR_POLLIN; agent->control_sock_pfd.desc.s = agent->control_sock; agent->control_sock_pfd.client_data = agent->control_sock; status = apr_pollset_add(agent->pollset, &agent->control_sock_pfd); if(status != APR_SUCCESS) { apt_log(APT_PRIO_WARNING,"Failed to Add Control Socket to Pollset"); mrcp_client_agent_control_socket_destroy(agent); apr_pollset_destroy(agent->pollset); return FALSE; } return TRUE; }
apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, int for_read) { apr_interval_time_t timeout; apr_pollfd_t pfd; int type = for_read ? APR_POLLIN : APR_POLLOUT; apr_pollset_t *pollset; apr_status_t status; /* TODO - timeout should be less each time through this loop */ if (f) { pfd.desc_type = APR_POLL_FILE; pfd.desc.f = f; pollset = f->pollset; if (pollset == NULL) { status = apr_pollset_create(&(f->pollset), 1, f->pool, 0); if (status != APR_SUCCESS) { return status; } pollset = f->pollset; } timeout = f->timeout; } else { pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = s; pollset = s->pollset; timeout = s->timeout; } pfd.reqevents = type; /* Remove the object if it was in the pollset, then add in the new * object with the correct reqevents value. Ignore the status result * on the remove, because it might not be in there (yet). */ (void) apr_pollset_remove(pollset, &pfd); /* ### check status code */ (void) apr_pollset_add(pollset, &pfd); do { int numdesc; const apr_pollfd_t *pdesc; status = apr_pollset_poll(pollset, timeout, &numdesc, &pdesc); if (numdesc == 1 && (pdesc[0].rtnevents & type) != 0) { return APR_SUCCESS; } } while (APR_STATUS_IS_EINTR(status)); return status; }
serf_context_t *serf_context_create_ex( void *user_baton, serf_socket_add_t addf, serf_socket_remove_t rmf, apr_pool_t *pool) { serf_context_t *ctx = apr_pcalloc(pool, sizeof(*ctx)); ctx->pool = pool; if (user_baton != NULL) { ctx->pollset_baton = user_baton; ctx->pollset_add = addf; ctx->pollset_rm = rmf; } else { /* build the pollset with a (default) number of connections */ serf_pollset_t *ps = apr_pcalloc(pool, sizeof(*ps)); /* ### TODO: As of APR 1.4.x apr_pollset_create_ex can return a status ### other than APR_SUCCESS, so we should handle it. ### Probably move creation of the pollset to later when we have ### the possibility of returning status to the caller. */ #ifdef BROKEN_WSAPOLL /* APR 1.4.x switched to using WSAPoll() on Win32, but it does not * properly handle errors on a non-blocking sockets (such as * connecting to a server where no listener is active). * * So, sadly, we must force using select() on Win32. * * http://mail-archives.apache.org/mod_mbox/apr-dev/201105.mbox/%[email protected]%3E */ (void) apr_pollset_create_ex(&ps->pollset, MAX_CONN, pool, 0, APR_POLLSET_SELECT); #else (void) apr_pollset_create(&ps->pollset, MAX_CONN, pool, 0); #endif ctx->pollset_baton = ps; ctx->pollset_add = pollset_add; ctx->pollset_rm = pollset_rm; } /* default to a single connection since that is the typical case */ ctx->conns = apr_array_make(pool, 1, sizeof(serf_connection_t *)); /* Initialize progress status */ ctx->progress_read = 0; ctx->progress_written = 0; ctx->authn_types = SERF_AUTHN_ALL; ctx->server_authn_info = apr_hash_make(pool); return ctx; }
APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, apr_file_t **out, apr_pool_t *pool) { int filedes[2]; int err; if (pipe(filedes) == -1) { return errno; } (*in) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); (*out) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); (*in)->pool = (*out)->pool = pool; (*in)->filedes = filedes[0]; (*out)->filedes = filedes[1]; (*in)->flags = APR_INHERIT; (*out)->flags = APR_INHERIT; (*in)->is_pipe = (*out)->is_pipe = 1; (*out)->fname = (*in)->fname = NULL; (*in)->buffered = (*out)->buffered = 0; (*in)->blocking = (*out)->blocking = BLK_ON; (*in)->timeout = (*out)->timeout = -1; (*in)->ungetchar = -1; (*in)->thlock = (*out)->thlock = NULL; (void) apr_pollset_create(&(*in)->pollset, 1, pool, 0); (void) apr_pollset_create(&(*out)->pollset, 1, pool, 0); apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup, apr_pool_cleanup_null); apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; }
void LLPumpIO::rebuildPollset() { LLMemType m1(LLMemType::MTYPE_IO_PUMP); // lldebugs << "LLPumpIO::rebuildPollset()" << llendl; if(mPollset) { //lldebugs << "destroying pollset" << llendl; apr_pollset_destroy(mPollset); mPollset = NULL; } U32 size = 0; running_chains_t::iterator run_it = mRunningChains.begin(); running_chains_t::iterator run_end = mRunningChains.end(); for(; run_it != run_end; ++run_it) { size += (*run_it).mDescriptors.size(); } //lldebugs << "found " << size << " descriptors." << llendl; if(size) { // Recycle the memory pool const S32 POLLSET_POOL_RECYCLE_COUNT = 100; if(mCurrentPool && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT))) { apr_pool_destroy(mCurrentPool); mCurrentPool = NULL; mCurrentPoolReallocCount = 0; } if(!mCurrentPool) { apr_status_t status = apr_pool_create(&mCurrentPool, mPool); (void)ll_apr_warn_status(status); } // add all of the file descriptors run_it = mRunningChains.begin(); LLChainInfo::conditionals_t::iterator fd_it; LLChainInfo::conditionals_t::iterator fd_end; apr_pollset_create(&mPollset, size, mCurrentPool, 0); for(; run_it != run_end; ++run_it) { fd_it = (*run_it).mDescriptors.begin(); fd_end = (*run_it).mDescriptors.end(); for(; fd_it != fd_end; ++fd_it) { apr_pollset_add(mPollset, &((*fd_it).second)); } } } }
int poll_worker_create( poll_worker_t **worker, poll_mgr_t *mgr) { poll_worker_t *w = (poll_worker_t*) malloc(sizeof(poll_worker_t)); w->mgr = mgr; apr_pool_create(&w->mp_poll, NULL); w->ht_jobs = apr_hash_make(w->mp_poll); apr_thread_mutex_create(&w->mx_poll, APR_THREAD_MUTEX_UNNESTED, w->mp_poll); apr_pollset_create(&w->ps, 1000, w->mp_poll, APR_POLLSET_THREADSAFE); w->fg_exit = false; poll_worker_start(w); *worker = w; return 0; }
/* Create a CGI bucket using pipes from script stdout 'out' * and stderr 'err', for request 'r'. */ static apr_bucket *cgi_bucket_create(request_rec *r, apr_file_t *out, apr_file_t *err, apr_bucket_alloc_t *list) { apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); apr_status_t rv; apr_pollfd_t fd; struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; b->type = &bucket_type_cgi; b->length = (apr_size_t)(-1); b->start = -1; /* Create the pollset */ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) "apr_pollset_create(); check system or user limits"); return NULL; } fd.desc_type = APR_POLL_FILE; fd.reqevents = APR_POLLIN; fd.p = r->pool; fd.desc.f = out; /* script's stdout */ fd.client_data = (void *)1; rv = apr_pollset_add(data->pollset, &fd); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) "apr_pollset_add(); check system or user limits"); return NULL; } fd.desc.f = err; /* script's stderr */ fd.client_data = (void *)2; rv = apr_pollset_add(data->pollset, &fd); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) "apr_pollset_add(); check system or user limits"); return NULL; } data->r = r; b->data = data; return b; }
APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p) { #ifdef _WIN32_WCE return APR_ENOTIMPL; #else HANDLE hproc = GetCurrentProcess(); HANDLE newhand = NULL; if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, 0, FALSE, DUPLICATE_SAME_ACCESS)) { return apr_get_os_error(); } (*new_file) = (apr_file_t *) apr_pcalloc(p, sizeof(apr_file_t)); (*new_file)->filehand = newhand; (*new_file)->flags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT); (*new_file)->pool = p; (*new_file)->fname = apr_pstrdup(p, old_file->fname); (*new_file)->append = old_file->append; (*new_file)->buffered = FALSE; (*new_file)->ungetchar = old_file->ungetchar; #if APR_HAS_THREADS if (old_file->mutex) { apr_thread_mutex_create(&((*new_file)->mutex), APR_THREAD_MUTEX_DEFAULT, p); } #endif apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), file_cleanup, apr_pool_cleanup_null); #if APR_FILES_AS_SOCKETS /* Create a pollset with room for one descriptor. */ /* ### check return codes */ (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); #endif return APR_SUCCESS; #endif /* !defined(_WIN32_WCE) */ }
APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p) { *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t)); memcpy(*new_file, old_file, sizeof(apr_file_t)); (*new_file)->pool = p; if (old_file->buffered) { (*new_file)->buffer = apr_palloc(p, old_file->bufsize); (*new_file)->bufsize = old_file->bufsize; if (old_file->direction == 1) { memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); } else { memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); } } if (old_file->mutex) { apr_thread_mutex_create(&((*new_file)->mutex), APR_THREAD_MUTEX_DEFAULT, p); apr_thread_mutex_destroy(old_file->mutex); } if (old_file->fname) { (*new_file)->fname = apr_pstrdup(p, old_file->fname); } if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { apr_pool_cleanup_register(p, (void *)(*new_file), file_cleanup, file_cleanup); } old_file->filehand = INVALID_HANDLE_VALUE; apr_pool_cleanup_kill(old_file->pool, (void *)old_file, file_cleanup); #if APR_FILES_AS_SOCKETS /* Create a pollset with room for one descriptor. */ /* ### check return codes */ (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); #endif return APR_SUCCESS; }
/* XXX: Problem; we need to choose between blocking and nonblocking based * on how *thefile was opened, and we don't have that information :-/ * Hack; assume a blocking socket, since the most common use for the fn * would be to handle stdio-style or blocking pipes. Win32 doesn't have * select() blocking for pipes anyways :( */ APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, apr_os_file_t *thefile, int register_cleanup, apr_pool_t *pool) { (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); (*file)->pool = pool; (*file)->pipe = 1; (*file)->timeout = -1; (*file)->ungetchar = -1; (*file)->filehand = *thefile; (void) apr_pollset_create(&(*file)->pollset, 1, pool, 0); if (register_cleanup) { apr_pool_cleanup_register(pool, *file, file_cleanup, apr_pool_cleanup_null); } return APR_SUCCESS; }
/* Create a CGI bucket using pipes from script stdout 'out' * and stderr 'err', for request 'r'. */ static apr_bucket *cgi_bucket_create(request_rec *r, apr_file_t *out, apr_file_t *err, apr_bucket_alloc_t *list) { apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); apr_status_t rv; apr_pollfd_t fd; struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; b->type = &bucket_type_cgi; b->length = (apr_size_t)(-1); b->start = -1; /* Create the pollset */ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); AP_DEBUG_ASSERT(rv == APR_SUCCESS); fd.desc_type = APR_POLL_FILE; fd.reqevents = APR_POLLIN; fd.p = r->pool; fd.desc.f = out; /* script's stdout */ fd.client_data = (void *)1; rv = apr_pollset_add(data->pollset, &fd); AP_DEBUG_ASSERT(rv == APR_SUCCESS); fd.desc.f = err; /* script's stderr */ fd.client_data = (void *)2; rv = apr_pollset_add(data->pollset, &fd); AP_DEBUG_ASSERT(rv == APR_SUCCESS); data->r = r; b->data = data; return b; }
int sock_listen(net_sock_t *nsock, int max_pending) { int err; network_sock_t *sock = (network_sock_t *)nsock; if (sock == NULL) return(1); err = apr_socket_listen(sock->fd, max_pending); if (err != APR_SUCCESS) return(err); //** Create the polling info apr_pollset_create(&(sock->pollset), 1, sock->mpool, APR_POLLSET_THREADSAFE); // sock->pfd = { sock->mpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL }; sock->pfd.p = sock->mpool; sock->pfd.desc_type = APR_POLL_SOCKET; sock->pfd.reqevents = APR_POLLIN; sock->pfd.rtnevents = 0; sock->pfd.desc.s = sock->fd; sock->pfd.client_data = NULL; apr_pollset_add(sock->pollset, &(sock->pfd)); return(0); }
SWITCH_DECLARE(switch_status_t) switch_pollset_create(switch_pollset_t ** pollset, uint32_t size, switch_memory_pool_t *p, uint32_t flags) { return apr_pollset_create(pollset, size, p, flags); }
void LLPluginProcessParent::updatePollset() { if(!sInstancesMutex) { // No instances have been created yet. There's no work to do. return; } LLMutexLock lock(sInstancesMutex); if(sPollSet) { LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL; // delete the existing pollset. apr_pollset_destroy(sPollSet); sPollSet = NULL; sPollSetPool.destroy(); } std::list<LLPluginProcessParent*>::iterator iter; int count = 0; // Count the number of instances that want to be in the pollset for(iter = sInstances.begin(); iter != sInstances.end(); iter++) { (*iter)->mPolledInput = false; if((*iter)->mPollFD.client_data) { // This instance has a socket that needs to be polled. ++count; } } if(sUseReadThread && sReadThread && !sReadThread->isQuitting()) { if(!sPollSet && (count > 0)) { #ifdef APR_POLLSET_NOCOPY // The pollset doesn't exist yet. Create it now. sPollSetPool.create(); apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY); if(status != APR_SUCCESS) { #endif // APR_POLLSET_NOCOPY LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL; sPollSet = NULL; sPollSetPool.destroy(); #ifdef APR_POLLSET_NOCOPY } else { LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL; // Pollset was created, add all instances to it. for(iter = sInstances.begin(); iter != sInstances.end(); iter++) { if((*iter)->mPollFD.client_data) { status = apr_pollset_add(sPollSet, &((*iter)->mPollFD)); if(status == APR_SUCCESS) { (*iter)->mPolledInput = true; } else { LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL; } } } } #endif // APR_POLLSET_NOCOPY } } }
apr_status_t run_test_server(serv_ctx_t *servctx, apr_short_interval_time_t duration, apr_pool_t *pool) { apr_status_t status; apr_pollset_t *pollset; apr_int32_t num; const apr_pollfd_t *desc; /* create a new pollset */ #ifdef BROKEN_WSAPOLL status = apr_pollset_create_ex(&pollset, 32, pool, 0, APR_POLLSET_SELECT); #else status = apr_pollset_create(&pollset, 32, pool, 0); #endif if (status != APR_SUCCESS) return status; /* Don't accept new connection while processing client connection. At least for present time.*/ if (servctx->client_sock) { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = servctx->client_sock; pfd.reqevents = APR_POLLIN | APR_POLLOUT; status = apr_pollset_add(pollset, &pfd); if (status != APR_SUCCESS) goto cleanup; if (servctx->proxy_client_sock) { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = servctx->proxy_client_sock; pfd.reqevents = APR_POLLIN | APR_POLLOUT; status = apr_pollset_add(pollset, &pfd); if (status != APR_SUCCESS) goto cleanup; } } else { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = servctx->serv_sock; pfd.reqevents = APR_POLLIN; status = apr_pollset_add(pollset, &pfd); if (status != APR_SUCCESS) goto cleanup; } status = apr_pollset_poll(pollset, APR_USEC_PER_SEC >> 1, &num, &desc); if (status != APR_SUCCESS) goto cleanup; while (num--) { if (desc->desc.s == servctx->serv_sock) { status = apr_socket_accept(&servctx->client_sock, servctx->serv_sock, servctx->pool); if (status != APR_SUCCESS) goto cleanup; serf__log_skt(TEST_VERBOSE, __FILE__, servctx->client_sock, "server/proxy accepted incoming connection.\n"); apr_socket_opt_set(servctx->client_sock, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(servctx->client_sock, 0); status = APR_SUCCESS; goto cleanup; } if (desc->desc.s == servctx->client_sock) { if (servctx->handshake) { status = servctx->handshake(servctx); if (status) goto cleanup; } /* Replay data to socket. */ status = replay(servctx, desc->rtnevents, pool); if (APR_STATUS_IS_EOF(status)) { apr_socket_close(servctx->client_sock); servctx->client_sock = NULL; if (servctx->reset) servctx->reset(servctx); /* If this is a proxy and the client closed the connection, also close the connection to the server. */ if (servctx->proxy_client_sock) { apr_socket_close(servctx->proxy_client_sock); servctx->proxy_client_sock = NULL; goto cleanup; } } else if (APR_STATUS_IS_EAGAIN(status)) { status = APR_SUCCESS; } else if (status != APR_SUCCESS) { /* Real error. */ goto cleanup; } } if (desc->desc.s == servctx->proxy_client_sock) { /* Replay data to proxy socket. */ status = proxy_replay(servctx, desc->rtnevents, pool); if (APR_STATUS_IS_EOF(status)) { apr_socket_close(servctx->proxy_client_sock); servctx->proxy_client_sock = NULL; } else if (APR_STATUS_IS_EAGAIN(status)) { status = APR_SUCCESS; } else if (status != APR_SUCCESS) { /* Real error. */ goto cleanup; } } desc++; } cleanup: apr_pollset_destroy(pollset); return status; }
//static void child_main(int child_num_arg) void body() { mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ my_child_num = child_num_arg; ap_my_pid = getpid(); requests_this_child = 0; ap_fatal_signal_child_setup(ap_server_conf); /* Get a sub context for global allocations in this child, so that * we can have cleanups occur when the child exits. */ apr_allocator_create(allocator); //// removed deref apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(pchild, pconf, NULL, allocator); //// removed deref apr_allocator_owner_set(allocator, pchild); apr_pool_create(ptrans, pchild); //// removed deref apr_pool_tag(ptrans, 65); // "transaction"); /* needs to be done before we switch UIDs so we have permissions */ ap_reopen_scoreboard(pchild, NULL, 0); status = apr_proc_mutex_child_init(accept_mutex, ap_lock_fname, pchild); //// removed deref if (status != APR_SUCCESS) { /* ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, */ /* "Couldnt initialize crossprocess lock in child " */ /* "%s %d", ap_lock_fname, ap_accept_lock_mech); */ clean_child_exit(APEXIT_CHILDFATAL); } if (unixd_setup_child() > 0) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); ap_create_sb_handle(sbh, pchild, my_child_num, 0); //// removed deref ap_update_child_status(sbh, SERVER_READY, NULL); /* Set up the pollfd array */ /* ### check the status */ (void) apr_pollset_create(pollset, num_listensocks, pchild, 0); //// removed deref num_listensocks = nondet(); assume(num_listensocks>0); lr = ap_listeners; i = num_listensocks; while (1) { if ( i<=0 ) break; int pfd = 0; pfd_desc_type = APR_POLL_SOCKET; pfd_desc_s = 1; // lr->sd; pfd_reqevents = APR_POLLIN; pfd_client_data = lr; /* ### check the status */ (void) apr_pollset_add(pollset, pfd); //// removed deref i--; } mpm_state = AP_MPMQ_RUNNING; bucket_alloc = apr_bucket_alloc_create(pchild); while(1>0) { if (die_now>0) break; conn_rec *current_conn; void *csd; /* * (Re)initialize this child to a pre-connection state. */ apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { clean_child_exit(0); } (void) ap_update_child_status(sbh, SERVER_READY, NULL); /* * Wait for an acceptable connection to arrive. */ /* Lock around "accept", if necessary */ SAFE_ACCEPT(accept_mutex_on()); do_ACCEPT=1; do_ACCEPT=0; dummy = nondet(); if(dummy > 0) { /* goto loc_return; */ while(1>0) { int ddd; ddd=ddd; } } if (num_listensocks == 1) { /* There is only one listener record, so refer to that one. */ lr = ap_listeners; } else { /* multiple listening sockets - need to poll */ while(1) { int numdesc; const void *pdesc; /* timeout == -1 == wait forever */ status = apr_pollset_poll(pollset, -1, numdesc, pdesc); //// removed deref if (status != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(status) > 0) { if (one_process>0 && shutdown_pending>0) { /* goto loc_return; */ while(1>0) { int ddd; ddd=ddd; } } goto loc_continueA; } /* Single Unix documents select as returning errnos * EBADF, EINTR, and EINVAL... and in none of those * cases does it make sense to continue. In fact * on Linux 2.0.x we seem to end up with EFAULT * occasionally, and we'd loop forever due to it. */ /* ap_log_error5(APLOG_MARK, APLOG_ERR, status, */ /* ap_server_conf, "apr_pollset_poll: (listen)"); */ clean_child_exit(1); } /* We can always use pdesc[0], but sockets at position N * could end up completely starved of attention in a very * busy server. Therefore, we round-robin across the * returned set of descriptors. While it is possible that * the returned set of descriptors might flip around and * continue to starve some sockets, we happen to know the * internal pollset implementation retains ordering * stability of the sockets. Thus, the round-robin should * ensure that a socket will eventually be serviced. */ if (last_poll_idx >= numdesc) last_poll_idx = 0; /* Grab a listener record from the client_data of the poll * descriptor, and advance our saved index to round-robin * the next fetch. * * ### hmm... this descriptor might have POLLERR rather * ### than POLLIN */ lr = 1; //pdesc[last_poll_idx++].client_data; break; loc_continueA: {int yyy2; yyy2=yyy2; } } } /* if we accept() something we don't want to die, so we have to * defer the exit */ status = nondet(); // lr->accept_func(&csd, lr, ptrans); SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ if (status == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1); } else if (status != APR_SUCCESS) { goto loc_continueB; } /* * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. */ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); if (current_conn > 0) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } /* Check the pod and the generation number after processing a * connection so that we'll go away if a graceful restart occurred * while we were processing the connection or we are the lucky * idle server process that gets to die. */ dummy = nondet(); if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ die_now = 1; } else if (ap_my_generation != dummy) { //ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ die_now = 1; } loc_continueB: { int uuu; uuu=uuu; } } clean_child_exit(0); /* loc_return: */ while(1>0) { int ddd; ddd=ddd; } }
static void pollset_remove(abts_case *tc, void *data) { apr_status_t rv; apr_pollset_t *pollset; const apr_pollfd_t *hot_files; apr_pollfd_t pfd; apr_int32_t num; rv = apr_pollset_create(&pollset, 5, p, 0); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLOUT; pfd.desc.s = s[0]; pfd.client_data = (void *)1; rv = apr_pollset_add(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); pfd.desc.s = s[1]; pfd.client_data = (void *)2; rv = apr_pollset_add(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); pfd.desc.s = s[2]; pfd.client_data = (void *)3; rv = apr_pollset_add(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); pfd.desc.s = s[3]; pfd.client_data = (void *)4; rv = apr_pollset_add(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_INT_EQUAL(tc, 4, num); /* now remove the pollset element referring to desc s[1] */ pfd.desc.s = s[1]; pfd.client_data = (void *)999; /* not used on this call */ rv = apr_pollset_remove(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); /* this time only three should match */ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_INT_EQUAL(tc, 3, num); ABTS_PTR_EQUAL(tc, (void *)1, hot_files[0].client_data); ABTS_PTR_EQUAL(tc, s[0], hot_files[0].desc.s); ABTS_PTR_EQUAL(tc, (void *)3, hot_files[1].client_data); ABTS_PTR_EQUAL(tc, s[2], hot_files[1].desc.s); ABTS_PTR_EQUAL(tc, (void *)4, hot_files[2].client_data); ABTS_PTR_EQUAL(tc, s[3], hot_files[2].desc.s); /* now remove the pollset elements referring to desc s[2] */ pfd.desc.s = s[2]; pfd.client_data = (void *)999; /* not used on this call */ rv = apr_pollset_remove(pollset, &pfd); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); /* this time only two should match */ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_INT_EQUAL(tc, 2, num); ABTS_ASSERT(tc, "Incorrect socket in result set", ((hot_files[0].desc.s == s[0]) && (hot_files[1].desc.s == s[3])) || ((hot_files[0].desc.s == s[3]) && (hot_files[1].desc.s == s[0]))); ABTS_ASSERT(tc, "Incorrect client data in result set", ((hot_files[0].client_data == (void *)1) && (hot_files[1].client_data == (void *)4)) || ((hot_files[0].client_data == (void *)4) && (hot_files[1].client_data == (void *)1))); }
static void setup_pollset(CuTest *tc) { apr_status_t rv; rv = apr_pollset_create(&pollset, LARGE_NUM_SOCKETS, p, 0); CuAssertIntEquals(tc, APR_SUCCESS, rv); }
static void pollset_remove(CuTest *tc) { apr_status_t rv; apr_pollset_t *pollset; const apr_pollfd_t *hot_files; apr_pollfd_t pfd; apr_int32_t num; rv = apr_pollset_create(&pollset, 5, p, 0); CuAssertIntEquals(tc, APR_SUCCESS, rv); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLOUT; pfd.desc.s = s[0]; pfd.client_data = (void *)1; rv = apr_pollset_add(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); pfd.desc.s = s[1]; pfd.client_data = (void *)2; rv = apr_pollset_add(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); pfd.desc.s = s[2]; pfd.client_data = (void *)3; rv = apr_pollset_add(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); pfd.desc.s = s[1]; pfd.client_data = (void *)4; rv = apr_pollset_add(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); pfd.desc.s = s[3]; pfd.client_data = (void *)5; rv = apr_pollset_add(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertIntEquals(tc, 5, num); /* now remove the pollset elements referring to desc s[1] */ pfd.desc.s = s[1]; pfd.client_data = (void *)999; /* not used on this call */ rv = apr_pollset_remove(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); /* this time only three should match */ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertIntEquals(tc, 3, num); CuAssertPtrEquals(tc, (void *)1, hot_files[0].client_data); CuAssertPtrEquals(tc, s[0], hot_files[0].desc.s); CuAssertPtrEquals(tc, (void *)3, hot_files[1].client_data); CuAssertPtrEquals(tc, s[2], hot_files[1].desc.s); CuAssertPtrEquals(tc, (void *)5, hot_files[2].client_data); CuAssertPtrEquals(tc, s[3], hot_files[2].desc.s); /* now remove the pollset elements referring to desc s[2] */ pfd.desc.s = s[2]; pfd.client_data = (void *)999; /* not used on this call */ rv = apr_pollset_remove(pollset, &pfd); CuAssertIntEquals(tc, APR_SUCCESS, rv); /* this time only two should match */ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertIntEquals(tc, 2, num); CuAssertPtrEquals(tc, (void *)1, hot_files[0].client_data); CuAssertPtrEquals(tc, s[0], hot_files[0].desc.s); CuAssertPtrEquals(tc, (void *)5, hot_files[1].client_data); CuAssertPtrEquals(tc, s[3], hot_files[1].desc.s); }
/* * 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; }
/* 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; }
APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, apr_file_t **out, apr_int32_t blocking, apr_pool_t *p) { #ifdef _WIN32_WCE return APR_ENOTIMPL; #else SECURITY_ATTRIBUTES sa; static unsigned long id = 0; DWORD dwPipeMode; DWORD dwOpenMode; char name[50]; sa.nLength = sizeof(sa); #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE sa.bInheritHandle = FALSE; #endif #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI sa.bInheritHandle = TRUE; #endif sa.lpSecurityDescriptor = NULL; (*in) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); (*in)->pool = p; (*in)->fname = NULL; (*in)->pipe = 1; (*in)->timeout = -1; (*in)->ungetchar = -1; (*in)->eof_hit = 0; (*in)->filePtr = 0; (*in)->bufpos = 0; (*in)->dataRead = 0; (*in)->direction = 0; (*in)->pOverlapped = NULL; (void) apr_pollset_create(&(*in)->pollset, 1, p, 0); (*out) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); (*out)->pool = p; (*out)->fname = NULL; (*out)->pipe = 1; (*out)->timeout = -1; (*out)->ungetchar = -1; (*out)->eof_hit = 0; (*out)->filePtr = 0; (*out)->bufpos = 0; (*out)->dataRead = 0; (*out)->direction = 0; (*out)->pOverlapped = NULL; (void) apr_pollset_create(&(*out)->pollset, 1, p, 0); if (apr_os_level >= APR_WIN_NT) { /* Create the read end of the pipe */ dwOpenMode = PIPE_ACCESS_INBOUND; if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*in)->pOverlapped = (OVERLAPPED*) apr_pcalloc(p, sizeof(OVERLAPPED)); (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*in)->timeout = 0; } dwPipeMode = 0; sprintf(name, "\\\\.\\pipe\\apr-pipe-%u.%lu", getpid(), id++); (*in)->filehand = CreateNamedPipe(name, dwOpenMode, dwPipeMode, 1, //nMaxInstances, 0, //nOutBufferSize, 65536, //nInBufferSize, 1, //nDefaultTimeOut, &sa); /* Create the write end of the pipe */ dwOpenMode = FILE_ATTRIBUTE_NORMAL; if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*out)->pOverlapped = (OVERLAPPED*) apr_pcalloc(p, sizeof(OVERLAPPED)); (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*out)->timeout = 0; } (*out)->filehand = CreateFile(name, GENERIC_WRITE, // access mode 0, // share mode &sa, // Security attributes OPEN_EXISTING, // dwCreationDisposition dwOpenMode, // Pipe attributes NULL); // handle to template file } else { /* Pipes on Win9* are blocking. Live with it. */ if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) { return apr_get_os_error(); } } apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup, apr_pool_cleanup_null); apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; #endif /* _WIN32_WCE */ }
/* 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) { apr_pool_t *p = r->pool; apr_socket_t *sock; apr_status_t err, rv; apr_size_t i, o, nbytes; char buffer[HUGE_STRING_LEN]; apr_socket_t *client_socket = ap_get_module_config(r->connection->conn_config, &core_module); int failed; 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 *uri_addr, *connect_addr; apr_uri_t uri; const char *connectname; int connectport = 0; /* is this for us? */ if (r->method_number != M_CONNECT) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: declining URL %s", url); return DECLINED; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: 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_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port); /* do a DNS lookup for the destination host */ err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 0, p); /* are we connecting directly, or via a proxy? */ if (proxyname) { connectname = proxyname; connectport = proxyport; err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p); } else { connectname = uri.hostname; connectport = uri.port; connect_addr = uri_addr; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport); /* check if ProxyBlock directive on this host */ if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } /* Check if it is an allowed port */ if (conf->allowed_connect_ports->nelts == 0) { /* Default setting if not overridden by AllowCONNECT */ switch (uri.port) { case APR_URI_HTTPS_DEFAULT_PORT: case APR_URI_SNEWS_DEFAULT_PORT: break; default: /* XXX can we call ap_proxyerror() here to get a nice log message? */ return HTTP_FORBIDDEN; } } else if(!allowed_port(conf, uri.port)) { /* XXX can we call ap_proxyerror() here to get a nice log message? */ return HTTP_FORBIDDEN; } /* * Step Two: Make the Connection * * We have determined who to connect to. Now make the connection. */ /* get all the possible IP addresses for the destname and loop through them * until we get a successful connection */ if (APR_SUCCESS != err) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, "DNS lookup failure for: ", connectname, NULL)); } /* * 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", connect_addr, connectname, conf, r->server, r->pool); /* handle a permanent error from the above loop */ if (failed) { if (proxyname) { return DECLINED; } else { return HTTP_BAD_GATEWAY; } } /* * Step Three: Send the Request * * Send the HTTP/1.1 CONNECT request to the remote server */ /* we are acting as a tunnel - the output filter stack should * be completely empty, because when we are done here we are done completely. * We add the NULL filter to the stack to do this... */ r->output_filters = NULL; r->connection->output_filters = NULL; /* 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_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: sending the CONNECT request to the remote proxy"); nbytes = apr_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri); apr_socket_send(sock, buffer, &nbytes); nbytes = apr_snprintf(buffer, sizeof(buffer), "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); apr_socket_send(sock, buffer, &nbytes); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: Returning 200 OK Status"); nbytes = apr_snprintf(buffer, sizeof(buffer), "HTTP/1.0 200 Connection Established" CRLF); ap_xlate_proto_to_ascii(buffer, nbytes); apr_socket_send(client_socket, buffer, &nbytes); nbytes = apr_snprintf(buffer, sizeof(buffer), "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); ap_xlate_proto_to_ascii(buffer, nbytes); apr_socket_send(client_socket, buffer, &nbytes); #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_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: setting up poll()"); /* * Step Four: Handle Data Transfer * * Handle two way transfer of data over the socket (this is a tunnel). */ /* r->sent_bodyct = 1;*/ 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, "proxy: CONNECT: 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); while (1) { /* Infinite loop until error (one side closes the connection) */ if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) { apr_socket_close(sock); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: CONNECT: error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } #ifdef DEBUGGING ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: woke from select(), 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_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: sock was set"); #endif nbytes = sizeof(buffer); rv = apr_socket_recv(sock, buffer, &nbytes); if (rv == APR_SUCCESS) { o = 0; i = nbytes; while(i > 0) { nbytes = i; /* This is just plain wrong. No module should ever write directly * to the client. For now, this works, but this is high on my list of * things to fix. The correct line is: * if ((nbytes = ap_rwrite(buffer + o, nbytes, r)) < 0) * rbb */ rv = apr_socket_send(client_socket, buffer + o, &nbytes); if (rv != APR_SUCCESS) break; o += nbytes; i -= nbytes; } } else break; } else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) break; } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { #ifdef DEBUGGING ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: client was set"); #endif nbytes = sizeof(buffer); rv = apr_socket_recv(client_socket, buffer, &nbytes); if (rv == APR_SUCCESS) { o = 0; i = nbytes; #ifdef DEBUGGING ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: read %d from client", i); #endif while(i > 0) { nbytes = i; rv = apr_socket_send(sock, buffer + o, &nbytes); if (rv != APR_SUCCESS) break; o += nbytes; i -= nbytes; } } else break; } else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) { rv = APR_EOF; break; } } else break; } if (rv != APR_SUCCESS) { break; } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: finished with poll() - cleaning up"); /* * Step Five: Clean Up * * Close the socket and clean up */ apr_socket_close(sock); return OK; }
/* This is the thread that actually does all the work. */ static int32 worker_thread(void *dummy) { int worker_slot = (int)dummy; apr_allocator_t *allocator; apr_bucket_alloc_t *bucket_alloc; apr_status_t rv = APR_EINIT; int last_poll_idx = 0; sigset_t sig_mask; int requests_this_child = 0; apr_pollset_t *pollset = NULL; ap_listen_rec *lr = NULL; ap_sb_handle_t *sbh = NULL; int i; /* each worker thread is in control of its own destiny...*/ int this_worker_should_exit = 0; /* We have 2 pools that we create/use throughout the lifetime of this * worker. The first and longest lived is the pworker pool. From * this we create the ptrans pool, the lifetime of which is the same * as each connection and is reset prior to each attempt to * process a connection. */ apr_pool_t *ptrans = NULL; apr_pool_t *pworker = NULL; mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ on_exit_thread(check_restart, (void*)worker_slot); /* block the signals for this thread only if we're not running as a * single process. */ if (!one_process) { sigfillset(&sig_mask); sigprocmask(SIG_BLOCK, &sig_mask, NULL); } /* Each worker thread is fully in control of it's destinay and so * to allow each thread to handle the lifetime of it's own resources * we create and use a subcontext for every thread. * The subcontext is a child of the pconf pool. */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&pworker, pconf, NULL, allocator); apr_allocator_owner_set(allocator, pworker); apr_pool_create(&ptrans, pworker); apr_pool_tag(ptrans, "transaction"); ap_create_sb_handle(&sbh, pworker, 0, worker_slot); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* We add an extra socket here as we add the udp_sock we use for signalling * death. This gets added after the others. */ apr_pollset_create(&pollset, num_listening_sockets + 1, pworker, 0); for (lr = ap_listeners, i = num_listening_sockets; i--; lr = lr->next) { apr_pollfd_t pfd = {0}; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = lr->sd; pfd.reqevents = APR_POLLIN; pfd.client_data = lr; apr_pollset_add(pollset, &pfd); } { apr_pollfd_t pfd = {0}; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = udp_sock; pfd.reqevents = APR_POLLIN; apr_pollset_add(pollset, &pfd); } bucket_alloc = apr_bucket_alloc_create(pworker); mpm_state = AP_MPMQ_RUNNING; while (!this_worker_should_exit) { conn_rec *current_conn; void *csd; /* (Re)initialize this child to a pre-connection state. */ apr_pool_clear(ptrans); if ((ap_max_requests_per_thread > 0 && requests_this_child++ >= ap_max_requests_per_thread)) clean_child_exit(0, worker_slot); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); apr_thread_mutex_lock(accept_mutex); /* We always (presently) have at least 2 sockets we listen on, so * we don't have the ability for a fast path for a single socket * as some MPM's allow :( */ for (;;) { apr_int32_t numdesc = 0; const apr_pollfd_t *pdesc = NULL; rv = apr_pollset_poll(pollset, -1, &numdesc, &pdesc); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { if (one_process && shutdown_pending) return; continue; } ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_pollset_poll: (listen)"); clean_child_exit(1, worker_slot); } /* We can always use pdesc[0], but sockets at position N * could end up completely starved of attention in a very * busy server. Therefore, we round-robin across the * returned set of descriptors. While it is possible that * the returned set of descriptors might flip around and * continue to starve some sockets, we happen to know the * internal pollset implementation retains ordering * stability of the sockets. Thus, the round-robin should * ensure that a socket will eventually be serviced. */ if (last_poll_idx >= numdesc) last_poll_idx = 0; /* Grab a listener record from the client_data of the poll * descriptor, and advance our saved index to round-robin * the next fetch. * * ### hmm... this descriptor might have POLLERR rather * ### than POLLIN */ lr = pdesc[last_poll_idx++].client_data; /* The only socket we add without client_data is the first, the UDP socket * we listen on for restart signals. If we've therefore gotten a hit on that * listener lr will be NULL here and we know we've been told to die. * Before we jump to the end of the while loop with this_worker_should_exit * set to 1 (causing us to exit normally we hope) we release the accept_mutex * as we want every thread to go through this same routine :) * Bit of a hack, but compared to what I had before... */ if (lr == NULL) { this_worker_should_exit = 1; apr_thread_mutex_unlock(accept_mutex); goto got_a_black_spot; } goto got_fd; } got_fd: /* Run beos_accept to accept the connection and set things up to * allow us to process it. We always release the accept_lock here, * even if we failt o accept as otherwise we'll starve other workers * which would be bad. */ rv = beos_accept(&csd, lr, ptrans); apr_thread_mutex_unlock(accept_mutex); if (rv == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1, worker_slot); } else if (rv != APR_SUCCESS) continue; current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, worker_slot, sbh, bucket_alloc); if (current_conn) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } if (ap_my_generation != ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ this_worker_should_exit = 1; } got_a_black_spot: } apr_pool_destroy(ptrans); apr_pool_destroy(pworker); clean_child_exit(0, worker_slot); } static int make_worker(int slot) { thread_id tid; if (slot + 1 > ap_max_child_assigned) ap_max_child_assigned = slot + 1; (void) ap_update_child_status_from_indexes(0, slot, SERVER_STARTING, (request_rec*)NULL); if (one_process) { set_signals(); ap_scoreboard_image->parent[0].pid = getpid(); ap_scoreboard_image->servers[0][slot].tid = find_thread(NULL); return 0; } tid = spawn_thread(worker_thread, "apache_worker", B_NORMAL_PRIORITY, (void *)slot); if (tid < B_NO_ERROR) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "spawn_thread: Unable to start a new thread"); /* In case system resources are maxed out, we don't want * Apache running away with the CPU trying to fork over and * over and over again. */ (void) ap_update_child_status_from_indexes(0, slot, SERVER_DEAD, (request_rec*)NULL); sleep(10); return -1; } resume_thread(tid); ap_scoreboard_image->servers[0][slot].tid = tid; return 0; }
int jtagHostLoop() { apr_status_t rv; apr_pool_t *mp; apr_pollset_t *pollset; apr_int32_t num; const apr_pollfd_t *ret_pfd; apr_initialize(); apr_pool_create(&mp, NULL); serv_ctx_t *channel_contexts[IPDBG_CHANNELS]; apr_pollset_create(&pollset, DEF_POLLSET_NUM, mp, 0); for(uint8_t ch = 0; ch < IPDBG_CHANNELS; ++ch) { serv_ctx_t *serv_ctx = apr_palloc(mp, sizeof(serv_ctx_t)); channel_contexts[ch] = serv_ctx; serv_ctx->channel_number = ch; serv_ctx->channel_state = listening; serv_ctx->up_buf_level = 0; serv_ctx->down_buf_level = 0; if(ch == 0) serv_ctx->valid_mask = IPDBG_LA_VALID_MASK; if(ch == 1) serv_ctx->valid_mask = IPDBG_IOVIEW_VALID_MASK; if(ch == 2) serv_ctx->valid_mask = IPDBG_GDB_VALID_MASK; if(ch == 3) serv_ctx->valid_mask = IPDBG_WFG_VALID_MASK; apr_socket_t *listening_sock = create_listen_sock(mp, ch); assert(listening_sock); apr_pollfd_t pfd = { mp, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, serv_ctx }; pfd.desc.s = listening_sock; apr_pollset_add(pollset, &pfd); } // reset JtagCDC uint16_t val; ipdbgJTAGtransfer(&val, 0xf00); while (1) { size_t transfers = 0; for(size_t ch = 0 ; ch < IPDBG_CHANNELS ; ++ch) { for(size_t idx = 0 ; idx < channel_contexts[ch]->down_buf_level; ++idx) { uint16_t val; ipdbgJTAGtransfer(&val, channel_contexts[ch]->down_buf[idx] | channel_contexts[ch]->valid_mask); transfers++; distribute_to_up_buffer(val, channel_contexts); } channel_contexts[ch]->down_buf_level = 0; } for(size_t k = transfers ; k < MIN_TRANSFERS ; ++k) { uint16_t val; ipdbgJTAGtransfer(&val, 0x000); distribute_to_up_buffer(val, channel_contexts); } rv = apr_pollset_poll(pollset, DEF_POLL_TIMEOUT, &num, &ret_pfd); if (rv == APR_SUCCESS) { int i; /* scan the active sockets */ for (i = 0; i < num; i++) { serv_ctx_t *serv_ctx = ret_pfd[i].client_data; if(serv_ctx) { if (serv_ctx->channel_state == listening) { apr_socket_t *listening_sock = ret_pfd[i].desc.s; /* the listen socket is readable. that indicates we accepted a new connection */ do_accept(serv_ctx, pollset, listening_sock, mp); apr_socket_close(listening_sock); apr_pollset_remove(pollset, &ret_pfd[i]); } else { int ret = TRUE; if(ret_pfd[i].rtnevents & (APR_POLLIN | APR_POLLHUP)) { ret = connection_rx_cb(serv_ctx, pollset, ret_pfd[i].desc.s); } else // (ret_pfd[i].rtnevents & APR_POLLOUT) { ret = connection_tx_cb(serv_ctx, pollset, ret_pfd[i].desc.s); } if (ret == FALSE) { //printf("closing connection %d", serv_ctx->channel_number); apr_socket_t *sock = ret_pfd[i].desc.s; apr_socket_close(sock); apr_pollset_remove(pollset, &ret_pfd[i]); apr_socket_t *listening_sock = create_listen_sock(mp, serv_ctx->channel_number); serv_ctx->channel_state = listening; apr_pollfd_t pfd = { mp, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, serv_ctx }; pfd.desc.s = listening_sock; apr_pollset_add(pollset, &pfd); } } } } } } return 0; }
void* thread_socket_pipe_receiver(apr_thread_t* thd, void* data) { frl_socket_pipe* pipe = (frl_socket_pipe*)data; apr_status_t state; apr_socket_t* listen_sock; apr_socket_create(&listen_sock, pipe->sock_addr->family, SOCK_STREAM, APR_PROTO_TCP, pipe->sockpool); apr_socket_opt_set(listen_sock, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(listen_sock, 0); apr_socket_opt_set(listen_sock, APR_SO_REUSEADDR, 1); pipe->recv_state = apr_socket_bind(listen_sock, pipe->sock_addr); F_ERROR_IF_RUN(APR_SUCCESS != pipe->recv_state, return NULL, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Binding Error: %d\n", pipe->recv_state); pipe->recv_state = apr_socket_listen(listen_sock, SOMAXCONN); F_ERROR_IF_RUN(APR_SUCCESS != pipe->recv_state, return NULL, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Listen Error: %d\n", pipe->recv_state); apr_uint32_t hash; apr_pollset_t* pollset; apr_pollset_create(&pollset, pipe->replicate+2, pipe->sockpool, 0); apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL }; pfd.desc.s = listen_sock; apr_pollset_add(pollset, &pfd); do { // the fun loop apr_int32_t total; const apr_pollfd_t* ret_pfd; pipe->recv_state = apr_pollset_poll(pollset, SOCKET_PIPE_POLL_TIMEOUT, &total, &ret_pfd); if (APR_SUCCESS == pipe->recv_state) { for (int i = 0; i < total; i++) { if (ret_pfd[i].desc.s == listen_sock) { apr_socket_t* accept_sock; state = apr_socket_accept(&accept_sock, listen_sock, pipe->sockpool); F_ERROR_IF_RUN(APR_SUCCESS != state, continue, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Accept Error: %d\n", state); // accept connection, initiate recv frl_pipe_state_t* pipestate = (frl_pipe_state_t*)frl_slab_palloc(pipe->statepool); apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate }; pipestate->state = FRL_PIPE_READ_HEADER_START; pipestate->reader = (char*)&pipestate->header; pipestate->offset = 0; pipestate->size = SIZEOF_FRL_PIPE_HEADER_T; pfd.desc.s = accept_sock; apr_socket_opt_set(accept_sock, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(accept_sock, 0); apr_pollset_add(pollset, &pfd); } else { if (ret_pfd[i].rtnevents & APR_POLLIN) { frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data; apr_size_t len_a = pipestate->size-pipestate->offset; state = apr_socket_recv(ret_pfd[i].desc.s, pipestate->reader, &len_a); pipestate->offset += len_a; pipestate->reader += len_a; // read buffer to reader if ((pipestate->offset >= pipestate->size)||(APR_STATUS_IS_EAGAIN(state))) { pipestate->offset = pipestate->size; PIPE_STATE_TO_COMPLETE(pipestate->state); // read complete, move state to complete } else if ((APR_STATUS_IS_EOF(state))||(len_a == 0)) { apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); // remote error, close connection continue; } switch (pipestate->state) { case FRL_PIPE_READ_HEADER_COMPLETE: { // recv header (hash & size) pipestate->data.offset = 0; pipestate->data.size = pipestate->header.size; state = pipe->recv_before(&pipestate->data.buf, &pipestate->data.size); if (FRL_PROGRESS_IS_INTERRUPT(state)) { apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); continue; } pipestate->state = FRL_PIPE_READ_BLOCK_START; // start to read block (<= 4092 bytes each) pipestate->reader = pipestate->buffer; pipestate->offset = 0; if (pipestate->data.size < SIZEOF_FRL_PIPE_BLOCK_BUFFER) pipestate->size = pipestate->data.size+SIZEOF_FRL_PIPE_HEADER_T; else pipestate->size = SOCKET_PACKAGE_SIZE; break; } case FRL_PIPE_READ_BLOCK_COMPLETE: { // a block complete, move to data memcpy(pipestate->data.buf+pipestate->data.offset, &pipestate->block.start, pipestate->block.header.size); hash = hashlittle(&pipestate->block.start, pipestate->size-SIZEOF_FRL_PIPE_HEADER_T); if (hash != pipestate->block.header.hash) { // check the hash fingerprint of the block apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); continue; } pipestate->data.offset += pipestate->block.header.size; if (pipestate->data.offset >= pipestate->data.size) { // finish read, report state to remote apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); hash = hashlittle(pipestate->data.buf, pipestate->data.size); if (hash != pipestate->header.hash) { // check hash fingerprint of all data frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); } else { pfd.reqevents = APR_POLLOUT; state = pipe->recv_after(pipestate->data.buf, pipestate->data.size); if (FRL_PROGRESS_IS_INTERRUPT(state)) { frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); } else { pipestate->state = FRL_PIPE_SEND_HEADER_START; pipestate->reader = (char*)&pipestate->header; pipestate->offset = 0; pipestate->size = SIZEOF_FRL_PIPE_HEADER_T; apr_pollset_add(pollset, &pfd); } } continue; } // to start read successor block pipestate->state = FRL_PIPE_READ_BLOCK_START; pipestate->reader = pipestate->buffer; pipestate->offset = 0; if (pipestate->data.size-pipestate->data.offset < SIZEOF_FRL_PIPE_BLOCK_BUFFER) pipestate->size = pipestate->data.size-pipestate->data.offset+SIZEOF_FRL_PIPE_HEADER_T; else pipestate->size = SOCKET_PACKAGE_SIZE; break; } default: break; } } else if (ret_pfd[i].rtnevents & APR_POLLOUT) { // send report information, basic header frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data; apr_size_t len_a = pipestate->size-pipestate->offset; state = apr_socket_send(ret_pfd[i].desc.s, pipestate->reader, &len_a); pipestate->offset += len_a; pipestate->reader += len_a; if ((pipestate->offset >= pipestate->size)||(APR_STATUS_IS_EAGAIN(state))) { pipestate->offset = pipestate->size; PIPE_STATE_TO_COMPLETE(pipestate->state); } else if ((APR_STATUS_IS_EOF(state))||(len_a == 0)) { apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLOUT, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); continue; } switch (pipestate->state) { case FRL_PIPE_SEND_HEADER_COMPLETE: { // complete, return to listen state apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLOUT, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); pfd.reqevents = APR_POLLIN; pipestate->state = FRL_PIPE_DISABLED; pipestate->reader = 0; pipestate->offset = 0; pipestate->size = 0; apr_pollset_add(pollset, &pfd); break; } default: break; } } else { // other errors, close connection frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data; apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN | APR_POLLOUT, 0, { NULL }, pipestate }; pfd.desc.s = ret_pfd[i].desc.s; apr_pollset_remove(pollset, &pfd); frl_slab_pfree(pipestate); apr_socket_close(ret_pfd[i].desc.s); } } } } else if (!APR_STATUS_IS_TIMEUP(pipe->recv_state)) {
APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, apr_file_t **out, apr_int32_t blocking, apr_pool_t *pool_in, apr_pool_t *pool_out) { #ifdef _WIN32_WCE return APR_ENOTIMPL; #else SECURITY_ATTRIBUTES sa; static unsigned long id = 0; DWORD dwPipeMode; DWORD dwOpenMode; sa.nLength = sizeof(sa); #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE sa.bInheritHandle = FALSE; #endif #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI sa.bInheritHandle = TRUE; #endif sa.lpSecurityDescriptor = NULL; (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); (*in)->pool = pool_in; (*in)->fname = NULL; (*in)->pipe = 1; (*in)->timeout = -1; (*in)->ungetchar = -1; (*in)->eof_hit = 0; (*in)->filePtr = 0; (*in)->bufpos = 0; (*in)->dataRead = 0; (*in)->direction = 0; (*in)->pOverlapped = NULL; #if APR_FILES_AS_SOCKETS (void) apr_pollset_create(&(*in)->pollset, 1, p, 0); #endif (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); (*out)->pool = pool_out; (*out)->fname = NULL; (*out)->pipe = 1; (*out)->timeout = -1; (*out)->ungetchar = -1; (*out)->eof_hit = 0; (*out)->filePtr = 0; (*out)->bufpos = 0; (*out)->dataRead = 0; (*out)->direction = 0; (*out)->pOverlapped = NULL; #if APR_FILES_AS_SOCKETS (void) apr_pollset_create(&(*out)->pollset, 1, p, 0); #endif if (apr_os_level >= APR_WIN_NT) { char rand[8]; int pid = getpid(); #define FMT_PIPE_NAME "\\\\.\\pipe\\apr-pipe-%x.%lx." /* ^ ^ ^ * pid | | * | | * id | * | * hex-escaped rand[8] (16 bytes) */ char name[sizeof FMT_PIPE_NAME + 2 * sizeof(pid) + 2 * sizeof(id) + 2 * sizeof(rand)]; apr_size_t pos; /* Create the read end of the pipe */ dwOpenMode = PIPE_ACCESS_INBOUND; #ifdef FILE_FLAG_FIRST_PIPE_INSTANCE dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; #endif if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*in)->pOverlapped = (OVERLAPPED*) apr_pcalloc((*in)->pool, sizeof(OVERLAPPED)); (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*in)->timeout = 0; } dwPipeMode = 0; apr_generate_random_bytes(rand, sizeof rand); pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++); apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL); (*in)->filehand = CreateNamedPipe(name, dwOpenMode, dwPipeMode, 1, /* nMaxInstances, */ 0, /* nOutBufferSize, */ 65536, /* nInBufferSize, */ 1, /* nDefaultTimeOut, */ &sa); if ((*in)->filehand == INVALID_HANDLE_VALUE) { apr_status_t rv = apr_get_os_error(); file_cleanup(*in); return rv; } /* Create the write end of the pipe */ dwOpenMode = FILE_ATTRIBUTE_NORMAL; if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*out)->pOverlapped = (OVERLAPPED*) apr_pcalloc((*out)->pool, sizeof(OVERLAPPED)); (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*out)->timeout = 0; } (*out)->filehand = CreateFile(name, GENERIC_WRITE, /* access mode */ 0, /* share mode */ &sa, /* Security attributes */ OPEN_EXISTING, /* dwCreationDisposition */ dwOpenMode, /* Pipe attributes */ NULL); /* handle to template file */ if ((*out)->filehand == INVALID_HANDLE_VALUE) { apr_status_t rv = apr_get_os_error(); file_cleanup(*out); file_cleanup(*in); return rv; } } else { /* Pipes on Win9* are blocking. Live with it. */ if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) { return apr_get_os_error(); } } apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup, apr_pool_cleanup_null); apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; #endif /* _WIN32_WCE */ }
void ap_mpm_child_main(apr_pool_t *pconf) { ap_listen_rec *lr = NULL; int requests_this_child = 0; int rv = 0; unsigned long ulTimes; int my_pid = getpid(); ULONG rc, c; HQUEUE workq; apr_pollset_t *pollset; int num_listeners; TID server_maint_tid; void *sb_mem; /* Stop Ctrl-C/Ctrl-Break signals going to child processes */ DosSetSignalExceptionFocus(0, &ulTimes); set_signals(); /* Create pool for child */ apr_pool_create(&pchild, pconf); ap_run_child_init(pchild, ap_server_conf); /* Create an event semaphore used to trigger other threads to shutdown */ rc = DosCreateEventSem(NULL, &shutdown_event, 0, FALSE); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "unable to create shutdown semaphore, exiting"); clean_child_exit(APEXIT_CHILDFATAL); } /* Gain access to the scoreboard. */ rc = DosGetNamedSharedMem(&sb_mem, ap_scoreboard_fname, PAG_READ|PAG_WRITE); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "scoreboard not readable in child, exiting"); clean_child_exit(APEXIT_CHILDFATAL); } ap_calc_scoreboard_size(); ap_init_scoreboard(sb_mem); /* Gain access to the accpet mutex */ rc = DosOpenMutexSem(NULL, &ap_mpm_accept_mutex); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "accept mutex couldn't be accessed in child, exiting"); clean_child_exit(APEXIT_CHILDFATAL); } /* Find our pid in the scoreboard so we know what slot our parent allocated us */ for (child_slot = 0; ap_scoreboard_image->parent[child_slot].pid != my_pid && child_slot < HARD_SERVER_LIMIT; child_slot++); if (child_slot == HARD_SERVER_LIMIT) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "child pid not found in scoreboard, exiting"); clean_child_exit(APEXIT_CHILDFATAL); } ap_my_generation = ap_scoreboard_image->parent[child_slot].generation; memset(ap_scoreboard_image->servers[child_slot], 0, sizeof(worker_score) * HARD_THREAD_LIMIT); /* Set up an OS/2 queue for passing connections & termination requests * to worker threads */ rc = DosCreateQueue(&workq, QUE_FIFO, apr_psprintf(pchild, "/queues/httpd/work.%d", my_pid)); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "unable to create work queue, exiting"); clean_child_exit(APEXIT_CHILDFATAL); } /* Create initial pool of worker threads */ for (c = 0; c < ap_min_spare_threads; c++) { // ap_scoreboard_image->servers[child_slot][c].tid = _beginthread(worker_main, NULL, 128*1024, (void *)c); } /* Start maintenance thread */ server_maint_tid = _beginthread(server_maintenance, NULL, 32768, NULL); /* Set up poll */ for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) { num_listeners++; } apr_pollset_create(&pollset, num_listeners, pchild, 0); for (lr = ap_listeners; lr != NULL; lr = lr->next) { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = lr->sd; pfd.reqevents = APR_POLLIN; pfd.client_data = lr; apr_pollset_add(pollset, &pfd); } /* Main connection accept loop */ do { apr_pool_t *pconn; worker_args_t *worker_args; int last_poll_idx = 0; apr_pool_create(&pconn, pchild); worker_args = apr_palloc(pconn, sizeof(worker_args_t)); worker_args->pconn = pconn; if (num_listeners == 1) { rv = apr_socket_accept(&worker_args->conn_sd, ap_listeners->sd, pconn); } else { const apr_pollfd_t *poll_results; apr_int32_t num_poll_results; rc = DosRequestMutexSem(ap_mpm_accept_mutex, SEM_INDEFINITE_WAIT); if (shutdown_pending) { DosReleaseMutexSem(ap_mpm_accept_mutex); break; } rv = APR_FROM_OS_ERROR(rc); if (rv == APR_SUCCESS) { rv = apr_pollset_poll(pollset, -1, &num_poll_results, &poll_results); DosReleaseMutexSem(ap_mpm_accept_mutex); } if (rv == APR_SUCCESS) { if (last_poll_idx >= num_listeners) { last_poll_idx = 0; } lr = poll_results[last_poll_idx++].client_data; rv = apr_socket_accept(&worker_args->conn_sd, lr->sd, pconn); last_poll_idx++; } } if (rv != APR_SUCCESS) { if (!APR_STATUS_IS_EINTR(rv)) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_socket_accept"); clean_child_exit(APEXIT_CHILDFATAL); } } else { DosWriteQueue(workq, WORKTYPE_CONN, sizeof(worker_args_t), worker_args, 0); requests_this_child++; } if (ap_max_requests_per_child != 0 && requests_this_child >= ap_max_requests_per_child) break; } while (!shutdown_pending && ap_my_generation == ap_scoreboard_image->global->running_generation); ap_scoreboard_image->parent[child_slot].quiescing = 1; DosPostEventSem(shutdown_event); DosWaitThread(&server_maint_tid, DCWW_WAIT); if (is_graceful) { char someleft; /* tell our worker threads to exit */ for (c=0; c<HARD_THREAD_LIMIT; c++) { if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0); } } do { someleft = 0; for (c=0; c<HARD_THREAD_LIMIT; c++) { if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { someleft = 1; DosSleep(1000); break; } } } while (someleft); } else { DosPurgeQueue(workq); for (c=0; c<HARD_THREAD_LIMIT; c++) { if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { DosKillThread(ap_scoreboard_image->servers[child_slot][c].tid); } } } apr_pool_destroy(pchild); }
static void setup_pollset(abts_case *tc, void *data) { apr_status_t rv; rv = apr_pollset_create(&pollset, LARGE_NUM_SOCKETS, p, 0); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); }