Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 59043) +++ channels/chan_iax2.c (working copy) @@ -854,6 +854,8 @@ static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime); static void destroy_user(struct iax2_user *user); static void prune_peers(void); +static void *iax2_dup_variable_datastore(void *); +static void iax2_free_variable_datastore(void *); static const struct ast_channel_tech iax2_tech = { .type = "IAX2", @@ -880,6 +882,42 @@ .fixup = iax2_fixup, }; +static struct ast_datastore_info iax2_variable_datastore_info = { + .type = "IAX2_VARIABLE", + .duplicate = iax2_dup_variable_datastore, + .destroy = iax2_free_variable_datastore, +}; + +static void *iax2_dup_variable_datastore(void *old) +{ + AST_LIST_HEAD(, ast_var_t) *oldlist = old, *newlist; + struct ast_var_t *oldvar, *newvar; + + newlist = ast_calloc(sizeof(*oldlist), 1); + AST_LIST_HEAD_INIT(newlist); + AST_LIST_LOCK(oldlist); + AST_LIST_TRAVERSE(oldlist, oldvar, entries) { + newvar = ast_var_assign(ast_var_name(oldvar), ast_var_value(oldvar)); + AST_LIST_INSERT_TAIL(newlist, newvar, entries); + } + AST_LIST_UNLOCK(oldlist); + return newlist; +} + +static void iax2_free_variable_datastore(void *old) +{ + AST_LIST_HEAD(, ast_var_t) *oldlist = old; + struct ast_var_t *oldvar; + + AST_LIST_LOCK(oldlist); + while ((oldvar = AST_LIST_REMOVE_HEAD(oldlist, entries))) { + ast_free(oldvar); + } + AST_LIST_UNLOCK(oldlist); + AST_LIST_HEAD_DESTROY(oldlist); + ast_free(oldlist); +} + static void insert_idle_thread(struct iax2_thread *thread) { if (thread->type == IAX_THREAD_TYPE_DYNAMIC) { @@ -2921,6 +2959,7 @@ struct parsed_dial_string pds; struct create_addr_info cai; struct ast_var_t *var; + struct ast_datastore *variablestore = ast_channel_datastore_find(c, &iax2_variable_datastore_info, NULL); if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "Channel is already in use (%s)?\n", c->name); @@ -3045,16 +3084,19 @@ iaxs[callno]->sockfd = cai.sockfd; /* Add remote vars */ - AST_LIST_TRAVERSE(&c->varshead, var, entries) { - if (!strncmp(ast_var_name(var), "~IAX2~", strlen("~IAX2~"))) { + if (variablestore) { + AST_LIST_HEAD(, ast_var_t) *variablelist = variablestore->data; + AST_LIST_LOCK(variablelist); + AST_LIST_TRAVERSE(variablelist, var, entries) { char tmp[256]; int i; /* Automatically divide the value up into sized chunks */ - for (i = 0; i < strlen(ast_var_value(var)); i += 255 - (strlen(ast_var_name(var)) - strlen("~IAX2~") + 1)) { - snprintf(tmp, sizeof(tmp), "%s=%s", ast_var_name(var) + strlen("~IAX2~"), ast_var_value(var) + i); + for (i = 0; i < strlen(ast_var_value(var)); i += 255 - (strlen(ast_var_name(var)) + 1)) { + snprintf(tmp, sizeof(tmp), "%s=%s", ast_var_name(var), ast_var_value(var) + i); iax_ie_append_str(&ied, IAX_IE_VARIABLE, tmp); } } + AST_LIST_UNLOCK(variablelist); } /* Transmit the string in a "NEW" request */ @@ -3062,7 +3104,7 @@ ast_mutex_unlock(&iaxsl[callno]); ast_setstate(c, AST_STATE_RINGING); - + return 0; } @@ -3400,6 +3442,7 @@ struct ast_channel *tmp; struct chan_iax2_pvt *i; struct ast_variable *v = NULL; + struct ast_datastore *variablestore = NULL; if (!(i = iaxs[callno])) { ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno); @@ -3455,8 +3498,32 @@ } } - for (v = i->vars ; v ; v = v->next) - pbx_builtin_setvar_helper(tmp, v->name, v->value); + /* Set inherited variables */ + if (i->vars) { + AST_LIST_HEAD(, ast_var_t) *varlist; + varlist = ast_calloc(1, sizeof(*varlist)); + variablestore = ast_channel_datastore_alloc(&iax2_variable_datastore_info, NULL); + if (variablestore && varlist) { + variablestore->data = varlist; + variablestore->inheritance = DATASTORE_INHERIT_FOREVER; + AST_LIST_HEAD_INIT(varlist); + for (v = i->vars ; v ; v = v->next) { + struct ast_var_t *newvar = ast_var_assign(v->name, v->value); + if (!newvar) { + ast_log(LOG_ERROR, "Out of memory\n"); + break; + } + AST_LIST_INSERT_TAIL(varlist, newvar, entries); + } + ast_channel_datastore_add(tmp, variablestore); + } else { + ast_log(LOG_ERROR, "Out of memory\n"); + if (variablestore) + ast_channel_datastore_free(variablestore); + if (varlist) + ast_free(varlist); + } + } ast_module_ref(ast_module_info->self); return tmp; @@ -5336,6 +5403,42 @@ } if (ies->encmethods) ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED); + if (!res) { + struct ast_datastore *variablestore; + struct ast_variable *var, *prev = NULL; + AST_LIST_HEAD(, ast_var_t) *varlist; + varlist = ast_calloc(1, sizeof(*varlist)); + variablestore = ast_channel_datastore_alloc(&iax2_variable_datastore_info, NULL); + if (variablestore && varlist && p->owner) { + variablestore->data = varlist; + variablestore->inheritance = DATASTORE_INHERIT_FOREVER; + AST_LIST_HEAD_INIT(varlist); + for (var = ies->vars; var; var = var->next) { + struct ast_var_t *newvar = ast_var_assign(var->name, var->value); + if (prev) + ast_free(prev); + prev = var; + if (!newvar) { + /* Don't abort list traversal, as this would leave ies->vars in an inconsistent state. */ + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + } else { + AST_LIST_INSERT_TAIL(varlist, newvar, entries); + } + } + if (prev) + free(prev); + ies->vars = NULL; + ast_channel_datastore_add(p->owner, variablestore); + } else { + if (p->owner) + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + if (variablestore) + ast_channel_datastore_free(variablestore); + if (varlist) + ast_free(varlist); + } + } + if (!res) res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1); return res; @@ -6517,20 +6620,57 @@ static int acf_iaxvar_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - const char *value; - char tmp[256]; - snprintf(tmp, sizeof(tmp), "~IAX2~%s", data); - value = pbx_builtin_getvar_helper(chan, tmp); - ast_copy_string(buf, value ? value : "", len); + struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL); + AST_LIST_HEAD(, ast_var_t) *varlist; + struct ast_var_t *var; + if (!variablestore) { + *buf = '\0'; + return 0; + } + + AST_LIST_LOCK(varlist); + AST_LIST_TRAVERSE(varlist, var, entries) { + if (strcmp(var->name, data) == 0) { + ast_copy_string(buf, var->value, len); + break; + } + } + AST_LIST_UNLOCK(varlist); return 0; } -static int acf_iaxvar_write(struct ast_channel *chan, const char *cmd, char *varname, const char *value) +static int acf_iaxvar_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { - char tmp[256]; - /* Inherit forever */ - snprintf(tmp, sizeof(tmp), "__~IAX2~%s", varname); - pbx_builtin_setvar_helper(chan, tmp, value); + struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL); + AST_LIST_HEAD(, ast_var_t) *varlist; + struct ast_var_t *var; + + if (!variablestore) { + variablestore = ast_channel_datastore_alloc(&iax2_variable_datastore_info, NULL); + if (!variablestore) { + ast_log(LOG_ERROR, "Memory allocation error\n"); + return -1; + } + varlist = ast_calloc(1, sizeof(*varlist)); + AST_LIST_HEAD_INIT(varlist); + variablestore->data = varlist; + variablestore->inheritance = DATASTORE_INHERIT_FOREVER; + ast_channel_datastore_add(chan, variablestore); + } else + varlist = variablestore->data; + + AST_LIST_LOCK(varlist); + AST_LIST_TRAVERSE_SAFE_BEGIN(varlist, var, entries) { + if (strcmp(var->name, data) == 0) { + AST_LIST_REMOVE_CURRENT(varlist, entries); + ast_var_delete(var); + break; + } + } + AST_LIST_TRAVERSE_SAFE_END + var = ast_var_assign(data, value); + AST_LIST_INSERT_TAIL(varlist, var, entries); + AST_LIST_UNLOCK(varlist); return 0; } @@ -7099,16 +7239,38 @@ if(!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format))) iax2_destroy(fr->callno); else if (ies.vars) { + struct ast_datastore *variablestore; struct ast_variable *var, *prev = NULL; - char tmp[256]; - for (var = ies.vars; var; var = var->next) { + AST_LIST_HEAD(, ast_var_t) *varlist; + varlist = ast_calloc(1, sizeof(*varlist)); + variablestore = ast_channel_datastore_alloc(&iax2_variable_datastore_info, NULL); + if (variablestore && varlist) { + variablestore->data = varlist; + variablestore->inheritance = DATASTORE_INHERIT_FOREVER; + AST_LIST_HEAD_INIT(varlist); + for (var = ies.vars; var; var = var->next) { + struct ast_var_t *newvar = ast_var_assign(var->name, var->value); + if (prev) + ast_free(prev); + prev = var; + if (!newvar) { + /* Don't abort list traversal, as this would leave ies.vars in an inconsistent state. */ + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + } else { + AST_LIST_INSERT_TAIL(varlist, newvar, entries); + } + } if (prev) free(prev); - prev = var; - snprintf(tmp, sizeof(tmp), "__~IAX2~%s", var->name); - pbx_builtin_setvar_helper(c, tmp, var->value); + ies.vars = NULL; + ast_channel_datastore_add(c, variablestore); + } else { + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + if (variablestore) + ast_channel_datastore_free(variablestore); + if (varlist) + ast_free(varlist); } - ies.vars = NULL; } } else { ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD); @@ -7495,8 +7657,42 @@ using_prefs); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); - if(!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format))) + if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format))) iax2_destroy(fr->callno); + else if (ies.vars) { + struct ast_datastore *variablestore; + struct ast_variable *var, *prev = NULL; + AST_LIST_HEAD(, ast_var_t) *varlist; + varlist = ast_calloc(1, sizeof(*varlist)); + variablestore = ast_channel_datastore_alloc(&iax2_variable_datastore_info, NULL); + if (variablestore && varlist) { + variablestore->data = varlist; + variablestore->inheritance = DATASTORE_INHERIT_FOREVER; + AST_LIST_HEAD_INIT(varlist); + for (var = ies.vars; var; var = var->next) { + struct ast_var_t *newvar = ast_var_assign(var->name, var->value); + if (prev) + ast_free(prev); + prev = var; + if (!newvar) { + /* Don't abort list traversal, as this would leave ies.vars in an inconsistent state. */ + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + } else { + AST_LIST_INSERT_TAIL(varlist, newvar, entries); + } + } + if (prev) + free(prev); + ies.vars = NULL; + ast_channel_datastore_add(c, variablestore); + } else { + ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n"); + if (variablestore) + ast_channel_datastore_free(variablestore); + if (varlist) + ast_free(varlist); + } + } } else { ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD); /* If this is a TBD call, we're ready but now what... */