common.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /*
  2. * Copyright (C) 2009 Mamadou Diop.
  3. *
  4. * Contact: Mamadou Diop <diopmamadou(at)doubango.org>
  5. *
  6. * This file is part of Open Source Doubango Framework.
  7. *
  8. * DOUBANGO is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * DOUBANGO is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with DOUBANGO.
  20. *
  21. */
  22. #include "common.h"
  23. #include "invite.h"
  24. #include "message.h"
  25. #include "options.h"
  26. #include "publish.h"
  27. #include "register.h"
  28. #include "subscribe.h"
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. /* === default values === */
  33. #define DEFAULT_REALM "open-ims.test"
  34. #define DEFAULT_IMPI "bob@"DEFAULT_REALM
  35. #define DEFAULT_IMPU "sip:bob@"DEFAULT_REALM
  36. #ifndef DEFAULT_LOCAL_IP
  37. //# ifdef ANDROID /* On the emulator */
  38. //# define DEFAULT_LOCAL_IP "10.0.2.15"
  39. //# define DEFAULT_LOCAL_IP "192.168.0.14"
  40. //# else
  41. # define DEFAULT_LOCAL_IP TNET_SOCKET_HOST_ANY
  42. //# endif
  43. #endif
  44. extern ctx_t* ctx;
  45. int stack_callback(const tsip_event_t *sipevent);
  46. int session_handle_event(const tsip_event_t *sipevent);
  47. int session_tostring(const session_t* session);
  48. /* our SIP callback function */
  49. int stack_callback(const tsip_event_t *_event)
  50. {
  51. int ret = 0;
  52. if(!_event) { /* should never happen ...but who know? */
  53. TSK_DEBUG_WARN("Null SIP event.");
  54. return -1;
  55. }
  56. #if 0
  57. tsk_safeobj_lock(ctx);
  58. #endif
  59. switch(_event->type) {
  60. case tsip_event_register: {
  61. /* REGISTER */
  62. ret = register_handle_event(_event);
  63. break;
  64. }
  65. case tsip_event_invite: {
  66. /* INVITE */
  67. ret = invite_handle_event(_event);
  68. break;
  69. }
  70. case tsip_event_message: {
  71. /* MESSAGE */
  72. ret = message_handle_event(_event);
  73. break;
  74. }
  75. case tsip_event_options: {
  76. /* OPTIONS */
  77. ret = options_handle_event(_event);
  78. break;
  79. }
  80. case tsip_event_publish: {
  81. /* PUBLISH */
  82. ret = publish_handle_event(_event);
  83. break;
  84. }
  85. case tsip_event_subscribe: {
  86. /* SUBSCRIBE */
  87. ret = subscribe_handle_event(_event);
  88. break;
  89. }
  90. case tsip_event_dialog: {
  91. /* Common to all dialogs */
  92. ret = session_handle_event(_event);
  93. break;
  94. }
  95. case tsip_event_stack: {
  96. switch(_event->code) {
  97. case tsip_event_code_stack_started:
  98. TSK_DEBUG_INFO("Stack started");
  99. break;
  100. case tsip_event_code_stack_stopped:
  101. TSK_DEBUG_INFO("Stack stopped");
  102. break;
  103. case tsip_event_code_stack_failed_to_start:
  104. TSK_DEBUG_INFO("Stack failed to start");
  105. break;
  106. case tsip_event_code_stack_failed_to_stop:
  107. TSK_DEBUG_INFO("Stack failed to stop");
  108. break;
  109. }
  110. break;
  111. }
  112. default: {
  113. /* Unsupported */
  114. TSK_DEBUG_WARN("%d not supported as SIP event.", _event->type);
  115. ret = -3;
  116. break;
  117. }
  118. }
  119. #if 0
  120. tsk_safeobj_unlock(ctx);
  121. #endif
  122. return ret;
  123. }
  124. /* ==================================================================
  125. ========================== Context =================================
  126. */
  127. ctx_t* ctx_create()
  128. {
  129. return tsk_object_new(ctx_def_t);
  130. }
  131. static tsk_object_t* ctx_ctor(tsk_object_t * self, va_list * app)
  132. {
  133. ctx_t *ctx = self;
  134. if(ctx) {
  135. /* stack */
  136. ctx->stack = tsip_stack_create(stack_callback, DEFAULT_REALM, DEFAULT_IMPI, DEFAULT_IMPU, /* Mandatory parameters */
  137. TSIP_STACK_SET_LOCAL_IP(DEFAULT_LOCAL_IP), /* local IP */
  138. TSIP_STACK_SET_NULL() /* Mandatory */);
  139. /* SIP Sessions */
  140. ctx->sessions = tsk_list_create();
  141. /* user's parameters */
  142. ctx->params = tsk_list_create();
  143. /* init internal mutex */
  144. tsk_safeobj_init(ctx);
  145. }
  146. return self;
  147. }
  148. static tsk_object_t* ctx_dtor(tsk_object_t * self)
  149. {
  150. ctx_t *ctx = self;
  151. if(ctx) {
  152. /* Stop the stack (as sessions are alive, you will continue to receive callbacks)*/
  153. tsip_stack_stop(ctx->stack);
  154. /* sessions : should be freed before the stack as explained on the Programmer's Guide
  155. * As all dialogs have been hanged up, the list should be empty ...but who know?*/
  156. TSK_OBJECT_SAFE_FREE(ctx->sessions);
  157. /* Destroy the stack */
  158. TSK_OBJECT_SAFE_FREE(ctx->stack);
  159. /* Identity */
  160. TSK_FREE(ctx->identity.display_name);
  161. TSK_FREE(ctx->identity.impu);
  162. TSK_FREE(ctx->identity.preferred);
  163. TSK_FREE(ctx->identity.impi);
  164. TSK_FREE(ctx->identity.password);
  165. /* Network */
  166. TSK_FREE(ctx->network.local_ip);
  167. TSK_FREE(ctx->network.proxy_cscf);
  168. TSK_FREE(ctx->network.proxy_cscf_trans);
  169. TSK_FREE(ctx->network.realm);
  170. /* Security */
  171. TSK_FREE(ctx->security.operator_id);
  172. /* Params */
  173. TSK_OBJECT_SAFE_FREE(ctx->params);
  174. /* deinit internal mutex */
  175. tsk_safeobj_deinit(ctx);
  176. }
  177. return self;
  178. }
  179. static const tsk_object_def_t ctx_def_s = {
  180. sizeof(ctx_t),
  181. ctx_ctor,
  182. ctx_dtor,
  183. tsk_null,
  184. };
  185. const tsk_object_def_t *ctx_def_t = &ctx_def_s;
  186. /* ==================================================================
  187. ========================== Stack =================================
  188. */
  189. int stack_dump()
  190. {
  191. const tsk_list_item_t* item;
  192. tsk_list_foreach(item, ctx->sessions) {
  193. session_tostring(item->data);
  194. }
  195. return 0;
  196. }
  197. int stack_config(const opts_L_t* opts)
  198. {
  199. const tsk_list_item_t* item;
  200. const opt_t* opt;
  201. int ret = 0;
  202. tsk_param_t* param;
  203. tsk_bool_t pcscf_changed = tsk_false;
  204. tsk_bool_t stun_done = tsk_false;
  205. if(!opts) {
  206. return -1;
  207. }
  208. tsk_list_foreach(item, opts) {
  209. opt = item->data;
  210. /* Stack-level option */
  211. if(opt->lv != lv_none && opt->lv != lv_stack) {
  212. continue;
  213. }
  214. switch(opt->type) {
  215. case opt_amf: {
  216. break;
  217. }
  218. case opt_dhcpv4:
  219. case opt_dhcpv6: {
  220. tsip_stack_set(ctx->stack,
  221. TSIP_STACK_SET_DISCOVERY_DHCP(tsk_true),
  222. TSIP_STACK_SET_NULL());
  223. break;
  224. }
  225. case opt_dname: {
  226. break;
  227. }
  228. case opt_dns_naptr: {
  229. tsip_stack_set(ctx->stack,
  230. TSIP_STACK_SET_DISCOVERY_NAPTR(tsk_true),
  231. TSIP_STACK_SET_NULL());
  232. break;
  233. }
  234. case opt_header: {
  235. if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))) {
  236. ret = tsip_stack_set(ctx->stack,
  237. TSIP_STACK_SET_HEADER(param->name, param->value),
  238. TSIP_STACK_SET_NULL());
  239. TSK_OBJECT_SAFE_FREE(param);
  240. }
  241. break;
  242. }
  243. case opt_impi: {
  244. tsk_strupdate(&ctx->identity.impi, opt->value);
  245. ret = tsip_stack_set(ctx->stack,
  246. TSIP_STACK_SET_IMPI(ctx->identity.impi),
  247. TSIP_STACK_SET_NULL());
  248. break;
  249. }
  250. case opt_impu: {
  251. tsk_strupdate(&ctx->identity.impu, opt->value);
  252. ret = tsip_stack_set(ctx->stack,
  253. TSIP_STACK_SET_IMPU(ctx->identity.impu),
  254. TSIP_STACK_SET_NULL());
  255. break;
  256. }
  257. case opt_ipv6: {
  258. pcscf_changed = tsk_true;
  259. ctx->network.ipv6 = tsk_true;
  260. break;
  261. }
  262. case opt_local_ip: {
  263. ret = tsip_stack_set(ctx->stack,
  264. TSIP_STACK_SET_LOCAL_IP(opt->value),
  265. TSIP_STACK_SET_NULL());
  266. break;
  267. }
  268. case opt_local_port: {
  269. unsigned port = (unsigned)atoi(opt->value);
  270. ret = tsip_stack_set(ctx->stack,
  271. TSIP_STACK_SET_LOCAL_PORT(port),
  272. TSIP_STACK_SET_NULL());
  273. break;
  274. }
  275. case opt_opid: {
  276. break;
  277. }
  278. case opt_password: {
  279. ret = tsip_stack_set(ctx->stack,
  280. TSIP_STACK_SET_PASSWORD(opt->value),
  281. TSIP_STACK_SET_NULL());
  282. break;
  283. }
  284. case opt_pcscf_ip: {
  285. pcscf_changed = tsk_true;
  286. tsk_strupdate(&ctx->network.proxy_cscf, opt->value);
  287. break;
  288. }
  289. case opt_pcscf_port: {
  290. pcscf_changed = tsk_true;
  291. ctx->network.proxy_cscf_port = atoi(opt->value);
  292. break;
  293. }
  294. case opt_pcscf_trans: {
  295. pcscf_changed = tsk_true;
  296. tsk_strupdate(&ctx->network.proxy_cscf_trans, opt->value);
  297. break;
  298. }
  299. case opt_realm: {
  300. ret = tsip_stack_set(ctx->stack,
  301. TSIP_STACK_SET_REALM(opt->value),
  302. TSIP_STACK_SET_NULL());
  303. break;
  304. }
  305. case opt_sigcomp_id: {
  306. /* add compartment */
  307. ret = tsip_stack_set(ctx->stack,
  308. TSIP_STACK_SET_SIGCOMP_NEW_COMPARTMENT(opt->value),
  309. TSIP_STACK_SET_NULL());
  310. break;
  311. }
  312. case opt_stun_ip:
  313. case opt_stun_pwd:
  314. case opt_stun_port:
  315. case opt_stun_usr: {
  316. if(!stun_done) {
  317. const opt_t* _opt;
  318. const char* ip = tsk_null, *usr = tsk_null, *pwd = tsk_null;
  319. unsigned port = 0;
  320. if((_opt = opt_get_by_type(opts, opt_stun_ip))) {
  321. ip = _opt->value;
  322. }
  323. if((_opt = opt_get_by_type(opts, opt_stun_port))) {
  324. port = atoi(_opt->value);
  325. }
  326. if((_opt = opt_get_by_type(opts, opt_stun_usr))) {
  327. usr = _opt->value;
  328. }
  329. if((_opt = opt_get_by_type(opts, opt_stun_pwd))) {
  330. pwd = _opt->value;
  331. }
  332. if(ip && port) {
  333. tsip_stack_set(ctx->stack,
  334. TSIP_STACK_SET_STUN_SERVER(ip, port),
  335. TSIP_STACK_SET_NULL());
  336. }
  337. if(usr) {
  338. tsip_stack_set(ctx->stack,
  339. TSIP_STACK_SET_STUN_CRED(usr, pwd),
  340. TSIP_STACK_SET_NULL());
  341. }
  342. stun_done = tsk_true;
  343. }
  344. break;
  345. }
  346. }/* switch */
  347. } /* foreach */
  348. /* whether Proxy-CSCF config has changed */
  349. if(pcscf_changed) {
  350. ret = tsip_stack_set(ctx->stack,
  351. TSIP_STACK_SET_PROXY_CSCF(ctx->network.proxy_cscf, ctx->network.proxy_cscf_port, ctx->network.proxy_cscf_trans, ctx->network.ipv6 ? "ipv6" : "ipv4"),
  352. TSIP_STACK_SET_NULL());
  353. }
  354. return ret;
  355. }
  356. int stack_run(const opts_L_t* opts)
  357. {
  358. if(!ctx->stack) {
  359. TSK_DEBUG_ERROR("Stack is Null.");
  360. return -1;
  361. }
  362. else {
  363. return tsip_stack_start(ctx->stack);
  364. }
  365. }
  366. /* ==================================================================
  367. ========================== Session =================================
  368. */
  369. /* Find SIP session by id */
  370. int pred_find_session_by_id(const tsk_list_item_t *item, const void* id)
  371. {
  372. const session_t* session;
  373. if(item && item->data) {
  374. session = item->data;
  375. return (int)(tsip_ssession_get_id(session->handle)
  376. - *((tsip_ssession_id_t*)id));
  377. }
  378. return -1;
  379. }
  380. session_t* session_create(session_type_t type, tsip_ssession_handle_t* handle)
  381. {
  382. session_t* session = tsk_object_new(session_def_t, type, handle);
  383. if(!session) {
  384. TSK_DEBUG_ERROR("Failed to create new SIP session");
  385. return tsk_null;
  386. }
  387. switch(type) {
  388. case st_invite: {
  389. /* Enable all features (QoS, Session timers, SigComp, ...) */
  390. tsip_ssession_set(session->handle,
  391. TSIP_SSESSION_SET_USERDATA(session),
  392. /*=== MEDIA */
  393. TSIP_SSESSION_SET_MEDIA(
  394. // 100rel
  395. TSIP_MSESSION_SET_100rel(tsk_false),
  396. // Session timers
  397. TSIP_MSESSION_SET_TIMERS(3600, "uac"),
  398. // QoS
  399. TSIP_MSESSION_SET_QOS(tmedia_qos_stype_segmented, tmedia_qos_strength_optional),
  400. // close media params
  401. TSIP_MSESSION_SET_NULL()
  402. ),
  403. TSIP_SSESSION_SET_NULL());
  404. break;
  405. }
  406. default:
  407. break;
  408. }
  409. return session;
  410. }
  411. const session_t* session_get_by_sid(const sessions_L_t* sessions, tsip_ssession_id_t sid)
  412. {
  413. const tsk_list_item_t* item;
  414. if((item = tsk_list_find_item_by_pred(sessions, pred_find_session_by_id, &sid))) {
  415. return item->data;
  416. }
  417. else {
  418. return tsk_null;
  419. }
  420. }
  421. int session_tostring(const session_t* session)
  422. {
  423. //char* temp = tsk_null;
  424. printf("== Session: ");
  425. if(session) {
  426. /* Session Id */
  427. printf("sid=%llu", tsip_ssession_get_id(session->handle));
  428. /* Type */
  429. printf(" type=");
  430. switch(session->type) {
  431. case st_invite:
  432. printf("INVITE");
  433. break;
  434. case st_message:
  435. printf("MESSAGE");
  436. break;
  437. case st_publish:
  438. printf("PUBLISH");
  439. break;
  440. case st_register:
  441. printf("REGISTER");
  442. break;
  443. case st_subscribe:
  444. printf("SUBSCRIBE");
  445. break;
  446. default:
  447. printf("(null)");
  448. break;
  449. }
  450. /* From */
  451. printf(" from=%s", session->from ? session->from : ctx->identity.impu);
  452. /* From */
  453. printf(" to=%s", session->to ? session->to : ctx->identity.impu);
  454. }
  455. else {
  456. printf("(invalid)");
  457. }
  458. printf("\n");
  459. return -1;
  460. }
  461. /* handle events -common to all sessions */
  462. int session_handle_event(const tsip_event_t *_event)
  463. {
  464. const session_t* session;
  465. /* Find associated session */
  466. if(!(session = session_get_by_sid(ctx->sessions, tsip_ssession_get_id(_event->ss)))) {
  467. /* Silentky ignore */
  468. return 0;
  469. }
  470. switch(_event->code) {
  471. /* === 7xx ==> errors === */
  472. case tsip_event_code_dialog_transport_error:
  473. case tsip_event_code_dialog_global_error:
  474. case tsip_event_code_dialog_message_error:
  475. /* do not guess that the dialog is terminated, wait for "tsip_event_code_dialog_terminated" event */
  476. break;
  477. /* === 8xx ==> success === */
  478. case tsip_event_code_dialog_request_incoming:
  479. case tsip_event_code_dialog_request_cancelled:
  480. case tsip_event_code_dialog_request_sent:
  481. break;
  482. /* === 9xx ==> Informational === */
  483. case tsip_event_code_dialog_terminated: {
  484. /* we no longer need the session
  485. * -> remove and destroy the session */
  486. TSK_DEBUG_INFO("Dialog Terminated --> %s", _event->phrase);
  487. tsk_list_remove_item_by_data(ctx->sessions, session);
  488. break;
  489. }
  490. case tsip_event_code_dialog_connected:
  491. ((session_t*)session)->connected = tsk_true;
  492. break;
  493. case tsip_event_code_dialog_terminating:
  494. break;
  495. }
  496. return 0;
  497. }
  498. /* handle commands -common to all sessions */
  499. const session_t* session_handle_cmd(cmd_type_t cmd, const opts_L_t* opts)
  500. {
  501. const session_t* session = tsk_null;
  502. const opt_t* opt;
  503. const tsk_list_item_t* item;
  504. tsk_param_t* param;
  505. int ret = 0;
  506. /* Check if there is a session with is Id */
  507. if((opt = opt_get_by_type(opts, opt_sid))) {
  508. tsip_ssession_id_t sid = atoi(opt->value);
  509. session = session_get_by_sid(ctx->sessions, sid);
  510. }
  511. #define TYPE_FROM_CMD(_CMD) \
  512. ((_CMD==cmd_audio || _CMD==cmd_video || _CMD==cmd_audiovideo || _CMD==cmd_file || _CMD==cmd_large_message) ? st_invite : \
  513. ((_CMD==cmd_message || _CMD==cmd_sms) ? st_message : \
  514. (_CMD==cmd_options ? st_options : \
  515. (_CMD==cmd_publish ? st_publish : \
  516. (_CMD==cmd_register ? st_register : \
  517. (_CMD==cmd_subscribe ? st_subscribe : st_none))))))
  518. /* === Command === */
  519. switch(cmd) {
  520. case cmd_audio:
  521. case cmd_video:
  522. case cmd_audiovideo:
  523. case cmd_file:
  524. case cmd_large_message:
  525. case cmd_message:
  526. case cmd_sms:
  527. case cmd_options:
  528. case cmd_publish:
  529. case cmd_register:
  530. case cmd_subscribe: {
  531. if(!session) { /* Create "client-side-session" */
  532. session_t* _session;
  533. if((_session = session_client_create(TYPE_FROM_CMD(cmd))) && (session = _session)) {
  534. tsk_list_push_back_data(ctx->sessions, (void**)&_session);
  535. }
  536. }
  537. break;
  538. }
  539. default: {
  540. if(session) {
  541. /* hold, resume, refer, update, ...all in-dialog commands */
  542. break;
  543. }
  544. else {
  545. TSK_DEBUG_WARN("Session handling: Cannot handle this command [%d]", cmd);
  546. goto bail;
  547. }
  548. }
  549. } /* switch */
  550. if(!session) {
  551. TSK_DEBUG_ERROR("SIP Session is Null");
  552. goto bail;
  553. }
  554. /* === User Options === */
  555. tsk_list_foreach(item, opts) {
  556. opt = item->data;
  557. /* Session-level option? */
  558. if(opt->lv != lv_none && opt->lv != lv_session) {
  559. continue;
  560. }
  561. switch(opt->type) {
  562. case opt_caps: {
  563. if(!tsk_strnullORempty(opt->value)) {
  564. if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))) {
  565. ret = tsip_ssession_set(session->handle,
  566. TSIP_SSESSION_SET_CAPS(param->name, param->value),
  567. TSIP_SSESSION_SET_NULL());
  568. TSK_OBJECT_SAFE_FREE(param);
  569. }
  570. }
  571. break;
  572. }
  573. case opt_expires: {
  574. if(!tsk_strnullORempty(opt->value)) {
  575. unsigned expires = atoi(opt->value);
  576. ret = tsip_ssession_set(session->handle,
  577. TSIP_SSESSION_SET_EXPIRES(expires),
  578. TSIP_SSESSION_SET_NULL());
  579. }
  580. break;
  581. }
  582. case opt_from: {
  583. /* You should use TSIP_SSESSION_SET_OPTION(TSIP_SSESSION_OPTION_FROM, value)
  584. instead of TSIP_SSESSION_SET_HEADER() to set the destination URI. */
  585. break;
  586. }
  587. case opt_header: {
  588. if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))) {
  589. ret = tsip_ssession_set(session->handle,
  590. TSIP_SSESSION_SET_HEADER(param->name, param->value),
  591. TSIP_SSESSION_SET_NULL());
  592. TSK_OBJECT_SAFE_FREE(param);
  593. }
  594. break;
  595. }
  596. case opt_payload: {
  597. /* Will be handled by the caller */
  598. break;
  599. }
  600. case opt_silent: {
  601. /* valueless option */
  602. ret = tsip_ssession_set(session->handle,
  603. TSIP_SSESSION_SET_SILENT_HANGUP(tsk_true),
  604. TSIP_SSESSION_SET_NULL());
  605. break;
  606. }
  607. case opt_sigcomp_id: {
  608. /* sigcomp-id */
  609. ret = tsip_ssession_set(session->handle,
  610. TSIP_SSESSION_SET_SIGCOMP_COMPARTMENT(opt->value),
  611. TSIP_SSESSION_SET_NULL());
  612. break;
  613. }
  614. case opt_to: {
  615. /* You should use TSIP_SSESSION_SET_OPTION(TSIP_SSESSION_OPTION_TO, value)
  616. instead of TSIP_SSESSION_SET_HEADER() to set the destination URI. */
  617. if((cmd != cmd_sms) && (cmd != cmd_ect) && !tsk_strnullORempty(opt->value)) { /* SMS will use SMSC Address as Request URI */
  618. ret = tsip_ssession_set(session->handle,
  619. TSIP_SSESSION_SET_TO(opt->value),
  620. TSIP_SSESSION_SET_NULL());
  621. }
  622. break;
  623. }
  624. default: {
  625. /* will be handled by the caller */
  626. break;
  627. }
  628. }
  629. } /* foreach */
  630. bail:
  631. return session;
  632. }
  633. int session_hangup(tsip_ssession_id_t sid)
  634. {
  635. const session_t* session;
  636. if((session = session_get_by_sid(ctx->sessions, sid))) {
  637. switch(session->type) {
  638. case st_invite:
  639. tsip_api_invite_send_bye(session->handle,
  640. /* You can add your parameters */
  641. TSIP_ACTION_SET_NULL());
  642. break;
  643. case st_message:
  644. break;
  645. case st_publish:
  646. tsip_api_publish_send_unpublish(session->handle,
  647. /* You can add your parameters */
  648. TSIP_ACTION_SET_NULL());
  649. break;
  650. case st_register:
  651. tsip_api_register_send_unregister(session->handle,
  652. /* You can add your parameters */
  653. TSIP_ACTION_SET_NULL());
  654. break;
  655. case st_subscribe:
  656. tsip_api_subscribe_send_unsubscribe(session->handle,
  657. /* You can add your parameters */
  658. TSIP_ACTION_SET_NULL());
  659. break;
  660. default:
  661. TSK_DEBUG_WARN("Cannot hangup session with this type [%d]", session->type);
  662. return -2;
  663. }
  664. return 0;
  665. }
  666. else {
  667. TSK_DEBUG_WARN("Failed to find session with sid=%llu", sid);
  668. return -1;
  669. }
  670. }
  671. static tsk_object_t* session_ctor(tsk_object_t * self, va_list * app)
  672. {
  673. session_t *session = self;
  674. if(session) {
  675. session->type = va_arg(*app, session_type_t);
  676. if((session->handle = va_arg(*app, tsip_ssession_handle_t*))) {
  677. int ret;
  678. /* "server-side-session" */
  679. if((ret = tsip_ssession_take_ownership(session->handle))) {
  680. TSK_DEBUG_ERROR("Failed to take ownership [%d]", ret);
  681. }
  682. }
  683. else {
  684. /* "client-side-session" */
  685. session->handle = tsip_ssession_create(ctx->stack,
  686. TSIP_SSESSION_SET_NULL());
  687. }
  688. }
  689. return self;
  690. }
  691. static tsk_object_t* session_dtor(tsk_object_t * self)
  692. {
  693. session_t *session = self;
  694. if(session) {
  695. TSK_OBJECT_SAFE_FREE(session->handle);
  696. TSK_FREE(session->to);
  697. TSK_FREE(session->from);
  698. }
  699. return self;
  700. }
  701. static int session_cmp(const tsk_object_t *_ss1, const tsk_object_t *_ss2)
  702. {
  703. const session_t *ss1 = _ss1;
  704. const session_t *ss2 = _ss2;
  705. if(ss1 && ss1) {
  706. if(ss1->handle && ss2->handle) {
  707. return tsk_object_cmp(ss1->handle, ss2->handle);
  708. }
  709. else {
  710. return (ss2 - ss1);
  711. }
  712. }
  713. else if(!ss1 && !ss2) {
  714. return 0;
  715. }
  716. else {
  717. return -1;
  718. }
  719. }
  720. static const tsk_object_def_t session_def_s = {
  721. sizeof(session_t),
  722. session_ctor,
  723. session_dtor,
  724. session_cmp,
  725. };
  726. const tsk_object_def_t *session_def_t = &session_def_s;
  727. tsip_action_handle_t* action_get_config(const opts_L_t* opts)
  728. {
  729. const opt_t* opt;
  730. const tsk_list_item_t* item;
  731. tsip_action_handle_t* action_config = tsk_null;
  732. tsk_param_t* param;
  733. if(TSK_LIST_IS_EMPTY(opts)) {
  734. return tsk_null;
  735. }
  736. tsk_list_foreach(item, opts) {
  737. opt = item->data;
  738. /* action level? */
  739. if(opt->lv != lv_action) {
  740. continue;
  741. }
  742. /* create new action */
  743. if(!action_config && !(action_config = tsip_action_create(tsip_atype_config,
  744. TSIP_ACTION_SET_NULL()))) {
  745. break;
  746. }
  747. switch(opt->type) {
  748. case opt_header: {
  749. if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))) {
  750. tsip_action_set(action_config,
  751. TSIP_ACTION_SET_HEADER(param->name, param->value),
  752. TSIP_ACTION_SET_NULL());
  753. TSK_OBJECT_SAFE_FREE(param);
  754. }
  755. break;
  756. }
  757. case opt_payload: {
  758. tsip_action_set(action_config,
  759. TSIP_ACTION_SET_PAYLOAD(opt->value, tsk_strlen(opt->value)),
  760. TSIP_ACTION_SET_NULL());
  761. break;
  762. }
  763. default: {
  764. break;
  765. }
  766. }
  767. }
  768. return action_config;
  769. }