qos_ctx_helpers.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 SOMA Networks, Inc.
00005  * Written by Ovidiu Sas (osas)
00006  *
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License 
00020  * along with this program; if not, write to the Free Software 
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  * History:
00024  * -------
00025  * 2007-07-16 initial version (osas)
00026  */
00027 
00028 #include "../../mem/mem.h"
00029 #include "../../mem/shm_mem.h"
00030 #include "../../parser/sdp/sdp_cloner.h"
00031 #include "../dialog/dlg_hash.h"
00032 #include "qos_ctx_helpers.h"
00033 
00034 #define ERROR_MATCH           -1
00035 #define NO_INVITE_REQ_MATCH    0
00036 #define NO_INVITE_RESP_MATCH   1
00037 #define PENDING_MATCH          2
00038 #define NEGOTIATED_MATCH       3
00039 #define NO_ACK_REQ_MATCH       4
00040 #define NO_UPDATE_REQ_MATCH    7
00041 #define NO_UPDATE_RESP_MATCH   8
00042 
00043 
00044 #define N_UNKNOWN       0
00045 /* INVITE/200_ok */
00046 #define N_INVITE_200OK  1
00047 /* 200_ok/ACK */
00048 #define N_200OK_ACK     2
00049 /* early media (http://www.ietf.org/rfc/rfc3959.txt) */
00050 /* 183_early_media/PRACK */
00051 #define N_183_PRACK     3
00052 
00053 qos_ctx_t *build_new_qos_ctx(void) {
00054    qos_ctx_t *ctx = NULL;
00055 
00056    ctx = (qos_ctx_t *)shm_malloc(sizeof(qos_ctx_t));
00057    if (ctx!=NULL) {
00058       memset(ctx, 0, sizeof(qos_ctx_t));
00059    } else {
00060       LM_ERR("No enough shared memory\n");
00061       return NULL;
00062    }
00063    if (!lock_init(&ctx->lock)) {
00064       shm_free(ctx);
00065       return NULL;
00066    }
00067    return ctx;
00068 }
00069 
00070 void destroy_qos(qos_sdp_t *qos_sdp)
00071 {
00072    free_cloned_sdp_session(qos_sdp->sdp_session[0]);
00073    free_cloned_sdp_session(qos_sdp->sdp_session[1]);
00074    shm_free(qos_sdp);
00075 
00076    return;
00077 }
00078 
00079 
00080 void print_qos_sdp(qos_sdp_t *qos_sdp)
00081 {
00082    if (qos_sdp == NULL) {
00083       return;
00084    }
00085    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",
00086       qos_sdp, qos_sdp->prev, qos_sdp->next, qos_sdp->method_dir, qos_sdp->method_id,
00087       qos_sdp->method.len ,qos_sdp->method.s, qos_sdp->cseq.len, qos_sdp->cseq.s,
00088       qos_sdp->negotiation, qos_sdp->sdp_session[0], qos_sdp->sdp_session[1]);
00089    /* print_sdp_session(qos_sdp->sdp_session[0]); */
00090    /* print_sdp_session(qos_sdp->sdp_session[1]); */
00091 }
00092 
00093 
00094 
00095 /*
00096  * Find a matching sdp inside the local qos_ctx
00097  * for the given session received via message _m with the given direction, cseq and method
00098  * 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.
00099  */
00100 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)
00101 {
00102    qos_sdp_t *qos_sdp;
00103    str *received_cnt_disp, *local_cnt_disp;
00104 
00105    LM_DBG("received session: %p and other_role: %s\n", session, (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00106 
00107    switch (_m->first_line.type) {
00108       case SIP_REQUEST:
00109          switch (cseq_method_id) {
00110             case METHOD_INVITE:
00111                return NO_INVITE_REQ_MATCH;
00112                break;
00113             case METHOD_ACK:
00114                /* searching into the pending_sdp list */
00115                qos_sdp = qos_ctx->pending_sdp;
00116                LM_DBG("searching the negotiated_sdp: %p\n", qos_sdp);
00117                while (qos_sdp) {
00118                   if (METHOD_INVITE == qos_sdp->method_id && dir != qos_sdp->method_dir && qos_sdp->negotiation == N_200OK_ACK &&
00119                      cseq_number->len == qos_sdp->cseq.len && 0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
00120                      LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
00121                         qos_sdp, qos_sdp->sdp_session[other_role]);
00122                      /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
00123                      if (qos_sdp->sdp_session[other_role] != NULL) {
00124                         local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
00125                         received_cnt_disp = &(session->cnt_disp);
00126                         if (local_cnt_disp->len == received_cnt_disp->len) {
00127                            if (local_cnt_disp->len == 0) {
00128                               LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
00129                               *_qos_sdp = qos_sdp;
00130                               return PENDING_MATCH;
00131                            } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
00132                               LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
00133                               *_qos_sdp = qos_sdp;
00134                               return PENDING_MATCH;
00135                            }
00136                         } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
00137                            0==strncmp(local_cnt_disp->s, "session", 7)) {
00138                            /* We may have an offer with cnt_disp='session' and an answer with cnt_disp='' */
00139                            *_qos_sdp = qos_sdp;
00140                            return PENDING_MATCH;
00141                         }
00142                      } else {
00143                         LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00144                      }
00145                   }
00146                   qos_sdp = qos_sdp->next;
00147                }
00148                return NO_ACK_REQ_MATCH;
00149                break;
00150             case METHOD_UPDATE:
00151                return NO_UPDATE_REQ_MATCH;
00152                break;
00153             case METHOD_PRACK:
00154                LM_ERR("PRACK not implemented yet\n");
00155                return ERROR_MATCH;
00156                break;
00157             default:
00158                LM_ERR("Unexpected method id %d\n", cseq_method_id);
00159                return ERROR_MATCH;
00160          }
00161          break;
00162       case SIP_REPLY:
00163          switch (cseq_method_id) {
00164             case METHOD_INVITE:
00165                /* searching into the pending_sdp list */
00166                qos_sdp = qos_ctx->pending_sdp;
00167                while (qos_sdp) {
00168                   //print_qos_sdp(qos_sdp);
00169                   if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
00170                      qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
00171                      0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
00172                      LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
00173                         qos_sdp, qos_sdp->sdp_session[other_role]);
00174                      /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
00175                      if (qos_sdp->sdp_session[other_role] != NULL) {
00176                         local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
00177                         received_cnt_disp = &(session->cnt_disp);
00178                         if (local_cnt_disp->len == received_cnt_disp->len) {
00179                            if (local_cnt_disp->len == 0) {
00180                               LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
00181                               *_qos_sdp = qos_sdp;
00182                               return PENDING_MATCH;
00183                            } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
00184                               LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
00185                               *_qos_sdp = qos_sdp;
00186                               return PENDING_MATCH;
00187                            }
00188                         } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
00189                            0==strncmp(local_cnt_disp->s, "session", 7)) {
00190                            /* We have an offer with cnt_disp='session' and an answer with cnt_disp='' */
00191                            *_qos_sdp = qos_sdp;
00192                            return PENDING_MATCH;
00193                         }
00194                      } else {
00195                         LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00196                      }
00197                   }
00198                   qos_sdp = qos_sdp->next;
00199                }
00200                /* searching into the negotiated_sdp list */
00201                qos_sdp = qos_ctx->negotiated_sdp;
00202                LM_DBG("searching the negotiated_sdp: %p\n", qos_sdp);
00203                while (qos_sdp) {
00204                   //print_qos_sdp(qos_sdp);
00205                   if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
00206                      qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
00207                      0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
00208                      LM_DBG("method_id, dir and cseq match with previous session %p\n", qos_sdp->sdp_session[other_role]);
00209                      if (qos_sdp->sdp_session[other_role] != NULL) {
00210                         local_cnt_disp = &(qos_sdp->sdp_session[other_role]->cnt_disp);
00211                         received_cnt_disp = &(session->cnt_disp);
00212                         if (local_cnt_disp->len == received_cnt_disp->len) {
00213                            if (local_cnt_disp->len == 0) {
00214                               LM_DBG("no cnt disp header ... => %p\n", qos_sdp);
00215                               *_qos_sdp = qos_sdp;
00216                               return NEGOTIATED_MATCH;
00217                            } else if (0==strncmp(local_cnt_disp->s, received_cnt_disp->s, local_cnt_disp->len)) {
00218                               LM_DBG("'%.*s' => %p\n", local_cnt_disp->len, local_cnt_disp->s, qos_sdp);
00219                               *_qos_sdp = qos_sdp;
00220                               return NEGOTIATED_MATCH;
00221                            }
00222                         } else if (received_cnt_disp->len == 0 && local_cnt_disp->len == 7 &&
00223                            0==strncasecmp(local_cnt_disp->s, "session", 7)) {
00224                            /* We have an offer with cnt_disp='session' and an answer with cnt_disp='' */
00225                            *_qos_sdp = qos_sdp;
00226                            return NEGOTIATED_MATCH;
00227                         }
00228                      } else {
00229                         LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00230                      }
00231                   }
00232                   qos_sdp = qos_sdp->next;
00233                }
00234                return NO_INVITE_RESP_MATCH;
00235                break;
00236             case METHOD_UPDATE:
00237                LM_ERR("FIXME\n");
00238                return NO_UPDATE_RESP_MATCH;
00239                break;
00240             default:
00241                LM_ERR("Unexpected reply for method id %d\n", cseq_method_id);
00242                return ERROR_MATCH;
00243          }
00244          break;
00245       default:
00246          LM_ERR("Unknown SIP message type: %d\n", _m->first_line.type);
00247          return ERROR_MATCH;
00248    }
00249    LM_ERR("FIXME: out of case\n");
00250    return ERROR_MATCH;
00251 }
00252 
00253 void link_pending_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
00254 {
00255    if (qos_sdp->prev != NULL) LM_ERR("got qos_sdp->prev=%p\n", qos_sdp->prev);
00256    if (qos_sdp->next != NULL) LM_ERR("got qos_sdp->next=%p\n", qos_sdp->next);
00257 
00258    if (qos_ctx->pending_sdp) {
00259       LM_DBG("Adding pending qos_sdp: %p\n", qos_sdp);
00260       if (qos_ctx->pending_sdp->prev != NULL) LM_ERR("got qos_ctx->pending_sdp->prev=%p\n", qos_ctx->pending_sdp->prev);
00261       qos_sdp->next = qos_ctx->pending_sdp;
00262       qos_ctx->pending_sdp->prev = qos_sdp;
00263       qos_ctx->pending_sdp = qos_sdp;
00264    } else {
00265       LM_DBG("Inserting pending qos_sdp: %p\n", qos_sdp);
00266       qos_ctx->pending_sdp = qos_sdp;
00267    }
00268 }
00269 
00270 void unlink_pending_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
00271 {
00272    if (qos_sdp->next)
00273       qos_sdp->next->prev = qos_sdp->prev;
00274 
00275    if (qos_sdp->prev)
00276       qos_sdp->prev->next = qos_sdp->next;
00277    else
00278       qos_ctx->pending_sdp = qos_sdp->next;
00279 
00280    qos_sdp->next = qos_sdp->prev = NULL;
00281 }
00282 void unlink_negotiated_qos_sdp(qos_ctx_t *qos_ctx, qos_sdp_t *qos_sdp)
00283 {
00284    if (qos_sdp->next)
00285       qos_sdp->next->prev = qos_sdp->prev;
00286 
00287    if (qos_sdp->prev)
00288       qos_sdp->prev->next = qos_sdp->next;
00289    else
00290       qos_ctx->negotiated_sdp = qos_sdp->next;
00291 
00292    qos_sdp->next = qos_sdp->prev = NULL;
00293 }
00294 
00295 
00296 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)
00297 {
00298    qos_sdp_t *next_qos_sdp;
00299    qos_sdp_t *temp_qos_sdp = qos_ctx->negotiated_sdp;
00300 
00301    if (qos_sdp->prev != NULL) LM_ERR("got qos_sdp->prev=%p\n", qos_sdp->prev);
00302    if (qos_sdp->next != NULL) LM_ERR("got qos_sdp->next=%p\n", qos_sdp->next);
00303 
00304    if (temp_qos_sdp) {
00305       while (temp_qos_sdp) {
00306          next_qos_sdp = temp_qos_sdp->next;
00307          if (qos_sdp->negotiation == temp_qos_sdp->negotiation) {
00308             LM_DBG("run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx=%p, temp_qos_sdp=%p, role=%d, _m=%p)\n",
00309                qos_ctx, temp_qos_sdp, role, _m);
00310             run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx, temp_qos_sdp, role, _m);
00311 
00312             unlink_negotiated_qos_sdp(qos_ctx, temp_qos_sdp);
00313             destroy_qos(temp_qos_sdp);
00314             break;
00315          }
00316          temp_qos_sdp = next_qos_sdp;
00317       }
00318       if (qos_ctx->negotiated_sdp) {
00319          LM_DBG("Adding negotiated qos_sdp: %p\n", qos_sdp);
00320          if (qos_ctx->negotiated_sdp->prev != NULL) LM_ERR("got qos_ctx->negotiated_sdp->prev=%p\n", qos_ctx->negotiated_sdp->prev);
00321          qos_sdp->next = qos_ctx->negotiated_sdp;
00322          qos_ctx->negotiated_sdp->prev = qos_sdp;
00323          qos_ctx->negotiated_sdp = qos_sdp;
00324       } else {
00325          LM_DBG("Inserting negotiated qos_sdp: %p\n", qos_sdp);
00326          qos_ctx->negotiated_sdp = qos_sdp;
00327       }
00328    } else {
00329       LM_DBG("Inserting first negotiated qos_sdp: %p\n", qos_sdp);
00330       qos_ctx->negotiated_sdp = qos_sdp;
00331    }
00332 
00333    LM_DBG("run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
00334       qos_ctx, qos_sdp, role, _m);
00335    run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx, qos_sdp, role, _m);
00336 }
00337 
00338 int add_pending_sdp_session(qos_ctx_t *qos_ctx, unsigned int dir, str *cseq_number, str *cseq_method, int cseq_method_id,
00339             unsigned int role, unsigned int negotiation, sdp_session_cell_t *session, struct sip_msg *_m)
00340 {
00341    unsigned int len;
00342    sdp_session_cell_t *cloned_session;
00343    qos_sdp_t *qos_sdp;
00344    char *p;
00345 
00346    len = sizeof(qos_sdp_t) + cseq_method->len + cseq_number->len;
00347    qos_sdp = (qos_sdp_t *)shm_malloc(len);
00348    LM_DBG("alloc qos_sdp: %p\n", qos_sdp);
00349    if (qos_sdp==NULL) {
00350       LM_ERR("oom %d\n", len);
00351       return -1;
00352    } else {
00353       memset(qos_sdp, 0, len);
00354       LM_DBG("Allocated memory for qos_sdp: %p\n", qos_sdp);
00355 
00356       cloned_session = clone_sdp_session_cell(session);
00357       if (cloned_session==NULL) {
00358          shm_free(qos_sdp);
00359          LM_DBG("free qos_sdp: %p\n", qos_sdp);
00360          return -1;
00361       }
00362       qos_sdp->sdp_session[role] = cloned_session;
00363 
00364       LM_DBG("qos_sdp->sdp_session[%d]=%p\n", role, qos_sdp->sdp_session[role]);
00365 
00366       if (_m->first_line.type == SIP_REQUEST) {
00367          qos_sdp->method_dir = dir;
00368       } else {
00369          /* This is a SIP_REPLY and we need to set
00370           * the direction for the SIP_REQUEST */
00371          if (dir==DLG_DIR_UPSTREAM)
00372             qos_sdp->method_dir = DLG_DIR_DOWNSTREAM;
00373          else
00374             qos_sdp->method_dir = DLG_DIR_UPSTREAM;
00375       }
00376       qos_sdp->method_id = cseq_method_id;
00377       qos_sdp->negotiation = negotiation;
00378       p = (char*)(qos_sdp+1);
00379 
00380       qos_sdp->method.s = p;
00381       qos_sdp->method.len = cseq_method->len;
00382       memcpy( p, cseq_method->s, cseq_method->len);
00383       p += cseq_method->len;
00384 
00385       qos_sdp->cseq.s = p;
00386       qos_sdp->cseq.len = cseq_number->len;
00387       memcpy( p,cseq_number->s, cseq_number->len);
00388       /* p += cseq_number->len; */
00389 
00390       link_pending_qos_sdp(qos_ctx, qos_sdp);
00391 
00392       LM_DBG("run_qos_callbacks(QOSCB_ADD_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
00393          qos_ctx, qos_sdp, role, _m);
00394       run_qos_callbacks(QOSCB_ADD_SDP, qos_ctx, qos_sdp, role, _m);
00395    }
00396    return 0;
00397 }
00398 
00399 
00400 
00401 
00402 /*
00403  * Add the sdp carried by the given SIP message into the qos context.
00404  */
00405 void add_sdp(qos_ctx_t *qos_ctx, unsigned int dir, struct sip_msg *_m, unsigned int role, unsigned int other_role)
00406 {
00407    qos_sdp_t *qos_sdp;
00408    sdp_session_cell_t *recv_session;
00409    str *cseq_number, *cseq_method;
00410    int cseq_method_id, sdp_match;
00411 
00412    if ( (!_m->cseq && parse_headers(_m,HDR_CSEQ_F,0)<0) || !_m->cseq || !_m->cseq->parsed) {
00413       LM_ERR("bad sip message or missing CSeq hdr\n");
00414       return;
00415    }
00416 
00417    cseq_number = &((get_cseq(_m))->number);
00418    cseq_method = &((get_cseq(_m))->method);
00419    cseq_method_id = (get_cseq(_m))->method_id;
00420 
00421    LM_DBG("cseq=`%.*s' `%.*s' and dir=%d\n",
00422       cseq_number->len, cseq_number->s,
00423       cseq_method->len, cseq_method->s, dir);
00424 
00425    /* Let's iterate through all the received sessions */
00426    recv_session = _m->sdp->sessions;
00427    while(recv_session) {
00428       qos_sdp = NULL;
00429       sdp_match = find_qos_sdp(qos_ctx, dir, other_role, cseq_number, cseq_method_id, recv_session, _m, &qos_sdp);
00430 
00431       switch (sdp_match) {
00432          case NO_INVITE_REQ_MATCH:
00433             if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_INVITE_200OK, recv_session, _m)) {
00434                LM_ERR("Unable to add new sdp session\n");
00435                goto error;
00436             }
00437 
00438             break;
00439          case NO_INVITE_RESP_MATCH:
00440             if (0!=add_pending_sdp_session( qos_ctx, dir, cseq_number, cseq_method, cseq_method_id, role, N_200OK_ACK, recv_session, _m)) {
00441                LM_ERR("Unable to add new sdp session\n");
00442                goto error;
00443             }
00444 
00445             break;
00446          case ERROR_MATCH:
00447          case NO_ACK_REQ_MATCH:
00448          case NO_UPDATE_REQ_MATCH:
00449          case NO_UPDATE_RESP_MATCH:
00450             LM_ERR("error match: %d\n", sdp_match);
00451             break;
00452          case PENDING_MATCH:
00453             LM_DBG("we have a pending match: %p\n", qos_sdp);
00454             /* Let's save the received session */
00455             qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session);
00456             if (qos_sdp->sdp_session[role] == NULL) {
00457                LM_ERR("PENDING_MATCH:oom: Unable to add new sdp session\n");
00458                return;
00459             }
00460 
00461             /* Negotiation completed, need to move the established SDP into the negotiated_sdp */
00462 
00463             /* removing qos_sdp from qos_ctx->pending_sdp list */
00464             unlink_pending_qos_sdp(qos_ctx, qos_sdp);
00465             /* inserting qos_sdp into the qos_ctx->negotiated_sdp list */
00466             link_negotiated_qos_sdp_and_run_cb(qos_ctx, qos_sdp, role, _m);
00467 
00468             break;
00469          case NEGOTIATED_MATCH:
00470             LM_DBG("we have a negotiated match: %p\n", qos_sdp);
00471             /* some sanity checks */
00472             if (qos_sdp->sdp_session[role]) {
00473                free_cloned_sdp_session(qos_sdp->sdp_session[role]);
00474             } else {
00475                LM_ERR("missing sdp_session for %s\n", (role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00476             }
00477             /* Let's save the received session */
00478             qos_sdp->sdp_session[role] = clone_sdp_session_cell(recv_session);
00479             if (qos_sdp->sdp_session[role]  == NULL) {
00480                LM_ERR("NEGOTIATED_MATCH:oom: Unable to add new sdp session\n");
00481                return;
00482             }
00483 
00484             LM_DBG("run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
00485                qos_ctx, qos_sdp, role, _m);
00486             run_qos_callbacks(QOSCB_UPDATE_SDP, qos_ctx, qos_sdp, role, _m);
00487 
00488             break;
00489          default:
00490             LM_CRIT("Undefined return code from find_qos_sdp(): %d\n", sdp_match);
00491       }
00492       recv_session = recv_session->next;
00493    }
00494 
00495    return;
00496 error:
00497    shm_free(qos_sdp);
00498    LM_DBG("free qos_sdp: %p\n", qos_sdp);
00499    return;
00500 }
00501 
00502 /*
00503  * Remove the sdp previously added.
00504  */
00505 void remove_sdp(qos_ctx_t *qos_ctx, unsigned int dir, struct sip_msg *_m, unsigned int role, unsigned int other_role)
00506 {
00507    str *cseq_number, *cseq_method;
00508    int cseq_method_id;
00509    qos_sdp_t *qos_sdp;
00510 
00511    if ( (!_m->cseq && parse_headers(_m,HDR_CSEQ_F,0)<0) || !_m->cseq || !_m->cseq->parsed) {
00512       LM_ERR("bad sip message or missing CSeq hdr\n");
00513       return;
00514    }
00515 
00516    cseq_number = &((get_cseq(_m))->number);
00517    cseq_method = &((get_cseq(_m))->method);
00518    cseq_method_id = (get_cseq(_m))->method_id;
00519 
00520    if (_m->first_line.type == SIP_REPLY) {
00521       switch (cseq_method_id) {
00522          case METHOD_INVITE:
00523          case METHOD_UPDATE:
00524                /* searching into the pending_sdp list only */
00525                qos_sdp = qos_ctx->pending_sdp;
00526                while (qos_sdp) {
00527                   qos_sdp = qos_sdp->next;
00528                   if (cseq_method_id == qos_sdp->method_id && dir != qos_sdp->method_dir &&
00529                      qos_sdp->negotiation == N_INVITE_200OK && cseq_number->len == qos_sdp->cseq.len &&
00530                      0 == strncmp(cseq_number->s, qos_sdp->cseq.s, cseq_number->len)) {
00531                      LM_DBG("method_id, dir and cseq match with previous session %p->%p\n",
00532                         qos_sdp, qos_sdp->sdp_session[other_role]);
00533                      /* print_sdp_session(qos_sdp->sdp_session[other_role]); */
00534                      if (qos_sdp->sdp_session[other_role] != NULL) {
00535                         LM_DBG("run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx=%p, qos_sdp=%p, role=%d, _m=%p)\n",
00536                            qos_ctx, qos_sdp, role, _m);
00537                         run_qos_callbacks(QOSCB_REMOVE_SDP, qos_ctx, qos_sdp, role, _m);
00538                         unlink_negotiated_qos_sdp(qos_ctx, qos_sdp);
00539                         /* Here we free up the pending qos_sdp */
00540                         destroy_qos(qos_sdp);
00541                         continue;
00542                      } else {
00543                         LM_ERR("skipping search for null sdp for %s\n", (other_role==QOS_CALLER)?"QOS_CALLER":"QOS_CALLEE");
00544                      }
00545                   }
00546                } /* end while (qos_sdp) */
00547             break;
00548          default:
00549             LM_ERR("Unexpected method id %d\n", cseq_method_id);
00550       }
00551    } else {
00552       LM_ERR("we remove sdp only for a SIP_REPLY, not for a %d\n",
00553          _m->first_line.type);
00554    }
00555 
00556    return;
00557 }
00558 
00559 void destroy_qos_ctx(qos_ctx_t *qos_ctx)
00560 {
00561    qos_sdp_t * qos_sdp, * next_qos_sdp;
00562 
00563    lock_get(&qos_ctx->lock);
00564 
00565    qos_sdp = qos_ctx->pending_sdp;
00566    while (qos_sdp) {
00567       next_qos_sdp = qos_sdp->next;
00568       destroy_qos(qos_sdp);
00569       qos_sdp = next_qos_sdp;
00570    }
00571    qos_sdp = qos_ctx->negotiated_sdp;
00572    while (qos_sdp) {
00573       next_qos_sdp = qos_sdp->next;
00574       destroy_qos(qos_sdp);
00575       qos_sdp = next_qos_sdp;
00576    }
00577 
00578    lock_release(&qos_ctx->lock);
00579 
00580    lock_destroy(&qos_ctx->lock);
00581 
00582    LM_DBG("free qos_ctx: %p\n", qos_ctx);
00583    shm_free(qos_ctx);
00584 
00585    return;
00586 }
00587 

Generated on Thu May 24 08:00:53 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6