void mesh_state_cleanup(struct mesh_state* mstate) { struct mesh_area* mesh; int i; if(!mstate) return; mesh = mstate->s.env->mesh; /* drop unsent replies */ if(!mstate->replies_sent) { struct mesh_reply* rep; struct mesh_cb* cb; for(rep=mstate->reply_list; rep; rep=rep->next) { comm_point_drop_reply(&rep->query_reply); mesh->num_reply_addrs--; } for(cb=mstate->cb_list; cb; cb=cb->next) { fptr_ok(fptr_whitelist_mesh_cb(cb->cb)); (*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL, sec_status_unchecked, NULL); mesh->num_reply_addrs--; } } /* de-init modules */ for(i=0; i<mesh->mods.num; i++) { fptr_ok(fptr_whitelist_mod_clear(mesh->mods.mod[i]->clear)); (*mesh->mods.mod[i]->clear)(&mstate->s, i); mstate->s.minfo[i] = NULL; mstate->s.ext_state[i] = module_finished; } alloc_reg_release(mstate->s.env->alloc, mstate->s.region); }
void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate, enum module_ev ev, struct outbound_entry* e) { enum module_ext_state s; verbose(VERB_ALGO, "mesh_run: start"); while(mstate) { /* run the module */ fptr_ok(fptr_whitelist_mod_operate( mesh->mods.mod[mstate->s.curmod]->operate)); (*mesh->mods.mod[mstate->s.curmod]->operate) (&mstate->s, ev, mstate->s.curmod, e); /* examine results */ mstate->s.reply = NULL; regional_free_all(mstate->s.env->scratch); s = mstate->s.ext_state[mstate->s.curmod]; verbose(VERB_ALGO, "mesh_run: %s module exit state is %s", mesh->mods.mod[mstate->s.curmod]->name, strextstate(s)); e = NULL; if(mesh_continue(mesh, mstate, s, &ev)) continue; /* run more modules */ ev = module_event_pass; if(mesh->run.count > 0) { /* pop random element off the runnable tree */ mstate = (struct mesh_state*)mesh->run.root->key; (void)rbtree_delete(&mesh->run, mstate); } else mstate = NULL; } if(verbosity >= VERB_ALGO) { mesh_stats(mesh, "mesh_run: end"); mesh_log_list(mesh); } }
/** call timeouts handlers, and return how long to wait for next one or -1 */ static void handle_timeouts(struct event_base* base, struct timeval* now, struct timeval* wait) { struct event* p; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } return; } #endif /* event times out, remove it */ (void)rbtree_delete(base->times, p); p->ev_events &= ~EV_TIMEOUT; fptr_ok(fptr_whitelist_event(p->ev_callback)); (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } }
/** handle is_signal events and see if signalled */ static void _getdns_handle_signal(struct _getdns_event* ev) { DWORD ret; //log_assert(ev->is_signal && ev->hEvent); /* see if the event is signalled */ ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, 0 /* return immediately */, 0 /* not alertable for IOcomple*/); if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", wsa_strerror(WSAGetLastError())); return; } if(ret == WSA_WAIT_TIMEOUT) { /* not signalled */ return; } /* reset the signal */ if(!WSAResetEvent(ev->hEvent)) log_err("getdns: WSAResetEvent failed: %s", wsa_strerror(WSAGetLastError())); /* do the callback (which may set the signal again) */ fptr_ok(fptr_whitelist_event(ev->ev_callback)); (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); }
/** pass time */ static void time_passes(struct replay_runtime* runtime, struct replay_moment* mom) { struct fake_timer *t; struct timeval tv = mom->elapse; if(mom->string) { char* xp = macro_process(runtime->vars, runtime, mom->string); double sec; if(!xp) fatal_exit("could not macro expand %s", mom->string); verbose(VERB_ALGO, "EVAL %s", mom->string); sec = atof(xp); free(xp); #ifndef S_SPLINT_S tv.tv_sec = sec; tv.tv_usec = (int)((sec - (double)tv.tv_sec) *1000000. + 0.5); #endif } timeval_add(&runtime->now_tv, &tv); runtime->now_secs = (time_t)runtime->now_tv.tv_sec; #ifndef S_SPLINT_S log_info("elapsed %d.%6.6d now %d.%6.6d", (int)tv.tv_sec, (int)tv.tv_usec, (int)runtime->now_tv.tv_sec, (int)runtime->now_tv.tv_usec); #endif /* see if any timers have fired; and run them */ while( (t=replay_get_oldest_timer(runtime)) ) { t->enabled = 0; log_info("fake_timer callback"); fptr_ok(fptr_whitelist_comm_timer(t->cb)); (*t->cb)(t->cb_arg); } }
/** * callback results to mesh cb entry * @param m: mesh state to send it for. * @param rcode: if not 0, error code. * @param rep: reply to send (or NULL if rcode is set). * @param r: callback entry */ static void mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, struct mesh_cb* r) { int secure; char* reason = NULL; /* bogus messages are not made into servfail, sec_status passed * to the callback function */ if(rep && rep->security == sec_status_secure) secure = 1; else secure = 0; if(!rep && rcode == LDNS_RCODE_NOERROR) rcode = LDNS_RCODE_SERVFAIL; if(!rcode && rep->security == sec_status_bogus) { if(!(reason = errinf_to_str(&m->s))) rcode = LDNS_RCODE_SERVFAIL; } /* send the reply */ if(rcode) { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL); } else { size_t udp_size = r->edns.udp_size; ldns_buffer_clear(r->buf); r->edns.edns_version = EDNS_ADVERTISED_VERSION; r->edns.udp_size = EDNS_ADVERTISED_SIZE; r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, r->qflags, r->buf, 0, 1, m->s.env->scratch, udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO), secure)) { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, sec_status_unchecked, NULL); } else { fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, rep->security, reason); } } free(reason); m->s.env->mesh->num_reply_addrs--; }
/** signal handler */ static RETSIGTYPE sigh(int sig) { struct event* ev; if(!signal_base || sig < 0 || sig >= MAX_SIG) return; ev = signal_base->signals[sig]; if(!ev) return; fptr_ok(fptr_whitelist_event(ev->ev_callback)); (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); }
/** set content of event */ void event_set(struct event* ev, int fd, short bits, void (*cb)(int, short, void *), void* arg) { ev->node.key = ev; ev->ev_fd = fd; ev->ev_events = bits; ev->ev_callback = cb; fptr_ok(fptr_whitelist_event(ev->ev_callback)); ev->ev_arg = arg; ev->added = 0; }
void modstack_desetup(struct module_stack* stack, struct module_env* env) { int i; for(i=0; i<stack->num; i++) { fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit)); (*stack->mod[i]->deinit)(env, i); } stack->num = 0; free(stack->mod); stack->mod = NULL; }
/** print mem stats */ static int print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) { int m; size_t msg, rrset, val, iter; #ifdef HAVE_SBRK extern void* unbound_start_brk; void* cur = sbrk(0); if(!print_longnum(ssl, "mem.total.sbrk"SQ, (size_t)((char*)cur - (char*)unbound_start_brk))) return 0; #endif /* HAVE_SBRK */ msg = slabhash_get_mem(daemon->env->msg_cache); rrset = slabhash_get_mem(&daemon->env->rrset_cache->table); val=0; iter=0; m = modstack_find(&worker->env.mesh->mods, "validator"); if(m != -1) { fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> mods.mod[m]->get_mem)); val = (*worker->env.mesh->mods.mod[m]->get_mem) (&worker->env, m); } m = modstack_find(&worker->env.mesh->mods, "iterator"); if(m != -1) { fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> mods.mod[m]->get_mem)); iter = (*worker->env.mesh->mods.mod[m]->get_mem) (&worker->env, m); } if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset)) return 0; if(!print_longnum(ssl, "mem.cache.message"SQ, msg)) return 0; if(!print_longnum(ssl, "mem.mod.iterator"SQ, iter)) return 0; if(!print_longnum(ssl, "mem.mod.validator"SQ, val)) return 0; return 1; }
/* timers in testbound for autotrust. statistics tested in tpkg. */ struct comm_timer* comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg) { struct replay_runtime* runtime = (struct replay_runtime*)base; struct fake_timer* t = (struct fake_timer*)calloc(1, sizeof(*t)); t->cb = cb; t->cb_arg = cb_arg; fptr_ok(fptr_whitelist_comm_timer(t->cb)); /* check in advance */ t->runtime = runtime; t->next = runtime->timer_list; runtime->timer_list = t; return (struct comm_timer*)t; }
/** * Continue processing the mesh state at another module. * Handles module to modules tranfer of control. * Handles module finished. * @param mesh: the mesh area. * @param mstate: currently active mesh state. * Deleted if finished, calls _done and _supers to * send replies to clients and inform other mesh states. * This in turn may create additional runnable mesh states. * @param s: state at which the current module exited. * @param ev: the event sent to the module. * returned is the event to send to the next module. * @return true if continue processing at the new module. * false if not continued processing is needed. */ static int mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate, enum module_ext_state s, enum module_ev* ev) { mstate->num_activated++; if(mstate->num_activated > MESH_MAX_ACTIVATION) { /* module is looping. Stop it. */ log_err("internal error: looping module stopped"); log_query_info(VERB_QUERY, "pass error for qstate", &mstate->s.qinfo); s = module_error; } if(s == module_wait_module || s == module_restart_next) { /* start next module */ mstate->s.curmod++; if(mesh->mods.num == mstate->s.curmod) { log_err("Cannot pass to next module; at last module"); log_query_info(VERB_QUERY, "pass error for qstate", &mstate->s.qinfo); mstate->s.curmod--; return mesh_continue(mesh, mstate, module_error, ev); } if(s == module_restart_next) { fptr_ok(fptr_whitelist_mod_clear( mesh->mods.mod[mstate->s.curmod]->clear)); (*mesh->mods.mod[mstate->s.curmod]->clear) (&mstate->s, mstate->s.curmod); mstate->s.minfo[mstate->s.curmod] = NULL; } *ev = module_event_pass; return 1; } if(s == module_error && mstate->s.return_rcode == LDNS_RCODE_NOERROR) { /* error is bad, handle pass back up below */ mstate->s.return_rcode = LDNS_RCODE_SERVFAIL; } if(s == module_error || s == module_finished) { if(mstate->s.curmod == 0) { mesh_query_done(mstate); mesh_walk_supers(mesh, mstate); mesh_state_delete(&mstate->s); return 0; } /* pass along the locus of control */ mstate->s.curmod --; *ev = module_event_moddone; return 1; } return 0; }
/** call select and callbacks for that */ static int handle_select(struct event_base* base, struct timeval* wait) { fd_set r, w; int ret, i; #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { ret = errno; if(settime(base) < 0) return -1; errno = ret; if(ret == EAGAIN || ret == EINTR) return 0; return -1; } if(settime(base) < 0) return -1; for(i=0; i<base->maxfd+1; i++) { short bits = 0; if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { continue; } if(FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if(FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->fds[i]->ev_events; if(bits) { fptr_ok(fptr_whitelist_event( base->fds[i]->ev_callback)); (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, bits, base->fds[i]->ev_arg); if(ret==0) break; } } return 0; }
void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate) { struct mesh_state_ref* ref; RBTREE_FOR(ref, struct mesh_state_ref*, &mstate->super_set) { /* make super runnable */ (void)rbtree_insert(&mesh->run, &ref->s->run_node); /* callback the function to inform super of result */ fptr_ok(fptr_whitelist_mod_inform_super( mesh->mods.mod[ref->s->s.curmod]->inform_super)); (*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s, ref->s->s.curmod, &ref->s->s); } }
/** detect dependency cycle for query and target */ static int causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen, uint16_t t, uint16_t c) { struct query_info qinf; qinf.qname = name; qinf.qname_len = namelen; qinf.qtype = t; qinf.qclass = c; fptr_ok(fptr_whitelist_modenv_detect_cycle( qstate->env->detect_cycle)); return (*qstate->env->detect_cycle)(qstate, &qinf, (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming, qstate->is_valrec); }
void tube_handle_signal(int ATTR_UNUSED(fd), short ATTR_UNUSED(events), void* arg) { struct tube* tube = (struct tube*)arg; uint8_t* buf; uint32_t len = 0; verbose(VERB_ALGO, "tube handle_signal"); while(tube_poll(tube)) { if(tube_read_msg(tube, &buf, &len, 1)) { fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, buf, len, NETEVENT_NOERROR, tube->listen_arg); } } }
/* * Inserts a node into a red black tree. * * Returns NULL on failure or the pointer to the newly added node * otherwise. */ getdns_rbnode_t * getdns_rbtree_insert (getdns_rbtree_t *rbtree, getdns_rbnode_t *data) { /* XXX Not necessary, but keeps compiler quiet... */ int r = 0; /* We start at the root of the tree */ getdns_rbnode_t *node = rbtree->root; getdns_rbnode_t *parent = RBTREE_NULL; fptr_ok(fptr_whitelist_getdns_rbtree_cmp(rbtree->cmp)); /* Lets find the new parent... */ while (node != RBTREE_NULL) { /* Compare two keys, do we have a duplicate? */ if ((r = rbtree->cmp(data->key, node->key)) == 0) { return NULL; } parent = node; if (r < 0) { node = node->left; } else { node = node->right; } } /* Initialize the new node */ data->parent = parent; data->left = data->right = RBTREE_NULL; data->color = RED; rbtree->count++; /* Insert it into the tree... */ if (parent != RBTREE_NULL) { if (r < 0) { parent->left = data; } else { parent->right = data; } } else { rbtree->root = data; } /* Fix up the red-black properties... */ getdns_rbtree_insert_fixup(rbtree, data); return data; }
static int generate_cname_request(struct module_qstate* qstate, struct ub_packed_rrset_key* alias_rrset) { struct module_qstate* subq = NULL; struct query_info subqi; memset(&subqi, 0, sizeof(subqi)); get_cname_target(alias_rrset, &subqi.qname, &subqi.qname_len); if(!subqi.qname) return 0; /* unexpected: not a valid CNAME RDATA */ subqi.qtype = qstate->qinfo.qtype; subqi.qclass = qstate->qinfo.qclass; fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq); }
uint64_t alloc_get_id(struct alloc_cache* alloc) { uint64_t id = alloc->next_id++; if(id == alloc->last_id) { log_warn("rrset alloc: out of 64bit ids. Clearing cache."); fptr_ok(fptr_whitelist_alloc_cleanup(alloc->cleanup)); (*alloc->cleanup)(alloc->cleanup_arg); /* start back at first number */ /* like in alloc_init*/ alloc->next_id = (uint64_t)alloc->thread_num; alloc->next_id <<= THRNUM_SHIFT; /* in steps for comp. */ alloc->next_id += 1; /* portability. */ /* and generate new and safe id */ id = alloc->next_id++; } return id; }
/** enumerate all subkeys of base, and call process(hk, arg) on them */ void enum_guids(const char* base, void (*process_it)(HKEY,void*), void* arg) { char subname[1024]; HKEY base_hk, sub_hk; DWORD sz = sizeof(subname); DWORD i = 0, ret; if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)base, 0, /* reserved, mustbezero */ NULL, /* class of key, ignored */ REG_OPTION_NON_VOLATILE, /* values saved on disk */ KEY_WRITE|KEY_ENUMERATE_SUB_KEYS, NULL, /* use default security descriptor */ &base_hk, /* result */ NULL)) /* not interested if key new or existing */ { log_win_err("could not open enum registry key", GetLastError()); return; } while( (ret=RegEnumKeyEx(base_hk, i, (LPTSTR)subname, &sz, NULL, NULL, 0, NULL)) == ERROR_SUCCESS) { verbose(VERB_ALGO, "enum %d %s", (int)i, subname); /* process it */ if(RegOpenKeyEx(base_hk, (LPCTSTR)subname, 0, KEY_WRITE, &sub_hk)) { log_win_err("enum cannot RegOpenKey", GetLastError()); } else { fptr_ok(fptr_whitelist_enum_reg(process_it)); (*process_it)(sub_hk, arg); RegCloseKey(sub_hk); } /* prepare for next iteration */ i++; sz = sizeof(subname); } if(ret == ERROR_MORE_DATA) { log_err("part of %s has registry keys that are too long", base); } else if(ret != ERROR_NO_MORE_ITEMS) { log_win_err("cannot RegEnumKey", GetLastError()); } RegCloseKey(base_hk); }
/** call timeouts handlers, and return how long to wait for next one or -1 */ void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, struct timeval* wait) { struct _getdns_event* p; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif //verbose(VERB_CLIENT, "winsock_event handle_timeouts"); while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } //verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", // (long long)wait->tv_sec, (int)wait->tv_usec); return; } #endif /* event times out, remove it */ (void)_getdns_rbtree_delete(base->times, p); p->ev_events &= ~EV_TIMEOUT; fptr_ok(fptr_whitelist_event(p->ev_callback)); (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } //verbose(VERB_CLIENT, "winsock_event wait=(-1)"); }
int modstack_setup(struct module_stack* stack, const char* module_conf, struct module_env* env) { int i; if(stack->num != 0) modstack_desetup(stack, env); /* fixed setup of the modules */ if(!modstack_config(stack, module_conf)) { return 0; } env->need_to_validate = 0; /* set by module init below */ for(i=0; i<stack->num; i++) { verbose(VERB_OPS, "init module %d: %s", i, stack->mod[i]->name); fptr_ok(fptr_whitelist_mod_init(stack->mod[i]->init)); if(!(*stack->mod[i]->init)(env, i)) { log_err("module init for module %s failed", stack->mod[i]->name); return 0; } } return 1; }
/** Report on memory usage by this thread and global */ static void worker_mem_report(struct worker* ATTR_UNUSED(worker), struct serviced_query* ATTR_UNUSED(cur_serv)) { #ifdef UNBOUND_ALLOC_STATS /* debug func in validator module */ size_t total, front, back, mesh, msg, rrset, infra, ac, superac; size_t me, iter, val, anch; int i; if(verbosity < VERB_ALGO) return; front = listen_get_mem(worker->front); back = outnet_get_mem(worker->back); msg = slabhash_get_mem(worker->env.msg_cache); rrset = slabhash_get_mem(&worker->env.rrset_cache->table); infra = infra_get_mem(worker->env.infra_cache); mesh = mesh_get_mem(worker->env.mesh); ac = alloc_get_mem(&worker->alloc); superac = alloc_get_mem(&worker->daemon->superalloc); anch = anchors_get_mem(worker->env.anchors); iter = 0; val = 0; for(i=0; i<worker->env.mesh->mods.num; i++) { fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> mods.mod[i]->get_mem)); if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) val += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); else iter += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); } me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig) + comm_point_get_mem(worker->cmd_com) + sizeof(worker->rndstate) + regional_get_mem(worker->scratchpad) + sizeof(*worker->env.scratch_buffer) + sldns_buffer_capacity(worker->env.scratch_buffer) + forwards_get_mem(worker->env.fwds) + hints_get_mem(worker->env.hints); if(worker->thread_num == 0) me += acl_list_get_mem(worker->daemon->acl); if(cur_serv) { me += serviced_get_mem(cur_serv); } total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me; log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " "rrset=%u infra=%u iter=%u val=%u anchors=%u " "alloccache=%u globalalloccache=%u me=%u", (unsigned)total, (unsigned)front, (unsigned)back, (unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, (unsigned)ac, (unsigned)superac, (unsigned)me); debug_total_mem(total); #else /* no UNBOUND_ALLOC_STATS */ size_t val = 0; int i; if(verbosity < VERB_QUERY) return; for(i=0; i<worker->env.mesh->mods.num; i++) { fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> mods.mod[i]->get_mem)); if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) val += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); } verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u", (unsigned)slabhash_get_mem(worker->env.msg_cache), (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), (unsigned)infra_get_mem(worker->env.infra_cache), (unsigned)val); #endif /* UNBOUND_ALLOC_STATS */ }
/** call select and callbacks for that */ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) { fd_set r, w; int ret, i, timeout = 0, numwait = 0; struct _getdns_event* eventlist[WSK_MAX_ITEMS]; #ifndef S_SPLINT_S if (wait->tv_sec == (time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); /* if ((ret = select(base->max + 1, &r, &w, NULL, wait)) == -1) { ret = errno; if (settime(base) < 0) return -1; errno = ret; if (ret == EAGAIN || ret == EINTR) return 0; return -1; } */ /* prepare event array */ for (i = 0; i<base->max; i++) { if (base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) continue; /* skip timer only events */ eventlist[numwait] = base->items[i]; base->waitfor[numwait++] = base->items[i]->hEvent; if (numwait == WSK_MAX_ITEMS) break; /* sanity check */ } ret = WSAWaitForMultipleEvents(base->max, base->waitfor, 0 /* do not wait for all, just one will do */, wait ? timeout : WSA_INFINITE, 0); /* we are not alertable (IO completion events) */ if (ret == WSA_WAIT_IO_COMPLETION) { log_err("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); return -1; } else if (ret == WSA_WAIT_FAILED) { log_err("getdns: WSAWaitForMultipleEvents failed: %s", wsa_strerror(WSAGetLastError())); return -1; } else if (ret == WSA_WAIT_TIMEOUT) { was_timeout = 1; } else startidx = ret - WSA_WAIT_EVENT_0; if (settime(base) < 0) return -1; for (i = 0; i<base->max + 1; i++) { short bits = 0; if (!base->items[i] || !(FD_ISSET(i, &base->ready))) { continue; } if (FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if (FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->items[i]->ev_events; if (bits) { fptr_ok(fptr_whitelist_event( base->items[i]->ev_callback)); (*base->items[i]->ev_callback)(base->items[i]->ev_fd, bits, base->items[i]->ev_arg); if (ret == 0) break; } } return 0; }
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) { DWORD timeout = 0; /* in milliseconds */ DWORD ret; WSANETWORKEVENTS netev; struct _getdns_event* eventlist[WSK_MAX_ITEMS]; int i, numwait = 0, startidx = 0, was_timeout = 0; int newstickies = 0; struct timeval nultm; printf("in handle select\n"); #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; if (wait) // timeout = 10 + wait->tv_usec / 1000; timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; if(base->tcp_stickies) { wait = &nultm; nultm.tv_sec = 0; nultm.tv_usec = 0; timeout = 0; /* no waiting, we have sticky events */ } #endif /* prepare event array */ for(i=0; i<base->max; i++) { if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) continue; /* skip timer only events */ eventlist[numwait] = base->items[i]; base->waitfor[numwait++] = base->items[i]->hEvent; printf("winsock_event bmax=%d numwait=%d wait=%x " "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, (int)timeout, base->items[i]->hEvent); if (numwait == WSK_MAX_ITEMS) break; /* sanity check */ } //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); /* do the wait */ if(numwait == 0) { /* WSAWaitFor.. doesn't like 0 event objects */ if(wait) { Sleep(timeout); } was_timeout = 1; } else { //g do not sched udp write for (i = 0; i<base->max; i++) { if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { //gprintf("skip UDP sched\n"); (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, EV_WRITE & eventlist[i]->ev_events, eventlist[i]->ev_arg); return 0; } } //gprintf("before wait %d\n", base->items[0]->ev_events); ret = WSAWaitForMultipleEvents(numwait, base->waitfor, 0 /* do not wait for all, just one will do */, wait?timeout:WSA_INFINITE, 0); /* we are not alertable (IO completion events) */ //gprintf("after wait %d %d\n", ret, numwait); if(ret == WSA_WAIT_IO_COMPLETION) { //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); return -1; } else if(ret == WSA_WAIT_FAILED) { //printf("getdns: WSAWaitForMultipleEvents failed: %s", // wsa_strerror(WSAGetLastError())); return -1; } else if(ret == WSA_WAIT_TIMEOUT) { //printf("timeout\n"); was_timeout = 1; } else startidx = ret - WSA_WAIT_EVENT_0; } ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", // was_timeout, startidx); /* get new time after wait */ if(settime(base) < 0) return -1; /* callbacks */ if(base->tcp_stickies) startidx = 0; /* process all events, some are sticky */ for(i=startidx; i<numwait; i++) eventlist[i]->just_checked = 1; //verbose(VERB_CLIENT, "winsock_event signals"); for(i=startidx; i<numwait; i++) { if(!base->waitfor[i]) continue; /* was deleted */ if(eventlist[i]->is_signal) { eventlist[i]->just_checked = 0; _getdns_handle_signal(eventlist[i]); } } /* early exit - do not process network, exit quickly */ if(base->need_to_exit) return 0; //verbose(VERB_CLIENT, "winsock_event net"); for(i=startidx; i<numwait; i++) { short bits = 0; /* eventlist[i] fired */ /* see if eventlist[i] is still valid and just checked from * WSAWaitForEvents */ if(!base->waitfor[i]) continue; /* was deleted */ if(!eventlist[i]->just_checked) continue; /* added by other callback */ if(eventlist[i]->is_signal) continue; /* not a network event at all */ eventlist[i]->just_checked = 0; if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, base->waitfor[i], /* reset the event handle */ /*NULL,*/ /* do not reset the event handle */ &netev) != 0) { log_err("getdns: WSAEnumNetworkEvents failed: %s", wsa_strerror(WSAGetLastError())); return -1; } if((netev.lNetworkEvents & FD_READ)) { if(netev.iErrorCode[FD_READ_BIT] != 0) printf("FD_READ_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_READ_BIT])); bits |= EV_READ; printf("FD_READ_BIT\n"); } if((netev.lNetworkEvents & FD_WRITE)) { if(netev.iErrorCode[FD_WRITE_BIT] != 0) printf("FD_WRITE_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); bits |= EV_WRITE; printf("FD_WRITE_BIT\n"); } if((netev.lNetworkEvents & FD_CONNECT)) { if(netev.iErrorCode[FD_CONNECT_BIT] != 0) printf("FD_CONNECT_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); bits |= EV_READ; bits |= EV_WRITE; printf("FD_CONNECT_BIT\n"); } if((netev.lNetworkEvents & FD_ACCEPT)) { if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) printf("FD_ACCEPT_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); bits |= EV_READ; printf("FD_ACCEPT_BIT\n"); } if((netev.lNetworkEvents & FD_CLOSE)) { if(netev.iErrorCode[FD_CLOSE_BIT] != 0) printf("FD_CLOSE_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); bits |= EV_READ; bits |= EV_WRITE; printf("FD_CLOSE_BIT\n"); } if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { /* printf("winsock %d pass sticky %s%s\n", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ bits |= eventlist[i]->old_events; } if(eventlist[i]->is_tcp && bits) { eventlist[i]->old_events = bits; eventlist[i]->stick_events = 1; if((eventlist[i]->ev_events & bits)) { newstickies = 1; } /* printf("winsock %d store sticky %s%s", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ } if((bits & eventlist[i]->ev_events)) { /* printf( "winsock event callback %p fd=%d " "%s%s%s%s%s ; %s%s%s\n", eventlist[i], eventlist[i]->ev_fd, (netev.lNetworkEvents&FD_READ)?" FD_READ":"", (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", (netev.lNetworkEvents&FD_CONNECT)? " FD_CONNECT":"", (netev.lNetworkEvents&FD_ACCEPT)? " FD_ACCEPT":"", (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", (bits&EV_READ)?" EV_READ":"", (bits&EV_WRITE)?" EV_WRITE":"", (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); */ fptr_ok(fptr_whitelist_event( eventlist[i]->ev_callback)); (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, bits & eventlist[i]->ev_events, eventlist[i]->ev_arg); } /* if(eventlist[i]->is_tcp && bits) printf( "winsock %d got sticky %s%s\n", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ } //verbose(VERB_CLIENT, "winsock_event net"); if(base->tcp_reinvigorated) { printf("winsock_event reinvigorated\n"); base->tcp_reinvigorated = 0; newstickies = 1; } base->tcp_stickies = newstickies; //gprintf("winsock_event handle_select end\n"); return 0; }
int tube_handle_listen(struct comm_point* c, void* arg, int error, struct comm_reply* ATTR_UNUSED(reply_info)) { struct tube* tube = (struct tube*)arg; ssize_t r; if(error != NETEVENT_NOERROR) { fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, NULL, 0, error, tube->listen_arg); return 0; } if(tube->cmd_read < sizeof(tube->cmd_len)) { /* complete reading the length of control msg */ r = read(c->fd, ((uint8_t*)&tube->cmd_len) + tube->cmd_read, sizeof(tube->cmd_len) - tube->cmd_read); if(r==0) { /* error has happened or */ /* parent closed pipe, must have exited somehow */ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, NULL, 0, NETEVENT_CLOSED, tube->listen_arg); return 0; } if(r==-1) { if(errno != EAGAIN && errno != EINTR) { log_err("rpipe error: %s", strerror(errno)); } /* nothing to read now, try later */ return 0; } tube->cmd_read += r; if(tube->cmd_read < sizeof(tube->cmd_len)) { /* not complete, try later */ return 0; } tube->cmd_msg = (uint8_t*)calloc(1, tube->cmd_len); if(!tube->cmd_msg) { log_err("malloc failure"); tube->cmd_read = 0; return 0; } } /* cmd_len has been read, read remainder */ r = read(c->fd, tube->cmd_msg+tube->cmd_read-sizeof(tube->cmd_len), tube->cmd_len - (tube->cmd_read - sizeof(tube->cmd_len))); if(r==0) { /* error has happened or */ /* parent closed pipe, must have exited somehow */ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, NULL, 0, NETEVENT_CLOSED, tube->listen_arg); return 0; } if(r==-1) { /* nothing to read now, try later */ if(errno != EAGAIN && errno != EINTR) { log_err("rpipe error: %s", strerror(errno)); } return 0; } tube->cmd_read += r; if(tube->cmd_read < sizeof(tube->cmd_len) + tube->cmd_len) { /* not complete, try later */ return 0; } tube->cmd_read = 0; fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, tube->cmd_msg, tube->cmd_len, NETEVENT_NOERROR, tube->listen_arg); /* also frees the buf */ tube->cmd_msg = NULL; return 0; }