Merge "res_smdi: Fix shutdown ref."
authorJenkins2 <jenkins2@gerrit.asterisk.org>
Fri, 15 Dec 2017 18:24:43 +0000 (12:24 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Fri, 15 Dec 2017 18:24:43 +0000 (12:24 -0600)
17 files changed:
CHANGES
UPGRADE.txt
apps/app_queue.c
configs/samples/rtp.conf.sample
include/asterisk/res_pjsip.h
include/asterisk/rtp_engine.h
main/loader.c
main/rtp_engine.c
main/stasis_endpoints.c
res/res_clialiases.c
res/res_hep.c
res/res_musiconhold.c
res/res_pjsip.c
res/res_pjsip/pjsip_options.c
res/res_rtp_asterisk.c
res/res_smdi.c
rest-api/api-docs/events.json

diff --git a/CHANGES b/CHANGES
index b2b7409..f367f46 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -26,6 +26,17 @@ chan_sip
    headers be retrieved from the REFER message and made accessible to the
    dialplan in the hash TRANSFER_DATA.
 
+AMI
+------------------
+ * The ContactStatus and Status fields for the manager events ContactStatus
+   and ContactStatusDetail are now set to "NonQualified" when a contact exists
+   but has not been qualified.
+
+ARI
+------------------
+ * The ContactInfo event's contact_status field is now set to "NonQualified"
+   when a contact exists but has not been qualified.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 15.1.0 to Asterisk 15.2.0 ------------
 ------------------------------------------------------------------------------
index 39c0f8c..dd37b25 100644 (file)
@@ -31,6 +31,15 @@ app_macro:
    built.  Users should migrate to app_stack (Gosub).  A warning is logged
    the first time any Macro is used.
 
+AMI:
+ - The ContactStatus and Status fields for the manager events ContactStatus
+   and ContactStatusDetail are now set to "NonQualified" when a contact exists
+   but has not been qualified.
+
+ARI:
+ - The ContactInfo event's contact_status field is now set to "NonQualified"
+   when a contact exists but has not been qualified.
+
 New in 15.0.0:
 
 Build System:
index 801695f..a140847 100644 (file)
@@ -1575,6 +1575,7 @@ struct member {
        char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
        char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
        char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
+       int state_id;                        /*!< Extension state callback id (if using hint) */
        char membername[80];                 /*!< Member name to use in queue logs */
        int penalty;                         /*!< Are we a last resort? */
        int calls;                           /*!< Number of calls serviced by this member */
@@ -2632,12 +2633,21 @@ static int get_queue_member_status(struct member *cur)
        return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
 }
 
+static void destroy_queue_member_cb(void *obj)
+{
+       struct member *mem = obj;
+
+       if (mem->state_id != -1) {
+               ast_extension_state_del(mem->state_id, extension_state_cb);
+       }
+}
+
 /*! \brief allocate space for new queue member and set fields based on parameters passed */
 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
 {
        struct member *cur;
 
-       if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
+       if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
                cur->ringinuse = ringinuse;
                cur->penalty = penalty;
                cur->paused = paused;
@@ -2664,6 +2674,10 @@ static struct member *create_queue_member(const char *interface, const char *mem
 
                        ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
                        ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
+
+                       cur->state_id = ast_extension_state_add(cur->state_context, cur->state_exten, extension_state_cb, NULL);
+               } else {
+                       cur->state_id = -1;
                }
                cur->status = get_queue_member_status(cur);
        }
@@ -11084,8 +11098,6 @@ static int unload_module(void)
 
        device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
 
-       ast_extension_state_del(0, extension_state_cb);
-
        ast_unload_realtime("queue_members");
        ao2_cleanup(queues);
        ao2_cleanup(pending_members);
@@ -11243,8 +11255,6 @@ static int load_module(void)
        err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
        err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
 
-       ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
-
        if (err) {
                unload_module();
                return AST_MODULE_LOAD_DECLINE;
index 9bc3de3..de9d590 100644 (file)
@@ -21,9 +21,17 @@ rtpend=20000
 ; rtcpinterval = 5000  ; Milliseconds between rtcp reports
                        ;(min 500, max 60000, default 5000)
 ;
-; Enable strict RTP protection. This will drop RTP packets that
-; do not come from the source of the RTP stream. This option is
-; enabled by default.
+; Enable strict RTP protection.  This will drop RTP packets that do not come
+; from the recoginized source of the RTP stream.  Strict RTP qualifies RTP
+; packet stream sources before accepting them upon initial connection and
+; when the connection is renegotiated (e.g., transfers and direct media).
+; Initial connection and renegotiation starts a learning mode to qualify
+; stream source addresses.  Once Asterisk has recognized a stream it will
+; allow other streams to qualify and replace the current stream for 5
+; seconds after starting learning mode.  Once learning mode completes the
+; current stream is locked in and cannot change until the next
+; renegotiation.
+; This option is enabled by default.
 ; strictrtp=yes
 ;
 ; Number of packets containing consecutive sequence values needed
index e71eb98..6c48d2e 100644 (file)
@@ -289,9 +289,13 @@ struct ast_sip_contact {
  * \brief Status type for a contact.
  */
 enum ast_sip_contact_status_type {
+       /*! Frequency > 0, but no response from remote uri */
        UNAVAILABLE,
+       /*! Frequency > 0, and got response from remote uri */
        AVAILABLE,
+       /*! Default last status, and when a contact status object is not found */
        UNKNOWN,
+       /*! Frequency == 0, has a contact, but don't know status (non-qualified) */
        CREATED,
        REMOVED,
 };
index f9d686a..c77be45 100644 (file)
@@ -1383,6 +1383,16 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
 void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload);
 
 /*!
+ * \brief Determine the type of RTP stream media from the codecs mapped.
+ * \since 13.19.0
+ *
+ * \param codecs Codecs structure to look in
+ *
+ * \return Media type or AST_MEDIA_TYPE_UNKNOWN if no codecs mapped.
+ */
+enum ast_media_type ast_rtp_codecs_get_stream_type(struct ast_rtp_codecs *codecs);
+
+/*!
  * \brief Retrieve rx payload mapped information by payload type
  *
  * \param codecs Codecs structure to look in
index 49151cc..e073365 100644 (file)
@@ -167,38 +167,51 @@ static int do_full_reload = 0;
 
 static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item);
 
-/* when dynamic modules are being loaded, ast_module_register() will
-   need to know what filename the module was loaded from while it
-   is being registered
-*/
+/*!
+ * \internal
+ *
+ * This variable is set by load_dynamic_module so ast_module_register
+ * can know what pointer is being registered.
+ *
+ * This is protected by the module_list lock.
+ */
 static struct ast_module *resource_being_loaded;
 
-/* XXX: should we check for duplicate resource names here? */
-
+/*!
+ * \internal
+ * \brief Used by AST_MODULE_INFO to register with the module loader.
+ *
+ * This function is automatically called when each module is opened.
+ * It must never be used from outside AST_MODULE_INFO.
+ */
 void ast_module_register(const struct ast_module_info *info)
 {
-       struct ast_module *mod = resource_being_loaded;
+       struct ast_module *mod;
+
+       /*
+        * This lock protects resource_being_loaded as well as the module
+        * list.  Normally we already have a lock on module_list when we
+        * begin the load but locking again from here prevents corruption
+        * if an asterisk module is dlopen'ed from outside the module loader.
+        */
+       AST_DLLIST_LOCK(&module_list);
+       mod = resource_being_loaded;
+       if (!mod) {
+               AST_DLLIST_UNLOCK(&module_list);
+               return;
+       }
 
        ast_debug(5, "Registering module %s\n", info->name);
 
+       /* This tells load_dynamic_module that we're registered. */
+       resource_being_loaded = NULL;
+
        mod->info = info;
        if (ast_opt_ref_debug) {
                mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
        }
        AST_LIST_HEAD_INIT(&mod->users);
 
-       /* during startup, before the loader has been initialized,
-          there are no threads, so there is no need to take the lock
-          on this list to manipulate it. it is also possible that it
-          might be unsafe to use the list lock at that point... so
-          let's avoid it altogether
-       */
-       AST_DLLIST_LOCK(&module_list);
-       /* it is paramount that the new entry be placed at the tail of
-          the list, otherwise the code that uses dlopen() to load
-          dynamic modules won't be able to find out if the module it
-          just opened was registered or failed to load
-       */
        AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
        AST_DLLIST_UNLOCK(&module_list);
 
@@ -206,6 +219,13 @@ void ast_module_register(const struct ast_module_info *info)
        *((struct ast_module **) &(info->self)) = mod;
 }
 
+static void module_destroy(struct ast_module *mod)
+{
+       AST_LIST_HEAD_DESTROY(&mod->users);
+       ao2_cleanup(mod->ref_debug);
+       ast_free(mod);
+}
+
 void ast_module_unregister(const struct ast_module_info *info)
 {
        struct ast_module *mod = NULL;
@@ -226,9 +246,7 @@ void ast_module_unregister(const struct ast_module_info *info)
 
        if (mod) {
                ast_debug(5, "Unregistering module %s\n", info->name);
-               AST_LIST_HEAD_DESTROY(&mod->users);
-               ao2_cleanup(mod->ref_debug);
-               ast_free(mod);
+               module_destroy(mod);
        }
 }
 
@@ -511,6 +529,8 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
        int space;      /* room needed for the descriptor */
        int missing_so = 0;
 
+       ast_assert(!resource_being_loaded);
+
        space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
        if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
                missing_so = 1;
@@ -523,34 +543,23 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
           any symbols, and don't export any symbols. this will allow us to peek into
           the module's info block (if available) to see what flags it has set */
 
-       resource_being_loaded = ast_calloc(1, space);
+       mod = resource_being_loaded = ast_calloc(1, space);
        if (!resource_being_loaded)
                return NULL;
        strcpy(resource_being_loaded->resource, resource_in);
        if (missing_so)
                strcat(resource_being_loaded->resource, ".so");
 
-       if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) {
-               if (!suppress_logging) {
+       lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL);
+       if (resource_being_loaded) {
+               resource_being_loaded = NULL;
+               if (lib) {
+                       ast_log(LOG_ERROR, "Module '%s' did not register itself during load\n", resource_in);
+                       logged_dlclose(resource_in, lib);
+               } else if (!suppress_logging) {
                        ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
                }
-               ast_free(resource_being_loaded);
-               return NULL;
-       }
-
-       /* the dlopen() succeeded, let's find out if the module
-          registered itself */
-       /* note that this will only work properly as long as
-          ast_module_register() (which is called by the module's
-          constructor) places the new module at the tail of the
-          module_list
-       */
-       if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) {
-               ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
-               /* no, it did not, so close it and return */
-               logged_dlclose(resource_in, lib);
-               /* note that the module's destructor will call ast_module_unregister(),
-                  which will free the structure we allocated in resource_being_loaded */
+               ast_free(mod);
                return NULL;
        }
 
@@ -564,19 +573,20 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
        }
 
        logged_dlclose(resource_in, lib);
-       resource_being_loaded = NULL;
 
        /* start the load process again */
-       resource_being_loaded = ast_calloc(1, space);
+       mod = resource_being_loaded = ast_calloc(1, space);
        if (!resource_being_loaded)
                return NULL;
        strcpy(resource_being_loaded->resource, resource_in);
        if (missing_so)
                strcat(resource_being_loaded->resource, ".so");
 
-       if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
+       lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL);
+       resource_being_loaded = NULL;
+       if (!lib) {
                ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
-               ast_free(resource_being_loaded);
+               ast_free(mod);
                return NULL;
        }
 
@@ -585,7 +595,6 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
           time too :) */
 
        AST_DLLIST_LAST(&module_list)->lib = lib;
-       resource_being_loaded = NULL;
 
        return AST_DLLIST_LAST(&module_list);
 }
@@ -621,9 +630,7 @@ int modules_shutdown(void)
                                ast_verb(1, "Unloading %s\n", mod->resource);
                                mod->info->unload();
                        }
-                       AST_LIST_HEAD_DESTROY(&mod->users);
-                       ao2_cleanup(mod->ref_debug);
-                       ast_free(mod);
+                       module_destroy(mod);
                        somethingchanged = 1;
                }
                AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
index 2431ffc..68c53e7 100644 (file)
@@ -1176,6 +1176,25 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
        ast_rwlock_unlock(&codecs->codecs_lock);
 }
 
+enum ast_media_type ast_rtp_codecs_get_stream_type(struct ast_rtp_codecs *codecs)
+{
+       enum ast_media_type stream_type = AST_MEDIA_TYPE_UNKNOWN;
+       int payload;
+       struct ast_rtp_payload_type *type;
+
+       ast_rwlock_rdlock(&codecs->codecs_lock);
+       for (payload = 0; payload < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++payload) {
+               type = AST_VECTOR_GET(&codecs->payload_mapping_rx, payload);
+               if (type && type->asterisk_format) {
+                       stream_type = ast_format_get_type(type->format);
+                       break;
+               }
+       }
+       ast_rwlock_unlock(&codecs->codecs_lock);
+
+       return stream_type;
+}
+
 struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload)
 {
        struct ast_rtp_payload_type *type = NULL;
index 161fdfa..5cee22e 100644 (file)
@@ -82,7 +82,7 @@
                                                <enum name="Unknown"/>
                                                <enum name="Unreachable"/>
                                                <enum name="Reachable"/>
-                                               <enum name="Created"/>
+                                               <enum name="Unqualified"/>
                                                <enum name="Removed"/>
                                                <enum name="Updated"/>
                                        </enumlist>
index 1a2fc69..337c31c 100644 (file)
@@ -103,7 +103,7 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_
        struct cli_alias tmp = {
                .cli_entry.command = e->command,
        };
-       char *generator;
+       char *generator = NULL;
        const char *line;
 
        /* Try to find the alias based on the CLI entry */
@@ -118,14 +118,10 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_
        case CLI_GENERATE:
                line = a->line;
                line += (strlen(alias->alias));
-               if (!strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) {
-                       generator = NULL;
-               } else if (!ast_strlen_zero(a->word)) {
+               if (strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) {
                        struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1);
                        ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line);
                        generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n);
-               } else {
-                       generator = ast_cli_generator(alias->real_cmd, a->word, a->n);
                }
                ao2_ref(alias, -1);
                return generator;
index 25b4d13..ba036d7 100644 (file)
@@ -421,7 +421,7 @@ int hepv3_is_loaded(void)
 {
        RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
 
-       return (config != NULL) ? 1 : 0;
+       return config && config->general->enabled;
 }
 
 struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
index ef1b81c..17e91b7 100644 (file)
@@ -333,6 +333,7 @@ static int ast_moh_files_next(struct ast_channel *chan)
                }
        } else {
                state->announcement = 0;
+               state->samples = 0;
        }
 
        if (!state->class->total_files) {
@@ -1934,6 +1935,9 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc
                ast_cli(a->fd, "Class: %s\n", class->name);
                ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
                ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
+               if (ast_test_flag(class, MOH_ANNOUNCEMENT)) {
+                       ast_cli(a->fd, "\tAnnouncement: %s\n", S_OR(class->announcement, "<none>"));
+               }
                if (ast_test_flag(class, MOH_CUSTOM)) {
                        ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
                        ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->kill_delay / 1000);
index 21e43f0..b50ee5f 100644 (file)
                                        <enumlist>
                                                <enum name="Reachable"/>
                                                <enum name="Unreachable"/>
+                                               <enum name="NonQualified"/>
                                        </enumlist>
                                </parameter>
                                <parameter name="RoundtripUsec">
index fbe07d5..f9df2f0 100644 (file)
@@ -41,7 +41,7 @@ static const char *status_map [] = {
        [UNAVAILABLE] = "Unreachable",
        [AVAILABLE] = "Reachable",
        [UNKNOWN] = "Unknown",
-       [CREATED] = "Created",
+       [CREATED] = "NonQualified",
        [REMOVED] = "Removed",
 };
 
@@ -49,7 +49,7 @@ static const char *short_status_map [] = {
        [UNAVAILABLE] = "Unavail",
        [AVAILABLE] = "Avail",
        [UNKNOWN] = "Unknown",
-       [CREATED] = "Created",
+       [CREATED] = "NonQual",
        [REMOVED] = "Removed",
 };
 
@@ -205,24 +205,12 @@ static void update_contact_status(const struct ast_sip_contact *contact,
                return;
        }
 
-       if (is_contact_refresh
-               && status->status == CREATED) {
-               /*
-                * The contact status hasn't been updated since creation
-                * and we don't want to re-send a created status.
-                */
-               if (contact->qualify_frequency
-                       || status->rtt_start.tv_sec > 0) {
-                       /* Ignore, the status will change soon. */
-                       return;
-               }
-
-               /*
-                * Convert to a regular contact status update
-                * because the status may never change.
-                */
-               is_contact_refresh = 0;
-               value = UNKNOWN;
+       /*
+        * If the current status is CREATED, and it's a refresh or the given value is
+        * also CREATED then there is nothing to update as nothing needs to change.
+        */
+       if (status->status == CREATED && (is_contact_refresh || status->status == value)) {
+               return;
        }
 
        update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
@@ -595,7 +583,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact)
 
                schedule_qualify(contact, contact->qualify_frequency * 1000);
        } else {
-               update_contact_status(contact, UNKNOWN, 0);
+               update_contact_status(contact, CREATED, 0);
        }
 }
 
@@ -1127,7 +1115,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact)
        if (contact->qualify_frequency) {
                schedule_qualify(contact, initial_interval);
        } else {
-               update_contact_status(contact, UNKNOWN, 0);
+               update_contact_status(contact, CREATED, 0);
        }
 }
 
index bdc8330..51e509c 100644 (file)
@@ -256,6 +256,8 @@ struct rtp_learning_info {
        struct timeval received; /*!< The time of the first received packet */
        int max_seq;    /*!< The highest sequence number received */
        int packets;    /*!< The number of remaining packets before the source is accepted */
+       /*! Type of media stream carried by the RTP instance */
+       enum ast_media_type stream_type;
 };
 
 #ifdef HAVE_OPENSSL_SRTP
@@ -3095,18 +3097,30 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
                info->received = ast_tvnow();
        }
 
-       /*
-        * Protect against packet floods by checking that we
-        * received the packet sequence in at least the minimum
-        * allowed time.
-        */
-       if (ast_tvzero(info->received)) {
-               info->received = ast_tvnow();
-       } else if (!info->packets && (ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration )) {
-               /* Packet flood; reset */
-               info->packets = learning_min_sequential - 1;
-               info->received = ast_tvnow();
+       switch (info->stream_type) {
+       case AST_MEDIA_TYPE_UNKNOWN:
+       case AST_MEDIA_TYPE_AUDIO:
+               /*
+                * Protect against packet floods by checking that we
+                * received the packet sequence in at least the minimum
+                * allowed time.
+                */
+               if (ast_tvzero(info->received)) {
+                       info->received = ast_tvnow();
+               } else if (!info->packets
+                       && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
+                       /* Packet flood; reset */
+                       info->packets = learning_min_sequential - 1;
+                       info->received = ast_tvnow();
+               }
+               break;
+       case AST_MEDIA_TYPE_VIDEO:
+       case AST_MEDIA_TYPE_IMAGE:
+       case AST_MEDIA_TYPE_TEXT:
+       case AST_MEDIA_TYPE_END:
+               break;
        }
+
        info->max_seq = seq;
 
        return info->packets;
@@ -5951,6 +5965,15 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                         * source and we should switch to it.
                         */
                        if (!ast_sockaddr_cmp(&rtp->rtp_source_learn.proposed_address, &addr)) {
+                               if (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_UNKNOWN) {
+                                       struct ast_rtp_codecs *codecs;
+
+                                       codecs = ast_rtp_instance_get_codecs(instance);
+                                       rtp->rtp_source_learn.stream_type =
+                                               ast_rtp_codecs_get_stream_type(codecs);
+                                       ast_verb(4, "%p -- Strict RTP qualifying stream type: %s\n",
+                                               rtp, ast_codec_media_type2str(rtp->rtp_source_learn.stream_type));
+                               }
                                if (!rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
                                        /* Accept the new RTP stream */
                                        ast_verb(4, "%p -- Strict RTP switching source address to %s\n",
index e2b2e1b..612a4b8 100644 (file)
@@ -586,9 +586,8 @@ static void *smdi_read(void *iface_p)
        struct ast_smdi_interface *iface = iface_p;
        struct ast_smdi_md_message *md_msg;
        struct ast_smdi_mwi_message *mwi_msg;
-       char c = '\0';
        char *cp = NULL;
-       int i;
+       int i, c;
        int start = 0;
 
        /* read an smdi message */
@@ -616,7 +615,14 @@ static void *smdi_read(void *iface_p)
 
                        /* read the message desk number */
                        for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
-                               md_msg->mesg_desk_num[i] = fgetc(iface->file);
+                               c = fgetc(iface->file);
+                               if (c == EOF) {
+                                       ast_log(LOG_ERROR, "Unexpected EOF while reading MD message\n");
+                                       ao2_ref(md_msg, -1);
+                                       ao2_ref(iface, -1);
+                                       return NULL;
+                               }
+                               md_msg->mesg_desk_num[i] = (char) c;
                                ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
                        }
 
@@ -626,7 +632,14 @@ static void *smdi_read(void *iface_p)
 
                        /* read the message desk terminal number */
                        for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
-                               md_msg->mesg_desk_term[i] = fgetc(iface->file);
+                               c = fgetc(iface->file);
+                               if (c == EOF) {
+                                       ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n");
+                                       ao2_ref(md_msg, -1);
+                                       ao2_ref(iface, -1);
+                                       return NULL;
+                               }
+                               md_msg->mesg_desk_term[i] = (char) c;
                                ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
                        }
 
@@ -635,7 +648,14 @@ static void *smdi_read(void *iface_p)
                        ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
 
                        /* read the message type */
-                       md_msg->type = fgetc(iface->file);
+                       c = fgetc(iface->file);
+                       if (c == EOF) {
+                               ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n");
+                               ao2_ref(md_msg, -1);
+                               ao2_ref(iface, -1);
+                               return NULL;
+                       }
+                       md_msg->type = (char) c;
 
                        ast_debug(1, "Message type is '%c'\n", md_msg->type);
 
@@ -717,7 +737,7 @@ static void *smdi_read(void *iface_p)
 
                        /* discard the 'I' (from 'MWI') */
                        fgetc(iface->file);
-                       
+
                        /* read the forwarding station number (may be blank) */
                        cp = &mwi_msg->fwd_st[0];
                        for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
@@ -740,8 +760,16 @@ static void *smdi_read(void *iface_p)
                        ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
 
                        /* read the mwi failure cause */
-                       for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++)
-                               mwi_msg->cause[i] = fgetc(iface->file);
+                       for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) {
+                               c = fgetc(iface->file);
+                               if (c == EOF) {
+                                       ast_log(LOG_ERROR, "Unexpected EOF while reading MWI message\n");
+                                       ao2_ref(mwi_msg, -1);
+                                       ao2_ref(iface, -1);
+                                       return NULL;
+                               }
+                               mwi_msg->cause[i] = (char) c;
+                       }
 
                        mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
 
index 9ebbac0..e1b31bb 100644 (file)
                                                        "Unreachable",
                                                        "Reachable",
                                                        "Unknown",
-                                                       "Created",
+                                                       "NonQualified",
                                                        "Removed"
                                                ]
                                        }