diff options
author | Patrick McHardy <kaber@trash.net> | 2011-06-17 08:11:11 +0200 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-06-17 08:11:11 +0200 |
commit | 9364aaccb699c6d19ac2cbe760c208b34ba7838a (patch) | |
tree | 28c0aef25a69f14117caf64e09fc9597d2c915ea /main | |
parent | 84c94e92c153057470194aadf7ae22a2569f1bd4 (diff) | |
parent | 62b90dd0a4ea809bdb11bc27288b6acf717edcd8 (diff) |
Merge 192.168.0.100:/repos/git/asterisk
Diffstat (limited to 'main')
-rw-r--r-- | main/channel.c | 20 | ||||
-rw-r--r-- | main/db.c | 299 | ||||
-rw-r--r-- | main/dnsmgr.c | 8 | ||||
-rw-r--r-- | main/event.c | 29 | ||||
-rw-r--r-- | main/features.c | 99 | ||||
-rw-r--r-- | main/manager.c | 78 | ||||
-rw-r--r-- | main/netsock2.c | 19 | ||||
-rw-r--r-- | main/rtp_engine.c | 21 |
8 files changed, 340 insertions, 233 deletions
diff --git a/main/channel.c b/main/channel.c index 9c9d6ca5a..57629dbc5 100644 --- a/main/channel.c +++ b/main/channel.c @@ -7387,7 +7387,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000)); if ((caller_warning || callee_warning) && config->play_warning) { long next_warn = config->play_warning; - if (time_left_ms < config->play_warning) { + if (time_left_ms < config->play_warning && config->warning_freq > 0) { /* At least one warning was played, which means we are returning after feature */ long warns_passed = (config->play_warning - time_left_ms) / config->warning_freq; /* It is 'warns_passed * warning_freq' NOT '(warns_passed + 1) * warning_freq', @@ -7608,28 +7608,42 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha /*! \brief Sets an option on a channel */ int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block) { + int res; + + ast_channel_lock(chan); if (!chan->tech->setoption) { errno = ENOSYS; + ast_channel_unlock(chan); return -1; } if (block) ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n"); - return chan->tech->setoption(chan, option, data, datalen); + res = chan->tech->setoption(chan, option, data, datalen); + ast_channel_unlock(chan); + + return res; } int ast_channel_queryoption(struct ast_channel *chan, int option, void *data, int *datalen, int block) { + int res; + + ast_channel_lock(chan); if (!chan->tech->queryoption) { errno = ENOSYS; + ast_channel_unlock(chan); return -1; } if (block) ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n"); - return chan->tech->queryoption(chan, option, data, datalen); + res = chan->tech->queryoption(chan, option, data, datalen); + ast_channel_unlock(chan); + + return res; } struct tonepair_def { @@ -100,9 +100,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </manager> ***/ +#define MAX_DB_FIELD 256 + static DB *astdb; AST_MUTEX_DEFINE_STATIC(dblock); static ast_cond_t dbcond; +typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data); static void db_sync(void); @@ -143,15 +146,84 @@ static inline int subkeymatch(const char *key, const char *suffix) return 0; } -int ast_db_deltree(const char *family, const char *keytree) +static const char *dbt_data2str(DBT *dbt) { - char prefix[256]; - DBT key, data; - char *keys; - int res; - int pass; + char *data = ""; + + if (dbt->size) { + data = dbt->data; + data[dbt->size - 1] = '\0'; + } + + return data; +} + +static inline const char *dbt_data2str_full(DBT *dbt, const char *def) +{ + return S_OR(dbt_data2str(dbt), def); +} + +static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync) +{ + DBT key = { 0, }, value = { 0, }, last_key = { 0, }; int counter = 0; - + int res, last = 0; + char last_key_s[MAX_DB_FIELD]; + + ast_mutex_lock(&dblock); + if (dbinit()) { + ast_mutex_unlock(&dblock); + return -1; + } + + /* Somehow, the database can become corrupted such that astdb->seq will continue looping through + * the database indefinitely. The pointer to last_key.data ends up getting re-used by the BDB lib + * so this specifically queries for the last entry, makes a copy of the key, and then uses it as + * a sentinel to avoid repeatedly looping over the list. */ + + if (astdb->seq(astdb, &last_key, &value, R_LAST)) { + /* Empty database */ + ast_mutex_unlock(&dblock); + return 0; + } + + memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s))); + last_key_s[last_key.size - 1] = '\0'; + for (res = astdb->seq(astdb, &key, &value, R_FIRST); + !res; + res = astdb->seq(astdb, &key, &value, R_NEXT)) { + /* The callback might delete the key, so we have to check it before calling */ + last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s); + counter += cb(&key, &value, filter, data); + if (last) { + break; + } + } + + if (sync) { + db_sync(); + } + + ast_mutex_unlock(&dblock); + + return counter; +} + +static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data) +{ + int res = 0; + + if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) { + astdb->del(astdb, key, 0); + res = 1; + } + return res; +} + +int ast_db_deltree(const char *family, const char *keytree) +{ + char prefix[MAX_DB_FIELD]; + if (family) { if (keytree) { snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree); @@ -163,36 +235,13 @@ int ast_db_deltree(const char *family, const char *keytree) } else { prefix[0] = '\0'; } - - ast_mutex_lock(&dblock); - if (dbinit()) { - ast_mutex_unlock(&dblock); - return -1; - } - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - pass = 0; - while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { - if (key.size) { - keys = key.data; - keys[key.size - 1] = '\0'; - } else { - keys = "<bad key>"; - } - if (keymatch(keys, prefix)) { - astdb->del(astdb, &key, 0); - counter++; - } - } - db_sync(); - ast_mutex_unlock(&dblock); - return counter; + + return process_db_keys(db_deltree_cb, NULL, prefix, 1); } int ast_db_put(const char *family, const char *keys, const char *value) { - char fullkey[256]; + char fullkey[MAX_DB_FIELD]; DBT key, data; int res, fullkeylen; @@ -214,12 +263,13 @@ int ast_db_put(const char *family, const char *keys, const char *value) ast_mutex_unlock(&dblock); if (res) ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family); + return res; } int ast_db_get(const char *family, const char *keys, char *value, int valuelen) { - char fullkey[256] = ""; + char fullkey[MAX_DB_FIELD] = ""; DBT key, data; int res, fullkeylen; @@ -263,7 +313,7 @@ int ast_db_get(const char *family, const char *keys, char *value, int valuelen) int ast_db_del(const char *family, const char *keys) { - char fullkey[256]; + char fullkey[MAX_DB_FIELD]; DBT key; int res, fullkeylen; @@ -319,7 +369,7 @@ static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct as static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { int res; - char tmp[256]; + char tmp[MAX_DB_FIELD]; switch (cmd) { case CLI_INIT: @@ -402,13 +452,23 @@ static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struc return CLI_SUCCESS; } +static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data) +{ + struct ast_cli_args *a = data; + const char *key_s = dbt_data2str_full(key, "<bad key>"); + const char *value_s = dbt_data2str_full(value, "<bad value>"); + + if (keymatch(key_s, filter)) { + ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s); + return 1; + } + + return 0; +} + static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char prefix[256]; - DBT key, data; - char *keys, *values; - int res; - int pass; + char prefix[MAX_DB_FIELD]; int counter = 0; switch (cmd) { @@ -435,45 +495,33 @@ static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct a } else { return CLI_SHOWUSAGE; } - ast_mutex_lock(&dblock); - if (dbinit()) { - ast_mutex_unlock(&dblock); + + if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) { ast_cli(a->fd, "Database unavailable\n"); - return CLI_SUCCESS; - } - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - pass = 0; - while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { - if (key.size) { - keys = key.data; - keys[key.size - 1] = '\0'; - } else { - keys = "<bad key>"; - } - if (data.size) { - values = data.data; - values[data.size - 1]='\0'; - } else { - values = "<bad value>"; - } - if (keymatch(keys, prefix)) { - ast_cli(a->fd, "%-50s: %-25s\n", keys, values); - counter++; - } + return CLI_SUCCESS; } - ast_mutex_unlock(&dblock); + ast_cli(a->fd, "%d results found.\n", counter); - return CLI_SUCCESS; + return CLI_SUCCESS; +} + +static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data) +{ + struct ast_cli_args *a = data; + const char *key_s = dbt_data2str_full(key, "<bad key>"); + const char *value_s = dbt_data2str_full(value, "<bad value>"); + + if (subkeymatch(key_s, filter)) { + ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s); + return 1; + } + + return 0; } static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char suffix[256]; - DBT key, data; - char *keys, *values; - int res; - int pass; + char suffix[MAX_DB_FIELD]; int counter = 0; switch (cmd) { @@ -493,48 +541,40 @@ static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struc } else { return CLI_SHOWUSAGE; } - ast_mutex_lock(&dblock); - if (dbinit()) { - ast_mutex_unlock(&dblock); + + if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) { ast_cli(a->fd, "Database unavailable\n"); - return CLI_SUCCESS; - } - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - pass = 0; - while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { - if (key.size) { - keys = key.data; - keys[key.size - 1] = '\0'; - } else { - keys = "<bad key>"; - } - if (data.size) { - values = data.data; - values[data.size - 1]='\0'; - } else { - values = "<bad value>"; - } - if (subkeymatch(keys, suffix)) { - ast_cli(a->fd, "%-50s: %-25s\n", keys, values); - counter++; - } + return CLI_SUCCESS; } - ast_mutex_unlock(&dblock); + ast_cli(a->fd, "%d results found.\n", counter); - return CLI_SUCCESS; + return CLI_SUCCESS; +} + +static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data) +{ + struct ast_db_entry **ret = data; + struct ast_db_entry *cur; + const char *key_s = dbt_data2str_full(key, "<bad key>"); + const char *value_s = dbt_data2str_full(value, "<bad value>"); + size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1; + + if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) { + cur->next = *ret; + cur->key = cur->data + value_slen; + strcpy(cur->data, value_s); + strcpy(cur->key, key_s); + *ret = cur; + return 1; + } + + return 0; } struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree) { - char prefix[256]; - DBT key, data; - char *keys, *values; - int values_len; - int res; - int pass; - struct ast_db_entry *last = NULL; - struct ast_db_entry *cur, *ret=NULL; + char prefix[MAX_DB_FIELD]; + struct ast_db_entry *ret = NULL; if (!ast_strlen_zero(family)) { if (!ast_strlen_zero(keytree)) { @@ -547,44 +587,13 @@ struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree) } else { prefix[0] = '\0'; } - ast_mutex_lock(&dblock); - if (dbinit()) { - ast_mutex_unlock(&dblock); + + if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) { ast_log(LOG_WARNING, "Database unavailable\n"); - return NULL; - } - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - pass = 0; - while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) { - if (key.size) { - keys = key.data; - keys[key.size - 1] = '\0'; - } else { - keys = "<bad key>"; - } - if (data.size) { - values = data.data; - values[data.size - 1] = '\0'; - } else { - values = "<bad value>"; - } - values_len = strlen(values) + 1; - if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) { - cur->next = NULL; - cur->key = cur->data + values_len; - strcpy(cur->data, values); - strcpy(cur->key, keys); - if (last) { - last->next = cur; - } else { - ret = cur; - } - last = cur; - } + return NULL; } - ast_mutex_unlock(&dblock); - return ret; + + return ret; } void ast_db_freetree(struct ast_db_entry *dbe) @@ -637,7 +646,7 @@ static int manager_dbget(struct mansession *s, const struct message *m) char idText[256] = ""; const char *family = astman_get_header(m, "Family"); const char *key = astman_get_header(m, "Key"); - char tmp[256]; + char tmp[MAX_DB_FIELD]; int res; if (ast_strlen_zero(family)) { diff --git a/main/dnsmgr.c b/main/dnsmgr.c index 23e1ab6ef..999bd92f4 100644 --- a/main/dnsmgr.c +++ b/main/dnsmgr.c @@ -131,6 +131,14 @@ int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_ return 0; } + /* + * If it's actually an IP address and not a name, there's no + * need for a managed lookup. + */ + if (ast_sockaddr_parse(result, name, PARSE_PORT_FORBID)) { + return 0; + } + ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name); /* do a lookup now but add a manager so it will automagically get updated in the background */ diff --git a/main/event.c b/main/event.c index 246821eac..fad8e66ee 100644 --- a/main/event.c +++ b/main/event.c @@ -381,12 +381,12 @@ static int match_sub_ie_val_to_event(const struct ast_event_ie_val *sub_ie_val, int res = 0; AST_LIST_TRAVERSE(&check_ie_vals->ie_vals, event_ie_val, entry) { - if (event_ie_val->ie_type == sub_ie_val->ie_type) { + if (sub_ie_val->ie_type == event_ie_val->ie_type) { break; } } if (!event_ie_val) { - /* The did not find the event ie the subscriber cares about. */ + /* We did not find the event ie the subscriber cares about. */ return 0; } @@ -444,12 +444,14 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ }; const enum ast_event_type event_types[] = { type, AST_EVENT_ALL }; int i; + int want_specific_event;/* TRUE if looking for subscribers wanting specific parameters. */ if (type >= AST_EVENT_TOTAL) { ast_log(LOG_ERROR, "%u is an invalid type!\n", type); return res; } + want_specific_event = 0; va_start(ap, type); for (ie_type = va_arg(ap, enum ast_event_ie_type); ie_type != AST_EVENT_IE_END; @@ -492,6 +494,7 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ } if (insert) { + want_specific_event = 1; AST_LIST_INSERT_TAIL(&check_ie_vals.ie_vals, ie_value, entry); } else { ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype); @@ -501,17 +504,22 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ for (i = 0; i < ARRAY_LEN(event_types); i++) { AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]); - AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) { - AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { - if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) { - /* The current subscription ie did not match an event ie. */ + if (want_specific_event) { + AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) { + AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { + if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) { + /* The current subscription ie did not match an event ie. */ + break; + } + } + if (!ie_val) { + /* Everything matched. A subscriber is looking for this event. */ break; } } - if (!ie_val) { - /* Everything matched. A subscriber is looking for this event. */ - break; - } + } else { + /* Just looking to see if there are ANY subscribers to the event type. */ + sub = AST_RWLIST_FIRST(&ast_event_subs[event_types[i]]); } AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]); if (sub) { @@ -1340,6 +1348,7 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...) void *data = va_arg(ap, void *); size_t datalen = va_arg(ap, size_t); ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen); + break; } case AST_EVENT_IE_PLTYPE_EXISTS: ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n"); diff --git a/main/features.c b/main/features.c index 81421f17b..728118188 100644 --- a/main/features.c +++ b/main/features.c @@ -577,7 +577,7 @@ static const struct ast_datastore_info dial_features_info = { .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, - }; +}; /* Forward declarations */ static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot); @@ -2898,8 +2898,12 @@ int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, con /*! \brief Check if a feature exists */ static int feature_check(struct ast_channel *chan, struct ast_flags *features, char *code) { + char *chan_dynamic_features; + ast_channel_lock(chan); + chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); + ast_channel_unlock(chan); - return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_CHECK, NULL); + return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); } static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) @@ -5747,17 +5751,42 @@ static int manager_park(struct mansession *s, const struct message *m) return 0; } +/*! + * The presence of this datastore on the channel indicates that + * someone is attemting to pickup or has picked up the channel. + * The purpose is to prevent a race between two channels + * attempting to pickup the same channel. + */ +static const struct ast_datastore_info pickup_active = { + .type = "pickup-active", +}; + +int ast_can_pickup(struct ast_channel *chan) +{ + if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) + && (chan->_state == AST_STATE_RINGING + || chan->_state == AST_STATE_RING + /* + * Check the down state as well because some SIP devices do not + * give 180 ringing when they can just give 183 session progress + * instead. Issue 14005. (Some ISDN switches as well for that + * matter.) + */ + || chan->_state == AST_STATE_DOWN) + && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { + return 1; + } + return 0; +} + static int find_channel_by_group(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ ast_channel_lock(target); - if (chan != target && (chan->pickupgroup & target->callgroup) && - !target->pbx && - ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING)) && - !target->masq && - !ast_test_flag(target, AST_FLAG_ZOMBIE)) { + if (chan != target && (chan->pickupgroup & target->callgroup) + && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } @@ -5808,23 +5837,30 @@ int ast_pickup_call(struct ast_channel *chan) return res; } -/*! - * \brief Pickup a call target, Common Code. - * \param chan channel that initiated pickup. - * \param target channel. - * - * Answer calling channel, flag channel as answered on queue, masq channels together. - */ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) { struct ast_party_connected_line connected_caller; struct ast_channel *chans[2] = { chan, target }; + struct ast_datastore *ds_pickup; + const char *chan_name;/*!< A masquerade changes channel names. */ + const char *target_name;/*!< A masquerade changes channel names. */ + int res = -1; - ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name); - ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); + target_name = ast_strdupa(target->name); + ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); + + /* Mark the target to block any call pickup race. */ + ds_pickup = ast_datastore_alloc(&pickup_active, NULL); + if (!ds_pickup) { + ast_log(LOG_WARNING, + "Unable to create channel datastore on '%s' for call pickup\n", target_name); + return -1; + } + ast_channel_datastore_add(target, ds_pickup); ast_party_connected_line_init(&connected_caller); ast_party_connected_line_copy(&connected_caller, &target->connected); + ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { ast_channel_update_connected_line(chan, &connected_caller, NULL); @@ -5832,37 +5868,48 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) ast_party_connected_line_free(&connected_caller); ast_channel_lock(chan); + chan_name = ast_strdupa(chan->name); ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); ast_channel_unlock(chan); connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); ast_party_connected_line_free(&connected_caller); + ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); + if (ast_answer(chan)) { - ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); - return -1; + ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); + goto pickup_failed; } if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { - ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); - return -1; + ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); + goto pickup_failed; } if (ast_channel_masquerade(target, chan)) { - ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); - return -1; + ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, + target_name); + goto pickup_failed; } /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, - "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name); + "Channel: %s\r\n" + "TargetChannel: %s\r\n", + chan_name, target_name); - /* Do the masquerade manually to make sure that is is completed. */ - ast_channel_unlock(target); + /* Do the masquerade manually to make sure that it is completed. */ ast_do_masquerade(target); + res = 0; + +pickup_failed: ast_channel_lock(target); + if (!ast_channel_datastore_remove(target, ds_pickup)) { + ast_datastore_free(ds_pickup); + } - return 0; + return res; } static char *app_bridge = "Bridge"; diff --git a/main/manager.c b/main/manager.c index ea2e2a975..c4d1e1101 100644 --- a/main/manager.c +++ b/main/manager.c @@ -5480,6 +5480,39 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *g } } +static void process_output(struct mansession *s, struct ast_str *out, struct ast_variable *params, enum output_format format) +{ + char *buf; + size_t l; + + if (!s->f) + return; + + /* Ensure buffer is NULL-terminated */ + fprintf(s->f, "%c", 0); + fflush(s->f); + + if ((l = ftell(s->f))) { + if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) { + ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); + } else { + if (format == FORMAT_XML || format == FORMAT_HTML) { + xml_translate(&out, buf, params, format); + } else { + ast_str_append(&out, 0, "%s", buf); + } + munmap(buf, l); + } + } else if (format == FORMAT_XML || format == FORMAT_HTML) { + xml_translate(&out, "", params, format); + } + + fclose(s->f); + s->f = NULL; + close(s->fd); + s->fd = -1; +} + static int generic_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, @@ -5629,29 +5662,7 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser, ast_str_append(&out, 0, ROW_FMT, TEST_STRING); } - if (s.f != NULL) { /* have temporary output */ - char *buf; - size_t l; - - if ((l = ftell(s.f))) { - if (MAP_FAILED == (buf = mmap(NULL, l + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) { - ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); - } else { - buf[l] = '\0'; - if (format == FORMAT_XML || format == FORMAT_HTML) { - xml_translate(&out, buf, params, format); - } else { - ast_str_append(&out, 0, "%s", buf); - } - munmap(buf, l + 1); - } - } else if (format == FORMAT_XML || format == FORMAT_HTML) { - xml_translate(&out, "", params, format); - } - fclose(s.f); - s.f = NULL; - s.fd = -1; - } + process_output(&s, out, params, format); if (format == FORMAT_XML) { ast_str_append(&out, 0, "</ajax-response>\n"); @@ -5963,26 +5974,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n"); } - if (s.f != NULL) { /* have temporary output */ - char *buf; - size_t l = ftell(s.f); - - if (l) { - if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) { - if (format == FORMAT_XML || format == FORMAT_HTML) { - xml_translate(&out, buf, params, format); - } else { - ast_str_append(&out, 0, "%s", buf); - } - munmap(buf, l); - } - } else if (format == FORMAT_XML || format == FORMAT_HTML) { - xml_translate(&out, "", params, format); - } - fclose(s.f); - s.f = NULL; - s.fd = -1; - } + process_output(&s, out, params, format); if (format == FORMAT_XML) { ast_str_append(&out, 0, "</ajax-response>\n"); diff --git a/main/netsock2.c b/main/netsock2.c index 25f15a2fc..d6561fba2 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -121,8 +121,10 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format) int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags) { char *s = str; + char *orig_str = str;/* Original string in case the port presence is incorrect. */ + char *host_end = NULL;/* Delay terminating the host in case the port presence is incorrect. */ - ast_debug(5, "Splitting '%s' gives...\n", str); + ast_debug(5, "Splitting '%s' into...\n", str); *host = NULL; *port = NULL; if (*s == '[') { @@ -130,7 +132,8 @@ int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags) for (; *s && *s != ']'; ++s) { } if (*s == ']') { - *s++ = '\0'; + host_end = s; + ++s; } if (*s == ':') { *port = s + 1; @@ -148,11 +151,10 @@ int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags) } } if (*port) { - **port = '\0'; + host_end = *port; ++*port; } } - ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port); switch (flags & PARSE_PORT_MASK) { case PARSE_PORT_IGNORE: @@ -160,18 +162,23 @@ int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags) break; case PARSE_PORT_REQUIRE: if (*port == NULL) { - ast_log(LOG_WARNING, "missing port\n"); + ast_log(LOG_WARNING, "Port missing in %s\n", orig_str); return 0; } break; case PARSE_PORT_FORBID: if (*port != NULL) { - ast_log(LOG_WARNING, "port disallowed\n"); + ast_log(LOG_WARNING, "Port disallowed in %s\n", orig_str); return 0; } break; } + /* Can terminate the host string now if needed. */ + if (host_end) { + *host_end = '\0'; + } + ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port ? *port : ""); return 1; } diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 3c5ef8b36..a1c460578 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -66,6 +66,8 @@ struct ast_rtp_instance { int timeout; /*! RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */ int holdtimeout; + /*! RTP keepalive interval */ + int keepalive; /*! DTMF mode in use */ enum ast_rtp_dtmf_mode dtmf_mode; /*! Glue currently in use */ @@ -1781,6 +1783,11 @@ void ast_rtp_instance_set_hold_timeout(struct ast_rtp_instance *instance, int ti instance->holdtimeout = timeout; } +void ast_rtp_instance_set_keepalive(struct ast_rtp_instance *instance, int interval) +{ + instance->keepalive = interval; +} + int ast_rtp_instance_get_timeout(struct ast_rtp_instance *instance) { return instance->timeout; @@ -1791,6 +1798,11 @@ int ast_rtp_instance_get_hold_timeout(struct ast_rtp_instance *instance) return instance->holdtimeout; } +int ast_rtp_instance_get_keepalive(struct ast_rtp_instance *instance) +{ + return instance->keepalive; +} + struct ast_rtp_engine *ast_rtp_instance_get_engine(struct ast_rtp_instance *instance) { return instance->engine; @@ -1850,6 +1862,15 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance) return instance->srtp; } +int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level) +{ + if (instance->engine->sendcng) { + return instance->engine->sendcng(instance, level); + } + + return -1; +} + static void set_next_mime_type(const struct ast_format *format, int rtp_code, char *type, char *subtype, unsigned int sample_rate) { int x = mime_types_len; |