[asterisk-commits] oej: branch oej/codename-pineapple r46391 - in
/team/oej/codename-pineapple/c...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Sat Oct 28 14:20:06 MST 2006
Author: oej
Date: Sat Oct 28 16:20:06 2006
New Revision: 46391
URL: http://svn.digium.com/view/asterisk?rev=46391&view=rev
Log:
Moving SIP transfer code to sip3_refer.c
Modified:
team/oej/codename-pineapple/channels/chan_sip3.c
team/oej/codename-pineapple/channels/sip3/sip3_compose.c
team/oej/codename-pineapple/channels/sip3/sip3_parse.c
team/oej/codename-pineapple/channels/sip3/sip3_refer.c
team/oej/codename-pineapple/channels/sip3/sip3funcs.h
Modified: team/oej/codename-pineapple/channels/chan_sip3.c
URL: http://svn.digium.com/view/asterisk/team/oej/codename-pineapple/channels/chan_sip3.c?rev=46391&r1=46390&r2=46391&view=diff
==============================================================================
--- team/oej/codename-pineapple/channels/chan_sip3.c (original)
+++ team/oej/codename-pineapple/channels/chan_sip3.c Sat Oct 28 16:20:06 2006
@@ -384,8 +384,6 @@
static int transmit_message_with_text(struct sip_dialog *p, const char *text);
static int transmit_refer(struct sip_dialog *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_dialog *p, int newmsgs, int oldmsgs, char *vmexten);
-static int transmit_notify_with_sipfrag(struct sip_dialog *p, int cseq, char *message, int terminate);
-static void copy_request(struct sip_request *dst, const struct sip_request *src);
static void receive_message(struct sip_dialog *p, struct sip_request *req);
static void parse_moved_contact(struct sip_dialog *p, struct sip_request *req);
static int sip_send_mwi_to_peer(struct sip_peer *peer);
@@ -403,10 +401,7 @@
static void build_route(struct sip_dialog *p, struct sip_request *req, int backwards);
static enum check_auth_result register_verify(struct sip_dialog *p, struct sockaddr_in *sin,
struct sip_request *req, char *uri);
-static struct sip_dialog *get_sip_dialog_byid_locked(const char *callid, const char *totag, const char *fromtag);
static void check_pendings(struct sip_dialog *p);
-static void *sip_park_thread(void *stuff);
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno);
static int sip_sipredirect(struct sip_dialog *p, const char *dest);
/*--- Codec handling / SDP */
@@ -425,9 +420,6 @@
static int restart_monitor(void);
static int sip_send_mwi_to_peer(struct sip_peer *peer);
static int sip_addrcmp(char *name, struct sockaddr_in *sin); /* Support for peer matching */
-static int sip_refer_allocate(struct sip_dialog *p);
-static void ast_quiet_chan(struct ast_channel *chan);
-static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
/*--- Device monitoring and Device/extension state handling */
static int cb_extensionstate(char *context, char* exten, int state, void *data);
@@ -479,8 +471,6 @@
static void update_peer(struct sip_peer *p, int expiry);
/*--- Parsing SIP requests and responses */
-static void extract_uri(struct sip_dialog *p, struct sip_request *req);
-static int get_refer_info(struct sip_dialog *transferer, struct sip_request *outgoing_req);
static int get_also_info(struct sip_dialog *p, struct sip_request *oreq);
static int parse_ok_contact(struct sip_dialog *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_dialog *pvt);
@@ -492,14 +482,12 @@
/*--- Constructing requests and responses */
static void initreqprep(struct sip_request *req, struct sip_dialog *p, int sipmethod);
-static int init_resp(struct sip_request *resp, const char *msg);
static int create_addr_from_peer(struct sip_dialog *r, struct sip_peer *peer);
static int add_vidupdate(struct sip_request *req);
static void build_rpid(struct sip_dialog *p);
/*------Request handling functions */
static int handle_request_invite(struct sip_dialog *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e);
-static int handle_request_refer(struct sip_dialog *p, struct sip_request *req, int debug, int seqno, int *nounlock);
static int handle_request_bye(struct sip_dialog *p, struct sip_request *req);
static int handle_request_register(struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, char *e);
static int handle_request_cancel(struct sip_dialog *p, struct sip_request *req);
@@ -510,7 +498,6 @@
static int handle_invite_replaces(struct sip_dialog *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
static int handle_request_notify(struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
static int handle_invite_replaces(struct sip_dialog *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
-static int local_attended_transfer(struct sip_dialog *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
/*------Response handling functions */
static void handle_response_invite(struct sip_dialog *p, int resp, char *rest, struct sip_request *req, int seqno);
@@ -523,7 +510,6 @@
/*------ T38 Support --------- */
static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_dialog *pvt, int reinvite); /*!< T38 negotiation helper function */
-static int transmit_response_with_t38_sdp(struct sip_dialog *p, char *msg, struct sip_request *req, enum xmittype reliable);
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
@@ -2083,17 +2069,8 @@
return 0;
}
-/*! \brief Add 'Content-Length' header to SIP message */
-GNURK int add_header_contentLength(struct sip_request *req, int len)
-{
- char clen[10];
-
- snprintf(clen, sizeof(clen), "%d", len);
- return add_header(req, "Content-Length", clen);
-}
-
/*! \brief Initialize SIP response, based on SIP request */
-static int init_resp(struct sip_request *resp, const char *msg)
+GNURK int init_resp(struct sip_request *resp, const char *msg)
{
/* Initialize a response */
memset(resp, 0, sizeof(*resp));
@@ -2206,12 +2183,6 @@
append_date(&resp);
add_header(&resp, "Unsupported", unsupported);
return send_response(p, &resp, XMIT_UNRELIABLE, 0);
-}
-
-/*! \brief Used for 200 OK and 183 early media */
-static int transmit_response_with_t38_sdp(struct sip_dialog *p, char *msg, struct sip_request *req, enum xmittype reliable)
-{
- return transmit_response_with_attachment(WITH_T38_SDP, p, msg, req, reliable);
}
/*! \brief Respond with authorization request */
@@ -2388,7 +2359,7 @@
}
/*! \brief copy SIP request (mostly used to save request for responses) */
-static void copy_request(struct sip_request *dst, const struct sip_request *src)
+GNURK void copy_request(struct sip_request *dst, const struct sip_request *src)
{
long offset;
int x;
@@ -2431,19 +2402,6 @@
initialize_initreq(p, &req);
p->lastinvite = p->ocseq;
return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-}
-
-/*! \brief Check Contact: URI of SIP message */
-static void extract_uri(struct sip_dialog *p, struct sip_request *req)
-{
- char stripped[256];
- char *c;
-
- ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
- c = get_in_brackets(stripped);
- c = strsep(&c, ";"); /* trim ; and beyond */
- if (!ast_strlen_zero(c))
- ast_string_field_set(p, uri, c);
}
/*! \brief Build contact header - the contact header we send out */
@@ -2970,7 +2928,7 @@
}
/*! \brief Notify a transferring party of the status of transfer */
-static int transmit_notify_with_sipfrag(struct sip_dialog *p, int cseq, char *message, int terminate)
+GNURK int transmit_notify_with_sipfrag(struct sip_dialog *p, int cseq, char *message, int terminate)
{
struct sip_request req;
char tmp[BUFSIZ/2];
@@ -3001,13 +2959,6 @@
reqprep(&req, p, SIP_MESSAGE, 0, 1);
add_text(&req, text);
return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Allocate SIP refer structure */
-static int sip_refer_allocate(struct sip_dialog *p)
-{
- p->refer = ast_calloc(1, sizeof(struct sip_refer));
- return p->refer ? 1 : 0;
}
/*! \brief Transmit SIP REFER message (initiated by the transfer() dialplan application
@@ -4057,12 +4008,12 @@
return -1;
}
-/*! \brief Lock interface lock and find matching pvt lock
+/*! \brief Lock dialog list lock and find matching pvt lock
- Their tag is fromtag, our tag is to-tag
- This means that in some transactions, totag needs to be their tag :-)
depending upon the direction
*/
-static struct sip_dialog *get_sip_dialog_byid_locked(const char *callid, const char *totag, const char *fromtag)
+GNURK struct sip_dialog *get_sip_dialog_byid_locked(const char *callid, const char *totag, const char *fromtag)
{
struct sip_dialog *sip_dialog_ptr;
@@ -4111,162 +4062,6 @@
ast_log(LOG_DEBUG, "Found no match for callid %s to-tag %s from-tag %s\n", callid, totag, fromtag);
return sip_dialog_ptr;
}
-
-/*! \brief Call transfer support (the REFER method)
- * Extracts Refer headers into pvt dialog structure */
-static int get_refer_info(struct sip_dialog *transferer, struct sip_request *outgoing_req)
-{
-
- const char *p_referred_by = NULL;
- char *h_refer_to = NULL;
- char *h_referred_by = NULL;
- char *refer_to;
- const char *p_refer_to;
- char *referred_by_uri = NULL;
- char *ptr;
- struct sip_request *req = NULL;
- const char *transfer_context = NULL;
- struct sip_refer *referdata;
-
-
- req = outgoing_req;
- referdata = transferer->refer;
-
- if (!req)
- req = &transferer->initreq;
-
- p_refer_to = get_header(req, "Refer-To");
- if (ast_strlen_zero(p_refer_to)) {
- ast_log(LOG_WARNING, "Refer-To Header missing. Skipping transfer.\n");
- return -2; /* Syntax error */
- }
- h_refer_to = ast_strdupa(p_refer_to);
- refer_to = get_in_brackets(h_refer_to);
- ast_uri_decode(refer_to);
-
- if (strncasecmp(refer_to, "sip:", 4)) {
- ast_log(LOG_WARNING, "Can't transfer to non-sip: URI. (Refer-to: %s)?\n", refer_to);
- return -3;
- }
- refer_to += 4; /* Skip sip: */
-
- /* Get referred by header if it exists */
- p_referred_by = get_header(req, "Referred-By");
- if (!ast_strlen_zero(p_referred_by)) {
- char *lessthan;
- h_referred_by = ast_strdupa(p_referred_by);
- ast_uri_decode(h_referred_by);
-
- /* Store referrer's caller ID name */
- ast_copy_string(referdata->referred_by_name, h_referred_by, sizeof(referdata->referred_by_name));
- if ((lessthan = strchr(referdata->referred_by_name, '<'))) {
- *(lessthan - 1) = '\0'; /* Space */
- }
-
- referred_by_uri = get_in_brackets(h_referred_by);
- if(strncasecmp(referred_by_uri, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a sip: header (Referred-by: %s). Skipping.\n", referred_by_uri);
- referred_by_uri = (char *) NULL;
- } else {
- referred_by_uri += 4; /* Skip sip: */
- }
- }
-
- /* Check for arguments in the refer_to header */
- if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */
- *ptr++ = '\0';
- if (!strncasecmp(ptr, "REPLACES=", 9)) {
- char *to = NULL, *from = NULL;
-
- /* This is an attended transfer */
- referdata->attendedtransfer = 1;
- strncpy(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
- ast_uri_decode(referdata->replaces_callid);
- if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ {
- *ptr++ = '\0';
- }
-
- if (ptr) {
- /* Find the different tags before we destroy the string */
- to = strcasestr(ptr, "to-tag=");
- from = strcasestr(ptr, "from-tag=");
- }
-
- /* Grab the to header */
- if (to) {
- ptr = to + 7;
- if ((to = strchr(ptr, '&')))
- *to = '\0';
- if ((to = strchr(ptr, ';')))
- *to = '\0';
- ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag));
- }
-
- if (from) {
- ptr = from + 9;
- if ((to = strchr(ptr, '&')))
- *to = '\0';
- if ((to = strchr(ptr, ';')))
- *to = '\0';
- ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag));
- }
-
- if (option_debug > 1)
- 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>" );
- }
- }
-
- if ((ptr = strchr(refer_to, '@'))) { /* Separate domain */
- char *urioption;
-
- *ptr++ = '\0';
- if ((urioption = strchr(ptr, ';')))
- *urioption++ = '\0';
- /* Save the domain for the dial plan */
- strncpy(referdata->refer_to_domain, ptr, sizeof(referdata->refer_to_domain));
- if (urioption)
- strncpy(referdata->refer_to_urioption, urioption, sizeof(referdata->refer_to_urioption));
- }
-
- if ((ptr = strchr(refer_to, ';'))) /* Remove options */
- *ptr = '\0';
- ast_copy_string(referdata->refer_to, refer_to, sizeof(referdata->refer_to));
-
- if (referred_by_uri) {
- if ((ptr = strchr(referred_by_uri, ';'))) /* Remove options */
- *ptr = '\0';
- ast_copy_string(referdata->referred_by, referred_by_uri, sizeof(referdata->referred_by));
- } else {
- referdata->referred_by[0] = '\0';
- }
-
- /* Determine transfer context */
- if (transferer->owner) /* Mimic behaviour in res_features.c */
- transfer_context = pbx_builtin_getvar_helper(transferer->owner, "TRANSFER_CONTEXT");
-
- /* By default, use the context in the channel sending the REFER */
- if (ast_strlen_zero(transfer_context)) {
- transfer_context = S_OR(transferer->owner->macrocontext,
- S_OR(transferer->context, global.default_context));
- }
-
- strncpy(referdata->refer_to_context, transfer_context, sizeof(referdata->refer_to_context));
-
- /* Either an existing extension or the parking extension */
- if (ast_exists_extension(NULL, transfer_context, refer_to, 1, NULL) ) {
- if (sip_debug_test_pvt(transferer)) {
- ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, referred_by_uri);
- }
- /* We are ready to transfer to the extension */
- return 0;
- }
- if (sip_debug_test_pvt(transferer))
- ast_verbose("Failed SIP Transfer to non-existing extension %s in context %s\n n", refer_to, transfer_context);
-
- /* Failure, we can't find this extension */
- return -1;
-}
-
/*! \brief Call transfer support (old way, deprecated by the IETF)--*/
static int get_also_info(struct sip_dialog *p, struct sip_request *oreq)
@@ -5936,261 +5731,15 @@
}
-/*! \brief 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
-*/
-static void *sip_park_thread(void *stuff)
-{
- struct ast_channel *transferee, *transferer; /* Chan1: The transferee, Chan2: The transferer */
- struct sip_dual *d;
- struct sip_request req;
- int ext;
- int res;
-
- d = stuff;
- transferee = d->chan1;
- transferer = d->chan2;
- copy_request(&req, &d->req);
- free(d);
-
- if (!transferee || !transferer) {
- ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
- return NULL;
- }
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name);
-
- ast_channel_lock(transferee);
- if (ast_do_masquerade(transferee)) {
- ast_log(LOG_WARNING, "Masquerade failed.\n");
- transmit_response(transferer->tech_pvt, "503 Internal error", &req);
- ast_channel_unlock(transferee);
- return NULL;
- }
- ast_channel_unlock(transferee);
-
- res = ast_park_call(transferee, transferer, 0, &ext);
-
-
-#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
- if (!res) {
- transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
- } else {
- /* Then tell the transferer what happened */
- sprintf(buf, "Call parked on extension '%d'", ext);
- transmit_message_with_text(transferer->tech_pvt, buf);
- }
-#endif
-
- /* Any way back to the current call??? */
- /* Transmit response to the REFER request */
- transmit_response(transferer->tech_pvt, "202 Accepted", &req);
- if (!res) {
- /* Transfer succeeded */
- append_history(transferer->tech_pvt, "SIPpark","Parked call on %d", ext);
- transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE);
- transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
- ast_hangup(transferer); /* This will cause a BYE */
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP Call parked on extension '%d'\n", ext);
- } else {
- transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE);
- append_history(transferer->tech_pvt, "SIPpark","Parking failed\n");
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP Call parked failed \n");
- /* Do not hangup call */
- }
- return NULL;
-}
-
-/*! \brief Park a call using the subsystem in res_features.c
- This is executed in a separate thread
-*/
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno)
-{
- struct sip_dual *d;
- struct ast_channel *transferee, *transferer;
- /* Chan2m: The transferer, chan1m: The transferee */
- pthread_t th;
-
- transferee = ast_channel_alloc(0);
- transferer = ast_channel_alloc(0);
- if ((!transferer) || (!transferee)) {
- if (transferee) {
- transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferee);
- }
- if (transferer) {
- transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferer);
- }
- return -1;
- }
- ast_string_field_build(transferee, name, "Parking/%s", chan1->name);
-
- /* Make formats okay */
- transferee->readformat = chan1->readformat;
- transferee->writeformat = chan1->writeformat;
-
- /* Prepare for taking over the channel */
- ast_channel_masquerade(transferee, chan1);
-
- /* Setup the extensions and such */
- ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
- ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
- transferee->priority = chan1->priority;
-
- /* We make a clone of the peer channel too, so we can play
- back the announcement */
- ast_string_field_build(transferer, name, "SIPPeer/%s", chan2->name);
-
- /* Make formats okay */
- transferer->readformat = chan2->readformat;
- transferer->writeformat = chan2->writeformat;
-
- /* Prepare for taking over the channel */
- ast_channel_masquerade(transferer, chan2);
-
- /* Setup the extensions and such */
- ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
- ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
- transferer->priority = chan2->priority;
-
- ast_channel_lock(transferer);
- if (ast_do_masquerade(transferer)) {
- ast_log(LOG_WARNING, "Masquerade failed :(\n");
- ast_channel_unlock(transferer);
- transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferer);
- return -1;
- }
- ast_channel_unlock(transferer);
- if (!transferer || !transferee) {
- if (!transferer) {
- if (option_debug)
- ast_log(LOG_DEBUG, "No transferer channel, giving up parking\n");
- }
- if (!transferee) {
- if (option_debug)
- ast_log(LOG_DEBUG, "No transferee channel, giving up parking\n");
- }
- return -1;
- }
- if ((d = ast_calloc(1, sizeof(*d)))) {
- /* Save original request for followup */
- copy_request(&d->req, req);
- d->chan1 = transferee; /* Transferee */
- d->chan2 = transferer; /* Transferer */
- d->seqno = seqno;
- if (ast_pthread_create_background(&th, NULL, sip_park_thread, d) < 0) {
- /* Could not start thread */
- free(d); /* We don't need it anymore. If thread is created, d will be free'd
- by sip_park_thread() */
- return 0;
- }
- }
- return -1;
-}
-
/*! \brief Turn off generator data
XXX Does this function belong in the SIP channel?
*/
-static void ast_quiet_chan(struct ast_channel *chan)
+GNURK void ast_quiet_chan(struct ast_channel *chan)
{
if (chan && chan->_state == AST_STATE_UP) {
if (chan->generatordata)
ast_deactivate_generator(chan);
}
-}
-
-/*! \brief Attempt transfer of SIP call
- This fix for attended transfers on a local PBX */
-static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target)
-{
- int res = 0;
- struct ast_channel *peera = NULL,
- *peerb = NULL,
- *peerc = NULL,
- *peerd = NULL;
-
-
- /* We will try to connect the transferee with the target and hangup
- all channels to the transferer */
- if (option_debug > 3) {
- ast_log(LOG_DEBUG, "Sip transfer:--------------------\n");
- if (transferer->chan1)
- ast_log(LOG_DEBUG, "-- Transferer to PBX channel: %s State %s\n", transferer->chan1->name, ast_state2str(transferer->chan1->_state));
- else
- ast_log(LOG_DEBUG, "-- No transferer first channel - odd??? \n");
- if (target->chan1)
- ast_log(LOG_DEBUG, "-- Transferer to PBX second channel (target): %s State %s\n", target->chan1->name, ast_state2str(target->chan1->_state));
- else
- ast_log(LOG_DEBUG, "-- No target first channel ---\n");
- if (transferer->chan2)
- ast_log(LOG_DEBUG, "-- Bridged call to transferee: %s State %s\n", transferer->chan2->name, ast_state2str(transferer->chan2->_state));
- else
- ast_log(LOG_DEBUG, "-- No bridged call to transferee\n");
- if (target->chan2)
- 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)");
- else
- ast_log(LOG_DEBUG, "-- No target second channel ---\n");
- ast_log(LOG_DEBUG, "-- END Sip transfer:--------------------\n");
- }
- if (transferer->chan2) { /* We have a bridge on the transferer's channel */
- peera = transferer->chan1; /* Transferer - PBX -> transferee channel * the one we hangup */
- peerb = target->chan1; /* Transferer - PBX -> target channel - This will get lost in masq */
- peerc = transferer->chan2; /* Asterisk to Transferee */
- peerd = target->chan2; /* Asterisk to Target */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP transfer: Four channels to handle\n");
- } else if (target->chan2) { /* Transferer has no bridge (IVR), but transferee */
- peera = target->chan1; /* Transferer to PBX -> target channel */
- peerb = transferer->chan1; /* Transferer to IVR*/
- peerc = target->chan2; /* Asterisk to Target */
- peerd = transferer->chan2; /* Nothing */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP transfer: Three channels to handle\n");
- }
-
- if (peera && peerb && peerc && (peerb != peerc)) {
- ast_quiet_chan(peera); /* Stop generators */
- ast_quiet_chan(peerb);
- ast_quiet_chan(peerc);
- if (peerd)
- ast_quiet_chan(peerd);
-
- /* Fix CDRs so they're attached to the remaining channel */
- if (peera->cdr && peerb->cdr)
- peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
- else if (peera->cdr)
- peerb->cdr = peera->cdr;
- peera->cdr = NULL;
-
- if (peerb->cdr && peerc->cdr)
- peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
- else if (peerc->cdr)
- peerb->cdr = peerc->cdr;
- peerc->cdr = NULL;
-
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP transfer: trying to masquerade %s into %s\n", peerc->name, peerb->name);
- if (ast_channel_masquerade(peerb, peerc)) {
- ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
- res = -1;
- } else
- ast_log(LOG_DEBUG, "SIP transfer: Succeeded to masquerade channels.\n");
- return res;
- } else {
- ast_log(LOG_NOTICE, "SIP Transfer attempted with no appropriate bridged calls to transfer\n");
- if (transferer->chan1)
- ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV);
- if (target->chan1)
- ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV);
- return -1;
- }
- return 0;
}
/*! \brief Handle incoming notifications
@@ -6921,7 +6470,7 @@
}
} else {
/* The other side is already setup for T.38 most likely so we need to acknowledge this too */
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
+ transmit_response_with_attachment(WITH_T38_SDP, p, "200 OK", req, XMIT_CRITICAL);
p->t38.state = T38_ENABLED;
if (option_debug)
ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
@@ -6939,7 +6488,7 @@
}
} else {
/* we are not bridged in a call */
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
+ transmit_response_with_attachment(WITH_T38_SDP, p, "200 OK", req, XMIT_CRITICAL);
p->t38.state = T38_ENABLED;
if (option_debug)
ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
@@ -6998,458 +6547,6 @@
return res;
}
-/*! \brief Find all call legs and bridge transferee with target
- * called from handle_request_refer */
-static int local_attended_transfer(struct sip_dialog *transferer, struct sip_dual *current, struct sip_request *req, int seqno)
-{
- struct sip_dual target; /* Chan 1: Call from tranferer to Asterisk */
- /* Chan 2: Call from Asterisk to target */
- int res = 0;
- struct sip_dialog *targetcall_pvt;
- int error = 0;
-
- /* Check if the call ID of the replaces header does exist locally */
- if (!(targetcall_pvt = get_sip_dialog_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag,
- transferer->refer->replaces_callid_fromtag))) {
- if (transferer->refer->localtransfer) {
- /* We did not find the refered call. Sorry, can't accept then */
- transmit_response(transferer, "202 Accepted", req);
- /* Let's fake a response from someone else in order
- to follow the standard */
- transmit_notify_with_sipfrag(transferer, seqno, "481 Call leg/transaction does not exist", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
- transferer->refer->status = REFER_FAILED;
- return -1;
- }
- /* Fall through for remote transfers that we did not find locally */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP attended transfer: Not our call - generating INVITE with replaces\n");
- return 0;
- }
-
- /* Ok, we can accept this transfer */
- transmit_response(transferer, "202 Accepted", req);
- append_history(transferer, "Xfer", "Refer accepted");
- if (!targetcall_pvt->owner) { /* No active channel */
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: No owner of target call\n");
- error = 1;
- }
- /* We have a channel, find the bridge */
- target.chan1 = targetcall_pvt->owner; /* Transferer to Asterisk */
-
- if (!error) {
- target.chan2 = ast_bridged_channel(targetcall_pvt->owner); /* Asterisk to target */
-
- if (!target.chan2 || !(target.chan2->_state == AST_STATE_UP || target.chan2->_state == AST_STATE_RINGING) ) {
- /* Wrong state of new channel */
- if (option_debug > 3) {
- if (target.chan2)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: Wrong state of target call: %s\n", ast_state2str(target.chan2->_state));
- else if (target.chan1->_state != AST_STATE_RING)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: No target channel\n");
- else
- ast_log(LOG_DEBUG, "SIP attended transfer: Attempting transfer in ringing state\n");
- }
- if (target.chan1->_state != AST_STATE_RING)
- error = 1;
- }
- }
- if (error) { /* Cancel transfer */
- transmit_notify_with_sipfrag(transferer, seqno, "503 Service Unavailable", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
- transferer->refer->status = REFER_FAILED;
- ast_mutex_unlock(&targetcall_pvt->lock);
- ast_channel_unlock(current->chan1);
- ast_channel_unlock(target.chan1);
- return -1;
- }
-
- /* Transfer */
- if (option_debug > 3 && sipdebug) {
- if (current->chan2) /* We have two bridges */
- ast_log(LOG_DEBUG, "SIP attended transfer: trying to bridge %s and %s\n", target.chan1->name, current->chan2->name);
- else /* One bridge, propably transfer of IVR/voicemail etc */
- ast_log(LOG_DEBUG, "SIP attended transfer: trying to make %s take over (masq) %s\n", target.chan1->name, current->chan1->name);
- }
-
- ast_set_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
-
- /* Perform the transfer */
- res = attempt_transfer(current, &target);
- ast_mutex_unlock(&targetcall_pvt->lock);
- if (res) {
- /* Failed transfer */
- /* Could find better message, but they will get the point */
- transmit_notify_with_sipfrag(transferer, seqno, "486 Busy", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- if (targetcall_pvt->owner)
- ast_channel_unlock(targetcall_pvt->owner);
- /* Right now, we have to hangup, sorry. Bridge is destroyed */
- ast_hangup(transferer->owner);
- } else {
- /* Transfer succeeded! */
-
- /* Tell transferer that we're done. */
- transmit_notify_with_sipfrag(transferer, seqno, "200 OK", TRUE);
- append_history(transferer, "Xfer", "Refer succeeded");
- transferer->refer->status = REFER_200OK;
- if (targetcall_pvt->owner) {
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
- ast_channel_unlock(targetcall_pvt->owner);
- }
- }
- return 1;
-}
-
-
-/*! \brief Handle incoming REFER request */
-/*! \page SIP_REFER SIP transfer Support (REFER)
-
- REFER is used for call transfer in SIP. We get a REFER
- to place a new call with an INVITE somwhere and then
- keep the transferor up-to-date of the transfer. If the
- transfer fails, get back on line with the orginal call.
-
- - REFER can be sent outside or inside of a dialog.
- Asterisk only accepts REFER inside of a dialog.
-
- - If we get a replaces header, it is an attended transfer
-
- \par Blind transfers
- The transferor provides the transferee
- with the transfer targets contact. The signalling between
- transferer or transferee should not be cancelled, so the
- call is recoverable if the transfer target can not be reached
- by the transferee.
-
- In this case, Asterisk receives a TRANSFER from
- the transferor, thus is the transferee. We should
- try to set up a call to the contact provided
- and if that fails, re-connect the current session.
- If the new call is set up, we issue a hangup.
- In this scenario, we are following section 5.2
- in the SIP CC Transfer draft. (Transfer without
- a GRUU)
-
- \par Transfer with consultation hold
- In this case, the transferor
- talks to the transfer target before the transfer takes place.
- This is implemented with SIP hold and transfer.
- Note: The invite From: string could indicate a transfer.
- (Section 6. Transfer with consultation hold)
- The transferor places the transferee on hold, starts a call
- with the transfer target to alert them to the impending
- transfer, terminates the connection with the target, then
- proceeds with the transfer (as in Blind transfer above)
-
- \par Attended transfer
- The transferor places the transferee
- on hold, calls the transfer target to alert them,
- places the target on hold, then proceeds with the transfer
- using a Replaces header field in the Refer-to header. This
- will force the transfee to send an Invite to the target,
- with a replaces header that instructs the target to
- hangup the call between the transferor and the target.
- In this case, the Refer/to: uses the AOR address. (The same
- URI that the transferee used to establish the session with
- the transfer target (To: ). The Require: replaces header should
- be in the INVITE to avoid the wrong UA in a forked SIP proxy
- scenario to answer and have no call to replace with.
-
- The referred-by header is *NOT* required, but if we get it,
- can be copied into the INVITE to the transfer target to
- inform the target about the transferor
-
- "Any REFER request has to be appropriately authenticated.".
-
- We can't destroy dialogs, since we want the call to continue.
-
- */
-/* XXX note that out-of-dialog refers are killed in match_or_create_dialog() */
-static int handle_request_refer(struct sip_dialog *p, struct sip_request *req, int debug, int seqno, int *nounlock)
-{
- struct sip_dual current; /* Chan1: Call between asterisk and transferer */
- /* Chan2: Call between asterisk and transferee */
-
- int res = 0;
-
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- 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");
-
- if (!p->owner) {
- /* This is a REFER outside of an existing SIP dialog */
- /* We can't handle that, so decline it */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Call %s: Declined REFER, outside of dialog...\n", p->callid);
- transmit_response(p, "603 Declined (No dialog)", req);
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- append_history(p, "Xfer", "Refer failed. Outside of dialog.");
- ast_set_flag(&p->flags[0], SIP_ALREADYGONE);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- return 0;
- }
-
-
- /* Check if transfer is allowed from this device */
- if (p->allowtransfer == TRANSFER_CLOSED ) {
- /* Transfer not allowed, decline */
- transmit_response(p, "603 Declined (policy)", req);
- append_history(p, "Xfer", "Refer failed. Allowtransfer == closed.");
- /* Do not destroy SIP session */
- return 0;
- }
-
- if(!ast_test_flag(req, SIP_PKT_IGNORE) && ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- /* Already have a pending REFER */
- transmit_response(p, "491 Request pending", req);
- append_history(p, "Xfer", "Refer failed. Request pending.");
- return 0;
- }
-
- /* Allocate memory for call transfer data */
- if (!p->refer && !sip_refer_allocate(p)) {
- transmit_response(p, "500 Internal Server Error", req);
- append_history(p, "Xfer", "Refer failed. Memory allocation error.");
- return -3;
- }
-
- res = get_refer_info(p, req); /* Extract headers */
-
- p->refer->status = REFER_SENT;
-
- if (res != 0) {
- switch (res) {
- case -2: /* Syntax error */
- transmit_response(p, "400 Bad Request (Refer-to missing)", req);
- append_history(p, "Xfer", "Refer failed. Refer-to missing.");
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to black hole can't be handled (no refer-to: )\n");
- break;
- case -3:
- transmit_response(p, "603 Declined (Non sip: uri)", req);
- append_history(p, "Xfer", "Refer failed. Non SIP uri");
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to non-SIP uri denied\n");
- break;
- default:
- /* Refer-to extension not found, fake a failed transfer */
- transmit_response(p, "202 Accepted", req);
- append_history(p, "Xfer", "Refer failed. Bad extension.");
- transmit_notify_with_sipfrag(p, seqno, "404 Not found", TRUE);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to bad extension: %s\n", p->refer->refer_to);
- break;
- }
- return 0;
- }
- if (ast_strlen_zero(p->context))
- ast_string_field_set(p, context, global.default_context);
-
- /* If we do not support SIP domains, all transfers are local */
- if (global.allow_external_domains && check_sip_domain(p->refer->refer_to_domain, NULL, 0)) {
- p->refer->localtransfer = 1;
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "This SIP transfer is local : %s\n", p->refer->refer_to_domain);
- } else if (domains_configured()) {
- /* This PBX don't bother with SIP domains, so all transfers are local */
- p->refer->localtransfer = 1;
- } else
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "This SIP transfer is to a remote SIP extension (remote domain %s)\n", p->refer->refer_to_domain);
-
- /* Is this a repeat of a current request? Ignore it */
- /* Don't know what else to do right now. */
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- return res;
-
- /* If this is a blind transfer, we have the following
- channels to work with:
- - chan1, chan2: The current call between transferer and transferee (2 channels)
- - target_channel: A new call from the transferee to the target (1 channel)
- We need to stay tuned to what happens in order to be able
- to bring back the call to the transferer */
-
- /* If this is a attended transfer, we should have all call legs within reach:
- - chan1, chan2: The call between the transferer and transferee (2 channels)
- - target_channel, targetcall_pvt: The call between the transferer and the target (2 channels)
- We want to bridge chan2 with targetcall_pvt!
-
- The replaces call id in the refer message points
- to the call leg between Asterisk and the transferer.
- So we need to connect the target and the transferee channel
- and hangup the two other channels silently
-
- If the target is non-local, the call ID could be on a remote
- machine and we need to send an INVITE with replaces to the
- target. We basically handle this as a blind transfer
- and let the sip_call function catch that we need replaces
- header in the INVITE.
- */
-
-
- /* Get the transferer's channel */
- current.chan1 = p->owner;
-
- /* Find the other part of the bridge (2) - transferee */
- current.chan2 = ast_bridged_channel(current.chan1);
-
- if (sipdebug && option_debug > 2)
- 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>");
-
- if (!current.chan2 && !p->refer->attendedtransfer) {
- /* No bridged channel, propably IVR or echo or similar... */
- /* Guess we should masquerade or something here */
- /* Until we figure it out, refuse transfer of such calls */
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG,"Refused SIP transfer on non-bridged channel.\n");
- p->refer->status = REFER_FAILED;
- append_history(p, "Xfer", "Refer failed. Non-bridged channel.");
- transmit_response(p, "603 Declined", req);
- return -1;
- }
-
- if (current.chan2) {
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Got SIP transfer, applying to bridged peer '%s'\n", current.chan2->name);
-
- ast_queue_control(current.chan1, AST_CONTROL_UNHOLD);
- }
-
- ast_set_flag(&p->flags[0], SIP_GOTREFER);
-
- /* Attended transfer: Find all call legs and bridge transferee with target*/
- if (p->refer->attendedtransfer) {
- if ((res = local_attended_transfer(p, ¤t, req, seqno)))
- return res; /* We're done with the transfer */
- /* Fall through for remote transfers that we did not find locally */
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP attended transfer: Still not our call - generating INVITE with replaces\n");
- /* Fallthrough if we can't find the call leg internally */
- }
-
-
- /* Parking a call */
- if (p->refer->localtransfer && !strcmp(p->refer->refer_to, ast_parking_ext())) {
- /* Must release c's lock now, because it will not longer be accessible after the transfer! */
- *nounlock = 1;
- ast_channel_unlock(current.chan1);
- copy_request(¤t.req, req);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- p->refer->status = REFER_200OK;
- append_history(p, "Xfer", "REFER to call parking.");
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP transfer to parking: trying to park %s. Parked by %s\n", current.chan2->name, current.chan1->name);
- sip_park(current.chan2, current.chan1, req, seqno);
- return res;
- }
-
- /* Blind transfers and remote attended xfers */
- transmit_response(p, "202 Accepted", req);
-
- if (current.chan1 && current.chan2) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "chan1->name: %s\n", current.chan1->name);
[... 1184 lines stripped ...]
More information about the asterisk-commits
mailing list