From 605b9a914e39b95cf36af09cb812a1f0f31521f3 Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Wed, 6 Dec 2006 20:46:01 +0000 Subject: 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 --- main/manager.c | 188 +++++++++++++++++++-------------------------------------- 1 file changed, 61 insertions(+), 127 deletions(-) (limited to 'main') 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; } -- cgit v1.2.3