aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c369
1 files changed, 233 insertions, 136 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index dc8e98713..2768b3a4c 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -948,13 +948,6 @@ static const struct cfsip_options {
*/
#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO"
-/*! \brief SIP Extensions we support
- \note This should be generated based on the previous array
- in combination with settings.
- \todo We should not have "timer" if it's disabled in the configuration file.
-*/
-#define SUPPORTED_EXTENSIONS "replaces, timer"
-
/*! \brief Standard SIP unsecure port for UDP and TCP from RFC 3261. DO NOT CHANGE THIS */
#define STANDARD_SIP_PORT 5060
/*! \brief Standard SIP TLS port from RFC 3261. DO NOT CHANGE THIS */
@@ -3104,6 +3097,32 @@ cleanup:
return NULL;
}
+/* this func is used with ao2_callback to unlink/delete all marked
+ peers */
+static int peer_is_marked(void *peerobj, void *arg, int flags)
+{
+ struct sip_peer *peer = peerobj;
+ return peer->the_mark ? CMP_MATCH : 0;
+}
+
+
+/* \brief Unlink all marked peers from ao2 containers */
+static void unlink_marked_peers_from_tables(void)
+{
+ ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
+ "initiating callback to remove marked peers");
+ ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
+ "initiating callback to remove marked peers");
+}
+
+/* \brief Unlink single peer from all ao2 containers */
+static void unlink_peer_from_tables(struct sip_peer *peer)
+{
+ ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
+ if (peer->addr.sin_addr.s_addr) {
+ ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
+ }
+}
/*!
* helper functions to unreference various types of objects.
@@ -3754,34 +3773,34 @@ static int retrans_pkt(const void *data)
struct sip_pkt *pkt = (struct sip_pkt *)data, *prev, *cur = NULL;
int reschedule = DEFAULT_RETRANS;
int xmitres = 0;
-
+
/* Lock channel PVT */
sip_pvt_lock(pkt->owner);
if (pkt->retrans < MAX_RETRANS) {
pkt->retrans++;
- if (!pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */
+ if (!pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */
if (sipdebug)
- ast_debug(4, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
+ ast_debug(4, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
} else {
- int siptimer_a;
-
- if (sipdebug)
- ast_debug(4, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
- if (!pkt->timer_a)
- pkt->timer_a = 2 ;
- else
- pkt->timer_a = 2 * pkt->timer_a;
-
- /* For non-invites, a maximum of 4 secs */
- siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
- if (pkt->method != SIP_INVITE && siptimer_a > 4000)
- siptimer_a = 4000;
-
- /* Reschedule re-transmit */
+ int siptimer_a;
+
+ if (sipdebug)
+ ast_debug(4, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
+ if (!pkt->timer_a)
+ pkt->timer_a = 2 ;
+ else
+ pkt->timer_a = 2 * pkt->timer_a;
+
+ /* For non-invites, a maximum of 4 secs */
+ siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
+ if (pkt->method != SIP_INVITE && siptimer_a > 4000)
+ siptimer_a = 4000;
+
+ /* Reschedule re-transmit */
reschedule = siptimer_a;
- ast_debug(4, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
- }
+ ast_debug(4, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
+ }
if (sip_debug_test_pvt(pkt->owner)) {
const struct sockaddr_in *dst = sip_real_dst(pkt->owner);
@@ -3793,12 +3812,13 @@ 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);
- sip_pvt_unlock(pkt->owner);
- if (xmitres == XMIT_ERROR)
+ if (xmitres == XMIT_ERROR) {
ast_log(LOG_WARNING, "Network error on retransmit in dialog %s\n", pkt->owner->callid);
- else
+ } else {
+ sip_pvt_unlock(pkt->owner);
return reschedule;
- }
+ }
+ }
/* Too many retries */
if (pkt->owner && pkt->method != SIP_OPTIONS && xmitres == 0) {
if (pkt->is_fatal || sipdebug) /* Tell us if it's critical or if we're debugging */
@@ -3808,13 +3828,13 @@ static int retrans_pkt(const void *data)
} else if (pkt->method == SIP_OPTIONS && sipdebug) {
ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) -- See doc/sip-retransmit.txt.\n", pkt->owner->callid);
- }
+ }
if (xmitres == XMIT_ERROR) {
ast_log(LOG_WARNING, "Transmit error :: Cancelling transmission on Call ID %s\n", pkt->owner->callid);
append_history(pkt->owner, "XmitErr", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)");
- } else
+ } else {
append_history(pkt->owner, "MaxRetries", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)");
-
+ }
pkt->retransid = -1;
if (pkt->is_fatal) {
@@ -3824,9 +3844,9 @@ static int retrans_pkt(const void *data)
sip_pvt_lock(pkt->owner);
}
- if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
+ if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
pkt->owner->owner->hangupcause = AST_CAUSE_NO_USER_RESPONSE;
-
+
if (pkt->owner->owner) {
sip_alreadygone(pkt->owner);
ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet (see doc/sip-retransmit.txt).\n", pkt->owner->callid);
@@ -3846,7 +3866,7 @@ static int retrans_pkt(const void *data)
if (pkt->method == SIP_BYE) {
/* We're not getting answers on SIP BYE's. Tear down the call anyway. */
- if (pkt->owner->owner)
+ if (pkt->owner->owner)
ast_channel_unlock(pkt->owner->owner);
append_history(pkt->owner, "ByeFailure", "Remote peer doesn't respond to bye. Destroying call anyway.");
pvt_set_needdestroy(pkt->owner, "no response to BYE");
@@ -3985,10 +4005,6 @@ static int __sip_autodestruct(const void *data)
}
}
- if (p->subscribed == MWI_NOTIFICATION)
- if (p->relatedpeer)
- p->relatedpeer = unref_peer(p->relatedpeer, "__sip_autodestruct: unref peer p->relatedpeer"); /* Remove link to peer. If it's realtime, make sure it's gone from memory) */
-
/* Reset schedule ID */
p->autokillid = -1;
@@ -6090,7 +6106,6 @@ static int sip_hangup(struct ast_channel *ast)
if (p->invitestate == INV_CALLING) {
/* We can't send anything in CALLING state */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- __sip_pretend_ack(p);
/* Do we need a timer here if we don't hear from them at all? Yes we do or else we will get hung dialogs and those are no fun. */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
append_history(p, "DELAY", "Not sending cancel, waiting for timeout");
@@ -8130,10 +8145,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
int vportno = -1; /*!< RTP Video port number */
int tportno = -1; /*!< RTP Text port number */
int udptlportno = -1; /*!< UDPTL Image port number */
- struct sockaddr_in sin; /*!< media socket address */
- struct sockaddr_in vsin; /*!< video socket address */
- struct sockaddr_in isin; /*!< image socket address */
- struct sockaddr_in tsin; /*!< text socket address */
+ struct sockaddr_in sin = { 0, }; /*!< media socket address */
+ struct sockaddr_in vsin = { 0, }; /*!< video socket address */
+ struct sockaddr_in isin = { 0, }; /*!< image socket address */
+ struct sockaddr_in tsin = { 0, }; /*!< text socket address */
/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */
int peercapability = 0, peernoncodeccapability = 0;
@@ -8648,7 +8663,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_set_write_format(p->owner, p->owner->writeformat);
}
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1)) {
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)
+ && (sin.sin_addr.s_addr || vsin.sin_addr.s_addr ||
+ isin.sin_addr.s_addr || tsin.sin_addr.s_addr)
+ && (!sendonly || sendonly == -1)) {
ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
/* Activate a re-invite */
ast_queue_frame(p->owner, &ast_null_frame);
@@ -8664,7 +8682,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
if (sip_cfg.notifyhold)
sip_peer_hold(p, FALSE);
ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */
- } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) {
+ } else if (!(sin.sin_addr.s_addr || vsin.sin_addr.s_addr ||
+ isin.sin_addr.s_addr || tsin.sin_addr.s_addr)
+ || (sendonly && sendonly != -1)) {
int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD);
ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
S_OR(p->mohsuggest, NULL),
@@ -9096,6 +9116,20 @@ static void ts_ast_rtp_destroy(void *data)
}
#endif
+/*! \brief Add "Supported" header to sip message. Since some options may
+ * be disabled in the config, the sip_pvt must be inspected to determine what
+ * is supported for this dialog. */
+static int add_supported_header(struct sip_pvt *pvt, struct sip_request *req)
+{
+ int res;
+ if (st_get_mode(pvt) != SESSION_TIMER_MODE_REFUSE) {
+ res = add_header(req, "Supported", "replaces, timer");
+ } else {
+ res = add_header(req, "Supported", "replaces");
+ }
+ return res;
+}
+
/*! \brief Add header to SIP message */
static int add_header(struct sip_request *req, const char *var, const char *value)
{
@@ -9507,14 +9541,13 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
if (!ast_strlen_zero(global_useragent))
add_header(resp, "Server", global_useragent);
add_header(resp, "Allow", ALLOWED_METHODS);
- add_header(resp, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, resp);
/* If this is an invite, add Session-Timers related headers if the feature is active for this session */
if (p->method == SIP_INVITE && p->stimer && p->stimer->st_active == TRUE && p->stimer->st_active_peer_ua == TRUE) {
char se_hdr[256];
snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval,
strefresher2str(p->stimer->st_ref));
- add_header(resp, "Require", "timer");
add_header(resp, "Session-Expires", se_hdr);
}
@@ -10607,7 +10640,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if (sipdebug) {
if (oldsdp == TRUE)
add_header(&req, "X-asterisk-Info", "SIP re-invite (Session-Timers)");
@@ -10983,7 +11016,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
}
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if(p->notify_headers) {
char buf[512];
@@ -11315,27 +11348,36 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
int need = strlen(caller->cid.cid_num) + strlen(p->fromdomain) + sizeof("sip:@");
local_target = alloca(need);
snprintf(local_target, need, "sip:%s@%s", caller->cid.cid_num, p->fromdomain);
- local_display = ast_strdupa(caller->cid.cid_name);
+ if (!(ast_strlen_zero(caller->cid.cid_name))) {
+ local_display = ast_strdupa(caller->cid.cid_name);
+ }
ast_channel_unlock(caller);
caller = NULL;
}
+ /* We create a fake call-id which the phone will send back in an INVITE
+ * Replaces header which we can grab and do some magic with. */
+ if (sip_cfg.pedanticsipchecking) {
+ ast_str_append(&tmp, 0, "<dialog id=\"%s\" call-id=\"pickup-%s\" local-tag=\"%s\" remote-tag=\"%s\" direction=\"recipient\">\n",
+ p->exten, p->callid, p->theirtag, p->tag);
+ } else {
+ ast_str_append(&tmp, 0, "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n",
+ p->exten, p->callid);
+ }
+ ast_str_append(&tmp, 0,
+ "<remote>\n"
+ /* See the limitations of this above. Luckily the phone seems to still be
+ happy when these values are not correct. */
+ "<identity display=\"%s\">%s</identity>\n"
+ "<target uri=\"%s\"/>\n"
+ "</remote>\n"
+ "<local>\n"
+ "<identity>%s</identity>\n"
+ "<target uri=\"%s\"/>\n"
+ "</local>\n",
+ local_display, local_target, local_target, mto, mto);
+ } else {
+ ast_str_append(&tmp, 0, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
}
-
- /* We create a fake call-id which the phone will send back in an INVITE
- Replaces header which we can grab and do some magic with. */
- ast_str_append(&tmp, 0,
- "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n"
- "<remote>\n"
- /* See the limitations of this above. Luckily the phone seems to still be
- happy when these values are not correct. */
- "<identity display=\"%s\">%s</identity>\n"
- "<target uri=\"%s\"/>\n"
- "</remote>\n"
- "<local>\n"
- "<identity>%s</identity>\n"
- "<target uri=\"%s\"/>\n"
- "</local>\n",
- p->exten, p->callid, local_display, local_target, local_target, mto, mto);
} else {
ast_str_append(&tmp, 0, "<dialog id=\"%s\">\n", p->exten);
}
@@ -11424,7 +11466,7 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
add_header(&req, "Subscription-state", terminate ? "terminated;reason=noresource" : "active");
add_header(&req, "Content-Type", "message/sipfrag;version=2.0");
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
add_content(&req, tmp);
@@ -11976,7 +12018,7 @@ static int transmit_refer(struct sip_pvt *p, const char *dest)
add_header(&req, "Refer-To", referto);
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if (!ast_strlen_zero(p->our_contact))
add_header(&req, "Referred-By", p->our_contact);
@@ -12114,7 +12156,6 @@ static int expire_register(const void *data)
peer->expire = -1;
peer->portinuri = 0;
- memset(&peer->addr, 0, sizeof(peer->addr));
destroy_association(peer); /* remove registration data from storage */
set_socket_transport(&peer->socket, peer->default_outbound_transport);
@@ -12136,12 +12177,13 @@ static int expire_register(const void *data)
if (peer->selfdestruct ||
ast_test_flag(&peer->flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
- ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
- if (peer->addr.sin_addr.s_addr) {
- ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
- }
+ unlink_peer_from_tables(peer);
}
+ /* Only clear the addr after we check for destruction. The addr must remain
+ * in order to unlink from the peers_by_ip container correctly */
+ memset(&peer->addr, 0, sizeof(peer->addr));
+
unref_peer(peer, "removing peer ref for expire_register");
return 0;
@@ -15131,14 +15173,6 @@ static int dialog_needdestroy(void *dialogobj, void *arg, int flags)
return 0;
}
-/* this func is used with ao2_callback to unlink/delete all marked
- peers */
-static int peer_is_marked(void *peerobj, void *arg, int flags)
-{
- struct sip_peer *peer = peerobj;
- return peer->the_mark ? CMP_MATCH : 0;
-}
-
/*! \brief Remove temporary realtime objects from memory (CLI) */
/*! \todo XXXX Propably needs an overhaul after removal of the devices */
static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -15241,8 +15275,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
}
ao2_iterator_destroy(&i);
if (pruned) {
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "initiating callback to remove marked peers");
+ unlink_marked_peers_from_tables();
ast_cli(a->fd, "%d peers pruned.\n", pruned);
} else
ast_cli(a->fd, "No peers found to prune.\n");
@@ -17642,7 +17675,11 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
}
}
-/*! \brief Check pending actions on SIP call */
+/*! \brief Check pending actions on SIP call
+ *
+ * \note both sip_pvt and sip_pvt's owner channel (if present)
+ * must be locked for this function.
+ */
static void check_pendings(struct sip_pvt *p)
{
if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
@@ -17657,6 +17694,9 @@ static void check_pendings(struct sip_pvt *p)
if (p->pendinginvite)
return;
+ if (p->owner) {
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ }
/* Perhaps there is an SD change INVITE outstanding */
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
}
@@ -17682,12 +17722,21 @@ static void check_pendings(struct sip_pvt *p)
static int sip_reinvite_retry(const void *data)
{
struct sip_pvt *p = (struct sip_pvt *) data;
+ struct ast_channel *owner;
sip_pvt_lock(p); /* called from schedule thread which requires a lock */
+ while ((owner = p->owner) && ast_channel_trylock(owner)) {
+ sip_pvt_unlock(p);
+ usleep(1);
+ sip_pvt_lock(p);
+ }
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
p->waitid = -1;
check_pendings(p);
sip_pvt_unlock(p);
+ if (owner) {
+ ast_channel_unlock(owner);
+ }
dialog_unref(p, "unref the dialog ptr from sip_reinvite_retry, because it held a dialog ptr");
return 0;
}
@@ -17840,7 +17889,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
/* Check for Session-Timers related headers */
if (st_get_mode(p) != SESSION_TIMER_MODE_REFUSE && p->outgoing_call == TRUE && !reinvite) {
p_hdrval = (char*)get_header(req, "Session-Expires");
- if (!ast_strlen_zero(p_hdrval)) {
+ if (!ast_strlen_zero(p_hdrval)) {
/* UAS supports Session-Timers */
enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO;
int tmp_st_interval = 0;
@@ -19970,7 +20019,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
struct sip_pvt *subscription = NULL;
replace_id += 7; /* Worst case we are looking at \0 */
- if ((subscription = get_sip_pvt_byid_locked(replace_id, NULL, NULL)) == NULL) {
+ if ((subscription = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
ast_log(LOG_NOTICE, "Unable to find subscription with call-id: %s\n", replace_id);
transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
error = 1;
@@ -20215,10 +20264,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
}
/* Session-Timers */
- if (p->sipoptions & SIP_OPT_TIMER) {
+ if ((p->sipoptions & SIP_OPT_TIMER) && !ast_strlen_zero(get_header(req, "Session-Expires"))) {
/* The UAC has requested session-timers for this session. Negotiate
the session refresh interval and who will be the refresher */
- ast_debug(2, "Incoming INVITE with 'timer' option enabled\n");
+ ast_debug(2, "Incoming INVITE with 'timer' option supported and \"Session-Expires\" header.\n");
/* Allocate Session-Timers struct w/in the dialog */
if (!p->stimer)
@@ -20226,17 +20275,15 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
/* Parse the Session-Expires header */
p_uac_se_hdr = get_header(req, "Session-Expires");
- if (!ast_strlen_zero(p_uac_se_hdr)) {
- rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref);
- if (rtn != 0) {
- transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
+ rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref);
+ if (rtn != 0) {
+ transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
+ p->invitestate = INV_COMPLETED;
+ if (!p->lastinvite) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
+ res = -1;
+ goto request_invite_cleanup;
}
/* Parse the Min-SE header */
@@ -21303,7 +21350,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
int firststate = AST_EXTENSION_REMOVED;
struct sip_peer *authpeer = NULL;
const char *eventheader = get_header(req, "Event"); /* Get Event package name */
- const char *acceptheader = get_header(req, "Accept");
int resubscribe = (p->subscribed != NONE);
char *temp, *event;
struct ao2_iterator i;
@@ -21429,51 +21475,94 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */
unsigned int pidf_xml;
+ const char *accept;
+ int start = 0;
+ enum subscriptiontype subscribed = NONE;
+ const char *unknown_acceptheader = NULL;
if (authpeer) /* We do not need the authpeer any more */
unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 2)");
/* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */
- pidf_xml = strstr(acceptheader, "application/pidf+xml") ? 1 : 0;
-
- /* Older versions of Polycom firmware will claim pidf+xml, but really
- * they only support xpidf+xml. */
- if (pidf_xml && strstr(p->useragent, "Polycom")) {
- p->subscribed = XPIDF_XML;
- } else if (pidf_xml) {
- p->subscribed = PIDF_XML; /* RFC 3863 format */
- } else if (strstr(acceptheader, "application/dialog-info+xml")) {
- p->subscribed = DIALOG_INFO_XML;
- /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
- } else if (strstr(acceptheader, "application/cpim-pidf+xml")) {
- p->subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
- } else if (strstr(acceptheader, "application/xpidf+xml")) {
- p->subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
- } else if (ast_strlen_zero(acceptheader)) {
+ accept = __get_header(req, "Accept", &start);
+ while ((subscribed == NONE) && !ast_strlen_zero(accept)) {
+ pidf_xml = strstr(accept, "application/pidf+xml") ? 1 : 0;
+
+ /* Older versions of Polycom firmware will claim pidf+xml, but really
+ * they only support xpidf+xml. */
+ if (pidf_xml && strstr(p->useragent, "Polycom")) {
+ subscribed = XPIDF_XML;
+ } else if (pidf_xml) {
+ subscribed = PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/dialog-info+xml")) {
+ subscribed = DIALOG_INFO_XML;
+ /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
+ } else if (strstr(accept, "application/cpim-pidf+xml")) {
+ subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/xpidf+xml")) {
+ subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
+ } else {
+ unknown_acceptheader = accept;
+ }
+ /* check to see if there is another Accept header present */
+ accept = __get_header(req, "Accept", &start);
+ }
+
+ if (!start) {
if (p->subscribed == NONE) { /* if the subscribed field is not already set, and there is no accept header... */
transmit_response(p, "489 Bad Event", req);
-
- ast_log(LOG_WARNING, "SUBSCRIBE failure: no Accept header: pvt: stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: no Accept header: pvt: "
+ "stateid: %d, laststate: %d, dialogver: %d, subscribecont: "
+ "'%s', subscribeuri: '%s'\n",
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
pvt_set_needdestroy(p, "no Accept header");
return 0;
}
/* if p->subscribed is non-zero, then accept is not obligatory; according to rfc 3265 section 3.1.3, at least.
so, we'll just let it ride, keeping the value from a previous subscription, and not abort the subscription */
- } else {
+ } else if (subscribed == NONE) {
/* Can't find a format for events that we know about */
char mybuf[200];
- snprintf(mybuf, sizeof(mybuf), "489 Bad Event (format %s)", acceptheader);
+ if (!ast_strlen_zero(unknown_acceptheader)) {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event (format %s)", unknown_acceptheader);
+ } else {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event");
+ }
transmit_response(p, mybuf, req);
-
- ast_log(LOG_WARNING, "SUBSCRIBE failure: unrecognized format: '%s' pvt: subscribed: %d, stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- acceptheader, (int)p->subscribed, p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: unrecognized format:"
+ "'%s' pvt: subscribed: %d, stateid: %d, laststate: %d,"
+ "dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
+ unknown_acceptheader,
+ (int)p->subscribed,
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
pvt_set_needdestroy(p, "unrecognized format");
return 0;
+ } else {
+ p->subscribed = subscribed;
+ }
+ } else if (!strcmp(event, "message-summary")) {
+ int start = 0;
+ int found_supported = 0;
+ const char *acceptheader;
+
+ acceptheader = __get_header(req, "Accept", &start);
+ while (!found_supported && !ast_strlen_zero(acceptheader)) {
+ found_supported = strcmp(acceptheader, "application/simple-message-summary") ? 0 : 1;
+ if (!found_supported && (option_debug > 2)) {
+ ast_log(LOG_DEBUG, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader);
+ }
+ acceptheader = __get_header(req, "Accept", &start);
}
- } else if (!strcmp(event, "message-summary")) {
- if (!ast_strlen_zero(acceptheader) && strcmp(acceptheader, "application/simple-message-summary")) {
+ if (start && !found_supported) {
/* Format requested that we do not support */
transmit_response(p, "406 Not Acceptable", req);
ast_debug(2, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader);
@@ -21482,6 +21571,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 3)");
return 0;
}
+
/* Looks like they actually want a mailbox status
This version of Asterisk supports mailbox subscriptions
The subscribed URI needs to exist in the dial plan
@@ -22954,7 +23044,7 @@ enum st_mode st_get_mode(struct sip_pvt *p)
static int sip_poke_noanswer(const void *data)
{
struct sip_peer *peer = (struct sip_peer *)data;
-
+
peer->pokeexpire = -1;
if (peer->lastms > -1) {
@@ -22973,12 +23063,15 @@ static int sip_poke_noanswer(const void *data)
peer->call = dialog_unref(peer->call, "unref dialog peer->call");
/* peer->call = sip_destroy(peer->call);*/
}
-
- peer->lastms = -1;
- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+
+ /* Don't send a devstate change if nothing changed. */
+ if (peer->lastms > -1) {
+ peer->lastms = -1;
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+ }
/* Try again quickly */
- AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched,
+ AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched,
DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer,
unref_peer(_data, "removing poke peer ref"),
unref_peer(peer, "removing poke peer ref"),
@@ -23772,6 +23865,8 @@ static void set_peer_defaults(struct sip_peer *peer)
peer->timer_t1 = global_t1;
peer->timer_b = global_timer_b;
clear_peer_mailboxes(peer);
+ peer->transports = default_transports;
+ peer->default_outbound_transport = default_primary_transport;
}
/*! \brief Create temporary peer (used in autocreatepeer mode) */
@@ -23914,6 +24009,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
/* If we have realm authentication information, remove them (reload) */
clear_realm_authentication(peer->auth);
peer->auth = NULL;
+ /* 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;
@@ -25145,6 +25241,8 @@ static int reload_config(enum channelreloadreason reason)
ast_netsock_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP");
}
}
+ } else {
+ ast_netsock_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP");
}
if (stunaddr.sin_addr.s_addr != 0) {
ast_debug(1, "stun to %s:%d\n",
@@ -25803,9 +25901,8 @@ static int sip_do_reload(enum channelreloadreason reason)
start_poke = time(0);
/* Prune peers who still are supposed to be deleted */
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "callback to remove marked peers");
-
+ unlink_marked_peers_from_tables();
+
ast_debug(4, "--------------- Done destroying pruned peers\n");
/* Send qualify (OPTIONS) to all peers */