This source file includes following definitions.
- tmxr_init_line
- tmxr_report_connection
- tmxr_report_disconnection
- loop_write_ex
- loop_write
- loop_read_ex
- loop_read
- tmxr_read
- tmxr_write
- tmxr_rmvrc
- tmxr_find_ldsc
- tmxr_get_ldsc
- growstring
- tmxr_mux_attach_string
- tmxr_line_attach_string
- hash32s
- tmxr_poll_conn
- tmxr_reset_ln_ex
- tmxr_close_ln
- tmxr_reset_ln
- tmxr_set_get_modem_bits
- tmxr_set_line_loopback
- tmxr_get_line_loopback
- tmxr_set_line_halfduplex
- tmxr_get_line_halfduplex
- tmxr_input_pending_ln
- tmxr_getc_ln
- tmxr_get_packet_ln
- tmxr_get_packet_ln_ex
- tmxr_poll_rx
- tmxr_rqln_bare
- tmxr_rqln
- tmxr_putc_ln
- tmxr_put_packet_ln
- tmxr_put_packet_ln_ex
- tmxr_poll_tx
- tmxr_send_buffered_data
- tmxr_tqln
- tmxr_tpqln
- tmxr_tpbusyln
- _mux_detach_line
- tmxr_detach_ln
- _tmln_speed_delta
- tmxr_set_line_speed
- tmxr_open_master
- tmxr_set_line_unit
- tmxr_set_line_output_unit
- tmxr_start_poll
- tmxr_stop_poll
- tmxr_add_to_open_list
- _tmxr_remove_from_open_list
- _tmxr_locate_line_send_expect
- tmxr_locate_line_send
- tmxr_locate_line_expect
- tmxr_change_async
- tmxr_attach_ex
- tmxr_startup
- tmxr_shutdown
- tmxr_show_open_devices
- tmxr_close_master
- tmxr_detach
- tmxr_activate
- tmxr_activate_after
- tmxr_attach_help
- tmxr_ex
- tmxr_dep
- tmxr_msg
- tmxr_linemsg
- tmxr_linemsgf
- tmxr_linemsgvf
- tmxr_fconns
- tmxr_fstats
- tmxr_dscln
- tmxr_set_log
- tmxr_set_nolog
- tmxr_show_log
- tmxr_set_lnorder
- tmxr_show_lnorder
- tmxr_show_summ
- tmxr_show_cstat
- tmxr_show_lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 #include "sim_defs.h"
94 #include "sim_sock.h"
95 #include "sim_timer.h"
96 #include "sim_tmxr.h"
97 #include "scp.h"
98
99 #define DBG_CTR 0
100
101 #include "../dps8/dps8.h"
102 #include "../dps8/dps8_sir.h"
103
104 #include <ctype.h>
105 #include <time.h>
106 #include <sys/time.h>
107 #include <signal.h>
108 #include <unistd.h>
109 #include <math.h>
110
111 #if defined(__MINGW64__) || defined(__MINGW32__)
112 # include "../dps8/bsd_random.h"
113 # define random bsd_random
114 # define srandom bsd_srandom
115 #endif
116
117
118
119
120
121 #define FREE(p) do \
122 { \
123 free((p)); \
124 (p) = NULL; \
125 } while(0)
126
127
128
129
130 #define TN_IAC 0xFFu
131 #define TN_DONT 0xFEu
132 #define TN_DO 0xFDu
133 #define TN_WONT 0xFCu
134 #define TN_WILL 0xFBu
135 #define TN_SB 0xFAu
136 #define TN_GA 0xF9u
137 #define TN_EL 0xF8u
138 #define TN_EC 0xF7u
139 #define TN_AYT 0xF6u
140 #define TN_AO 0xF5u
141 #define TN_IP 0xF4u
142 #define TN_BRK 0xF3u
143 #define TN_DATAMK 0xF2u
144 #define TN_NOP 0xF1u
145 #define TN_SE 0xF0u
146
147
148
149 #define TN_BIN 0
150 #define TN_ECHO 1
151 #define TN_SGA 3
152 #define TN_STATUS 5
153 #define TN_TIMING 6
154 #define TN_NAOCRD 10
155 #define TN_NAOHTS 11
156 #define TN_NAOHTD 12
157 #define TN_NAOFFD 13
158 #define TN_NAOVTS 14
159 #define TN_NAOVTD 15
160 #define TN_NAOLFD 16
161 #define TN_EXTEND 17
162 #define TN_LOGOUT 18
163 #define TN_BM 19
164 #define TN_DET 20
165 #define TN_SENDLO 23
166 #define TN_TERMTY 24
167 #define TN_ENDREC 25
168 #define TN_TUID 26
169 #define TN_OUTMRK 27
170 #define TN_TTYLOC 28
171 #define TN_3270 29
172 #define TN_X3PAD 30
173 #define TN_NAWS 31
174 #define TN_TERMSP 32
175 #define TN_TOGFLO 33
176 #define TN_LINE 34
177 #define TN_XDISPL 35
178 #define TN_ENVIRO 36
179 #define TN_AUTH 37
180 #define TN_ENCRYP 38
181 #define TN_NEWENV 39
182 #define TN_TN3270 40
183 #define TN_CHARST 42
184 #define TN_COMPRT 44
185 #define TN_KERMIT 47
186
187 #define TN_CR 015
188 #define TN_LF 012
189 #define TN_NUL 000
190
191
192
193 #define TNS_NORM 000
194 #define TNS_IAC 001
195 #define TNS_WILL 002
196 #define TNS_WONT 003
197 #define TNS_SKIP 004
198 #define TNS_CRPAD 005
199 #define TNS_DO 006
200
201
202
203 #define TNOS_DONT 001
204 #define TNOS_WONT 002
205
206
207
208
209
210
211
212
213
214
215
216 static u_char mantra[] = {
217 TN_IAC, TN_WILL, TN_LINE,
218 TN_IAC, TN_WILL, TN_SGA,
219 TN_IAC, TN_WILL, TN_ECHO,
220 TN_IAC, TN_WILL, TN_BIN,
221 TN_IAC, TN_DO, TN_BIN
222 };
223
224 #define TMXR_GUARD ((sizeof(mantra)))
225
226
227
228 static void tmxr_add_to_open_list (TMXR* mux);
229
230
231
232
233
234
235
236
237
238
239
240
241 static void tmxr_init_line (TMLN *lp)
242 {
243 lp->tsta = 0;
244 lp->xmte = 1;
245 lp->dstb = 0;
246 lp->rxbpr = lp->rxbpi = lp->rxcnt = lp->rxpcnt = 0;
247 if (!lp->txbfd || lp->notelnet)
248 lp->txbpr = lp->txbpi = lp->txcnt = lp->txpcnt = 0;
249 lp->txdrp = 0;
250 tmxr_set_get_modem_bits (lp, 0, 0, NULL);
251 if ((!lp->mp->buffered) && (!lp->txbfd)) {
252 lp->txbfd = 0;
253 lp->txbsz = TMXR_MAXBUF;
254 lp->txb = (char *)realloc (lp->txb, lp->txbsz);
255 if (!lp->txb)
256 {
257 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
258 __func__, __FILE__, __LINE__);
259 #if defined(USE_BACKTRACE)
260 # if defined(SIGUSR2)
261 (void)raise(SIGUSR2);
262
263 # endif
264 #endif
265 abort();
266 }
267 lp->rxbsz = TMXR_MAXBUF;
268 lp->rxb = (char *)realloc(lp->rxb, lp->rxbsz);
269 if (!lp->rxb)
270 {
271 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
272 __func__, __FILE__, __LINE__);
273 #if defined(USE_BACKTRACE)
274 # if defined(SIGUSR2)
275 (void)raise(SIGUSR2);
276
277 # endif
278 #endif
279 abort();
280 }
281 lp->rbr = (char *)realloc(lp->rbr, lp->rxbsz);
282 if (!lp->rbr)
283 {
284 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
285 __func__, __FILE__, __LINE__);
286 #if defined(USE_BACKTRACE)
287 # if defined(SIGUSR2)
288 (void)raise(SIGUSR2);
289
290 # endif
291 #endif
292 abort();
293 }
294 }
295 if (lp->loopback) {
296 lp->lpbsz = lp->rxbsz;
297 lp->lpb = (char *)realloc(lp->lpb, lp->lpbsz);
298 if (!lp->lpb)
299 {
300 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
301 __func__, __FILE__, __LINE__);
302 #if defined(USE_BACKTRACE)
303 # if defined(SIGUSR2)
304 (void)raise(SIGUSR2);
305
306 # endif
307 #endif
308 abort();
309 }
310 lp->lpbcnt = lp->lpbpi = lp->lpbpr = 0;
311 }
312 if (lp->rxpb) {
313 lp->rxpboffset = lp->rxpbsize = 0;
314 FREE (lp->rxpb);
315 lp->rxpb = NULL;
316 }
317 if (lp->txpb) {
318 lp->txpbsize = lp->txppsize = lp->txppoffset = 0;
319 FREE (lp->txpb);
320 lp->txpb = NULL;
321 }
322 (void)memset (lp->rbr, 0, lp->rxbsz);
323 return;
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 static void tmxr_report_connection (TMXR *mp, TMLN *lp)
340 {
341 int32 unwritten, psave;
342 char cmsg[160];
343 char dmsg[80] = "";
344 char lmsg[80] = "";
345 char msgbuf[512] = "";
346
347 if ((!lp->notelnet) || (sim_switches & SWMASK ('V'))) {
348 (void)sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name);
349
350 if (mp->dptr) {
351 (void)sprintf (dmsg, "%s device",
352 sim_dname (mp->dptr));
353
354 if (mp->lines > 1)
355 (void)sprintf (lmsg, ", line %d", (int)(lp-mp->ldsc));
356 }
357
358 (void)sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg);
359 }
360
361 if (!mp->buffered) {
362 lp->txbpi = 0;
363 lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf));
364 lp->rxcnt = lp->txcnt = lp->txdrp = 0;
365 lp->rxpcnt = lp->txpcnt = 0;
366 }
367 else
368 if (lp->txcnt > lp->txbsz)
369 lp->txbpr = (lp->txbpi + 1) % lp->txbsz;
370 else
371 lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf));
372
373 psave = lp->txbpi;
374 lp->txbpi = lp->txbpr;
375 tmxr_linemsg (lp, msgbuf);
376 lp->txbpi = psave;
377
378 unwritten = tmxr_send_buffered_data (lp);
379
380 if (unwritten == 0)
381 lp->xmte = 1;
382
383 lp->txcnt -= (int32)strlen (msgbuf);
384 return;
385 }
386
387
388
389
390
391
392
393
394
395
396
397 static void tmxr_report_disconnection (TMLN *lp)
398 {
399 if (lp->notelnet)
400 return;
401 tmxr_linemsgf (lp, "\r\nDisconnected from the %s simulator\r\n\n", sim_name);
402 return;
403 }
404
405 static int32 loop_write_ex (TMLN *lp, char *buf, int32 length, t_bool prefix_datagram)
406 {
407 int32 written = 0;
408 int32 loopfree = lp->lpbsz - lp->lpbcnt;
409
410 if (lp->datagram && prefix_datagram) {
411 if ((size_t)loopfree < (size_t)(length + sizeof(length)))
412 return written;
413 loop_write_ex (lp, (char *)&length, sizeof(length), FALSE);
414 }
415 while (length) {
416 int32 chunksize;
417
418 loopfree = lp->lpbsz - lp->lpbcnt;
419 if (loopfree == 0)
420 break;
421 if (loopfree < length)
422 length = loopfree;
423 if (lp->lpbpi >= lp->lpbpr)
424 chunksize = lp->lpbsz - lp->lpbpi;
425 else
426 chunksize = lp->lpbpr - lp->lpbpi;
427 if (chunksize > length)
428 chunksize = length;
429 memcpy (&lp->lpb[lp->lpbpi], buf, chunksize);
430 buf += chunksize;
431 length -= chunksize;
432 written += chunksize;
433 lp->lpbpi = (lp->lpbpi + chunksize) % lp->lpbsz;
434 }
435 lp->lpbcnt += written;
436 return written;
437 }
438
439 static int32 loop_write (TMLN *lp, char *buf, int32 length)
440 {
441 return loop_write_ex (lp, buf, length, TRUE);
442 }
443
444 static int32 loop_read_ex (TMLN *lp, char *buf, int32 bufsize)
445 {
446 int32 bytesread = 0;
447
448 while (bufsize > 0) {
449 int32 chunksize;
450 int32 loopused = lp->lpbcnt;
451
452 if (loopused < bufsize)
453 bufsize = loopused;
454 if (loopused == 0)
455 break;
456 if (lp->lpbpi > lp->lpbpr)
457 chunksize = lp->lpbpi - lp->lpbpr;
458 else
459 chunksize = lp->lpbsz - lp->lpbpr;
460 if (chunksize > bufsize)
461 chunksize = bufsize;
462 memcpy (buf, &lp->lpb[lp->lpbpr], chunksize);
463 buf += chunksize;
464 bufsize -= chunksize;
465 bytesread += chunksize;
466 lp->lpbpr = (lp->lpbpr + chunksize) % lp->lpbsz;
467 }
468 lp->lpbcnt -= bytesread;
469 return bytesread;
470 }
471
472 static int32 loop_read (TMLN *lp, char *buf, int32 bufsize)
473 {
474 if (lp->datagram) {
475 int32 pktsize;
476
477 if (lp->lpbcnt < (int32)sizeof(pktsize))
478 return 0;
479 if ((sizeof(pktsize) != loop_read_ex (lp, (char *)&pktsize, sizeof(pktsize))) ||
480 (pktsize > bufsize))
481 return -1;
482 bufsize = pktsize;
483 }
484 return loop_read_ex (lp, buf, bufsize);
485 }
486
487
488
489
490
491
492
493
494
495 static int32 tmxr_read (TMLN *lp, int32 length)
496 {
497 int32 i = lp->rxbpi;
498
499 if (lp->loopback)
500 return loop_read (lp, &(lp->rxb[i]), length);
501 else
502 return sim_read_sock (lp->sock, &(lp->rxb[i]), length);
503 }
504
505
506
507
508
509
510
511
512 static int32 tmxr_write (TMLN *lp, int32 length)
513 {
514 int32 written;
515 int32 i = lp->txbpr;
516
517 if (lp->loopback)
518 return loop_write (lp, &(lp->txb[i]), length);
519
520 written = sim_write_sock (lp->sock, &(lp->txb[i]), length);
521
522 if (written == SOCKET_ERROR)
523 if (lp->datagram)
524 return written;
525 else
526 return -1;
527 else
528 return written;
529 }
530
531
532
533
534
535
536
537
538 static void tmxr_rmvrc (TMLN *lp, int32 p)
539 {
540 for ( ; p < lp->rxbpi; p++) {
541 lp->rxb[p] = lp->rxb[p + 1];
542 lp->rbr[p] = lp->rbr[p + 1];
543 }
544
545 lp->rbr[p] = 0;
546 lp->rxbpi = lp->rxbpi - 1;
547 return;
548 }
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565 static TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, const TMXR *mp)
566 {
567 if (mp == NULL)
568 return NULL;
569 if (uptr) {
570 DEVICE *dptr = find_dev_from_unit (uptr);
571 if (dptr == NULL)
572 return NULL;
573 val = (int32) (uptr - dptr->units);
574 }
575 if ((val < 0) || (val >= mp->lines))
576 return NULL;
577 return mp->ldsc + val;
578 }
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596 static TMLN *tmxr_get_ldsc (UNIT *uptr, const char *cptr, TMXR *mp, t_stat *status)
597 {
598 t_value ln;
599 TMLN *lp = NULL;
600 t_stat code = SCPE_OK;
601
602 if (mp == NULL)
603 code = SCPE_IERR;
604
605 else if (uptr) {
606 lp = tmxr_find_ldsc (uptr, mp->lines, mp);
607
608 if (lp == NULL)
609 code = SCPE_IERR;
610 }
611
612 else if (cptr == NULL)
613 code = SCPE_MISVAL;
614
615 else {
616 ln = get_uint (cptr, 10, mp->lines - 1, &code);
617
618 if (code == SCPE_OK)
619 lp = mp->ldsc + (int32) ln;
620 }
621
622 if (status)
623 *status = code;
624
625 return lp;
626 }
627
628
629
630
631
632
633
634
635
636
637
638 static char *growstring(char **string, size_t growth)
639 {
640 if (!*string)
641 {
642 fprintf(stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
643 __func__, __FILE__, __LINE__);
644 #if defined(USE_BACKTRACE)
645 # if defined(SIGUSR2)
646 (void)raise(SIGUSR2);
647
648 # endif
649 #endif
650 abort();
651 }
652 *string = (char *)realloc (*string, 1 + (*string ? strlen (*string) : 0) + growth);
653 if (!*string)
654 {
655 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
656 __func__, __FILE__, __LINE__);
657 #if defined(USE_BACKTRACE)
658 # if defined(SIGUSR2)
659 (void)raise(SIGUSR2);
660
661 # endif
662 #endif
663 abort();
664 }
665 return *string + strlen(*string);
666 }
667
668 static char *tmxr_mux_attach_string(char *old, TMXR *mp)
669 {
670 char* tptr = NULL;
671 int32 i;
672 TMLN *lp;
673
674 FREE (old);
675 tptr = (char *) calloc (1, 1);
676 if (tptr == NULL)
677 return tptr;
678
679 if (mp->port)
680 (void)sprintf (growstring(&tptr, 33 + strlen (mp->port)), "%s%s",
681 mp->port, mp->notelnet ? ";notelnet" : "");
682 if (mp->logfiletmpl[0])
683 (void)sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s",
684 mp->logfiletmpl);
685 while ((*tptr == ',') || (*tptr == ' '))
686 memmove (tptr, tptr+1, strlen(tptr+1)+1);
687 for (i=0; i<mp->lines; ++i) {
688 char *lptr;
689 lp = mp->ldsc + i;
690
691 lptr = tmxr_line_attach_string(lp);
692 if (lptr) {
693 char *tempstr = growstring(&tptr, 10 + strlen(lptr));
694 (void)sprintf(tempstr, "%s%s", *tptr ? "," : "", lptr);
695 FREE (lptr);
696 }
697 }
698 if (mp->lines == 1)
699 while ((*tptr == ',') || (*tptr == ' '))
700 memcpy (tptr, tptr+1, strlen(tptr+1)+1);
701 if (*tptr == '\0') {
702 FREE (tptr);
703 tptr = NULL;
704 }
705 return tptr;
706 }
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723 char *tmxr_line_attach_string(TMLN *lp)
724 {
725 char* tptr = NULL;
726
727 tptr = (char *) calloc (1, 1);
728 if (tptr == NULL)
729 return tptr;
730
731 if (lp->destination || lp->port || lp->txlogname) {
732 if ((lp->mp->lines > 1) || (lp->port))
733 (void)sprintf (growstring(&tptr, 32), "Line=%d", (int)(lp-lp->mp->ldsc));
734 if (lp->modem_control != lp->mp->modem_control)
735 (void)sprintf (growstring(&tptr, 32), ",%s", lp->modem_control ? "Modem" : "NoModem");
736 if (lp->txbfd && (lp->txbsz != lp->mp->buffered))
737 (void)sprintf (growstring(&tptr, 32), ",Buffered=%d", lp->txbsz);
738 if (!lp->txbfd && (lp->mp->buffered > 0))
739 (void)sprintf (growstring(&tptr, 32), ",UnBuffered");
740 if (lp->mp->datagram != lp->datagram)
741 (void)sprintf (growstring(&tptr, 8), ",%s", lp->datagram ? "UDP" : "TCP");
742 if (lp->mp->packet != lp->packet)
743 (void)sprintf (growstring(&tptr, 8), ",Packet");
744 if (lp->port)
745 (void)sprintf (growstring(&tptr, 32 + strlen (lp->port)), ",%s%s",
746 lp->port, ((lp->mp->notelnet != lp->notelnet) && \
747 (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : "");
748 if (lp->destination) {
749 (void)sprintf (growstring(&tptr, 25 + strlen (lp->destination)),
750 ",Connect=%s%s", lp->destination,
751 ((lp->mp->notelnet != lp->notelnet) && \
752 (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : "");
753 }
754 if (lp->txlogname)
755 (void)sprintf (growstring(&tptr, 12 + strlen (lp->txlogname)), ",Log=%s", lp->txlogname);
756 if (lp->loopback)
757 (void)sprintf (growstring(&tptr, 12 ), ",Loopback");
758 }
759 if (*tptr == '\0') {
760 FREE (tptr);
761 tptr = NULL;
762 }
763 return tptr;
764 }
765
766 static inline uint32_t
767 hash32s(const void *buf, size_t len, uint32_t h)
768 {
769 const unsigned char *p = buf;
770
771 for (size_t i = 0; i < len; i++)
772 h = h * 31 + p[i];
773
774 h ^= h >> 17;
775 h *= UINT32_C(0xed5ad4bb);
776 h ^= h >> 11;
777 h *= UINT32_C(0xac4c1b51);
778 h ^= h >> 15;
779 h *= UINT32_C(0x31848bab);
780 h ^= h >> 14;
781
782 return h;
783 }
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799 int32 tmxr_poll_conn (TMXR *mp)
800 {
801 SOCKET newsock;
802 TMLN *lp = NULL;
803 int32 *op;
804 int32 i, j;
805 int st1ret;
806 char *address;
807 char msg[512];
808 uint32 poll_time = sim_os_msec ();
809 struct timespec ts;
810
811 (void)lp;
812 (void)memset (msg, 0, sizeof (msg));
813 if (mp->last_poll_time == 0) {
814 UNIT *uptr = mp->uptr;
815
816 if (!uptr)
817 return -1;
818
819 if (mp->poll_interval == 0)
820 mp->poll_interval = TMXR_DEFAULT_CONNECT_POLL_INTERVAL;
821
822 if (!(uptr->dynflags & TMUF_NOASYNCH)) {
823 uptr->dynflags |= UNIT_TM_POLL;
824 sim_cancel (uptr);
825 }
826 for (i=0; i < mp->lines; i++) {
827 uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
828
829 if (!(mp->uptr->dynflags & TMUF_NOASYNCH)) {
830 uptr->dynflags |= UNIT_TM_POLL;
831 sim_cancel (uptr);
832 }
833 }
834 }
835
836 if ((poll_time - mp->last_poll_time) < mp->poll_interval*1000)
837 return -1;
838
839 st1ret = clock_gettime(SIR_WALLCLOCK, &ts);
840 if (st1ret != 0)
841 {
842 fprintf (stderr, "\rFATAL: clock_gettime failure! Aborting at %s[%s:%d]\r\n",
843 __func__, __FILE__, __LINE__);
844 #if defined(USE_BACKTRACE)
845 # if defined(SIGUSR2)
846 (void)raise(SIGUSR2);
847
848 # endif
849 #endif
850 abort();
851 }
852
853 uint32_t h = 0;
854 #if __STDC_VERSION__ < 201112L
855
856 void *(*mallocptr)() = malloc;
857 h = hash32s(&mallocptr, sizeof(mallocptr), h);
858 #endif
859 void *ptr = &ptr;
860 h = hash32s(&ptr, sizeof(ptr), h);
861 time_t t = time(0);
862 h = hash32s(&t, sizeof(t), h);
863 #if !defined(_AIX)
864 for (int i = 0; i < 1000; i++)
865 {
866 unsigned long counter = 0;
867 clock_t start = clock();
868 while (clock() == start)
869 {
870 counter++;
871 }
872 h = hash32s(&start, sizeof(start), h);
873 h = hash32s(&counter, sizeof(counter), h);
874 }
875 #endif
876 int mypid = (int)_sir_getpid();
877 h = hash32s(&mypid, sizeof(mypid), h);
878 char rnd[4];
879 FILE *f = fopen("/dev/urandom", "rb");
880 if (f)
881 {
882 if (fread(rnd, sizeof(rnd), 1, f))
883 {
884 h = hash32s(rnd, sizeof(rnd), h);
885 }
886 fclose(f);
887 }
888 srandom(h);
889
890 mp->last_poll_time = poll_time;
891
892
893
894 if (mp->master) {
895 if (mp->ring_sock != INVALID_SOCKET) {
896 newsock = mp->ring_sock;
897 mp->ring_sock = INVALID_SOCKET;
898 address = mp->ring_ipad;
899 mp->ring_ipad = NULL;
900 }
901 else
902 newsock = sim_accept_conn_ex (mp->master, &address, (mp->packet ? SIM_SOCK_OPT_NODELAY : 0));
903
904 if (newsock != INVALID_SOCKET) {
905 snprintf (msg, sizeof (msg)-1, "tmxr_poll_conn() - Connection from %s", address);
906 op = mp->lnorder;
907 i = mp->lines;
908 ++mp->sessions;
909
910 for (j = 0; j < mp->lines; j++, i++) {
911 if (op && (*op >= 0) && (*op < mp->lines))
912 i = *op++;
913 else
914 i = j;
915
916 lp = mp->ldsc + i;
917 if ((lp->conn == FALSE) &&
918 (lp->destination == NULL) &&
919 (lp->master == 0) &&
920 (lp->ser_connect_pending == FALSE) &&
921 (lp->modem_control ? ((lp->modembits & TMXR_MDM_DTR) != 0) : TRUE))
922 break;
923 }
924
925 if (i >= mp->lines) {
926 int32 ringable_count = 0;
927
928 for (j = 0; j < mp->lines; j++, i++) {
929 lp = mp->ldsc + j;
930 if ((lp->conn == FALSE) &&
931 (lp->destination == NULL) &&
932 (lp->master == 0) &&
933 (lp->ser_connect_pending == FALSE) &&
934 ((lp->modembits & TMXR_MDM_DTR) == 0)) {
935 ++ringable_count;
936 tmxr_set_get_modem_bits (lp, TMXR_MDM_RNG, 0, NULL);
937 }
938 }
939 if (ringable_count > 0) {
940 if (mp->ring_start_time == 0) {
941 mp->ring_start_time = poll_time;
942 mp->ring_sock = newsock;
943 mp->ring_ipad = address;
944 }
945 else {
946 if ((poll_time - mp->ring_start_time) < TMXR_MODEM_RING_TIME*1000) {
947 mp->ring_sock = newsock;
948 mp->ring_ipad = address;
949 }
950 else {
951 int ln;
952
953
954 for (ln = 0; ln < lp->mp->lines; ln++) {
955 TMLN *tlp = lp->mp->ldsc + ln;
956 if (((tlp->destination == NULL) && (tlp->master == 0)) &&
957 (tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
958 tlp->modembits &= ~TMXR_MDM_RNG;
959 }
960 mp->ring_start_time = 0;
961 tmxr_msg (newsock, "No answer on any connection\r\n");
962 sim_close_sock (newsock);
963 FREE (address);
964 }
965 }
966 }
967 else {
968 tmxr_msg (newsock, "All connections busy\r\n");
969 sim_close_sock (newsock);
970 FREE (address);
971 }
972 }
973 else {
974 lp = mp->ldsc + i;
975 lp->conn = TRUE;
976 lp->sock = newsock;
977 lp->ipad = address;
978 tmxr_init_line (lp);
979 lp->notelnet = mp->notelnet;
980 if (!lp->notelnet) {
981 sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
982 lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
983 if (!lp->telnet_sent_opts)
984 {
985 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
986 __func__, __FILE__, __LINE__);
987 #if defined(USE_BACKTRACE)
988 # if defined(SIGUSR2)
989 (void)raise(SIGUSR2);
990
991 # endif
992 #endif
993 abort();
994 }
995 (void)memset (lp->telnet_sent_opts, 0, 256);
996 }
997 tmxr_report_connection (mp, lp);
998 lp->cnms = sim_os_msec ();
999 return i;
1000 }
1001 }
1002 }
1003
1004
1005 for (i = 0; i < mp->lines; i++) {
1006 int j, r = (int)random();
1007 lp = mp->ldsc + i;
1008
1009 if (lp->ser_connect_pending) {
1010 lp->ser_connect_pending = FALSE;
1011 lp->conn = TRUE;
1012 return i;
1013 }
1014
1015
1016
1017 if (lp->loopback)
1018 continue;
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 for (j=0; j<2; j++)
1030 switch (((unsigned)j+(unsigned)r)&1) {
1031 case 0:
1032 if (lp->connecting) {
1033 char *sockname, *peername;
1034
1035 switch (sim_check_conn(lp->connecting, FALSE))
1036 {
1037 case 1:
1038 lp->conn = TRUE;
1039 lp->sock = lp->connecting;
1040 lp->connecting = 0;
1041 int lpdlen = 1;
1042 if (lp->destination != NULL)
1043 lpdlen = 1+strlen (lp->destination);
1044 lp->ipad = (char *)realloc (lp->ipad, lpdlen);
1045 if (!lp->ipad)
1046 {
1047 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1048 __func__, __FILE__, __LINE__);
1049 #if defined(USE_BACKTRACE)
1050 # if defined(SIGUSR2)
1051 (void)raise(SIGUSR2);
1052
1053 # endif
1054 #endif
1055 abort();
1056 }
1057 if (lp->destination != NULL)
1058 (void)strcpy (lp->ipad, lp->destination);
1059 lp->cnms = sim_os_msec ();
1060 sim_getnames_sock (lp->sock, &sockname, &peername);
1061 if (lp->destination)
1062 snprintf (msg, sizeof(msg)-1,
1063 "tmxr_poll_conn() - Outgoing Line Connection to %s (%s->%s) established",
1064 lp->destination, sockname, peername);
1065 FREE (sockname);
1066 FREE (peername);
1067 return i;
1068 case -1:
1069 snprintf (msg, sizeof(msg)-1, "tmxr_poll_conn() - Outgoing Line Connection to %s failed",
1070 lp->destination);
1071 tmxr_reset_ln (lp);
1072 break;
1073 }
1074 }
1075 break;
1076 case 1:
1077 if (lp->master) {
1078 while (INVALID_SOCKET != (newsock = sim_accept_conn_ex (lp->master, &address,
1079 (lp->packet ? SIM_SOCK_OPT_NODELAY : 0)))) {
1080 char *sockname, *peername;
1081
1082 sim_getnames_sock (newsock, &sockname, &peername);
1083 snprintf (msg, sizeof(msg)-1, "tmxr_poll_conn() - Incoming Line Connection from %s (%s->%s)",
1084 address, peername, sockname);
1085 FREE (sockname);
1086 FREE (peername);
1087 ++mp->sessions;
1088
1089 if (lp->destination) {
1090 char host[sizeof(msg) - 64];
1091
1092 if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) {
1093 tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n");
1094 snprintf (msg, sizeof(msg)-1, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s",
1095 address, host);
1096 sim_close_sock (newsock);
1097 FREE (address);
1098 continue;
1099 }
1100 if (lp->connecting) {
1101 snprintf (msg, sizeof(msg)-1, "tmxr_poll_conn() - aborting outgoing line connection attempt to: %s",
1102 lp->destination);
1103 sim_close_sock (lp->connecting);
1104 lp->connecting = 0;
1105 }
1106 }
1107 if (lp->conn == FALSE) {
1108 if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) {
1109 lp->conn = TRUE;
1110 lp->sock = newsock;
1111 lp->ipad = address;
1112 tmxr_init_line (lp);
1113 if (!lp->notelnet) {
1114 sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
1115 lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
1116 if (!lp->telnet_sent_opts)
1117 {
1118 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1119 __func__, __FILE__, __LINE__);
1120 #if defined(USE_BACKTRACE)
1121 # if defined(SIGUSR2)
1122 (void)raise(SIGUSR2);
1123
1124 # endif
1125 #endif
1126 abort();
1127 }
1128 (void)memset (lp->telnet_sent_opts, 0, 256);
1129 }
1130 tmxr_report_connection (mp, lp);
1131 lp->cnms = sim_os_msec ();
1132 return i;
1133 }
1134 else {
1135 tmxr_msg (newsock, "Line connection not available\r\n");
1136 sim_close_sock (newsock);
1137 FREE (address);
1138 }
1139 }
1140 else {
1141 tmxr_msg (newsock, "Line connection busy\r\n");
1142 sim_close_sock (newsock);
1143 FREE (address);
1144 }
1145 }
1146 }
1147 break;
1148 }
1149
1150
1151
1152 if (lp->destination && (!lp->sock) && (!lp->connecting) &&
1153 (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR))) {
1154 snprintf (msg, sizeof(msg)-1, "tmxr_poll_conn() - establishing outgoing connection to: %s", lp->destination);
1155 lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL,
1156 lp->destination, "localhost", NULL,
1157 (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) |
1158 (lp->mp->packet ? SIM_SOCK_OPT_NODELAY : 0) |
1159 SIM_SOCK_OPT_BLOCKING);
1160 }
1161
1162 }
1163
1164 return -1;
1165 }
1166
1167
1168
1169 static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial)
1170 {
1171 char msg[512];
1172
1173 if (lp->txlog)
1174 (void)fflush (lp->txlog);
1175
1176 tmxr_send_buffered_data (lp);
1177
1178 snprintf (msg, sizeof(msg)-1, "tmxr_reset_ln_ex(%s)", closeserial ? "TRUE" : "FALSE");
1179
1180 if (lp->sock) {
1181 sim_close_sock (lp->sock);
1182 FREE (lp->telnet_sent_opts);
1183 lp->telnet_sent_opts = NULL;
1184 lp->sock = 0;
1185 lp->conn = FALSE;
1186 lp->cnms = 0;
1187 lp->xmte = 1;
1188 }
1189 FREE(lp->ipad);
1190 lp->ipad = NULL;
1191 if ((lp->destination)
1192 ) {
1193 if (lp->connecting) {
1194 sim_close_sock (lp->connecting);
1195 lp->connecting = 0;
1196 }
1197 if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) {
1198 snprintf (msg, sizeof(msg)-1, "tmxr_reset_ln_ex() - connecting to %s", lp->destination);
1199 lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL,
1200 lp->destination, "localhost", NULL,
1201 (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) |
1202 (lp->packet ? SIM_SOCK_OPT_NODELAY : 0) |
1203 SIM_SOCK_OPT_BLOCKING);
1204 }
1205 }
1206 tmxr_init_line (lp);
1207 return SCPE_OK;
1208 }
1209
1210 t_stat tmxr_close_ln (TMLN *lp)
1211 {
1212 return tmxr_reset_ln_ex (lp, TRUE);
1213 }
1214
1215 t_stat tmxr_reset_ln (TMLN *lp)
1216 {
1217 return tmxr_reset_ln_ex (lp, FALSE);
1218 }
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232 t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
1233 {
1234 int32 before_modem_bits, incoming_state = 0;
1235 DEVICE *dptr;
1236
1237 if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) ||
1238 (bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
1239 (bits_to_set & bits_to_clear))
1240 return SCPE_ARG;
1241 before_modem_bits = lp->modembits;
1242 lp->modembits |= bits_to_set;
1243 lp->modembits &= ~(bits_to_clear | TMXR_MDM_INCOMING);
1244 if ((lp->sock) || (lp->loopback)) {
1245 if (lp->modembits & TMXR_MDM_DTR) {
1246 incoming_state = TMXR_MDM_DSR;
1247 if (lp->modembits & TMXR_MDM_RTS)
1248 incoming_state |= TMXR_MDM_CTS;
1249 if (lp->halfduplex) {
1250 if (incoming_state & TMXR_MDM_CTS)
1251 incoming_state |= TMXR_MDM_DCD;
1252 }
1253 else
1254 incoming_state |= TMXR_MDM_DCD;
1255 }
1256
1257
1258
1259 }
1260 else {
1261 if (((before_modem_bits & TMXR_MDM_DTR) == 0) &&
1262 ((lp->modembits & TMXR_MDM_DTR) != 0) &&
1263 (lp->conn == FALSE) &&
1264 (lp->modembits & TMXR_MDM_RNG)) {
1265 if ((lp->destination == NULL) &&
1266 (lp->master == 0) &&
1267 (lp->mp && (lp->mp->ring_sock))) {
1268 int ln;
1269
1270 lp->conn = TRUE;
1271 lp->sock = lp->mp->ring_sock;
1272 lp->mp->ring_sock = INVALID_SOCKET;
1273 lp->ipad = lp->mp->ring_ipad;
1274 lp->mp->ring_ipad = NULL;
1275 lp->mp->ring_start_time = 0;
1276 tmxr_init_line (lp);
1277 lp->notelnet = lp->mp->notelnet;
1278 if (!lp->notelnet) {
1279 sim_write_sock (lp->sock, (char *)mantra, sizeof(mantra));
1280 lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
1281 if (!lp->telnet_sent_opts)
1282 {
1283 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1284 __func__, __FILE__, __LINE__);
1285 #if defined(USE_BACKTRACE)
1286 # if defined(SIGUSR2)
1287 (void)raise(SIGUSR2);
1288
1289 # endif
1290 #endif
1291 abort();
1292 }
1293 (void)memset (lp->telnet_sent_opts, 0, 256);
1294 }
1295 tmxr_report_connection (lp->mp, lp);
1296 lp->cnms = sim_os_msec ();
1297 lp->modembits &= ~TMXR_MDM_RNG;
1298
1299 for (ln = 0; ln < lp->mp->lines; ln++) {
1300 TMLN *tlp = lp->mp->ldsc + ln;
1301 if (((tlp->destination == NULL) && (tlp->master == 0)) &&
1302 (tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
1303 tlp->modembits &= ~TMXR_MDM_RNG;
1304 }
1305 }
1306 }
1307 if ((lp->master) || (lp->mp && lp->mp->master) ||
1308 (lp->port && lp->destination))
1309 incoming_state = TMXR_MDM_DSR;
1310 else
1311 incoming_state = 0;
1312 }
1313 lp->modembits |= incoming_state;
1314 dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
1315 (void)dptr;
1316
1317
1318
1319
1320 if (incoming_bits)
1321 *incoming_bits = lp->modembits;
1322 if (lp->mp && lp->modem_control) {
1323 if (bits_to_set | bits_to_clear) {
1324 if (lp->loopback) {
1325 if ((lp->modembits ^ before_modem_bits) & TMXR_MDM_DTR) {
1326 lp->ser_connect_pending = (lp->modembits & TMXR_MDM_DTR);
1327 lp->conn = !(lp->modembits & TMXR_MDM_DTR);
1328 }
1329 return SCPE_OK;
1330 }
1331 if ((lp->sock) || (lp->connecting)) {
1332 if ((before_modem_bits & bits_to_clear & TMXR_MDM_DTR) != 0) {
1333 if (lp->sock)
1334 tmxr_report_disconnection (lp);
1335 tmxr_reset_ln (lp);
1336 }
1337 }
1338 else {
1339 if ((lp->destination) &&
1340 (bits_to_set & ~before_modem_bits &
1341 TMXR_MDM_DTR)) {
1342 char msg[512];
1343
1344 snprintf (msg, sizeof(msg)-1, "tmxr_set_get_modem_bits() - establishing outgoing connection to: %s",
1345 lp->destination);
1346 lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL,
1347 (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) |
1348 (lp->packet ? SIM_SOCK_OPT_NODELAY : 0) |
1349 SIM_SOCK_OPT_BLOCKING);
1350 }
1351 }
1352 }
1353 return SCPE_OK;
1354 }
1355 if ((lp->sock) || (lp->connecting)) {
1356 if ((before_modem_bits & bits_to_clear & TMXR_MDM_DTR) != 0) {
1357 if (lp->sock)
1358 tmxr_report_disconnection (lp);
1359 tmxr_reset_ln (lp);
1360 }
1361 }
1362 return SCPE_INCOMP;
1363 }
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 t_stat tmxr_set_line_loopback (TMLN *lp, t_bool enable_loopback)
1375 {
1376 if (lp->loopback == (enable_loopback != FALSE))
1377 return SCPE_OK;
1378 lp->loopback = (enable_loopback != FALSE);
1379 if (lp->loopback) {
1380 lp->lpbsz = lp->rxbsz;
1381 lp->lpb = (char *)realloc(lp->lpb, lp->lpbsz);
1382 if (!lp->lpb)
1383 {
1384 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1385 __func__, __FILE__, __LINE__);
1386 #if defined(USE_BACKTRACE)
1387 # if defined(SIGUSR2)
1388 (void)raise(SIGUSR2);
1389
1390 # endif
1391 #endif
1392 abort();
1393 }
1394 lp->lpbcnt = lp->lpbpi = lp->lpbpr = 0;
1395 if (!lp->conn)
1396 lp->ser_connect_pending = TRUE;
1397 }
1398 else {
1399 FREE (lp->lpb);
1400 lp->lpb = NULL;
1401 lp->lpbsz = 0;
1402 }
1403 return SCPE_OK;
1404 }
1405
1406 t_bool tmxr_get_line_loopback (TMLN *lp)
1407 {
1408 return (lp->loopback != FALSE);
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425 t_stat tmxr_set_line_halfduplex (TMLN *lp, t_bool enable_halfduplex)
1426 {
1427 if (lp->halfduplex == (enable_halfduplex != FALSE))
1428 return SCPE_OK;
1429 lp->halfduplex = (enable_halfduplex != FALSE);
1430 return SCPE_OK;
1431 }
1432
1433 t_bool tmxr_get_line_halfduplex (TMLN *lp)
1434 {
1435 return (lp->halfduplex != FALSE);
1436 }
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 int32 tmxr_input_pending_ln (TMLN *lp)
1453 {
1454 return (lp->rxbpi - lp->rxbpr);
1455 }
1456
1457 int32 tmxr_getc_ln (TMLN *lp)
1458 {
1459 int32 j;
1460 t_stat val = 0;
1461 uint32 tmp;
1462
1463 if ((lp->conn && lp->rcve) &&
1464 ((!lp->rxbps) ||
1465 (sim_gtime () >= lp->rxnexttime))) {
1466 if (!sim_send_poll_data (&lp->send, &val)) {
1467 j = lp->rxbpi - lp->rxbpr;
1468 if (j) {
1469 tmp = lp->rxb[lp->rxbpr];
1470 val = TMXR_VALID | (tmp & 0377);
1471 if (lp->rbr[lp->rxbpr]) {
1472 lp->rbr[lp->rxbpr] = 0;
1473 val = val | SCPE_BREAK;
1474 }
1475 lp->rxbpr = lp->rxbpr + 1;
1476 }
1477 }
1478 }
1479 if (lp->rxbpi == lp->rxbpr)
1480 lp->rxbpi = lp->rxbpr = 0;
1481 if (lp->rxbps) {
1482 if (val)
1483 lp->rxnexttime = floor (sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ())/lp->rxbpsfactor));
1484 }
1485 return val;
1486 }
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize)
1508 {
1509 return tmxr_get_packet_ln_ex (lp, pbuf, psize, 0);
1510 }
1511
1512 t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte)
1513 {
1514 int32 c;
1515 size_t pktsize;
1516 size_t fc_size = (frame_byte ? 1 : 0);
1517
1518 while (TMXR_VALID & (c = tmxr_getc_ln (lp))) {
1519 if (lp->rxpboffset + 3 > lp->rxpbsize) {
1520 lp->rxpbsize += 512;
1521 lp->rxpb = (uint8 *)realloc (lp->rxpb, lp->rxpbsize);
1522 if (!lp->rxpb)
1523 {
1524 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1525 __func__, __FILE__, __LINE__);
1526 #if defined(USE_BACKTRACE)
1527 # if defined(SIGUSR2)
1528 (void)raise(SIGUSR2);
1529
1530 # endif
1531 #endif
1532 abort();
1533 }
1534 }
1535 if ((lp->rxpboffset == 0) && (fc_size) && (c != frame_byte)) {
1536 continue;
1537 }
1538 if ((lp->datagram) && (lp->rxpboffset == fc_size)) {
1539
1540
1541
1542
1543 lp->rxpb[lp->rxpboffset++] = (uint8)(((1 + lp->rxbpi - lp->rxbpr) >> 8) & 0xFF);
1544 lp->rxpb[lp->rxpboffset++] = (uint8)((1 + lp->rxbpi - lp->rxbpr) & 0xFF);
1545 }
1546 lp->rxpb[lp->rxpboffset++] = c & 0xFF;
1547 if (lp->rxpboffset >= (2 + fc_size)) {
1548 pktsize = (lp->rxpb[0+fc_size] << 8) | lp->rxpb[1+fc_size];
1549 if (pktsize == (lp->rxpboffset - 2)) {
1550 ++lp->rxpcnt;
1551 *pbuf = &lp->rxpb[2+fc_size];
1552 *psize = pktsize;
1553 lp->rxpboffset = 0;
1554 return SCPE_OK;
1555 }
1556 }
1557 }
1558 *pbuf = NULL;
1559 *psize = 0;
1560 if (lp->conn)
1561 return SCPE_OK;
1562 return SCPE_LOST;
1563 }
1564
1565
1566
1567
1568
1569
1570
1571
1572 void tmxr_poll_rx (TMXR *mp)
1573 {
1574 int32 i, nbytes, j;
1575 TMLN *lp;
1576
1577 for (i = 0; i < mp->lines; i++) {
1578 lp = mp->ldsc + i;
1579 if (!(lp->sock
1580 || lp->loopback) ||
1581 !(lp->rcve))
1582 continue;
1583
1584 nbytes = 0;
1585 if (lp->rxbpi == 0)
1586 nbytes = tmxr_read (lp,
1587 lp->rxbsz - TMXR_GUARD);
1588 else if (lp->tsta)
1589 nbytes = tmxr_read (lp,
1590 lp->rxbsz - lp->rxbpi);
1591
1592 if (nbytes < 0) {
1593 if (!lp->datagram) {
1594 if (!lp->txbfd || lp->notelnet)
1595 lp->txbpi = lp->txbpr = 0;
1596 tmxr_close_ln (lp);
1597 }
1598 }
1599
1600 else if (nbytes > 0) {
1601
1602 j = lp->rxbpi;
1603 lp->rxbpi = lp->rxbpi + nbytes;
1604 lp->rxcnt = lp->rxcnt + nbytes;
1605
1606
1607
1608 if (!lp->notelnet) {
1609 for (; j < lp->rxbpi; ) {
1610 u_char tmp = (u_char)lp->rxb[j];
1611 switch (lp->tsta) {
1612
1613 case TNS_NORM:
1614 if (tmp == TN_IAC) {
1615 lp->tsta = TNS_IAC;
1616 tmxr_rmvrc (lp, j);
1617 break;
1618 }
1619 if ((tmp == TN_CR) && lp->dstb)
1620 lp->tsta = TNS_CRPAD;
1621 j = j + 1;
1622 break;
1623
1624 case TNS_IAC:
1625 if (tmp == TN_IAC) {
1626 lp->tsta = TNS_NORM;
1627 j = j + 1;
1628 break;
1629 }
1630 if (tmp == TN_BRK) {
1631 lp->tsta = TNS_NORM;
1632 lp->rxb[j] = 0;
1633 lp->rbr[j] = 1;
1634 j = j + 1;
1635 break;
1636 }
1637 switch (tmp) {
1638 case TN_WILL:
1639 lp->tsta = TNS_WILL;
1640 break;
1641 case TN_WONT:
1642 lp->tsta = TNS_WONT;
1643 break;
1644 case TN_DO:
1645 lp->tsta = TNS_DO;
1646 break;
1647 case TN_DONT:
1648 lp->tsta = TNS_SKIP;
1649 break;
1650 case TN_GA: case TN_EL:
1651 case TN_EC: case TN_AYT:
1652 case TN_AO: case TN_IP:
1653 case TN_NOP:
1654 lp->tsta = TNS_NORM;
1655 break;
1656 case TN_SB:
1657 case TN_DATAMK:
1658 case TN_SE:
1659 lp->tsta = TNS_NORM;
1660 break;
1661 }
1662 tmxr_rmvrc (lp, j);
1663 break;
1664
1665 case TNS_WILL:
1666 if ((tmp == TN_STATUS) ||
1667 (tmp == TN_TIMING) ||
1668 (tmp == TN_NAOCRD) ||
1669 (tmp == TN_NAOHTS) ||
1670 (tmp == TN_NAOHTD) ||
1671 (tmp == TN_NAOFFD) ||
1672 (tmp == TN_NAOVTS) ||
1673 (tmp == TN_NAOVTD) ||
1674 (tmp == TN_NAOLFD) ||
1675 (tmp == TN_EXTEND) ||
1676 (tmp == TN_LOGOUT) ||
1677 (tmp == TN_BM) ||
1678 (tmp == TN_DET) ||
1679 (tmp == TN_SENDLO) ||
1680 (tmp == TN_TERMTY) ||
1681 (tmp == TN_ENDREC) ||
1682 (tmp == TN_TUID) ||
1683 (tmp == TN_OUTMRK) ||
1684 (tmp == TN_TTYLOC) ||
1685 (tmp == TN_3270) ||
1686 (tmp == TN_X3PAD) ||
1687 (tmp == TN_NAWS) ||
1688 (tmp == TN_TERMSP) ||
1689 (tmp == TN_TOGFLO) ||
1690 (tmp == TN_XDISPL) ||
1691 (tmp == TN_ENVIRO) ||
1692 (tmp == TN_AUTH) ||
1693 (tmp == TN_ENCRYP) ||
1694 (tmp == TN_NEWENV) ||
1695 (tmp == TN_TN3270) ||
1696 (tmp == TN_CHARST) ||
1697 (tmp == TN_COMPRT) ||
1698 (tmp == TN_KERMIT)) {
1699
1700 if (0 == (lp->telnet_sent_opts[tmp] & TNOS_DONT)) {
1701 lp->notelnet = TRUE;
1702 tmxr_putc_ln (lp, TN_IAC);
1703 lp->notelnet = FALSE;
1704 tmxr_putc_ln (lp, TN_DONT);
1705 tmxr_putc_ln (lp, tmp);
1706 lp->telnet_sent_opts[tmp] |= TNOS_DONT;
1707 }
1708 }
1709
1710 case TNS_WONT:
1711 if (tmp == TN_BIN) {
1712 if (lp->tsta == TNS_WILL) {
1713 lp->dstb = 0;
1714 }
1715 else {
1716 lp->dstb = 1;
1717 }
1718 }
1719 tmxr_rmvrc (lp, j);
1720 lp->tsta = TNS_NORM;
1721 break;
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737 case TNS_CRPAD:
1738 lp->tsta = TNS_NORM;
1739 if ((tmp == TN_LF) ||
1740 (tmp == TN_NUL))
1741 tmxr_rmvrc (lp, j);
1742 break;
1743
1744 case TNS_DO:
1745 if ((tmp == TN_STATUS) ||
1746 (tmp == TN_TIMING) ||
1747 (tmp == TN_NAOCRD) ||
1748 (tmp == TN_NAOHTS) ||
1749 (tmp == TN_NAOHTD) ||
1750 (tmp == TN_NAOFFD) ||
1751 (tmp == TN_NAOVTS) ||
1752 (tmp == TN_NAOVTD) ||
1753 (tmp == TN_NAOLFD) ||
1754 (tmp == TN_EXTEND) ||
1755 (tmp == TN_LOGOUT) ||
1756 (tmp == TN_BM) ||
1757 (tmp == TN_DET) ||
1758 (tmp == TN_SENDLO) ||
1759 (tmp == TN_TERMTY) ||
1760 (tmp == TN_ENDREC) ||
1761 (tmp == TN_TUID) ||
1762 (tmp == TN_OUTMRK) ||
1763 (tmp == TN_TTYLOC) ||
1764 (tmp == TN_3270) ||
1765 (tmp == TN_X3PAD) ||
1766 (tmp == TN_NAWS) ||
1767 (tmp == TN_TERMSP) ||
1768 (tmp == TN_TOGFLO) ||
1769 (tmp == TN_XDISPL) ||
1770 (tmp == TN_ENVIRO) ||
1771 (tmp == TN_AUTH) ||
1772 (tmp == TN_ENCRYP) ||
1773 (tmp == TN_NEWENV) ||
1774 (tmp == TN_TN3270) ||
1775 (tmp == TN_CHARST) ||
1776 (tmp == TN_COMPRT) ||
1777 (tmp == TN_KERMIT)) {
1778
1779 if (0 == (lp->telnet_sent_opts[tmp] & TNOS_WONT)) {
1780 lp->notelnet = TRUE;
1781 tmxr_putc_ln (lp, TN_IAC);
1782 lp->notelnet = FALSE;
1783 tmxr_putc_ln (lp, TN_WONT);
1784 tmxr_putc_ln (lp, tmp);
1785 lp->telnet_sent_opts[tmp] |= TNOS_WONT;
1786 }
1787 }
1788
1789 case TNS_SKIP: default:
1790 tmxr_rmvrc (lp, j);
1791 lp->tsta = TNS_NORM;
1792 break;
1793 }
1794 }
1795 }
1796 }
1797 }
1798 for (i = 0; i < mp->lines; i++) {
1799 lp = mp->ldsc + i;
1800 if (lp->rxbpi == lp->rxbpr)
1801 lp->rxbpi = lp->rxbpr = 0;
1802 }
1803 return;
1804 }
1805
1806
1807
1808 int32 tmxr_rqln_bare (const TMLN *lp, t_bool speed)
1809 {
1810 if ((speed) && (lp->rxbps)) {
1811 if (sim_gtime () < lp->rxnexttime)
1812 return 0;
1813 else
1814 return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz : 0)) ? 1 : 0;
1815 }
1816 return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz: 0));
1817 }
1818
1819 int32 tmxr_rqln (const TMLN *lp)
1820 {
1821 return tmxr_rqln_bare (lp, TRUE);
1822 }
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837 t_stat tmxr_putc_ln (TMLN *lp, int32 chr)
1838 {
1839 if ((lp->conn == FALSE) &&
1840 (!lp->txbfd || lp->notelnet)) {
1841 ++lp->txdrp;
1842 return SCPE_LOST;
1843 }
1844
1845 #define TXBUF_AVAIL(lp) (lp->txbsz - tmxr_tqln (lp))
1846
1847 #define TXBUF_CHAR(lp, c) { \
1848 lp->txb[lp->txbpi++] = (char)(c); \
1849 lp->txbpi %= lp->txbsz; \
1850 if (lp->txbpi == lp->txbpr) \
1851 lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \
1852 }
1853
1854 if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {
1855 if ((TN_IAC == (u_char) chr) && (!lp->notelnet))
1856 TXBUF_CHAR (lp, TN_IAC);
1857 TXBUF_CHAR (lp, chr);
1858 if ((!lp->txbfd) && ((unsigned long int)TXBUF_AVAIL (lp) <= TMXR_GUARD))
1859 lp->xmte = 0;
1860 if (lp->txlog)
1861 fputc (chr, lp->txlog);
1862 sim_exp_check (&lp->expect, chr);
1863 return SCPE_OK;
1864 }
1865 ++lp->txdrp; lp->xmte = 0;
1866 return SCPE_STALL;
1867 }
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886 t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size)
1887 {
1888 return tmxr_put_packet_ln_ex (lp, buf, size, 0);
1889 }
1890
1891 t_stat tmxr_put_packet_ln_ex (TMLN *lp, const uint8 *buf, size_t size, uint8 frame_byte)
1892 {
1893 t_stat r;
1894 size_t fc_size = (frame_byte ? 1 : 0);
1895 size_t pktlen_size = (lp->datagram ? 0 : 2);
1896
1897 if ((!lp->conn) && (!lp->loopback))
1898 return SCPE_LOST;
1899 if (lp->txppoffset < lp->txppsize) {
1900 return SCPE_STALL;
1901 }
1902 if (lp->txpbsize < size + pktlen_size + fc_size) {
1903 lp->txpbsize = size + pktlen_size + fc_size;
1904 lp->txpb = (uint8 *)realloc (lp->txpb, lp->txpbsize);
1905 if (!lp->txpb)
1906 {
1907 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1908 __func__, __FILE__, __LINE__);
1909 #if defined(USE_BACKTRACE)
1910 # if defined(SIGUSR2)
1911 (void)raise(SIGUSR2);
1912
1913 # endif
1914 #endif
1915 abort();
1916 }
1917 }
1918 lp->txpb[0] = frame_byte;
1919 if (!lp->datagram) {
1920 lp->txpb[0+fc_size] = (size >> 8) & 0xFF;
1921 lp->txpb[1+fc_size] = size & 0xFF;
1922 }
1923 memcpy (lp->txpb + pktlen_size + fc_size, buf, size);
1924 lp->txppsize = size + pktlen_size + fc_size;
1925 lp->txppoffset = 0;
1926 ++lp->txpcnt;
1927 while ((lp->txppoffset < lp->txppsize) &&
1928 (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
1929 ++lp->txppoffset;
1930 (void)r;
1931 tmxr_send_buffered_data (lp);
1932 return (lp->conn || lp->loopback) ? SCPE_OK : SCPE_LOST;
1933 }
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943 void tmxr_poll_tx (TMXR *mp)
1944 {
1945 int32 i, nbytes;
1946 TMLN *lp;
1947
1948 for (i = 0; i < mp->lines; i++) {
1949 lp = mp->ldsc + i;
1950 if (!lp->conn)
1951 continue;
1952 nbytes = tmxr_send_buffered_data (lp);
1953 if (nbytes == 0) {
1954 lp->xmte = 1;
1955 }
1956 }
1957 return;
1958 }
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968 int32 tmxr_send_buffered_data (TMLN *lp)
1969 {
1970 int32 nbytes, sbytes;
1971 t_stat r;
1972
1973 nbytes = tmxr_tqln(lp);
1974 if (nbytes) {
1975 if (lp->txbpr < lp->txbpi)
1976 sbytes = tmxr_write (lp, nbytes);
1977 else
1978 sbytes = tmxr_write (lp, lp->txbsz - lp->txbpr);
1979 if (sbytes >= 0) {
1980 lp->txbpr = (lp->txbpr + sbytes);
1981 if (lp->txbpr >= lp->txbsz)
1982 lp->txbpr = 0;
1983 lp->txcnt = lp->txcnt + sbytes;
1984 nbytes = nbytes - sbytes;
1985 if ((nbytes == 0) && (lp->datagram))
1986 lp->txbpi = lp->txbpr = 0;
1987 }
1988 if (sbytes < 0) {
1989 lp->txbpi = lp->txbpr = 0;
1990 lp->rxpboffset = lp->txppoffset = lp->txppsize = 0;
1991 tmxr_close_ln (lp);
1992 return nbytes;
1993 }
1994 if (nbytes && (lp->txbpr == 0)) {
1995 sbytes = tmxr_write (lp, nbytes);
1996 if (sbytes > 0) {
1997 lp->txbpr = (lp->txbpr + sbytes);
1998 if (lp->txbpr >= lp->txbsz)
1999 lp->txbpr = 0;
2000 lp->txcnt = lp->txcnt + sbytes;
2001 nbytes = nbytes - sbytes;
2002 }
2003 }
2004 }
2005 while ((lp->txppoffset < lp->txppsize) &&
2006 (lp->txbsz > nbytes) &&
2007 (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
2008 ++lp->txppoffset;
2009 (void)r;
2010 if ((nbytes == 0) && (tmxr_tqln(lp) > 0))
2011 return tmxr_send_buffered_data (lp);
2012 return tmxr_tqln(lp) + tmxr_tpqln(lp);
2013 }
2014
2015
2016
2017 int32 tmxr_tqln (const TMLN *lp)
2018 {
2019 return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0));
2020 }
2021
2022
2023
2024 int32 tmxr_tpqln (const TMLN *lp)
2025 {
2026 return (lp->txppsize - lp->txppoffset);
2027 }
2028
2029
2030
2031 t_bool tmxr_tpbusyln (const TMLN *lp)
2032 {
2033 return (0 != (lp->txppsize - lp->txppoffset));
2034 }
2035
2036 static void _mux_detach_line (TMLN *lp, t_bool close_listener, t_bool close_connecting)
2037 {
2038 if (close_listener && lp->master) {
2039 sim_close_sock (lp->master);
2040 lp->master = 0;
2041 FREE (lp->port);
2042 lp->port = NULL;
2043 }
2044 if (lp->sock) {
2045 tmxr_report_disconnection (lp);
2046 tmxr_reset_ln (lp);
2047 }
2048 if (close_connecting) {
2049 FREE (lp->destination);
2050 lp->destination = NULL;
2051 if (lp->connecting) {
2052 lp->sock = lp->connecting;
2053 lp->connecting = 0;
2054 tmxr_reset_ln (lp);
2055 }
2056 }
2057 tmxr_set_line_loopback (lp, FALSE);
2058 }
2059
2060 t_stat tmxr_detach_ln (TMLN *lp)
2061 {
2062 UNIT *uptr = NULL;
2063
2064 _mux_detach_line (lp, TRUE, TRUE);
2065 if (lp->mp) {
2066 if (lp->uptr)
2067 uptr = lp->uptr;
2068 else
2069 uptr = lp->mp->uptr;
2070 }
2071 if (uptr && uptr->filename) {
2072
2073 uptr->filename = tmxr_mux_attach_string (uptr->filename, lp->mp);
2074
2075 if (uptr->filename == NULL)
2076 tmxr_detach (lp->mp, uptr);
2077 }
2078 return SCPE_OK;
2079 }
2080
2081 static int32 _tmln_speed_delta (CONST char *cptr)
2082 {
2083 struct {
2084 const char *bps;
2085 int32 delta;
2086 } *spd, speeds[] = {
2087 { "50", TMLN_SPD_50_BPS },
2088 { "75", TMLN_SPD_75_BPS },
2089 { "110", TMLN_SPD_110_BPS },
2090 { "134", TMLN_SPD_134_BPS },
2091 { "150", TMLN_SPD_150_BPS },
2092 { "300", TMLN_SPD_300_BPS },
2093 { "600", TMLN_SPD_600_BPS },
2094 { "1200", TMLN_SPD_1200_BPS },
2095 { "1800", TMLN_SPD_1800_BPS },
2096 { "2000", TMLN_SPD_2000_BPS },
2097 { "2400", TMLN_SPD_2400_BPS },
2098 { "3600", TMLN_SPD_3600_BPS },
2099 { "4800", TMLN_SPD_4800_BPS },
2100 { "7200", TMLN_SPD_7200_BPS },
2101 { "9600", TMLN_SPD_9600_BPS },
2102 { "19200", TMLN_SPD_19200_BPS },
2103 { "38400", TMLN_SPD_38400_BPS },
2104 { "57600", TMLN_SPD_57600_BPS },
2105 { "76800", TMLN_SPD_76800_BPS },
2106 { "115200", TMLN_SPD_115200_BPS },
2107 { "0", 0 } };
2108 int nspeed;
2109 char speed[24];
2110
2111 nspeed = (uint32)strtotv (cptr, &cptr, 10);
2112 if ((*cptr != '\0') && (*cptr != '-') && (*cptr != '*'))
2113 return -1;
2114 (void)sprintf (speed, "%d", nspeed);
2115
2116 spd = speeds;
2117 while (1) {
2118 if (0 == strcmp(spd->bps, speed))
2119 return spd->delta;
2120 if (spd->delta == 0)
2121 break;
2122 ++spd;
2123 }
2124 return -1;
2125 }
2126
2127 t_stat tmxr_set_line_speed (TMLN *lp, CONST char *speed)
2128 {
2129 UNIT *uptr;
2130 CONST char *cptr;
2131 t_stat r;
2132
2133 if (!speed || !*speed)
2134 return SCPE_2FARG;
2135 if (_tmln_speed_delta (speed) < 0)
2136 return SCPE_ARG;
2137 if (lp == NULL)
2138 return SCPE_ARG;
2139 lp->rxbps = (uint32)strtotv (speed, &cptr, 10);
2140 if (*cptr == '*') {
2141 uint32 rxbpsfactor = (uint32) get_uint (cptr+1, 10, 32, &r);
2142 if (r != SCPE_OK)
2143 return r;
2144 lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE * rxbpsfactor;
2145 }
2146 lp->rxdelta = _tmln_speed_delta (speed);
2147 lp->rxnexttime = 0.0;
2148 uptr = lp->uptr;
2149 if ((!uptr) && (lp->mp))
2150 uptr = lp->mp->uptr;
2151 if (uptr)
2152 uptr->wait = lp->rxdelta;
2153 if (lp->rxbpsfactor == 0.0)
2154 lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE;
2155 lp->txbps = lp->rxbps;
2156 lp->txdelta = lp->rxdelta;
2157 lp->txnexttime = lp->rxnexttime;
2158 return SCPE_OK;
2159 }
2160
2161
2162
2163
2164
2165
2166
2167
2168 t_stat tmxr_open_master (TMXR *mp, CONST char *cptr)
2169 {
2170 int32 i, line, nextline = -1;
2171 char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE],
2172 logfiletmpl[CBUFSIZE], buffered[CBUFSIZE], hostport[CBUFSIZE*2],
2173 port[CBUFSIZE], option[CBUFSIZE], speed[CBUFSIZE];
2174 SOCKET sock;
2175 CONST char *tptr = cptr;
2176 t_bool nolog, notelnet, listennotelnet, modem_control, loopback, datagram, packet;
2177 TMLN *lp = NULL;
2178 t_stat r = SCPE_OK;
2179
2180 if (*tptr == '\0')
2181 return SCPE_ARG;
2182 for (i = 0; i < mp->lines; i++) {
2183 lp = mp->ldsc + i;
2184 lp->mp = mp;
2185 lp->modem_control = mp->modem_control;
2186 if (lp->rxbpsfactor == 0.0)
2187 lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE;
2188 }
2189 mp->ring_sock = INVALID_SOCKET;
2190 FREE (mp->ring_ipad);
2191 mp->ring_ipad = NULL;
2192 mp->ring_start_time = 0;
2193 while (*tptr) {
2194 line = nextline;
2195 (void)memset(logfiletmpl, '\0', sizeof(logfiletmpl));
2196 (void)memset(listen, '\0', sizeof(listen));
2197 (void)memset(destination, '\0', sizeof(destination));
2198 (void)memset(buffered, '\0', sizeof(buffered));
2199 (void)memset(port, '\0', sizeof(port));
2200 (void)memset(option, '\0', sizeof(option));
2201 (void)memset(speed, '\0', sizeof(speed));
2202 nolog = notelnet = listennotelnet = loopback = FALSE;
2203 datagram = mp->datagram;
2204 packet = mp->packet;
2205 if (mp->buffered)
2206 (void)sprintf(buffered, "%d", mp->buffered);
2207 if (line != -1)
2208 notelnet = listennotelnet = mp->notelnet;
2209 modem_control = mp->modem_control;
2210 while (*tptr) {
2211 tptr = get_glyph_nc (tptr, tbuf, ',');
2212 if (!tbuf[0])
2213 break;
2214 cptr = tbuf;
2215 if (!isdigit((unsigned char)*cptr)) {
2216 char gbuf[CBUFSIZE];
2217 CONST char *init_cptr = cptr;
2218
2219 cptr = get_glyph (cptr, gbuf, '=');
2220 if (0 == MATCH_CMD (gbuf, "LINE")) {
2221 if ((NULL == cptr) || ('\0' == *cptr))
2222 return sim_messagef (SCPE_2FARG, "Missing Line Specifier\n");
2223 nextline = (int32) get_uint (cptr, 10, mp->lines-1, &r);
2224 if (r)
2225 return sim_messagef (SCPE_ARG, "Invalid Line Specifier: %s\n", cptr);
2226 break;
2227 }
2228 if (0 == MATCH_CMD (gbuf, "LOG")) {
2229 if ((NULL == cptr) || ('\0' == *cptr))
2230 return sim_messagef (SCPE_2FARG, "Missing Log Specifier\n");
2231 strncpy(logfiletmpl, cptr, sizeof(logfiletmpl)-1);
2232 continue;
2233 }
2234 if (0 == MATCH_CMD (gbuf, "LOOPBACK")) {
2235 if ((NULL != cptr) && ('\0' != *cptr))
2236 return sim_messagef (SCPE_2MARG, "Unexpected Loopback Specifier: %s\n", cptr);
2237 loopback = TRUE;
2238 continue;
2239 }
2240 if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) || (0 == MATCH_CMD (gbuf, "UNBUFFERED"))) {
2241 if ((NULL != cptr) && ('\0' != *cptr))
2242 return sim_messagef (SCPE_2MARG, "Unexpected Unbuffered Specifier: %s\n", cptr);
2243 buffered[0] = '\0';
2244 continue;
2245 }
2246 if (0 == MATCH_CMD (gbuf, "BUFFERED")) {
2247 if ((NULL == cptr) || ('\0' == *cptr))
2248 (void)strcpy (buffered, "32768");
2249 else {
2250 i = (int32) get_uint (cptr, 10, 1024*1024, &r);
2251 if (r || (i == 0))
2252 return sim_messagef (SCPE_ARG, "Invalid Buffered Specifier: %s\n", cptr);
2253 (void)sprintf(buffered, "%d", i);
2254 }
2255 continue;
2256 }
2257 if (0 == MATCH_CMD (gbuf, "NOLOG")) {
2258 if ((NULL != cptr) && ('\0' != *cptr))
2259 return sim_messagef (SCPE_2MARG, "Unexpected NoLog Specifier: %s\n", cptr);
2260 nolog = TRUE;
2261 continue;
2262 }
2263 if (0 == MATCH_CMD (gbuf, "NOMODEM")) {
2264 if ((NULL != cptr) && ('\0' != *cptr))
2265 return sim_messagef (SCPE_2MARG, "Unexpected NoModem Specifier: %s\n", cptr);
2266 modem_control = FALSE;
2267 continue;
2268 }
2269 if (0 == MATCH_CMD (gbuf, "MODEM")) {
2270 if ((NULL != cptr) && ('\0' != *cptr))
2271 return sim_messagef (SCPE_2MARG, "Unexpected Modem Specifier: %s\n", cptr);
2272 modem_control = TRUE;
2273 continue;
2274 }
2275 if ((0 == MATCH_CMD (gbuf, "DATAGRAM")) || (0 == MATCH_CMD (gbuf, "UDP"))) {
2276 if ((NULL != cptr) && ('\0' != *cptr))
2277 return sim_messagef (SCPE_2MARG, "Unexpected Datagram Specifier: %s\n", cptr);
2278 notelnet = datagram = TRUE;
2279 continue;
2280 }
2281 if (0 == MATCH_CMD (gbuf, "PACKET")) {
2282 if ((NULL != cptr) && ('\0' != *cptr))
2283 return sim_messagef (SCPE_2MARG, "Unexpected Packet Specifier: %s\n", cptr);
2284 packet = TRUE;
2285 continue;
2286 }
2287 if ((0 == MATCH_CMD (gbuf, "STREAM")) || (0 == MATCH_CMD (gbuf, "TCP"))) {
2288 if ((NULL != cptr) && ('\0' != *cptr))
2289 return sim_messagef (SCPE_2MARG, "Unexpected Stream Specifier: %s\n", cptr);
2290 datagram = FALSE;
2291 continue;
2292 }
2293 if (0 == MATCH_CMD (gbuf, "CONNECT")) {
2294 if ((NULL == cptr) || ('\0' == *cptr))
2295 return sim_messagef (SCPE_2FARG, "Missing Connect Specifier\n");
2296 (void)strcpy (destination, cptr);
2297 continue;
2298 }
2299 if (0 == MATCH_CMD (gbuf, "SPEED")) {
2300 if ((NULL == cptr) || ('\0' == *cptr) ||
2301 (_tmln_speed_delta (cptr) < 0))
2302 return sim_messagef (SCPE_ARG, "Invalid Speed Specifier: %s\n", (cptr ? cptr : ""));
2303 (void)strcpy (speed, cptr);
2304 continue;
2305 }
2306 cptr = get_glyph (gbuf, port, ';');
2307 if (sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL, NULL))
2308 return sim_messagef (SCPE_ARG, "Invalid Port Specifier: %s\n", port);
2309 if (cptr) {
2310 char *tptr = gbuf + (cptr - gbuf);
2311 (void)get_glyph (cptr, tptr, 0);
2312 if (0 == MATCH_CMD (cptr, "NOTELNET"))
2313 listennotelnet = TRUE;
2314 else
2315 if (0 == MATCH_CMD (cptr, "TELNET"))
2316 listennotelnet = FALSE;
2317 else
2318 return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", tptr);
2319 }
2320 cptr = init_cptr;
2321 }
2322 cptr = get_glyph_nc (cptr, port, ';');
2323 sock = sim_master_sock (port, &r);
2324 if (r)
2325 return sim_messagef (SCPE_ARG, "Invalid Port Specifier: %s\n", port);
2326 if (sock == INVALID_SOCKET)
2327 return sim_messagef (SCPE_OPENERR, "Can't open network port: %s\n", port);
2328 sim_close_sock (sock);
2329 sim_os_ms_sleep (2);
2330 (void)strcpy (listen, port);
2331 cptr = get_glyph (cptr, option, ';');
2332 (void)cptr;
2333 if (option[0]) {
2334 if (0 == MATCH_CMD (option, "NOTELNET"))
2335 listennotelnet = TRUE;
2336 else
2337 if (0 == MATCH_CMD (option, "TELNET"))
2338 listennotelnet = FALSE;
2339 else {
2340 if (*tptr)
2341 return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", tptr);
2342 }
2343 }
2344 }
2345 if (destination[0]) {
2346
2347 char *eptr;
2348
2349 (void)memset (hostport, '\0', sizeof(hostport));
2350 strncpy (hostport, destination, sizeof(hostport));
2351 if ((eptr = strchr (hostport, ';')))
2352 *(eptr++) = '\0';
2353 if (eptr) {
2354 (void)get_glyph (eptr, eptr, 0);
2355 if (0 == MATCH_CMD (eptr, "NOTELNET"))
2356 notelnet = TRUE;
2357 else
2358 if (0 == MATCH_CMD (eptr, "TELNET"))
2359 if (datagram)
2360 return sim_messagef (SCPE_ARG, "Telnet invalid on Datagram socket\n");
2361 else
2362 notelnet = FALSE;
2363 else
2364 return sim_messagef (SCPE_ARG, "Unexpected specifier: %s\n", eptr);
2365 }
2366 sock = sim_connect_sock_ex (NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) |
2367 (packet ? SIM_SOCK_OPT_NODELAY : 0) |
2368 SIM_SOCK_OPT_BLOCKING);
2369 if (sock != INVALID_SOCKET)
2370 sim_close_sock (sock);
2371 else
2372 return sim_messagef (SCPE_ARG, "Invalid destination: %s\n", hostport);
2373 }
2374 if (line == -1) {
2375 if (modem_control != mp->modem_control)
2376 return SCPE_ARG;
2377 if (logfiletmpl[0]) {
2378 #if defined(__GNUC__)
2379 # if !defined(__clang_version__)
2380 # if !defined(__INTEL_COMPILER)
2381 # if __GNUC__ > 7
2382 # pragma GCC diagnostic push
2383 # pragma GCC diagnostic ignored "-Wstringop-truncation"
2384 # endif
2385 # endif
2386 # endif
2387 #endif
2388 strncpy(mp->logfiletmpl, logfiletmpl, sizeof(mp->logfiletmpl)-1);
2389 #if defined(__GNUC__)
2390 # if !defined(__clang_version__)
2391 # if !defined(__INTEL_COMPILER)
2392 # if __GNUC__ > 7
2393 # pragma GCC diagnostic pop
2394 # endif
2395 # endif
2396 # endif
2397 #endif
2398 for (i = 0; i < mp->lines; i++) {
2399 lp = mp->ldsc + i;
2400 sim_close_logfile (&lp->txlogref);
2401 lp->txlog = NULL;
2402 lp->txlogname = (char *)realloc(lp->txlogname, CBUFSIZE);
2403 if (!lp->txlogname)
2404 {
2405 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2406 __func__, __FILE__, __LINE__);
2407 #if defined(USE_BACKTRACE)
2408 # if defined(SIGUSR2)
2409 (void)raise(SIGUSR2);
2410
2411 # endif
2412 #endif
2413 abort();
2414 }
2415 if (mp->lines > 1)
2416 (void)sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i);
2417 else
2418 (void)strcpy (lp->txlogname, mp->logfiletmpl);
2419 r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
2420 if (r == SCPE_OK)
2421 setvbuf (lp->txlog, NULL, _IOFBF, 65536);
2422 else {
2423 FREE (lp->txlogname);
2424 lp->txlogname = NULL;
2425 break;
2426 }
2427 }
2428 }
2429 mp->buffered = atoi(buffered);
2430 for (i = 0; i < mp->lines; i++) {
2431 lp = mp->ldsc + i;
2432 if (mp->buffered) {
2433 lp->txbsz = mp->buffered;
2434 lp->txbfd = 1;
2435 lp->rxbsz = mp->buffered;
2436 }
2437 else {
2438 lp->txbsz = TMXR_MAXBUF;
2439 lp->txbfd = 0;
2440 lp->rxbsz = TMXR_MAXBUF;
2441 }
2442 lp->txbpi = lp->txbpr = 0;
2443 lp->txb = (char *)realloc(lp->txb, lp->txbsz);
2444 if (!lp->txb)
2445 {
2446 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2447 __func__, __FILE__, __LINE__);
2448 #if defined(USE_BACKTRACE)
2449 # if defined(SIGUSR2)
2450 (void)raise(SIGUSR2);
2451
2452 # endif
2453 #endif
2454 abort();
2455 }
2456 lp->rxb = (char *)realloc(lp->rxb, lp->rxbsz);
2457 if (!lp->rxb)
2458 {
2459 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2460 __func__, __FILE__, __LINE__);
2461 #if defined(USE_BACKTRACE)
2462 # if defined(SIGUSR2)
2463 (void)raise(SIGUSR2);
2464
2465 # endif
2466 #endif
2467 abort();
2468 }
2469 lp->rbr = (char *)realloc(lp->rbr, lp->rxbsz);
2470 if (!lp->rbr)
2471 {
2472 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2473 __func__, __FILE__, __LINE__);
2474 #if defined(USE_BACKTRACE)
2475 # if defined(SIGUSR2)
2476 (void)raise(SIGUSR2);
2477
2478 # endif
2479 #endif
2480 abort();
2481 }
2482 }
2483 if (nolog) {
2484 mp->logfiletmpl[0] = '\0';
2485 for (i = 0; i < mp->lines; i++) {
2486 lp = mp->ldsc + i;
2487 FREE(lp->txlogname);
2488 lp->txlogname = NULL;
2489 if (lp->txlog) {
2490 sim_close_logfile (&lp->txlogref);
2491 lp->txlog = NULL;
2492 }
2493 }
2494 }
2495 if ((listen[0]) && (!datagram)) {
2496 sock = sim_master_sock (listen, &r);
2497 if (r)
2498 return sim_messagef (SCPE_ARG, "Invalid network listen port: %s\n", listen);
2499 if (sock == INVALID_SOCKET)
2500 return sim_messagef (SCPE_OPENERR, "Can't open network socket for listen port: %s\n", listen);
2501 if (mp->port) {
2502 sim_close_sock (mp->master);
2503 mp->master = 0;
2504 FREE (mp->port);
2505 mp->port = NULL;
2506 }
2507 sim_printf ("Listening on port %s\n", listen);
2508 mp->port = (char *)realloc (mp->port, 1 + strlen (listen));
2509 if (!mp->port)
2510 {
2511 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2512 __func__, __FILE__, __LINE__);
2513 #if defined(USE_BACKTRACE)
2514 # if defined(SIGUSR2)
2515 (void)raise(SIGUSR2);
2516
2517 # endif
2518 #endif
2519 abort();
2520 }
2521 (void)strcpy (mp->port, listen);
2522 mp->master = sock;
2523 mp->ring_sock = INVALID_SOCKET;
2524 if (mp->ring_ipad) FREE (mp->ring_ipad);
2525 mp->ring_ipad = NULL;
2526 mp->ring_start_time = 0;
2527 mp->notelnet = listennotelnet;
2528 for (i = 0; i < mp->lines; i++) {
2529 lp = mp->ldsc + i;
2530 lp->mp = mp;
2531 lp->packet = mp->packet;
2532 if (speed[0])
2533 tmxr_set_line_speed (lp, speed);
2534 tmxr_init_line (lp);
2535 lp->sock = 0;
2536 }
2537 }
2538 if (loopback) {
2539 if (mp->lines > 1)
2540 return sim_messagef (SCPE_ARG, "Ambiguous Loopback specification\n");
2541 sim_printf ("Operating in loopback mode\n");
2542 for (i = 0; i < mp->lines; i++) {
2543 lp = mp->ldsc + i;
2544 tmxr_set_line_loopback (lp, loopback);
2545 if (speed[0])
2546 tmxr_set_line_speed (lp, speed);
2547 }
2548 }
2549 if (destination[0]) {
2550 if (mp->lines > 1)
2551 return sim_messagef (SCPE_ARG, "Ambiguous Destination specification\n");
2552 lp = &mp->ldsc[0];
2553 lp->datagram = datagram;
2554 if (datagram) {
2555 if (listen[0]) {
2556 lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
2557 if (!lp->port)
2558 {
2559 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2560 __func__, __FILE__, __LINE__);
2561 #if defined(USE_BACKTRACE)
2562 # if defined(SIGUSR2)
2563 (void)raise(SIGUSR2);
2564
2565 # endif
2566 #endif
2567 abort();
2568 }
2569 (void)strcpy (lp->port, listen);
2570 }
2571 else
2572 return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n");
2573 }
2574 lp->packet = packet;
2575 sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL,
2576 (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) |
2577 (packet ? SIM_SOCK_OPT_NODELAY : 0) |
2578 SIM_SOCK_OPT_BLOCKING);
2579 if (sock != INVALID_SOCKET) {
2580 _mux_detach_line (lp, FALSE, TRUE);
2581 lp->destination = (char *)malloc(1+strlen(hostport));
2582 if (!lp->destination)
2583 {
2584 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2585 __func__, __FILE__, __LINE__);
2586 #if defined(USE_BACKTRACE)
2587 # if defined(SIGUSR2)
2588 (void)raise(SIGUSR2);
2589
2590 # endif
2591 #endif
2592 abort();
2593 }
2594 (void)strcpy (lp->destination, hostport);
2595 lp->mp = mp;
2596 if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) {
2597 lp->connecting = sock;
2598 lp->ipad = (char *)malloc (1 + strlen (lp->destination));
2599 if (!lp->ipad)
2600 {
2601 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2602 __func__, __FILE__, __LINE__);
2603 #if defined(USE_BACKTRACE)
2604 # if defined(SIGUSR2)
2605 (void)raise(SIGUSR2);
2606
2607 # endif
2608 #endif
2609 abort();
2610 }
2611 (void)strcpy (lp->ipad, lp->destination);
2612 }
2613 else
2614 sim_close_sock (sock);
2615 lp->notelnet = notelnet;
2616 tmxr_init_line (lp);
2617 if (speed[0] && (!datagram))
2618 tmxr_set_line_speed (lp, speed);
2619 return SCPE_OK;
2620 }
2621 else
2622 return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n",
2623 datagram ? "Datagram" : "Stream", datagram ? listen : "",
2624 datagram ? "<->" : "", hostport);
2625 }
2626 }
2627 else {
2628 lp = &mp->ldsc[line];
2629 lp->mp = mp;
2630 if (logfiletmpl[0]) {
2631 sim_close_logfile (&lp->txlogref);
2632 lp->txlog = NULL;
2633 lp->txlogname = (char *)realloc (lp->txlogname, 1 + strlen (logfiletmpl));
2634 if (!lp->txlogname)
2635 {
2636 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2637 __func__, __FILE__, __LINE__);
2638 #if defined(USE_BACKTRACE)
2639 # if defined(SIGUSR2)
2640 (void)raise(SIGUSR2);
2641
2642 # endif
2643 #endif
2644 abort();
2645 }
2646 (void)strcpy (lp->txlogname, logfiletmpl);
2647 r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
2648 if (r == SCPE_OK)
2649 setvbuf(lp->txlog, NULL, _IOFBF, 65536);
2650 else {
2651 FREE (lp->txlogname);
2652 lp->txlogname = NULL;
2653 return sim_messagef (r, "Can't open log file: %s\n", logfiletmpl);
2654 }
2655 }
2656 if (buffered[0] == '\0') {
2657 lp->rxbsz = lp->txbsz = TMXR_MAXBUF;
2658 lp->txbfd = 0;
2659 }
2660 else {
2661 lp->rxbsz = lp->txbsz = atoi(buffered);
2662 lp->txbfd = 1;
2663 }
2664 lp->txbpi = lp->txbpr = 0;
2665 lp->txb = (char *)realloc (lp->txb, lp->txbsz);
2666 if (!lp->txb)
2667 {
2668 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2669 __func__, __FILE__, __LINE__);
2670 #if defined(USE_BACKTRACE)
2671 # if defined(SIGUSR2)
2672 (void)raise(SIGUSR2);
2673
2674 # endif
2675 #endif
2676 abort();
2677 }
2678 lp->rxb = (char *)realloc (lp->rxb, lp->rxbsz);
2679 if (!lp->rxb)
2680 {
2681 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2682 __func__, __FILE__, __LINE__);
2683 #if defined(USE_BACKTRACE)
2684 # if defined(SIGUSR2)
2685 (void)raise(SIGUSR2);
2686
2687 # endif
2688 #endif
2689 abort();
2690 }
2691 lp->rbr = (char *)realloc (lp->rbr, lp->rxbsz);
2692 if (!lp->rbr)
2693 {
2694 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2695 __func__, __FILE__, __LINE__);
2696 #if defined(USE_BACKTRACE)
2697 # if defined(SIGUSR2)
2698 (void)raise(SIGUSR2);
2699
2700 # endif
2701 #endif
2702 abort();
2703 }
2704 lp->packet = packet;
2705 if (nolog) {
2706 FREE(lp->txlogname);
2707 lp->txlogname = NULL;
2708 if (lp->txlog) {
2709 sim_close_logfile (&lp->txlogref);
2710 lp->txlog = NULL;
2711 }
2712 }
2713 if ((listen[0]) && (!datagram)) {
2714 if ((mp->lines == 1) && (mp->master))
2715 return sim_messagef (SCPE_ARG, "Single Line MUX can have either line specific OR MUS listener but NOT both\n");
2716 sock = sim_master_sock (listen, &r);
2717 if (r)
2718 return sim_messagef (SCPE_ARG, "Invalid Listen Specification: %s\n", listen);
2719 if (sock == INVALID_SOCKET)
2720 return sim_messagef (SCPE_OPENERR, "Can't listen on port: %s\n", listen);
2721 _mux_detach_line (lp, TRUE, FALSE);
2722 sim_printf ("Line %d Listening on port %s\n", line, listen);
2723 lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
2724 if (!lp->port)
2725 {
2726 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2727 __func__, __FILE__, __LINE__);
2728 #if defined(USE_BACKTRACE)
2729 # if defined(SIGUSR2)
2730 (void)raise(SIGUSR2);
2731
2732 # endif
2733 #endif
2734 abort();
2735 }
2736 (void)strcpy (lp->port, listen);
2737 lp->master = sock;
2738 if (listennotelnet != mp->notelnet)
2739 lp->notelnet = listennotelnet;
2740 else
2741 lp->notelnet = mp->notelnet;
2742 }
2743 if (destination[0]) {
2744 lp->datagram = datagram;
2745 if (datagram) {
2746 if (listen[0]) {
2747 lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
2748 if (!lp->port)
2749 {
2750 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2751 __func__, __FILE__, __LINE__);
2752 #if defined(USE_BACKTRACE)
2753 # if defined(SIGUSR2)
2754 (void)raise(SIGUSR2);
2755
2756 # endif
2757 #endif
2758 abort();
2759 }
2760 (void)strcpy (lp->port, listen);
2761 }
2762 else
2763 return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n");
2764 }
2765 sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL,
2766 (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (packet ? SIM_SOCK_OPT_NODELAY : 0));
2767 if (sock != INVALID_SOCKET) {
2768 _mux_detach_line (lp, FALSE, TRUE);
2769 lp->destination = (char *)malloc(1+strlen(hostport));
2770 if (!lp->destination)
2771 {
2772 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2773 __func__, __FILE__, __LINE__);
2774 #if defined(USE_BACKTRACE)
2775 # if defined(SIGUSR2)
2776 (void)raise(SIGUSR2);
2777
2778 # endif
2779 #endif
2780 abort();
2781 }
2782 (void)strcpy (lp->destination, hostport);
2783 if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) {
2784 lp->connecting = sock;
2785 lp->ipad = (char *)malloc (1 + strlen (lp->destination));
2786 if (!lp->ipad)
2787 {
2788 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2789 __func__, __FILE__, __LINE__);
2790 #if defined(USE_BACKTRACE)
2791 # if defined(SIGUSR2)
2792 (void)raise(SIGUSR2);
2793
2794 # endif
2795 #endif
2796 abort();
2797 }
2798 (void)strcpy (lp->ipad, lp->destination);
2799 }
2800 else
2801 sim_close_sock (sock);
2802 lp->notelnet = notelnet;
2803 tmxr_init_line (lp);
2804 }
2805 else
2806 return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n",
2807 datagram ? "Datagram" : "Stream", datagram ? listen : "",
2808 datagram ? "<->" : "", hostport);
2809 }
2810 }
2811 if (loopback) {
2812 if (lp != NULL) {
2813 tmxr_set_line_loopback (lp, loopback);
2814 sim_printf ("Line %d operating in loopback mode\n", line);
2815 }
2816 }
2817 if (lp != NULL) lp->modem_control = modem_control;
2818 if (speed[0] && (!datagram)
2819 )
2820 tmxr_set_line_speed (lp, speed);
2821 r = SCPE_OK;
2822 }
2823 if (r == SCPE_OK)
2824 tmxr_add_to_open_list (mp);
2825 return r;
2826 }
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847 t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll)
2848 {
2849 if ((line < 0) || (line >= mp->lines))
2850 return SCPE_ARG;
2851 mp->ldsc[line].uptr = uptr_poll;
2852 return SCPE_OK;
2853 }
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874 t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll)
2875 {
2876 if ((line < 0) || (line >= mp->lines))
2877 return SCPE_ARG;
2878 mp->ldsc[line].o_uptr = uptr_poll;
2879 return SCPE_OK;
2880 }
2881
2882 static TMXR **tmxr_open_devices = NULL;
2883 static int tmxr_open_device_count = 0;
2884
2885 t_stat tmxr_start_poll (void)
2886 {
2887 return SCPE_OK;
2888 }
2889
2890 t_stat tmxr_stop_poll (void)
2891 {
2892 return SCPE_OK;
2893 }
2894
2895 static void tmxr_add_to_open_list (TMXR* mux)
2896 {
2897 int i;
2898 t_bool found = FALSE;
2899
2900 for (i=0; i<tmxr_open_device_count; ++i)
2901 if (tmxr_open_devices[i] == mux) {
2902 found = TRUE;
2903 break;
2904 }
2905 if (!found) {
2906 tmxr_open_devices = (TMXR **)realloc(tmxr_open_devices, (tmxr_open_device_count+1)*sizeof(*tmxr_open_devices));
2907 if (!tmxr_open_devices)
2908 {
2909 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2910 __func__, __FILE__, __LINE__);
2911 #if defined(USE_BACKTRACE)
2912 # if defined(SIGUSR2)
2913 (void)raise(SIGUSR2);
2914
2915 # endif
2916 #endif
2917 abort();
2918 }
2919 tmxr_open_devices[tmxr_open_device_count++] = mux;
2920 for (i=0; i<mux->lines; i++)
2921 if (0 == mux->ldsc[i].send.delay)
2922 mux->ldsc[i].send.delay = SEND_DEFAULT_DELAY;
2923 }
2924 }
2925
2926 static void _tmxr_remove_from_open_list (const TMXR* mux)
2927 {
2928 int i, j;
2929
2930 for (i=0; i<tmxr_open_device_count; ++i)
2931 if (tmxr_open_devices[i] == mux) {
2932 for (j=i+1; j<tmxr_open_device_count; ++j)
2933 tmxr_open_devices[j-1] = tmxr_open_devices[j];
2934 --tmxr_open_device_count;
2935 break;
2936 }
2937 }
2938
2939 static t_stat _tmxr_locate_line_send_expect (const char *cptr, SEND **snd, EXPECT **exp)
2940 {
2941 char gbuf[CBUFSIZE];
2942 DEVICE *dptr;
2943 int i;
2944 t_stat r;
2945
2946 if (snd)
2947 *snd = NULL;
2948 if (exp)
2949 *exp = NULL;
2950 cptr = get_glyph(cptr, gbuf, ':');
2951 dptr = find_dev (gbuf);
2952 if (!dptr)
2953 return SCPE_ARG;
2954
2955 for (i=0; i<tmxr_open_device_count; ++i)
2956 if (tmxr_open_devices[i]->dptr == dptr) {
2957 int line = (int)get_uint (cptr, 10, tmxr_open_devices[i]->lines, &r);
2958 if (r != SCPE_OK)
2959 return r;
2960 if (snd)
2961 *snd = &tmxr_open_devices[i]->ldsc[line].send;
2962 if (exp)
2963 *exp = &tmxr_open_devices[i]->ldsc[line].expect;
2964 return SCPE_OK;
2965 }
2966 return SCPE_ARG;
2967 }
2968
2969 t_stat tmxr_locate_line_send (const char *cptr, SEND **snd)
2970 {
2971 return _tmxr_locate_line_send_expect (cptr, snd, NULL);
2972 }
2973
2974 t_stat tmxr_locate_line_expect (const char *cptr, EXPECT **exp)
2975 {
2976 return _tmxr_locate_line_send_expect (cptr, NULL, exp);
2977 }
2978
2979 t_stat tmxr_change_async (void)
2980 {
2981 return SCPE_OK;
2982 }
2983
2984
2985
2986 t_stat tmxr_attach_ex (TMXR *mp, UNIT *uptr, CONST char *cptr, t_bool async)
2987 {
2988 t_stat r;
2989 int32 i;
2990
2991 r = tmxr_open_master (mp, cptr);
2992 if (r != SCPE_OK)
2993 return r;
2994 mp->uptr = uptr;
2995 uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);
2996 uptr->flags = uptr->flags | UNIT_ATT;
2997 uptr->tmxr = (void *)mp;
2998 if ((mp->lines > 1) ||
2999 ((mp->master == 0) &&
3000 (mp->ldsc[0].connecting == 0)
3001 ))
3002 uptr->dynflags = uptr->dynflags | UNIT_ATTMULT;
3003
3004 uptr->dynflags |= TMUF_NOASYNCH;
3005
3006 if (mp->dptr == NULL)
3007 mp->dptr = find_dev_from_unit (uptr);
3008
3009 if (mp->dptr) {
3010 for (i=0; i<mp->lines; i++) {
3011 mp->ldsc[i].expect.dptr = mp->dptr;
3012 mp->ldsc[i].expect.dbit = TMXR_DBG_EXP;
3013 mp->ldsc[i].send.dptr = mp->dptr;
3014 mp->ldsc[i].send.dbit = TMXR_DBG_SEND;
3015 }
3016 }
3017 tmxr_add_to_open_list (mp);
3018 return SCPE_OK;
3019 }
3020
3021 t_stat tmxr_startup (void)
3022 {
3023 return SCPE_OK;
3024 }
3025
3026 t_stat tmxr_shutdown (void)
3027 {
3028 if (tmxr_open_device_count)
3029 return SCPE_IERR;
3030 return SCPE_OK;
3031 }
3032
3033 t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
3034 {
3035 int i, j;
3036
3037 if (0 == tmxr_open_device_count)
3038 fprintf(st, "No Attached Multiplexer Devices\n");
3039 else {
3040 for (i=0; i<tmxr_open_device_count; ++i) {
3041 TMXR *mp = tmxr_open_devices[i];
3042 TMLN *lp;
3043 char *attach;
3044
3045 fprintf(st, "Multiplexer device: %s", (mp->dptr ? sim_dname (mp->dptr) : ""));
3046 if (mp->lines > 1) {
3047 fprintf(st, ", ");
3048 tmxr_show_lines(st, NULL, 0, mp);
3049 }
3050 if (mp->packet)
3051 fprintf(st, ", Packet");
3052 if (mp->datagram)
3053 fprintf(st, ", UDP");
3054 if (mp->notelnet)
3055 fprintf(st, ", Telnet=disabled");
3056 if (mp->modem_control)
3057 fprintf(st, ", ModemControl=enabled");
3058 if (mp->buffered)
3059 fprintf(st, ", Buffered=%d", mp->buffered);
3060 attach = tmxr_mux_attach_string (NULL, mp);
3061 if (attach)
3062 fprintf(st, ",\n attached to %s, ", attach);
3063 FREE (attach);
3064 tmxr_show_summ(st, NULL, 0, mp);
3065 fprintf(st, ", sessions=%d", mp->sessions);
3066 if (mp->lines == 1) {
3067 if (mp->ldsc->rxbps) {
3068 fprintf(st, ", Speed=%lu", (unsigned long)mp->ldsc->rxbps);
3069 if (mp->ldsc->rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
3070 fprintf(st, "*%.0f", mp->ldsc->rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
3071 fprintf(st, " bps");
3072 }
3073 }
3074 fprintf(st, "\n");
3075 if (mp->ring_start_time) {
3076 fprintf (st, " incoming Connection from: %s ringing for %lu milliseconds\n",
3077 mp->ring_ipad, (unsigned long)sim_os_msec () - (unsigned long)mp->ring_start_time);
3078 }
3079 for (j = 0; j < mp->lines; j++) {
3080 lp = mp->ldsc + j;
3081 if (mp->lines > 1) {
3082 if (lp->dptr && (mp->dptr != lp->dptr))
3083 fprintf (st, "Device: %s ", sim_dname(lp->dptr));
3084 fprintf (st, "Line: %d", j);
3085 if (mp->notelnet != lp->notelnet)
3086 fprintf (st, " - %stelnet", lp->notelnet ? "no" : "");
3087 if (lp->uptr && (lp->uptr != lp->mp->uptr))
3088 fprintf (st, " - Unit: %s", sim_uname (lp->uptr));
3089 if (mp->modem_control != lp->modem_control)
3090 fprintf(st, ", ModemControl=%s", lp->modem_control ? "enabled" : "disabled");
3091 if (lp->loopback)
3092 fprintf(st, ", Loopback");
3093 if (lp->rxbps) {
3094 fprintf(st, ", Speed=%lu", (unsigned long)lp->rxbps);
3095 if (lp->rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
3096 fprintf(st, "*%.0f", lp->rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
3097 fprintf(st, " bps");
3098 }
3099 fprintf (st, "\n");
3100 }
3101 if ((!lp->sock) && (!lp->connecting)
3102 && (!lp->master)) {
3103 if (lp->modem_control)
3104 tmxr_fconns (st, lp, -1);
3105 continue;
3106 }
3107 tmxr_fconns (st, lp, -1);
3108 tmxr_fstats (st, lp, -1);
3109 }
3110 }
3111 }
3112 return SCPE_OK;
3113 }
3114
3115
3116
3117
3118
3119
3120
3121
3122 t_stat tmxr_close_master (TMXR *mp)
3123 {
3124 int32 i;
3125 TMLN *lp;
3126
3127 for (i = 0; i < mp->lines; i++) {
3128 lp = mp->ldsc + i;
3129
3130 if (!lp->destination && lp->sock) {
3131 tmxr_report_disconnection (lp);
3132 tmxr_reset_ln (lp);
3133 }
3134 else {
3135 if (lp->sock) {
3136 tmxr_report_disconnection (lp);
3137 tmxr_reset_ln (lp);
3138 }
3139 FREE (lp->destination);
3140 lp->destination = NULL;
3141 if (lp->connecting) {
3142 lp->sock = lp->connecting;
3143 lp->connecting = 0;
3144 tmxr_reset_ln (lp);
3145 }
3146 lp->conn = FALSE;
3147 }
3148 if (lp->master) {
3149 sim_close_sock (lp->master);
3150 lp->master = 0;
3151 FREE (lp->port);
3152 lp->port = NULL;
3153 }
3154 lp->txbfd = 0;
3155 FREE (lp->txb);
3156 lp->txb = NULL;
3157 FREE (lp->rxb);
3158 lp->rxb = NULL;
3159 FREE (lp->rbr);
3160 lp->rbr = NULL;
3161 lp->modembits = 0;
3162 }
3163
3164 if (mp->master)
3165 sim_close_sock (mp->master);
3166 mp->master = 0;
3167 FREE (mp->port);
3168 mp->port = NULL;
3169 if (mp->ring_sock != INVALID_SOCKET) {
3170 sim_close_sock (mp->ring_sock);
3171 mp->ring_sock = INVALID_SOCKET;
3172 FREE (mp->ring_ipad);
3173 mp->ring_ipad = NULL;
3174 mp->ring_start_time = 0;
3175 }
3176 _tmxr_remove_from_open_list (mp);
3177 return SCPE_OK;
3178 }
3179
3180
3181
3182
3183
3184
3185 t_stat tmxr_detach (TMXR *mp, UNIT *uptr)
3186 {
3187 int32 i;
3188
3189 if (!(uptr->flags & UNIT_ATT))
3190 return SCPE_OK;
3191 tmxr_close_master (mp);
3192 FREE (uptr->filename);
3193 uptr->filename = NULL;
3194 uptr->tmxr = NULL;
3195 mp->last_poll_time = 0;
3196 for (i=0; i < mp->lines; i++) {
3197 UNIT *uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
3198 UNIT *o_uptr = mp->ldsc[i].o_uptr ? mp->ldsc[i].o_uptr : mp->uptr;
3199
3200 uptr->dynflags &= ~UNIT_TM_POLL;
3201 o_uptr->dynflags &= ~UNIT_TM_POLL;
3202 }
3203 uptr->flags &= ~(UNIT_ATT);
3204 uptr->dynflags &= ~(UNIT_TM_POLL|TMUF_NOASYNCH);
3205 return SCPE_OK;
3206 }
3207
3208 t_stat tmxr_activate (UNIT *uptr, int32 interval)
3209 {
3210 if (uptr->dynflags & UNIT_TMR_UNIT)
3211 return sim_timer_activate (uptr, interval);
3212 return _sim_activate (uptr, interval);
3213 }
3214
3215 t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime)
3216 {
3217 return _sim_activate_after (uptr, usecs_walltime);
3218 }
3219
3220
3221
3222 t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
3223 {
3224 TMXR *mux = (TMXR *)dptr->help_ctx;
3225 t_bool single_line = FALSE;
3226
3227 if (mux)
3228 single_line = (mux->lines == 1);
3229
3230 if (!flag)
3231 fprintf (st, "%s Multiplexer Attach Help\n\n", dptr->name);
3232 if (single_line) {
3233 fprintf (st, "The %s multiplexer may be connected to terminal emulators supporting the\n", dptr->name);
3234 fprintf (st, "Telnet protocol via sockets.\n\n");
3235 if (mux->modem_control) {
3236 fprintf (st, "The %s device is a full modem control device and therefore is capable of\n", dptr->name);
3237 fprintf (st, "passing port configuration information and modem signals.\n");
3238 }
3239 fprintf (st, "A Telnet listening port can be configured with:\n\n");
3240 fprintf (st, " sim> ATTACH %s {interface:}port\n\n", dptr->name);
3241 fprintf (st, "Line buffering can be enabled for the %s device with:\n\n", dptr->name);
3242 fprintf (st, " sim> ATTACH %s Buffer{=bufsize}\n\n", dptr->name);
3243 fprintf (st, "Line buffering can be disabled for the %s device with:\n\n", dptr->name);
3244 fprintf (st, " sim> ATTACH %s NoBuffer\n\n", dptr->name);
3245 fprintf (st, "The default buffer size is 32k bytes, the max buffer size is 1024k bytes\n\n");
3246 fprintf (st, "The outbound traffic the %s device can be logged to a file with:\n", dptr->name);
3247 fprintf (st, " sim> ATTACH %s Log=LogFileName\n\n", dptr->name);
3248 fprintf (st, "File logging can be disabled for the %s device with:\n\n", dptr->name);
3249 fprintf (st, " sim> ATTACH %s NoLog\n\n", dptr->name);
3250 fprintf (st, "The %s device may be connected to a serial port on the host system.\n", dptr->name);
3251 }
3252 else {
3253 fprintf (st, "%s multiplexer lines may be connected to terminal emulators supporting the\n", dptr->name);
3254 fprintf (st, "Telnet protocol via sockets, or to hardware terminals via host serial\n");
3255 fprintf (st, "ports. Concurrent Telnet and serial connections may be mixed on a given\n");
3256 fprintf (st, "multiplexer.\n\n");
3257 if (mux && mux->modem_control) {
3258 fprintf (st, "The %s device is a full modem control device and therefore is capable of\n", dptr->name);
3259 fprintf (st, "passing port configuration information and modem signals on all lines.\n");
3260 }
3261 fprintf (st, "Modem Control signalling behaviors can be enabled/disabled on a specific\n");
3262 fprintf (st, "multiplexer line with:\n\n");
3263 fprintf (st, " sim> ATTACH %s Line=n,Modem\n", dptr->name);
3264 fprintf (st, " sim> ATTACH %s Line=n,NoModem\n\n", dptr->name);
3265 fprintf (st, "A Telnet listening port can be configured with:\n\n");
3266 fprintf (st, " sim> ATTACH %s {interface:}port\n\n", dptr->name);
3267 if (mux)
3268 fprintf (st, "Line buffering for all %d lines on the %s device can be configured with:\n\n", mux->lines, dptr->name);
3269 else
3270 fprintf (st, "Line buffering for all lines on the %s device can be configured with:\n\n", dptr->name);
3271 fprintf (st, " sim> ATTACH %s Buffer{=bufsize}\n\n", dptr->name);
3272 if (mux)
3273 fprintf (st, "Line buffering for all %d lines on the %s device can be disabled with:\n\n", mux->lines, dptr->name);
3274 else
3275 fprintf (st, "Line buffering for all lines on the %s device can be disabled with:\n\n", dptr->name);
3276 fprintf (st, " sim> ATTACH %s NoBuffer\n\n", dptr->name);
3277 fprintf (st, "The default buffer size is 32k bytes, the max buffer size is 1024k bytes\n\n");
3278 fprintf (st, "The outbound traffic for the lines of the %s device can be logged to files\n", dptr->name);
3279 fprintf (st, "with:\n\n");
3280 fprintf (st, " sim> ATTACH %s Log=LogFileName\n\n", dptr->name);
3281 fprintf (st, "The log file name for each line uses the above LogFileName as a template\n");
3282 fprintf (st, "for the actual file name which will be LogFileName_n where n is the line\n");
3283 fprintf (st, "number.\n\n");
3284 fprintf (st, "Multiplexer lines may be connected to serial ports on the host system.\n");
3285 }
3286 fprintf (st, "Serial ports may be specified as an operating system specific device names\n");
3287 fprintf (st, "or using simh generic serial names. simh generic names are of the form\n");
3288 fprintf (st, "serN, where N is from 0 thru one less than the maximum number of serial\n");
3289 fprintf (st, "ports on the local system. The mapping of simh generic port names to OS \n");
3290 fprintf (st, "specific names can be displayed using the following command:\n\n");
3291 fprintf (st, " sim> SHOW SERIAL\n");
3292 fprintf (st, " Serial devices:\n");
3293 fprintf (st, " ser0 COM1 (\\Device\\Serial0)\n");
3294 fprintf (st, " ser1 COM3 (Winachcf0)\n\n");
3295 if (single_line) {
3296 fprintf (st, " sim> ATTACH %s Connect=ser0\n\n", dptr->name);
3297 fprintf (st, "or equivalently:\n\n");
3298 fprintf (st, " sim> ATTACH %s Connect=COM1\n\n", dptr->name);
3299 }
3300 else {
3301 fprintf (st, " sim> ATTACH %s Line=n,Connect=ser0\n\n", dptr->name);
3302 fprintf (st, "or equivalently:\n\n");
3303 fprintf (st, " sim> ATTACH %s Line=n,Connect=COM1\n\n", dptr->name);
3304 if (mux)
3305 fprintf (st, "Valid line numbers are from 0 thru %d\n\n", mux->lines-1);
3306 }
3307 if (single_line) {
3308 fprintf (st, "The input data rate for the %s device can be controlled by\n", dptr->name);
3309 fprintf (st, "specifying SPEED=nnn{*fac} on the ATTACH command.\n");
3310 }
3311 else {
3312 fprintf (st, "The input data rate for all lines or a particular line of a the %s\n", dptr->name);
3313 fprintf (st, "device can be controlled by specifying SPEED=nnn{*fac} on the ATTACH command.\n");
3314 }
3315 fprintf (st, "SPEED values can be any one of:\n\n");
3316 fprintf (st, " 0 50 75 110 134 150 300 600 1200 1800 2000 2400\n");
3317 fprintf (st, " 3600 4800 7200 9600 19200 38400 57600 76800 115200\n\n");
3318 fprintf (st, "A SPEED value of 0 causes input data to be delivered to the simulated\n");
3319 fprintf (st, "port as fast as it arrives.\n\n");
3320 fprintf (st, "If a simulated multiplexor devices can programmatically set a serial\n");
3321 fprintf (st, "port line speed, the programmatically specified speed will take precedence\n");
3322 fprintf (st, "over any input speed specified on an attach command.\n");
3323 fprintf (st, "Some simulated systems run very much faster than the original system\n");
3324 fprintf (st, "which is being simulated. To accommodate this, the speed specified may\n");
3325 fprintf (st, "include a factor which will increase the input data delivery rate by\n");
3326 fprintf (st, "the specified factor. A factor is specified with a speed value of the\n");
3327 fprintf (st, "form \"speed*factor\". Factor values can range from 1 thru 32.\n");
3328 fprintf (st, "Example:\n\n");
3329 fprintf (st, " sim> ATTACH %s 1234,SPEED=2400\n", dptr->name);
3330 fprintf (st, " sim> ATTACH %s 1234,SPEED=9600*8\n", dptr->name);
3331 if (!single_line)
3332 fprintf (st, " sim> ATTACH %s Line=2,SPEED=2400\n", dptr->name);
3333 fprintf (st, "\n");
3334 fprintf (st, "The SPEED parameter only influences the rate at which data is delivered\n");
3335 fprintf (st, "into the simulated multiplexor port. Output data rates are unaffected\n");
3336 fprintf (st, "If an attach command specifies a speed multiply factor, that value will\n");
3337 fprintf (st, "persist independent of any programmatic action by the simulated system to\n");
3338 fprintf (st, "change the port speed.\n\n");
3339 fprintf (st, "An optional serial port configuration string may be present after the port\n");
3340 fprintf (st, "name. If present, it must be separated from the port name with a semicolon\n");
3341 fprintf (st, "and has this form:\n\n");
3342 fprintf (st, " <rate>-<charsize><parity><stopbits>\n\n");
3343 fprintf (st, "where:\n");
3344 fprintf (st, " rate = communication rate in bits per second\n");
3345 fprintf (st, " charsize = character size in bits (5-8, including optional parity)\n");
3346 fprintf (st, " parity = parity designator (N/E/O/M/S for no/even/odd/mark/space parity)\n");
3347 fprintf (st, " stopbits = number of stop bits (1, 1.5, or 2)\n\n");
3348 fprintf (st, "As an example:\n\n");
3349 fprintf (st, " 9600-8n1\n\n");
3350 fprintf (st, "The supported rates, sizes, and parity options are host-specific. If\n");
3351 fprintf (st, "a configuration string is not supplied, then the default of 9600-8N1\n");
3352 fprintf (st, "is used.\n");
3353 fprintf (st, "Note: The serial port configuration option is only available on multiplexer\n");
3354 fprintf (st, " lines which are not operating with full modem control behaviors enabled.\n");
3355 fprintf (st, " Lines with full modem control behaviors enabled have all of their\n");
3356 fprintf (st, " configuration managed by the Operating System running within the\n");
3357 fprintf (st, " simulator.\n\n");
3358 fprintf (st, "An attachment to a serial port with the '-V' switch will cause a\n");
3359 fprintf (st, "connection message to be output to the connected serial port.\n");
3360 fprintf (st, "This will help to confirm the correct port has been connected and\n");
3361 fprintf (st, "that the port settings are reasonable for the connected device.\n");
3362 fprintf (st, "This would be done as:\n\n");
3363 if (single_line)
3364 fprintf (st, " sim> ATTACH -V %s Connect=SerN\n", dptr->name);
3365 else {
3366 fprintf (st, " sim> ATTACH -V %s Line=n,Connect=SerN\n\n", dptr->name);
3367 fprintf (st, "Line specific tcp listening ports are supported. These are configured\n");
3368 fprintf (st, "using commands of the form:\n\n");
3369 fprintf (st, " sim> ATTACH %s Line=n,{interface:}port{;notelnet}\n\n", dptr->name);
3370 }
3371 fprintf (st, "Direct computer to computer connections (Virtual Null Modem cables) may\n");
3372 fprintf (st, "be established using the telnet protocol or via raw tcp sockets.\n\n");
3373 fprintf (st, " sim> ATTACH %s Line=n,Connect=host:port{;notelnet}\n\n", dptr->name);
3374 fprintf (st, "Computer to computer virtual connections can be one way (as illustrated\n");
3375 fprintf (st, "above) or symmetric. A symmetric connection is configured by combining\n");
3376 if (single_line) {
3377 fprintf (st, "a one way connection with a tcp listening port on the same line:\n\n");
3378 fprintf (st, " sim> ATTACH %s listenport,Connect=host:port\n\n", dptr->name);
3379 }
3380 else {
3381 fprintf (st, "a one way connection with a tcp listening port on the same line:\n\n");
3382 fprintf (st, " sim> ATTACH %s Line=n,listenport,Connect=host:port\n\n", dptr->name);
3383 }
3384 fprintf (st, "When symmetric virtual connections are configured, incoming connections\n");
3385 fprintf (st, "on the specified listening port are checked to assure that they actually\n");
3386 fprintf (st, "come from the specified connection destination host system.\n\n");
3387 if (single_line) {
3388 fprintf (st, "The %s device can be attached in LOOPBACK mode:\n\n", dptr->name);
3389 fprintf (st, " sim> ATTACH %s Loopback\n\n", dptr->name);
3390 }
3391 else {
3392 fprintf (st, "A line on the %s device can be attached in LOOPBACK mode:\n\n", dptr->name);
3393 fprintf (st, " sim> ATTACH %s Line=n,Loopback\n\n", dptr->name);
3394 }
3395 fprintf (st, "When operating in LOOPBACK mode, all outgoing data arrives as input and\n");
3396 fprintf (st, "outgoing modem signals (if enabled) (DTR and RTS) are reflected in the\n");
3397 fprintf (st, "incoming modem signals (DTR->(DCD and DSR), RTS->CTS)\n\n");
3398 if (single_line)
3399 fprintf (st, "The connection configured for the %s device is unconfigured by:\n\n", dptr->name);
3400 else
3401 fprintf (st, "All connections configured for the %s device are unconfigured by:\n\n", dptr->name);
3402 fprintf (st, " sim> DETACH %s\n\n", dptr->name);
3403 if (dptr->modifiers) {
3404 MTAB *mptr;
3405
3406 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++)
3407 if (mptr->valid == &tmxr_dscln) {
3408 fprintf (st, "A specific line on the %s device can be disconnected with:\n\n", dptr->name);
3409 fprintf (st, " sim> SET %s %s=n\n\n", dptr->name, mptr->mstring);
3410 fprintf (st, "This will cause a telnet connection to be closed, but a serial port will\n");
3411 fprintf (st, "normally have DTR dropped for 500ms and raised again (thus hanging up a\n");
3412 fprintf (st, "modem on that serial port).\n\n");
3413 fprintf (st, "A line which is connected to a serial port can be manually closed by\n");
3414 fprintf (st, "adding the -C switch to a %s command.\n\n", mptr->mstring);
3415 fprintf (st, " sim> SET -C %s %s=n\n\n", dptr->name, mptr->mstring);
3416 }
3417 }
3418 return SCPE_OK;
3419 }
3420
3421
3422
3423 t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
3424 {
3425 return SCPE_NOFNC;
3426 }
3427
3428 t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
3429 {
3430 return SCPE_NOFNC;
3431 }
3432
3433
3434
3435 void tmxr_msg (SOCKET sock, const char *msg)
3436 {
3437 if ((sock) && (sock != INVALID_SOCKET))
3438 sim_write_sock (sock, msg, (int32)strlen (msg));
3439 return;
3440 }
3441
3442
3443
3444 void tmxr_linemsg (TMLN *lp, const char *msg)
3445 {
3446 while (*msg) {
3447 while (SCPE_STALL == tmxr_putc_ln (lp, (int32)(*msg)))
3448 if (lp->txbsz == tmxr_send_buffered_data (lp))
3449 sim_os_ms_sleep (10);
3450 ++msg;
3451 }
3452 return;
3453 }
3454
3455
3456
3457 void tmxr_linemsgf (TMLN *lp, const char *fmt, ...)
3458 {
3459 va_list arglist;
3460
3461 va_start (arglist, fmt);
3462 tmxr_linemsgvf (lp, fmt, arglist);
3463 va_end (arglist);
3464 }
3465
3466 void tmxr_linemsgvf (TMLN *lp, const char *fmt, va_list arglist)
3467 {
3468 char stackbuf[STACKBUFSIZE];
3469 int32 bufsize = sizeof(stackbuf);
3470 char *buf = stackbuf;
3471 int32 i, len;
3472
3473 buf[bufsize-1] = '\0';
3474 while (1) {
3475 len = vsnprintf (buf, bufsize-1, fmt, arglist);
3476
3477
3478
3479 if ((len < 0) || (len >= bufsize-1)) {
3480 if (buf != stackbuf)
3481 FREE (buf);
3482 if (bufsize >= (INT_MAX / 2))
3483 return;
3484 bufsize = bufsize * 2;
3485 if (bufsize < len + 2)
3486 bufsize = len + 2;
3487 buf = (char *) malloc (bufsize);
3488 if (!buf)
3489 {
3490 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3491 __func__, __FILE__, __LINE__);
3492 #if defined(USE_BACKTRACE)
3493 # if defined(SIGUSR2)
3494 (void)raise(SIGUSR2);
3495
3496 # endif
3497 #endif
3498 abort();
3499 }
3500 buf[bufsize-1] = '\0';
3501 continue;
3502 }
3503 break;
3504 }
3505
3506
3507
3508 for (i = 0; i < len; ++i) {
3509 if (('\n' == buf[i]) && ((i == 0) || ('\r' != buf[i-1]))) {
3510 while (SCPE_STALL == tmxr_putc_ln (lp, '\r'))
3511 if (lp->txbsz == tmxr_send_buffered_data (lp))
3512 sim_os_ms_sleep (10);
3513 }
3514 while (SCPE_STALL == tmxr_putc_ln (lp, buf[i]))
3515 if (lp->txbsz == tmxr_send_buffered_data (lp))
3516 sim_os_ms_sleep (10);
3517 }
3518 if (buf != stackbuf)
3519 FREE (buf);
3520 return;
3521 }
3522
3523
3524
3525 void tmxr_fconns (FILE *st, const TMLN *lp, int32 ln)
3526 {
3527 int32 hr, mn, sc;
3528 uint32 tctime;
3529
3530 if (ln >= 0)
3531 fprintf (st, "line %d: ", ln);
3532
3533 if ((lp->sock) || (lp->connecting)) {
3534 if (lp->destination)
3535 if (lp->datagram)
3536 fprintf (st, "Datagram Connection from %s to remote port %s\n", lp->port, lp->destination);
3537 else
3538 fprintf (st, "Connection to remote port %s\n", lp->destination);
3539 else
3540 fprintf (st, "Connection from IP address %s\n", lp->ipad);
3541 }
3542 else
3543 if (lp->destination)
3544 fprintf (st, "Connecting to remote port %s\n", lp->destination);
3545 if (lp->sock) {
3546 char *sockname, *peername;
3547
3548 sim_getnames_sock (lp->sock, &sockname, &peername);
3549 fprintf (st, "Connection %s->%s\n", sockname, peername);
3550 FREE (sockname);
3551 FREE (peername);
3552 }
3553
3554 if ((lp->port) && (!lp->datagram))
3555 fprintf (st, "Listening on port %s\n", lp->port);
3556 if (lp->cnms) {
3557 tctime = (sim_os_msec () - lp->cnms) / 1000;
3558 hr = tctime / 3600;
3559 mn = (tctime / 60) % 60;
3560 sc = tctime % 60;
3561 if (tctime)
3562 fprintf (st, " %s %02d:%02d:%02d\n", lp->connecting ? "Connecting for" : "Connected", hr, mn, sc);
3563 }
3564 else
3565 fprintf (st, " Line disconnected\n");
3566
3567 if (lp->modem_control) {
3568 fprintf (st, " Modem Bits: %s%s%s%s%s%s\n", (lp->modembits & TMXR_MDM_DTR) ? "DTR " : "",
3569 (lp->modembits & TMXR_MDM_RTS) ? "RTS " : "",
3570 (lp->modembits & TMXR_MDM_DCD) ? "DCD " : "",
3571 (lp->modembits & TMXR_MDM_RNG) ? "RNG " : "",
3572 (lp->modembits & TMXR_MDM_CTS) ? "CTS " : "",
3573 (lp->modembits & TMXR_MDM_DSR) ? "DSR " : "");
3574 }
3575
3576 if (
3577 (lp->sock) && (!lp->datagram))
3578 fprintf (st, " %s\n", (lp->notelnet) ? "Telnet disabled (RAW data)" : "Telnet protocol");
3579 if (lp->send.buffer)
3580 sim_show_send_input (st, &lp->send);
3581 if (lp->expect.buf)
3582 sim_exp_showall (st, &lp->expect);
3583 if (lp->txlog)
3584 fprintf (st, " Logging to %s\n", lp->txlogname);
3585 return;
3586 }
3587
3588
3589
3590 void tmxr_fstats (FILE *st, const TMLN *lp, int32 ln)
3591 {
3592 static const char *enab = "on";
3593 static const char *dsab = "off";
3594
3595 if (ln >= 0)
3596 fprintf (st, "Line %d:", ln);
3597 if ((!lp->sock) && (!lp->connecting)
3598 )
3599 fprintf (st, " not connected\n");
3600 else {
3601 if (ln >= 0)
3602 fprintf (st, "\n");
3603 fprintf (st, " input (%s)", (lp->rcve? enab: dsab));
3604 if (lp->rxcnt)
3605 fprintf (st, " queued/total = %d/%d", tmxr_rqln (lp), lp->rxcnt);
3606 if (lp->rxpcnt)
3607 fprintf (st, " packets = %d", lp->rxpcnt);
3608 fprintf (st, "\n output (%s)", (lp->xmte? enab: dsab));
3609 if (lp->txcnt || lp->txbpi)
3610 fprintf (st, " queued/total = %d/%d", tmxr_tqln (lp), lp->txcnt);
3611 if (lp->txpcnt || tmxr_tpqln (lp))
3612 fprintf (st, " packet data queued/packets sent = %d/%d",
3613 tmxr_tpqln (lp), lp->txpcnt);
3614 fprintf (st, "\n");
3615 }
3616 if (lp->txbfd)
3617 fprintf (st, " output buffer size = %d\n", lp->txbsz);
3618 if (lp->txcnt || lp->txbpi)
3619 fprintf (st, " bytes in buffer = %d\n",
3620 ((lp->txcnt > 0) && (lp->txcnt > lp->txbsz)) ? lp->txbsz : lp->txbpi);
3621 if (lp->txdrp)
3622 fprintf (st, " dropped = %d\n", lp->txdrp);
3623 return;
3624 }
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652 t_stat tmxr_dscln (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
3653 {
3654 TMXR *mp = (TMXR *) desc;
3655 TMLN *lp;
3656 t_stat status;
3657
3658 if (val)
3659 uptr = NULL;
3660
3661 lp = tmxr_get_ldsc (uptr, cptr, mp, &status);
3662
3663 if (lp == NULL)
3664 return status;
3665
3666 if ((lp->sock)
3667 ) {
3668 if (!lp->notelnet)
3669 tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");
3670 tmxr_reset_ln_ex (lp, (sim_switches & SWMASK ('C')));
3671 }
3672
3673 return SCPE_OK;
3674 }
3675
3676
3677
3678 t_stat tmxr_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
3679 {
3680 TMXR *mp = (TMXR *) desc;
3681 TMLN *lp;
3682 t_stat r;
3683
3684 if (cptr == NULL)
3685 return SCPE_2FARG;
3686 lp = tmxr_find_ldsc (uptr, val, mp);
3687 if (lp == NULL)
3688 return SCPE_IERR;
3689 if (lp->txlog)
3690 tmxr_set_nolog (NULL, val, NULL, desc);
3691 lp->txlogname = (char *) calloc (CBUFSIZE, sizeof (char));
3692 if (lp->txlogname == NULL)
3693 return SCPE_MEM;
3694 strncpy (lp->txlogname, cptr, CBUFSIZE-1);
3695 r = sim_open_logfile (cptr, TRUE, &lp->txlog, &lp->txlogref);
3696 if (r != SCPE_OK) {
3697 FREE (lp->txlogname);
3698 return r;
3699 }
3700 if (lp->txlog == NULL) {
3701 FREE (lp->txlogname);
3702 return SCPE_OPENERR;
3703 }
3704 if (mp->uptr)
3705 lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
3706 return SCPE_OK;
3707 }
3708
3709
3710
3711 t_stat tmxr_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
3712 {
3713 TMXR *mp = (TMXR *) desc;
3714 TMLN *lp;
3715
3716 if (cptr)
3717 return SCPE_2MARG;
3718 lp = tmxr_find_ldsc (uptr, val, mp);
3719 if (lp == NULL)
3720 return SCPE_IERR;
3721 if (lp->txlog) {
3722 sim_close_logfile (&lp->txlogref);
3723 FREE (lp->txlogname);
3724 lp->txlog = NULL;
3725 lp->txlogname = NULL;
3726 }
3727 if (mp->uptr)
3728 lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
3729 return SCPE_OK;
3730 }
3731
3732
3733
3734 t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
3735 {
3736 const TMXR *mp = (const TMXR *) desc;
3737 TMLN *lp;
3738
3739 lp = tmxr_find_ldsc (uptr, val, mp);
3740 if (lp == NULL)
3741 return SCPE_IERR;
3742 if (lp->txlog)
3743 fprintf (st, "logging to %s", lp->txlogname);
3744 else fprintf (st, "no logging");
3745 return SCPE_OK;
3746 }
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776 t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *carg, void *desc)
3777 {
3778 TMXR *mp = (TMXR *) desc;
3779 char *tbuf;
3780 char *tptr;
3781 CONST char *cptr;
3782 t_addr low, high, max = (t_addr) mp->lines - 1;
3783 int32 *list;
3784 t_bool *set;
3785 uint32 line, idx = 0;
3786 t_stat result = SCPE_OK;
3787
3788 if (mp->lnorder == NULL)
3789 return SCPE_NXPAR;
3790
3791 else if ((carg == NULL) || (*carg == '\0'))
3792 return SCPE_MISVAL;
3793
3794 list = (int32 *) calloc (mp->lines, sizeof (int32));
3795 if (list == NULL)
3796 return SCPE_MEM;
3797
3798 set = (t_bool *) calloc (mp->lines, sizeof (t_bool));
3799 if (set == NULL) {
3800 FREE (list);
3801 return SCPE_MEM;
3802 }
3803
3804 tbuf = (char *) calloc (strlen(carg)+2, sizeof(*carg));
3805 if (tbuf == NULL) {
3806 FREE(set);
3807 FREE(list);
3808 return SCPE_MEM;
3809 }
3810 (void)strcpy (tbuf, carg);
3811 tptr = tbuf + strlen (tbuf);
3812 *tptr++ = ';';
3813 *tptr = '\0';
3814 cptr = tbuf;
3815
3816 while (*cptr) {
3817 cptr = get_range (NULL, cptr, &low, &high, 10, max, ';');
3818
3819 if (cptr == NULL) {
3820 result = SCPE_ARG;
3821 break;
3822 }
3823
3824 else if ((low > max) || (high > max)) {
3825 result = SCPE_SUB;
3826 break;
3827 }
3828
3829 else if ((low == 0) && (high == max)) {
3830 list [0] = -1;
3831 idx = (uint32) max + 1;
3832 break;
3833 }
3834
3835 else
3836 for (line = (uint32) low; line <= (uint32) high; line++)
3837 if (set [line] == FALSE) {
3838 set [line] = TRUE;
3839 list [idx] = line;
3840 idx = idx + 1;
3841 }
3842 }
3843
3844 if (result == SCPE_OK) {
3845 if (idx <= max)
3846 for (line = 0; line <= max; line++)
3847 if (set [line] == FALSE) {
3848 list [idx] = line;
3849 idx = idx + 1;
3850 }
3851
3852 memcpy (mp->lnorder, list, mp->lines * sizeof (int32));
3853 }
3854
3855 FREE (list);
3856 FREE (set);
3857 FREE (tbuf);
3858
3859 return result;
3860 }
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877 t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
3878 {
3879 int32 i, j, low, last;
3880 const TMXR *mp = (const TMXR *) desc;
3881 int32 *iptr = mp->lnorder;
3882 t_bool first = TRUE;
3883
3884 if (iptr == NULL)
3885 return SCPE_NXPAR;
3886
3887 if (*iptr < 0)
3888 fprintf (st, "Order=0-%d\n", mp->lines - 1);
3889
3890 else {
3891 low = last = *iptr++;
3892
3893 for (j = 1; j <= mp->lines; j++) {
3894 if (j < mp->lines)
3895 i = *iptr++;
3896 else
3897 i = -1;
3898
3899 if (i != last + 1) {
3900 if (first) {
3901 fputs ("Order=", st);
3902 first = FALSE;
3903 }
3904
3905 else
3906 fputc (';', st);
3907
3908 if (low == last)
3909 fprintf (st, "%d", last);
3910
3911 else
3912 fprintf (st, "%d-%d", low, last);
3913
3914 low = i;
3915 }
3916
3917 last = i;
3918 }
3919 }
3920
3921 if (first == FALSE)
3922 fputc ('\n', st);
3923
3924 return SCPE_OK;
3925 }
3926
3927
3928
3929 t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
3930 {
3931 const TMXR *mp = (const TMXR *) desc;
3932 int32 i, t;
3933
3934 if (mp == NULL)
3935 return SCPE_IERR;
3936 for (i = t = 0; i < mp->lines; i++)
3937 if ((mp->ldsc[i].sock != 0)
3938 )
3939 t = t + 1;
3940 if (mp->lines > 1)
3941 fprintf (st, "%d current connection%s", t, (t != 1) ? "s" : "");
3942 else
3943 fprintf (st, "%s", (t == 1) ? "connected" : "disconnected");
3944 return SCPE_OK;
3945 }
3946
3947
3948
3949 t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
3950 {
3951 const TMXR *mp = (const TMXR *) desc;
3952 int32 i, any;
3953
3954 if (mp == NULL)
3955 return SCPE_IERR;
3956 for (i = any = 0; i < mp->lines; i++) {
3957 if ((mp->ldsc[i].sock != 0)
3958 || mp->ldsc[i].modem_control) {
3959 if ((mp->ldsc[i].sock != 0)
3960 )
3961 any++;
3962 if (val)
3963 tmxr_fconns (st, &mp->ldsc[i], i);
3964 else
3965 if ((mp->ldsc[i].sock != 0)
3966 )
3967 tmxr_fstats (st, &mp->ldsc[i], i);
3968 }
3969 }
3970 if (any == 0)
3971 fprintf (st, (mp->lines == 1? "disconnected\n": "all disconnected\n"));
3972 return SCPE_OK;
3973 }
3974
3975
3976
3977 t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
3978 {
3979 const TMXR *mp = (const TMXR *) desc;
3980
3981 if (mp == NULL)
3982 return SCPE_IERR;
3983 fprintf (st, "lines=%d", mp->lines);
3984 return SCPE_OK;
3985 }