Merge "chan_sip: Peers with distinct source ports don't match, regardless of transport."
authorJenkins2 <jenkins2@gerrit.asterisk.org>
Wed, 21 Mar 2018 14:42:54 +0000 (09:42 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Wed, 21 Mar 2018 14:42:54 +0000 (09:42 -0500)
1  2 
channels/chan_sip.c

diff --combined channels/chan_sip.c
                                <para>At least one variable pair must be specified.
                                <replaceable>name</replaceable>=<replaceable>value</replaceable></para>
                        </parameter>
 +                      <parameter name="Call-ID" required="false">
 +                              <para>When specified, SIP notity will be sent as a part of an existing dialog.</para>
 +                      </parameter>
                </syntax>
                <description>
                        <para>Sends a SIP Notify event.</para>
@@@ -9286,7 -9283,7 +9286,7 @@@ static enum match_req_res match_req_to_
  }
  
  /*! \brief This function creates a dialog to handle a forked request.  This dialog
 - * exists only to properly terminiate the the forked request immediately.
 + * exists only to properly terminiate the forked request immediately.
   */
  static void forked_invite_init(struct sip_request *req, const char *new_theirtag, struct sip_pvt *original, struct ast_sockaddr *addr)
  {
@@@ -10964,25 -10961,22 +10964,25 @@@ static int process_sdp(struct sip_pvt *
        if (portno != -1 || vportno != -1 || tportno != -1) {
                /* We are now ready to change the sip session and RTP structures with the offered codecs, since
                   they are acceptable */
 +              unsigned int framing;
                ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
                ast_format_cap_append_from_cap(p->jointcaps, newjointcapability, AST_MEDIA_TYPE_UNKNOWN); /* Our joint codec profile for this call */
                ast_format_cap_remove_by_type(p->peercaps, AST_MEDIA_TYPE_UNKNOWN);
                ast_format_cap_append_from_cap(p->peercaps, newpeercapability, AST_MEDIA_TYPE_UNKNOWN); /* The other side's capability in latest offer */
                p->jointnoncodeccapability = newnoncodeccapability;     /* DTMF capabilities */
  
 +              tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0);
 +              framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt);
                /* respond with single most preferred joint codec, limiting the other side's choice */
                if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) {
 -                      unsigned int framing;
 -
 -                      tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0);
 -                      framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt);
                        ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
                        ast_format_cap_append(p->jointcaps, tmp_fmt, framing);
 -                      ao2_ref(tmp_fmt, -1);
                }
 +              if (!ast_rtp_codecs_get_framing(&newaudiortp)) {
 +                      /* Peer did not force us to use a specific framing, so use our own */
 +                      ast_rtp_codecs_set_framing(&newaudiortp, framing);
 +              }
 +              ao2_ref(tmp_fmt, -1);
        }
  
        /* Setup audio address and port */
@@@ -11346,7 -11340,7 +11346,7 @@@ static int process_sdp_a_ice(const cha
  {
        struct ast_rtp_engine_ice *ice;
        int found = FALSE;
 -      char ufrag[256], pwd[256], foundation[32], transport[4], address[46], cand_type[6], relay_address[46] = "";
 +      char ufrag[256], pwd[256], foundation[33], transport[4], address[46], cand_type[6], relay_address[46] = "";
        struct ast_rtp_engine_ice_candidate candidate = { 0, };
        unsigned int port, relay_port = 0;
  
        } else if (sscanf(a, "ice-pwd: %255s", pwd) == 1) {
                ice->set_authentication(instance, NULL, pwd);
                found = TRUE;
 -      } else if (sscanf(a, "candidate: %31s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, (unsigned *)&candidate.priority,
 +      } else if (sscanf(a, "candidate: %32s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, (unsigned *)&candidate.priority,
                          address, &port, cand_type, relay_address, &relay_port) >= 7) {
  
                if (rtcp_mux_offered && ast_test_flag(&p->flags[2], SIP_PAGE3_RTCP_MUX) && candidate.id > 1) {
@@@ -11491,7 -11485,6 +11491,7 @@@ static int process_sdp_a_audio(const ch
                if (framing && p->autoframing) {
                        ast_debug(1, "Setting framing to %ld\n", framing);
                        ast_format_cap_set_framing(p->caps, framing);
 +                      ast_rtp_codecs_set_framing(newaudiortp, framing);
                }
                found = TRUE;
        } else if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
@@@ -15598,13 -15591,11 +15598,13 @@@ static int manager_sipnotify(struct man
  {
        const char *channame = astman_get_header(m, "Channel");
        struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL);
 +      const char *callid = astman_get_header(m, "Call-ID");
        struct sip_pvt *p;
        struct ast_variable *header, *var;
  
        if (ast_strlen_zero(channame)) {
                astman_send_error(s, m, "SIPNotify requires a channel name");
 +              ast_variables_destroy(vars);
                return 0;
        }
  
                channame += 4;
        }
  
 -      if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL, 0))) {
 -              astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)");
 -              return 0;
 -      }
 +      /* check if Call-ID header is set */
 +      if (!ast_strlen_zero(callid)) {
 +              struct sip_pvt tmp_dialog = {
 +                      .callid = callid,
 +              };
  
 -      if (create_addr(p, channame, NULL, 0)) {
 -              /* Maybe they're not registered, etc. */
 -              dialog_unlink_all(p);
 -              dialog_unref(p, "unref dialog inside for loop" );
 -              /* sip_destroy(p); */
 -              astman_send_error(s, m, "Could not create address");
 -              return 0;
 -      }
 +              p = ao2_find(dialogs, &tmp_dialog, OBJ_SEARCH_OBJECT);
 +              if (!p) {
 +                      astman_send_error(s, m, "Call-ID not found");
 +                      ast_variables_destroy(vars);
 +                      return 0;
 +              }
  
 -      /* Notify is outgoing call */
 -      ast_set_flag(&p->flags[0], SIP_OUTGOING);
 -      sip_notify_alloc(p);
 +              if (!(p->notify)) {
 +                      sip_notify_alloc(p);
 +              } else {
 +                      ast_variables_destroy(p->notify->headers);
 +              }
 +      } else {
 +              if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL, 0))) {
 +                      astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)");
 +                      ast_variables_destroy(vars);
 +                      return 0;
 +              }
 +
 +              if (create_addr(p, channame, NULL, 0)) {
 +                      /* Maybe they're not registered, etc. */
 +                      dialog_unlink_all(p);
 +                      dialog_unref(p, "unref dialog inside for loop" );
 +                      /* sip_destroy(p); */
 +                      astman_send_error(s, m, "Could not create address");
 +                      ast_variables_destroy(vars);
 +                      return 0;
 +              }
 +
 +              /* Notify is outgoing call */
 +              ast_set_flag(&p->flags[0], SIP_OUTGOING);
 +              sip_notify_alloc(p);
 +
 +      }
  
        p->notify->headers = header = ast_variable_new("Subscription-State", "terminated", "");
  
                }
        }
  
 -      /* Now that we have the peer's address, set our ip and change callid */
 -      ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
 -      build_via(p);
 +      if (ast_strlen_zero(callid)) {
 +              /* Now that we have the peer's address, set our ip and change callid */
 +              ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
 +              build_via(p);
  
 -      change_callid_pvt(p, NULL);
 +              change_callid_pvt(p, NULL);
  
 -      sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
 -      transmit_invite(p, SIP_NOTIFY, 0, 2, NULL);
 +              sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
 +              transmit_invite(p, SIP_NOTIFY, 0, 2, NULL);
 +      } else {
 +              sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
 +              transmit_invite(p, SIP_NOTIFY, 0, 1, NULL);
 +      }
        dialog_unref(p, "bump down the count of p since we're done with it.");
  
        astman_send_ack(s, m, "Notify Sent");
@@@ -15812,7 -15775,7 +15812,7 @@@ static int sip_reregister(const void *d
        if (r->call && r->call->do_history) {
                append_history(r->call, "RegistryRenew", "Account: %s@%s", r->username, r->hostname);
        }
 -      /* Since registry's are only added/removed by the the monitor thread, this
 +      /* Since registry's are only added/removed by the monitor thread, this
           may be overkill to reference/dereference at all here */
        if (sipdebug) {
                ast_log(LOG_NOTICE, "   -- Re-registration for  %s@%s\n", r->username, r->hostname);
@@@ -22479,7 -22442,7 +22479,7 @@@ static void sip_dump_history(struct sip
                return;
        }
  
 -      if (!option_debug && !sipdebug) {
 +      if (!sipdebug && !DEBUG_ATLEAST(1)) {
                if (!errmsg) {
                        ast_log(LOG_NOTICE, "You must have debugging enabled (SIP or Asterisk) in order to dump SIP history.\n");
                        errmsg = 1;
                return;
        }
  
 -      ast_debug(1, "\n---------- SIP HISTORY for '%s' \n", dialog->callid);
 +      ast_log(LOG_DEBUG, "\n---------- SIP HISTORY for '%s' \n", dialog->callid);
        if (dialog->subscribed) {
 -              ast_debug(1, "  * Subscription\n");
 +              ast_log(LOG_DEBUG, "  * Subscription\n");
        } else {
 -              ast_debug(1, "  * SIP Call\n");
 +              ast_log(LOG_DEBUG, "  * SIP Call\n");
        }
        if (dialog->history) {
                AST_LIST_TRAVERSE(dialog->history, hist, list)
 -                      ast_debug(1, "  %-3.3d. %s\n", ++x, hist->event);
 +                      ast_log(LOG_DEBUG, "  %-3.3d. %s\n", ++x, hist->event);
        }
        if (!x) {
 -              ast_debug(1, "Call '%s' has no history\n", dialog->callid);
 +              ast_log(LOG_DEBUG, "Call '%s' has no history\n", dialog->callid);
        }
 -      ast_debug(1, "\n---------- END SIP HISTORY for '%s' \n", dialog->callid);
 +      ast_log(LOG_DEBUG, "\n---------- END SIP HISTORY for '%s' \n", dialog->callid);
  }
  
  
@@@ -23434,8 -23397,6 +23434,8 @@@ static void change_redirecting_informat
                redirecting->from.number.valid = 1;
                ast_free(redirecting->from.number.str);
                redirecting->from.number.str = redirecting_from_number;
 +      } else {
 +              ast_free(redirecting_from_number);
        }
        if (!ast_strlen_zero(redirecting_from_name)) {
                ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name);
                redirecting->from.name.valid = 1;
                ast_free(redirecting->from.name.str);
                redirecting->from.name.str = redirecting_from_name;
 +      } else {
 +              ast_free(redirecting_from_name);
        }
        if (!ast_strlen_zero(p->cid_tag)) {
                ast_free(redirecting->from.tag);
                redirecting->to.number.valid = 1;
                ast_free(redirecting->to.number.str);
                redirecting->to.number.str = redirecting_to_number;
 +      } else {
 +              ast_free(redirecting_to_number);
        }
        if (!ast_strlen_zero(redirecting_to_name)) {
 -              ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number);
 +              ast_debug(3, "Got redirecting to name %s\n", redirecting_to_name);
                update_redirecting->to.name = 1;
                redirecting->to.name.valid = 1;
                ast_free(redirecting->to.name.str);
                redirecting->to.name.str = redirecting_to_name;
 +      } else {
 +              ast_free(redirecting_to_name);
        }
        redirecting->reason.code = reason;
        ast_free(redirecting->reason.str);
@@@ -23988,9 -23943,6 +23988,9 @@@ static void handle_response_invite(stru
                        ast_queue_control(p->owner, AST_CONTROL_RINGING);
                        if (ast_channel_state(p->owner) != AST_STATE_UP) {
                                ast_setstate(p->owner, AST_STATE_RINGING);
 +                              if (p->relatedpeer) {
 +                                      ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "SIP/%s", p->relatedpeer->name);
 +                              }
                        }
                }
                if (find_sdp(req)) {
@@@ -24501,7 -24453,6 +24501,7 @@@ static void handle_response_subscribe(s
                        ast_cc_monitor_failed(monitor_instance->core_id,
                                monitor_instance->device_name,
                                "Received error response to our SUBSCRIBE");
 +                      ao2_ref(monitor_instance, -1);
                }
                return;
        }
@@@ -26354,7 -26305,7 +26354,7 @@@ static int handle_request_invite(struc
  
                if (p->owner) {
                        ast_debug(3, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid);
 -                      transmit_response_reliable(p, "400 Bad request", req);  /* The best way to not not accept the transfer */
 +                      transmit_response_reliable(p, "400 Bad request", req);  /* The best way to not accept the transfer */
                        check_via(p, req);
                        copy_request(&p->initreq, req);
                        /* Do not destroy existing call */
  
                if (replaces_pvt == p) {
                        ast_log(LOG_NOTICE, "INVITE with replaces into it's own call id (%s == %s)!\n", replace_id, p->callid);
 -                      transmit_response_reliable(p, "400 Bad request", req);  /* The best way to not not accept the transfer */
 +                      transmit_response_reliable(p, "400 Bad request", req);  /* The best way to not accept the transfer */
                        error = 1;
                }
  
                                        ast_log(LOG_NOTICE, "Call from '%s' (%s) to extension"
                                                " '%s' rejected because extension not found in context '%s'.\n",
                                                S_OR(p->username, p->peername), ast_sockaddr_stringify(&p->recv), decoded_exten, p->context);
 +                                      sip_report_failed_acl(p, "no_extension_match");
                                }
                                break;
                        case SIP_GET_DEST_REFUSED:
@@@ -27432,7 -27382,7 +27432,7 @@@ static int handle_request_cancel(struc
        } else {
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
        }
 -      if (ast_str_strlen(p->initreq.data) > 0) {
 +      if (p->initreq.data && 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
@@@ -29457,7 -29407,7 +29457,7 @@@ static int sip_prepare_socket(struct si
                return s->fd;
        }
        if ((s->type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) &&
 -                      s->tcptls_session) {
 +                      s->tcptls_session && s->tcptls_session->stream) {
                return ast_iostream_get_fd(s->tcptls_session->stream);
        }
        if ((s->type & (AST_TRANSPORT_WS | AST_TRANSPORT_WSS))) {
@@@ -30336,7 -30286,6 +30336,7 @@@ static int sip_send_keepalive(const voi
        struct sip_peer *peer = (struct sip_peer*) data;
        int res = 0;
        const char keepalive[] = "\r\n";
 +      size_t count = sizeof(keepalive) - 1;
  
        peer->keepalivesend = -1;
  
  
        /* Send the packet out using the proper method for this peer */
        if ((peer->socket.fd != -1) && (peer->socket.type == AST_TRANSPORT_UDP)) {
 -              res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr);
 +              res = ast_sendto(peer->socket.fd, keepalive, count, 0, &peer->addr);
        } else if ((peer->socket.type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) &&
                   peer->socket.tcptls_session) {
 -              res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive));
 +              res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, count);
        } else if (peer->socket.type == AST_TRANSPORT_UDP) {
 -              res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr);
 +              res = ast_sendto(sipsock, keepalive, count, 0, &peer->addr);
        }
  
        if (res == -1) {
                }
        }
  
 -      if (res != sizeof(keepalive)) {
 +      if (res != count) {
                ast_log(LOG_WARNING, "sip_send_keepalive to %s returned %d: %s\n", ast_sockaddr_stringify(&peer->addr), res, strerror(errno));
        }
  
@@@ -30766,14 -30715,6 +30766,14 @@@ static struct ast_channel *sip_request_
                }
        }
  
 +      /* If stripping the DNID left us with nothing, bail out */
 +      if (ast_strlen_zero(tmp)) {
 +              dialog_unlink_all(p);
 +              dialog_unref(p, "unref dialog p from bad destination");
 +              *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
 +              return NULL;
 +      }
 +
        /* Divvy up the items separated by slashes */
        AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
  
@@@ -34393,7 -34334,7 +34393,7 @@@ static int peer_cmp_cb(void *obj, void 
  }
  
  /*!
 - * Hash function based on the the peer's ip address.  For IPv6, we use the end
 + * Hash function based on the peer's ip address.  For IPv6, we use the end
   * of the address.
   * \todo Find a better hashing function
   */
@@@ -34451,10 -34392,9 +34451,9 @@@ static int peer_ipcmp_cb_full(void *obj
        }
  
        /* We matched the IP, check to see if we need to match by port as well. */
-       if ((peer->transports & peer2->transports) & (AST_TRANSPORT_TLS | AST_TRANSPORT_TCP)) {
-               /* peer matching on port is not possible with TCP/TLS */
-               return CMP_MATCH | CMP_STOP;
-       } else if (ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
+       if (((peer->transports & peer2->transports) &
+               (AST_TRANSPORT_UDP | AST_TRANSPORT_WS | AST_TRANSPORT_WSS)) &&
+               ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
                /* We are allowing match without port for peers configured that
                 * way in this pass through the peers. */
                return ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) ?
@@@ -35744,6 -35684,5 +35743,6 @@@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_M
        .unload = unload_module,
        .reload = reload,
        .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 -      .nonoptreq = "res_crypto,res_http_websocket",
 +      .requires = "ccss,dnsmgr,udptl",
 +      .optional_modules = "res_crypto,res_http_websocket",
  );