2 * Copyright 2016 VMS Software, Inc. All Rights Reserved.
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
11 # define OPENSSL_SYS_VMS
12 # pragma message disable DOLLARID
15 # include <openssl/opensslconf.h>
17 # if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
19 * On VMS, you need to define this to get the declaration of fileno(). The
20 * value 2 is to make sure no function defined in POSIX-2 is left undefined.
22 # define _POSIX_C_SOURCE 2
27 # undef _POSIX_C_SOURCE
29 # include <sys/types.h>
30 # include <sys/socket.h>
31 # include <netinet/in.h>
41 typedef struct _iosb
{ /* Copied from IOSBDEF.H for Alpha */
42 # pragma __nomember_alignment
45 unsigned short int iosb$w_status
; /* Final I/O status */
47 __struct
{ /* 16-bit byte count variant */
48 unsigned short int iosb$w_bcnt
; /* 16-bit byte count */
50 unsigned int iosb$l_dev_depend
; /* 32-bit device dependent info */
51 unsigned int iosb$l_pid
; /* 32-bit pid */
54 __struct
{ /* 32-bit byte count variant */
55 unsigned int iosb$l_bcnt
; /* 32-bit byte count (unaligned) */
56 unsigned short int iosb$w_dev_depend_high
; /* 16-bit device dependent info */
62 unsigned int iosb$l_getxxi_status
; /* Final GETxxI status */
63 unsigned int iosb$l_reg_status
; /* Final $Registry status */
65 unsigned int iosb$l_reserved
; /* Reserved field */
71 # define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status
72 # define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt
73 # define iosb$r_l iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l
74 # define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend
75 # define iosb$l_pid iosb$r_l.iosb$l_pid
76 # define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt
77 # 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
78 # define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status
79 # define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status
80 # endif /* #if !defined(__VAXC) */
82 # endif /* End of IOSBDEF */
91 # include "vms_term_sock.h"
94 static struct _iosb TerminalDeviceIosb
;
96 IOSB TerminalDeviceIosb
;
99 static char TerminalDeviceBuff
[255 + 2];
100 static int TerminalSocketPair
[2] = {0, 0};
101 static unsigned short TerminalDeviceChan
= 0;
103 static int CreateSocketPair (int, int, int, int *);
104 static void SocketPairTimeoutAst (int);
105 static int TerminalDeviceAst (int);
106 static void LogMessage (char *, ...);
109 ** Socket Pair Timeout Value (must be 0-59 seconds)
111 # define SOCKET_PAIR_TIMEOUT_VALUE 20
114 ** Socket Pair Timeout Block which is passed to timeout AST
116 typedef struct _SocketPairTimeoutBlock
{
117 unsigned short SockChan1
;
118 unsigned short SockChan2
;
121 # ifdef TERM_SOCK_TEST
123 /*----------------------------------------------------------------------------*/
125 /*----------------------------------------------------------------------------*/
126 int main (int argc
, char *argv
[], char *envp
[])
133 LogMessage ("Enter 'q' or 'Q' to quit ...");
134 while (strcasecmp (TermBuff
, "Q")) {
136 ** Create the terminal socket
138 status
= TerminalSocket (TERM_SOCK_CREATE
, &TermSock
);
139 if (status
!= TERM_SOCK_SUCCESS
)
143 ** Process the terminal input
145 LogMessage ("Waiting on terminal I/O ...\n");
146 len
= recv (TermSock
, TermBuff
, sizeof (TermBuff
), 0) ;
147 TermBuff
[len
] = '\0';
148 LogMessage ("Received terminal I/O [%s]", TermBuff
);
151 ** Delete the terminal socket
153 status
= TerminalSocket (TERM_SOCK_DELETE
, &TermSock
);
154 if (status
!= TERM_SOCK_SUCCESS
)
163 /*----------------------------------------------------------------------------*/
165 /*----------------------------------------------------------------------------*/
166 int TerminalSocket (int FunctionCode
, int *ReturnSocket
)
169 $
DESCRIPTOR (TerminalDeviceDesc
, "SYS$COMMAND");
172 ** Process the requested function code
174 switch (FunctionCode
) {
175 case TERM_SOCK_CREATE
:
177 ** Create a socket pair
179 status
= CreateSocketPair (AF_INET
, SOCK_STREAM
, 0, TerminalSocketPair
);
181 LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status
);
182 if (TerminalSocketPair
[0])
183 close (TerminalSocketPair
[0]);
184 if (TerminalSocketPair
[1])
185 close (TerminalSocketPair
[1]);
186 return (TERM_SOCK_FAILURE
);
190 ** Assign a channel to the terminal device
192 status
= sys$
assign (&TerminalDeviceDesc
,
195 if (! (status
& 1)) {
196 LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status
);
197 close (TerminalSocketPair
[0]);
198 close (TerminalSocketPair
[1]);
199 return (TERM_SOCK_FAILURE
);
203 ** Queue an async IO to the terminal device
205 status
= sys$
qio (EFN$C_ENF
,
212 sizeof (TerminalDeviceBuff
) - 2,
214 if (! (status
& 1)) {
215 LogMessage ("TerminalSocket: SYS$QIO () - %08X", status
);
216 close (TerminalSocketPair
[0]);
217 close (TerminalSocketPair
[1]);
218 return (TERM_SOCK_FAILURE
);
222 ** Return the input side of the socket pair
224 *ReturnSocket
= TerminalSocketPair
[1];
227 case TERM_SOCK_DELETE
:
229 ** Cancel any pending IO on the terminal channel
231 status
= sys$
cancel (TerminalDeviceChan
);
232 if (! (status
& 1)) {
233 LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status
);
234 close (TerminalSocketPair
[0]);
235 close (TerminalSocketPair
[1]);
236 return (TERM_SOCK_FAILURE
);
240 ** Deassign the terminal channel
242 status
= sys$
dassgn (TerminalDeviceChan
);
243 if (! (status
& 1)) {
244 LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status
);
245 close (TerminalSocketPair
[0]);
246 close (TerminalSocketPair
[1]);
247 return (TERM_SOCK_FAILURE
);
251 ** Close the terminal socket pair
253 close (TerminalSocketPair
[0]);
254 close (TerminalSocketPair
[1]);
257 ** Return the initialized socket
264 ** Invalid function code
266 LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode
);
267 return (TERM_SOCK_FAILURE
);
274 return (TERM_SOCK_SUCCESS
);
278 /*----------------------------------------------------------------------------*/
280 /*----------------------------------------------------------------------------*/
281 static int CreateSocketPair (int SocketFamily
,
286 struct dsc$descriptor AscTimeDesc
= {0, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, NULL
};
287 static const char* LocalHostAddr
= {"127.0.0.1"};
288 unsigned short TcpAcceptChan
= 0,
290 unsigned long BinTimeBuff
[2];
291 struct sockaddr_in sin
;
292 char AscTimeBuff
[32];
306 $
DESCRIPTOR (TcpDeviceDesc
, "TCPIP$DEVICE");
311 SockDesc1
= socket (SocketFamily
, SocketType
, 0);
313 LogMessage ("CreateSocketPair: socket () - %d", errno
);
318 ** Initialize the socket information
321 memset ((char *) &sin
, 0, slen
);
322 sin
.sin_family
= SocketFamily
;
323 sin
.sin_addr
.s_addr
= inet_addr (LocalHostAddr
);
327 ** Bind the socket to the local IP
329 status
= bind (SockDesc1
, (struct sockaddr
*) &sin
, slen
);
331 LogMessage ("CreateSocketPair: bind () - %d", errno
);
337 ** Get the socket name so we can save the port number
339 status
= getsockname (SockDesc1
, (struct sockaddr
*) &sin
, &slen
);
341 LogMessage ("CreateSocketPair: getsockname () - %d", errno
);
345 LocalHostPort
= sin
.sin_port
;
348 ** Setup a listen for the socket
350 listen (SockDesc1
, 5);
353 ** Get the binary (64-bit) time of the specified timeout value
355 sprintf (AscTimeBuff
, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE
);
356 AscTimeDesc
.dsc$w_length
= strlen (AscTimeBuff
);
357 AscTimeDesc
.dsc$a_pointer
= AscTimeBuff
;
358 status
= sys$
bintim (&AscTimeDesc
, BinTimeBuff
);
359 if (! (status
& 1)) {
360 LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status
);
366 ** Assign another channel to the TCP/IP device for the accept.
367 ** This is the channel that ends up being connected to.
369 status
= sys$
assign (&TcpDeviceDesc
, &TcpDeviceChan
, 0, 0, 0);
370 if (! (status
& 1)) {
371 LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status
);
377 ** Get the channel of the first socket for the accept
379 TcpAcceptChan
= decc$
get_sdc (SockDesc1
);
382 ** Perform the accept using $QIO so we can do this asynchronously
384 status
= sys$
qio (EFN$C_ENF
,
386 IO$_ACCESS
| IO$M_ACCEPT
,
391 if (! (status
& 1)) {
392 LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status
);
394 sys$
dassgn (TcpDeviceChan
);
399 ** Create the second socket to do the connect
401 SockDesc2
= socket (SocketFamily
, SocketType
, 0);
403 LogMessage ("CreateSocketPair: socket () - %d", errno
);
404 sys$
cancel (TcpAcceptChan
);
406 sys$
dassgn (TcpDeviceChan
);
411 ** Setup the Socket Pair Timeout Block
413 sptb
.SockChan1
= TcpAcceptChan
;
414 sptb
.SockChan2
= decc$
get_sdc (SockDesc2
);
417 ** Before we block on the connect, set a timer that can cancel I/O on our
418 ** two sockets if it never connects.
420 status
= sys$
setimr (EFN$C_ENF
,
422 SocketPairTimeoutAst
,
425 if (! (status
& 1)) {
426 LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status
);
427 sys$
cancel (TcpAcceptChan
);
430 sys$
dassgn (TcpDeviceChan
);
435 ** Now issue the connect
437 memset ((char *) &sin
, 0, sizeof (sin
)) ;
438 sin
.sin_family
= SocketFamily
;
439 sin
.sin_addr
.s_addr
= inet_addr (LocalHostAddr
) ;
440 sin
.sin_port
= LocalHostPort
;
442 status
= connect (SockDesc2
, (struct sockaddr
*) &sin
, sizeof (sin
));
444 LogMessage ("CreateSocketPair: connect () - %d", errno
);
445 sys$
cantim (&sptb
, 0);
446 sys$
cancel (TcpAcceptChan
);
449 sys$
dassgn (TcpDeviceChan
);
454 ** Wait for the asynch $QIO to finish. Note that if the I/O was aborted
455 ** (SS$_ABORT), then we probably canceled it from the AST routine - so log
458 status
= sys$
synch (EFN$C_ENF
, &iosb
);
459 if (! (iosb
.iosb$w_status
& 1)) {
460 if (iosb
.iosb$w_status
== SS$_ABORT
)
461 LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout");
463 LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d",
465 sys$
cantim (&sptb
, 0);
469 sys$
dassgn (TcpDeviceChan
);
474 ** Here we're successfully connected, so cancel the timer, convert the
475 ** I/O channel to a socket fd, close the listener socket and return the
478 sys$
cantim (&sptb
, 0);
481 SocketPair
[0] = SockDesc2
;
482 SocketPair
[1] = socket_fd (TcpDeviceChan
);
488 /*----------------------------------------------------------------------------*/
490 /*----------------------------------------------------------------------------*/
491 static void SocketPairTimeoutAst (int astparm
)
493 SPTB
*sptb
= (SPTB
*) astparm
;
495 sys$
cancel (sptb
->SockChan2
); /* Cancel the connect() */
496 sys$
cancel (sptb
->SockChan1
); /* Cancel the accept() */
502 /*----------------------------------------------------------------------------*/
504 /*----------------------------------------------------------------------------*/
505 static int TerminalDeviceAst (int astparm
)
510 ** Terminate the terminal buffer
512 TerminalDeviceBuff
[TerminalDeviceIosb
.iosb$w_bcnt
] = '\0';
513 strcat (TerminalDeviceBuff
, "\n");
516 ** Send the data read from the terminal device throught the socket pair
518 send (TerminalSocketPair
[0], TerminalDeviceBuff
,
519 TerminalDeviceIosb
.iosb$w_bcnt
+ 1, 0);
522 ** Queue another async IO to the terminal device
524 status
= sys$
qio (EFN$C_ENF
,
531 sizeof (TerminalDeviceBuff
) - 1,
541 /*----------------------------------------------------------------------------*/
543 /*----------------------------------------------------------------------------*/
544 static void LogMessage (char *msg
, ...)
546 char *Month
[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
547 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
548 static unsigned int pid
= 0;
555 ** Get the process pid
561 ** Convert the current time into local time
563 CurTime
= time (NULL
);
564 LocTime
= localtime (&CurTime
);
567 ** Format the message buffer
569 sprintf (MsgBuff
, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n",
570 LocTime
->tm_mday
, Month
[LocTime
->tm_mon
],
571 (LocTime
->tm_year
+ 1900), LocTime
->tm_hour
, LocTime
->tm_min
,
572 LocTime
->tm_sec
, pid
, msg
);
575 ** Get any variable arguments and add them to the print of the message
578 va_start (args
, msg
);
579 vfprintf (stderr
, MsgBuff
, args
);
583 ** Flush standard error output
585 fsync (fileno (stderr
));