jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "sm.h" 00022 00045 /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ 00046 union xhashv 00047 { 00048 void **val; 00049 sess_t *sess_val; 00050 }; 00051 00052 static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) { 00053 sm_t sm = mi->mod->mm->sm; 00054 int ns, iq, elem, attr; 00055 jid_t jid; 00056 sess_t sess = (sess_t) NULL; 00057 mod_ret_t ret; 00058 00059 /* if we've got this namespace, its from a c2s */ 00060 if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0) 00061 return mod_PASS; 00062 00063 /* don't bother if its a failure */ 00064 if(pkt->type & pkt_SESS_FAILED) { 00065 /* !!! check failed=1, handle */ 00066 pkt_free(pkt); 00067 return mod_HANDLED; 00068 } 00069 00070 /* session commands */ 00071 if(pkt->type & pkt_SESS) { 00072 00073 ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL); 00074 00075 /* only end can get away without a target */ 00076 attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL); 00077 if(attr < 0 && pkt->type != pkt_SESS_END) { 00078 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00079 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00080 00081 pkt->nad = NULL; 00082 pkt_free(pkt); 00083 00084 return mod_HANDLED; 00085 } 00086 00087 /* session start */ 00088 if(pkt->type == pkt_SESS) { 00089 jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00090 00091 if(jid != NULL) 00092 sess = sess_start(sm, jid); 00093 00094 if(jid == NULL || sess == NULL) { 00095 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00096 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00097 00098 pkt->nad = NULL; 00099 pkt_free(pkt); 00100 if(jid != NULL) 00101 jid_free(jid); 00102 00103 return mod_HANDLED; 00104 } 00105 00106 /* c2s component that is handling this session */ 00107 strcpy(sess->c2s, pkt->rfrom->domain); 00108 00109 /* remember what c2s calls us */ 00110 attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); 00111 snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00112 00113 /* mark PBX session as fake */ 00114 if(!strncmp("PBX", sess->c2s_id, 3)) { 00115 sess->fake = 1; 00116 } 00117 00118 /* add our id */ 00119 nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0); 00120 00121 /* mark that it started OK */ 00122 nad_set_attr(pkt->nad, 1, -1, "action", "started", 7); 00123 00124 /* set this SM name */ 00125 nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0); 00126 00127 /* inform c2s */ 00128 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00129 00130 pkt->nad = NULL; 00131 pkt_free(pkt); 00132 jid_free(jid); 00133 00134 return mod_HANDLED; 00135 } 00136 00137 /* user create */ 00138 if(pkt->type == pkt_SESS_CREATE) { 00139 jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00140 00141 if(jid == NULL || user_create(sm, jid) != 0) { 00142 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00143 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00144 00145 pkt->nad = NULL; 00146 pkt_free(pkt); 00147 if(jid != NULL) 00148 jid_free(jid); 00149 00150 return mod_HANDLED; 00151 } 00152 00153 /* inform c2s */ 00154 nad_set_attr(pkt->nad, 1, -1, "action", "created", 7); 00155 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00156 00157 pkt->nad = NULL; 00158 pkt_free(pkt); 00159 jid_free(jid); 00160 00161 return mod_HANDLED; 00162 } 00163 00164 /* user delete */ 00165 if(pkt->type == pkt_SESS_DELETE) { 00166 jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00167 if(jid == NULL) { 00168 pkt_free(pkt); 00169 return mod_HANDLED; 00170 } 00171 00172 user_delete(sm, jid); 00173 00174 /* inform c2s */ 00175 nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7); 00176 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00177 00178 pkt->nad = NULL; 00179 pkt_free(pkt); 00180 jid_free(jid); 00181 00182 return mod_HANDLED; 00183 } 00184 00185 /* get the session id */ 00186 attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); 00187 if(attr < 0) { 00188 log_debug(ZONE, "no session id, bouncing"); 00189 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00190 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00191 00192 pkt->nad = NULL; 00193 pkt_free(pkt); 00194 00195 return mod_HANDLED; 00196 } 00197 00198 /* find the corresponding session */ 00199 sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00200 00201 /* active check */ 00202 if(sess == NULL) { 00203 log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00204 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00205 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00206 00207 pkt->nad = NULL; 00208 pkt_free(pkt); 00209 00210 return mod_HANDLED; 00211 } 00212 00213 /* make sure its from them */ 00214 attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); 00215 if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { 00216 log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id); 00217 pkt_free(pkt); 00218 return mod_HANDLED; 00219 } 00220 00221 /* session end */ 00222 if(pkt->type == pkt_SESS_END) { 00223 sm_c2s_action(sess, "ended", NULL); 00224 sess_end(sess); 00225 00226 pkt_free(pkt); 00227 return mod_HANDLED; 00228 } 00229 00230 log_debug(ZONE, "unknown session packet, dropping"); 00231 pkt_free(pkt); 00232 00233 return mod_HANDLED; 00234 } 00235 00236 /* otherwise, its a normal packet for the session */ 00237 00238 /* #ifdef ENABLE_SUPERSEDED // FIXME XXX TODO clients are not yet ready for this */ 00239 /* check for RFC3920 session request * 00240 * with RFC3920bis it is unneeded * 00241 * session is activated by bind, so we just return back result */ 00242 if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 && 00243 (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 && 00244 (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) { 00245 log_debug(ZONE, "session create request"); 00246 00247 /* build a result packet */ 00248 nad_drop_elem(pkt->nad, elem); 00249 nad_set_attr(pkt->nad, iq, -1, "type", "result", 6); 00250 00251 /* return the result */ 00252 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00253 00254 pkt->nad = NULL; 00255 pkt_free(pkt); 00256 00257 return mod_HANDLED; 00258 } 00259 /* #endif */ 00260 /* get the session id */ 00261 attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); 00262 if(attr < 0) { 00263 log_debug(ZONE, "no session id, bouncing"); 00264 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00265 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00266 00267 pkt->nad = NULL; 00268 pkt_free(pkt); 00269 00270 return mod_HANDLED; 00271 } 00272 00273 /* find the corresponding session */ 00274 sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00275 00276 /* active check */ 00277 if(sess == NULL) { 00278 log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00279 nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); 00280 sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); 00281 00282 pkt->nad = NULL; 00283 pkt_free(pkt); 00284 00285 return mod_HANDLED; 00286 } 00287 00288 /* make sure its from them */ 00289 attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); 00290 if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { 00291 log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id); 00292 pkt_free(pkt); 00293 return mod_HANDLED; 00294 } 00295 00296 /* where it came from */ 00297 pkt->source = sess; 00298 00299 /* hand it to the modules */ 00300 ret = mm_in_sess(pkt->sm->mm, sess, pkt); 00301 switch(ret) { 00302 case mod_HANDLED: 00303 break; 00304 00305 case mod_PASS: 00306 /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */ 00307 if(pkt->type == pkt_IQ_RESULT) 00308 break; 00309 else 00310 ret = -stanza_err_FEATURE_NOT_IMPLEMENTED; 00311 00312 default: 00313 pkt_sess(pkt_error(pkt, -ret), sess); 00314 00315 break; 00316 } 00317 00318 return mod_HANDLED; 00319 } 00320 00321 static mod_ret_t _session_pkt_router(mod_instance_t mi, pkt_t pkt) { 00322 sess_t sess; 00323 union xhashv xhv; 00324 00325 /* we want unadvertisments */ 00326 if(pkt->from == NULL || !(pkt->rtype & route_ADV) || pkt->rtype != route_ADV_UN) 00327 return mod_PASS; 00328 00329 log_debug(ZONE, "component '%s' went offline, checking for sessions held there", jid_full(pkt->from)); 00330 00331 /* this is fairly inefficient, especially if we have a lot of sessions 00332 * online, but it shouldn't be called that often (components are usually 00333 * long-running) */ 00334 00335 xhv.sess_val = &sess; 00336 if(xhash_iter_first(mi->mod->mm->sm->sessions)) 00337 do { 00338 xhash_iter_get(mi->mod->mm->sm->sessions, NULL, NULL, xhv.val); 00339 if(sess && strcmp(sess->c2s, pkt->from->domain) == 0) 00340 sess_end(sess); 00341 } while (xhash_iter_next(mi->mod->mm->sm->sessions)); 00342 00343 return mod_PASS; 00344 } 00345 00346 DLLEXPORT int module_init(mod_instance_t mi, char *arg) { 00347 if(mi->mod->init) return 0; 00348 00349 mi->mod->in_router = _session_in_router; 00350 mi->mod->pkt_router = _session_pkt_router; 00351 00352 return 0; 00353 }