/* do not free sem at the end if session was found */ session js_session_primary_all_sem(udata user) { session cur, top; /* ignore illeagal calls, or users with no sessions */ if (user == NULL || user->sessions == NULL) return NULL; /* find primary session */ SEM_LOCK(user->sem); if (user->sessions == NULL) { SEM_UNLOCK(user->sem); return NULL; } top = user->sessions; for (cur = top; cur != NULL; cur = cur->next) if (cur->priority > top->priority) top = cur; /* return it if it's active */ if (top->priority > -128) return top; else { /* otherwise there's no active session */ SEM_UNLOCK(user->sem); return NULL; } }
mreturn mod_browse_reply(mapi m, void *arg) { xmlnode browse, ns, cur; session s; if (m->packet->type != JPACKET_IQ) return M_IGNORE; if (!NSCHECK(m->packet->iq, NS_BROWSE)) return M_PASS; /* first, is this a valid request? */ switch (jpacket_subtype(m->packet)) { case JPACKET__RESULT: case JPACKET__ERROR: return M_PASS; case JPACKET__SET: js_bounce(m->si, m->packet->x, TERROR_NOTALLOWED); return M_HANDLED; } log_debug("handling query for user %s", m->user->user); /* get this dudes browse info */ browse = mod_browse_get(m, m->packet->to); /* insert the namespaces */ ns = xdb_get(m->si->xc, m->packet->to, NS_XDBNSLIST); for (cur = xmlnode_get_firstchild(ns); cur != NULL; cur = xmlnode_get_nextsibling(cur)) if (xmlnode_get_attrib(cur, "type") == NULL) xmlnode_insert_tag_node(browse, cur); /* only include the generic <ns>foo</ns> */ xmlnode_free(ns); /* include any connected resources if there's a s10n from them */ if (js_trust(m->user, m->packet->from)) { SEM_LOCK(m->user->sem); for (s = m->user->sessions; s != NULL; s = s->next) { /* if(s->priority < 0) continue; *** include all resources I guess */ if (xmlnode_get_tag (browse, spools(m->packet->p, "?jid=", jid_full(s->id), m->packet->p)) != NULL) continue; /* already in the browse result */ cur = xmlnode_insert_tag(browse, "user"); xmlnode_put_attrib(cur, "type", "client"); xmlnode_put_attrib(cur, "jid", jid_full(s->id)); } SEM_UNLOCK(m->user->sem); } /* XXX include iq:filter forwards */ jutil_iqresult(m->packet->x); jpacket_reset(m->packet); xmlnode_insert_tag_node(m->packet->x, browse); js_deliver(m->si, m->packet); xmlnode_free(browse); return M_HANDLED; }
void fast_mtq_send(fast_mtq f_mtq, void *arg) { fast_mtq_elem e = (fast_mtq_elem) arg; if (f_mtq->shutdown) return; e->mtq_next = NULL; SEM_LOCK(f_mtq->sem); if (f_mtq->first) { f_mtq->last->mtq_next = e; } else { f_mtq->first = e; } f_mtq->last = e; f_mtq->queue++; f_mtq->queue2++; COND_SIGNAL(f_mtq->cond); SEM_UNLOCK(f_mtq->sem); }
/* * js_session_get -- find the session for a resource * * Given a user and a resource, find the corresponding session * if the user is logged in. Otherwise return NULL. * * parameters * user -- the user's udata record * res -- the resource to search for * * returns * a pointer to the session if the user is logged in * NULL if the user isn't logged in on this resource */ session js_session_get(udata user, char *res) { session cur; /* session pointer */ /* screen out illeagal calls */ if (user == NULL || res == NULL) return NULL; /* find the session and return it */ SEM_LOCK(user->sem); for (cur = user->sessions; cur != NULL; cur = cur->next) if ((j_strcmp(res, cur->res) == 0) && (!cur->exit_flag)) { SEM_UNLOCK(user->sem); return cur; } /* find any matching resource that is a subset and return it */ for (cur = user->sessions; cur != NULL; cur = cur->next) if ((j_strncmp(res, cur->res, j_strlen(cur->res)) == 0) && (!cur->exit_flag)) { SEM_UNLOCK(user->sem); return cur; } SEM_UNLOCK(user->sem); /* if we got this far, there is no session */ return NULL; }
/* always deliver threads */ static void js_outgoing_packet(jsmi si, jpacket jp, dpacket p) { session s = NULL; udata u; /* attempt to locate the session by matching the special resource */ u = js_user(si, p->id, 0); if (u == NULL) { log_notice(p->host, "Bouncing packet intended for nonexistant user: %s", xmlnode2str(p->x)); deliver_fail(dpacket_new(p->x), "Invalid User"); return; } SEM_LOCK(u->sem); for (s = u->sessions; s != NULL; s = s->next) if (j_strcmp(p->id->resource, s->route->resource) == 0) break; SEM_UNLOCK(u->sem); THREAD_DEC(u->ref); if (s != NULL) { /* just pass to the session normally */ js_session_from(s, jp); return; } log_notice(p->host, "Bouncing %s packet intended for session %s", xmlnode_get_name(jp->x), jid_full(p->id)); deliver_fail(dpacket_new(p->x), "Invalid Session"); }
/* match will find a child in the parent, and either replace (if it's an insert) or remove (if data is NULL) */ int xdb_act(xdbcache xc, jid owner, char *ns, char *act, char *match, xmlnode data) { xdbrequest_p cur; struct timeval tv; if (xc->shutdown) return 1; if (xc == NULL || owner == NULL || ns == NULL) { log_alert("xdb_set", "Programming Error: xdb_set() called with NULL\n"); return 1; } log_debug("XDB SET"); cur = malloc(sizeof(xdbrequest_t)); memset(cur, 0, sizeof(xdbrequest_t)); cur->set = 1; cur->data = data; cur->ns = ns; cur->owner = owner; cur->act = act; cur->match = match; gettimeofday(&tv, NULL); cur->sent = tv.tv_sec; SEM_LOCK(xc->sem); cur->id = xc->id++; cur->next = xc->first; xc->first = cur; SEM_UNLOCK(xc->sem); /* send it on it's way */ xdb_deliver(xc->i, cur, 0); cur->external = 1; /* if it hasn't already returned, we should block here until it returns */ while (cur->preblock != 1) usleep(10); /* if it didn't actually get set, flag that */ if (cur->data == NULL) { free(cur); return 1; } xmlnode_free(cur->data); free(cur); return 0; }
/* * js_session_end -- shut down the session * * This function gets called when the user disconnects or when the server shuts * down. It changes the user's presence to offline, cleans up the session data * and sends an end spacket * * parameters * s -- the session to end * reason -- the reason the session is shutting down (for logging) * */ void js_session_end(session s, char *reason) { session cur; /* used to iterate over the user's session list when removing the session from the list */ /* ignore illegal calls */ if (s == NULL || s->exit_flag == 1 || reason == NULL) return; /* so it doesn't get freed */ THREAD_INC(s->u->ref); /* log the reason the session ended */ log_debug("end %d '%s'", s, reason); /* flag the session to exit ASAP */ s->exit_flag = 1; /* make sure we're not the primary session */ s->priority = -129; /* presence will be updated in _js_session_end to be shore that only session thread is changing this value */ /* * remove this session from the user's session list -- * first check if this session is at the head of the list */ SEM_LOCK(s->u->sem); if (s == s->u->sessions) { /* yup, just bump up the next session */ s->u->sessions = s->next; } else { /* no, we have to traverse the list to find it */ for (cur = s->u->sessions; cur->next != s; cur = cur->next); cur->next = s->next; } s->u->scount--; SEM_UNLOCK(s->u->sem); /* end */ { packet_thread_p pt; pt = pmalloco(s->p, sizeof(packet_thread_t)); pt->s = s; pt->type = 1; fast_mtq_send(s->q->mtq, pt); } }
void *fast_mtq_thread(void *arg) { fast_mtq f_mtq = (fast_mtq) arg; register fast_mtq_elem e; void *cb_arg; cb_arg = f_mtq->arg; if (f_mtq->start_cb) { cb_arg = (f_mtq->start_cb) (cb_arg); } log_debug("fast mtq thread start"); while (1) { /* check if something to resolv */ SEM_LOCK(f_mtq->sem); e = NULL; if (f_mtq->shutdown != 2) { if ((!(f_mtq->first)) && (!(f_mtq->shutdown))) { COND_WAIT(f_mtq->cond, f_mtq->sem); } /* get element */ e = f_mtq->first; if (e) { f_mtq->first = e->mtq_next; f_mtq->queue--; f_mtq->queue2--; } } SEM_UNLOCK(f_mtq->sem); if (e) { (f_mtq->cb) (cb_arg, (void *) e); } else { if (f_mtq->shutdown) break; } } log_alert("mtq", "fast mtq thread stop %d [%d][%d]", f_mtq->shutdown, f_mtq->queue, f_mtq->queue2); if (f_mtq->stop_cb) { (f_mtq->stop_cb) (cb_arg); } return NULL; }
/* main slave thread */ void *mtq_main(void *arg) { mth t = (mth)arg; mtqqueue mq; /* temp call structure */ _mtqqueue mqcall; /* temp call structure */ log_debug("mtq","%X starting mq=%d",t->thread,t->mtq); while(1) { /* check if something to resolv */ SEM_LOCK(t->mtq->sem); if (t->mtq->last == NULL) { COND_WAIT(t->mtq->cond,t->mtq->sem); } /* get element */ mq = t->mtq->last; if (mq != NULL) { mqcall.f = mq->f; mqcall.arg = mq->arg; /* remove call from list */ t->mtq->last = t->mtq->last->prev; t->mtq->dl--; /* add mq to list */ mq->prev = NULL; if (t->mtq->free_last == NULL) t->mtq->free_last = mq; else t->mtq->free_first->prev = mq; t->mtq->free_first = mq; } SEM_UNLOCK(t->mtq->sem); if (mq != NULL) { (*(mqcall.f))(mqcall.arg); } else { /* mq is NULL here, so no more packets in queue */ if (mtq__shutdown == 1) break; } } /* loop end */ log_debug("mtq","%X ending mq=%d",t->thread,t->mtq); return NULL; }
result xdb_results(instance id, dpacket p, void *arg) { xdbcache xc = (xdbcache) arg; xdbrequest_p cur, last; unsigned int idnum; char *idstr; if (p->type != p_NORM || *(xmlnode_get_name(p->x)) != 'x') return r_PASS; /* yes, we are matching ANY <x*> element */ log_debug("xdb_results checking xdb packet %s", xmlnode2str(p->x)); if ((idstr = xmlnode_get_attrib(p->x, "id")) == NULL) return r_ERR; idnum = atoi(idstr); SEM_LOCK(xc->sem); for (last = NULL, cur = xc->first; (cur) && (cur->id != idnum); last = cur, cur = cur->next); if (!cur) { pool_free(p->p); SEM_UNLOCK(xc->sem); return r_DONE; } /* associte only a non-error packet w/ waiting cache */ if (j_strcmp(xmlnode_get_attrib(p->x, "type"), "error") == 0) { cur->data = NULL; pool_free(p->p); } else cur->data = p->x; if (!last) xc->first = cur->next; else last->next = cur->next; cur->external = 0; SEM_UNLOCK(xc->sem); cur->preblock = 1; return r_DONE; }
void xdb_shutdown(void *arg) { xdbcache xc = (xdbcache) arg; xdbrequest_p cur; log_debug("XDB SHUTDOWN"); xc->shutdown = 1; SEM_LOCK(xc->sem); while (xc->first) { cur = xc->first; xc->first = cur->next; cur->data = NULL; cur->preblock = 1; } SEM_UNLOCK(xc->sem); }
/** resend packets. heartbeat thread */ result xdb_thump(void *arg) { xdbcache xc = (xdbcache) arg; xdbrequest_p cur, next, last; struct timeval tv; time_t now; if (xc->shutdown) return r_UNREG; gettimeofday(&tv, NULL); now = tv.tv_sec; SEM_LOCK(xc->sem); /* spin through the cache looking for stale requests */ for (last = NULL, cur = xc->first; cur;) { next = cur->next; if ((cur->external) && ((now - cur->sent) > 30)) { if (!last) xc->first = next; else last->next = next; cur->data = NULL; cur->preblock = 1; } else { last = cur; if ((cur->external) && ((now - cur->sent) > 10)) { log_alert("xdb", "Resend xdb packet"); xdb_deliver(xc->i, cur, 1); } } cur = next; } SEM_UNLOCK(xc->sem); return r_DONE; }
/** Shut down transport, kill all sessions */ void it_shutdown(void *arg) { iti ti = (iti) arg; log_alert(ZONE,"JIT Transport, shutting down"); ti->shutdown = 1; /* wait */ usleep(1000); if (ti->sessions_count) { SEM_LOCK(ti->sessions_sem); wpxhash_walk(ti->sessions,it_sessions_end,NULL); SEM_UNLOCK(ti->sessions_sem); } while (ti->sessions_count > 0) usleep(100); wpxhash_free(ti->sessions); ti->sessions = NULL; }
/* any thread */ result js_packet(instance i, dpacket p, void *arg) { jsmi si = (jsmi) arg; jpacket jp = NULL; session s = NULL; packet_thread_p pt; udata u; char *type, *authto; log_debug("incoming packet %s", xmlnode2str(p->x)); /* if this is a routed packet */ if (p->type == p_ROUTE) { type = xmlnode_get_attrib(p->x, "type"); /* new session requests */ if (j_strcmp(type, "session") == 0) { js_session_new_mtq(si, p); return r_DONE; } /* get the internal jpacket */ if (xmlnode_get_firstchild(p->x) != NULL) /* XXX old libjabber jpacket_new() wasn't null safe, this is just safety */ jp = jpacket_new(xmlnode_get_firstchild(p->x)); /* auth/reg requests */ if (jp != NULL && j_strcmp(type, "auth") == 0) { /* check and see if we're configured to forward auth packets for processing elsewhere */ if ((authto = xmlnode_get_data(js_config(si, "auth"))) != NULL) { xmlnode_put_attrib(p->x, "oto", xmlnode_get_attrib(p->x, "to")); /* preserve original to */ xmlnode_put_attrib(p->x, "to", authto); deliver(dpacket_new(p->x), i); return r_DONE; } /* internally, hide the route to/from addresses on the authreg request */ xmlnode_put_attrib(jp->x, "to", xmlnode_get_attrib(p->x, "to")); xmlnode_put_attrib(jp->x, "from", xmlnode_get_attrib(p->x, "from")); xmlnode_put_attrib(jp->x, "route", xmlnode_get_attrib(p->x, "type")); jpacket_reset(jp); jp->aux1 = (void *) si; pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_authreg, pt); return r_DONE; } /* if it's an error */ if (j_strcmp(type, "error") == 0) { /* look for users online */ u = js_user(si, p->id, 1); if (u == NULL) { /* if this was a message, it should have been delievered to that session, store offline */ if (jp != NULL && jp->type == JPACKET_MESSAGE) { pt = pmalloco(jp->p, sizeof (packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } xmlnode_free(p->x); return r_DONE; /* log_notice(p->host, "Bouncing packet intended for nonexistant user: %s", xmlnode2str(p->x)); deliver_fail(dpacket_new(p->x), "Invalid User"); return r_DONE; */ } if (p->id->resource != NULL) { SEM_LOCK(u->sem); for (s = u->sessions; s != NULL; s = s->next) if (j_strcmp (p->id->resource, s->route->resource) == 0) break; SEM_UNLOCK(u->sem); if (s != NULL) { s->sid = NULL; /* they generated the error, no use in sending there anymore! */ js_session_end(s, "Disconnected"); } } else { session temp; /* a way to boot an entire user off */ SEM_LOCK(u->sem); for (s = u->sessions; s != NULL;) { temp = s; s = s->next; js_session_end_nosem(temp, "Removed"); } u->pass = NULL; /* so they can't log back in */ SEM_UNLOCK(u->sem); xmlnode_free(p->x); THREAD_DEC(u->ref); return r_DONE; } THREAD_DEC(u->ref); /* if this was a message, it should have been delievered to that session, store offline */ if (jp != NULL && jp->type == JPACKET_MESSAGE) { pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } /* drop and return */ if (xmlnode_get_firstchild(p->x) != NULL) log_notice(p->host, "Dropping a bounced session packet to %s", jid_full(p->id)); xmlnode_free(p->x); return r_DONE; } /* uhh, empty packet, *shrug* */ if (jp == NULL) { log_notice(p->host, "Dropping an invalid or empty route packet: %s", xmlnode2str(p->x), jid_full(p->id)); xmlnode_free(p->x); return r_DONE; } /* ============================================================== */ /* attempt to locate the session by matching the special resource */ u = js_user(si, p->id, 1); if (u == NULL) { /* only when route packet to users not online */ pt = pmalloco(p->p, sizeof(packet_thread_t)); pt->p = p; pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } /* user is online :) */ SEM_LOCK(u->sem); for (s = u->sessions; s != NULL; s = s->next) if (j_strcmp(p->id->resource, s->route->resource) == 0) break; SEM_UNLOCK(u->sem); THREAD_DEC(u->ref); if (s != NULL) { /* just pass to the session normally */ js_session_from(s, jp); return r_DONE; } log_notice(p->host, "Bouncing %s packet intended for session %s", xmlnode_get_name(jp->x), jid_full(p->id)); deliver_fail(dpacket_new(p->x), "Invalid Session"); return r_DONE; } /* normal server-server packet, should we make sure it's not spoofing us? if so, if ghash_get(p->to->server) then bounce w/ security error */ jp = jpacket_new(p->x); if (jp == NULL) { log_warn(p->host, "Dropping invalid incoming packet: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; }
/* * js_session_new -- creates a new session, registers the resource for it * * Sets up all the data associated with the new session, then send it a * start spacket, which basically notifies all modules about the new session * * returns * a pointer to the new session */ session js_session_new(jsmi si, dpacket dp) { pool p; session s, cur; udata u; int i; char routeres[10]; /* screen out illegal calls */ if (dp == NULL || dp->id->user == NULL || dp->id->resource == NULL || xmlnode_get_attrib(dp->x, "from") == NULL) return NULL; if ((u = js_user(si, dp->id, 0)) == NULL) return NULL; if (u->scount >= MAX_USER_SESSIONS) { THREAD_DEC(u->ref); return NULL; } log_debug("session_create %s", jid_full(dp->id)); /* create session */ p = pool_heap(1024); s = pmalloco(p, sizeof(struct session_struct)); s->p = p; s->si = si; /* save authorative remote session id */ s->sid = jid_new(p, xmlnode_get_attrib(dp->x, "from")); /* session identity */ s->id = jid_new(p, jid_full(dp->id)); /* id bez resource */ s->uid = jid_user(s->id); s->route = jid_new(p, jid_full(dp->id)); snprintf(routeres, 9, "%X", s); jid_set(s->route, routeres, JID_RESOURCE); s->res = pstrdup(p, dp->id->resource); s->u = u; jid_full(s->sid); jid_full(s->uid); jid_full(s->id); jid_full(s->route); { register char *text; text = xmlnode_get_attrib(dp->x, "ip"); if (text) { s->ip = pstrdup(s->p, xmlnode_get_attrib(dp->x, "ip")); xmlnode_hide_attrib(dp->x, "ip"); } else s->ip = "none"; } /* default settings */ s->exit_flag = 0; s->roster = 0; s->priority = -129; s->presence = jutil_presnew(JPACKET__UNAVAILABLE, NULL, NULL); xmlnode_put_attrib(s->presence, "from", jid_full(s->id)); s->c_in = s->c_out = 0; for (i = 0; i < es_LAST; i++) s->events[i] = NULL; SEM_LOCK(u->sem); if (u->sessions != NULL) { s->q = get_mtq_queue(si, u->sessions->q); for (cur = u->sessions; cur != NULL; cur = cur->next) if (j_strcmp(dp->id->resource, cur->res) == 0) js_session_end_nosem(cur, "Replaced by new connection"); } else { s->q = get_mtq_queue(si, NULL); } /* make sure we're linked with the user */ s->next = s->u->sessions; s->u->sessions = s; s->u->scount++; SEM_UNLOCK(u->sem); /* session start */ { packet_thread_p pt; pt = malloc(sizeof(packet_thread_t)); pt->s = s; pt->type = 0; fast_mtq_send(s->q->mtq, pt); } THREAD_DEC(u->ref); return s; }
void mtq_send(mtq q, pool p, mtq_callback f, void *arg) { mtqqueue mq; /* one element */ mtq mtq; /* initialization stuff */ if(mtq__master == NULL) { mtq_init(); } if(q != NULL) { mtq = q; } else { /* take next thread */ mtq__master->random++; if (mtq__master->random >= MTQ_THREADS) mtq__master->random = 0; mtq = mtq__master->all[mtq__master->random]->mtq; } /* build queue */ log_debug(ZONE,"mtq_send insert into mtq=%p",mtq); /* lock operation on queue */ SEM_LOCK(mtq->sem); /* find free memory */ mq = mtq->free_last; if (mq == NULL) { while ((mq = malloc(sizeof(_mtqqueue)))==NULL) Sleep(1000); /* it means new malloc maybe we should free this mq later ? */ log_alert(ZONE,"MTQ new queue malloc"); mq->memory = 1; mtq->length++; } else { /* take it out from queue */ mtq->free_last = mtq->free_last->prev; } mq->f = f; mq->arg = arg; mq->prev = NULL; mtq->dl++; /* if queue is empty */ if (mtq->last == NULL) mtq->last = mq; else mtq->first->prev = mq; mtq->first = mq; COND_SIGNAL(mtq->cond); SEM_UNLOCK(mtq->sem); }
/** Callback processing incoming Jabber packets. */ result it_receive(instance i, dpacket d, void *arg) { iti ti = (iti) arg; jpacket jp; session s; session_ref alt_s; unsigned char *user; log_debug(ti->i->id,"Packet received: %s\n",xmlnode2str(d->x)); switch(d->type) { case p_ROUTE: { /* ignore */ return r_PASS; } case p_NONE: case p_NORM: jp = jpacket_new(d->x); break; default: return r_ERR; } if (!jp->from ||/* !jp->from->user ||*/ jp->type == JPACKET_UNKNOWN /* || jpacket_subtype(jp) == JPACKET__ERROR */) { /* ignore invalid packets */ xmlnode_free(jp->x); return r_DONE; } /* JID user part should be case insensitive */ /* convert user part of from JID to lower case */ if(jp->from->user != NULL) for(user = jp->from->user; *user != '\0'; user++) if(*user < 128) *user = tolower(*user); /* Mangle "from" JID, save original attribute for XDB conversion */ xmlnode_put_attrib(jp->x, "origfrom", xmlnode_get_attrib(jp->x, "from")); xmlnode_put_attrib(jp->x, "from", jid_full(jp->from)); SEM_LOCK(ti->sessions_sem); s = (session) wpxhash_get(ti->sessions,jid_full(jid_user(jp->from))); alt_s = (session_ref) wpxhash_get(ti->sessions_alt,jp->to->user); if (s != NULL) { if (s->exit_flag) { SEM_UNLOCK(ti->sessions_sem); log_alert("exit flag","message to exiting session"); if (jp->type != JPACKET_PRESENCE){ jutil_error(jp->x,TERROR_NOTFOUND); it_deliver(ti,jp->x); } else xmlnode_free(jp->x); } else if ((alt_s != NULL) && ( (jp->type == JPACKET_MESSAGE) // all messages || ((jp->type == JPACKET_IQ) && (j_strcmp(xmlnode_get_attrib(jp->iq,"xmlns"),NS_VCARD) == -1)) // all IQs except of vCard || (jp->type == JPACKET_PRESENCE) )) { // all presences _targeted_to_specific_user_ // rewriting "to" and "from" and putting packet back on the wire xmlnode_put_attrib(jp->x, "from", jid_full(it_uin2jid(jp->p,s->uin,jp->to->server))); xmlnode_put_attrib(jp->x, "to", jid_full(alt_s->s->orgid)); SEM_UNLOCK(ti->sessions_sem); it_deliver(ti,jp->x); } else { jp->aux1 = (void *) s; mtq_send(s->q,jp->p,it_session_jpacket,(void *) jp); SEM_UNLOCK(ti->sessions_sem); } } else { SEM_UNLOCK(ti->sessions_sem); if(jpacket_subtype(jp)!=JPACKET__ERROR) it_unknown(ti,jp); else xmlnode_free(jp->x); } return r_DONE; }
/* blocks until namespace is retrieved, host must map back to this service! */ xmlnode xdb_get(xdbcache xc, jid owner, char *ns) { xdbrequest_p cur; xmlnode x; struct timeval tv; if (xc->shutdown) return NULL; if (xc == NULL || owner == NULL || ns == NULL) { if (ns) { log_alert("xdb_get", "Programming Error: xdb_get() called with NULL ns: %s\n", ns); } else { log_alert("xdb_get", "Programming Error: xdb_get() called with NULL ns: NULL\n"); } if (owner) { log_alert("owner", "%s", jid_full(owner)); } return NULL; } log_debug("XDB GET"); /* init this newx */ cur = malloc(sizeof(xdbrequest_t)); memset(cur, 0, sizeof(xdbrequest_t)); // cur->set = 0; // cur->data = NULL; cur->ns = ns; cur->owner = owner; gettimeofday(&tv, NULL); cur->sent = tv.tv_sec; SEM_LOCK(xc->sem); cur->id = xc->id++; cur->next = xc->first; xc->first = cur; SEM_UNLOCK(xc->sem); /* send it on it's way */ xdb_deliver(xc->i, cur, 0); cur->external = 1; /* if it hasn't already returned, we should block here until it returns */ while (cur->preblock != 1) usleep(10); /* newx.data is now the returned xml packet */ /* return the xmlnode inside <xdb>...</xdb> */ for (x = xmlnode_get_firstchild(cur->data); x != NULL && xmlnode_get_type(x) != NTYPE_TAG; x = xmlnode_get_nextsibling(x)); /* there were no children (results) to the xdb request, free the packet */ if (x == NULL) xmlnode_free(cur->data); free(cur); return x; }