APR_DECLARE(apr_status_t) apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont) { if (gethostname(buf, len) == -1) { buf[0] = '\0'; return APR_FROM_OS_ERROR(sock_errno()); } else if (!memchr(buf, '\0', len)) { /* buffer too small */ buf[0] = '\0'; return APR_ENAMETOOLONG; } return APR_SUCCESS; }
static void setup_gx(int port, apr_int64_t signature) { int e; apr_pool_t* subpool; /* set up pool */ if (0 != (e = apr_pool_create_alloc(&gx.pool, 0))) { gpsmon_fatalx(FLINE, e, "apr_pool_create_alloc failed"); } /* set up port, event */ gx.port = port; gx.signature = signature; if (!event_init()) { gpsmon_fatalx(FLINE, APR_FROM_OS_ERROR(errno), "event_init failed"); } if (0 != (e = apr_pool_create_alloc(&subpool, gx.pool))) { gpsmon_fatalx(FLINE, e, "apr_pool_create_alloc failed"); } /* qexec hash table */ gx.qexectab = apr_hash_make(subpool); CHECKMEM(gx.qexectab); /* qlog hash table */ gx.qlogtab = apr_hash_make(subpool); CHECKMEM(gx.qlogtab); /* segment hash table */ gx.segmenttab = apr_hash_make(subpool); CHECKMEM(gx.segmenttab); /* queryseg hash table */ gx.querysegtab = apr_hash_make(subpool); CHECKMEM(gx.querysegtab); /* pidtab */ gx.pidtab = apr_hash_make(subpool); CHECKMEM(gx.pidtab); /* device metrics hashes */ net_devices = apr_hash_make(gx.pool); CHECKMEM(net_devices); disk_devices = apr_hash_make(gx.pool); CHECKMEM(disk_devices); }
apr_status_t apr_file_check_read(apr_file_t *fd) { int rc; if (!fd->pipe) return APR_SUCCESS; /* Not a pipe, assume no waiting */ rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN); if (rc == ERROR_TIMEOUT) return APR_TIMEUP; return APR_FROM_OS_ERROR(rc); }
APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on) { int one; struct linger li; if (on) one = 1; else one = 0; if (opt & APR_SO_KEEPALIVE) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_DEBUG) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_REUSEADDR) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_SNDBUF) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_NONBLOCK) { if (ioctl(sock->socketdes, FIONBIO, (caddr_t)&one, sizeof(one)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } else { sock->nonblock = one; } } if (opt & APR_SO_LINGER) { li.l_onoff = on; li.l_linger = APR_MAX_SECS_TO_LINGER; if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_TCP_NODELAY) { if (setsockopt(sock->socketdes, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(int)) == -1) { return APR_FROM_OS_ERROR(sock_errno()); } } return APR_SUCCESS; }
APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) { apr_ssize_t rv; int fds, err = 0; do { if (!sock->nonblock || (err == SOCEWOULDBLOCK && sock->timeout != 0)) { fds = sock->socketdes; rv = select(&fds, 1, 0, 0, sock->timeout >= 0 ? sock->timeout/1000 : -1); if (rv != 1) { *len = 0; err = sock_errno(); if (rv == 0) return APR_TIMEUP; if (err == SOCEINTR) continue; return APR_FROM_OS_ERROR(err); } } rv = recv(sock->socketdes, buf, (*len), 0); err = rv < 0 ? sock_errno() : 0; } while (err == SOCEINTR || (err == SOCEWOULDBLOCK && sock->timeout != 0)); if (err) { *len = 0; return APR_FROM_OS_ERROR(err); } (*len) = rv; return rv == 0 ? APR_EOF : APR_SUCCESS; }
APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock, apr_wait_type_t direction) { int pollsocket = sock->socketdes; int wait_rc = select(&pollsocket, direction == APR_WAIT_READ, direction == APR_WAIT_WRITE, 0, sock->timeout / 1000); if (wait_rc == 0) { return APR_TIMEUP; } else if (wait_rc < 0) { return APR_FROM_OS_ERROR(sock_errno()); } return APR_SUCCESS; }
apr_status_t jxr_send_brigade(jaxer_connection * ac, apr_bucket_brigade * bb) { apr_bucket *bucket; apr_status_t rv; compat_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ac->request, "mod_jaxer: sending a brigade (sock=%d)", ac->sock); for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) { char *write_buf; apr_size_t write_buf_len; if (APR_BUCKET_IS_EOS(bucket)) break; if (APR_BUCKET_IS_FLUSH(bucket)) continue; if ((rv = apr_bucket_read(bucket, (const char **)&write_buf, &write_buf_len, APR_BLOCK_READ)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, ac->request, "mod_jaxer: can't read request from bucket"); return rv; } { int type = jxr_msg_get_type(write_buf); apr_size_t pos; // not used apr_size_t len = jxr_msg_get_length(write_buf, &pos); compat_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ac->request, "mod_jaxer: sending a brigade (type=%s len=%d)", sBlockType[type], len); } /* Write the buffer to jaxer server */ if(0 > jxr_socket_sendfull(ac, write_buf, (int) write_buf_len)) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, APR_FROM_OS_ERROR(rv), ac->request, "mod_jaxer: can't write to socket"); return apr_get_os_error(); } } compat_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ac->request, "mod_jaxer: sent a brigade (sock=%d)", ac->sock); return APR_SUCCESS; }
static apr_status_t socket_cleanup(void *sock) { apr_socket_t *thesocket = sock; if (thesocket->socketdes < 0) { return APR_EINVALSOCK; } if (soclose(thesocket->socketdes) == 0) { thesocket->socketdes = -1; return APR_SUCCESS; } else { return APR_FROM_OS_ERROR(sock_errno()); } }
/* callback from libevent when a udp socket is ready to be read. This function determines the packet type, then calls gx_recvqlog() or gx_recvqexec(). */ static void gx_recvfrom(SOCKET sock, short event, void* arg) { gpmon_packet_t pkt; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); int n; if (!(event & EV_READ)) return; n = recvfrom(sock, &pkt, sizeof(pkt), 0, (void*) &addr, &addrlen); if (n == -1) { gpmon_warningx(FLINE, APR_FROM_OS_ERROR(errno), "recvfrom failed"); return; } if (n != sizeof(pkt)) { gpmon_warning(FLINE, "bad packet (length %d). Expected packet size %d", n, sizeof(pkt)); return; } /* do some packet marshaling */ if (0 != gpmon_ntohpkt(pkt.magic, pkt.version, pkt.pkttype)) { gpmon_warning(FLINE, "error with packet marshaling"); return; } /* process the packet */ switch (pkt.pkttype) { case GPMON_PKTTYPE_QLOG: gx_recvqlog(&pkt); break; case GPMON_PKTTYPE_SEGINFO: gx_recvsegment(&pkt); break; case GPMON_PKTTYPE_QEXEC: gx_recvqexec(&pkt); break; default: gpmon_warning(FLINE, "unexpected packet type %d", pkt.pkttype); return; } }
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) { ULONG rc; ULONG byteswritten; if (!thefile->isopen) { return APR_EBADF; } rc = DosWrite(thefile->filedes, &ch, 1, &byteswritten); if (rc) { return APR_FROM_OS_ERROR(rc); } return APR_SUCCESS; }
apr_status_t proc_read_ipc(fcgid_ipc * ipc_handle, const char *buffer, apr_size_t * size) { apr_status_t rv; fcgid_namedpipe_handle *handle_info; DWORD bytesread; handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info; if (ReadFile(handle_info->handle_pipe, (LPVOID) buffer, *size, &bytesread, &handle_info->overlap_read)) { *size = bytesread; return APR_SUCCESS; } else if ((rv = GetLastError()) != ERROR_IO_PENDING) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_FROM_OS_ERROR(rv), ipc_handle->request, "mod_fcgid: can't read from pipe"); return rv; } else { /* it's ERROR_IO_PENDING */ DWORD transferred; DWORD dwWaitResult = WaitForSingleObject(handle_info->overlap_read.hEvent, ipc_handle->communation_timeout * 1000); if (dwWaitResult == WAIT_OBJECT_0) { if (!GetOverlappedResult(handle_info->handle_pipe, &handle_info->overlap_read, &transferred, FALSE /* don't wait */ ) || transferred == 0) { rv = apr_get_os_error(); ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, ipc_handle->request, "mod_fcgid: get overlap result error"); return rv; } *size = transferred; return APR_SUCCESS; } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ipc_handle->request, "mod_fcgid: read timeout from pipe"); return APR_ETIMEDOUT; } } }
APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) { ULONG rc; if (mutex->hMutex == 0) return APR_SUCCESS; while (DosReleaseMutexSem(mutex->hMutex) == 0); rc = DosCloseMutexSem(mutex->hMutex); if (!rc) { mutex->hMutex = 0; return APR_SUCCESS; } return APR_FROM_OS_ERROR(rc); }
/* * read_with_timeout() * Uses async i/o to emulate unix non-blocking i/o with timeouts. */ static apr_status_t read_with_timeout(apr_file_t *file, void *buf, apr_size_t len_in, apr_size_t *nbytes) { apr_status_t rv; DWORD res; DWORD len = (DWORD)len_in; DWORD bytesread = 0; /* Handle the zero timeout non-blocking case */ if (file->timeout == 0) { /* Peek at the pipe. If there is no data available, return APR_EAGAIN. * If data is available, go ahead and read it. */ if (file->pipe) { DWORD bytes; if (!PeekNamedPipe(file->filehand, NULL, 0, NULL, &bytes, NULL)) { rv = apr_get_os_error(); if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) { rv = APR_EOF; } *nbytes = 0; return rv; } else { if (bytes == 0) { *nbytes = 0; return APR_EAGAIN; } if (len > bytes) { len = bytes; } } } else { /* ToDo: Handle zero timeout non-blocking file i/o * This is not needed until an APR application needs to * timeout file i/o (which means setting file i/o non-blocking) */ } } if (file->pOverlapped && !file->pipe) { file->pOverlapped->Offset = (DWORD)file->filePtr; file->pOverlapped->OffsetHigh = (DWORD)(file->filePtr >> 32); }
APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, apr_os_shm_t *osshm, apr_pool_t *pool) { int rc; apr_shm_t *newm = (apr_shm_t *)apr_palloc(pool, sizeof(apr_shm_t)); ULONG flags = PAG_COMMIT|PAG_READ|PAG_WRITE; newm->pool = pool; rc = DosGetSharedMem(&(newm->memblock), flags); if (rc) { return APR_FROM_OS_ERROR(rc); } *m = newm; return APR_SUCCESS; }
apr_status_t apr_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on) { socklen_t option_len = sizeof (int); int os_error = 0; switch(opt) { case APR_SO_ERROR: if (getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, &os_error, &option_len) < 0) return errno; else *on = APR_FROM_OS_ERROR (os_error); break; default: *on = apr_is_option_set(sock, opt); } return APR_SUCCESS; }
APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, apr_pool_t *pool) { int rc; apr_thread_cond_t *cv; cv = apr_pcalloc(pool, sizeof(**cond)); rc = DosCreateEventSem(NULL, &cv->semaphore, DCE_POSTONE, FALSE); if (rc == 0) { rc = DosCreateMutexSem(NULL, &cv->mutex, 0, FALSE); } *cond = cv; cv->pool = pool; apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup, apr_pool_cleanup_null); return APR_FROM_OS_ERROR(rc); }
static void send_fully(SOCKET sock, const void* p_, int len) { const char* p = p_; const char* q = p + len; while (p < q) { int n = send(sock, p, q - p, 0); if (n == -1) { switch (errno) { case EINTR: case EAGAIN: continue; } gpsmon_fatalx(FLINE, APR_FROM_OS_ERROR(errno), "send failed"); } p += n; } }
APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, const char *filename, apr_pool_t *pool) { int rc; apr_shm_t *newm = (apr_shm_t *)apr_palloc(pool, sizeof(apr_shm_t)); char *name = NULL; ULONG flags = PAG_READ|PAG_WRITE; newm->pool = pool; name = apr_pstrcat(pool, "\\SHAREMEM\\", filename, NULL); rc = DosGetNamedSharedMem(&(newm->memblock), name, flags); if (rc) { return APR_FROM_OS_ERROR(rc); } *m = newm; return APR_SUCCESS; }
static apr_status_t file_dup(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p) { int rv; apr_file_t *dup_file; if (*new_file == NULL) { dup_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t)); if (dup_file == NULL) { return APR_ENOMEM; } dup_file->filedes = -1; } else { dup_file = *new_file; } dup_file->pool = p; rv = DosDupHandle(old_file->filedes, &dup_file->filedes); if (rv) { return APR_FROM_OS_ERROR(rv); } dup_file->fname = apr_pstrdup(dup_file->pool, old_file->fname); dup_file->buffered = old_file->buffered; dup_file->isopen = old_file->isopen; dup_file->flags = old_file->flags & ~APR_INHERIT; dup_file->ungetchar = old_file->ungetchar; /* TODO - dup pipes correctly */ dup_file->pipe = old_file->pipe; if (*new_file == NULL) { apr_pool_cleanup_register(dup_file->pool, dup_file, apr_file_cleanup, apr_pool_cleanup_null); *new_file = dup_file; } return APR_SUCCESS; }
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) { if (thefile->buffered) { ULONG written = 0; int rc = 0; if (thefile->direction == 1 && thefile->bufpos) { rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written); thefile->filePtr += written; if (rc == 0) thefile->bufpos = 0; } return APR_FROM_OS_ERROR(rc); } else { /* There isn't anything to do if we aren't buffering the output * so just return success. */ return APR_SUCCESS; } }
APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, apr_int32_t flags, char *buf, apr_size_t *len) { apr_ssize_t rv; int serrno; do { rv = recvfrom(sock->socketdes, buf, (*len), flags, (struct sockaddr*)&from->sa, &from->salen); } while (rv == -1 && (serrno = sock_errno()) == EINTR); if (rv == -1 && serrno == SOCEWOULDBLOCK && sock->timeout != 0) { apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1); if (arv != APR_SUCCESS) { *len = 0; return arv; } else { do { rv = recvfrom(sock->socketdes, buf, *len, flags, (struct sockaddr*)&from->sa, &from->salen); } while (rv == -1 && (serrno = sock_errno()) == EINTR); } } if (rv == -1) { (*len) = 0; return APR_FROM_OS_ERROR(serrno); } (*len) = rv; if (rv == 0 && sock->type == SOCK_STREAM) return APR_EOF; return APR_SUCCESS; }
AP_DECLARE(apr_status_t) ap_regkey_value_raw_set(ap_regkey_t *key, const char *valuename, const void *value, apr_size_t valuesize, apr_int32_t valuetype, apr_pool_t *pool) { LONG rc; #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_size_t valuelen = strlen(valuename) + 1; apr_size_t wvallen = 256; apr_wchar_t wvalname[256]; apr_status_t rv; rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen); if (rv != APR_SUCCESS) return rv; else if (valuelen) return APR_ENAMETOOLONG; rc = RegSetValueExW(key->hkey, wvalname, 0, valuetype, (LPBYTE)value, (DWORD)valuesize); } #endif /* APR_HAS_UNICODE_FS */ #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { rc = RegSetValueEx(key->hkey, valuename, 0, valuetype, (LPBYTE)value, (DWORD)valuesize); } #endif if (rc != ERROR_SUCCESS) { return APR_FROM_OS_ERROR(rc); } return APR_SUCCESS; }
static void server_maintenance(void *vpArg) { int num_idle, num_needed; ULONG num_pending = 0; int threadnum; HQUEUE workq; ULONG rc; PID owner; rc = DosOpenQueue(&owner, &workq, apr_psprintf(pchild, "/queues/httpd/work.%d", getpid())); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "unable to open work queue in maintenance thread"); return; } do { for (num_idle=0, threadnum=0; threadnum < HARD_THREAD_LIMIT; threadnum++) { num_idle += ap_scoreboard_image->servers[child_slot][threadnum].status == SERVER_READY; } DosQueryQueue(workq, &num_pending); num_needed = ap_min_spare_threads - num_idle + num_pending; if (num_needed > 0) { for (threadnum=0; threadnum < num_needed; threadnum++) { add_worker(); } } if (num_idle - num_pending > ap_max_spare_threads) { DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0); } } while (DosWaitEventSem(shutdown_event, 500) == ERROR_TIMEOUT); }
APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, apr_int32_t flags, const char *buf, apr_size_t *len) { apr_ssize_t rv; int serrno; do { rv = sendto(sock->socketdes, buf, (*len), flags, (struct sockaddr*)&where->sa, where->salen); } while (rv == -1 && (serrno = sock_errno()) == EINTR); if (rv == -1 && serrno == SOCEWOULDBLOCK && sock->timeout != 0) { apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; } else { do { rv = sendto(sock->socketdes, buf, *len, flags, (const struct sockaddr*)&where->sa, where->salen); } while (rv == -1 && (serrno = sock_errno()) == SOCEINTR); } } if (rv == -1) { *len = 0; return APR_FROM_OS_ERROR(serrno); } *len = rv; return APR_SUCCESS; }
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 worker_main(void *vpArg) { long conn_id; conn_rec *current_conn; apr_pool_t *pconn; apr_allocator_t *allocator; apr_bucket_alloc_t *bucket_alloc; worker_args_t *worker_args; HQUEUE workq; PID owner; int rc; REQUESTDATA rd; ULONG len; BYTE priority; int thread_slot = (int)vpArg; EXCEPTIONREGISTRATIONRECORD reg_rec = { NULL, thread_exception_handler }; ap_sb_handle_t *sbh; /* Trap exceptions in this thread so we don't take down the whole process */ DosSetExceptionHandler( ®_rec ); rc = DosOpenQueue(&owner, &workq, apr_psprintf(pchild, "/queues/httpd/work.%d", getpid())); if (rc) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, "unable to open work queue, exiting"); ap_scoreboard_image->servers[child_slot][thread_slot].tid = 0; } conn_id = ID_FROM_CHILD_THREAD(child_slot, thread_slot); ap_update_child_status_from_indexes(child_slot, thread_slot, SERVER_READY, NULL); apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); bucket_alloc = apr_bucket_alloc_create_ex(allocator); while (rc = DosReadQueue(workq, &rd, &len, (PPVOID)&worker_args, 0, DCWW_WAIT, &priority, NULLHANDLE), rc == 0 && rd.ulData != WORKTYPE_EXIT) { pconn = worker_args->pconn; ap_create_sb_handle(&sbh, pconn, child_slot, thread_slot); current_conn = ap_run_create_connection(pconn, ap_server_conf, worker_args->conn_sd, conn_id, sbh, bucket_alloc); if (current_conn) { ap_process_connection(current_conn, worker_args->conn_sd); ap_lingering_close(current_conn); } apr_pool_destroy(pconn); ap_update_child_status_from_indexes(child_slot, thread_slot, SERVER_READY, NULL); } ap_update_child_status_from_indexes(child_slot, thread_slot, SERVER_DEAD, NULL); apr_bucket_alloc_destroy(bucket_alloc); apr_allocator_destroy(allocator); }
static apr_status_t bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type_e block) { char *buf; ssize_t ret; BucketData *data; data = (BucketData *) bucket->data; *str = NULL; *len = 0; if (!data->bufferResponse && block == APR_NONBLOCK_READ) { /* * The bucket brigade that Hooks::handleRequest() passes using * ap_pass_brigade() is always passed through ap_content_length_filter, * which is a filter which attempts to read all data from the * bucket brigade and computes the Content-Length header from * that. We don't want this to happen; because suppose that the * Rails application sends back 1 GB of data, then * ap_content_length_filter will buffer this entire 1 GB of data * in memory before passing it to the HTTP client. * * ap_content_length_filter aborts and passes the bucket brigade * down the filter chain when it encounters an APR_EAGAIN, except * for the first read. So by returning APR_EAGAIN on every * non-blocking read request, we can prevent ap_content_length_filter * from buffering all data. */ //return APR_EAGAIN; } buf = (char *) apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, bucket->list); if (buf == NULL) { return APR_ENOMEM; } do { ret = read(data->state->connection, buf, APR_BUCKET_BUFF_SIZE); } while (ret == -1 && errno == EINTR); if (ret > 0) { apr_bucket_heap *h; data->state->bytesRead += ret; *str = buf; *len = ret; bucket->data = NULL; /* Change the current bucket (which is a Passenger Bucket) into a heap bucket * that contains the data that we just read. This newly created heap bucket * will be the first in the bucket list. */ bucket = apr_bucket_heap_make(bucket, buf, *len, apr_bucket_free); h = (apr_bucket_heap *) bucket->data; h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ /* And after this newly created bucket we insert a new Passenger Bucket * which can read the next chunk from the stream. */ APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create( data->state, bucket->list, data->bufferResponse)); /* The newly created Passenger Bucket has a reference to the session * object, so we can delete data here. */ delete data; return APR_SUCCESS; } else if (ret == 0) { data->state->completed = true; delete data; bucket->data = NULL; apr_bucket_free(buf); bucket = apr_bucket_immortal_make(bucket, "", 0); *str = (const char *) bucket->data; *len = 0; return APR_SUCCESS; } else /* ret == -1 */ { int e = errno; data->state->completed = true; data->state->errorCode = e; delete data; bucket->data = NULL; apr_bucket_free(buf); return APR_FROM_OS_ERROR(e); } }
AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result, ap_regkey_t *key, const char *valuename, apr_pool_t *pool) { /* Retrieve a registry string value, and explode any envvars * that the system has configured (e.g. %SystemRoot%/someapp.exe) */ LONG rc; DWORD type; apr_size_t size = 0; #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_size_t valuelen = strlen(valuename) + 1; apr_size_t wvallen = 256; apr_wchar_t wvalname[256]; apr_wchar_t *wvalue; apr_status_t rv; rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen); if (rv != APR_SUCCESS) return rv; else if (valuelen) return APR_ENAMETOOLONG; /* Read to NULL buffer to determine value size */ rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, (DWORD *)&size); if (rc != ERROR_SUCCESS) { return APR_FROM_OS_ERROR(rc); } if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) { return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER); } wvalue = apr_palloc(pool, size); /* Read value based on size query above */ rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, (LPBYTE)wvalue, (DWORD *)&size); if (rc != ERROR_SUCCESS) { return APR_FROM_OS_ERROR(rc); } if (type == REG_EXPAND_SZ) { apr_wchar_t zbuf[1]; size = ExpandEnvironmentStringsW(wvalue, zbuf, 0); if (size) { apr_wchar_t *tmp = wvalue; /* The size returned by ExpandEnvironmentStringsW is wchars */ wvalue = apr_palloc(pool, size * 2); size = ExpandEnvironmentStringsW(tmp, wvalue, (DWORD)size); } } else { /* count wchars from RegQueryValueExW, rather than bytes */ size /= 2; } /* ###: deliberately overallocate all but the trailing null. * We could precalculate the exact buffer here instead, the question * is a matter of storage v.s. cpu cycles. */ valuelen = (size - 1) * 3 + 1; *result = apr_palloc(pool, valuelen); rv = apr_conv_ucs2_to_utf8(wvalue, &size, *result, &valuelen); if (rv != APR_SUCCESS) return rv; else if (size) return APR_ENAMETOOLONG; } #endif /* APR_HAS_UNICODE_FS */ #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { /* Read to NULL buffer to determine value size */ rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, (DWORD *)&size); if (rc != ERROR_SUCCESS) return APR_FROM_OS_ERROR(rc); if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) { return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER); } *result = apr_palloc(pool, size); /* Read value based on size query above */ rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, (DWORD *)&size); if (rc != ERROR_SUCCESS) return APR_FROM_OS_ERROR(rc); if (type == REG_EXPAND_SZ) { /* Advise ExpandEnvironmentStrings that we have a zero char * buffer to force computation of the required length. */ char zbuf[1]; size = ExpandEnvironmentStrings(*result, zbuf, 0); if (size) { char *tmp = *result; *result = apr_palloc(pool, size); size = ExpandEnvironmentStrings(tmp, *result, (DWORD)size); } } } #endif return APR_SUCCESS; }
static void gx_accept(SOCKET sock, short event, void* arg) { SOCKET nsock; gp_smon_to_mmon_packet_t pkt; struct sockaddr_in a; socklen_t alen = sizeof(a); char* p; char* q; if (event & EV_TIMEOUT) { if (gx.tcp_sock) { /* start watching connect request again */ if (event_add(&gx.listen_event, 0)) { gpsmon_fatal(FLINE, "event_add failed"); } return; } gpmon_fatal(FLINE, "smon terminates due to no requests come after %" FMT64 " seconds\n", opt.terminate_timeout); } if (0 == (event & EV_READ)) return; if (-1 == (nsock = accept(sock, (void*) &a, &alen))) { gpmon_warningx(FLINE, APR_FROM_OS_ERROR(errno), "accept failed"); return; } TR1(("accepted\n")); /* we do this one at a time */ if (gx.tcp_sock) { gpmon_warning(FLINE, "cannot accept new connection before old one dies"); close(nsock); return; } p = (char*) &pkt; q = p + sizeof(pkt); while (p < q) { int n = recv(nsock, p, q - p, 0); if (n == -1) { gpmon_warningx(FLINE, APR_FROM_OS_ERROR(errno), "recv failed"); close(nsock); return; } p += n; } if (0 != gpmon_ntohpkt(pkt.header.magic, pkt.header.version, pkt.header.pkttype)) { close(nsock); return; } if (pkt.header.pkttype != GPMON_PKTTYPE_HELLO) { close(nsock); return; } if (pkt.u.hello.signature != gx.signature) { gx_exit("bad signature... maybe a new gpmmon has started"); } /* echo the hello */ pkt.u.hello.pid = getpid(); TR2(("accepted pkt.magic = %x\n", (int) pkt.header.magic)); send_smon_to_mon_pkt(nsock, &pkt); struct timeval tv; tv.tv_sec = opt.terminate_timeout; tv.tv_usec = 0; event_set(&gx.tcp_event, nsock, EV_READ | EV_PERSIST | EV_TIMEOUT, gx_gettcpcmd, 0); if (event_add(&gx.tcp_event, &tv)) { gpmon_warningx(FLINE, APR_FROM_OS_ERROR(errno), "event_add failed"); close(nsock); return; } gx.tcp_sock = nsock; TR1(("connection established --------------------- \n")); }
static void gx_gettcpcmd(SOCKET sock, short event, void* arg) { char dump; int n, e; apr_pool_t* oldpool; apr_hash_t* qetab; apr_hash_t* qdtab; apr_hash_t* pidtab; apr_hash_t* segtab; if (event & EV_TIMEOUT) // didn't get command from gpmmon, quit { if(gx.tcp_sock) { close(gx.tcp_sock); gx.tcp_sock=0; } return; } apr_hash_t* querysegtab; n = recv(sock, &dump, 1, 0); if (n == 0) gx_exit("peer closed"); if (n == -1) gx_exit("socket error"); if (dump != 'D') gx_exit("bad data"); TR1(("start dump %c\n", dump)); qetab = gx.qexectab; qdtab = gx.qlogtab; pidtab = gx.pidtab; segtab = gx.segmenttab; querysegtab = gx.querysegtab; oldpool = apr_hash_pool_get(qetab); /* make new hashtabs for next cycle */ { apr_pool_t* newpool; if (0 != (e = apr_pool_create_alloc(&newpool, gx.pool))) { gpsmon_fatalx(FLINE, e, "apr_pool_create_alloc failed"); } /* qexec hash table */ gx.qexectab = apr_hash_make(newpool); CHECKMEM(gx.qexectab); /* qlog hash table */ gx.qlogtab = apr_hash_make(newpool); CHECKMEM(gx.qlogtab); /* segment hash table */ gx.segmenttab = apr_hash_make(newpool); CHECKMEM(gx.segmenttab); /* queryseg hash table */ gx.querysegtab = apr_hash_make(newpool); CHECKMEM(gx.querysegtab); /* pidtab hash table */ gx.pidtab = apr_hash_make(newpool); CHECKMEM(gx.pidtab); } /* push out a metric of the machine */ send_machine_metrics(sock); send_fsinfo(sock); /* push out records */ { apr_hash_index_t* hi; gp_smon_to_mmon_packet_t* ppkt = 0; gp_smon_to_mmon_packet_t localPacketObject; pidrec_t* pidrec; int count = 0; apr_hash_t* query_cpu_table = NULL; for (hi = apr_hash_first(0, querysegtab); hi; hi = apr_hash_next(hi)) { void* vptr; apr_hash_this(hi, 0, 0, &vptr); ppkt = vptr; if (ppkt->header.pkttype != GPMON_PKTTYPE_QUERYSEG) continue; TR2(("sending magic %x, pkttype %d\n", ppkt->header.magic, ppkt->header.pkttype)); send_smon_to_mon_pkt(sock, ppkt); count++; } for (hi = apr_hash_first(0, segtab); hi; hi = apr_hash_next(hi)) { void* vptr; apr_hash_this(hi, 0, 0, &vptr); ppkt = vptr; if (ppkt->header.pkttype != GPMON_PKTTYPE_SEGINFO) continue; /* fill in hostname */ strncpy(ppkt->u.seginfo.hostname, gx.hostname, sizeof(ppkt->u.seginfo.hostname) - 1); ppkt->u.seginfo.hostname[sizeof(ppkt->u.seginfo.hostname) - 1] = 0; TR2(("sending magic %x, pkttype %d\n", ppkt->header.magic, ppkt->header.pkttype)); send_smon_to_mon_pkt(sock, ppkt); count++; } for (hi = apr_hash_first(0, qdtab); hi; hi = apr_hash_next(hi)) { void* vptr; apr_hash_this(hi, 0, 0, &vptr); ppkt = vptr; if (ppkt->header.pkttype != GPMON_PKTTYPE_QLOG) continue; TR2(("sending magic %x, pkttype %d\n", ppkt->header.magic, ppkt->header.pkttype)); send_smon_to_mon_pkt(sock, ppkt); count++; } for (hi = apr_hash_first(0, qetab); hi; hi = apr_hash_next(hi)) { gpmon_qexec_t* qexec; void *vptr; apr_hash_this(hi, 0, 0, &vptr); qexec = vptr; /* fill in _p_metrics */ pidrec = apr_hash_get(pidtab, &qexec->key.hash_key.pid, sizeof(qexec->key.hash_key.pid)); if (pidrec) { qexec->_p_metrics = pidrec->p_metrics; qexec->_cpu_elapsed = pidrec->cpu_elapsed; } else { memset(&qexec->_p_metrics, 0, sizeof(qexec->_p_metrics)); } /* fill in _hname */ strncpy(qexec->_hname, gx.hostname, sizeof(qexec->_hname) - 1); qexec->_hname[sizeof(qexec->_hname) - 1] = 0; if (0 == create_qexec_packet(qexec, &localPacketObject)) { break; } TR2(("sending qexec, pkttype %d\n", localPacketObject.header.pkttype)); send_smon_to_mon_pkt(sock, &localPacketObject); count++; } // calculate CPU utilization per query for this machine query_cpu_table = apr_hash_make(oldpool); CHECKMEM(query_cpu_table); // loop through PID's and add to Query CPU Hash Table for (hi = apr_hash_first(0, pidtab); hi; hi = apr_hash_next(hi)) { void* vptr; pidrec_t* lookup; apr_hash_this(hi, 0, 0, &vptr); pidrec = vptr; TR2(("tmid %d ssid %d ccnt %d pid %d (CPU elapsed %d CPU Percent %.2f)\n", pidrec->query_key.tmid, pidrec->query_key.ssid, pidrec->query_key.ccnt, pidrec->pid, pidrec->cpu_elapsed, pidrec->p_metrics.cpu_pct)); // table is keyed on query key lookup = apr_hash_get(query_cpu_table, &pidrec->query_key, sizeof(pidrec->query_key)); if (lookup) { // found other pids with same query key so add the metrics to that lookup->cpu_elapsed += pidrec->cpu_elapsed; lookup->p_metrics.cpu_pct += pidrec->p_metrics.cpu_pct; } else { // insert existing pid record into table keyed by query key apr_hash_set(query_cpu_table, &pidrec->query_key, sizeof(pidrec->query_key), pidrec); } } // reset packet to 0 ppkt = &localPacketObject; memset(ppkt, 0, sizeof(gp_smon_to_mmon_packet_t)); gp_smon_to_mmon_set_header(ppkt,GPMON_PKTTYPE_QUERY_HOST_METRICS); // add the hostname into the packet for DEBUGGING purposes only. This is not used strncpy(ppkt->u.qlog.user, gx.hostname, sizeof(ppkt->u.qlog.user) - 1); ppkt->u.qlog.user[sizeof(ppkt->u.qlog.user) - 1] = 0; // loop through the query per cpu table and send the metrics for (hi = apr_hash_first(0, query_cpu_table); hi; hi = apr_hash_next(hi)) { void* vptr; apr_hash_this(hi, 0, 0, &vptr); pidrec = vptr; ppkt->u.qlog.key.tmid = pidrec->query_key.tmid; ppkt->u.qlog.key.ssid = pidrec->query_key.ssid; ppkt->u.qlog.key.ccnt = pidrec->query_key.ccnt; ppkt->u.qlog.cpu_elapsed = pidrec->cpu_elapsed; ppkt->u.qlog.p_metrics.cpu_pct = pidrec->p_metrics.cpu_pct; TR2(("SEND tmid %d ssid %d ccnt %d (CPU elapsed %d CPU Percent %.2f)\n", ppkt->u.qlog.key.tmid, ppkt->u.qlog.key.ssid, ppkt->u.qlog.key.ccnt, ppkt->u.qlog.cpu_elapsed, ppkt->u.qlog.p_metrics.cpu_pct)); send_smon_to_mon_pkt(sock, ppkt); count++; } TR1(("end dump ... sent %d entries\n", count)); } /* get rid of the old pool */ { apr_pool_destroy(oldpool); } struct timeval tv; tv.tv_sec = opt.terminate_timeout; tv.tv_usec = 0; if (event_add(&gx.tcp_event, &tv)) //reset timeout { gpmon_warningx(FLINE, APR_FROM_OS_ERROR(errno), "event_add failed"); } return; }