]> git.ipfire.org Git - thirdparty/openssl.git/blob - apps/vms_term_sock.c
Style
[thirdparty/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