]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Multiple revisions 372709,373165,373532,373652,374456
authorMatthew Jordan <mjordan@digium.com>
Fri, 2 Nov 2012 15:27:56 +0000 (15:27 +0000)
committerMatthew Jordan <mjordan@digium.com>
Fri, 2 Nov 2012 15:27:56 +0000 (15:27 +0000)
........
  r372709 | mjordan | 2012-09-08 20:19:21 -0500 (Sat, 08 Sep 2012) | 38 lines

  Only re-create an SRTP session when needed; respond with correct crypto policy

  In r356604, SRTP handling was fixed to accomodate multiple crypto keys in an
  SDP offer and the ability to re-create an SRTP session when the crypto keys
  changed.  In certain circumstances - most notably when a phone is put on
  hold after having been bridged for a significant amount of time - the act
  of re-creating the SRTP session causes problems for certain models of phones.
  The patch committed in r356604 always re-created the SRTP session regardless
  of whether or not the cryptographic keys changed.  Since this is technically
  not necessary, this patch modifies the behavior to only re-create the SRTP
  session if Asterisk detects that the remote key has changed.  This allows
  models of phones that do not handle the SRTP session changing to continue
  to work, while also providing the behavior needed for those phones that do
  re-negotiate cryptographic keys.

  In addition, in Asterisk 1.8 only, it was found that phones that offer
  AES_CM_128_HMAC_SHA1_32 will end up with no audio if the phone is the
  initiator of the call.  The phone will send an INVITE request specifying
  that AES_CM_128_HMAC_SHA1_32 be used for the cryptographic policy; Asterisk
  will set its policy to that value.  Unfortunately, when the call is Answered
  and a 200 OK is sent back to the UA, the policy sent in the response's SDP
  will be the hard coded value AES_CM_128_HMAC_SHA1_80.  This potentially
  results in Asterisk using the INVITE request's policy of
  AES_CM_128_HMAC_SHA1_32, while the phone uses Asterisk's response of
  AES_CM_128_HMAC_SHA1_80.  Hilarity ensues as both endpoints think the other
  is crazy.

  This patch fixes that by caching the policy from the request and responding
  with it.  Note that this is not a problem in Asterisk 10 and later, as the
  ability to configure the policy was added in that version.

  (issue ASTERISK-20194)
  Reported by: Nicolo Mazzon
  Tested by: Nicolo Mazzon

  Review: https://reviewboard.asterisk.org/r/2099
........
  r373165 | file | 2012-09-19 11:02:18 -0500 (Wed, 19 Sep 2012) | 10 lines

  Fix a regression where direct media was not permitted for calls using SIP INFO DTMF.

  A change was committed to fix direct media ACL support. This change wrongly assumed that
  only a single channel technology structure exists for chan_sip. This is in fact false as
  a second exists for calls using SIP INFO DTMF. The code which performs direct media ACL
  checking now checks for both the non-INFO DTMF and INFO DTMF channel technology structures.

  (closes issue ASTERISK-20409)
  Reported by: michele cicciotti privatewave
........
  r373532 | file | 2012-09-24 19:09:46 -0500 (Mon, 24 Sep 2012) | 5 lines

  Add missing checks that I neglected. The SIP technology and SIP info technology should be considered equal.

  (closes issue ASTERISK-20409)
  Reported by: michele cicciotti privatewave
........
  r373652 | twilson | 2012-09-25 12:21:19 -0500 (Tue, 25 Sep 2012) | 18 lines

  Properly handle UAC/UAS roles for SIP session timers

  The SIP session timer mechanism contains a mandatory 'refresher' parameter
  (included in the Session-Expires header) which is used in the session timer
  offer/answer signaling within a SIP Invite dialog. It looks like asterisk is
  interpreting the uac resp. uas role only as the initial role of client and
  server (caller is uac, callee is uas). The standard rfc 4028 however assigns
  the client role to the ((RE)-Invite) requester, the server role to the
  ((RE)-Invite) responder.

  This patch has Asterisk track the actual refresher as "us" or "them" as opposed
  to relying on just the configured "uas" or "uac" properties.

  (closes issue AST-922)
  Reported by: Thomas Airmont

  Review: https://reviewboard.asterisk.org/r/2118/
........
  r374456 | file | 2012-10-04 12:39:18 -0500 (Thu, 04 Oct 2012) | 14 lines

  Fix a regression from direct media ACLs where the directrtpsetup option no longer works.

  A check was added for direct media ACLs that immediately forbid remote bridging if there
  was no bridged channel. This caused directrtpsetup to no longer function as it needs this
  information before bridging actually occurs.

  Logic has now been adjusted so if there is no bridged channel a remote bridge will still
  be attempted.

  (closes issue ASTERISK-20511)
  Reported by: kristoff

  Review: https://reviewboard.asterisk.org/r/2146/
........

Merged revisions 372709,373165,373532,373652,374456 from http://svn.asterisk.org/svn/asterisk/branches/1.8

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@375590 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
channels/sip/include/sip.h
channels/sip/sdp_crypto.c
configs/sip.conf.sample

index 40fdcd2018c7269f55faf8014eec10d345ff0600..3b2359bfd5c774232d8a8131e0055876a6a7131a 100644 (file)
@@ -758,7 +758,7 @@ static int global_qualify_gap;          /*!< Time between our group of peer poke
 static int global_qualify_peers;        /*!< Number of peers to poke at a given time */
 
 static enum st_mode global_st_mode;           /*!< Mode of operation for Session-Timers           */
-static enum st_refresher global_st_refresher; /*!< Session-Timer refresher                        */
+static enum st_refresher_param global_st_refresher; /*!< Session-Timer refresher                        */
 static int global_min_se;                     /*!< Lowest threshold for session refresh interval  */
 static int global_max_se;                     /*!< Highest threshold for session refresh interval */
 
@@ -1602,8 +1602,8 @@ static int  proc_session_timer(const void *vp);
 static void stop_session_timer(struct sip_pvt *p);
 static void start_session_timer(struct sip_pvt *p);
 static void restart_session_timer(struct sip_pvt *p);
-static const char *strefresher2str(enum st_refresher r);
-static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref);
+static const char *strefresherparam2str(enum st_refresher r);
+static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref);
 static int parse_minse(const char *p_hdrval, int *const p_interval);
 static int st_get_se(struct sip_pvt *, int max);
 static enum st_refresher st_get_refresher(struct sip_pvt *);
@@ -10451,7 +10451,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
        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));
+                       p->stimer->st_ref == SESSION_TIMER_REFRESHER_US ? "uas" : "uac");
                add_header(resp, "Session-Expires", se_hdr);
        }
 
@@ -10623,7 +10623,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, ui
            && sipmethod == SIP_INVITE) {
                char se_hdr[256];
                snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval,
-                       strefresher2str(p->stimer->st_ref));
+                       p->stimer->st_ref == SESSION_TIMER_REFRESHER_US ? "uac" : "uas");
                add_header(req, "Session-Expires", se_hdr);
                snprintf(se_hdr, sizeof(se_hdr), "%d", st_get_se(p, FALSE));
                add_header(req, "Min-SE", se_hdr);
@@ -16880,23 +16880,34 @@ static enum st_mode str2stmode(const char *s)
 }
 
 /* Session-Timer Refreshers */
+static const struct _map_x_s strefresher_params[] = {
+        { SESSION_TIMER_REFRESHER_PARAM_UNKNOWN, "unknown" },
+        { SESSION_TIMER_REFRESHER_PARAM_UAC,     "uac"     },
+        { SESSION_TIMER_REFRESHER_PARAM_UAS,     "uas"     },
+        { -1,                                NULL  },
+};
+
 static const struct _map_x_s strefreshers[] = {
-        { SESSION_TIMER_REFRESHER_AUTO,     "auto"},
-        { SESSION_TIMER_REFRESHER_UAC,      "uac"},
-        { SESSION_TIMER_REFRESHER_UAS,      "uas"},
-        { -1,                               NULL},
+        { SESSION_TIMER_REFRESHER_AUTO, "auto" },
+        { SESSION_TIMER_REFRESHER_US,   "us"   },
+        { SESSION_TIMER_REFRESHER_THEM, "them" },
+        { -1,                           NULL   },
 };
 
-static const char *strefresher2str(enum st_refresher r)
+static const char *strefresherparam2str(enum st_refresher r)
 {
-       return map_x_s(strefreshers, r, "Unknown");
+       return map_x_s(strefresher_params, r, "Unknown");
 }
 
-static enum st_refresher str2strefresher(const char *s)
+static enum st_refresher str2strefresherparam(const char *s)
 {
-       return map_s_x(strefreshers, s, -1);
+       return map_s_x(strefresher_params, s, -1);
 }
 
+static const char *strefresher2str(enum st_refresher r)
+{
+       return map_x_s(strefreshers, r, "Unknown");
+}
 
 static int peer_status(struct sip_peer *peer, char *status, int statuslen)
 {
@@ -18042,7 +18053,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                }
 
                ast_cli(fd, "  Sess-Timers  : %s\n", stmode2str(peer->stimer.st_mode_oper));
-               ast_cli(fd, "  Sess-Refresh : %s\n", strefresher2str(peer->stimer.st_ref));
+               ast_cli(fd, "  Sess-Refresh : %s\n", strefresherparam2str(peer->stimer.st_ref));
                ast_cli(fd, "  Sess-Expires : %d secs\n", peer->stimer.st_max_se);
                ast_cli(fd, "  Min-Sess     : %d secs\n", peer->stimer.st_min_se);
                ast_cli(fd, "  RTP Engine   : %s\n", peer->engine);
@@ -18099,7 +18110,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
                astman_append(s, "SIP-T.38EC: %s\r\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
                astman_append(s, "SIP-T.38MaxDtgrm: %d\r\n", peer->t38_maxdatagram);
                astman_append(s, "SIP-Sess-Timers: %s\r\n", stmode2str(peer->stimer.st_mode_oper));
-               astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresher2str(peer->stimer.st_ref));
+               astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresherparam2str(peer->stimer.st_ref));
                astman_append(s, "SIP-Sess-Expires: %d\r\n", peer->stimer.st_max_se);
                astman_append(s, "SIP-Sess-Min: %d\r\n", peer->stimer.st_min_se);
                astman_append(s, "SIP-RTP-Engine: %s\r\n", peer->engine);
@@ -18239,7 +18250,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
                ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), user->cid_name, user->cid_num, "<unspecified>"));
                ast_cli(a->fd, "  ACL          : %s\n", AST_CLI_YESNO(user->ha != NULL));
                ast_cli(a->fd, "  Sess-Timers  : %s\n", stmode2str(user->stimer.st_mode_oper));
-               ast_cli(a->fd, "  Sess-Refresh : %s\n", strefresher2str(user->stimer.st_ref));
+               ast_cli(a->fd, "  Sess-Refresh : %s\n", strefresherparam2str(user->stimer.st_ref));
                ast_cli(a->fd, "  Sess-Expires : %d secs\n", user->stimer.st_max_se);
                ast_cli(a->fd, "  Sess-Min-SE  : %d secs\n", user->stimer.st_min_se);
                ast_cli(a->fd, "  RTP Engine   : %s\n", user->engine);
@@ -18682,7 +18693,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
        ast_cli(a->fd, "  Outb. proxy:            %s %s\n", ast_strlen_zero(sip_cfg.outboundproxy.name) ? "<not set>" : sip_cfg.outboundproxy.name,
                                                        sip_cfg.outboundproxy.force ? "(forced)" : "");
        ast_cli(a->fd, "  Session Timers:         %s\n", stmode2str(global_st_mode));
-       ast_cli(a->fd, "  Session Refresher:      %s\n", strefresher2str (global_st_refresher));
+       ast_cli(a->fd, "  Session Refresher:      %s\n", strefresherparam2str(global_st_refresher));
        ast_cli(a->fd, "  Session Expires:        %d secs\n", global_max_se);
        ast_cli(a->fd, "  Session Min-SE:         %d secs\n", global_min_se);
        ast_cli(a->fd, "  Timer T1:               %d\n", global_t1);
@@ -19114,7 +19125,7 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                                        ast_cli(a->fd, "  S-Timer Peer Sts:       %s\n", cur->stimer->st_active_peer_ua ? "Active" : "Inactive");
                                        ast_cli(a->fd, "  S-Timer Cached Min-SE:  %d\n", cur->stimer->st_cached_min_se);
                                        ast_cli(a->fd, "  S-Timer Cached SE:      %d\n", cur->stimer->st_cached_max_se);
-                                       ast_cli(a->fd, "  S-Timer Cached Ref:     %s\n", strefresher2str(cur->stimer->st_cached_ref));
+                                       ast_cli(a->fd, "  S-Timer Cached Ref:     %s\n", strefresherparam2str(cur->stimer->st_cached_ref));
                                        ast_cli(a->fd, "  S-Timer Cached Mode:    %s\n", stmode2str(cur->stimer->st_cached_mode));
                                }
                        }
@@ -20754,15 +20765,18 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        p_hdrval = (char*)get_header(req, "Session-Expires");
                        if (!ast_strlen_zero(p_hdrval)) {
                                /* UAS supports Session-Timers */
-                               enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO;
+                               enum st_refresher_param st_ref_param;
                                int tmp_st_interval = 0;
-                               rtn = parse_session_expires(p_hdrval, &tmp_st_interval, &tmp_st_ref);
+                               rtn = parse_session_expires(p_hdrval, &tmp_st_interval, &st_ref_param);
                                if (rtn != 0) {
                                        ast_set_flag(&p->flags[0], SIP_PENDINGBYE);     
                                }
-                               if (tmp_st_ref == SESSION_TIMER_REFRESHER_UAC ||
-                                       tmp_st_ref == SESSION_TIMER_REFRESHER_UAS) {
-                                       p->stimer->st_ref = tmp_st_ref;
+                               if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) {
+                                  p->stimer->st_ref = SESSION_TIMER_REFRESHER_US;
+                               } else if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAS) {
+                                       p->stimer->st_ref = SESSION_TIMER_REFRESHER_THEM;
+                               } else {
+                                       ast_log(LOG_WARNING, "Unknown refresher on %s\n", p->callid);
                                }
                                if (tmp_st_interval) {
                                        p->stimer->st_interval = tmp_st_interval;
@@ -20773,7 +20787,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        } else {
                                /* UAS doesn't support Session-Timers */
                                if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {
-                                       p->stimer->st_ref = SESSION_TIMER_REFRESHER_UAC;
+                                       p->stimer->st_ref = SESSION_TIMER_REFRESHER_US;
                                        p->stimer->st_active_peer_ua = FALSE;
                                        start_session_timer(p);
                                }
@@ -22787,7 +22801,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
        int uac_min_se = -1;            /* UAC's Min-SE in integer format                           */
        int st_active = FALSE;          /* Session-Timer on/off boolean                             */
        int st_interval = 0;            /* Session-Timer negotiated refresh interval                */
-       enum st_refresher st_ref;       /* Session-Timer session refresher                          */
+       enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher     */
        int dlg_min_se = -1;
        struct {
                char exten[AST_MAX_EXTENSION];
@@ -22795,7 +22809,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
        } pickup = {
                        .exten = "",
        };
-       st_ref = SESSION_TIMER_REFRESHER_AUTO;
 
        /* Find out what they support */
        if (!p->sipoptions) {
@@ -23322,6 +23335,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
 
        /* Session-Timers */
        if ((p->sipoptions & SIP_OPT_TIMER) && !ast_strlen_zero(get_header(req, "Session-Expires"))) {
+               enum st_refresher_param st_ref_param;
+
                /* 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 supported and \"Session-Expires\" header.\n");
@@ -23332,7 +23347,8 @@ 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");
-               rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref);
+               rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
+               tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
                if (rtn != 0) {
                        transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
                        p->invitestate = INV_COMPLETED;
@@ -23374,8 +23390,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
 
                        p->stimer->st_active_peer_ua = TRUE;
                        st_active = TRUE;
-                       if (st_ref == SESSION_TIMER_REFRESHER_AUTO) {
-                               st_ref = st_get_refresher(p);
+                       if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
+                               tmp_st_ref = st_get_refresher(p);
                        }
 
                        if (uac_max_se > 0) {
@@ -23416,7 +23432,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                case SESSION_TIMER_MODE_ORIGINATE:
                        st_active = TRUE;
                        st_interval = st_get_se(p, TRUE);
-                       st_ref = SESSION_TIMER_REFRESHER_UAS;
+                       tmp_st_ref = SESSION_TIMER_REFRESHER_US;
                        p->stimer->st_active_peer_ua = FALSE;
                        break;
 
@@ -23428,9 +23444,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
        if (reinvite == 0) {
                /* Session-Timers: Start session refresh timer based on negotiation/config */
                if (st_active == TRUE) {
-                       p->stimer->st_active   = TRUE;
+                       p->stimer->st_active = TRUE;
                        p->stimer->st_interval = st_interval;
-                       p->stimer->st_ref      = st_ref;
+                       p->stimer->st_ref = tmp_st_ref;
                        start_session_timer(p);
                }
        } else {
@@ -23443,7 +23459,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        /* The UAC may be adjusting the session-timers mid-session */
                        if (st_interval > 0) {
                                p->stimer->st_interval = st_interval;
-                               p->stimer->st_ref      = st_ref;
+                               p->stimer->st_ref      = tmp_st_ref;
                        }
 
                        restart_session_timer(p);
@@ -26660,7 +26676,6 @@ static void start_session_timer(struct sip_pvt *p)
 static int proc_session_timer(const void *vp)
 {
        struct sip_pvt *p = (struct sip_pvt *) vp;
-       int sendreinv = FALSE;
        int res = 0;
 
        if (!p->stimer) {
@@ -26678,23 +26693,7 @@ static int proc_session_timer(const void *vp)
                goto return_unref;
        }
 
-       switch (p->stimer->st_ref) {
-       case SESSION_TIMER_REFRESHER_UAC:
-               if (p->outgoing_call == TRUE) {
-                       sendreinv = TRUE;
-               }
-               break;
-       case SESSION_TIMER_REFRESHER_UAS:
-               if (p->outgoing_call != TRUE) {
-                       sendreinv = TRUE;
-               }
-               break;
-       default:
-               ast_log(LOG_ERROR, "Unknown session refresher %d\n", p->stimer->st_ref);
-               goto return_unref;
-       }
-
-       if (sendreinv == TRUE) {
+       if (p->stimer->st_ref == SESSION_TIMER_REFRESHER_US) {
                res = 1;
                transmit_reinvite_with_sdp(p, FALSE, TRUE);
        } else {
@@ -26761,7 +26760,7 @@ int parse_minse (const char *p_hdrval, int *const p_interval)
 
 
 /*! \brief Session-Timers: Function for parsing Session-Expires header */
-int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref)
+int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref)
 {
        char *p_token;
        int  ref_idx;
@@ -26772,7 +26771,7 @@ int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_r
                return -1;
        }
 
-       *p_ref = SESSION_TIMER_REFRESHER_AUTO;
+       *p_ref = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
        *p_interval = 0;
 
        p_se_hdr = ast_strdupa(p_hdrval);
@@ -26797,10 +26796,10 @@ int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_r
                        p_se_hdr = ast_skip_blanks(p_se_hdr);
 
                        if (!strncasecmp(p_se_hdr, "uac", strlen("uac"))) {
-                               *p_ref = SESSION_TIMER_REFRESHER_UAC;
+                               *p_ref = SESSION_TIMER_REFRESHER_PARAM_UAC;
                                ast_debug(2, "Refresher: UAC\n");
                        } else if (!strncasecmp(p_se_hdr, "uas", strlen("uas"))) {
-                               *p_ref = SESSION_TIMER_REFRESHER_UAS;
+                               *p_ref = SESSION_TIMER_REFRESHER_PARAM_UAS;
                                ast_debug(2, "Refresher: UAS\n");
                        } else {
                                ast_log(LOG_WARNING, "Invalid refresher value %s\n", p_se_hdr);
@@ -26872,20 +26871,24 @@ int st_get_se(struct sip_pvt *p, int max)
 
 
 /*! \brief Get the entity (UAC or UAS) that's acting as the session-timer refresher
+ * \note This is only called when processing an INVITE, so in that case Asterisk is
+ *       always currently the UAS. If this is ever used to process responses, the
+ *       function will have to be changed.
  * \param p pointer to the SIP dialog
 */
 enum st_refresher st_get_refresher(struct sip_pvt *p)
 {
-       if (p->stimer->st_cached_ref != SESSION_TIMER_REFRESHER_AUTO)
+       if (p->stimer->st_cached_ref != SESSION_TIMER_REFRESHER_AUTO) {
                return p->stimer->st_cached_ref;
+       }
 
        if (p->relatedpeer) {
-               p->stimer->st_cached_ref = p->relatedpeer->stimer.st_ref;
+               p->stimer->st_cached_ref = (p->relatedpeer->stimer.st_ref == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
                return p->stimer->st_cached_ref;
        }
        
-       p->stimer->st_cached_ref = global_st_refresher;
-       return global_st_refresher;
+       p->stimer->st_cached_ref = (global_st_refresher == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
+       return p->stimer->st_cached_ref;
 }
 
 
@@ -28320,7 +28323,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        peer->stimer.st_min_se = global_min_se;
                                }
                        } else if (!strcasecmp(v->name, "session-refresher")) {
-                               int i = (int) str2strefresher(v->value);
+                               int i = (int) str2strefresherparam(v->value);
                                if (i < 0) {
                                        ast_log(LOG_WARNING, "Invalid session-refresher '%s' at line %d of %s\n", v->value, v->lineno, config);
                                        peer->stimer.st_ref = global_st_refresher;
@@ -28816,7 +28819,7 @@ static int reload_config(enum channelreloadreason reason)
 
        /* Session-Timers */
        global_st_mode = SESSION_TIMER_MODE_ACCEPT;
-       global_st_refresher = SESSION_TIMER_REFRESHER_UAS;
+       global_st_refresher = SESSION_TIMER_REFRESHER_PARAM_UAS;
        global_min_se  = DEFAULT_MIN_SE;
        global_max_se  = DEFAULT_MAX_SE;
 
@@ -29311,10 +29314,10 @@ static int reload_config(enum channelreloadreason reason)
                                global_min_se = DEFAULT_MIN_SE;
                        }
                } else if (!strcasecmp(v->name, "session-refresher")) {
-                       int i = (int) str2strefresher(v->value);
+                       int i = (int) str2strefresherparam(v->value);
                        if (i < 0) {
                                ast_log(LOG_WARNING, "Invalid session-refresher '%s' at line %d of %s\n", v->value, v->lineno, config);
-                               global_st_refresher = SESSION_TIMER_REFRESHER_UAS;
+                               global_st_refresher = SESSION_TIMER_REFRESHER_PARAM_UAS;
                        } else {
                                global_st_refresher = i;
                        }
@@ -29733,7 +29736,8 @@ static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan)
 
        if (!(opp_chan = ast_bridged_channel(chan))) {
                return NULL;
-       } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) {
+       } else if (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) ||
+                  (!(opp = opp_chan->tech_pvt))) {
                return NULL;
        }
 
@@ -29809,21 +29813,22 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
-       if (!(opp_chan = ast_bridged_channel(chan))) {
-               return AST_RTP_GLUE_RESULT_FORBID;
-       } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) {
+       if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) ||
+                                                      (!(opp = opp_chan->tech_pvt)))) {
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
        sip_pvt_lock(p);
-       while (sip_pvt_trylock(opp)) {
+       while (opp && sip_pvt_trylock(opp)) {
                sip_pvt_unlock(p);
                usleep(1);
                sip_pvt_lock(p);
        }
 
        if (!(p->rtp)) {
-               sip_pvt_unlock(opp);
+               if (opp) {
+                       sip_pvt_unlock(opp);
+               }
                sip_pvt_unlock(p);
                return AST_RTP_GLUE_RESULT_FORBID;
        }
@@ -29833,7 +29838,7 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc
 
        if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
                res = AST_RTP_GLUE_RESULT_REMOTE;
-               if (!apply_directmedia_ha(p, opp, "audio")) {
+               if (opp && !apply_directmedia_ha(p, opp, "audio")) {
                        res = AST_RTP_GLUE_RESULT_FORBID;
                }
        } else if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
@@ -29842,7 +29847,9 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc
                res = AST_RTP_GLUE_RESULT_FORBID;
        }
 
-       sip_pvt_unlock(opp);
+       if (opp) {
+               sip_pvt_unlock(opp);
+       }
 
        if (p->srtp) {
                res = AST_RTP_GLUE_RESULT_FORBID;
@@ -29864,21 +29871,22 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
-       if (!(opp_chan = ast_bridged_channel(chan))) {
-               return AST_RTP_GLUE_RESULT_FORBID;
-       } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) {
+       if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) ||
+                                                      (!(opp = opp_chan->tech_pvt)))) {
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
        sip_pvt_lock(p);
-       while (sip_pvt_trylock(opp)) {
+       while (opp && sip_pvt_trylock(opp)) {
                sip_pvt_unlock(p);
                usleep(1);
                sip_pvt_lock(p);
        }
 
        if (!(p->vrtp)) {
-               sip_pvt_unlock(opp);
+               if (opp) {
+                       sip_pvt_unlock(opp);
+               }
                sip_pvt_unlock(p);
                return AST_RTP_GLUE_RESULT_FORBID;
        }
@@ -29888,12 +29896,14 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru
 
        if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
                res = AST_RTP_GLUE_RESULT_REMOTE;
-               if (!apply_directmedia_ha(p, opp, "video")) {
+               if (opp && !apply_directmedia_ha(p, opp, "video")) {
                        res = AST_RTP_GLUE_RESULT_FORBID;
                }
        }
 
-       sip_pvt_unlock(opp);
+       if (opp) {
+               sip_pvt_unlock(opp);
+       }
        sip_pvt_unlock(p);
 
        return res;
@@ -29910,21 +29920,22 @@ static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, stru
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
-       if (!(opp_chan = ast_bridged_channel(chan))) {
-               return AST_RTP_GLUE_RESULT_FORBID;
-       } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) {
+       if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) ||
+                                                      (!(opp = opp_chan->tech_pvt)))) {
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
        sip_pvt_lock(p);
-       while (sip_pvt_trylock(opp)) {
+       while (opp && sip_pvt_trylock(opp)) {
                sip_pvt_unlock(p);
                usleep(1);
                sip_pvt_lock(p);
        }
 
        if (!(p->trtp)) {
-               sip_pvt_unlock(opp);
+               if (opp) {
+                       sip_pvt_unlock(opp);
+               }
                sip_pvt_unlock(p);
                return AST_RTP_GLUE_RESULT_FORBID;
        }
@@ -29934,12 +29945,14 @@ static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, stru
 
        if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
                res = AST_RTP_GLUE_RESULT_REMOTE;
-               if (!apply_directmedia_ha(p, opp, "text")) {
+               if (opp && !apply_directmedia_ha(p, opp, "text")) {
                        res = AST_RTP_GLUE_RESULT_FORBID;
                }
        }
 
-       sip_pvt_unlock(opp);
+       if (opp) {
+               sip_pvt_unlock(opp);
+       }
        sip_pvt_unlock(p);
 
        return res;
index c1263f075daf0f07b712b178f710f7edd475b66e..ae5437fafa1463be8c19b19e56dce5c397dd38ed 100644 (file)
@@ -525,9 +525,15 @@ enum st_mode {
 
 /*! \brief The entity playing the refresher role for Session-Timers */
 enum st_refresher {
-        SESSION_TIMER_REFRESHER_AUTO,    /*!< Negotiated                      */
-        SESSION_TIMER_REFRESHER_UAC,     /*!< Session is refreshed by the UAC */
-        SESSION_TIMER_REFRESHER_UAS      /*!< Session is refreshed by the UAS */
+        SESSION_TIMER_REFRESHER_AUTO, /*!< Negotiated                      */
+        SESSION_TIMER_REFRESHER_US,   /*!< Initially prefer session refresh by Asterisk */
+        SESSION_TIMER_REFRESHER_THEM, /*!< Initially prefer session refresh by the other side */
+};
+
+enum st_refresher_param {
+       SESSION_TIMER_REFRESHER_PARAM_UNKNOWN,
+       SESSION_TIMER_REFRESHER_PARAM_UAC,
+       SESSION_TIMER_REFRESHER_PARAM_UAS,
 };
 
 /*! \brief Define some implemented SIP transports
@@ -901,14 +907,14 @@ struct sip_notify {
 struct sip_st_dlg {
        int st_active;                     /*!< Session-Timers on/off */
        int st_interval;                   /*!< Session-Timers negotiated session refresh interval */
+       enum st_refresher st_ref;          /*!< Session-Timers cached refresher */
        int st_schedid;                    /*!< Session-Timers ast_sched scheduler id */
-       enum st_refresher st_ref;          /*!< Session-Timers session refresher */
        int st_expirys;                    /*!< Session-Timers number of expirys */
        int st_active_peer_ua;             /*!< Session-Timers on/off in peer UA */
        int st_cached_min_se;              /*!< Session-Timers cached Min-SE */
        int st_cached_max_se;              /*!< Session-Timers cached Session-Expires */
        enum st_mode st_cached_mode;       /*!< Session-Timers cached M.O. */
-       enum st_refresher st_cached_ref;   /*!< Session-Timers cached refresher */
+       enum st_refresher st_cached_ref;   /*!< Session-Timers session refresher */
        unsigned char quit_flag:1;         /*!< Stop trying to lock; just quit */
 };
 
@@ -917,10 +923,10 @@ struct sip_st_dlg {
  *   of SIP Session-Timers feature on a per user/peer basis.
  */
 struct sip_st_cfg {
-       enum st_mode st_mode_oper;    /*!< Mode of operation for Session-Timers           */
-       enum st_refresher st_ref;     /*!< Session-Timer refresher                        */
-       int st_min_se;                /*!< Lowest threshold for session refresh interval  */
-       int st_max_se;                /*!< Highest threshold for session refresh interval */
+       enum st_mode st_mode_oper;      /*!< Mode of operation for Session-Timers           */
+       enum st_refresher_param st_ref; /*!< Session-Timer refresher                        */
+       int st_min_se;                  /*!< Lowest threshold for session refresh interval  */
+       int st_max_se;                  /*!< Highest threshold for session refresh interval */
 };
 
 /*! \brief Structure for remembering offered media in an INVITE, to make sure we reply
index 3a95ce9a6c127c4e71ca901e1cfe52d931f6d6bf..ea8ea64162ddd58329ef4a8ffd0a08f714038430 100644 (file)
@@ -49,6 +49,8 @@ struct sdp_crypto {
        char *a_crypto;
        unsigned char local_key[SRTP_MASTER_LEN];
        char local_key64[SRTP_MASTER_LEN64];
+       unsigned char remote_key[SRTP_MASTER_LEN];
+       char suite[64];
 };
 
 static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound);
@@ -257,12 +259,20 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in
                return -1;
        }
 
-
        if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) {
-               ast_log(LOG_WARNING, "SRTP sdescriptions key %d != %d\n", key_len, SRTP_MASTER_LEN);
+               ast_log(LOG_WARNING, "SRTP descriptions key %d != %d\n", key_len, SRTP_MASTER_LEN);
                return -1;
        }
 
+       if (!memcmp(p->remote_key, remote_key, sizeof(p->remote_key))) {
+               ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n");
+               return 0;
+       }
+
+       /* Set the accepted policy and remote key */
+       ast_copy_string(p->suite, suite, sizeof(p->suite));
+       memcpy(p->remote_key, remote_key, sizeof(p->remote_key));
+
        if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) {
                return -1;
        }
@@ -280,13 +290,17 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in
 int sdp_crypto_offer(struct sdp_crypto *p)
 {
        char crypto_buf[128];
-       const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80"; /* Crypto offer */
+
+       if (ast_strlen_zero(p->suite)) {
+               /* Default crypto offer */
+               strcpy(p->suite, "AES_CM_128_HMAC_SHA1_80");
+       }
 
        if (p->a_crypto) {
                ast_free(p->a_crypto);
        }
 
-       if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n",  crypto_suite, p->local_key64) < 1) {
+       if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n",  p->suite, p->local_key64) < 1) {
                return -1;
        }
 
index 4a1f76d1c3a25f0faac3ea8fb6772aaed17a546f..3a4a72c6905ba1e8c4de3ccbadd6b97f680dbc2b 100644 (file)
@@ -560,11 +560,20 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ; * session-expires   - Maximum session refresh interval in seconds. Defaults to 1800 secs.
 ; * session-minse     - Minimum session refresh interval in seconds. Defualts to 90 secs.
 ; * session-refresher - The session refresher (uac|uas). Defaults to 'uas'.
+;                            uac - Default to the caller initially refreshing when possible
+;                            uas - Default to the callee initially refreshing when possible
+;
+; Note that, due to recommendations in RFC 4028, Asterisk will always honor the other
+; endpoint's preference for who will handle refreshes. Asterisk will never override the
+; preferences of the other endpoint. Doing so could result in Asterisk and the endpoint
+; fighting over who sends the refreshes. This holds true for the initiation of session
+; timers and subsequent re-INVITE requests whether Asterisk is the caller or callee, or
+; whether Asterisk is currently the refresher or not.
 ;
 ;session-timers=originate
 ;session-expires=600
 ;session-minse=90
-;session-refresher=uas
+;session-refresher=uac
 ;
 ;--------------------------- SIP DEBUGGING ---------------------------------------------------
 ;sipdebug = yes                 ; Turn on SIP debugging by default, from