qos_ctx_helpers.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2007 SOMA Networks, Inc.
  5. * Written by Ovidiu Sas (osas)
  6. *
  7. * This file is part of Kamailio, a free SIP server.
  8. *
  9. * Kamailio is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version
  13. *
  14. * Kamailio is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * History:
  24. * -------
  25. * 2007-07-16 initial version (osas)
  26. */
  27. #include "../../mem/mem.h"
  28. #include "../../mem/shm_mem.h"
  29. #include "../../parser/sdp/sdp_cloner.h"
  30. #include "../dialog/dlg_hash.h"
  31. #include "qos_ctx_helpers.h"
  32. #define ERROR_MATCH -1
  33. #define NO_INVITE_REQ_MATCH 0
  34. #define NO_INVITE_RESP_MATCH 1
  35. #define PENDING_MATCH 2
  36. #define NEGOTIATED_MATCH 3
  37. #define NO_ACK_REQ_MATCH 4
  38. #define NO_UPDATE_REQ_MATCH 7
  39. #define NO_UPDATE_RESP_MATCH 8
  40. #define N_UNKNOWN 0
  41. /* INVITE/200_ok */
  42. #define N_INVITE_200OK 1
  43. /* 200_ok/ACK */
  44. #define N_200OK_ACK 2
  45. /* early media (http://www.ietf.org/rfc/rfc3959.txt) */
  46. /* 183_early_media/PRACK */
  47. #define N_183_PRACK 3
  48. qos_ctx_t *build_new_qos_ctx(void) {
  49. qos_ctx_t *ctx = NULL;
  50. ctx = (qos_ctx_t *)shm_malloc(sizeof(qos_ctx_t));
  51. if (ctx!=NULL) {
  52. memset(ctx, 0, sizeof(qos_ctx_t));
  53. } else {
  54. LM_ERR("No enough shared memory\n");
  55. return NULL;
  56. }
  57. if (!lock_init(&ctx->lock)) {
  58. shm_free(ctx);
  59. return NULL;
  60. }
  61. return ctx;
  62. }
  63. void destroy_qos(qos_sdp_t *qos_sdp)
  64. {
  65. free_cloned_sdp_session(qos_sdp->sdp_session[0]);
  66. free_cloned_sdp_session(qos_sdp->sdp_session[1]);
  67. shm_free(qos_sdp);
  68. return;
  69. }
  70. void print_qos_sdp(qos_sdp_t *qos_sdp)
  71. {
  72. if (qos_sdp == NULL) {
  73. return;
  74. }
  75. LM_DBG("[%p] prev->%p next->%p method_dir=%d method_id=%d method='%.*s' cseq='%.*s' negotiation=%d sdp[0:QOS_CALLER]=%p sdp[1:QOS_CALLEE]=%p\n",
  76. qos_sdp, qos_sdp->prev, qos_sdp->next, qos_sdp->method_dir, qos_sdp->method_id,
  77. qos_sdp->method.len ,qos_sdp->method.s, qos_sdp->cseq.len, qos_sdp->cseq.s,
  78. qos_sdp->negotiation, qos_sdp->sdp_session[0], qos_sdp->sdp_session[1]);
  79. /* print_sdp_session(qos_sdp->sdp_session[0]); */
  80. /* print_sdp_session(qos_sdp->sdp_session[1]); */
  81. }
  82. /*
  83. * Find a matching sdp inside the local qos_ctx
  84. * for the given session received via message _m with the given direction, cseq and method
  85. * and return the type of the match and a pointer to the matched qos_sdp so we can properly insert the given session into the qos_ctx->qos_sdp.
  86. */
  87. int find_qos_sdp(qos_ctx_t *qos_ctx, unsigned int dir, unsigned int other_role, str *cseq_number, int cseq_method_id, sdp_session_cell_t *session, struct sip_msg *_m, qos_sdp_t **_qos_sdp)
  88. {
  89. qos_sdp_t *qos_sdp;
  90. str *received_cnt_disp, *local_cnt_disp;
  91. LM_DBG("received session: %p and other_role: %s\n", session, (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  92. switch (_m->first_line.type) {
  93. case SIP_REQUEST:
  94. switch (cseq_method_id) {
  95. case METHOD_INVITE:
  96. return NO_INVITE_REQ_MATCH;
  97. break;
  98. case METHOD_ACK:
  99. /* searching into the pending_sdp list */
  100. qos_sdp = qos_ctx->pending_sdp;
  101. LM_DBG("searching the negotiated_sdp: %p\n", qos_sdp);
  102. while (qos_sdp) {
  103. if (METHOD_INVITE == qos_sdp->method_id && dir != qos_sdp->method_dir && qos_sdp->negotiation == N_200OK_ACK &&
  104. cseq_number->len == qos_sdp->cseq.len && 0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
  105. LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
  106. qos_sdp, qos_sdp->sdp_session[other_role]);
  107. /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
  108. if (qos_sdp->sdp_session[other_role] != NULL) {
  109. local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
  110. received_cnt_disp = &(session->cnt_disp);
  111. if (local_cnt_disp->len == received_cnt_disp->len) {
  112. if (local_cnt_disp->len == 0) {
  113. LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
  114. *_qos_sdp = qos_sdp;
  115. return PENDING_MATCH;
  116. } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
  117. LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
  118. *_qos_sdp = qos_sdp;
  119. return PENDING_MATCH;
  120. }
  121. } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
  122. 0==strncmp(local_cnt_disp->s, "session", 7)) {
  123. /* We may have an offer with cnt_disp='session' and an answer with cnt_disp='' */
  124. *_qos_sdp = qos_sdp;
  125. return PENDING_MATCH;
  126. }
  127. } else {
  128. LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  129. }
  130. }
  131. qos_sdp = qos_sdp->next;
  132. }
  133. return NO_ACK_REQ_MATCH;
  134. break;
  135. case METHOD_UPDATE:
  136. return NO_UPDATE_REQ_MATCH;
  137. break;
  138. case METHOD_PRACK:
  139. LM_ERR("PRACK not implemented yet\n");
  140. return ERROR_MATCH;
  141. break;
  142. default:
  143. LM_ERR("Unexpected method id %d\n", cseq_method_id);
  144. return ERROR_MATCH;
  145. }
  146. break;
  147. case SIP_REPLY:
  148. switch (cseq_method_id) {
  149. case METHOD_INVITE:
  150. /* searching into the pending_sdp list */
  151. qos_sdp = qos_ctx->pending_sdp;
  152. while (qos_sdp) {
  153. //print_qos_sdp(qos_sdp);
  154. if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
  155. qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
  156. 0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
  157. LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
  158. qos_sdp, qos_sdp->sdp_session[other_role]);
  159. /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
  160. if (qos_sdp->sdp_session[other_role] != NULL) {
  161. local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
  162. received_cnt_disp = &(session->cnt_disp);
  163. if (local_cnt_disp->len == received_cnt_disp->len) {
  164. if (local_cnt_disp->len == 0) {
  165. LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
  166. *_qos_sdp = qos_sdp;
  167. return PENDING_MATCH;
  168. } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
  169. LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
  170. *_qos_sdp = qos_sdp;
  171. return PENDING_MATCH;
  172. }
  173. } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
  174. 0==strncmp(local_cnt_disp->s, "session", 7)) {
  175. /* We have an offer with cnt_disp='session' and an answer with cnt_disp='' */
  176. *_qos_sdp = qos_sdp;
  177. return PENDING_MATCH;
  178. }
  179. } else {
  180. LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  181. }
  182. }
  183. qos_sdp = qos_sdp->next;
  184. }
  185. /* searching into the negotiated_sdp list */
  186. qos_sdp = qos_ctx->negotiated_sdp;
  187. LM_DBG("searching the negotiated_sdp: %p\n", qos_sdp);
  188. while (qos_sdp) {
  189. //print_qos_sdp(qos_sdp);
  190. if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
  191. qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
  192. 0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
  193. LM_DBG("method_id, dir and cseq match with previous session %p\n", qos_sdp->sdp_session[other_role]);
  194. if (qos_sdp->sdp_session[other_role] != NULL) {
  195. local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
  196. received_cnt_disp = &(session->cnt_disp);
  197. if (local_cnt_disp->len == received_cnt_disp->len) {
  198. if (local_cnt_disp->len == 0) {
  199. LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
  200. *_qos_sdp = qos_sdp;
  201. return NEGOTIATED_MATCH;
  202. } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
  203. LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
  204. *_qos_sdp = qos_sdp;
  205. return NEGOTIATED_MATCH;
  206. }
  207. } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
  208. 0==strncasecmp(local_cnt_disp->s, "session", 7)) {
  209. /* We have an offer with cnt_disp='session' and an answer with cnt_disp='' */
  210. *_qos_sdp = qos_sdp;
  211. return NEGOTIATED_MATCH;
  212. }
  213. } else {
  214. LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  215. }
  216. }
  217. qos_sdp = qos_sdp->next;
  218. }
  219. return NO_INVITE_RESP_MATCH;
  220. break;
  221. case METHOD_UPDATE:
  222. LM_ERR("FIXME\n");
  223. return NO_UPDATE_RESP_MATCH;
  224. break;
  225. default:
  226. LM_ERR("Unexpected reply for method id %d\n", cseq_method_id);
  227. return ERROR_MATCH;
  228. }
  229. break;
  230. default:
  231. LM_ERR("Unknown SIP message type: %d\n", _m->first_line.type);
  232. return ERROR_MATCH;
  233. }
  234. LM_ERR("FIXME: out of case\n");
  235. return ERROR_MATCH;
  236. }
  237. void link_pending_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
  238. {
  239. if (qos_sdp->prev != NULL) LM_ERR("got qos_sdp->prev=%p\n", qos_sdp->prev);
  240. if (qos_sdp->next != NULL) LM_ERR("got qos_sdp->next=%p\n", qos_sdp->next);
  241. if (qos_ctx->pending_sdp) {
  242. LM_DBG("Adding pending qos_sdp: %p\n", qos_sdp);
  243. if (qos_ctx->pending_sdp->prev != NULL) LM_ERR("got qos_ctx->pending_sdp->prev=%p\n", qos_ctx->pending_sdp->prev);
  244. qos_sdp->next = qos_ctx->pending_sdp;
  245. qos_ctx->pending_sdp->prev = qos_sdp;
  246. qos_ctx->pending_sdp = qos_sdp;
  247. } else {
  248. LM_DBG("Inserting pending qos_sdp: %p\n", qos_sdp);
  249. qos_ctx->pending_sdp = qos_sdp;
  250. }
  251. }
  252. void unlink_pending_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
  253. {
  254. if (qos_sdp->next)
  255. qos_sdp->next->prev = qos_sdp->prev;
  256. if (qos_sdp->prev)
  257. qos_sdp->prev->next = qos_sdp->next;
  258. else
  259. qos_ctx->pending_sdp = qos_sdp->next;
  260. qos_sdp->next = qos_sdp->prev = NULL;
  261. }
  262. void unlink_negotiated_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
  263. {
  264. if (qos_sdp->next)
  265. qos_sdp->next->prev = qos_sdp->prev;
  266. if (qos_sdp->prev)
  267. qos_sdp->prev->next = qos_sdp->next;
  268. else
  269. qos_ctx->negotiated_sdp = qos_sdp->next;
  270. qos_sdp->next = qos_sdp->prev = NULL;
  271. }
  272. void link_negotiated_qos_sdp_and_run_cb(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp, unsigned int role, struct sip_msg *_m)
  273. {
  274. qos_sdp_t *next_qos_sdp;
  275. qos_sdp_t *temp_qos_sdp = qos_ctx->negotiated_sdp;
  276. if (qos_sdp->prev != NULL) LM_ERR("got qos_sdp->prev=%p\n", qos_sdp->prev);
  277. if (qos_sdp->next != NULL) LM_ERR("got qos_sdp->next=%p\n", qos_sdp->next);
  278. if (temp_qos_sdp) {
  279. while (temp_qos_sdp) {
  280. next_qos_sdp = temp_qos_sdp->next;
  281. if (qos_sdp->negotiation == temp_qos_sdp->negotiation) {
  282. LM_DBG("run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx=%p, temp_qos_sdp=%p, role=%d, _m=%p)\n",
  283. qos_ctx, temp_qos_sdp, role, _m);
  284. run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx, temp_qos_sdp, role, _m);
  285. unlink_negotiated_qos_sdp(qos_ctx, temp_qos_sdp);
  286. destroy_qos(temp_qos_sdp);
  287. break;
  288. }
  289. temp_qos_sdp = next_qos_sdp;
  290. }
  291. if (qos_ctx->negotiated_sdp) {
  292. LM_DBG("Adding negotiated qos_sdp: %p\n", qos_sdp);
  293. if (qos_ctx->negotiated_sdp->prev != NULL) LM_ERR("got qos_ctx->negotiated_sdp->prev=%p\n", qos_ctx->negotiated_sdp->prev);
  294. qos_sdp->next = qos_ctx->negotiated_sdp;
  295. qos_ctx->negotiated_sdp->prev = qos_sdp;
  296. qos_ctx->negotiated_sdp = qos_sdp;
  297. } else {
  298. LM_DBG("Inserting negotiated qos_sdp: %p\n", qos_sdp);
  299. qos_ctx->negotiated_sdp = qos_sdp;
  300. }
  301. } else {
  302. LM_DBG("Inserting first negotiated qos_sdp: %p\n", qos_sdp);
  303. qos_ctx->negotiated_sdp = qos_sdp;
  304. }
  305. LM_DBG("run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
  306. qos_ctx, qos_sdp, role, _m);
  307. run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx, qos_sdp, role, _m);
  308. }
  309. int add_pending_sdp_session(qos_ctx_t *qos_ctx, unsigned int dir, str *cseq_number, str *cseq_method, int cseq_method_id,
  310. unsigned int role, unsigned int negotiation, sdp_session_cell_t *session, struct sip_msg *_m)
  311. {
  312. unsigned int len;
  313. sdp_session_cell_t *cloned_session;
  314. qos_sdp_t *qos_sdp;
  315. char *p;
  316. len = sizeof(qos_sdp_t) + cseq_method->len + cseq_number->len;
  317. qos_sdp = (qos_sdp_t *)shm_malloc(len);
  318. LM_DBG("alloc qos_sdp: %p\n", qos_sdp);
  319. if (qos_sdp==NULL) {
  320. LM_ERR("oom %d\n", len);
  321. return -1;
  322. } else {
  323. memset(qos_sdp, 0, len);
  324. LM_DBG("Allocated memory for qos_sdp: %p\n", qos_sdp);
  325. cloned_session = clone_sdp_session_cell(session);
  326. if (cloned_session==NULL) {
  327. shm_free(qos_sdp);
  328. LM_DBG("free qos_sdp: %p\n", qos_sdp);
  329. return -1;
  330. }
  331. qos_sdp->sdp_session[role] = cloned_session;
  332. LM_DBG("qos_sdp->sdp_session[%d]=%p\n", role, qos_sdp->sdp_session[role]);
  333. if (_m->first_line.type == SIP_REQUEST) {
  334. qos_sdp->method_dir = dir;
  335. } else {
  336. /* This is a SIP_REPLY and we need to set
  337. * the direction for the SIP_REQUEST */
  338. if (dir==DLG_DIR_UPSTREAM)
  339. qos_sdp->method_dir = DLG_DIR_DOWNSTREAM;
  340. else
  341. qos_sdp->method_dir = DLG_DIR_UPSTREAM;
  342. }
  343. qos_sdp->method_id = cseq_method_id;
  344. qos_sdp->negotiation = negotiation;
  345. p = (char*)(qos_sdp+1);
  346. qos_sdp->method.s = p;
  347. qos_sdp->method.len = cseq_method->len;
  348. memcpy( p, cseq_method->s, cseq_method->len);
  349. p += cseq_method->len;
  350. qos_sdp->cseq.s = p;
  351. qos_sdp->cseq.len = cseq_number->len;
  352. memcpy( p,cseq_number->s, cseq_number->len);
  353. /* p += cseq_number->len; */
  354. link_pending_qos_sdp(qos_ctx, qos_sdp);
  355. LM_DBG("run_qos_callbacks(QOSCB_ADD_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
  356. qos_ctx, qos_sdp, role, _m);
  357. run_qos_callbacks(QOSCB_ADD_SDP, qos_ctx, qos_sdp, role, _m);
  358. }
  359. return 0;
  360. }
  361. /*
  362. * Add the sdp carried by the given SIP message into the qos context.
  363. */
  364. void add_sdp(qos_ctx_t *qos_ctx, unsigned int dir, struct sip_msg *_m, unsigned int role, unsigned int other_role)
  365. {
  366. qos_sdp_t *qos_sdp;
  367. sdp_session_cell_t *recv_session;
  368. str *cseq_number, *cseq_method;
  369. int cseq_method_id, sdp_match;
  370. if ( (!_m->cseq && parse_headers(_m,HDR_CSEQ_F,0)<0) || !_m->cseq || !_m->cseq->parsed) {
  371. LM_ERR("bad sip message or missing CSeq hdr\n");
  372. return;
  373. }
  374. cseq_number = &((get_cseq(_m))->number);
  375. cseq_method = &((get_cseq(_m))->method);
  376. cseq_method_id = (get_cseq(_m))->method_id;
  377. LM_DBG("cseq=`%.*s' `%.*s' and dir=%d\n",
  378. cseq_number->len, cseq_number->s,
  379. cseq_method->len, cseq_method->s, dir);
  380. /* Let's iterate through all the received sessions */
  381. recv_session = ((sdp_info_t*)_m->body)->sessions;
  382. while(recv_session) {
  383. qos_sdp = NULL;
  384. sdp_match = find_qos_sdp(qos_ctx, dir, other_role, cseq_number, cseq_method_id, recv_session, _m, &qos_sdp);
  385. switch (sdp_match) {
  386. case NO_INVITE_REQ_MATCH:
  387. if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_INVITE_200OK, recv_session, _m)) {
  388. LM_ERR("Unable to add new sdp session\n");
  389. goto error;
  390. }
  391. break;
  392. case NO_INVITE_RESP_MATCH:
  393. if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_200OK_ACK, recv_session, _m)) {
  394. LM_ERR("Unable to add new sdp session\n");
  395. goto error;
  396. }
  397. break;
  398. case ERROR_MATCH:
  399. case NO_ACK_REQ_MATCH:
  400. case NO_UPDATE_REQ_MATCH:
  401. case NO_UPDATE_RESP_MATCH:
  402. LM_ERR("error match: %d\n", sdp_match);
  403. break;
  404. case PENDING_MATCH:
  405. LM_DBG("we have a pending match: %p\n", qos_sdp);
  406. /* Let's save the received session */
  407. qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session);
  408. if (qos_sdp->sdp_session[role] == NULL) {
  409. LM_ERR("PENDING_MATCH:oom: Unable to add new sdp session\n");
  410. return;
  411. }
  412. /* Negotiation completed, need to move the established SDP into the negotiated_sdp */
  413. /* removing qos_sdp from qos_ctx->pending_sdp list */
  414. unlink_pending_qos_sdp(qos_ctx, qos_sdp);
  415. /* inserting qos_sdp into the qos_ctx->negotiated_sdp list */
  416. link_negotiated_qos_sdp_and_run_cb(qos_ctx, qos_sdp, role, _m);
  417. break;
  418. case NEGOTIATED_MATCH:
  419. LM_DBG("we have a negotiated match: %p\n", qos_sdp);
  420. /* some sanity checks */
  421. if (qos_sdp->sdp_session[role]) {
  422. free_cloned_sdp_session(qos_sdp->sdp_session[role]);
  423. } else {
  424. LM_ERR("missing sdp_session for %s\n", (role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  425. }
  426. /* Let's save the received session */
  427. qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session);
  428. if (qos_sdp->sdp_session[role] == NULL) {
  429. LM_ERR("NEGOTIATED_MATCH:oom: Unable to add new sdp session\n");
  430. return;
  431. }
  432. LM_DBG("run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
  433. qos_ctx, qos_sdp, role, _m);
  434. run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx, qos_sdp, role, _m);
  435. break;
  436. default:
  437. LM_CRIT("Undefined return code from find_qos_sdp(): %d\n", sdp_match);
  438. }
  439. recv_session = recv_session->next;
  440. }
  441. return;
  442. error:
  443. shm_free(qos_sdp);
  444. LM_DBG("free qos_sdp: %p\n", qos_sdp);
  445. return;
  446. }
  447. /*
  448. * Remove the sdp previously added.
  449. */
  450. void remove_sdp(qos_ctx_t *qos_ctx, unsigned int dir, struct sip_msg *_m, unsigned int role, unsigned int other_role)
  451. {
  452. str *cseq_number;
  453. int cseq_method_id;
  454. qos_sdp_t *qos_sdp;
  455. if ( (!_m->cseq && parse_headers(_m,HDR_CSEQ_F,0)<0) || !_m->cseq || !_m->cseq->parsed) {
  456. LM_ERR("bad sip message or missing CSeq hdr\n");
  457. return;
  458. }
  459. cseq_number = &((get_cseq(_m))->number);
  460. cseq_method_id = (get_cseq(_m))->method_id;
  461. if (_m->first_line.type == SIP_REPLY) {
  462. switch (cseq_method_id) {
  463. case METHOD_INVITE:
  464. case METHOD_UPDATE:
  465. /* searching into the pending_sdp list only */
  466. qos_sdp = qos_ctx->pending_sdp;
  467. while (qos_sdp) {
  468. qos_sdp = qos_sdp->next;
  469. if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
  470. qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
  471. 0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
  472. LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
  473. qos_sdp, qos_sdp->sdp_session[other_role]);
  474. /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
  475. if (qos_sdp->sdp_session[other_role] != NULL) {
  476. LM_DBG("run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
  477. qos_ctx, qos_sdp, role, _m);
  478. run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx, qos_sdp, role, _m);
  479. unlink_negotiated_qos_sdp(qos_ctx, qos_sdp);
  480. /* Here we free up the pending qos_sdp */
  481. destroy_qos(qos_sdp);
  482. continue;
  483. } else {
  484. LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
  485. }
  486. }
  487. } /* end while (qos_sdp) */
  488. break;
  489. default:
  490. LM_ERR("Unexpected method id %d\n", cseq_method_id);
  491. }
  492. } else {
  493. LM_ERR("we remove sdp only for a SIP_REPLY, not for a %d\n",
  494. _m->first_line.type);
  495. }
  496. return;
  497. }
  498. void destroy_qos_ctx(qos_ctx_t *qos_ctx)
  499. {
  500. qos_sdp_t * qos_sdp, * next_qos_sdp;
  501. lock_get(&qos_ctx->lock);
  502. qos_sdp = qos_ctx->pending_sdp;
  503. while (qos_sdp) {
  504. next_qos_sdp = qos_sdp->next;
  505. destroy_qos(qos_sdp);
  506. qos_sdp = next_qos_sdp;
  507. }
  508. qos_sdp = qos_ctx->negotiated_sdp;
  509. while (qos_sdp) {
  510. next_qos_sdp = qos_sdp->next;
  511. destroy_qos(qos_sdp);
  512. qos_sdp = next_qos_sdp;
  513. }
  514. lock_release(&qos_ctx->lock);
  515. lock_destroy(&qos_ctx->lock);
  516. LM_DBG("free qos_ctx: %p\n", qos_ctx);
  517. shm_free(qos_ctx);
  518. return;
  519. }