xref: /illumos-gate/usr/src/cmd/vntsd/listen.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo /*
22*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*1ae08745Sheppo  * Use is subject to license terms.
24*1ae08745Sheppo  */
25*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
26*1ae08745Sheppo 
27*1ae08745Sheppo /*
28*1ae08745Sheppo  * Each group has a listen thread. It is created at the time
29*1ae08745Sheppo  * of a group creation and destroyed when a group does not have
30*1ae08745Sheppo  * any console associated with it.
31*1ae08745Sheppo  */
32*1ae08745Sheppo 
33*1ae08745Sheppo #include <stdio.h>
34*1ae08745Sheppo #include <stdlib.h>
35*1ae08745Sheppo #include <string.h>
36*1ae08745Sheppo #include <unistd.h>
37*1ae08745Sheppo #include <sys/types.h>
38*1ae08745Sheppo #include <sys/socket.h>
39*1ae08745Sheppo #include <netinet/in.h>
40*1ae08745Sheppo #include <thread.h>
41*1ae08745Sheppo #include <assert.h>
42*1ae08745Sheppo #include <signal.h>
43*1ae08745Sheppo #include <ctype.h>
44*1ae08745Sheppo #include <syslog.h>
45*1ae08745Sheppo #include "vntsd.h"
46*1ae08745Sheppo 
47*1ae08745Sheppo /*
48*1ae08745Sheppo  * check the state of listen thread. exit if there is an fatal error
49*1ae08745Sheppo  * or the group is removed.
50*1ae08745Sheppo  */
51*1ae08745Sheppo static void
52*1ae08745Sheppo listen_chk_status(vntsd_group_t *groupp, int status)
53*1ae08745Sheppo {
54*1ae08745Sheppo 	char	    err_msg[VNTSD_LINE_LEN];
55*1ae08745Sheppo 
56*1ae08745Sheppo 
57*1ae08745Sheppo 	D1(stderr, "t@%d listen_chk_status() status=%d group=%s "
58*1ae08745Sheppo 	    "tcp=%lld group status = %x\n", thr_self(), status,
59*1ae08745Sheppo 	    groupp->group_name, groupp->tcp_port, groupp->status);
60*1ae08745Sheppo 
61*1ae08745Sheppo 	(void) snprintf(err_msg, sizeof (err_msg),
62*1ae08745Sheppo 	    "Group:%s TCP port %lld status %x",
63*1ae08745Sheppo 	    groupp->group_name, groupp->tcp_port, groupp->status);
64*1ae08745Sheppo 
65*1ae08745Sheppo 
66*1ae08745Sheppo 	switch (status) {
67*1ae08745Sheppo 
68*1ae08745Sheppo 	case VNTSD_SUCCESS:
69*1ae08745Sheppo 		return;
70*1ae08745Sheppo 
71*1ae08745Sheppo 	case VNTSD_STATUS_INTR:
72*1ae08745Sheppo 		assert(groupp->status & VNTSD_GROUP_SIG_WAIT);
73*1ae08745Sheppo 		/* close listen socket */
74*1ae08745Sheppo 		(void) mutex_lock(&groupp->lock);
75*1ae08745Sheppo 		(void) close(groupp->sockfd);
76*1ae08745Sheppo 		groupp->sockfd = -1;
77*1ae08745Sheppo 
78*1ae08745Sheppo 		/* let group know */
79*1ae08745Sheppo 		groupp->status &= ~VNTSD_GROUP_SIG_WAIT;
80*1ae08745Sheppo 		(void) cond_signal(&groupp->cvp);
81*1ae08745Sheppo 
82*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
83*1ae08745Sheppo 		/* exit thread */
84*1ae08745Sheppo 		thr_exit(0);
85*1ae08745Sheppo 		break;
86*1ae08745Sheppo 
87*1ae08745Sheppo 	case VNTSD_STATUS_ACCEPT_ERR:
88*1ae08745Sheppo 		return;
89*1ae08745Sheppo 
90*1ae08745Sheppo 	case VNTSD_STATUS_NO_CONS:
91*1ae08745Sheppo 	default:
92*1ae08745Sheppo 		/* fatal, exit thread */
93*1ae08745Sheppo 
94*1ae08745Sheppo 		(void) mutex_lock(&groupp->lock);
95*1ae08745Sheppo 		(void) close(groupp->sockfd);
96*1ae08745Sheppo 		groupp->sockfd = -1;
97*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
98*1ae08745Sheppo 		vntsd_log(status, err_msg);
99*1ae08745Sheppo 		vntsd_clean_group(groupp);
100*1ae08745Sheppo 
101*1ae08745Sheppo 		thr_exit(0);
102*1ae08745Sheppo 		break;
103*1ae08745Sheppo 	}
104*1ae08745Sheppo }
105*1ae08745Sheppo 
106*1ae08745Sheppo /* allocate and initialize listening socket. */
107*1ae08745Sheppo static int
108*1ae08745Sheppo open_socket(int port_no, int *sockfd)
109*1ae08745Sheppo {
110*1ae08745Sheppo 
111*1ae08745Sheppo 	struct	    sockaddr_in addr;
112*1ae08745Sheppo 	int	    on;
113*1ae08745Sheppo 
114*1ae08745Sheppo 
115*1ae08745Sheppo 	/* allocate a socket */
116*1ae08745Sheppo 	*sockfd = socket(AF_INET, SOCK_STREAM, 0);
117*1ae08745Sheppo 	if (*sockfd < 0) {
118*1ae08745Sheppo 		if (errno == EINTR) {
119*1ae08745Sheppo 			return (VNTSD_STATUS_INTR);
120*1ae08745Sheppo 		}
121*1ae08745Sheppo 		return (VNTSD_ERR_LISTEN_SOCKET);
122*1ae08745Sheppo 	}
123*1ae08745Sheppo 
124*1ae08745Sheppo #ifdef DEBUG
125*1ae08745Sheppo 	/* set reuse local socket address */
126*1ae08745Sheppo 	on = 1;
127*1ae08745Sheppo 	if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) {
128*1ae08745Sheppo 		return (VNTSD_ERR_LISTEN_OPTS);
129*1ae08745Sheppo 	}
130*1ae08745Sheppo #endif
131*1ae08745Sheppo 
132*1ae08745Sheppo 	addr.sin_family = AF_INET;
133*1ae08745Sheppo 	addr.sin_addr.s_addr = (vntsd_ip_addr()).s_addr;
134*1ae08745Sheppo 	addr.sin_port = htons(port_no);
135*1ae08745Sheppo 
136*1ae08745Sheppo 	/* bind socket */
137*1ae08745Sheppo 	if (bind(*sockfd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
138*1ae08745Sheppo 		if (errno == EINTR) {
139*1ae08745Sheppo 			return (VNTSD_STATUS_INTR);
140*1ae08745Sheppo 		}
141*1ae08745Sheppo 		return (VNTSD_ERR_LISTEN_BIND);
142*1ae08745Sheppo 
143*1ae08745Sheppo 	}
144*1ae08745Sheppo 
145*1ae08745Sheppo 	if (listen(*sockfd, VNTSD_MAX_SOCKETS) == -1) {
146*1ae08745Sheppo 		if (errno == EINTR) {
147*1ae08745Sheppo 			return (VNTSD_STATUS_INTR);
148*1ae08745Sheppo 		}
149*1ae08745Sheppo 		return (VNTSD_ERR_LISTEN_BIND);
150*1ae08745Sheppo 	}
151*1ae08745Sheppo 
152*1ae08745Sheppo 	D1(stderr, "t@%d open_socket() sockfd=%d\n", thr_self(), *sockfd);
153*1ae08745Sheppo 	return (VNTSD_SUCCESS);
154*1ae08745Sheppo }
155*1ae08745Sheppo 
156*1ae08745Sheppo /* ceate console selection thread */
157*1ae08745Sheppo static int
158*1ae08745Sheppo create_console_thread(vntsd_group_t *groupp, int sockfd)
159*1ae08745Sheppo {
160*1ae08745Sheppo 	vntsd_client_t	    *clientp;
161*1ae08745Sheppo 	vntsd_thr_arg_t	    arg;
162*1ae08745Sheppo 	int		    rv;
163*1ae08745Sheppo 
164*1ae08745Sheppo 
165*1ae08745Sheppo 	assert(groupp);
166*1ae08745Sheppo 	D1(stderr, "t@%d create_console_thread@%lld:client@%d\n", thr_self(),
167*1ae08745Sheppo 	    groupp->tcp_port, sockfd);
168*1ae08745Sheppo 
169*1ae08745Sheppo 	/* allocate a new client */
170*1ae08745Sheppo 	clientp = (vntsd_client_t *)malloc(sizeof (vntsd_client_t));
171*1ae08745Sheppo 	if (clientp  == NULL) {
172*1ae08745Sheppo 		return (VNTSD_ERR_NO_MEM);
173*1ae08745Sheppo 	}
174*1ae08745Sheppo 
175*1ae08745Sheppo 	/* initialize the client */
176*1ae08745Sheppo 	bzero(clientp, sizeof (vntsd_client_t));
177*1ae08745Sheppo 
178*1ae08745Sheppo 	clientp->sockfd = sockfd;
179*1ae08745Sheppo 	clientp->cons_tid = (thread_t)-1;
180*1ae08745Sheppo 
181*1ae08745Sheppo 	(void) mutex_init(&clientp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
182*1ae08745Sheppo 
183*1ae08745Sheppo 	/* append client to group */
184*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
185*1ae08745Sheppo 
186*1ae08745Sheppo 	if ((rv = vntsd_que_append(&groupp->no_cons_clientpq, clientp))
187*1ae08745Sheppo 	    != VNTSD_SUCCESS) {
188*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
189*1ae08745Sheppo 		vntsd_free_client(clientp);
190*1ae08745Sheppo 		return (rv);
191*1ae08745Sheppo 	}
192*1ae08745Sheppo 
193*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
194*1ae08745Sheppo 
195*1ae08745Sheppo 	(void) mutex_lock(&clientp->lock);
196*1ae08745Sheppo 
197*1ae08745Sheppo 	/* parameters for console thread */
198*1ae08745Sheppo 	bzero(&arg, sizeof (arg));
199*1ae08745Sheppo 
200*1ae08745Sheppo 	arg.handle = groupp;
201*1ae08745Sheppo 	arg.arg = clientp;
202*1ae08745Sheppo 
203*1ae08745Sheppo 	/* create console selection thread */
204*1ae08745Sheppo 	if (thr_create(NULL, 0, (thr_func_t)vntsd_console_thread,
205*1ae08745Sheppo 		    &arg, THR_DETACHED, &clientp->cons_tid)) {
206*1ae08745Sheppo 
207*1ae08745Sheppo 		(void) mutex_unlock(&clientp->lock);
208*1ae08745Sheppo 		(void) mutex_lock(&groupp->lock);
209*1ae08745Sheppo 		(void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp);
210*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
211*1ae08745Sheppo 		vntsd_free_client(clientp);
212*1ae08745Sheppo 
213*1ae08745Sheppo 		return (VNTSD_ERR_CREATE_CONS_THR);
214*1ae08745Sheppo 	}
215*1ae08745Sheppo 
216*1ae08745Sheppo 	(void) mutex_unlock(&clientp->lock);
217*1ae08745Sheppo 
218*1ae08745Sheppo 	return (VNTSD_SUCCESS);
219*1ae08745Sheppo }
220*1ae08745Sheppo 
221*1ae08745Sheppo /* listen thread */
222*1ae08745Sheppo void *
223*1ae08745Sheppo vntsd_listen_thread(vntsd_group_t *groupp)
224*1ae08745Sheppo {
225*1ae08745Sheppo 
226*1ae08745Sheppo 	int		newsockfd;
227*1ae08745Sheppo 	size_t		clilen;
228*1ae08745Sheppo 	struct		sockaddr_in cli_addr;
229*1ae08745Sheppo 	int		rv;
230*1ae08745Sheppo 	int		num_cons;
231*1ae08745Sheppo 
232*1ae08745Sheppo 	assert(groupp);
233*1ae08745Sheppo 
234*1ae08745Sheppo 	D1(stderr, "t@%d listen@%lld\n", thr_self(), groupp->tcp_port);
235*1ae08745Sheppo 
236*1ae08745Sheppo 
237*1ae08745Sheppo 	/* initialize listen socket */
238*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
239*1ae08745Sheppo 	rv = open_socket(groupp->tcp_port, &groupp->sockfd);
240*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
241*1ae08745Sheppo 	listen_chk_status(groupp, rv);
242*1ae08745Sheppo 
243*1ae08745Sheppo 	for (; ; ) {
244*1ae08745Sheppo 
245*1ae08745Sheppo 		clilen = sizeof (cli_addr);
246*1ae08745Sheppo 
247*1ae08745Sheppo 		/* listen to the socket */
248*1ae08745Sheppo 		newsockfd = accept(groupp->sockfd, (struct sockaddr *)&cli_addr,
249*1ae08745Sheppo 			    &clilen);
250*1ae08745Sheppo 
251*1ae08745Sheppo 		D1(stderr, "t@%d listen_thread() connected sockfd=%d\n",
252*1ae08745Sheppo 		    thr_self(), newsockfd);
253*1ae08745Sheppo 
254*1ae08745Sheppo 		if (newsockfd <=  0) {
255*1ae08745Sheppo 
256*1ae08745Sheppo 			if (errno == EINTR) {
257*1ae08745Sheppo 				listen_chk_status(groupp, VNTSD_STATUS_INTR);
258*1ae08745Sheppo 			} else {
259*1ae08745Sheppo 				listen_chk_status(groupp,
260*1ae08745Sheppo 				    VNTSD_STATUS_ACCEPT_ERR);
261*1ae08745Sheppo 			}
262*1ae08745Sheppo 			continue;
263*1ae08745Sheppo 		}
264*1ae08745Sheppo 		num_cons = vntsd_chk_group_total_cons(groupp);
265*1ae08745Sheppo 		if (num_cons == 0) {
266*1ae08745Sheppo 			(void) close(newsockfd);
267*1ae08745Sheppo 			listen_chk_status(groupp, VNTSD_STATUS_NO_CONS);
268*1ae08745Sheppo 		}
269*1ae08745Sheppo 
270*1ae08745Sheppo 		/* a connection is established */
271*1ae08745Sheppo 		rv = vntsd_set_telnet_options(newsockfd);
272*1ae08745Sheppo 		if (rv != VNTSD_SUCCESS) {
273*1ae08745Sheppo 			(void) close(newsockfd);
274*1ae08745Sheppo 			listen_chk_status(groupp, rv);
275*1ae08745Sheppo 		}
276*1ae08745Sheppo 		rv = create_console_thread(groupp, newsockfd);
277*1ae08745Sheppo 		if (rv != VNTSD_SUCCESS) {
278*1ae08745Sheppo 			(void) close(newsockfd);
279*1ae08745Sheppo 			listen_chk_status(groupp, rv);
280*1ae08745Sheppo 		}
281*1ae08745Sheppo 	}
282*1ae08745Sheppo 
283*1ae08745Sheppo 	/*NOTREACHED*/
284*1ae08745Sheppo 	return (NULL);
285*1ae08745Sheppo }
286