Path: blob/main/crypto/openssl/apps/lib/vms_term_sock.c
34869 views
/*1* Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.2* Copyright 2016 VMS Software, Inc. All Rights Reserved.3*4* Licensed under the Apache License 2.0 (the "License"). You may not use5* this file except in compliance with the License. You can obtain a copy6* in the file LICENSE in the source distribution or at7* https://www.openssl.org/source/license.html8*/910#ifdef __VMS11# define OPENSSL_SYS_VMS12# pragma message disable DOLLARID131415# include <openssl/opensslconf.h>1617# if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)18/*19* On VMS, you need to define this to get the declaration of fileno(). The20* value 2 is to make sure no function defined in POSIX-2 is left undefined.21*/22# define _POSIX_C_SOURCE 223# endif2425# include <stdio.h>2627# undef _POSIX_C_SOURCE2829# include <sys/types.h>30# include <sys/socket.h>31# include <netinet/in.h>32# include <inet.h>33# include <unistd.h>34# include <string.h>35# include <errno.h>36# include <starlet.h>37# include <iodef.h>38# ifdef __alpha39# include <iosbdef.h>40# else41typedef struct _iosb { /* Copied from IOSBDEF.H for Alpha */42# pragma __nomember_alignment43__union {44__struct {45unsigned short int iosb$w_status; /* Final I/O status */46__union {47__struct { /* 16-bit byte count variant */48unsigned short int iosb$w_bcnt; /* 16-bit byte count */49__union {50unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */51unsigned int iosb$l_pid; /* 32-bit pid */52} iosb$r_l;53} iosb$r_bcnt_16;54__struct { /* 32-bit byte count variant */55unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */56unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */57} iosb$r_bcnt_32;58} iosb$r_devdepend;59} iosb$r_io_64;60__struct {61__union {62unsigned int iosb$l_getxxi_status; /* Final GETxxI status */63unsigned int iosb$l_reg_status; /* Final $Registry status */64} iosb$r_l_status;65unsigned int iosb$l_reserved; /* Reserved field */66} iosb$r_get_64;67} iosb$r_io_get;68} IOSB;6970# if !defined(__VAXC)71# define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status72# define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt73# define iosb$r_l iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l74# define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend75# define iosb$l_pid iosb$r_l.iosb$l_pid76# define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt77# 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_high78# define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status79# define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status80# endif /* #if !defined(__VAXC) */8182# endif /* End of IOSBDEF */8384# include <efndef.h>85# include <stdlib.h>86# include <ssdef.h>87# include <time.h>88# include <stdarg.h>89# include <descrip.h>9091# include "vms_term_sock.h"9293# ifdef __alpha94static struct _iosb TerminalDeviceIosb;95# else96IOSB TerminalDeviceIosb;97# endif9899static char TerminalDeviceBuff[255 + 2];100static int TerminalSocketPair[2] = {0, 0};101static unsigned short TerminalDeviceChan = 0;102103static int CreateSocketPair (int, int, int, int *);104static void SocketPairTimeoutAst (int);105static int TerminalDeviceAst (int);106static void LogMessage (char *, ...);107108/*109** Socket Pair Timeout Value (must be 0-59 seconds)110*/111# define SOCKET_PAIR_TIMEOUT_VALUE 20112113/*114** Socket Pair Timeout Block which is passed to timeout AST115*/116typedef struct _SocketPairTimeoutBlock {117unsigned short SockChan1;118unsigned short SockChan2;119} SPTB;120121# ifdef TERM_SOCK_TEST122123/*----------------------------------------------------------------------------*/124/* */125/*----------------------------------------------------------------------------*/126int main (int argc, char *argv[], char *envp[])127{128char TermBuff[80];129int TermSock,130status,131len;132133LogMessage ("Enter 'q' or 'Q' to quit ...");134while (OPENSSL_strcasecmp (TermBuff, "Q")) {135/*136** Create the terminal socket137*/138status = TerminalSocket (TERM_SOCK_CREATE, &TermSock);139if (status != TERM_SOCK_SUCCESS)140exit (1);141142/*143** Process the terminal input144*/145LogMessage ("Waiting on terminal I/O ...\n");146len = recv (TermSock, TermBuff, sizeof(TermBuff), 0) ;147TermBuff[len] = '\0';148LogMessage ("Received terminal I/O [%s]", TermBuff);149150/*151** Delete the terminal socket152*/153status = TerminalSocket (TERM_SOCK_DELETE, &TermSock);154if (status != TERM_SOCK_SUCCESS)155exit (1);156}157158return 1;159160}161# endif162163/*----------------------------------------------------------------------------*/164/* */165/*----------------------------------------------------------------------------*/166int TerminalSocket (int FunctionCode, int *ReturnSocket)167{168int status;169$DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND");170171/*172** Process the requested function code173*/174switch (FunctionCode) {175case TERM_SOCK_CREATE:176/*177** Create a socket pair178*/179status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair);180if (status == -1) {181LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status);182if (TerminalSocketPair[0])183close (TerminalSocketPair[0]);184if (TerminalSocketPair[1])185close (TerminalSocketPair[1]);186return TERM_SOCK_FAILURE;187}188189/*190** Assign a channel to the terminal device191*/192status = sys$assign (&TerminalDeviceDesc,193&TerminalDeviceChan,1940, 0, 0);195if (! (status & 1)) {196LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status);197close (TerminalSocketPair[0]);198close (TerminalSocketPair[1]);199return TERM_SOCK_FAILURE;200}201202/*203** Queue an async IO to the terminal device204*/205status = sys$qio (EFN$C_ENF,206TerminalDeviceChan,207IO$_READVBLK,208&TerminalDeviceIosb,209TerminalDeviceAst,2100,211TerminalDeviceBuff,212sizeof(TerminalDeviceBuff) - 2,2130, 0, 0, 0);214if (! (status & 1)) {215LogMessage ("TerminalSocket: SYS$QIO () - %08X", status);216close (TerminalSocketPair[0]);217close (TerminalSocketPair[1]);218return TERM_SOCK_FAILURE;219}220221/*222** Return the input side of the socket pair223*/224*ReturnSocket = TerminalSocketPair[1];225break;226227case TERM_SOCK_DELETE:228/*229** Cancel any pending IO on the terminal channel230*/231status = sys$cancel (TerminalDeviceChan);232if (! (status & 1)) {233LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status);234close (TerminalSocketPair[0]);235close (TerminalSocketPair[1]);236return TERM_SOCK_FAILURE;237}238239/*240** Deassign the terminal channel241*/242status = sys$dassgn (TerminalDeviceChan);243if (! (status & 1)) {244LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status);245close (TerminalSocketPair[0]);246close (TerminalSocketPair[1]);247return TERM_SOCK_FAILURE;248}249250/*251** Close the terminal socket pair252*/253close (TerminalSocketPair[0]);254close (TerminalSocketPair[1]);255256/*257** Return the initialized socket258*/259*ReturnSocket = 0;260break;261262default:263/*264** Invalid function code265*/266LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode);267return TERM_SOCK_FAILURE;268break;269}270271/*272** Return success273*/274return TERM_SOCK_SUCCESS;275276}277278/*----------------------------------------------------------------------------*/279/* */280/*----------------------------------------------------------------------------*/281static int CreateSocketPair (int SocketFamily,282int SocketType,283int SocketProtocol,284int *SocketPair)285{286struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};287static const char* LocalHostAddr = {"127.0.0.1"};288unsigned short TcpAcceptChan = 0,289TcpDeviceChan = 0;290unsigned long BinTimeBuff[2];291struct sockaddr_in sin;292char AscTimeBuff[32];293short LocalHostPort;294int status;295unsigned int slen;296297# ifdef __alpha298struct _iosb iosb;299# else300IOSB iosb;301# endif302303int SockDesc1 = 0,304SockDesc2 = 0;305SPTB sptb;306$DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE");307308/*309** Create a socket310*/311SockDesc1 = socket (SocketFamily, SocketType, 0);312if (SockDesc1 < 0) {313LogMessage ("CreateSocketPair: socket () - %d", errno);314return -1;315}316317/*318** Initialize the socket information319*/320slen = sizeof(sin);321memset ((char *) &sin, 0, slen);322sin.sin_family = SocketFamily;323sin.sin_addr.s_addr = inet_addr (LocalHostAddr);324sin.sin_port = 0;325326/*327** Bind the socket to the local IP328*/329status = bind (SockDesc1, (struct sockaddr *) &sin, slen);330if (status < 0) {331LogMessage ("CreateSocketPair: bind () - %d", errno);332close (SockDesc1);333return -1;334}335336/*337** Get the socket name so we can save the port number338*/339status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen);340if (status < 0) {341LogMessage ("CreateSocketPair: getsockname () - %d", errno);342close (SockDesc1);343return -1;344} else345LocalHostPort = sin.sin_port;346347/*348** Setup a listen for the socket349*/350listen (SockDesc1, 5);351352/*353** Get the binary (64-bit) time of the specified timeout value354*/355BIO_snprintf(AscTimeBuff, sizeof(AscTimeBuff), "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE);356AscTimeDesc.dsc$w_length = strlen (AscTimeBuff);357AscTimeDesc.dsc$a_pointer = AscTimeBuff;358status = sys$bintim (&AscTimeDesc, BinTimeBuff);359if (! (status & 1)) {360LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status);361close (SockDesc1);362return -1;363}364365/*366** Assign another channel to the TCP/IP device for the accept.367** This is the channel that ends up being connected to.368*/369status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0);370if (! (status & 1)) {371LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status);372close (SockDesc1);373return -1;374}375376/*377** Get the channel of the first socket for the accept378*/379TcpAcceptChan = decc$get_sdc (SockDesc1);380381/*382** Perform the accept using $QIO so we can do this asynchronously383*/384status = sys$qio (EFN$C_ENF,385TcpAcceptChan,386IO$_ACCESS | IO$M_ACCEPT,387&iosb,3880, 0, 0, 0, 0,389&TcpDeviceChan,3900, 0);391if (! (status & 1)) {392LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status);393close (SockDesc1);394sys$dassgn (TcpDeviceChan);395return -1;396}397398/*399** Create the second socket to do the connect400*/401SockDesc2 = socket (SocketFamily, SocketType, 0);402if (SockDesc2 < 0) {403LogMessage ("CreateSocketPair: socket () - %d", errno);404sys$cancel (TcpAcceptChan);405close (SockDesc1);406sys$dassgn (TcpDeviceChan);407return (-1) ;408}409410/*411** Setup the Socket Pair Timeout Block412*/413sptb.SockChan1 = TcpAcceptChan;414sptb.SockChan2 = decc$get_sdc (SockDesc2);415416/*417** Before we block on the connect, set a timer that can cancel I/O on our418** two sockets if it never connects.419*/420status = sys$setimr (EFN$C_ENF,421BinTimeBuff,422SocketPairTimeoutAst,423&sptb,4240);425if (! (status & 1)) {426LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status);427sys$cancel (TcpAcceptChan);428close (SockDesc1);429close (SockDesc2);430sys$dassgn (TcpDeviceChan);431return -1;432}433434/*435** Now issue the connect436*/437memset ((char *) &sin, 0, sizeof(sin)) ;438sin.sin_family = SocketFamily;439sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ;440sin.sin_port = LocalHostPort ;441442status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof(sin));443if (status < 0) {444LogMessage ("CreateSocketPair: connect () - %d", errno);445sys$cantim (&sptb, 0);446sys$cancel (TcpAcceptChan);447close (SockDesc1);448close (SockDesc2);449sys$dassgn (TcpDeviceChan);450return -1;451}452453/*454** Wait for the asynch $QIO to finish. Note that if the I/O was aborted455** (SS$_ABORT), then we probably canceled it from the AST routine - so log456** a timeout.457*/458status = sys$synch (EFN$C_ENF, &iosb);459if (! (iosb.iosb$w_status & 1)) {460if (iosb.iosb$w_status == SS$_ABORT)461LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout");462else {463LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d",464iosb.iosb$w_status);465sys$cantim (&sptb, 0);466}467close (SockDesc1);468close (SockDesc2);469sys$dassgn (TcpDeviceChan);470return -1;471}472473/*474** Here we're successfully connected, so cancel the timer, convert the475** I/O channel to a socket fd, close the listener socket and return the476** connected pair.477*/478sys$cantim (&sptb, 0);479480close (SockDesc1) ;481SocketPair[0] = SockDesc2 ;482SocketPair[1] = socket_fd (TcpDeviceChan);483484return (0) ;485486}487488/*----------------------------------------------------------------------------*/489/* */490/*----------------------------------------------------------------------------*/491static void SocketPairTimeoutAst (int astparm)492{493SPTB *sptb = (SPTB *) astparm;494495sys$cancel (sptb->SockChan2); /* Cancel the connect() */496sys$cancel (sptb->SockChan1); /* Cancel the accept() */497498return;499500}501502/*----------------------------------------------------------------------------*/503/* */504/*----------------------------------------------------------------------------*/505static int TerminalDeviceAst (int astparm)506{507int status;508509/*510** Terminate the terminal buffer511*/512TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0';513strcat (TerminalDeviceBuff, "\n");514515/*516** Send the data read from the terminal device through the socket pair517*/518send (TerminalSocketPair[0], TerminalDeviceBuff,519TerminalDeviceIosb.iosb$w_bcnt + 1, 0);520521/*522** Queue another async IO to the terminal device523*/524status = sys$qio (EFN$C_ENF,525TerminalDeviceChan,526IO$_READVBLK,527&TerminalDeviceIosb,528TerminalDeviceAst,5290,530TerminalDeviceBuff,531sizeof(TerminalDeviceBuff) - 1,5320, 0, 0, 0);533534/*535** Return status536*/537return status;538539}540541/*----------------------------------------------------------------------------*/542/* */543/*----------------------------------------------------------------------------*/544static void LogMessage (char *msg, ...)545{546char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",547"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};548static unsigned int pid = 0;549va_list args;550time_t CurTime;551struct tm *LocTime;552char MsgBuff[256];553554/*555** Get the process pid556*/557if (pid == 0)558pid = getpid ();559560/*561** Convert the current time into local time562*/563CurTime = time (NULL);564LocTime = localtime (&CurTime);565566/*567** Format the message buffer568*/569BIO_snprintf(MsgBuff, sizeof(MsgBuff), "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n",570LocTime->tm_mday, Month[LocTime->tm_mon],571(LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min,572LocTime->tm_sec, pid, msg);573574/*575** Get any variable arguments and add them to the print of the message576** buffer577*/578va_start (args, msg);579vfprintf (stderr, MsgBuff, args);580va_end (args);581582/*583** Flush standard error output584*/585fsync (fileno (stderr));586587return;588589}590#endif591592593