This source file includes following definitions.
- alloc_buffer
- accessWriteCallback
- accessReadCallback
- accessReadStart
- accessStartWriteActual
- accessStartWrite
- accessPutCharForce
- accessPutStrForce
- accessStartWriteStr
- accessLogon
- accessCloseCallback
- accessCloseConnection
- accessProcessInput
- accessTelnetReadCallback
- evHandler
- accessTelnetConnect
- onNewAccess
- uv_open_access
- accessPutChar
- accessGetChar
- accessPutStr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <uv.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include "dps8.h"
24 #include "dps8_sys.h"
25 #include "dps8_cpu.h"
26 #include "dps8_utils.h"
27 #include "libtelnet.h"
28 #include "uvutil.h"
29
30 #if defined(NO_LOCALE)
31 # define xstrerror_l strerror
32 #endif
33
34 #if defined(FREE)
35 # undef FREE
36 #endif
37 #define FREE(p) do \
38 { \
39 free((p)); \
40 (p) = NULL; \
41 } while(0)
42
43 #define USE_REQ_DATA
44
45 static void accessTelnetReadCallback (uv_tcp_t * client,
46 ssize_t nread,
47 unsigned char * buf);
48
49
50
51
52
53 static void alloc_buffer (UNUSED uv_handle_t * handle, size_t suggested_size,
54 uv_buf_t * buf)
55 {
56
57 #if !defined(__clang_analyzer__)
58 * buf = uv_buf_init ((char *) malloc (suggested_size),
59 (uint) suggested_size);
60 #endif
61 }
62
63 static void accessWriteCallback (uv_write_t * req, int status)
64 {
65 if (status < 0)
66 {
67 if (status == -ECONNRESET || status == -ECANCELED ||
68 status == -EPIPE)
69 {
70
71 }
72 else
73 {
74 sim_warn ("accessWriteCallback status %d (%s)\r\n", -status,
75 xstrerror_l(-status));
76 }
77
78
79 accessCloseConnection (req->handle);
80 }
81
82 #if defined(USE_REQ_DATA)
83 FREE (req->data);
84 #else
85 unsigned int nbufs = req->nbufs;
86 uv_buf_t * bufs = req->bufs;
87 for (unsigned int i = 0; i < nbufs; i ++)
88 {
89 if (bufs && bufs[i].base)
90 {
91 FREE (bufs[i].base);
92
93 }
94 if (req->bufsml[i].base)
95 {
96 FREE (req->bufsml[i].base);
97 }
98 }
99 #endif
100
101
102
103 FREE (req);
104 }
105
106
107
108
109
110
111
112 static void accessReadCallback (uv_stream_t* stream,
113 ssize_t nread,
114 const uv_buf_t* buf)
115 {
116 uv_access * access = (uv_access *) stream->data;
117 if (nread < 0)
118 {
119
120 {
121 accessCloseConnection (stream);
122 }
123 }
124 else if (nread > 0)
125 {
126 if (access->telnetp)
127 {
128 telnet_recv (access->telnetp, buf->base, (size_t) nread);
129 }
130 else
131 {
132 accessTelnetReadCallback ((uv_tcp_t *) stream,
133 (ssize_t) nread,
134 (unsigned char *) buf->base);
135 }
136 }
137 if (buf->base)
138 free (buf->base);
139 }
140
141
142
143
144
145 static void accessReadStart (uv_tcp_t * client)
146 {
147 if (! client || uv_is_closing ((uv_handle_t *) client))
148 return;
149 uv_read_start ((uv_stream_t *) client, alloc_buffer, accessReadCallback);
150 }
151
152
153
154 static void accessStartWriteActual (uv_tcp_t * client, char * data,
155 ssize_t datalen)
156 {
157 if (! client || uv_is_closing ((uv_handle_t *) client))
158 return;
159
160 #if !defined(__clang_analyzer__)
161 uv_write_t * req = (uv_write_t *) malloc (sizeof (uv_write_t));
162 if (!req)
163 {
164 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
165 __func__, __FILE__, __LINE__);
166 # if defined(USE_BACKTRACE)
167 # if defined(SIGUSR2)
168 (void)raise(SIGUSR2);
169
170 # endif
171 # endif
172 abort();
173 }
174
175 (void)memset (req, 0, sizeof (uv_write_t));
176 uv_buf_t buf = uv_buf_init ((char *) malloc ((unsigned long) datalen),
177 (uint) datalen);
178 # if defined(USE_REQ_DATA)
179 req->data = buf.base;
180 # endif
181 memcpy (buf.base, data, (unsigned long) datalen);
182
183 int ret = uv_write (req, (uv_stream_t *) client, & buf, 1,
184 accessWriteCallback);
185
186
187
188
189 if (ret < 0 && ret != -EBADF)
190 sim_printf ("uv_write returns %d\r\n", ret);
191 #endif
192 }
193
194 void accessStartWrite (uv_tcp_t * client, char * data, ssize_t datalen)
195 {
196 if ((client == NULL) || uv_is_closing ((uv_handle_t *) client))
197 return;
198 uv_access * access = (uv_access *) client->data;
199 if (access->telnetp)
200 telnet_send (access->telnetp, data, (size_t) datalen);
201 else
202 accessStartWriteActual (client, data, (ssize_t) datalen);
203 }
204
205 static void accessPutCharForce (uv_access * access, char ch)
206 {
207
208 accessStartWrite (access->client, & ch, 1);
209 }
210
211 static void accessPutStrForce (uv_access * access, char * str)
212 {
213 size_t l = strlen (str);
214 accessStartWrite (access->client, str, (ssize_t) l);
215 }
216
217 void accessStartWriteStr (uv_tcp_t * client, char * data)
218 {
219 accessStartWrite (client, data, (ssize_t) strlen (data));
220 }
221
222 static void accessLogon (uv_access * access, unsigned char * buf, ssize_t nread)
223 {
224 for (ssize_t nchar = 0; nchar < nread; nchar ++)
225 {
226 unsigned char kar = buf[nchar];
227
228 if ((unsigned long) access->pwPos >= sizeof (access->pwBuffer) - 1)
229 {
230
231 switch (kar)
232 {
233 case '\b':
234 case 127:
235 {
236
237 accessPutStrForce (access, "\b \b");
238 access->pwBuffer[access->pwPos] = 0;
239 if (access->pwPos > 0)
240 access->pwPos -= 1;
241 }
242 break;
243
244 case '\n':
245 case '\r':
246 {
247 access->pwBuffer[access->pwPos] = 0;
248 goto check;
249 }
250
251 default:
252 break;
253 }
254 continue;
255 }
256
257 if (isprint (kar))
258 {
259 accessPutCharForce (access, '*');
260 access->pwBuffer[access->pwPos++] = (char) kar;
261 access->pwBuffer[access->pwPos] = 0;
262 }
263 else
264 {
265 switch (kar)
266 {
267 case '\b':
268 case 127:
269 {
270
271 accessPutStrForce (access, "\b \b");
272
273 access->pwBuffer[access->pwPos] = 0;
274 if (access->pwPos > 0)
275 access->pwPos -= 1;
276 }
277 break;
278
279 case '\n':
280 case '\r':
281 {
282 access->pwBuffer[access->pwPos] = 0;
283 goto check;
284 }
285
286 default:
287 break;
288 }
289 }
290 }
291 return;
292
293 check:;
294 char cpy[access->pwPos + 1];
295 char *fname = NULL, tbuffer[256];
296 struct tm *timeinfo;
297 memcpy (cpy, access->pwBuffer, (unsigned long) access->pwPos);
298 cpy[access->pwPos] = 0;
299 trim (cpy);
300
301 access->pwPos = 0;
302 accessPutStrForce (access, "\r\n");
303
304 struct sockaddr cname;
305 int cnamelen = sizeof (cname);
306 int ret = uv_tcp_getpeername (access->client, & cname, & cnamelen);
307 if (ret > -1)
308 {
309 struct sockaddr_in * p = (struct sockaddr_in *) & cname;
310 fname = inet_ntoa (p->sin_addr);
311 }
312 if (strcmp (cpy, access->pw) == 0)
313 {
314 if (fname == NULL)
315 sim_printf ("\r[OPC emulation: ACCESS GRANTED]\r\n");
316 else
317 sim_printf ("\r[OPC emulation: ACCESS GRANTED to %s]\r\n", fname);
318 accessPutStrForce (access, "\r[OPC emulation: ACCESS GRANTED]\r\n");
319 access->loggedOn = true;
320 if (access->atime)
321 {
322 timeinfo = localtime(&access->atime);
323 strftime(tbuffer, sizeof(tbuffer),
324 "\r[OPC emulation: Last successful login %A, %B %d, %Y at %I:%M %p %Z]\r\n", timeinfo);
325 accessPutStrForce (access, tbuffer);
326 }
327 if (access->rtime)
328 {
329 timeinfo = localtime(&access->rtime);
330 strftime(tbuffer, sizeof(tbuffer),
331 "\r[OPC emulation: Last failed attempt %A, %B %d, %Y at %I:%M %p %Z]\r\n", timeinfo);
332 accessPutStrForce (access, tbuffer);
333 }
334 if (access->rcount)
335 {
336 char buffer[64];
337 snprintf(buffer, sizeof(buffer), "%lu", access->rcount);
338 accessPutStrForce (access, "\r[OPC emulation: ");
339 accessPutStrForce (access, buffer);
340 accessPutStrForce (access, " failed attempt(s) since last successful login]\r\n");
341 }
342 access->atime = time(NULL);
343 access->rcount = 0;
344 if (access->connected)
345 access->connected (access->client);
346 }
347 else
348 {
349
350
351
352 accessPutStrForce (access, "[OPC emulation: ACCESS DENIED]\r\n");
353 if (fname == NULL)
354 sim_printf ("\r[OPC emulation: ACCESS DENIED]\r\n");
355 else
356 sim_printf ("\r[OPC emulation: ACCESS DENIED to %s]\r\n", fname);
357 access->rtime = time(NULL);
358 access->rcount++;
359 accessPutStrForce (access, "\rMultics has disconnected you\r\n");
360 accessCloseConnection ((uv_stream_t *) access->client);
361 return;
362 }
363 }
364
365 static void accessCloseCallback (uv_handle_t * stream)
366 {
367 FREE (stream);
368
369 }
370
371 void accessCloseConnection (uv_stream_t* stream)
372 {
373 uv_access * access = (uv_access *) stream->data;
374 char *pname = NULL;
375 struct sockaddr name;
376 int namelen = sizeof (name);
377 int ret = uv_tcp_getpeername (access->client, & name, & namelen);
378 if (ret > -1)
379 {
380 struct sockaddr_in * p = (struct sockaddr_in *) & name;
381 pname = inet_ntoa (p -> sin_addr);
382 }
383
384 if (pname == NULL)
385 sim_printf ("\r[OPC emulation: DISCONNECT]\r\n");
386 else
387 sim_printf ("\r[OPC emulation: DISCONNECT %s]\r\n", pname);
388 libtelnet_set_invalid(access->telnetp);
389
390 if (access->telnetp)
391 {
392 libtelnet_set_invalid(access->telnetp);
393 telnet_free (access->telnetp);
394 access->telnetp = NULL;
395 }
396 if (! uv_is_closing ((uv_handle_t *) stream))
397 uv_close ((uv_handle_t *) stream, accessCloseCallback);
398 access->client = NULL;
399 }
400
401 static void accessProcessInput (uv_access * access, unsigned char * buf,
402 ssize_t nread)
403 {
404 if (access->inBuffer)
405 {
406
407 unsigned char * new =
408 realloc (access->inBuffer,
409 (unsigned long) (access->inSize + nread));
410 if (! new)
411 {
412 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
413 __func__, __FILE__, __LINE__);
414 #if defined(USE_BACKTRACE)
415 # if defined(SIGUSR2)
416 (void)raise(SIGUSR2);
417
418 # endif
419 #endif
420 abort();
421 }
422 memcpy (new + access->inSize, buf, (unsigned long) nread);
423 access->inSize += nread;
424 access->inBuffer = new;
425 }
426 else
427 {
428 access->inBuffer = malloc ((unsigned long) nread);
429 if (! access->inBuffer)
430 {
431 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
432 __func__, __FILE__, __LINE__);
433 #if defined(USE_BACKTRACE)
434 # if defined(SIGUSR2)
435 (void)raise(SIGUSR2);
436
437 # endif
438 #endif
439 abort();
440 }
441 memcpy (access->inBuffer, buf, (unsigned long) nread);
442 access->inSize = (uint) nread;
443 access->inUsed = 0;
444 }
445
446
447
448
449
450
451 }
452
453 static void accessTelnetReadCallback (uv_tcp_t * client,
454 ssize_t nread,
455 unsigned char * buf)
456 {
457 uv_access * access = (uv_access *) client->data;
458 if (access)
459 {
460 if (access->loggedOn)
461 accessProcessInput (access, buf, nread);
462 else
463 accessLogon (access, buf, nread);
464 }
465 }
466
467 static void evHandler (UNUSED telnet_t *telnet, telnet_event_t *event,
468 void *user_data)
469 {
470 uv_tcp_t * client = (uv_tcp_t *) user_data;
471
472 if (! telnet || ! libtelnet_is_valid(telnet)) {
473 if (! sim_quiet) {
474 sim_warn ("evHandler telnet status invalid\r\n");
475 }
476 return;
477 }
478
479 switch (event->type)
480 {
481 case TELNET_EV_DATA:
482 {
483 accessTelnetReadCallback (client, (ssize_t) event->data.size,
484 (unsigned char *)event->data.buffer);
485 }
486 break;
487
488 case TELNET_EV_SEND:
489 {
490 accessStartWriteActual (client, (char *) event->data.buffer,
491 (ssize_t) event->data.size);
492 }
493 break;
494
495 case TELNET_EV_DO:
496 {
497 if (event->neg.telopt == TELNET_TELOPT_BINARY)
498 {
499
500 }
501 else if (event->neg.telopt == TELNET_TELOPT_SGA)
502 {
503
504 }
505 else if (event->neg.telopt == TELNET_TELOPT_ECHO)
506 {
507
508 }
509 else
510 {
511 if (! sim_quiet) {
512 sim_printf ("evHandler DO %d\r\n", event->neg.telopt);
513 }
514 }
515 }
516 break;
517
518 case TELNET_EV_DONT:
519 {
520 if (! sim_quiet) {
521 sim_printf ("evHandler DONT %d\r\n", event->neg.telopt);
522 }
523 }
524 break;
525
526 case TELNET_EV_WILL:
527 {
528 if (! sim_quiet) {
529 if (event->neg.telopt != 3) {
530 sim_printf ("evHandler WILL %d\r\n", event->neg.telopt);
531 }
532 }
533 }
534 break;
535
536 case TELNET_EV_WONT:
537 {
538 if (! sim_quiet) {
539 sim_printf ("evHandler WONT %d\r\n", event->neg.telopt);
540 }
541 }
542 break;
543
544 case TELNET_EV_ERROR:
545 {
546 if (! sim_quiet) {
547 sim_warn ("libtelnet evHandler error <%s>\r\n", event->error.msg);
548 }
549 }
550 break;
551
552 case TELNET_EV_IAC:
553 {
554 if (event->iac.cmd == 243 ||
555 event->iac.cmd == 244)
556 {
557 if (! sim_quiet) {
558 sim_warn ("libtelnet dropping unassociated BRK or IP\r\n");
559 }
560 }
561 else
562 if (! sim_quiet) {
563 if (event->iac.cmd != 241) {
564 sim_warn ("libtelnet unhandled IAC event %d\r\n", event->iac.cmd);
565 }
566 }
567 }
568 break;
569
570 default:
571 if (! sim_quiet) {
572 sim_printf ("evHandler: unhandled event %d\r\n", event->type);
573 }
574 break;
575 }
576
577 }
578
579 static const telnet_telopt_t my_telopts[] =
580 {
581 { TELNET_TELOPT_SGA, TELNET_WILL, TELNET_DO },
582 { TELNET_TELOPT_ECHO, TELNET_WILL, TELNET_DONT },
583
584
585 { TELNET_TELOPT_BINARY, TELNET_WONT, TELNET_DONT },
586
587 { -1, 0, 0 }
588 };
589
590 static void * accessTelnetConnect (uv_tcp_t * client)
591 {
592 void * p = (void *) telnet_init (my_telopts, evHandler, 0, client);
593 if (!p)
594 {
595 (void)fprintf(stderr, "\rtelnet_init failed at %s[%s:%d]\r\n",
596 __func__, __FILE__, __LINE__);
597 return NULL;
598 }
599 const telnet_telopt_t * q = my_telopts;
600 while (q->telopt != -1)
601 {
602 telnet_negotiate (p, q->us, (unsigned char) q->telopt);
603 q ++;
604 }
605 return p;
606 }
607
608
609
610
611
612 static void onNewAccess (uv_stream_t * server, int status)
613 {
614 if (status < 0)
615 {
616 (void)fprintf (stderr, "\r[OPC emulation: new connection error %s]\r\n", uv_strerror(status));
617
618 return;
619 }
620
621 uv_access * access = (uv_access *) server->data;
622
623 uv_tcp_t * client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
624 if (!client)
625 {
626 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
627 __func__, __FILE__, __LINE__);
628 #if defined(USE_BACKTRACE)
629 # if defined(SIGUSR2)
630 (void)raise(SIGUSR2);
631
632 # endif
633 #endif
634 abort();
635 }
636 uv_tcp_init (access->loop, client);
637 client->data = server->data;
638 if (uv_accept (server, (uv_stream_t *) client) == 0)
639 {
640
641 if (access->client)
642 {
643 access->loggedOn = false;
644
645 char *pname = NULL;
646 struct sockaddr lname;
647 int lnamelen = sizeof (lname);
648 int ret = uv_tcp_getpeername (access->client, & lname, & lnamelen);
649 if (ret > -1)
650 {
651 struct sockaddr_in * p = (struct sockaddr_in *) & lname;
652 pname = inet_ntoa (p -> sin_addr);
653 }
654
655 if (pname == NULL)
656 sim_printf ("\r[OPC emulation: BUMPED]\r\n");
657 else
658 sim_printf ("\r[OPC emulation: BUMPED %s]\r\n", pname);
659 accessPutStrForce (access, "\r[OPC emulation: BUMPED]\r\n");
660 accessPutStrForce (access, "\rMultics has disconnected you\r\n");
661 libtelnet_set_invalid(access->telnetp);
662 accessCloseConnection ((uv_stream_t *) access->client);
663 }
664 access->client = client;
665 uv_tcp_nodelay (client, 1);
666 struct sockaddr name;
667 int namelen = sizeof (name);
668 int ret = uv_tcp_getpeername (access->client, & name, & namelen);
669 if (ret < 0)
670 {
671 sim_printf ("\r[OPC emulation: CONNECT; addr err %d]\r\n", ret);
672 }
673 else
674 {
675 struct sockaddr_in * p = (struct sockaddr_in *) & name;
676 sim_printf ("\r[OPC emulation: CONNECT %s]\r\n", inet_ntoa (p -> sin_addr));
677 }
678
679 if (access->useTelnet)
680 {
681 access->telnetp = accessTelnetConnect (access->client);
682 if (!access->telnetp)
683 {
684 sim_warn ("ltnConnect failed\r\n");
685 return;
686 }
687 }
688 else
689 {
690 access->telnetp = NULL;
691 }
692 access->loggedOn = ! strlen (access->pw);
693 if (access->loggedOn)
694 access->connected (access->client);
695 else
696 access->connectPrompt (access->client);
697 accessReadStart (access->client);
698 }
699 else
700 {
701 uv_close ((uv_handle_t *) client, accessCloseCallback);
702 }
703 }
704
705 void uv_open_access (uv_access * access)
706 {
707 if (access->open == true)
708 {
709 sim_printf ("\r[OPC emulation: OPC already initialized]\r\n");
710 }
711
712 if (! access->port)
713 {
714
715 return;
716 }
717
718 if (! access->loop)
719 access->loop = uv_default_loop ();
720
721
722 if (access->open)
723 return;
724
725 uv_tcp_init (access->loop, & access->server);
726 access->server.data = (void *) access;
727 struct sockaddr_in addr;
728 uv_ip4_addr (access->address, access->port, & addr);
729 uv_tcp_bind (& access->server, (const struct sockaddr *) & addr, 0);
730 #define DEFAULT_BACKLOG 1024
731 int r = uv_listen ((uv_stream_t *) & access->server,
732 DEFAULT_BACKLOG,
733 onNewAccess);
734 if (r)
735 {
736 (void)fprintf (stderr, "\r[OPC emulation: listen error: %s:%ld: %s]\r\n",
737 access->address, (long) access->port, uv_strerror(r));
738 }
739 access->open = true;
740 if (access->address != NULL)
741 sim_printf ("\r[OPC emulation: TELNET server listening on %s:%ld]\r\n",
742 access->address, (long) access->port);
743 else
744 sim_printf ("\r[OPC emulation: TELNET server listening on 0.0.0.0:%ld]\r\n",
745 (long) access->port);
746 }
747
748 #if !defined(QUIET_UNUSED)
749 void accessPutChar (uv_access * access, char ch)
750 {
751
752 if (access->loggedOn)
753 accessStartWrite (access->client, & ch, 1);
754 }
755 #endif
756
757 int accessGetChar (uv_access * access)
758 {
759
760 if (! access->client)
761 {
762 if (access->inBuffer)
763 FREE (access->inBuffer);
764 access->inBuffer = NULL;
765 access->inSize = 0;
766 access->inUsed = 0;
767 return SCPE_OK;
768 }
769
770 if (access->inBuffer && access->inUsed < access->inSize)
771 {
772 unsigned char c = access->inBuffer[access->inUsed ++];
773 if (access->inUsed >= access->inSize)
774 {
775 FREE (access->inBuffer);
776 access->inBuffer = NULL;
777 access->inSize = 0;
778 access->inUsed = 0;
779
780
781
782 }
783 return (int) c + SCPE_KFLAG;
784 }
785 return SCPE_OK;
786
787 }
788
789 #if !defined(QUIET_UNUSED)
790 void accessPutStr (uv_access * access, char * str)
791 {
792 size_t l = strlen (str);
793
794
795 if (access->loggedOn)
796 accessStartWrite (access->client, str, (ssize_t) l);
797 }
798 #endif