xref: /illumos-gate/usr/src/cmd/vntsd/write.c (revision d10e4ef2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 /*
28  * write thread - read from vcc console and  write to tcp client. There are one
29  * writer and multiple readers per console. The first client who connects to
30  * a console get write access.
31  * Writer thread writes vcc data to all tcp clients that connected to
32  * the console.
33  */
34 
35 #include <stdio.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <thread.h>
44 #include <synch.h>
45 #include <signal.h>
46 #include <assert.h>
47 #include <poll.h>
48 #include <syslog.h>
49 #include <libintl.h>
50 #include "vntsd.h"
51 #include "chars.h"
52 
53 /* handle for writing all clients  */
54 typedef	struct write_buf {
55 	uint_t	sz;	    /* data size */
56 	char	*buf;
57 } write_buf_t;
58 
59 /*
60  * check the state of write thread. exit if no more client connects to the
61  * console.
62  */
63 static void
64 write_chk_status(vntsd_cons_t *consp, int status)
65 {
66 
67 	if ((consp->status & VNTSD_CONS_DELETED) || (consp->clientpq == NULL)) {
68 		thr_exit(0);
69 	}
70 
71 	switch (status) {
72 	case VNTSD_STATUS_VCC_IO_ERR:
73 		assert(consp->group != NULL);
74 		if (vntsd_vcc_err(consp) != VNTSD_STATUS_CONTINUE) {
75 			thr_exit(0);
76 		}
77 		break;
78 	case VNTSD_STATUS_INTR:
79 		thr_exit(0);
80 	default:
81 		break;
82 
83 	}
84 }
85 
86 /*
87  * skip_terminal_null()
88  * scan terminal null character sequence (0x5e 0x40)
89  * return number of characters in the buf after skipping terminal null
90  * sequence. buf size must be at least sz+1.
91  */
92 static int
93 skip_terminal_null(char *buf, int sz)
94 {
95 	int	    i, j;
96 	static int  term_null_seq = 0;
97 
98 	assert(sz >= 0);
99 
100 	if (term_null_seq) {
101 		/* skip 0x5e previously */
102 		term_null_seq = 0;
103 
104 		if (buf[0] != 0x40) {
105 			/* not terminal null sequence put 0x5e back */
106 			for (i = sz; i > 0; i--) {
107 				buf[i] = buf[i-1];
108 			}
109 
110 			buf[0] = 0x5e;
111 
112 			sz++;
113 		} else {
114 			/* skip terminal null sequence */
115 			sz--;
116 
117 			if (sz == 0) {
118 				return (sz);
119 			}
120 
121 			for (i = 0; i < sz; i++) {
122 				buf[i] = buf[i+1];
123 			}
124 		}
125 	}
126 
127 	for (; ; ) {
128 		for (i = 0; i < sz; i++) {
129 			if (buf[i]  == '\0') {
130 				return (i);
131 			}
132 
133 			if (buf[i] == 0x5e) {
134 				/* possible terminal null sequence */
135 				if (i == sz -1) {
136 					/* last character in buffer */
137 					term_null_seq = 1;
138 					sz--;
139 					buf[i] = 0;
140 					return (sz);
141 				}
142 
143 				if (buf[i+1] == 0x40) {
144 					/* found terminal null sequence */
145 					sz -= 2;
146 					for (j = i; j < sz -i; j++) {
147 						buf[j] = buf[j+2];
148 					}
149 					break;
150 				}
151 
152 				if (buf[i+1] == '\0') {
153 					buf[i] = 0;
154 					term_null_seq = 1;
155 					return (i);
156 				}
157 
158 			}
159 		}
160 
161 		if (i == sz) {
162 			/* end of scan */
163 			return (sz);
164 		}
165 	}
166 }
167 
168 /* read data from vcc */
169 static int
170 read_vcc(vntsd_cons_t *consp, char *buf, ssize_t *sz)
171 {
172 	/* read from vcc */
173 	*sz = read(consp->vcc_fd, buf, VNTSD_MAX_BUF_SIZE);
174 
175 	if (errno == EINTR) {
176 		return (VNTSD_STATUS_INTR);
177 	}
178 
179 	if ((*sz > 0)) {
180 		return (VNTSD_SUCCESS);
181 	}
182 	return (VNTSD_STATUS_VCC_IO_ERR);
183 }
184 
185 /*
186  * write to a client
187  * this function is passed as a parameter to vntsd_que_find.
188  * for each client that connected to the console, vntsd_que_find
189  * applies this function.
190  */
191 static boolean_t
192 write_one_client(vntsd_client_t *clientp, write_buf_t *write_buf)
193 {
194 	int rv;
195 
196 	rv = vntsd_write_client(clientp, write_buf->buf, write_buf->sz);
197 	if (rv != VNTSD_SUCCESS) {
198 		(void) mutex_lock(&clientp->lock);
199 		clientp->status |= VNTSD_CLIENT_IO_ERR;
200 		assert(clientp->cons);
201 		(void) thr_kill(clientp->cons_tid, NULL);
202 		(void) mutex_unlock(&clientp->lock);
203 	}
204 	return (B_FALSE);
205 
206 }
207 
208 /* vntsd_write_thread() */
209 void*
210 vntsd_write_thread(vntsd_cons_t *consp)
211 {
212 	char		buf[VNTSD_MAX_BUF_SIZE+1];
213 	int		sz;
214 	int		rv;
215 	write_buf_t	write_buf;
216 
217 	D1(stderr, "t@%d vntsd_write@%d\n", thr_self(), consp->vcc_fd);
218 
219 	assert(consp);
220 	write_chk_status(consp, VNTSD_SUCCESS);
221 
222 	for (; ; ) {
223 		bzero(buf,  VNTSD_MAX_BUF_SIZE +1);
224 
225 		/* read data */
226 		rv = read_vcc(consp, buf, &sz);
227 
228 		write_chk_status(consp, rv);
229 
230 		if (sz <= 0) {
231 			continue;
232 		}
233 
234 		/* has data */
235 		if ((sz = skip_terminal_null(buf, sz)) == 0) {
236 			/* terminal null sequence */
237 			continue;
238 		}
239 
240 		write_buf.sz = sz;
241 		write_buf.buf = buf;
242 
243 		/*
244 		 * output data to all clients connected
245 		 * to this console
246 		 */
247 
248 		(void) mutex_lock(&consp->lock);
249 		(void) vntsd_que_find(consp->clientpq,
250 		    (compare_func_t)write_one_client, &write_buf);
251 		(void) mutex_unlock(&consp->lock);
252 
253 		write_chk_status(consp, VNTSD_SUCCESS);
254 
255 	}
256 
257 	/*NOTREACHED*/
258 	return (NULL);
259 }
260