📄 deliver.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL"). You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/. * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL. * * * --------------------------------------------------------------------------*/#include "jsm.h"/** * @file jsm/deliver.c * @brief handle incoming packets and check how they can be delivered *//** * handle stanzas addressed to one of the users handled by this jsm's hosts. * * Attempts to deliver it to the correct session/thread, * must have a valid to/from address already before getting here * * It is first tried if one of the e_DELIVER modules handles the packets, * iff not stanzas addressed to the server itself are passed to * js_server_main(), packets explicitly addressed to a resource (session) * are passed to js_session_to(), and packets addressed to a user are passed * to js_offline_main(), other stanzas are bounced as "item-not-found". * * @param si the session manager instance * @param p the packet to deliver * @param ht the hash table containing the users of the relevant host */void js_deliver_local(jsmi si, jpacket p, xht ht) { int incremented = 0; udata user = NULL; session s = NULL; /* first, collect some facts */ user = js_user(si, p->to, ht); s = js_session_get(user, p->to->resource); /* lock the udata from being freed while we are working on it */ if (user != NULL) { user->ref++; incremented++; } log_debug2(ZONE, LOGT_DELIVER, "delivering locally to %s",jid_full(p->to)); /* let some modules fight over it */ if(js_mapi_call(si, e_DELIVER, p, user, s)) { /* the packet has been handled by one of the modules */ if (incremented != 0) { user->ref--; /* release lock */ } return; } if(p->to->user == NULL) { /* this is for the server */ js_psend(si,p,js_server_main); if (incremented != 0) { user->ref--; /* release lock */ } return; } /* the packet has neither been handled by the e_DELIVER modules nor was for the server */ if(s != NULL) { /* it's sent right to the resource */ js_session_to(s, p); if (incremented != 0) { user->ref--; /* release lock */ } return; } if(user != NULL) { /* valid user, but no session */ p->aux1 = (void *)user; /* performance hack, we already know the user */ js_psend(si,p,js_offline_main); /* the offline thread will release our lock on the udata structure */ return; } /* release lock on the udata structure */ if (incremented != 0) { user->ref--; } /* no user, so bounce the packet */ js_bounce_xmpp(si,p->x,XTERROR_NOTFOUND);}/** * handle incoming <route type='session'/> packets, we get passed from jabberd: * create a new session * * @param i the jsm instance we are running in * @param p the packet we should receive * @param si our jsm instance internal data * @return always r_DONE */result _js_routed_session_packet(instance i, dpacket p, jsmi si) { session s = NULL; /* the new session */ /* try to create the new session */ if ((s = js_session_new(si, p)) == NULL) { /* session start failed */ log_warn(p->host,"Unable to create session %s",jid_full(p->id)); xmlnode_put_attrib(p->x,"type","error"); xmlnode_put_attrib(p->x,"error","Session Failed"); } else { /* reset to the routed id for this session for the reply below */ xmlnode_put_attrib(p->x,"to",jid_full(s->route)); } /* reply */ jutil_tofrom(p->x); deliver(dpacket_new(p->x), i); return r_DONE;}/** * handle incoming <route type='auth'/> packets, we get passed from jabberd: * authentication or registration requests * * Check if another component is configured to handle the auth packets * using the <auth/> element containing the other component's address * in jsm's configuration. * * If not let js_authreg process the request. * * @param i the jsm instance we are running in * @param p the packet we should receive * @param si our jsm instance internal data * @param jp the wrapped packet we received * @return always r_DONE */result _js_routed_auth_packet(instance i, dpacket p, jsmi si, jpacket jp) { char *authto = NULL; /* 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; mtq_send(NULL,jp->p,js_authreg,(void *)jp); return r_DONE;}/** * handle incoming <route type='error'/> packets, we get passed from jabberd: * most likely returned packets we sent to the client connection manager - the * user seems to have disconnected (or the component has crashed *g*) * * Cancel the session, store bounced messages offline again. * * @param i the jsm instance we are running in * @param p the packet we should receive * @param si our jsm instance internal data * @param ht the hash table containing the users of the relevant host * @param jp the wrapped packet we received * @param s the session this packet is for * @param u the user data for the receipient * @return always r_DONE */result _js_routed_error_packet(instance i, dpacket p, jsmi si, xht ht, jpacket jp, session s, udata u) { /* ooh, incoming routed errors in reference to this session, the session is kaput */ if (s != NULL) { s->sid = NULL; /* they generated the error, no use in sending there anymore! */ js_session_end(s, "Disconnected"); } else if (p->id->resource == NULL) { /* a way to boot an entire user off */ for(s = u->sessions; s != NULL; s = s->next) js_session_end(s,"Removed"); u->pass = NULL; /* so they can't log back in */ xmlnode_free(p->x); return r_DONE; } /* if this was a message, it should have been delievered to that session, store offline */ if (jp != NULL && jp->type == JPACKET_MESSAGE) { js_deliver_local(si, jp, ht); /* (re)deliver it locally again, should go to another session or offline */ 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;}/** * handle incoming <route/> packets, we get passed from jabberd * * @param i the jsm instance we are running in * @param p the packet we should receive * @param si our jsm instance internal data * @param ht the hash table containing the users of the relevant host * @return always r_DONE */result _js_routed_packet(instance i, dpacket p, jsmi si, xht ht) { jpacket jp = NULL; xmlnode child = NULL; /* the actual stanza in the <route/> element */ char *type = NULL; /* the type of the route packet: NULL, auth, session, or error */ session s = NULL; /* the session this packet is for */ udata u = NULL; /* the user's data */ type = xmlnode_get_attrib(p->x,"type"); /* new session requests */ if(j_strcmp(type,"session") == 0) return _js_routed_session_packet(i, p, si); /* Find the first real element */ child = xmlnode_get_firstchild(p->x); while (child != NULL) { if (xmlnode_get_type(child) == NTYPE_TAG) break; child = xmlnode_get_nextsibling(child); } /* As long as we found one process */ if (child != NULL) jp = jpacket_new(child); /* auth/reg requests */ if(jp != NULL && j_strcmp(type,"auth") == 0) return _js_routed_auth_packet(i, p, si, jp); /* this is a packet to be processed as outgoing for a session */ /* attempt to locate the session by matching the special resource */ u = js_user(si, p->id, ht); if (u == NULL) { /* no user!?!?! */ 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; } for(s = u->sessions; s != NULL; s = s->next) if(j_strcmp(p->id->resource, s->route->resource) == 0) break; /* if it's an error */ if(j_strcmp(type,"error") == 0) return _js_routed_error_packet(i, p, si, ht, jp, s, u); if(jp == NULL) { /* uhh, empty packet, *shrug* */ 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; } if(s != NULL) { /* just pass to the session normally */ js_session_from(s, jp); } else { /* bounce back as an error */ 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;}/** * handle packets we get passed from jabberd * * This is the input for packets we receive from jabberd ... * * @param i the jsm instance we are running in * @param p the packet we should receive * @param arg our jsm instance internal data * @return always r_DONE */result js_packet(instance i, dpacket p, void *arg){ jsmi si = (jsmi)arg; jpacket jp = NULL; xht ht = NULL; log_debug2(ZONE, LOGT_DELIVER, "(%X)incoming packet %s",si,xmlnode2str(p->x)); /* make sure this hostname is in the master table */ if((ht = (xht)xhash_get(si->hosts,p->host)) == NULL) { ht = xhash_new(j_atoi(xmlnode_get_data(js_config(si,"maxusers")),USERS_PRIME)); log_debug2(ZONE, LOGT_DELIVER, "creating user hash %X for %s",ht,p->host); xhash_put(si->hosts,pstrdup(si->p,p->host), (void *)ht); log_debug2(ZONE, LOGT_DELIVER, "checking %X",xhash_get(si->hosts,p->host)); } /* if this is a routed packet */ if(p->type == p_ROUTE) { return _js_routed_packet(i, p, si, ht); } /* normal server-server packet, should we make sure it's not spoofing us? if so, if xhash_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; } js_deliver_local(si, jp, ht); return r_DONE;}/** * take a packet and deliver it either locally if it has ourself as the destination * or deliver it using jabberd if it is for a non-instance-local host * * This function checks if the packet is local, and will then call j_deliver_local() to deliver it. * If it is not instance-local it will call deliver() to deliver it using jabberd. * * @note any jpacket sent to deliver *MUST* match jpacket_new(p->x), * jpacket is simply a convenience wrapper * */void js_deliver(jsmi si, jpacket p) { xht ht; /* hashtable containing the users of the relevant host */ /* does it have a destination address? */ if (p->to == NULL) { log_warn(NULL,"jsm: Invalid Recipient, returning data %s",xmlnode2str(p->x)); js_bounce_xmpp(si,p->x,XTERROR_BAD); return; } /* does it have a sender address? */ if (p->from == NULL) { log_warn(NULL,"jsm: Invalid Sender, discarding data %s",xmlnode2str(p->x)); xmlnode_free(p->x); return; } log_debug2(ZONE, LOGT_DELIVER, "deliver(to[%s],from[%s],type[%d],packet[%s])",jid_full(p->to),jid_full(p->from),p->type,xmlnode2str(p->x)); /* external or local delivery? */ if ((ht = (xht)xhash_get(si->hosts,p->to->server)) != NULL) { js_deliver_local(si, p, ht); return; } deliver(dpacket_new(p->x), si->i);}/** * send a packet to a function * * @param si the instance local data * @param p the packet to send * @param f the function to send the packet to */void js_psend(jsmi si, jpacket p, mtq_callback f){ jpq q; if(p == NULL || si == NULL) return; log_debug2(ZONE, LOGT_DELIVER, "psending to %X packet %X",f,p); q = pmalloc(p->p, sizeof(_jpq)); q->p = p; q->si = si; mtq_send(NULL, p->p, f, (void *)q);}/* for fun, a tidbit from late nite irc (ya had to be there)<temas> What is 1+1<temas> Why did you hardcode stuff<temas> Was the movie good?<temas> DId the nukes explode?*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -