sip_replaces.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <pjsip-ua/sip_replaces.h>
  20. #include <pjsip-ua/sip_inv.h>
  21. #include <pjsip/print_util.h>
  22. #include <pjsip/sip_endpoint.h>
  23. #include <pjsip/sip_errno.h>
  24. #include <pjsip/sip_parser.h>
  25. #include <pjsip/sip_transport.h>
  26. #include <pjsip/sip_ua_layer.h>
  27. #include <pjsip/sip_util.h>
  28. #include <pj/assert.h>
  29. #include <pj/log.h>
  30. #include <pj/pool.h>
  31. #include <pj/string.h>
  32. #define THIS_FILE "sip_replaces.c"
  33. /*
  34. * Replaces header vptr.
  35. */
  36. static int replaces_hdr_print( pjsip_replaces_hdr *hdr,
  37. char *buf, pj_size_t size);
  38. static pjsip_replaces_hdr* replaces_hdr_clone( pj_pool_t *pool,
  39. const pjsip_replaces_hdr *hdr);
  40. static pjsip_replaces_hdr* replaces_hdr_shallow_clone( pj_pool_t *pool,
  41. const pjsip_replaces_hdr*);
  42. static pjsip_hdr_vptr replaces_hdr_vptr =
  43. {
  44. (pjsip_hdr_clone_fptr) &replaces_hdr_clone,
  45. (pjsip_hdr_clone_fptr) &replaces_hdr_shallow_clone,
  46. (pjsip_hdr_print_fptr) &replaces_hdr_print,
  47. };
  48. /* Globals */
  49. static pjsip_endpoint *the_endpt;
  50. static pj_bool_t is_initialized;
  51. PJ_DEF(pjsip_replaces_hdr*) pjsip_replaces_hdr_create(pj_pool_t *pool)
  52. {
  53. pjsip_replaces_hdr *hdr = PJ_POOL_ZALLOC_T(pool, pjsip_replaces_hdr);
  54. hdr->type = PJSIP_H_OTHER;
  55. hdr->name.ptr = "Replaces";
  56. hdr->name.slen = 8;
  57. hdr->vptr = &replaces_hdr_vptr;
  58. pj_list_init(hdr);
  59. pj_list_init(&hdr->other_param);
  60. return hdr;
  61. }
  62. static int replaces_hdr_print( pjsip_replaces_hdr *hdr,
  63. char *buf, pj_size_t size)
  64. {
  65. char *p = buf;
  66. char *endbuf = buf+size;
  67. pj_ssize_t printed;
  68. const pjsip_parser_const_t *pc = pjsip_parser_const();
  69. copy_advance(p, hdr->name);
  70. *p++ = ':';
  71. *p++ = ' ';
  72. copy_advance(p, hdr->call_id);
  73. copy_advance_pair(p, ";to-tag=", 8, hdr->to_tag);
  74. copy_advance_pair(p, ";from-tag=", 10, hdr->from_tag);
  75. if (hdr->early_only) {
  76. const pj_str_t str_early_only = { ";early-only", 11 };
  77. copy_advance(p, str_early_only);
  78. }
  79. printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
  80. &pc->pjsip_TOKEN_SPEC,
  81. &pc->pjsip_TOKEN_SPEC, ';');
  82. if (printed < 0)
  83. return (int)printed;
  84. p += printed;
  85. return (int)(p - buf);
  86. }
  87. static pjsip_replaces_hdr* replaces_hdr_clone( pj_pool_t *pool,
  88. const pjsip_replaces_hdr *rhs)
  89. {
  90. pjsip_replaces_hdr *hdr = pjsip_replaces_hdr_create(pool);
  91. pj_strdup(pool, &hdr->call_id, &rhs->call_id);
  92. pj_strdup(pool, &hdr->to_tag, &rhs->to_tag);
  93. pj_strdup(pool, &hdr->from_tag, &rhs->from_tag);
  94. hdr->early_only = rhs->early_only;
  95. pjsip_param_clone(pool, &hdr->other_param, &rhs->other_param);
  96. return hdr;
  97. }
  98. static pjsip_replaces_hdr*
  99. replaces_hdr_shallow_clone( pj_pool_t *pool,
  100. const pjsip_replaces_hdr *rhs )
  101. {
  102. pjsip_replaces_hdr *hdr = PJ_POOL_ALLOC_T(pool, pjsip_replaces_hdr);
  103. pj_memcpy(hdr, rhs, sizeof(*hdr));
  104. pjsip_param_shallow_clone(pool, &hdr->other_param, &rhs->other_param);
  105. return hdr;
  106. }
  107. /*
  108. * Parse Replaces header.
  109. */
  110. static pjsip_hdr *parse_hdr_replaces(pjsip_parse_ctx *ctx)
  111. {
  112. pjsip_replaces_hdr *hdr = pjsip_replaces_hdr_create(ctx->pool);
  113. const pj_str_t to_tag = { "to-tag", 6 };
  114. const pj_str_t from_tag = { "from-tag", 8 };
  115. const pj_str_t early_only_tag = { "early-only", 10 };
  116. /*pj_scan_get(ctx->scanner, &pjsip_TOKEN_SPEC, &hdr->call_id);*/
  117. /* Get Call-ID (until ';' is found). using pjsip_TOKEN_SPEC doesn't work
  118. * because it stops parsing when '@' character is found.
  119. */
  120. pj_scan_get_until_ch(ctx->scanner, ';', &hdr->call_id);
  121. while (*ctx->scanner->curptr == ';') {
  122. pj_str_t pname, pvalue;
  123. pj_scan_get_char(ctx->scanner);
  124. pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0);
  125. if (pj_stricmp(&pname, &to_tag)==0) {
  126. hdr->to_tag = pvalue;
  127. } else if (pj_stricmp(&pname, &from_tag)==0) {
  128. hdr->from_tag = pvalue;
  129. } else if (pj_stricmp(&pname, &early_only_tag)==0) {
  130. hdr->early_only = PJ_TRUE;
  131. } else {
  132. pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param);
  133. param->name = pname;
  134. param->value = pvalue;
  135. pj_list_push_back(&hdr->other_param, param);
  136. }
  137. }
  138. pjsip_parse_end_hdr_imp( ctx->scanner );
  139. return (pjsip_hdr*)hdr;
  140. }
  141. /* Deinitialize Replaces */
  142. static void pjsip_replaces_deinit_module(pjsip_endpoint *endpt)
  143. {
  144. PJ_TODO(provide_initialized_flag_for_each_endpoint);
  145. PJ_UNUSED_ARG(endpt);
  146. is_initialized = PJ_FALSE;
  147. }
  148. /*
  149. * Initialize Replaces support in PJSIP.
  150. */
  151. PJ_DEF(pj_status_t) pjsip_replaces_init_module(pjsip_endpoint *endpt)
  152. {
  153. pj_status_t status;
  154. const pj_str_t STR_REPLACES = { "replaces", 8 };
  155. the_endpt = endpt;
  156. if (is_initialized)
  157. return PJ_SUCCESS;
  158. /* Register Replaces header parser */
  159. status = pjsip_register_hdr_parser( "Replaces", NULL,
  160. &parse_hdr_replaces);
  161. if (status != PJ_SUCCESS)
  162. return status;
  163. /* Register "replaces" capability */
  164. status = pjsip_endpt_add_capability(endpt, NULL, PJSIP_H_SUPPORTED, NULL,
  165. 1, &STR_REPLACES);
  166. /* Register deinit module to be executed when PJLIB shutdown */
  167. if (pjsip_endpt_atexit(endpt, &pjsip_replaces_deinit_module) != PJ_SUCCESS)
  168. {
  169. /* Failure to register this function may cause this module won't
  170. * work properly when the stack is restarted (without quitting
  171. * application).
  172. */
  173. pj_assert(!"Failed to register Replaces deinit.");
  174. PJ_LOG(1, (THIS_FILE, "Failed to register Replaces deinit."));
  175. }
  176. is_initialized = PJ_TRUE;
  177. return PJ_SUCCESS;
  178. }
  179. /*
  180. * Verify that incoming request with Replaces header can be processed.
  181. */
  182. PJ_DEF(pj_status_t) pjsip_replaces_verify_request( pjsip_rx_data *rdata,
  183. pjsip_dialog **p_dlg,
  184. pj_bool_t lock_dlg,
  185. pjsip_tx_data **p_tdata)
  186. {
  187. const pj_str_t STR_REPLACES = { "Replaces", 8 };
  188. pjsip_replaces_hdr *rep_hdr;
  189. int code = 200;
  190. const char *warn_text = NULL;
  191. pjsip_hdr res_hdr_list;
  192. pjsip_dialog *dlg = NULL;
  193. pjsip_inv_session *inv;
  194. pj_status_t status = PJ_SUCCESS;
  195. PJ_ASSERT_RETURN(rdata && p_dlg, PJ_EINVAL);
  196. /* Check that pjsip_replaces_init_module() has been called. */
  197. PJ_ASSERT_RETURN(the_endpt != NULL, PJ_EINVALIDOP);
  198. /* Init output arguments */
  199. *p_dlg = NULL;
  200. if (p_tdata) *p_tdata = NULL;
  201. pj_list_init(&res_hdr_list);
  202. /* Find Replaces header */
  203. rep_hdr = (pjsip_replaces_hdr*)
  204. pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES,
  205. NULL);
  206. if (!rep_hdr) {
  207. /* No Replaces header. No further processing is necessary. */
  208. return PJ_SUCCESS;
  209. }
  210. /* Check that there's no other Replaces header and return 400 Bad Request
  211. * if not.
  212. */
  213. if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES,
  214. rep_hdr->next)) {
  215. code = PJSIP_SC_BAD_REQUEST;
  216. warn_text = "Found multiple Replaces headers";
  217. goto on_return;
  218. }
  219. /* Find the dialog identified by Replaces header (and always lock the
  220. * dialog no matter what application wants).
  221. */
  222. dlg = pjsip_ua_find_dialog(&rep_hdr->call_id, &rep_hdr->to_tag,
  223. &rep_hdr->from_tag, PJ_TRUE);
  224. /* Respond with 481 "Call/Transaction Does Not Exist" response if
  225. * no dialog is found.
  226. */
  227. if (dlg == NULL) {
  228. code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
  229. warn_text = "No dialog found for Replaces request";
  230. goto on_return;
  231. }
  232. /* Get the invite session within the dialog */
  233. inv = pjsip_dlg_get_inv_session(dlg);
  234. /* Return 481 if no invite session is present. */
  235. if (inv == NULL) {
  236. code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
  237. warn_text = "No INVITE session found for Replaces request";
  238. goto on_return;
  239. }
  240. /* Return 603 Declined response if invite session has already
  241. * terminated
  242. */
  243. if (inv->state >= PJSIP_INV_STATE_DISCONNECTED) {
  244. code = PJSIP_SC_DECLINE;
  245. warn_text = "INVITE session already terminated";
  246. goto on_return;
  247. }
  248. /* If "early-only" flag is present, check that the invite session
  249. * has not been confirmed yet. If the session has been confirmed,
  250. * return 486 "Busy Here" response.
  251. */
  252. if (rep_hdr->early_only && inv->state >= PJSIP_INV_STATE_CONNECTING) {
  253. code = PJSIP_SC_BUSY_HERE;
  254. warn_text = "INVITE session already established";
  255. goto on_return;
  256. }
  257. /* If the Replaces header field matches an early dialog that was not
  258. * initiated by this UA, it returns a 481 (Call/Transaction Does Not
  259. * Exist) response to the new INVITE.
  260. */
  261. if (inv->state <= PJSIP_INV_STATE_EARLY && inv->role != PJSIP_ROLE_UAC)
  262. {
  263. /* Really return 481 only if call haven't reached early state or
  264. * accept-replace-in-early-state (ticket #1587) is not allowed.
  265. */
  266. if (inv->state != PJSIP_INV_STATE_EARLY ||
  267. pjsip_cfg()->endpt.accept_replace_in_early_state == PJ_FALSE)
  268. {
  269. code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
  270. warn_text = "Found early INVITE session but not initiated by "
  271. "this UA";
  272. goto on_return;
  273. }
  274. }
  275. /*
  276. * Looks like everything is okay!!
  277. */
  278. *p_dlg = dlg;
  279. status = PJ_SUCCESS;
  280. code = 200;
  281. on_return:
  282. /* Create response if necessary */
  283. if (code != 200) {
  284. /* If we have dialog we must unlock it */
  285. if (dlg)
  286. pjsip_dlg_dec_lock(dlg);
  287. /* Create response */
  288. if (p_tdata) {
  289. pjsip_tx_data *tdata;
  290. const pjsip_hdr *h;
  291. status = pjsip_endpt_create_response(the_endpt, rdata, code,
  292. NULL, &tdata);
  293. if (status != PJ_SUCCESS)
  294. return status;
  295. /* Add response headers. */
  296. h = res_hdr_list.next;
  297. while (h != &res_hdr_list) {
  298. pjsip_hdr *cloned;
  299. cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
  300. PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
  301. pjsip_msg_add_hdr(tdata->msg, cloned);
  302. h = h->next;
  303. }
  304. /* Add warn text, if any */
  305. if (warn_text) {
  306. pjsip_warning_hdr *warn_hdr;
  307. pj_str_t warn_value = pj_str((char*)warn_text);
  308. warn_hdr=pjsip_warning_hdr_create(tdata->pool, 399,
  309. pjsip_endpt_name(the_endpt),
  310. &warn_value);
  311. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)warn_hdr);
  312. }
  313. *p_tdata = tdata;
  314. }
  315. /* Can not return PJ_SUCCESS when response message is produced.
  316. * Ref: PROTOS test ~#2490
  317. */
  318. if (status == PJ_SUCCESS)
  319. status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
  320. } else {
  321. /* If application doesn't want to lock the dialog, unlock it */
  322. if (!lock_dlg)
  323. pjsip_dlg_dec_lock(dlg);
  324. }
  325. return status;
  326. }