/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* vntsd uses configuration information provided by vcc to export access
* to Ldom console access over regular TCP sockets. When it starts, it opens
* the vcc driver control port and obtains the list of ports that have been
* created by the vcc driver as well as TCP port number and group associated
* with each port.
* vntsd consists of multiple components as the follows:
*
* vntsd.c
* This module initializes vnts daemon, process user options such as instance
* number, ip address and etc., and provides main thread to poll any console
* port change.
*
* vntsdvcc.c
* This module provides vcc driver interface. It opens vcc driver control
* ports, read initial configuration, and provides interface to read, write and
* ioctl virtual console ports. This module creates a listen thread for each
* console group. It further dynamically adds and removes virtual consoles
* and groups following instructions of the vcc driver. This module
* is executed in the same thread as vntsd.c which is blocked on vcc control
* poll interface.
*
* listen.c
* This is a group listen thread. Each group's tcp-port has a listen thread
* associated with it. The thread is created when a console is associated with
* a new group and is removed when all consoles in the group are removed.
*
* console.c
* This is a console selection thread. The thread is created when a client
* connects to a group TCP port and exited when client disconnects. If there is
* only one console in the group, the client is connected to that console. If
* there are multiple consoles in the group, the client is asked to select a
* console. After determining which console to connect to, this thread
* a write thread if the cient is a writer and it self read in client input.
*
* read.c
* it reads input from a TCP client, processes
* special daemon and telent commands and write to vcc driver if the client
* is a writer. The client is a writer if the client is the first one connects
* to the console. Read thread print out an error message if a reader attempt
* to input to vcc. Read thread exits if console is deleted, client
* disconnects, or there is a fatal error.
*
* Write.c
* Write thread is creaed when first client connects to a console. It reads
* from vcc and writes to all clients that connect to the same console.
* Write thread exits when all clients disconnect from the console.
*
* cmd.c
* This is a supporting module for handling special daemon and telnet commands.
*
* common.c
* supporting modules shared by threads modules.
*
* queue.c
* This is a moudle supporting queue operations. Vntsd organizes its data
* in multiple queues <see data structure below>.
*
* vntsd.xml
* This is a manifest to support SMF interfaces.
*
* Data structures
* each group has a vntsd_group_t structure, which contains a queue of
* all console in that group.
* each console has a vntsd_cons_t structure, which contains a queue of
* all clients that connected to the console.
*
* +----------+ +----------+ +----------+
* | group |-->| group |-->| group |-->....
* +----------+ +----------+ +----------+
* |
* |<-----------------------------------------+
* |<------------------------+ |
* |<--------+ | |
* | | | |
* | +----------+ +----------+ +----------+
* +----->| console |---->| console |---->| lconsole |---> ....
* +----------+ +----------+ +----------+
* | |
* | | +----------+ +----------+
* | +---->| client |----->| client |----->......
* | +----------+ +----------+
* | | |
* |<------------+ |
* |<------------------------------+
*
* Locks
* Each vntsd has one lock to protect the group queue
* Each group has one lock to protect the console queue, the queue for
* clients without a console connection and status.
* Each console has one lock to protect client queue and status.
* Each client has one lock to protect the state of the client. The client
* states are:
*
* VCC_CLIENT_READER
* A client is connected to a console as either a writer or a reader.
* if this client is the first one connects the console, the client is
* a writer, otherwise the client is a reader. A writer' write thread
* reads from vcc and send output to all readers connected to the
* same console. a reader's write thread is blocked until a reader becomes
* a writer.
*
* When a client selected a console, the client becomes a reader if
* there is another client connected to the console before the client.
* A client will be a writer if
* 1. client is the first one connected to the console or
* 2. client has entered a ~w daemon command or
* 3. all clients connected to the console before the client have
* disconnected from the console.
*
* VCC_CLIENT_MOVE_CONS_FORWARD
* VCC_CLIENT_MOVE_CONS_BACKWOARD
* A client is disconnecting from one console and move to the next or
* previous console in the group queue.
* A client is in one of these state if
* 1. the client has entered the daemon command and
* 2. the vntsd is in process of switching the client from one
* console to another.
*
* VCC_CLIENT_DISABLE_DAEMON_CMD
* vntsd is in processing of a client's daemon command or the client is
* in selecting console.
* A client is in this state if
* 1. the client has not selected a console or
* 2. the vntsd is processing a client's daemon command.
*
* VCC_CLIENT_ACQUIRE_WRITER
* A reader forces to become a writer via vntsd special command.
* A client is in this state if
* 1. the client is a reader and
* 2. client has entered a daemon command to become a writer.
*
* VCC_CLIENT_CONS_DELETED
* The console that the client is connected to is being deleted and
* waiting for the client to disconnect.
* A client is in this state if
* 1. the console a client is connected to is being removed and
* 2. the vntsd is in process of disconnecting the client from the console.
*
*/
#ifndef _VNTSD_H
#define _VNTSD_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/shm.h>
#include <strings.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stropts.h>
#include <errno.h>
#include <sys/param.h>
#include "../../uts/sun4v/sys/vcc.h"
#define DEBUG
/* vntsd limits */
#define VNTSD_MAX_BUF_SIZE 128
#define VNTSD_LINE_LEN 100
#define VNTSD_MAX_SOCKETS 5
#define VNTSD_EOL_LEN 2
/* secons before re-send signal for cv_wait */
#define VNTSD_CV_WAIT_DELTIME 10
#define VCC_PATH_PREFIX \
"/devices/virtual-devices@100/channel-devices@200/"
#define VCC_DEVICE_PATH "/devices%s"
#define VCC_DEVICE_CTL_PATH VCC_PATH_PREFIX "%s:ctl"
/* common messages */
#define VNTSD_NO_WRITE_ACCESS_MSG "You do not have write access"
/* vntsd options */
#define VNTSD_OPT_DAEMON_OFF 0x1
#define VNTSD_OPT_AUTH_CHECK 0x2 /* Enable auth checking */
/*
* group states
* When a console is removed or vntsd is exiting, main thread
* notifies listen, read and write thread to exit.
* After those threads exit, main thread clears up group structurre.
*
* VNTSD_GROUP_SIG_WAIT
* The main thread is waiting for listen thread to exit.
* VNTSD_GROUP_CLEAN_CONS
* There are console(s) in the group that are being removed.
* This is a transition state where the corresponding vcc port has been
* removed, but vntsd has not done its clean up yet.
* VNTSD_GROUP_IN_CLEANUP
* vntsd main thread has started cleaning up the group.
*/
#define VNTSD_GROUP_SIG_WAIT 0x1
#define VNTSD_GROUP_CLEAN_CONS 0x2
#define VNTSD_GROUP_IN_CLEANUP 0x4
/*
* console states
* There are two states when a console is removed
* VNTSD_CONS_DELETED
* the console is being deleted
* VNTSD_CONS_SIG_WAIT
* console is waiting for all clients to exit.
*/
#define VNTSD_CONS_DELETED 0x1 /* deleted */
#define VNTSD_CONS_SIG_WAIT 0x2 /* waiting for signal */
#define VNTSD_CLIENT_IO_ERR 0x1 /* reader */
#define VNTSD_CLIENT_DISABLE_DAEMON_CMD 0x2 /* disable daemon cmd */
#define VNTSD_CLIENT_TIMEOUT 0x4 /* timeout */
#define VNTSD_CLIENT_CONS_DELETED 0x8 /* console deleted */
/* generic que structure */
typedef struct vntsd_que {
void *handle; /* element in queue */
struct vntsd_que *nextp; /* next queue element */
struct vntsd_que *prevp; /* previous queue element */
} vntsd_que_t;
struct vntsd_cons;
struct vntsd_group;
struct vntsd;
/* client structure */
typedef struct vntsd_client {
mutex_t lock; /* protect the client */
uint_t status; /* client's state */
int sockfd; /* connection socket */
thread_t cons_tid; /* console thread */
struct vntsd_cons *cons; /* back link to console configuration */
char prev_char; /* previous char read by this client */
} vntsd_client_t;
/* console structure */
typedef struct vntsd_cons {
mutex_t lock; /* protect console port */
cond_t cvp; /* sync between threads */
vntsd_que_t *clientpq; /* client que */
uint_t status; /* client's state */
int vcc_fd; /* vcc console port */
thread_t wr_tid; /* write thread */
uint_t cons_no; /* console port number */
char domain_name[MAXPATHLEN]; /* domain name */
char dev_name[MAXPATHLEN];
struct vntsd_group *group; /* back link to group */
} vntsd_cons_t;
/* group structure */
typedef struct vntsd_group {
mutex_t lock; /* protect group */
cond_t cvp; /* sync remove group */
uint_t status; /* group status */
char group_name[MAXPATHLEN];
uint64_t tcp_port; /* telnet port */
thread_t listen_tid; /* listen thread */
int sockfd; /* listen socket */
vntsd_que_t *conspq; /* console queue */
uint_t num_cons; /* num console */
/* clients have no console connection */
vntsd_que_t *no_cons_clientpq;
struct vntsd *vntsd;
} vntsd_group_t;
/* daemon structure */
typedef struct vntsd {
mutex_t lock; /* protect vntsd */
mutex_t tmo_lock; /* protect tmo queue */
int instance; /* vcc instance */
struct in_addr ip_addr; /* ip address to listen */
uint64_t options; /* daemon options */
int timeout; /* connection timeout */
char *devinst; /* device name */
int ctrl_fd; /* vcc ctrl port */
vntsd_que_t *grouppq; /* group queue */
uint_t num_grps; /* num groups */
vntsd_que_t *tmoq; /* timeout queue */
thread_t tid; /* main thread id */
} vntsd_t;
/* handle for creating thread */
typedef struct vntsd_thr_arg {
void *handle;
void *arg;
} vntsd_thr_arg_t;
/* timeout structure */
typedef struct vntsd_timeout {
thread_t tid; /* thread tid */
uint_t minutes; /* idle minutes */
vntsd_client_t *clientp; /* client */
} vntsd_timeout_t;
/* vntsd status and error definitions */
typedef enum {
/* status */
VNTSD_SUCCESS = 0, /* success */
VNTSD_STATUS_CONTINUE, /* continue to execute */
VNTSD_STATUS_EXIT_SIG, /* exit siginal */
VNTSD_STATUS_SIG, /* known signal */
VNTSD_STATUS_NO_HOST_NAME, /* no host name set */
VNTSD_STATUS_CLIENT_QUIT, /* client disconnected from group */
VNTSD_STATUS_RESELECT_CONS, /* client re-selecting console */
VNTSD_STATUS_VCC_IO_ERR, /* a vcc io error occurs */
VNTSD_STATUS_MOV_CONS_FORWARD, /* down arrow */
VNTSD_STATUS_MOV_CONS_BACKWARD, /* up arrow */
VNTSD_STATUS_ACQUIRE_WRITER, /* force become the writer */
VNTSD_STATUS_INTR, /* thread receive a signal */
VNTSD_STATUS_DISCONN_CONS, /* disconnect a client from cons */
VNTSD_STATUS_NO_CONS, /* disconnect a client from cons */
VNTSD_STATUS_AUTH_ENABLED, /* auth enabled; can't process '-p' */
/* resource errors */
VNTSD_ERR_NO_MEM, /* memory allocation error */
VNTSD_ERR_NO_DRV, /* cannot open vcc port */
/* vcc errors */
VNTSD_ERR_VCC_CTRL_DATA, /* vcc ctrl data error */
VNTSD_ERR_VCC_POLL, /* error poll vcc driver */
VNTSD_ERR_VCC_IOCTL, /* vcc ioctl call error */
VNTSD_ERR_VCC_GRP_NAME, /* group name differs from database */
VNTSD_ERR_ADD_CONS_FAILED, /* addition of a console failed */
/* create thread errors */
VNTSD_ERR_CREATE_LISTEN_THR, /* listen thread creation failed */
VNTSD_ERR_CREATE_CONS_THR, /* create console thread err */
VNTSD_ERR_CREATE_WR_THR, /* listen thread creation failed */
/* listen thread errors */
VNTSD_ERR_LISTEN_SOCKET, /* can not create tcp socket */
VNTSD_ERR_LISTEN_OPTS, /* can not set socket opt */
VNTSD_ERR_LISTEN_BIND, /* can not bind socket */
VNTSD_STATUS_ACCEPT_ERR, /* accept error */
/* tcp client read and write errors */
VNTSD_ERR_WRITE_CLIENT, /* writing tcp client err */
/* tcp client timeout */
VNTSD_ERR_CLIENT_TIMEOUT, /* client has no activity for timeout */
/* signal errors */
VNTSD_ERR_SIG, /* unknown signal */
/* user input error */
VNTSD_ERR_INVALID_INPUT, /* client typed in */
/* internal errors */
VNTSD_ERR_EL_NOT_FOUND, /* element not found */
VNTSD_ERR_UNKNOWN_CMD /* unknown error/cmd */
} vntsd_status_t;
/* function prototype defines */
typedef int (*compare_func_t)(void *el, void *data);
typedef int (*el_func_t)(void *el);
typedef void (*clean_func_t)(void *el);
typedef void (*sig_handler_t)(int sig);
typedef void *(*thr_func_t)(void *);
/* function prototype */
void vntsd_log(vntsd_status_t err, char *msg);
struct in_addr vntsd_ip_addr(void);
void vntsd_get_config(vntsd_t *vntsdp);
void vntsd_daemon_wakeup(vntsd_t *vntsdp);
int vntsd_open_vcc(char *domain_name, uint_t cons_no);
void vntsd_delete_cons(vntsd_t *vntsdp);
void vntsd_clean_group(vntsd_group_t *groupp);
void *vntsd_listen_thread(vntsd_group_t *groupp);
void *vntsd_console_thread(vntsd_thr_arg_t *argp);
int vntsd_read(vntsd_client_t *clientp);
void *vntsd_write_thread(vntsd_cons_t *consp);
boolean_t vntsd_cons_by_consno(vntsd_cons_t *consp, int *cons_id);
int vntsd_que_append(vntsd_que_t **que_hd, void *handle);
int vntsd_que_rm(vntsd_que_t **que_hd, void *handle);
void *vntsd_que_find(vntsd_que_t *que_hd, compare_func_t
compare_func, void *data);
void *vntsd_que_walk(vntsd_que_t *que_hd, el_func_t el_func);
int vntsd_que_insert_after(vntsd_que_t *que, void *handle,
void *next);
void *vntsd_que_pos(vntsd_que_t *que_hd, void *handle, int pos);
void vntsd_free_que(vntsd_que_t **q, clean_func_t clean_func);
int vntsd_read_char(vntsd_client_t *clientp, char *c);
int vntsd_read_line(vntsd_client_t *clientp, char *buf, int *size);
int vntsd_read_data(vntsd_client_t *clientp, char *c);
int vntsd_get_yes_no(vntsd_client_t *clientp, char *msg,
int *yes_no);
int vntsd_ctrl_cmd(vntsd_client_t *clientp, char c);
int vntsd_process_daemon_cmd(vntsd_client_t *clientp, char c);
int vntsd_telnet_cmd(vntsd_client_t *clientp, char c);
int vntsd_set_telnet_options(int fd);
int vntsd_write_client(vntsd_client_t *client, char *buffer,
size_t sz);
int vntsd_write_fd(int fd, void *buffer, size_t sz);
int vntsd_write_line(vntsd_client_t *clientp, char *line);
int vntsd_write_lines(vntsd_client_t *clientp, char *lines);
extern char vntsd_eol[];
void vntsd_clean_group(vntsd_group_t *portp);
void vntsd_free_client(vntsd_client_t *clientp);
int vntsd_attach_timer(vntsd_timeout_t *tmop);
int vntsd_detach_timer(vntsd_timeout_t *tmop);
void vntsd_reset_timer(thread_t tid);
void vntsd_init_esctable_msgs(void);
int vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf);
int vntsd_vcc_err(vntsd_cons_t *consp);
int vntsd_cons_chk_intr(vntsd_client_t *clientp);
boolean_t vntsd_vcc_cons_alive(vntsd_cons_t *consp);
boolean_t vntsd_notify_client_cons_del(vntsd_client_t *clientp);
int vntsd_chk_group_total_cons(vntsd_group_t *groupp);
boolean_t vntsd_mark_deleted_cons(vntsd_cons_t *consp);
boolean_t auth_check_fd(int sock_fd, char *group_name);
#ifdef DEBUG
extern int vntsddbg;
#define D1 if (vntsddbg & 0x01) (void) fprintf
#define D2 if (vntsddbg & 0x02) (void) fprintf
#define D3 if (vntsddbg & 0x04) (void) fprintf
#define DERR if (vntsddbg & 0x08) (void) fprintf
#else /* not DEBUG */
#define D1
#define D2
#define D3
#define DERR
#endif /* not DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* _VNTSD_H */