sip_timer.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /*
  2. * Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include <pjsip-ua/sip_timer.h>
  19. #include <pjsip/print_util.h>
  20. #include <pjsip/sip_endpoint.h>
  21. #include <pjsip/sip_event.h>
  22. #include <pjsip/sip_transaction.h>
  23. #include <pj/log.h>
  24. #include <pj/math.h>
  25. #include <pj/os.h>
  26. #include <pj/pool.h>
  27. #define THIS_FILE "sip_timer.c"
  28. /* Constant of Session Timers */
  29. #define ABS_MIN_SE 90 /* Absolute Min-SE, in seconds */
  30. #define REFRESHER_EXPIRE_TIMER_ID 2 /* Refresher expire timer id */
  31. /* String definitions */
  32. static const pj_str_t STR_SE = {"Session-Expires", 15};
  33. static const pj_str_t STR_SHORT_SE = {"x", 1};
  34. static const pj_str_t STR_MIN_SE = {"Min-SE", 6};
  35. static const pj_str_t STR_REFRESHER = {"refresher", 9};
  36. static const pj_str_t STR_UAC = {"uac", 3};
  37. static const pj_str_t STR_UAS = {"uas", 3};
  38. static const pj_str_t STR_TIMER = {"timer", 5};
  39. /* Enumeration of refresher */
  40. enum timer_refresher {
  41. TR_UNKNOWN,
  42. TR_UAC,
  43. TR_UAS
  44. };
  45. /* Structure definition of Session Timers */
  46. struct pjsip_timer
  47. {
  48. pj_bool_t active; /**< Active/inactive flag */
  49. pjsip_timer_setting setting; /**< Session Timers setting */
  50. enum timer_refresher refresher; /**< Session refresher */
  51. pj_time_val last_refresh; /**< Timestamp of last
  52. refresh */
  53. pj_timer_entry timer; /**< Timer entry */
  54. pj_bool_t use_update; /**< Use UPDATE method to
  55. refresh the session */
  56. pj_bool_t with_sdp; /**< SDP in UPDATE? */
  57. pjsip_role_e role; /**< Role in last INVITE/
  58. UPDATE transaction. */
  59. void *refresh_tdata; /**< The tdata of refresh
  60. request */
  61. pj_timer_entry expire_timer; /**< Timer entry for expire
  62. refresher */
  63. pj_int32_t last_422_cseq; /**< Last 422 resp CSeq. */
  64. };
  65. /* Local functions & vars */
  66. static void stop_timer(pjsip_inv_session *inv);
  67. static void start_timer(pjsip_inv_session *inv);
  68. static pj_bool_t is_initialized;
  69. const pjsip_method pjsip_update_method = { PJSIP_OTHER_METHOD, {"UPDATE", 6}};
  70. /*
  71. * Session-Expires header vptr.
  72. */
  73. static int se_hdr_print(pjsip_sess_expires_hdr *hdr,
  74. char *buf, pj_size_t size);
  75. static pjsip_sess_expires_hdr* se_hdr_clone(pj_pool_t *pool,
  76. const pjsip_sess_expires_hdr *hdr);
  77. static pjsip_sess_expires_hdr* se_hdr_shallow_clone(
  78. pj_pool_t *pool,
  79. const pjsip_sess_expires_hdr* hdr);
  80. static pjsip_hdr_vptr se_hdr_vptr =
  81. {
  82. (pjsip_hdr_clone_fptr) &se_hdr_clone,
  83. (pjsip_hdr_clone_fptr) &se_hdr_shallow_clone,
  84. (pjsip_hdr_print_fptr) &se_hdr_print,
  85. };
  86. /*
  87. * Min-SE header vptr.
  88. */
  89. static int min_se_hdr_print(pjsip_min_se_hdr *hdr,
  90. char *buf, pj_size_t size);
  91. static pjsip_min_se_hdr* min_se_hdr_clone(pj_pool_t *pool,
  92. const pjsip_min_se_hdr *hdr);
  93. static pjsip_min_se_hdr* min_se_hdr_shallow_clone(
  94. pj_pool_t *pool,
  95. const pjsip_min_se_hdr* hdr);
  96. static pjsip_hdr_vptr min_se_hdr_vptr =
  97. {
  98. (pjsip_hdr_clone_fptr) &min_se_hdr_clone,
  99. (pjsip_hdr_clone_fptr) &min_se_hdr_shallow_clone,
  100. (pjsip_hdr_print_fptr) &min_se_hdr_print,
  101. };
  102. /*
  103. * Session-Expires header vptr.
  104. */
  105. static int se_hdr_print(pjsip_sess_expires_hdr *hdr,
  106. char *buf, pj_size_t size)
  107. {
  108. char *p = buf;
  109. char *endbuf = buf+size;
  110. pj_ssize_t printed;
  111. const pjsip_parser_const_t *pc = pjsip_parser_const();
  112. const pj_str_t *hname = pjsip_cfg()->endpt.use_compact_form?
  113. &hdr->sname : &hdr->name;
  114. /* Print header name and value */
  115. if ((endbuf - p) < (hname->slen + 16))
  116. return -1;
  117. copy_advance(p, (*hname));
  118. *p++ = ':';
  119. *p++ = ' ';
  120. printed = pj_utoa(hdr->sess_expires, p);
  121. p += printed;
  122. /* Print 'refresher' param */
  123. if (hdr->refresher.slen)
  124. {
  125. if ((endbuf - p) < (STR_REFRESHER.slen + 2 + hdr->refresher.slen))
  126. return -1;
  127. *p++ = ';';
  128. copy_advance(p, STR_REFRESHER);
  129. *p++ = '=';
  130. copy_advance(p, hdr->refresher);
  131. }
  132. /* Print generic params */
  133. printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
  134. &pc->pjsip_TOKEN_SPEC,
  135. &pc->pjsip_TOKEN_SPEC, ';');
  136. if (printed < 0)
  137. return (int)printed;
  138. p += printed;
  139. return (int)(p - buf);
  140. }
  141. static pjsip_sess_expires_hdr* se_hdr_clone(pj_pool_t *pool,
  142. const pjsip_sess_expires_hdr *hsrc)
  143. {
  144. pjsip_sess_expires_hdr *hdr = pjsip_sess_expires_hdr_create(pool);
  145. hdr->sess_expires = hsrc->sess_expires;
  146. pj_strdup(pool, &hdr->refresher, &hsrc->refresher);
  147. pjsip_param_clone(pool, &hdr->other_param, &hsrc->other_param);
  148. return hdr;
  149. }
  150. static pjsip_sess_expires_hdr* se_hdr_shallow_clone(
  151. pj_pool_t *pool,
  152. const pjsip_sess_expires_hdr* hsrc)
  153. {
  154. pjsip_sess_expires_hdr *hdr = PJ_POOL_ALLOC_T(pool,pjsip_sess_expires_hdr);
  155. pj_memcpy(hdr, hsrc, sizeof(*hdr));
  156. pjsip_param_shallow_clone(pool, &hdr->other_param, &hsrc->other_param);
  157. return hdr;
  158. }
  159. /*
  160. * Min-SE header vptr.
  161. */
  162. static int min_se_hdr_print(pjsip_min_se_hdr *hdr,
  163. char *buf, pj_size_t size)
  164. {
  165. char *p = buf;
  166. char *endbuf = buf+size;
  167. pj_ssize_t printed;
  168. const pjsip_parser_const_t *pc = pjsip_parser_const();
  169. /* Print header name and value */
  170. if ((endbuf - p) < (hdr->name.slen + 16))
  171. return -1;
  172. copy_advance(p, hdr->name);
  173. *p++ = ':';
  174. *p++ = ' ';
  175. printed = pj_utoa(hdr->min_se, p);
  176. p += printed;
  177. /* Print generic params */
  178. printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
  179. &pc->pjsip_TOKEN_SPEC,
  180. &pc->pjsip_TOKEN_SPEC, ';');
  181. if (printed < 0)
  182. return (int)printed;
  183. p += printed;
  184. return (int)(p - buf);
  185. }
  186. static pjsip_min_se_hdr* min_se_hdr_clone(pj_pool_t *pool,
  187. const pjsip_min_se_hdr *hsrc)
  188. {
  189. pjsip_min_se_hdr *hdr = pjsip_min_se_hdr_create(pool);
  190. hdr->min_se = hsrc->min_se;
  191. pjsip_param_clone(pool, &hdr->other_param, &hsrc->other_param);
  192. return hdr;
  193. }
  194. static pjsip_min_se_hdr* min_se_hdr_shallow_clone(
  195. pj_pool_t *pool,
  196. const pjsip_min_se_hdr* hsrc)
  197. {
  198. pjsip_min_se_hdr *hdr = PJ_POOL_ALLOC_T(pool, pjsip_min_se_hdr);
  199. pj_memcpy(hdr, hsrc, sizeof(*hdr));
  200. pjsip_param_shallow_clone(pool, &hdr->other_param, &hsrc->other_param);
  201. return hdr;
  202. }
  203. /*
  204. * Parse Session-Expires header.
  205. */
  206. static pjsip_hdr *parse_hdr_se(pjsip_parse_ctx *ctx)
  207. {
  208. pjsip_sess_expires_hdr *hdr = pjsip_sess_expires_hdr_create(ctx->pool);
  209. const pjsip_parser_const_t *pc = pjsip_parser_const();
  210. pj_str_t token;
  211. pj_scan_get(ctx->scanner, &pc->pjsip_DIGIT_SPEC, &token);
  212. hdr->sess_expires = pj_strtoul(&token);
  213. while (*ctx->scanner->curptr == ';') {
  214. pj_str_t pname, pvalue;
  215. pj_scan_get_char(ctx->scanner);
  216. pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0);
  217. if (pj_stricmp(&pname, &STR_REFRESHER)==0) {
  218. hdr->refresher = pvalue;
  219. } else {
  220. pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param);
  221. param->name = pname;
  222. param->value = pvalue;
  223. pj_list_push_back(&hdr->other_param, param);
  224. }
  225. }
  226. pjsip_parse_end_hdr_imp( ctx->scanner );
  227. return (pjsip_hdr*)hdr;
  228. }
  229. /*
  230. * Parse Min-SE header.
  231. */
  232. static pjsip_hdr *parse_hdr_min_se(pjsip_parse_ctx *ctx)
  233. {
  234. pjsip_min_se_hdr *hdr = pjsip_min_se_hdr_create(ctx->pool);
  235. const pjsip_parser_const_t *pc = pjsip_parser_const();
  236. pj_str_t token;
  237. pj_scan_get(ctx->scanner, &pc->pjsip_DIGIT_SPEC, &token);
  238. hdr->min_se = pj_strtoul(&token);
  239. while (*ctx->scanner->curptr == ';') {
  240. pj_str_t pname, pvalue;
  241. pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param);
  242. pj_scan_get_char(ctx->scanner);
  243. pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0);
  244. param->name = pname;
  245. param->value = pvalue;
  246. pj_list_push_back(&hdr->other_param, param);
  247. }
  248. pjsip_parse_end_hdr_imp( ctx->scanner );
  249. return (pjsip_hdr*)hdr;
  250. }
  251. /* Add "Session-Expires" and "Min-SE" headers. Note that "Min-SE" header
  252. * can only be added to INVITE/UPDATE request and 422 response.
  253. */
  254. static void add_timer_headers(pjsip_inv_session *inv, pjsip_tx_data *tdata,
  255. pj_bool_t add_se, pj_bool_t add_min_se)
  256. {
  257. pjsip_timer *timer = inv->timer;
  258. /* Add Session-Expires header */
  259. if (add_se) {
  260. pjsip_sess_expires_hdr *hdr;
  261. hdr = pjsip_sess_expires_hdr_create(tdata->pool);
  262. hdr->sess_expires = timer->setting.sess_expires;
  263. if (timer->refresher != TR_UNKNOWN)
  264. hdr->refresher = (timer->refresher == TR_UAC? STR_UAC : STR_UAS);
  265. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hdr);
  266. }
  267. /* Add Min-SE header */
  268. if (add_min_se) {
  269. pjsip_min_se_hdr *hdr;
  270. hdr = pjsip_min_se_hdr_create(tdata->pool);
  271. hdr->min_se = timer->setting.min_se;
  272. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hdr);
  273. }
  274. }
  275. /* Timer callback. When the timer is fired, it can be time to refresh
  276. * the session if UA is the refresher, otherwise it is time to end
  277. * the session.
  278. */
  279. static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
  280. {
  281. pjsip_inv_session *inv = (pjsip_inv_session*) entry->user_data;
  282. pjsip_tx_data *tdata = NULL;
  283. pj_status_t status;
  284. pj_bool_t as_refresher;
  285. int entry_id;
  286. char obj_name[PJ_MAX_OBJ_NAME];
  287. pj_assert(inv);
  288. PJ_UNUSED_ARG(timer_heap);
  289. /* Lock dialog. */
  290. pjsip_dlg_inc_lock(inv->dlg);
  291. /* Check our role */
  292. as_refresher =
  293. (inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
  294. (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
  295. entry_id = entry->id;
  296. pj_ansi_strxcpy(obj_name, inv->pool->obj_name, PJ_MAX_OBJ_NAME);
  297. /* Do action based on role(refresher or refreshee).
  298. * As refresher:
  299. * - send refresh, or
  300. * - end session if there is no response to the refresh request.
  301. * As refreshee:
  302. * - end session if there is no refresh request received.
  303. */
  304. if (as_refresher && (entry_id != REFRESHER_EXPIRE_TIMER_ID)) {
  305. pj_time_val now;
  306. /* As refresher, reshedule the refresh request on the following:
  307. * - must not send re-INVITE if another INVITE or SDP negotiation
  308. * is in progress.
  309. * - must not send UPDATE with SDP if SDP negotiation is in progress
  310. */
  311. pjmedia_sdp_neg_state neg_state = pjmedia_sdp_neg_get_state(inv->neg);
  312. inv->timer->timer.id = 0;
  313. if ( (!inv->timer->use_update && (
  314. inv->invite_tsx != NULL ||
  315. neg_state != PJMEDIA_SDP_NEG_STATE_DONE)
  316. )
  317. ||
  318. (inv->timer->use_update && inv->timer->with_sdp &&
  319. neg_state != PJMEDIA_SDP_NEG_STATE_DONE
  320. )
  321. )
  322. {
  323. pj_time_val delay = {1, 0};
  324. inv->timer->timer.id = 1;
  325. pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer,
  326. &delay);
  327. pjsip_dlg_dec_lock(inv->dlg);
  328. PJ_LOG(3, (obj_name,
  329. "Reschedule refresh request after %ld seconds as "
  330. "there is another SDP negotiation in progress",
  331. delay.sec));
  332. return;
  333. }
  334. /* Refresher, refresh the session */
  335. if (inv->timer->use_update) {
  336. const pjmedia_sdp_session *offer = NULL;
  337. if (inv->timer->with_sdp) {
  338. pjmedia_sdp_neg_get_active_local(inv->neg, &offer);
  339. }
  340. status = pjsip_inv_update(inv, NULL, offer, &tdata);
  341. } else {
  342. /* Create re-INVITE without modifying session */
  343. pjsip_msg_body *body;
  344. const pjmedia_sdp_session *offer = NULL;
  345. pj_assert(pjmedia_sdp_neg_get_state(inv->neg) ==
  346. PJMEDIA_SDP_NEG_STATE_DONE);
  347. status = pjsip_inv_invite(inv, &tdata);
  348. if (status == PJ_SUCCESS)
  349. status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov,
  350. inv->neg, &offer);
  351. if (status == PJ_SUCCESS)
  352. status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
  353. if (status == PJ_SUCCESS) {
  354. status = pjsip_create_sdp_body(tdata->pool,
  355. (pjmedia_sdp_session*)offer, &body);
  356. tdata->msg->body = body;
  357. }
  358. }
  359. pj_gettimeofday(&now);
  360. PJ_LOG(4, (obj_name,
  361. "Refreshing session after %lds (expiration period=%ds)",
  362. (now.sec-inv->timer->last_refresh.sec),
  363. inv->timer->setting.sess_expires));
  364. } else {
  365. pj_time_val now;
  366. pj_str_t reason = pj_str("No session refresh received.");
  367. if (as_refresher)
  368. inv->timer->expire_timer.id = 0;
  369. else
  370. inv->timer->timer.id = 0;
  371. /* Terminate the session */
  372. status = pjsip_inv_end_session(inv, PJSIP_SC_REQUEST_TIMEOUT,
  373. &reason, &tdata);
  374. pj_gettimeofday(&now);
  375. PJ_LOG(3, (obj_name,
  376. "No session %s received after %lds "
  377. "(expiration period=%ds), stopping session now!",
  378. (as_refresher?"refresh response":"refresh"),
  379. (now.sec-inv->timer->last_refresh.sec),
  380. inv->timer->setting.sess_expires));
  381. }
  382. /* Unlock dialog. */
  383. pjsip_dlg_dec_lock(inv->dlg);
  384. /* Send message, if any */
  385. if (tdata && status == PJ_SUCCESS) {
  386. inv->timer->refresh_tdata = tdata;
  387. status = pjsip_inv_send_msg(inv, tdata);
  388. }
  389. /*
  390. * At this point, dialog might have already been destroyed,
  391. * including its pool used by the invite session.
  392. */
  393. /* Print error message, if any */
  394. if (status != PJ_SUCCESS) {
  395. PJ_PERROR(2, (obj_name, status,
  396. "Error in %s session timer",
  397. ((as_refresher && entry_id != REFRESHER_EXPIRE_TIMER_ID)?
  398. "refreshing" : "terminating")));
  399. }
  400. }
  401. /* Start Session Timers */
  402. static void start_timer(pjsip_inv_session *inv)
  403. {
  404. const pj_str_t UPDATE = { "UPDATE", 6 };
  405. pjsip_timer *timer = inv->timer;
  406. pj_time_val delay = {0};
  407. pj_assert(inv->timer->active == PJ_TRUE);
  408. stop_timer(inv);
  409. inv->timer->use_update =
  410. (pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL,
  411. &UPDATE) == PJSIP_DIALOG_CAP_SUPPORTED);
  412. if (!inv->timer->use_update) {
  413. /* INVITE always needs SDP */
  414. inv->timer->with_sdp = PJ_TRUE;
  415. }
  416. pj_timer_entry_init(&timer->timer,
  417. 1, /* id */
  418. inv, /* user data */
  419. timer_cb); /* callback */
  420. /* Set delay based on role, refresher or refreshee */
  421. if ((timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
  422. (timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS))
  423. {
  424. /* Add refresher expire timer */
  425. pj_timer_entry_init(&timer->expire_timer,
  426. REFRESHER_EXPIRE_TIMER_ID, /* id */
  427. inv, /* user data */
  428. timer_cb); /* callback */
  429. delay.sec = timer->setting.sess_expires;
  430. /* Schedule the timer */
  431. pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->expire_timer,
  432. &delay);
  433. /* Next refresh, the delay is half of session expire */
  434. delay.sec = timer->setting.sess_expires / 2;
  435. } else {
  436. /* Send BYE if no refresh received until this timer fired, delay
  437. * is the minimum of 32 seconds and one third of the session interval
  438. * before session expiration.
  439. */
  440. delay.sec = timer->setting.sess_expires -
  441. timer->setting.sess_expires/3;
  442. delay.sec = PJ_MAX((long)timer->setting.sess_expires-32, delay.sec);
  443. }
  444. /* Schedule the timer */
  445. pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->timer, &delay);
  446. /* Update last refresh time */
  447. pj_gettimeofday(&timer->last_refresh);
  448. }
  449. /* Stop Session Timers */
  450. static void stop_timer(pjsip_inv_session *inv)
  451. {
  452. if (inv->timer->timer.id != 0) {
  453. pjsip_endpt_cancel_timer(inv->dlg->endpt, &inv->timer->timer);
  454. inv->timer->timer.id = 0;
  455. }
  456. if (inv->timer->expire_timer.id != 0) {
  457. pjsip_endpt_cancel_timer(inv->dlg->endpt, &inv->timer->expire_timer);
  458. inv->timer->expire_timer.id = 0;
  459. }
  460. }
  461. /* Deinitialize Session Timers */
  462. static void pjsip_timer_deinit_module(pjsip_endpoint *endpt)
  463. {
  464. PJ_TODO(provide_initialized_flag_for_each_endpoint);
  465. PJ_UNUSED_ARG(endpt);
  466. is_initialized = PJ_FALSE;
  467. }
  468. /*
  469. * Initialize Session Timers support in PJSIP.
  470. */
  471. PJ_DEF(pj_status_t) pjsip_timer_init_module(pjsip_endpoint *endpt)
  472. {
  473. pj_status_t status;
  474. PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
  475. if (is_initialized)
  476. return PJ_SUCCESS;
  477. /* Register Session-Expires header parser */
  478. status = pjsip_register_hdr_parser( STR_SE.ptr, STR_SHORT_SE.ptr,
  479. &parse_hdr_se);
  480. if (status != PJ_SUCCESS)
  481. return status;
  482. /* Register Min-SE header parser */
  483. status = pjsip_register_hdr_parser( STR_MIN_SE.ptr, NULL,
  484. &parse_hdr_min_se);
  485. if (status != PJ_SUCCESS)
  486. return status;
  487. /* Register 'timer' capability to endpoint */
  488. status = pjsip_endpt_add_capability(endpt, NULL, PJSIP_H_SUPPORTED,
  489. NULL, 1, &STR_TIMER);
  490. if (status != PJ_SUCCESS)
  491. return status;
  492. /* Register deinit module to be executed when PJLIB shutdown */
  493. if (pjsip_endpt_atexit(endpt, &pjsip_timer_deinit_module) != PJ_SUCCESS) {
  494. /* Failure to register this function may cause this module won't
  495. * work properly when the stack is restarted (without quitting
  496. * application).
  497. */
  498. pj_assert(!"Failed to register Session Timer deinit.");
  499. PJ_LOG(1, (THIS_FILE, "Failed to register Session Timer deinit."));
  500. }
  501. is_initialized = PJ_TRUE;
  502. return PJ_SUCCESS;
  503. }
  504. /*
  505. * Initialize Session Timers setting with default values.
  506. */
  507. PJ_DEF(pj_status_t) pjsip_timer_setting_default(pjsip_timer_setting *setting)
  508. {
  509. pj_bzero(setting, sizeof(pjsip_timer_setting));
  510. setting->sess_expires = PJSIP_SESS_TIMER_DEF_SE;
  511. setting->min_se = ABS_MIN_SE;
  512. return PJ_SUCCESS;
  513. }
  514. /*
  515. * Initialize Session Timers in an INVITE session.
  516. */
  517. PJ_DEF(pj_status_t) pjsip_timer_init_session(
  518. pjsip_inv_session *inv,
  519. const pjsip_timer_setting *setting)
  520. {
  521. pjsip_timer_setting *s;
  522. pj_assert(is_initialized);
  523. PJ_ASSERT_RETURN(inv, PJ_EINVAL);
  524. /* Allocate and/or reset Session Timers structure */
  525. if (!inv->timer)
  526. inv->timer = PJ_POOL_ZALLOC_T(inv->pool, pjsip_timer);
  527. else
  528. pj_bzero(inv->timer, sizeof(pjsip_timer));
  529. s = &inv->timer->setting;
  530. /* Init Session Timers setting */
  531. if (setting) {
  532. PJ_ASSERT_RETURN(setting->min_se >= ABS_MIN_SE,
  533. PJ_ETOOSMALL);
  534. PJ_ASSERT_RETURN(setting->sess_expires >= setting->min_se,
  535. PJ_EINVAL);
  536. pj_memcpy(s, setting, sizeof(*s));
  537. } else {
  538. pjsip_timer_setting_default(s);
  539. }
  540. return PJ_SUCCESS;
  541. }
  542. /*
  543. * Create Session-Expires header.
  544. */
  545. PJ_DEF(pjsip_sess_expires_hdr*) pjsip_sess_expires_hdr_create(
  546. pj_pool_t *pool)
  547. {
  548. pjsip_sess_expires_hdr *hdr = PJ_POOL_ZALLOC_T(pool,
  549. pjsip_sess_expires_hdr);
  550. pj_assert(is_initialized);
  551. hdr->type = PJSIP_H_OTHER;
  552. hdr->name = STR_SE;
  553. hdr->sname = STR_SHORT_SE;
  554. hdr->vptr = &se_hdr_vptr;
  555. pj_list_init(hdr);
  556. pj_list_init(&hdr->other_param);
  557. return hdr;
  558. }
  559. /*
  560. * Create Min-SE header.
  561. */
  562. PJ_DEF(pjsip_min_se_hdr*) pjsip_min_se_hdr_create(pj_pool_t *pool)
  563. {
  564. pjsip_min_se_hdr *hdr = PJ_POOL_ZALLOC_T(pool, pjsip_min_se_hdr);
  565. pj_assert(is_initialized);
  566. hdr->type = PJSIP_H_OTHER;
  567. hdr->name = STR_MIN_SE;
  568. hdr->vptr = &min_se_hdr_vptr;
  569. pj_list_init(hdr);
  570. pj_list_init(&hdr->other_param);
  571. return hdr;
  572. }
  573. /*
  574. * This function generates headers for Session Timers for intial and
  575. * refresh INVITE or UPDATE.
  576. */
  577. PJ_DEF(pj_status_t) pjsip_timer_update_req(pjsip_inv_session *inv,
  578. pjsip_tx_data *tdata)
  579. {
  580. PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
  581. /* Check if Session Timers is supported */
  582. if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
  583. return PJ_SUCCESS;
  584. pj_assert(is_initialized);
  585. /* Make sure Session Timers is initialized */
  586. if (inv->timer == NULL)
  587. pjsip_timer_init_session(inv, NULL);
  588. /* If refresher role (i.e: ours or peer) has been set/negotiated,
  589. * better to keep it.
  590. */
  591. if (inv->timer->refresher != TR_UNKNOWN) {
  592. pj_bool_t as_refresher;
  593. /* Check our refresher role */
  594. as_refresher =
  595. (inv->timer->refresher==TR_UAC && inv->timer->role==PJSIP_ROLE_UAC) ||
  596. (inv->timer->refresher==TR_UAS && inv->timer->role==PJSIP_ROLE_UAS);
  597. /* Update transaction role */
  598. inv->timer->role = PJSIP_ROLE_UAC;
  599. /* Update refresher role */
  600. inv->timer->refresher = as_refresher? TR_UAC : TR_UAS;
  601. }
  602. /* Add Session Timers headers */
  603. add_timer_headers(inv, tdata, PJ_TRUE, PJ_TRUE);
  604. return PJ_SUCCESS;
  605. }
  606. /*
  607. * This function will handle Session Timers part of INVITE/UPDATE
  608. * responses with code:
  609. * - 422 (Session Interval Too Small)
  610. * - 2xx final response
  611. */
  612. PJ_DEF(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
  613. const pjsip_rx_data *rdata,
  614. pjsip_status_code *st_code)
  615. {
  616. const pjsip_msg *msg;
  617. PJ_ASSERT_ON_FAIL(inv && rdata,
  618. {if(st_code)*st_code=PJSIP_SC_INTERNAL_SERVER_ERROR;return PJ_EINVAL;});
  619. /* Check if Session Timers is supported */
  620. if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0) {
  621. if (rdata->msg_info.msg->line.status.code ==
  622. PJSIP_SC_SESSION_TIMER_TOO_SMALL)
  623. {
  624. return PJSIP_EINVALIDSTATUS;
  625. } else {
  626. return PJ_SUCCESS;
  627. }
  628. }
  629. pj_assert(is_initialized);
  630. msg = rdata->msg_info.msg;
  631. pj_assert(msg->type == PJSIP_RESPONSE_MSG);
  632. /* Only process response of INVITE or UPDATE */
  633. if (rdata->msg_info.cseq->method.id != PJSIP_INVITE_METHOD &&
  634. pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_update_method))
  635. {
  636. return PJ_SUCCESS;
  637. }
  638. if (msg->line.status.code == PJSIP_SC_SESSION_TIMER_TOO_SMALL) {
  639. /* Our Session-Expires is too small, let's update it based on
  640. * Min-SE header in the response.
  641. */
  642. pjsip_tx_data *tdata;
  643. pjsip_min_se_hdr *min_se_hdr;
  644. pjsip_hdr *hdr;
  645. pjsip_via_hdr *via;
  646. /* Get Min-SE value from response */
  647. min_se_hdr = (pjsip_min_se_hdr*)
  648. pjsip_msg_find_hdr_by_name(msg, &STR_MIN_SE, NULL);
  649. if (min_se_hdr == NULL) {
  650. /* Response 422 MUST contain Min-SE header */
  651. PJ_LOG(3, (inv->pool->obj_name,
  652. "Received 422 (Session Interval Too Small) response "
  653. "without Min-SE header!"));
  654. pjsip_timer_end_session(inv);
  655. return PJSIP_EMISSINGHDR;
  656. }
  657. /* Avoid 422 retry loop. Ignore it and stop retrying if dialog is
  658. * established, otherwise, just return error to disconnect the call.
  659. */
  660. if (rdata->msg_info.cseq->cseq == inv->timer->last_422_cseq + 1) {
  661. if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
  662. inv->invite_tsx = NULL;
  663. return PJ_SUCCESS;
  664. } else {
  665. return PJSIP_ERRNO_FROM_SIP_STATUS(
  666. PJSIP_SC_SESSION_TIMER_TOO_SMALL);
  667. }
  668. }
  669. inv->timer->last_422_cseq = rdata->msg_info.cseq->cseq;
  670. /* Session Timers should have been initialized here */
  671. pj_assert(inv->timer);
  672. /* Update Min-SE */
  673. inv->timer->setting.min_se = PJ_MAX(min_se_hdr->min_se,
  674. inv->timer->setting.min_se);
  675. /* Update Session Timers setting */
  676. if (inv->timer->setting.sess_expires < inv->timer->setting.min_se)
  677. inv->timer->setting.sess_expires = inv->timer->setting.min_se;
  678. /* Prepare to restart the request */
  679. /* Get the original INVITE/UPDATE request. */
  680. tdata = pjsip_rdata_get_tsx((pjsip_rx_data*)rdata)->last_tx;
  681. /* Remove branch param in Via header. */
  682. via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
  683. pj_assert(via);
  684. via->branch_param.slen = 0;
  685. /* Restore strict route set.
  686. * See https://github.com/pjsip/pjproject/issues/492
  687. */
  688. pjsip_restore_strict_route_set(tdata);
  689. /* Must invalidate the message! */
  690. pjsip_tx_data_invalidate_msg(tdata);
  691. pjsip_tx_data_add_ref(tdata);
  692. /* Update Session Timers headers */
  693. hdr = (pjsip_hdr*) pjsip_msg_find_hdr_by_name(tdata->msg,
  694. &STR_MIN_SE, NULL);
  695. if (hdr != NULL) pj_list_erase(hdr);
  696. hdr = (pjsip_hdr*) pjsip_msg_find_hdr_by_names(tdata->msg, &STR_SE,
  697. &STR_SHORT_SE, NULL);
  698. if (hdr != NULL) pj_list_erase(hdr);
  699. add_timer_headers(inv, tdata, PJ_TRUE, PJ_TRUE);
  700. /* Restart UAC if this is initial INVITE, or simply reset tsx for
  701. * subsequent INVITE.
  702. */
  703. if (inv->state < PJSIP_INV_STATE_CONFIRMED)
  704. pjsip_inv_uac_restart(inv, PJ_FALSE);
  705. else if (tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD)
  706. inv->invite_tsx = NULL;
  707. /* Resend the updated request */
  708. pjsip_inv_send_msg(inv, tdata);
  709. return PJ_SUCCESS;
  710. } else if (msg->line.status.code/100 == 2) {
  711. pjsip_sess_expires_hdr *se_hdr;
  712. /* Find Session-Expires header */
  713. se_hdr = (pjsip_sess_expires_hdr*) pjsip_msg_find_hdr_by_names(
  714. msg, &STR_SE,
  715. &STR_SHORT_SE, NULL);
  716. if (se_hdr == NULL) {
  717. /* Remote doesn't support/want Session Timers, check if local
  718. * require or force to use Session Timers.
  719. */
  720. if (inv->options & PJSIP_INV_REQUIRE_TIMER) {
  721. if (st_code)
  722. *st_code = PJSIP_SC_EXTENSION_REQUIRED;
  723. pjsip_timer_end_session(inv);
  724. return PJSIP_ERRNO_FROM_SIP_STATUS(
  725. PJSIP_SC_EXTENSION_REQUIRED);
  726. }
  727. if ((inv->options & PJSIP_INV_ALWAYS_USE_TIMER) == 0) {
  728. /* Session Timers not forced */
  729. pjsip_timer_end_session(inv);
  730. return PJ_SUCCESS;
  731. }
  732. }
  733. /* Make sure Session Timers is initialized */
  734. if (inv->timer == NULL)
  735. pjsip_timer_init_session(inv, NULL);
  736. /* Session expiration period specified by remote is lower than our
  737. * Min-SE.
  738. */
  739. if (se_hdr &&
  740. se_hdr->sess_expires < inv->timer->setting.min_se)
  741. {
  742. /* See ticket #954, instead of returning non-PJ_SUCCESS (which
  743. * may cause disconnecting call/dialog), let's just accept the
  744. * SE and update our local SE, as long as it isn't less than 90s.
  745. */
  746. if (se_hdr->sess_expires >= ABS_MIN_SE) {
  747. PJ_LOG(3, (inv->pool->obj_name,
  748. "Peer responds with bad Session-Expires, %ds, "
  749. "which is less than Min-SE specified in request, "
  750. "%ds. Well, let's just accept and use it.",
  751. se_hdr->sess_expires, inv->timer->setting.min_se));
  752. inv->timer->setting.sess_expires = se_hdr->sess_expires;
  753. inv->timer->setting.min_se = se_hdr->sess_expires;
  754. }
  755. //if (st_code)
  756. // *st_code = PJSIP_SC_SESSION_TIMER_TOO_SMALL;
  757. //pjsip_timer_end_session(inv);
  758. //return PJSIP_ERRNO_FROM_SIP_STATUS(
  759. // PJSIP_SC_SESSION_TIMER_TOO_SMALL);
  760. }
  761. /* Update SE. Session-Expires in response cannot be lower than Min-SE.
  762. * Session-Expires in response can only be equal or lower than in
  763. * request.
  764. */
  765. if (se_hdr &&
  766. se_hdr->sess_expires <= inv->timer->setting.sess_expires &&
  767. se_hdr->sess_expires >= inv->timer->setting.min_se)
  768. {
  769. /* Good SE from remote, update local SE */
  770. inv->timer->setting.sess_expires = se_hdr->sess_expires;
  771. }
  772. /* Set the refresher */
  773. if (se_hdr && pj_stricmp(&se_hdr->refresher, &STR_UAC) == 0)
  774. inv->timer->refresher = TR_UAC;
  775. else if (se_hdr && pj_stricmp(&se_hdr->refresher, &STR_UAS) == 0)
  776. inv->timer->refresher = TR_UAS;
  777. else
  778. /* UAS should set the refresher, however, there is a case that
  779. * UAS doesn't support/want Session Timers but the UAC insists
  780. * to use Session Timers.
  781. */
  782. inv->timer->refresher = TR_UAC;
  783. /* Remember our role in this transaction */
  784. inv->timer->role = PJSIP_ROLE_UAC;
  785. /* Finally, set active flag and start the Session Timers */
  786. inv->timer->active = PJ_TRUE;
  787. start_timer(inv);
  788. } else if (pjsip_method_cmp(&rdata->msg_info.cseq->method,
  789. &pjsip_update_method) == 0 &&
  790. msg->line.status.code >= 400 && msg->line.status.code < 600)
  791. {
  792. /* This is to handle error response to previous UPDATE that was
  793. * sent without SDP. In this case, retry sending UPDATE but
  794. * with SDP this time.
  795. * Note: the additional expressions are to check that the
  796. * UPDATE was really the one sent by us, not by other
  797. * call components (e.g. to change codec)
  798. */
  799. if (inv->timer->timer.id == 0 && inv->timer->use_update &&
  800. inv->timer->with_sdp == PJ_FALSE)
  801. {
  802. inv->timer->with_sdp = PJ_TRUE;
  803. timer_cb(NULL, &inv->timer->timer);
  804. }
  805. }
  806. return PJ_SUCCESS;
  807. }
  808. PJ_DEF(pj_status_t) pjsip_timer_handle_refresh_error(
  809. pjsip_inv_session *inv,
  810. pjsip_event *event)
  811. {
  812. PJ_ASSERT_RETURN(inv && event, PJ_EINVAL);
  813. /* Check if Session Timers is supported */
  814. if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
  815. return PJ_SUCCESS;
  816. pj_assert(is_initialized);
  817. if (inv->timer && inv->timer->active) {
  818. pj_bool_t as_refresher;
  819. /* Check our role */
  820. as_refresher = ((inv->timer->refresher == TR_UAC) &&
  821. (inv->timer->role == PJSIP_ROLE_UAC)) ||
  822. ((inv->timer->refresher == TR_UAS) &&
  823. (inv->timer->role == PJSIP_ROLE_UAS));
  824. if ((as_refresher) && (event->type == PJSIP_EVENT_TSX_STATE) &&
  825. (inv->timer->refresh_tdata == event->body.tsx_state.tsx->last_tx))
  826. {
  827. pjsip_status_code st_code;
  828. pjsip_tx_data *bye;
  829. pj_status_t status;
  830. st_code =
  831. (pjsip_status_code)event->body.tsx_state.tsx->status_code;
  832. PJ_LOG(3, (inv->pool->obj_name,
  833. "Receive error %d for refresh request %.*s/cseq=%d",
  834. st_code, (int)event->body.tsx_state.tsx->method.name.slen,
  835. event->body.tsx_state.tsx->method.name.ptr,
  836. event->body.tsx_state.tsx->cseq));
  837. if (st_code == 503 && PJSIP_SESS_TIMER_RETRY_DELAY >= 0) {
  838. /* Retry the refresh after some delay */
  839. pj_time_val delay = {PJSIP_SESS_TIMER_RETRY_DELAY, 0};
  840. PJ_LOG(3, (inv->pool->obj_name, "Scheduling to retry refresh "
  841. "request after %ld second(s)", delay.sec));
  842. inv->timer->timer.id = 1;
  843. pjsip_endpt_schedule_timer(inv->dlg->endpt,
  844. &inv->timer->timer, &delay);
  845. } else {
  846. PJ_LOG(3, (inv->pool->obj_name, "Ending session now"));
  847. status = pjsip_inv_end_session(inv,
  848. event->body.tsx_state.tsx->status_code,
  849. pjsip_get_status_text(st_code),
  850. &bye);
  851. if (status == PJ_SUCCESS && bye)
  852. status = pjsip_inv_send_msg(inv, bye);
  853. }
  854. }
  855. }
  856. return PJ_SUCCESS;
  857. }
  858. /*
  859. * Handle incoming INVITE or UPDATE request.
  860. */
  861. PJ_DEF(pj_status_t) pjsip_timer_process_req(pjsip_inv_session *inv,
  862. const pjsip_rx_data *rdata,
  863. pjsip_status_code *st_code)
  864. {
  865. pjsip_min_se_hdr *min_se_hdr;
  866. pjsip_sess_expires_hdr *se_hdr;
  867. const pjsip_msg *msg;
  868. unsigned min_se;
  869. PJ_ASSERT_ON_FAIL(inv && rdata,
  870. {if(st_code)*st_code=PJSIP_SC_INTERNAL_SERVER_ERROR;return PJ_EINVAL;});
  871. /* Check if Session Timers is supported */
  872. if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
  873. return PJ_SUCCESS;
  874. pj_assert(is_initialized);
  875. msg = rdata->msg_info.msg;
  876. pj_assert(msg->type == PJSIP_REQUEST_MSG);
  877. /* Only process INVITE or UPDATE request */
  878. if (msg->line.req.method.id != PJSIP_INVITE_METHOD &&
  879. pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_update_method))
  880. {
  881. return PJ_SUCCESS;
  882. }
  883. /* Make sure Session Timers is initialized */
  884. if (inv->timer == NULL)
  885. pjsip_timer_init_session(inv, NULL);
  886. /* Find Session-Expires header */
  887. se_hdr = (pjsip_sess_expires_hdr*) pjsip_msg_find_hdr_by_names(
  888. msg, &STR_SE, &STR_SHORT_SE, NULL);
  889. /* Find Min-SE header */
  890. min_se_hdr = (pjsip_min_se_hdr*) pjsip_msg_find_hdr_by_name(msg,
  891. &STR_MIN_SE, NULL);
  892. /* Update Min-SE */
  893. min_se = inv->timer->setting.min_se;
  894. if (min_se_hdr)
  895. min_se = PJ_MAX(min_se_hdr->min_se, min_se);
  896. /* Validate SE. Session-Expires cannot be lower than Min-SE
  897. * (or 90 seconds if Min-SE is not set).
  898. */
  899. if (se_hdr && se_hdr->sess_expires < min_se) {
  900. if (st_code)
  901. *st_code = PJSIP_SC_SESSION_TIMER_TOO_SMALL;
  902. return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_SESSION_TIMER_TOO_SMALL);
  903. }
  904. /* Update SE. Note that there is a case that SE is not available in the
  905. * request (which means remote doesn't want/support it), but local insists
  906. * to use Session Timers.
  907. */
  908. if (se_hdr) {
  909. /* Update SE as specified by peer. */
  910. inv->timer->setting.sess_expires = se_hdr->sess_expires;
  911. } else if (inv->timer->setting.sess_expires < min_se) {
  912. /* There is no SE in the request (remote support Session Timers but
  913. * doesn't want to use it, it just specify Min-SE) and local SE is
  914. * lower than Min-SE specified by remote.
  915. */
  916. inv->timer->setting.sess_expires = min_se;
  917. }
  918. /* If incoming request has no SE header, it means remote doesn't
  919. * support/want Session Timers. So let's check if local require or
  920. * force to use Session Timers. Note that Supported and Require headers
  921. * negotiation should have been verified by invite session.
  922. */
  923. if (se_hdr == NULL) {
  924. if ((inv->options &
  925. (PJSIP_INV_REQUIRE_TIMER | PJSIP_INV_ALWAYS_USE_TIMER)) == 0)
  926. {
  927. /* Session Timers not forced/required */
  928. pjsip_timer_end_session(inv);
  929. return PJ_SUCCESS;
  930. }
  931. }
  932. /* Set the refresher */
  933. if (se_hdr && pj_stricmp(&se_hdr->refresher, &STR_UAC) == 0)
  934. inv->timer->refresher = TR_UAC;
  935. else if (se_hdr && pj_stricmp(&se_hdr->refresher, &STR_UAS) == 0)
  936. inv->timer->refresher = TR_UAS;
  937. else {
  938. /* If refresher role (i.e: ours or peer) has been set/negotiated,
  939. * better to keep it.
  940. */
  941. if (inv->timer->refresher != TR_UNKNOWN) {
  942. pj_bool_t as_refresher;
  943. /* Check our refresher role */
  944. as_refresher =
  945. (inv->timer->refresher==TR_UAC && inv->timer->role==PJSIP_ROLE_UAC) ||
  946. (inv->timer->refresher==TR_UAS && inv->timer->role==PJSIP_ROLE_UAS);
  947. /* Update refresher role */
  948. inv->timer->refresher = as_refresher? TR_UAS : TR_UAC;
  949. } else {
  950. /* If UAC supports timer and Session-Expires header is present
  951. * in the request, set UAC as refresher.
  952. * If UAC doesn't support timer and a proxy inserts a
  953. * Session-Expires header, then UAS has to be the
  954. * refresher (according to RFC 4028 Section 9).
  955. */
  956. pj_bool_t uac_supports_timer = PJ_FALSE;
  957. pjsip_supported_hdr *sup_hdr;
  958. sup_hdr = (pjsip_supported_hdr*)
  959. pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
  960. if (sup_hdr) {
  961. unsigned i;
  962. for (i = 0; i < sup_hdr->count; i++) {
  963. if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER) == 0) {
  964. uac_supports_timer = PJ_TRUE;
  965. break;
  966. }
  967. }
  968. }
  969. inv->timer->refresher = (uac_supports_timer && se_hdr)? TR_UAC:
  970. TR_UAS;
  971. }
  972. }
  973. /* Remember our role in this transaction */
  974. inv->timer->role = PJSIP_ROLE_UAS;
  975. /* Set active flag */
  976. inv->timer->active = PJ_TRUE;
  977. return PJ_SUCCESS;
  978. }
  979. /*
  980. * Handle outgoing response with status code 2xx & 422.
  981. */
  982. PJ_DEF(pj_status_t) pjsip_timer_update_resp(pjsip_inv_session *inv,
  983. pjsip_tx_data *tdata)
  984. {
  985. pjsip_msg *msg;
  986. /* Check if Session Timers is supported */
  987. if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
  988. return PJ_SUCCESS;
  989. pj_assert(is_initialized);
  990. PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
  991. msg = tdata->msg;
  992. if (msg->line.status.code/100 == 2)
  993. {
  994. if (inv->timer && inv->timer->active) {
  995. /* Add Session-Expires header and start the timer */
  996. add_timer_headers(inv, tdata, PJ_TRUE, PJ_FALSE);
  997. /* Add 'timer' to Require header (see ticket #1560). */
  998. if (inv->timer->refresher == TR_UAC) {
  999. pjsip_require_hdr *req_hdr;
  1000. pj_bool_t req_hdr_has_timer = PJ_FALSE;
  1001. req_hdr = (pjsip_require_hdr*)
  1002. pjsip_msg_find_hdr(tdata->msg, PJSIP_H_REQUIRE,
  1003. NULL);
  1004. if (req_hdr == NULL) {
  1005. req_hdr = pjsip_require_hdr_create(tdata->pool);
  1006. PJ_ASSERT_RETURN(req_hdr, PJ_ENOMEM);
  1007. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
  1008. } else {
  1009. unsigned i;
  1010. for (i = 0; i < req_hdr->count; ++i) {
  1011. if (pj_stricmp(&req_hdr->values[i], &STR_TIMER)) {
  1012. req_hdr_has_timer = PJ_TRUE;
  1013. break;
  1014. }
  1015. }
  1016. }
  1017. if (!req_hdr_has_timer)
  1018. req_hdr->values[req_hdr->count++] = STR_TIMER;
  1019. }
  1020. /* Finally, start timer. */
  1021. start_timer(inv);
  1022. }
  1023. }
  1024. else if (msg->line.status.code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
  1025. {
  1026. /* Add Min-SE header */
  1027. add_timer_headers(inv, tdata, PJ_FALSE, PJ_TRUE);
  1028. }
  1029. return PJ_SUCCESS;
  1030. }
  1031. /*
  1032. * End the Session Timers.
  1033. */
  1034. PJ_DEF(pj_status_t) pjsip_timer_end_session(pjsip_inv_session *inv)
  1035. {
  1036. PJ_ASSERT_RETURN(inv, PJ_EINVAL);
  1037. if (inv->timer) {
  1038. /* Reset active flag */
  1039. inv->timer->active = PJ_FALSE;
  1040. /* Stop Session Timers */
  1041. stop_timer(inv);
  1042. }
  1043. return PJ_SUCCESS;
  1044. }