aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_bridge.c3
-rw-r--r--channels/chan_dahdi.c83
-rw-r--r--channels/chan_gtalk.c2
-rw-r--r--channels/chan_iax2.c22
-rw-r--r--channels/chan_jingle.c2
-rw-r--r--channels/chan_mgcp.c2
-rw-r--r--channels/chan_sip.c821
-rw-r--r--channels/sip/include/sip.h13
-rw-r--r--channels/sip/reqresp_parser.c16
9 files changed, 629 insertions, 335 deletions
diff --git a/channels/chan_bridge.c b/channels/chan_bridge.c
index a58cfcc59..7b01909ae 100644
--- a/channels/chan_bridge.c
+++ b/channels/chan_bridge.c
@@ -229,6 +229,9 @@ static struct ast_channel *bridge_request(const char *type, struct ast_format_ca
ast_format_copy(&p->input->rawwriteformat, &slin);
ast_format_copy(&p->output->rawwriteformat, &slin);
+ ast_answer(p->output);
+ ast_answer(p->input);
+
return p->input;
}
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 131279ea0..321be6625 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -38,12 +38,12 @@
*/
/*** MODULEINFO
- <use>res_smdi</use>
+ <use type="module">res_smdi</use>
<depend>dahdi</depend>
<depend>tonezone</depend>
- <use>pri</use>
- <use>ss7</use>
- <use>openr2</use>
+ <use type="external">pri</use>
+ <use type="external">ss7</use>
+ <use type="external">openr2</use>
***/
#include "asterisk.h"
@@ -9491,6 +9491,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
int features;
struct ast_str *chan_name;
struct ast_variable *v;
+ char *dashptr;
+ char device_name[AST_CHANNEL_NAME];
if (i->subs[idx].owner) {
ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
@@ -9672,7 +9674,13 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
/* Configure the new channel jb */
ast_jb_configure(tmp, &global_jbconf);
- ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
+ /* Set initial device state */
+ ast_copy_string(device_name, tmp->name, sizeof(device_name));
+ dashptr = strrchr(device_name, '-');
+ if (dashptr) {
+ *dashptr = '\0';
+ }
+ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
for (v = i->vars ; v ; v = v->next)
pbx_builtin_setvar_helper(tmp, v->name, v->value);
@@ -13933,17 +13941,22 @@ static void *mfcr2_monitor(void *data)
#endif
static void dahdi_pri_message(struct pri *pri, char *s)
{
- int x, y;
- int dchan = -1, span = -1, dchancount = 0;
+ int x;
+ int y;
+ int dchan = -1;
+ int span = -1;
+ int dchancount = 0;
if (pri) {
for (x = 0; x < NUM_SPANS; x++) {
for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
- if (pris[x].pri.dchans[y])
+ if (pris[x].pri.dchans[y]) {
dchancount++;
+ }
- if (pris[x].pri.dchans[y] == pri)
+ if (pris[x].pri.dchans[y] == pri) {
dchan = y;
+ }
}
if (dchan >= 0) {
span = x;
@@ -13951,14 +13964,18 @@ static void dahdi_pri_message(struct pri *pri, char *s)
}
dchancount = 0;
}
- if (dchancount > 1 && (span > -1))
- ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
- else if (span > -1)
- ast_verbose("%d %s", span+1, s);
- else
- ast_verbose("%s", s);
- } else
- ast_verbose("%s", s);
+ if (-1 < span) {
+ if (1 < dchancount) {
+ ast_verbose("[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
+ } else {
+ ast_verbose("PRI Span: %d %s", span + 1, s);
+ }
+ } else {
+ ast_verbose("PRI Span: ? %s", s);
+ }
+ } else {
+ ast_verbose("PRI Span: ? %s", s);
+ }
ast_mutex_lock(&pridebugfdlock);
@@ -13975,18 +13992,22 @@ static void dahdi_pri_message(struct pri *pri, char *s)
#if defined(HAVE_PRI)
static void dahdi_pri_error(struct pri *pri, char *s)
{
- int x, y;
- int dchan = -1, span = -1;
+ int x;
+ int y;
+ int dchan = -1;
+ int span = -1;
int dchancount = 0;
if (pri) {
for (x = 0; x < NUM_SPANS; x++) {
for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
- if (pris[x].pri.dchans[y])
+ if (pris[x].pri.dchans[y]) {
dchancount++;
+ }
- if (pris[x].pri.dchans[y] == pri)
+ if (pris[x].pri.dchans[y] == pri) {
dchan = y;
+ }
}
if (dchan >= 0) {
span = x;
@@ -13994,14 +14015,18 @@ static void dahdi_pri_error(struct pri *pri, char *s)
}
dchancount = 0;
}
- if ((dchancount > 1) && (span > -1))
- ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
- else if (span > -1)
- ast_log(LOG_ERROR, "%d %s", span+1, s);
- else
- ast_log(LOG_ERROR, "%s", s);
- } else
- ast_log(LOG_ERROR, "%s", s);
+ if (-1 < span) {
+ if (1 < dchancount) {
+ ast_log(LOG_ERROR, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
+ } else {
+ ast_log(LOG_ERROR, "PRI Span: %d %s", span + 1, s);
+ }
+ } else {
+ ast_log(LOG_ERROR, "PRI Span: ? %s", s);
+ }
+ } else {
+ ast_log(LOG_ERROR, "PRI Span: ? %s", s);
+ }
ast_mutex_lock(&pridebugfdlock);
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index d8dd736e4..3b08d8ce4 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -34,7 +34,7 @@
/*** MODULEINFO
<depend>iksemel</depend>
<depend>res_jabber</depend>
- <use>openssl</use>
+ <use type="external">openssl</use>
***/
#include "asterisk.h"
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 0802474ee..9f5f32deb 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -32,7 +32,7 @@
*/
/*** MODULEINFO
- <use>crypto</use>
+ <use type="external">crypto</use>
***/
#include "asterisk.h"
@@ -5363,10 +5363,6 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat
/* these two cannot be sent, because they require a result */
errno = ENOSYS;
return -1;
- case AST_OPTION_FORMAT_READ:
- case AST_OPTION_FORMAT_WRITE:
- case AST_OPTION_MAKE_COMPATIBLE:
- return -1;
case AST_OPTION_OPRMODE:
errno = EINVAL;
return -1;
@@ -5383,7 +5379,16 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat
ast_mutex_unlock(&iaxsl[callno]);
return 0;
}
- default:
+ /* These options are sent to the other side across the network where
+ * they will be passed to whatever channel is bridged there. Don't
+ * do anything silly like pass an option that transmits pointers to
+ * memory on this machine to a remote machine to use */
+ case AST_OPTION_TONE_VERIFY:
+ case AST_OPTION_TDD:
+ case AST_OPTION_RELAXDTMF:
+ case AST_OPTION_AUDIO_MODE:
+ case AST_OPTION_DIGIT_DETECT:
+ case AST_OPTION_FAX_DETECT:
{
unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
struct chan_iax2_pvt *pvt;
@@ -5411,7 +5416,12 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat
ast_free(h);
return res;
}
+ default:
+ return -1;
}
+
+ /* Just in case someone does a break instead of a return */
+ return -1;
}
static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *datalen)
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
index d0a027c3d..53b1a85e4 100644
--- a/channels/chan_jingle.c
+++ b/channels/chan_jingle.c
@@ -30,7 +30,7 @@
/*** MODULEINFO
<depend>iksemel</depend>
<depend>res_jabber</depend>
- <use>openssl</use>
+ <use type="external">openssl</use>
***/
#include "asterisk.h"
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 293a2c1fe..bd92fe9b0 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -30,7 +30,7 @@
*/
/*** MODULEINFO
- <use>res_pktccops</use>
+ <use type="module">res_pktccops</use>
***/
#include "asterisk.h"
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4c0e2a66c..18eba2371 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -162,7 +162,7 @@
*/
/*** MODULEINFO
- <use>res_crypto</use>
+ <use type="module">res_crypto</use>
<depend>chan_local</depend>
***/
@@ -1121,9 +1121,10 @@ static void temp_pvt_cleanup(void *);
/*! \brief A per-thread temporary pvt structure */
AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
-/*! \brief Authentication list for realm authentication
- * \todo Move the sip_auth list to AST_LIST */
-static struct sip_auth *authl = NULL;
+/*! \brief Authentication container for realm authentication */
+static struct sip_auth_container *authl = NULL;
+/*! \brief Global authentication container protection while adjusting the references. */
+AST_MUTEX_DEFINE_STATIC(authl_lock);
/* --- Sockets and networking --------------*/
@@ -1230,8 +1231,8 @@ static int get_address_family_filter(const struct ast_sockaddr *addr);
/*--- Transmitting responses and requests */
static int sipsock_read(int *id, int fd, short events, void *ignore);
-static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len);
-static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod);
+static int __sip_xmit(struct sip_pvt *p, struct ast_str *data);
+static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int fatal, int sipmethod);
static void add_cc_call_info_to_response(struct sip_pvt *p, struct sip_request *resp);
static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static int retrans_pkt(const void *data);
@@ -1329,13 +1330,11 @@ static int add_sip_domain(const char *domain, const enum domain_mode mode, const
static void clear_sip_domains(void);
/*--- SIP realm authentication */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno);
-static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
+static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno);
+static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm);
/*--- Misc functions */
static void check_rtp_timeout(struct sip_pvt *dialog, time_t t);
-static int sip_do_reload(enum channelreloadreason reason);
static int reload_config(enum channelreloadreason reason);
static int expire_register(const void *data);
static void *do_monitor(void *data);
@@ -1471,7 +1470,7 @@ static int method_match(enum sipmethod id, const char *name);
static void parse_copy(struct sip_request *dst, const struct sip_request *src);
static const char *find_alias(const char *name, const char *_default);
static const char *__get_header(const struct sip_request *req, const char *name, int *start);
-static int lws2sws(char *msgbuf, int len);
+static void lws2sws(struct ast_str *msgbuf);
static void extract_uri(struct sip_pvt *p, struct sip_request *req);
static char *remove_uri_parameters(char *uri);
static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
@@ -1549,7 +1548,6 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest
static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
-static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
/*------ SRTP Support -------- */
@@ -2639,7 +2637,7 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
req.socket.fd = tcptls_session->fd;
/* Read in headers one line at a time */
- while (req.len < 4 || strncmp(REQ_OFFSET_TO_STR(&req, len - 4), "\r\n\r\n", 4)) {
+ while (ast_str_strlen(req.data) < 4 || strncmp(REQ_OFFSET_TO_STR(&req, data->used - 4), "\r\n\r\n", 4)) {
if (!tcptls_session->client && !authenticated ) {
if ((timeout = sip_check_authtimeout(start)) < 0) {
goto cleanup;
@@ -2686,7 +2684,6 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
goto cleanup;
}
ast_str_append(&req.data, 0, "%s", buf);
- req.len = req.data->used;
}
copy_request(&reqcpy, &req);
parse_request(&reqcpy);
@@ -2739,7 +2736,6 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
}
cl -= strlen(buf);
ast_str_append(&req.data, 0, "%s", buf);
- req.len = req.data->used;
}
}
/*! \todo XXX If there's no Content-Length or if the content-length and what
@@ -3342,13 +3338,18 @@ static inline const char *get_transport_pvt(struct sip_pvt *p)
return get_transport(p->socket.type);
}
-/*! \brief Transmit SIP message
- Sends a SIP request or response on a given socket (in the pvt)
- Called by retrans_pkt, send_request, send_response and
- __sip_reliable_xmit
- \return length of transmitted message, XMIT_ERROR on known network failures -1 on other failures.
-*/
-static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len)
+/*!
+ * \internal
+ * \brief Transmit SIP message
+ *
+ * \details
+ * Sends a SIP request or response on a given socket (in the pvt)
+ * \note
+ * Called by retrans_pkt, send_request, send_response and __sip_reliable_xmit
+ *
+ * \return length of transmitted message, XMIT_ERROR on known network failures -1 on other failures.
+ */
+static int __sip_xmit(struct sip_pvt *p, struct ast_str *data)
{
int res = 0;
const struct ast_sockaddr *dst = sip_real_dst(p);
@@ -3360,9 +3361,9 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len)
}
if (p->socket.type == SIP_TRANSPORT_UDP) {
- res = ast_sendto(p->socket.fd, data->str, len, 0, dst);
+ res = ast_sendto(p->socket.fd, data->str, ast_str_strlen(data), 0, dst);
} else if (p->socket.tcptls_session) {
- res = sip_tcptls_write(p->socket.tcptls_session, data->str, len);
+ res = sip_tcptls_write(p->socket.tcptls_session, data->str, ast_str_strlen(data));
} else {
ast_debug(2, "Socket type is TCP but no tcptls_session is present to write to\n");
return XMIT_ERROR;
@@ -3378,8 +3379,8 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len)
res = XMIT_ERROR; /* Don't bother with trying to transmit again */
}
}
- if (res != len) {
- ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_sockaddr_stringify(dst), res, strerror(errno));
+ if (res != ast_str_strlen(data)) {
+ ast_log(LOG_WARNING, "sip_xmit of %p (len %zu) to %s returned %d: %s\n", data, ast_str_strlen(data), ast_sockaddr_stringify(dst), res, strerror(errno));
}
return res;
@@ -3394,7 +3395,7 @@ static void build_via(struct sip_pvt *p)
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
snprintf(p->via, sizeof(p->via), "SIP/2.0/%s %s;branch=z9hG4bK%08x%s",
get_transport_pvt(p),
- ast_sockaddr_stringify(&p->ourip),
+ ast_sockaddr_stringify_remote(&p->ourip),
(int) p->branch, rport);
}
@@ -3626,7 +3627,7 @@ static int retrans_pkt(const void *data)
}
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data->str);
- xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
+ xmitres = __sip_xmit(pkt->owner, pkt->data);
/* If there was no error during the network transmission, schedule the next retransmission,
* but if the next retransmission is going to be beyond our timeout period, mark the packet's
@@ -3745,10 +3746,12 @@ static int retrans_pkt(const void *data)
return 0;
}
-/*! \brief Transmit packet with retransmits
- \return 0 on success, -1 on failure to allocate packet
-*/
-static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod)
+/*!
+ * \internal
+ * \brief Transmit packet with retransmits
+ * \return 0 on success, -1 on failure to allocate packet
+ */
+static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int fatal, int sipmethod)
{
struct sip_pkt *pkt = NULL;
int siptimer_a = DEFAULT_RETRANS;
@@ -3764,7 +3767,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res
/* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */
/*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */
if (!(p->socket.type & SIP_TRANSPORT_UDP)) {
- xmitres = __sip_xmit(p, data, len); /* Send packet */
+ xmitres = __sip_xmit(p, data); /* Send packet */
if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */
append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)");
return AST_FAILURE;
@@ -3777,12 +3780,11 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res
return AST_FAILURE;
}
/* copy data, add a terminator and save length */
- if (!(pkt->data = ast_str_create(len))) {
+ if (!(pkt->data = ast_str_create(ast_str_strlen(data)))) {
ast_free(pkt);
return AST_FAILURE;
}
ast_str_set(&pkt->data, 0, "%s%s", data->str, "\0");
- pkt->packetlen = len;
/* copy other parameters from the caller */
pkt->method = sipmethod;
pkt->seqno = seqno;
@@ -3812,7 +3814,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res
ast_debug(4, "*** SIP TIMER: Initializing retransmit timer on packet: Id #%d\n", pkt->retransid);
}
- xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); /* Send packet */
+ xmitres = __sip_xmit(pkt->owner, pkt->data); /* Send packet */
if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */
append_history(pkt->owner, "XmitErr", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)");
@@ -4097,7 +4099,6 @@ static void add_blank(struct sip_request *req)
if (!req->lines) {
/* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */
ast_str_append(&req->data, 0, "\r\n");
- req->len = ast_str_strlen(req->data);
}
}
@@ -4170,8 +4171,8 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
}
res = (reliable) ?
- __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
- __sip_xmit(p, req->data, req->len);
+ __sip_reliable_xmit(p, seqno, 1, req->data, (reliable == XMIT_CRITICAL), req->method) :
+ __sip_xmit(p, req->data);
deinit_req(req);
if (res > 0) {
return 0;
@@ -4179,9 +4180,11 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
return res;
}
-/*! \brief Send SIP Request to the other part of the dialogue
- \return see \ref __sip_xmit
-*/
+/*!
+ * \internal
+ * \brief Send SIP Request to the other part of the dialogue
+ * \return see \ref __sip_xmit
+ */
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
{
int res;
@@ -4209,8 +4212,8 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
deinit_req(&tmp);
}
res = (reliable) ?
- __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
- __sip_xmit(p, req->data, req->len);
+ __sip_reliable_xmit(p, seqno, 0, req->data, (reliable == XMIT_CRITICAL), req->method) :
+ __sip_xmit(p, req->data);
deinit_req(req);
return res;
}
@@ -4438,8 +4441,11 @@ static const char *sip_get_callid(struct ast_channel *chan)
return chan->tech_pvt ? ((struct sip_pvt *) chan->tech_pvt)->callid : "";
}
-/*! \brief Send SIP MESSAGE text within a call
- Called from PBX core sendtext() application */
+/*!
+ * \internal
+ * \brief Send SIP MESSAGE text within a call
+ * \note Called from PBX core sendtext() application
+ */
static int sip_sendtext(struct ast_channel *ast, const char *text)
{
struct sip_pvt *dialog = ast->tech_pvt;
@@ -4609,8 +4615,10 @@ static void sip_destroy_peer(struct sip_peer *peer)
ast_debug(3, "-REALTIME- peer Destroyed. Name: %s. Realtime Peer objects: %d\n", peer->name, rpeerobjs);
} else
ast_atomic_fetchadd_int(&speerobjs, -1);
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
+ if (peer->auth) {
+ ao2_t_ref(peer->auth, -1, "Removing peer authentication");
+ peer->auth = NULL;
+ }
if (peer->dnsmgr)
ast_dnsmgr_release(peer->dnsmgr);
clear_peer_mailboxes(peer);
@@ -5111,6 +5119,8 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
*/
static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
{
+ struct sip_auth_container *credentials;
+
/* this checks that the dialog is contacting the peer on a valid
* transport type based on the peers transport configuration,
* otherwise, this function bails out */
@@ -5199,12 +5209,26 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
dialog->allowtransfer = peer->allowtransfer;
dialog->jointnoncodeccapability = dialog->noncodeccapability;
dialog->rtptimeout = peer->rtptimeout;
- dialog->peerauth = peer->auth;
+
+ /* Update dialog authorization credentials */
+ ao2_lock(peer);
+ credentials = peer->auth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for dialog");
+ }
+ ao2_unlock(peer);
+ ao2_lock(dialog);
+ if (dialog->peerauth) {
+ ao2_t_ref(dialog->peerauth, -1, "Unref old dialog peer auth");
+ }
+ dialog->peerauth = credentials;
+ ao2_unlock(dialog);
+
dialog->maxcallbitrate = peer->maxcallbitrate;
dialog->disallowed_methods = peer->disallowed_methods;
ast_cc_copy_config_params(dialog->cc_params, peer->cc_params);
if (ast_strlen_zero(dialog->tohost))
- ast_string_field_set(dialog, tohost, ast_sockaddr_stringify_host(&dialog->sa));
+ ast_string_field_set(dialog, tohost, ast_sockaddr_stringify_host_remote(&dialog->sa));
if (!ast_strlen_zero(peer->fromdomain)) {
ast_string_field_set(dialog, fromdomain, peer->fromdomain);
if (!dialog->initreq.headers) {
@@ -5464,7 +5488,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
return -1;
}
- if (p->trtp && !p->vsrtp && setup_srtp(&p->tsrtp) < 0) {
+ if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) {
ast_log(LOG_WARNING, "SRTP text setup failed\n");
return -1;
}
@@ -5726,6 +5750,12 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
ao2_ref(p->socket.tcptls_session, -1);
p->socket.tcptls_session = NULL;
}
+
+ if (p->peerauth) {
+ ao2_t_ref(p->peerauth, -1, "Removing active peer authentication");
+ p->peerauth = NULL;
+ }
+
p->caps = ast_format_cap_destroy(p->caps);
p->jointcaps = ast_format_cap_destroy(p->jointcaps);
p->peercaps = ast_format_cap_destroy(p->peercaps);
@@ -7350,7 +7380,7 @@ static char *generate_uri(struct sip_pvt *pvt, char *buf, size_t size)
* use the handy random string generation function we already have
*/
ast_str_append(&uri, 0, "%s", generate_random_string(buf, size));
- ast_str_append(&uri, 0, "@%s", ast_sockaddr_stringify(&pvt->ourip));
+ ast_str_append(&uri, 0, "@%s", ast_sockaddr_stringify_remote(&pvt->ourip));
ast_copy_string(buf, ast_str_buffer(uri), size);
return buf;
}
@@ -7360,7 +7390,7 @@ static void build_callid_pvt(struct sip_pvt *pvt)
{
char buf[33];
- const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify(&pvt->ourip));
+ const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify_remote(&pvt->ourip));
ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
@@ -7371,7 +7401,7 @@ static void build_callid_registry(struct sip_registry *reg, const struct ast_soc
{
char buf[33];
- const char *host = S_OR(fromdomain, ast_sockaddr_stringify_host(ourip));
+ const char *host = S_OR(fromdomain, ast_sockaddr_stringify_host_remote(ourip));
ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
}
@@ -8291,8 +8321,10 @@ static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_requ
/*! \brief Parse multiline SIP headers into one header
This is enabled if pedanticsipchecking is enabled */
-static int lws2sws(char *msgbuf, int len)
+static void lws2sws(struct ast_str *data)
{
+ char *msgbuf = data->str;
+ int len = ast_str_strlen(data);
int h = 0, t = 0;
int lws = 0;
@@ -8332,7 +8364,7 @@ static int lws2sws(char *msgbuf, int len)
lws = 0;
}
msgbuf[t] = '\0';
- return t;
+ data->used = t;
}
/*! \brief Parse a SIP message
@@ -8708,11 +8740,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
memset(p->offered_media, 0, sizeof(p->offered_media));
-
- /* default: novideo and notext set */
- p->novideo = TRUE;
- p->notext = TRUE;
-
if (p->vrtp) {
ast_rtp_codecs_payloads_clear(&newvideortp, NULL);
}
@@ -8770,7 +8797,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_debug(3, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED.");
}
-
+ /* default: novideo and notext set */
+ p->novideo = TRUE;
+ p->notext = TRUE;
/* Scan media stream (m=) specific parameters loop */
while (!ast_strlen_zero(nextm)) {
@@ -8789,8 +8818,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
nextm = get_sdp_iterate(&next, req, "m");
/* Search for audio media definition */
- if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
- (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) {
+ if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0 && x) ||
+ (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0 && x)) {
if (!strcmp(protocol, "SAVP")) {
secure_audio = 1;
} else if (strcmp(protocol, "AVP")) {
@@ -8817,8 +8846,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec);
}
/* Search for video media definition */
- } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
- (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len >= 0)) {
+ } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0 && x) ||
+ (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len >= 0 && x)) {
if (!strcmp(protocol, "SAVP")) {
secure_video = 1;
} else if (strcmp(protocol, "AVP")) {
@@ -8845,8 +8874,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec);
}
/* Search for text media definition */
- } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) {
+ } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0 && x) ||
+ (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0 && x)) {
text = TRUE;
p->notext = FALSE;
p->offered_media[SDP_TEXT].offered = TRUE;
@@ -8867,8 +8896,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
}
/* Search for image media definition */
- } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) ||
- (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0) )) {
+ } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0 && x) ||
+ (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0 && x) )) {
image = TRUE;
if (debug)
ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
@@ -9707,9 +9736,8 @@ static int add_header(struct sip_request *req, const char *var, const char *valu
}
ast_str_append(&req->data, 0, "%s: %s\r\n", var, value);
- req->header[req->headers] = req->len;
+ req->header[req->headers] = ast_str_strlen(req->data);
- req->len = ast_str_strlen(req->data);
req->headers++;
return 0;
@@ -9743,7 +9771,6 @@ static int finalize_content(struct sip_request *req)
if (ast_str_strlen(req->content)) {
ast_str_append(&req->data, 0, "\r\n%s", ast_str_buffer(req->content));
- req->len = ast_str_strlen(req->data);
}
req->lines = ast_str_strlen(req->content) ? 1 : 0;
return 0;
@@ -9839,13 +9866,13 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
/* Add rport to first VIA header if requested */
snprintf(new, sizeof(new), "%s;received=%s;rport=%d%s%s",
- leftmost, ast_sockaddr_stringify_addr(&p->recv),
+ leftmost, ast_sockaddr_stringify_addr_remote(&p->recv),
ast_sockaddr_port(&p->recv),
others ? "," : "", others ? others : "");
} else {
/* We should *always* add a received to the topmost via */
snprintf(new, sizeof(new), "%s;received=%s%s%s",
- leftmost, ast_sockaddr_stringify_addr(&p->recv),
+ leftmost, ast_sockaddr_stringify_addr_remote(&p->recv),
others ? "," : "", others ? others : "");
}
oh = new; /* the header to copy */
@@ -9981,7 +10008,6 @@ static int init_resp(struct sip_request *resp, const char *msg)
goto e_free_data;
resp->header[0] = 0;
ast_str_set(&resp->data, 0, "SIP/2.0 %s\r\n", msg);
- resp->len = resp->data->used;
resp->headers++;
return 0;
@@ -10004,7 +10030,6 @@ static int init_req(struct sip_request *req, int sipmethod, const char *recip)
req->method = sipmethod;
req->header[0] = 0;
ast_str_set(&req->data, 0, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
- req->len = ast_str_strlen(req->data);
req->headers++;
return 0;
@@ -10719,7 +10744,7 @@ static int add_rpid(struct sip_request *req, struct sip_pvt *p)
return 0;
if (ast_strlen_zero(lid_name))
lid_name = lid_num;
- fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip));
+ fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip));
lid_num = ast_uri_encode(lid_num, tmp2, sizeof(tmp2), ast_uri_sip_user);
@@ -11200,12 +11225,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
p->sessionid, p->sessionversion,
(ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ?
"IP6" : "IP4",
- ast_sockaddr_stringify_addr(&dest));
+ ast_sockaddr_stringify_addr_remote(&dest));
snprintf(connection, sizeof(connection), "c=IN %s %s\r\n",
(ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ?
"IP6" : "IP4",
- ast_sockaddr_stringify_addr(&dest));
+ ast_sockaddr_stringify_addr_remote(&dest));
if (add_audio) {
if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) {
@@ -11388,7 +11413,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
if (!ast_sockaddr_cmp(&udptldest, &dest)) {
ast_str_append(&m_modem, 0, "c=IN %s %s\r\n",
(ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ?
- "IP6" : "IP4", ast_sockaddr_stringify_addr(&udptldest));
+ "IP6" : "IP4", ast_sockaddr_stringify_addr_remote(&udptldest));
}
ast_str_append(&a_modem, 0, "a=T38FaxVersion:%d\r\n", p->t38.our_parms.version);
@@ -11743,10 +11768,10 @@ static void build_contact(struct sip_pvt *p)
if (p->socket.type == SIP_TRANSPORT_UDP) {
ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user,
- ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip));
+ ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip));
} else {
ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", user,
- ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip),
+ ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip),
get_transport(p->socket.type));
}
}
@@ -11787,7 +11812,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
- d = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip));
+ d = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip));
if (p->owner) {
if ((ast_party_id_presentation(&p->owner->connected.id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
l = p->owner->connected.id.number.valid ? p->owner->connected.id.number.str : NULL;
@@ -11951,11 +11976,11 @@ static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt)
if (!pvt->owner->redirecting.from.name.valid
|| ast_strlen_zero(diverting_name)) {
snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number,
- ast_sockaddr_stringify_host(&pvt->ourip), reason);
+ ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
} else {
snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s",
diverting_name, diverting_number,
- ast_sockaddr_stringify_host(&pvt->ourip), reason);
+ ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
}
add_header(req, "Diversion", header_text);
@@ -12582,7 +12607,7 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs,
struct sip_request req;
struct ast_str *out = ast_str_alloca(500);
int ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
- const char *domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip));
+ const char *domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip));
const char *exten = S_OR(vmexten, default_vmexten);
initreqprep(&req, p, SIP_NOTIFY, NULL);
@@ -12912,6 +12937,19 @@ static int sip_reg_timeout(const void *data)
return 0;
}
+static const char *sip_sanitized_host(const char *host)
+{
+ struct ast_sockaddr addr = { { 0, 0, }, };
+
+ /* peer/sip_pvt->tohost and sip_registry->hostname should never have a port
+ * in them, so we use PARSE_PORT_FORBID here. If this lookup fails, we return
+ * the original host which is most likely a host name and not an IP. */
+ if (!ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID)) {
+ return host;
+ }
+ return ast_sockaddr_stringify_host_remote(&addr);
+}
+
/*! \brief Transmit register to SIP proxy or UA
* auth = NULL on the initial registration (from sip_reregister())
*/
@@ -13065,19 +13103,19 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
ast_debug(1, "Scheduled a registration timeout for %s id #%d \n", r->hostname, r->timeout);
}
- snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->tag);
+ snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)), p->tag);
if (!ast_strlen_zero(p->theirtag)) {
- snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->theirtag);
+ snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)), p->theirtag);
} else {
- snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, S_OR(r->regdomain,p->tohost));
+ snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)));
}
/* Fromdomain is what we are registering to, regardless of actual
host name from SRV */
if (portno && portno != STANDARD_SIP_PORT) {
- snprintf(addr, sizeof(addr), "sip:%s:%d", S_OR(p->fromdomain,S_OR(r->regdomain,r->hostname)), portno);
+ snprintf(addr, sizeof(addr), "sip:%s:%d", S_OR(p->fromdomain,S_OR(r->regdomain, sip_sanitized_host(r->hostname))), portno);
} else {
- snprintf(addr, sizeof(addr), "sip:%s", S_OR(p->fromdomain,S_OR(r->regdomain,r->hostname)));
+ snprintf(addr, sizeof(addr), "sip:%s", S_OR(p->fromdomain,S_OR(r->regdomain, sip_sanitized_host(r->hostname))));
}
ast_string_field_set(p, uri, addr);
@@ -13151,6 +13189,7 @@ static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *ms
struct ast_msg_var_iterator *i;
const char *var, *val;
+ build_via(p);
initreqprep(&req, p, SIP_MESSAGE, NULL);
ast_string_field_set(p, msg_body, ast_msg_get_body(msg));
initialize_initreq(p, &req);
@@ -13368,7 +13407,7 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
}
-/*! \brief return the request and response heade for a 401 or 407 code */
+/*! \brief return the request and response header for a 401 or 407 code */
static void auth_headers(enum sip_auth_type code, char **header, char **respheader)
{
if (code == WWW_AUTH) { /* 401 */
@@ -16116,6 +16155,15 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
}
}
+ /* Override the context with the message context _BEFORE_
+ * getting the destination. This way we can guarantee the correct
+ * extension is used in the message context when it is present. */
+ if (!ast_strlen_zero(p->messagecontext)) {
+ ast_string_field_set(p, context, p->messagecontext);
+ } else if (!ast_strlen_zero(sip_cfg.messagecontext)) {
+ ast_string_field_set(p, context, sip_cfg.messagecontext);
+ }
+
get_destination(p, NULL, NULL);
if (!(msg = ast_msg_alloc())) {
@@ -16132,14 +16180,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
res = ast_msg_set_to(msg, "%s", to);
res |= ast_msg_set_from(msg, "%s", get_in_brackets(from));
res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf));
-
- if (!ast_strlen_zero(p->messagecontext)) {
- res |= ast_msg_set_context(msg, "%s", p->messagecontext);
- } else if (!ast_strlen_zero(sip_cfg.messagecontext)) {
- res |= ast_msg_set_context(msg, "%s", sip_cfg.messagecontext);
- } else {
- res |= ast_msg_set_context(msg, "%s", p->context);
- }
+ res |= ast_msg_set_context(msg, "%s", p->context);
if (!ast_strlen_zero(p->peername)) {
res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername);
@@ -17210,7 +17251,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
char codec_buf[512];
struct ast_codec_pref *pref;
struct ast_variable *v;
- struct sip_auth *auth;
int x = 0, load_realtime;
struct ast_format codec;
int realtimepeers;
@@ -17238,6 +17278,15 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
}
if (peer && type==0 ) { /* Normal listing */
struct ast_str *mailbox_str = ast_str_alloca(512);
+ struct sip_auth_container *credentials;
+
+ ao2_lock(peer);
+ credentials = peer->auth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for show");
+ }
+ ao2_unlock(peer);
+
ast_cli(fd, "\n\n");
ast_cli(fd, " * Name : %s\n", peer->name);
ast_cli(fd, " Description : %s\n", peer->description);
@@ -17247,9 +17296,19 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>");
ast_cli(fd, " Remote Secret: %s\n", ast_strlen_zero(peer->remotesecret)?"<Not set>":"<Set>");
- for (auth = peer->auth; auth; auth = auth->next) {
- ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username);
- ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>"));
+ if (credentials) {
+ struct sip_auth *auth;
+
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s %s\n",
+ auth->realm,
+ auth->username,
+ !ast_strlen_zero(auth->secret)
+ ? "<Secret set>"
+ : (!ast_strlen_zero(auth->md5secret)
+ ? "<MD5secret set>" : "<Not set>"));
+ }
+ ao2_t_ref(credentials, -1, "Unref peer auth for show");
}
ast_cli(fd, " Context : %s\n", peer->context);
ast_cli(fd, " Subscr.Cont. : %s\n", S_OR(peer->subscribecontext, "<Not set>") );
@@ -17339,13 +17398,13 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
ast_cli(fd, " Status : ");
peer_status(peer, status, sizeof(status));
ast_cli(fd, "%s\n", status);
- ast_cli(fd, " Useragent : %s\n", peer->useragent);
- ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact);
+ ast_cli(fd, " Useragent : %s\n", peer->useragent);
+ ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact);
ast_cli(fd, " Qualify Freq : %d ms\n", peer->qualifyfreq);
if (peer->chanvars) {
- ast_cli(fd, " Variables :\n");
+ ast_cli(fd, " Variables :\n");
for (v = peer->chanvars ; v ; v = v->next)
- ast_cli(fd, " %s = %s\n", v->name, v->value);
+ ast_cli(fd, " %s = %s\n", v->name, v->value);
}
ast_cli(fd, " Sess-Timers : %s\n", stmode2str(peer->stimer.st_mode_oper));
@@ -17439,13 +17498,13 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
astman_append(s, "Status: ");
peer_status(peer, status, sizeof(status));
astman_append(s, "%s\r\n", status);
- astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent);
- astman_append(s, "Reg-Contact: %s\r\n", peer->fullcontact);
+ astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent);
+ astman_append(s, "Reg-Contact: %s\r\n", peer->fullcontact);
astman_append(s, "QualifyFreq: %d ms\r\n", peer->qualifyfreq);
astman_append(s, "Parkinglot: %s\r\n", peer->parkinglot);
if (peer->chanvars) {
for (v = peer->chanvars ; v ; v = v->next) {
- astman_append(s, "ChanVariable: %s=%s\r\n", v->name, v->value);
+ astman_append(s, "ChanVariable: %s=%s\r\n", v->name, v->value);
}
}
astman_append(s, "SIP-Use-Reason-Header : %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON)) ? "Y" : "N");
@@ -17806,6 +17865,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
int realtimeregs;
char codec_buf[SIPBUFSIZE];
const char *msg; /* temporary msg pointer */
+ struct sip_auth_container *credentials;
switch (cmd) {
case CLI_INIT:
@@ -17818,12 +17878,19 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
return NULL;
}
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
realtimepeers = ast_check_realtime("sippeers");
realtimeregs = ast_check_realtime("sipregs");
- if (a->argc != 3)
- return CLI_SHOWUSAGE;
+ ast_mutex_lock(&authl_lock);
+ credentials = authl;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref global auth for show");
+ }
+ ast_mutex_unlock(&authl_lock);
+
ast_cli(a->fd, "\n\nGlobal Settings:\n");
ast_cli(a->fd, "----------------\n");
ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_sockaddr_stringify(&bindaddr));
@@ -17847,10 +17914,24 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, " Allow unknown access: %s\n", AST_CLI_YESNO(sip_cfg.allowguest));
ast_cli(a->fd, " Allow subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
ast_cli(a->fd, " Allow overlap dialing: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP)));
- ast_cli(a->fd, " Allow promsic. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
+ ast_cli(a->fd, " Allow promisc. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
ast_cli(a->fd, " Enable call counters: %s\n", AST_CLI_YESNO(global_callcounter));
ast_cli(a->fd, " SIP domain support: %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
- ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(authl != NULL));
+ ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(credentials != NULL));
+ if (credentials) {
+ struct sip_auth *auth;
+
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ ast_cli(a->fd, " Realm. auth entry: Realm %-15.15s User %-10.20s %s\n",
+ auth->realm,
+ auth->username,
+ !ast_strlen_zero(auth->secret)
+ ? "<Secret set>"
+ : (!ast_strlen_zero(auth->md5secret)
+ ? "<MD5secret set>" : "<Not set>"));
+ }
+ ao2_t_ref(credentials, -1, "Unref global auth for show");
+ }
ast_cli(a->fd, " Our auth realm %s\n", sip_cfg.realm);
ast_cli(a->fd, " Use domains as realms: %s\n", AST_CLI_YESNO(sip_cfg.domainsasrealm));
ast_cli(a->fd, " Call to non-local dom.: %s\n", AST_CLI_YESNO(sip_cfg.allow_external_domains));
@@ -19048,20 +19129,39 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
const char *username;
const char *secret;
const char *md5secret;
- struct sip_auth *auth = NULL; /* Realm authentication */
+ struct sip_auth *auth; /* Realm authentication credential */
+ struct sip_auth_container *credentials;
if (!ast_strlen_zero(p->domain))
ast_copy_string(uri, p->domain, sizeof(uri));
else if (!ast_strlen_zero(p->uri))
ast_copy_string(uri, p->uri, sizeof(uri));
else
- snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_sockaddr_stringify_host(&p->sa));
+ snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_sockaddr_stringify_host_remote(&p->sa));
snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random());
- /* Check if we have separate auth credentials */
- if(!(auth = find_realm_authentication(p->peerauth, p->realm))) /* Start with peer list */
- auth = find_realm_authentication(authl, p->realm); /* If not, global list */
+ /* Check if we have peer credentials */
+ ao2_lock(p);
+ credentials = p->peerauth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for digest");
+ }
+ ao2_unlock(p);
+ auth = find_realm_authentication(credentials, p->realm);
+ if (!auth) {
+ /* If not, check global credentials */
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref peer auth for digest");
+ }
+ ast_mutex_lock(&authl_lock);
+ credentials = authl;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref global auth for digest");
+ }
+ ast_mutex_unlock(&authl_lock);
+ auth = find_realm_authentication(credentials, p->realm);
+ }
if (auth) {
ast_debug(3, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username);
@@ -19075,11 +19175,16 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
username = p->authname;
secret = p->relatedpeer
&& !ast_strlen_zero(p->relatedpeer->remotesecret)
- ? p->relatedpeer->remotesecret : p->peersecret;
+ ? p->relatedpeer->remotesecret : p->peersecret;
md5secret = p->peermd5secret;
}
- if (ast_strlen_zero(username)) /* We have no authentication */
+ if (ast_strlen_zero(username)) {
+ /* We have no authentication */
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref auth for digest");
+ }
return -1;
+ }
/* Calculate SIP digest response */
snprintf(a1, sizeof(a1), "%s:%s:%s", username, p->realm, secret);
@@ -19099,7 +19204,7 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
/* only include the opaque string if it's set */
if (!ast_strlen_zero(p->opaque)) {
- snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque);
+ snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque);
}
/* XXX We hard code our qop to "auth" for now. XXX */
@@ -19110,6 +19215,9 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref auth for digest");
+ }
return 0;
}
@@ -20586,6 +20694,131 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
ref_peer(peer, "adding poke peer ref"));
}
+/*!
+ * \internal
+ * \brief Handle responses to INFO messages
+ *
+ * \note The INFO method MUST NOT change the state of calls or
+ * related sessions (RFC 2976).
+ */
+static void handle_response_info(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+{
+ int sipmethod = SIP_INFO;
+
+ switch (resp) {
+ case 401: /* Not www-authorized on SIP method */
+ case 407: /* Proxy auth required */
+ ast_log(LOG_WARNING, "Host '%s' requests authentication (%d) for '%s'\n",
+ ast_sockaddr_stringify(&p->sa), resp, sip_methods[sipmethod].text);
+ break;
+ case 405: /* Method not allowed */
+ case 501: /* Not Implemented */
+ mark_method_unallowed(&p->allowed_methods, sipmethod);
+ if (p->relatedpeer) {
+ mark_method_allowed(&p->relatedpeer->disallowed_methods, sipmethod);
+ }
+ ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n",
+ ast_sockaddr_stringify(&p->sa), sip_methods[sipmethod].text);
+ break;
+ default:
+ if (300 <= resp && resp < 700) {
+ ast_verb(3, "Got SIP %s response %d \"%s\" back from host '%s'\n",
+ sip_methods[sipmethod].text, resp, rest, ast_sockaddr_stringify(&p->sa));
+ }
+ break;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Handle auth requests to a MESSAGE request
+ * \return TRUE if authentication failed.
+ */
+static int do_message_auth(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+{
+ char *header;
+ char *respheader;
+ char digest[1024];
+
+ if (p->options) {
+ p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
+ }
+
+ if (p->authtries == MAX_AUTHTRIES) {
+ ast_log(LOG_NOTICE, "Failed to authenticate MESSAGE with host '%s'\n",
+ ast_sockaddr_stringify(&p->sa));
+ return -1;
+ }
+
+ ++p->authtries;
+ auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader);
+ memset(digest, 0, sizeof(digest));
+ if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) {
+ /* There's nothing to use for authentication */
+ ast_debug(1, "Nothing to use for MESSAGE authentication\n");
+ return -1;
+ }
+
+ if (p->do_history) {
+ append_history(p, "MessageAuth", "Try: %d", p->authtries);
+ }
+
+ transmit_message_with_text(p, p->msg_body, 0, 1);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Handle responses to MESSAGE messages
+ *
+ * \note The MESSAGE method should not change the state of calls
+ * or related sessions if associated with a dialog. (Implied by
+ * RFC 3428 Section 2).
+ */
+static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+{
+ int sipmethod = SIP_MESSAGE;
+ int in_dialog = ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
+
+ switch (resp) {
+ case 401: /* Not www-authorized on SIP method */
+ case 407: /* Proxy auth required */
+ if (do_message_auth(p, resp, rest, req, seqno) && !in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE authentication failed");
+ }
+ break;
+ case 405: /* Method not allowed */
+ case 501: /* Not Implemented */
+ mark_method_unallowed(&p->allowed_methods, sipmethod);
+ if (p->relatedpeer) {
+ mark_method_allowed(&p->relatedpeer->disallowed_methods, sipmethod);
+ }
+ ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n",
+ ast_sockaddr_stringify(&p->sa), sip_methods[sipmethod].text);
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE not implemented or allowed");
+ }
+ break;
+ default:
+ if (100 <= resp && resp < 200) {
+ /* Must allow provisional responses for out-of-dialog requests. */
+ } else if (200 <= resp && resp < 300) {
+ p->authtries = 0; /* Reset authentication counter */
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE delivery accepted");
+ }
+ } else if (300 <= resp && resp < 700) {
+ ast_verb(3, "Got SIP %s response %d \"%s\" back from host '%s'\n",
+ sip_methods[sipmethod].text, resp, rest, ast_sockaddr_stringify(&p->sa));
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, (300 <= resp && resp < 600)
+ ? "MESSAGE delivery failed" : "MESSAGE delivery refused");
+ }
+ }
+ break;
+ }
+}
+
/*! \brief Immediately stop RTP, VRTP and UDPTL as applicable */
static void stop_media_flows(struct sip_pvt *p)
{
@@ -20706,6 +20939,12 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
* we just always call the response handler. Good gravy!
*/
handle_response_publish(p, resp, rest, req, seqno);
+ } else if (sipmethod == SIP_INFO) {
+ /* More good gravy! */
+ handle_response_info(p, resp, rest, req, seqno);
+ } else if (sipmethod == SIP_MESSAGE) {
+ /* More good gravy! */
+ handle_response_message(p, resp, rest, req, seqno);
} else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
switch(resp) {
case 100: /* 100 Trying */
@@ -20719,11 +20958,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
break;
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
- if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) {
- /* We successfully transmitted a message
- or a video update request in INFO */
- /* Nothing happens here - the message is inside a dialog */
- } else if (sipmethod == SIP_INVITE) {
+ if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_NOTIFY) {
handle_response_notify(p, resp, rest, req, seqno);
@@ -20749,8 +20984,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
handle_response_register(p, resp, rest, req, seqno);
else if (sipmethod == SIP_UPDATE) {
handle_response_update(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_MESSAGE) {
- handle_response_message(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) {
if (p->options)
p->options->auth_type = resp;
@@ -20852,7 +21085,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
pvt_set_needdestroy(p, "received 491 response");
}
break;
- case 405:
+ case 405: /* Method not allowed */
case 501: /* Not Implemented */
mark_method_unallowed(&p->allowed_methods, sipmethod);
if (p->relatedpeer) {
@@ -20863,7 +21096,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
else
ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_sockaddr_stringify(&p->sa), msg);
break;
- /* Fallthrough */
default:
if ((resp >= 200) && (resp < 300)) { /* on any 2XX response do the following */
if (sipmethod == SIP_INVITE) {
@@ -20883,17 +21115,17 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
case 301: /* Moved permanently */
case 302: /* Moved temporarily */
case 305: /* Use Proxy */
- if (p->owner) {
- struct ast_party_redirecting redirecting;
- struct ast_set_party_redirecting update_redirecting;
-
- ast_party_redirecting_init(&redirecting);
- change_redirecting_information(p, req, &redirecting,
- &update_redirecting, TRUE);
- ast_channel_set_redirecting(p->owner, &redirecting,
- &update_redirecting);
- ast_party_redirecting_free(&redirecting);
- }
+ if (p->owner) {
+ struct ast_party_redirecting redirecting;
+ struct ast_set_party_redirecting update_redirecting;
+
+ ast_party_redirecting_init(&redirecting);
+ change_redirecting_information(p, req, &redirecting,
+ &update_redirecting, TRUE);
+ ast_channel_set_redirecting(p->owner, &redirecting,
+ &update_redirecting);
+ ast_party_redirecting_free(&redirecting);
+ }
/* Fall through */
case 486: /* Busy here */
case 600: /* Busy everywhere */
@@ -20922,15 +21154,14 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
break;
default:
/* Send hangup */
- if (owner && sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO && sipmethod != SIP_BYE)
+ if (owner && sipmethod != SIP_BYE)
ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR);
break;
}
/* ACK on invite */
if (sipmethod == SIP_INVITE)
transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO)
- sip_alreadygone(p);
+ sip_alreadygone(p);
if (!p->owner) {
pvt_set_needdestroy(p, "transaction completed");
}
@@ -20991,10 +21222,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
}
} else if (sipmethod == SIP_BYE) {
pvt_set_needdestroy(p, "transaction completed");
- } else if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) {
- /* We successfully transmitted a message or
- a video update request in INFO */
- ;
}
break;
case 401: /* www-auth */
@@ -23298,13 +23525,21 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
}
ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
-
- /* For blind transfers, move the call to the new extensions. For attended transfers on multiple
- servers - generate an INVITE with Replaces. Either way, let the dial plan decided */
- /* indicate before masquerade so the indication actually makes it to the real channel
- when using local channels with MOH passthru */
- ast_indicate(current.chan2, AST_CONTROL_UNHOLD);
- res = ast_async_goto(current.chan2, p->refer->refer_to_context, p->refer->refer_to, 1);
+ {
+ char *refer_to_context = ast_strdupa(p->refer->refer_to_context);
+ char *refer_to = ast_strdupa(p->refer->refer_to);
+
+ /* Do not hold the pvt lock during the indicate and async_goto. Those functions
+ * lock channels which will invalidate locking order if the pvt lock is held.*/
+ ao2_unlock(p);
+ /* For blind transfers, move the call to the new extensions. For attended transfers on multiple
+ * servers - generate an INVITE with Replaces. Either way, let the dial plan decided */
+ /* indicate before masquerade so the indication actually makes it to the real channel
+ *when using local channels with MOH passthru */
+ ast_indicate(current.chan2, AST_CONTROL_UNHOLD);
+ res = ast_async_goto(current.chan2, refer_to_context, refer_to, 1);
+ ao2_lock(p);
+ }
if (!res) {
ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans,
@@ -23397,7 +23632,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
}
else
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- if (p->initreq.len > 0) {
+ if (ast_str_strlen(p->initreq.data) > 0) {
struct sip_pkt *pkt, *prev_pkt;
/* If the CANCEL we are receiving is a retransmission, and we already have scheduled
* a reliable 487, then we don't want to schedule another one on top of the previous
@@ -23580,42 +23815,6 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
return 1;
}
-/*!
- * \internal
- * \brief Handle auth requests to a MESSAGE request
- */
-static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
-{
- char *header, *respheader;
- char digest[1024];
-
- if (p->options) {
- p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
- }
-
- if ((p->authtries == MAX_AUTHTRIES)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on MESSAGE to '%s'\n", get_header(&p->initreq, "From"));
- pvt_set_needdestroy(p, "MESSAGE authentication failed");
- return;
- }
-
- p->authtries++;
- auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader);
- memset(digest, 0, sizeof(digest));
- if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) {
- /* There's nothing to use for authentication */
- ast_debug(1, "Nothing to use for MESSAGE authentication\n");
- pvt_set_needdestroy(p, "MESSAGE authentication failed");
- return;
- }
-
- if (p->do_history) {
- append_history(p, "MessageAuth", "Try: %d", p->authtries);
- }
-
- transmit_message_with_text(p, p->msg_body, 0, 1);
-}
-
/*! \brief Handle incoming MESSAGE request */
static int handle_request_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e)
{
@@ -23654,6 +23853,8 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f
}
if (ast_strlen_zero(peer)) {
ast_log(LOG_WARNING, "MESSAGE(to) is invalid for SIP - '%s'\n", to);
+ dialog_unlink_all(pvt, TRUE, TRUE);
+ dialog_unref(pvt, "MESSAGE(to) is invalid for SIP");
return -1;
}
@@ -25015,7 +25216,6 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
return -1;
}
- req.len = res;
req.socket.fd = sipsock;
set_socket_transport(&req.socket, SIP_TRANSPORT_UDP);
req.socket.tcptls_session = NULL;
@@ -25041,7 +25241,7 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
if (sip_debug_test_addr(addr)) /* Set the debug flag early on packet level */
req->debug = 1;
if (sip_cfg.pedanticsipchecking)
- req->len = lws2sws(req->data->str, req->len); /* Fix multiline headers */
+ lws2sws(req->data); /* Fix multiline headers */
if (req->debug) {
ast_verbose("\n<--- SIP read from %s:%s --->\n%s\n<------------->\n",
get_transport(req->socket.type), ast_sockaddr_stringify(addr), req->data->str);
@@ -25065,7 +25265,7 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
/* Find the active SIP dialog or create a new one */
p = find_call(req, addr, req->method); /* returns p with a reference only. _NOT_ locked*/
if (p == NULL) {
- ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req->len);
+ ast_debug(1, "Invalid SIP message - rejected , no callid, len %zu\n", ast_str_strlen(req->data));
ast_mutex_unlock(&netlock);
return 1;
}
@@ -25296,13 +25496,14 @@ create_tcptls_session_fail:
/*!
* \brief Get cached MWI info
- * \retval 0 At least one message is waiting
- * \retval 1 no messages waiting
+ * \return TRUE if found MWI in cache
*/
static int get_cached_mwi(struct sip_peer *peer, int *new, int *old)
{
struct sip_mailbox *mailbox;
+ int in_cache;
+ in_cache = 0;
AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
struct ast_event *event;
event = ast_event_get_cached(AST_EVENT_MWI,
@@ -25314,9 +25515,10 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old)
*new += ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
*old += ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
ast_event_destroy(event);
+ in_cache = 1;
}
- return (*new || *old) ? 0 : 1;
+ return in_cache;
}
/*! \brief Send message waiting indication to alert peer that they've got voicemail */
@@ -25336,12 +25538,11 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e
if (event) {
newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
oldmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
- } else if (!cache_only) { /* Fall back to manually checking the mailbox */
+ } else if (!get_cached_mwi(peer, &newmsgs, &oldmsgs) && !cache_only) {
+ /* Fall back to manually checking the mailbox */
struct ast_str *mailbox_str = ast_str_alloca(512);
peer_mailboxes_to_str(&mailbox_str, peer);
ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs);
- } else {
- get_cached_mwi(peer, &newmsgs, &oldmsgs);
}
if (peer->mwipvt) {
@@ -25974,7 +26175,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
if (!ast_strlen_zero(peer->tohost))
ast_string_field_set(p, tohost, peer->tohost);
else
- ast_string_field_set(p, tohost, ast_sockaddr_stringify_host(&peer->addr));
+ ast_string_field_set(p, tohost, ast_sockaddr_stringify_host_remote(&peer->addr));
/* Recalculate our side, and recalculate Call ID */
ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
@@ -26605,20 +26806,48 @@ static void clear_sip_domains(void)
AST_LIST_UNLOCK(&domain_list);
}
+/*!
+ * \internal
+ * \brief Realm authentication container destructor.
+ *
+ * \param obj Container object to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_realm_authentication(void *obj)
+{
+ struct sip_auth_container *credentials = obj;
+ struct sip_auth *auth;
+
+ while ((auth = AST_LIST_REMOVE_HEAD(&credentials->list, node))) {
+ ast_free(auth);
+ }
+}
-/*! \brief Add realm authentication in list */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno)
+/*!
+ * \internal
+ * \brief Add realm authentication to credentials.
+ *
+ * \param credentials Realm authentication container to create/add authentication credentials.
+ * \param configuration Credential configuration value.
+ * \param lineno Line number in config file.
+ *
+ * \return Nothing
+ */
+static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno)
{
- char authcopy[256];
+ char *authcopy;
char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL;
- struct sip_auth *a, *b, *auth;
+ struct sip_auth *auth;
- if (ast_strlen_zero(configuration))
- return authlist;
+ if (ast_strlen_zero(configuration)) {
+ /* Nothing to add */
+ return;
+ }
ast_debug(1, "Auth config :: %s\n", configuration);
- ast_copy_string(authcopy, configuration, sizeof(authcopy));
+ authcopy = ast_strdupa(configuration);
username = authcopy;
/* split user[:secret] and relm */
@@ -26627,7 +26856,7 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons
*realm++ = '\0';
if (ast_strlen_zero(username) || ast_strlen_zero(realm)) {
ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno);
- return authlist;
+ return;
}
/* parse username at ':' for secret, or '#" for md5secret */
@@ -26637,9 +26866,21 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons
*md5secret++ = '\0';
}
- if (!(auth = ast_calloc(1, sizeof(*auth))))
- return authlist;
+ /* Create the continer if needed. */
+ if (!*credentials) {
+ *credentials = ao2_t_alloc(sizeof(**credentials), destroy_realm_authentication,
+ "Create realm auth container.");
+ if (!*credentials) {
+ /* Failed to create the credentials container. */
+ return;
+ }
+ }
+ /* Create the authentication credential entry. */
+ auth = ast_calloc(1, sizeof(*auth));
+ if (!auth) {
+ return;
+ }
ast_copy_string(auth->realm, realm, sizeof(auth->realm));
ast_copy_string(auth->username, username, sizeof(auth->username));
if (secret)
@@ -26647,46 +26888,36 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons
if (md5secret)
ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret));
- /* find the end of the list */
- for (b = NULL, a = authlist; a ; b = a, a = a->next)
- ;
- if (b)
- b->next = auth; /* Add structure add end of list */
- else
- authlist = auth;
+ /* Add credential to container list. */
+ AST_LIST_INSERT_TAIL(&(*credentials)->list, auth, node);
ast_verb(3, "Added authentication for realm %s\n", realm);
-
- return authlist;
-
-}
-
-/*! \brief Clear realm authentication list (at reload) */
-static int clear_realm_authentication(struct sip_auth *authlist)
-{
- struct sip_auth *a = authlist;
- struct sip_auth *b;
-
- while (a) {
- b = a;
- a = a->next;
- ast_free(b);
- }
-
- return 1;
}
-/*! \brief Find authentication for a specific realm */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm)
+/*!
+ * \internal
+ * \brief Find authentication for a specific realm.
+ *
+ * \param credentials Realm authentication container to search.
+ * \param realm Authentication realm to find.
+ *
+ * \return Found authentication credential or NULL.
+ */
+static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm)
{
- struct sip_auth *a;
+ struct sip_auth *auth;
- for (a = authlist; a; a = a->next) {
- if (!strcasecmp(a->realm, realm))
- break;
+ if (credentials) {
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ if (!strcasecmp(auth->realm, realm)) {
+ break;
+ }
+ }
+ } else {
+ auth = NULL;
}
- return a;
+ return auth;
}
/*! \brief
@@ -26932,8 +27163,13 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
peer->portinuri = 0;
/* If we have realm authentication information, remove them (reload) */
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
+ ao2_lock(peer);
+ if (peer->auth) {
+ ao2_t_ref(peer->auth, -1, "Removing old peer authentication");
+ peer->auth = NULL;
+ }
+ ao2_unlock(peer);
+
/* clear the transport information. We will detect if a default value is required after parsing the config */
peer->default_outbound_transport = 0;
peer->transports = 0;
@@ -26997,7 +27233,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
} else if (!strcasecmp(v->name, "md5secret")) {
ast_string_field_set(peer, md5secret, v->value);
} else if (!strcasecmp(v->name, "auth")) {
- peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
+ add_realm_authentication(&peer->auth, v->value, v->lineno);
} else if (!strcasecmp(v->name, "callerid")) {
char cid_name[80] = { '\0' }, cid_num[80] = { '\0' };
@@ -27609,9 +27845,13 @@ static int reload_config(enum channelreloadreason reason)
if (reason != CHANNEL_MODULE_LOAD) {
ast_debug(4, "--------------- SIP reload started\n");
- clear_realm_authentication(authl);
clear_sip_domains();
- authl = NULL;
+ ast_mutex_lock(&authl_lock);
+ if (authl) {
+ ao2_t_ref(authl, -1, "Removing old global authentication");
+ authl = NULL;
+ }
+ ast_mutex_unlock(&authl_lock);
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
@@ -28340,12 +28580,12 @@ static int reload_config(enum channelreloadreason reason)
}
/* Build list of authentication to various SIP realms, i.e. service providers */
- for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
- /* Format for authentication is auth = username:password@realm */
- if (!strcasecmp(v->name, "auth")) {
- authl = add_realm_authentication(authl, v->value, v->lineno);
+ for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
+ /* Format for authentication is auth = username:password@realm */
+ if (!strcasecmp(v->name, "auth")) {
+ add_realm_authentication(&authl, v->value, v->lineno);
}
- }
+ }
if (bindport) {
if (ast_sockaddr_port(&bindaddr)) {
@@ -28665,24 +28905,22 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
{
struct sip_pvt *p;
+ /* Lock the channel and the private safely. */
+ ast_channel_lock(chan);
p = chan->tech_pvt;
if (!p) {
+ ast_channel_unlock(chan);
return -1;
}
- /*
- * Lock both the pvt and it's owner safely.
- */
sip_pvt_lock(p);
- while (p->owner && ast_channel_trylock(p->owner)) {
- sip_pvt_unlock(p);
- usleep(1);
- sip_pvt_lock(p);
- }
-
- if (!p->owner) {
+ if (p->owner != chan) {
+ /* I suppose it could be argued that if this happens it is a bug. */
+ ast_debug(1, "The private is not owned by channel %s anymore.\n", chan->name);
sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
return 0;
}
+
if (udptl) {
ast_udptl_get_peer(udptl, &p->udptlredirip);
} else {
@@ -28701,8 +28939,8 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
}
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
- ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
return 0;
}
@@ -28809,10 +29047,21 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
struct sip_pvt *p;
int changed = 0;
+ /* Lock the channel and the private safely. */
+ ast_channel_lock(chan);
p = chan->tech_pvt;
if (!p) {
+ ast_channel_unlock(chan);
return -1;
}
+ sip_pvt_lock(p);
+ if (p->owner != chan) {
+ /* I suppose it could be argued that if this happens it is a bug. */
+ ast_debug(1, "The private is not owned by channel %s anymore.\n", chan->name);
+ sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
+ return 0;
+ }
/* Disable early RTP bridge */
if ((instance || vinstance || tinstance) &&
@@ -28821,25 +29070,10 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
return 0;
}
- /*
- * Lock both the pvt and it's owner safely.
- */
- sip_pvt_lock(p);
- while (p->owner && ast_channel_trylock(p->owner)) {
- sip_pvt_unlock(p);
- usleep(1);
- sip_pvt_lock(p);
- }
-
- if (!p->owner) {
- sip_pvt_unlock(p);
- return 0;
- }
-
if (p->alreadygone) {
/* If we're destroyed, don't bother */
- ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
return 0;
}
@@ -28847,8 +29081,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
that are known to be behind a NAT, then stop the process now
*/
if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
- ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
return 0;
}
@@ -28890,8 +29124,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
}
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
- ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
return 0;
}
@@ -29892,6 +30126,7 @@ static int load_module(void)
if (!(sip_tech.capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_FAILURE;
}
+
/* the fact that ao2_containers can't resize automatically is a major worry! */
/* if the number of objects gets above MAX_XXX_BUCKETS, things will slow down */
peers = ao2_t_container_alloc(HASH_PEER_SIZE, peer_hash_cb, peer_cmp_cb, "allocate peers");
@@ -29900,6 +30135,11 @@ static int load_module(void)
dialogs_needdestroy = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs_needdestroy");
dialogs_rtpcheck = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs for rtpchecks");
threadt = ao2_t_container_alloc(HASH_DIALOG_SIZE, threadt_hash_cb, threadt_cmp_cb, "allocate threadt table");
+ if (!peers || !peers_by_ip || !dialogs || !dialogs_needdestroy || !dialogs_rtpcheck
+ || !threadt) {
+ ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n");
+ return AST_MODULE_LOAD_FAILURE;
+ }
if (!(sip_cfg.caps = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_FAILURE;
@@ -29923,7 +30163,7 @@ static int load_module(void)
sip_reloadreason = CHANNEL_MODULE_LOAD;
can_parse_xml = sip_is_xml_parsable();
- if(reload_config(sip_reloadreason)) { /* Load the configuration from sip.conf */
+ if (reload_config(sip_reloadreason)) { /* Load the configuration from sip.conf */
return AST_MODULE_LOAD_DECLINE;
}
@@ -30133,7 +30373,12 @@ static int unload_module(void)
/* Free memory for local network address mask */
ast_free_ha(localaddr);
- clear_realm_authentication(authl);
+ ast_mutex_lock(&authl_lock);
+ if (authl) {
+ ao2_t_ref(authl, -1, "Removing global authentication");
+ authl = NULL;
+ }
+ ast_mutex_unlock(&authl_lock);
destroy_escs();
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index e8dba3067..f5cf93d2b 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -745,7 +745,6 @@ struct sip_socket {
struct sip_request {
ptrdiff_t rlPart1; /*!< Offset of the SIP Method Name or "SIP/2.0" protocol version */
ptrdiff_t rlPart2; /*!< Offset of the Request URI or Response Status */
- int len; /*!< bytes used in data[], excluding trailing null terminator. Rarely used. */
int headers; /*!< # of SIP Headers */
int method; /*!< Method of this request */
int lines; /*!< Body Content */
@@ -830,11 +829,16 @@ struct sip_history {
/*! \brief sip_auth: Credentials for authentication to other SIP services */
struct sip_auth {
+ AST_LIST_ENTRY(sip_auth) node;
char realm[AST_MAX_EXTENSION]; /*!< Realm in which these credentials are valid */
char username[256]; /*!< Username */
char secret[256]; /*!< Secret */
char md5secret[256]; /*!< MD5Secret */
- struct sip_auth *next; /*!< Next auth structure in list */
+};
+
+/*! \brief Container of SIP authentication credentials. */
+struct sip_auth_container {
+ AST_LIST_HEAD_NOLOCK(, sip_auth) list;
};
/*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
@@ -1047,7 +1051,7 @@ struct sip_pvt {
struct ast_channel *owner; /*!< Who owns us (if we have an owner) */
struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */
struct sip_notify *notify; /*!< Custom notify type */
- struct sip_auth *peerauth; /*!< Realm authentication */
+ struct sip_auth_container *peerauth;/*!< Realm authentication credentials */
int noncecount; /*!< Nonce-count */
unsigned int stalenonce:1; /*!< Marks the current nonce as responded too */
char lastmsg[256]; /*!< Last Message sent/received */
@@ -1144,7 +1148,6 @@ struct sip_pkt {
struct timeval time_sent; /*!< When pkt was sent */
int64_t retrans_stop_time; /*!< Time in ms after 'now' that retransmission must stop */
int retrans_stop; /*!< Timeout is reached, stop retransmission */
- int packetlen; /*!< Length of packet */
struct ast_str *data;
};
@@ -1211,7 +1214,7 @@ struct sip_peer {
* for incoming calls
*/
unsigned short deprecated_username:1; /*!< If it's a realtime peer, are they using the deprecated "username" instead of "defaultuser" */
- struct sip_auth *auth; /*!< Realm authentication list */
+ struct sip_auth_container *auth;/*!< Realm authentication credentials */
int amaflags; /*!< AMA Flags (for billing) */
int callingpres; /*!< Calling id presentation */
int inUse; /*!< Number of calls in use */
diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c
index 6c7031730..37d77d418 100644
--- a/channels/sip/reqresp_parser.c
+++ b/channels/sip/reqresp_parser.c
@@ -1029,14 +1029,14 @@ int get_in_brackets_full(char *tmp,char **out,char **residue)
only affects token based display-names there is no danger of brackets being in quotes */
if (first_bracket) {
parse = first_bracket;
- } else {
+ } else {
parse = tmp;
}
if ((second_bracket = strchr(parse, '>'))) {
*second_bracket++ = '\0';
if (out) {
- *out = first_bracket;
+ *out = (char *) parse;
}
if (residue) {
*residue = second_bracket;
@@ -1045,9 +1045,9 @@ int get_in_brackets_full(char *tmp,char **out,char **residue)
}
if ((first_bracket)) {
- ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
+ ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
return -1;
- }
+ }
if (out) {
*out = tmp;
@@ -1076,6 +1076,7 @@ AST_TEST_DEFINE(get_in_brackets_test)
char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
char no_name_no_brackets[] = "sip:name@host";
+ char missing_start_bracket[] = "name not in quotes sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char *uri = NULL;
switch (cmd) {
@@ -1140,6 +1141,13 @@ AST_TEST_DEFINE(get_in_brackets_test)
res = AST_TEST_FAIL;
}
+ /* Test 8, no start bracket, but with ending bracket. */
+ if (!(uri = get_in_brackets(missing_start_bracket)) || !(strcmp(uri, in_brackets))) {
+
+ ast_test_status_update(test, "Test 8 failed. %s\n", uri);
+ res = AST_TEST_FAIL;
+ }
+
return res;
}