aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b>2006-12-06 20:46:01 +0000
committerrizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b>2006-12-06 20:46:01 +0000
commitdcc00a652f889d49f4eea810648a8b7416eb8b84 (patch)
tree71684e7342a3135822acaa5bfa6484368b032b5e
parent4b06443b149d96085655607d2866afbbb9f72f6a (diff)
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: http://svn.digium.com/svn/asterisk/trunk@48338 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--main/manager.c188
1 files changed, 61 insertions, 127 deletions
diff --git a/main/manager.c b/main/manager.c
index 1cc991ea9..52b6f790c 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -105,9 +105,7 @@ struct eventqent {
static AST_LIST_HEAD_STATIC(all_events, eventqent);
-static int enabled = 0;
static int portno = DEFAULT_MANAGER_PORT;
-static int asock = -1; /* the accept socket */
static int displayconnects = 1;
static int timestampevents = 0;
static int httptimeout = 60;
@@ -2138,11 +2136,39 @@ static int get_input(struct mansession *s, char *output)
*/
static void *session_do(void *data)
{
- struct mansession *s = data;
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);
- s->f = fdopen(s->fd, "w+");
+ s->f = ser->f;
astman_append(s, "Asterisk Call Manager/1.0\r\n"); /* welcome prompt */
ast_mutex_unlock(&s->__lock);
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));
}
destroy_session(s);
+
+done:
+ free(ser);
return NULL;
}
@@ -2205,80 +2234,6 @@ static void purge_sessions(int n_max)
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
* can be dispatched to clients.
@@ -2904,16 +2859,33 @@ struct ast_http_uri managerxmluri = {
static int registered = 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)
{
struct ast_config *cfg = NULL;
const char *val;
char *cat = NULL;
- int oldportno = portno;
- static struct sockaddr_in ba;
- int x = 1;
- int flags;
int webenabled = 0;
+ int enabled = 0;
int newhttptimeout = 60;
struct ast_manager_user *user = NULL;
@@ -2986,28 +2958,18 @@ int init_manager(void)
if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
newhttptimeout = atoi(val);
- memset(&ba, 0, sizeof(ba));
- ba.sin_family = AF_INET;
- ba.sin_port = htons(portno);
+ memset(&ami_desc.sin, 0, sizeof(struct sockaddr_in));
+ if (enabled)
+ ami_desc.sin.sin_family = AF_INET;
+ ami_desc.sin.sin_port = htons(portno);
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);
- 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);
while ((cat = ast_category_browse(cfg, cat))) {
@@ -3107,35 +3069,7 @@ int init_manager(void)
if (newhttptimeout > 0)
httptimeout = newhttptimeout;
- /* If not enabled, do nothing */
- 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);
- }
+ server_start(&ami_desc);
return 0;
}