📄 deliver.c
字号:
result deliver_null(instance i, dpacket p, void* arg){ pool_free(p->p); return r_DONE;}result deliver_config_null(instance i, xmlnode x, void *arg){ if(i == NULL) return r_PASS; register_phandler(i, o_DELIVER, deliver_null, NULL); return r_DONE;}void deliver(dpacket p, instance i){ ilist a, b; if(deliver__flag == 1 && p == NULL && i == NULL) { /* begin delivery of postponed messages */ deliver_msg d; while((d=(deliver_msg)pth_msgport_get(deliver__mp))!=NULL) { deliver(d->p,d->i); } pth_msgport_destroy(deliver__mp); deliver__mp = NULL; deliver__flag = -1; /* disable all queueing crap */ } /* Ensure the packet is valid */ if (p == NULL) return; /* catch the @-internal xdb crap */ if(p->type == p_XDB && *(p->host) == '-') { deliver_internal(p, i); return; } if(deliver__flag == 0) { /* postpone delivery till later */ deliver_msg d = pmalloco(xmlnode_pool(p->x) ,sizeof(_deliver_msg)); if(deliver__mp == NULL) deliver__mp = pth_msgport_create("deliver__"); d->i = i; d->p = p; pth_msgport_put(deliver__mp, (void*)d); return; } log_debug2(ZONE, LOGT_DELIVER, "DELIVER %d:%s %s", p->type, p->host, xmlnode2str(p->x)); b = NULL; a = deliver_hashmatch(deliver_hashtable(p->type), p->host); if(p->type == p_XDB) b = deliver_hashmatch(deliver__ns, xmlnode_get_attrib(p->x,"ns")); else if(p->type == p_LOG) b = deliver_hashmatch(deliver__logtype, xmlnode_get_attrib(p->x,"type")); deliver_instance(deliver_intersect(a, b), p);}/* util to check and see which instance this hostname is going to get mapped to for normal packets */instance deliver_hostcheck(char *host){ ilist l; if(host == NULL) return NULL; if((l = deliver_hashmatch(deliver__hnorm,host)) == NULL || l->next != NULL) return NULL; return l->i;}void deliver_init(void){ deliver__hnorm = xhash_new(401); deliver__hlog = xhash_new(401); deliver__hxdb = xhash_new(401); register_config("host",deliver_config_host,NULL); register_config("ns",deliver_config_ns,NULL); register_config("logtype",deliver_config_logtype,NULL); register_config("uplink",deliver_config_uplink,NULL); register_config("null",deliver_config_null,NULL);}/** * free the delivery structures ... this is called when we already have shutdown the server * therefore we cannot register it with register_shutdown() */void deliver_shutdown(void) { if (deliver__hnorm) xhash_free(deliver__hnorm); if (deliver__hxdb) xhash_free(deliver__hxdb); if (deliver__hlog) xhash_free(deliver__hlog); if (deliver__ns) xhash_free(deliver__ns); if (deliver__logtype) xhash_free(deliver__logtype);}/* register a function to handle delivery for this instance */void register_phandler(instance id, order o, phandler f, void *arg){ handel newh, h1, last; pool p; /* create handel and setup */ p = pool_new(); /* use our own little pool */ newh = pmalloco(p, sizeof(_handel)); newh->p = p; newh->f = f; newh->arg = arg; newh->o = o; /* if we're the only handler, easy */ if(id->hds == NULL) { id->hds = newh; return; } /* place according to handler preference */ switch(o) { case o_PRECOND: /* always goes to front of list */ newh->next = id->hds; id->hds = newh; break; case o_COND: h1 = id->hds; last = NULL; while(h1->o < o_PREDELIVER) { last = h1; h1 = h1->next; if(h1 == NULL) break; } if(last == NULL) { /* goes to front of list */ newh->next = h1; id->hds = newh; } else if(h1 == NULL) { /* goes at end of list */ last->next = newh; } else { /* goes between last and h1 */ newh->next = h1; last->next = newh; } break; case o_PREDELIVER: h1 = id->hds; last = NULL; while(h1->o < o_DELIVER) { last = h1; h1 = h1->next; if(h1 == NULL) break; } if(last == NULL) { /* goes to front of list */ newh->next = h1; id->hds = newh; } else if(h1 == NULL) { /* goes at end of list */ last->next = newh; } else { /* goes between last and h1 */ newh->next = h1; last->next = newh; } break; case o_DELIVER: /* always add to the end */ for(h1 = id->hds; h1->next != NULL; h1 = h1->next); h1->next = newh; break; default: ; }}/* bounce on the delivery, use the result to better gague what went wrong */void deliver_fail(dpacket p, char *err){ xterror xt; char message[MAX_LOG_SIZE]; log_debug2(ZONE, LOGT_DELIVER, "delivery failed (%s)", err); if(p==NULL) return; switch(p->type) { case p_LOG: /* stderr and drop */ snprintf(message, MAX_LOG_SIZE, "WARNING! Logging Failed: %s\n",xmlnode2str(p->x)); fprintf(stderr, "%s\n", message); pool_free(p->p); break; case p_XDB: /* log_warning and drop */ log_warn(p->host,"dropping a %s xdb request to %s for %s",xmlnode_get_attrib(p->x,"type"),xmlnode_get_attrib(p->x,"to"),xmlnode_get_attrib(p->x,"ns")); /* drop through and treat like a route failure */ case p_ROUTE: /* route packet bounce */ if(j_strcmp(xmlnode_get_attrib(p->x,"type"),"error") == 0) { /* already bounced once, drop */ log_warn(p->host,"dropping a routed packet to %s from %s: %s",xmlnode_get_attrib(p->x,"to"),xmlnode_get_attrib(p->x,"from"),err); pool_free(p->p); }else{ log_notice(p->host,"bouncing a routed packet to %s from %s: %s",xmlnode_get_attrib(p->x,"to"),xmlnode_get_attrib(p->x,"from"),err); /* turn into an error and bounce */ jutil_tofrom(p->x); xmlnode_put_attrib(p->x,"type","error"); xmlnode_put_attrib(p->x,"error",err); deliver(dpacket_new(p->x),NULL); } break; case p_NORM: /* normal packet bounce */ if(j_strcmp(xmlnode_get_attrib(p->x,"type"),"error") == 0) { /* can't bounce an error */ log_warn(p->host,"dropping a packet to %s from %s: %s",xmlnode_get_attrib(p->x,"to"),xmlnode_get_attrib(p->x,"from"),err); pool_free(p->p); }else{ log_notice(p->host,"bouncing a packet to %s from %s: %s",xmlnode_get_attrib(p->x,"to"),xmlnode_get_attrib(p->x,"from"),err); /* turn into an error */ if(err == NULL) { jutil_error_xmpp(p->x,XTERROR_EXTERNAL); }else{ xt = XTERROR_EXTERNAL; strncpy(xt.msg, err, sizeof(xt.msg)); xt.msg[sizeof(xt.msg)-1] = 0; jutil_error_xmpp(p->x,xt); } deliver(dpacket_new(p->x),NULL); } break; default: ; }}/* actually perform the delivery to an instance */void deliver_instance(instance i, dpacket p){ handel h, hlast; result r; dpacket pig = p; if(i == NULL) { deliver_fail(p, "Unable to deliver, destination unknown"); return; } log_debug2(ZONE, LOGT_DELIVER, "delivering to instance '%s'", i->id); /* try all the handlers */ hlast = h = i->hds; while(h != NULL) { /* there may be multiple delivery handlers, make a backup copy first if we have to */ if(h->o == o_DELIVER && h->next != NULL) pig = dpacket_copy(p); /* call the handler */ if((r = (h->f)(i,p,h->arg)) == r_ERR) { deliver_fail(p, "Internal Delivery Error"); break; } /* if a non-delivery handler says it handled it, we have to be done */ if(h->o != o_DELIVER && r == r_DONE) break; /* if a conditional handler wants to halt processing */ if(h->o == o_COND && r == r_LAST) break; /* deal with that backup copy we made */ if(h->o == o_DELIVER && h->next != NULL) { if(r == r_DONE) /* they ate it, use copy */ p = pig; else pool_free(pig->p); /* they never used it, trash copy */ } /* unregister this handler */ if(r == r_UNREG) { if(h == i->hds) { /* removing the first in the list */ i->hds = h->next; pool_free(h->p); hlast = h = i->hds; }else{ /* removing from anywhere in the list */ hlast->next = h->next; pool_free(h->p); h = hlast->next; } continue; } hlast = h; h = h->next; }}dpacket dpacket_new(xmlnode x){ dpacket p; char *str; if(x == NULL) return NULL; /* create the new packet */ p = pmalloco(xmlnode_pool(x),sizeof(_dpacket)); p->x = x; p->p = xmlnode_pool(x); /* determine it's type */ p->type = p_NORM; if(*(xmlnode_get_name(x)) == 'r') p->type = p_ROUTE; else if(*(xmlnode_get_name(x)) == 'x') p->type = p_XDB; else if(*(xmlnode_get_name(x)) == 'l') p->type = p_LOG; /* xdb results are shipped as normal packets */ if(p->type == p_XDB && (str = xmlnode_get_attrib(p->x,"type")) != NULL && (*str == 'r' || *str == 'e' )) p->type = p_NORM; /* determine who to route it to, overriding the default to="" attrib only for logs where we use from */ if(p->type == p_LOG) p->id = jid_new(p->p, xmlnode_get_attrib(x, "from")); else p->id = jid_new(p->p, xmlnode_get_attrib(x, "to")); if(p->id == NULL) { log_warn(NULL,"Packet Delivery Failed, invalid packet, dropping %s",xmlnode2str(x)); xmlnode_free(x); return NULL; } /* make sure each packet has the basics, norm has a to/from, log has a type, xdb has a namespace */ switch(p->type) { case p_LOG: if(xmlnode_get_attrib(x,"type")==NULL) p=NULL; break; case p_XDB: if(xmlnode_get_attrib(x,"ns") == NULL) p=NULL; /* fall through */ case p_NORM: if(xmlnode_get_attrib(x,"to")==NULL||xmlnode_get_attrib(x,"from")==NULL) p=NULL; break; case p_ROUTE: if(xmlnode_get_attrib(x,"to")==NULL) p=NULL; break; case p_NONE: p=NULL; break; } if(p==NULL) { log_warn(NULL,"Packet Delivery Failed, invalid packet, dropping %s",xmlnode2str(x)); xmlnode_free(x); return NULL; } p->host = p->id->server; return p;}dpacket dpacket_copy(dpacket p){ dpacket p2; p2 = dpacket_new(xmlnode_dup(p->x)); return p2;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -