static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
+static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin, int *nounlock);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
return res;
}
-/*! \brief Handle the transfer part of INVITE with a replaces: header,
- meaning a target pickup or an attended transfer */
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin)
+/*! \brief Handle the transfer part of INVITE with a replaces: header,
+ meaning a target pickup or an attended transfer
+
+ \note this function is called by handle_request_invite(). Four locks
+ held at the beginning of this function, p, p->owner, p->refer->refer_call->owner...
+ only p's lock should remain at the end of this function. p's lock is held by sipsock_read()
+*/
+static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin, int *nounlock)
{
- struct ast_frame *f;
int earlyreplace = 0;
int oneleggedreplace = 0; /* Call with no bridge, propably IVR or voice message */
struct ast_channel *c = p->owner; /* Our incoming call */
transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE);
/* Do something more clever here */
ast_channel_unlock(c);
+ ast_channel_unlock(replacecall);
ast_mutex_unlock(&p->refer->refer_call->lock);
return 1;
}
transmit_response_reliable(p, "503 Service Unavailable", req);
append_history(p, "Xfer", "INVITE/Replace Failed. No new channel.");
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ ast_channel_unlock(replacecall);
ast_mutex_unlock(&p->refer->refer_call->lock);
return 1;
}
ast_quiet_chan(targetcall);
if (option_debug > 3)
ast_log(LOG_DEBUG, "Invite/Replaces: preparing to masquerade %s into %s\n", c->name, replacecall->name);
- /* Unlock clone, but not original (replacecall) */
- if (!oneleggedreplace)
- ast_channel_unlock(c);
-
- /* Unlock PVT */
- ast_mutex_unlock(&p->refer->refer_call->lock);
/* Make sure that the masq does not free our PVT for the old call */
if (! earlyreplace && ! oneleggedreplace )
else if (option_debug > 3)
ast_log(LOG_DEBUG, "Invite/Replaces: Going to masquerade %s into %s\n", c->name, replacecall->name);
- /* The masquerade will happen as soon as someone reads a frame from the channel */
-
/* C should now be in place of replacecall */
- /* ast_read needs to lock channel */
- ast_channel_unlock(c);
-
+ if (ast_do_masquerade(replacecall)) {
+ ast_log(LOG_WARNING, "Failed to perform masquerade with INVITE replaces\n");
+ }
+
if (earlyreplace || oneleggedreplace ) {
- /* Force the masq to happen */
- if ((f = ast_read(replacecall))) { /* Force the masq to happen */
- ast_frfree(f);
- f = NULL;
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "Invite/Replace: Could successfully read frame from RING channel!\n");
- } else {
- ast_log(LOG_WARNING, "Invite/Replace: Could not read frame from RING channel \n");
- }
c->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- if (!oneleggedreplace)
- ast_channel_unlock(replacecall);
- } else { /* Bridged call, UP channel */
- if ((f = ast_read(replacecall))) { /* Force the masq to happen */
- /* Masq ok */
- ast_frfree(f);
- f = NULL;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Invite/Replace: Could successfully read frame from channel! Masq done.\n");
- } else {
- ast_log(LOG_WARNING, "Invite/Replace: Could not read frame from channel. Transfer failed\n");
- }
- ast_channel_unlock(replacecall);
}
- ast_mutex_unlock(&p->refer->refer_call->lock);
ast_setstate(c, AST_STATE_DOWN);
if (option_debug > 3) {
ast_log(LOG_DEBUG, "End After transfer:----------------------------\n");
}
- ast_channel_unlock(p->owner); /* Unlock new owner */
- if (!oneleggedreplace)
- ast_mutex_unlock(&p->lock); /* Unlock SIP structure */
+ /* unlock sip pvt and owner so hangup can do its thing */
+ ast_channel_unlock(replacecall);
+ ast_channel_unlock(c);
+ ast_mutex_unlock(&p->refer->refer_call->lock);
+ ast_mutex_unlock(&p->lock);
+ *nounlock = 1;
/* The call should be down with no ast_channel, so hang it up */
c->tech_pvt = NULL;
ast_hangup(c);
+
+ ast_mutex_lock(&p->lock); /* lock PVT structure again after hangup */
+
return 0;
}
/* Go and take over the target call */
if (sipdebug && option_debug > 3)
ast_log(LOG_DEBUG, "Sending this call to the invite/replcaes handler %s\n", p->callid);
- return handle_invite_replaces(p, req, debug, ast_test_flag(req, SIP_PKT_IGNORE), seqno, sin);
+ return handle_invite_replaces(p, req, debug, ast_test_flag(req, SIP_PKT_IGNORE), seqno, sin, nounlock);
}