aboutsummaryrefslogtreecommitdiff
path: root/vendor/voclient/voapps/lib/vosUtil.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/voclient/voapps/lib/vosUtil.c')
-rw-r--r--vendor/voclient/voapps/lib/vosUtil.c998
1 files changed, 998 insertions, 0 deletions
diff --git a/vendor/voclient/voapps/lib/vosUtil.c b/vendor/voclient/voapps/lib/vosUtil.c
new file mode 100644
index 00000000..732daf45
--- /dev/null
+++ b/vendor/voclient/voapps/lib/vosUtil.c
@@ -0,0 +1,998 @@
+/**
+ * VOSUTIL - Utility routines for the VOSAMP tools.
+ *
+ * @file vosUtil.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Utility routines for the VOSAMP tools.
+ *
+ */
+
+#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 <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+
+#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 VOS_DEBUG (getenv("VOS_DBG")!=NULL||access("/tmp/VOS_DBG",F_OK)==0)
+
+
+typedef struct {
+ int nbytes; /* length of msg body */
+ int mode; /* sync, async, notify */
+ int type; /* SAMP cmd, data, result */
+ char fname[SZ_FNAME]; /* upload data name */
+ int fsize; /* data file size */
+ char session[SZ_APPNAME]; /* session name */
+ int sessionPort; /* session port number */
+ char recipient[SZ_APPNAME]; /* recipient app name */
+ char senderIP[SZ_HOSTIP]; /* sender's IP address */
+ int senderPort; /* sender's port */
+
+ int verbose; /* verbose flag */
+ int debug; /* debug flag */
+} cmdHdr, *cmdHdrP;
+
+cmdHdr msgHdr;
+
+
+extern char *to, senderIP[SZ_HOSTIP];
+
+
+char *vos_toURL (char *arg);
+char *vos_optArg (char *arg);
+char *vos_getLocalIP (void);
+char *vos_getFName (char *path);
+char *vos_typeName (int type);
+
+int *vos_toIntArray (char *arg, int *nrows);
+int vos_urlType (char *url);
+int vos_getURL (char *url, char *fname);
+
+
+
+/* Private socket routines.
+ */
+int vos_openServerSocket (int port);
+int vos_openClientSocket (char *host, int port, int retry);
+int vos_sockRead (int fd, void *vptr, int nbytes);
+int vos_sockWrite (int fd, void *vptr, int nbytes);
+void vos_setNonBlock (int sock);
+int vos_sockWriteHdr (int fd, int len, char *name, int type, int mode,
+ char *to);
+int vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode);
+void vos_sockPrintHdr (char *msg, int fd);
+struct hostent *vos_getHostByName (char *lhost);
+struct hostent *vos_dupHostent (struct hostent *hentry);
+
+
+
+
+/****************************************************************************
+ */
+
+
+/**
+ * VOS_URLTYPE -- Determine the type of a URL parameter
+ */
+int
+vos_urlType (char *url)
+{
+ if (strncasecmp (url, "http://127.0.0.1", 16) == 0)
+ return (VOS_LOCALURL);
+ else if (strncasecmp (url, "file://", 7) == 0)
+ return (VOS_LOCALURI);
+ else if (strncasecmp (url, "http://", 7) == 0)
+ return (VOS_REMOTE);
+ else if (access (url, F_OK) == 0)
+ return (VOS_LOCALFILE);
+
+ return (-1);
+}
+
+
+/**
+ * VOS_GETFNAME -- Get a filename from a path or URL.
+ */
+char *
+vos_getFName (char *path)
+{
+ static char fname[SZ_FNAME];
+ static int filenum = 0;
+
+ memset (fname, 0, SZ_FNAME);
+ if (access (path, R_OK) == 0) {
+ int i, len = strlen (path);
+
+ for (i=len-1; i >=0 && path[i] != '/'; i--) ; /* get filename */
+ strcpy (fname, &path[i+1]);
+ }
+
+ if (!fname[0])
+ sprintf (fname, "vos%d_%03d", (int)getpid(), filenum++);
+
+ return (fname);
+}
+
+
+/**
+ * VOS_TYPENAME -- Convert a message type code to a string.
+ */
+char *
+vos_typeName (int type)
+{
+ switch (type) {
+ case SAMP_DATA: return ("SAMP_DATA");
+ case SAMP_CMD: return ("SAMP_CMD");
+ case SAMP_RELAY: return ("SAMP_RELAY");
+ case SAMP_TEST: return ("SAMP_TEST");
+ case SAMP_QUIT: return ("SAMP_QUIT");
+ default: return ("unknown");
+ }
+}
+
+
+/**
+ * VOS_GETURL -- Utility routine to do a simple URL download to the file.
+ */
+int
+vos_getURL (char *url, char *fname)
+{
+ int stat = 0;
+ char errBuf[SZ_LINE];
+ FILE *fd;
+ CURL *curl_handle;
+
+
+ if (access (fname, F_OK) == 0) /* see if file already exists */
+ unlink (fname);
+
+
+ /* For the CURL operation to download the file.
+ */
+ curl_global_init (CURL_GLOBAL_ALL); /* init curl session */
+ curl_handle = curl_easy_init ();
+
+ /* Open the output file.
+ */
+ if ((fd = fopen (fname, "wb")) == NULL) {
+ fprintf (stderr, "Error: cannot open output file '%s'\n", fname);
+ curl_easy_cleanup (curl_handle);
+ return -1;
+ }
+
+ /* Set cURL options
+ */
+ curl_easy_setopt (curl_handle, CURLOPT_URL, url);
+ curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, fd);
+ curl_easy_setopt (curl_handle, CURLOPT_ERRORBUFFER, errBuf);
+ curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1);
+
+ /* Do the download.
+ */
+ if ((stat = curl_easy_perform (curl_handle)) != 0) {
+ /* Error in download, clean up.
+ */
+ fprintf (stderr, "Error: can't download '%s' : %s\n", url, errBuf);
+ unlink (fname);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+ return (-1);
+ }
+
+ fflush (fd);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+
+ return (1);
+}
+
+
+/**
+ * VOS_OPTARG -- Input command arguments are allowed to be of the form
+ * 'param=value', but the SAMP interface only wants the value string.
+ * Skip past the '=' and return the value, or just return the value if
+ * there is no parameter name.
+ */
+char *
+vos_optArg (char *arg)
+{
+ char *ip, first = (arg ? *arg : 0);
+
+ if (!arg || !first) return ("");
+ return ( ((ip = strchr (arg, (int) '=')) ? ++ip : arg) );
+}
+
+
+/**
+ * VOS_TOURL -- Convert the argument to a URL suitable for a message.
+ */
+char *
+vos_toURL (char *arg)
+{
+ /* If we have an existing protocol simply return the argument.
+ */
+ if ((strncmp (arg, "http:", 5) == 0) ||
+ (strncmp (arg, "file:", 5) == 0) ||
+ (strncmp (arg, "ftp:", 4) == 0))
+ return (arg);
+
+ if (access (arg, F_OK) == 0) {
+ static char buf[SZ_FNAME];
+
+ memset (buf, 0, SZ_FNAME);
+ if (arg[0] != '/') {
+ char cwd[SZ_FNAME];
+
+ memset (cwd, 0, SZ_FNAME);
+ getcwd (cwd, (unsigned long) SZ_FNAME);
+ sprintf (buf, "file://%s/%s", cwd, arg);
+ } else
+ sprintf (buf, "file://%s", arg);
+
+ return (buf);
+ }
+
+ return (arg);
+}
+
+
+/**
+ * VOS_TOINTARRAY -- Convert a range string to an unpacked array of ints.
+ */
+#define MAX_RANGES 256
+#define SZ_ROW 16
+
+int *
+vos_toIntArray (char *arg, int *nrows)
+{
+ int i, val, nvalues;
+ static int ranges[MAX_RANGES], values[MAX_ROWS];
+ extern int vot_decodeRanges(), get_next_number();
+
+
+ memset (values, 0, (sizeof(int) * MAX_ROWS));
+ memset (ranges, 0, (sizeof(int) * MAX_RANGES));
+
+ if (vot_decodeRanges (arg, ranges, MAX_RANGES, &nvalues) < 0)
+ fprintf (stderr, "Error decoding range string.\n");
+
+ for (i=0, val=0; (val = get_next_number (ranges, val)) > 0; i++ )
+ values[i] = val;
+
+ *nrows = nvalues;
+ return (values);
+}
+
+
+
+/*****************************************************************************
+**** Socket Utilities
+*****************************************************************************/
+
+
+#define SELWIDTH 32
+#define SOCK_MAX_TRY 3
+
+/**
+ * VOS_OPENSERVERSOCKET -- Open a socket to be used on the 'server' side.
+ *
+ * @brief Open a socket to be used on the 'server' side
+ * @fn int vos_openServerSocket (int port)
+ *
+ * @param port port number to open
+ * @return socket descriptor
+ *
+ */
+int
+vos_openServerSocket (int port)
+{
+ struct sockaddr_in servaddr; /* server address */
+ int ps = 0; /* parallel socket descriptor */
+ int32_t yes = 1, ntries = 5;
+
+
+ /* Create a socket.
+ */
+ if ((ps = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf (stderr, "openServerSocket(%d): %s\n", port, strerror(errno));
+ return (-1);
+ }
+ setsockopt (ps, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "server socket %d on %s:%d\n", ps,
+ vos_getLocalIP(), port );
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof servaddr);
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /* Bind to the server socket and listen for a connection.
+ */
+ while (ntries--) {
+ if (bind (ps, (struct sockaddr*)&servaddr, sizeof servaddr) < 0) {
+ if (!ntries)
+ return (-1);
+ } else {
+ if ((listen (ps, SOMAXCONN)) < 0) {
+ fprintf (stderr,
+ "serverSock: listen(%d:%s)", port, strerror(errno));
+ if (!ntries)
+ return (-1);
+ } else {
+ break;
+ }
+ }
+ sleep (1);
+ }
+
+ return (ps);
+}
+
+
+/**
+ * VOS_OPENCLIENTSOCKET -- Open a socket to be used on the 'client' side.
+ *
+ * @brief Open a socket to be used on the 'client' side
+ * @fn int vos_openClientSocket (char *host, int port, int retry)
+ *
+ * @param host host name
+ * @param port port number to open
+ * @param retry attempt to reconnect?
+ * @return socket descriptor
+ *
+ */
+int
+vos_openClientSocket (char *host, int port, int retry)
+{
+ char *ip, lhost[SZ_LINE];
+ struct sockaddr_in servaddr; /* server address */
+ int ps = 0; /* parallel socket descriptor */
+ socklen_t ctry = 0, yes = 1;
+
+
+ /* Remove any server port information from the host specification.
+ */
+ memset (lhost, 0, SZ_LINE);
+ strcpy (lhost, host);
+ if ( (ip = strchr (lhost, (int) ':')) )
+ *ip = '\0';
+
+ /* Create a socket.
+ */
+ if ((ps = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf (stderr, "openClientSocket(%s:%d): %s\n",
+ host, port, strerror(errno));
+ return (-1);
+ }
+ setsockopt (ps, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof (struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+
+ /* Connect to server.
+ */
+ for (ctry = (retry ? 0 : SOCK_MAX_TRY); ctry <= SOCK_MAX_TRY; ctry++) {
+
+ if ( !inet_aton(lhost, &servaddr.sin_addr) ) {
+ struct hostent *he = vos_getHostByName ( lhost );
+
+ if (!he) {
+ fprintf (stderr, "Cannot resolve address.\n");
+ exit (2);
+ }
+ if (he->h_addrtype != AF_INET ||
+ he->h_length != sizeof (servaddr.sin_addr)) {
+ fprintf (stderr, "Cannot handle addr type %d, length %d.\n",
+ he->h_addrtype, he->h_length);
+ exit(2);
+ }
+ memcpy (&servaddr.sin_addr, he->h_addr_list[0],
+ sizeof (servaddr.sin_addr) );
+ }
+
+ if (connect (ps, (struct sockaddr *)&servaddr, sizeof servaddr) < 0) {
+ if (!retry || ctry == SOCK_MAX_TRY) {
+ fprintf (stderr,
+ "client connect() failed to %s:%d, try %d, retry %d\n",
+ lhost, port, ctry, retry);
+ close (ps);
+ ps = -1;
+ break;
+ } else
+ sleep (1);
+ } else
+ break;
+ }
+
+ return (ps);
+}
+
+
+/**
+ * VOS_TESTCLIENTSOCKET -- Test a socket to be used on the 'client' side.
+ *
+ * @brief Test a socket to be used on the 'client' side
+ * @fn int vos_testClientSocket (char *host, int port)
+ *
+ * @param host host name
+ * @param port port number to open
+ * @return socket descriptor or -1 if connect fails
+ *
+ */
+int
+vos_testClientSocket (char *host, int port)
+{
+ char *ip, lhost[SZ_LINE];
+ struct sockaddr_in servaddr; /* server address */
+ int sock = 0; /* socket descriptor */
+ socklen_t yes = 1;
+
+
+ /* Remove any server port information from the host specification.
+ */
+ memset (lhost, 0, SZ_LINE);
+ strcpy (lhost, host);
+ if ( (ip = strchr (lhost, (int) ':')) )
+ *ip = '\0';
+
+ /* Create a socket.
+ */
+ if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof (struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+
+ /* Connect to server.
+ */
+ if ( !inet_aton(lhost, &servaddr.sin_addr) ) {
+ struct hostent *he = vos_getHostByName ( lhost );
+
+ if (!he)
+ return (-1);
+ if (he->h_addrtype != AF_INET ||
+ he->h_length != sizeof (servaddr.sin_addr)) {
+ return (-1);
+ }
+ memcpy (&servaddr.sin_addr, he->h_addr_list[0],
+ sizeof (servaddr.sin_addr) );
+ }
+
+ if (connect (sock, (struct sockaddr *)&servaddr, sizeof servaddr) < 0) {
+ close (sock);
+ sock = -1;
+ }
+ return (sock);
+}
+
+
+/**
+ * VOS_SOCKWRITEHDR -- Write the socket message header.
+ */
+int
+vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode)
+{
+ int nread = 0;
+
+ memset (&msgHdr, 0, sizeof (msgHdr));
+ if ((nread = vos_sockRead (fd, &msgHdr, sizeof (msgHdr))) > 0) {
+ *len = msgHdr.nbytes;
+ *type = msgHdr.type;
+ *mode = msgHdr.mode;
+ to = strdup (msgHdr.recipient);
+ strcpy (senderIP, msgHdr.senderIP);
+ if (name)
+ strcpy (name, msgHdr.fname); /* must be at least SZ_FNAME */
+ }
+
+ if (VOS_DEBUG)
+ vos_sockPrintHdr ("Read Hdr", fd);
+
+ return (nread);
+}
+
+
+/**
+ * VOS_SOCKWRITEHDR -- Write the socket message header.
+ */
+int
+vos_sockWriteHdr (int fd, int len, char *name, int type, int mode, char *to)
+{
+ int nwrite = 0;
+
+ memset (&msgHdr, 0, sizeof (msgHdr));
+ msgHdr.nbytes = len;
+ msgHdr.type = type;
+ msgHdr.mode = mode;
+ if (name && name[0]) {
+ struct stat st;
+ stat (name, &st);
+ strcpy (msgHdr.fname, name);
+ msgHdr.fsize = st.st_size;
+ }
+ strcpy (msgHdr.recipient, (to ? to : "all"));
+ strcpy (msgHdr.senderIP, vos_getLocalIP());
+
+ if (VOS_DEBUG)
+ vos_sockPrintHdr ("Write Hdr", fd);
+
+ return ((nwrite = vos_sockWrite (fd, &msgHdr, sizeof(msgHdr))));
+}
+
+
+/**
+ * VOS_SOCKPRINTHDR -- Debug utility to print a message header.
+ */
+void
+vos_sockPrintHdr (char *msg, int fd)
+{
+ fprintf (stderr, "%s: fd=%d\n", msg, fd);
+ fprintf (stderr, " { 'type' : %d, 'mode' : %d,\n",
+ msgHdr.type, msgHdr.mode);
+ fprintf (stderr, " 'fname' : '%s', 'nbytes' : %d, 'fsize' : %d,\n",
+ msgHdr.fname, msgHdr.nbytes, msgHdr.fsize);
+ fprintf (stderr, " 'session' : '%s', 'port' : %d,\n",
+ msgHdr.session, msgHdr.sessionPort);
+ fprintf (stderr, " 'sender' : '%s', 'port' : %d, 'to' : '%s'\n",
+ msgHdr.senderIP, msgHdr.senderPort, msgHdr.recipient);
+ fprintf (stderr, " }\n");
+}
+
+
+/**
+ * VOS_SOCKREAD -- Read exactly "n" bytes from a socket descriptor.
+ *
+ * @brief Recv exactly "n" bytes from a socket descriptor.
+ * @fn int vos_sockRead (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_sockRead (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nread = 0, nleft = nbytes, nb = 0;
+ fd_set allset, fds;
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ vos_setNonBlock (fd);
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ fds = allset;
+ if (select (SELWIDTH, &fds, NULL, NULL, NULL)) {
+ if ( (nb = recv (fd, ptr, nleft, 0)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call recv() again */
+ else {
+ fprintf (stderr, "[%d] vos_sockRead:[%d] %s\n",
+ (int) getpid(), fd, strerror(errno));
+ return (-1);
+ }
+ } else if (nb == 0)
+ break; /* EOF */
+ nleft -= nb;
+ ptr += nb;
+ nread += nb;
+ }
+ }
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "sockRead: %d bytes on fd=%d\n", nread, fd);
+
+ return (nread); /* return no. of bytes read */
+}
+
+
+/**
+ * VOS_SOCKWRITE -- Write exactly "n" bytes to a socket descriptor.
+ *
+ * @brief Send exactly "n" bytes to a socket descriptor.
+ * @fn int vos_sockWrite (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_sockWrite (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nwritten = 0, nleft = nbytes, nb = 0;
+ fd_set allset, fds;
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ vos_setNonBlock (fd);
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ fds = allset;
+ if (select (SELWIDTH, NULL, &fds, NULL, NULL)) {
+ if ( (nb = send (fd, ptr, nleft, 0)) <= 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call send() again */
+ else {
+ /*
+ fprintf (stderr, "[%d] vos_sockWrite[%d]: %s\n",
+ (int) getpid(), fd, strerror (errno));
+ */
+ return (-1);
+ }
+ }
+ nleft -= nb;
+ ptr += nb;
+ nwritten += nb;
+ }
+ }
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "sockWrite: %d bytes on fd=%d\n", nwritten, fd);
+
+ return (nwritten);
+}
+
+
+/**
+ * VOS_FILEREAD -- Read exactly "n" bytes from a socket descriptor.
+ *
+ * @brief Recv exactly "n" bytes from a socket descriptor.
+ * @fn int vos_sockRead (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_fileRead (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nread = 0, nleft = nbytes, nb = 0;
+
+ while (nleft > 0) {
+ if ( (nb = read(fd, ptr, nleft)) < 0) {
+ if (errno == EINTR)
+ nb = 0; /* and call read() again */
+ else
+ return(-1);
+ } else if (nb == 0)
+ break; /* EOF */
+ nleft -= nb;
+ ptr += nb;
+ nread += nb;
+ }
+ return (nread); /* return no. of bytes read */
+}
+
+
+/**
+ * VOS_FILEWRITE -- Write exactly "n" bytes to a file descriptor.
+ *
+ * @brief Send exactly "n" bytes to a file descriptor.
+ * @fn int vos_fileWrite (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_fileWrite (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nwritten = 0, nleft = nbytes, nb = 0;
+
+ while (nleft > 0) {
+ if ( (nb = write(fd, ptr, nleft)) <= 0) {
+ if (errno == EINTR)
+ nb = 0; /* and call write() again */
+ else
+ return(-1); /* error */
+ }
+ nleft -= nb;
+ ptr += nb;
+ nwritten += nb;
+ }
+ return (nwritten);
+}
+
+
+/**
+ * VOS_SETNONBLOCK -- Set a non-blocking mode on the socket descriptor.
+ */
+void
+vos_setNonBlock (int sock)
+{
+ int flags;
+
+
+ /* Set socket to non-blocking.
+ */
+ if ((flags = fcntl (sock, F_GETFL, 0)) < 0) {
+ /* Handle error */
+ return;
+ }
+ if (fcntl (sock, F_SETFL, flags | O_NONBLOCK) < 0) {
+ /* Handle error */
+ return;
+ }
+}
+
+
+/**
+ * VOS_GETLOCALIP -- Get the IP address of the local machine.
+ */
+char *
+vos_getLocalIP (void)
+{
+ const char *kGoogleDnsIp = "8.8.8.8"; /* Google's public DNS server */
+ unsigned short kDnsPort = 53;
+ struct sockaddr_in serv;
+ int sock, err;
+ const char *p;
+ char buffer[SZ_BUF];
+ static int initialized = 0;
+ static char localIP[SZ_BUF];
+
+
+ /* Only get the IP once, afterwards just return the value.
+ */
+ if (initialized++)
+ return (localIP);
+
+ memset (buffer, 0, SZ_BUF);
+ memset (localIP, 0, SZ_BUF);
+
+ if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ return ("127.0.0.1"); /* cannot get socket, punt */
+
+ memset (&serv, 0, sizeof (serv));
+ serv.sin_family = AF_INET;
+ serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
+ serv.sin_port = htons(kDnsPort);
+
+ if ((err = connect(sock, (struct sockaddr*)&serv, sizeof(serv))) >= 0) {
+ struct sockaddr_in name;
+ socklen_t namelen = sizeof(name);
+
+ if ((err=getsockname(sock, (struct sockaddr*)&name, &namelen)) < 0)
+ strcpy (buffer, "127.0.0.1"); /* cannot connect socket */
+ else
+ if ((p=inet_ntop(AF_INET, &name.sin_addr, buffer, SZ_BUF)) == NULL)
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+ } else
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+
+ if (strncmp (buffer, "192.168.", 8) == 0)
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+
+ close(sock);
+
+ strcpy (localIP, buffer);
+ return (localIP);
+}
+
+
+/**
+ * VOS_GETHOSTBYNAME -- Get the host entry associated with a (cached) name.
+ *
+ * @fn char *vos_getHostByName (char *name)
+ *
+ * @param name host name
+ * @return host entry structure pointer
+ */
+typedef struct {
+ char name[SZ_LINE];
+ char ip[SZ_LINE];
+ struct hostent *host;
+} hostTab, *hostTabP;
+
+struct hostent_wrapper {
+ struct hostent hentry;
+ int status;
+};
+
+static hostTab hostab[MAX_CLIENTS];
+
+
+struct hostent *
+vos_getHostByName (char *name)
+{
+ static int initialized = 0;
+ struct in_addr x_addr;
+ struct hostent *hp = (struct hostent *) NULL;
+ hostTab *h = (hostTabP) hostab;
+ int i, len;
+
+
+ if (!initialized) {
+ memset (hostab, 0, sizeof (hostab));
+ initialized++;
+ }
+
+ for (i=0; i < MAX_CLIENTS; i++, h++) {
+ if (h && h->name[0]) {
+ len = min (strlen (name), strlen (h->name));
+ if (strncmp (name, h->name, len) == 0)
+ return (h->host);
+ } else
+ break; /* end of cache list */
+ }
+
+ /* If we overflow the cache use a DNS lookup.
+ */
+ if (i >= MAX_CLIENTS) {
+ fprintf (stderr, "vos_getHostByName(): cache overflow on '%s'", name);
+ hp = gethostbyname (name);
+ return (hp);
+ }
+
+ /* Host not found, resolve and add it to the cache.
+ */
+ hp = gethostbyname (name);
+ if (hp == (struct hostent *) NULL) {
+ fprintf (stderr, "vos_getHostByName: cannot resolve '%s'\n", name);
+ exit (0);
+ }
+
+ strcpy (h->name, name);
+ x_addr.s_addr = *((unsigned long *) hp->h_addr_list[0]);
+ strcpy (h->ip, inet_ntoa (x_addr));
+
+ h->host = vos_dupHostent (hp);
+ return (h->host);
+}
+
+
+/**
+ * VOS_DUPHOSTENT -- Duplicate a hostent structure via a deep copy.
+ */
+struct hostent *
+vos_dupHostent (struct hostent *hentry)
+{
+ struct hostent_wrapper *oldhw = NULL;
+ struct hostent_wrapper *newhw = NULL;
+ int i = 0;
+ int aliascount=0;
+ int addrcount=0;
+
+
+ if (!hentry)
+ return NULL;
+
+ oldhw = (struct hostent_wrapper *) hentry;
+ newhw = (struct hostent_wrapper *) malloc (sizeof (struct hostent_wrapper));
+ bzero(newhw, sizeof (struct hostent_wrapper));
+
+ newhw->hentry.h_addrtype = hentry->h_addrtype;
+ newhw->hentry.h_length = hentry->h_length;
+ newhw->status = oldhw->status;
+
+ if (hentry->h_name)
+ newhw->hentry.h_name = strdup(hentry->h_name);
+
+ if (hentry->h_aliases) {
+ for (i=0; hentry->h_aliases[i] != 0; i++)
+ aliascount++;
+ aliascount++;
+
+ newhw->hentry.h_aliases = (char **)malloc (aliascount * sizeof (char*));
+ bzero(newhw->hentry.h_aliases, aliascount * sizeof(char*));
+
+ for (i=0; hentry->h_aliases[i] != 0; i++) {
+ if (hentry->h_aliases[i])
+ newhw->hentry.h_aliases[i] = strdup (hentry->h_aliases[i]);
+ }
+ }
+
+ if (hentry->h_addr_list) {
+ for (i=0; hentry->h_addr_list[i] != 0; i++)
+ addrcount++;
+ addrcount++;
+
+ newhw->hentry.h_addr_list =
+ (char **) malloc (addrcount * sizeof (char *));
+ bzero (newhw->hentry.h_addr_list, addrcount * sizeof (char *));
+
+ for (i=0; hentry->h_addr_list[i] != 0; i++) {
+ if (hentry->h_addr_list[i])
+ newhw->hentry.h_addr_list[i] = strdup (hentry->h_addr_list[i]);
+ }
+ }
+
+ return (struct hostent *) newhw;
+}
+
+/**
+ * VOS_STRSUB -- Do a string subsitution.
+ */
+int
+vos_strsub (char *in, char *from, char *to, char *outstr, int maxch)
+{
+ int flen = strlen (from);
+ int nsub = 0;
+ char *ip, *op;
+
+ if (!from || !to)
+ return (0);
+
+ for (ip=in, op=outstr; *ip; ip++) {
+ if (! *ip || (ip - in) > maxch)
+ break;
+ if (*ip == '$') {
+ /* Start of a macro.
+ */
+ if (strncasecmp (ip, from, flen) == 0) {
+ /* Our macro, do the substitution.
+ */
+ char *tp = to;
+
+ ip += flen - 1; /* skip the input macro */
+ while (*tp) /* copy replacement string */
+ *op++ = *tp++;
+ nsub++;
+ } else {
+ /* Not our macro, just pass it through.
+ */
+ *op++ = *ip;
+ }
+ } else {
+ *op++ = *ip;
+ }
+ }
+ *op = '\0';
+
+ return (nsub);
+}