Merge "chan_sip: option 'notifyringing' change and doc fix"
authorMark Michelson <mmichelson@digium.com>
Thu, 21 Jan 2016 21:22:53 +0000 (15:22 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Thu, 21 Jan 2016 21:22:53 +0000 (15:22 -0600)
1  2 
channels/chan_sip.c

diff --combined channels/chan_sip.c
@@@ -997,9 -997,9 +997,9 @@@ static struct ao2_container *threadt
  static struct ao2_container *peers;
  static struct ao2_container *peers_by_ip;
  
 -/*! \brief  A bogus peer, to be used when authentication should fail */
 -static struct sip_peer *bogus_peer;
 -/*! \brief  We can recognise the bogus peer by this invalid MD5 hash */
 +/*! \brief A bogus peer, to be used when authentication should fail */
 +static AO2_GLOBAL_OBJ_STATIC(g_bogus_peer);
 +/*! \brief We can recognize the bogus peer by this invalid MD5 hash */
  #define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string"
  
  /*! \brief  The register list: Other SIP proxies we register with and receive calls from */
@@@ -1399,7 -1399,6 +1399,7 @@@ static char *remove_uri_parameters(cha
  static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
  static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
  static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
 +static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req);
  static int set_address_from_contact(struct sip_pvt *pvt);
  static void check_via(struct sip_pvt *p, const struct sip_request *req);
  static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
@@@ -1710,7 -1709,6 +1710,7 @@@ static int publish_expire(const void *d
        ast_assert(esc != NULL);
  
        ao2_unlink(esc->compositor, esc_entry);
 +      esc_entry->sched_id = -1;
        ao2_ref(esc_entry, -1);
        return 0;
  }
@@@ -1743,11 -1741,6 +1743,11 @@@ static struct sip_esc_entry *create_esc
        /* Bump refcount for scheduler */
        ao2_ref(esc_entry, +1);
        esc_entry->sched_id = ast_sched_add(sched, expires_ms, publish_expire, esc_entry);
 +      if (esc_entry->sched_id == -1) {
 +              ao2_ref(esc_entry, -1);
 +              ao2_ref(esc_entry, -1);
 +              return NULL;
 +      }
  
        /* Note: This links the esc_entry into the ESC properly */
        create_new_sip_etag(esc_entry, 0);
@@@ -4757,11 -4750,6 +4757,11 @@@ static int sip_queryoption(struct ast_c
        struct sip_pvt *p = (struct sip_pvt *) ast_channel_tech_pvt(chan);
        char *cp;
  
 +      if (!p) {
 +              ast_debug(1, "Attempt to Ref a null pointer. Sip private structure is gone!\n");
 +              return -1;
 +      }
 +
        sip_pvt_lock(p);
  
        switch (option) {
@@@ -9370,9 -9358,6 +9370,9 @@@ static int sip_register(const char *val
                return -1;
        }
  
 +      reg->expire = -1;
 +      reg->timeout = -1;
 +
        if (ast_string_field_init(reg, 256)) {
                ao2_t_ref(reg, -1, "failed to string_field_init, drop reg");
                return -1;
@@@ -9446,8 -9431,6 +9446,8 @@@ static int sip_subscribe_mwi(const cha
                return -1;
        }
  
 +      mwi->resub = -1;
 +
        if (ast_string_field_init(mwi, 256)) {
                ao2_t_ref(mwi, -1, "failed to string_field_init, drop mwi");
                return -1;
        }
        ast_string_field_set(mwi, hostname, hostname);
        ast_string_field_set(mwi, mailbox, mailbox);
 -      mwi->resub = -1;
        mwi->portno = portnum;
        mwi->transport = transport;
  
@@@ -10634,11 -10618,7 +10634,11 @@@ static int process_sdp(struct sip_pvt *
        /* Setup audio address and port */
        if (p->rtp) {
                if (sa && portno > 0) {
 -                      start_ice(p->rtp, (req->method != SIP_RESPONSE) ? 0 : 1);
 +                      /* Start ICE negotiation here, only when it is response, and setting that we are conrolling agent,
 +                         as we are offerer */
 +                      if (req->method == SIP_RESPONSE) {
 +                              start_ice(p->rtp, 1);
 +                      }
                        ast_sockaddr_set_port(sa, portno);
                        ast_rtp_instance_set_remote_address(p->rtp, sa);
                        if (debug) {
@@@ -13412,11 -13392,6 +13412,11 @@@ static enum sip_result add_sdp(struct s
                if (!doing_directmedia) {
                        if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
                                add_ice_to_sdp(p->rtp, &a_audio);
 +                              /* Start ICE negotiation, and setting that we are controlled agent,
 +                                 as this is response to offer */
 +                              if (resp->method == SIP_RESPONSE) {
 +                                      start_ice(p->rtp, 0);
 +                              }
                        }
  
                        add_dtls_to_sdp(p->rtp, &a_audio);
@@@ -14655,7 -14630,7 +14655,7 @@@ static void state_notify_build_xml(stru
  
        switch (data->state) {
        case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
-               statestring = (sip_cfg.notifyringing) ? "early" : "confirmed";
+               statestring = (sip_cfg.notifyringing == NOTIFYRINGING_ENABLED) ? "early" : "confirmed";
                local_state = NOTIFY_INUSE;
                pidfstate = "busy";
                pidfnote = "Ringing";
@@@ -16136,49 -16111,6 +16136,49 @@@ static int parse_ok_contact(struct sip_
        return TRUE;
  }
  
 +/*!
 + * \brief Parses SIP reason header according to RFC3326 and sets channel's hangupcause if configured so
 + *  and header present
 + *
 + * \note This is used in BYE and CANCEL request and SIP response, but according to RFC3326 it could
 + *       appear in any request, but makes not a lot of sense in others than BYE or CANCEL.
 + *       Currently only implemented for Q.850 status codes.
 + * \retval 0 success
 + * \retval -1 on failure or if not configured
 + */
 +static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req)
 +{
 +      int ret, cause;
 +      const char *rp, *rh;
 +
 +      if (!pvt->owner) {
 +              return -1;
 +      }
 +
 +      if (!ast_test_flag(&pvt->flags[1], SIP_PAGE2_Q850_REASON) ||
 +              !(rh = sip_get_header(req, "Reason"))) {
 +              return -1;
 +      }
 +
 +      rh = ast_skip_blanks(rh);
 +      if (strncasecmp(rh, "Q.850", 5)) {
 +              return -1;
 +      }
 +
 +      ret = -1;
 +      cause = ast_channel_hangupcause(pvt->owner);
 +      rp = strstr(rh, "cause=");
 +      if (rp && sscanf(rp + 6, "%3d", &cause) == 1) {
 +              ret = 0;
 +              ast_channel_hangupcause_set(pvt->owner, cause & 0x7f);
 +              if (req->debug) {
 +                      ast_verbose("Using Reason header for cause code: %d\n",
 +                                              ast_channel_hangupcause(pvt->owner));
 +              }
 +      }
 +      return ret;
 +}
 +
  /*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
   *
   * \note This calls parse_uri which has the unexpected property that passing more
@@@ -17242,7 -17174,8 +17242,7 @@@ static enum check_auth_result register_
        /* If we don't want username disclosure, use the bogus_peer when a user
         * is not found. */
        if (!peer && sip_cfg.alwaysauthreject && sip_cfg.autocreatepeer == AUTOPEERS_DISABLED) {
 -              peer = bogus_peer;
 -              sip_ref_peer(peer, "register_verify: ref the bogus_peer");
 +              peer = ao2_t_global_obj_ref(g_bogus_peer, "register_verify: Get the bogus peer.");
        }
  
        if (!(peer && ast_apply_acl(peer->acl, addr, "SIP Peer ACL: "))) {
@@@ -18495,7 -18428,6 +18495,7 @@@ static enum check_auth_result check_pee
        enum check_auth_result res;
        int debug = sip_debug_test_addr(addr);
        struct sip_peer *peer;
 +      struct sip_peer *bogus_peer;
  
        if (sipmethod == SIP_SUBSCRIBE) {
                /* For subscribes, match on device name only; for other methods,
                /* If you do mind, we use a peer that will never authenticate.
                 * This ensures that we follow the same code path as regular
                 * auth: less chance for username disclosure. */
 -              peer = bogus_peer;
 -              sip_ref_peer(peer, "sip_ref_peer: check_peer_ok: must ref bogus_peer so unreffing it does not fail");
 +              peer = ao2_t_global_obj_ref(g_bogus_peer, "check_peer_ok: Get the bogus peer.");
 +              if (!peer) {
 +                      return AUTH_DONT_KNOW;
 +              }
 +              bogus_peer = peer;
 +      } else {
 +              bogus_peer = NULL;
        }
  
        /*  build_peer, called through sip_find_peer, is not able to check the
@@@ -21193,7 -21120,7 +21193,7 @@@ static char *sip_show_settings(struct a
        ast_cli(a->fd, "  Outbound reg. timeout:  %d secs\n", global_reg_timeout);
        ast_cli(a->fd, "  Outbound reg. attempts: %d\n", global_regattempts_max);
        ast_cli(a->fd, "  Outbound reg. retry 403:%d\n", global_reg_retry_403);
-       ast_cli(a->fd, "  Notify ringing state:   %s\n", AST_CLI_YESNO(sip_cfg.notifyringing));
+       ast_cli(a->fd, "  Notify ringing state:   %s%s\n", AST_CLI_YESNO(sip_cfg.notifyringing), sip_cfg.notifyringing == NOTIFYRINGING_NOTINUSE ? " (when not in use)" : "");
        if (sip_cfg.notifyringing) {
                ast_cli(a->fd, "    Include CID:          %s%s\n",
                                AST_CLI_YESNO(sip_cfg.notifycid),
@@@ -24170,13 -24097,27 +24170,13 @@@ static void handle_response(struct sip_
                msg = "";
  
        sipmethod = find_sip_method(msg);
 -
        owner = p->owner;
        if (owner) {
 -              const char *rp = NULL, *rh = NULL;
 -
                ast_channel_hangupcause_set(owner, 0);
 -              if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = sip_get_header(req, "Reason"))) {
 -                      rh = ast_skip_blanks(rh);
 -                      if (!strncasecmp(rh, "Q.850", 5)) {
 -                              int cause = ast_channel_hangupcause(owner);
 -                              rp = strstr(rh, "cause=");
 -                              if (rp && sscanf(rp + 6, "%30d", &cause) == 1) {
 -                                      ast_channel_hangupcause_set(owner, cause & 0x7f);
 -                                      if (req->debug)
 -                                              ast_verbose("Using Reason header for cause code: %d\n", ast_channel_hangupcause(owner));
 -                              }
 -                      }
 -              }
 -
 -              if (!ast_channel_hangupcause(owner))
 +              if (use_reason_header(p, req)) {
 +                      /* Use the SIP cause */
                        ast_channel_hangupcause_set(owner, hangup_sip2cause(resp));
 +              }
        }
  
        if (p->socket.type == AST_TRANSPORT_UDP) {
@@@ -26468,8 -26409,6 +26468,8 @@@ static int handle_request_cancel(struc
                return 0;
        }
  
 +      use_reason_header(p, req);
 +
        /* At this point, we could have cancelled the invite at the same time
           as the other side sends a CANCEL. Our final reply with error code
           might not have been received by the other side before the CANCEL
  
        stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
        if (p->owner) {
 -              sip_queue_hangup_cause(p, 0);
 +              sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
        } else {
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
        }
@@@ -26665,7 -26604,6 +26665,7 @@@ static int handle_request_bye(struct si
                stop_session_timer(p); /* Stop Session-Timer */
        }
  
 +      use_reason_header(p, req);
        if (!ast_strlen_zero(sip_get_header(req, "Also"))) {
                ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method.  Ask vendor to support REFER instead\n",
                        ast_sockaddr_stringify(&p->recv));
                                ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR);
                }
        } else if (p->owner) {
 -              sip_queue_hangup_cause(p, 0);
 +              sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
                sip_scheddestroy_final(p, DEFAULT_TRANS_TIMEOUT);
                ast_debug(3, "Received bye, issuing owner hangup\n");
        } else {
@@@ -31510,8 -31448,6 +31510,8 @@@ static int reload_config(enum channelre
        sip_cfg.peer_rtupdate = TRUE;
        global_dynamic_exclude_static = 0;      /* Exclude static peers */
        sip_cfg.tcp_enabled = FALSE;
 +      sip_cfg.websocket_enabled = TRUE;
 +      sip_cfg.websocket_write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
  
        /* Session-Timers */
        global_st_mode = SESSION_TIMER_MODE_ACCEPT;
                } else if (!strcasecmp(v->name, "directrtpsetup")) {
                        sip_cfg.directrtpsetup = ast_true(v->value);
                } else if (!strcasecmp(v->name, "notifyringing")) {
-                       sip_cfg.notifyringing = ast_true(v->value);
+                       if (!strcasecmp(v->value, "notinuse")) {
+                               sip_cfg.notifyringing = NOTIFYRINGING_NOTINUSE;
+                       } else {
+                               sip_cfg.notifyringing = ast_true(v->value) ? NOTIFYRINGING_ENABLED : NOTIFYRINGING_DISABLED;
+                       }
                } else if (!strcasecmp(v->name, "notifyhold")) {
                        sip_cfg.notifyhold = ast_true(v->value);
                } else if (!strcasecmp(v->name, "notifycid")) {
                ast_log(LOG_ERROR, "SIP TCP Server start failed. Not listening on TCP socket.\n");
        } else {
                ast_debug(2, "SIP TCP server started\n");
 +              if (sip_tcp_desc.accept_fd >= 0) {
 +                      int flags = 1;
 +                      if (setsockopt(sip_tcp_desc.accept_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) {
 +                              ast_log(LOG_ERROR, "Error enabling TCP keep-alive on sip socket: %s\n", strerror(errno));
 +                      }
 +              }
        }
  
        /* Start TLS server if needed */
                        ast_log(LOG_ERROR, "TLS Server start failed. Not listening on TLS socket.\n");
                        sip_tls_desc.tls_cfg = NULL;
                }
 +              if (sip_tls_desc.accept_fd >= 0) {
 +                      int flags = 1;
 +                      if (setsockopt(sip_tls_desc.accept_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) {
 +                              ast_log(LOG_ERROR, "Error enabling TCP keep-alive on sip socket: %s\n", strerror(errno));
 +                              sip_tls_desc.tls_cfg = NULL;
 +                      }
 +              }
        } else if (sip_tls_desc.tls_cfg->enabled) {
                sip_tls_desc.tls_cfg = NULL;
                ast_log(LOG_WARNING, "SIP TLS server did not load because of errors.\n");
@@@ -33228,7 -33155,7 +33232,7 @@@ static int sip_do_reload(enum channelre
  /*! \brief Force reload of module from cli */
  static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  {
 -      static struct sip_peer *tmp_peer, *new_peer;
 +      static struct sip_peer *new_peer;
  
        switch (cmd) {
        case CLI_INIT:
        ast_mutex_unlock(&sip_reload_lock);
        restart_monitor();
  
 -      tmp_peer = bogus_peer;
        /* Create new bogus peer possibly with new global settings. */
        if ((new_peer = temp_peer("(bogus_peer)"))) {
                ast_string_field_set(new_peer, md5secret, BOGUS_PEER_MD5SECRET);
                ast_clear_flag(&new_peer->flags[0], SIP_INSECURE);
 -              bogus_peer = new_peer;
 -              ao2_t_ref(tmp_peer, -1, "unref the old bogus_peer during reload");
 +              ao2_t_global_obj_replace_unref(g_bogus_peer, new_peer,
 +                      "Replacing the old bogus peer during reload.");
 +              ao2_t_ref(new_peer, -1, "done with new_peer");
        } else {
                ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n");
                /* You probably have bigger (memory?) issues to worry about though.. */
@@@ -34508,8 -34435,6 +34512,8 @@@ static int unload_module(void)
   */
  static int load_module(void)
  {
 +      struct sip_peer *bogus_peer;
 +
        ast_verbose("SIP channel loading...\n");
  
        if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) {
        /* Make sure the auth will always fail. */
        ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET);
        ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE);
 +      ao2_t_global_obj_replace_unref(g_bogus_peer, bogus_peer, "Set the initial bogus peer.");
 +      ao2_t_ref(bogus_peer, -1, "Module load is done with the bogus peer.");
  
        /* Prepare the version that does not require DTMF BEGIN frames.
         * We need to use tricks such as memcpy and casts because the variable
@@@ -34867,7 -34790,7 +34871,7 @@@ static int unload_module(void
                ast_debug(2, "TCP/TLS thread container did not become empty :(\n");
        }
  
 -      ao2_t_cleanup(bogus_peer, "unref the bogus_peer");
 +      ao2_t_global_obj_release(g_bogus_peer, "Release the bogus peer.");
  
        ao2_t_cleanup(peers, "unref the peers table");
        ao2_t_cleanup(peers_by_ip, "unref the peers_by_ip table");