/** * VOSAMP - Example task to send a single SAMP message for the cmdline. * * Usage: * * vosamp [] [args ...] * * Where * command to process * -%,--test run unit tests * -h,--help print help summary * -d,--debug debug output * -v,--verbose verbose output * -q,--quiet suppress all output * * -i,--interactive interactive mode * -m,--many handle multiple messages * -s,--sender handle only messages from * * -t,--to send to specified application (or all) * -p,--pattern message pattern: sync|async|notify * -f,--file send all commands in the file * -n,--nokeepalive disable keep_alive feature * * -P,--proxy proxy process connection * -T,--timeout keepalive timeout * -S,--session session name * * -r,--return return result to API * * * Subcommands: * * snoop print all received messages * * session list list all nodes in current session * session leave|exit|logout leave the current session * session join the named session * * status print Hub availability * list list all registered clients * access print availability * handle wait for message * * send [ ...] generalized message send * exec execute a client command * pointAt point at given coords * setenv set an environment value * getenv get an environment value * setparam set a parameter value * getparam get a parameter value * * load load the named image/table file * loadImage load the named image * loadVOTable load the named VOTable * loadFITS load the named FITS bintable * showRow [] [] highlight specified row * selectRows [] [] select specified rows * bibcode load the named bibcode * * * @file vosamp.c * @author Mike Fitzpatrick * @date 6/03/12 * * @brief Desktop SAMP messaging utility. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "samp.h" /* LIBSAMP interface */ #include "voApps.h" /* voApps interface */ #define SZ_MTYPE 64 #define SZ_BUF 128 #define SZ_HOSTIP 16 #define SZ_APPNAME 16 #define SZ_BLOCK 4096 #define HUB_TIMEOUT /* allow timeout */ #define ENV_PROXY "VOSAMP_PROXY" #define MAX_ARGS 8 #define VOS_TIMEOUT 600 /* 10-min proxy timeout */ #define VOS_DEFPORT 3999 #define VOS_HUBWAIT 3 #define MATCH(s) (strcasecmp(cmd,s)==0) char senderIP[SZ_HOSTIP]; char fname[SZ_FNAME]; char *to = NULL; static int sampH = 0; /* samp struct handle */ /* task options */ static int verbose = 0; /* verbose output */ static int quiet = 0; /* suppress all output */ static int debug = 0; /* verbose output */ static int interact = 0; /* interactive shell */ static int multiple = 0; /* accept multiple msgs */ static int xml_trace = 0; /* trace XML_RPC */ static int keep_alive = 1; /* lingering connection */ static int proxy_pid = 0; /* proxy vosamp pid */ static int proxy_port = VOS_DEFPORT; /* proxy vosamp port */ static int svr_sock = 0; /* child server socket */ static int ipc_sock = 0; /* IPC sock (parent/child) */ static int session_sock = 0; /* session mgr socket */ static int input_sock = 0; /* cmd input socket */ static int use_ipc = 1; /* use IPC */ static int have_dotfile = 0; /* have a valid .vosamp? */ static int in_parent = 1; /* are we parent process? */ static int do_return = 1; /* return result to API */ static int return_stat = OK; /* return status */ static int numargs = 0; /* number of cmdline args */ static int timeout = VOS_TIMEOUT; /* child timeout */ static int hub_connected = 0; /* connected to SAMP hub */ static int sess_connected = 0; /* connected to session mgr */ char *session_host = SESS_DEFHOST; /* session manager host IP */ int session_port = SESS_DEFPORT; /* session manager port */ static char *proxy = NULL; /* proxy connection string */ static char *session = NULL; /* session name */ static char *pattern = NULL; /* SAMP msg pattern */ static char *cmdfile = NULL; /* input command file */ static char *filt_mtype = NULL; /* snoop filter mtype */ static char *filt_sender = NULL; /* snoop sender name */ static char cmd[SZ_CMD]; /* command name */ static char cmdline[SZ_CMD]; /* full command line */ static char proxy_host[SZ_FNAME]; /* proxy vosamp host name */ static char dotfile[SZ_FNAME]; /* path to local dotfile */ static char psession[SZ_FNAME]; /* proxy file session name */ static char *args[MAX_ARGS]; /* command args buffer */ static FILE *fd = (FILE *) NULL; static fd_set allset, fds; static struct timeval tm; static int vos_sendToProxy (char *cmdline); static int vos_startProxy (void); static int vos_sampInit (void); static int vos_sendCmd (int sock, char *cmdline); static int vos_invalidArg (int argc, char *argv[], int nargs, int exist); static void vos_sampShutdown (void); static void vos_cmdHelp (char *cmd); static void vos_procCmd(int sampH, char *to, char *cmd, char **argv, int argc); static void vos_handleCmdInput (void); static void vos_msgHandler (char *sender, char *mtype, char *msg_id, Map map); static void vos_sessionHandler (char *sender, char *mtype, char *id, Map map); static void vos_forwardCmd (char *sess_cmd); static void vos_printMessage (char *mtype, char *sender, Map map); static void vos_rewriteCmd (char *line, char *fname); static void vosDebug (char *format, ...); static char *vos_rewriteURL (char *in); static char *vos_dotFile (); int vos_uploadFiles (int fd, char *cmdline); int vos_recvFile (int sock, int size, char *fname); int vos_sendFile (int sock, char *path, char *fname); int vos_openSession (char *host, int port, char *session_name); int vos_closeSession (int sock); extern char *vos_toURL (char *arg); extern char *vos_optArg (char *arg); extern char *vos_getLocalIP (void); extern char *vos_getFName (char *url); extern char *vos_typeName (int type); extern int *vos_toIntArray (char *arg, int *nrows); extern int vot_atoi (char *v); /* Utility socket routines. */ extern int vos_fileRead (int fd, void *vptr, int nbytes); extern int vos_fileWrite (int fd, void *vptr, int nbytes); extern int vos_openServerSocket (int port); extern int vos_openClientSocket (char *host, int port, int retry); extern int vos_testClientSocket (char *host, int port); extern int vos_sockRead (int fd, void *vptr, int nbytes); extern int vos_sockWrite (int fd, void *vptr, int nbytes); 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_urlType (char *url); extern int vos_getURL (char *url, char *fname); extern double vot_atof (char *v); extern void vos_setNonBlock (int sock); extern struct hostent *vos_getHostByName (char *lhost); extern struct hostent *vos_dupHostent (struct hostent *hentry); /* Task specific option declarations. */ int vosamp (int argc, char **argv, size_t *len, void **result); static Task self = { "vosamp", vosamp, 0, 0, 0 }; static char *opts = "%:hnrdif:mps:t:vP:T:S:"; static struct option long_opts[] = { { "return", 0, 0, 'r'}, /* task option */ { "help", 2, 0, 'h'}, /* required */ { "test", 1, 0, '%'}, /* required */ { "debug", 2, 0, 'd'}, /* debug */ { "verbose", 2, 0, 'v'}, /* verbose output */ { "quiet", 2, 0, 'q'}, /* suppress output */ { "many", 2, 0, 'm'}, /* multiple msgs */ { "sender", 1, 0, 's'}, /* sender filter */ { "interactive", 2, 0, 'i'}, /* interactive mode */ { "file", 1, 0, 'f'}, /* cmd file */ { "pattern", 1, 0, 'p'}, /* msg pattern */ { "proxy", 1, 0, 'P'}, /* proxy connection */ { "session", 1, 0, 'S'}, /* session name */ { "to", 1, 0, 't'}, /* recipient name */ { "nokeepalive", 2, 0, 'n'}, /* keep connection */ { "timeout", 1, 0, 'T'}, /* connection timeout */ { NULL, 0, 0, 0 } }; static void Usage (void); static void Tests (char *input); /**************************************************************************** * Program entry point. */ int vosamp (int argc, char **argv, size_t *reslen, void **result) { char **pargv, optval[SZ_FNAME], ch, *env_proxy = NULL; int i, pos = 0, len = 0; time_t expiry; /* Initialize. */ memset (cmd, 0, SZ_CMD); memset (cmdline, 0, SZ_CMD); memset (dotfile, 0, SZ_FNAME); memset (psession, 0, SZ_FNAME); memset (proxy_host, 0, SZ_FNAME); strcpy (proxy_host, vos_getLocalIP ()); strcpy (dotfile, vos_dotFile ()); for (i=0; i < MAX_ARGS; i++) args[i] = calloc (1, SZ_LINE); *reslen = 0; *result = NULL; return_stat = OK; /* 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 (self.nfail); case 'h': Usage (); return (OK); case 'd': debug++; break; case 'v': verbose++; break; case 'q': quiet++; break; case 'n': keep_alive = 0; break; case 'm': multiple++; break; case 'i': interact++; break; case 's': filt_sender = strdup (optval); i++; break; case 'f': cmdfile = strdup (optval); i++; break; case 't': to = strdup (optval); i++; break; case 'p': pattern = strdup (optval); i++; break; case 'P': proxy = strdup (optval); i++; break; case 'S': session = strdup (optval); i++; break; case 'T': timeout = vot_atoi (optval); i++; break; case 'r': do_return=1; break; default: fprintf (stderr, "Invalid option '%s'\n", optval); return (1); } } else if (ch == PARG_ERR) { return (ERR); } else { /* Remainder of argv is the subcommand and its arguments. */ if (pargv[i] == NULL) break; if (!cmd[0]) { strcpy (cmd, optval); } else { if (strcasecmp (cmd, "exec") == 0 || strcasecmp (cmd, "echo") == 0) { strcat (args[0], optval); strcat (args[0], " "); } else { char *ip; while (pargv[i]) { if (strstr (pargv[i], "://") == NULL) { /* replace ':' w/ '=' */ for (ip=pargv[i]; *ip; ip++) *ip = ((*ip == ':') ? '=' : *ip); } strcpy (args[numargs++], pargv[i++]); } break; } } } } /* Print command help if that's all we're asked. */ if (strncmp (cmd, "?", 1) == 0 || strncasecmp (cmd, "help", 4) == 0) { Usage (); return (OK); } if (strncmp(args[0], "?", 1) == 0 || strncasecmp(args[0], "help", 4) == 0) { vos_cmdHelp (cmd); return (OK); } if (strncmp(cmd, "access", 6) == 0 && strncasecmp(args[0], "hub", 3) == 0) { int hub_connected = vos_sampInit (); printf ("%s\n", (hub_connected ? "yes" : "no")); if (hub_connected) vos_sampShutdown (); return ( (hub_connected ? OK : ERR) ); } if (strcmp (cmd, "handle") == 0 || strcmp (cmd, "snoop") == 0) keep_alive = 0; /* Sanity checks. */ if (interact || argc <= 1) cmdfile = strdup ("-"); if (to == NULL) to = strdup ("all"); if (pattern == NULL) pattern = strdup ("async"); /* Initialize the SAMP interface. tm.tv_sec = VOS_HUBWAIT; */ tm.tv_sec = timeout; tm.tv_usec = 0; session_sock = 0; /* Check for environment definitions. */ if ((env_proxy = getenv (ENV_PROXY))) proxy = strdup (env_proxy); if (proxy) { /* We've been asked to send the command to a particular proxy, just * send the command line and any required data. */ char *cp = strchr (proxy, (int)':'); vosDebug ("Using proxy '%s'\n", proxy); if (cp) { proxy_port = vot_atoi (cp+1); *cp = '\0'; strcpy (proxy_host, proxy); } else { proxy_port = VOS_DEFPORT; strcpy (proxy_host, proxy); } use_ipc++; have_dotfile++; ipc_sock = vos_openClientSocket (proxy_host, proxy_port, 1); } else { /* See if we have a local proxy running we can use instead of starting * a new connection. Data references remain local unless being * passed on to the session manager service. */ FILE *fd = (FILE *) NULL; if (keep_alive && access (dotfile , R_OK) == 0) { if ((fd = fopen (dotfile, "r+")) != (FILE *) NULL) { time_t now = time ((time_t) 0); int test = 0; /* Read the dotfile contents. */ fscanf (fd, "%s %d %d %ld %s", proxy_host, &proxy_port, &proxy_pid, &expiry, psession); fclose (fd); /* Make sure we can reach the running proxy, otherwise * assume it is a stale dotfile. */ if ((test = vos_testClientSocket(proxy_host, proxy_port)) < 0) { if (verbose) fprintf (stderr, "Removing stale .vosamp file ...\n"); unlink (dotfile); goto samp_init; } else { vos_sockWriteHdr (test, 0, NULL, SAMP_TEST, 0, "proxy"); close (test); } /* Check for a stale dotfile. */ if (now <= (expiry - 2)) { use_ipc++; have_dotfile++; } else { if (verbose) fprintf (stderr, "Removing stale .vosamp file ...\n"); unlink (dotfile); goto samp_init; } } } else { /* First do some sanity checks on the command. If we're asked * to quit, then simply don't connect. */ if (strncasecmp ("quit", cmd, 4) == 0) { return (OK); } /* No remote command specified, no local connection, so connect to * the Hub as a new application. * * Start the keep-alive proxy server. */ samp_init: if (keep_alive) { vos_startProxy (); use_ipc = 1; } else { if (! (hub_connected = vos_sampInit ())) { fprintf (stderr, "Error: cannot connect to Hub.\n"); return (ERR); } use_ipc = 0; } } } /* Process a single command if we're not in keep_alive mode. */ if (!keep_alive) { vos_procCmd (sampH, to, cmd, args, numargs); goto cleanup_; } /* Open an IPC socket to the proxy. */ while (in_parent && ipc_sock <= 0) { vosDebug ("opening ipc socket to %s:%d\n", proxy_host, proxy_port); ipc_sock = vos_openClientSocket (proxy_host, proxy_port, 1); if (ipc_sock < 0) { if (verbose) fprintf (stderr, "Cannot open client ipc_sock\n"); sleep (1); } } vosDebug ("ipc socket %d\n", ipc_sock); /* Process the messages in the named file, or from the cmdline. Since * there is some overhead in connecting to the hub, this is an efficient * way to send multiple messages from a single connection. */ if (cmdfile) { fd = (cmdfile[0] == '-' ? stdin : fopen (cmdfile, "r")); /* Send the command string from the stdin or the cmd file. */ fprintf (stderr, "vosamp> "); #ifdef FGETS while (fgets (cmdline, SZ_CMD, fd) && !feof (fd) && !ferror (fd)) { #else FD_ZERO (&allset); FD_SET (fileno (stdin), &allset); while (1) { memcpy (&fds, &allset, sizeof(allset)); if (select (8, &fds, NULL, NULL, NULL) == 0) continue; if (fgets (cmdline, SZ_CMD, stdin) == NULL) continue; #endif len = strlen (cmdline); if (cmdline[len-1] == '\n') cmdline[len-1] = '\0'; if (strncasecmp (cmdline, "quit", 4) == 0 || strncasecmp (cmdline, "logo", 4) == 0) break; else if (cmdline[0]) { vos_sendToProxy (cmdline); fprintf (stderr, "vosamp> "); } } if (fd != stdin) fclose (fd); } else if (cmd[0]) { /* Send the command string from the commandline. */ int i, len = 0; memset (cmdline, 0, SZ_CMD); sprintf (cmdline, "%s %s ", cmd, args[0]); for (i=1; i < numargs; i++) { strcat (cmdline, args[i]); strcat (cmdline, " "); } len = strlen (cmdline); cmdline[len-1] = '\0'; vos_sendToProxy (cmdline); } close (ipc_sock); /* Close down and clean up. */ cleanup_: if (!keep_alive) vos_sampShutdown (); if (to) free ((void *) to); if (proxy) free ((void *) proxy); if (cmdfile) free ((void *) cmdfile); if (pattern) free ((void *) pattern); if (session) free ((void *) session); if (filt_sender) free ((void *) filt_sender); return (return_stat); } /** * VOS_SENDTOPROXY -- Send a cmdline to the proxy. */ static int vos_sendToProxy (char *cmdline) { /* See if we need to join a session before processing the cmd. */ if (session && psession[0] != '\0') { /* Have session param and running a proxy. */ memset (cmdline, 0, SZ_CMD); sprintf (cmdline, "session %s", session); } else if (strcasecmp (cmd, "session") == 0 && (psession[0] && strcasecmp (psession, "none") == 0)) { /* Have session command and not running a proxy. */ memset (cmdline, 0, SZ_CMD); sprintf (cmdline, "session %s", args[0]); } if (strcasecmp (proxy_host, vos_getLocalIP())) { int nfiles = vos_uploadFiles (ipc_sock, cmdline); vosDebug ("....sent %d data files....\n", nfiles); } if (strncmp (cmd, "?", 1) == 0 || strncmp (cmd, "help", 4) == 0) { vos_cmdHelp (cmd); return (0); } /* Send the command string. */ vosDebug ("sending to proxy: '%s'\n", cmdline); if (vos_sendCmd (ipc_sock, cmdline) == 0) { vosDebug ("sending to proxy fails: '%s'\n", cmdline); if (verbose) fprintf (stderr, "Error writing command '%s'\n", cmdline); return (0); } else { short nread, len; vosDebug ("reading ipc response ....\n"); nread = vos_sockRead (ipc_sock, &len, sizeof (short)); vosDebug ("ipc response len = %d....\n", len); if (len > 0) { char *res = calloc (1, (len+1)); nread = vos_sockRead (ipc_sock, res, len); vosDebug ("ipc response nread = %d....res = '%s'\n", nread, res); if ((nread > 0 && strcmp (res, "OK") != 0) || verbose) printf ("%s\n", res); if (res) free ((void *) res); } return (1); } return (0); } /** * VOS_STARTPROXY -- Start the VOSAMP proxy process. */ static int vos_startProxy (void) { /* Start the keep-alive proxy server. */ if (keep_alive && in_parent && !have_dotfile) { switch ( fork() ) { case 0: /* start child proxy */ vosDebug ("child pid\n"); /* Open server socket, read future input from socket. */ vosDebug ("child opening server port %d...\n", proxy_port); if ((svr_sock = vos_openServerSocket (proxy_port)) < 0) { fprintf (stderr, "Cannot open VOSAMP port %d\n", proxy_port); if (have_dotfile) unlink (dotfile); } FD_ZERO (&allset); FD_SET (svr_sock, &allset); vos_setNonBlock (svr_sock); vosDebug ("child svr_sock %d...\n", svr_sock); if (session) { /* Open a client connection to the VOSAMP Session Manager. */ vosDebug ("initializing session '%s' on %s:%d\n", session, session_host, session_port); if ((session_sock = vos_openSession (session_host, session_port, session)) < 2) { vosDebug ("session open fails...\n"); session_sock = 0; session = NULL; } else { vosDebug ("child session sock %d...\n", session_sock); FD_SET (session_sock, &allset); vos_setNonBlock (session_sock); sess_connected = 1; } } /* Now initialize the SAMP interface. */ vosDebug ("initializing SAMP connection\n"); #ifdef HUB_BLOCKS while (vos_sampInit () == 0) { /* Wait for a Hub connection. */ if (debug || verbose) { fprintf (stderr, "Waiting for Hub ...."); sleep (VOS_HUBWAIT); } } #else hub_connected = vos_sampInit (); #endif in_parent = 0; vos_handleCmdInput (); /* Child never returns from this point ..... */ exit (0); break; case -1: /* fork fails */ if (verbose && in_parent) fprintf (stderr, "%d proxy fork failure.\n", (int)getpid()); break; default: /* parent exits */ vosDebug ("parent pid\n"); sleep (2); /* give child a chance to start */ } } return (0); } /** * VOS_SENDCMD -- Send a SAMP_CMD to the specified socket. */ static int vos_sendCmd (int sock, char *cmdline) { char res[SZ_LINE]; int nread = 0, nwrite = 0, len = (cmdline ? strlen (cmdline) : 0); vosDebug ("sendCmd: '%s'\n", cmdline); memset (res, 0, SZ_LINE); if (vos_sockWriteHdr (sock, len, NULL, SAMP_CMD, SAMP_NOTIFY, to)) { vosDebug ("writing cmdline '%s' fd=%d\n", cmdline, sock); nwrite = vos_sockWrite (sock, cmdline, len); /* See if we have a result returned to us. If so, it will be * a character string we should just print out. */ if (session && sock != session_sock) { vosDebug ("reading response fd=%d\n", sock); nread = vos_sockRead (sock, &len, sizeof (int)); if (len > 0) { char *res = calloc (1, (len+1)); nread = vos_sockRead (sock, res, len); if ((nread > 0 && strcmp (res, "OK") != 0) || verbose) printf ("%s\n", res); if (res) free ((void *) res); } } else return (1); } return (nread); } /** * VOS_UPLOADFILES -- Upload any files on the commandline to the remote * host. The remote client is responsible for rewriting the commandline * as appropriate, our job here is to suss out which are the file arguments. */ int vos_uploadFiles (int sock, char *cmdline) { char *ip, *op, buf[SZ_BUF], fname[SZ_FNAME]; int nfiles = 0; for (ip=cmdline; *ip; ) { memset (buf, 0, SZ_BUF); memset (fname, 0, SZ_FNAME); for (op=buf; *ip && !isspace(*ip); ) /* get token */ *op++ = *ip++; /* Upload the file. If we have a file:// URL strip out the * local pathname. Note that in this implementation we're * limited to a single data file per-message. */ if (strncmp ("file://", buf, 7) == 0) { strcpy (fname, &buf[7]); if (access (fname, F_OK) < 0) /* file doesn't exist */ return (-1); } if (access (buf, F_OK) == 0) strcpy (fname, buf); if (fname[0]) { /* upload the file */ vosDebug ("uploading file '%s'....\n", fname); if (vos_sendFile (sock, fname, vos_getFName (fname)) != OK) fprintf (stderr, "Error sending file '%s'\n", fname); nfiles++; } while (*ip && isspace (*ip)) /* skip whitespace */ ip++; } return (nfiles); } /** * VOS_SENDFILE -- Send a file to a remote host. */ int vos_sendFile (int sock, char *path, char *fname) { char block[SZ_BLOCK]; int fd, nread = 0, nleft = 0, size = 0, nb = 0; struct stat fs; if (access (path, R_OK) != 0 || stat (path, &fs) != 0) return (ERR); size = fs.st_size; nleft = size; if ((fd = open (path, O_RDONLY))) { /* Send the header to pass the filename and size, then * send the data itself. */ vos_sockWriteHdr (sock, size, fname, SAMP_DATA, 0, to); while (nleft > 0) { memset (block, 0, SZ_BLOCK); nb = min (SZ_BLOCK, nleft); /* Read from the file, write it to the socket. */ vos_fileRead (fd, block, nb); vos_sockWrite (sock, block, nb); nleft -= nb; nread += nb; } close (fd); } return (OK); } /** * VOS_RECVFILE -- Receive a file of the specified size from a remote host. */ int vos_recvFile (int sock, int size, char *fname) { char block[SZ_BLOCK]; int fd, nread = 0, nleft = size, nb = 0; /* Read the file from the socket, write to the filename. */ vosDebug ("receiving file '%s'....%d\n", fname, size); if ((fd = open (fname, O_WRONLY|O_CREAT, 0664))) { while (nleft > 0) { memset (block, 0, SZ_BLOCK); nb = min (SZ_BLOCK, nleft); /* Read from the socket, write it to the file. */ vos_sockRead (sock, block, nb); vos_fileWrite (fd, block, nb); nleft -= nb; nread += nb; } close (fd); } return (OK); } /** * VOS_HANDLECMDINPUT -- Handle input from an input source. */ static void vos_handleCmdInput () { register int i, read_timeout = 0, rc; char line[SZ_CMD]; static char data_file[SZ_FNAME]; memset (line, 0, SZ_CMD); memset (data_file, 0, SZ_FNAME); while (1) { /* loop until timeout */ /* Initialize the input file descriptor set and cmd buffer. */ memset (line, 0, SZ_CMD); memset (cmd, 0, SZ_CMD); for (i=0; i < MAX_ARGS; i++) memset (args[i], 0, SZ_LINE); memcpy (&fds, &allset, sizeof(allset)); if ((rc = select (8, &fds, NULL, NULL, (timeout ? &tm : NULL))) == 0) { read_timeout++; /* input timeout */ if (hub_connected && !samp_hubRunning()) { hub_connected = 0; } if (!hub_connected && samp_hubRunning()) { hub_connected = vos_sampInit(); #ifdef HUB_TIMEOUT } else { unlink (dotfile); /* clean up the dotfile */ vos_sampShutdown (); /* shutdown Hub connection */ return; #endif } continue; } else if (rc < 0) { /* Select error .... */ vosDebug ("select error '%s'\n", strerror (errno)); continue; } if (FD_ISSET(svr_sock, &fds)) { int nbytes = 0, nread = 0, type = 0, mode = 0; char fname[SZ_FNAME]; /* Accept a connection on the proxy port from a cmdline client. */ vosDebug ("got input on server socket....\n"); memset (fname, 0, SZ_FNAME); if ((ipc_sock = accept (svr_sock, NULL, NULL)) < 0) { fprintf (stderr, "accept() errno %d: %s", errno, strerror(errno)); continue; } if (vos_sockReadHdr (ipc_sock, &nbytes, fname, &type, &mode)) { vosDebug ("server input: msgType = %s....\n", vos_typeName (type)); if (strcasecmp (proxy_host, senderIP) && type == SAMP_DATA) { if (vos_recvFile (ipc_sock, nbytes, fname) != OK) { if (verbose || debug) fprintf (stderr, "Error in recvFile '%s'\n", fname); } strcpy (data_file, fname); if (vos_sockReadHdr(ipc_sock, &nbytes, fname,&type,&mode)) { nread = vos_sockRead (ipc_sock, line, nbytes); vos_rewriteCmd (line, data_file); } memset (data_file, 0, SZ_FNAME); } else if (type == SAMP_CMD) { nread = vos_sockRead (ipc_sock, line, nbytes); vosDebug ("server cmd = '%s'....nr=%d nb=%d\n", line, nread, nbytes); if (data_file[0]) { vos_rewriteCmd (line, data_file); memset (data_file, 0, SZ_FNAME); } } else if (type == SAMP_RESULT) { ; /* Not yet implemented */ } else if (type == SAMP_TEST) { close (ipc_sock); /* Test connection, just ignore. */ } } input_sock = ipc_sock; } else if (FD_ISSET(session_sock, &fds)) { int nbytes = 0, nread = 0, type = 0, mode = 0; /* Accept a command from the session manager for forwarding. */ if (vos_sockReadHdr (session_sock, &nbytes, fname, &type, &mode)) { vosDebug ("got input on session socket....\n"); nread = vos_sockRead (session_sock, line, nbytes); input_sock = session_sock; } else { /* Session manager closed the socket, shut it down and * disconnect. */ vosDebug ("Closing session socket....\n"); FD_CLR (session_sock, &allset); close (session_sock); if (session) free ((void *) session); session = NULL; session_sock = 0; continue; } } else vosDebug ("Ignoring input on other descriptor ...\n"); /* Kill any trailing spaces and make sure we have an actual cmdline. */ if (isspace(line[strlen(line)-1])) line[strlen(line)-1] = '\0'; if (line[0] == '\0') continue; /* Check whether the command we want to process is directed to the * proxy process itself. If so we process it locally rather than * as a SAMP message for other clients. */ vosDebug ("handleCmd line: '%s'\n", line); if (strncasecmp (line, "exec", 4) == 0 || strncasecmp (line, "echo", 4) == 0) { /* Special-case for exec/echo cmd to create single arg */ strncpy (cmd, line, 4); sprintf (args[0], "%s", &line[5]); numargs = 1; vos_procCmd (sampH, to, cmd, args, numargs); } else if (strncasecmp (line, "status", 4) == 0) { if (ipc_sock > 0) { short slen, nwrite; char buf[SZ_LINE]; memset (buf, 0, SZ_LINE); sprintf (buf, "Status: SAMP Hub: %s ", (hub_connected ? "ON " : "OFF")); if (sess_connected) { strcat (buf, "Session Mgr: ON (session='"); strcat (buf, session); strcat (buf, "')"); } else strcat (buf, "Session Mgr: OFF"); slen = strlen (buf); /* return result string */ if (vos_sockWrite (ipc_sock, &slen, sizeof (short))) nwrite = vos_sockWrite (ipc_sock, buf, slen); continue; } } else if (strncasecmp (line, "quit", 4) == 0) { /* Quit the proxy process and return. */ if (access (vos_dotFile(), F_OK) == 0) unlink (vos_dotFile()); vos_sampShutdown (); /* shutdown Hub connection */ exit (0); } else if (strncasecmp (line, "list", 4) == 0) { /* List the connected clients. */ verbose++, numargs=1; vos_procCmd (sampH, to, "listClients", args, numargs); } else if (strncasecmp (line, "session", 7) == 0) { /* Special commands for Session management. */ numargs = sscanf (line, "%s %s", cmd, args[0]); if (strcmp (args[0], "list") == 0) { memset (args[0], 0, SZ_LINE); strcpy (args[0], "listNodes"); if (session_sock == 0) { fprintf (stderr, "Error: No session established\n"); return; } else { verbose++; numargs=1; vos_procCmd (sampH, to, "listNodes", args, numargs); } } else if (strncmp (args[0], "leave", 5) == 0) { if (session_sock) vos_closeSession (session_sock); } else { /* Open a client connection to the VOSAMP Session Manager. */ if (vos_testClientSocket (session_host, session_port) < 0) { fprintf (stderr, "Error: Session manager not available at %s:%d\n", session_host, session_port); return; } vosDebug ("initializing session '%s' on %s:%d\n", args[0], session_host, session_port); session_sock = 0; session = strdup (args[0]); if ((session_sock = vos_openSession (session_host, session_port, args[0])) < 2) { vosDebug ("session open fails...\n"); session_sock = 0, session = NULL; } else { vosDebug ("child session sock %d...\n", session_sock); FD_SET (session_sock, &allset); vos_setNonBlock (session_sock); sess_connected = 1; } } } else { /* Process the input command as a SAMP message. Only process * the command if we're connected to a Hub */ if (hub_connected) { numargs = sscanf (line, "%s %s %s %s %s %s %s %s %s", cmd, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); vos_procCmd (sampH, to, cmd, args, numargs); } } } #ifdef FOO if (ipc_sock) close (ipc_sock); /* close the socket descriptor */ #endif } /** * VOS_REWRITECMD -- Rewrite the command string with filename substitution. */ static void vos_rewriteCmd (char *line, char *fname) { char *ip, *op, buf[SZ_CMD], obuf[SZ_CMD]; memset (obuf, 0, SZ_CMD); for (ip=line; *ip; ) { memset (buf, 0, SZ_CMD); for (op=buf; *ip && !isspace(*ip); ) /* get token */ *op++ = *ip++; /* 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); while (*ip && isspace (*ip)) /* skip whitespace */ strncat (obuf, ip++, 1); } memset (line, 0, SZ_CMD); strcpy (line, obuf); } /** * VOS_REWRITEURL -- Rwrite a URL argument so it is compatible with the * session manager. Upload any local files if needed. */ static char * vos_rewriteURL (char *in) { static char out[SZ_URL], path[SZ_LINE], *fname; char tmpfile[SZ_LINE]; memset (path, 0, SZ_LINE); /* initialize */ memset (tmpfile, 0, SZ_LINE); memset (out, 0, SZ_URL); switch (vos_urlType (in)) { case VOS_LOCALURL: sprintf (tmpfile, "/tmp/%s", vos_getFName (in)); vos_getURL (in, tmpfile); strcpy (path, tmpfile); break; case VOS_LOCALURI: strcpy (path, &in[7]); break; case VOS_LOCALFILE: strcpy (path, in); break; case VOS_REMOTE: /* Nothing to do, simply return the string. */ return (in); } /* Get the filename from the path. Format the new URL so that the * session manager can easily rewrite it to use the smgr data space. */ fname = vos_getFName (path); sprintf (out, "SESSION_URL/%s", fname); /* Send data to the session manager for storage as the 'fname'. The * session manager will rewrite the URL. */ if (session_sock && vos_sendFile (session_sock, path, fname) != OK) fprintf (stderr, "Error uploading file '%s'\n", in); return (out); } /** * USAGE -- Print a task usage summary. */ static void Usage (void) { fprintf (stderr, " Usage:\n" "\n" " %% vosamp [-hvd] [-t to] [-p pattern] [-f file] [args ...]\n" "\n" " where:\n" " command to process\n" " -%%,--test run unit tests\n" " -h,--help print help summary\n" " -d,--debug debug output\n" " -v,--verbose verbose output\n" " -q,--quiet suppress all output\n" "\n" " -i,--interact interactive mode\n" " -m,--many handle multiple messages\n" " -s,--sender handle only messages from \n" "\n" " -t,--to send to specified app (or all)\n" " -p,--pattern message pattern: sync|async|notify\n" " -f,--file send all commands in the file\n" " -n,--nokeepalive disable keep_alive feature\n" "\n" " -P,--proxy use specfied proxy IP\n" " -T,--timeout keepalive timeout\n" "\n" " -r,--return return result to API\n" "\n" " Commands:\n" "\n" " snoop print all received messages\n" " send [ ...] generalized message send\n" "\n" " status print Hub availability\n" " list list all registered clients\n" " access print availability\n" " handle wait for message\n" "\n" " exec execute a client command\n" " setenv set an environment value\n" " getenv get an environment value\n" " setparam set a parameter value\n" " getparam get a parameter value\n" "\n" " load load the image/table\n" " loadImage load the named image\n" " loadVOTable load the named VOTable\n" " loadFITS load the named FITS bintable\n" " loadSpec load the named spectrum\n" " loadResource load the named VO Resource\n" "\n" " pointAt point at given coords\n" " showRow [] [] highlight specified row\n" " selectRows [] [] select specified rows\n" " bibcode load the bibcode\n" "\n\n" " Examples:\n\n" " 1) Load a VOTable to Topcat:\n\n" " %% vosamp load /path/example.xml\n" " %% vosamp load http://foo.edu/example.xml\n" " %% vosamp load http://foo.edu/query?RA=0.0&DEC=0.0&SR=0.1\n" "\n" " 2) Send a command string to IRAF:\n" "\n" " %% vosamp -t iraf exec 'display dev$pix 1'\n" "\n" " 3) List all clients in a SAMP desktop session:\n" "\n" " %% vosamp list\n" "\n" " 4) Check whether a Hub is available from a script:\n" "\n" " set isHub = `vosamp access Hub`\n" " if ($isHub == \"no\") then\n" " echo \"No Hub available, quitting .....\"\n" " exit 1\n" " else\n" " ....do something....\n" " endif\n" "\n" ); } /** * Tests -- Task unit tests. */ static void Tests (char *input) { Task *task = &self; char *img = "http://iraf.noao.edu/votest/ypix.fits"; char *vot = "http://iraf.noao.edu/votest/usno-b.xml"; char *bin = "http://iraf.noao.edu/votest/usno-b.fits"; if (access (input, F_OK) != 0) { fprintf (stderr, "Error: cannot open input file '%s'\n", input); return; } vo_taskTest (task, "--help", NULL); vo_taskTest (task, "load", input, NULL); vo_taskTest (task, "load", img, NULL); vo_taskTest (task, "loadImage", img, NULL); vo_taskTest (task, "load", vot, NULL); vo_taskTest (task, "loadVOTable", vot, NULL); vo_taskTest (task, "load", bin, NULL); vo_taskTest (task, "loadFITS", bin, NULL); vo_taskTest (task, "access", "hub", NULL); vo_taskTest (task, "list", NULL); vo_taskTest (task, "load", input, NULL); vo_taskTestReport (self); } /** * VOS_DOTFILE -- Create a pathname to the .vosamp file indicating a * running local proxy server. */ static char * vos_dotFile () { static char dotfile[SZ_FNAME]; static int initialized = 0; if (! initialized) { char *home = NULL; if ((home = getenv ("HOME")) == NULL) home = "./"; memset (dotfile, 0, SZ_FNAME); sprintf (dotfile, "%s/.vosamp", home); } initialized++; return (dotfile); } /** * VOS_SAMPINIT -- Initialize the SAMP/Proxy interface connection. */ static int vos_sampInit (void) { FILE *df; /* If there's no Hub running, don't bother .... */ if (!samp_hubRunning()) return (0); /* Initialize the SAMP interface. */ sampH = sampInit ("vosamp", "VOClient SAMP Task"); /* if (samp_hubActive (sampH) == 0) { vosDebug ("sampInit failed to connect ....\n"); vos_sampShutdown (); return (0); } */ /* Set alternative messaging pattern if requested. Valid values are * 'synch', 'asynch' or 'notify'. */ if (pattern) { switch (tolower(pattern[0])) { case 's': samp_setSyncMode (sampH); break; /* default */ case 'a': samp_setASyncMode (sampH); break; case 'n': samp_setNotifyMode (sampH); break; default: if (verbose) fprintf (stderr, "Warning: Invalid pattern '%s'\n", pattern); } } else { /* Use Synchronous mode by default so we don't exit before receiving * the reply. Otherwise, we could cause an error in the recipient. */ samp_setSyncMode (sampH); } /* If we're not sending to a specific client, disable the name mapping * to speed up the connection. if (strncmp (to, "all", 3) == 0) samp_setOpt (sampH, "mapClients", 0); */ samp_Metadata (sampH, "author.name", "Mike Fitzpatrick, NOAO"); samp_Metadata (sampH, "author.email", "fitz@noao.edu"); samp_Metadata (sampH, "samp.description.html", "http://iraf.noao.edu/voclient/vosamp.html"); samp_Metadata (sampH, "samp.icon.url", "http://iraf.noao.edu/voclient/vao_icon.gif"); /* If we're in session mode, subscribe to all message types. The * same handler is used to pass on the message to other clients in * the session. */ if (session) samp_Subscribe (sampH, "*", vos_sessionHandler); /* Register with the Hub and begin messaging. */ sampStartup (sampH); /* Write the dotfile. */ if (!interact && (df = fopen (vos_dotFile(), "w+")) != (FILE *) NULL) { fprintf (df, "%s %d %d %ld %s\n", vos_getLocalIP(), proxy_port, (int) getpid(), (long) (time((time_t)0) + timeout), (session ? session : "none")); fclose (df); } return (sampH); } /** * VOS_SAMPSHUTDOWN -- Shutdown the SAMP/Proxy interface connection. */ static void vos_sampShutdown (void) { if (sampShutdown (sampH) < 0) /* clean up */ fprintf (stderr, "SAMP shutdown fails\n"); sampClose (sampH); } /** * VOS_MSGHANDLER -- Incoming message handler. */ static void vos_msgHandler (char *sender, char *mtype, char *msg_id, int params) { vosDebug ("in vos_msgHandler.....\n"); if (filt_sender && strcasecmp (filt_sender, sender)) return; /* Either no filters were set, or the message is of the requested type, * print the contents. */ if (!quiet) vos_printMessage (mtype, samp_id2app (sampH, sender), params); if (!interact && !multiple) { /* Do a clean disconnect .... */ if (sampShutdown (sampH) < 0) fprintf (stderr, "SAMP shutdown fails\n"); sampClose (sampH); exit (0); } } /** * VOS_PRINTMESSAGE -- Print a received message to the stdout. */ static void vos_printMessage (char *mtype, char *sender, Map map) { int i, npars = samp_getMapSize (map); char *key = NULL; Map smap; if (verbose) printf ("sender: '%s'\t", sender); printf ("%s", mtype); for (i=0; i < npars; i++) { key = samp_getMapKey (map, i); if (strncmp (key, "meta", 4) == 0 || strncmp (key, "sub", 3) == 0) { smap = samp_getMapFromMap (map, key); printf ("\n"); samp_printMap (key, smap); } else printf ("\t%s=%s", key, samp_getMapVal (map, i)); } printf ("\n"); } /** * VOS_SESSIONHANDLER -- Generic session message-forwarding handler. */ #define MTYPE(s) (strcasecmp(mtype,s)==0) static void vos_sessionHandler (char *sender, char *mtype, char *msg_id, Map map) { char sess_url[SZ_URL], sess_cmd[SZ_CMD], num[SZ_FNAME]; char *tid = NULL, *imid = NULL, *url = NULL, *sid = NULL; char *name = NULL, *value = NULL, *cmd = NULL, *bibcode = NULL; char *key = NULL, *val = NULL; int i, row = 0, rows = 0, len, nelem; float ra, dec; Map meta, ids; if (!mtype) return; memset (sess_url, 0, SZ_URL); memset (sess_cmd, 0, SZ_CMD); /* vosDebug ("sender: '%s' mtype: '%s' id: '%s'\n", sender, mtype, msg_id); */ /* Process the mtype. */ if (MTYPE ("samp.app.ping")) { ; /* FIXME -- no-op */ } else if (MTYPE ("samp.app.status")) { ; /* FIXME -- no-op */ } else if (MTYPE ("table.load.fits")) { tid = strdup (samp_getStringFromMap (map, "table-id")); url = strdup (samp_getStringFromMap (map, "url")); name = strdup (samp_getStringFromMap (map, "name")); sprintf (sess_cmd, "loadFITS %s %s", vos_rewriteURL(url), tid); } else if (MTYPE ("table.load.votable")) { /* Get parameters from the message Map. */ tid = strdup (samp_getStringFromMap (map, "table-id")); url = strdup (samp_getStringFromMap (map, "url")); name = strdup (samp_getStringFromMap (map, "name")); sprintf (sess_cmd, "loadVOTable %s %s", vos_rewriteURL(url), tid); } else if (MTYPE ("table.highlight.row")) { tid = strdup (samp_getStringFromMap (map, "table-id")); url = strdup (samp_getStringFromMap (map, "url")); row = samp_getIntFromMap (map, "row"); sprintf (sess_cmd, "showRow %s %d", vos_rewriteURL(url), row); } else if (MTYPE ("image.load.fits")) { imid = strdup (samp_getStringFromMap (map, "image-id")); url = strdup (samp_getStringFromMap (map, "url")); name = strdup (samp_getStringFromMap (map, "name")); sprintf (sess_cmd, "loadImage %s %s", vos_rewriteURL(url), imid); } else if (MTYPE ("coord.pointAt.sky")) { ra = samp_getFloatFromMap (map, "ra"); dec = samp_getFloatFromMap (map, "dec"); sprintf (sess_cmd, "pointAt %g %g", ra, dec); } else if (MTYPE ("client.cmd.exec")) { cmd = strdup (samp_getStringFromMap (map, "cmd")); sprintf (sess_cmd, "exec %s", cmd); } else if (MTYPE ("client.env.get")) { /** NYI **/ name = strdup (samp_getStringFromMap (map, "name")); } else if (MTYPE ("client.env.set")) { name = strdup (samp_getStringFromMap (map, "name")); value = strdup (samp_getStringFromMap (map, "value")); sprintf (sess_cmd, "setenv %s %s", name, value); } else if (MTYPE ("client.param.get")) { /** NYI **/ name = strdup (samp_getStringFromMap (map, "name")); } else if (MTYPE ("client.param.set")) { name = strdup (samp_getStringFromMap (map, "name")); value = strdup (samp_getStringFromMap (map, "value")); sprintf (sess_cmd, "setparam %s %s", name, value); } else if (MTYPE ("bibcode.load")) { bibcode = strdup (samp_getStringFromMap (map, "bibcode")); sprintf (sess_cmd, "bibcode %s", bibcode); } else if (MTYPE ("table.select.rowList")) { tid = strdup (samp_getStringFromMap (map, "table-id")); url = strdup (samp_getStringFromMap (map, "url")); rows = samp_getListFromMap (map, "row-list"); sprintf (sess_cmd, "selectRows %s %s ", vos_rewriteURL(url), tid); len = samp_listLen (rows); for (i=0; i < len; i++) { sprintf (num, "%d%c", samp_getIntFromList(rows,i), (i < (len - 1) ? ',' : ' ')); strcat (sess_cmd, num); } } else if (MTYPE ("spectrum.load.ssa-generic")) { url = strdup (samp_getStringFromMap (map, "url")); sid = strdup (samp_getStringFromMap (map, "spectrum-id")); name = strdup (samp_getStringFromMap (map, "name")); meta = samp_getMapFromMap (map, "meta"); sprintf (sess_cmd, "loadSpec %s %s %s", vos_rewriteURL(url), (name ? name : " "), (sid ? sid : " ")); } else if (MTYPE ("voresource.loadlist.*")) { /* NYI */ name = strdup (samp_getStringFromMap (map, "name")); ids = samp_getMapFromMap (map, "ids"); nelem = samp_getMapSize (ids); for (i=0; i < nelem; i++) { key = samp_getMapKey (ids, i); val = samp_getMapVal (ids, i); /* Forward the resources individually. */ memset (sess_cmd, 0, SZ_CMD); sprintf (sess_cmd, "loadResource %s", vos_rewriteURL(url)); vos_forwardCmd (sess_cmd); } goto clean_up; } else if (MTYPE ("samp.hub.disconnect")) { ; /* ignore hub ejections */ } else if (MTYPE ("samp.hub.event.subscriptions")) { ; /* ignore client subscriptions */ } else if (MTYPE ("samp.hub.unregister") || MTYPE ("samp.hub.event.unregister")) { ; /* ignore hub closures */ } else { if (verbose && debug) fprintf (stderr, "unknown mtype '%s'\n", mtype); } /* Forward the session command. */ vos_forwardCmd (sess_cmd); if (verbose && debug) fprintf (stderr, "sessionHandler: cmdline = '%s'\n", sess_cmd); /* Clean up. */ clean_up: if (tid) free (tid); if (url) free (url); if (cmd) free (cmd); if (sid) free (sid); if (imid) free (imid); if (name) free (name); if (value) free (value); if (bibcode) free (bibcode); } /** * VOS_FORWARDCMD -- Forward a session command. */ static void vos_forwardCmd (char *sess_cmd) { int ssock = session_sock, len, nwrite; len = strlen (sess_cmd); if (vos_sockWriteHdr (ssock, len, NULL, SAMP_CMD, SAMP_NOTIFY, to)) nwrite = vos_sockWrite (ssock, sess_cmd, len); } /** * VOS_PROCCMD -- Process the command and its arguments. */ static void vos_procCmd (int sampH, char *to, char *cmd, char *args[], int numargs) { int i, reslen = 0, stat = OK, ssock = session_sock; char *result = NULL; char buf[SZ_BUF]; char sess_cmd[SZ_BUF]; /* Print command help. */ if (!use_ipc) { if (strncmp (cmd, "?", 1) == 0) { Usage (); return; } if (strncmp (args[0], "?", 1) == 0) { vos_cmdHelp (cmd); return; } } /******************************************** *** VOSAMP Custom Commands ** ********************************************/ memset (buf, 0, SZ_BUF); memset (sess_cmd, 0, SZ_BUF); if (MATCH ("status")) { stat = (sampH >= 0); } else if (MATCH ("handle")) { int timeout = (vot_atoi (args[1]) == 0 ? 999999 : vot_atoi (args[1])); if (verbose) fprintf (stderr, "Waiting for '%s' ....\n", args[0]); if (*args[1]) filt_sender = args[1]; samp_Subscribe (sampH, (filt_mtype = args[0]), vos_msgHandler); samp_DeclareSubscriptions (sampH); sleep (timeout); } else if (MATCH ("snoop")) { /* Subscribe to all message types and install the snoop handler. * Sleep forever so the handler can print anything it receives. */ multiple = 1; samp_Subscribe (sampH, "*", vos_msgHandler); samp_DeclareSubscriptions (sampH); sleep (9999999); } else if (MATCH ("send")) { if (strcasecmp (to, "all")) /* no recipient, use broadcast */ samp_setASyncMode (sampH); stat = samp_sendGeneric (sampH, to, args[0], &args[1]); } else if (MATCH ("echo")) { /* ECHO */ if (!use_ipc) { for (i=0; i < numargs; i++) printf ("%s ", args[i]); printf ("\n"); } } else if (MATCH ("start")) { /* START */ if (!use_ipc) printf ("Starting SAMP interface .....\n"); sampStartup (sampH); } else if (MATCH ("stop")) { /* STOP */ if (!use_ipc) printf ("Stopping SAMP interface .....\n"); sampShutdown (sampH); } else if (MATCH ("help")) { /* HELP */ Usage (); } else if (MATCH ("quit")) { /* QUIT */ if (sampShutdown (sampH) < 0) { if (!use_ipc) fprintf (stderr, "Shutdown fails\n"); } sampClose (sampH); unlink (vos_dotFile()); exit (0); } else if (MATCH ("trace")) { /* TRACE */ xml_trace++; if (xml_trace % 2) setenv ("XMLRPC_TRACE_XML", "1", 1); else unsetenv ("XMLRPC_TRACE_XML"); } else if (MATCH ("listNodes")) { /* LIST NODES */ int type, mode, nbytes, len, nwrite; char buf[SZ_BUF]; len = strlen ("list"); if (vos_sockWriteHdr (ssock, len, "list", SAMP_CMD, SAMP_NOTIFY, to)) { nwrite = vos_sockWrite (ssock, "list", len); memset (buf, 0, SZ_BUF); if (vos_sockReadHdr (session_sock, &nbytes, NULL, &type, &mode)) reslen = vos_sockRead (session_sock, buf, nbytes); result = strdup (buf); } } else if (MATCH ("listClients")) { /* LIST CLIENTS */ char *clist = NULL; samp_mapClients (sampH); clist = samp_getClients (sampH); if (use_ipc) { reslen = strlen (clist); result = strdup (clist); } else { printf ("\nClients:\n%s\n", clist); } /******************************************** *** Hub Administrative Messages *** ********************************************/ } else if (MATCH ("ping")) { /* samp.app.ping */ stat = samp_Ping (sampH, "Hub"); /******************************************** *** Client Administrative Messages *** ********************************************/ } else if (MATCH ("ping")) { /* samp.app.ping */ stat = samp_Ping (sampH, to); } else if (MATCH ("access")) { /* samp.app.ping */ stat = samp_Ping (sampH, (to=args[0])); if (use_ipc) { result = strdup ((stat < 0 ? "no" : "yes")); reslen = strlen (result); return_stat = (stat < 0 ? ERR : OK); } else { printf ("%s\n", (stat < 0 ? "no" : "yes")); return_stat = (stat < 0 ? ERR : OK); } /******************************************** *** Table/Image Load Message Types *** ********************************************/ /* image.load.fits */ } else if (MATCH ("loadImage")) { if ((stat = vos_invalidArg (numargs, args, 1, 1))) { return_stat = ERR; goto cmd_exit_; } stat = samp_imageLoadFITS (sampH, to, vos_toURL (args[0]), /* URL/file */ vos_optArg (args[1]), /* imgId */ vos_optArg (args[2])); /* name */ sprintf (sess_cmd, "loadImage %s %s", vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1])); if (session && input_sock != session_sock) vos_sendCmd (session_sock, sess_cmd); } else if (MATCH ("loadFITS")) { /* table.load.fits */ if ((stat = vos_invalidArg (numargs, args, 1, 1))) { return_stat = ERR; goto cmd_exit_; } stat = samp_tableLoadFITS (sampH, to, vos_toURL (args[0]), /* URL/file */ vos_optArg (args[1]), /* tblId */ vos_optArg (args[2])); /* name */ sprintf (sess_cmd, "loadFITS %s %s", vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1])); if (session && input_sock != session_sock) vos_sendCmd (session_sock, sess_cmd); } else if (MATCH ("loadVOTable")) { /* table.load.votable */ if ((stat = vos_invalidArg (numargs, args, 1, 1))) { return_stat = ERR; goto cmd_exit_; } stat = samp_tableLoadVOTable (sampH, to, vos_toURL (args[0]), /* URL/file */ vos_optArg (args[1]), /* tblId */ vos_optArg (args[2])); /* name */ sprintf (sess_cmd, "loadVOTable %s %s", vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1])); if (session && input_sock != session_sock) vos_sendCmd (session_sock, sess_cmd); } else if (MATCH ("load")) { char fname[SZ_LINE]; extern int vot_fileType(); memset (fname, 0, SZ_LINE); if (strncmp (args[0], "http://", 7) == 0) { strcpy (fname, "/tmp/vostmp"); /* temp download name */ if (access (fname, F_OK) == 0) unlink (fname); if (vos_getURL (args[0], fname) <= 0) fprintf (stderr, "Error accessing url '%s'\n", args[0]); } else if (strncmp (args[0], "file://", 7) == 0) { strcpy (fname, &args[0][7]); } else strcpy (fname, args[0]); if (access (fname, F_OK) == 0) { switch (vot_fileType (fname)) { case VOT_FITS: stat = samp_imageLoadFITS (sampH, to, vos_toURL (fname), /* URL/file */ vos_optArg (args[1]), /* imgId */ vos_optArg (args[2])); /* name */ sprintf (sess_cmd, "loadImage %s %s", vos_rewriteURL(vos_toURL (fname)), vos_optArg (args[1])); if (session && input_sock != session_sock) vos_sendCmd (session_sock, sess_cmd); break; case VOT_VOTABLE: stat = samp_tableLoadVOTable (sampH, to, vos_toURL (fname), /* URL/file */ vos_optArg (args[1]), /* tblId */ vos_optArg (args[2])); /* name */ sprintf (sess_cmd, "loadVOTable %s %s", vos_rewriteURL(vos_toURL (fname)), vos_optArg (args[1])); if (session && input_sock != session_sock) vos_sendCmd (session_sock, sess_cmd); break; case VOT_FITS_SPEC: break; case VOT_VOTABLE_SPEC: break; default: if (!use_ipc) fprintf (stderr, "Error: cannot determine file type of '%s'.\n", args[0]); } } else fprintf (stderr, "Error: cannot access '%s'.\n", fname); /******************************************** *** Resource Message Types *** ********************************************/ } else if (MATCH ("loadResource")) { /* voresource.loadlist */ if ((stat = vos_invalidArg (numargs, args, 1, 1))) { return_stat = ERR; goto cmd_exit_; } /* NYI */ /******************************************** *** Utility Message Types *** ********************************************/ } else if (MATCH ("showRow")) { /* table.highlight.row */ /* showRow [] */ stat = samp_tableHighlightRow (sampH, to, vos_optArg (args[2]), /* table-id */ vos_toURL (args[0]), /* URL/file */ vot_atoi(args[1])); /* row */ } else if (MATCH ("selectRows")) { /* table.select.rowList */ int nrows = 0; int *rows = vos_toIntArray (args[2], &nrows); stat = samp_tableSelectRowList (sampH, to, vos_optArg (args[0]), /* table-id */ vos_toURL (args[1]), /* URL/file */ rows, /* rows[] */ nrows); /* row */ } else if (MATCH ("pointAt")) { /* coord.pointAt.sky */ stat = samp_coordPointAtSky (sampH, to, vot_atof (args[0]), /* RA */ vot_atof (args[1])); /* Dec */ /******************************************** *** Spectrum Load Message Types *** ********************************************/ } else if (MATCH ("loadSpec")) { /* spectrum.load.ssa-generic */ /* FIXME -- meta map not implemented */ stat = samp_specLoadSSAGeneric (sampH, to, vos_toURL (args[0]), /* URL */ 0, /* Map meta */ /* NYI */ vos_optArg (args[2]), /* spectrumId */ vos_optArg (args[3])); /* name */ /******************************************** *** Bibcode Message Types *** ********************************************/ } else if (MATCH ("bibcode")) { /* bibcode.load */ stat = samp_bibLoad (sampH, to, args[1]); /******************************************** *** VO/IRAF Message Types *** ********************************************/ } else if (MATCH ("exec")) { /* client.cmd.exec */ samp_cmdExec (sampH, to, args[0]); } else if (MATCH ("getenv")) { /* client.env.get */ char *v = samp_envGet (sampH, to, args[0]); /* name */ if (use_ipc) { reslen = strlen (v); result = strdup (v); } else printf ("%s\n", v); if (v) free ((void *) v); } else if (MATCH ("setenv")) { /* client.env.set */ stat = samp_envSet (sampH, to, args[0], /* name */ args[1]); /* value */ } else if (MATCH ("getparam")) { /* client.param.get */ char *v = samp_paramGet (sampH, to, args[0]); /* name */ if (use_ipc) { reslen = strlen (v); result = strdup (v); } else printf ("%s\n", v); if (v) free ((void *) v); } else if (MATCH ("setparam")) { /* client.param.set */ stat = samp_paramSet (sampH, to, args[0], /* name */ args[1]); /* value */ /******************************************** *** Unknown Command *** ********************************************/ } else { if (use_ipc) { memset (buf, 0, SZ_BUF); sprintf (buf, "Error: unknown command '%s'\n", cmd); result = strdup (buf); reslen = strlen (buf); } else fprintf (stderr, "Error: unknown command '%s'\n", cmd); } if (!quiet) { if (!reslen) { result = strdup ((stat < 0 ? "Error" : "OK")); reslen = strlen (result); return_stat = (stat < 0 ? ERR : OK); } } vosDebug ("procCmd: reslen=%d result='%s'\n", reslen, result); /* Return result to the remote caller. */ cmd_exit_: if (ipc_sock > 0) { int nwrite; short slen = reslen; if (vos_sockWrite (ipc_sock, &slen, sizeof (short))) nwrite = vos_sockWrite (ipc_sock, result, slen); } if (result) free (result); } /** * VOS_INVALIDARG -- Check arguments for validity. */ static int vos_invalidArg (int argc, char *argv[], int nargs, int exist) { int stat = 0; /* See if the number of args we have is less than what we require. */ if (argc < nargs) { fprintf (stderr, "Error: invalid number of args for command '%s'\n", cmd); return ((stat = -1)); } /* See whether we require the existance of the first argument. If this * is a local file it must exist, assume URLs are valid. */ if (exist) { if (!argv[0] || !argv[0][0]) return ((stat = -1)); if (strncmp ("http", argv[0], 4) && access (argv[0], R_OK)) { fprintf (stderr, "Error: cannot access file '%s'\n", args[0]); return ((stat = -1)); } } return (stat); } /** * VOS_CMDHELP -- Print a command help summary for interactive mode. */ static void vos_cmdHelp (char *cmd) { if (MATCH ("status")) { printf ("status\n"); } else if (MATCH ("handle")) { ; } else if (MATCH ("snoop")) { printf ("snoop\n"); } else if (MATCH ("send")) { ; } else if (MATCH ("start")) { printf ("start\n"); } else if (MATCH ("stop")) { printf ("stop\n"); } else if (MATCH ("echo")) { printf ("echo \n"); } else if (MATCH ("help")) { printf ("help \n"); } else if (MATCH ("quit")) { printf ("quit\n"); } else if (MATCH ("trace")) { printf ("trace\n"); } else if (MATCH ("listClients")) { printf ("listClients\n"); } else if (MATCH ("ping")) { printf ("ping \n"); } else if (MATCH ("access")) { printf ("access \n"); } else if (MATCH ("loadImage") || MATCH ("loadFITS")) { printf ("loadImage [ []]\n"); } else if (MATCH ("loadVOTable")) { printf ("loadVOTable [ []]\n"); } else if (MATCH ("loadResource")) { ; } else if (MATCH ("showRow")) { printf ("showRow \n"); } else if (MATCH ("selectRows")) { printf ("selectRows \n"); } else if (MATCH ("pointAt")) { printf ("pointAt \t# coords in decimal degrees\n"); } else if (MATCH ("loadSpec")) { printf ("loadSpec [ ]\n"); } else if (MATCH ("bibcode")) { printf ("bibcode \n"); } else if (MATCH ("exec")) { printf ("exec \n"); } else if (MATCH ("getenv")) { printf ("getenv \n"); } else if (MATCH ("setenv")) { printf ("setenv \n"); } else if (MATCH ("getparam")) { printf ("getparam \n"); } else if (MATCH ("setparam")) { printf ("setparam \n"); } } /** * VOSDEBUG -- Utility to print debug messages. */ static void vosDebug (char *format, ...) { va_list argp; char buf[1024]; extern char *vo_encodeString (); if (!debug) return; /* Format the message. */ memset (buf, 0, 1024); va_start (argp, format); vo_encodeString (buf, format, &argp); va_end (argp); if (buf[strlen(buf)-1] != '\n') /* ensure a newline */ strcat (buf, "\n"); fprintf (stderr, "[%d] %s", (int)getpid(), buf); } /** * VOS_OPENSESSION -- Open a connection to the VOSAMP Session Manager. * * @brief Open a connection to the VOSAMP Session Manager. * @fn int vos_openSession (char *host, int port, char *session_name) * * @param host session manager host * @param port session manager connection port * @param name session name * @return fd to the session socket */ int vos_openSession (char *host, int port, char *session_name) { int sock = 0, cb_sock = 0, cb_port = 0, nr, nw, len, ready = SESS_READY; char cmd[SZ_LINE]; /* Open a socket to the connection port. */ if ((sock = vos_openClientSocket (host, port, 1)) <= 0) return (1); /* Read the callback port number. */ if ((nr = vos_sockRead (sock, &cb_port, sizeof (short))) != sizeof (short)) return (1); /* Close the socket to the connection port. */ close (sock); /* Open a new connection to the callback port. */ if ((cb_sock = vos_openClientSocket (host, cb_port, 1)) <= 0) return (1); /* Write the 'ready' code to the callback prot. */ nw = vos_sockWrite (cb_sock, &ready, sizeof (short)); /* Send the 'connect' message to connect to the named session. The * server will either create a new session or have us join an existing * session created by another node. */ memset (cmd, 0, SZ_LINE); sprintf (cmd, "connect %s", session_name); len = strlen (cmd); if (vos_sockWriteHdr (cb_sock, len, NULL, SAMP_CMD, SAMP_NOTIFY, "smgr")) nw = vos_sockWrite (cb_sock, cmd, len); /* Return 0 if we can connect, 1 on err, or the callback descriptor. */ return (cb_sock); } /** * VOS_CLOSESESSION -- Close the specified session connection. * * @brief Close the specified session connection. * @fn int vos_closeSession (int sock) * * @param sock session socket fd * @return 0 if cmd was sent, 1 otherwise */ int vos_closeSession (int sock) { if (vos_sockWriteHdr (sock, 0, NULL, SAMP_QUIT, SAMP_NOTIFY, "smgr")) return (1); return (0); }