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 * Each group has a listen thread. It is created at the time 29 * of a group creation and destroyed when a group does not have 30 * any console associated with it. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <netinet/in.h> 40 #include <thread.h> 41 #include <assert.h> 42 #include <signal.h> 43 #include <ctype.h> 44 #include <syslog.h> 45 #include "vntsd.h" 46 47 /* 48 * check the state of listen thread. exit if there is an fatal error 49 * or the group is removed. 50 */ 51 static void 52 listen_chk_status(vntsd_group_t *groupp, int status) 53 { 54 char err_msg[VNTSD_LINE_LEN]; 55 56 57 D1(stderr, "t@%d listen_chk_status() status=%d group=%s " 58 "tcp=%lld group status = %x\n", thr_self(), status, 59 groupp->group_name, groupp->tcp_port, groupp->status); 60 61 (void) snprintf(err_msg, sizeof (err_msg), 62 "Group:%s TCP port %lld status %x", 63 groupp->group_name, groupp->tcp_port, groupp->status); 64 65 66 switch (status) { 67 68 case VNTSD_SUCCESS: 69 return; 70 71 case VNTSD_STATUS_INTR: 72 assert(groupp->status & VNTSD_GROUP_SIG_WAIT); 73 /* close listen socket */ 74 (void) mutex_lock(&groupp->lock); 75 (void) close(groupp->sockfd); 76 groupp->sockfd = -1; 77 78 /* let group know */ 79 groupp->status &= ~VNTSD_GROUP_SIG_WAIT; 80 (void) cond_signal(&groupp->cvp); 81 82 (void) mutex_unlock(&groupp->lock); 83 /* exit thread */ 84 thr_exit(0); 85 break; 86 87 case VNTSD_STATUS_ACCEPT_ERR: 88 return; 89 90 case VNTSD_STATUS_NO_CONS: 91 default: 92 /* fatal, exit thread */ 93 94 (void) mutex_lock(&groupp->lock); 95 (void) close(groupp->sockfd); 96 groupp->sockfd = -1; 97 (void) mutex_unlock(&groupp->lock); 98 vntsd_log(status, err_msg); 99 vntsd_clean_group(groupp); 100 101 thr_exit(0); 102 break; 103 } 104 } 105 106 /* allocate and initialize listening socket. */ 107 static int 108 open_socket(int port_no, int *sockfd) 109 { 110 111 struct sockaddr_in addr; 112 int on; 113 114 115 /* allocate a socket */ 116 *sockfd = socket(AF_INET, SOCK_STREAM, 0); 117 if (*sockfd < 0) { 118 if (errno == EINTR) { 119 return (VNTSD_STATUS_INTR); 120 } 121 return (VNTSD_ERR_LISTEN_SOCKET); 122 } 123 124 #ifdef DEBUG 125 /* set reuse local socket address */ 126 on = 1; 127 if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) { 128 return (VNTSD_ERR_LISTEN_OPTS); 129 } 130 #endif 131 132 addr.sin_family = AF_INET; 133 addr.sin_addr.s_addr = (vntsd_ip_addr()).s_addr; 134 addr.sin_port = htons(port_no); 135 136 /* bind socket */ 137 if (bind(*sockfd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 138 if (errno == EINTR) { 139 return (VNTSD_STATUS_INTR); 140 } 141 return (VNTSD_ERR_LISTEN_BIND); 142 143 } 144 145 if (listen(*sockfd, VNTSD_MAX_SOCKETS) == -1) { 146 if (errno == EINTR) { 147 return (VNTSD_STATUS_INTR); 148 } 149 return (VNTSD_ERR_LISTEN_BIND); 150 } 151 152 D1(stderr, "t@%d open_socket() sockfd=%d\n", thr_self(), *sockfd); 153 return (VNTSD_SUCCESS); 154 } 155 156 /* ceate console selection thread */ 157 static int 158 create_console_thread(vntsd_group_t *groupp, int sockfd) 159 { 160 vntsd_client_t *clientp; 161 vntsd_thr_arg_t arg; 162 int rv; 163 164 165 assert(groupp); 166 D1(stderr, "t@%d create_console_thread@%lld:client@%d\n", thr_self(), 167 groupp->tcp_port, sockfd); 168 169 /* allocate a new client */ 170 clientp = (vntsd_client_t *)malloc(sizeof (vntsd_client_t)); 171 if (clientp == NULL) { 172 return (VNTSD_ERR_NO_MEM); 173 } 174 175 /* initialize the client */ 176 bzero(clientp, sizeof (vntsd_client_t)); 177 178 clientp->sockfd = sockfd; 179 clientp->cons_tid = (thread_t)-1; 180 181 (void) mutex_init(&clientp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 182 183 /* append client to group */ 184 (void) mutex_lock(&groupp->lock); 185 186 if ((rv = vntsd_que_append(&groupp->no_cons_clientpq, clientp)) 187 != VNTSD_SUCCESS) { 188 (void) mutex_unlock(&groupp->lock); 189 vntsd_free_client(clientp); 190 return (rv); 191 } 192 193 (void) mutex_unlock(&groupp->lock); 194 195 (void) mutex_lock(&clientp->lock); 196 197 /* parameters for console thread */ 198 bzero(&arg, sizeof (arg)); 199 200 arg.handle = groupp; 201 arg.arg = clientp; 202 203 /* create console selection thread */ 204 if (thr_create(NULL, 0, (thr_func_t)vntsd_console_thread, 205 &arg, THR_DETACHED, &clientp->cons_tid)) { 206 207 (void) mutex_unlock(&clientp->lock); 208 (void) mutex_lock(&groupp->lock); 209 (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 210 (void) mutex_unlock(&groupp->lock); 211 vntsd_free_client(clientp); 212 213 return (VNTSD_ERR_CREATE_CONS_THR); 214 } 215 216 (void) mutex_unlock(&clientp->lock); 217 218 return (VNTSD_SUCCESS); 219 } 220 221 /* listen thread */ 222 void * 223 vntsd_listen_thread(vntsd_group_t *groupp) 224 { 225 226 int newsockfd; 227 size_t clilen; 228 struct sockaddr_in cli_addr; 229 int rv; 230 int num_cons; 231 232 assert(groupp); 233 234 D1(stderr, "t@%d listen@%lld\n", thr_self(), groupp->tcp_port); 235 236 237 /* initialize listen socket */ 238 (void) mutex_lock(&groupp->lock); 239 rv = open_socket(groupp->tcp_port, &groupp->sockfd); 240 (void) mutex_unlock(&groupp->lock); 241 listen_chk_status(groupp, rv); 242 243 for (; ; ) { 244 245 clilen = sizeof (cli_addr); 246 247 /* listen to the socket */ 248 newsockfd = accept(groupp->sockfd, (struct sockaddr *)&cli_addr, 249 &clilen); 250 251 D1(stderr, "t@%d listen_thread() connected sockfd=%d\n", 252 thr_self(), newsockfd); 253 254 if (newsockfd <= 0) { 255 256 if (errno == EINTR) { 257 listen_chk_status(groupp, VNTSD_STATUS_INTR); 258 } else { 259 listen_chk_status(groupp, 260 VNTSD_STATUS_ACCEPT_ERR); 261 } 262 continue; 263 } 264 num_cons = vntsd_chk_group_total_cons(groupp); 265 if (num_cons == 0) { 266 (void) close(newsockfd); 267 listen_chk_status(groupp, VNTSD_STATUS_NO_CONS); 268 } 269 270 /* a connection is established */ 271 rv = vntsd_set_telnet_options(newsockfd); 272 if (rv != VNTSD_SUCCESS) { 273 (void) close(newsockfd); 274 listen_chk_status(groupp, rv); 275 } 276 rv = create_console_thread(groupp, newsockfd); 277 if (rv != VNTSD_SUCCESS) { 278 (void) close(newsockfd); 279 listen_chk_status(groupp, rv); 280 } 281 } 282 283 /*NOTREACHED*/ 284 return (NULL); 285 } 286