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 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 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 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 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 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 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 591