Newer
Older
Olle Johansson
committed
case 410: /* Gone */
return AST_CAUSE_UNALLOCATED;
case 411: /* Length required */
return AST_CAUSE_INTERWORKING;
case 413: /* Request entity too large */
return AST_CAUSE_INTERWORKING;
case 414: /* Request URI too large */
return AST_CAUSE_INTERWORKING;
case 415: /* Unsupported media type */
return AST_CAUSE_INTERWORKING;
case 420: /* Bad extension */
return AST_CAUSE_NO_ROUTE_DESTINATION;
case 480: /* No answer */
return AST_CAUSE_NO_ANSWER;
Olle Johansson
committed
case 481: /* No answer */
return AST_CAUSE_INTERWORKING;
case 482: /* Loop detected */
return AST_CAUSE_INTERWORKING;
case 483: /* Too many hops */
return AST_CAUSE_NO_ANSWER;
Olle Johansson
committed
case 484: /* Address incomplete */
return AST_CAUSE_INVALID_NUMBER_FORMAT;
case 485: /* Ambigous */
return AST_CAUSE_UNALLOCATED;
case 486: /* Busy everywhere */
Martin Pycko
committed
return AST_CAUSE_BUSY;
Olle Johansson
committed
case 487: /* Request terminated */
return AST_CAUSE_INTERWORKING;
case 488: /* No codecs approved */
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
Olle Johansson
committed
case 491: /* Request pending */
return AST_CAUSE_INTERWORKING;
case 493: /* Undecipherable */
return AST_CAUSE_INTERWORKING;
case 500: /* Server internal failure */
return AST_CAUSE_FAILURE;
case 501: /* Call rejected */
return AST_CAUSE_FACILITY_REJECTED;
case 502:
return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
case 503: /* Service unavailable */
return AST_CAUSE_CONGESTION;
Olle Johansson
committed
case 504: /* Gateway timeout */
return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
case 505: /* SIP version not supported */
return AST_CAUSE_INTERWORKING;
case 600: /* Busy everywhere */
return AST_CAUSE_USER_BUSY;
case 603: /* Decline */
return AST_CAUSE_CALL_REJECTED;
case 604: /* Does not exist anywhere */
return AST_CAUSE_UNALLOCATED;
case 606: /* Not acceptable */
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
Martin Pycko
committed
default:
return AST_CAUSE_NORMAL;
}
/* Never reached */
return 0;
}
/*! \brief Convert Asterisk hangup causes to SIP codes
\verbatim
Possible values from causes.h
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY
AST_CAUSE_FAILURE AST_CAUSE_CONGESTION AST_CAUSE_UNALLOCATED
In addition to these, a lot of PRI codes is defined in causes.h
...should we take care of them too ?
Quote RFC 3398
ISUP Cause value SIP response
---------------- ------------
1 unallocated number 404 Not Found
2 no route to network 404 Not found
3 no route to destination 404 Not found
16 normal call clearing --- (*)
17 user busy 486 Busy here
18 no user responding 408 Request Timeout
19 no answer from the user 480 Temporarily unavailable
20 subscriber absent 480 Temporarily unavailable
21 call rejected 403 Forbidden (+)
22 number changed (w/o diagnostic) 410 Gone
22 number changed (w/ diagnostic) 301 Moved Permanently
23 redirection to new destination 410 Gone
26 non-selected user clearing 404 Not Found (=)
27 destination out of order 502 Bad Gateway
28 address incomplete 484 Address incomplete
29 facility rejected 501 Not implemented
31 normal unspecified 480 Temporarily unavailable
static const char *hangup_cause2sip(int cause)
Martin Pycko
committed
{
switch (cause) {
case AST_CAUSE_UNALLOCATED: /* 1 */
case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */
case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */
return "404 Not Found";
case AST_CAUSE_CONGESTION: /* 34 */
case AST_CAUSE_SWITCH_CONGESTION: /* 42 */
return "503 Service Unavailable";
case AST_CAUSE_NO_USER_RESPONSE: /* 18 */
return "408 Request Timeout";
case AST_CAUSE_NO_ANSWER: /* 19 */
return "480 Temporarily unavailable";
case AST_CAUSE_CALL_REJECTED: /* 21 */
return "403 Forbidden";
case AST_CAUSE_NUMBER_CHANGED: /* 22 */
return "410 Gone";
case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */
return "480 Temporarily unavailable";
case AST_CAUSE_INVALID_NUMBER_FORMAT:
return "484 Address incomplete";
case AST_CAUSE_USER_BUSY:
return "486 Busy here";
case AST_CAUSE_FAILURE:
case AST_CAUSE_FACILITY_REJECTED: /* 29 */
return "501 Not Implemented";
case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
return "503 Service Unavailable";
/* Used in chan_iax2 */
case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
return "502 Bad Gateway";
case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */
return "488 Not Acceptable Here";
case AST_CAUSE_NOTDEFINED:
Martin Pycko
committed
default:
ast_log(LOG_DEBUG, "AST hangup cause %d (no match found in SIP)\n", cause);
Martin Pycko
committed
return NULL;
}
Martin Pycko
committed
/* Never reached */
return 0;
}
Olle Johansson
committed
/*! \brief sip_hangup: Hangup SIP call
* Part of PBX interface, called from ast_hangup */
static int sip_hangup(struct ast_channel *ast)
{
struct sip_pvt *p = ast->tech_pvt;
struct ast_flags locflags = {0};
if (!p) {
ast_log(LOG_DEBUG, "Asked to hangup channel that was not connected\n");
Kevin P. Fleming
committed
if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
if (option_debug >3)
ast_log(LOG_DEBUG, "SIP Transfer: Not hanging up right now... Rescheduling hangup for %s.\n", p->callid);
if (p->autokillid > -1)
sip_cancel_destroy(p);
sip_scheddestroy(p, 32000);
ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Really hang up next time */
ast_clear_flag(&p->flags[0], SIP_NEEDDESTROY);
p->owner->tech_pvt = NULL;
p->owner = NULL; /* Owner will be gone after we return, so take it away */
return 0;
}
if (option_debug) {
if (ast_test_flag(ast, AST_FLAG_ZOMBIE) && p->refer && option_debug)
ast_log(LOG_DEBUG, "SIP Transfer: Hanging up Zombie channel %s after transfer ... Call-ID: %s\n", ast->name, p->callid);
else
ast_log(LOG_DEBUG, "Hangup call %s, SIP callid %s)\n", ast->name, p->callid);
}
if (option_debug && ast_test_flag(ast, AST_FLAG_ZOMBIE)) {
ast_log(LOG_DEBUG, "Hanging up zombie call. Be scared.\n");
}
ast_mutex_lock(&p->lock);
if (option_debug && sipdebug)
ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
Kevin P. Fleming
committed
update_call_counter(p, DEC_CALL_LIMIT);
Kevin P. Fleming
committed
ast_log(LOG_WARNING, "Huh? We aren't the owner? Can't hangup call.\n");
ast_mutex_unlock(&p->lock);
Kevin P. Fleming
committed
/* If the call is not UP, we need to send CANCEL instead of BYE */
if (ast->_state != AST_STATE_UP) {
if (option_debug > 3)
ast_log(LOG_DEBUG, "Hanging up channel in state %s (not UP)\n", ast_state2str(ast->_state));
}
Kevin P. Fleming
committed
p = ast->tech_pvt;
if (p->vad)
ast->tech_pvt = NULL;
Russell Bryant
committed
ast_atomic_fetchadd_int(&usecnt, -1);
ast_set_flag(&locflags, SIP_NEEDDESTROY);
Kevin P. Fleming
committed
/* Start the process if it's not already started */
if (!ast_test_flag(&p->flags[0], SIP_ALREADYGONE) && !ast_strlen_zero(p->initreq.data)) {
Kevin P. Fleming
committed
if (needcancel) { /* Outgoing call, not up */
if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
/* stop retransmitting an INVITE that has not received a response */
__sip_pretend_ack(p);
Kevin P. Fleming
committed
/* if we can't send right now, mark it pending */
if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE)) {
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
} else {
/* Send a new request: CANCEL */
transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
/* Actually don't destroy us yet, wait for the 487 on our original
INVITE, but do set an autodestruct just in case we never get it. */
ast_clear_flag(&locflags, SIP_NEEDDESTROY);
Kevin P. Fleming
committed
sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
}
if ( p->initid != -1 ) {
/* channel still up - reverse dec of inUse counter
only if the channel is not auto-congested */
Kevin P. Fleming
committed
update_call_counter(p, INC_CALL_LIMIT);
Kevin P. Fleming
committed
} else { /* Incoming call, not up */
const char *res;
if (ast->hangupcause && (res = hangup_cause2sip(ast->hangupcause)))
transmit_response_reliable(p, res, &p->initreq);
transmit_response_reliable(p, "603 Declined", &p->initreq);
Martin Pycko
committed
}
Kevin P. Fleming
committed
} else { /* Call is in UP state, send BYE */
if (!p->pendinginvite) {
char *audioqos = "";
char *videoqos = "";
if (p->rtp)
audioqos = ast_rtp_get_quality(p->rtp);
if (p->vrtp)
videoqos = ast_rtp_get_quality(p->vrtp);
/* Send a hangup */
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
/* Get RTCP quality before end of call */
if (recordhistory) {
if (p->rtp)
append_history(p, "RTCPaudio", "Quality:%s", audioqos);
append_history(p, "RTCPvideo", "Quality:%s", videoqos);
if (p->rtp && oldowner)
pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos);
if (p->vrtp && oldowner)
pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos);
} else {
/* Note we will need a BYE when this all settles out
but we can't send one while we have "INVITE" outstanding. */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
}
ast_copy_flags(&p->flags[0], &locflags, SIP_NEEDDESTROY);
ast_mutex_unlock(&p->lock);
Olle Johansson
committed
/*! \brief Try setting codec suggested by the SIP_CODEC channel variable */
static void try_suggested_sip_codec(struct sip_pvt *p)
{
int fmt;
const char *codec;
codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
if (!codec)
return;
fmt = ast_getformatbyname(codec);
if (fmt) {
ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC} variable\n", codec);
Olle Johansson
committed
if (p->jointcapability & fmt) {
p->jointcapability &= fmt;
p->capability &= fmt;
} else
ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
} else
ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
return;
}
/*! \brief sip_answer: Answer SIP call , send 200 OK on Invite
* Part of PBX interface */
static int sip_answer(struct ast_channel *ast)
{
Olle Johansson
committed
int res = 0;
struct sip_pvt *p = ast->tech_pvt;
Olle Johansson
committed
try_suggested_sip_codec(p);
ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
if (p->t38.state == T38_PEER_DIRECT) {
p->t38.state = T38_ENABLED;
if (option_debug > 1)
ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
} else {
res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
}
/*! \brief Send frame to media channel (rtp) */
static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
{
struct sip_pvt *p = ast->tech_pvt;
switch (frame->frametype) {
case AST_FRAME_VOICE:
Russell Bryant
committed
char s1[512], s2[512], s3[512];
ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %s(%d) read/write = %s(%d)/%s(%d)\n",
frame->subclass,
ast_getformatname_multiple(s1, sizeof(s1) - 1, ast->nativeformats & AST_FORMAT_AUDIO_MASK),
ast->nativeformats & AST_FORMAT_AUDIO_MASK,
ast_getformatname_multiple(s2, sizeof(s2) - 1, ast->readformat),
ast->readformat,
ast_getformatname_multiple(s3, sizeof(s3) - 1, ast->writeformat),
ast->writeformat);
Mark Spencer
committed
return 0;
if (p) {
ast_mutex_lock(&p->lock);
if (p->rtp) {
/* If channel is not up, activate early media session */
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
p->lastrtptx = time(NULL);
res = ast_rtp_write(p->rtp, frame);
ast_mutex_unlock(&p->lock);
break;
case AST_FRAME_VIDEO:
if (p) {
ast_mutex_lock(&p->lock);
if (p->vrtp) {
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
p->lastrtptx = time(NULL);
res = ast_rtp_write(p->vrtp, frame);
ast_mutex_unlock(&p->lock);
break;
case AST_FRAME_IMAGE:
return 0;
case AST_FRAME_MODEM:
if (p) {
ast_mutex_lock(&p->lock);
if (p->udptl) {
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
transmit_response_with_t38_sdp(p, "183 Session Progress", &p->initreq, XMIT_RELIABLE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
res = ast_udptl_write(p->udptl, frame);
}
ast_mutex_unlock(&p->lock);
}
break;
ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
return 0;
/*! \brief sip_fixup: Fix up a channel: If a channel is consumed, this is called.
Basically update any ->owner links */
Mark Spencer
committed
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
struct sip_pvt *p;
if (newchan && ast_test_flag(newchan, AST_FLAG_ZOMBIE))
ast_log(LOG_DEBUG, "New channel is zombie\n");
if (oldchan && ast_test_flag(oldchan, AST_FLAG_ZOMBIE))
ast_log(LOG_DEBUG, "Old channel is zombie\n");
if (!newchan || !newchan->tech_pvt) {
if (!newchan)
ast_log(LOG_WARNING, "No new channel! Fixup of %s failed.\n", oldchan->name);
else
ast_log(LOG_WARNING, "No SIP tech_pvt! Fixup of %s failed.\n", oldchan->name);
return -1;
}
p = newchan->tech_pvt;
Mark Spencer
committed
ast_mutex_lock(&p->lock);
append_history(p, "Masq", "Old channel: %s\n", oldchan->name);
append_history(p, "Masq (cont)", "...new owner: %s\n", newchan->name);
if (p->owner != oldchan)
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
else {
p->owner = newchan;
ret = 0;
if (option_debug > 2)
ast_log(LOG_DEBUG, "SIP Fixup: New owner for dialogue %s: %s (Old parent: %s)\n", p->callid, p->owner->name, oldchan->name);
Mark Spencer
committed
ast_mutex_unlock(&p->lock);
/*! \brief Send DTMF character on SIP channel
within one call, we're able to transmit in many methods simultaneously */
static int sip_senddigit(struct ast_channel *ast, char digit)
{
struct sip_pvt *p = ast->tech_pvt;
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
break;
case SIP_DTMF_RFC2833:
if (p->rtp)
ast_rtp_senddigit(p->rtp, digit);
break;
case SIP_DTMF_INBAND:
/*! \brief Transfer SIP call */
Mark Spencer
committed
static int sip_transfer(struct ast_channel *ast, const char *dest)
struct sip_pvt *p = ast->tech_pvt;
if (ast->_state == AST_STATE_RING)
res = sip_sipredirect(p, dest);
else
res = transmit_refer(p, dest);
/*! \brief Play indication to user
* With SIP a lot of indications is sent as messages, letting the device play
the indication - busy signal, congestion etc
\return -1 to force ast_indicate to send indication in audio, 0 if SIP can handle the indication by sending a message
*/
Kevin P. Fleming
committed
static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
struct sip_pvt *p = ast->tech_pvt;
int res = 0;
ast_mutex_lock(&p->lock);
switch(condition) {
case AST_CONTROL_RINGING:
if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
(ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {
/* Send 180 ringing if out-of-band seems reasonable */
transmit_response(p, "180 Ringing", &p->initreq);
ast_set_flag(&p->flags[0], SIP_RINGING);
if (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
/* Well, if it's not reasonable, just send in-band */
transmit_response(p, "486 Busy Here", &p->initreq);
ast_set_flag(&p->flags[0], SIP_ALREADYGONE);
ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
transmit_response(p, "503 Service Unavailable", &p->initreq);
ast_set_flag(&p->flags[0], SIP_ALREADYGONE);
ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
Kevin P. Fleming
committed
transmit_response(p, "100 Trying", &p->initreq);
break;
}
res = -1;
break;
case AST_CONTROL_PROGRESS:
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
Kevin P. Fleming
committed
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, p->mohinterpret);
break;
Kevin P. Fleming
committed
case AST_CONTROL_UNHOLD:
ast_moh_stop(ast);
break;
case AST_CONTROL_VIDUPDATE: /* Request a video frame update */
if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
/*! \brief Initiate a call in the SIP channel
called from sip_request_call (calls from the pbx ) for outbound channels
and from handle_request_invite for inbound channels
*/
static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title)
int what;
int needvideo = 0;
Mark Spencer
committed
ast_mutex_unlock(&i->lock);
/* Don't hold a sip pvt lock while we allocate a channel */
Mark Spencer
committed
ast_mutex_lock(&i->lock);
ast_log(LOG_WARNING, "Unable to allocate AST channel structure for SIP channel\n");
return NULL;
}
tmp->tech = &sip_tech;
/* Select our native format based on codec preference until we receive
something from another device to the contrary. */
if (i->jointcapability) /* The joint capabilities of us and peer */
what = i->jointcapability;
else if (i->capability) /* Our configured capability for this peer */
what = i->capability;
what = global_capability; /* Global codec support */
/* Set the native formats for audio and merge in video */
tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
if (option_debug > 2) {
char buf[BUFSIZ];
ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
ast_log(LOG_DEBUG, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->capability));
ast_log(LOG_DEBUG, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, ast_codec_choose(&i->prefs, what, 1)));
if (i->prefcodec)
ast_log(LOG_DEBUG, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->prefcodec));
}
/* XXX Why are we choosing a codec from the native formats?? */
fmt = ast_best_codec(tmp->nativeformats);
/* If we have a prefcodec setting, we have an inbound channel that set a
preferred format for this call. Otherwise, we check the jointcapability
We also check for vrtp. If it's not there, we are not allowed do any video anyway.
*/
if (i->vrtp) {
if (i->prefcodec)
needvideo = i->prefcodec & AST_FORMAT_VIDEO_MASK; /* Outbound call */
else
needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK; /* Inbound call */
}
if (option_debug > 2) {
if (needvideo)
ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
else
ast_log(LOG_DEBUG, "This channel will not be able to handle video.\n");
}
ast_string_field_build(tmp, name, "SIP/%s-%08x", title, (int)(long) i);
else if (strchr(i->fromdomain,':'))
ast_string_field_build(tmp, name, "SIP/%s-%08x", strchr(i->fromdomain,':') + 1, (int)(long) i);
ast_string_field_build(tmp, name, "SIP/%s-%08x", i->fromdomain, (int)(long) i);
if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
i->vad = ast_dsp_new();
ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
}
if (i->rtp) {
tmp->fds[0] = ast_rtp_fd(i->rtp);
tmp->fds[1] = ast_rtcp_fd(i->rtp);
}
if (needvideo && i->vrtp) {
tmp->fds[2] = ast_rtp_fd(i->vrtp);
tmp->fds[3] = ast_rtcp_fd(i->vrtp);
}
if (i->udptl) {
tmp->fds[5] = ast_udptl_fd(i->udptl);
}
if (state == AST_STATE_RING)
tmp->rings = 1;
tmp->adsicpe = AST_ADSI_UNAVAILABLE;
tmp->writeformat = fmt;
tmp->rawwriteformat = fmt;
tmp->readformat = fmt;
tmp->rawreadformat = fmt;
tmp->tech_pvt = i;
tmp->callgroup = i->callgroup;
tmp->pickupgroup = i->pickupgroup;
tmp->cid.cid_pres = i->callingpres;
if (!ast_strlen_zero(i->accountcode))
ast_string_field_set(tmp, accountcode, i->accountcode);
if (i->amaflags)
tmp->amaflags = i->amaflags;
if (!ast_strlen_zero(i->language))
ast_string_field_set(tmp, language, i->language);
Russell Bryant
committed
ast_atomic_fetchadd_int(&usecnt, 1);
ast_update_use_count();
ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
/* Don't use ast_set_callerid() here because it will
* generate a NewCallerID event before the NewChannel event */
tmp->cid.cid_num = ast_strdup(i->cid_num);
tmp->cid.cid_ani = ast_strdup(i->cid_num);
tmp->cid.cid_name = ast_strdup(i->cid_name);
if (!ast_strlen_zero(i->rdnis))
tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
tmp->cid.cid_dnid = ast_strdup(i->exten);
if (!ast_strlen_zero(i->uri))
pbx_builtin_setvar_helper(tmp, "SIPURI", i->uri);
if (!ast_strlen_zero(i->domain))
pbx_builtin_setvar_helper(tmp, "SIPDOMAIN", i->domain);
if (!ast_strlen_zero(i->useragent))
pbx_builtin_setvar_helper(tmp, "SIPUSERAGENT", i->useragent);
if (!ast_strlen_zero(i->callid))
pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
ast_setstate(tmp, state);
Russell Bryant
committed
if (i->rtp)
ast_jb_configure(tmp, &global_jbconf);
if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
ast_hangup(tmp);
tmp = NULL;
}
/* Set channel variables for this call from configuration */
for (v = i->chanvars ; v ; v = v->next)
pbx_builtin_setvar_helper(tmp,v->name,v->value);
if (recordhistory)
append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);
Russell Bryant
committed
/*! \brief Reads one line of SIP message body */
static char *get_body_by_line(const char *line, const char *name, int nameLen)
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=')
return ast_skip_blanks(line + nameLen + 1);
/*! \brief Lookup 'name' in the SDP starting
* at the 'start' line. Returns the matching line, and 'start'
* is updated with the next line number.
*/
static const char *get_sdp_iterate(int *start, struct sip_request *req, const char *name)
{
int len = strlen(name);
while (*start < req->sdp_end) {
const char *r = get_body_by_line(req->line[(*start)++], name, len);
if (r[0] != '\0')
return r;
}
/*! \brief Get a line from an SDP message body */
static const char *get_sdp(struct sip_request *req, const char *name)
{
int dummy = 0;
return get_sdp_iterate(&dummy, req, name);
}
/*! \brief Get a specific line from the message body */
static char *get_body(struct sip_request *req, char *name)
{
int x;
int len = strlen(name);
char *r;
for (x = 0; x < req->lines; x++) {
r = get_body_by_line(req->line[x], name, len);
if (r[0] != '\0')
return r;
}
return "";
}
Olle Johansson
committed
/*! \brief Find compressed SIP alias */
static const char *find_alias(const char *name, const char *_default)
{
/*! \brief Structure for conversion between compressed SIP and "normal" SIP */
static const struct cfalias {
char * const fullname;
char * const shortname;
} aliases[] = {
{ "Content-Type", "c" },
{ "Content-Encoding", "e" },
{ "From", "f" },
{ "Call-ID", "i" },
{ "Contact", "m" },
{ "Content-Length", "l" },
{ "Subject", "s" },
{ "To", "t" },
{ "Supported", "k" },
{ "Refer-To", "r" },
{ "Referred-By", "b" },
{ "Allow-Events", "u" },
{ "Event", "o" },
{ "Via", "v" },
{ "Accept-Contact", "a" },
{ "Reject-Contact", "j" },
{ "Request-Disposition", "d" },
{ "Session-Expires", "x" },
};
Olle Johansson
committed
for (x=0; x<sizeof(aliases) / sizeof(aliases[0]); x++)
if (!strcasecmp(aliases[x].fullname, name))
return aliases[x].shortname;
return _default;
}
static const char *__get_header(const struct sip_request *req, const char *name, int *start)
{
int pass;
/*
* Technically you can place arbitrary whitespace both before and after the ':' in
* a header, although RFC3261 clearly says you shouldn't before, and place just
* one afterwards. If you shouldn't do it, what absolute idiot decided it was
* a good idea to say you can do it, and if you can do it, why in the hell would.
* you say you shouldn't.
* Anyways, pedanticsipchecking controls whether we allow spaces before ':',
* and we always allow spaces after that for compatibility.
*/
for (pass = 0; name && pass < 2;pass++) {
int x, len = strlen(name);
for (x=*start; x<req->headers; x++) {
if (!strncasecmp(req->header[x], name, len)) {
char *r = req->header[x] + len; /* skip name */
if (pedanticsipchecking)
r = ast_skip_blanks(r);
if (*r == ':') {
return ast_skip_blanks(r+1);
}
}
}
if (pass == 0) /* Try aliases */
name = find_alias(name, NULL);
}
/* Don't return NULL, so get_header is always a valid pointer */
return "";
}
/*! \brief Get header from SIP request */
static const char *get_header(const struct sip_request *req, const char *name)
{
int start = 0;
return __get_header(req, name, &start);
}
/*! \brief Read RTP from network */
static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect)
/* Retrieve audio/etc from channel. Assumes p->lock is already held. */
struct ast_frame *f;
if (!p->rtp) {
/* We have no RTP allocated for this channel */
return &ast_null_frame;
}
switch(ast->fdno) {
case 0:
f = ast_rtp_read(p->rtp); /* RTP Audio */
break;
case 1:
f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */
break;
case 2:
f = ast_rtp_read(p->vrtp); /* RTP Video */
break;
case 3:
f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */
case 5:
f = ast_udptl_read(p->udptl); /* UDPTL for T.38 */
break;
default:
f = &ast_null_frame;
/* Don't forward RFC2833 if we're not supposed to */
if (f && (f->frametype == AST_FRAME_DTMF) &&
(ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_RFC2833))
return &ast_null_frame;
/* We already hold the channel lock */
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
if (option_debug)
ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
Mark Spencer
committed
ast_set_read_format(p->owner, p->owner->readformat);
ast_set_write_format(p->owner, p->owner->writeformat);
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner, p->vad, f);
if (f && f->frametype == AST_FRAME_DTMF) {
if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
if (option_debug)
ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
*faxdetect = 1;
} else if (option_debug) {
ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
}
}
/*! \brief Read SIP RTP from channel */
static struct ast_frame *sip_read(struct ast_channel *ast)
{
struct ast_frame *fr;
struct sip_pvt *p = ast->tech_pvt;
ast_mutex_lock(&p->lock);
fr = sip_rtp_read(ast, p, &faxdetected);
p->lastrtprx = time(NULL);
/* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
/* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
if (!p->pendinginvite) {
if (option_debug > 2)
ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
p->t38.state = T38_LOCAL_REINVITE;
transmit_reinvite_with_t38_sdp(p);
if (option_debug > 1)
ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s", p->t38.state, ast->name);
}
} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
if (option_debug > 2)
ast_log(LOG_DEBUG, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n", ast->name);
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
}
}
ast_mutex_unlock(&p->lock);
Olle Johansson
committed
/*! \brief Generate 32 byte random string for callid's etc */
static char *generate_random_string(char *buf, size_t size)
Tilghman Lesher
committed
long val[4];
for (x=0; x<4; x++)
Tilghman Lesher
committed
val[x] = ast_random();
snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
Olle Johansson
committed
return buf;
}
/*! \brief Build SIP Call-ID value for a non-REGISTER transaction */
static void build_callid_pvt(struct sip_pvt *pvt)
{
char buf[33];
Russell Bryant
committed
const char *host = S_OR(pvt->fromdomain, ast_inet_ntoa(pvt->ourip));
Olle Johansson
committed
ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
}
/*! \brief Build SIP Call-ID value for a REGISTER transaction */
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain)
{
Olle Johansson
committed
char buf[33];
Russell Bryant
committed
const char *host = S_OR(fromdomain, ast_inet_ntoa(ourip));
Olle Johansson
committed
ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
/*! \brief Make our SIP dialog tag */
Kevin P. Fleming
committed
static void make_our_tag(char *tagbuf, size_t len)
{
Tilghman Lesher
committed
snprintf(tagbuf, len, "as%08lx", ast_random());
Kevin P. Fleming
committed
}
/*! \brief Allocate SIP_PVT structure and set defaults */
static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
int useglobal_nat, const int intended_method)
if (!(p = ast_calloc(1, sizeof(*p))))
Kevin P. Fleming
committed
if (ast_string_field_init(p, 512)) {
free(p);
return NULL;
}