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