jabberd2  2.2.16
sm/sess.c
Go to the documentation of this file.
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 }