res_pjsip: Remove ephemeral registered contacts on transport shutdown.
[asterisk/asterisk.git] / res / res_pjsip / pjsip_configuration.c
index 00c2233..715ffe8 100644 (file)
@@ -22,6 +22,7 @@
 #include "asterisk/test.h"
 #include "asterisk/statsd.h"
 #include "asterisk/pbx.h"
+#include "asterisk/stream.h"
 
 /*! \brief Number of buckets for persistent endpoint information */
 #define PERSISTENT_BUCKETS 53
@@ -365,42 +366,29 @@ static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf)
 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
        struct ast_sip_endpoint *endpoint = obj;
+       enum ast_sip_dtmf_mode dtmf = ast_sip_str_to_dtmf(var->value);
 
-       if (!strcasecmp(var->value, "rfc4733")) {
-               endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
-       } else if (!strcasecmp(var->value, "inband")) {
-               endpoint->dtmf = AST_SIP_DTMF_INBAND;
-       } else if (!strcasecmp(var->value, "info")) {
-               endpoint->dtmf = AST_SIP_DTMF_INFO;
-       } else if (!strcasecmp(var->value, "auto")) {
-               endpoint->dtmf = AST_SIP_DTMF_AUTO;
-       } else if (!strcasecmp(var->value, "none")) {
-               endpoint->dtmf = AST_SIP_DTMF_NONE;
-       } else {
+       if (dtmf == -1) {
                return -1;
        }
 
+       endpoint->dtmf = dtmf;
        return 0;
 }
 
 static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
 {
        const struct ast_sip_endpoint *endpoint = obj;
+       char dtmf_str[20];
+       int result = -1;
 
-       switch (endpoint->dtmf) {
-       case AST_SIP_DTMF_RFC_4733 :
-               *buf = "rfc4733"; break;
-       case AST_SIP_DTMF_INBAND :
-               *buf = "inband"; break;
-       case AST_SIP_DTMF_INFO :
-               *buf = "info"; break;
-       case AST_SIP_DTMF_AUTO :
-               *buf = "auto"; break;
-       default:
-               *buf = "none";
-       }
+       result = ast_sip_dtmf_to_str(endpoint->dtmf, dtmf_str, sizeof(dtmf_str));
 
-       *buf = ast_strdup(*buf);
+       if (result == 0) {
+               *buf = ast_strdup(dtmf_str);
+       } else {
+               *buf = ast_strdup("none");
+       }
        return 0;
 }
 
@@ -1142,6 +1130,37 @@ static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf)
        return 0;
 }
 
+static int from_user_handler(const struct aco_option *opt,
+       struct ast_variable *var, void *obj)
+{
+       struct ast_sip_endpoint *endpoint = obj;
+       /* Valid non-alphanumeric characters for URI */
+       char *valid_uri_marks = "-_.!~*`()";
+       const char *val;
+
+       for (val = var->value; *val; val++) {
+               if (!strchr(valid_uri_marks, *val) && !isdigit(*val) && !isalpha(*val)) {
+                       ast_log(LOG_ERROR, "Error configuring endpoint '%s' - '%s' field "
+                       "contains invalid character '%c'\n",
+                       ast_sorcery_object_get_id(endpoint), var->name, *val);
+                       return -1;
+               }
+       }
+
+       ast_string_field_set(endpoint, fromuser, var->value);
+
+       return 0;
+}
+
+static int from_user_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+       const struct ast_sip_endpoint *endpoint = obj;
+
+       *buf = ast_strdup(endpoint->fromuser);
+
+       return 0;
+}
+
 static int set_var_handler(const struct aco_option *opt,
        struct ast_variable *var, void *obj)
 {
@@ -1321,6 +1340,37 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o
                return -1;
        }
 
+       endpoint->media.topology = ast_stream_topology_create_from_format_cap(endpoint->media.codecs);
+       if (!endpoint->media.topology) {
+               return -1;
+       }
+
+       endpoint->media.rtcp_mux |= endpoint->media.bundle;
+
+       /*
+        * If webrtc has been enabled then enable those attributes, and default
+        * some, that are needed in order for webrtc to work.
+        */
+       endpoint->media.bundle |= endpoint->media.webrtc;
+       endpoint->media.rtcp_mux |= endpoint->media.webrtc;
+       endpoint->media.rtp.use_avpf |= endpoint->media.webrtc;
+       endpoint->media.rtp.ice_support |= endpoint->media.webrtc;
+       endpoint->media.rtp.use_received_transport |= endpoint->media.webrtc;
+
+       if (endpoint->media.webrtc) {
+               endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
+               endpoint->media.rtp.dtls_cfg.enabled = 1;
+               endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS;
+               endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;
+
+               if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile) ||
+                       (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.cafile))) {
+                       ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert "
+                               "or ca file has not been specified", ast_sorcery_object_get_id(endpoint));
+                       return -1;
+               }
+       }
+
        return 0;
 }
 
@@ -1708,9 +1758,7 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags)
 
        if (number) {
                print_name_len = strlen(id) + strlen(number) + 2;
-               if (!(print_name = alloca(print_name_len))) {
-                       return -1;
-               }
+               print_name = ast_alloca(print_name_len);
                snprintf(print_name, print_name_len, "%s/%s", id, number);
        }
 
@@ -1909,7 +1957,7 @@ int ast_res_pjsip_initialize_configuration(void)
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
-       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
+       ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "from_user", "", from_user_handler, from_user_to_str, NULL, 0, 0);
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
@@ -1939,6 +1987,14 @@ int ast_res_pjsip_initialize_configuration(void)
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));
 
        if (ast_sip_initialize_sorcery_transport()) {
                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
@@ -2001,6 +2057,8 @@ int ast_res_pjsip_initialize_configuration(void)
 
        load_all_endpoints();
 
+       ast_sip_location_prune_boot_contacts();
+
        return 0;
 }
 
@@ -2058,7 +2116,8 @@ static void endpoint_destructor(void* obj)
 
        ast_string_field_free_memory(endpoint);
 
-       ao2_ref(endpoint->media.codecs, -1);
+       ao2_cleanup(endpoint->media.codecs);
+       ast_stream_topology_free(endpoint->media.topology);
        subscription_configuration_destroy(&endpoint->subscription);
        info_configuration_destroy(&endpoint->info);
        media_configuration_destroy(&endpoint->media);
@@ -2071,6 +2130,8 @@ static void endpoint_destructor(void* obj)
        ast_variables_destroy(endpoint->channel_vars);
        AST_VECTOR_FREE(&endpoint->ident_method_order);
        ast_free(endpoint->contact_user);
+       ast_free_acl_list(endpoint->contact_acl);
+       ast_free_acl_list(endpoint->acl);
 }
 
 static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)