diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/voclient/voapps/vosession.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'vendor/voclient/voapps/vosession.c')
-rw-r--r-- | vendor/voclient/voapps/vosession.c | 1278 |
1 files changed, 1278 insertions, 0 deletions
diff --git a/vendor/voclient/voapps/vosession.c b/vendor/voclient/voapps/vosession.c new file mode 100644 index 00000000..958f1787 --- /dev/null +++ b/vendor/voclient/voapps/vosession.c @@ -0,0 +1,1278 @@ +/** + * VOSESSION -- Inter-Desktop Session Manager for the VOSAMP task. + * + * Usage: + * + * vosession [<opts>] + * + * Where + * -%,--test run unit tests + * -h,--help print help summary + * -d,--debug debug output + * -v,--verbose verbose output + * + * Subcommands: + * + * status print Hub availability + * list list all registered clients + * + * + * @file vosession.c + * @author Mike Fitzpatrick + * @date 6/03/12 + * + * @brief Session Manager for the VOSAMP task. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <time.h> + +#include <netdb.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + + +#include "samp.h" /* LIBSAMP interface */ +#include "voApps.h" /* voApps interface */ + + +#define SZ_BUF 128 +#define SZ_MTYPE 64 +#define SZ_HOSTIP 16 + +#define MAX_ARGS 8 /* Max args in a command */ +#define MAX_SESSIONS 64 /* Max sessions to manage */ +#define MAX_PORTS 128 /* Max ports to manage */ + +#define SESS_SELWIDTH 32 /* select fd width */ +#define SESS_TIMEOUT 3600 /* 1-hr timeout */ +#define SESS_DISCONNECT 309 /* Session Mgr command timeout */ + +#define MATCH(s) (strcasecmp(cmd,s)==0) + + +/* Connected session client. + */ +typedef struct { + int sock; /* socket descriptor */ + int port; /* connection port */ + char hostIP[SZ_HOSTIP]; /* host IP address */ + char session[SZ_LINE]; /* session name */ + + void *back; /* linked-list back ptr */ + void *next; /* linked-list next ptr */ +} Node, *NodeP; + + +/* Session structure. + */ +typedef struct { + int nclients; /* number of clients */ + Node *clients; /* clients in session */ + char name[SZ_LINE]; /* session name */ + char dataCache[SZ_LINE]; /* path to local data cache */ + + int ncmds; /* Number of commands sent */ + int nfiles; /* Number of files uploaded */ + long nbytes; /* Number of files uploaded */ + time_t start_time; /* session start time */ + time_t end_time; /* session end time */ + time_t last_cmd; /* session last command */ + + void *back; /* linked-list back ptr */ + void *next; /* linked-list next ptr */ +} Session, *SessionP; + + +static int nSessions = 0; +static Session* sessHead = NULL; +static Session* sessTail = NULL; + +static int nClients = 0; +static Node* clientHead = NULL; +static Node* clientTail = NULL; + +static int verbose = FALSE; /* verbose output */ +static int debug = FALSE; /* verbose output */ +static int interactive = FALSE; /* interactive mode */ +static int xml_trace = FALSE; /* trace XML_RPC */ +static int timeout = SESS_TIMEOUT; /* select() doesn't timeout */ +static int svr_port = SESS_DEFPORT; /* connection port */ +static int selwidth = SESS_SELWIDTH;/* select() width */ + +static int keep_alive = TRUE; /* lingering connection */ +static int svr_sock = FALSE; /* server socket descriptor */ +static int cb_sock = 0; /* callback socket descriptor */ +static int cb_port = 0; /* callback port number */ +static int socks[MAX_PORTS]; /* available sockets */ + + +static char *to = NULL; /* message recipient */ +static char *session = NULL; /* session name */ +static char cmd[SZ_CMD]; /* command name */ +static char *args[MAX_ARGS]; /* command args buffer */ +static char data_file[SZ_URL]; /* uploaded data file */ + + +static fd_set allset, rfds; +static struct timeval tm; + + +#define NOAO +#ifdef NOAO +static char *sessionData = "/iraf/web/vosession"; +static char *sessionUrlBase = "http://iraf.noao.edu/vosession"; +#else +static char *sessionData = "/tmp/vosession"; +static char *sessionUrlBase = "file:///tmp/vosession"; +#endif +static char logfile[SZ_LINE]; +static char statfile[SZ_LINE]; + + + +/* Utility socket routines. + */ +extern int vos_openServerSocket (int port); +extern int vos_openClientSocket (char *host, int port, int retry); +extern int vos_sockRead (int fd, void *vptr, int nbytes); +extern int vos_sockWrite (int fd, void *vptr, int nbytes); +extern void vos_setNonBlock (int sock); +extern int vos_sockWriteHdr (int fd, int len, char *name, int type, + int mode, char *to); +extern int vos_sockReadHdr (int fd, int *len, char *name, int *type, + int *mode); +extern int vos_recvFile (int sock, int size, char *fname); +extern int vot_atoi (char *v); +extern char *vo_logtime (void); +extern char *vos_typeName (int type); + + + +/* Task specific option declarations. + */ +static char *opts = "h%:dikp:tuvS:T:"; +static struct option long_opts[] = { + { "help", 2, 0, 'h'}, /* required */ + { "test", 1, 0, '%'}, /* required */ + { "debug", 2, 0, 'd'}, /* debug */ + { "interactive", 2, 0, 'i'}, /* interactive mode */ + { "keepalive", 2, 0, 'k'}, /* keep connection */ + { "port", 1, 0, 'p'}, /* server port */ + { "trace", 2, 0, 't'}, /* trace cmds */ + { "url", 2, 0, 'u'}, /* upload data base URL */ + { "verbose", 2, 0, 'v'}, /* verbose */ + { "session", 1, 0, 'S'}, /* session name */ + { "timeout", 1, 0, 'T'}, /* connection timeout */ + { NULL, 0, 0, 0 } +}; + +static void Usage (void); +static void Tests (char *input); + + +static int sess_procCmd (int sock, int msgtype, int nbytes, char *fname); +static int sess_forwardMessage (int sender, char *msg); +static int sess_connectClient (int sock); +static int sess_disconnectClient (int sock); +static int sess_disconnectAllClients (void); +static int sess_joinSession (int sock, char *session_name); +static int sess_leaveSession (int sock, char *session_name); + +static Session *sess_newSession (char *name); +static int sess_freeSession (Session *s); + +static Node *sess_newNode (int sock); +static int sess_freeNode (Node *n); + +static Session *sess_byName (char *name); +static Session *sess_bySock (int sock); +static Node *sess_clientBySock (int sock); + +#ifdef SESSION_EXTRAS +static Session *sess_byPort (int port); +static Node *sess_clientByPort (int port); +static int sess_portToSock (int port); +#endif + +static int sess_newPort (void); +static int sess_freePort (int port); +static int sess_sockToPort (int sock); + +static char *sess_tok (char *str, int tok); +static void sess_rewriteCmd (char *line, char *session, char *fname); +static void sessLog (char *formtat, ...); +static void sess_writeStats (Session *session); +static void sess_printSessions (void); +static void sess_printClients (void); + + + + +/**************************************************************************** + * Program entry point. + ***************************************************************************/ +int +main (int argc, char **argv) +{ + char **pargv, optval[SZ_FNAME], ch; + int i, rc, pos = 0; + + + + /* Initialize. + */ + memset (logfile, 0, SZ_LINE); + memset (data_file, 0, SZ_URL); + svr_port = SESS_DEFPORT; + for (i=0; i < MAX_ARGS; i++) + args[i] = calloc (1, SZ_LINE); + + + /* Parse the argument list. + */ + pargv = vo_paramInit (argc, argv, opts, long_opts); + i = 0; + while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) { + i++; + if (ch > 0) { + switch (ch) { + case '%': Tests (optval); return (OK); + case 'h': Usage (); return (OK); + + case 'd': debug++; break; + case 'v': verbose++; break; + case 'k': keep_alive=0; break; + + case 'p': svr_port = vot_atoi(optval); break; + case 't': xml_trace=1; break; + + case 'S': session = strdup (optval); break; + case 'T': timeout = vot_atoi (optval); break; + + default: + fprintf (stderr, "Invalid option '%s'\n", optval); + return (1); + } + + } else if (ch == PARG_ERR) { + return (ERR); + + } else { + /* There is no other cmdline arg. + */ + fprintf (stderr, "Invalid option '%s'\n", argv[i]); + return (1); + } + } + + + /* Sanity checks. + */ + if (to == NULL) + to = strdup ("all"); + + /* Create the working session directory. + */ + if (access (sessionData, F_OK) < 0) { + if (mkdir (sessionData, 0755) < 0) { + fprintf (stderr, "Cannot create session directory '%s'\n", + sessionData); + return (1); + } + } + sprintf (logfile, "%s/Log", sessionData); + sprintf (statfile, "%s/Stats", sessionData); + + + /* Initialize the socket interface and timeouts. + */ + tm.tv_sec = timeout; + tm.tv_usec = 0; + + if ((svr_sock = vos_openServerSocket (svr_port)) < 0) { + sessLog ("Cannot open server connection port %d\n", svr_port); + return (1); + } else if (debug) { + sessLog ("=======================================\n"); + sessLog ("VOSession server started on port %4d\n", svr_port); + sessLog ("=======================================\n"); + } + + FD_ZERO (&allset); + FD_SET (svr_sock, &allset); + vos_setNonBlock (svr_sock); + if (interactive) { + FD_SET (fileno(stdin), &allset); + vos_setNonBlock (fileno(stdin)); + } + + + /* Begin processing. + */ + while (1) { + /* Initialize the input file descriptor set. + */ + memcpy (&rfds, &allset, sizeof(allset)); + rc = select (selwidth, &rfds, NULL, NULL, &tm); + if (rc == 0) { + time_t now = time (NULL); + Session *s = (Session *) NULL; + Node *n = (Node *) NULL; + + /* Send a disconnect to all subscribed clients that have been + * inactive for more than SESS_DISCONNECT seconds (1-hr); + */ + for (s=sessHead; s; s=s->next) { + if ((now - s->last_cmd) >= SESS_DISCONNECT) { + sessLog ("Session timeout for '%s'\n", s->name); + for (n=s->clients; n; n=n->next) { + sess_disconnectClient (n->sock); + sess_leaveSession (n->sock, s->name); + } + } + } + continue; + } + + /* Loop over the active descriptors to process input. + */ + for (i=0; i < selwidth+1; i++) { + if (FD_ISSET(i, &rfds)) { + if (i == svr_sock) { + /* Accept a new connection on the port. + */ + if (sess_connectClient (svr_sock) != 0) + sessLog ("Cannot connect Client: ", strerror(errno)); + + } else { + /* Handle input from existing client-node connection. + */ + int nread=0, nbytes=0, type=0, mode=0; + char fname[SZ_FNAME]; + + memset (fname, 0, SZ_FNAME); + if (debug > 1) sessLog ("Input on fd %d ....\n", i); + + /* Read the length of the message and type. + */ + nread = vos_sockReadHdr (i, &nbytes, fname, &type, &mode); + if (nread <= 0) { + /* Error on the socket or client closed connection. + */ + sess_disconnectClient (i); + } else { + /* Read the command. + */ + sess_procCmd (i, type, nbytes, fname); + } + } /* end is server socket */ + } /* end FD_ISSET */ + } /* end for */ + } /* end while */ + + + /* Clean up. Note, we should never actually get here.... + */ + if (to) free ((void *) to); + if (session) free ((void *) session); + sess_disconnectAllClients (); + + /* Close the the connection socket. + */ + if (svr_sock) + close (svr_sock); + + return (OK); +} + + + + +/*************************************************************************** +**** Client Handling Procedures **** +***************************************************************************/ + +/** + * SESS_PROCCMD -- Process a command message. + */ +static int +sess_procCmd (int sock, int msgtype, int nbytes, char *fname) +{ + + int i, len, nsent, type=0, mode=0, nread=0; + char line[SZ_LINE], path[SZ_LINE]; + Session *s = (Session *) sess_bySock (sock); + + + memset (line, 0, SZ_LINE); /* initialize */ + memset (path, 0, SZ_LINE); + + /* Read the command header. This will either be a SAMP_DATA + * message in which case we get a filename, or SAMP_CMD where + * we ignore the fname value and then read the command string. + */ + switch (msgtype) { + case SAMP_DATA: + sprintf (path, "%s/%s", s->dataCache, fname); + + if (vos_recvFile (sock, nbytes, path) != OK) { + if (debug) + sessLog ("Error receiving file '%s'\n", fname); + } + strcpy (data_file, fname); + + vos_sockReadHdr (sock, &nbytes, fname, &type, &mode); + nread = vos_sockRead (sock, line, nbytes); + if (debug) sessLog ("SAMP_DATA: '%s' '%s'\n", line, fname); + sess_rewriteCmd (line, s->name, data_file); + memset (data_file, 0, SZ_FNAME); + + s->nfiles++; + s->nbytes += nbytes; + + /* Forward to other connected clients. + */ + s->ncmds++; + s->last_cmd = time (NULL); + nsent = sess_forwardMessage (sock, line); + if (debug) + sessLog ("Forwarded to %d clients in '%s'\n", nsent, s->name); + + break; + + case SAMP_CMD: + case SAMP_RELAY: + nread = vos_sockRead (sock, line, nbytes); + + if (debug) + sessLog ("%s[%d][%s]: '%s'\n", vos_typeName (msgtype), nread, + (s ? s->name : ""), line); + if (s && line[0] && data_file[0]) { + sess_rewriteCmd (line, s->name, data_file); + memset (data_file, 0, SZ_FNAME); + } + + if (strncasecmp (line, "quit", 4) == 0) { /* QUIT */ + sess_disconnectClient (sock); + + } else if (strncasecmp (line, "list", 4) == 0) { /* LIST */ + Node *n = (Node *) NULL; + char buf[(4*SZ_LINE)], line[SZ_LINE]; + + memset (buf, 0, (4 * SZ_LINE)); + sprintf (buf, "Clients in session '%s':\n", s->name); + for (i=0,n=clientHead; n; n=n->next,i++) { + memset (line, 0, SZ_LINE); + sprintf (line, " [%d]: host: %16.16s port: %d\n", + i, n->hostIP, n->port); + strcat (buf, line); + } + + /* Write the result string back to the client. + */ + len = strlen (buf); + if (vos_sockWriteHdr (sock, len, NULL, SAMP_RESULT, + SAMP_NOTIFY, "all")) + nread = vos_sockWrite (sock, buf, strlen (buf)); + + } else if (strncasecmp (line, "connect", 4) == 0) { /* JOIN */ + sess_joinSession (sock, sess_tok (line, 2)); + + } else if (strncasecmp (line, "leave", 4) == 0) { /* LEAVE */ + sess_leaveSession (sock, s->name); + + } else { /* ELSE .... */ + if (line[0] && msgtype == SAMP_CMD) { + nsent = sess_forwardMessage (sock, line); + if (debug) + sessLog ("Forward to %d clients in '%s'\n", nsent, s->name); + } + } + if (s) { + s->ncmds++; + s->last_cmd = time (NULL); + } + break; + + case SAMP_RESULT: + if (debug) + sessLog ("%s[%s]: '%s'\n", vos_typeName (msgtype), + (s ? s->name : ""), " "); + break; /* Not yet implemented */ + + case SAMP_QUIT: + sess_leaveSession (sock, NULL); + sess_disconnectClient (sock); + break; + + default: + sessLog ("cmd: '%s'\n", cmd); + } + + return (0); +} + + +/** + * SESS_FORWARDMESSAGE -- Forward the message to all clients in the session + * other than the one which originated it. + */ +static int +sess_forwardMessage (int sender, char *msg) +{ + Session *s = sess_bySock (sender); + Node *n = (Node *) NULL; + int len, nw, sock, nsent = 0; + + + for (n=s->clients; n; n=n->next) { + sock = n->sock; + if (sock != sender) { + if (debug) fprintf (stderr, "forward to '%s'\n", n->hostIP); + len = strlen (msg); + if (vos_sockWriteHdr (sock, len, NULL, SAMP_RELAY, 0, "all")) + nw = vos_sockWrite (sock, msg, len); + nsent++; + } + } + + return (nsent); +} + + +/** + * SESS_CONNECTCLIENT -- Connect a client on the named socket. + */ +static int +sess_connectClient (int sock) +{ + int new, nr; + short ready, sport; + struct sockaddr_in client; + size_t size = sizeof (client); + char sname[SZ_LINE]; + + + memset (sname, 0, SZ_LINE); + + if ((new = accept (sock, (struct sockaddr *) &client, + (socklen_t *) &size)) < 0) { + sessLog ("svr_sock accept() errno %d: %s", errno, strerror(errno)); + + } else { + char *host = inet_ntoa (client.sin_addr); + int port = ntohs (client.sin_port); + Node *node = (Node *) NULL; + + + /* Attach the client to the list of connected hosts. + */ + node = sess_newNode (new); + node->port = port; + node->sock = new; + strcpy (node->hostIP, host); + if (clientHead) { + clientTail->next = node; + clientTail = node; + } else { + clientHead = clientTail = node; + } + nClients++; + + /* Open new server connection and send the callback + * port number over the connection. After that, we + * don't need the initial connection so release it. + */ + cb_port = sport = sess_newPort (); + cb_sock = vos_openServerSocket (cb_port); + if (debug) + sessLog ("Connect from host:%s, port:%d, fd:%d, cb_port: %d\n", + host, port, new, cb_port); + vos_sockWrite (new, &sport, sizeof(short)); + cb_port = sport; + close (new); + + /* Waiting for callback to connect. + */ + if ((new = accept (cb_sock, NULL, NULL)) < 0) + sessLog ("cb_sock accept() errno %d: %s", errno, strerror(errno)); + vos_setNonBlock (new); + + /* Wait for the callback ready message so we know + * we are connected to the client. + */ + nr = vos_sockRead (new, &ready, sizeof(short)); + if (ready == SESS_READY) { +#ifdef READ_CONNECT + int nbytes=0, type=0, mode=0; + + /* Read the session name. + */ + vos_sockReadHdr (new, &nbytes, NULL, &type, &mode); + nr = vos_sockRead (new, sname, nbytes); + + if (verbose) + sessLog ("Connect host %s:%d\n", + inet_ntoa(client.sin_addr), ntohs(client.sin_port), sname); + strcpy (node->session, sname); +#else + if (verbose) + sessLog ("Connect host %s:%d\n", + inet_ntoa (client.sin_addr), ntohs (client.sin_port)); +#endif + } + + + /* Add the client socket fd to the master set of + * active descriptors. + */ + FD_SET (new, &allset); + } + + return (0); +} + + +/** + * SESS_DISCONNECTCLIENT -- Shutdown client on the named socket. + */ +static int +sess_disconnectClient (int sock) +{ + Node *client = sess_clientBySock (sock); + + sessLog ("Disconnecting client %d....\n", sock); + FD_CLR (sock, &allset); + close (sock); + + sess_freeNode (client); + sess_freePort (client->port); + + return (0); +} + + +/** + * SESS_DISCONNECTALLCLIENTS -- Shutdown all connected clients + */ +static int +sess_disconnectAllClients () +{ + Session *s = (Session *) NULL; + Node *n = (Node *) NULL; + + /* Loop over all the session and their client lists and disconnect + * the client. We do it here rather than following the client list + * since we'll also clean up the data cache when the session is closed. + */ + for (s=sessHead; s; s=s->next) { + for (n=s->clients; n; n=n->next) { + if (debug) + sessLog ("Disconnecting host %s on port %d from '%s'\n", + n->hostIP, n->port, s->name); + + sess_leaveSession (n->sock, s->name); + } + } + return (0); +} + + + + +/*************************************************************************** +**** Session Procedures **** +***************************************************************************/ + +/** + * SESS_JOINSESSION -- Join (or create) a session. + */ +static int +sess_joinSession (int sock, char *session_name) +{ + Session *s = (Session *) NULL; + Node *n = (Node *) NULL; + int found = 0; + + + if (sessHead) { + s = sess_byName (session_name); + if (s == (Session *) NULL) { + /* Name not found, create a new session pointer. + */ + s = sess_newSession (session_name); + sessTail->next = s; + sessTail = s; + nSessions++; + } + + } else { + /* No active sessions, create one. + */ + s = sessHead = sessTail = sess_newSession (session_name); + + /* Create the working session directory. + */ + sprintf (s->dataCache, "%s/%s", sessionData, session_name); + if (access (s->dataCache, F_OK) < 0) { + if (debug) sessLog ("Making session cache directory '%s'\n", + s->dataCache); + if (mkdir (s->dataCache, 0755) < 0) { + fprintf (stderr, "Cannot create session cache directory '%s'\n", + s->dataCache); + return (1); + } + } + nSessions++; + } + + /* Now attach the node the session list of clients, both the master + * client list and the client list in each session. + */ + for (n=clientHead; n; n=n->next) { /* master client list */ + if (sock == n->sock) + strcpy (n->session, session_name); + } + found = 0; + for (n=s->clients; n && n->next; n=n->next) { + if (n->sock == sock) { /* skip to end of client list */ + /* client is already in session. + */ + found++; + } + } + + /* Add to client list if it isn't already found. + */ + if (!found) { + if (n) { + n->next = sess_newNode (sock); + strcpy (n->session, session_name); + } else { + s->clients = sess_newNode (sock); + strcpy (s->clients->session, session_name); + } + s->nclients++; + } + + if (debug > 1) { sess_printSessions (); sess_printClients (); } + return (0); +} + + +/** + * SESS_LEAVESESSION -- Leave an open session. + */ +static int +sess_leaveSession (int sock, char *session_name) +{ + Session *s = (Session *) NULL; + int port = sess_sockToPort (sock); + + + s = (session_name ? sess_byName (session_name) : sess_bySock (sock)); + if (s) { + Node *n = s->clients; + + while (n && n->port != port) + n = n->next; + + if (n) { + sessLog ("%s leaves session '%s'\n", n->hostIP, s->name); + sess_freeNode (n); + s->nclients--; + } + + if (s->nclients == 0) { + /* Remove the working session directory and its contents. + */ + if (access (s->dataCache, F_OK) == 0) { + char cmd[SZ_LINE]; + + memset (cmd, 0, SZ_LINE); + sprintf (cmd, "/bin/rm -rf %s", s->dataCache); + if (debug) sessLog ("Removing session cache directory '%s'\n", + s->dataCache); + + system (cmd); /* FIXME */ + } + sess_freeSession (s); + } + } + + if (debug > 1) sess_printSessions (); + return (0); +} + + +/** + * SESS_BYNAME - Find a Session pointer by name. + */ +static Session * +sess_byName (char *name) +{ + Session *s = (Session *) NULL; + + for (s=sessHead; s; s=s->next) + if (strcasecmp (name, s->name) == 0) + break; + + return (s); +} + + +/** + * SESS_BYSOCK - Find a Session socket descriptor. + */ +static Session * +sess_bySock (int sock) +{ + Session *s = (Session *) NULL; + Node *n = (Node *) NULL; + + for (n=clientHead; n; n=n->next) { + if (sock == n->sock) + return (sess_byName (n->session)); + } + return (s); +} + + +/** + * SESS_CLIENTBYSOCK - Find a Node pointer by socket fd. + */ +static Node * +sess_clientBySock (int sock) +{ + Node *n = (Node *) NULL; + + for (n=clientHead; n; n=n->next) { + if (n->sock == sock) + return (n); + } + + return ((Node *) NULL); +} + + +/** + * SESS_SOCKTOPORT - Lookup a port number by the socket fd. + */ +static int +sess_sockToPort (int sock) +{ + Node *n = (Node *) NULL; + + for (n=clientHead; n; n=n->next) { + if (n->sock == sock) + return (n->port); + } + + return (-1); +} + + +#ifdef SESSION_EXTRAS +/** + * SESS_CLIENTBYPORT - Find a Node pointer by port number. + */ +static Node * +sess_clientByPort (int port) +{ + Node *n = (Node *) NULL; + + for (n=clientHead; n; n=n->next) { + if (n->port == port) + return (n); + } + + return ((Node *) NULL); +} + + +/** + * SESS_BYPORT - Find a Session port number. + */ +static Session * +sess_byPort (int port) +{ + Session *s = (Session *) NULL; + Node *n = (Node *) NULL; + + for (n=clientHead; n; n=n->next) { + if (port == n->port) + return (sess_byName (n->session)); + } + return (s); +} + + +/** + * SESS_PORTTOSOCK - Lookup a socket fd by the client port number. + */ +static int +sess_portToSock (int port) +{ + Node *n = clientHead; + + for (n=clientHead; n; n=n->next) + if (n->port == port) + return (n->sock); + + return (-1); +} +#endif + + +/** + * SESS_NEWSESSION - Create a new Session structure. + */ +static Session * +sess_newSession (char *name) +{ + Session *s = (Session *) calloc (1, sizeof (Session)); + + strcpy (s->name, name); + s->start_time = time (NULL); + return (s); +} + + +/** + * SESS_FREESESSION - Release a Session structure. + */ +static int +sess_freeSession (Session *s) +{ + Session *back = (Session *) (s ? s->back : NULL); + Session *next = (Session *) (s ? s->next : NULL); + + if (s == sessHead) + sessHead = (Session *) next; /* head of the list */ + else if (s->next == (Session *) NULL) + sessHead = (Session *) back; /* tail of the list */ + else + back->next = (void *) s->next; /* middle of the list */ + + if (s->nclients == 0) { + fprintf (stderr, "Free up session resources for '%s'\n", s->name); + } + nSessions--; + + s->end_time = time (NULL); + + sess_writeStats (s); /* log the session stats */ + + free ((void *) s); + if (debug > 1) sess_printSessions (); + return (0); +} + + +/** + * SESS_NEWNODE - Create a new Node structure. + */ +static Node * +sess_newNode (int sock) +{ + Node *n = (Node *) calloc (1, sizeof (Node)); + Node *client = sess_clientBySock (sock); + + if (client) { + n->sock = client->sock; + n->port = client->port; + strcpy (n->hostIP, client->hostIP); + } + + return (n); +} + + +/** + * SESS_FREENODE - Free a Node structure. + */ +static int +sess_freeNode (Node *node) +{ + if (node->back) { + Node *back = node->back; + back->next = node->next; + } + if (node->next) { + Node *next = node->next; + next->back = node->back; + } + + free ((void *) node); + return (0); +} + + +/** + * SESS_PRINTSESSIONS - Utility to print the session list. + */ +static void +sess_printSessions (void) +{ + Session *s = sessHead; + Node *n = (Node *) NULL; + int i, j; + + if (!s) { + fprintf (stderr, "No active sessions\n"); + + } else { + for (s=sessHead,i=0; s; s=s->next, i++) { + fprintf (stderr, "Session[%d]: session '%s' has %d client%c\n", + i, s->name, s->nclients, (s->nclients > 1 ? 's':' ')); + for (n=sessHead->clients,j=0; n; n=n->next, j++) { + fprintf (stderr, " Client[%d]: port: %d host: %s\n", + j, n->port, n->hostIP); + } + } + } +} + + +/** + * SESS_PRINTCLIENTS - Utility to print the client list. + */ +static void +sess_printClients (void) +{ + Node *n = (Node *) NULL; + int i; + + for (n=clientHead,i=0; n; n=n->next, i++) { + fprintf (stderr, "Client[%d]: port:%d sock:%d host:%s session:%s\n", + i, n->port, n->sock, n->hostIP, n->session); + } +} + + +/*************************************************************************** +**** Utility Procedures **** +***************************************************************************/ + +/** + * SESS_WRITESTATS -- Log the sessions statistics. + */ +static void +sess_writeStats (Session *s) +{ + FILE *fd; + char buf[SZ_LINE]; + double nsec; + + + if (s) { + memset (buf, 0, SZ_LINE); + nsec = (s->end_time - s->start_time); + sprintf (buf, + "%s %16.16s ncmds: %d nfiles: %d nbytes: %ld time: %6.1f min\n", + vo_logtime(), s->name, s->ncmds, s->nfiles, s->nbytes, (nsec/60.)); + + if ((fd = fopen (statfile, "w+"))) { + if (debug) + sessLog ("%s", buf); + fprintf (fd, "%s", buf); + fflush (fd); fclose (fd); + } + } else + sessLog ("Error: writeStats gets null session"); +} + + +/** + * SESSLOG -- Print a message to the logfile. + */ +static void +sessLog (char *format, ...) +{ + FILE *fd; + va_list argp; + char *buf = calloc (1, 1024); + char *tstr = NULL; + int len=0; + extern char *vo_encodeString (); + + + /* Format the message. + */ + va_start (argp, format); + vo_encodeString (buf, format, &argp); + va_end (argp); + + len = strlen (buf); /* ensure a newline */ + if (buf[len-1] != '\n') + strcat (buf, "\n"); + + + /* Log the message. + */ + tstr = vo_logtime (); + if (logfile[0] == '-' || strcasecmp (logfile, "stdout") == 0) { + printf ("%s %s", tstr, buf); + + } else { + if ((fd = fopen (logfile, "w+"))) { + if (debug) + fprintf (stderr, "%s %s", tstr, buf); + fprintf (fd, "%s %s", tstr, buf); + fflush (fd); fclose (fd); + } + } + + free ((void *) buf); +} + + +/** + * SESS_NEWPORT -- Get an open socket/port entry. + */ +static int +sess_newPort () +{ + int i, p; + + for (i=0; i < MAX_PORTS; i++) { + p = svr_port + i + 3; + if (socks[i] == 0) { + socks[i] = p; + return (p); + } + } + + sessLog ("Error: No available client ports.\n"); + return (-1); +} + + +/** + * SESS_FREEPORT -- Free a socket/port entry. + */ +static int +sess_freePort (int port) +{ + int i, p; + + for (i=0; i < MAX_PORTS; i++) { + p = svr_port + i + 3; + if (p == port) { + close (socks[p]); + socks[i] = 0; + } + } + + return (0); +} + + +/** + * SESS_TOK -- Get the specified (1-indexed) w/s delimited token from str. + */ +static char * +sess_tok (char *str, int toknum) +{ + register int i; + static char tok[SZ_FNAME]; + char *ip = str, *op = tok; + + + memset (tok, 0, SZ_FNAME); /* initialize */ + + for (i=1; i < toknum; i++) { /* skip ahead to the token */ + while (!isspace ((int) (*ip)) && *ip) ip++; + while ( isspace ((int) (*ip)) && *ip) ip++; + } + + do { + *op++ = *ip++; + } while (!isspace ((int) (*ip)) && *ip); /* copy the token */ + + return (tok); +} + + +/** + * SESS_REWRITECMD -- Rewrite the command string with filename substitution. + */ +static void +sess_rewriteCmd (char *line, char *session, char *fname) +{ + char *ip, *op, buf[SZ_LINE], obuf[SZ_LINE], name[SZ_FNAME]; + + + memset (obuf, 0, SZ_LINE); + for (ip=line; *ip; ) { + memset (buf, 0, SZ_LINE); + memset (name, 0, SZ_FNAME); + + for (op=buf; *ip && !isspace(*ip); ) /* get token */ + *op++ = *ip++; + +#ifdef USE_FILE_URI + /* Replace file-URI and absolute paths with the replacement filename. + */ + if (strncmp ("file://", buf, 7) == 0 || buf[0] == '/') + strcat (obuf, fname); + else + strcat (obuf, buf); +#else + /* Replace 'SESSION_URL' with the session dataCache URL. + */ + if (strncmp ("SESSION_URL", buf, 11) == 0) { + strcpy (name, (buf[11] ? &buf[12] : fname)); + sprintf (buf, "%s/%s/%s", sessionUrlBase, session, name); + } + strcat (obuf, buf); +#endif + + while (*ip && isspace (*ip)) /* skip whitespace */ + strncat (obuf, ip++, 1); + } + + memset (line, 0, SZ_LINE); + strcpy (line, obuf); +} + + + +/** + * USAGE -- Print a task usage summary. + */ +static void +Usage (void) +{ + fprintf (stderr, + " Usage:\n" + "\n" + " %% vosession [-hvd] [-p <port>]\n" + "\n" + " where <cmd> command to process\n" + " -h print help summary\n" + " -v verbose output\n" + " -d debug output\n" + "\n" + " -p <port> server port\n" + "\n" + ); +} + + +/** + * Tests -- Task unit tests. + */ +static void +Tests (char *input) +{ + ; /* no-op */ +} |