mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +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 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; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user