Newer
Older
Mark Spencer
committed
struct sip_request req;
Mark Spencer
committed
int ext;
int res;
Mark Spencer
committed
d = stuff;
transferee = d->chan1;
transferer = d->chan2;
Mark Spencer
committed
copy_request(&req, &d->req);
Mark Spencer
committed
free(d);
if (!transferee || !transferer) {
ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
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 */
}
Mark Spencer
committed
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)
Mark Spencer
committed
{
struct sip_dual *d;
struct ast_channel *transferee, *transferer;
/* Chan2m: The transferer, chan1m: The transferee */
Mark Spencer
committed
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);
Mark Spencer
committed
return -1;
}
ast_string_field_build(transferee, name, "Parking/%s", chan1->name);
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);
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);
ast_channel_unlock(transferer);
if (!transferer || !transferee) {
if (!transferer)
ast_log(LOG_DEBUG, "No transferer channel, giving up parking\n");
if (!transferee)
ast_log(LOG_DEBUG, "No transferee channel, giving up parking\n");
return -1;
}
if ((d = ast_calloc(1, sizeof(*d)))) {
Mark Spencer
committed
/* 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(&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() */
Mark Spencer
committed
return 0;
}
}
Mark Spencer
committed
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)
{
if (chan && chan->_state == AST_STATE_UP) {
if (chan->generatordata)
ast_deactivate_generator(chan);
}
}
Mark Spencer
committed
/*! \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)
struct ast_channel *peera = NULL,
*peerc = NULL,
*peerd = NULL;
12167
12168
12169
12170
12171
12172
12173
12174
12175
12176
12177
12178
12179
12180
12181
12182
12183
12184
12185
12186
12187
12188
12189
12190
12191
12192
12193
12194
12195
12196
12197
12198
12199
12200
12201
12202
12203
/* 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);
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);
} else
ast_log(LOG_DEBUG, "SIP transfer: Succeeded to masquerade channels.\n");
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 Get tag from packet
*
* \return Returns the pointer to the provided tag buffer,
* or NULL if the tag was not found.
*/
static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize)
const char *thetag;
if (!tagbuf)
return NULL;
tagbuf[0] = '\0'; /* reset the buffer */
thetag = get_header(req, header);
thetag = strcasestr(thetag, ";tag=");
if (thetag) {
thetag += 5;
ast_copy_string(tagbuf, thetag, tagbufsize);
return strsep(&tagbuf, ";");
Russell Bryant
committed
return NULL;
/*! \brief Handle incoming notifications */
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e)
{
/* This is mostly a skeleton for future improvements */
/* Mostly created to return proper answers on notifications on outbound REFER's */
int res = 0;
const char *event = get_header(req, "Event");
char *eventid = NULL;
char *sep;
if( (sep = strchr(event, ';')) ) { /* XXX bug here - overwriting string ? */
*sep++ = '\0';
eventid = sep;
}
if (option_debug > 1 && sipdebug)
ast_log(LOG_DEBUG, "Got NOTIFY Event: %s\n", event);
if (strcmp(event, "refer")) {
/* We don't understand this event. */
/* Here's room to implement incoming voicemail notifications :-) */
transmit_response(p, "489 Bad event", req);
if (!p->lastinvite)
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return -1;
} else {
/* Save nesting depth for now, since there might be other events we will
support in the future */
12296
12297
12298
12299
12300
12301
12302
12303
12304
12305
12306
12307
12308
12309
12310
12311
12312
12313
12314
12315
12316
12317
12318
12319
12320
12321
12322
12323
12324
12325
12326
12327
12328
12329
12330
12331
12332
12333
12334
12335
12336
12337
12338
12339
12340
12341
12342
12343
12344
12345
12346
/* Handle REFER notifications */
char buf[1024];
char *cmd, *code;
int respcode;
int success = TRUE;
/* EventID for each transfer... EventID is basically the REFER cseq
We are getting notifications on a call that we transfered
We should hangup when we are getting a 200 OK in a sipfrag
Check if we have an owner of this event */
/* Check the content type */
if (strncasecmp(get_header(req, "Content-Type"), "message/sipfrag", strlen("message/sipfrag"))) {
/* We need a sipfrag */
transmit_response(p, "400 Bad request", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return -1;
}
/* Get the text of the attachment */
if (get_msg_text(buf, sizeof(buf), req)) {
ast_log(LOG_WARNING, "Unable to retrieve attachment from NOTIFY %s\n", p->callid);
transmit_response(p, "400 Bad request", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return -1;
}
/*
From the RFC...
A minimal, but complete, implementation can respond with a single
NOTIFY containing either the body:
SIP/2.0 100 Trying
if the subscription is pending, the body:
SIP/2.0 200 OK
if the reference was successful, the body:
SIP/2.0 503 Service Unavailable
if the reference failed, or the body:
SIP/2.0 603 Declined
if the REFER request was accepted before approval to follow the
reference could be obtained and that approval was subsequently denied
(see Section 2.4.7).
If there are several REFERs in the same dialog, we need to
match the ID of the event header...
*/
if (option_debug > 2)
ast_log(LOG_DEBUG, "* SIP Transfer NOTIFY Attachment: \n---%s\n---\n", buf);
cmd = ast_skip_blanks(buf);
code = cmd;
/* We are at SIP/2.0 */
while(*code && (*code > 32)) { /* Search white space */
code++;
}
*code++ = '\0';
code = ast_skip_blanks(code);
sep = code;
sep++;
while(*sep && (*sep > 32)) { /* Search white space */
sep++;
}
*sep++ = '\0'; /* Response string */
12361
12362
12363
12364
12365
12366
12367
12368
12369
12370
12371
12372
12373
12374
12375
12376
12377
12378
12379
12380
12381
12382
12383
12384
12385
12386
12387
12388
12389
12390
12391
12392
12393
12394
12395
respcode = atoi(code);
switch (respcode) {
case 100: /* Trying: */
/* Don't do anything yet */
break;
case 183: /* Ringing: */
/* Don't do anything yet */
break;
case 200: /* OK: The new call is up, hangup this call */
/* Hangup the call that we are replacing */
break;
case 301: /* Moved permenantly */
case 302: /* Moved temporarily */
/* Do we get the header in the packet in this case? */
success = FALSE;
break;
case 503: /* Service Unavailable: The new call failed */
/* Cancel transfer, continue the call */
success = FALSE;
break;
case 603: /* Declined: Not accepted */
/* Cancel transfer, continue the current call */
success = FALSE;
break;
}
if (!success) {
ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n");
}
/* Confirm that we received this packet */
transmit_response(p, "200 OK", req);
return res;
};
}
/*! \brief Handle incoming OPTIONS request */
static int handle_request_options(struct sip_pvt *p, struct sip_request *req)
{
int res;
res = get_destination(p, req);
build_contact(p);
/* XXX Should we authenticate OPTIONS? XXX */
if (ast_strlen_zero(p->context))
ast_string_field_set(p, context, default_context);
if (res < 0)
transmit_response_with_allow(p, "404 Not Found", req, 0);
else
transmit_response_with_allow(p, "200 OK", req, 0);
/* Destroy if this OPTIONS was the opening request, but not if
it's in the middle of a normal call flow. */
if (!p->lastinvite)
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return res;
}
12418
12419
12420
12421
12422
12423
12424
12425
12426
12427
12428
12429
12430
12431
12432
12433
12434
12435
12436
12437
/*! \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)
{
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 */
struct ast_channel *replacecall = p->refer->refer_call->owner; /* The channel we're about to take over */
struct ast_channel *targetcall; /* The bridge to the take-over target */
/* Check if we're in ring state */
if (replacecall->_state == AST_STATE_RING)
earlyreplace = 1;
/* Check if we have a bridge */
if (!(targetcall = ast_bridged_channel(replacecall))) {
/* We have no bridge */
if (!earlyreplace) {
if (option_debug > 1)
ast_log(LOG_DEBUG, " Attended transfer attempted to replace call with no bridge (maybe ringing). Channel %s!\n", replacecall->name);
12439
12440
12441
12442
12443
12444
12445
12446
12447
12448
12449
12450
12451
12452
12453
12454
12455
12456
12457
12458
12459
12460
12461
12462
12463
12464
12465
12466
12467
12468
12469
12470
12471
12472
12473
12474
12475
12476
12477
12478
12479
12480
12481
12482
12483
12484
12485
12486
12487
12488
12489
12490
12491
12492
12493
12494
12495
oneleggedreplace = 1;
}
}
if (option_debug > 3 && targetcall && targetcall->_state == AST_STATE_RINGING)
ast_log(LOG_DEBUG, "SIP transfer: Target channel is in ringing state\n");
if (option_debug > 3) {
if (targetcall)
ast_log(LOG_DEBUG, "SIP transfer: Invite Replace incoming channel should bridge to channel %s while hanging up channel %s\n", targetcall->name, replacecall->name);
else
ast_log(LOG_DEBUG, "SIP transfer: Invite Replace incoming channel should replace and hang up channel %s (one call leg)\n", replacecall->name);
}
if (ignore) {
ast_log(LOG_NOTICE, "Ignoring this INVITE with replaces in a stupid way.\n");
/* We should answer something here. If we are here, the
call we are replacing exists, so an accepted
can't harm */
transmit_response_with_sdp(p, "200 OK", req, 1);
/* Do something more clever here */
ast_channel_unlock(c);
ast_mutex_unlock(&p->refer->refer_call->lock);
return 1;
}
if (!c) {
/* What to do if no channel ??? */
ast_log(LOG_ERROR, "Unable to create new channel. Invite/replace failed.\n");
transmit_response_with_sdp(p, "503 Service Unavailable", req, 1);
append_history(p, "Xfer", "INVITE/Replace Failed. No new channel.");
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
ast_mutex_unlock(&p->refer->refer_call->lock);
return 1;
}
append_history(p, "Xfer", "INVITE/Replace received");
/* We have three channels to play with
channel c: New incoming call
targetcall: Call from PBX to target
p->refer->refer_call: SIP pvt dialog from transferer to pbx.
replacecall: The owner of the previous
We need to masq C into refer_call to connect to
targetcall;
If we are talking to internal audio stream, target call is null.
*/
/* Fake call progress */
transmit_response(p, "100 Trying", req);
ast_setstate(c, AST_STATE_RING);
/* Masquerade the new call into the referred call to connect to target call
Targetcall is not touched by the masq */
/* Answer the incoming call and set channel to UP state */
transmit_response_with_sdp(p, "200 OK", req, 1);
ast_setstate(c, AST_STATE_UP);
/* Stop music on hold and other generators */
ast_quiet_chan(replacecall);
ast_quiet_chan(targetcall);
12497
12498
12499
12500
12501
12502
12503
12504
12505
12506
12507
12508
12509
12510
12511
12512
12513
12514
12515
12516
12517
12518
12519
12520
12521
12522
12523
12524
12525
12526
12527
12528
12529
12530
12531
12532
12533
12534
12535
12536
12537
12538
12539
12540
12541
12542
12543
12544
12545
12546
12547
12548
12549
12550
12551
12552
12553
12554
12555
12556
12557
12558
12559
12560
12561
12562
12563
12564
12565
12566
12567
12568
12569
12570
12571
12572
12573
12574
12575
12576
12577
12578
12579
12580
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) */
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 */
ast_set_flag(&p->refer->refer_call->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
/* Prepare the masquerade - if this does not happen, we will be gone */
if(ast_channel_masquerade(replacecall, c))
ast_log(LOG_ERROR, "Failed to masquerade C into Replacecall\n");
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 (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;
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) {
struct ast_channel *test;
ast_log(LOG_DEBUG, "After transfer:----------------------------\n");
ast_log(LOG_DEBUG, " -- C: %s State %s\n", c->name, ast_state2str(c->_state));
if (replacecall)
ast_log(LOG_DEBUG, " -- replacecall: %s State %s\n", replacecall->name, ast_state2str(replacecall->_state));
if (p->owner) {
ast_log(LOG_DEBUG, " -- P->owner: %s State %s\n", p->owner->name, ast_state2str(p->owner->_state));
test = ast_bridged_channel(p->owner);
if (test)
ast_log(LOG_DEBUG, " -- Call bridged to P->owner: %s State %s\n", test->name, ast_state2str(test->_state));
else
ast_log(LOG_DEBUG, " -- No call bridged to C->owner \n");
} else
ast_log(LOG_DEBUG, " -- No channel yet \n");
ast_log(LOG_DEBUG, "End After transfer:----------------------------\n");
}
ast_channel_unlock(p->owner); /* Unlock new owner */
ast_mutex_unlock(&p->lock); /* Unlock SIP structure */
/* The call should be down with no ast_channel, so hang it up */
c->tech_pvt = NULL;
ast_hangup(c);
return 0;
}
/*! \brief Handle incoming INVITE request
\note If the INVITE has a Replaces header, it is part of an
* attended transfer. If so, we do not go through the dial
* plan but tries to find the active call and masquerade
* into it
*/
static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e)
{
int res = 1;
int gotdest;
const char *p_replaces;
char *replace_id = NULL;
const char *required;
unsigned int required_profile = 0;
struct ast_channel *c = NULL; /* New channel */
/* Find out what they support */
if (!p->sipoptions) {
const char *supported = get_header(req, "Supported");
if (supported)
parse_sip_options(p, supported);
}
/* Find out what they require */
if (required && !ast_strlen_zero(required)) {
required_profile = parse_sip_options(NULL, required);
if (required_profile && required_profile != SIP_OPT_REPLACES) {
/* At this point we only support REPLACES */
transmit_response_with_unsupported(p, "420 Bad extension (unsupported)", req, required);
Olle Johansson
committed
ast_log(LOG_WARNING,"Received SIP INVITE with unsupported required extension: %s\n", required);
Kevin P. Fleming
committed
if (!p->lastinvite)
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return -1;
}
}
/* Check if this is a loop */
if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && p->owner && (p->owner->_state != AST_STATE_UP)) {
/* This is a call to ourself. Send ourselves an error code and stop
processing immediately, as SIP really has no good mechanism for
being able to call yourself */
/* If pedantic is on, we need to check the tags. If they're different, this is
in fact a forked call through a SIP proxy somewhere. */
transmit_response(p, "482 Loop Detected", req);
/* We do NOT destroy p here, so that our response will be accepted */
return 0;
}
if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->pendinginvite) {
/* We already have a pending invite. Sorry. You are on hold. */
transmit_response(p, "491 Request Pending", req);
if (option_debug)
ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
return 0;
}
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641
12642
12643
12644
12645
12646
12647
12648
12649
12650
12651
12652
12653
12654
12655
12656
12657
12658
12659
12660
12661
12662
12663
12664
12665
12666
12667
12668
12669
if ((p_replaces = get_header(req, "Replaces")) && !ast_strlen_zero(p_replaces)) {
/* We have a replaces header */
char *ptr;
char *fromtag = NULL;
char *totag = NULL;
char *start, *to;
int error = 0;
if (p->owner) {
if (option_debug > 2)
ast_log(LOG_DEBUG, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid);
transmit_response(p, "400 Bad request", req); /* The best way to not not accept the transfer */
/* Do not destroy existing call */
return -1;
}
if (sipdebug && option_debug > 2)
ast_log(LOG_DEBUG, "INVITE part of call transfer. Replaces [%s]\n", p_replaces);
/* Create a buffer we can manipulate */
replace_id = ast_strdupa(p_replaces);
ast_uri_decode(replace_id);
if (!p->refer && !sip_refer_allocate(p)) {
transmit_response(p, "500 Server Internal Error", req);
append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return -1;
}
/* Todo: (When we find phones that support this)
if the replaces header contains ";early-only"
we can only replace the call in early
stage, not after it's up.
If it's not in early mode, 486 Busy.
*/
/* Skip leading whitespace */
replace_id = ast_skip_blanks(replace_id);
start = replace_id;
while ( (ptr = strsep(&start, ";")) ) {
ptr = ast_skip_blanks(ptr); /* XXX maybe unnecessary ? */
if ( (to = strcasestr(ptr, "to-tag=") ) )
totag = to + 7; /* skip the keyword */
else if ( (to = strcasestr(ptr, "from-tag=") ) ) {
fromtag = to + 9; /* skip the keyword */
fromtag = strsep(&fromtag, "&"); /* trim what ? */
}
}
12682
12683
12684
12685
12686
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
12706
12707
12708
12709
12710
12711
12712
12713
12714
12715
12716
12717
12718
12719
12720
12721
12722
12723
12724
12725
12726
12727
12728
12729
12730
12731
12732
12733
12734
12735
12736
12737
12738
if (sipdebug && option_debug > 3)
ast_log(LOG_DEBUG,"Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n", replace_id, fromtag ? fromtag : "<no from tag>", totag ? totag : "<no to tag>");
/* Try to find call that we are replacing
If we have a Replaces header, we need to cancel that call if we succeed with this call
*/
if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
transmit_response(p, "481 Call Leg Does Not Exist (Replaces)", req);
error = 1;
}
/* At this point, bot the pvt and the owner of the call to be replaced is locked */
/* The matched call is the call from the transferer to Asterisk .
We want to bridge the bridged part of the call to the
incoming invite, thus taking over the refered call */
if (p->refer->refer_call == p) {
ast_log(LOG_NOTICE, "INVITE with replaces into it's own call id (%s == %s)!\n", replace_id, p->callid);
p->refer->refer_call = NULL;
transmit_response(p, "400 Bad request", req); /* The best way to not not accept the transfer */
error = 1;
}
if (!error && !p->refer->refer_call->owner) {
/* Oops, someting wrong anyway, no owner, no call */
ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
/* Check for better return code */
transmit_response(p, "481 Call Leg Does Not Exist (Replace)", req);
error = 1;
}
if (!error && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP ) {
ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
transmit_response(p, "603 Declined (Replaces)", req);
error = 1;
}
if (error) { /* Give up this dialog */
append_history(p, "Xfer", "INVITE/Replace Failed.");
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
ast_mutex_unlock(&p->lock);
if (p->refer->refer_call) {
ast_mutex_unlock(&p->refer->refer_call->lock);
ast_channel_unlock(p->refer->refer_call->owner);
}
return -1;
}
}
/* Check if this is an INVITE that sets up a new dialog or
a re-invite in an existing dialog */
if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
sip_cancel_destroy(p);
/* This also counts as a pending invite */
p->pendinginvite = seqno;
check_via(p, req);
if (!p->owner) { /* Not a re-invite */
/* Use this as the basis */
copy_request(&p->initreq, req);
if (debug)
ast_verbose("Using INVITE request as basis request - %s\n", p->callid);
append_history(p, "Invite", "New call: %s", p->callid);
parse_ok_contact(p, req);
} else { /* Re-invite on existing call */
/* Handle SDP here if we already have an owner */
if (find_sdp(req)) {
if (process_sdp(p, req)) {
transmit_response(p, "488 Not acceptable here", req);
Kevin P. Fleming
committed
if (!p->lastinvite)
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
} else {
p->jointcapability = p->capability;
ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
}
if (recordhistory) /* This is a response, note what it was for */
}
} else if (debug)
ast_verbose("Ignoring this INVITE request\n");
if (!p->lastinvite && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner) {
/* This is a new invite */
/* Handle authentication if this is our first invite */
res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
if (res == AUTH_CHALLENGE_SENT)
return 0;
if (res < 0) { /* Something failed in authentication */
if (res == AUTH_FAKE_AUTH) {
ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
transmit_fake_auth_response(p, req, 1);
} else {
ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
transmit_response_reliable(p, "403 Forbidden", req);
}
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
ast_string_field_free(p, theirtag);
return 0;
}
/* We have a succesful authentication, process the SDP portion if there is one */
if (find_sdp(req)) {
if (process_sdp(p, req)) {
/* Unacceptable codecs */
transmit_response_reliable(p, "488 Not acceptable here", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
if (option_debug)
ast_log(LOG_DEBUG, "No compatible codecs for this SIP call.\n");
} else { /* No SDP in invite, call control session */
p->jointcapability = p->capability;
if (option_debug > 1)
ast_log(LOG_DEBUG, "No SDP in Invite, third party call control\n");
/* Queue NULL frame to prod ast_rtp_bridge if appropriate */
/* This seems redundant ... see !p-owner above */
ast_queue_frame(p->owner, &ast_null_frame);
/* Initialize the context if it hasn't been already */
if (ast_strlen_zero(p->context))
ast_string_field_set(p, context, default_context);
/* Check number of concurrent calls -vs- incoming limit HERE */
if (option_debug)
ast_log(LOG_DEBUG, "Checking SIP call limits for device %s\n", p->username);
if ((res = update_call_counter(p, INC_CALL_LIMIT))) {
ast_log(LOG_NOTICE, "Failed to place call for user %s, too many calls\n", p->username);
transmit_response_reliable(p, "480 Temporarily Unavailable (Call limit) ", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
}
return 0;
}
gotdest = get_destination(p, NULL); /* Get destination right away */
get_rdnis(p, NULL); /* Get redirect information */
extract_uri(p, req); /* Get the Contact URI */
build_contact(p); /* Build our contact header */
ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
if (!replace_id && gotdest) { /* No matching extension found */
if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) {
transmit_response_reliable(p, "484 Address Incomplete", req);
Kevin P. Fleming
committed
update_call_counter(p, DEC_CALL_LIMIT);
transmit_response_reliable(p, "404 Not Found", req);
Kevin P. Fleming
committed
update_call_counter(p, DEC_CALL_LIMIT);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
} else {
/* If no extension was specified, use the s one */
/* Basically for calling to IP/Host name only */
if (ast_strlen_zero(p->exten))
ast_string_field_set(p, exten, "s");
/* Initialize our tag */
Kevin P. Fleming
committed
make_our_tag(p->tag, sizeof(p->tag));
/* First invitation - create the channel */
c = sip_new(p, AST_STATE_DOWN, S_OR(p->username, NULL));
/* Save Record-Route for any later requests we make on this dialogue */
build_route(p, req, 0);
if (c) {
/* Pre-lock the call */
} else {
if (option_debug > 1 && sipdebug) {
if (!ast_test_flag(req, SIP_PKT_IGNORE))
ast_log(LOG_DEBUG, "Got a SIP re-invite for call %s\n", p->callid);
else
ast_log(LOG_DEBUG, "Got a SIP re-transmit of INVITE for call %s\n", p->callid);
}
if (!ast_test_flag(req, SIP_PKT_IGNORE) && p)
p->lastinvite = seqno;
if (replace_id) { /* Attended transfer or call pickup - we're the target */
/* 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);
}
if (c) { /* We have a call -either a new call or an old one (RE-INVITE) */
switch(c->_state) {
case AST_STATE_DOWN:
if (option_debug > 1)
ast_log(LOG_DEBUG, "%s: New call is still down.... Trying... \n", c->name);
transmit_response(p, "100 Trying", req);
ast_setstate(c, AST_STATE_RING);
if (strcmp(p->exten, ast_pickup_ext())) { /* Call to extension -start pbx on this call */
Kevin P. Fleming
committed
enum ast_pbx_result res;
res = ast_pbx_start(c);
switch(res) {
Kevin P. Fleming
committed
case AST_PBX_FAILED:
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
if (ast_test_flag(req, SIP_PKT_IGNORE))
Kevin P. Fleming
committed
transmit_response(p, "503 Unavailable", req);
else
transmit_response_reliable(p, "503 Unavailable", req);
Kevin P. Fleming
committed
break;
case AST_PBX_CALL_LIMIT:
ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
if (ast_test_flag(req, SIP_PKT_IGNORE))
Kevin P. Fleming
committed
transmit_response(p, "480 Temporarily Unavailable", req);
else
transmit_response_reliable(p, "480 Temporarily Unavailable", req);
Kevin P. Fleming
committed
break;
case AST_PBX_SUCCESS:
/* nothing to do */
break;
}
if (res) {
/* Unlock locks so ast_hangup can do its magic */
ast_mutex_unlock(&c->lock);
ast_mutex_unlock(&p->lock);
ast_hangup(c);
ast_mutex_lock(&p->lock);
c = NULL;
}
} else { /* Pickup call in call group */
if (ast_pickup_call(c)) {
ast_log(LOG_NOTICE, "Nothing to pick up for %s\n", p->callid);
if (ast_test_flag(req, SIP_PKT_IGNORE))
transmit_response(p, "503 Unavailable", req); /* OEJ - Right answer? */
transmit_response_reliable(p, "503 Unavailable", req);
ast_set_flag(&p->flags[0], SIP_ALREADYGONE);
/* Unlock locks so ast_hangup can do its magic */
ast_mutex_unlock(&p->lock);
c->hangupcause = AST_CAUSE_CALL_REJECTED;
} else {
ast_mutex_unlock(&p->lock);
ast_setstate(c, AST_STATE_DOWN);
c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
ast_hangup(c);
ast_mutex_lock(&p->lock);
c = NULL;
}
break;
case AST_STATE_RING:
transmit_response(p, "100 Trying", req);
break;
case AST_STATE_RINGING:
transmit_response(p, "180 Ringing", req);
break;
case AST_STATE_UP:
if (option_debug > 1)
Olle Johansson
committed
ast_log(LOG_DEBUG, "%s: This call is UP.... \n", c->name);
12959
12960
12961
12962
12963
12964
12965
12966
12967
12968
12969
12970
12971
12972
12973
12974
12975
12976
12977
12978
12979
12980
12981
12982
12983
12984
12985
12986
12987
12988
12989
12990
12991
12992
12993
12994
12995
12996
12997
12998
12999
13000
if (p->t38.state == T38_PEER_REINVITE) {
struct ast_channel *bridgepeer = NULL;
struct sip_pvt *bridgepvt = NULL;
if ((bridgepeer = ast_bridged_channel(p->owner))) {
/* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
/*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
if (!strcasecmp(bridgepeer->tech->type, "SIP")) { /* If we are bridged to SIP channel */
bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
if (bridgepvt->t38.state == T38_DISABLED) {
if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
/* Send re-invite to the bridged channel */
sip_handle_t38_reinvite(bridgepeer, p, 1);
} else { /* Something is wrong with peers udptl struct */
ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
ast_mutex_lock(&bridgepvt->lock);
bridgepvt->t38.state = T38_DISABLED;
ast_mutex_unlock(&bridgepvt->lock);
if (option_debug > 1)
ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
if (ast_test_flag(req, SIP_PKT_IGNORE))
transmit_response(p, "488 Not acceptable here", req);
else
transmit_response_reliable(p, "488 Not acceptable here", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
}
}
} else {
/* Other side is not a SIP channel */
if (ast_test_flag(req, SIP_PKT_IGNORE))
transmit_response(p, "488 Not acceptable here", req);
else
transmit_response_reliable(p, "488 Not acceptable here", req);
p->t38.state = T38_DISABLED;
if (option_debug > 1)
ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
}
} else {
/* we are not bridged in a call */
transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
p->t38.state = T38_ENABLED;