vms_term_sock.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
  3. * Copyright 2016 VMS Software, Inc. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License 2.0 (the "License"). You may not use
  6. * this file except in compliance with the License. You can obtain a copy
  7. * in the file LICENSE in the source distribution or at
  8. * https://www.openssl.org/source/license.html
  9. */
  10. #ifdef __VMS
  11. # define OPENSSL_SYS_VMS
  12. # pragma message disable DOLLARID
  13. # include <openssl/opensslconf.h>
  14. # if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
  15. /*
  16. * On VMS, you need to define this to get the declaration of fileno(). The
  17. * value 2 is to make sure no function defined in POSIX-2 is left undefined.
  18. */
  19. # define _POSIX_C_SOURCE 2
  20. # endif
  21. # include <stdio.h>
  22. # undef _POSIX_C_SOURCE
  23. # include <sys/types.h>
  24. # include <sys/socket.h>
  25. # include <netinet/in.h>
  26. # include <inet.h>
  27. # include <unistd.h>
  28. # include <string.h>
  29. # include <errno.h>
  30. # include <starlet.h>
  31. # include <iodef.h>
  32. # ifdef __alpha
  33. # include <iosbdef.h>
  34. # else
  35. typedef struct _iosb { /* Copied from IOSBDEF.H for Alpha */
  36. # pragma __nomember_alignment
  37. __union {
  38. __struct {
  39. unsigned short int iosb$w_status; /* Final I/O status */
  40. __union {
  41. __struct { /* 16-bit byte count variant */
  42. unsigned short int iosb$w_bcnt; /* 16-bit byte count */
  43. __union {
  44. unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */
  45. unsigned int iosb$l_pid; /* 32-bit pid */
  46. } iosb$r_l;
  47. } iosb$r_bcnt_16;
  48. __struct { /* 32-bit byte count variant */
  49. unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */
  50. unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */
  51. } iosb$r_bcnt_32;
  52. } iosb$r_devdepend;
  53. } iosb$r_io_64;
  54. __struct {
  55. __union {
  56. unsigned int iosb$l_getxxi_status; /* Final GETxxI status */
  57. unsigned int iosb$l_reg_status; /* Final $Registry status */
  58. } iosb$r_l_status;
  59. unsigned int iosb$l_reserved; /* Reserved field */
  60. } iosb$r_get_64;
  61. } iosb$r_io_get;
  62. } IOSB;
  63. # if !defined(__VAXC)
  64. # define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status
  65. # define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt
  66. # define iosb$r_l iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l
  67. # define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend
  68. # define iosb$l_pid iosb$r_l.iosb$l_pid
  69. # define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt
  70. # 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
  71. # define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status
  72. # define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status
  73. # endif /* #if !defined(__VAXC) */
  74. # endif /* End of IOSBDEF */
  75. # include <efndef.h>
  76. # include <stdlib.h>
  77. # include <ssdef.h>
  78. # include <time.h>
  79. # include <stdarg.h>
  80. # include <descrip.h>
  81. # include "vms_term_sock.h"
  82. # ifdef __alpha
  83. static struct _iosb TerminalDeviceIosb;
  84. # else
  85. IOSB TerminalDeviceIosb;
  86. # endif
  87. static char TerminalDeviceBuff[255 + 2];
  88. static int TerminalSocketPair[2] = {0, 0};
  89. static unsigned short TerminalDeviceChan = 0;
  90. static int CreateSocketPair (int, int, int, int *);
  91. static void SocketPairTimeoutAst (int);
  92. static int TerminalDeviceAst (int);
  93. static void LogMessage (char *, ...);
  94. /*
  95. ** Socket Pair Timeout Value (must be 0-59 seconds)
  96. */
  97. # define SOCKET_PAIR_TIMEOUT_VALUE 20
  98. /*
  99. ** Socket Pair Timeout Block which is passed to timeout AST
  100. */
  101. typedef struct _SocketPairTimeoutBlock {
  102. unsigned short SockChan1;
  103. unsigned short SockChan2;
  104. } SPTB;
  105. # ifdef TERM_SOCK_TEST
  106. /*----------------------------------------------------------------------------*/
  107. /* */
  108. /*----------------------------------------------------------------------------*/
  109. int main (int argc, char *argv[], char *envp[])
  110. {
  111. char TermBuff[80];
  112. int TermSock,
  113. status,
  114. len;
  115. LogMessage ("Enter 'q' or 'Q' to quit ...");
  116. while (strcasecmp (TermBuff, "Q")) {
  117. /*
  118. ** Create the terminal socket
  119. */
  120. status = TerminalSocket (TERM_SOCK_CREATE, &TermSock);
  121. if (status != TERM_SOCK_SUCCESS)
  122. exit (1);
  123. /*
  124. ** Process the terminal input
  125. */
  126. LogMessage ("Waiting on terminal I/O ...\n");
  127. len = recv (TermSock, TermBuff, sizeof(TermBuff), 0) ;
  128. TermBuff[len] = '\0';
  129. LogMessage ("Received terminal I/O [%s]", TermBuff);
  130. /*
  131. ** Delete the terminal socket
  132. */
  133. status = TerminalSocket (TERM_SOCK_DELETE, &TermSock);
  134. if (status != TERM_SOCK_SUCCESS)
  135. exit (1);
  136. }
  137. return 1;
  138. }
  139. # endif
  140. /*----------------------------------------------------------------------------*/
  141. /* */
  142. /*----------------------------------------------------------------------------*/
  143. int TerminalSocket (int FunctionCode, int *ReturnSocket)
  144. {
  145. int status;
  146. $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND");
  147. /*
  148. ** Process the requested function code
  149. */
  150. switch (FunctionCode) {
  151. case TERM_SOCK_CREATE:
  152. /*
  153. ** Create a socket pair
  154. */
  155. status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair);
  156. if (status == -1) {
  157. LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status);
  158. if (TerminalSocketPair[0])
  159. close (TerminalSocketPair[0]);
  160. if (TerminalSocketPair[1])
  161. close (TerminalSocketPair[1]);
  162. return TERM_SOCK_FAILURE;
  163. }
  164. /*
  165. ** Assign a channel to the terminal device
  166. */
  167. status = sys$assign (&TerminalDeviceDesc,
  168. &TerminalDeviceChan,
  169. 0, 0, 0);
  170. if (! (status & 1)) {
  171. LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status);
  172. close (TerminalSocketPair[0]);
  173. close (TerminalSocketPair[1]);
  174. return TERM_SOCK_FAILURE;
  175. }
  176. /*
  177. ** Queue an async IO to the terminal device
  178. */
  179. status = sys$qio (EFN$C_ENF,
  180. TerminalDeviceChan,
  181. IO$_READVBLK,
  182. &TerminalDeviceIosb,
  183. TerminalDeviceAst,
  184. 0,
  185. TerminalDeviceBuff,
  186. sizeof(TerminalDeviceBuff) - 2,
  187. 0, 0, 0, 0);
  188. if (! (status & 1)) {
  189. LogMessage ("TerminalSocket: SYS$QIO () - %08X", status);
  190. close (TerminalSocketPair[0]);
  191. close (TerminalSocketPair[1]);
  192. return TERM_SOCK_FAILURE;
  193. }
  194. /*
  195. ** Return the input side of the socket pair
  196. */
  197. *ReturnSocket = TerminalSocketPair[1];
  198. break;
  199. case TERM_SOCK_DELETE:
  200. /*
  201. ** Cancel any pending IO on the terminal channel
  202. */
  203. status = sys$cancel (TerminalDeviceChan);
  204. if (! (status & 1)) {
  205. LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status);
  206. close (TerminalSocketPair[0]);
  207. close (TerminalSocketPair[1]);
  208. return TERM_SOCK_FAILURE;
  209. }
  210. /*
  211. ** Deassign the terminal channel
  212. */
  213. status = sys$dassgn (TerminalDeviceChan);
  214. if (! (status & 1)) {
  215. LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status);
  216. close (TerminalSocketPair[0]);
  217. close (TerminalSocketPair[1]);
  218. return TERM_SOCK_FAILURE;
  219. }
  220. /*
  221. ** Close the terminal socket pair
  222. */
  223. close (TerminalSocketPair[0]);
  224. close (TerminalSocketPair[1]);
  225. /*
  226. ** Return the initialized socket
  227. */
  228. *ReturnSocket = 0;
  229. break;
  230. default:
  231. /*
  232. ** Invalid function code
  233. */
  234. LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode);
  235. return TERM_SOCK_FAILURE;
  236. break;
  237. }
  238. /*
  239. ** Return success
  240. */
  241. return TERM_SOCK_SUCCESS;
  242. }
  243. /*----------------------------------------------------------------------------*/
  244. /* */
  245. /*----------------------------------------------------------------------------*/
  246. static int CreateSocketPair (int SocketFamily,
  247. int SocketType,
  248. int SocketProtocol,
  249. int *SocketPair)
  250. {
  251. struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
  252. static const char* LocalHostAddr = {"127.0.0.1"};
  253. unsigned short TcpAcceptChan = 0,
  254. TcpDeviceChan = 0;
  255. unsigned long BinTimeBuff[2];
  256. struct sockaddr_in sin;
  257. char AscTimeBuff[32];
  258. short LocalHostPort;
  259. int status;
  260. unsigned int slen;
  261. # ifdef __alpha
  262. struct _iosb iosb;
  263. # else
  264. IOSB iosb;
  265. # endif
  266. int SockDesc1 = 0,
  267. SockDesc2 = 0;
  268. SPTB sptb;
  269. $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE");
  270. /*
  271. ** Create a socket
  272. */
  273. SockDesc1 = socket (SocketFamily, SocketType, 0);
  274. if (SockDesc1 < 0) {
  275. LogMessage ("CreateSocketPair: socket () - %d", errno);
  276. return -1;
  277. }
  278. /*
  279. ** Initialize the socket information
  280. */
  281. slen = sizeof(sin);
  282. memset ((char *) &sin, 0, slen);
  283. sin.sin_family = SocketFamily;
  284. sin.sin_addr.s_addr = inet_addr (LocalHostAddr);
  285. sin.sin_port = 0;
  286. /*
  287. ** Bind the socket to the local IP
  288. */
  289. status = bind (SockDesc1, (struct sockaddr *) &sin, slen);
  290. if (status < 0) {
  291. LogMessage ("CreateSocketPair: bind () - %d", errno);
  292. close (SockDesc1);
  293. return -1;
  294. }
  295. /*
  296. ** Get the socket name so we can save the port number
  297. */
  298. status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen);
  299. if (status < 0) {
  300. LogMessage ("CreateSocketPair: getsockname () - %d", errno);
  301. close (SockDesc1);
  302. return -1;
  303. } else
  304. LocalHostPort = sin.sin_port;
  305. /*
  306. ** Setup a listen for the socket
  307. */
  308. listen (SockDesc1, 5);
  309. /*
  310. ** Get the binary (64-bit) time of the specified timeout value
  311. */
  312. sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE);
  313. AscTimeDesc.dsc$w_length = strlen (AscTimeBuff);
  314. AscTimeDesc.dsc$a_pointer = AscTimeBuff;
  315. status = sys$bintim (&AscTimeDesc, BinTimeBuff);
  316. if (! (status & 1)) {
  317. LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status);
  318. close (SockDesc1);
  319. return -1;
  320. }
  321. /*
  322. ** Assign another channel to the TCP/IP device for the accept.
  323. ** This is the channel that ends up being connected to.
  324. */
  325. status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0);
  326. if (! (status & 1)) {
  327. LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status);
  328. close (SockDesc1);
  329. return -1;
  330. }
  331. /*
  332. ** Get the channel of the first socket for the accept
  333. */
  334. TcpAcceptChan = decc$get_sdc (SockDesc1);
  335. /*
  336. ** Perform the accept using $QIO so we can do this asynchronously
  337. */
  338. status = sys$qio (EFN$C_ENF,
  339. TcpAcceptChan,
  340. IO$_ACCESS | IO$M_ACCEPT,
  341. &iosb,
  342. 0, 0, 0, 0, 0,
  343. &TcpDeviceChan,
  344. 0, 0);
  345. if (! (status & 1)) {
  346. LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status);
  347. close (SockDesc1);
  348. sys$dassgn (TcpDeviceChan);
  349. return -1;
  350. }
  351. /*
  352. ** Create the second socket to do the connect
  353. */
  354. SockDesc2 = socket (SocketFamily, SocketType, 0);
  355. if (SockDesc2 < 0) {
  356. LogMessage ("CreateSocketPair: socket () - %d", errno);
  357. sys$cancel (TcpAcceptChan);
  358. close (SockDesc1);
  359. sys$dassgn (TcpDeviceChan);
  360. return (-1) ;
  361. }
  362. /*
  363. ** Setup the Socket Pair Timeout Block
  364. */
  365. sptb.SockChan1 = TcpAcceptChan;
  366. sptb.SockChan2 = decc$get_sdc (SockDesc2);
  367. /*
  368. ** Before we block on the connect, set a timer that can cancel I/O on our
  369. ** two sockets if it never connects.
  370. */
  371. status = sys$setimr (EFN$C_ENF,
  372. BinTimeBuff,
  373. SocketPairTimeoutAst,
  374. &sptb,
  375. 0);
  376. if (! (status & 1)) {
  377. LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status);
  378. sys$cancel (TcpAcceptChan);
  379. close (SockDesc1);
  380. close (SockDesc2);
  381. sys$dassgn (TcpDeviceChan);
  382. return -1;
  383. }
  384. /*
  385. ** Now issue the connect
  386. */
  387. memset ((char *) &sin, 0, sizeof(sin)) ;
  388. sin.sin_family = SocketFamily;
  389. sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ;
  390. sin.sin_port = LocalHostPort ;
  391. status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof(sin));
  392. if (status < 0 ) {
  393. LogMessage ("CreateSocketPair: connect () - %d", errno);
  394. sys$cantim (&sptb, 0);
  395. sys$cancel (TcpAcceptChan);
  396. close (SockDesc1);
  397. close (SockDesc2);
  398. sys$dassgn (TcpDeviceChan);
  399. return -1;
  400. }
  401. /*
  402. ** Wait for the asynch $QIO to finish. Note that if the I/O was aborted
  403. ** (SS$_ABORT), then we probably canceled it from the AST routine - so log
  404. ** a timeout.
  405. */
  406. status = sys$synch (EFN$C_ENF, &iosb);
  407. if (! (iosb.iosb$w_status & 1)) {
  408. if (iosb.iosb$w_status == SS$_ABORT)
  409. LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout");
  410. else {
  411. LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d",
  412. iosb.iosb$w_status);
  413. sys$cantim (&sptb, 0);
  414. }
  415. close (SockDesc1);
  416. close (SockDesc2);
  417. sys$dassgn (TcpDeviceChan);
  418. return -1;
  419. }
  420. /*
  421. ** Here we're successfully connected, so cancel the timer, convert the
  422. ** I/O channel to a socket fd, close the listener socket and return the
  423. ** connected pair.
  424. */
  425. sys$cantim (&sptb, 0);
  426. close (SockDesc1) ;
  427. SocketPair[0] = SockDesc2 ;
  428. SocketPair[1] = socket_fd (TcpDeviceChan);
  429. return (0) ;
  430. }
  431. /*----------------------------------------------------------------------------*/
  432. /* */
  433. /*----------------------------------------------------------------------------*/
  434. static void SocketPairTimeoutAst (int astparm)
  435. {
  436. SPTB *sptb = (SPTB *) astparm;
  437. sys$cancel (sptb->SockChan2); /* Cancel the connect() */
  438. sys$cancel (sptb->SockChan1); /* Cancel the accept() */
  439. return;
  440. }
  441. /*----------------------------------------------------------------------------*/
  442. /* */
  443. /*----------------------------------------------------------------------------*/
  444. static int TerminalDeviceAst (int astparm)
  445. {
  446. int status;
  447. /*
  448. ** Terminate the terminal buffer
  449. */
  450. TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0';
  451. strcat (TerminalDeviceBuff, "\n");
  452. /*
  453. ** Send the data read from the terminal device through the socket pair
  454. */
  455. send (TerminalSocketPair[0], TerminalDeviceBuff,
  456. TerminalDeviceIosb.iosb$w_bcnt + 1, 0);
  457. /*
  458. ** Queue another async IO to the terminal device
  459. */
  460. status = sys$qio (EFN$C_ENF,
  461. TerminalDeviceChan,
  462. IO$_READVBLK,
  463. &TerminalDeviceIosb,
  464. TerminalDeviceAst,
  465. 0,
  466. TerminalDeviceBuff,
  467. sizeof(TerminalDeviceBuff) - 1,
  468. 0, 0, 0, 0);
  469. /*
  470. ** Return status
  471. */
  472. return status;
  473. }
  474. /*----------------------------------------------------------------------------*/
  475. /* */
  476. /*----------------------------------------------------------------------------*/
  477. static void LogMessage (char *msg, ...)
  478. {
  479. char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  480. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  481. static unsigned int pid = 0;
  482. va_list args;
  483. time_t CurTime;
  484. struct tm *LocTime;
  485. char MsgBuff[256];
  486. /*
  487. ** Get the process pid
  488. */
  489. if (pid == 0)
  490. pid = getpid ();
  491. /*
  492. ** Convert the current time into local time
  493. */
  494. CurTime = time (NULL);
  495. LocTime = localtime (&CurTime);
  496. /*
  497. ** Format the message buffer
  498. */
  499. sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n",
  500. LocTime->tm_mday, Month[LocTime->tm_mon],
  501. (LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min,
  502. LocTime->tm_sec, pid, msg);
  503. /*
  504. ** Get any variable arguments and add them to the print of the message
  505. ** buffer
  506. */
  507. va_start (args, msg);
  508. vfprintf (stderr, MsgBuff, args);
  509. va_end (args);
  510. /*
  511. ** Flush standard error output
  512. */
  513. fsync (fileno (stderr));
  514. return;
  515. }
  516. #endif