vms_term_sock.c 17 KB

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