#include "release_call.h"
Go to the source code of this file.
Functions | |
| void | alter_dialog_route_set (dlg_t *d, enum p_dialog_direction dir) |
| Alters the saved dlg_t routes for the dialog by removing the first routes before myself. | |
| int | send_request (str, str, dlg_t *, transaction_cb, enum p_dialog_direction) |
| 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. | |
| int | release_call_confirmed (p_dialog *d, int reason_code, str reason_text) |
| This functions sends BYE for a confirmed dialog. | |
| int | release_call_previous (p_dialog *d, enum release_call_situation situation, int reason_code, str reason_text) |
| Function that releases a call in early or early200 situation early200 is when the callee has already sent out 200 but that hasn't arrived yet to the caller. | |
| int | release_call_early (p_dialog *d, int reason_code, str reason_text) |
| int | release_call_early200 (p_dialog *d, int reason_code, str reason_text) |
| int | release_call_p (p_dialog *d, int reason_code, str reason_text) |
| Releases a dialog either confirmed or early the dialog is given with a lock on the hash! | |
| int | release_call (str callid, int reason_code, str reason_text) |
| Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog. | |
| int | P_release_call_onreply (struct sip_msg *msg, char *str1, char *str2) |
| Releases a call from the on reply route block called with any reply to an INVITE useful in cases of rejecting a call when you are processing the SDP or handling QoS things - the sip message being processed - the first parameter "orig" or "term" - [optional] the Reason header that you want to go to the messages. | |
Variables | |
| tm_binds | tmb |
| Structure with pointers to tm funcs. | |
| dlg_func_t | dialogb |
| Structure with pointers to dialog funcs. | |
| str | pcscf_record_route_mo_uri |
| URI for Record-route originating. | |
| str | pcscf_record_route_mt_uri |
| URI for Record-route terminating. | |
| static str | reason_hdr_s = {"Reason: SIP ;cause=",19} |
| static str | reason_hdr_1 = {" ;text=\"",8} |
| static str | reason_hdr_e = {"\"\r\n",3} |
| static str | _488_text_s = {"Not Acceptable Here",19} |
| static str | method_CANCEL_s = {"CANCEL",6} |
| static str | method_ACK_s = {"ACK",3} |
| static str | method_BYE_s = {"BYE",3} |
| static str | content_length_s = {"Content-Length: 0\r\n",19} |
| void alter_dialog_route_set | ( | dlg_t * | d, | |
| enum p_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 511 of file release_call.c.
References DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, NULL, pcscf_record_route_mo_uri, and pcscf_record_route_mt_uri.
Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().
00512 { 00513 rr_t *r,*r_new; 00514 str p; /*this is going to point to the scscf uri*/ 00515 00516 00517 00518 switch (dir) { 00519 case DLG_MOBILE_ORIGINATING: 00520 p = pcscf_record_route_mo_uri; 00521 break; 00522 case DLG_MOBILE_TERMINATING: 00523 p = pcscf_record_route_mt_uri; 00524 break; 00525 default: 00526 return; 00527 } 00528 //LOG(L_CRIT,"Looking for <%.*s> in\n",p.len,p.s); 00529 //for(r=d->route_set;r!=NULL;r=r->next) 00530 // LOG(L_CRIT,"<%.*s>\n",r->nameaddr.uri.len,r->nameaddr.uri.s); 00531 00532 for(r=d->route_set;r!=NULL;r=r->next) { 00533 if (r->nameaddr.uri.len>=p.len && 00534 strncasecmp(r->nameaddr.uri.s,p.s,r->nameaddr.uri.len)==0) 00535 { 00536 r_new=r->next; 00537 r->next=NULL; 00538 shm_free_rr(&d->route_set); 00539 d->route_set = r_new; 00540 return; 00541 } 00542 00543 } 00544 }
| int send_request | ( | str | , | |
| str | , | |||
| dlg_t * | , | |||
| transaction_cb | , | |||
| enum | p_dialog_direction | |||
| ) |
Definition at line 477 of file release_call.c.
References dialogb, M_NAME, and NULL.
Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().
00478 { 00479 if((d!=NULL) && (method.s!=NULL)) 00480 { 00481 enum p_dialog_direction *cbp=NULL; 00482 00483 if (method.len !=3 || memcmp(method.s,"ACK",3)!=0) 00484 { 00485 /*In case of ACK i don't want to even send the direction 00486 * moreover as the memory is freed in the callback function 00487 * and the ACK is never replied it would be a bug if i did*/ 00488 cbp = shm_malloc(sizeof(enum p_dialog_direction)); 00489 if (!cbp){ 00490 LOG(L_ERR,"ERR:"M_NAME":send_request(): error allocating %d bytes\n",sizeof(enum p_dialog_direction)); 00491 return 0; 00492 } 00493 *cbp=dir; 00494 } 00495 dialogb.request_inside(&method,&reqbuf,NULL, d,cb,cbp); 00496 return 1; 00497 } 00498 00499 return 0; 00500 }
| void confirmed_response | ( | struct cell * | , | |
| int | , | |||
| struct tmcb_params * | ||||
| ) |
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 175 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(), _s_dialog::hash, _p_dialog::hash, M_NAME, _s_dialog::state, and _p_dialog::state.
Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().
00176 { 00177 p_dialog *d; 00178 unsigned int hash; 00179 str call_id; 00180 00181 enum p_dialog_direction dir; 00182 00183 00184 if (!ps->param) return; 00185 dir = *((enum p_dialog_direction *) *(ps->param)); 00186 shm_free(*ps->param); 00187 *ps->param = 0; 00188 00189 //call_id = cscf_get_call_id(ps->rpl,0); 00190 call_id = t->callid; 00191 call_id.s+=9; 00192 call_id.len-=11; 00193 00194 LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a BYE for a call release for <%.*s> DIR[%d].\n", 00195 call_id.len,call_id.s,dir); 00196 00197 d = get_p_dialog_dir(call_id,dir); 00198 if (!d) { 00199 LOG(L_ERR,"ERR:"M_NAME":confirmed_response(): Received a BYE for a call release but there is no dialog for <%.*s> DIR[%d].\n", 00200 call_id.len,call_id.s,dir); 00201 return; 00202 } 00203 00204 if (ps->code>=200){ 00205 if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){ 00206 hash=d->hash; 00207 del_p_dialog(d); 00208 d_unlock(hash); 00209 } else { 00210 hash=d->hash; 00211 d->state=DLG_STATE_TERMINATED_ONE_SIDE; 00212 d_unlock(hash); 00213 } 00214 } 00215 }
| int release_call_confirmed | ( | p_dialog * | d, | |
| int | reason_code, | |||
| str | reason_text | |||
| ) |
This functions sends BYE for a confirmed dialog.
| d | - the p_dialog to end | |
| reason | - the Reason: header to include in the messages |
Definition at line 95 of file release_call.c.
References alter_dialog_route_set(), _p_dialog::call_id, confirmed_response(), content_length_s, del_p_dialog(), _p_dialog::dialog_c, _p_dialog::dialog_s, _p_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_p_dialog_dir_nolock(), _p_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_BYE_s, reason_hdr_1, reason_hdr_e, reason_hdr_s, send_request(), and STR_APPEND.
Referenced by release_call_p().
00096 { 00097 enum p_dialog_direction odir; 00098 p_dialog *o; 00099 str r; 00100 str hdrs={0,0}; 00101 char buf[256]; 00102 00103 LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Releasing call <%.*s> DIR[%d].\n", 00104 d->call_id.len,d->call_id.s,d->direction); 00105 00106 r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s", 00107 reason_hdr_s.len,reason_hdr_s.s, 00108 reason_code, 00109 reason_hdr_1.len,reason_hdr_1.s, 00110 reason_text.len,reason_text.s, 00111 reason_hdr_e.len,reason_hdr_e.s); 00112 r.s = buf; 00113 00114 hdrs.len = r.len+content_length_s.len; 00115 hdrs.s = pkg_malloc(hdrs.len); 00116 if (!hdrs.s){ 00117 LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Error allocating %d bytes.\n",hdrs.len); 00118 hdrs.len=0; 00119 goto error; 00120 } 00121 hdrs.len=0; 00122 STR_APPEND(hdrs,r); 00123 STR_APPEND(hdrs,content_length_s); 00124 00125 /* get the dialog in the other direction to see if something going on there and mark as in releasing */ 00126 switch (d->direction){ 00127 case DLG_MOBILE_ORIGINATING: 00128 odir = DLG_MOBILE_TERMINATING; 00129 break; 00130 case DLG_MOBILE_TERMINATING: 00131 odir = DLG_MOBILE_ORIGINATING; 00132 break; 00133 default: 00134 odir = d->direction; 00135 } 00136 00137 o = get_p_dialog_dir_nolock(d->call_id,odir); 00138 if (o && !o->is_releasing) o->is_releasing = 1; 00139 00140 d->is_releasing++; 00141 00142 if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){ 00143 LOG(L_ERR,"ERR:"M_NAME":release_call_confirmed(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction); 00144 del_p_dialog(d); 00145 goto error; 00146 } 00147 if (d->is_releasing==1) { 00148 /*Before generating a request, we have to generate 00149 * the route_set in the dlg , because the route set 00150 * in the dialog is for the UAC everything which was in the 00151 * Record-Routes (including local address)*/ 00152 alter_dialog_route_set(d->dialog_c,d->direction); 00153 00154 /*first generate the bye for called user*/ 00155 /*then generate the bye for the calling user*/ 00156 send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction); 00157 send_request(method_BYE_s,hdrs,d->dialog_s,confirmed_response,d->direction); 00158 00159 /*the dialog is droped by the callback-function when receives the two replies */ 00160 } 00161 00162 if (hdrs.s) pkg_free(hdrs.s); 00163 return 1; 00164 error: 00165 if (hdrs.s) pkg_free(hdrs.s); 00166 return 0; 00167 }
| int release_call_previous | ( | p_dialog * | d, | |
| enum release_call_situation | situation, | |||
| int | reason_code, | |||
| str | reason_text | |||
| ) |
Function that releases a call in early or early200 situation early200 is when the callee has already sent out 200 but that hasn't arrived yet to the caller.
| d | - p_dialog of the call - flag to distinguish between two situations |
This function is full of tricks to fake states and to decieve the transaction module so that it lets us end a call in weird state
any move in the order of functions to clarify the structure can lead to a crash in P-CSCF so watch out!
Definition at line 237 of file release_call.c.
References alter_dialog_route_set(), _p_dialog::call_id, confirmed_response(), content_length_s, del_p_dialog(), _p_dialog::dialog_c, _p_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, DLG_STATE_TERMINATED_ONE_SIDE, get_p_dialog_dir_nolock(), _p_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_ACK_s, method_BYE_s, method_CANCEL_s, reason_hdr_1, reason_hdr_e, reason_hdr_s, RELEASE_CALL_WEIRD, send_request(), _p_dialog::state, STR_APPEND, and tmb.
Referenced by P_release_call_onreply(), release_call_early(), and release_call_early200().
00238 { 00239 struct cell* t; 00240 p_dialog *o; 00241 enum p_dialog_direction odir; 00242 int i; 00243 str r; 00244 str hdrs={0,0}; 00245 char buf[256]; 00246 00247 LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Releasing call <%.*s> DIR[%d].\n", 00248 d->call_id.len,d->call_id.s,d->direction); 00249 00250 r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s", 00251 reason_hdr_s.len,reason_hdr_s.s, 00252 reason_code, 00253 reason_hdr_1.len,reason_hdr_1.s, 00254 reason_text.len,reason_text.s, 00255 reason_hdr_e.len,reason_hdr_e.s); 00256 r.s = buf; 00257 00258 hdrs.len = r.len+content_length_s.len; 00259 hdrs.s = pkg_malloc(hdrs.len); 00260 if (!hdrs.s){ 00261 LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Error allocating %d bytes.\n",hdrs.len); 00262 hdrs.len=0; 00263 goto error; 00264 } 00265 hdrs.len=0; 00266 STR_APPEND(hdrs,r); 00267 STR_APPEND(hdrs,content_length_s); 00268 00269 /* get the dialog in the other direction to see if something going on there and mark as in releasing */ 00270 switch (d->direction){ 00271 case DLG_MOBILE_ORIGINATING: 00272 odir = DLG_MOBILE_TERMINATING; 00273 break; 00274 case DLG_MOBILE_TERMINATING: 00275 odir = DLG_MOBILE_ORIGINATING; 00276 break; 00277 default: 00278 odir = d->direction; 00279 } 00280 00281 o = get_p_dialog_dir_nolock(d->call_id,odir); 00282 if (o && !o->is_releasing) o->is_releasing = 1; 00283 00284 d->is_releasing++; 00285 00286 if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){ 00287 LOG(L_ERR,"ERR:"M_NAME":release_call_previous(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction); 00288 del_p_dialog(d); 00289 goto error; 00290 } 00291 00292 alter_dialog_route_set(d->dialog_c,d->direction); 00293 00294 d->state=DLG_STATE_TERMINATED_ONE_SIDE; 00295 /*this is just a trick to use the same callback function*/ 00296 00297 /*trick or treat!*/ 00298 d->dialog_c->state=DLG_CONFIRMED; 00299 00300 if (situation == RELEASE_CALL_WEIRD){ 00301 send_request(method_ACK_s,hdrs,d->dialog_c,0,0); 00302 send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction); 00303 //d->dialog_c->state=DLG_EARLY; 00304 } else {/*(situation == RELEASE_CALL_EARLY)*/ 00305 send_request(method_CANCEL_s,hdrs,d->dialog_c,confirmed_response,d->direction); 00306 //d->dialog_c->state=DLG_EARLY; 00307 } 00308 00309 /*i need the cell of the invite!!*/ 00310 /*this is very experimental 00311 * and very tricky too*/ 00312 t=tmb.t_gett(); 00313 00314 if (t && t!=(void*) -1 && t->uas.request) { 00315 /*first trick: i really want to get this reply sent even though we are onreply*/ 00316 *tmb.route_mode=MODE_ONFAILURE; 00317 00318 /*second trick .. i haven't recieve any response from the uac 00319 * if i don't do this i get a cancel sent to the S-CSCF .. its not a big deal*/ 00320 /*if i cared about sip forking then probably i would not do that and let the 00321 * CANCEL go to the S-CSCF (reread specifications needed)*/ 00322 for (i=0; i< t->nr_of_outgoings; i++) 00323 t->uac[i].last_received=99; 00324 /*t->uas.status=100;*/ /*no one cares about this*/ 00325 /*now its safe to do this*/ 00326 00327 tmb.t_reply(t->uas.request,reason_code,reason_text.s); 00328 *tmb.route_mode=MODE_ONREPLY; 00329 tmb.t_release(t->uas.request); 00330 00331 /*needed because if not i get last message retransmited... 00332 * probably there is a more logical way to do this.. but since i really 00333 * want this transaction to end .. whats the point?*/ 00334 } 00335 00336 return 1; 00337 error: 00338 if (hdrs.s) pkg_free(hdrs.s); 00339 return 0; 00340 }
| int release_call_early | ( | p_dialog * | d, | |
| int | reason_code, | |||
| str | reason_text | |||
| ) |
Definition at line 343 of file release_call.c.
References RELEASE_CALL_EARLY, and release_call_previous().
Referenced by release_call_p().
00344 { 00345 /*CANCEL will be badly routed because the response hasn't being processed 00346 * it will be sent to I-CSCF who will relay to S-CSCF and from there to term@P-CSCF*/ 00347 return release_call_previous(d,RELEASE_CALL_EARLY,reason_code,reason_text); 00348 }
| int release_call_early200 | ( | p_dialog * | d, | |
| int | reason_code, | |||
| str | reason_text | |||
| ) |
Definition at line 350 of file release_call.c.
References release_call_previous(), and RELEASE_CALL_WEIRD.
00351 { 00352 return release_call_previous(d,RELEASE_CALL_WEIRD,reason_code,reason_text); 00353 }
| int release_call_p | ( | p_dialog * | d, | |
| int | reason_code, | |||
| str | reason_text | |||
| ) |
Releases a dialog either confirmed or early the dialog is given with a lock on the hash!
| d | - p_dialog to release | |
| reason | - Reason header to include in messages |
Definition at line 370 of file release_call.c.
References DLG_STATE_CONFIRMED, release_call_confirmed(), release_call_early(), and _p_dialog::state.
Referenced by release_call(), and terminate_p_dialog().
00371 { 00372 if (d->state>=DLG_STATE_CONFIRMED) 00373 return(release_call_confirmed(d,reason_code,reason_text)); 00374 else 00375 return(release_call_early(d,reason_code,reason_text)); 00376 }
| int release_call | ( | str | callid, | |
| int | reason_code, | |||
| str | reason_text | |||
| ) |
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 386 of file release_call.c.
00387 { 00388 p_dialog *d=0; 00389 unsigned int hash; 00390 int res = 0; 00391 00392 d = get_p_dialog_dir(callid,DLG_MOBILE_ORIGINATING); 00393 if (d) { 00394 hash = d->hash; 00395 if (release_call_p(d,reason_code,reason_text)>0) res = 1; 00396 goto done; 00397 } 00398 d = get_p_dialog_dir(callid,DLG_MOBILE_TERMINATING); 00399 if (d) { 00400 hash = d->hash; 00401 if (release_call_p(d,reason_code,reason_text)>0) res = 1; 00402 goto done; 00403 } 00404 00405 /*Neither ORGINATING nor TERMINATING is UNKNOWN!*/ 00406 /*or doesn't exist*/ 00407 /*drop it silently?*/ 00408 /*treat it as ORIGINATING or TERMINATING?*/ 00409 done: 00410 if (d) d_unlock(hash); 00411 return 0; 00412 }
| int P_release_call_onreply | ( | struct sip_msg * | msg, | |
| char * | str1, | |||
| char * | str2 | |||
| ) |
Releases a call from the on reply route block called with any reply to an INVITE useful in cases of rejecting a call when you are processing the SDP or handling QoS things - the sip message being processed - the first parameter "orig" or "term" - [optional] the Reason header that you want to go to the messages.
Definition at line 426 of file release_call.c.
References _488_text_s, cscf_get_call_id(), CSCF_RETURN_BREAK, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, d_unlock(), DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_p_dialog_dir(), _p_dialog::hash, is_p_dialog_dir(), M_NAME, NULL, RELEASE_CALL_EARLY, release_call_previous(), and RELEASE_CALL_WEIRD.
00427 { 00428 enum p_dialog_direction dir; 00429 p_dialog *d=NULL; 00430 str callid; 00431 struct hdr_field *h1; 00432 str reason={NULL,0}; 00433 00434 if (str2) { 00435 reason.s=str2; 00436 reason.len=strlen(str2); 00437 } else 00438 reason = _488_text_s; 00439 00440 00441 dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING; 00442 00443 if (msg->first_line.type== SIP_REQUEST) 00444 { 00445 LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n"); 00446 return CSCF_RETURN_FALSE; 00447 } 00448 00449 callid=cscf_get_call_id(msg,&h1); 00450 if (is_p_dialog_dir(callid,dir)) { 00451 d=get_p_dialog_dir(callid,dir); 00452 if (msg->first_line.u.reply.statuscode > 199) 00453 { 00454 release_call_previous(d,RELEASE_CALL_WEIRD,488,reason); 00455 d_unlock(d->hash); 00456 return CSCF_RETURN_TRUE; 00457 } else { 00458 release_call_previous(d,RELEASE_CALL_EARLY,488,reason); 00459 d_unlock(d->hash); 00460 return CSCF_RETURN_TRUE; 00461 } 00462 } else { 00463 LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply : unable to find dialog\n"); 00464 return CSCF_RETURN_BREAK; 00465 } 00466 00467 }
str reason_hdr_s = {"Reason: SIP ;cause=",19} [static] |
Definition at line 70 of file release_call.c.
Referenced by release_call_confirmed(), and release_call_previous().
str reason_hdr_1 = {" ;text=\"",8} [static] |
Definition at line 71 of file release_call.c.
Referenced by release_call_confirmed(), and release_call_previous().
str reason_hdr_e = {"\"\r\n",3} [static] |
Definition at line 72 of file release_call.c.
Referenced by release_call_confirmed(), and release_call_previous().
str _488_text_s = {"Not Acceptable Here",19} [static] |
str method_CANCEL_s = {"CANCEL",6} [static] |
str method_ACK_s = {"ACK",3} [static] |
str method_BYE_s = {"BYE",3} [static] |
Definition at line 80 of file release_call.c.
Referenced by release_call_confirmed(), and release_call_previous().
str content_length_s = {"Content-Length: 0\r\n",19} [static] |
Definition at line 88 of file release_call.c.
Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().
1.5.2