mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-09 11:28:25 +00:00
Merge "ARI: Detect duplicate channel IDs" into 13
This commit is contained in:
@@ -4669,4 +4669,16 @@ int ast_channel_feature_hooks_append(struct ast_channel *chan, struct ast_bridge
|
||||
*/
|
||||
int ast_channel_feature_hooks_replace(struct ast_channel *chan, struct ast_bridge_features *features);
|
||||
|
||||
enum ast_channel_error {
|
||||
/* Unable to determine what error occurred. */
|
||||
AST_CHANNEL_ERROR_UNKNOWN,
|
||||
/* Channel with this ID already exists */
|
||||
AST_CHANNEL_ERROR_ID_EXISTS,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Get error code for latest channel operation.
|
||||
*/
|
||||
enum ast_channel_error ast_channel_errno(void);
|
||||
|
||||
#endif /* _ASTERISK_CHANNEL_H */
|
||||
|
||||
@@ -25,3 +25,5 @@ int ast_channel_internal_is_finalized(struct ast_channel *chan);
|
||||
void ast_channel_internal_cleanup(struct ast_channel *chan);
|
||||
int ast_channel_internal_setup_topics(struct ast_channel *chan);
|
||||
|
||||
void ast_channel_internal_errno_set(enum ast_channel_error error);
|
||||
enum ast_channel_error ast_channel_internal_errno(void);
|
||||
|
||||
@@ -767,6 +767,27 @@ static const struct ast_channel_tech null_tech = {
|
||||
|
||||
static void ast_channel_destructor(void *obj);
|
||||
static void ast_dummy_channel_destructor(void *obj);
|
||||
static int ast_channel_by_uniqueid_cb(void *obj, void *arg, void *data, int flags);
|
||||
|
||||
static int does_id_conflict(const char *uniqueid)
|
||||
{
|
||||
struct ast_channel *conflict;
|
||||
int length = 0;
|
||||
|
||||
if (ast_strlen_zero(uniqueid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
conflict = ast_channel_callback(ast_channel_by_uniqueid_cb, (char *) uniqueid, &length, OBJ_NOLOCK);
|
||||
if (conflict) {
|
||||
ast_log(LOG_ERROR, "Channel Unique ID '%s' already in use by channel %s(%p)\n",
|
||||
uniqueid, ast_channel_name(conflict), conflict);
|
||||
ast_channel_unref(conflict);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Create a new channel structure */
|
||||
static struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 0)))
|
||||
@@ -940,16 +961,33 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
|
||||
ast_channel_tech_set(tmp, &null_tech);
|
||||
}
|
||||
|
||||
ast_channel_internal_finalize(tmp);
|
||||
|
||||
ast_atomic_fetchadd_int(&chancount, +1);
|
||||
|
||||
/* You might scream "locking inversion" at seeing this but it is actually perfectly fine.
|
||||
* Since the channel was just created nothing can know about it yet or even acquire it.
|
||||
*/
|
||||
ast_channel_lock(tmp);
|
||||
|
||||
ao2_link(channels, tmp);
|
||||
ao2_lock(channels);
|
||||
|
||||
if (assignedids && (does_id_conflict(assignedids->uniqueid) || does_id_conflict(assignedids->uniqueid2))) {
|
||||
ast_channel_internal_errno_set(AST_CHANNEL_ERROR_ID_EXISTS);
|
||||
ao2_unlock(channels);
|
||||
/* This is a bit unorthodox, but we can't just call ast_channel_stage_snapshot_done()
|
||||
* because that will result in attempting to publish the channel snapshot. That causes
|
||||
* badness in some places, such as CDRs. So we need to manually clear the flag on the
|
||||
* channel that says that a snapshot is being cleared.
|
||||
*/
|
||||
ast_clear_flag(ast_channel_flags(tmp), AST_FLAG_SNAPSHOT_STAGE);
|
||||
ast_channel_unlock(tmp);
|
||||
return ast_channel_unref(tmp);
|
||||
}
|
||||
|
||||
ast_channel_internal_finalize(tmp);
|
||||
|
||||
ast_atomic_fetchadd_int(&chancount, +1);
|
||||
|
||||
ao2_link_flags(channels, tmp, OBJ_NOLOCK);
|
||||
|
||||
ao2_unlock(channels);
|
||||
|
||||
if (endpoint) {
|
||||
ast_endpoint_add_channel(endpoint, tmp);
|
||||
@@ -10842,3 +10880,8 @@ int ast_channel_feature_hooks_replace(struct ast_channel *chan, struct ast_bridg
|
||||
{
|
||||
return channel_feature_hooks_set_full(chan, features, 1);
|
||||
}
|
||||
|
||||
enum ast_channel_error ast_channel_errno(void)
|
||||
{
|
||||
return ast_channel_internal_errno();
|
||||
}
|
||||
|
||||
@@ -1484,6 +1484,7 @@ static int pvt_cause_cmp_fn(void *obj, void *vstr, int flags)
|
||||
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function)
|
||||
{
|
||||
struct ast_channel *tmp;
|
||||
|
||||
#if defined(REF_DEBUG)
|
||||
tmp = __ao2_alloc_debug(sizeof(*tmp), destructor,
|
||||
AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 1);
|
||||
@@ -1675,3 +1676,25 @@ int ast_channel_internal_setup_topics(struct ast_channel *chan)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_THREADSTORAGE(channel_errno);
|
||||
|
||||
void ast_channel_internal_errno_set(enum ast_channel_error error)
|
||||
{
|
||||
enum ast_channel_error *error_code = ast_threadstorage_get(&channel_errno, sizeof(*error_code));
|
||||
if (!error_code) {
|
||||
return;
|
||||
}
|
||||
|
||||
*error_code = error;
|
||||
}
|
||||
|
||||
enum ast_channel_error ast_channel_internal_errno(void)
|
||||
{
|
||||
enum ast_channel_error *error_code = ast_threadstorage_get(&channel_errno, sizeof(*error_code));
|
||||
if (!error_code) {
|
||||
return AST_CHANNEL_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return *error_code;
|
||||
}
|
||||
|
||||
@@ -1109,7 +1109,12 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
|
||||
}
|
||||
|
||||
if (ast_dial_prerun(dial, other, format_cap)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
if (ast_channel_errno() == AST_CHANNEL_ERROR_ID_EXISTS) {
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Channel with given unique ID already exists");
|
||||
} else {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
}
|
||||
ast_dial_destroy(dial);
|
||||
ast_free(origination);
|
||||
ast_channel_cleanup(other);
|
||||
|
||||
@@ -253,6 +253,7 @@ static void ast_ari_channels_originate_cb(
|
||||
case 500: /* Internal Server Error */
|
||||
case 501: /* Not Implemented */
|
||||
case 400: /* Invalid parameters for originating a channel. */
|
||||
case 409: /* Channel with given unique ID already exists. */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -483,6 +484,7 @@ static void ast_ari_channels_originate_with_id_cb(
|
||||
case 500: /* Internal Server Error */
|
||||
case 501: /* Not Implemented */
|
||||
case 400: /* Invalid parameters for originating a channel. */
|
||||
case 409: /* Channel with given unique ID already exists. */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -142,6 +142,10 @@
|
||||
{
|
||||
"code": 400,
|
||||
"reason": "Invalid parameters for originating a channel."
|
||||
},
|
||||
{
|
||||
"code": 409,
|
||||
"reason": "Channel with given unique ID already exists."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -298,6 +302,10 @@
|
||||
{
|
||||
"code": 400,
|
||||
"reason": "Invalid parameters for originating a channel."
|
||||
},
|
||||
{
|
||||
"code": 409,
|
||||
"reason": "Channel with given unique ID already exists."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user