jabberd2  2.2.17
sess.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
31 void sess_route(sess_t sess, pkt_t pkt) {
32  int ns;
33 
34  log_debug(ZONE, "routing pkt 0x%X to %s (%s) for %s", pkt, sess->c2s, sess->c2s_id, jid_full(sess->jid));
35 
36  if(pkt == NULL)
37  return;
38 
39  /* wrap it up */
40  ns = nad_append_namespace(pkt->nad, 1, uri_SESSION, "sm");
41 
42  nad_set_attr(pkt->nad, 1, ns, "c2s", sess->c2s_id, 0);
43  nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);
44 
45  nad_set_attr(pkt->nad, 0, -1, "to", sess->c2s, 0);
46  nad_set_attr(pkt->nad, 0, -1, "from", sess->user->jid->domain, 0);
47 
48  /* remove error attribute */
49  nad_set_attr(pkt->nad, 0, -1, "error", NULL, 0);
50 
51  /* and send it out */
52  sx_nad_write(sess->user->sm->router, pkt->nad);
53 
54  /* free up the packet */
55  if(pkt->rto != NULL) jid_free(pkt->rto);
56  if(pkt->rfrom != NULL) jid_free(pkt->rfrom);
57  if(pkt->to != NULL) jid_free(pkt->to);
58  if(pkt->from != NULL) jid_free(pkt->from);
59  free(pkt);
60 }
61 
62 static void _sess_end_guts(sess_t sess) {
63  sess_t scan;
64 
65  /* fake an unavailable presence from this session, so that modules and externals know we're gone */
66  if(sess->available || sess->A != NULL)
67  mm_in_sess(sess->user->sm->mm, sess, pkt_create(sess->user->sm, "presence", "unavailable", NULL, NULL));
68 
69  /* inform the modules */
70  mm_sess_end(sess->user->sm->mm, sess);
71 
72  /* unlink it from this users sessions */
73  if(sess->user->sessions == sess)
74  sess->user->sessions = sess->next;
75  else {
76  for(scan = sess->user->sessions; scan != NULL && scan->next != sess; scan = scan->next);
77  if(scan != NULL)
78  scan->next = sess->next;
79  }
80 
81  /* and from global sessions */
82  xhash_zap(sess->user->sm->sessions, sess->sm_id);
83 }
84 
85 void sess_end(sess_t sess) {
86  log_debug(ZONE, "shutting down session %s", jid_full(sess->jid));
87 
88  _sess_end_guts(sess);
89 
90  log_write(sess->user->sm->log, LOG_NOTICE, "session ended: jid=%s", jid_full(sess->jid));
91 
92  /* if it was the last session, free the user */
93  if(sess->user->sessions == NULL) {
94  mm_user_unload(sess->user->sm->mm, sess->user);
95  log_write(sess->user->sm->log, LOG_NOTICE, "user unloaded jid=%s", jid_user(sess->jid));
96  user_free(sess->user);
97  }
98 
99  /* free the session */
100  pool_free(sess->p);
101 }
102 
104  pool_t p;
105  user_t user;
106  sess_t sess, scan;
107  sha1_state_t sha1;
108  char hash[20];
109  int replaced = 0;
110 
111  log_debug(ZONE, "session requested for %s", jid_full(jid));
112 
113  /* check whether it is to serviced domain */
114  if(xhash_get(sm->hosts, jid->domain) == NULL) {
115  log_write(sm->log, LOG_ERR, "request to start session in non-serviced domain: jid=%s", jid_full(jid));
116  return NULL;
117  }
118 
119  /* get user data for this guy */
120  user = user_load(sm, jid);
121 
122  /* unknown user */
123  if(user == NULL) {
124  if(config_get(sm->config, "user.auto-create") == NULL) {
125  log_write(sm->log, LOG_NOTICE, "user not found and user.auto-create not enabled, can't start session: jid=%s", jid_full(jid));
126  return NULL;
127  }
128 
129  log_debug(ZONE, "auto-creating user %s", jid_user(jid));
130 
131  if(user_create(sm, jid) != 0)
132  return NULL;
133 
134  user = user_load(sm, jid);
135  if(user == NULL) {
136  log_write(sm->log, LOG_NOTICE, "couldn't load user, can't start session: jid=%s", jid_full(jid));
137  return NULL;
138  }
139  }
140 
141  /* kill their old session if they have one */
142  for(scan = user->sessions; scan != NULL; scan = scan->next)
143  if(jid_compare_full(scan->jid, jid) == 0) {
144  log_debug(ZONE, "replacing session %s (%s)", jid_full(jid), scan->c2s_id);
145 
146  /* !!! this "replaced" stuff is a hack - its really a subaction of "ended".
147  * hurrah, another control protocol rewrite is needed :(
148  */
149  sm_c2s_action(scan, "replaced", NULL);
150 
151  _sess_end_guts(scan);
152 
153  pool_free(scan->p);
154 
155  replaced = 1;
156 
157  break;
158  }
159 
160  /* make a new session */
161  p = pool_new();
162 
163  sess = (sess_t) pmalloco(p, sizeof(struct sess_st));
164  sess->p = p;
165 
166  /* fill it out */
167  sess->pri = 0;
168  sess->user = user;
169 
170  sess->jid = jid_dup(jid);
171  pool_cleanup(sess->p, (void (*))(void *) jid_free, sess->jid);
172 
173  /* a place for modules to store stuff */
174  sess->module_data = (void **) pmalloco(sess->p, sizeof(void *) * sess->user->sm->mm->nindex);
175 
176  /* add it to the list */
177  sess->next = user->sessions;
178  user->sessions = sess;
179 
180  /* who c2s should address things to */
181  sha1_init(&sha1);
182  datetime_out(time(NULL), dt_DATETIME, sess->sm_id, 41);
183  sha1_append(&sha1, sess->sm_id, strlen(sess->sm_id));
184  sha1_append(&sha1, jid_full(sess->jid), strlen(jid_full(sess->jid)));
185  sha1_finish(&sha1, hash);
186  hex_from_raw(hash, 20, sess->sm_id);
187 
188  log_debug(ZONE, "smid is %s", sess->sm_id);
189 
190  /* remember it */
191  xhash_put(sm->sessions, sess->sm_id, sess);
192 
193  /* inform the modules */
194  /* !!! catch the return value - if its 1, don't let them in */
195  mm_sess_start(sm->mm, sess);
196 
197  if(replaced)
198  log_write(sm->log, LOG_NOTICE, "session replaced: jid=%s", jid_full(sess->jid));
199  else
200  log_write(sm->log, LOG_NOTICE, "session started: jid=%s", jid_full(sess->jid));
201 
202  return sess;
203 }
204 
206 sess_t sess_match(user_t user, char *resource) {
207  sess_t sess;
208 
209  for(sess = user->sessions; sess != NULL; sess = sess->next) {
210  /* exact matches */
211  if(strcmp(sess->jid->resource, resource) == 0)
212  return sess;
213  }
214 
215  return NULL;
216 }