mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-03 20:38:59 +00:00
remove duplicated code to start the server threads, use
the infrastructure exposed in http.c earlier today. As a bonus, now we can restart the session on a different port just reloading the module. On passing, fix a bug in the handling of 'enabled' in the configuration file - previously, a missing "enabled=" line in manager.conf meant "whatever the state was before" instead of a specific value. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48338 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
188
main/manager.c
188
main/manager.c
@@ -105,9 +105,7 @@ struct eventqent {
|
|||||||
|
|
||||||
static AST_LIST_HEAD_STATIC(all_events, eventqent);
|
static AST_LIST_HEAD_STATIC(all_events, eventqent);
|
||||||
|
|
||||||
static int enabled = 0;
|
|
||||||
static int portno = DEFAULT_MANAGER_PORT;
|
static int portno = DEFAULT_MANAGER_PORT;
|
||||||
static int asock = -1; /* the accept socket */
|
|
||||||
static int displayconnects = 1;
|
static int displayconnects = 1;
|
||||||
static int timestampevents = 0;
|
static int timestampevents = 0;
|
||||||
static int httptimeout = 60;
|
static int httptimeout = 60;
|
||||||
@@ -2138,11 +2136,39 @@ static int get_input(struct mansession *s, char *output)
|
|||||||
*/
|
*/
|
||||||
static void *session_do(void *data)
|
static void *session_do(void *data)
|
||||||
{
|
{
|
||||||
struct mansession *s = data;
|
|
||||||
struct message m; /* XXX watch out, this is 20k of memory! */
|
struct message m; /* XXX watch out, this is 20k of memory! */
|
||||||
|
struct server_instance *ser = data;
|
||||||
|
struct mansession *s = ast_calloc(1, sizeof(*s));
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
s->writetimeout = 100;
|
||||||
|
s->waiting_thread = AST_PTHREADT_NULL;
|
||||||
|
|
||||||
|
flags = fcntl(ser->fd, F_GETFL);
|
||||||
|
if (!block_sockets) /* make sure socket is non-blocking */
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
else
|
||||||
|
flags &= ~O_NONBLOCK;
|
||||||
|
fcntl(ser->fd, F_SETFL, flags);
|
||||||
|
|
||||||
|
ast_mutex_init(&s->__lock);
|
||||||
|
s->send_events = -1;
|
||||||
|
/* these fields duplicate those in the 'ser' structure */
|
||||||
|
s->fd = ser->fd;
|
||||||
|
s->f = ser->f;
|
||||||
|
s->sin = ser->requestor;
|
||||||
|
|
||||||
|
ast_atomic_fetchadd_int(&num_sessions, 1);
|
||||||
|
AST_LIST_LOCK(&sessions);
|
||||||
|
AST_LIST_INSERT_HEAD(&sessions, s, list);
|
||||||
|
AST_LIST_UNLOCK(&sessions);
|
||||||
|
/* Hook to the tail of the event queue */
|
||||||
|
s->last_ev = grab_last();
|
||||||
ast_mutex_lock(&s->__lock);
|
ast_mutex_lock(&s->__lock);
|
||||||
s->f = fdopen(s->fd, "w+");
|
s->f = ser->f;
|
||||||
astman_append(s, "Asterisk Call Manager/1.0\r\n"); /* welcome prompt */
|
astman_append(s, "Asterisk Call Manager/1.0\r\n"); /* welcome prompt */
|
||||||
ast_mutex_unlock(&s->__lock);
|
ast_mutex_unlock(&s->__lock);
|
||||||
memset(&m, 0, sizeof(m));
|
memset(&m, 0, sizeof(m));
|
||||||
@@ -2176,6 +2202,9 @@ static void *session_do(void *data)
|
|||||||
ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
|
ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
|
||||||
}
|
}
|
||||||
destroy_session(s);
|
destroy_session(s);
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(ser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2205,80 +2234,6 @@ static void purge_sessions(int n_max)
|
|||||||
AST_LIST_UNLOCK(&sessions);
|
AST_LIST_UNLOCK(&sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief The thread accepting connections on the manager interface port.
|
|
||||||
* As a side effect, it purges stale sessions, one per each iteration,
|
|
||||||
* which is at least every 5 seconds.
|
|
||||||
*/
|
|
||||||
static void *accept_thread(void *ignore)
|
|
||||||
{
|
|
||||||
pthread_attr_t attr;
|
|
||||||
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
struct mansession *s;
|
|
||||||
int as;
|
|
||||||
struct sockaddr_in sin;
|
|
||||||
socklen_t sinlen;
|
|
||||||
struct protoent *p;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
purge_sessions(1);
|
|
||||||
purge_events();
|
|
||||||
|
|
||||||
/* Wait for something to happen, but timeout every few seconds so
|
|
||||||
we can ditch any old manager sessions */
|
|
||||||
if (ast_wait_for_input(asock, 5000) < 1)
|
|
||||||
continue;
|
|
||||||
sinlen = sizeof(sin);
|
|
||||||
as = accept(asock, (struct sockaddr *)&sin, &sinlen);
|
|
||||||
if (as < 0) {
|
|
||||||
ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
p = getprotobyname("tcp");
|
|
||||||
if (p) {
|
|
||||||
int arg = 1;
|
|
||||||
if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
|
|
||||||
ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = ast_calloc(1, sizeof(*s)); /* allocate a new record */
|
|
||||||
if (!s) {
|
|
||||||
close(as);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
s->sin = sin;
|
|
||||||
s->writetimeout = 100;
|
|
||||||
s->waiting_thread = AST_PTHREADT_NULL;
|
|
||||||
|
|
||||||
flags = fcntl(as, F_GETFL);
|
|
||||||
if (!block_sockets) /* For safety, make sure socket is non-blocking */
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
else
|
|
||||||
flags &= ~O_NONBLOCK;
|
|
||||||
fcntl(as, F_SETFL, flags);
|
|
||||||
|
|
||||||
ast_mutex_init(&s->__lock);
|
|
||||||
s->fd = as;
|
|
||||||
s->send_events = -1;
|
|
||||||
|
|
||||||
ast_atomic_fetchadd_int(&num_sessions, 1);
|
|
||||||
AST_LIST_LOCK(&sessions);
|
|
||||||
AST_LIST_INSERT_HEAD(&sessions, s, list);
|
|
||||||
AST_LIST_UNLOCK(&sessions);
|
|
||||||
/* Hook to the tail of the event queue */
|
|
||||||
s->last_ev = grab_last();
|
|
||||||
if (ast_pthread_create_background(&s->ms_t, &attr, session_do, s))
|
|
||||||
destroy_session(s);
|
|
||||||
}
|
|
||||||
pthread_attr_destroy(&attr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* events are appended to a queue from where they
|
* events are appended to a queue from where they
|
||||||
* can be dispatched to clients.
|
* can be dispatched to clients.
|
||||||
@@ -2904,16 +2859,33 @@ struct ast_http_uri managerxmluri = {
|
|||||||
static int registered = 0;
|
static int registered = 0;
|
||||||
static int webregged = 0;
|
static int webregged = 0;
|
||||||
|
|
||||||
|
/*! \brief cleanup code called at each iteration of server_root,
|
||||||
|
* guaranteed to happen every 5 seconds at most
|
||||||
|
*/
|
||||||
|
static void purge_old_stuff(void *data)
|
||||||
|
{
|
||||||
|
purge_sessions(1);
|
||||||
|
purge_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct server_args ami_desc = {
|
||||||
|
.accept_fd = -1,
|
||||||
|
.master = AST_PTHREADT_NULL,
|
||||||
|
.is_ssl = 0,
|
||||||
|
.poll_timeout = 5000, /* wake up every 5 seconds */
|
||||||
|
.periodic_fn = purge_old_stuff,
|
||||||
|
.name = "AMI server",
|
||||||
|
.accept_fn = server_root, /* thread doing the accept() */
|
||||||
|
.worker_fn = session_do, /* thread handling the session */
|
||||||
|
};
|
||||||
|
|
||||||
int init_manager(void)
|
int init_manager(void)
|
||||||
{
|
{
|
||||||
struct ast_config *cfg = NULL;
|
struct ast_config *cfg = NULL;
|
||||||
const char *val;
|
const char *val;
|
||||||
char *cat = NULL;
|
char *cat = NULL;
|
||||||
int oldportno = portno;
|
|
||||||
static struct sockaddr_in ba;
|
|
||||||
int x = 1;
|
|
||||||
int flags;
|
|
||||||
int webenabled = 0;
|
int webenabled = 0;
|
||||||
|
int enabled = 0;
|
||||||
int newhttptimeout = 60;
|
int newhttptimeout = 60;
|
||||||
struct ast_manager_user *user = NULL;
|
struct ast_manager_user *user = NULL;
|
||||||
|
|
||||||
@@ -2986,28 +2958,18 @@ int init_manager(void)
|
|||||||
if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
|
if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
|
||||||
newhttptimeout = atoi(val);
|
newhttptimeout = atoi(val);
|
||||||
|
|
||||||
memset(&ba, 0, sizeof(ba));
|
memset(&ami_desc.sin, 0, sizeof(struct sockaddr_in));
|
||||||
ba.sin_family = AF_INET;
|
if (enabled)
|
||||||
ba.sin_port = htons(portno);
|
ami_desc.sin.sin_family = AF_INET;
|
||||||
|
ami_desc.sin.sin_port = htons(portno);
|
||||||
|
|
||||||
if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
|
if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
|
||||||
if (!inet_aton(val, &ba.sin_addr)) {
|
if (!inet_aton(val, &ami_desc.sin.sin_addr)) {
|
||||||
ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
|
ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
|
||||||
memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
|
memset(&ami_desc.sin.sin_addr, 0, sizeof(ami_desc.sin.sin_addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((asock > -1) && ((portno != oldportno) || !enabled)) {
|
|
||||||
#if 0
|
|
||||||
/* Can't be done yet */
|
|
||||||
close(asock);
|
|
||||||
asock = -1;
|
|
||||||
#else
|
|
||||||
ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
AST_LIST_LOCK(&users);
|
AST_LIST_LOCK(&users);
|
||||||
|
|
||||||
while ((cat = ast_category_browse(cfg, cat))) {
|
while ((cat = ast_category_browse(cfg, cat))) {
|
||||||
@@ -3107,35 +3069,7 @@ int init_manager(void)
|
|||||||
if (newhttptimeout > 0)
|
if (newhttptimeout > 0)
|
||||||
httptimeout = newhttptimeout;
|
httptimeout = newhttptimeout;
|
||||||
|
|
||||||
/* If not enabled, do nothing */
|
server_start(&ami_desc);
|
||||||
if (!enabled)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (asock < 0) {
|
|
||||||
asock = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (asock < 0) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
|
|
||||||
if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
|
|
||||||
close(asock);
|
|
||||||
asock = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (listen(asock, 2)) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
|
|
||||||
close(asock);
|
|
||||||
asock = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
flags = fcntl(asock, F_GETFL);
|
|
||||||
fcntl(asock, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
if (option_verbose)
|
|
||||||
ast_verbose("Asterisk Management interface listening on port %d\n", portno);
|
|
||||||
ast_pthread_create_background(&accept_thread_ptr, NULL, accept_thread, NULL);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user