VSI submission: redirect terminal input through socket
authorRichard Levitte <levitte@openssl.org>
Wed, 3 Aug 2016 19:16:43 +0000 (21:16 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 15 Sep 2016 21:23:06 +0000 (23:23 +0200)
This is needed, because on VMS, select() can only be used on sockets.  being
able to use select() on all kinds of file descriptors is unique to Unix.

So, the solution for VMS is to create a layer that translates input from
standard input to socket communication.

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
apps/s_client.c
apps/s_server.c
apps/vms_term_sock.c [new file with mode: 0755]
apps/vms_term_sock.h [new file with mode: 0755]

index b909c9a..1c7429f 100644 (file)
 # define APPS_WIN16
 #endif
 
+#ifdef OPENSSL_SYS_VMS
+# include "vms_term_sock.h"
+#endif
 /*
  * With IPv6, it looks like Digital has mixed up the proper order of
  * recursive header file inclusion, resulting in the compiler complaining
@@ -745,6 +748,10 @@ int MAIN(int argc, char **argv)
     int crl_download = 0;
     STACK_OF(X509_CRL) *crls = NULL;
     int prot_opt = 0, no_prot_opt = 0;
+#if defined(OPENSSL_SYS_VMS)  
+    int stdin_sock;
+    TerminalSocket(TERM_SOCK_CREATE, &stdin_sock);
+#endif 
 
     meth = SSLv23_client_method();
 
@@ -1457,7 +1464,20 @@ int MAIN(int argc, char **argv)
 
 #ifdef FIONBIO
     if (c_nbio) {
+#if defined(OPENSSL_SYS_VMS) && defined(__VMS_VER) && (__VMS_VER >= 70000000)  
+        /* For 64-bit --> 32-bit restricted APIs (IOCTL) */
+#if __INITIAL_POINTER_SIZE == 64 
+#pragma __required_pointer_size __save 
+#pragma __required_pointer_size 32 
+#endif 
+        unsigned int l = 1;
+#if __INITIAL_POINTER_SIZE == 64 
+#pragma __required_pointer_size __restore 
+#endif 
+#else  
         unsigned long l = 1;
+#endif /* OPENSSL_SYS_VMS */
+
         BIO_printf(bio_c_out, "turning on non blocking io\n");
         if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) {
             ERR_print_errors(bio_err);
@@ -1561,8 +1581,14 @@ int MAIN(int argc, char **argv)
     SSL_set_connect_state(con);
 
     /* ok, lets connect */
+#if defined(OPENSSL_SYS_VMS)  
+    if (stdin_sock > SSL_get_fd(con))
+        width = stdin_sock + 1;
+    else
+        width = SSL_get_fd(con) + 1;
+#else  
     width = SSL_get_fd(con) + 1;
-
+#endif
     read_tty = 1;
     write_tty = 0;
     tty_on = 0;
@@ -1743,10 +1769,16 @@ int MAIN(int argc, char **argv)
         if (!ssl_pending) {
 #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined (OPENSSL_SYS_BEOS_R5)
             if (tty_on) {
+
+#if defined(OPENSSL_SYS_VMS)
+                if (read_tty)
+                    openssl_fdset(stdin_sock, &readfds);
+#else
                 if (read_tty)
                     openssl_fdset(fileno(stdin), &readfds);
                 if (write_tty)
                     openssl_fdset(fileno(stdout), &writefds);
+#endif
             }
             if (read_ssl)
                 openssl_fdset(SSL_get_fd(con), &readfds);
@@ -1907,7 +1939,7 @@ int MAIN(int argc, char **argv)
                 goto shut;
             }
         }
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5) || defined(OPENSSL_SYS_VMS) 
         /* Assume Windows/DOS/BeOS can always write */
         else if (!ssl_pending && write_tty)
 #else
@@ -2009,13 +2041,25 @@ int MAIN(int argc, char **argv)
 #elif defined(OPENSSL_SYS_BEOS_R5)
         else if (stdin_set)
 #else
-        else if (FD_ISSET(fileno(stdin), &readfds))
+
+#if defined(OPENSSL_SYS_VMS)  
+          else if (FD_ISSET(stdin_sock,&readfds))  
+#else  
+          else if (FD_ISSET(fileno(stdin),&readfds))  
+#endif 
+
 #endif
         {
             if (crlf) {
                 int j, lf_num;
 
                 i = raw_read_stdin(cbuf, BUFSIZZ / 2);
+               #if defined(OPENSSL_SYS_VMS)
+                    i = recv(stdin_sock, cbuf, BUFSIZZ/2, 0);
+                #else
+                    i = raw_read_stdin(cbuf, BUFSIZZ/2);
+                #endif
+
                 lf_num = 0;
                 /* both loops are skipped when i <= 0 */
                 for (j = 0; j < i; j++)
@@ -2031,8 +2075,13 @@ int MAIN(int argc, char **argv)
                 }
                 assert(lf_num == 0);
             } else
-                i = raw_read_stdin(cbuf, BUFSIZZ);
-
+               {
+                       #if defined(OPENSSL_SYS_VMS) 
+                       i = recv(stdin_sock, cbuf, BUFSIZZ, 0);
+                       #else
+                       i = raw_read_stdin(cbuf, BUFSIZZ);
+                       #endif
+               }
             if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) {
                 BIO_printf(bio_err, "DONE\n");
                 ret = 0;
@@ -2126,6 +2175,9 @@ int MAIN(int argc, char **argv)
         BIO_free(bio_c_msg);
         bio_c_msg = NULL;
     }
+#if defined(OPENSSL_SYS_VMS) 
+    TerminalSocket(TERM_SOCK_DELETE, &stdin_sock);
+#endif
     apps_shutdown();
     OPENSSL_EXIT(ret);
 }
index 7038998..a835db0 100644 (file)
@@ -197,6 +197,11 @@ typedef unsigned int u_int;
 #include "s_apps.h"
 #include "timeouts.h"
 
+#ifdef OPENSSL_SYS_VMS
+# include "vms_term_sock.h"
+#endif
+
+
 #if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000)
 /* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
 # undef FIONBIO
@@ -2187,6 +2192,10 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
 #else
     struct timeval *timeoutp;
 #endif
+#if defined(OPENSSL_SYS_VMS)            
+        int stdin_sock;
+        TerminalSocket (TERM_SOCK_CREATE, &stdin_sock);
+#endif
 
     if ((buf = OPENSSL_malloc(bufsize)) == NULL) {
         BIO_printf(bio_err, "out of memory\n");
@@ -2194,7 +2203,19 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
     }
 #ifdef FIONBIO
     if (s_nbio) {
+#    if defined(OPENSSL_SYS_VMS) && defined(__VMS_VER) && (__VMS_VER >= 70000000)               
+        /* For 64-bit --> 32-bit restricted APIs (IOCTL) */             
+#       if __INITIAL_POINTER_SIZE == 64                 
+#           pragma __required_pointer_size __save               
+#           pragma __required_pointer_size 32           
+#   endif               
+        unsigned int sl =1; 
+#       if __INITIAL_POINTER_SIZE == 64                 
+#           pragma __required_pointer_size __restore            
+#       endif           
+#    else               
         unsigned long sl = 1;
+#    endif /* OPENSSL_SYS_VMS */
 
         if (!s_quiet)
             BIO_printf(bio_err, "turning on non blocking io\n");
@@ -2307,7 +2328,15 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
     }
 #endif
 
-    width = s + 1;
+
+#if defined(OPENSSL_SYS_VMS)   
+        if (stdin_sock > s)    
+            width = stdin_sock + 1;             
+    else                       
+        width=s+1;             
+#else                 
+    width=s+1;                 
+#endif
     for (;;) {
         int read_from_terminal;
         int read_from_sslcon;
@@ -2318,7 +2347,11 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
         if (!read_from_sslcon) {
             FD_ZERO(&readfds);
 #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined(OPENSSL_SYS_BEOS_R5)
-            openssl_fdset(fileno(stdin), &readfds);
+    #  if defined(OPENSSL_SYS_VMS)              
+                        openssl_fdset(stdin_sock,&readfds);             
+    #  else                    
+                        openssl_fdset(stdin),&readfds);
+    #endif
 #endif
             openssl_fdset(s, &readfds);
             /*
@@ -2369,7 +2402,11 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
 
             if (i <= 0)
                 continue;
-            if (FD_ISSET(fileno(stdin), &readfds))
+#if defined(OPENSSL_SYS_VMS)            
+                        if (FD_ISSET(stdin_sock,&readfds))              
+#else
+                       if (FD_ISSET(fileno(stdin),&readfds))
+#endif
                 read_from_terminal = 1;
 #endif
             if (FD_ISSET(s, &readfds))
@@ -2379,8 +2416,12 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
             if (s_crlf) {
                 int j, lf_num;
 
-                i = raw_read_stdin(buf, bufsize / 2);
-                lf_num = 0;
+       #if defined(OPENSSL_SYS_VMS)             
+                i=recv(stdin_sock, buf, bufsize/2, 0);
+       #else
+               i = raw_read_stdin(buf, bufsize / 2)
+       #endif 
+               lf_num = 0;
                 /* both loops are skipped when i <= 0 */
                 for (j = 0; j < i; j++)
                     if (buf[j] == '\n')
@@ -2395,7 +2436,11 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
                 }
                 assert(lf_num == 0);
             } else
-                i = raw_read_stdin(buf, bufsize);
+#if defined(OPENSSL_SYS_VMS)            
+                                i=recv(stdin_sock,buf,bufsize, 0);
+#else
+                               i = raw_read_stdin(buf, bufsize);
+#endif 
             if (!s_quiet && !s_brief) {
                 if ((i <= 0) || (buf[0] == 'Q')) {
                     BIO_printf(bio_s_out, "DONE\n");
@@ -2476,7 +2521,7 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
                     srp_callback_parm.user =
                         SRP_VBASE_get1_by_user(srp_callback_parm.vb,
                                                srp_callback_parm.login);
-                    if (srp_callback_parm.user)
+                     if (srp_callback_parm.user)
                         BIO_printf(bio_s_out, "LOOKUP done %s\n",
                                    srp_callback_parm.user->info);
                     else
@@ -2585,6 +2630,9 @@ static int sv_body(char *hostname, int s, int stype, unsigned char *context)
     }
     if (ret >= 0)
         BIO_printf(bio_s_out, "ACCEPT\n");
+#if defined(OPENSSL_SYS_VMS)            
+        TerminalSocket (TERM_SOCK_DELETE, &stdin_sock);                 
+#endif
     return (ret);
 }
 
@@ -2802,8 +2850,20 @@ static int www_body(char *hostname, int s, int stype, unsigned char *context)
 
 #ifdef FIONBIO
     if (s_nbio) {
-        unsigned long sl = 1;
 
+#    if defined(OPENSSL_SYS_VMS) && defined(__VMS_VER) && (__VMS_VER >= 70000000)               
+        /* For 64-bit --> 32-bit restricted APIs (IOCTL) */             
+#       if __INITIAL_POINTER_SIZE == 64                 
+#           pragma __required_pointer_size __save               
+#           pragma __required_pointer_size 32           
+#   endif               
+        unsigned int sl ;
+#       if __INITIAL_POINTER_SIZE == 64                 
+#           pragma __required_pointer_size __restore            
+#       endif           
+#    else               
+        unsigned long sl=1;             
+#    endif /* OPENSSL_SYS_VMS */
         if (!s_quiet)
             BIO_printf(bio_err, "turning on non blocking io\n");
         if (BIO_socket_ioctl(s, FIONBIO, &sl) < 0)
diff --git a/apps/vms_term_sock.c b/apps/vms_term_sock.c
new file mode 100755 (executable)
index 0000000..33d81cc
--- /dev/null
@@ -0,0 +1,597 @@
+#ifdef __VMS 
+#define OPENSSL_SYS_VMS
+#pragma message disable DOLLARID
+
+
+#include <openssl/OPENSSLCONF.H>
+
+#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
+/*
+ * On VMS, you need to define this to get the declaration of fileno().  The
+ * value 2 is to make sure no function defined in POSIX-2 is left undefined.
+ */
+# define _POSIX_C_SOURCE 2
+#endif
+
+#include <stdio.h>
+
+#undef _POSIX_C_SOURCE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <starlet.h>
+#include <iodef.h>
+#ifdef __alpha
+#include <iosbdef.h>
+#else
+typedef struct _iosb {                 /* Copied from IOSBDEF.H for Alpha  */
+#pragma __nomember_alignment
+    __union  {
+        __struct  {
+            unsigned short int iosb$w_status; /* Final I/O status           */
+            __union  {
+                __struct  {             /* 16-bit byte count variant        */
+                    unsigned short int iosb$w_bcnt; /* 16-bit byte count    */
+                    __union  {
+                        unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */
+                        unsigned int iosb$l_pid; /* 32-bit pid              */
+                        } iosb$r_l;
+                    } iosb$r_bcnt_16;
+                __struct  {             /* 32-bit byte count variant        */
+                    unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */
+                    unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */
+                    } iosb$r_bcnt_32;
+                } iosb$r_devdepend;
+            } iosb$r_io_64;
+        __struct  {
+            __union  {
+                unsigned int iosb$l_getxxi_status; /* Final GETxxI status   */
+                unsigned int iosb$l_reg_status; /* Final $Registry status   */
+                } iosb$r_l_status;
+            unsigned int iosb$l_reserved; /* Reserved field                 */
+            } iosb$r_get_64;
+        } iosb$r_io_get;
+    } IOSB;
+
+#if !defined(__VAXC)
+#define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status
+#define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt
+#define iosb$r_l        iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l
+#define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend
+#define iosb$l_pid iosb$r_l.iosb$l_pid
+#define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt
+#define iosb$w_dev_depend_high iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$w_dev_depend_high
+#define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status
+#define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status
+#endif          /* #if !defined(__VAXC) */
+
+#endif                                 /* End of IOSBDEF */
+
+#include <efndef.h>
+#include <stdlib.h>
+#include <ssdef.h>
+#include <time.h>
+#include <stdarg.h>
+#include <descrip.h>
+
+#include "vms_term_sock.h"
+
+#ifdef __alpha
+static struct _iosb TerminalDeviceIosb;
+#else
+IOSB TerminalDeviceIosb;
+#endif
+
+static char TerminalDeviceBuff[255 + 2];
+static int TerminalSocketPair[2] = {0, 0};
+static unsigned short TerminalDeviceChan = 0;
+
+static int CreateSocketPair (int, int, int, int *);
+static void SocketPairTimeoutAst (int);
+static int TerminalDeviceAst (int);
+static void LogMessage (char *, ...);
+
+/*
+** Socket Pair Timeout Value (must be 0-59 seconds)
+*/
+#define SOCKET_PAIR_TIMEOUT_VALUE 20
+
+/*
+** Socket Pair Timeout Block which is passed to timeout AST
+*/
+typedef struct _SocketPairTimeoutBlock {
+    unsigned short SockChan1;
+    unsigned short SockChan2;
+    } SPTB;
+
+#ifdef TERM_SOCK_TEST
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+int main (int argc, char *argv[], char *envp[])
+{
+char TermBuff[80];
+int TermSock,
+    status,
+    len;
+
+LogMessage ("Enter 'q' or 'Q' to quit ...");
+while (strcasecmp (TermBuff, "Q"))
+    {
+    /*
+    ** Create the terminal socket
+    */
+    status = TerminalSocket (TERM_SOCK_CREATE, &TermSock);
+    if (status != TERM_SOCK_SUCCESS)
+       exit (1);
+
+    /*
+    ** Process the terminal input
+    */
+    LogMessage ("Waiting on terminal I/O ...\n");
+    len = recv (TermSock, TermBuff, sizeof (TermBuff), 0) ;
+    TermBuff[len] = '\0';
+    LogMessage ("Received terminal I/O [%s]", TermBuff);
+
+    /*
+    ** Delete the terminal socket
+    */
+    status = TerminalSocket (TERM_SOCK_DELETE, &TermSock);
+    if (status != TERM_SOCK_SUCCESS)
+       exit (1);
+    }
+
+return 1;
+
+}
+#endif 
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+int TerminalSocket (int FunctionCode, int *ReturnSocket)
+{
+int status;
+$DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND");
+
+/*
+** Process the requested function code
+*/
+switch (FunctionCode)
+   {
+   case TERM_SOCK_CREATE:
+       /*
+       ** Create a socket pair
+       */
+       status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair);
+       if (status == -1)
+           {
+           LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status);
+           if (TerminalSocketPair[0])
+               close (TerminalSocketPair[0]);
+           if (TerminalSocketPair[1])
+               close (TerminalSocketPair[1]);
+           return (TERM_SOCK_FAILURE);
+           }
+
+       /*
+       ** Assign a channel to the terminal device
+       */
+       status = sys$assign (&TerminalDeviceDesc,
+                            &TerminalDeviceChan, 
+                            0, 0, 0);
+       if (! (status & 1))
+           {
+           LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status);
+           close (TerminalSocketPair[0]);
+           close (TerminalSocketPair[1]);
+           return (TERM_SOCK_FAILURE);
+           }
+
+       /*
+       ** Queue an async IO to the terminal device
+       */
+       status = sys$qio (EFN$C_ENF,
+                         TerminalDeviceChan,
+                         IO$_READVBLK,
+                         &TerminalDeviceIosb, 
+                         TerminalDeviceAst, 
+                         0, 
+                         TerminalDeviceBuff,
+                         sizeof (TerminalDeviceBuff) - 2,
+                         0, 0, 0, 0);
+       if (! (status & 1))
+           {
+           LogMessage ("TerminalSocket: SYS$QIO () - %08X", status);
+           close (TerminalSocketPair[0]);
+           close (TerminalSocketPair[1]);
+           return (TERM_SOCK_FAILURE);
+           }
+
+       /*
+       ** Return the input side of the socket pair
+       */
+       *ReturnSocket = TerminalSocketPair[1];
+        break;
+
+   case TERM_SOCK_DELETE:
+       /*
+       ** Cancel any pending IO on the terminal channel
+       */
+       status = sys$cancel (TerminalDeviceChan);
+       if (! (status & 1))
+           {
+           LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status);
+           close (TerminalSocketPair[0]);
+           close (TerminalSocketPair[1]);
+           return (TERM_SOCK_FAILURE);
+           }
+
+       /*
+       ** Deassign the terminal channel
+       */
+       status = sys$dassgn (TerminalDeviceChan);
+       if (! (status & 1))
+           {
+           LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status);
+           close (TerminalSocketPair[0]);
+           close (TerminalSocketPair[1]);
+           return (TERM_SOCK_FAILURE);
+           }
+
+       /*
+       ** Close the terminal socket pair
+       */
+       close (TerminalSocketPair[0]);
+       close (TerminalSocketPair[1]);
+
+       /*
+       ** Return the initialized socket
+       */
+       *ReturnSocket = 0;
+       break;
+
+    default:
+       /*
+       ** Invalid function code
+       */
+       LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode);
+       return (TERM_SOCK_FAILURE);
+       break;
+    }  
+
+/*
+** Return success
+*/
+return (TERM_SOCK_SUCCESS);
+
+}
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+static int CreateSocketPair (
+    int                SocketFamily,
+    int                SocketType,
+    int                SocketProtocol,
+    int                *SocketPair)
+{
+struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
+static const char* LocalHostAddr = {"127.0.0.1"};
+unsigned short TcpAcceptChan = 0,
+              TcpDeviceChan = 0;
+unsigned long BinTimeBuff[2];
+struct sockaddr_in sin;
+char AscTimeBuff[32];
+short LocalHostPort;
+int status; 
+unsigned int slen;
+
+#ifdef __alpha
+struct _iosb iosb;
+#else
+IOSB iosb;
+#endif
+
+int SockDesc1 = 0,
+    SockDesc2 = 0;
+SPTB sptb;
+$DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE");
+
+/*
+** Create a socket
+*/
+SockDesc1 = socket (SocketFamily, SocketType, 0);
+if (SockDesc1 < 0)
+    {
+    LogMessage ("CreateSocketPair: socket () - %d", errno);
+    return (-1);
+    }
+
+/*
+** Initialize the socket information
+*/
+slen = sizeof (sin);
+memset ((char *) &sin, 0, slen);
+sin.sin_family = SocketFamily;
+sin.sin_addr.s_addr = inet_addr (LocalHostAddr);
+sin.sin_port = 0;
+
+/*
+** Bind the socket to the local IP
+*/
+status = bind (SockDesc1, (struct sockaddr *) &sin, slen);
+if (status < 0)
+    {
+    LogMessage ("CreateSocketPair: bind () - %d", errno);
+    close (SockDesc1);   
+    return (-1);
+    }
+
+/*
+** Get the socket name so we can save the port number
+*/
+status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen);
+if (status < 0)
+    {
+    LogMessage ("CreateSocketPair: getsockname () - %d", errno);
+    close (SockDesc1); 
+    return (-1);
+    }
+else
+    LocalHostPort = sin.sin_port;                      
+
+/*
+** Setup a listen for the socket
+*/
+listen (SockDesc1, 5);
+
+/*
+** Get the binary (64-bit) time of the specified timeout value
+*/
+sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE);
+AscTimeDesc.dsc$w_length = strlen (AscTimeBuff);
+AscTimeDesc.dsc$a_pointer = AscTimeBuff;
+status = sys$bintim (&AscTimeDesc, BinTimeBuff);
+if (! (status & 1))
+    {
+    LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status);
+    close (SockDesc1);
+    return (-1);
+    }
+
+/*
+** Assign another channel to the TCP/IP device for the accept.
+** This is the channel that ends up being connected to.
+*/
+status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0);
+if (! (status & 1))
+    {
+    LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status);
+    close (SockDesc1);
+    return (-1);
+    }
+
+/*
+** Get the channel of the first socket for the accept
+*/
+TcpAcceptChan = decc$get_sdc (SockDesc1);              
+
+/*
+** Perform the accept using $QIO so we can do this asynchronously
+*/
+status = sys$qio (EFN$C_ENF, 
+                 TcpAcceptChan,
+                  IO$_ACCESS | IO$M_ACCEPT,
+                  &iosb,
+                 0, 0, 0, 0, 0,
+                  &TcpDeviceChan,
+                  0, 0);
+if (! (status & 1))
+    {
+    LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status);
+    close (SockDesc1);
+    sys$dassgn (TcpDeviceChan);
+    return (-1);
+    }
+
+/*
+** Create the second socket to do the connect
+*/
+SockDesc2 = socket (SocketFamily, SocketType, 0);
+if (SockDesc2 < 0)
+    {
+    LogMessage ("CreateSocketPair: socket () - %d", errno);
+    sys$cancel (TcpAcceptChan);
+    close (SockDesc1);
+    sys$dassgn (TcpDeviceChan);
+    return (-1) ;
+    } 
+
+/*
+** Setup the Socket Pair Timeout Block
+*/
+sptb.SockChan1 = TcpAcceptChan;
+sptb.SockChan2 = decc$get_sdc (SockDesc2);
+
+/*
+** Before we block on the connect, set a timer that can cancel I/O on our two 
+** sockets if it never connects.
+*/
+status = sys$setimr (EFN$C_ENF, 
+                    BinTimeBuff, 
+                    SocketPairTimeoutAst, 
+                    &sptb, 
+                    0);
+if (! (status & 1))
+    {
+    LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status);
+    sys$cancel (TcpAcceptChan);
+    close (SockDesc1);
+    close (SockDesc2);
+    sys$dassgn (TcpDeviceChan);
+    return (-1);
+    }
+
+/*
+** Now issue the connect
+*/
+memset ((char *) &sin, 0, sizeof (sin)) ;
+sin.sin_family = SocketFamily;
+sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ;
+sin.sin_port = LocalHostPort ;
+
+status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof (sin));
+if (status < 0 )
+    {
+    LogMessage ("CreateSocketPair: connect () - %d", errno);
+    sys$cantim (&sptb, 0);
+    sys$cancel (TcpAcceptChan);
+    close (SockDesc1);
+    close (SockDesc2);
+    sys$dassgn (TcpDeviceChan);
+    return (-1);
+    }
+
+/*
+** Wait for the asynch $QIO to finish.  Note that if the I/O was aborted 
+** (SS$_ABORT), then we probably canceled it from the AST routine - so log a 
+** timeout.
+*/
+status = sys$synch (EFN$C_ENF, &iosb);
+if (! (iosb.iosb$w_status & 1))
+    {
+    if (iosb.iosb$w_status == SS$_ABORT)
+       LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout");
+    else 
+       {
+        LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d", iosb.iosb$w_status);
+        sys$cantim (&sptb, 0);
+        }
+    close (SockDesc1);
+    close (SockDesc2);
+    sys$dassgn (TcpDeviceChan);
+    return (-1);
+    }
+
+/*
+** Here we're successfully connected, so cancel the timer, convert the I/O 
+** channel to a socket fd, close the listener socket and return the connected 
+** pair.
+*/
+sys$cantim (&sptb, 0);
+
+close (SockDesc1) ;
+SocketPair[0] = SockDesc2 ;
+SocketPair[1] = socket_fd (TcpDeviceChan);
+
+return (0) ;
+
+}
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+static void SocketPairTimeoutAst (int astparm)
+{
+SPTB *sptb = (SPTB *) astparm;
+
+sys$cancel (sptb->SockChan2);                  /* Cancel the connect() */
+sys$cancel (sptb->SockChan1);                  /* Cancel the accept()  */
+
+return;
+
+}
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+static int TerminalDeviceAst (int astparm)
+{
+int status;
+
+/*
+** Terminate the terminal buffer
+*/
+TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0';
+strcat (TerminalDeviceBuff, "\n");
+
+/*
+** Send the data read from the terminal device throught the socket pair
+*/
+send (TerminalSocketPair[0], TerminalDeviceBuff, TerminalDeviceIosb.iosb$w_bcnt + 1, 0);
+
+/*
+** Queue another async IO to the terminal device
+*/
+status = sys$qio (EFN$C_ENF,
+                 TerminalDeviceChan,
+                 IO$_READVBLK,
+                 &TerminalDeviceIosb, 
+                 TerminalDeviceAst, 
+                 0, 
+                 TerminalDeviceBuff,
+                 sizeof (TerminalDeviceBuff) - 1,
+                 0, 0, 0, 0);
+
+/*
+** Return status
+*/
+return status;
+
+}
+\f
+/*----------------------------------------------------------------------------*/
+/*                                                                            */
+/*----------------------------------------------------------------------------*/
+static void LogMessage (char *msg, ...)
+{
+char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
+                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+static unsigned int pid = 0;
+va_list args;
+time_t CurTime;
+struct tm *LocTime;
+char MsgBuff[256];
+
+/*
+** Get the process pid
+*/
+if (pid == 0)
+    pid = getpid ();
+
+/*
+** Convert the current time into local time
+*/
+CurTime = time (NULL);
+LocTime = localtime (&CurTime);
+
+/*
+** Format the message buffer
+*/
+sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n",
+         LocTime->tm_mday, Month[LocTime->tm_mon], (LocTime->tm_year + 1900),
+         LocTime->tm_hour, LocTime->tm_min, LocTime->tm_sec, pid, msg);
+
+/*
+** Get any variable arguments and add them to the print of the message buffer 
+*/
+va_start (args, msg);
+vfprintf (stderr, MsgBuff, args);
+va_end (args);
+
+/*
+** Flush standard error output
+*/
+fsync (fileno (stderr));
+
+return;
+
+}
+#endif
diff --git a/apps/vms_term_sock.h b/apps/vms_term_sock.h
new file mode 100755 (executable)
index 0000000..4b445a9
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef TERM_SOCK_H
+#define TERM_SOCK_H
+
+/*
+** Terminal Socket Function Codes
+*/
+#define TERM_SOCK_CREATE       1
+#define TERM_SOCK_DELETE       2
+
+/*
+** Terminal Socket Status Codes
+*/
+#define TERM_SOCK_FAILURE      0
+#define TERM_SOCK_SUCCESS      1
+
+/*
+** Terminal Socket Prototype
+*/
+int TerminalSocket (int FunctionCode, int *ReturnSocket);
+
+#endif