123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- /*
- * Copyright 2016 VMS Software, Inc. All Rights Reserved.
- *
- * Licensed under the OpenSSL license (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- #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
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- 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
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- 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);
- }
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- 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) ;
- }
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- static void SocketPairTimeoutAst (int astparm)
- {
- SPTB *sptb = (SPTB *) astparm;
- sys$cancel (sptb->SockChan2); /* Cancel the connect() */
- sys$cancel (sptb->SockChan1); /* Cancel the accept() */
- return;
- }
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- 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;
- }
- /*----------------------------------------------------------------------------*/
- /* */
- /*----------------------------------------------------------------------------*/
- 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
|