blob: eb932655a8a66f4ef847f56146dcd89b66b52954 [file] [log] [blame]
Benny Prijono26ff9062006-02-21 23:47:00 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono26ff9062006-02-21 23:47:00 +00005 *
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, MA 02111-1307 USA
19 */
20#include <pjsip-ua/sip_xfer.h>
21#include <pjsip-simple/evsub_msg.h>
22#include <pjsip/sip_dialog.h>
23#include <pjsip/sip_errno.h>
24#include <pjsip/sip_endpoint.h>
25#include <pjsip/sip_module.h>
26#include <pjsip/sip_transport.h>
27#include <pj/assert.h>
28#include <pj/pool.h>
29#include <pj/string.h>
30
Benny Prijono19eeb6e2009-06-04 22:16:47 +000031/* Subscription expiration */
32#ifndef PJSIP_XFER_EXPIRES
33# define PJSIP_XFER_EXPIRES 600
34#endif
35
Benny Prijono26ff9062006-02-21 23:47:00 +000036
37/*
38 * Refer module (mod-refer)
39 */
40static struct pjsip_module mod_xfer =
41{
Benny Prijono2f8992b2006-02-25 21:16:36 +000042 NULL, NULL, /* prev, next. */
43 { "mod-refer", 9 }, /* Name. */
44 -1, /* Id */
45 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
46 NULL, /* load() */
47 NULL, /* start() */
48 NULL, /* stop() */
49 NULL, /* unload() */
50 NULL, /* on_rx_request() */
51 NULL, /* on_rx_response() */
52 NULL, /* on_tx_request. */
53 NULL, /* on_tx_response() */
54 NULL, /* on_tsx_state() */
Benny Prijono26ff9062006-02-21 23:47:00 +000055};
56
57
58/* Declare PJSIP_REFER_METHOD, so that if somebody declares this in
59 * sip_msg.h we can catch the error here.
60 */
61enum
62{
63 PJSIP_REFER_METHOD = PJSIP_OTHER_METHOD
64};
65
Benny Prijono1f61a8f2007-08-16 10:11:44 +000066PJ_DEF_DATA(const pjsip_method) pjsip_refer_method = {
Benny Prijonoba5926a2007-05-02 11:29:37 +000067 (pjsip_method_e) PJSIP_REFER_METHOD,
Benny Prijono26ff9062006-02-21 23:47:00 +000068 { "REFER", 5}
69};
70
Benny Prijono1f61a8f2007-08-16 10:11:44 +000071PJ_DEF(const pjsip_method*) pjsip_get_refer_method()
72{
73 return &pjsip_refer_method;
74}
Benny Prijono26ff9062006-02-21 23:47:00 +000075
76/*
77 * String constants
78 */
79const pj_str_t STR_REFER = { "refer", 5 };
80const pj_str_t STR_MESSAGE = { "message", 7 };
81const pj_str_t STR_SIPFRAG = { "sipfrag", 7 };
82const pj_str_t STR_SIPFRAG_VERSION = {";version=2.0", 12 };
83
84
85/*
86 * Transfer struct.
87 */
88struct pjsip_xfer
89{
90 pjsip_evsub *sub; /**< Event subscribtion record. */
91 pjsip_dialog *dlg; /**< The dialog. */
92 pjsip_evsub_user user_cb; /**< The user callback. */
93 pj_str_t refer_to_uri; /**< The full Refer-To URI. */
94 int last_st_code; /**< st_code sent in last NOTIFY */
95 pj_str_t last_st_text; /**< st_text sent in last NOTIFY */
96};
97
98
99typedef struct pjsip_xfer pjsip_xfer;
100
101
102
103/*
104 * Forward decl for evsub callback.
105 */
106static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
107static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
108 pjsip_event *event);
109static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
110 pjsip_rx_data *rdata,
111 int *p_st_code,
112 pj_str_t **p_st_text,
113 pjsip_hdr *res_hdr,
114 pjsip_msg_body **p_body);
115static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
116 pjsip_rx_data *rdata,
117 int *p_st_code,
118 pj_str_t **p_st_text,
119 pjsip_hdr *res_hdr,
120 pjsip_msg_body **p_body);
121static void xfer_on_evsub_client_refresh(pjsip_evsub *sub);
122static void xfer_on_evsub_server_timeout(pjsip_evsub *sub);
123
124
125/*
126 * Event subscription callback for xference.
127 */
128static pjsip_evsub_user xfer_user =
129{
130 &xfer_on_evsub_state,
131 &xfer_on_evsub_tsx_state,
132 &xfer_on_evsub_rx_refresh,
133 &xfer_on_evsub_rx_notify,
134 &xfer_on_evsub_client_refresh,
135 &xfer_on_evsub_server_timeout,
136};
137
138
139
140
141/*
142 * Initialize the REFER subsystem.
143 */
144PJ_DEF(pj_status_t) pjsip_xfer_init_module(pjsip_endpoint *endpt)
145{
146 const pj_str_t accept = { "message/sipfrag;version=2.0", 27 };
147 pj_status_t status;
148
149 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
150 PJ_ASSERT_RETURN(mod_xfer.id == -1, PJ_EINVALIDOP);
151
152 status = pjsip_endpt_register_module(endpt, &mod_xfer);
153 if (status != PJ_SUCCESS)
154 return status;
155
156 status = pjsip_endpt_add_capability( endpt, &mod_xfer, PJSIP_H_ALLOW,
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000157 NULL, 1,
158 &pjsip_get_refer_method()->name);
Benny Prijono26ff9062006-02-21 23:47:00 +0000159 if (status != PJ_SUCCESS)
160 return status;
161
Benny Prijono19eeb6e2009-06-04 22:16:47 +0000162 status = pjsip_evsub_register_pkg(&mod_xfer, &STR_REFER,
163 PJSIP_XFER_EXPIRES, 1, &accept);
Benny Prijono26ff9062006-02-21 23:47:00 +0000164 if (status != PJ_SUCCESS)
165 return status;
166
167 return PJ_SUCCESS;
168}
169
170
171/*
172 * Create transferer (sender of REFER request).
173 *
174 */
175PJ_DEF(pj_status_t) pjsip_xfer_create_uac( pjsip_dialog *dlg,
176 const pjsip_evsub_user *user_cb,
177 pjsip_evsub **p_evsub )
178{
179 pj_status_t status;
180 pjsip_xfer *xfer;
181 pjsip_evsub *sub;
182
183 PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);
184
185 pjsip_dlg_inc_lock(dlg);
186
187 /* Create event subscription */
188 status = pjsip_evsub_create_uac( dlg, &xfer_user, &STR_REFER,
189 PJSIP_EVSUB_NO_EVENT_ID, &sub);
190 if (status != PJ_SUCCESS)
191 goto on_return;
192
193 /* Create xfer session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000194 xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000195 xfer->dlg = dlg;
196 xfer->sub = sub;
197 if (user_cb)
198 pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
199
200 /* Attach to evsub */
201 pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
202
203 *p_evsub = sub;
204
205on_return:
206 pjsip_dlg_dec_lock(dlg);
207 return status;
208
209}
210
211
212
213
214/*
215 * Create transferee (receiver of REFER request).
216 *
217 */
218PJ_DEF(pj_status_t) pjsip_xfer_create_uas( pjsip_dialog *dlg,
219 const pjsip_evsub_user *user_cb,
220 pjsip_rx_data *rdata,
221 pjsip_evsub **p_evsub )
222{
223 pjsip_evsub *sub;
224 pjsip_xfer *xfer;
225 const pj_str_t STR_EVENT = {"Event", 5 };
226 pjsip_event_hdr *event_hdr;
227 pj_status_t status;
228
229 /* Check arguments */
230 PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
231
232 /* Must be request message */
233 PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
234 PJSIP_ENOTREQUESTMSG);
235
236 /* Check that request is REFER */
237 PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000238 pjsip_get_refer_method())==0,
Benny Prijono26ff9062006-02-21 23:47:00 +0000239 PJSIP_ENOTREFER);
240
241 /* Lock dialog */
242 pjsip_dlg_inc_lock(dlg);
243
244 /* The evsub framework expects an Event header in the request,
245 * while a REFER request conveniently doesn't have one (pun intended!).
246 * So create a dummy Event header.
247 */
248 if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
249 &STR_EVENT, NULL)==NULL)
250 {
251 event_hdr = pjsip_event_hdr_create(rdata->tp_info.pool);
252 event_hdr->event_type = STR_REFER;
253 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr*)event_hdr);
254 }
255
256 /* Create server subscription */
257 status = pjsip_evsub_create_uas( dlg, &xfer_user, rdata,
258 PJSIP_EVSUB_NO_EVENT_ID, &sub);
259 if (status != PJ_SUCCESS)
260 goto on_return;
261
262 /* Create server xfer subscription */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000263 xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
Benny Prijono26ff9062006-02-21 23:47:00 +0000264 xfer->dlg = dlg;
265 xfer->sub = sub;
266 if (user_cb)
267 pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
268
269 /* Attach to evsub */
270 pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
271
272 /* Done: */
273 *p_evsub = sub;
274
275on_return:
276 pjsip_dlg_dec_lock(dlg);
277 return status;
278}
279
280
281
282/*
283 * Call this function to create request to initiate REFER subscription.
284 *
285 */
286PJ_DEF(pj_status_t) pjsip_xfer_initiate( pjsip_evsub *sub,
287 const pj_str_t *refer_to_uri,
288 pjsip_tx_data **p_tdata)
289{
290 pjsip_xfer *xfer;
291 const pj_str_t refer_to = { "Refer-To", 8};
292 pjsip_tx_data *tdata;
293 pjsip_generic_string_hdr *hdr;
294 pj_status_t status;
295
296 /* sub and p_tdata argument must be valid. */
297 PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);
298
299
300 /* Get the xfer object. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000301 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000302 PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
303
304 /* refer_to_uri argument MAY be NULL for subsequent REFER requests,
305 * but it MUST be specified in the first REFER.
306 */
307 PJ_ASSERT_RETURN((refer_to_uri || xfer->refer_to_uri.slen), PJ_EINVAL);
308
309 /* Lock dialog. */
310 pjsip_dlg_inc_lock(xfer->dlg);
311
312 /* Create basic REFER request */
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000313 status = pjsip_evsub_initiate(sub, pjsip_get_refer_method(), -1,
Benny Prijono26ff9062006-02-21 23:47:00 +0000314 &tdata);
315 if (status != PJ_SUCCESS)
316 goto on_return;
317
318 /* Save Refer-To URI. */
319 if (refer_to_uri == NULL) {
320 refer_to_uri = &xfer->refer_to_uri;
321 } else {
322 pj_strdup(xfer->dlg->pool, &xfer->refer_to_uri, refer_to_uri);
323 }
324
325 /* Create and add Refer-To header. */
326 hdr = pjsip_generic_string_hdr_create(tdata->pool, &refer_to,
327 refer_to_uri);
328 if (!hdr) {
329 pjsip_tx_data_dec_ref(tdata);
330 status = PJ_ENOMEM;
331 goto on_return;
332 }
333
334 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
335
336
337 /* Done. */
338 *p_tdata = tdata;
339
340 status = PJ_SUCCESS;
341
342on_return:
343 pjsip_dlg_dec_lock(xfer->dlg);
344 return status;
345}
346
347
348/*
349 * Accept the incoming REFER request by sending 2xx response.
350 *
351 */
352PJ_DEF(pj_status_t) pjsip_xfer_accept( pjsip_evsub *sub,
353 pjsip_rx_data *rdata,
354 int st_code,
355 const pjsip_hdr *hdr_list )
356{
357 /*
358 * Don't need to add custom headers, so just call basic
359 * evsub response.
360 */
361 return pjsip_evsub_accept( sub, rdata, st_code, hdr_list );
362}
363
364
365/*
366 * For notifier, create NOTIFY request to subscriber, and set the state
367 * of the subscription.
368 */
369PJ_DEF(pj_status_t) pjsip_xfer_notify( pjsip_evsub *sub,
370 pjsip_evsub_state state,
371 int xfer_st_code,
372 const pj_str_t *xfer_st_text,
373 pjsip_tx_data **p_tdata)
374{
375 pjsip_tx_data *tdata;
376 pjsip_xfer *xfer;
377 const pj_str_t reason = { "noresource", 10 };
378 char *body;
379 int bodylen;
380 pjsip_msg_body *msg_body;
381 pj_status_t status;
382
383
384 /* Check arguments. */
385 PJ_ASSERT_RETURN(sub, PJ_EINVAL);
386
387 /* Get the xfer object. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000388 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000389 PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
390
391
392 /* Lock object. */
393 pjsip_dlg_inc_lock(xfer->dlg);
394
395 /* Create the NOTIFY request.
396 * Note that reason is only used when state is TERMINATED, and
397 * the defined termination reason for REFER is "noresource".
398 */
399 status = pjsip_evsub_notify( sub, state, NULL, &reason, &tdata);
400 if (status != PJ_SUCCESS)
401 goto on_return;
402
403
404 /* Check status text */
405 if (xfer_st_text==NULL || xfer_st_text->slen==0)
406 xfer_st_text = pjsip_get_status_text(xfer_st_code);
407
408 /* Save st_code and st_text, for current_notify() */
409 xfer->last_st_code = xfer_st_code;
410 pj_strdup(xfer->dlg->pool, &xfer->last_st_text, xfer_st_text);
411
412 /* Create sipfrag content. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000413 body = (char*) pj_pool_alloc(tdata->pool, 128);
Benny Prijono48374a22008-04-17 20:54:22 +0000414 bodylen = pj_ansi_snprintf(body, 128, "SIP/2.0 %u %.*s\r\n",
Benny Prijono26ff9062006-02-21 23:47:00 +0000415 xfer_st_code,
416 (int)xfer_st_text->slen,
417 xfer_st_text->ptr);
418 PJ_ASSERT_ON_FAIL(bodylen > 0 && bodylen < 128,
419 {status=PJ_EBUG; pjsip_tx_data_dec_ref(tdata);
420 goto on_return; });
421
422
423 /* Create SIP message body. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000424 msg_body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
Benny Prijono26ff9062006-02-21 23:47:00 +0000425 msg_body->content_type.type = STR_MESSAGE;
426 msg_body->content_type.subtype = STR_SIPFRAG;
427 msg_body->content_type.param = STR_SIPFRAG_VERSION;
428 msg_body->data = body;
429 msg_body->len = bodylen;
430 msg_body->print_body = &pjsip_print_text_body;
431 msg_body->clone_data = &pjsip_clone_text_data;
432
433 /* Attach sipfrag body. */
434 tdata->msg->body = msg_body;
435
436
437 /* Done. */
438 *p_tdata = tdata;
439
440
441on_return:
442 pjsip_dlg_dec_lock(xfer->dlg);
443 return status;
444
445}
446
447
448/*
449 * Send current state and the last sipfrag body.
450 */
451PJ_DEF(pj_status_t) pjsip_xfer_current_notify( pjsip_evsub *sub,
452 pjsip_tx_data **p_tdata )
453{
454 pjsip_xfer *xfer;
455 pj_status_t status;
456
457
458 /* Check arguments. */
459 PJ_ASSERT_RETURN(sub, PJ_EINVAL);
460
461 /* Get the xfer object. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000462 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000463 PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
464
465 pjsip_dlg_inc_lock(xfer->dlg);
466
467 status = pjsip_xfer_notify(sub, pjsip_evsub_get_state(sub),
468 xfer->last_st_code, &xfer->last_st_text,
469 p_tdata);
470
471 pjsip_dlg_dec_lock(xfer->dlg);
472
473 return status;
474}
475
476
477/*
478 * Send request message.
479 */
480PJ_DEF(pj_status_t) pjsip_xfer_send_request( pjsip_evsub *sub,
481 pjsip_tx_data *tdata)
482{
483 return pjsip_evsub_send_request(sub, tdata);
484}
485
486
487/*
488 * This callback is called by event subscription when subscription
489 * state has changed.
490 */
491static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
492{
493 pjsip_xfer *xfer;
494
Benny Prijonoa1e69682007-05-11 15:14:34 +0000495 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000496 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
497
498 if (xfer->user_cb.on_evsub_state)
499 (*xfer->user_cb.on_evsub_state)(sub, event);
500
501}
502
503/*
504 * Called when transaction state has changed.
505 */
506static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
507 pjsip_event *event)
508{
509 pjsip_xfer *xfer;
510
Benny Prijonoa1e69682007-05-11 15:14:34 +0000511 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000512 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
513
514 if (xfer->user_cb.on_tsx_state)
515 (*xfer->user_cb.on_tsx_state)(sub, tsx, event);
516}
517
518/*
519 * Called when REFER is received to refresh subscription.
520 */
521static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
522 pjsip_rx_data *rdata,
523 int *p_st_code,
524 pj_str_t **p_st_text,
525 pjsip_hdr *res_hdr,
526 pjsip_msg_body **p_body)
527{
528 pjsip_xfer *xfer;
529
Benny Prijonoa1e69682007-05-11 15:14:34 +0000530 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000531 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
532
533 if (xfer->user_cb.on_rx_refresh) {
534 (*xfer->user_cb.on_rx_refresh)(sub, rdata, p_st_code, p_st_text,
535 res_hdr, p_body);
536
537 } else {
538 /* Implementors MUST send NOTIFY if it implements on_rx_refresh
539 * (implementor == "us" from evsub point of view.
540 */
541 pjsip_tx_data *tdata;
542 pj_status_t status;
543
544 if (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED) {
545 status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
546 xfer->last_st_code,
547 &xfer->last_st_text,
548 &tdata);
549 } else {
550 status = pjsip_xfer_current_notify(sub, &tdata);
551 }
552
553 if (status == PJ_SUCCESS)
554 pjsip_xfer_send_request(sub, tdata);
555 }
556}
557
558
559/*
560 * Called when NOTIFY is received.
561 */
562static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
563 pjsip_rx_data *rdata,
564 int *p_st_code,
565 pj_str_t **p_st_text,
566 pjsip_hdr *res_hdr,
567 pjsip_msg_body **p_body)
568{
569 pjsip_xfer *xfer;
570
Benny Prijonoa1e69682007-05-11 15:14:34 +0000571 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000572 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
573
574 if (xfer->user_cb.on_rx_notify)
575 (*xfer->user_cb.on_rx_notify)(sub, rdata, p_st_code, p_st_text,
576 res_hdr, p_body);
577}
578
579/*
580 * Called when it's time to send SUBSCRIBE.
581 */
582static void xfer_on_evsub_client_refresh(pjsip_evsub *sub)
583{
584 pjsip_xfer *xfer;
585
Benny Prijonoa1e69682007-05-11 15:14:34 +0000586 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000587 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
588
589 if (xfer->user_cb.on_client_refresh) {
590 (*xfer->user_cb.on_client_refresh)(sub);
591 } else {
592 pj_status_t status;
593 pjsip_tx_data *tdata;
594
Benny Prijono19eeb6e2009-06-04 22:16:47 +0000595 status = pjsip_evsub_initiate(sub, NULL, PJSIP_XFER_EXPIRES, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +0000596 if (status == PJ_SUCCESS)
597 pjsip_xfer_send_request(sub, tdata);
598 }
599}
600
601
602/*
603 * Called when no refresh is received after the interval.
604 */
605static void xfer_on_evsub_server_timeout(pjsip_evsub *sub)
606{
607 pjsip_xfer *xfer;
608
Benny Prijonoa1e69682007-05-11 15:14:34 +0000609 xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
Benny Prijono26ff9062006-02-21 23:47:00 +0000610 PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
611
612 if (xfer->user_cb.on_server_timeout) {
613 (*xfer->user_cb.on_server_timeout)(sub);
614 } else {
615 pj_status_t status;
616 pjsip_tx_data *tdata;
617
618 status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
619 xfer->last_st_code,
620 &xfer->last_st_text, &tdata);
621 if (status == PJ_SUCCESS)
622 pjsip_xfer_send_request(sub, tdata);
623 }
624}
625