jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 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 00031 void sess_route(sess_t sess, pkt_t pkt) { 00032 int ns; 00033 00034 log_debug(ZONE, "routing pkt 0x%X to %s (%s) for %s", pkt, sess->c2s, sess->c2s_id, jid_full(sess->jid)); 00035 00036 if(pkt == NULL) 00037 return; 00038 00039 /* wrap it up */ 00040 ns = nad_append_namespace(pkt->nad, 1, uri_SESSION, "sm"); 00041 00042 nad_set_attr(pkt->nad, 1, ns, "c2s", sess->c2s_id, 0); 00043 nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0); 00044 00045 nad_set_attr(pkt->nad, 0, -1, "to", sess->c2s, 0); 00046 nad_set_attr(pkt->nad, 0, -1, "from", sess->user->jid->domain, 0); 00047 00048 /* remove error attribute */ 00049 nad_set_attr(pkt->nad, 0, -1, "error", NULL, 0); 00050 00051 /* and send it out */ 00052 sx_nad_write(sess->user->sm->router, pkt->nad); 00053 00054 /* free up the packet */ 00055 if(pkt->rto != NULL) jid_free(pkt->rto); 00056 if(pkt->rfrom != NULL) jid_free(pkt->rfrom); 00057 if(pkt->to != NULL) jid_free(pkt->to); 00058 if(pkt->from != NULL) jid_free(pkt->from); 00059 free(pkt); 00060 } 00061 00062 static void _sess_end_guts(sess_t sess) { 00063 sess_t scan; 00064 00065 /* fake an unavailable presence from this session, so that modules and externals know we're gone */ 00066 if(sess->available || sess->A != NULL) 00067 mm_in_sess(sess->user->sm->mm, sess, pkt_create(sess->user->sm, "presence", "unavailable", NULL, NULL)); 00068 00069 /* inform the modules */ 00070 mm_sess_end(sess->user->sm->mm, sess); 00071 00072 /* unlink it from this users sessions */ 00073 if(sess->user->sessions == sess) 00074 sess->user->sessions = sess->next; 00075 else { 00076 for(scan = sess->user->sessions; scan != NULL && scan->next != sess; scan = scan->next); 00077 if(scan != NULL) 00078 scan->next = sess->next; 00079 } 00080 00081 /* and from global sessions */ 00082 xhash_zap(sess->user->sm->sessions, sess->sm_id); 00083 } 00084 00085 void sess_end(sess_t sess) { 00086 log_debug(ZONE, "shutting down session %s", jid_full(sess->jid)); 00087 00088 _sess_end_guts(sess); 00089 00090 log_write(sess->user->sm->log, LOG_NOTICE, "session ended: jid=%s", jid_full(sess->jid)); 00091 00092 /* if it was the last session, free the user */ 00093 if(sess->user->sessions == NULL) { 00094 mm_user_unload(sess->user->sm->mm, sess->user); 00095 log_write(sess->user->sm->log, LOG_NOTICE, "user unloaded jid=%s", jid_user(sess->jid)); 00096 user_free(sess->user); 00097 } 00098 00099 /* free the session */ 00100 pool_free(sess->p); 00101 } 00102 00103 sess_t sess_start(sm_t sm, jid_t jid) { 00104 pool_t p; 00105 user_t user; 00106 sess_t sess, scan; 00107 sha1_state_t sha1; 00108 char hash[20]; 00109 int replaced = 0; 00110 00111 log_debug(ZONE, "session requested for %s", jid_full(jid)); 00112 00113 /* check whether it is to serviced domain */ 00114 if(xhash_get(sm->hosts, jid->domain) == NULL) { 00115 log_write(sm->log, LOG_ERR, "request to start session in non-serviced domain: jid=%s", jid_full(jid)); 00116 return NULL; 00117 } 00118 00119 /* get user data for this guy */ 00120 user = user_load(sm, jid); 00121 00122 /* unknown user */ 00123 if(user == NULL) { 00124 if(config_get(sm->config, "user.auto-create") == NULL) { 00125 log_write(sm->log, LOG_NOTICE, "user not found and user.auto-create not enabled, can't start session: jid=%s", jid_full(jid)); 00126 return NULL; 00127 } 00128 00129 log_debug(ZONE, "auto-creating user %s", jid_user(jid)); 00130 00131 if(user_create(sm, jid) != 0) 00132 return NULL; 00133 00134 user = user_load(sm, jid); 00135 if(user == NULL) { 00136 log_write(sm->log, LOG_NOTICE, "couldn't load user, can't start session: jid=%s", jid_full(jid)); 00137 return NULL; 00138 } 00139 } 00140 00141 /* kill their old session if they have one */ 00142 for(scan = user->sessions; scan != NULL; scan = scan->next) 00143 if(jid_compare_full(scan->jid, jid) == 0) { 00144 log_debug(ZONE, "replacing session %s (%s)", jid_full(jid), scan->c2s_id); 00145 00146 /* !!! this "replaced" stuff is a hack - its really a subaction of "ended". 00147 * hurrah, another control protocol rewrite is needed :( 00148 */ 00149 sm_c2s_action(scan, "replaced", NULL); 00150 00151 _sess_end_guts(scan); 00152 00153 pool_free(scan->p); 00154 00155 replaced = 1; 00156 00157 break; 00158 } 00159 00160 /* make a new session */ 00161 p = pool_new(); 00162 00163 sess = (sess_t) pmalloco(p, sizeof(struct sess_st)); 00164 sess->p = p; 00165 00166 /* fill it out */ 00167 sess->pri = 0; 00168 sess->user = user; 00169 00170 sess->jid = jid_dup(jid); 00171 pool_cleanup(sess->p, (void (*))(void *) jid_free, sess->jid); 00172 00173 /* a place for modules to store stuff */ 00174 sess->module_data = (void **) pmalloco(sess->p, sizeof(void *) * sess->user->sm->mm->nindex); 00175 00176 /* add it to the list */ 00177 sess->next = user->sessions; 00178 user->sessions = sess; 00179 00180 /* who c2s should address things to */ 00181 sha1_init(&sha1); 00182 datetime_out(time(NULL), dt_DATETIME, sess->sm_id, 41); 00183 sha1_append(&sha1, sess->sm_id, strlen(sess->sm_id)); 00184 sha1_append(&sha1, jid_full(sess->jid), strlen(jid_full(sess->jid))); 00185 sha1_finish(&sha1, hash); 00186 hex_from_raw(hash, 20, sess->sm_id); 00187 00188 log_debug(ZONE, "smid is %s", sess->sm_id); 00189 00190 /* remember it */ 00191 xhash_put(sm->sessions, sess->sm_id, sess); 00192 00193 /* inform the modules */ 00194 /* !!! catch the return value - if its 1, don't let them in */ 00195 mm_sess_start(sm->mm, sess); 00196 00197 if(replaced) 00198 log_write(sm->log, LOG_NOTICE, "session replaced: jid=%s", jid_full(sess->jid)); 00199 else 00200 log_write(sm->log, LOG_NOTICE, "session started: jid=%s", jid_full(sess->jid)); 00201 00202 return sess; 00203 } 00204 00206 sess_t sess_match(user_t user, char *resource) { 00207 sess_t sess; 00208 00209 for(sess = user->sessions; sess != NULL; sess = sess->next) { 00210 /* exact matches */ 00211 if(strcmp(sess->jid->resource, resource) == 0) 00212 return sess; 00213 } 00214 00215 return NULL; 00216 }