jabberd2  2.3.4
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  unsigned 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, const 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 }
user_t user
user this session belongs to
Definition: sm.h:256
jid_t jid
session jid (user@host/res)
Definition: sm.h:258
static sm_t sm
Definition: main.c:33
void pool_free(pool_t p)
Definition: pool.c:226
struct sess_st * sess_t
Definition: c2s.h:55
data structures and prototypes for the session manager
int nindex
counter for module instance sequence (!!! should be local to mm_new)
Definition: sm.h:370
#define sx_nad_write(s, nad)
Definition: sx.h:166
int pri
current priority of this session
Definition: sm.h:268
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:339
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:347
jid_t rfrom
addressing of enclosing route
Definition: sm.h:134
log_t log
log context
Definition: sm.h:200
void mm_sess_end(mm_t mm, sess_t sess)
session ending
Definition: mm.c:415
config_t config
config context
Definition: sm.h:198
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
jid_t A
list of jids that this session has sent directed presence to
Definition: sm.h:271
mm_t mm
module subsystem
Definition: sm.h:213
xht hosts
vHosts map
Definition: sm.h:224
void sm_c2s_action(sess_t dest, const char *action, const char *target)
send a new action route
Definition: sm.c:280
void ** module_data
per-session module data
Definition: sm.h:274
jid_t rto
Definition: sm.h:134
sm_t sm
sm context
Definition: sm.h:237
SM_API user_t user_load(sm_t sm, jid_t jid)
fetch user data
Definition: user.c:52
char * resource
Definition: jid.h:46
#define pool_new()
Definition: pool.h:97
xht sessions
pointers to all connected sessions (key is random sm id)
Definition: sm.h:191
char c2s_id[44]
remote id (for session control)
Definition: sm.h:263
pool_t p
memory pool this session is allocated off
Definition: sm.h:254
sess_t next
next session (in a list of sessions)
Definition: sm.h:276
void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:375
void pool_cleanup(pool_t p, pool_cleanup_t f, void *arg)
public cleanup utils, insert in a way that they are run FIFO, before mem frees
Definition: pool.c:251
void sess_end(sess_t sess)
Definition: sess.c:85
sess_t sessions
list of action sessions
Definition: sm.h:243
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
sx_t router
SX of router connection.
Definition: sm.h:186
packet summary data wrapper
Definition: sm.h:129
void sha1_init(sha1_state_t *ctx)
Definition: sha1.c:28
void * pmalloco(pool_t p, int size)
easy safety utility (for creating blank mem for structs, etc)
Definition: pool.c:183
nad_t nad
nad of the entire packet
Definition: sm.h:146
session manager global context
Definition: sm.h:167
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
void datetime_out(time_t t, datetime_t type, char *date, int datelen)
Definition: datetime.c:114
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
char * domain
Definition: jid.h:45
char sm_id[41]
local id (for session control)
Definition: sm.h:262
Definition: jid.h:42
sess_t sess_start(sm_t sm, jid_t jid)
Definition: sess.c:103
int jid_compare_full(jid_t a, jid_t b)
compare two full jids
Definition: jid.c:364
void sha1_finish(sha1_state_t *ctx, unsigned char hashout[20])
Definition: sha1.c:65
void xhash_zap(xht h, const char *key)
Definition: xhash.c:235
#define log_debug(...)
Definition: log.h:65
int mm_sess_start(mm_t mm, sess_t sess)
session starting
Definition: mm.c:384
sess_t sess_match(user_t user, const char *resource)
match a session by resource
Definition: sess.c:206
mod_ret_t mm_in_sess(mm_t mm, sess_t sess, pkt_t pkt)
packets from active session
Definition: mm.c:441
void hex_from_raw(const unsigned char *in, int inlen, char *out)
turn raw into hex - out must be (inlen*2)+1
Definition: hex.c:26
config_elem_t config_get(config_t c, const char *key)
get the config element for this key
Definition: config.c:271
SM_API void user_free(user_t user)
Definition: user.c:80
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
int available
true if this session is available
Definition: sm.h:267
static void _sess_end_guts(sess_t sess)
Definition: sess.c:62
jid_t to
Definition: sm.h:140
void sha1_append(sha1_state_t *ctx, const unsigned char *dataIn, int len)
Definition: sha1.c:47
jid_t jid_dup(jid_t jid)
duplicate a jid
Definition: jid.c:373
jid_t jid
user jid (user@host)
Definition: sm.h:239
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define ZONE
Definition: mio_impl.h:76
c2s_t c2s
Definition: c2s.h:75
int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix)
declare a namespace on an already-existing element
Definition: nad.c:770
pool - base node for a pool.
Definition: pool.h:80
#define uri_SESSION
Definition: uri.h:53
pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from)
Definition: pkt.c:328
int mm_user_unload(mm_t mm, user_t user)
user data is about to be unloaded
Definition: mm.c:690
void sess_route(sess_t sess, pkt_t pkt)
send a packet to the client for this session
Definition: sess.c:31
SM_API int user_create(sm_t sm, jid_t jid)
initialise a user
Definition: user.c:88
data for a single user
Definition: sm.h:234