Print <ABSENT> if a STACK is NULL.
[openssl.git] / apps / vms_term_sock.c
1 /*
2  * Copyright 2016 VMS Software, Inc. All Rights Reserved.
3  *
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
8  */
9
10 #ifdef __VMS
11 # define OPENSSL_SYS_VMS
12 # pragma message disable DOLLARID
13
14
15 # include <openssl/opensslconf.h>
16
17 # if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
18 /*
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.
21  */
22 #  define _POSIX_C_SOURCE 2
23 # endif
24
25 # include <stdio.h>
26
27 # undef _POSIX_C_SOURCE
28
29 # 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 __alpha
39 #  include <iosbdef.h>
40 # else
41 typedef struct _iosb {           /* Copied from IOSBDEF.H for Alpha  */
42 #  pragma __nomember_alignment
43     __union  {
44         __struct  {
45             unsigned short int iosb$w_status; /* Final I/O status           */
46             __union  {
47                 __struct  {             /* 16-bit byte count variant        */
48                     unsigned short int iosb$w_bcnt; /* 16-bit byte count    */
49                     __union  {
50                         unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */
51                         unsigned int iosb$l_pid; /* 32-bit pid              */
52                     } iosb$r_l;
53                 } iosb$r_bcnt_16;
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 */
57                 } iosb$r_bcnt_32;
58             } iosb$r_devdepend;
59         } iosb$r_io_64;
60         __struct  {
61             __union  {
62                 unsigned int iosb$l_getxxi_status; /* Final GETxxI status   */
63                 unsigned int iosb$l_reg_status; /* Final $Registry status   */
64             } iosb$r_l_status;
65             unsigned int iosb$l_reserved; /* Reserved field                 */
66         } iosb$r_get_64;
67     } iosb$r_io_get;
68 } IOSB;
69
70 #  if !defined(__VAXC)
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) */
81
82 # endif  /* End of IOSBDEF */
83
84 # include <efndef.h>
85 # include <stdlib.h>
86 # include <ssdef.h>
87 # include <time.h>
88 # include <stdarg.h>
89 # include <descrip.h>
90
91 # include "vms_term_sock.h"
92
93 # ifdef __alpha
94 static struct _iosb TerminalDeviceIosb;
95 # else
96 IOSB TerminalDeviceIosb;
97 # endif
98
99 static char TerminalDeviceBuff[255 + 2];
100 static int TerminalSocketPair[2] = {0, 0};
101 static unsigned short TerminalDeviceChan = 0;
102
103 static int CreateSocketPair (int, int, int, int *);
104 static void SocketPairTimeoutAst (int);
105 static int TerminalDeviceAst (int);
106 static void LogMessage (char *, ...);
107
108 /*
109 ** Socket Pair Timeout Value (must be 0-59 seconds)
110 */
111 # define SOCKET_PAIR_TIMEOUT_VALUE 20
112
113 /*
114 ** Socket Pair Timeout Block which is passed to timeout AST
115 */
116 typedef struct _SocketPairTimeoutBlock {
117     unsigned short SockChan1;
118     unsigned short SockChan2;
119 } SPTB;
120
121 # ifdef TERM_SOCK_TEST
122 \f
123 /*----------------------------------------------------------------------------*/
124 /*                                                                            */
125 /*----------------------------------------------------------------------------*/
126 int main (int argc, char *argv[], char *envp[])
127 {
128     char TermBuff[80];
129     int TermSock,
130         status,
131         len;
132
133     LogMessage ("Enter 'q' or 'Q' to quit ...");
134     while (strcasecmp (TermBuff, "Q")) {
135         /*
136         ** Create the terminal socket
137         */
138         status = TerminalSocket (TERM_SOCK_CREATE, &TermSock);
139         if (status != TERM_SOCK_SUCCESS)
140             exit (1);
141
142         /*
143         ** Process the terminal input
144         */
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);
149
150         /*
151         ** Delete the terminal socket
152         */
153         status = TerminalSocket (TERM_SOCK_DELETE, &TermSock);
154         if (status != TERM_SOCK_SUCCESS)
155             exit (1);
156     }
157
158     return 1;
159
160 }
161 # endif
162 \f
163 /*----------------------------------------------------------------------------*/
164 /*                                                                            */
165 /*----------------------------------------------------------------------------*/
166 int TerminalSocket (int FunctionCode, int *ReturnSocket)
167 {
168     int status;
169     $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND");
170
171     /*
172     ** Process the requested function code
173     */
174     switch (FunctionCode) {
175     case TERM_SOCK_CREATE:
176         /*
177         ** Create a socket pair
178         */
179         status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair);
180         if (status == -1) {
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);
187         }
188
189         /*
190         ** Assign a channel to the terminal device
191         */
192         status = sys$assign (&TerminalDeviceDesc,
193                              &TerminalDeviceChan,
194                              0, 0, 0);
195         if (! (status & 1)) {
196             LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status);
197             close (TerminalSocketPair[0]);
198             close (TerminalSocketPair[1]);
199             return (TERM_SOCK_FAILURE);
200         }
201
202         /*
203         ** Queue an async IO to the terminal device
204         */
205         status = sys$qio (EFN$C_ENF,
206                           TerminalDeviceChan,
207                           IO$_READVBLK,
208                           &TerminalDeviceIosb,
209                           TerminalDeviceAst,
210                           0,
211                           TerminalDeviceBuff,
212                           sizeof (TerminalDeviceBuff) - 2,
213                           0, 0, 0, 0);
214         if (! (status & 1)) {
215             LogMessage ("TerminalSocket: SYS$QIO () - %08X", status);
216             close (TerminalSocketPair[0]);
217             close (TerminalSocketPair[1]);
218             return (TERM_SOCK_FAILURE);
219         }
220
221         /*
222         ** Return the input side of the socket pair
223         */
224         *ReturnSocket = TerminalSocketPair[1];
225         break;
226
227     case TERM_SOCK_DELETE:
228         /*
229         ** Cancel any pending IO on the terminal channel
230         */
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);
237         }
238
239         /*
240         ** Deassign the terminal channel
241         */
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);
248         }
249
250         /*
251         ** Close the terminal socket pair
252         */
253         close (TerminalSocketPair[0]);
254         close (TerminalSocketPair[1]);
255
256         /*
257         ** Return the initialized socket
258         */
259         *ReturnSocket = 0;
260         break;
261
262     default:
263         /*
264         ** Invalid function code
265         */
266         LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode);
267         return (TERM_SOCK_FAILURE);
268         break;
269     }
270
271     /*
272     ** Return success
273     */
274     return (TERM_SOCK_SUCCESS);
275
276 }
277 \f
278 /*----------------------------------------------------------------------------*/
279 /*                                                                            */
280 /*----------------------------------------------------------------------------*/
281 static int CreateSocketPair (int SocketFamily,
282                              int SocketType,
283                              int SocketProtocol,
284                              int *SocketPair)
285 {
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,
289         TcpDeviceChan = 0;
290     unsigned long BinTimeBuff[2];
291     struct sockaddr_in sin;
292     char AscTimeBuff[32];
293     short LocalHostPort;
294     int status;
295     unsigned int slen;
296
297 # ifdef __alpha
298     struct _iosb iosb;
299 # else
300     IOSB iosb;
301 # endif
302
303     int SockDesc1 = 0,
304         SockDesc2 = 0;
305     SPTB sptb;
306     $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE");
307
308     /*
309     ** Create a socket
310     */
311     SockDesc1 = socket (SocketFamily, SocketType, 0);
312     if (SockDesc1 < 0) {
313         LogMessage ("CreateSocketPair: socket () - %d", errno);
314         return (-1);
315     }
316
317     /*
318     ** Initialize the socket information
319     */
320     slen = sizeof (sin);
321     memset ((char *) &sin, 0, slen);
322     sin.sin_family = SocketFamily;
323     sin.sin_addr.s_addr = inet_addr (LocalHostAddr);
324     sin.sin_port = 0;
325
326     /*
327     ** Bind the socket to the local IP
328     */
329     status = bind (SockDesc1, (struct sockaddr *) &sin, slen);
330     if (status < 0) {
331         LogMessage ("CreateSocketPair: bind () - %d", errno);
332         close (SockDesc1);
333         return (-1);
334     }
335
336     /*
337     ** Get the socket name so we can save the port number
338     */
339     status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen);
340     if (status < 0) {
341         LogMessage ("CreateSocketPair: getsockname () - %d", errno);
342         close (SockDesc1);
343         return (-1);
344     } else
345         LocalHostPort = sin.sin_port;
346
347     /*
348     ** Setup a listen for the socket
349     */
350     listen (SockDesc1, 5);
351
352     /*
353     ** Get the binary (64-bit) time of the specified timeout value
354     */
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);
361         close (SockDesc1);
362         return (-1);
363     }
364
365     /*
366     ** Assign another channel to the TCP/IP device for the accept.
367     ** This is the channel that ends up being connected to.
368     */
369     status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0);
370     if (! (status & 1)) {
371         LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status);
372         close (SockDesc1);
373         return (-1);
374     }
375
376     /*
377     ** Get the channel of the first socket for the accept
378     */
379     TcpAcceptChan = decc$get_sdc (SockDesc1);
380
381     /*
382     ** Perform the accept using $QIO so we can do this asynchronously
383     */
384     status = sys$qio (EFN$C_ENF,
385                       TcpAcceptChan,
386                       IO$_ACCESS | IO$M_ACCEPT,
387                       &iosb,
388                       0, 0, 0, 0, 0,
389                       &TcpDeviceChan,
390                       0, 0);
391     if (! (status & 1)) {
392         LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status);
393         close (SockDesc1);
394         sys$dassgn (TcpDeviceChan);
395         return (-1);
396     }
397
398     /*
399     ** Create the second socket to do the connect
400     */
401     SockDesc2 = socket (SocketFamily, SocketType, 0);
402     if (SockDesc2 < 0) {
403         LogMessage ("CreateSocketPair: socket () - %d", errno);
404         sys$cancel (TcpAcceptChan);
405         close (SockDesc1);
406         sys$dassgn (TcpDeviceChan);
407         return (-1) ;
408     }
409
410     /*
411     ** Setup the Socket Pair Timeout Block
412     */
413     sptb.SockChan1 = TcpAcceptChan;
414     sptb.SockChan2 = decc$get_sdc (SockDesc2);
415
416     /*
417     ** Before we block on the connect, set a timer that can cancel I/O on our
418     ** two sockets if it never connects.
419     */
420     status = sys$setimr (EFN$C_ENF,
421                          BinTimeBuff,
422                          SocketPairTimeoutAst,
423                          &sptb,
424                          0);
425     if (! (status & 1)) {
426         LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status);
427         sys$cancel (TcpAcceptChan);
428         close (SockDesc1);
429         close (SockDesc2);
430         sys$dassgn (TcpDeviceChan);
431         return (-1);
432     }
433
434     /*
435     ** Now issue the connect
436     */
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 ;
441
442     status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof (sin));
443     if (status < 0 ) {
444         LogMessage ("CreateSocketPair: connect () - %d", errno);
445         sys$cantim (&sptb, 0);
446         sys$cancel (TcpAcceptChan);
447         close (SockDesc1);
448         close (SockDesc2);
449         sys$dassgn (TcpDeviceChan);
450         return (-1);
451     }
452
453     /*
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
456     ** a timeout.
457     */
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");
462         else {
463             LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d",
464                         iosb.iosb$w_status);
465             sys$cantim (&sptb, 0);
466         }
467         close (SockDesc1);
468         close (SockDesc2);
469         sys$dassgn (TcpDeviceChan);
470         return (-1);
471     }
472
473     /*
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
476     ** connected pair.
477     */
478     sys$cantim (&sptb, 0);
479
480     close (SockDesc1) ;
481     SocketPair[0] = SockDesc2 ;
482     SocketPair[1] = socket_fd (TcpDeviceChan);
483
484     return (0) ;
485
486 }
487 \f
488 /*----------------------------------------------------------------------------*/
489 /*                                                                            */
490 /*----------------------------------------------------------------------------*/
491 static void SocketPairTimeoutAst (int astparm)
492 {
493     SPTB *sptb = (SPTB *) astparm;
494
495     sys$cancel (sptb->SockChan2); /* Cancel the connect() */
496     sys$cancel (sptb->SockChan1); /* Cancel the accept() */
497
498     return;
499
500 }
501 \f
502 /*----------------------------------------------------------------------------*/
503 /*                                                                            */
504 /*----------------------------------------------------------------------------*/
505 static int TerminalDeviceAst (int astparm)
506 {
507     int status;
508
509     /*
510     ** Terminate the terminal buffer
511     */
512     TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0';
513     strcat (TerminalDeviceBuff, "\n");
514
515     /*
516     ** Send the data read from the terminal device throught the socket pair
517     */
518     send (TerminalSocketPair[0], TerminalDeviceBuff,
519           TerminalDeviceIosb.iosb$w_bcnt + 1, 0);
520
521     /*
522     ** Queue another async IO to the terminal device
523     */
524     status = sys$qio (EFN$C_ENF,
525                       TerminalDeviceChan,
526                       IO$_READVBLK,
527                       &TerminalDeviceIosb,
528                       TerminalDeviceAst,
529                       0,
530                       TerminalDeviceBuff,
531                       sizeof (TerminalDeviceBuff) - 1,
532                       0, 0, 0, 0);
533
534     /*
535     ** Return status
536     */
537     return status;
538
539 }
540 \f
541 /*----------------------------------------------------------------------------*/
542 /*                                                                            */
543 /*----------------------------------------------------------------------------*/
544 static void LogMessage (char *msg, ...)
545 {
546     char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
547                      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
548     static unsigned int pid = 0;
549     va_list args;
550     time_t CurTime;
551     struct tm *LocTime;
552     char MsgBuff[256];
553
554     /*
555     ** Get the process pid
556     */
557     if (pid == 0)
558         pid = getpid ();
559
560     /*
561     ** Convert the current time into local time
562     */
563     CurTime = time (NULL);
564     LocTime = localtime (&CurTime);
565
566     /*
567     ** Format the message buffer
568     */
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);
573
574     /*
575     ** Get any variable arguments and add them to the print of the message
576     ** buffer
577     */
578     va_start (args, msg);
579     vfprintf (stderr, MsgBuff, args);
580     va_end (args);
581
582     /*
583     ** Flush standard error output
584     */
585     fsync (fileno (stderr));
586
587     return;
588
589 }
590 #endif