![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
sip3_refer.c File Reference
Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)
Definition in file sip3_refer.c.
#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <regex.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/features.h"
#include "asterisk/srv.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/astobj.h"
#include "asterisk/dnsmgr.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/monitor.h"
#include "asterisk/localtime.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/compiler.h"
#include "sip3.h"
#include "sip3funcs.h"
Include dependency graph for sip3_refer.c:

Go to the source code of this file.
Data Structures | |
| struct | c_referstatusstring |
| Table to convert from REFER status variable to string. More... | |
Functions | |
| static int | attempt_transfer (struct sip_dual *transferer, struct sip_dual *target) |
| Attempt transfer of SIP call This fix for attended transfers on a local PBX. | |
| static int | get_refer_info (struct sip_dialog *transferer, struct sip_request *outgoing_req) |
| Call transfer support (the REFER method) Extracts Refer headers into pvt dialog structure. | |
| int | handle_request_refer (struct sip_dialog *p, struct sip_request *req, int debug, int seqno, int *nounlock) |
| static int | local_attended_transfer (struct sip_dialog *transferer, struct sip_dual *current, struct sip_request *req, int seqno) |
| Find all call legs and bridge transferee with target called from handle_request_refer. | |
| const char * | referstatus2str (enum referstatus rstatus) |
| Convert transfer status to string. | |
| static int | sip_park (struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno) |
| Park a call using the subsystem in res_features.c This is executed in a separate thread. | |
| static void * | sip_park_thread (void *stuff) |
| Park SIP call support function Starts in a new thread, then parks the call XXX Should we add a wait period after streaming audio and before hangup?? Sometimes the audio can't be heard before hangup. | |
| int | sip_refer_allocate (struct sip_dialog *p) |
| Allocate SIP refer structure. | |
| GNURK int | transmit_notify_with_sipfrag (struct sip_dialog *p, int cseq, char *message, int terminate) |
| Notify a transferring party of the status of transfer. | |
Variables | |
| static const struct c_referstatusstring | referstatusstrings [] |
| Table to convert from REFER status variable to string. | |
|
||||||||||||
|
Attempt transfer of SIP call This fix for attended transfers on a local PBX.
Definition at line 451 of file sip3_refer.c. References ast_channel::_state, ast_cdr_append(), ast_channel_masquerade(), ast_log(), ast_quiet_chan(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), ast_state2str(), sip_dual::chan1, sip_dual::chan2, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, and option_debug. 00452 { 00453 int res = 0; 00454 struct ast_channel *peera = NULL, 00455 *peerb = NULL, 00456 *peerc = NULL, 00457 *peerd = NULL; 00458 00459 00460 /* We will try to connect the transferee with the target and hangup 00461 all channels to the transferer */ 00462 if (option_debug > 3) { 00463 ast_log(LOG_DEBUG, "Sip transfer:--------------------\n"); 00464 if (transferer->chan1) 00465 ast_log(LOG_DEBUG, "-- Transferer to PBX channel: %s State %s\n", transferer->chan1->name, ast_state2str(transferer->chan1->_state)); 00466 else 00467 ast_log(LOG_DEBUG, "-- No transferer first channel - odd??? \n"); 00468 if (target->chan1) 00469 ast_log(LOG_DEBUG, "-- Transferer to PBX second channel (target): %s State %s\n", target->chan1->name, ast_state2str(target->chan1->_state)); 00470 else 00471 ast_log(LOG_DEBUG, "-- No target first channel ---\n"); 00472 if (transferer->chan2) 00473 ast_log(LOG_DEBUG, "-- Bridged call to transferee: %s State %s\n", transferer->chan2->name, ast_state2str(transferer->chan2->_state)); 00474 else 00475 ast_log(LOG_DEBUG, "-- No bridged call to transferee\n"); 00476 if (target->chan2) 00477 ast_log(LOG_DEBUG, "-- Bridged call to transfer target: %s State %s\n", target->chan2 ? target->chan2->name : "<none>", target->chan2 ? ast_state2str(target->chan2->_state) : "(none)"); 00478 else 00479 ast_log(LOG_DEBUG, "-- No target second channel ---\n"); 00480 ast_log(LOG_DEBUG, "-- END Sip transfer:--------------------\n"); 00481 } 00482 if (transferer->chan2) { /* We have a bridge on the transferer's channel */ 00483 peera = transferer->chan1; /* Transferer - PBX -> transferee channel * the one we hangup */ 00484 peerb = target->chan1; /* Transferer - PBX -> target channel - This will get lost in masq */ 00485 peerc = transferer->chan2; /* Asterisk to Transferee */ 00486 peerd = target->chan2; /* Asterisk to Target */ 00487 if (option_debug > 2) 00488 ast_log(LOG_DEBUG, "SIP transfer: Four channels to handle\n"); 00489 } else if (target->chan2) { /* Transferer has no bridge (IVR), but transferee */ 00490 peera = target->chan1; /* Transferer to PBX -> target channel */ 00491 peerb = transferer->chan1; /* Transferer to IVR*/ 00492 peerc = target->chan2; /* Asterisk to Target */ 00493 peerd = transferer->chan2; /* Nothing */ 00494 if (option_debug > 2) 00495 ast_log(LOG_DEBUG, "SIP transfer: Three channels to handle\n"); 00496 } 00497 00498 if (peera && peerb && peerc && (peerb != peerc)) { 00499 ast_quiet_chan(peera); /* Stop generators */ 00500 ast_quiet_chan(peerb); 00501 ast_quiet_chan(peerc); 00502 if (peerd) 00503 ast_quiet_chan(peerd); 00504 00505 /* Fix CDRs so they're attached to the remaining channel */ 00506 if (peera->cdr && peerb->cdr) 00507 peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr); 00508 else if (peera->cdr) 00509 peerb->cdr = peera->cdr; 00510 peera->cdr = NULL; 00511 00512 if (peerb->cdr && peerc->cdr) 00513 peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr); 00514 else if (peerc->cdr) 00515 peerb->cdr = peerc->cdr; 00516 peerc->cdr = NULL; 00517 00518 if (option_debug > 3) 00519 ast_log(LOG_DEBUG, "SIP transfer: trying to masquerade %s into %s\n", peerc->name, peerb->name); 00520 if (ast_channel_masquerade(peerb, peerc)) { 00521 ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name); 00522 res = -1; 00523 } else 00524 ast_log(LOG_DEBUG, "SIP transfer: Succeeded to masquerade channels.\n"); 00525 return res; 00526 } else { 00527 ast_log(LOG_NOTICE, "SIP Transfer attempted with no appropriate bridged calls to transfer\n"); 00528 if (transferer->chan1) 00529 ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV); 00530 if (target->chan1) 00531 ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV); 00532 return -1; 00533 } 00534 return 0; 00535 }
|
|
||||||||||||
|
Call transfer support (the REFER method) Extracts Refer headers into pvt dialog structure.
Definition at line 203 of file sip3_refer.c. References ast_exists_extension(), ast_log(), ast_strdupa, ast_strlen_zero(), ast_uri_decode(), ast_verbose(), sip_refer::attendedtransfer, sip_globals::default_context, get_header(), get_in_brackets(), global, sip_dialog::initreq, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, option_debug, sip_dialog::owner, pbx_builtin_getvar_helper(), sip_dialog::refer, sip_refer::refer_to, sip_refer::refer_to_context, sip_refer::refer_to_domain, sip_refer::refer_to_urioption, sip_refer::referred_by, sip_refer::referred_by_name, sip_refer::replaces_callid, sip_refer::replaces_callid_fromtag, sip_refer::replaces_callid_totag, S_OR, sip_debug_test_pvt(), and strcasestr(). 00204 { 00205 00206 const char *p_referred_by = NULL; 00207 char *h_refer_to = NULL; 00208 char *h_referred_by = NULL; 00209 char *refer_to; 00210 const char *p_refer_to; 00211 char *referred_by_uri = NULL; 00212 char *ptr; 00213 struct sip_request *req = NULL; 00214 const char *transfer_context = NULL; 00215 struct sip_refer *referdata; 00216 00217 00218 req = outgoing_req; 00219 referdata = transferer->refer; 00220 00221 if (!req) 00222 req = transferer->initreq; 00223 00224 p_refer_to = get_header(req, "Refer-To"); 00225 if (ast_strlen_zero(p_refer_to)) { 00226 ast_log(LOG_WARNING, "Refer-To Header missing. Skipping transfer.\n"); 00227 return -2; /* Syntax error */ 00228 } 00229 h_refer_to = ast_strdupa(p_refer_to); 00230 refer_to = get_in_brackets(h_refer_to); 00231 ast_uri_decode(refer_to); 00232 00233 if (strncasecmp(refer_to, "sip:", 4)) { 00234 ast_log(LOG_WARNING, "Can't transfer to non-sip: URI. (Refer-to: %s)?\n", refer_to); 00235 return -3; 00236 } 00237 refer_to += 4; /* Skip sip: */ 00238 00239 /* Get referred by header if it exists */ 00240 p_referred_by = get_header(req, "Referred-By"); 00241 if (!ast_strlen_zero(p_referred_by)) { 00242 char *lessthan; 00243 h_referred_by = ast_strdupa(p_referred_by); 00244 ast_uri_decode(h_referred_by); 00245 00246 /* Store referrer's caller ID name */ 00247 ast_copy_string(referdata->referred_by_name, h_referred_by, sizeof(referdata->referred_by_name)); 00248 if ((lessthan = strchr(referdata->referred_by_name, '<'))) { 00249 *(lessthan - 1) = '\0'; /* Space */ 00250 } 00251 00252 referred_by_uri = get_in_brackets(h_referred_by); 00253 if(strncasecmp(referred_by_uri, "sip:", 4)) { 00254 ast_log(LOG_WARNING, "Huh? Not a sip: header (Referred-by: %s). Skipping.\n", referred_by_uri); 00255 referred_by_uri = (char *) NULL; 00256 } else { 00257 referred_by_uri += 4; /* Skip sip: */ 00258 } 00259 } 00260 00261 /* Check for arguments in the refer_to header */ 00262 if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */ 00263 *ptr++ = '\0'; 00264 if (!strncasecmp(ptr, "REPLACES=", 9)) { 00265 char *to = NULL, *from = NULL; 00266 00267 /* This is an attended transfer */ 00268 referdata->attendedtransfer = 1; 00269 strncpy(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid)); 00270 ast_uri_decode(referdata->replaces_callid); 00271 if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ { 00272 *ptr++ = '\0'; 00273 } 00274 00275 if (ptr) { 00276 /* Find the different tags before we destroy the string */ 00277 to = strcasestr(ptr, "to-tag="); 00278 from = strcasestr(ptr, "from-tag="); 00279 } 00280 00281 /* Grab the to header */ 00282 if (to) { 00283 ptr = to + 7; 00284 if ((to = strchr(ptr, '&'))) 00285 *to = '\0'; 00286 if ((to = strchr(ptr, ';'))) 00287 *to = '\0'; 00288 ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag)); 00289 } 00290 00291 if (from) { 00292 ptr = from + 9; 00293 if ((to = strchr(ptr, '&'))) 00294 *to = '\0'; 00295 if ((to = strchr(ptr, ';'))) 00296 *to = '\0'; 00297 ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag)); 00298 } 00299 00300 if (option_debug > 1) 00301 ast_log(LOG_DEBUG,"Attended transfer: Will use Replace-Call-ID : %s F-tag: %s T-tag: %s\n", referdata->replaces_callid, referdata->replaces_callid_fromtag ? referdata->replaces_callid_fromtag : "<none>", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "<none>" ); 00302 } 00303 } 00304 00305 if ((ptr = strchr(refer_to, '@'))) { /* Separate domain */ 00306 char *urioption; 00307 00308 *ptr++ = '\0'; 00309 if ((urioption = strchr(ptr, ';'))) 00310 *urioption++ = '\0'; 00311 /* Save the domain for the dial plan */ 00312 strncpy(referdata->refer_to_domain, ptr, sizeof(referdata->refer_to_domain)); 00313 if (urioption) 00314 strncpy(referdata->refer_to_urioption, urioption, sizeof(referdata->refer_to_urioption)); 00315 } 00316 00317 if ((ptr = strchr(refer_to, ';'))) /* Remove options */ 00318 *ptr = '\0'; 00319 ast_copy_string(referdata->refer_to, refer_to, sizeof(referdata->refer_to)); 00320 00321 if (referred_by_uri) { 00322 if ((ptr = strchr(referred_by_uri, ';'))) /* Remove options */ 00323 *ptr = '\0'; 00324 ast_copy_string(referdata->referred_by, referred_by_uri, sizeof(referdata->referred_by)); 00325 } else { 00326 referdata->referred_by[0] = '\0'; 00327 } 00328 00329 /* Determine transfer context */ 00330 if (transferer->owner) /* Mimic behaviour in res_features.c */ 00331 transfer_context = pbx_builtin_getvar_helper(transferer->owner, "TRANSFER_CONTEXT"); 00332 00333 /* By default, use the context in the channel sending the REFER */ 00334 if (ast_strlen_zero(transfer_context)) { 00335 transfer_context = S_OR(transferer->owner->macrocontext, 00336 S_OR(transferer->context, global.default_context)); 00337 } 00338 00339 strncpy(referdata->refer_to_context, transfer_context, sizeof(referdata->refer_to_context)); 00340 00341 /* Either an existing extension or the parking extension */ 00342 if (ast_exists_extension(NULL, transfer_context, refer_to, 1, NULL) ) { 00343 if (sip_debug_test_pvt(transferer)) { 00344 ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, referred_by_uri); 00345 } 00346 /* We are ready to transfer to the extension */ 00347 return 0; 00348 } 00349 if (sip_debug_test_pvt(transferer)) 00350 ast_verbose("Failed SIP Transfer to non-existing extension %s in context %s\n n", refer_to, transfer_context); 00351 00352 /* Failure, we can't find this extension */ 00353 return -1; 00354 }
|
|
||||||||||||||||||||||||
|
Definition at line 708 of file sip3_refer.c. References sip_globals::allow_external_domains, sip_dialog::allowtransfer, append_history, ast_async_goto(), ast_bridged_channel(), AST_CAUSE_NORMAL_CLEARING, ast_channel_unlock, ast_clear_flag, AST_CONTROL_UNHOLD, ast_log(), ast_parking_ext(), ast_queue_control(), ast_set_flag, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_uri_encode(), ast_verbose(), sip_refer::attendedtransfer, sip_dual::chan1, sip_dual::chan2, check_sip_domain(), context, sip_globals::default_context, domains_configured(), FALSE, sip_dialog::flags, get_refer_info(), global, ast_channel::hangupcause, local_attended_transfer(), sip_refer::localtransfer, LOG_DEBUG, option_debug, sip_dialog::owner, pbx_builtin_setvar_helper(), sip_dialog::refer, REFER_200OK, REFER_FAILED, REFER_SENT, sip_refer::refer_to, sip_refer::refer_to_context, sip_refer::refer_to_domain, sip_refer::referred_by, sip_refer::replaces_callid, sip_refer::replaces_callid_fromtag, sip_refer::replaces_callid_totag, sip_dual::req, SIP_ALREADYGONE, SIP_DEFER_BYE_ON_TRANSFER, SIP_GOTREFER, SIP_NEEDDESTROY, SIP_OUTGOING, sip_park(), SIP_PKT_DEBUG, SIP_PKT_IGNORE, sip_refer_allocate(), sipdebug, sip_refer::status, TRANSFER_CLOSED, transmit_notify_with_sipfrag(), transmit_response(), and TRUE. 00709 { 00710 struct sip_dual current; /* Chan1: Call between asterisk and transferer */ 00711 /* Chan2: Call between asterisk and transferee */ 00712 00713 int res = 0; 00714 00715 if (ast_test_flag(req, SIP_PKT_DEBUG)) 00716 ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n", p->callid, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "callee" : "caller"); 00717 00718 if (!p->owner) { 00719 /* This is a REFER outside of an existing SIP dialog */ 00720 /* We can't handle that, so decline it */ 00721 if (option_debug > 2) 00722 ast_log(LOG_DEBUG, "Call %s: Declined REFER, outside of dialog...\n", p->callid); 00723 transmit_response(p, "603 Declined (No dialog)", req); 00724 if (!ast_test_flag(req, SIP_PKT_IGNORE)) { 00725 append_history(p, "Xfer", "Refer failed. Outside of dialog."); 00726 ast_set_flag(&p->flags[0], SIP_ALREADYGONE); 00727 ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 00728 } 00729 return 0; 00730 } 00731 00732 00733 /* Check if transfer is allowed from this device */ 00734 if (p->allowtransfer == TRANSFER_CLOSED ) { 00735 /* Transfer not allowed, decline */ 00736 transmit_response(p, "603 Declined (policy)", req); 00737 append_history(p, "Xfer", "Refer failed. Allowtransfer == closed."); 00738 /* Do not destroy SIP session */ 00739 return 0; 00740 } 00741 00742 if(!ast_test_flag(req, SIP_PKT_IGNORE) && ast_test_flag(&p->flags[0], SIP_GOTREFER)) { 00743 /* Already have a pending REFER */ 00744 transmit_response(p, "491 Request pending", req); 00745 append_history(p, "Xfer", "Refer failed. Request pending."); 00746 return 0; 00747 } 00748 00749 /* Allocate memory for call transfer data */ 00750 if (!p->refer && !sip_refer_allocate(p)) { 00751 transmit_response(p, "500 Internal Server Error", req); 00752 append_history(p, "Xfer", "Refer failed. Memory allocation error."); 00753 return -3; 00754 } 00755 00756 res = get_refer_info(p, req); /* Extract headers */ 00757 00758 p->refer->status = REFER_SENT; 00759 00760 if (res != 0) { 00761 switch (res) { 00762 case -2: /* Syntax error */ 00763 transmit_response(p, "400 Bad Request (Refer-to missing)", req); 00764 append_history(p, "Xfer", "Refer failed. Refer-to missing."); 00765 if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug) 00766 ast_log(LOG_DEBUG, "SIP transfer to black hole can't be handled (no refer-to: )\n"); 00767 break; 00768 case -3: 00769 transmit_response(p, "603 Declined (Non sip: uri)", req); 00770 append_history(p, "Xfer", "Refer failed. Non SIP uri"); 00771 if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug) 00772 ast_log(LOG_DEBUG, "SIP transfer to non-SIP uri denied\n"); 00773 break; 00774 default: 00775 /* Refer-to extension not found, fake a failed transfer */ 00776 transmit_response(p, "202 Accepted", req); 00777 append_history(p, "Xfer", "Refer failed. Bad extension."); 00778 transmit_notify_with_sipfrag(p, seqno, "404 Not found", TRUE); 00779 ast_clear_flag(&p->flags[0], SIP_GOTREFER); 00780 if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug) 00781 ast_log(LOG_DEBUG, "SIP transfer to bad extension: %s\n", p->refer->refer_to); 00782 break; 00783 } 00784 return 0; 00785 } 00786 if (ast_strlen_zero(p->context)) 00787 ast_string_field_set(p, context, global.default_context); 00788 00789 /* If we do not support SIP domains, all transfers are local */ 00790 if (global.allow_external_domains && check_sip_domain(p->refer->refer_to_domain, NULL, 0)) { 00791 p->refer->localtransfer = 1; 00792 if (sipdebug && option_debug > 2) 00793 ast_log(LOG_DEBUG, "This SIP transfer is local : %s\n", p->refer->refer_to_domain); 00794 } else if (domains_configured()) { 00795 /* This PBX don't bother with SIP domains, so all transfers are local */ 00796 p->refer->localtransfer = 1; 00797 } else 00798 if (sipdebug && option_debug > 2) 00799 ast_log(LOG_DEBUG, "This SIP transfer is to a remote SIP extension (remote domain %s)\n", p->refer->refer_to_domain); 00800 00801 /* Is this a repeat of a current request? Ignore it */ 00802 /* Don't know what else to do right now. */ 00803 if (ast_test_flag(req, SIP_PKT_IGNORE)) 00804 return res; 00805 00806 /* If this is a blind transfer, we have the following 00807 channels to work with: 00808 - chan1, chan2: The current call between transferer and transferee (2 channels) 00809 - target_channel: A new call from the transferee to the target (1 channel) 00810 We need to stay tuned to what happens in order to be able 00811 to bring back the call to the transferer */ 00812 00813 /* If this is a attended transfer, we should have all call legs within reach: 00814 - chan1, chan2: The call between the transferer and transferee (2 channels) 00815 - target_channel, targetcall_pvt: The call between the transferer and the target (2 channels) 00816 We want to bridge chan2 with targetcall_pvt! 00817 00818 The replaces call id in the refer message points 00819 to the call leg between Asterisk and the transferer. 00820 So we need to connect the target and the transferee channel 00821 and hangup the two other channels silently 00822 00823 If the target is non-local, the call ID could be on a remote 00824 machine and we need to send an INVITE with replaces to the 00825 target. We basically handle this as a blind transfer 00826 and let the sip_call function catch that we need replaces 00827 header in the INVITE. 00828 */ 00829 00830 00831 /* Get the transferer's channel */ 00832 current.chan1 = p->owner; 00833 00834 /* Find the other part of the bridge (2) - transferee */ 00835 current.chan2 = ast_bridged_channel(current.chan1); 00836 00837 if (sipdebug && option_debug > 2) 00838 ast_log(LOG_DEBUG, "SIP %s transfer: Transferer channel %s, transferee channel %s\n", p->refer->attendedtransfer ? "attended" : "blind", current.chan1->name, current.chan2 ? current.chan2->name : "<none>"); 00839 00840 if (!current.chan2 && !p->refer->attendedtransfer) { 00841 /* No bridged channel, propably IVR or echo or similar... */ 00842 /* Guess we should masquerade or something here */ 00843 /* Until we figure it out, refuse transfer of such calls */ 00844 if (sipdebug && option_debug > 2) 00845 ast_log(LOG_DEBUG,"Refused SIP transfer on non-bridged channel.\n"); 00846 p->refer->status = REFER_FAILED; 00847 append_history(p, "Xfer", "Refer failed. Non-bridged channel."); 00848 transmit_response(p, "603 Declined", req); 00849 return -1; 00850 } 00851 00852 if (current.chan2) { 00853 if (sipdebug && option_debug > 3) 00854 ast_log(LOG_DEBUG, "Got SIP transfer, applying to bridged peer '%s'\n", current.chan2->name); 00855 00856 ast_queue_control(current.chan1, AST_CONTROL_UNHOLD); 00857 } 00858 00859 ast_set_flag(&p->flags[0], SIP_GOTREFER); 00860 00861 /* Attended transfer: Find all call legs and bridge transferee with target*/ 00862 if (p->refer->attendedtransfer) { 00863 if ((res = local_attended_transfer(p, ¤t, req, seqno))) 00864 return res; /* We're done with the transfer */ 00865 /* Fall through for remote transfers that we did not find locally */ 00866 if (sipdebug && option_debug > 3) 00867 ast_log(LOG_DEBUG, "SIP attended transfer: Still not our call - generating INVITE with replaces\n"); 00868 /* Fallthrough if we can't find the call leg internally */ 00869 } 00870 00871 00872 /* Parking a call */ 00873 if (p->refer->localtransfer && !strcmp(p->refer->refer_to, ast_parking_ext())) { 00874 /* Must release c's lock now, because it will not longer be accessible after the transfer! */ 00875 *nounlock = 1; 00876 ast_channel_unlock(current.chan1); 00877 current.req = req; 00878 ast_clear_flag(&p->flags[0], SIP_GOTREFER); 00879 p->refer->status = REFER_200OK; 00880 append_history(p, "Xfer", "REFER to call parking."); 00881 if (sipdebug && option_debug > 3) 00882 ast_log(LOG_DEBUG, "SIP transfer to parking: trying to park %s. Parked by %s\n", current.chan2->name, current.chan1->name); 00883 sip_park(current.chan2, current.chan1, req, seqno); 00884 return res; 00885 } 00886 00887 /* Blind transfers and remote attended xfers */ 00888 transmit_response(p, "202 Accepted", req); 00889 00890 if (current.chan1 && current.chan2) { 00891 if (option_debug > 2) 00892 ast_log(LOG_DEBUG, "chan1->name: %s\n", current.chan1->name); 00893 pbx_builtin_setvar_helper(current.chan1, "BLINDTRANSFER", current.chan2->name); 00894 } 00895 if (current.chan2) { 00896 pbx_builtin_setvar_helper(current.chan2, "BLINDTRANSFER", current.chan1->name); 00897 pbx_builtin_setvar_helper(current.chan2, "SIPDOMAIN", p->refer->refer_to_domain); 00898 pbx_builtin_setvar_helper(current.chan2, "SIPTRANSFER", "yes"); 00899 /* One for the new channel */ 00900 pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER", "yes"); 00901 if (p->refer->referred_by) 00902 pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REFERER", p->refer->referred_by); 00903 if (p->refer->referred_by) 00904 /* Attended transfer to remote host, prepare headers for the INVITE */ 00905 pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REFERER", p->refer->referred_by); 00906 } 00907 /* Generate an URI-encoded string */ 00908 if (p->refer->replaces_callid && !ast_strlen_zero(p->refer->replaces_callid)) { 00909 char tempheader[BUFSIZ]; 00910 char tempheader2[BUFSIZ]; 00911 snprintf(tempheader, sizeof(tempheader), "%s%s%s%s%s", p->refer->replaces_callid, 00912 p->refer->replaces_callid_totag ? ";to-tag=" : "", 00913 p->refer->replaces_callid_totag, 00914 p->refer->replaces_callid_fromtag ? ";from-tag=" : "", 00915 p->refer->replaces_callid_fromtag); 00916 00917 /* Convert it to URL encoding, also convert reserved strings */ 00918 ast_uri_encode(tempheader, tempheader2, sizeof(tempheader2), 1); 00919 00920 if (current.chan2) 00921 pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REPLACES", tempheader2); 00922 } 00923 /* Must release lock now, because it will not longer 00924 be accessible after the transfer! */ 00925 *nounlock = 1; 00926 ast_channel_unlock(current.chan1); 00927 ast_channel_unlock(current.chan2); 00928 00929 /* Connect the call */ 00930 00931 /* FAKE ringing if not attended transfer */ 00932 if (!p->refer->attendedtransfer) 00933 transmit_notify_with_sipfrag(p, seqno, "183 Ringing", FALSE); 00934 00935 /* For blind transfer, this will lead to a new call */ 00936 /* For attended transfer to remote host, this will lead to 00937 a new SIP call with a replaces header, if the dial plan allows it 00938 */ 00939 if (!current.chan2) { 00940 /* We have no bridge, so we're talking with Asterisk somehow */ 00941 /* We need to masquerade this call */ 00942 /* What to do to fix this situation: 00943 * Set up the new call in a new channel 00944 * Let the new channel masq into this channel 00945 Please add that code here :-) 00946 */ 00947 transmit_response(p, "202 Accepted", req); 00948 p->refer->status = REFER_FAILED; 00949 transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable (can't handle one-legged xfers)", TRUE); 00950 ast_clear_flag(&p->flags[0], SIP_GOTREFER); 00951 append_history(p, "Xfer", "Refer failed (only bridged calls)."); 00952 return -1; 00953 } 00954 ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */ 00955 00956 /* For blind transfers, move the call to the new extensions. For attended transfers on multiple 00957 servers - generate an INVITE with Replaces. Either way, let the dial plan decided */ 00958 res = ast_async_goto(current.chan2, p->refer->refer_to_context, p->refer->refer_to, 1); 00959 00960 if (!res) { 00961 /* Success - we have a new channel */ 00962 if (option_debug > 2) 00963 ast_log(LOG_DEBUG, "%s transfer succeeded. Telling transferer.\n", p->refer->attendedtransfer? "Attended" : "Blind"); 00964 transmit_notify_with_sipfrag(p, seqno, "200 Ok", TRUE); 00965 if (p->refer->localtransfer) 00966 p->refer->status = REFER_200OK; 00967 if (p->owner) 00968 p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00969 append_history(p, "Xfer", "Refer succeeded."); 00970 ast_clear_flag(&p->flags[0], SIP_GOTREFER); 00971 /* Do not hangup call, the other side do that when we say 200 OK */ 00972 /* We could possibly implement a timer here, auto congestion */ 00973 res = 0; 00974 } else { 00975 ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Don't delay hangup */ 00976 if (option_debug > 2) 00977 ast_log(LOG_DEBUG, "%s transfer failed. Resuming original call.\n", p->refer->attendedtransfer? "Attended" : "Blind"); 00978 append_history(p, "Xfer", "Refer failed."); 00979 /* Failure of some kind */ 00980 p->refer->status = REFER_FAILED; 00981 transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable", TRUE); 00982 ast_clear_flag(&p->flags[0], SIP_GOTREFER); 00983 res = -1; 00984 } 00985 return res; 00986 }
|
|
||||||||||||||||||||
|
Find all call legs and bridge transferee with target called from handle_request_refer.
Definition at line 539 of file sip3_refer.c. References ast_channel::_state, append_history, ast_bridged_channel(), ast_channel_unlock, ast_clear_flag, ast_hangup(), ast_log(), ast_set_flag, ast_state2str(), AST_STATE_RING, AST_STATE_RINGING, AST_STATE_UP, attempt_transfer(), sip_dual::chan1, sip_dual::chan2, dialog_lock(), error(), FALSE, sip_dialog::flags, get_sip_dialog_byid_locked(), sip_refer::localtransfer, LOG_DEBUG, option_debug, sip_dialog::owner, sip_dialog::refer, REFER_200OK, REFER_FAILED, sip_refer::replaces_callid, sip_refer::replaces_callid_fromtag, sip_refer::replaces_callid_totag, SIP_DEFER_BYE_ON_TRANSFER, SIP_GOTREFER, sipdebug, sip_refer::status, transmit_notify_with_sipfrag(), transmit_response(), and TRUE. 00540 { 00541 struct sip_dual target; /* Chan 1: Call from tranferer to Asterisk */ 00542 /* Chan 2: Call from Asterisk to target */ 00543 int res = 0; 00544 struct sip_dialog *targetcall_pvt; 00545 int error = 0; 00546 00547 /* Check if the call ID of the replaces header does exist locally */ 00548 if (!(targetcall_pvt = get_sip_dialog_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag, 00549 transferer->refer->replaces_callid_fromtag))) { 00550 if (transferer->refer->localtransfer) { 00551 /* We did not find the refered call. Sorry, can't accept then */ 00552 transmit_response(transferer, "202 Accepted", req); 00553 /* Let's fake a response from someone else in order 00554 to follow the standard */ 00555 transmit_notify_with_sipfrag(transferer, seqno, "481 Call leg/transaction does not exist", TRUE); 00556 append_history(transferer, "Xfer", "Refer failed"); 00557 ast_clear_flag(&transferer->flags[0], SIP_GOTREFER); 00558 transferer->refer->status = REFER_FAILED; 00559 return -1; 00560 } 00561 /* Fall through for remote transfers that we did not find locally */ 00562 if (option_debug > 2) 00563 ast_log(LOG_DEBUG, "SIP attended transfer: Not our call - generating INVITE with replaces\n"); 00564 return 0; 00565 } 00566 00567 /* Ok, we can accept this transfer */ 00568 transmit_response(transferer, "202 Accepted", req); 00569 append_history(transferer, "Xfer", "Refer accepted"); 00570 if (!targetcall_pvt->owner) { /* No active channel */ 00571 if (option_debug > 3) 00572 ast_log(LOG_DEBUG, "SIP attended transfer: Error: No owner of target call\n"); 00573 error = 1; 00574 } 00575 /* We have a channel, find the bridge */ 00576 target.chan1 = targetcall_pvt->owner; /* Transferer to Asterisk */ 00577 00578 if (!error) { 00579 target.chan2 = ast_bridged_channel(targetcall_pvt->owner); /* Asterisk to target */ 00580 00581 if (!target.chan2 || !(target.chan2->_state == AST_STATE_UP || target.chan2->_state == AST_STATE_RINGING) ) { 00582 /* Wrong state of new channel */ 00583 if (option_debug > 3) { 00584 if (target.chan2) 00585 ast_log(LOG_DEBUG, "SIP attended transfer: Error: Wrong state of target call: %s\n", ast_state2str(target.chan2->_state)); 00586 else if (target.chan1->_state != AST_STATE_RING) 00587 ast_log(LOG_DEBUG, "SIP attended transfer: Error: No target channel\n"); 00588 else 00589 ast_log(LOG_DEBUG, "SIP attended transfer: Attempting transfer in ringing state\n"); 00590 } 00591 if (target.chan1->_state != AST_STATE_RING) 00592 error = 1; 00593 } 00594 } 00595 if (error) { /* Cancel transfer */ 00596 transmit_notify_with_sipfrag(transferer, seqno, "503 Service Unavailable", TRUE); 00597 append_history(transferer, "Xfer", "Refer failed"); 00598 ast_clear_flag(&transferer->flags[0], SIP_GOTREFER); 00599 transferer->refer->status = REFER_FAILED; 00600 dialog_lock(targetcall_pvt, FALSE); 00601 ast_channel_unlock(current->chan1); 00602 ast_channel_unlock(target.chan1); 00603 return -1; 00604 } 00605 00606 /* Transfer */ 00607 if (option_debug > 3 && sipdebug) { 00608 if (current->chan2) /* We have two bridges */ 00609 ast_log(LOG_DEBUG, "SIP attended transfer: trying to bridge %s and %s\n", target.chan1->name, current->chan2->name); 00610 else /* One bridge, propably transfer of IVR/voicemail etc */ 00611 ast_log(LOG_DEBUG, "SIP attended transfer: trying to make %s take over (masq) %s\n", target.chan1->name, current->chan1->name); 00612 } 00613 00614 ast_set_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */ 00615 00616 /* Perform the transfer */ 00617 res = attempt_transfer(current, &target); 00618 dialog_lock(targetcall_pvt, FALSE); 00619 if (res) { 00620 /* Failed transfer */ 00621 /* Could find better message, but they will get the point */ 00622 transmit_notify_with_sipfrag(transferer, seqno, "486 Busy", TRUE); 00623 append_history(transferer, "Xfer", "Refer failed"); 00624 if (targetcall_pvt->owner) 00625 ast_channel_unlock(targetcall_pvt->owner); 00626 /* Right now, we have to hangup, sorry. Bridge is destroyed */ 00627 ast_hangup(transferer->owner); 00628 } else { 00629 /* Transfer succeeded! */ 00630 00631 /* Tell transferer that we're done. */ 00632 transmit_notify_with_sipfrag(transferer, seqno, "200 OK", TRUE); 00633 append_history(transferer, "Xfer", "Refer succeeded"); 00634 transferer->refer->status = REFER_200OK; 00635 if (targetcall_pvt->owner) { 00636 if (option_debug) 00637 ast_log(LOG_DEBUG, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name); 00638 ast_channel_unlock(targetcall_pvt->owner); 00639 } 00640 } 00641 return 1; 00642 }
|
|
|
Convert transfer status to string. Definition at line 109 of file sip3_refer.c. References referstatusstrings. 00110 { 00111 int i = (sizeof(referstatusstrings) / sizeof(referstatusstrings[0])); 00112 int x; 00113 00114 for (x = 0; x < i; x++) { 00115 if (referstatusstrings[x].status == rstatus) 00116 return (char *) referstatusstrings[x].text; 00117 } 00118 return ""; 00119 }
|
|
||||||||||||||||||||
|
Park a call using the subsystem in res_features.c This is executed in a separate thread.
Definition at line 360 of file sip3_refer.c. References ast_calloc, AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_hangup(), ast_log(), ast_pthread_create_background, AST_STATE_DOWN, ast_channel::context, ast_channel::exten, free, ast_channel::hangupcause, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::priority, ast_channel::readformat, sip_park_thread(), and ast_channel::writeformat. 00361 { 00362 struct sip_dual *d; 00363 struct ast_channel *transferee, *transferer; 00364 /* Chan2m: The transferer, chan1m: The transferee */ 00365 pthread_t th; 00366 00367 transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "Parking/%s", chan1->name); 00368 transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "SIPPeer/%s", chan2->name); 00369 if ((!transferer) || (!transferee)) { 00370 if (transferee) { 00371 transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION; 00372 ast_hangup(transferee); 00373 } 00374 if (transferer) { 00375 transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION; 00376 ast_hangup(transferer); 00377 } 00378 return -1; 00379 } 00380 00381 /* Make formats okay */ 00382 transferee->readformat = chan1->readformat; 00383 transferee->writeformat = chan1->writeformat; 00384 00385 /* Prepare for taking over the channel */ 00386 ast_channel_masquerade(transferee, chan1); 00387 00388 /* Setup the extensions and such */ 00389 ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context)); 00390 ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten)); 00391 transferee->priority = chan1->priority; 00392 00393 /* We make a clone of the peer channel too, so we can play 00394 back the announcement */ 00395 00396 /* Make formats okay */ 00397 transferer->readformat = chan2->readformat; 00398 transferer->writeformat = chan2->writeformat; 00399 00400 /* Prepare for taking over the channel */ 00401 ast_channel_masquerade(transferer, chan2); 00402 00403 /* Setup the extensions and such */ 00404 ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context)); 00405 ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten)); 00406 transferer->priority = chan2->priority; 00407 00408 ast_channel_lock(transferer); 00409 if (ast_do_masquerade(transferer)) { 00410 ast_log(LOG_WARNING, "Masquerade failed :(\n"); 00411 ast_channel_unlock(transferer); 00412 transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION; 00413 ast_hangup(transferer); 00414 return -1; 00415 } 00416 ast_channel_unlock(transferer); 00417 if (!transferer || !transferee) { 00418 if (!transferer) { 00419 if (option_debug) 00420 ast_log(LOG_DEBUG, "No transferer channel, giving up parking\n"); 00421 } 00422 if (!transferee) { 00423 if (option_debug) 00424 ast_log(LOG_DEBUG, "No transferee channel, giving up parking\n"); 00425 } 00426 return -1; 00427 } 00428 if ((d = ast_calloc(1, sizeof(*d)))) { 00429 pthread_attr_t attr; 00430 00431 pthread_attr_init(&attr); 00432 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00433 00434 /* Save original request for followup */ 00435 d->req = req; 00436 d->chan1 = transferee; /* Transferee */ 00437 d->chan2 = transferer; /* Transferer */ 00438 d->seqno = seqno; 00439 if (ast_pthread_create_background(&th, &attr, sip_park_thread, d) < 0) { 00440 /* Could not start thread */ 00441 free(d); /* We don't need it anymore. If thread is created, d will be free'd 00442 by sip_park_thread() */ 00443 return 0; 00444 } 00445 } 00446 return -1; 00447 }
|
|
|
Park SIP call support function Starts in a new thread, then parks the call XXX Should we add a wait period after streaming audio and before hangup?? Sometimes the audio can't be heard before hangup.
Definition at line 133 of file sip3_refer.c. References append_history, AST_CAUSE_NORMAL_CLEARING, ast_channel_lock, ast_channel_unlock, ast_do_masquerade(), ast_hangup(), ast_log(), ast_park_call(), sip_dual::chan1, sip_dual::chan2, ext, free, ast_channel::hangupcause, LOG_DEBUG, LOG_ERROR, LOG_WARNING, option_debug, sip_dual::req, sip_dual::seqno, siprequest_free(), ast_channel::tech_pvt, transmit_message_with_text(), transmit_notify_with_sipfrag(), transmit_response(), and TRUE. 00134 { 00135 struct ast_channel *transferee, *transferer; /* Chan1: The transferee, Chan2: The transferer */ 00136 struct sip_dual *d; 00137 struct sip_request *req; 00138 int ext; 00139 int res; 00140 00141 d = stuff; 00142 transferee = d->chan1; 00143 transferer = d->chan2; 00144 00145 req = d->req; 00146 free(d); 00147 00148 if (!transferee || !transferer) { 00149 ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" ); 00150 return NULL; 00151 } 00152 if (option_debug > 3) 00153 ast_log(LOG_DEBUG, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name); 00154 00155 ast_channel_lock(transferee); 00156 if (ast_do_masquerade(transferee)) { 00157 ast_log(LOG_WARNING, "Masquerade failed.\n"); 00158 transmit_response(transferer->tech_pvt, "503 Internal error", req); 00159 ast_channel_unlock(transferee); 00160 00161 return NULL; 00162 } 00163 ast_channel_unlock(transferee); 00164 00165 res = ast_park_call(transferee, transferer, 0, &ext); 00166 00167 00168 #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE 00169 if (!res) { 00170 transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n"); 00171 } else { 00172 /* Then tell the transferer what happened */ 00173 sprintf(buf, "Call parked on extension '%d'", ext); 00174 transmit_message_with_text(transferer->tech_pvt, buf); 00175 } 00176 #endif 00177 00178 /* Any way back to the current call??? */ 00179 /* Transmit response to the REFER request */ 00180 transmit_response(transferer->tech_pvt, "202 Accepted", req); 00181 00182 if (!res) { 00183 /* Transfer succeeded */ 00184 append_history(transferer->tech_pvt, "SIPpark","Parked call on %d", ext); 00185 transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE); 00186 transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00187 ast_hangup(transferer); /* This will cause a BYE */ 00188 if (option_debug) 00189 ast_log(LOG_DEBUG, "SIP Call parked on extension '%d'\n", ext); 00190 } else { 00191 transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE); 00192 append_history(transferer->tech_pvt, "SIPpark","Parking failed\n"); 00193 if (option_debug) 00194 ast_log(LOG_DEBUG, "SIP Call parked failed \n"); 00195 /* Do not hangup call */ 00196 } 00197 siprequest_free(req); 00198 return NULL; 00199 }
|
|
|
Allocate SIP refer structure.
Definition at line 122 of file sip3_refer.c. References ast_calloc, and sip_dialog::refer. 00123 { 00124 p->refer = ast_calloc(1, sizeof(struct sip_refer)); 00125 return p->refer ? 1 : 0; 00126 }
|
|
||||||||||||||||||||
|
Notify a transferring party of the status of transfer.
Definition at line 989 of file sip3_refer.c. References add_header(), add_header_contentLength(), add_line(), ALLOWED_METHODS, initialize_initreq(), sip_dialog::initreq, reqprep(), send_request(), SIP_MAX_PACKET, SIP_NOTIFY, sipnet, siprequest_alloc(), SUPPORTED_EXTENSIONS, TRUE, and XMIT_RELIABLE. 00990 { 00991 struct sip_request *req; 00992 char tmp[BUFSIZ/2]; 00993 00994 req = siprequest_alloc(SIP_MAX_PACKET, &sipnet); 00995 00996 reqprep(req, p, SIP_NOTIFY, 0, TRUE); 00997 snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq); 00998 add_header(req, "Event", tmp); 00999 add_header(req, "Subscription-state", terminate ? "terminated;reason=noresource" : "active"); 01000 add_header(req, "Content-Type", "message/sipfrag;version=2.0"); 01001 add_header(req, "Allow", ALLOWED_METHODS); 01002 add_header(req, "Supported", SUPPORTED_EXTENSIONS); 01003 01004 snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message); 01005 add_header_contentLength(req, strlen(tmp)); 01006 add_line(req, tmp); 01007 01008 if (!p->initreq) 01009 initialize_initreq(p, req); 01010 01011 return send_request(p, req, XMIT_RELIABLE); 01012 }
|
|
|
Table to convert from REFER status variable to string.
|