jabberd2
2.2.17
Main Page
Data Structures
Files
File List
Globals
sm
mod_session.c
Go to the documentation of this file.
1
/*
2
* jabberd - Jabber Open Source Server
3
* Copyright (c) 2002-2003 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
45
/* union for xhash_iter_get to comply with strict-alias rules for gcc3 */
46
union
xhashv
47
{
48
void
**
val
;
49
sess_t
*
sess_val
;
50
};
51
52
static
mod_ret_t
_session_in_router
(
mod_instance_t
mi,
pkt_t
pkt) {
53
sm_t
sm
= mi->
mod
->
mm
->
sm
;
54
int
ns, iq, elem, attr;
55
jid_t
jid;
56
sess_t
sess = (
sess_t
) NULL;
57
mod_ret_t
ret;
58
59
/* if we've got this namespace, its from a c2s */
60
if
(pkt->
nad
->
ecur
<= 1 || (ns =
nad_find_namespace
(pkt->
nad
, 1,
uri_SESSION
, NULL)) < 0)
61
return
mod_PASS
;
62
63
/* don't bother if its a failure */
64
if
(pkt->
type
&
pkt_SESS_FAILED
) {
65
/* !!! check failed=1, handle */
66
pkt_free
(pkt);
67
return
mod_HANDLED
;
68
}
69
70
/* session commands */
71
if
(pkt->
type
&
pkt_SESS
) {
72
73
ns =
nad_find_namespace
(pkt->
nad
, 1,
uri_SESSION
, NULL);
74
75
/* only end can get away without a target */
76
attr =
nad_find_attr
(pkt->
nad
, 1, -1,
"target"
, NULL);
77
if
(attr < 0 && pkt->type !=
pkt_SESS_END
) {
78
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
79
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
80
81
pkt->
nad
= NULL;
82
pkt_free
(pkt);
83
84
return
mod_HANDLED
;
85
}
86
87
/* session start */
88
if
(pkt->
type
==
pkt_SESS
) {
89
jid =
jid_new
(
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr));
90
91
if
(jid != NULL)
92
sess =
sess_start
(sm, jid);
93
94
if
(jid == NULL || sess == NULL) {
95
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
96
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
97
98
pkt->
nad
= NULL;
99
pkt_free
(pkt);
100
if
(jid != NULL)
101
jid_free
(jid);
102
103
return
mod_HANDLED
;
104
}
105
106
/* c2s component that is handling this session */
107
strcpy(sess->
c2s
, pkt->
rfrom
->
domain
);
108
109
/* remember what c2s calls us */
110
attr =
nad_find_attr
(pkt->
nad
, 1, ns,
"c2s"
, NULL);
111
snprintf(sess->
c2s_id
,
sizeof
(sess->
c2s_id
),
"%.*s"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
112
113
/* mark PBX session as fake */
114
if
(!strncmp(
"PBX"
, sess->
c2s_id
, 3)) {
115
sess->
fake
= 1;
116
}
117
118
/* add our id */
119
nad_set_attr
(pkt->
nad
, 1, ns,
"sm"
, sess->
sm_id
, 0);
120
121
/* mark that it started OK */
122
nad_set_attr
(pkt->
nad
, 1, -1,
"action"
,
"started"
, 7);
123
124
/* set this SM name */
125
nad_set_attr
(pkt->
nad
, 0, -1,
"to"
, sm->
id
, 0);
126
127
/* inform c2s */
128
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
129
130
pkt->
nad
= NULL;
131
pkt_free
(pkt);
132
jid_free
(jid);
133
134
return
mod_HANDLED
;
135
}
136
137
/* user create */
138
if
(pkt->
type
==
pkt_SESS_CREATE
) {
139
jid =
jid_new
(
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr));
140
141
if
(jid == NULL ||
user_create
(sm, jid) != 0) {
142
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
143
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
144
145
pkt->
nad
= NULL;
146
pkt_free
(pkt);
147
if
(jid != NULL)
148
jid_free
(jid);
149
150
return
mod_HANDLED
;
151
}
152
153
/* inform c2s */
154
nad_set_attr
(pkt->
nad
, 1, -1,
"action"
,
"created"
, 7);
155
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
156
157
pkt->
nad
= NULL;
158
pkt_free
(pkt);
159
jid_free
(jid);
160
161
return
mod_HANDLED
;
162
}
163
164
/* user delete */
165
if
(pkt->
type
==
pkt_SESS_DELETE
) {
166
jid =
jid_new
(
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr));
167
if
(jid == NULL) {
168
pkt_free
(pkt);
169
return
mod_HANDLED
;
170
}
171
172
user_delete
(sm, jid);
173
174
/* inform c2s */
175
nad_set_attr
(pkt->
nad
, 1, -1,
"action"
,
"deleted"
, 7);
176
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
177
178
pkt->
nad
= NULL;
179
pkt_free
(pkt);
180
jid_free
(jid);
181
182
return
mod_HANDLED
;
183
}
184
185
/* get the session id */
186
attr =
nad_find_attr
(pkt->
nad
, 1, ns,
"sm"
, NULL);
187
if
(attr < 0) {
188
log_debug
(
ZONE
,
"no session id, bouncing"
);
189
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
190
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
191
192
pkt->
nad
= NULL;
193
pkt_free
(pkt);
194
195
return
mod_HANDLED
;
196
}
197
198
/* find the corresponding session */
199
sess =
xhash_getx
(sm->
sessions
,
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr));
200
201
/* active check */
202
if
(sess == NULL) {
203
log_debug
(
ZONE
,
"session %.*s doesn't exist, bouncing"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
204
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
205
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
206
207
pkt->
nad
= NULL;
208
pkt_free
(pkt);
209
210
return
mod_HANDLED
;
211
}
212
213
/* make sure its from them */
214
attr =
nad_find_attr
(pkt->
nad
, 1, ns,
"c2s"
, NULL);
215
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)) {
216
log_debug
(
ZONE
,
"invalid sender on route from %s for session %s (should be %s)"
, pkt->
rfrom
->
domain
, sess->
sm_id
, sess->
c2s_id
);
217
pkt_free
(pkt);
218
return
mod_HANDLED
;
219
}
220
221
/* session end */
222
if
(pkt->
type
==
pkt_SESS_END
) {
223
sm_c2s_action
(sess,
"ended"
, NULL);
224
sess_end
(sess);
225
226
pkt_free
(pkt);
227
return
mod_HANDLED
;
228
}
229
230
log_debug
(
ZONE
,
"unknown session packet, dropping"
);
231
pkt_free
(pkt);
232
233
return
mod_HANDLED
;
234
}
235
236
/* otherwise, its a normal packet for the session */
237
238
/* #ifdef ENABLE_SUPERSEDED // FIXME XXX TODO clients are not yet ready for this */
239
/* check for RFC3920 session request *
240
* with RFC3920bis it is unneeded *
241
* session is activated by bind, so we just return back result */
242
if
((ns =
nad_find_scoped_namespace
(pkt->
nad
,
uri_XSESSION
, NULL)) >= 0 &&
243
(iq =
nad_find_elem
(pkt->
nad
, 0, -1,
"iq"
, 1)) >= 0 &&
244
(elem =
nad_find_elem
(pkt->
nad
, iq, ns,
"session"
, 1)) >= 0) {
245
log_debug
(
ZONE
,
"session create request"
);
246
247
/* build a result packet */
248
nad_drop_elem
(pkt->
nad
, elem);
249
nad_set_attr
(pkt->
nad
, iq, -1,
"type"
,
"result"
, 6);
250
251
/* return the result */
252
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
253
254
pkt->
nad
= NULL;
255
pkt_free
(pkt);
256
257
return
mod_HANDLED
;
258
}
259
/* #endif */
260
/* get the session id */
261
attr =
nad_find_attr
(pkt->
nad
, 1, ns,
"sm"
, NULL);
262
if
(attr < 0) {
263
log_debug
(
ZONE
,
"no session id, bouncing"
);
264
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
265
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
266
267
pkt->
nad
= NULL;
268
pkt_free
(pkt);
269
270
return
mod_HANDLED
;
271
}
272
273
/* find the corresponding session */
274
sess =
xhash_getx
(sm->
sessions
,
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr));
275
276
/* active check */
277
if
(sess == NULL) {
278
log_debug
(
ZONE
,
"session %.*s doesn't exist, bouncing"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
279
nad_set_attr
(pkt->
nad
, 1, ns,
"failed"
,
"1"
, 1);
280
sx_nad_write
(sm->
router
,
stanza_tofrom
(pkt->
nad
, 0));
281
282
pkt->
nad
= NULL;
283
pkt_free
(pkt);
284
285
return
mod_HANDLED
;
286
}
287
288
/* make sure its from them */
289
attr =
nad_find_attr
(pkt->
nad
, 1, ns,
"c2s"
, NULL);
290
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)) {
291
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
);
292
pkt_free
(pkt);
293
return
mod_HANDLED
;
294
}
295
296
/* where it came from */
297
pkt->
source
= sess;
298
299
/* hand it to the modules */
300
ret =
mm_in_sess
(pkt->
sm
->
mm
, sess, pkt);
301
switch
(ret) {
302
case
mod_HANDLED
:
303
break
;
304
305
case
mod_PASS
:
306
/* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
307
if
(pkt->
type
==
pkt_IQ_RESULT
)
308
break
;
309
else
310
ret = -
stanza_err_FEATURE_NOT_IMPLEMENTED
;
311
312
default
:
313
pkt_sess
(
pkt_error
(pkt, -ret), sess);
314
315
break
;
316
}
317
318
return
mod_HANDLED
;
319
}
320
321
static
mod_ret_t
_session_pkt_router
(
mod_instance_t
mi,
pkt_t
pkt) {
322
sess_t
sess;
323
union
xhashv
xhv;
324
325
/* we want unadvertisments */
326
if
(pkt->
from
== NULL || !(pkt->
rtype
&
route_ADV
) || pkt->
rtype
!=
route_ADV_UN
)
327
return
mod_PASS
;
328
329
log_debug
(
ZONE
,
"component '%s' went offline, checking for sessions held there"
,
jid_full
(pkt->
from
));
330
331
/* this is fairly inefficient, especially if we have a lot of sessions
332
* online, but it shouldn't be called that often (components are usually
333
* long-running) */
334
335
xhv.
sess_val
= &sess;
336
if
(
xhash_iter_first
(mi->
mod
->
mm
->
sm
->
sessions
))
337
do
{
338
xhash_iter_get
(mi->
mod
->
mm
->
sm
->
sessions
, NULL, NULL, xhv.
val
);
339
if
(sess && strcmp(sess->
c2s
, pkt->
from
->
domain
) == 0)
340
sess_end
(sess);
341
}
while
(
xhash_iter_next
(mi->
mod
->
mm
->
sm
->
sessions
));
342
343
return
mod_PASS
;
344
}
345
346
DLLEXPORT
int
module_init
(
mod_instance_t
mi,
char
*arg) {
347
if
(mi->
mod
->
init
)
return
0;
348
349
mi->
mod
->
in_router
=
_session_in_router
;
350
mi->
mod
->
pkt_router
=
_session_pkt_router
;
351
352
return
0;
353
}
Generated by
1.8.1.1