mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Add reload support to chan_skinny.
Special thanks goes to DEA who had to redo this patch twice because we first put unload/load support in and later redid the way we configure devices and lines. (closes issue #10297) Reported by: DEA Patches: skinny-reload-trunkv2.diff uploaded by wedhorn (license 30) skinny-reload-trunk-v4.txt uploaded by DEA (license 3) With mods by me based on feedback from wedhorn and Russell and seanbright Tested by: DEA, mvanbaak, pj Review: http://reviewboard.digium.com/r/130/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@179122 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -970,6 +970,7 @@ int skinny_header_size = 12;
|
||||
*****************************/
|
||||
|
||||
static int skinnydebug = 0;
|
||||
static int skinnyreload = 0;
|
||||
|
||||
/* a hostname, portnumber, socket and such is usefull for VoIP protocols */
|
||||
static struct sockaddr_in bindaddr;
|
||||
@@ -1181,7 +1182,8 @@ struct skinny_subchannel {
|
||||
int immediate; \
|
||||
int hookstate; \
|
||||
int nat; \
|
||||
int canreinvite;
|
||||
int canreinvite; \
|
||||
int prune;
|
||||
|
||||
struct skinny_line {
|
||||
SKINNY_LINE_OPTIONS
|
||||
@@ -1212,6 +1214,7 @@ struct skinny_line_options{
|
||||
.capability = 0,
|
||||
.getforward = 0,
|
||||
.needdestroy = 0,
|
||||
.prune = 0,
|
||||
.hookstate = SKINNY_ONHOOK,
|
||||
};
|
||||
struct skinny_line_options *default_line = &default_line_struct;
|
||||
@@ -1256,7 +1259,8 @@ struct skinny_addon {
|
||||
int transfer; \
|
||||
int callwaiting; \
|
||||
int mwiblink; \
|
||||
int dnd;
|
||||
int dnd; \
|
||||
int prune;
|
||||
|
||||
struct skinny_device {
|
||||
SKINNY_DEVICE_OPTIONS
|
||||
@@ -1284,6 +1288,7 @@ struct skinny_device_options{
|
||||
.dnd = 0,
|
||||
.confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
|
||||
.capability = 0,
|
||||
.prune = 0,
|
||||
};
|
||||
struct skinny_device_options *default_device = &default_device_struct;
|
||||
|
||||
@@ -1324,6 +1329,7 @@ static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
|
||||
static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
|
||||
static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s);
|
||||
static void mwi_event_cb(const struct ast_event *event, void *userdata);
|
||||
static int skinny_reload(void);
|
||||
|
||||
static const struct ast_channel_tech skinny_tech = {
|
||||
.type = "Skinny",
|
||||
@@ -2718,6 +2724,27 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
|
||||
}
|
||||
}
|
||||
|
||||
static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "skinny reload";
|
||||
e->usage =
|
||||
"Usage: skinny reload\n"
|
||||
" Reloads the chan_skinny configuration\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != e->args)
|
||||
return CLI_SHOWUSAGE;
|
||||
|
||||
skinny_reload();
|
||||
return CLI_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
static char *complete_skinny_devices(const char *word, int state)
|
||||
{
|
||||
struct skinny_device *d;
|
||||
@@ -3521,6 +3548,7 @@ static struct ast_cli_entry cli_skinny[] = {
|
||||
AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"),
|
||||
AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"),
|
||||
AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"),
|
||||
AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"),
|
||||
};
|
||||
|
||||
static void start_rtp(struct skinny_subchannel *sub)
|
||||
@@ -6786,7 +6814,7 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||
if (type & (TYPE_DEVICE)) {
|
||||
struct skinny_line *l;
|
||||
AST_LIST_TRAVERSE(&lines, l, all) {
|
||||
if (!strcasecmp(v->value, l->name)) {
|
||||
if (!strcasecmp(v->value, l->name) && !l->prune) {
|
||||
|
||||
/* FIXME: temp solution about line conflicts */
|
||||
struct skinny_device *d;
|
||||
@@ -6794,7 +6822,7 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||
int lineinuse = 0;
|
||||
AST_LIST_TRAVERSE(&devices, d, list) {
|
||||
AST_LIST_TRAVERSE(&d->lines, l2, list) {
|
||||
if (l2 == l) {
|
||||
if (l2 == l && strcasecmp(d->id, CDEV->id)) {
|
||||
ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name);
|
||||
lineinuse++;
|
||||
}
|
||||
@@ -6868,32 +6896,35 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||
|
||||
static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
|
||||
{
|
||||
struct skinny_line *l;
|
||||
struct skinny_line *l, *temp;
|
||||
int update = 0;
|
||||
|
||||
ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
|
||||
|
||||
|
||||
/* We find the old line and remove it just before the new
|
||||
line is created */
|
||||
AST_LIST_LOCK(&lines);
|
||||
AST_LIST_TRAVERSE(&lines, l, all) {
|
||||
if (!strcasecmp(lname, l->name)) {
|
||||
ast_log(LOG_NOTICE, "Line %s already exists. Reconfiguring.\n", lname);
|
||||
AST_LIST_TRAVERSE(&lines, temp, all) {
|
||||
if (!strcasecmp(lname, temp->name) && temp->prune) {
|
||||
update = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!l) {
|
||||
ast_log(LOG_NOTICE, "Creating line %s.\n", lname);
|
||||
if (!(l=ast_calloc(1, sizeof(*l)))) {
|
||||
ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
|
||||
AST_LIST_UNLOCK(&lines);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(l, default_line, sizeof(*default_line));
|
||||
ast_mutex_init(&l->lock);
|
||||
ast_copy_string(l->name, lname, sizeof(l->name));
|
||||
AST_LIST_INSERT_TAIL(&lines, l, all);
|
||||
|
||||
if (!(l=ast_calloc(1, sizeof(*l)))) {
|
||||
ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
|
||||
AST_LIST_UNLOCK(&lines);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(l, default_line, sizeof(*default_line));
|
||||
ast_mutex_init(&l->lock);
|
||||
ast_copy_string(l->name, lname, sizeof(l->name));
|
||||
AST_LIST_INSERT_TAIL(&lines, l, all);
|
||||
|
||||
ast_mutex_lock(&l->lock);
|
||||
AST_LIST_UNLOCK(&lines);
|
||||
|
||||
|
||||
config_parse_variables(TYPE_LINE, l, v);
|
||||
|
||||
if (!ast_strlen_zero(l->mailbox)) {
|
||||
@@ -6911,32 +6942,43 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&l->lock);
|
||||
|
||||
/* We do not want to unlink or free the line yet, it needs
|
||||
to be available to detect a device reconfig when we load the
|
||||
devices. Old lines will be pruned after the reload completes */
|
||||
|
||||
ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
|
||||
{
|
||||
struct skinny_device *d;
|
||||
struct skinny_device *d, *temp;
|
||||
struct skinny_line *l, *ltemp;
|
||||
struct skinny_subchannel *sub;
|
||||
int update = 0;
|
||||
|
||||
ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
|
||||
|
||||
|
||||
AST_LIST_LOCK(&devices);
|
||||
AST_LIST_TRAVERSE(&devices, d, list) {
|
||||
if (!strcasecmp(dname, d->name)) {
|
||||
AST_LIST_TRAVERSE(&devices, temp, list) {
|
||||
if (!strcasecmp(dname, temp->name) && temp->prune) {
|
||||
update = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!d) {
|
||||
if (!(d = ast_calloc(1, sizeof(*d)))) {
|
||||
ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(d, default_device, sizeof(*default_device));
|
||||
ast_mutex_init(&d->lock);
|
||||
ast_copy_string(d->name, dname, sizeof(d->name));
|
||||
AST_LIST_INSERT_HEAD(&devices, d, list);
|
||||
|
||||
if (!(d = ast_calloc(1, sizeof(*d)))) {
|
||||
ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(d, default_device, sizeof(*default_device));
|
||||
ast_mutex_init(&d->lock);
|
||||
ast_copy_string(d->name, dname, sizeof(d->name));
|
||||
AST_LIST_INSERT_TAIL(&devices, d, list);
|
||||
|
||||
ast_mutex_lock(&d->lock);
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
|
||||
@@ -6951,8 +6993,52 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||
d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
|
||||
}
|
||||
|
||||
if (skinnyreload){
|
||||
AST_LIST_LOCK(&devices);
|
||||
AST_LIST_TRAVERSE(&devices, temp, list) {
|
||||
if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
|
||||
continue;
|
||||
}
|
||||
ast_mutex_lock(&d->lock);
|
||||
d->session = temp->session;
|
||||
d->session->device = d;
|
||||
|
||||
AST_LIST_LOCK(&d->lines);
|
||||
AST_LIST_TRAVERSE(&d->lines, l, list){
|
||||
l->device = d;
|
||||
|
||||
AST_LIST_LOCK(&temp->lines);
|
||||
AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
|
||||
if (strcasecmp(l->name, ltemp->name)) {
|
||||
continue;
|
||||
}
|
||||
ast_mutex_lock(<emp->lock);
|
||||
l->instance = ltemp->instance;
|
||||
l->hookstate = ltemp->hookstate;
|
||||
if (!AST_LIST_EMPTY(<emp->sub)) {
|
||||
ast_mutex_lock(&l->lock);
|
||||
l->sub = ltemp->sub;
|
||||
AST_LIST_TRAVERSE(&l->sub, sub, list) {
|
||||
sub->parent = l;
|
||||
}
|
||||
ast_mutex_unlock(&l->lock);
|
||||
}
|
||||
ast_mutex_unlock(<emp->lock);
|
||||
}
|
||||
AST_LIST_UNLOCK(&temp->lines);
|
||||
}
|
||||
AST_LIST_UNLOCK(&d->lines);
|
||||
ast_mutex_unlock(&d->lock);
|
||||
}
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&d->lock);
|
||||
return d;
|
||||
|
||||
ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
|
||||
|
||||
return d;
|
||||
|
||||
}
|
||||
|
||||
static int config_load(void)
|
||||
@@ -7102,19 +7188,87 @@ static void delete_devices(void)
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* XXX This never worked properly anyways.
|
||||
* Let's get rid of it, until we can fix it.
|
||||
*/
|
||||
static int reload(void)
|
||||
int skinny_reload(void)
|
||||
{
|
||||
delete_devices();
|
||||
config_load();
|
||||
restart_monitor();
|
||||
return 0;
|
||||
struct skinny_device *d;
|
||||
struct skinny_line *l;
|
||||
struct skinny_speeddial *sd;
|
||||
struct skinny_addon *a;
|
||||
struct skinny_req *req;
|
||||
|
||||
if (skinnyreload) {
|
||||
ast_verb(3, "Chan_skinny is already reloading.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
skinnyreload = 1;
|
||||
|
||||
/* Mark all devices and lines as candidates to be pruned */
|
||||
AST_LIST_LOCK(&devices);
|
||||
AST_LIST_TRAVERSE(&devices, d, list) {
|
||||
d->prune = 1;
|
||||
}
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
|
||||
AST_LIST_LOCK(&lines);
|
||||
AST_LIST_TRAVERSE(&lines, l, all) {
|
||||
l->prune = 1;
|
||||
}
|
||||
AST_LIST_UNLOCK(&lines);
|
||||
|
||||
config_load();
|
||||
|
||||
/* Remove any devices that no longer exist in the config */
|
||||
AST_LIST_LOCK(&devices);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&devices, d, list) {
|
||||
if (!d->prune) {
|
||||
continue;
|
||||
}
|
||||
ast_verb(3, "Removing device '%s'\n", d->name);
|
||||
/* Delete all lines for this device.
|
||||
We do not want to free the line here, that
|
||||
will happen below. */
|
||||
while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
|
||||
}
|
||||
/* Delete all speeddials for this device */
|
||||
while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
|
||||
free(sd);
|
||||
}
|
||||
/* Delete all addons for this device */
|
||||
while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
|
||||
free(a);
|
||||
}
|
||||
AST_LIST_REMOVE_CURRENT(list);
|
||||
free(d);
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&devices);
|
||||
|
||||
AST_LIST_LOCK(&lines);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&lines, l, all) {
|
||||
if (l->prune) {
|
||||
AST_LIST_REMOVE_CURRENT(all);
|
||||
free(l);
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&lines);
|
||||
|
||||
AST_LIST_TRAVERSE(&devices, d, list) {
|
||||
/* Do a soft reset to re-register the devices after
|
||||
cleaning up the removed devices and lines */
|
||||
if (d->session) {
|
||||
ast_verb(3, "Restarting device '%s'\n", d->name);
|
||||
if ((req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) {
|
||||
req->data.reset.resetType = 2;
|
||||
transmit_response(d, req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skinnyreload = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
@@ -7158,7 +7312,7 @@ static int load_module(void)
|
||||
/* And start the monitor for the first time */
|
||||
restart_monitor();
|
||||
|
||||
return res;
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
@@ -7237,7 +7391,14 @@ static int unload_module(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload(void)
|
||||
{
|
||||
skinny_reload();
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skinny Client Control Protocol (Skinny)",
|
||||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.reload = reload,
|
||||
);
|
||||
|
Reference in New Issue
Block a user