11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo /* 221ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231ae08745Sheppo * Use is subject to license terms. 241ae08745Sheppo */ 251ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 261ae08745Sheppo 271ae08745Sheppo /* 281ae08745Sheppo * write thread - read from vcc console and write to tcp client. There are one 291ae08745Sheppo * writer and multiple readers per console. The first client who connects to 301ae08745Sheppo * a console get write access. 311ae08745Sheppo * Writer thread writes vcc data to all tcp clients that connected to 321ae08745Sheppo * the console. 331ae08745Sheppo */ 341ae08745Sheppo 351ae08745Sheppo #include <stdio.h> 361ae08745Sheppo #include <stdio.h> 371ae08745Sheppo #include <stdlib.h> 381ae08745Sheppo #include <string.h> 391ae08745Sheppo #include <unistd.h> 401ae08745Sheppo #include <sys/types.h> 411ae08745Sheppo #include <sys/socket.h> 421ae08745Sheppo #include <netinet/in.h> 431ae08745Sheppo #include <thread.h> 441ae08745Sheppo #include <synch.h> 451ae08745Sheppo #include <signal.h> 461ae08745Sheppo #include <assert.h> 471ae08745Sheppo #include <poll.h> 481ae08745Sheppo #include <syslog.h> 491ae08745Sheppo #include <libintl.h> 501ae08745Sheppo #include "vntsd.h" 511ae08745Sheppo #include "chars.h" 521ae08745Sheppo 53*d10e4ef2Snarayan /* handle for writing all clients */ 54*d10e4ef2Snarayan typedef struct write_buf { 55*d10e4ef2Snarayan uint_t sz; /* data size */ 56*d10e4ef2Snarayan char *buf; 57*d10e4ef2Snarayan } write_buf_t; 58*d10e4ef2Snarayan 591ae08745Sheppo /* 601ae08745Sheppo * check the state of write thread. exit if no more client connects to the 611ae08745Sheppo * console. 621ae08745Sheppo */ 631ae08745Sheppo static void 641ae08745Sheppo write_chk_status(vntsd_cons_t *consp, int status) 651ae08745Sheppo { 661ae08745Sheppo 671ae08745Sheppo if ((consp->status & VNTSD_CONS_DELETED) || (consp->clientpq == NULL)) { 681ae08745Sheppo thr_exit(0); 691ae08745Sheppo } 701ae08745Sheppo 711ae08745Sheppo switch (status) { 721ae08745Sheppo case VNTSD_STATUS_VCC_IO_ERR: 731ae08745Sheppo assert(consp->group != NULL); 741ae08745Sheppo if (vntsd_vcc_err(consp) != VNTSD_STATUS_CONTINUE) { 751ae08745Sheppo thr_exit(0); 761ae08745Sheppo } 771ae08745Sheppo break; 781ae08745Sheppo case VNTSD_STATUS_INTR: 791ae08745Sheppo thr_exit(0); 801ae08745Sheppo default: 811ae08745Sheppo break; 821ae08745Sheppo 831ae08745Sheppo } 841ae08745Sheppo } 851ae08745Sheppo 861ae08745Sheppo /* 871ae08745Sheppo * skip_terminal_null() 881ae08745Sheppo * scan terminal null character sequence (0x5e 0x40) 891ae08745Sheppo * return number of characters in the buf after skipping terminal null 90*d10e4ef2Snarayan * sequence. buf size must be at least sz+1. 911ae08745Sheppo */ 921ae08745Sheppo static int 93*d10e4ef2Snarayan skip_terminal_null(char *buf, int sz) 941ae08745Sheppo { 951ae08745Sheppo int i, j; 961ae08745Sheppo static int term_null_seq = 0; 971ae08745Sheppo 981ae08745Sheppo assert(sz >= 0); 991ae08745Sheppo 1001ae08745Sheppo if (term_null_seq) { 1011ae08745Sheppo /* skip 0x5e previously */ 1021ae08745Sheppo term_null_seq = 0; 1031ae08745Sheppo 1041ae08745Sheppo if (buf[0] != 0x40) { 1051ae08745Sheppo /* not terminal null sequence put 0x5e back */ 1061ae08745Sheppo for (i = sz; i > 0; i--) { 1071ae08745Sheppo buf[i] = buf[i-1]; 1081ae08745Sheppo } 1091ae08745Sheppo 1101ae08745Sheppo buf[0] = 0x5e; 1111ae08745Sheppo 1121ae08745Sheppo sz++; 1131ae08745Sheppo } else { 1141ae08745Sheppo /* skip terminal null sequence */ 1151ae08745Sheppo sz--; 1161ae08745Sheppo 1171ae08745Sheppo if (sz == 0) { 1181ae08745Sheppo return (sz); 1191ae08745Sheppo } 1201ae08745Sheppo 1211ae08745Sheppo for (i = 0; i < sz; i++) { 1221ae08745Sheppo buf[i] = buf[i+1]; 1231ae08745Sheppo } 1241ae08745Sheppo } 1251ae08745Sheppo } 1261ae08745Sheppo 1271ae08745Sheppo for (; ; ) { 1281ae08745Sheppo for (i = 0; i < sz; i++) { 1291ae08745Sheppo if (buf[i] == '\0') { 1301ae08745Sheppo return (i); 1311ae08745Sheppo } 1321ae08745Sheppo 1331ae08745Sheppo if (buf[i] == 0x5e) { 1341ae08745Sheppo /* possible terminal null sequence */ 1351ae08745Sheppo if (i == sz -1) { 1361ae08745Sheppo /* last character in buffer */ 1371ae08745Sheppo term_null_seq = 1; 1381ae08745Sheppo sz--; 1391ae08745Sheppo buf[i] = 0; 1401ae08745Sheppo return (sz); 1411ae08745Sheppo } 1421ae08745Sheppo 1431ae08745Sheppo if (buf[i+1] == 0x40) { 1441ae08745Sheppo /* found terminal null sequence */ 1451ae08745Sheppo sz -= 2; 1461ae08745Sheppo for (j = i; j < sz -i; j++) { 1471ae08745Sheppo buf[j] = buf[j+2]; 1481ae08745Sheppo } 1491ae08745Sheppo break; 1501ae08745Sheppo } 1511ae08745Sheppo 1521ae08745Sheppo if (buf[i+1] == '\0') { 1531ae08745Sheppo buf[i] = 0; 1541ae08745Sheppo term_null_seq = 1; 1551ae08745Sheppo return (i); 1561ae08745Sheppo } 1571ae08745Sheppo 1581ae08745Sheppo } 1591ae08745Sheppo } 1601ae08745Sheppo 1611ae08745Sheppo if (i == sz) { 1621ae08745Sheppo /* end of scan */ 1631ae08745Sheppo return (sz); 1641ae08745Sheppo } 1651ae08745Sheppo } 1661ae08745Sheppo } 1671ae08745Sheppo 1681ae08745Sheppo /* read data from vcc */ 1691ae08745Sheppo static int 1701ae08745Sheppo read_vcc(vntsd_cons_t *consp, char *buf, ssize_t *sz) 1711ae08745Sheppo { 1721ae08745Sheppo /* read from vcc */ 1731ae08745Sheppo *sz = read(consp->vcc_fd, buf, VNTSD_MAX_BUF_SIZE); 1741ae08745Sheppo 1751ae08745Sheppo if (errno == EINTR) { 1761ae08745Sheppo return (VNTSD_STATUS_INTR); 1771ae08745Sheppo } 1781ae08745Sheppo 1791ae08745Sheppo if ((*sz > 0)) { 1801ae08745Sheppo return (VNTSD_SUCCESS); 1811ae08745Sheppo } 1821ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 1831ae08745Sheppo } 1841ae08745Sheppo 185*d10e4ef2Snarayan /* 186*d10e4ef2Snarayan * write to a client 187*d10e4ef2Snarayan * this function is passed as a parameter to vntsd_que_find. 188*d10e4ef2Snarayan * for each client that connected to the console, vntsd_que_find 189*d10e4ef2Snarayan * applies this function. 190*d10e4ef2Snarayan */ 1911ae08745Sheppo static boolean_t 192*d10e4ef2Snarayan write_one_client(vntsd_client_t *clientp, write_buf_t *write_buf) 1931ae08745Sheppo { 1941ae08745Sheppo int rv; 1951ae08745Sheppo 196*d10e4ef2Snarayan rv = vntsd_write_client(clientp, write_buf->buf, write_buf->sz); 1971ae08745Sheppo if (rv != VNTSD_SUCCESS) { 1981ae08745Sheppo (void) mutex_lock(&clientp->lock); 1991ae08745Sheppo clientp->status |= VNTSD_CLIENT_IO_ERR; 2001ae08745Sheppo assert(clientp->cons); 2011ae08745Sheppo (void) thr_kill(clientp->cons_tid, NULL); 2021ae08745Sheppo (void) mutex_unlock(&clientp->lock); 2031ae08745Sheppo } 2041ae08745Sheppo return (B_FALSE); 2051ae08745Sheppo 2061ae08745Sheppo } 2071ae08745Sheppo 2081ae08745Sheppo /* vntsd_write_thread() */ 2091ae08745Sheppo void* 2101ae08745Sheppo vntsd_write_thread(vntsd_cons_t *consp) 2111ae08745Sheppo { 2121ae08745Sheppo char buf[VNTSD_MAX_BUF_SIZE+1]; 2131ae08745Sheppo int sz; 2141ae08745Sheppo int rv; 215*d10e4ef2Snarayan write_buf_t write_buf; 2161ae08745Sheppo 2171ae08745Sheppo D1(stderr, "t@%d vntsd_write@%d\n", thr_self(), consp->vcc_fd); 2181ae08745Sheppo 2191ae08745Sheppo assert(consp); 2201ae08745Sheppo write_chk_status(consp, VNTSD_SUCCESS); 2211ae08745Sheppo 2221ae08745Sheppo for (; ; ) { 2231ae08745Sheppo bzero(buf, VNTSD_MAX_BUF_SIZE +1); 2241ae08745Sheppo 2251ae08745Sheppo /* read data */ 2261ae08745Sheppo rv = read_vcc(consp, buf, &sz); 2271ae08745Sheppo 2281ae08745Sheppo write_chk_status(consp, rv); 2291ae08745Sheppo 2301ae08745Sheppo if (sz <= 0) { 2311ae08745Sheppo continue; 2321ae08745Sheppo } 2331ae08745Sheppo 2341ae08745Sheppo /* has data */ 235*d10e4ef2Snarayan if ((sz = skip_terminal_null(buf, sz)) == 0) { 2361ae08745Sheppo /* terminal null sequence */ 2371ae08745Sheppo continue; 2381ae08745Sheppo } 2391ae08745Sheppo 240*d10e4ef2Snarayan write_buf.sz = sz; 241*d10e4ef2Snarayan write_buf.buf = buf; 2421ae08745Sheppo 2431ae08745Sheppo /* 2441ae08745Sheppo * output data to all clients connected 2451ae08745Sheppo * to this console 2461ae08745Sheppo */ 2471ae08745Sheppo 2481ae08745Sheppo (void) mutex_lock(&consp->lock); 2491ae08745Sheppo (void) vntsd_que_find(consp->clientpq, 250*d10e4ef2Snarayan (compare_func_t)write_one_client, &write_buf); 2511ae08745Sheppo (void) mutex_unlock(&consp->lock); 2521ae08745Sheppo 2531ae08745Sheppo write_chk_status(consp, VNTSD_SUCCESS); 2541ae08745Sheppo 2551ae08745Sheppo } 2561ae08745Sheppo 2571ae08745Sheppo /*NOTREACHED*/ 2581ae08745Sheppo return (NULL); 2591ae08745Sheppo } 260