void schedule(void (*f)(void*,void*,void*,void*),int nloops, void *a1, void *a2, void *a3, void *a4) { pool *p, *sub_pool; sched_t *s; if (scheds == NULL) { p = make_sub_pool(permanent_pool); pr_pool_tag(p, "Schedules Pool"); scheds = xaset_create(p, NULL); } else { p = scheds->pool; } sub_pool = make_sub_pool(p); pr_pool_tag(sub_pool, "schedule pool"); s = pcalloc(sub_pool, sizeof(sched_t)); s->pool = sub_pool; s->f = f; s->a1 = a1; s->a2 = a2; s->a3 = a3; s->a4 = a4; s->loops = nloops; xaset_insert(scheds, (xasetmember_t *) s); }
int child_add(pid_t pid, int fd) { pool *p; pr_child_t *ch; /* If no child-tracking list has been allocated, create one. */ if (!child_pool) { child_pool = make_sub_pool(permanent_pool); pr_pool_tag(child_pool, "Child Pool"); } if (!child_list) child_list = xaset_create(make_sub_pool(child_pool), NULL); p = make_sub_pool(child_pool); pr_pool_tag(p, "child session pool"); ch = pcalloc(p, sizeof(pr_child_t)); ch->ch_pool = p; ch->ch_pid = pid; time(&ch->ch_when); ch->ch_pipefd = fd; ch->ch_dead = FALSE; xaset_insert(child_list, (xasetmember_t *) ch); child_listlen++; return 0; }
static void create_main_server(void) { pool *main_pool; main_pool = make_sub_pool(permanent_pool); pr_pool_tag(main_pool, "testsuite#main_server pool"); server_list = xaset_create(main_pool, NULL); main_server = (server_rec *) pcalloc(main_pool, sizeof(server_rec)); xaset_insert(server_list, (xasetmember_t *) main_server); main_server->pool = main_pool; main_server->conf = xaset_create(main_pool, NULL); main_server->set = server_list; main_server->sid = 1; main_server->notes = pr_table_nalloc(main_pool, 0, 8); /* TCP KeepAlive is enabled by default, with the system defaults. */ main_server->tcp_keepalive = palloc(main_server->pool, sizeof(struct tcp_keepalive)); main_server->tcp_keepalive->keepalive_enabled = TRUE; main_server->tcp_keepalive->keepalive_idle = -1; main_server->tcp_keepalive->keepalive_count = -1; main_server->tcp_keepalive->keepalive_intvl = -1; main_server->ServerName = "Test Server"; main_server->ServerPort = 21; }
void schedule(void (*cb)(void *, void *, void *, void *), int nloops, void *arg1, void *arg2, void *arg3, void *arg4) { pool *p, *sub_pool; sched_t *s; if (cb == NULL || nloops < 0) { return; } if (scheds == NULL) { p = make_sub_pool(permanent_pool); pr_pool_tag(p, "Schedules Pool"); scheds = xaset_create(p, NULL); } else { p = scheds->pool; } sub_pool = make_sub_pool(p); pr_pool_tag(sub_pool, "schedule pool"); s = pcalloc(sub_pool, sizeof(sched_t)); s->pool = sub_pool; s->cb = cb; s->arg1 = arg1; s->arg2 = arg2; s->arg3 = arg3; s->arg4 = arg4; s->nloops = nloops; xaset_insert(scheds, (xasetmember_t *) s); }
int pr_timer_reset(int timerno, module *mod) { struct timer *t = NULL; if (!timers) { errno = EPERM; return -1; } if (_indispatch) { errno = EINTR; return -1; } pr_alarms_block(); if (!recycled) recycled = xaset_create(timer_pool, NULL); for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno && (t->mod == mod || mod == ANY_MODULE)) { t->count = t->interval; xaset_remove(timers, (xasetmember_t *) t); xaset_insert(recycled, (xasetmember_t *) t); nalarms++; /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is reset. */ handle_alarm(); break; } } pr_alarms_unblock(); if (t != NULL) { pr_trace_msg("timer", 7, "reset timer ID %d ('%s', for module '%s')", t->timerno, t->desc, t->mod ? t->mod->name : "[none]"); return t->timerno; } return 0; }
/* This function does the work of iterating through the list of registered * timers, checking to see if their callbacks should be invoked and whether * they should be removed from the registration list. Its return value is * the amount of time remaining on the first timer in the list. */ static int process_timers(int elapsed) { struct timer *t = NULL, *next = NULL; if (!recycled) recycled = xaset_create(timer_pool, NULL); if (!elapsed && !recycled->xas_list) { if (!timers) return 0; return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); } /* Critical code, no interruptions please */ if (_indispatch) return 0; pr_alarms_block(); _indispatch++; if (elapsed) { for (t = (struct timer *) timers->xas_list; t; t = next) { /* If this timer has already been handled, skip */ next = t->next; if (t->remove) { /* Move the timer onto the free_timers chain, for later reuse. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else if ((t->count -= elapsed) <= 0) { /* This timer's interval has elapsed, so trigger its callback. */ pr_trace_msg("timer", 4, "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking " "callback (%p)", t->interval, t->interval != 1 ? "seconds" : "second", t->timerno, t->desc ? t->desc : "<unknown>", t->mod ? t->mod->name : "<none>", t->callback); if (t->callback(t->interval, t->timerno, t->interval - t->count, t->mod) == 0) { /* A return value of zero means this timer is done, and can be * removed. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else { /* A non-zero return value from a timer callback signals that * the timer should be reused/restarted. */ pr_trace_msg("timer", 6, "restarting timer ID %d ('%s'), as per " "callback", t->timerno, t->desc ? t->desc : "<unknown>"); xaset_remove(timers, (xasetmember_t *) t); t->count = t->interval; xaset_insert(recycled, (xasetmember_t *) t); } } } } /* Put the recycled timers back into the main timer list. */ while ((t = (struct timer *) recycled->xas_list) != NULL) { xaset_remove(recycled, (xasetmember_t *) t); xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); } _indispatch--; pr_alarms_unblock(); /* If no active timers remain in the list, there is no reason to set the * SIGALRM handle. */ return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); }
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb, const char *desc) { struct timer *t = NULL; if (seconds <= 0 || cb == NULL || desc == NULL) { errno = EINVAL; return -1; } if (!timers) timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp); /* Check to see that, if specified, the timerno is not already in use. */ if (timerno >= 0) { for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno) { errno = EPERM; return -1; } } } if (!free_timers) free_timers = xaset_create(timer_pool, NULL); /* Try to use an old timer first */ pr_alarms_block(); t = (struct timer *) free_timers->xas_list; if (t != NULL) { xaset_remove(free_timers, (xasetmember_t *) t); } else { if (timer_pool == NULL) { timer_pool = make_sub_pool(permanent_pool); pr_pool_tag(timer_pool, "Timer Pool"); } /* Must allocate a new one */ t = palloc(timer_pool, sizeof(struct timer)); } if (timerno < 0) { /* Dynamic timer */ if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) { dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO; } timerno = dynamic_timerno++; } t->timerno = timerno; t->count = t->interval = seconds; t->callback = cb; t->mod = mod; t->remove = 0; t->desc = desc; /* If called while _indispatch, add to the recycled list to prevent * list corruption */ if (_indispatch) { if (!recycled) recycled = xaset_create(timer_pool, NULL); xaset_insert(recycled, (xasetmember_t *) t); } else { xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); nalarms++; set_sig_alarm(); /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is added. */ handle_alarm(); } pr_alarms_unblock(); pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), " "triggering in %ld %s", t->timerno, t->desc, t->mod ? t->mod->name : "[none]", t->interval, t->interval != 1 ? "seconds" : "second"); return timerno; }
int pr_timer_remove(int timerno, module *mod) { struct timer *t = NULL, *tnext = NULL; int nremoved = 0; /* If there are no timers currently registered, do nothing. */ if (!timers) return 0; pr_alarms_block(); for (t = (struct timer *) timers->xas_list; t; t = tnext) { tnext = t->next; if ((timerno < 0 || t->timerno == timerno) && (mod == ANY_MODULE || t->mod == mod)) { nremoved++; if (_indispatch) { t->remove++; } else { xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); nalarms++; /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is removed. */ handle_alarm(); } pr_trace_msg("timer", 7, "removed timer ID %d ('%s', for module '%s')", t->timerno, t->desc, t->mod ? t->mod->name : "[none]"); } /* If we are removing a specific timer, break out of the loop now. * Otherwise, keep removing any matching timers. */ if (nremoved > 0 && timerno >= 0) { break; } } pr_alarms_unblock(); if (nremoved == 0) { errno = ENOENT; return -1; } /* If we removed a specific timer because of the given timerno, return * that timerno value. */ if (timerno >= 0) { return timerno; } return nremoved; }
config_rec *pr_parser_config_ctxt_open(const char *name) { config_rec *c = NULL, *parent = *parser_curr_config; pool *c_pool = NULL, *parent_pool = NULL; xaset_t **set = NULL; if (name == NULL) { errno = EINVAL; return NULL; } if (parent) { parent_pool = parent->pool; set = &parent->subset; } else { parent_pool = (*parser_curr_server)->pool; set = &(*parser_curr_server)->conf; } /* Allocate a sub-pool for this config_rec. * * Note: special exception for <Global> configs: the parent pool is * 'global_config_pool' (a pool just for that context), not the pool of the * parent server. This keeps <Global> config recs from being freed * prematurely, and helps to avoid memory leaks. */ if (strncasecmp(name, "<Global>", 9) == 0) { if (global_config_pool == NULL) { global_config_pool = make_sub_pool(permanent_pool); pr_pool_tag(global_config_pool, "<Global> Pool"); } parent_pool = global_config_pool; } c_pool = make_sub_pool(parent_pool); pr_pool_tag(c_pool, "sub-config pool"); c = (config_rec *) pcalloc(c_pool, sizeof(config_rec)); if (!*set) { pool *set_pool = make_sub_pool(parent_pool); *set = xaset_create(set_pool, NULL); (*set)->pool = set_pool; } xaset_insert(*set, (xasetmember_t *) c); c->pool = c_pool; c->set = *set; c->parent = parent; c->name = pstrdup(c->pool, name); if (parent) { if (parent->config_type == CONF_DYNDIR) { c->flags |= CF_DYNAMIC; } } (void) pr_parser_config_ctxt_push(c); return c; }
static int counter_sess_init(void) { config_rec *c; c = find_config(main_server->conf, CONF_PARAM, "CounterEngine", FALSE); if (c != NULL) { counter_engine = *((int *) c->argv[0]); } if (counter_engine == FALSE) { return 0; } c = find_config(main_server->conf, CONF_PARAM, "CounterLog", FALSE); if (c != NULL) { const char *path = c->argv[0]; if (strcasecmp(path, "none") != 0) { int res, xerrno; PRIVS_ROOT res = pr_log_openfile(path, &counter_logfd, 0660); xerrno = errno; PRIVS_RELINQUISH; if (res < 0) { pr_log_debug(DEBUG2, MOD_COUNTER_VERSION ": error opening CounterLog '%s': %s", path, strerror(xerrno)); counter_logfd = -1; } } } /* Find all CounterFile directives for this vhost, and make sure they * have open handles. We need to do this here, and not in a POST_CMD * PASS handler because of the need to open handles that may be outside * of a chroot. */ c = find_config(main_server->conf, CONF_PARAM, "CounterFile", TRUE); while (c != NULL) { int xerrno = 0; const char *area = NULL, *path; pr_fh_t *fh; struct counter_fh *cfh; pr_signals_handle(); path = c->argv[0]; if (c->parent != NULL) { if (c->parent->config_type == CONF_ANON || c->parent->config_type == CONF_DIR) { area = c->parent->name; } else { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "unhandled configuration parent type (%d) for CounterFile, skipping", c->parent->config_type); c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE); continue; } } else { /* Toplevel CounterFile directive, in "server config" or <VirtualHost> * sections. */ area = "/"; } PRIVS_ROOT fh = pr_fsio_open(path, O_RDWR|O_CREAT); xerrno = errno; PRIVS_RELINQUISH if (fh == NULL) { pr_log_debug(DEBUG1, MOD_COUNTER_VERSION ": error opening CounterFile '%s': %s", path, strerror(xerrno)); counter_engine = FALSE; if (counter_fhs != NULL) { for (cfh = (struct counter_fh *) counter_fhs->xas_list; cfh; cfh = cfh->next) { (void) pr_fsio_close(cfh->fh); } } return 0; } (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "opened CounterFile '%s'", path); if (counter_fhs == NULL) { counter_fhs = xaset_create(counter_pool, NULL); } cfh = pcalloc(counter_pool, sizeof(struct counter_fh)); /* Ignore any trailing slash. */ cfh->arealen = strlen(area); if (cfh->arealen > 1 && area[cfh->arealen-1] == '/') { cfh->arealen--; } cfh->area = pstrndup(counter_pool, area, cfh->arealen); /* Mark any areas that use glob(3) characters. */ if (strpbrk(cfh->area, "[*?") != NULL) { cfh->isglob = TRUE; } cfh->fh = fh; xaset_insert(counter_fhs, (xasetmember_t *) cfh); c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE); } if (counter_fhs == NULL) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "no CounterFiles configured, disabling module"); counter_engine = FALSE; return 0; } pr_event_register(&counter_module, "core.exit", counter_exit_ev, NULL); /* If mod_vroot is present, we need to do a little more magic to counter * the mod_vroot magic. */ if (pr_module_exists("mod_vroot.c") == TRUE) { pr_event_register(&counter_module, "core.chroot", counter_chroot_ev, NULL); } return 0; }
conn_t *pr_ipbind_get_listening_conn(server_rec *server, pr_netaddr_t *addr, unsigned int port) { conn_t *l; pool *p; struct listener_rec *lr; if (listening_conn_list) { for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lr->next) { int use_elt = FALSE; pr_signals_handle(); if (addr != NULL && lr->addr != NULL) { const char *lr_ipstr = NULL; lr_ipstr = pr_netaddr_get_ipstr(lr->addr); /* Note: lr_ipstr should never be null. If it is, it means that * the lr->addr object never had its IP address resolved/stashed, * and in attempting to do, getnameinfo(3) failed for some reason. * * The IP address on which it's listening, if not available via * lr->addr, should thus be available via lr->conn->local_addr. */ if (lr_ipstr == NULL && lr->conn != NULL) { lr_ipstr = pr_netaddr_get_ipstr(lr->conn->local_addr); } if (lr_ipstr != NULL) { if (strcmp(pr_netaddr_get_ipstr(addr), lr_ipstr) == 0 && port == lr->port) { use_elt = TRUE; } } } else if (addr == NULL && port == lr->port) { use_elt = TRUE; } if (use_elt) { lr->claimed = TRUE; return lr->conn; } } } if (listening_conn_pool == NULL) { listening_conn_pool = make_sub_pool(permanent_pool); pr_pool_tag(listening_conn_pool, "Listening Connection Pool"); listening_conn_list = xaset_create(listening_conn_pool, NULL); } p = make_sub_pool(listening_conn_pool); pr_pool_tag(p, "Listening conn subpool"); l = pr_inet_create_conn(p, -1, addr, port, FALSE); if (l == NULL) { return NULL; } /* Inform any interested listeners that this socket was opened. */ pr_inet_generate_socket_event("core.ctrl-listen", server, l->local_addr, l->listen_fd); lr = pcalloc(p, sizeof(struct listener_rec)); lr->pool = p; lr->conn = l; lr->addr = pr_netaddr_dup(p, addr); if (lr->addr == NULL && errno != EINVAL) { return NULL; } lr->port = port; lr->claimed = TRUE; xaset_insert(listening_conn_list, (xasetmember_t *) lr); return l; }