diff options
-rw-r--r-- | channels/chan_iax2.c | 1 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 14 | ||||
-rw-r--r-- | channels/chan_sip.c | 15 | ||||
-rw-r--r-- | channels/chan_skinny.c | 9 | ||||
-rw-r--r-- | channels/chan_unistim.c | 168 | ||||
-rw-r--r-- | include/asterisk/vector.h | 214 | ||||
-rw-r--r-- | main/acl.c | 2 | ||||
-rw-r--r-- | main/format_cap.c | 2 | ||||
-rw-r--r-- | main/manager.c | 8 | ||||
-rw-r--r-- | main/rtp_engine.c | 8 | ||||
-rw-r--r-- | main/stasis_channels.c | 59 | ||||
-rw-r--r-- | res/res_pjsip_acl.c | 13 | ||||
-rw-r--r-- | tests/test_message.c | 16 | ||||
-rw-r--r-- | tests/test_vector.c | 428 |
14 files changed, 846 insertions, 111 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 253160a92..bb9c52bb8 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -13746,6 +13746,7 @@ static int set_config(const char *config_file, int reload, int forced) } else if (!strcasecmp(v->name, "calltokenoptional")) { if (add_calltoken_ignore(v->value)) { ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno); + return -1; } } else if (!strcasecmp(v->name, "calltokenexpiration")) { int temp = -1; diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 602d38d01..37935be4b 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -4104,7 +4104,19 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) ast_sockaddr_to_sin(&tmp, &gw->defaddr); } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { - gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL); + int acl_error = 0; + gw->ha = ast_append_ha(v->name, v->value, gw->ha, &acl_error); + if (acl_error) { + ast_log(LOG_ERROR, "Invalid ACL '%s' specified for MGCP gateway '%s' on line %d. Not creating.\n", + v->value, cat, v->lineno); + if (!gw_reload) { + ast_mutex_destroy(&gw->msgs_lock); + ast_free(gw); + } else { + gw->delme = 1; + } + return NULL; + } } else if (!strcasecmp(v->name, "port")) { gw->addr.sin_port = htons(atoi(v->value)); } else if (!strcasecmp(v->name, "context")) { diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 468bfbecb..528e208d9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -30608,7 +30608,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str ast_append_acl(v->name, v->value, &peer->acl, &ha_error, &acl_change_subscription_needed); } if (ha_error) { - ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); + ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value); + sip_unref_peer(peer, "Removing peer due to bad ACL configuration"); + return NULL; } } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny") || !strcasecmp(v->name, "contactacl")) { int ha_error = 0; @@ -30616,13 +30618,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str ast_append_acl(v->name + 7, v->value, &peer->contactacl, &ha_error, &acl_change_subscription_needed); } if (ha_error) { - ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); + ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value); + sip_unref_peer(peer, "Removing peer due to bad contact ACL configuration"); + return NULL; } } else if (!strcasecmp(v->name, "directmediapermit") || !strcasecmp(v->name, "directmediadeny") || !strcasecmp(v->name, "directmediaacl")) { int ha_error = 0; ast_append_acl(v->name + 11, v->value, &peer->directmediaacl, &ha_error, &acl_change_subscription_needed); if (ha_error) { - ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s\n", v->lineno, v->value); + ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value); + sip_unref_peer(peer, "Removing peer due to bad direct media ACL configuration"); + return NULL; } } else if (!strcasecmp(v->name, "port")) { peer->portinuri = 1; @@ -31566,7 +31572,8 @@ static int reload_config(enum channelreloadreason reason) int ha_error = 0; ast_append_acl(v->name + 7, v->value, &sip_cfg.contact_acl, &ha_error, &acl_change_subscription_needed); if (ha_error) { - ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); + ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Failing to load chan_sip.so\n", v->lineno, v->value); + return -1; } } else if (!strcasecmp(v->name, "rtautoclear")) { int i = atoi(v->value); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 5f30a13b5..1d7d65af4 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -8044,7 +8044,14 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp } } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { if (type & (TYPE_DEVICE)) { - CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL); + int acl_error = 0; + + CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, &acl_error); + if (acl_error) { + ast_log(LOG_ERROR, "Invalid ACL '%s' on line '%d'. Deleting device\n", + v->value, v->lineno); + CDEV->prune = 1; + } continue; } } else if (!strcasecmp(v->name, "allow")) { diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 4379aa5c6..82b3fced9 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -6395,6 +6395,85 @@ static struct unistim_line *find_line_by_number(struct unistim_device *d, const return ret; } +static void delete_device(struct unistim_device *d) +{ + struct unistim_line *l; + struct unistim_subchannel *sub; + struct unistimsession *s; + + if (unistimdebug) { + ast_verb(0, "Removing device '%s'\n", d->name); + } + AST_LIST_LOCK(&d->subs); + AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){ + if (sub->subtype == SUB_REAL) { + if (sub->owner) { + ast_log(LOG_WARNING, + "Device '%s' was not deleted : a call is in progress. Try again later.\n", + d->name); + AST_LIST_UNLOCK(&d->subs); + return; + } + } + if (sub->subtype == SUB_THREEWAY) { + ast_log(LOG_WARNING, + "Device '%s' with threeway call subchannels allocated, aborting.\n", + d->name); + AST_LIST_UNLOCK(&d->subs); + return; + } + AST_LIST_REMOVE_CURRENT(list); + ast_mutex_destroy(&sub->lock); + ast_free(sub); + } + AST_LIST_TRAVERSE_SAFE_END + AST_LIST_UNLOCK(&d->subs); + + + AST_LIST_LOCK(&d->lines); + AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){ + AST_LIST_REMOVE_CURRENT(list); + ast_mutex_destroy(&l->lock); + unistim_line_destroy(l); + } + AST_LIST_TRAVERSE_SAFE_END + AST_LIST_UNLOCK(&d->lines); + + if (d->session) { + if (sessions == d->session) { + sessions = d->session->next; + } else { + s = sessions; + while (s) { + if (s->next == d->session) { + s->next = d->session->next; + break; + } + s = s->next; + } + } + ast_mutex_destroy(&d->session->lock); + ast_free(d->session); + } + if (devices == d) { + devices = d->next; + } else { + struct unistim_device *d2 = devices; + while (d2) { + if (d2->next == d) { + d2->next = d->next; + break; + } + d2 = d2->next; + } + } + if (d->tz) { + d->tz = ast_tone_zone_unref(d->tz); + } + ast_mutex_destroy(&d->lock); + ast_free(d); +} + static struct unistim_device *build_device(const char *cat, const struct ast_variable *v) { struct unistim_device *d; @@ -6486,7 +6565,14 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var } else if (!strcasecmp(v->name, "tn")) { ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number)); } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { - d->ha = ast_append_ha(v->name, v->value, d->ha, NULL); + int acl_error = 0; + d->ha = ast_append_ha(v->name, v->value, d->ha, &acl_error); + if (acl_error) { + ast_log(LOG_ERROR, "Invalid ACL '%s' specified for device '%s' on line %d. Deleting device\n", + v->value, cat, v->lineno); + delete_device(d); + return NULL; + } } else if (!strcasecmp(v->name, "context")) { ast_copy_string(d->context, v->value, sizeof(d->context)); } else if (!strcasecmp(v->name, "maintext0")) { @@ -6853,85 +6939,7 @@ static int reload_config(void) d = devices; while (d) { if (d->to_delete) { - struct unistim_line *l; - struct unistim_subchannel *sub; - - if (unistimdebug) { - ast_verb(0, "Removing device '%s'\n", d->name); - } - AST_LIST_LOCK(&d->subs); - AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){ - if (sub->subtype == SUB_REAL) { - if (!sub) { - ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n", - d->name); - ast_config_destroy(cfg); - return 0; - } - if (sub->owner) { - ast_log(LOG_WARNING, - "Device '%s' was not deleted : a call is in progress. Try again later.\n", - d->name); - d = d->next; - continue; - } - } - if (sub->subtype == SUB_THREEWAY) { - ast_log(LOG_WARNING, - "Device '%s' with threeway call subchannels allocated, aborting.\n", - d->name); - break; - } - AST_LIST_REMOVE_CURRENT(list); - ast_mutex_destroy(&sub->lock); - ast_free(sub); - } - AST_LIST_TRAVERSE_SAFE_END - AST_LIST_UNLOCK(&d->subs); - - - AST_LIST_LOCK(&d->lines); - AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){ - AST_LIST_REMOVE_CURRENT(list); - ast_mutex_destroy(&l->lock); - unistim_line_destroy(l); - } - AST_LIST_TRAVERSE_SAFE_END - AST_LIST_UNLOCK(&d->lines); - - if (d->session) { - if (sessions == d->session) { - sessions = d->session->next; - } else { - s = sessions; - while (s) { - if (s->next == d->session) { - s->next = d->session->next; - break; - } - s = s->next; - } - } - ast_mutex_destroy(&d->session->lock); - ast_free(d->session); - } - if (devices == d) { - devices = d->next; - } else { - struct unistim_device *d2 = devices; - while (d2) { - if (d2->next == d) { - d2->next = d->next; - break; - } - d2 = d2->next; - } - } - if (d->tz) { - d->tz = ast_tone_zone_unref(d->tz); - } - ast_mutex_destroy(&d->lock); - ast_free(d); + delete_device(d); d = devices; continue; } diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index 0053d8a32..23db8a502 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -19,6 +19,8 @@ #ifndef _ASTERISK_VECTOR_H #define _ASTERISK_VECTOR_H +#include "asterisk/lock.h" + /*! \file * * \brief Vector container support. @@ -47,6 +49,20 @@ } /*! + * \brief Define a vector structure with a read/write lock + * + * \param name Optional vector struct name. + * \param type Vector element type. + */ +#define AST_VECTOR_RW(name, type) \ + struct name { \ + type *elems; \ + size_t max; \ + size_t current; \ + ast_rwlock_t lock; \ + } + +/*! * \brief Initialize a vector * * If \a size is 0, then no space will be allocated until the vector is @@ -72,6 +88,26 @@ }) /*! + * \brief Initialize a vector with a read/write lock + * + * If \a size is 0, then no space will be allocated until the vector is + * appended to. + * + * \param vec Vector to initialize. + * \param size Initial size of the vector. + * + * \return 0 on success. + * \return Non-zero on failure. + */ +#define AST_VECTOR_RW_INIT(vec, size) ({ \ + int res = -1; \ + if (AST_VECTOR_INIT(vec, size) == 0) { \ + res = ast_rwlock_init(&(vec)->lock); \ + } \ + res; \ +}) + +/*! * \brief Deallocates this vector. * * If any code to free the elements of this vector need to be run, that should @@ -87,6 +123,19 @@ } while (0) /*! + * \brief Deallocates this locked vector + * + * If any code to free the elements of this vector need to be run, that should + * be done prior to this call. + * + * \param vec Vector to deallocate. + */ +#define AST_VECTOR_RW_FREE(vec) do { \ + AST_VECTOR_FREE(vec); \ + ast_rwlock_destroy(&(vec)->lock); \ +} while(0) + +/*! * \brief Append an element to a vector, growing the vector if needed. * * \param vec Vector to append to. @@ -116,11 +165,11 @@ }) /*! - * \brief Insert an element at a specific position in a vector, growing the vector if needed. + * \brief Replace an element at a specific position in a vector, growing the vector if needed. * - * \param vec Vector to insert into. - * \param idx Position to insert at. - * \param elem Element to insert. + * \param vec Vector to replace into. + * \param idx Position to replace. + * \param elem Element to replace. * * \return 0 on success. * \return Non-zero on failure. @@ -131,7 +180,7 @@ * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering * of the vector itself. */ -#define AST_VECTOR_INSERT(vec, idx, elem) ({ \ +#define AST_VECTOR_REPLACE(vec, idx, elem) ({ \ int res = 0; \ do { \ if (((idx) + 1) > (vec)->max) { \ @@ -158,6 +207,46 @@ }) /*! + * \brief Insert an element at a specific position in a vector, growing the vector if needed. + * + * \param vec Vector to insert into. + * \param idx Position to insert at. + * \param elem Element to insert. + * + * \return 0 on success. + * \return Non-zero on failure. + * + * \warning This macro will shift existing elements right to make room for the new element. + * + * \warning Use of this macro with the expectation that the element will remain at the provided + * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering + * of the vector itself. + */ +#define AST_VECTOR_INSERT_AT(vec, idx, elem) ({ \ + int res = 0; \ + size_t __move; \ + do { \ + if ((vec)->current + 1 > (vec)->max) { \ + size_t new_max = (vec)->max ? 2 * (vec)->max : 1; \ + typeof((vec)->elems) new_elems = ast_realloc( \ + (vec)->elems, new_max * sizeof(*new_elems)); \ + if (new_elems) { \ + (vec)->elems = new_elems; \ + (vec)->max = new_max; \ + } else { \ + res = -1; \ + break; \ + } \ + } \ + __move = ((vec)->current - 1) * sizeof(typeof((vec)->elems[0])); \ + memmove(&(vec)->elems[(idx) + 1], &(vec)->elems[(idx)], __move); \ + (vec)->elems[(idx)] = (elem); \ + (vec)->current++; \ + } while (0); \ + res; \ +}) + +/*! * \brief Remove an element from a vector by index. * * Note that elements in the vector may be reordered, so that the remove can @@ -195,7 +284,6 @@ res; \ }) - /*! * \brief Remove an element from a vector that matches the given comparison * @@ -330,4 +418,118 @@ (vec)->elems[__idx]; \ }) +/*! + * \brief Get an element from a vector that matches the given comparison + * + * \param vec Vector to get from. + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * + * \return a pointer to the element that was found or NULL + */ +#define AST_VECTOR_GET_CMP(vec, value, cmp) ({ \ + void *res = NULL; \ + size_t idx; \ + typeof(value) __value = (value); \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value)) { \ + res = &(vec)->elems[idx]; \ + break; \ + } \ + } \ + res; \ +}) + +/*! + * \brief Execute a callback on every element in a vector + * + * \param vec Vector to operate on. + * \param callback A callback that takes at least 1 argument (the element) + * plus number of optional arguments + * + * \return the number of elements visited before the end of the vector + * was reached or CMP_STOP was returned. + */ +#define AST_VECTOR_CALLBACK(vec, callback, ...) ({ \ + size_t idx; \ + for (idx = 0; idx < (vec)->current; idx++) { \ + int rc = callback((vec)->elems[idx], ##__VA_ARGS__); \ + if (rc == CMP_STOP) { \ + idx++; \ + break; \ + }\ + } \ + idx; \ +}) + +/*! + * \brief Obtain read lock on vector + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_RDLOCK(vec) ast_rwlock_rdlock(&(vec)->lock) + +/*! + * \brief Obtain write lock on vector + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_WRLOCK(vec) ast_rwlock_wrlock(&(vec)->lock) + +/*! + * \brief Unlock vector + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_UNLOCK(vec) ast_rwlock_unlock(&(vec)->lock) + +/*! + * \brief Try to obtain read lock on vector failing immediately if unable + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_RDLOCK_TRY(vec) ast_rwlock_tryrdlock(&(vec)->lock) + +/*! + * \brief Try to obtain write lock on vector failing immediately if unable + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_WRLOCK_TRY(vec) ast_rwlock_trywrlock(&(vec)->lock) + +/*! + * \brief Try to obtain read lock on vector failing after timeout if unable + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_RDLOCK_TIMED(vec, timespec) ast_rwlock_timedrdlock(&(vec)->lock, timespec) + +/*! + * \brief Try to obtain write lock on vector failing after timeout if unable + * + * \param vec Vector to operate on. + * + * \return 0 if success + * \return Non-zero if error + */ +#define AST_VECTOR_RW_WRLOCK_TIMED(vec, timespec) ast_rwlock_timedwrlock(&(vec)->lock, timespec) + #endif /* _ASTERISK_VECTOR_H */ diff --git a/main/acl.c b/main/acl.c index 92b675443..d133b2a07 100644 --- a/main/acl.c +++ b/main/acl.c @@ -479,7 +479,7 @@ void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list ** AST_LIST_TRAVERSE(working_list, current, list) { if (!strcasecmp(current->name, tmp)) { /* ACL= */ /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */ - ast_log(LOG_ERROR, "Named ACL '%s' is already included in the ast_acl container.", tmp); + ast_log(LOG_ERROR, "Named ACL '%s' occurs multiple times in ACL definition. Please update your ACL configuration.", tmp); if (error) { *error = 1; } diff --git a/main/format_cap.c b/main/format_cap.c index 7456a444b..52262579c 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -139,7 +139,7 @@ static inline int format_cap_framed_init(struct format_cap_framed *framed, struc framed->framing = framing; if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { - if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) { + if (AST_VECTOR_REPLACE(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) { ao2_ref(framed, -1); return -1; } diff --git a/main/manager.c b/main/manager.c index 2ff9df930..846f6e604 100644 --- a/main/manager.c +++ b/main/manager.c @@ -8977,7 +8977,13 @@ static int __init_manager(int reload, int by_external_config) } else if (!strcasecmp(var->name, "deny") || !strcasecmp(var->name, "permit") || !strcasecmp(var->name, "acl")) { - ast_append_acl(var->name, var->value, &user->acl, NULL, &acl_subscription_flag); + int acl_error = 0; + + ast_append_acl(var->name, var->value, &user->acl, &acl_error, &acl_subscription_flag); + if (acl_error) { + ast_log(LOG_ERROR, "Invalid ACL '%s' for manager user '%s' on line %d. Deleting user\n"); + user->keep = 0; + } } else if (!strcasecmp(var->name, "read") ) { user->readperm = get_perm(var->value); } else if (!strcasecmp(var->name, "write") ) { diff --git a/main/rtp_engine.c b/main/rtp_engine.c index aa91b7da4..88d2db3d0 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -625,7 +625,7 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod } ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest); ao2_bump(type); - AST_VECTOR_INSERT(&dest->payloads, i, type); + AST_VECTOR_REPLACE(&dest->payloads, i, type); if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code); @@ -662,7 +662,7 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as new_type->format = ao2_bump(static_RTP_PT[payload].format); ast_debug(1, "Setting payload %d (%p) based on m type on %p\n", payload, new_type, codecs); - AST_VECTOR_INSERT(&codecs->payloads, payload, new_type); + AST_VECTOR_REPLACE(&codecs->payloads, payload, new_type); if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); @@ -727,7 +727,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, } else { new_type->format = ao2_bump(t->payload_type.format); } - AST_VECTOR_INSERT(&codecs->payloads, pt, new_type); + AST_VECTOR_REPLACE(&codecs->payloads, pt, new_type); if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); @@ -760,7 +760,7 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { type = AST_VECTOR_GET(&codecs->payloads, payload); ao2_cleanup(type); - AST_VECTOR_INSERT(&codecs->payloads, payload, NULL); + AST_VECTOR_REPLACE(&codecs->payloads, payload, NULL); } if (instance && instance->engine && instance->engine->payload_set) { diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 94a24e14f..7dc57bfed 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -364,6 +364,7 @@ static void ast_channel_publish_dial_internal(struct ast_channel *caller, } static void remove_dial_masquerade(struct ast_channel *peer); +static void remove_dial_masquerade_caller(struct ast_channel *caller); static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring); @@ -373,6 +374,11 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha { ast_assert(peer != NULL); + /* XXX With an early bridge the below dial masquerade datastore code could, theoretically, + * go away as the act of changing the channel during dialing would be done using the bridge + * API itself and not a masquerade. + */ + if (caller) { /* * Lock two or three channels. @@ -407,6 +413,7 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha ast_channel_unlock(forwarded); } ast_channel_unlock(peer); + remove_dial_masquerade_caller(caller); ast_channel_unlock(caller); } } @@ -1349,7 +1356,6 @@ static void dial_masquerade_datastore_cleanup(struct dial_masquerade_datastore * while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) { dial_target_free(cur); } - masq_data->caller = ast_channel_cleanup(masq_data->caller); } static void dial_masquerade_datastore_remove_chan(struct dial_masquerade_datastore *masq_data, struct ast_channel *chan) @@ -1399,6 +1405,16 @@ static void dial_masquerade_datastore_destroy(void *data) ao2_ref(data, -1); } +/*! + * \internal + * \brief Datastore destructor for dial_masquerade_datastore + */ +static void dial_masquerade_caller_datastore_destroy(void *data) +{ + dial_masquerade_datastore_cleanup(data); + ao2_ref(data, -1); +} + static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan); static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) @@ -1517,6 +1533,13 @@ static const struct ast_datastore_info dial_masquerade_info = { .chan_breakdown = dial_masquerade_breakdown, }; +static const struct ast_datastore_info dial_masquerade_caller_info = { + .type = "stasis-chan-dial-masq", + .destroy = dial_masquerade_caller_datastore_destroy, + .chan_fixup = dial_masquerade_fixup, + .chan_breakdown = dial_masquerade_breakdown, +}; + /*! * \internal * \brief Find the dial masquerade datastore on the given channel. @@ -1527,7 +1550,14 @@ static const struct ast_datastore_info dial_masquerade_info = { */ static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan) { - return ast_channel_datastore_find(chan, &dial_masquerade_info, NULL); + struct ast_datastore *datastore; + + datastore = ast_channel_datastore_find(chan, &dial_masquerade_info, NULL); + if (!datastore) { + datastore = ast_channel_datastore_find(chan, &dial_masquerade_caller_info, NULL); + } + + return datastore; } /*! @@ -1546,7 +1576,7 @@ static struct dial_masquerade_datastore *dial_masquerade_datastore_add( { struct ast_datastore *datastore; - datastore = ast_datastore_alloc(&dial_masquerade_info, NULL); + datastore = ast_datastore_alloc(!masq_data ? &dial_masquerade_caller_info : &dial_masquerade_info, NULL); if (!datastore) { return NULL; } @@ -1557,7 +1587,7 @@ static struct dial_masquerade_datastore *dial_masquerade_datastore_add( ast_datastore_free(datastore); return NULL; } - masq_data->caller = ast_channel_ref(chan); + masq_data->caller = chan; } datastore->data = masq_data; @@ -1663,3 +1693,24 @@ static void remove_dial_masquerade(struct ast_channel *peer) ast_channel_datastore_remove(peer, datastore); ast_datastore_free(datastore); } + +static void remove_dial_masquerade_caller(struct ast_channel *caller) +{ + struct ast_datastore *datastore; + struct dial_masquerade_datastore *masq_data; + + datastore = dial_masquerade_datastore_find(caller); + if (!datastore) { + return; + } + + masq_data = datastore->data; + if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) { + return; + } + + dial_masquerade_datastore_remove_chan(masq_data, caller); + + ast_channel_datastore_remove(caller, datastore); + ast_datastore_free(datastore); +} diff --git a/res/res_pjsip_acl.c b/res/res_pjsip_acl.c index a04f2b422..151ebeded 100644 --- a/res/res_pjsip_acl.c +++ b/res/res_pjsip_acl.c @@ -238,8 +238,21 @@ static int acl_handler(const struct aco_option *opt, struct ast_variable *var, v if (!strncmp(var->name, "contact_", 8)) { ast_append_acl(var->name + 8, var->value, &sip_acl->contact_acl, &error, &ignore); + if (error) { + ast_log(LOG_ERROR, "Bad contact ACL '%s' at line '%d' of pjsip.conf\n", + var->value, var->lineno); + } } else { ast_append_acl(var->name, var->value, &sip_acl->acl, &error, &ignore); + if (error) { + ast_log(LOG_ERROR, "Bad ACL '%s' at line '%d' of pjsip.conf\n", + var->value, var->lineno); + } + } + + if (error) { + ast_log(LOG_ERROR, "There is an error in ACL configuration. Blocking ALL SIP traffic.\n"); + ast_append_acl("deny", "0.0.0.0/0.0.0.0", &sip_acl->acl, NULL, &ignore); } return error; diff --git a/tests/test_message.c b/tests/test_message.c index 7140b5f17..26cd90a4d 100644 --- a/tests/test_message.c +++ b/tests/test_message.c @@ -160,7 +160,7 @@ static int verify_user_event_fields(int user_event, const char *header, const ch bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event); } ast_variable_list_append(&bad_headers_head, bad_header); - AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head); + AST_VECTOR_REPLACE(&bad_headers, user_event, bad_headers_head); } regfree(®exbuf); return -1; @@ -492,28 +492,28 @@ AST_TEST_DEFINE(test_message_queue_dialplan_nominal) ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^foo$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^From$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^bar$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Body$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^a body$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Custom$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^field$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 3, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 3, expected_response); ast_msg_set_to(msg, "foo"); ast_msg_set_from(msg, "bar"); @@ -609,21 +609,21 @@ AST_TEST_DEFINE(test_message_queue_both_nominal) ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^foo$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^From$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value","^bar$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response); expected_response = NULL; expected = ast_variable_new("Verify", "^Body$", __FILE__); ast_variable_list_append(&expected_response, expected); expected = ast_variable_new("Value", "^a body$", __FILE__); ast_variable_list_append(&expected_response, expected); - AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response); + AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response); ast_msg_set_to(msg, "foo"); ast_msg_set_from(msg, "bar"); diff --git a/tests/test_vector.c b/tests/test_vector.c new file mode 100644 index 000000000..eae188143 --- /dev/null +++ b/tests/test_vector.c @@ -0,0 +1,428 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Fairview 5 Engineering, LLC + * + * George Joseph <george.joseph@fairview5.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Vector tests + * + * \author George Joseph <george.joseph@fairview5.com> + * + * This module will run some vector tests. + * + * \ingroup tests + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/test.h" +#include "asterisk/utils.h" +#include "asterisk/strings.h" +#include "asterisk/module.h" +#include "asterisk/vector.h" + +#define test_validate_cleanup(condition) ({ \ + if (!(condition)) { \ + ast_test_status_update((test), "%s: %s\n", "Condition failed", #condition); \ + rc = AST_TEST_FAIL; \ + goto cleanup; \ + } \ +}) + +static int cleanup_count; + +static void cleanup(char *element) +{ + cleanup_count++; +} + +AST_TEST_DEFINE(basic_ops) +{ + AST_VECTOR(test_struct, char *) sv1; + int rc = AST_TEST_PASS; + + char *AAA = "AAA"; + char *BBB = "BBB"; + char *CCC = "CCC"; + char *ZZZ = "ZZZ"; + + switch (cmd) { + case TEST_INIT: + info->name = "basic"; + info->category = "/main/vector/"; + info->summary = "Test vector basic ops"; + info->description = "Test vector basic ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(sv1.max >= 4); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC); + + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == AAA); + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "ZZZ", 0 == strcmp) == ZZZ); + + AST_VECTOR_FREE(&sv1); + ast_test_validate(test, sv1.elems == NULL); + ast_test_validate(test, sv1.current == 0); + ast_test_validate(test, sv1.max == 0); + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0); + test_validate_cleanup(sv1.max == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(sv1.max >= 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Overwrite index 1 */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove index 0 and bring the last entry into it's empty slot */ + test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + + /* Replace 0 and 2 leaving 1 alone */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0); + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove 1 and compact preserving order */ + test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + + /* Equivalent of APPEND */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + /* This should fail because comparison is by pointer */ + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, "ZZZ", cleanup) != 0); + + /* This should work because we passing in the specific object to be removed */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* If we want a comparison by value, we need to pass in a comparison + * function. The comparison looks weird but that's what it takes. + */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* This element is gone so we shouldn't be able to find it or delete it again. */ + test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, "AAA", 0 == strcmp) == NULL); + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, "AAA", 0 == strcmp, cleanup) != 0); + + /* CCC should still be there though */ + test_validate_cleanup(*(char **)AST_VECTOR_GET_CMP(&sv1, "CCC", 0 == strcmp) == CCC); + +cleanup: + AST_VECTOR_FREE(&sv1); + return rc; +} + +static void cleanup_int(int element) +{ + cleanup_count++; +} + +AST_TEST_DEFINE(basic_ops_integer) +{ + AST_VECTOR(test_struct, int) sv1; + int rc = AST_TEST_PASS; + + int AAA = 1; + int BBB = 2; + int CCC = 3; + int ZZZ = 26; + + switch (cmd) { + case TEST_INIT: + info->name = "basic integer"; + info->category = "/main/vector/"; + info->summary = "Test integer vector basic ops"; + info->description = "Test integer vector basic ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 3) == 0); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(sv1.max == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + test_validate_cleanup(AST_VECTOR_INSERT_AT(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(sv1.max >= 4); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 4); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 3) == CCC); + + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == AAA); + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, ZZZ, AST_VECTOR_ELEM_DEFAULT_CMP) == ZZZ); + + AST_VECTOR_FREE(&sv1); + ast_test_validate(test, sv1.elems == NULL); + ast_test_validate(test, sv1.current == 0); + ast_test_validate(test, sv1.max == 0); + + ast_test_validate(test, AST_VECTOR_INIT(&sv1, 0) == 0); + test_validate_cleanup(sv1.max == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, AAA) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, BBB) == 0); + test_validate_cleanup(AST_VECTOR_APPEND(&sv1, CCC) == 0); + test_validate_cleanup(sv1.max >= 3); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == BBB); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Overwrite index 1 */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 1, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove index 0 and bring the last entry into it's empty slot */ + test_validate_cleanup(AST_VECTOR_REMOVE_UNORDERED(&sv1, 0) == 1); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + + /* Replace 0 and 2 leaving 1 alone */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 0, AAA) == 0); + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, CCC) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 2) == CCC); + + /* Remove 1 and compact preserving order */ + test_validate_cleanup(AST_VECTOR_REMOVE_ORDERED(&sv1, 1) == ZZZ); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + + /* Equivalent of APPEND */ + test_validate_cleanup(AST_VECTOR_REPLACE(&sv1, 2, ZZZ) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 3); + + /* This should work because we passing in the specific object to be removed */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_ELEM_ORDERED(&sv1, ZZZ, cleanup_int) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 2); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == AAA); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 1) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* If we want a comparison by value, we need to pass in a comparison + * function. + */ + cleanup_count = 0; + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) == 0); + test_validate_cleanup(AST_VECTOR_SIZE(&sv1) == 1); + test_validate_cleanup(AST_VECTOR_GET(&sv1, 0) == CCC); + test_validate_cleanup(cleanup_count == 1); + + /* This element is gone so we shouldn't be able to find it or delete it again. */ + test_validate_cleanup(AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == NULL); + test_validate_cleanup(AST_VECTOR_REMOVE_CMP_ORDERED(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP, cleanup_int) != 0); + + /* CCC should still be there though */ + test_validate_cleanup(*(int *)AST_VECTOR_GET_CMP(&sv1, CCC, AST_VECTOR_ELEM_DEFAULT_CMP) == CCC); + +cleanup: + AST_VECTOR_FREE(&sv1); + return rc; +} + + +static int cb(void *obj, void *arg, void *data) +{ + return strcmp(arg, "ARG") == 0 ? 0 : CMP_STOP; +} + +static int cb_first(void *obj, void *arg, void *data) +{ + return data == arg ? CMP_STOP : 0; +} + +AST_TEST_DEFINE(callbacks) +{ + AST_VECTOR(, char *) sv1; + int rc = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "callbacks"; + info->category = "/main/vector/"; + info->summary = "Test vector callback ops"; + info->description = "Test vector callback ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + AST_VECTOR_INIT(&sv1, 32); + + AST_VECTOR_APPEND(&sv1, "AAA"); + AST_VECTOR_APPEND(&sv1, "BBB"); + AST_VECTOR_APPEND(&sv1, "CCC"); + + test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb, "ARG", test) == 3); + + test_validate_cleanup(AST_VECTOR_CALLBACK(&sv1, cb_first, test, test) == 1); + +cleanup: + AST_VECTOR_FREE(&sv1); + + return rc; +} + +AST_TEST_DEFINE(locks) +{ + AST_VECTOR_RW(, char *) sv1; + int rc = AST_TEST_PASS; + struct timespec ts; + + switch (cmd) { + case TEST_INIT: + info->name = "locks"; + info->category = "/main/vector/"; + info->summary = "Test vector locking ops"; + info->description = "Test vector locking ops"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* We're not actually checking that locking works, + * just that the macro expansions work + */ + + AST_VECTOR_RW_INIT(&sv1, 0); + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TRY(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) != 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TRY(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + + ts.tv_nsec = 0; + ts.tv_sec = 2; + + test_validate_cleanup(AST_VECTOR_RW_RDLOCK_TIMED(&sv1, &ts) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) != 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + test_validate_cleanup(AST_VECTOR_RW_WRLOCK_TIMED(&sv1, &ts) == 0); + test_validate_cleanup(AST_VECTOR_RW_UNLOCK(&sv1) == 0); + +cleanup: + AST_VECTOR_RW_FREE(&sv1); + + return rc; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(locks); + AST_TEST_UNREGISTER(callbacks); + AST_TEST_UNREGISTER(basic_ops_integer); + AST_TEST_UNREGISTER(basic_ops); + + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(locks); + AST_TEST_REGISTER(callbacks); + AST_TEST_REGISTER(basic_ops_integer); + AST_TEST_REGISTER(basic_ops); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Vector test module"); |