#include "release_call.h"
#include "sip.h"
Go to the source code of this file.
Functions | |
| int | send_request (str method, str reqbuf, dlg_t *d, transaction_cb cb, enum s_dialog_direction dir) |
| void | confirmed_response (struct cell *t, int type, struct tmcb_params *ps) |
| Callback function for BYE requests! Identify the s_dialog, then see if one BYE has already been recieved if yes drop it , if no, wait for the second. | |
| void | alter_dialog_route_set (dlg_t *d, enum s_dialog_direction dir) |
| Alters the saved dlg_t routes for the dialog by removing the first routes before myself. | |
| int | release_call (str callid, str reason) |
| Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog. | |
| int | release_call_s (s_dialog *d, str reason) |
| Given an s_dialog, releases the call. | |
| int | release_subscription (s_dialog *d) |
Variables | |
| tm_binds | tmb |
| Structure with pointers to tm funcs. | |
| dlg_func_t | dialogb |
| Structure with pointers to dialog funcs. | |
| str | scscf_record_route_mo_uri |
| just the record route uri for Mobile Originating | |
| str | scscf_record_route_mt_uri |
| just the record route uri for Mobile Terminating | |
| static str | method_bye_s = {"BYE",3} |
| static str | default_reason_s = {"Reason: SIP ;cause=503 ;text=\"Session Terminated\"\r\n",51} |
| static str | content_length_s = {"Content-Length: 0\r\n",19} |
| static str | hdrs_notify_s = {"Subscription-State: terminated\r\n",32} |
| static str | method_NOTIFY_s = {"NOTIFY",6} |
| static str | hdr_expires_s = {"Expires: 0\r\n",12} |
| static str | hdr_event1_s = {"Event: ",7} |
| static str | hdr_event2_s = {"\r\n",2} |
| static str | hdr_contact1_s = {"Contact: <",10} |
| static str | hdr_contact2_s = {">\r\n",3} |
| static str | method_SUBSCRIBE_s = {"SUBSCRIBE",9} |
| int send_request | ( | str | method, | |
| str | reqbuf, | |||
| dlg_t * | d, | |||
| transaction_cb | cb, | |||
| enum s_dialog_direction | dir | |||
| ) |
Definition at line 83 of file release_call.c.
References dialogb, M_NAME, and NULL.
00084 { 00085 00086 if((d!=NULL) && (method.s!=NULL)) 00087 { 00088 enum s_dialog_direction *cbp=NULL; 00089 00090 if (method.len !=3 || memcmp(method.s,"ACK",3)!=0) 00091 { 00092 /*In case of ACK i don't want to even send the direction 00093 * moreover as the memory is freed in the callback function 00094 * and the ACK is never replied it would be a bug if i did*/ 00095 cbp = shm_malloc(sizeof(enum s_dialog_direction)); 00096 if (!cbp){ 00097 LOG(L_ERR,"ERR:"M_NAME":send_request(): error allocating %d bytes\n",sizeof(enum s_dialog_direction)); 00098 return 0; 00099 } 00100 *cbp=dir; 00101 } 00102 dialogb.request_inside(&method,&reqbuf,NULL, d,cb,cbp); 00103 return 1; 00104 } 00105 00106 return 0; 00107 }
| void confirmed_response | ( | struct cell * | t, | |
| int | type, | |||
| struct tmcb_params * | ps | |||
| ) |
Callback function for BYE requests! Identify the s_dialog, then see if one BYE has already been recieved if yes drop it , if no, wait for the second.
Definition at line 121 of file release_call.c.
References d_unlock(), del_p_dialog(), del_s_dialog(), DLG_STATE_TERMINATED_ONE_SIDE, get_p_dialog_dir(), get_s_dialog_dir(), _p_dialog::hash, _s_dialog::hash, M_NAME, _p_dialog::state, and _s_dialog::state.
Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().
00122 { 00123 s_dialog *d; 00124 unsigned int hash; 00125 str call_id; 00126 00127 enum s_dialog_direction dir; 00128 00129 00130 if (!ps->param) return; 00131 dir = *((enum s_dialog_direction *) *(ps->param)); 00132 shm_free(*ps->param); 00133 *ps->param = 0; 00134 00135 call_id = t->callid; 00136 call_id.s+=9; 00137 call_id.len-=11; 00138 00139 LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a %d response to BYE for a call release for <%.*s> DIR[%d].\n", 00140 ps->code, call_id.len,call_id.s,dir); 00141 00142 d = get_s_dialog_dir(call_id,dir); 00143 if (!d) { 00144 LOG(L_ERR,"ERR:"M_NAME":confirmed_response(): Received a BYE response for a call release but there is no dialog for <%.*s> DIR[%d].\n", 00145 call_id.len,call_id.s,dir); 00146 return; 00147 } 00148 00149 if (ps->code>=200){ 00150 if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){ 00151 hash=d->hash; 00152 LOG(L_INFO,"INFO:"M_NAME":confirmed_response(): Received a response to second BYE. Dialog is dropped.\n"); 00153 del_s_dialog(d); 00154 d_unlock(hash); 00155 } else { 00156 hash=d->hash; 00157 d->state=DLG_STATE_TERMINATED_ONE_SIDE; 00158 d_unlock(hash); 00159 } 00160 } 00161 }
| void alter_dialog_route_set | ( | dlg_t * | d, | |
| enum s_dialog_direction | dir | |||
| ) |
Alters the saved dlg_t routes for the dialog by removing the first routes before myself.
This is requiered because half of the RRset is useless.
| d | - the dialog to modify the Record-Routes | |
| dir | - the direction |
Definition at line 172 of file release_call.c.
References DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, NULL, scscf_record_route_mo_uri, and scscf_record_route_mt_uri.
00173 { 00174 rr_t *r,*r_new; 00175 str p; /*this is going to point to the scscf uri*/ 00176 00177 switch (dir) { 00178 case DLG_MOBILE_ORIGINATING: 00179 p = scscf_record_route_mo_uri; 00180 break; 00181 case DLG_MOBILE_TERMINATING: 00182 p = scscf_record_route_mt_uri; 00183 break; 00184 default: 00185 return; 00186 } 00187 00188 for(r=d->route_set;r!=NULL;r=r->next) { 00189 if (r->nameaddr.uri.len>=p.len && 00190 strncasecmp(r->nameaddr.uri.s,p.s,r->nameaddr.uri.len)==0) { 00191 r_new = r->next; 00192 r->next = NULL; 00193 shm_free_rr(&d->route_set); 00194 d->route_set = r_new; 00195 return; 00196 } 00197 } 00198 }
| int release_call | ( | str | callid, | |
| str | reason | |||
| ) |
Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog.
| callid | - the Call-ID to release | |
| reason | - the Reason header to include in messages |
Definition at line 208 of file release_call.c.
References d_unlock(), DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_s_dialog_dir(), _s_dialog::hash, and release_call_s().
00209 { 00210 s_dialog *d=0; 00211 unsigned int hash; 00212 int res = 0; 00213 00214 d = get_s_dialog_dir(callid,DLG_MOBILE_ORIGINATING); 00215 if (d) { 00216 hash = d->hash; 00217 if (release_call_s(d,reason)>0) res = 1; 00218 goto done; 00219 } 00220 d = get_s_dialog_dir(callid,DLG_MOBILE_TERMINATING); 00221 if (d) { 00222 hash = d->hash; 00223 if (release_call_s(d,reason)>0) res = 1; 00224 goto done; 00225 } 00226 00227 /*Neither ORGINATING nor TERMINATING is UNKNOWN!*/ 00228 /*or doesn't exist*/ 00229 /*drop it silently?*/ 00230 /*treat it as ORIGINATING or TERMINATING?*/ 00231 done: 00232 if (d) d_unlock(hash); 00233 return res; 00234 }
| int release_call_s | ( | s_dialog * | d, | |
| str | reason | |||
| ) |
Given an s_dialog, releases the call.
This function is already called with a lock in d after returning d should be unlocked.
| d | - pointer to the s_dialog structure | |
| reason | - Reason header to include |
Definition at line 245 of file release_call.c.
References alter_dialog_route_set(), _s_dialog::call_id, confirmed_response(), content_length_s, default_reason_s, _s_dialog::dialog_c, _s_dialog::dialog_s, _s_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, DLG_STATE_CONFIRMED, get_s_dialog_dir_nolock(), _s_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_bye_s, send_request(), _s_dialog::state, and STR_APPEND.
Referenced by release_call(), and terminate_s_dialog().
00246 { 00247 enum s_dialog_direction odir; 00248 s_dialog *o; 00249 str reqbuf={0,0}; 00250 00251 LOG(L_INFO,"DBG:"M_NAME":release_call_s(): Releasing call <%.*s> DIR[%d].\n", 00252 d->call_id.len,d->call_id.s,d->direction); 00253 00254 /* As for now, i'm only releasing confirmed dialogs */ 00255 if (d->state < DLG_STATE_CONFIRMED){ 00256 LOG(L_INFO,"ERR:"M_NAME":release_call_s(): Unable to release a non-confirmed dialog\n"); 00257 return -1; 00258 } 00259 00260 /* get the dialog in the other direction to see if something going on there and mark as in releasing */ 00261 switch (d->direction){ 00262 case DLG_MOBILE_ORIGINATING: 00263 odir = DLG_MOBILE_TERMINATING; 00264 break; 00265 case DLG_MOBILE_TERMINATING: 00266 odir = DLG_MOBILE_ORIGINATING; 00267 break; 00268 default: 00269 odir = d->direction; 00270 } 00271 00272 o = get_s_dialog_dir_nolock(d->call_id,odir); 00273 if (o && !o->is_releasing) o->is_releasing = 1; 00274 00275 d->is_releasing++; 00276 00277 if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){ 00278 LOG(L_ERR,"ERR:"M_NAME":release_call_s(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction); 00279 00280 return 0; 00281 } 00282 if (d->is_releasing==1) { 00283 /*Before generating a request, we have to generate 00284 * the route_set in the dlg , because the route set 00285 * in the dialog is for the UAC everything which was in the 00286 * Record-Routes (including local address)*/ 00287 alter_dialog_route_set(d->dialog_c,d->direction); 00288 00289 /*first generate the bye for called user*/ 00290 /*then generate the bye for the calling user*/ 00291 /*send_bye(d->dialog_c,bye_response,d->direction,reason); 00292 send_bye(d->dialog_s,bye_response,d->direction,reason);*/ 00293 00294 /*now prepare the headers*/ 00295 if (reason.len) 00296 { 00297 reqbuf.len = reason.len+content_length_s.len; 00298 reqbuf.s = pkg_malloc(reqbuf.len); 00299 if (!reqbuf.s){ 00300 LOG(L_ERR,"ERR:"M_NAME":release_call_s(): Error allocating %d bytes.\n", 00301 reqbuf.len); 00302 return 0; 00303 } 00304 reqbuf.len=0; 00305 STR_APPEND(reqbuf,reason); 00306 STR_APPEND(reqbuf,content_length_s); 00307 00308 } else { 00309 reqbuf.len = default_reason_s.len+content_length_s.len; 00310 reqbuf.s = pkg_malloc(reqbuf.len); 00311 if (!reqbuf.s){ 00312 LOG(L_ERR,"ERR:"M_NAME":release_call_s(): Error allocating %d bytes.\n", 00313 reqbuf.len); 00314 return 0; 00315 } 00316 reqbuf.len=0; 00317 STR_APPEND(reqbuf,default_reason_s); 00318 STR_APPEND(reqbuf,content_length_s); 00319 } 00320 00321 00322 send_request(method_bye_s,reqbuf,d->dialog_c,confirmed_response,d->direction); 00323 send_request(method_bye_s,reqbuf,d->dialog_s,confirmed_response,d->direction); 00324 00325 /*the dialog is droped by the callback-function when recieves the two replies */ 00326 } 00327 if (reqbuf.s) 00328 pkg_free(reqbuf.s); 00329 return 1; 00330 }
| int release_subscription | ( | s_dialog * | d | ) |
Definition at line 342 of file release_call.c.
References alter_dialog_route_set(), _s_dialog::call_id, confirmed_response(), content_length_s, del_s_dialog(), _s_dialog::dialog_c, _s_dialog::dialog_s, _s_dialog::direction, _s_dialog::event, hdr_contact1_s, hdr_contact2_s, hdr_event1_s, hdr_event2_s, hdr_expires_s, hdrs_notify_s, _s_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_NOTIFY_s, method_SUBSCRIBE_s, send_request(), and STR_APPEND.
Referenced by terminate_s_dialog().
00343 { 00344 /*i dont think in this case all the checking with the directions is needed 00345 * because the SUBSCRIBE initiated dialog doesnt go twice through the S-CSCF or does it?*/ 00346 str reqbuf={0,0}; 00347 str c_uri={0,0}; 00348 d->is_releasing++; 00349 00350 if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE) 00351 { 00352 LOG(L_ERR,"ERR:"M_NAME":release_subscription(): had to delete silently a SUBSCRIBE initiated dialog %.*s\n",d->call_id.len,d->call_id.s); 00353 del_s_dialog(d); 00354 return 1; 00355 } 00356 if (d->is_releasing==1) 00357 { 00358 d->dialog_c->state=DLG_CONFIRMED; 00359 alter_dialog_route_set(d->dialog_c,d->direction); 00360 00361 //SUBSCRIBE 00362 /*Add Contents-Length thing makes everything more complicated*/ 00363 c_uri = d->dialog_s->rem_target; 00364 reqbuf.len = hdr_expires_s.len+content_length_s.len; 00365 if (d->event.len) 00366 reqbuf.len+=hdr_event1_s.len+d->event.len+hdr_event2_s.len; 00367 if (c_uri.len) 00368 reqbuf.len+=hdr_contact1_s.len+c_uri.len+hdr_contact2_s.len; 00369 reqbuf.s=pkg_malloc(reqbuf.len); 00370 if (!reqbuf.s){ 00371 LOG(L_ERR,"ERR:"M_NAME":release_subscription(): Error allocating %d bytes.\n", 00372 reqbuf.len); 00373 return 0; 00374 } 00375 reqbuf.len=0; 00376 STR_APPEND(reqbuf,hdr_expires_s); 00377 if (d->event.len){ 00378 STR_APPEND(reqbuf,hdr_event1_s); 00379 STR_APPEND(reqbuf,d->event); 00380 STR_APPEND(reqbuf,hdr_event2_s); 00381 } 00382 if (c_uri.len){ 00383 STR_APPEND(reqbuf,hdr_contact1_s); 00384 STR_APPEND(reqbuf,c_uri); 00385 STR_APPEND(reqbuf,hdr_contact2_s); 00386 } 00387 STR_APPEND(reqbuf,content_length_s); 00388 00389 send_request(method_SUBSCRIBE_s,reqbuf,d->dialog_c,confirmed_response,d->direction); 00390 if (reqbuf.s) 00391 pkg_free(reqbuf.s); 00392 00393 //NOTIFY 00394 /*Now add the Contents-Length thing for the NOTIFY*/ 00395 c_uri = d->dialog_c->rem_target; 00396 reqbuf.len = hdrs_notify_s.len+content_length_s.len; 00397 if (d->event.len) 00398 reqbuf.len+=hdr_event1_s.len+d->event.len+hdr_event2_s.len; 00399 if (c_uri.len) 00400 reqbuf.len+=hdr_contact1_s.len+c_uri.len+hdr_contact2_s.len; 00401 reqbuf.s = pkg_malloc(reqbuf.len); 00402 if (!reqbuf.s){ 00403 LOG(L_ERR,"ERR:"M_NAME":release_subscription(): Error allocating %d bytes.\n", 00404 reqbuf.len); 00405 return 0; 00406 } 00407 reqbuf.len=0; 00408 STR_APPEND(reqbuf,hdrs_notify_s); 00409 if (d->event.len){ 00410 STR_APPEND(reqbuf,hdr_event1_s); 00411 STR_APPEND(reqbuf,d->event); 00412 STR_APPEND(reqbuf,hdr_event2_s); 00413 } 00414 if (c_uri.len){ 00415 STR_APPEND(reqbuf,hdr_contact1_s); 00416 STR_APPEND(reqbuf,c_uri); 00417 STR_APPEND(reqbuf,hdr_contact2_s); 00418 } 00419 STR_APPEND(reqbuf,content_length_s); 00420 00421 send_request(method_NOTIFY_s,reqbuf,d->dialog_s,confirmed_response,d->direction); 00422 if (reqbuf.s) 00423 pkg_free(reqbuf.s); 00424 } 00425 return 1; 00426 }
str method_bye_s = {"BYE",3} [static] |
str default_reason_s = {"Reason: SIP ;cause=503 ;text=\"Session Terminated\"\r\n",51} [static] |
str content_length_s = {"Content-Length: 0\r\n",19} [static] |
Definition at line 72 of file release_call.c.
str hdrs_notify_s = {"Subscription-State: terminated\r\n",32} [static] |
str method_NOTIFY_s = {"NOTIFY",6} [static] |
str hdr_expires_s = {"Expires: 0\r\n",12} [static] |
str hdr_event1_s = {"Event: ",7} [static] |
str hdr_event2_s = {"\r\n",2} [static] |
str hdr_contact1_s = {"Contact: <",10} [static] |
str hdr_contact2_s = {">\r\n",3} [static] |
str method_SUBSCRIBE_s = {"SUBSCRIBE",9} [static] |
1.5.2