This source file includes following definitions.
- accessMonotonicMs
- accessPeerEqual
- accessParsePeer
- accessGetPeer
- accessPeerText
- accessRateFind
- accessRatePermits
- accessRateFailure
- accessPendingFor
- accessRandomDelay
- accessForClient
- alloc_buffer
- accessWriteCallback
- accessReadCallback
- accessReadStart
- accessStartWriteActual
- accessStartWrite
- accessPutCharForce
- accessPutStrForce
- accessStartWriteStr
- accessLogon
- accessRelease
- accessTimerCloseCallback
- accessCloseCallback
- accessCloseConnection
- accessTimerCallback
- accessReject
- accessShutdownCallback
- accessDrainOld
- accessPromote
- accessCloseAll
- accessOpenSessions
- accessProcessInput
- accessTelnetReadCallback
- evHandler
- accessTelnetConnect
- accessListenerCloseCallback
- 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 <limits.h>
23 #include <signal.h>
24 #include "dps8.h"
25 #include "dps8_sys.h"
26 #include "dps8_cpu.h"
27 #include "dps8_utils.h"
28 #include "libtelnet.h"
29 #include "uvutil.h"
30
31
32
33 #define OPCON_MAX_PENDING_INPUT (16U * 1024U * 1024U)
34 #define OPCON_PENDING_PER_LISTENER 8U
35 #define OPCON_PENDING_PER_ADDRESS 2U
36 #define OPCON_PENDING_TOTAL 32U
37 #define OPCON_AUTH_TIMEOUT_MS 30000U
38 #define OPCON_FAILURE_WINDOW_MS 60000U
39 #define OPCON_FAILURE_LIMIT 5U
40 #define OPCON_RATE_SLOTS 128U
41 #define OPCON_DRAIN_TIMEOUT_MS 1000U
42 #define OPCON_MAX_DRAINING_PER_LISTENER 8U
43 #define OPCON_MAX_QUEUED_OUTPUT (4U * 1024U * 1024U)
44
45 #if defined(NO_LOCALE)
46 # define xstrerror_l strerror
47 #endif
48
49 #if defined(FREE)
50 # undef FREE
51 #endif
52 #define FREE(p) do \
53 { \
54 free((p)); \
55 (p) = NULL; \
56 } while(0)
57
58 #define USE_REQ_DATA
59
60 static void accessTelnetReadCallback (uv_tcp_t * client,
61 ssize_t nread,
62 unsigned char * buf);
63
64
65
66
67 typedef struct
68 {
69 int family;
70 unsigned char address[16];
71 } access_peer;
72
73 typedef enum
74 {
75 access_authenticating,
76 access_active,
77 access_rejected,
78 access_draining,
79 access_closing
80 } access_state;
81
82 typedef struct access_client_s
83 {
84 uv_access * owner;
85 uv_tcp_t * client;
86 telnet_t * telnetp;
87 uv_timer_t timer;
88 bool timer_inited;
89 unsigned int close_refs;
90 bool pending;
91 bool admitted;
92 bool closing;
93 bool promoted_in_read;
94 access_state state;
95 access_peer peer;
96 char pwBuffer[PW_SIZE + 1];
97 unsigned int pwPos;
98 struct access_client_s * next;
99 } access_client;
100
101 typedef struct
102 {
103 access_peer peer;
104 uint64_t last_seen_ms;
105 uint64_t failures_ms[OPCON_FAILURE_LIMIT];
106 unsigned int next_failure;
107 } access_rate_slot;
108
109 static access_client * access_sessions;
110 static unsigned int access_pending_total;
111 static access_rate_slot access_rates[OPCON_RATE_SLOTS];
112 static uint64_t access_jitter_counter;
113
114 static void accessPromote (access_client * session);
115 static void accessReject (access_client * session);
116 static void accessTimerCallback (uv_timer_t * timer);
117
118 static uint64_t accessMonotonicMs (void)
119 {
120 return uv_hrtime () / UINT64_C(1000000);
121 }
122
123 static bool accessPeerEqual (const access_peer * a, const access_peer * b)
124 {
125 if (a->family != b->family)
126 return false;
127 return memcmp (a->address, b->address,
128 a->family == AF_INET ? 4U : 16U) == 0;
129 }
130
131 static bool accessParsePeer (const struct sockaddr_storage * address,
132 int len, access_peer * peer)
133 {
134 memset (peer, 0, sizeof (*peer));
135 if (len < (int)sizeof (struct sockaddr) ||
136 (size_t)len > sizeof (*address))
137 return false;
138 if (address->ss_family == AF_INET)
139 {
140 struct sockaddr_in ipv4;
141
142
143 if ((size_t)len < sizeof (ipv4))
144 return false;
145 memcpy (&ipv4, address, sizeof (ipv4));
146
147
148 memcpy (peer->address, &ipv4.sin_addr, sizeof (ipv4.sin_addr));
149 }
150 else if (address->ss_family == AF_INET6)
151 {
152 struct sockaddr_in6 ipv6;
153 if ((size_t)len < sizeof (ipv6))
154 return false;
155 memcpy (&ipv6, address, sizeof (ipv6));
156 memcpy (peer->address, &ipv6.sin6_addr, sizeof (ipv6.sin6_addr));
157 }
158 else
159 return false;
160 peer->family = address->ss_family;
161 return true;
162 }
163
164 static bool accessGetPeer (uv_tcp_t * client, access_peer * peer)
165 {
166 struct sockaddr_storage address;
167 int len = sizeof (address);
168 if (uv_tcp_getpeername (client, (struct sockaddr *)&address, &len) != 0)
169 return false;
170 return accessParsePeer (&address, len, peer);
171 }
172
173 static const char * accessPeerText (const access_peer * peer,
174 char * buf, size_t size)
175 {
176 if (peer->family != AF_INET && peer->family != AF_INET6)
177 return NULL;
178 if (size > UINT_MAX)
179 return NULL;
180 return inet_ntop (peer->family, peer->address, buf, (socklen_t)size);
181 }
182
183 static access_rate_slot * accessRateFind (const access_peer * peer)
184 {
185 uint64_t now = accessMonotonicMs ();
186 access_rate_slot * available = NULL;
187 access_rate_slot * oldest = &access_rates[0];
188 for (unsigned int i = 0; i < OPCON_RATE_SLOTS; i ++)
189 {
190 access_rate_slot * slot = &access_rates[i];
191 if (slot->last_seen_ms < oldest->last_seen_ms)
192 oldest = slot;
193 if (slot->last_seen_ms &&
194 now - slot->last_seen_ms < OPCON_FAILURE_WINDOW_MS &&
195 accessPeerEqual (&slot->peer, peer))
196 return slot;
197 if (!available && (!slot->last_seen_ms ||
198 now - slot->last_seen_ms >=
199 OPCON_FAILURE_WINDOW_MS))
200 available = slot;
201 }
202 if (!available)
203 available = oldest;
204 memset (available, 0, sizeof (*available));
205 available->peer = *peer;
206 available->last_seen_ms = now;
207 return available;
208 }
209
210 static bool accessRatePermits (const access_peer * peer)
211 {
212 access_rate_slot * slot = accessRateFind (peer);
213 uint64_t now = accessMonotonicMs ();
214 unsigned int count = 0;
215 for (unsigned int i = 0; i < OPCON_FAILURE_LIMIT; i ++)
216 if (slot->failures_ms[i] &&
217 now - slot->failures_ms[i] < OPCON_FAILURE_WINDOW_MS)
218 ++count;
219 return count < OPCON_FAILURE_LIMIT;
220 }
221
222 static void accessRateFailure (const access_peer * peer)
223 {
224 access_rate_slot * slot = accessRateFind (peer);
225 slot->last_seen_ms = accessMonotonicMs ();
226 slot->failures_ms[slot->next_failure] = slot->last_seen_ms;
227 slot->next_failure = (slot->next_failure + 1U) % OPCON_FAILURE_LIMIT;
228 }
229
230 static unsigned int accessPendingFor (uv_access * access,
231 const access_peer * peer)
232 {
233 unsigned int count = 0;
234 for (access_client * s = access_sessions; s; s = s->next)
235 if (s->pending && (!access || s->owner == access) &&
236 (!peer || accessPeerEqual (&s->peer, peer)))
237 count ++;
238 return count;
239 }
240
241 static unsigned int accessRandomDelay (void)
242 {
243 uint64_t x = uv_hrtime () ^ (++access_jitter_counter *
244 UINT64_C(0x9e3779b97f4a7c15));
245 x ^= x >> 12;
246 x ^= x << 25;
247 x ^= x >> 27;
248 return 1000U + (unsigned int)((x * UINT64_C(2685821657736338717))
249 % UINT64_C(2001));
250 }
251
252 uv_access * accessForClient (uv_tcp_t * client)
253 {
254 if (!client || !client->data)
255 return NULL;
256 access_client * session = (access_client *)client->data;
257 return session->closing ? NULL : session->owner;
258 }
259
260
261
262
263
264 static void alloc_buffer (UNUSED uv_handle_t * handle, size_t suggested_size,
265 uv_buf_t * buf)
266 {
267
268 #if !defined(__clang_analyzer__)
269 if (suggested_size > UINT_MAX)
270 suggested_size = UINT_MAX;
271 char * base = (char *)malloc (suggested_size);
272 *buf = uv_buf_init (base, base ? (unsigned int)suggested_size : 0);
273 #endif
274 }
275
276 static void accessWriteCallback (uv_write_t * req, int status)
277 {
278 if (status < 0)
279 {
280 if (status == -ECONNRESET || status == -ECANCELED ||
281 status == -EPIPE)
282 {
283
284 }
285 else
286 {
287 sim_warn ("accessWriteCallback status %d (%s)\r\n", -status,
288 xstrerror_l(-status));
289 }
290
291
292 if (!uv_is_closing ((uv_handle_t *)req->handle))
293 accessCloseConnection (req->handle);
294 }
295
296 #if defined(USE_REQ_DATA)
297 FREE (req->data);
298 #else
299 unsigned int nbufs = req->nbufs;
300 uv_buf_t * bufs = req->bufs;
301 for (unsigned int i = 0; i < nbufs; i ++)
302 {
303 if (bufs && bufs[i].base)
304 {
305 FREE (bufs[i].base);
306
307 }
308 if (req->bufsml[i].base)
309 {
310 FREE (req->bufsml[i].base);
311 }
312 }
313 #endif
314
315
316
317 FREE (req);
318 }
319
320
321
322
323
324
325
326 static void accessReadCallback (uv_stream_t* stream,
327 ssize_t nread,
328 const uv_buf_t* buf)
329 {
330 access_client * session = (access_client *)stream->data;
331 uv_access * access = session ? session->owner : NULL;
332 if (nread < 0)
333 {
334 if (session && !session->closing)
335 accessCloseConnection (stream);
336 }
337 else if (nread > 0 && session && !session->closing && access)
338 {
339 if (session->telnetp)
340 {
341 telnet_recv (session->telnetp, buf->base, (size_t) nread);
342 }
343 else
344 {
345 accessTelnetReadCallback ((uv_tcp_t *) stream,
346 (ssize_t) nread,
347 (unsigned char *) buf->base);
348 }
349 session->promoted_in_read = false;
350 }
351 if (buf->base)
352 free (buf->base);
353 }
354
355
356
357
358
359 static void accessReadStart (uv_tcp_t * client)
360 {
361 if (! client || uv_is_closing ((uv_handle_t *) client))
362 return;
363 uv_read_start ((uv_stream_t *) client, alloc_buffer, accessReadCallback);
364 }
365
366
367
368 static void accessStartWriteActual (uv_tcp_t * client, char * data,
369 ssize_t datalen)
370 {
371 if (! client || uv_is_closing ((uv_handle_t *) client) ||
372 datalen <= 0 || (uint64_t)datalen > UINT_MAX || !data)
373 return;
374 access_client * session = (access_client *)client->data;
375 if (session && !session->closing && session->state != access_active)
376 {
377 size_t queued = uv_stream_get_write_queue_size ((uv_stream_t *)client);
378 if ((uint64_t)datalen > OPCON_MAX_QUEUED_OUTPUT ||
379 queued > OPCON_MAX_QUEUED_OUTPUT - (size_t)datalen)
380 {
381 sim_warn ("OPCON slow reader: write queue limit exceeded\r\n");
382 accessCloseConnection ((uv_stream_t *)client);
383 return;
384 }
385 }
386
387 #if !defined(__clang_analyzer__)
388 uv_write_t * req = (uv_write_t *) malloc (sizeof (uv_write_t));
389 if (!req)
390 {
391 sim_warn ("OPCON write allocation failed; dropping output\r\n");
392 return;
393 }
394
395 (void)memset (req, 0, sizeof (uv_write_t));
396 uv_buf_t buf = uv_buf_init ((char *) malloc ((unsigned long) datalen),
397 (uint) datalen);
398 if (!buf.base)
399 {
400 FREE (req);
401 return;
402 }
403 # if defined(USE_REQ_DATA)
404 req->data = buf.base;
405 # endif
406 memcpy (buf.base, data, (unsigned long) datalen);
407
408 int ret = uv_write (req, (uv_stream_t *) client, & buf, 1,
409 accessWriteCallback);
410
411
412
413
414 if (ret < 0)
415 {
416 if (ret != UV_EBADF && !sim_quiet)
417 sim_printf ("uv_write returns %d\r\n", ret);
418 FREE (buf.base);
419 FREE (req);
420 }
421 #endif
422 }
423
424 void accessStartWrite (uv_tcp_t * client, char * data, ssize_t datalen)
425 {
426 if ((client == NULL) || uv_is_closing ((uv_handle_t *) client))
427 return;
428 access_client * session = (access_client *)client->data;
429 if (!session || session->closing || !data || datalen <= 0 ||
430 (uint64_t)datalen > UINT_MAX)
431 return;
432 if (session->telnetp)
433 telnet_send (session->telnetp, data, (size_t) datalen);
434 else
435 accessStartWriteActual (client, data, (ssize_t) datalen);
436 }
437
438 static void accessPutCharForce (uv_tcp_t * client, char ch)
439 {
440
441 accessStartWrite (client, & ch, 1);
442 }
443
444 static void accessPutStrForce (uv_tcp_t * client, char * str)
445 {
446 size_t l = strlen (str);
447 accessStartWrite (client, str, (ssize_t) l);
448 }
449
450 void accessStartWriteStr (uv_tcp_t * client, char * data)
451 {
452 if (data)
453 accessStartWrite (client, data, (ssize_t) strlen (data));
454 }
455
456 static void accessLogon (access_client * session, unsigned char * buf,
457 ssize_t nread)
458 {
459 uv_access * access = session->owner;
460 uv_tcp_t * client = session->client;
461 for (ssize_t nchar = 0; nchar < nread; nchar ++)
462 {
463 unsigned char kar = buf[nchar];
464
465 if (session->pwPos >= sizeof (session->pwBuffer) - 1)
466 {
467
468 switch (kar)
469 {
470 case '\b':
471 case 127:
472 {
473
474 accessPutStrForce (client, "\b \b");
475
476 session->pwPos -= 1;
477 session->pwBuffer[session->pwPos] = 0;
478 }
479 break;
480
481 case '\n':
482 case '\r':
483 {
484 session->pwBuffer[session->pwPos] = 0;
485 goto check;
486 }
487
488 default:
489 break;
490 }
491 continue;
492 }
493
494 if (isprint (kar))
495 {
496 accessPutCharForce (client, '*');
497 session->pwBuffer[session->pwPos++] = (char) kar;
498 session->pwBuffer[session->pwPos] = 0;
499 }
500 else
501 {
502 switch (kar)
503 {
504 case '\b':
505 case 127:
506 {
507
508 accessPutStrForce (client, "\b \b");
509
510 if (session->pwPos > 0)
511 session->pwPos -= 1;
512 session->pwBuffer[session->pwPos] = 0;
513 }
514 break;
515
516 case '\n':
517 case '\r':
518 {
519 session->pwBuffer[session->pwPos] = 0;
520 goto check;
521 }
522
523 default:
524 break;
525 }
526 }
527 }
528 return;
529
530 check:;
531 char cpy[PW_SIZE + 1];
532 char *fname = NULL, tbuffer[256];
533 struct tm *timeinfo;
534 memcpy (cpy, session->pwBuffer, session->pwPos);
535 cpy[session->pwPos] = 0;
536 trim (cpy);
537
538 session->pwPos = 0;
539 memset (session->pwBuffer, 0, sizeof (session->pwBuffer));
540 accessPutStrForce (client, "\r\n");
541
542 char ip[INET6_ADDRSTRLEN];
543 fname = (char *)accessPeerText (&session->peer, ip, sizeof (ip));
544 if (strcmp (cpy, access->pw) == 0)
545 {
546 if (fname == NULL)
547 sim_printf ("\r[OPC emulation: ACCESS GRANTED]\r\n");
548 else
549 sim_printf ("\r[OPC emulation: ACCESS GRANTED to %s]\r\n", fname);
550 accessPutStrForce (client, "\r[OPC emulation: ACCESS GRANTED]\r\n");
551 if (access->atime)
552 {
553 timeinfo = localtime(&access->atime);
554 strftime(tbuffer, sizeof(tbuffer),
555 "\r[OPC emulation: Last successful login %A, %B %d, %Y at %I:%M %p %Z]\r\n", timeinfo);
556 accessPutStrForce (client, tbuffer);
557 }
558 if (access->rtime)
559 {
560 timeinfo = localtime(&access->rtime);
561 strftime(tbuffer, sizeof(tbuffer),
562 "\r[OPC emulation: Last failed attempt %A, %B %d, %Y at %I:%M %p %Z]\r\n", timeinfo);
563 accessPutStrForce (client, tbuffer);
564 }
565 if (access->rcount)
566 {
567 char buffer[64];
568 snprintf(buffer, sizeof(buffer), "%lu", access->rcount);
569 accessPutStrForce (client, "\r[OPC emulation: ");
570 accessPutStrForce (client, buffer);
571 accessPutStrForce (client, " failed attempt(s) since last successful login]\r\n");
572 }
573 access->atime = time(NULL);
574 access->rcount = 0;
575 if (session->closing)
576 return;
577 accessPromote (session);
578 session->promoted_in_read = true;
579 if (access->connected && !session->closing)
580 access->connected (client);
581 }
582 else
583 {
584
585
586
587 accessPutStrForce (client, "[OPC emulation: ACCESS DENIED]\r\n");
588 if (fname == NULL)
589 sim_printf ("\r[OPC emulation: ACCESS DENIED]\r\n");
590 else
591 sim_printf ("\r[OPC emulation: ACCESS DENIED to %s]\r\n", fname);
592 access->rtime = time(NULL);
593 access->rcount++;
594 accessPutStrForce (client, "\rMultics has disconnected you\r\n");
595 accessRateFailure (&session->peer);
596 accessReject (session);
597 return;
598 }
599 }
600
601 static void accessRelease (access_client * session)
602 {
603 if (--session->close_refs != 0)
604 return;
605 access_client ** link = &access_sessions;
606 while (*link && *link != session)
607 link = &(*link)->next;
608 if (*link == session)
609 *link = session->next;
610 if (session->pending)
611 {
612 --access_pending_total;
613 session->pending = false;
614 }
615 memset (session->pwBuffer, 0, sizeof (session->pwBuffer));
616 FREE (session);
617 }
618
619 static void accessTimerCloseCallback (uv_handle_t * handle)
620 {
621 access_client * session = (access_client *)handle->data;
622 accessRelease (session);
623 }
624
625 static void accessCloseCallback (uv_handle_t * stream)
626 {
627 access_client * session = (access_client *)stream->data;
628 if (session)
629 {
630
631
632 if (session->telnetp)
633 telnet_free (session->telnetp);
634 accessRelease (session);
635 }
636 FREE (stream);
637 }
638
639 void accessCloseConnection (uv_stream_t* stream)
640 {
641 if (!stream || uv_is_closing ((uv_handle_t *)stream))
642 return;
643 access_client * session = (access_client *)stream->data;
644 if (!session || session->closing)
645 return;
646 uv_access * access = session->owner;
647 const char *pname;
648 char ip[INET6_ADDRSTRLEN];
649 pname = accessPeerText (&session->peer, ip, sizeof (ip));
650
651
652
653
654 if (session->admitted)
655 {
656 if (pname == NULL)
657 sim_printf ("\r[OPC emulation: DISCONNECT]\r\n");
658 else
659 sim_printf ("\r[OPC emulation: DISCONNECT %s]\r\n", pname);
660 }
661 session->closing = true;
662 session->state = access_closing;
663 if (session->telnetp)
664 libtelnet_set_invalid (session->telnetp);
665 if (access && access->client == (uv_tcp_t *)stream)
666 {
667 access->client = NULL;
668 access->loggedOn = false;
669 FREE (access->inBuffer);
670 access->inSize = access->inUsed = 0;
671 }
672 (void)uv_read_stop (stream);
673 if (session->timer_inited)
674 {
675 uv_timer_stop (&session->timer);
676 uv_close ((uv_handle_t *)&session->timer, accessTimerCloseCallback);
677 }
678 uv_close ((uv_handle_t *) stream, accessCloseCallback);
679 }
680
681 static void accessTimerCallback (uv_timer_t * timer)
682 {
683 access_client * session = (access_client *)timer->data;
684 if (session && !session->closing)
685 accessCloseConnection ((uv_stream_t *)session->client);
686 }
687
688 static void accessReject (access_client * session)
689 {
690 if (session->closing)
691 return;
692 session->state = access_rejected;
693 (void)uv_read_stop ((uv_stream_t *)session->client);
694
695 uv_timer_stop (&session->timer);
696 if (uv_timer_start (&session->timer, accessTimerCallback,
697 accessRandomDelay (), 0) != 0)
698 accessCloseConnection ((uv_stream_t *)session->client);
699 }
700
701 static void accessShutdownCallback (uv_shutdown_t * req, UNUSED int status)
702 {
703 uv_stream_t * stream = req->handle;
704 if (!uv_is_closing ((uv_handle_t *)stream))
705 accessCloseConnection (stream);
706 FREE (req);
707 }
708
709 static void accessDrainOld (access_client * old)
710 {
711 uv_tcp_t * client = old->client;
712 if (old->closing)
713 return;
714
715 unsigned int draining = 0;
716 access_client * oldest = NULL;
717 for (access_client * s = access_sessions; s; s = s->next)
718 if (s->owner == old->owner && s->state == access_draining)
719 {
720 ++draining;
721 oldest = s;
722 }
723 if (draining >= OPCON_MAX_DRAINING_PER_LISTENER && oldest)
724 accessCloseConnection ((uv_stream_t *)oldest->client);
725
726 old->state = access_draining;
727 (void)uv_read_stop ((uv_stream_t *)client);
728 char ip[INET6_ADDRSTRLEN];
729 const char * pname = accessPeerText (&old->peer, ip, sizeof (ip));
730 if (pname)
731 sim_printf ("\r[OPC emulation: BUMPED %s]\r\n", pname);
732 else
733 sim_printf ("\r[OPC emulation: BUMPED]\r\n");
734 accessPutStrForce (client, "\r[OPC emulation: BUMPED]\r\n");
735 accessPutStrForce (client, "\rMultics has disconnected you\r\n");
736 if (old->closing)
737 return;
738
739 uv_shutdown_t * req = (uv_shutdown_t *)malloc (sizeof (*req));
740 if (!req)
741 {
742 accessCloseConnection ((uv_stream_t *)client);
743 return;
744 }
745 if (uv_timer_start (&old->timer, accessTimerCallback,
746 OPCON_DRAIN_TIMEOUT_MS, 0) != 0)
747 {
748 FREE (req);
749 accessCloseConnection ((uv_stream_t *)client);
750 return;
751 }
752 if (uv_shutdown (req, (uv_stream_t *)client,
753 accessShutdownCallback) != 0)
754 {
755 FREE (req);
756 accessCloseConnection ((uv_stream_t *)client);
757 }
758 }
759
760 static void accessPromote (access_client * session)
761 {
762 uv_access * access = session->owner;
763 uv_tcp_t * old = access->client;
764 uv_timer_stop (&session->timer);
765 if (session->pending)
766 {
767 session->pending = false;
768 --access_pending_total;
769 }
770 session->state = access_active;
771
772 FREE (access->inBuffer);
773 access->inSize = access->inUsed = 0;
774 access->client = session->client;
775 access->loggedOn = true;
776 if (old && old != session->client)
777 {
778 access_client * previous = (access_client *)old->data;
779 if (previous)
780 accessDrainOld (previous);
781 }
782 }
783
784 void accessCloseAll (uv_access * access)
785 {
786 for (access_client * session = access_sessions; session; )
787 {
788 access_client * next = session->next;
789 if (session->owner == access && !session->closing)
790 accessCloseConnection ((uv_stream_t *)session->client);
791 session = next;
792 }
793 }
794
795 unsigned int accessOpenSessions (void)
796 {
797 unsigned int count = 0;
798 for (access_client * session = access_sessions; session;
799 session = session->next)
800 ++count;
801 return count;
802 }
803
804 static void accessProcessInput (uv_access * access, unsigned char * buf,
805 ssize_t nread)
806 {
807 if (nread <= 0 || (uint64_t)nread > UINT_MAX - access->inSize ||
808 (uint64_t)access->inSize + (uint64_t)nread > OPCON_MAX_PENDING_INPUT)
809 {
810
811
812 accessCloseConnection ((uv_stream_t *)access->client);
813 return;
814 }
815 if (access->inBuffer)
816 {
817
818 unsigned char * new =
819 realloc (access->inBuffer,
820 (unsigned long) (access->inSize + nread));
821 if (! new)
822 {
823 sim_warn ("OPCON input allocation failed; disconnecting\r\n");
824 accessCloseConnection ((uv_stream_t *)access->client);
825 return;
826 }
827 memcpy (new + access->inSize, buf, (unsigned long) nread);
828 access->inSize += nread;
829 access->inBuffer = new;
830 }
831 else
832 {
833 access->inBuffer = malloc ((unsigned long) nread);
834 if (! access->inBuffer)
835 {
836 sim_warn ("OPCON input allocation failed; disconnecting\r\n");
837 accessCloseConnection ((uv_stream_t *)access->client);
838 return;
839 }
840 memcpy (access->inBuffer, buf, (unsigned long) nread);
841 access->inSize = (uint) nread;
842 access->inUsed = 0;
843 }
844
845
846
847
848
849
850 }
851
852 static void accessTelnetReadCallback (uv_tcp_t * client,
853 ssize_t nread,
854 unsigned char * buf)
855 {
856 access_client * session = (access_client *)client->data;
857 if (!session || session->closing || session->promoted_in_read)
858 return;
859 if (session->state == access_active &&
860 session->owner->client == client)
861 accessProcessInput (session->owner, buf, nread);
862 else if (session->state == access_authenticating)
863 accessLogon (session, buf, nread);
864 }
865
866 static void evHandler (UNUSED telnet_t *telnet, telnet_event_t *event,
867 void *user_data)
868 {
869 uv_tcp_t * client = (uv_tcp_t *) user_data;
870
871 if (! telnet || ! libtelnet_is_valid(telnet)) {
872 if (! sim_quiet) {
873 sim_warn ("evHandler telnet status invalid\r\n");
874 }
875 return;
876 }
877
878 switch (event->type)
879 {
880 case TELNET_EV_DATA:
881 {
882 accessTelnetReadCallback (client, (ssize_t) event->data.size,
883 (unsigned char *)event->data.buffer);
884 }
885 break;
886
887 case TELNET_EV_SEND:
888 {
889 accessStartWriteActual (client, (char *) event->data.buffer,
890 (ssize_t) event->data.size);
891 }
892 break;
893
894 case TELNET_EV_DO:
895 {
896 if (event->neg.telopt == TELNET_TELOPT_BINARY)
897 {
898
899 }
900 else if (event->neg.telopt == TELNET_TELOPT_SGA)
901 {
902
903 }
904 else if (event->neg.telopt == TELNET_TELOPT_ECHO)
905 {
906
907 }
908 else
909 {
910 if (! sim_quiet) {
911 sim_printf ("evHandler DO %d\r\n", event->neg.telopt);
912 }
913 }
914 }
915 break;
916
917 case TELNET_EV_DONT:
918 {
919 if (! sim_quiet) {
920 sim_printf ("evHandler DONT %d\r\n", event->neg.telopt);
921 }
922 }
923 break;
924
925 case TELNET_EV_WILL:
926 {
927 if (! sim_quiet) {
928 if (event->neg.telopt != 3) {
929 sim_printf ("evHandler WILL %d\r\n", event->neg.telopt);
930 }
931 }
932 }
933 break;
934
935 case TELNET_EV_WONT:
936 {
937 if (! sim_quiet) {
938 sim_printf ("evHandler WONT %d\r\n", event->neg.telopt);
939 }
940 }
941 break;
942
943 case TELNET_EV_ERROR:
944 {
945 if (! sim_quiet) {
946 sim_warn ("libtelnet evHandler error <%s>\r\n", event->error.msg);
947 }
948 }
949 break;
950
951 case TELNET_EV_IAC:
952 {
953 if (event->iac.cmd == 243 ||
954 event->iac.cmd == 244)
955 {
956 if (! sim_quiet) {
957 sim_warn ("libtelnet dropping unassociated BRK or IP\r\n");
958 }
959 }
960 else
961 if (! sim_quiet) {
962 if (event->iac.cmd != 241) {
963 sim_warn ("libtelnet unhandled IAC event %d\r\n", event->iac.cmd);
964 }
965 }
966 }
967 break;
968
969 default:
970 if (! sim_quiet) {
971 sim_printf ("evHandler: unhandled event %d\r\n", event->type);
972 }
973 break;
974 }
975
976 }
977
978 static const telnet_telopt_t my_telopts[] =
979 {
980 { TELNET_TELOPT_SGA, TELNET_WILL, TELNET_DO },
981 { TELNET_TELOPT_ECHO, TELNET_WILL, TELNET_DONT },
982
983
984 { TELNET_TELOPT_BINARY, TELNET_WONT, TELNET_DONT },
985
986 { -1, 0, 0 }
987 };
988
989 static void * accessTelnetConnect (uv_tcp_t * client)
990 {
991 void * p = (void *) telnet_init (my_telopts, evHandler, 0, client);
992 if (!p)
993 {
994 (void)fprintf(stderr, "\rtelnet_init failed at %s[%s:%d]\r\n",
995 __func__, __FILE__, __LINE__);
996 return NULL;
997 }
998 const telnet_telopt_t * q = my_telopts;
999 while (q->telopt != -1)
1000 {
1001 telnet_negotiate (p, q->us, (unsigned char) q->telopt);
1002 q ++;
1003 }
1004 return p;
1005 }
1006
1007
1008
1009
1010
1011 static void accessListenerCloseCallback (uv_handle_t * handle)
1012 {
1013 uv_access * access = (uv_access *)handle->data;
1014 if (access)
1015 access->open = false;
1016 }
1017
1018 static void onNewAccess (uv_stream_t * server, int status)
1019 {
1020 if (status < 0)
1021 {
1022 (void)fprintf (stderr, "\r[OPC emulation: new connection error %s]\r\n", uv_strerror(status));
1023
1024 return;
1025 }
1026
1027 uv_access * access = (uv_access *) server->data;
1028
1029 uv_tcp_t * client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
1030 if (!client)
1031 {
1032 sim_warn ("OPCON client allocation failed; rejecting connection\r\n");
1033 return;
1034 }
1035 int init_rc = uv_tcp_init (access->loop, client);
1036 if (init_rc < 0)
1037 {
1038 sim_warn ("OPCON TCP initialization failed: %s\r\n", uv_strerror (init_rc));
1039 FREE (client);
1040 return;
1041 }
1042 client->data = NULL;
1043 if (uv_accept (server, (uv_stream_t *) client) == 0)
1044 {
1045 access_client * session = (access_client *)calloc (1, sizeof (*session));
1046 if (!session)
1047 {
1048 uv_close ((uv_handle_t *)client, accessCloseCallback);
1049 return;
1050 }
1051 session->owner = access;
1052 session->client = client;
1053 session->close_refs = 1;
1054 session->state = access_authenticating;
1055 client->data = session;
1056 if (!accessGetPeer (client, &session->peer))
1057 {
1058 accessCloseConnection ((uv_stream_t *)client);
1059 return;
1060 }
1061
1062 if (access->pw[0] &&
1063 (access_pending_total >= OPCON_PENDING_TOTAL ||
1064 accessPendingFor (access, NULL) >= OPCON_PENDING_PER_LISTENER ||
1065 accessPendingFor (NULL, &session->peer) >=
1066 OPCON_PENDING_PER_ADDRESS ||
1067 !accessRatePermits (&session->peer)))
1068 {
1069 accessCloseConnection ((uv_stream_t *)client);
1070 return;
1071 }
1072
1073 int timer_rc = uv_timer_init (access->loop, &session->timer);
1074 if (timer_rc != 0)
1075 {
1076 accessCloseConnection ((uv_stream_t *)client);
1077 return;
1078 }
1079 session->timer_inited = true;
1080 session->timer.data = session;
1081 session->close_refs ++;
1082 session->admitted = true;
1083 session->next = access_sessions;
1084 access_sessions = session;
1085 if (access->pw[0])
1086 {
1087 session->pending = true;
1088 access_pending_total ++;
1089 if (uv_timer_start (&session->timer, accessTimerCallback,
1090 OPCON_AUTH_TIMEOUT_MS, 0) != 0)
1091 {
1092 accessCloseConnection ((uv_stream_t *)client);
1093 return;
1094 }
1095 }
1096
1097 (void)uv_tcp_nodelay (client, 1);
1098 char ip[INET6_ADDRSTRLEN];
1099 const char * pname = accessPeerText (&session->peer, ip, sizeof (ip));
1100 if (pname)
1101 sim_printf ("\r[OPC emulation: CONNECT %s]\r\n", pname);
1102 else
1103 sim_printf ("\r[OPC emulation: CONNECT]\r\n");
1104
1105 if (access->useTelnet)
1106 {
1107 session->telnetp = accessTelnetConnect (client);
1108 if (!session->telnetp)
1109 {
1110 sim_warn ("ltnConnect failed\r\n");
1111 accessCloseConnection ((uv_stream_t *)client);
1112 return;
1113 }
1114 }
1115 if (session->closing)
1116 return;
1117 if (!access->pw[0])
1118 {
1119 accessPromote (session);
1120 if (access->connected && !session->closing)
1121 access->connected (client);
1122 }
1123 else if (access->connectPrompt)
1124 access->connectPrompt (client);
1125 if (!session->closing)
1126 accessReadStart (client);
1127 }
1128 else
1129 {
1130 uv_close ((uv_handle_t *) client, accessCloseCallback);
1131 }
1132 }
1133
1134 void uv_open_access (uv_access * access)
1135 {
1136 if (access->open == true)
1137 {
1138 sim_printf ("\r[OPC emulation: OPC already initialized]\r\n");
1139 }
1140
1141 if (! access->port)
1142 {
1143
1144 return;
1145 }
1146
1147 if (! access->loop)
1148 access->loop = uv_default_loop ();
1149
1150
1151 if (access->open)
1152 return;
1153
1154 int r = uv_tcp_init (access->loop, & access->server);
1155 if (r < 0)
1156 return;
1157 access->open = true;
1158 access->server.data = (void *) access;
1159 struct sockaddr_in addr;
1160 r = uv_ip4_addr (access->address ? access->address : "0.0.0.0",
1161 access->port, & addr);
1162 if (r == 0)
1163 r = uv_tcp_bind (& access->server, (const struct sockaddr *) & addr, 0);
1164 #define DEFAULT_BACKLOG 1024
1165 if (r == 0)
1166 r = uv_listen ((uv_stream_t *) & access->server,
1167 DEFAULT_BACKLOG, onNewAccess);
1168 if (r)
1169 {
1170 (void)fprintf (stderr, "\r[OPC emulation: listen error: %s:%ld: %s]\r\n",
1171 access->address ? access->address : "0.0.0.0",
1172 (long) access->port, uv_strerror(r));
1173
1174
1175 uv_close ((uv_handle_t *)&access->server, accessListenerCloseCallback);
1176 return;
1177 }
1178 if (access->address != NULL)
1179 sim_printf ("\r[OPC emulation: TELNET server listening on %s:%ld]\r\n",
1180 access->address, (long) access->port);
1181 else
1182 sim_printf ("\r[OPC emulation: TELNET server listening on 0.0.0.0:%ld]\r\n",
1183 (long) access->port);
1184 }
1185
1186 #if !defined(QUIET_UNUSED)
1187 void accessPutChar (uv_access * access, char ch)
1188 {
1189
1190 if (access->loggedOn)
1191 accessStartWrite (access->client, & ch, 1);
1192 }
1193 #endif
1194
1195 int accessGetChar (uv_access * access)
1196 {
1197
1198 if (! access->client)
1199 {
1200 if (access->inBuffer)
1201 FREE (access->inBuffer);
1202 access->inBuffer = NULL;
1203 access->inSize = 0;
1204 access->inUsed = 0;
1205 return SCPE_OK;
1206 }
1207
1208 if (access->inBuffer && access->inUsed < access->inSize)
1209 {
1210 unsigned char c = access->inBuffer[access->inUsed ++];
1211 if (access->inUsed >= access->inSize)
1212 {
1213 FREE (access->inBuffer);
1214 access->inBuffer = NULL;
1215 access->inSize = 0;
1216 access->inUsed = 0;
1217
1218
1219
1220 }
1221 return (int) c + SCPE_KFLAG;
1222 }
1223 return SCPE_OK;
1224
1225 }
1226
1227 #if !defined(QUIET_UNUSED)
1228 void accessPutStr (uv_access * access, char * str)
1229 {
1230 size_t l = strlen (str);
1231
1232
1233 if (access->loggedOn)
1234 accessStartWrite (access->client, str, (ssize_t) l);
1235 }
1236 #endif