summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_skinny.c461
1 files changed, 245 insertions, 216 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index bb0888f26..a85421893 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -154,6 +154,7 @@ char dbgsub_buf[256];
#define DEBUG_TEMPLATE (1 << 6)
#define DEBUG_THREAD (1 << 7)
#define DEBUG_HINT (1 << 8)
+#define DEBUG_KEEPALIVE (1 << 9)
#define SKINNY_DEBUG(type, verb_level, text, ...) \
do{ \
if (skinnydebug & (type)) { \
@@ -1211,9 +1212,9 @@ union skinny_data {
/* packet composition */
struct skinny_req {
- int len;
- int res;
- int e;
+ uint32_t len;
+ uint32_t res;
+ uint32_t e;
union skinny_data data;
};
@@ -1612,13 +1613,17 @@ static AST_LIST_HEAD_STATIC(devices, skinny_device);
struct skinnysession {
pthread_t t;
ast_mutex_t lock;
- time_t start;
+ struct timeval start;
struct sockaddr_in sin;
int fd;
- char inbuf[SKINNY_MAX_PACKET];
char outbuf[SKINNY_MAX_PACKET];
struct skinny_device *device;
AST_LIST_ENTRY(skinnysession) list;
+ int lockstate; /* Only for use in the skinny_session thread */
+ int auth_timeout_sched;
+ int keepalive_timeout_sched;
+ struct timeval last_keepalive;
+ int keepalive_count;
};
static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
@@ -1643,6 +1648,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state);
static void dumpsub(struct skinny_subchannel *sub, int forcehangup);
static void activatesub(struct skinny_subchannel *sub, int state);
static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION]);
+static int skinny_nokeepalive_cb(const void *data);
static struct ast_channel_tech skinny_tech = {
.type = "Skinny",
@@ -2246,6 +2252,11 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
socklen_t slen;
int instance;
+ if (s->auth_timeout_sched && ast_sched_del(sched, s->auth_timeout_sched)) {
+ return 0;
+ }
+ s->auth_timeout_sched = 0;
+
AST_LIST_LOCK(&devices);
AST_LIST_TRAVERSE(&devices, d, list){
struct ast_sockaddr addr;
@@ -2309,38 +2320,9 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
return 1;
}
-static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
+static void end_session(struct skinnysession *s)
{
- struct skinny_device *d;
- struct skinny_line *l;
- struct skinny_speeddial *sd;
-
- d = s->device;
-
- if (d) {
- RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
- d->session = NULL;
-
- AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
- if (sd->stateid > -1)
- ast_extension_state_del(sd->stateid, NULL);
- }
- AST_LIST_TRAVERSE(&d->lines, l, list) {
- if (l->device == d) {
- ast_format_cap_remove_all(l->cap);
- ast_parse_allow_disallow(&l->prefs, l->cap, "all", 0);
- l->instance = 0;
- unregister_exten(l);
- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
- }
- }
-
- ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_OFFLINE);
- blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
- ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
- }
-
- return -1; /* main loop will destroy the session */
+ pthread_cancel(s->t);
}
#ifdef AST_DEVMODE
@@ -2406,7 +2388,7 @@ static int transmit_response_bysession(struct skinnysession *s, struct skinny_re
ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
if (res == -1) {
ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
- skinny_unregister(NULL, s);
+ end_session(s);
}
}
@@ -3313,15 +3295,16 @@ static void transmit_reset(struct skinny_device *d, int fullrestart)
transmit_response(d, req);
}
-static void transmit_keepaliveack(struct skinny_device *d)
+static void transmit_keepaliveack(struct skinnysession *s)
{
struct skinny_req *req;
+ struct skinny_device *d = s->device;
if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
return;
- SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting KEEP_ALIVE_ACK_MESSAGE to %s\n", d->name);
- transmit_response(d, req);
+ SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting KEEP_ALIVE_ACK_MESSAGE to %s\n", (d ? d->name : "unregistered"));
+ transmit_response_bysession(s, req);
}
static void transmit_registerack(struct skinny_device *d)
@@ -3737,6 +3720,11 @@ static char *skinny_debugs(void)
posn += 5;
ptr += 5;
}
+ if (skinnydebug & DEBUG_KEEPALIVE) {
+ strncpy(ptr, "keepalive ", 10);
+ posn += 10;
+ ptr += 10;
+ }
if (posn > 0) {
strncpy(--ptr, "\0", 1);
}
@@ -3745,7 +3733,7 @@ static char *skinny_debugs(void)
static char *complete_skinny_debug(const char *line, const char *word, int pos, int state)
{
- const char *debugOpts[]={ "all","audio","hint","lock","off","packet","show","sub","template","thread",NULL };
+ const char *debugOpts[]={ "all","audio","hint","keepalive","lock","off","packet","show","sub","template","thread",NULL };
char *wordptr = (char *)word;
char buf[32];
char *bufptr = buf;
@@ -3785,7 +3773,7 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
case CLI_INIT:
e->command = "skinny debug";
e->usage =
- "Usage: skinny debug {audio|hint|lock|off|packet|show|sub|template|thread}\n"
+ "Usage: skinny debug {audio|hint|keepalive|lock|off|packet|show|sub|template|thread}\n"
" Enables/Disables various Skinny debugging messages\n";
return NULL;
case CLI_GENERATE:
@@ -3811,7 +3799,7 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
}
if (!strncasecmp(arg, "all", 3)) {
- skinnydebug = DEBUG_GENERAL|DEBUG_SUB|DEBUG_PACKET|DEBUG_AUDIO|DEBUG_LOCK|DEBUG_TEMPLATE|DEBUG_THREAD|DEBUG_HINT;
+ skinnydebug = DEBUG_GENERAL|DEBUG_SUB|DEBUG_PACKET|DEBUG_AUDIO|DEBUG_LOCK|DEBUG_TEMPLATE|DEBUG_THREAD|DEBUG_HINT|DEBUG_KEEPALIVE;
continue;
}
@@ -3841,6 +3829,8 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
bitmask = DEBUG_THREAD;
} else if (!strncasecmp(arg, "hint", 4)) {
bitmask = DEBUG_HINT;
+ } else if (!strncasecmp(arg, "keepalive", 9)) {
+ bitmask = DEBUG_KEEPALIVE;
} else {
ast_cli(a->fd, "Skinny Debugging - option '%s' unknown\n", a->argv[i]);
result--;
@@ -6176,6 +6166,30 @@ static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *
return 1;
}
+static void handle_keepalive_message(struct skinny_req *req, struct skinnysession *s)
+{
+ if (ast_sched_del(sched, s->keepalive_timeout_sched)) {
+ return;
+ }
+
+#ifdef AST_DEVMODE
+ {
+ long keepalive_diff;
+ keepalive_diff = (long) ast_tvdiff_ms(ast_tvnow(), ast_tvadd(s->last_keepalive, ast_tv(keep_alive, 0)));
+ SKINNY_DEBUG(DEBUG_PACKET|DEBUG_KEEPALIVE, 3,
+ "Keep_alive %d on %s, %.3fs %s\n",
+ ++s->keepalive_count,
+ (s->device ? s->device->name : "unregistered"),
+ (float) labs(keepalive_diff) / 1000,
+ (keepalive_diff > 0 ? "late" : "early"));
+ }
+#endif
+
+ s->keepalive_timeout_sched = ast_sched_add(sched, keep_alive*3000, skinny_nokeepalive_cb, s);
+ s->last_keepalive = ast_tvnow();
+ transmit_keepaliveack(s);
+}
+
static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
{
struct skinny_subchannel *sub = NULL;
@@ -7212,16 +7226,15 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
struct skinny_speeddial *sd;
struct skinny_device *d = s->device;
- if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
+ if (!d && !(letohl(req->e) == REGISTER_MESSAGE || letohl(req->e) == ALARM_MESSAGE || letohl(req->e) == KEEP_ALIVE_MESSAGE)) {
ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
- ast_free(req);
return 0;
}
switch(letohl(req->e)) {
case KEEP_ALIVE_MESSAGE:
- SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEEP_ALIVE_MESSAGE from %s\n", d->name);
- transmit_keepaliveack(s->device);
+ SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEEP_ALIVE_MESSAGE from %s\n", (d ? d->name : "unregistered"));
+ handle_keepalive_message(req, s);
break;
case REGISTER_MESSAGE:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_MESSAGE from %s, name %s, type %d, protovers %d\n",
@@ -7233,7 +7246,6 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
transmit_capabilitiesreq(s->device);
} else {
transmit_registerrej(s);
- ast_free(req);
return -1;
}
case IP_PORT_MESSAGE:
@@ -7317,7 +7329,7 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
break;
case UNREGISTER_MESSAGE:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNREGISTER_MESSAGE from %s\n", d->name);
- res = skinny_unregister(req, s);
+ end_session(s);
break;
case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_TEMPLATE_REQ_MESSAGE from %s\n", d->name);
@@ -7339,194 +7351,221 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNKNOWN_MESSAGE(%x) from %s\n", letohl(req->e), d->name);
break;
}
- if (res >= 0 && req)
- ast_free(req);
return res;
}
static void destroy_session(struct skinnysession *s)
{
- struct skinnysession *cur;
- AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, cur, list) {
- if (cur == s) {
- AST_LIST_REMOVE_CURRENT(list);
- if (s->fd > -1) {
- close(s->fd);
- }
-
- if (s->device) {
- s->device->session = NULL;
- } else {
- ast_atomic_fetchadd_int(&unauth_sessions, -1);
- }
+ ast_mutex_lock(&s->lock);
+ if (s->fd > -1) {
+ close(s->fd);
+ }
- ast_mutex_destroy(&s->lock);
+ if (s->device) {
+ s->device->session = NULL;
+ } else {
+ ast_atomic_fetchadd_int(&unauth_sessions, -1);
+ }
+ ast_mutex_unlock(&s->lock);
+ ast_mutex_destroy(&s->lock);
+ ast_free(s);
+}
- ast_free(s);
+static int skinny_noauth_cb(const void *data)
+{
+ struct skinnysession *s = (struct skinnysession *)data;
+ ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds (SCHED %d)\n", auth_timeout, s->auth_timeout_sched);
+ s->auth_timeout_sched = 0;
+ end_session(s);
+ return 0;
+}
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&sessions);
+static int skinny_nokeepalive_cb(const void *data)
+{
+ struct skinnysession *s = (struct skinnysession *)data;
+ ast_log(LOG_WARNING, "Skinny Client failed to send keepalive in last %d seconds (SCHED %d)\n", keep_alive*3, s->keepalive_timeout_sched);
+ s->keepalive_timeout_sched = 0;
+ end_session(s);
+ return 0;
}
-static int get_input(struct skinnysession *s)
+static void skinny_session_cleanup(void *data)
{
- int res;
- int dlen = 0;
- int timeout = keep_alive * 1100;
- time_t now;
- int *bufaddr;
- struct pollfd fds[1];
+ struct skinnysession *s = (struct skinnysession *)data;
+ struct skinny_device *d = s->device;
+ struct skinny_line *l;
+ struct skinny_speeddial *sd;
- if (!s->device) {
- if(time(&now) == -1) {
- ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
- return -1;
- }
+ ast_verb(3, "Ending Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
- timeout = (auth_timeout - (now - s->start)) * 1000;
- if (timeout < 0) {
- /* we have timed out */
- ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
- return -1;
- }
+ if (s->lockstate) {
+ ast_mutex_unlock(&s->lock);
}
- fds[0].fd = s->fd;
- fds[0].events = POLLIN;
- fds[0].revents = 0;
- res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
- /* we add 10% to the keep_alive to deal */
- /* with network delays, etc */
- if (res < 0) {
- if (errno != EINTR) {
- ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
- return res;
- }
- } else if (res == 0) {
- if (s->device) {
- ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
- } else {
- ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
- }
- skinny_unregister(NULL, s);
- return -1;
+ if (s->auth_timeout_sched && !ast_sched_del(sched, s->auth_timeout_sched)) {
+ s->auth_timeout_sched = 0;
+ }
+ if (s->keepalive_timeout_sched && !ast_sched_del(sched, s->keepalive_timeout_sched)) {
+ s->keepalive_timeout_sched = 0;
}
- if (fds[0].revents) {
- ast_mutex_lock(&s->lock);
- memset(s->inbuf, 0, sizeof(s->inbuf));
- res = read(s->fd, s->inbuf, 4);
- if (res < 0) {
- ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
-
- ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
-
- skinny_unregister(NULL, s);
- ast_mutex_unlock(&s->lock);
- return res;
- } else if (res != 4) {
- ast_log(LOG_WARNING, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res);
- ast_mutex_unlock(&s->lock);
+ if (d) {
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ d->session = NULL;
- if (res == 0) {
- ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
- skinny_unregister(NULL, s);
+ AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
+ if (sd->stateid > -1)
+ ast_extension_state_del(sd->stateid, NULL);
+ }
+ AST_LIST_TRAVERSE(&d->lines, l, list) {
+ if (l->device != d) {
+ continue;
}
-
- return -1;
+ ast_format_cap_remove_all(l->cap);
+ ast_parse_allow_disallow(&l->prefs, l->cap, "all", 0);
+ l->instance = 0;
+ unregister_exten(l);
+ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
}
+ ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_OFFLINE);
+ blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
+ ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
+ }
- bufaddr = (int *)s->inbuf;
- dlen = letohl(*bufaddr);
- if (dlen < 4) {
- ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
- ast_mutex_unlock(&s->lock);
- return -1;
- }
- if (dlen+8 > sizeof(s->inbuf)) {
- ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET);
- dlen = sizeof(s->inbuf) - 8;
- }
- *bufaddr = htolel(dlen);
+ AST_LIST_LOCK(&sessions);
+ AST_LIST_REMOVE(&sessions, s, list);
+ AST_LIST_UNLOCK(&sessions);
- res = read(s->fd, s->inbuf+4, dlen+4);
- ast_mutex_unlock(&s->lock);
- if (res < 0) {
- ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
- return res;
- } else if (res != (dlen+4)) {
- ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
- return -1;
- }
- return res;
- }
- return 0;
+ destroy_session(s);
}
-static struct skinny_req *skinny_req_parse(struct skinnysession *s)
+static void *skinny_session(void *data)
{
- struct skinny_req *req;
- int *bufaddr;
+ int res;
+ struct skinny_req *req = NULL;
+ struct skinnysession *s = data;
- if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
- return NULL;
+ int dlen = 0;
+ struct pollfd fds[1];
- ast_mutex_lock(&s->lock);
- memcpy(req, s->inbuf, skinny_header_size);
- bufaddr = (int *)(s->inbuf);
- memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*bufaddr)-4);
+ if (!s) {
+ ast_verb(3, "Bad Skinny Session\n");
+ return 0;
+ }
- ast_mutex_unlock(&s->lock);
+ ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
- if (letohl(req->e) < 0) {
- ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
- ast_free(req);
- return NULL;
- }
+ pthread_cleanup_push(skinny_session_cleanup, s);
- return req;
-}
+ s->start = ast_tvnow();
+ s->last_keepalive = ast_tvnow();
+ s->keepalive_count = 0;
+ s->lockstate = 0;
-static void *skinny_session(void *data)
-{
- int res;
- struct skinny_req *req;
- struct skinnysession *s = data;
+ AST_LIST_LOCK(&sessions);
+ AST_LIST_INSERT_HEAD(&sessions, s, list);
+ AST_LIST_UNLOCK(&sessions);
- ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
+ s->auth_timeout_sched = ast_sched_add(sched, auth_timeout*1000, skinny_noauth_cb, s);
+ s->keepalive_timeout_sched = ast_sched_add(sched, keep_alive*3000, skinny_nokeepalive_cb, s);
for (;;) {
- res = get_input(s);
+
+ fds[0].fd = s->fd;
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+ res = ast_poll(fds, 1, -1); /* block */
if (res < 0) {
- ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
- destroy_session(s);
- return NULL;
+ if (errno != EINTR) {
+ ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
+ ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
+ break;
+ }
}
- if (res > 0)
- {
- if (!(req = skinny_req_parse(s))) {
- ast_verb(3, "Ending Skinny session from %s (failed parse)\n", ast_inet_ntoa(s->sin.sin_addr));
- destroy_session(s);
- return NULL;
+ if (fds[0].revents) {
+
+ if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) {
+ ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n");
+ break;
+ }
+
+ ast_mutex_lock(&s->lock);
+ s->lockstate = 1;
+
+ if ((res = read(s->fd, req, skinny_header_size)) != skinny_header_size) {
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Header read() returned error: %s\n", strerror(errno));
+ } else {
+ ast_log(LOG_WARNING, "Unable to read header. Only found %d bytes.\n", res);
+ }
+ break;
+ }
+
+ if (letohl(req->e) < 0) {
+ ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
+ break;
+ }
+
+ dlen = letohl(req->len) - 4;
+ if (dlen < 0) {
+ ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
+ break;
+ }
+ if (dlen > (SKINNY_MAX_PACKET - skinny_header_size)) {
+ ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET);
+ break;
}
+ res = 0;
+ while (1) {
+ int bytesread = res;
+ if ((res = read(s->fd, &req->data+bytesread, dlen-bytesread)) < 0) {
+ break;
+ }
+ res += bytesread;
+ if (res >= dlen) {
+ break;
+ }
+ ast_log(LOG_WARNING, "Partial data received, waiting\n");
+ if (sched_yield() < 0) {
+ ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno));
+ break;
+ }
+ }
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno));
+ break;
+ }
+ if (res != dlen) {
+ ast_log(LOG_WARNING, "Client sent wrong amount of data (%d), expected (%d).\n", res, dlen);
+ break;
+ }
+
+ s->lockstate = 0;
+ ast_mutex_unlock(&s->lock);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
res = handle_message(req, s);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (res < 0) {
ast_verb(3, "Ending Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
- destroy_session(s);
- return NULL;
+ break;
}
}
+
+ if (req) {
+ ast_free(req);
+ req = NULL;
+ }
}
+
ast_debug(3, "Skinny Session returned: %s\n", strerror(errno));
+ if (req) {
+ ast_free(req);
+ }
- if (s)
- destroy_session(s);
+ pthread_cleanup_pop(1);
return 0;
}
@@ -7566,20 +7605,10 @@ static void *accept_thread(void *ignore)
continue;
}
- memcpy(&s->sin, &sin, sizeof(sin));
ast_mutex_init(&s->lock);
+ memcpy(&s->sin, &sin, sizeof(sin));
s->fd = as;
- if(time(&s->start) == -1) {
- ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
- destroy_session(s);
- continue;
- }
-
- AST_LIST_LOCK(&sessions);
- AST_LIST_INSERT_HEAD(&sessions, s, list);
- AST_LIST_UNLOCK(&sessions);
-
if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
destroy_session(s);
}
@@ -8629,6 +8658,7 @@ static int unload_module(void)
struct skinny_line *l;
struct skinny_subchannel *sub;
struct ast_context *con;
+ int tempthread;
ast_rtp_glue_unregister(&skinny_rtp_glue);
ast_channel_unregister(&skinny_tech);
@@ -8639,11 +8669,21 @@ static int unload_module(void)
ast_manager_unregister("SKINNYlines");
ast_manager_unregister("SKINNYshowline");
+ ast_mutex_lock(&netlock);
+ if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
+ pthread_cancel(accept_t);
+ pthread_kill(accept_t, SIGURG);
+ pthread_join(accept_t, NULL);
+ }
+ accept_t = AST_PTHREADT_STOP;
+ ast_mutex_unlock(&netlock);
+
AST_LIST_LOCK(&sessions);
/* Destroy all the interfaces and free their memory */
while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ AST_LIST_UNLOCK(&sessions);
d = s->device;
AST_LIST_TRAVERSE(&d->lines, l, list){
ast_mutex_lock(&l->lock);
@@ -8663,26 +8703,15 @@ static int unload_module(void)
ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_OFFLINE);
blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
- if (s->fd > -1)
- close(s->fd);
- pthread_cancel(s->t);
- pthread_kill(s->t, SIGURG);
- pthread_join(s->t, NULL);
- free(s);
+ tempthread = s->t;
+ pthread_cancel(tempthread);
+ pthread_join(tempthread, NULL);
+ AST_LIST_LOCK(&sessions);
}
AST_LIST_UNLOCK(&sessions);
delete_devices();
- ast_mutex_lock(&netlock);
- if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
- pthread_cancel(accept_t);
- pthread_kill(accept_t, SIGURG);
- pthread_join(accept_t, NULL);
- }
- accept_t = AST_PTHREADT_STOP;
- ast_mutex_unlock(&netlock);
-
close(skinnysock);
if (sched) {
ast_sched_context_destroy(sched);