static void _ensure_pool_cleanup_gracefully_handles_cleaned_up_pool( void ) { pool_t pool; pool_init( &pool, 4, 16, allocator_default( ) ); pool_cleanup( &pool ); pool_cleanup( &pool ); }
static int _vacation_user_load(mod_instance_t mi, user_t user) { module_t mod = mi->mod; vacation_t v; os_t os; os_object_t o; v = (vacation_t) calloc(1, sizeof(struct _vacation_st)); user->module_data[mod->index] = v; if(storage_get(mod->mm->sm->st, "vacation-settings", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_time(os, o, "start", &v->start) && os_object_get_time(os, o, "end", &v->end) && os_object_get_str(os, o, "message", &v->msg)) v->msg = strdup(v->msg); else { v->start = 0; v->end = 0; v->msg = NULL; } } os_free(os); } pool_cleanup(user->p, (void (*))(void *) _vacation_user_free, v); return 0; }
/* public queue creation function, queue lives as long as the pool */ mtq mtq_new(pool p) { mtq q; int n,mtq_n; int count; if (p==NULL) return NULL; if(mtq__master == NULL) { mtq_init(); } /* find queue with less users */ count=999999; mtq_n = 0; for(n = 0; n < MTQ_THREADS; n++) if(mtq__master->all[n]->mtq->users_count < count) { count = mtq__master->all[n]->mtq->users_count; mtq_n = n; } q = mtq__master->all[mtq_n]->mtq; q->users_count++; pool_cleanup(p, mtq_cleanup, (void *)q); return q; }
static void _ensure_pool_is_empty_returns_non_zero_on_empty_legitimate_pool( void ) { pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); TEST_REQUIRE( pool_is_empty( &pool ) == 0 ); pool_cleanup( &pool ); }
static void _ensure_pool_is_empty_gracefully_handles_cleaned_up_pool( void ) { pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); pool_cleanup( &pool ); TEST_REQUIRE( pool_is_empty( &pool ) != 0 ); }
void aim_transport(instance i, xmlnode x) { ati ti; xmlnode config; char *eightbitcode, *utf8code = "UTF-8", *latin1code = "CP1252"; ti = pmalloco(i->p, sizeof(_ati)); ti->i = i; ti->xc = xdb_cache(i); log_notice(i->id, "AIM-Transport starting up for instance %s...", i->id); config = xdb_get(ti->xc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:aimtrans"); ti->vcard = xmlnode_new_tag_pool(i->p,"vCard"); xmlnode_put_attrib(ti->vcard,"xmlns",NS_VCARD); xmlnode_insert_node(ti->vcard,xmlnode_get_firstchild(xmlnode_get_tag(config,"vCard"))); ti->start_time = time(NULL); ti->session__list=xhash_new(101); ti->iq__callbacks = xhash_new(23); ti->pending__buddies = xhash_new(101); /* The aim.exe binary should not be necessary any more. */ ti->aimbinarydir = pstrdup(i->p, xmlnode_get_tag_data(config, "aimbinarydir")); eightbitcode = pstrdup(i->p, xmlnode_get_tag_data(config, "charset")); if( eightbitcode == NULL ) { log_notice( i->id, "Charset is not specified, using CP1252" ); eightbitcode = latin1code; } xmlnode_free(config); fromutf8 = iconv_open(eightbitcode, utf8code); if(fromutf8 == (iconv_t)(-1)) { log_error(i->id, "Conversion from %s to %s is not supported", utf8code, eightbitcode); raise(SIGINT); } toutf8 = iconv_open(utf8code, eightbitcode); if(toutf8 == (iconv_t)(-1)) { log_error(i->id, "Conversion from %s to %s is not supported", eightbitcode, utf8code); raise(SIGINT); } ti->send_buf = NULL; ti->modname = NULL; pth_mutex_init(&ti->buddies_mutex); at_init_iqcbs(ti); register_phandler(i, o_DELIVER, at_phandler, ti); pool_cleanup(i->p, at_shutdown, (void*)i); }
xdbcache xdb_cache(instance id) { xdbcache newx; if(id == NULL) { fprintf(stderr, "Programming Error: xdb_cache() called with NULL\n"); return NULL; } newx = pmalloco(id->p, sizeof(_xdbcache)); newx->i = id; /* flags it as the top of the ring too */ newx->next = newx->prev = newx; /* init ring */ pthread_mutex_init(&(newx->sem),NULL); /* register the handler in the instance to filter out xdb results */ register_phandler(id, o_PRECOND, xdb_results, (void *)newx); /* heartbeat to keep a watchful eye on xdb_cache */ register_beat(10,xdb_thump,(void *)newx); register_shutdown_first(xdb_shutdown, (void *)newx); pool_cleanup(id->p, xdb_shutdown, (void*)newx); return newx; }
static void _ensure_pool_return_gracefully_handles_cleaned_up_pool( void ) { void * item; pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); item = pool_take( &pool ); pool_cleanup( &pool ); pool_return( &pool, item ); }
static void _ensure_pool_delete_gracefully_handles_cleaned_up_pool( void ) { pool_t * pool; allocator_counted_t alloc; allocator_counted_init_default( &alloc ); pool = pool_new( 128, 4, allocator_counted_get( &alloc ) ); pool_cleanup( pool ); pool_delete( pool ); TEST_REQUIRE( allocator_counted_get_current_count( &alloc ) == 0 ); }
static void _ensure_pool_return_gracefully_handles_address_not_in_pool( void ) { unsigned item_not_in_pool; pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); pool_return( &pool, &item_not_in_pool ); TEST_REQUIRE( pool_take( &pool ) != &item_not_in_pool ); TEST_REQUIRE( pool_take( &pool ) == 0 ); pool_cleanup( &pool ); }
static void _ensure_pool_take_reuses_returned_elements( void ) { void * item; pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); item = pool_take( &pool ); pool_return( &pool, item ); TEST_REQUIRE( pool_take( &pool ) == item ); pool_cleanup( &pool ); }
static void _ensure_pool_take_returns_null_when_empty( void ) { void * item; pool_t pool; pool_init( &pool, 4, 1, allocator_default( ) ); pool_take( &pool ); item = pool_take( &pool ); TEST_REQUIRE( item == 0 ); pool_cleanup( &pool ); }
static void _ensure_pool_take_returns_object_when_not_empty( void ) { void * item; pool_t pool; pool_init( &pool, 4, 16, allocator_default( ) ); item = pool_take( &pool ); TEST_REQUIRE( item ); item = 0; pool_cleanup( &pool ); }
static void _ensure_pool_cleanup_releases_underlying_buffer( void ) { allocator_counted_t alloc; pool_t pool; allocator_counted_init_default( &alloc ); pool_init( &pool, 4, 16, allocator_counted_get( &alloc ) ); pool_cleanup( &pool ); TEST_REQUIRE( allocator_counted_get_current_count( &alloc ) == 0 ); }
static void _ensure_pool_init_with_zero_element_count_constructs_valid_empty_pool( void ) { allocator_counted_t alloc; pool_t pool; allocator_counted_init_default( &alloc ); pool_init( &pool, 4, 0, allocator_counted_get( &alloc ) ); TEST_REQUIRE( pool_is_empty( &pool ) ); pool_cleanup( &pool ); TEST_REQUIRE( allocator_counted_get_current_count( &alloc ) == 0 ); }
void slab_cleanup(slab_ctxt_t *ctxt) { /* any data to destruct ?*/ if(ctxt->destructor) { while( ++ctxt->const_bottom < ctxt->pool.count) { void *object = pool_get_raw(& ctxt->pool, ctxt->const_bottom); ctxt->destructor( object, ctxt->userdata); } } /* now cleanup the pool */ pool_cleanup(& ctxt->pool); }
// --------------------------------------------------------------------- // _dc_cleanup_pools // --------------------------------------------------------------------- void _dc_cleanup_pools() { if (dc_init_cons_pool_g != NULL) pool_cleanup(dc_init_cons_pool_g); if (dc_group_pool_g != NULL) pool_cleanup(dc_group_pool_g); if (dc_cons_pool_g != NULL) pool_cleanup(dc_cons_pool_g); if (dc_cell_pool_g != NULL) pool_cleanup(dc_cell_pool_g); if (dc_dep_pool_g != NULL) pool_cleanup(dc_dep_pool_g); dc_init_cons_pool_g = dc_group_pool_g = dc_cons_pool_g = dc_cell_pool_g = dc_dep_pool_g = NULL; }
/* public queue creation function, queue lives as long as the pool */ mtq mtq_new_que(pool p, mtq que) { mtq q; int n,mtq_n; int count; log_debug(ZONE,"MTQ(new)"); if (p==NULL) return NULL; if(mtq__master == NULL) { mtq_init(); } if (que) { que->users_count++; pool_cleanup(p, mtq_cleanup, (void *)que); return que; } /* find queue with less users */ count=999999; mtq_n = 0; for(n = 0; n < MTQ_THREADS; n++) if(mtq__master->all[n]->mtq->users_count < count) { count = mtq__master->all[n]->mtq->users_count; mtq_n = n; } q = mtq__master->all[mtq_n]->mtq; q->users_count++; pool_cleanup(p, mtq_cleanup, (void *)q); return q; }
/** * main */ int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct mysqlfs_opt opt = { .init_conns = 1, .max_idling_conns = 5, .mycnf_group = "mysqlfs", #ifdef DEBUG .logfile = "mysqlfs.log", #endif }; log_file = stderr; /** theopts kludge is used for both statusdir (if configured at build) and for osxnospotlight */ theopts = &opt; fuse_opt_parse(&args, &opt, mysqlfs_opts, mysqlfs_opt_proc); if (pool_init(&opt) < 0) { log_printf(LOG_ERROR, "Error: pool_init() failed\n"); fuse_opt_free_args(&args); return EXIT_FAILURE; } /* * I found that -- running from a script (ie no term?) -- the MySQLfs would not background, so the terminal is held; this makes automated testing difficult. * * I (allanc) put this into here to allow for AUTOTEST, but then autotest has to seek-and-destroy the app. This isn't quite perfect yet, I get some flakiness here, othertines the pid is 4 more than the parent, which is odd. */ if (0 < opt.bg) { if (0 < fork()) return EXIT_SUCCESS; //else // fprintf (stderr, "forked %d\n", getpid()); } /* only create a log file if we have a logfile set; note that --enable-debug sets a default above */ if (NULL != opt.logfile) log_file = log_init(opt.logfile, 1); fuse_main(args.argc, args.argv, &mysqlfs_oper); fuse_opt_free_args(&args); pool_cleanup(); return EXIT_SUCCESS; }
/** make a new one */ static user_t _user_alloc(sm_t sm, jid_t jid) { pool_t p; user_t user; p = pool_new(); user = (user_t) pmalloco(p, sizeof(struct user_st)); user->p = p; user->sm = sm; user->jid = jid_dup(jid); pool_cleanup(p, (void (*)(void *)) jid_free, user->jid); /* a place for modules to store stuff */ user->module_data = (void **) pmalloco(p, sizeof(void *) * sm->mm->nindex); return user; }
// Rate limit check: Prevent denial-of-service due to excessive database queries // Make sure owner is responsible for the query! int sm_storage_rate_limit(sm_t sm, const char *owner) { rate_t rt; user_t user; sess_t sess; item_t item; if (sm->query_rate_total == 0 || owner == NULL) return FALSE; user = xhash_get(sm->users, owner); if (user != NULL) { rt = (rate_t) xhash_get(sm->query_rates, owner); if (rt == NULL) { rt = rate_new(sm->query_rate_total, sm->query_rate_seconds, sm->query_rate_wait); xhash_put(sm->query_rates, pstrdup(xhash_pool(sm->query_rates), owner), (void *) rt); pool_cleanup(xhash_pool(sm->query_rates), (void (*)(void *)) rate_free, rt); } if(rate_check(rt) == 0) { log_write(sm->log, LOG_WARNING, "[%s] is being disconnected, too many database queries within %d seconds", owner, sm->query_rate_seconds); user = xhash_get(sm->users, owner); for (sess = user->sessions; sess != NULL; sess = sess->next) { sm_c2s_action(sess, "ended", NULL); } if(xhash_iter_first(user->roster)) do { xhash_iter_get(user->roster, NULL, NULL, (void *) &item); if(item->to) { pkt_router(pkt_create(user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(user->jid))); } } while(xhash_iter_next(user->roster)); return TRUE; } else { rate_add(rt, 1); } } else { log_debug(ZONE, "Error: could not get user data for %s", owner); } return FALSE; }
result base_file_config(instance id, xmlnode x, void *arg) { basefile bf; if(id == NULL) { log_debug(ZONE,"base_file_config validating configuration"); if (xmlnode_get_data(x) == NULL) { log_debug(ZONE,"base_file_config error: no filename provided."); xmlnode_put_attrib(x,"error","'file' tag must contain a filename to write to"); return r_ERR; } return r_PASS; } log_debug(ZONE,"base_file configuring instance %s",id->id); if(id->type != p_LOG) { log_alert(NULL,"ERROR in instance %s: <file>..</file> element only allowed in log sections", id->id); return r_ERR; } bf = pmalloco(id->p,sizeof(_basefile)); bf->filename = pstrdup(id->p,xmlnode_get_data(x)); bf->yesterday.tm_mday = -1; bf->last_time = 0; bf->f = NULL; pthread_mutex_init(&(bf->sem),NULL); /* Register a handler for this instance... */ register_phandler(id, o_DELIVER, base_file_deliver, (void*)bf); pool_cleanup(id->p, _base_file_shutdown, (void*)bf); return r_DONE; }
os_object_t os_object_new(os_t os) { os_object_t o; log_debug(ZONE, "creating new object"); o = (os_object_t) pmalloco(os->p, sizeof(struct os_object_st)); o->os = os; o->hash = xhash_new(51); /* make sure that the hash gets freed when the os pool gets freed */ pool_cleanup(os->p, (pool_cleanup_t) xhash_free, (void *)(o->hash) ); /* insert at the end, we have to preserve order */ o->prev = os->tail; if(os->tail != NULL) os->tail->next = o; os->tail = o; if(os->head == NULL) os->head = o; os->count++; return o; }
void os_object_put(os_object_t o, const char *key, const void *val, os_type_t type) { os_field_t osf; nad_t nad; log_debug(ZONE, "adding field %s (val %x type %d) to object", key, val, type); osf = pmalloco(o->os->p, sizeof(struct os_field_st)); osf->key = pstrdup(o->os->p, key); switch(type) { case os_type_BOOLEAN: case os_type_INTEGER: osf->val = (void *) (intptr_t) (* (int *) val); break; case os_type_STRING: osf->val = (void *) pstrdup(o->os->p, (char *) val); break; case os_type_NAD: nad = nad_copy((nad_t) val); /* make sure that the nad gets freed when the os pool gets freed */ pool_cleanup(o->os->p, (pool_cleanup_t) nad_free, (void *) nad); osf->val = (void *) nad; break; case os_type_UNKNOWN: break; } osf->type = type; xhash_put(o->hash, osf->key, (void *) osf); }
int os_object_get(os_t os, os_object_t o, const char *key, void **val, os_type_t type, os_type_t *ot) { os_field_t osf; nad_t nad; /* Type complexity is to deal with string/NADs. If an object contains xml, it will only be parsed and returned as a NAD if type == os_type_NAD, otherwise if type == os_type_UNKNOWN it will be returned as string, unless it's already been converted to a NAD */ osf = (os_field_t) xhash_get(o->hash, key); if(osf == NULL) { *val = NULL; return 0; } if (ot != NULL) *ot = osf->type; if (type == os_type_UNKNOWN) type = osf->type; if (type == os_type_UNKNOWN) type = osf->type; switch(type) { case os_type_BOOLEAN: case os_type_INTEGER: * (int *) val = (int) (intptr_t) osf->val; break; case os_type_STRING: *val = osf->val; break; case os_type_NAD: /* check to see whether it's already a NAD */ if (osf->type == os_type_NAD) { *val = osf->val; } else { /* parse the string into a NAD */ nad = nad_parse(((char *) osf->val) + 3, strlen(osf->val) - 3); if(nad == NULL) { /* unparseable NAD */ log_debug(ZONE, "cell returned from storage for key %s has unparseable XML content (%lu bytes)", key, strlen(osf->val)-3); *val = NULL; return 0; } /* replace the string with a NAD */ osf->val = (void *) nad; pool_cleanup(os->p, (pool_cleanup_t) nad_free, (void *) nad); *val = osf->val; osf->type = os_type_NAD; } break; default: *val = NULL; } log_debug(ZONE, "got field %s (val %x type %d) to object", key, *val, type); return 1; }
static void _ensure_pool_cleanup_gracefully_handles_null_pool( void ) { pool_cleanup( 0 ); }
void dnsrv(instance i, xmlnode x) { xdbcache xc = NULL; xmlnode config = NULL; xmlnode iternode = NULL; dns_resend_list tmplist = NULL; /* Setup a struct to hold dns_io handles */ dns_io di; di = pmalloco(i->p, sizeof(_dns_io)); di->mempool = i->p; /* Load config from xdb */ xc = xdb_cache(i); config = xdb_get(xc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:dnsrv"); /* Build a list of services/resend hosts */ iternode = xmlnode_get_lastchild(config); while (iternode != NULL) { if (j_strcmp("resend", xmlnode_get_name(iternode)) != 0) { iternode = xmlnode_get_prevsibling(iternode); continue; } /* Allocate a new list node */ tmplist = pmalloco(di->mempool, sizeof(_dns_resend_list)); tmplist->service = pstrdup(di->mempool, xmlnode_get_attrib(iternode, "service")); tmplist->host = pstrdup(di->mempool, xmlnode_get_data(iternode)); /* Insert this node into the list */ tmplist->next = di->svclist; di->svclist = tmplist; /* Move to next child */ iternode = xmlnode_get_prevsibling(iternode); } log_debug(ZONE, "dnsrv debug: %s\n", xmlnode2str(config)); /* Setup the hash of dns_packet_list */ di->packet_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"queuemax"),101)); di->packet_timeout = j_atoi(xmlnode_get_attrib(config,"queuetimeout"),60); register_beat(di->packet_timeout, dnsrv_beat_packets, (void *)di); /* Setup the internal hostname cache */ di->cache_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"cachemax"),1999)); di->cache_timeout = j_atoi(xmlnode_get_attrib(config,"cachetimeout"),3600); /* 1 hour dns cache? XXX would be nice to get the right value from dns! */ xmlnode_free(config); /* spawn a thread that get's forked, and wait for it since it sets up the fd's */ pth_join(pth_spawn(PTH_ATTR_DEFAULT,(void*)dnsrv_thread,(void*)di),NULL); if(di->pid < 0) { log_error(i->id,"dnsrv failed to start, unable to fork and/or create pipes"); return; } /* Start IO thread */ pth_spawn(PTH_ATTR_DEFAULT, dnsrv_process_io, di); /* Register an incoming packet handler */ register_phandler(i, o_DELIVER, dnsrv_deliver, (void*)di); /* register a cleanup function */ pool_cleanup(i->p, dnsrv_shutdown, (void*)di); }
static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, elem, target, targetns; st_ret_t ret; char filter[4096]; os_t os; os_object_t o; nad_t nad; pkt_t result; sess_t sscan; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "query", 1); /* find the first child */ target = elem + 1; while(target < pkt->nad->ecur) { if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth) break; target++; } /* not found, so we're done */ if(target == pkt->nad->ecur) return -stanza_err_BAD_REQUEST; /* find the target namespace */ targetns = NAD_ENS(pkt->nad, target); /* gotta have a namespace */ if(targetns < 0) { log_debug(ZONE, "no namespace specified"); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); /* get */ if(pkt->type == pkt_IQ) { #ifdef ENABLE_EXPERIMENTAL /* remember that this resource requested the namespace */ if(sess->module_data[mod->index] == NULL) { /* create new hash if necesary */ sess->module_data[mod->index] = xhash_new(101); pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]); } xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1); #endif snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os); switch(ret) { case st_SUCCESS: if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { result = pkt_new(sess->user->sm, nad_copy(nad)); if(result != NULL) { nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); os_free(os); return mod_HANDLED; } } } os_free(os); /* drop through */ log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND"); case st_NOTFOUND: log_debug(ZONE, "namespace not found, returning"); /* * !!! really, we should just return a 404. 1.4 just slaps a * result on the packet and sends it back. hurrah for * legacy namespaces. */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } } os = os_new(); o = os_object_new(os); snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); os_object_put(o, "ns", filter, os_type_STRING); os_object_put(o, "xml", pkt->nad, os_type_NAD); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: /* create result packet */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* and flush it to the session */ pkt_sess(result, sess); #ifdef ENABLE_EXPERIMENTAL /* push it to all resources that read this xmlns item */ snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* skip our resource and those that didn't read any private-storage */ if(sscan == sess || sscan->module_data[mod->index] == NULL) continue; /* check whether namespace was read */ if(xhash_get(sscan->module_data[mod->index], filter)) { result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } #endif /* finally free the packet */ pkt_free(pkt); return mod_HANDLED; } /* we never get here */ return 0; }
sess_t sess_start(sm_t sm, jid_t jid) { pool_t p; user_t user; sess_t sess, scan; sha1_state_t sha1; unsigned char hash[20]; int replaced = 0; log_debug(ZONE, "session requested for %s", jid_full(jid)); /* check whether it is to serviced domain */ if(xhash_get(sm->hosts, jid->domain) == NULL) { log_write(sm->log, LOG_ERR, "request to start session in non-serviced domain: jid=%s", jid_full(jid)); return NULL; } /* get user data for this guy */ user = user_load(sm, jid); /* unknown user */ if(user == NULL) { if(config_get(sm->config, "user.auto-create") == NULL) { log_write(sm->log, LOG_NOTICE, "user not found and user.auto-create not enabled, can't start session: jid=%s", jid_full(jid)); return NULL; } log_debug(ZONE, "auto-creating user %s", jid_user(jid)); if(user_create(sm, jid) != 0) return NULL; user = user_load(sm, jid); if(user == NULL) { log_write(sm->log, LOG_NOTICE, "couldn't load user, can't start session: jid=%s", jid_full(jid)); return NULL; } } /* kill their old session if they have one */ for(scan = user->sessions; scan != NULL; scan = scan->next) if(jid_compare_full(scan->jid, jid) == 0) { log_debug(ZONE, "replacing session %s (%s)", jid_full(jid), scan->c2s_id); /* !!! this "replaced" stuff is a hack - its really a subaction of "ended". * hurrah, another control protocol rewrite is needed :( */ sm_c2s_action(scan, "replaced", NULL); _sess_end_guts(scan); pool_free(scan->p); replaced = 1; break; } /* make a new session */ p = pool_new(); sess = (sess_t) pmalloco(p, sizeof(struct sess_st)); sess->p = p; /* fill it out */ sess->pri = 0; sess->user = user; sess->jid = jid_dup(jid); pool_cleanup(sess->p, (void (*))(void *) jid_free, sess->jid); /* a place for modules to store stuff */ sess->module_data = (void **) pmalloco(sess->p, sizeof(void *) * sess->user->sm->mm->nindex); /* add it to the list */ sess->next = user->sessions; user->sessions = sess; /* who c2s should address things to */ sha1_init(&sha1); datetime_out(time(NULL), dt_DATETIME, sess->sm_id, 41); sha1_append(&sha1, sess->sm_id, strlen(sess->sm_id)); sha1_append(&sha1, jid_full(sess->jid), strlen(jid_full(sess->jid))); sha1_finish(&sha1, hash); hex_from_raw(hash, 20, sess->sm_id); log_debug(ZONE, "smid is %s", sess->sm_id); /* remember it */ xhash_put(sm->sessions, sess->sm_id, sess); /* inform the modules */ /* !!! catch the return value - if its 1, don't let them in */ mm_sess_start(sm->mm, sess); if(replaced) log_write(sm->log, LOG_NOTICE, "session replaced: jid=%s", jid_full(sess->jid)); else log_write(sm->log, LOG_NOTICE, "session started: jid=%s", jid_full(sess->jid)); return sess; }