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