1 /*
2 * Copyright (c) 2016 Charles Anthony
3 * Copyright (c) 2016 Michal Tomek
4 * Copyright (c) 2021 The DPS8M Development Team
5 *
6 * All rights reserved.
7 *
8 * This software is made available under the terms of the ICU
9 * License, version 1.8.1 or later. For more details, see the
10 * LICENSE.md file at the top-level directory of this distribution.
11 */
12
13 // The FNP <--> libuv interface
14 //
15 // Every libuv TCP connection has a uv_tcp_t object.
16 //
17 // The uv_tcp_t object has a 'user data' field defined as "void * data".
18 //
19 // This code stores a pointer to a "struct uvClientData" in 'data'; this
20 // structure allows this code to determine which HSLA line the connection
21 // has been made with.
22 //
23 // The uvClientData structure contains:
24 //
25 // bool assoc
26 // uint fnpno;
27 // uint lineno;
28 //
29 // If 'assoc' is true, the TCP connection is associated with a particular
30 // HSLA line as specified by 'fnpno' and 'lineno'. A dialup line is
31 // associated by the user entering the FNP name and line number in the
32 // multiplexor dial in dialog. For slave and dialout lines, 'assoc'
33 // is always true as the assoication is predetermined by the FNP
34 // configuration.
35 //
36 // char buffer [1024];
37 // size_t nPos;
38 //
39 // Line canonicalization buffer used by the multiplexor dial in dialog.
40 //
41 // Each HSLA line is identified by a 'fnpno', 'lineno' pair. 'fnpno' indexes
42 // into the 'fnpUnitData' data structure and 'lineno' into
43 // 'fnpUnitData[fnpno].MState.line[]'.
44 //
45 // The 'line' structure contains:
46 //
47 // enum service_types service;
48 //
49 // This tracks the Multics' line configuration of 'dialup', 'dialout', and
50 // 'slave'.
51 //
52 // uv_tcp_t * client;
53 //
54 // If this is non-null, the HSLA has a TCP connection.
55 //
56 // telnet_t * telnetp;
57 //
58 // If this is non-null, Telnet is enabled on the connection.
59 //
60 // uv_tcp_t server;
61 //
62 // This is used by the 'slave' logic and holds the handle of the
63 // TCP server port for the slave line.
64 //
65 // The data field of 'server' points to a uvClientData structure; this
66 // field is used by the incoming connection handler to distinguish the
67 // slave and dialup server ports. (If null, dialup; else slave.)
68 //
69 // uv_connect_t doConnect;
70 //
71 // libuv uses a uv_connect_t object to create outbound connections;
72 // the dialout code uses 'doConnect' for this.
73 //
74 // int port;
75 //
76 // The port number that a slave line listens on, as set by Devices.txt.
77 //
78
79
80 // Dialup logic.
81 //
82 // The code assumes a single port number for all dialup lines, even for the
83 // case of multiple FNPs.
84 //
85 // 'fnpuvInit()' is called when by the 'fnpserverport' command logic. It
86 // creates a TCP server listen port, assigning 'on_new_connection()' as
87 // the connection callback handler.
88 //
89 // When a connection is made to the listen port, libuv invokes the
90 // 'on_new_connection()' callback handler.
91 //
92 // The handler creates a 'uv_tcp_t' object 'client' and accepts the
93 // connection.
94 //
95 // It then checks the 'data' field on the listener object to see if this
96 // is a dialup or slave listener. For the case of dialup, a 'uvClientData'
97 // object is created and its 'assoc' field is set to false to flag the
98 // the connection as not yet being associated with an HSLA line; the
99 // libtelnet data structure is intialized and the initial Telnet negotiations
100 // are started. 'client->data' is set the the 'uvClientData' object,
101 // reading is enabled on 'client', and the HSLA line selection dialog
102 // prompt is sent down the dialup connection.
103 //
104 // When input data is ready on the connection (user input), libuv allocates
105 // a buffer, fills it with the data calls the 'fuv_read_cb()' callback handler.
106 //
107 // The handler looks at the 'data' field of the connection to access the
108 // 'uvClientData' structure; if the sturcture indicates that Telnet
109 // processing is to be done, it passes the data to libtelent handler.
110 // Otherwise, it checks the 'assoc' field; if true the data is passed to the
111 // FNP incoming data handler; if false, to the multiplexor line selection
112 // dialog handler. The libtelnet handler, after stripping and processing
113 // Telnet overhead passes any remaining data on in the same manner.
114 // The data buffer is then freed, and the callback returns.
115 //
116 // Since the FNP incoming data handler is dependent on Multics accepting
117 // the input data before it can safely dispose of the data, it disables
118 // reading on the connection, and reenables it when Multics has accepted the
119 // data.
120
121 // Data are written to the TCP connections with 'fnpuv_start_write()'. The
122 // 'uvClientData' is inspected for telnet usage; if so, the data is passed
123 // to libtelnet for telnet packaging and is sent on to
124 // 'fnpuv_start_write_actual'. If telnet is not in play, the data is sent
125 // directly on to 'fnpuv_start_write_actual()' There, a buffer is allocated
126 // and the data copied and a 'uv_write_t' request object is created and
127 // initalized data the buffer address and length, and a write request
128 // is send to libuv.
129 //
130 // When the write is complete, libuv calls the write callback 'fuv_write_cb()',
131 // which frees the data buffers and destroys the write request object.
132
133 // Dialout logic
134 //
135 // When the FNP receives a 'dial_out' command, it calls 'fnpuv_dial_out()'.
136 // The dial string is parsed for IP address, port number and telnet flag.
137 // An 'uv_tcp_t' object constructed and its address stored in the HSLA
138 // 'client' field. An 'uvClientData' object is created, associated with
139 // the dialout line HSLA, and if the Telnet flag is set, the Telnet processor
140 // is initialized. The TCP connect is initiated and the procedure returns.
141 //
142 // When the connection succeeds or times out, the 'on_dialout_connect()' callback
143 // is called. on_dialout_connect retrieves the 'uvClientData'. If the connection
144 // succeeded, the connection data field is set to the 'uvClientData'; read is
145 // enabled on the connection, and the 'accept_new_terminal' flag is set which
146 // will cause an 'accept_new_terminal' command to be send to Multics.
147 //
148
149
150 #ifdef TUN
151 // TUN interface
152
153 // If makes more sense to me to have the emulator on an endpoint, but
154 // that's not really the way ethernet works; for the nonce, we will
155 // create a subnet and route to it with a tun device; the emulator
156 // will listen on the device and do the whole ARP rigamorole.
157 //
158 // It's not clear to me what happens if multiple emulators are listening
159 // on the same tun device, do they each get a copy of the message (i.e.
160 // are we wired as point-to-point)?
161 //
162 // Create device node:
163 // mkdir /dev/net (if it doesn't exist already)
164 // mknod /dev/net/tun c 10 200
165 // chmod 0666 /dev/net/tun
166 // modprobe tun
167 //
168 // The subnet gateway device is 'dps8m' at address 192.168.8.0
169 //
170 // sudo ip tuntap add mode tun dps8m
171 // sudo ip link set dps8m up
172 // sudo ip addr add 192.168.8.1/24 dev dps8m
173 #endif
174
175 #define ASSUME0 0
176
177
178 #include <stdio.h>
179 #include <stdlib.h>
180 #include <unistd.h>
181 #include <ctype.h>
182 //#include <uv.h>
183 #ifdef TUN
184 # include <string.h>
185 # include <fcntl.h>
186 # include <errno.h>
187 # include <sys/ioctl.h>
188 # include <sys/types.h>
189 # include <sys/stat.h>
190 # include <netinet/in.h>
191 # include <sys/socket.h>
192 # include <linux/if.h>
193 # include <linux/if_tun.h>
194 #endif
195
196 #include "dps8.h"
197 #include "dps8_scu.h"
198 #include "dps8_sys.h"
199 #include "dps8_iom.h"
200 #include "dps8_cable.h"
201 #include "dps8_cpu.h"
202 #include "dps8_fnp2.h"
203 #include "dps8_utils.h"
204 #include "fnpuv.h"
205 #include "fnptelnet.h"
206
207 //#define TEST
208
209 #define USE_REQ_DATA
210
211 // Making it up...
212 #define DEFAULT_BACKLOG 1024
213
214 #ifdef TUN
tun_alloc(char * dev)215 static int tun_alloc (char * dev)
216 {
217 struct ifreq ifr;
218 int fd, err;
219
220 if ((fd = open ("/dev/net/tun", O_RDWR)) < 0)
221 //return tun_alloc_old (dev);
222 return fd;
223
224 memset (& ifr, 0, sizeof (ifr));
225
226 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
227 * IFF_TAP - TAP device
228 *
229 * IFF_NO_PI - Do not provide packet information
230 */
231 ifr.ifr_flags = IFF_TUN;
232 if (* dev)
233 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
234
235 if ((err = ioctl (fd, TUNSETIFF, (void *) & ifr)) < 0)
236 {
237 close (fd);
238 return err;
239 }
240 strcpy (dev, ifr.ifr_name);
241 return fd;
242 }
243 #endif
244
245 //
246 // alloc_buffer: libuv callback handler to allocate buffers for incomingd data.
247 //
248
alloc_buffer(UNUSED uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)249 static void alloc_buffer (UNUSED uv_handle_t * handle, size_t suggested_size,
250 uv_buf_t * buf)
251 {
252 * buf = uv_buf_init ((char *) malloc (suggested_size), (uint) suggested_size);
253 }
254
255
fnpuv_associated_brk(uv_tcp_t * client)256 void fnpuv_associated_brk (uv_tcp_t * client)
257 {
258 if (! client || uv_is_closing ((uv_handle_t *) client))
259 return;
260 if (! client->data)
261 {
262 sim_warn ("fnpuv_associated_brk bad client data\r\n");
263 return;
264 }
265 uvClientData * p = (uvClientData *) client->data;
266 uint fnpno = p -> fnpno;
267 uint lineno = p -> lineno;
268 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
269 // The break key forces an input buffer flush.
270 // XXX is this a race condition? Is it possible for processFnpMbx to see
271 // the line_break before the accept input?
272 linep->accept_input = 1;
273 linep->line_break=true;
274 }
275
276 // read callback for connections that are associated with an HSLA line;
277 // forward the data to the FNP input handler
278
fnpuv_associated_readcb(uv_tcp_t * client,ssize_t nread,unsigned char * buf)279 void fnpuv_associated_readcb (uv_tcp_t * client,
280 ssize_t nread,
281 unsigned char * buf)
282 {
283 processLineInput (client, buf, nread);
284 }
285
fnpuv_3270_readcb(uv_tcp_t * client,ssize_t nread,unsigned char * buf)286 void fnpuv_3270_readcb (uv_tcp_t * client,
287 ssize_t nread,
288 unsigned char * buf)
289 {
290 process3270Input (client, buf, nread);
291 }
292
293 // read callback for connections that are no tassociated with an HSLA line;
294 // forward the data to the line selection dialog handler
295
fnpuv_unassociated_readcb(uv_tcp_t * client,ssize_t nread,unsigned char * buf)296 void fnpuv_unassociated_readcb (uv_tcp_t * client,
297 ssize_t nread,
298 unsigned char * buf)
299 {
300 //printf ("unaassoc. <%*s>\n", (int) nread, buf->base);
301 processUserInput (client, buf, nread);
302 }
303
fuv_close_cb(uv_handle_t * stream)304 static void fuv_close_cb (uv_handle_t * stream)
305 {
306 free (stream);
307 }
308
309 // teardown a connection
310
close_connection(uv_stream_t * stream)311 void close_connection (uv_stream_t* stream)
312 {
313 if (! stream)
314 {
315 sim_warn ("close_connection bad client data\r\n");
316 return;
317 }
318 uvClientData * p = (uvClientData *) stream->data;
319
320 // If stream->data, the stream is associated with a Multics line.
321 // Tear down that association
322 //if (p && fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno].service != service_3270)
323 if (p)
324 {
325 // If assoc is false, then the disconnect happened before the actual
326 // associaton took place
327 if (p->assoc)
328 {
329 struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
330 if (linep->service == service_3270)
331 {
332 // On the 3270, the station closing does not close the controller
333 sim_printf ("[FNP emulation: 3270 %d.%d DISCONNECT]\n", ASSUME0, p->stationNo);
334 }
335 else
336 {
337 sim_printf ("[FNP emulation: DISCONNECT %c.d%03d]\n", p->fnpno+'a', p->lineno);
338 #ifdef DISC_DELAY
339 linep -> line_disconnected = DISC_DELAY;
340 #else
341 linep -> line_disconnected = true;
342 #endif
343 linep -> listen = false;
344 if (linep->inBuffer)
345 free (linep->inBuffer);
346 linep->inBuffer = NULL;
347 linep->inSize = 0;
348 linep->inUsed = 0;
349 linep->nPos = 0;
350 }
351 if (linep->line_client)
352 {
353 // linep->line_client is a copied stream->data; will be freed
354 // below
355 linep->line_client = NULL;
356 }
357 }
358 else // ! p-assoc
359 {
360 sim_printf ("[FNP emulation: DISCONNECT]\n");
361 }
362 // Clean up allocated data
363 if (p->telnetp)
364 {
365 telnet_free (p->telnetp);
366 // telnet_free frees self
367 //free (p->telnetp);
368 p->telnetp = NULL;
369 }
370 if (((uvClientData *) stream->data)->ttype)
371 free (((uvClientData *) stream->data)->ttype);
372 free (stream->data);
373 stream->data = NULL;
374 } // if (p)
375 if (! uv_is_closing ((uv_handle_t *) stream))
376 uv_close ((uv_handle_t *) stream, fuv_close_cb);
377 }
378
379 //
380 // fuv_read_cb: libuv read complete callback
381 //
382 // Cleanup on read error.
383 // Forward data to appropriate handler.
384
fuv_read_cb(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)385 static void fuv_read_cb (uv_stream_t* stream,
386 ssize_t nread,
387 const uv_buf_t* buf)
388 {
389 if (nread < 0)
390 {
391 //if (nread == UV_EOF)
392 {
393 close_connection (stream);
394 }
395 }
396 else if (nread > 0)
397 {
398 if (! stream)
399 {
400 sim_warn ("fuv_read_cb bad client data\r\n");
401 return;
402 }
403 uvClientData * p = (uvClientData *) stream->data;
404 if (p)
405 {
406 if (p->telnetp)
407 {
408 telnet_recv (p->telnetp, buf->base, (size_t) nread);
409 }
410 else
411 {
412 #if 1
413 (* p->read_cb) ((uv_tcp_t *) stream, nread, (unsigned char *) buf->base);
414
415 #else
416 if (p -> assoc)
417 {
418 fnpuv_associated_readcb ((uv_tcp_t *) stream, nread, (unsigned char *) buf->base);
419 }
420 else
421 {
422 fnpuv_unassociated_readcb ((uv_tcp_t *) stream, nread, (unsigned char *) buf->base);
423 }
424 #endif
425 }
426 }
427 }
428
429 if (buf->base)
430 free (buf->base);
431 }
432
433 //
434 // fuv_write_cb: libuv write complete callback
435 //
436 // Cleanup on error
437 // Free buffers
438 //
439
fuv_write_cb(uv_write_t * req,int status)440 static void fuv_write_cb (uv_write_t * req, int status)
441 {
442 if (status < 0)
443 {
444 if (status == -ECONNRESET || status == -ECANCELED ||
445 status == -EPIPE)
446 {
447 // This occurs when the other end disconnects; not an "error"
448 }
449 else
450 {
451 sim_warn ("fuv_write_cb status %d (%s)\n", -status, strerror (-status));
452 }
453
454 // connection reset by peer
455 close_connection (req->handle);
456 }
457
458 #ifdef USE_REQ_DATA
459 //sim_printf ("freeing bufs %p\n", req->data);
460 free (req->data);
461 #else
462 unsigned int nbufs = req->nbufs;
463 uv_buf_t * bufs = req->bufs;
464 //if (! bufs)
465 # if 0
466 if (nbufs > ARRAY_SIZE(req->bufsml))
467 bufs = req->bufsml;
468 # endif
469 //sim_printf ("fuv_write_cb req %p req->data %p bufs %p nbufs %u\n", req, req->data, bufs, nbufs);
470 for (unsigned int i = 0; i < nbufs; i ++)
471 {
472 if (bufs && bufs[i].base)
473 {
474 //sim_printf ("freeing bufs%d %p\n", i, bufs[i].base);
475 free (bufs[i].base);
476 //bufp -> base = NULL;
477 }
478 if (req->bufsml[i].base)
479 {
480 //sim_printf ("freeing bufsml%d %p@%p\n", i, req->bufsml[i].base, & req->bufsml[i].base);
481 free (req->bufsml[i].base);
482 }
483 }
484 #endif
485
486 // the buf structure is copied; do not free.
487 //sim_printf ("freeing req %p\n", req);
488 free (req);
489 }
490
491 //
492 // fuv_write_3270_cb: libuv write complete callback
493 //
494 // Cleanup on error
495 // Free buffers
496 //
497
fuv_write_3270_cb(uv_write_t * req,int status)498 static void fuv_write_3270_cb (uv_write_t * req, int status)
499 {
500 fuv_write_cb (req, status);
501 set_3270_write_complete ((uv_tcp_t *) req->handle);
502 }
503
504 // Create and start a write request
505
fnpuv_start_write_3270_actual(UNUSED uv_tcp_t * client,unsigned char * data,ssize_t datalen)506 static void fnpuv_start_write_3270_actual (UNUSED uv_tcp_t * client, unsigned char * data, ssize_t datalen)
507 {
508 #ifdef TESTING
509 sim_printf ("fnpuv_start_write_3270_actual\r\n");
510 #endif
511 #if 0
512 sim_printf ("hex :");
513 for (ssize_t i = 0; i < datalen; i ++) sim_printf (" %02hhx", data[i]);
514 sim_printf ("\r\n");
515 sim_printf ("octal :");
516 for (ssize_t i = 0; i < datalen; i ++) sim_printf (" %03hho", data[i]);
517 sim_printf ("\r\n");
518 sim_printf ("ascii :");
519 for (ssize_t i = 0; i < datalen; i ++)
520 if (isprint (data[i]))
521 sim_printf ("%c", data[i]);
522 else
523 sim_printf ("\\%03hho", data[i]);
524 sim_printf ("\r\n");
525 sim_printf ("ebcdic:");
526 for (ssize_t i = 0; i < datalen; i ++)
527 if (isprint (e2a[data[i]]))
528 sim_printf ("%c", e2a[data[i]]);
529 else
530 sim_printf ("\\%03hho", e2a[data[i]]);
531 sim_printf ("\r\n");
532 #endif
533
534
535 // Find the client from the device selection call
536
537 uint stn_no;
538 for (stn_no = 0; stn_no < ADDR_MAP_ENTRIES; stn_no ++)
539 if (addr_map [stn_no] == fnpData.ibm3270ctlr[ASSUME0].selDevChar)
540 break;
541 if (stn_no >= ADDR_MAP_ENTRIES)
542 {
543 sim_printf ("fnpuv_start_write_3270_actual couldn't find selDevChar %02x\r\n", (unsigned int) fnpData.ibm3270ctlr[ASSUME0].selDevChar);
544 return;
545 }
546 uv_tcp_t * stn_client = fnpData.ibm3270ctlr[ASSUME0].stations[stn_no].client;
547 if (! stn_client || uv_is_closing ((uv_handle_t *) stn_client))
548 return;
549
550
551 // Allocate write request
552
553 uv_write_t * req = (uv_write_t *) malloc (sizeof (uv_write_t));
554 // This makes sure that bufs*.base and bufsml*.base are NULL
555 memset (req, 0, sizeof (uv_write_t));
556 uv_buf_t buf = uv_buf_init ((char *) malloc ((unsigned long) datalen), (uint) datalen);
557 //sim_printf ("allocated req %p data %p\n", req, buf.base);
558 #ifdef USE_REQ_DATA
559 req->data = buf.base;
560 #endif
561 //sim_printf ("fnpuv_start_write_actual req %p buf.base %p\n", req, buf.base);
562 memcpy (buf.base, data, (unsigned long) datalen);
563 int ret = uv_write (req, (uv_stream_t *) stn_client, & buf, 1, fuv_write_3270_cb);
564 // There seems to be a race condition when Mulitcs signals a disconnect_line;
565 // We close the socket, but Mulitcs is still writing its goodbye text trailing
566 // NULs.
567 // If the socket has been closed, write will return BADF; just ignore it.
568 if (ret < 0 && ret != -EBADF)
569 sim_printf ("[FNP emulation: uv_write returns %d]\n", ret);
570 }
571
fnpuv_start_write_actual(uv_tcp_t * client,unsigned char * data,ssize_t datalen)572 void fnpuv_start_write_actual (uv_tcp_t * client, unsigned char * data, ssize_t datalen)
573 {
574 if (! client || uv_is_closing ((uv_handle_t *) client))
575 return;
576 uv_write_t * req = (uv_write_t *) malloc (sizeof (uv_write_t));
577 // This makes sure that bufs*.base and bufsml*.base are NULL
578 memset (req, 0, sizeof (uv_write_t));
579 uv_buf_t buf = uv_buf_init ((char *) malloc ((unsigned long) datalen), (uint) datalen);
580 //sim_printf ("allocated req %p data %p\n", req, buf.base);
581 #ifdef USE_REQ_DATA
582 req->data = buf.base;
583 #endif
584 //sim_printf ("fnpuv_start_write_actual req %p buf.base %p\n", req, buf.base);
585 memcpy (buf.base, data, (unsigned long) datalen);
586 int ret = uv_write (req, (uv_stream_t *) client, & buf, 1, fuv_write_cb);
587 // There seems to be a race condition when Mulitcs signals a disconnect_line;
588 // We close the socket, but Mulitcs is still writing its goodbye text trailing
589 // NULs.
590 // If the socket has been closed, write will return BADF; just ignore it.
591 if (ret < 0 && ret != -EBADF)
592 sim_printf ("[FNP emulation: uv_write returns %d]\n", ret);
593 }
594
595 //
596 // Write data to a connection, doing Telnet if needed.
597 //
598
fnpuv_start_write(uv_tcp_t * client,unsigned char * data,ssize_t datalen)599 void fnpuv_start_write (uv_tcp_t * client, unsigned char * data, ssize_t datalen)
600 {
601 if (! client || uv_is_closing ((uv_handle_t *) client))
602 return;
603 uvClientData * p = (uvClientData *) client->data;
604 if (! p)
605 return;
606 if (!p->telnetp)
607 {
608 sim_warn ("telnetp NULL; dropping fnpuv_start_write()\n");
609 return;
610 }
611 telnet_send (p->telnetp, (char *) data, (size_t) datalen);
612 }
613
fnpuv_start_3270_write(uv_tcp_t * client,unsigned char * data,ssize_t datalen)614 void fnpuv_start_3270_write (uv_tcp_t * client, unsigned char * data, ssize_t datalen)
615 {
616 if (! client || uv_is_closing ((uv_handle_t *) client) || ! client->data)
617 return;
618 uvClientData * p = (uvClientData *) client->data;
619 if (! p)
620 return;
621 #ifdef TESTING
622 sim_printf ("fnpuv_start_3270_write\r\n");
623 #endif
624 #if 0
625 sim_printf ("hex :");
626 for (ssize_t i = 0; i < datalen; i ++) sim_printf (" %02hhx", data[i]);
627 sim_printf ("\r\n");
628 sim_printf ("octal :");
629 for (ssize_t i = 0; i < datalen; i ++) sim_printf (" %03hho", data[i]);
630 sim_printf ("\r\n");
631 sim_printf ("ascii :");
632 for (ssize_t i = 0; i < datalen; i ++)
633 if (isprint (data[i]))
634 sim_printf ("%c", data[i]);
635 else
636 sim_printf ("\\%03hho", data[i]);
637 sim_printf ("\r\n");
638 sim_printf ("ebcdic:");
639 for (ssize_t i = 0; i < datalen; i ++)
640 if (isprint (e2a[data[i]]))
641 sim_printf ("%c", e2a[data[i]]);
642 else
643 sim_printf ("\\%03hho", e2a[data[i]]);
644 sim_printf ("\r\n");
645 #endif
646
647 // Strip BSC protocol:
648 // STX <text> ETX
649 // EOT
650
651 if (datalen == 1 && data [0] == 0x37) // EOT
652 {
653 #ifdef TESTING
654 sim_printf ("fnpuv: detected EOT\r\n");
655 #endif
656 fnpuv_send_eor (client);
657 return;
658 }
659
660 unsigned char * actual_data_start = data;
661 unsigned long actual_datalen = (unsigned long) datalen;
662 //bool send_eor = false;
663 if (data [datalen - 1] == 0x03) // ETX
664 {
665 actual_datalen --;
666 //send_eor = true;
667 }
668 if (data [0] == 0x02) // STX
669 {
670 actual_data_start ++;
671 actual_datalen --;
672 if (data [1] == 0x27) // ESC
673 {
674 actual_data_start ++;
675 actual_datalen --;
676 }
677 }
678
679 telnet_send (p->telnetp, (char *) actual_data_start, (size_t) actual_datalen);
680 //if (send_eor)
681 //fnpuv_send_eor (client);
682 }
683
684
685 // C-string wrapper for fnpuv_start_write
686
fnpuv_start_writestr(uv_tcp_t * client,unsigned char * data)687 void fnpuv_start_writestr (uv_tcp_t * client, unsigned char * data)
688 {
689 //fnpuv_start_write (client, data, (ssize_t) strlen (data));
690 if (! client || uv_is_closing ((uv_handle_t *) client))
691 return;
692 if (! client->data)
693 {
694 sim_warn ("fnpuv_start_writestr bad client data\r\n");
695 return;
696 }
697 uvClientData * p = client->data;
698 (* p->write_cb) (client, data, (ssize_t) strlen ((char *) data));
699 }
700
fnpuv_send_eor(uv_tcp_t * client)701 void fnpuv_send_eor (uv_tcp_t * client)
702 {
703 if (! client || uv_is_closing ((uv_handle_t *) client))
704 return;
705 if (! client->data)
706 {
707 sim_warn ("fnpuv_send_eor bad client data\r\n");
708 return;
709 }
710 uvClientData * p = (uvClientData *) client->data;
711 ltnEOR (p->telnetp);
712 //unsigned char EOR [] = { TELNET_IAC, TELNET_EOR };
713 //fnpuv_start_write_special (client, (char *) EOR, sizeof (EOR));
714 }
715
716
fnpuv_recv_eor(uv_tcp_t * client)717 void fnpuv_recv_eor (uv_tcp_t * client)
718 {
719 fnpRecvEOR (client);
720 }
721
722 //
723 // Enable reading on connection
724 //
725
fnpuv_read_start(uv_tcp_t * client)726 void fnpuv_read_start (uv_tcp_t * client)
727 {
728 #ifdef TESTING
729 sim_printf ("fnpuv_read_start\r\n");
730 #endif
731 if (! client || uv_is_closing ((uv_handle_t *) client))
732 return;
733 uv_read_start ((uv_stream_t *) client, alloc_buffer, fuv_read_cb);
734 }
735
736 //
737 // Disable reading on connection
738 //
739
fnpuv_read_stop(uv_tcp_t * client)740 void fnpuv_read_stop (uv_tcp_t * client)
741 {
742 if (! client || uv_is_closing ((uv_handle_t *) client))
743 return;
744 uv_read_stop ((uv_stream_t *) client);
745 }
746
747 //
748 // Connection callback handler for dialup connections
749 //
750
on_new_connection(uv_stream_t * server,int status)751 static void on_new_connection (uv_stream_t * server, int status)
752 {
753 if (status < 0)
754 {
755 sim_printf ("[FNP emulation: New connection error %s]\n", uv_strerror (status));
756 // error!
757 return;
758 }
759
760 uv_tcp_t * client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
761 uv_tcp_init (fnpData.loop, client);
762 if (uv_accept (server, (uv_stream_t *) client) != 0)
763 {
764 uv_close ((uv_handle_t *) client, fuv_close_cb);
765 return;
766 }
767
768 // if server->data is non-null, this is a slave server; else a dialup
769 // server
770 if (server->data)
771 {
772 uvClientData * p = (uvClientData *) server->data;
773 struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
774 #if 1
775 // Slave servers only handle a single connection at a time
776 if (linep->line_client)
777 {
778 uv_close ((uv_handle_t *) client, fuv_close_cb);
779 # ifdef TESTING
780 sim_printf ("[FNP emulation: dropping 2nd slave]\n");
781 # endif
782 return;
783 }
784 #endif
785 linep->line_client = client;
786 }
787
788 struct sockaddr name;
789 int namelen = sizeof (name);
790 uv_tcp_nodelay (client,1);
791 int ret = uv_tcp_getpeername (client, & name, & namelen);
792 if (ret < 0)
793 {
794 sim_printf ("[FNP emulation: CONNECT; addr err %d]\n", ret);
795 }
796 else
797 {
798 struct sockaddr_in * p = (struct sockaddr_in *) & name;
799 sim_printf ("[FNP emulation: CONNECT %s]\n", inet_ntoa (p -> sin_addr));
800 }
801
802 uvClientData * p = (uvClientData *) malloc (sizeof (uvClientData));
803 if (! p)
804 {
805 sim_warn ("uvClientData malloc failed\n");
806 return;
807 }
808 client->data = p;
809 p->assoc = false;
810 p->nPos = 0;
811 p->ttype = NULL;
812 p->write_actual_cb = fnpuv_start_write_actual;
813 // dialup connections are routed through libtelent
814 if (! server->data)
815 {
816 p->read_cb = fnpuv_unassociated_readcb;
817 p->write_cb = fnpuv_start_write;
818 p->telnetp = ltnConnect (client);
819
820 if (! p->telnetp)
821 {
822 sim_warn ("ltnConnect failed\n");
823 return;
824 }
825 }
826 else
827 {
828 p->read_cb = fnpuv_associated_readcb;
829 p->write_cb = fnpuv_start_write_actual;
830 p->telnetp = NULL;
831 uvClientData * q = (uvClientData *) server->data;
832 p->fnpno = q->fnpno;
833 p->lineno = q->lineno;
834 p->assoc = true;
835 }
836 fnpuv_read_start (client);
837 if (! server->data)
838 fnpConnectPrompt (client);
839 else
840 {
841 uvClientData * p = (uvClientData *) server->data;
842 struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
843 if (linep->lineType == 0) /* LINE_NONE */
844 linep->lineType = 1; /* LINE_ASCII */
845 linep->accept_new_terminal = true;
846 reset_line (linep);
847 }
848 }
849
850 //
851 // Setup the dialup listener
852 //
853
fnpuvInit(int telnet_port,char * telnet_address)854 void fnpuvInit (int telnet_port, char * telnet_address)
855 {
856 // Ignore multiple calls; this means that once the listen port is
857 // opened, it can't be changed. Fixing this requires non-trivial
858 // changes.
859 if (fnpData.du_server_inited)
860 return;
861 fnpData.du_server_inited = true;
862
863 if (! fnpData.loop)
864 fnpData.loop = uv_default_loop ();
865
866 // Initialize the server socket
867 fnpData.loop = uv_default_loop ();
868 uv_tcp_init (fnpData.loop, & fnpData.du_server);
869
870 // XXX to do clean shutdown
871 // uv_loop_close (fnpData.loop);
872
873 // Flag the this server as being the dialup server
874 fnpData.du_server.data = NULL;
875
876 // Bind and listen
877 struct sockaddr_in addr;
878 sim_printf ("[FNP emulation: listening to %s %d]\n", telnet_address, telnet_port);
879 uv_ip4_addr (telnet_address, telnet_port, & addr);
880 uv_tcp_bind (& fnpData.du_server, (const struct sockaddr *) & addr, 0);
881 int r = uv_listen ((uv_stream_t *) & fnpData.du_server, DEFAULT_BACKLOG,
882 on_new_connection);
883 if (r)
884 {
885 sim_printf ("[FNP emulation: Listen error %s]\n", uv_strerror (r));
886 }
887 }
888
889 // Make a single pass through the libev event queue.
890
fnpuvProcessEvent(void)891 void fnpuvProcessEvent (void)
892 {
893 // UV_RUN_NOWAIT: Poll for i/o once but don’t block if there are no
894 // pending callbacks. Returns zero if done (no active handles or
895 // requests left), or non-zero if more callbacks are expected (meaning
896 // you should run the event loop again sometime in the future).
897
898 // Note that uv_run returns non-zero if that are any active_handles
899 // (e.g. TCP connection listener open); that means a non-zero
900 // return does not mean i/o is pending.
901 if (! fnpData.loop)
902 return;
903 /* int ret = */ uv_run (fnpData.loop, UV_RUN_NOWAIT);
904 }
905
906
907 //
908 // dialout line connection callback
909 //
910
on_dialout_connect(uv_connect_t * server,int status)911 static void on_dialout_connect (uv_connect_t * server, int status)
912 {
913 sim_printf ("[FNP emulation: dialout connect]\n");
914 uvClientData * p = (uvClientData *) server->handle->data;
915 // If data is NULL, assume that the line has already been torn down.
916 if (! p)
917 {
918 sim_printf ("[FNP emulation note: on_dialout_connect called with data == NULL]\n");
919 return;
920 }
921 struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
922 if (status < 0)
923 {
924 sim_printf ("[FNP emulation: Dial-out connection error %s]\n", uv_strerror (status));
925 //sim_printf ("%p\n", p);
926 //sim_printf ("%d.%d\n", p->fnpno, p->lineno);
927 linep->acu_dial_failure = true;
928 return;
929 }
930
931 uv_read_start ((uv_stream_t *) linep->line_client, alloc_buffer, fuv_read_cb);
932 linep->listen = true;
933 if (linep->lineType == 0) /* LINE_NONE */
934 linep->lineType = 1; /* LINE_ASCII */
935 linep->accept_new_terminal = true;
936 linep->was_CR = false;
937 linep->line_client->data = p;
938 if (p->telnetp)
939 {
940 ltnDialout (p->telnetp);
941 }
942 }
943
944 //
945 // Perform a dialout
946 //
947
fnpuv_dial_out(uint fnpno,uint lineno,word36 d1,word36 d2,word36 d3)948 void fnpuv_dial_out (uint fnpno, uint lineno, word36 d1, word36 d2, word36 d3)
949 {
950 if (! fnpData.loop)
951 return;
952 sim_printf ("[FNP emulation: received dial_out %c.h%03d %012"PRIo64" %012"PRIo64" %012"PRIo64"]\n", fnpno+'a', lineno, d1, d2, d3);
953 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
954 uint d01 = (d1 >> 30) & 017;
955 uint d02 = (d1 >> 24) & 017;
956 uint d03 = (d1 >> 18) & 017;
957 uint d04 = (d1 >> 12) & 017;
958 uint d05 = (d1 >> 6) & 017;
959 uint d06 = (d1 >> 0) & 017;
960 uint d07 = (d2 >> 30) & 017;
961 uint d08 = (d2 >> 24) & 017;
962 uint d09 = (d2 >> 18) & 017;
963 uint d10 = (d2 >> 12) & 017;
964 uint d11 = (d2 >> 6) & 017;
965 uint d12 = (d2 >> 0) & 017;
966 uint flags = (d3 >> 30) & 017;
967 uint p1 = (d3 >> 24) & 017;
968 uint p2 = (d3 >> 18) & 017;
969 uint p3 = (d3 >> 12) & 017;
970 uint p4 = (d3 >> 6) & 017;
971 uint p5 = (d3 >> 0) & 017;
972
973 uint oct1 = d01 * 100 + d02 * 10 + d03;
974 uint oct2 = d04 * 100 + d05 * 10 + d06;
975 uint oct3 = d07 * 100 + d08 * 10 + d09;
976 uint oct4 = d10 * 100 + d11 * 10 + d12;
977
978 uint port = ((((p1 * 10) + p2) * 10 + p3) * 10 + p4) * 10 + p5;
979
980 // Flags
981 // 1 Use Telnet
982 #ifdef TUN
983 // 2 Use TUN device (in which case 'port' is the netmask
984 #endif
985 // 4
986
987 #ifdef TUN
988 linep->is_tun = false;
989 if (flags & 2)
990 {
991 if (linep->tun_fd <= 0)
992 {
993 char a_name [IFNAMSIZ] = "dps8m";
994 linep->tun_fd = tun_alloc (a_name);
995 if (linep->tun_fd < 0)
996 {
997 sim_printf ("[FNP emulation: dialout TUN tun_alloc returned %d errno %d]\n", linep->tun_fd, errno);
998 return;
999 }
1000 int flags = fcntl (linep->tun_fd, F_GETFL, 0);
1001 if (flags < 0)
1002 {
1003 sim_printf ("[FNP emulation: dialout TUN F_GETFL returned < 0]\n");
1004 return;
1005 }
1006 flags |= O_NONBLOCK;
1007 int ret = fcntl (linep->tun_fd, F_SETFL, flags);
1008 if (ret)
1009 {
1010 sim_printf ("[FNP emulation: dialout TUN F_SETFL returned %d]\n", ret);
1011 return;
1012 }
1013 }
1014 linep->is_tun = true;
1015 return;
1016 }
1017 #endif
1018
1019
1020 // firewall
1021
1022 // Default is accept
1023 bool accept = true;
1024 uint32_t ip_addr = (uint32_t) ((oct1 << 24) | (oct2 << 16) | (oct3 << 8) | oct4);
1025 uint this_line = encodeline (fnpno, lineno);
1026 for (int i = 0; i < n_fw_entries; i ++)
1027 {
1028 struct fw_entry_s * p = fw_entries + i;
1029 if (this_line < p->line_0 || this_line > p->line_1)
1030 continue;
1031 if ((ip_addr & p->cidr_mask) != (p->ipaddr & p->cidr_mask))
1032 continue;
1033 accept = p->accept;
1034 break;
1035 }
1036
1037 if (! accept)
1038 {
1039 sim_printf ("Dialout %c.d%03d denied\r\n", fnpno + 'a', lineno);
1040 linep->acu_dial_failure = true;
1041 return;
1042 }
1043
1044 char ipaddr [256];
1045 sprintf (ipaddr, "%d.%d.%d.%d", oct1, oct2, oct3, oct4);
1046 sim_printf ("calling %s:%d\n", ipaddr,port);
1047
1048 struct sockaddr_in dest;
1049 uv_ip4_addr(ipaddr, (int) port, &dest);
1050
1051 linep->line_client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
1052 uv_tcp_init (fnpData.loop, linep->line_client);
1053
1054
1055 uvClientData * p = (uvClientData *) malloc (sizeof (uvClientData));
1056 if (! p)
1057 {
1058 sim_warn ("uvClientData malloc failed\n");
1059 return;
1060 }
1061 p->assoc = true;
1062 p->read_cb = fnpuv_associated_readcb;
1063 p->nPos = 0;
1064 p->ttype = NULL;
1065 p->fnpno = fnpno;
1066 p->lineno = lineno;
1067 linep->line_client->data = p;
1068
1069 if (flags & 1)
1070 {
1071 p->write_cb = fnpuv_start_write;
1072 p->write_actual_cb = fnpuv_start_write_actual;
1073 p->telnetp = ltnConnect (linep->line_client);
1074 if (! p->telnetp)
1075 {
1076 sim_warn ("ltnConnect failed\n");
1077 }
1078 }
1079 else
1080 {
1081 p->write_cb = fnpuv_start_write_actual;
1082 p->write_actual_cb = fnpuv_start_write_actual;
1083 p->telnetp = NULL; // Mark this line as 'not a telnet connection'
1084 }
1085
1086 uv_tcp_connect (& linep->doConnect, linep->line_client, (const struct sockaddr *) & dest, on_dialout_connect);
1087 }
1088
1089 #if 0
1090 static void on_slave_connect (uv_stream_t * server, int status)
1091 {
1092 sim_printf ("slave connect\n");
1093 uvClientData * p = (uvClientData *) server->data;
1094 struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
1095 if (status < 0)
1096 {
1097 sim_printf ("Slave connection error %s\n", uv_strerror (status));
1098 //linep->acu_dial_failure = true;
1099 return;
1100 }
1101
1102 uv_read_start ((uv_stream_t *) & linep->line_client, alloc_buffer, do_readcb);
1103 linep->accept_new_terminal = true;
1104 }
1105 #endif
1106
1107
1108 //
1109 // Start a slave line connection listener.
1110 //
1111
fnpuv_open_slave(uint fnpno,uint lineno)1112 void fnpuv_open_slave (uint fnpno, uint lineno)
1113 {
1114 if (! fnpData.loop)
1115 return;
1116 sim_printf ("[FNP emulation: fnpuv_open_slave %d.%d]\n", fnpno, lineno);
1117 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1118
1119 // Do we already have a listening port (ie not first time)?
1120 if (linep->server.data)
1121 return;
1122
1123 uv_tcp_init (fnpData.loop, & linep->server);
1124
1125 // Mark this server has being a slave server
1126 // XXX This does not get freed during a normal shutdown, as Multics
1127 // XXX doesn't tell idle slave lines anything. The emulator shutdown
1128 // XXX needs to call an FNP cleanup routine that frees this.
1129
1130 uvClientData * p = (uvClientData *) malloc (sizeof (uvClientData));
1131 if (! p)
1132 {
1133 sim_warn ("uvClientData malloc failed\n");
1134 return;
1135 }
1136 p->assoc = false;
1137 p->read_cb = fnpuv_associated_readcb;
1138 p->write_cb = fnpuv_start_write_actual;
1139 p->write_actual_cb = fnpuv_start_write_actual;
1140 p->nPos = 0;
1141 p->ttype = NULL;
1142 p->fnpno = fnpno;
1143 p->lineno = lineno;
1144 linep->server.data = p;
1145 linep->line_client = NULL;
1146
1147 struct sockaddr_in addr;
1148 uv_ip4_addr (fnpData.telnet_address, linep->port, & addr);
1149 uv_tcp_bind (& linep->server, (const struct sockaddr *) & addr, 0);
1150 sim_printf ("[FNP emulation: listening on port %d]\n", linep->port);
1151 int r = uv_listen ((uv_stream_t *) & linep->server, DEFAULT_BACKLOG,
1152 on_new_connection);
1153 if (r)
1154 {
1155 sim_printf ("[FNP emulation: Listen error %s]\n", uv_strerror (r));
1156 }
1157
1158 // It should be possible to run a peer-to-peer TCP instead of client server,
1159 // but it's not clear to me how.
1160
1161 #if 0
1162 linep->line_client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
1163 uv_tcp_init (fnpData.loop, linep->line_client);
1164
1165 uvClientData * p = (uvClientData *) malloc (sizeof (uvClientData));
1166 if (! p)
1167 {
1168 sim_warn ("uvClientData malloc failed\n");
1169 return;
1170 }
1171 p->assoc = false;
1172 p->ttype = NULL;
1173 p->telnetp = NULL;
1174 p->fnpno = fnpno;
1175 p->lineno = lineno;
1176
1177 linep->line_client->data = p;
1178
1179 struct sockaddr_in addr;
1180 uv_ip4_addr ("0.0.0.0", linep->port, & addr);
1181 uv_tcp_bind (linep->line_client, (const struct sockaddr *) & addr, 0);
1182 sim_printf ("listening on port %d\n", linep->port);
1183 int r = uv_listen ((uv_stream_t *) linep->line_client, DEFAULT_BACKLOG,
1184 on_slave_connect);
1185 if (r)
1186 {
1187 fprintf (stderr, "Listen error %s\n", uv_strerror (r));
1188 }
1189 #endif
1190 }
1191
1192 #ifdef TUN
processPacketInput(int fnpno,int lineno,unsigned char * buf,ssize_t nread)1193 static void processPacketInput (int fnpno, int lineno, unsigned char * buf, ssize_t nread)
1194 {
1195 //uvClientData * p = (uvClientData *) client->data;
1196 //uint fnpno = p -> fnpno;
1197 //uint lineno = p -> lineno;
1198 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
1199 {
1200 sim_printf ("[FNP emulation: processPacketInput bogus client data]\n");
1201 return;
1202 }
1203 //sim_printf ("assoc. %d.%d nread %ld <%*s>\n", fnpno, lineno, nread, (int) nread, buf);
1204 //{for (int i = 0; i < nread; i ++) sim_printf (" %03o", buf[i]);
1205 //sim_printf ("\n");
1206 //}
1207
1208 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1209 if (linep->inBuffer)
1210 {
1211 unsigned char * new = realloc (linep->inBuffer, (unsigned long) (linep->inSize + nread));
1212 if (! new)
1213 {
1214 sim_warn ("inBuffer realloc fail; dropping data\n");
1215 goto done;
1216 }
1217 memcpy (new + linep->inSize, buf, (unsigned long) nread);
1218 linep->inSize += nread;
1219 linep->inBuffer = new;
1220 }
1221 else
1222 {
1223 linep->inBuffer = malloc ((unsigned long) nread);
1224 if (! linep->inBuffer)
1225 {
1226 sim_warn ("inBuffer malloc fail; dropping data\n");
1227 goto done;
1228 }
1229 memcpy (linep->inBuffer, buf, (unsigned long) nread);
1230 linep->inSize = (uint) nread;
1231 linep->inUsed = 0;
1232 }
1233
1234 done:;
1235 }
1236
fnoTUNProcessLine(int fnpno,int lineno,struct t_line * linep)1237 static void fnoTUNProcessLine (int fnpno, int lineno, struct t_line * linep)
1238 {
1239 /* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
1240 unsigned char buffer [1500 + 16];
1241 ssize_t nread = read (linep->tun_fd, buffer, sizeof (buffer));
1242 if (nread < 0)
1243 {
1244 //perror ("Reading from interface");
1245 //close (linep->tun_fd);
1246 //exit (1);
1247 if (errno == EAGAIN)
1248 return;
1249 sim_printf ("%ld %d\n", nread, errno);
1250 return;
1251 }
1252
1253 // To make debugging easier, return data as a hex string rather than binary.
1254 // When the stack interface is debugged, switch to binary.
1255 unsigned char xbufr [2 * (1500 + 16)];
1256 unsigned char bin2hex [16] = "0123456789ABCDEF";
1257
1258 for (uint i = 0; i > nread; i ++)
1259 {
1260 xbufr [i * 2 + 0] = bin2hex [(buffer [i] >> 4) & 0xf];
1261 xbufr [i * 2 + 1] = bin2hex [(buffer [i] >> 0) & 0xf];
1262 }
1263 xbufr [nread * 2] = 0;
1264 processPacketInput (fnpno, lineno, xbufr, nread * 2 + 1);
1265
1266 // Debugging
1267 // 4 bytes of metadata
1268 # define ip 4
1269 /* Do whatever with the data */
1270 sim_printf("Read %ld bytes\n", nread);
1271 sim_printf ("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1272 buffer [0], buffer [1], buffer [2], buffer [3],
1273 buffer [4], buffer [5], buffer [6], buffer [7]);
1274 sim_printf ("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1275 buffer [8], buffer [9], buffer [10], buffer [11],
1276 buffer [12], buffer [13], buffer [14], buffer [15]);
1277 uint version = (buffer [ip + 0] >> 4) & 0xf;
1278 uint ihl = (buffer [ip + 0]) & 0xf;
1279 uint payload_offset = ip + ihl * 4;
1280 uint tos = buffer [ip + 1];
1281 uint tl = ((uint) (buffer [ip + 2]) << 8) +
1282 buffer [ip + 3];
1283 uint id = ((uint) (buffer [ip + 4]) << 8) +
1284 buffer [ip + 5];
1285
1286 uint df = (buffer [ip + 6] & 0x40) ? 1 : 0;
1287 uint mf = (buffer [ip + 6] & 0x20) ? 1 : 0;
1288 uint fragment_offset = ((uint) (buffer [ip + 6] & 0x1f) << 8) +
1289 buffer [ip + 7];
1290 uint ttl = buffer [ip + 8];
1291 uint protocol = buffer [ip + 9];
1292 uint header_checksum = (((uint) buffer [ip + 10]) << 8) +
1293 buffer [ip + 11];
1294 uint source_address = (((uint) buffer [ip + 12]) << 24) +
1295 (((uint) buffer [ip + 13]) << 16) +
1296 (((uint) buffer [ip + 14]) << 8) +
1297 buffer [ip + 15];
1298 uint dest_address = (((uint) buffer [ip + 16]) << 24) +
1299 (((uint) buffer [ip + 17]) << 16) +
1300 (((uint) buffer [ip + 18]) << 8) +
1301 buffer [ip + 19];
1302 if (protocol == 1)
1303 {
1304 uint type = buffer [payload_offset + 0];
1305 if (type == 0x08)
1306 {
1307 sim_printf ("ICMP Echo Request %d.%d.%d.%d %d.%d.%d.%d\n",
1308 buffer [ip + 12], buffer [ip + 13], buffer [ip + 14], buffer [ip + 15],
1309 buffer [ip + 16], buffer [ip + 17], buffer [ip + 18], buffer [ip + 19]);
1310 }
1311 else
1312 {
1313 sim_printf ("ICMP 0x%02x\n", type);
1314 sim_printf ("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1315 buffer [payload_offset + 0], buffer [payload_offset + 1], buffer [payload_offset + 2], buffer [payload_offset + 3],
1316 buffer [payload_offset + 4], buffer [payload_offset + 5], buffer [payload_offset + 6], buffer [payload_offset + 7]);
1317 }
1318 }
1319 if (protocol == 0x11)
1320 {
1321 sim_printf ("UDP\n");
1322
1323 }
1324 else
1325 {
1326 sim_printf ("protocol %02x\n", protocol);
1327 }
1328 }
1329
fnpTUNProcessEvent(void)1330 void fnpTUNProcessEvent (void)
1331 {
1332 unint32 numunits = fnp_dev.numunits;
1333 for (int fnpno = 0; fnpno < numnumts; fnpno ++)
1334 {
1335 for (int lineno = 0; lineno < MAX_LINES; lineno ++)
1336 {
1337 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1338 if (linep->is_tun)
1339 fnoTUNProcessLine (fnpno, lineno, linep);
1340 }
1341 }
1342 }
1343 #endif
1344
fnpuv3270Poll(bool start)1345 void fnpuv3270Poll (bool start)
1346 {
1347 // Called at 100Hz; to 1 second poll
1348 fnpData.du3270_poll = start ? 100 : 0;
1349 }
1350
1351 //
1352 // Connection callback handler for dialup connections
1353 //
1354
on_new_3270_connection(uv_stream_t * server,int status)1355 static void on_new_3270_connection (uv_stream_t * server, int status)
1356 {
1357 if (status < 0)
1358 {
1359 sim_printf ("[FNP 3270 emulation: New connection error %s]\n", uv_strerror (status));
1360 // error!
1361 return;
1362 }
1363
1364 uv_tcp_t * client = (uv_tcp_t *) malloc (sizeof (uv_tcp_t));
1365
1366 uv_tcp_init (fnpData.loop, client);
1367 if (uv_accept (server, (uv_stream_t *) client) != 0)
1368 {
1369 uv_close ((uv_handle_t *) client, fuv_close_cb);
1370 return;
1371 }
1372
1373 // Search for an availible station
1374 uint stn_no;
1375 for (stn_no = 0; stn_no < IBM3270_STATIONS_MAX; stn_no ++)
1376 {
1377 if (fnpData.ibm3270ctlr[ASSUME0].stations[stn_no].client == NULL)
1378 break;
1379 }
1380 if (stn_no >= IBM3270_STATIONS_MAX)
1381 {
1382 // No stations availible
1383 uv_close ((uv_handle_t *) client, fuv_close_cb);
1384 return;
1385 }
1386
1387 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
1388 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
1389 // Set the line client to NULL; the actual clients are in 'stations'
1390 fnpData.fnpUnitData[fnpno].MState.line[lineno].line_client = NULL;
1391
1392 fnpData.ibm3270ctlr[ASSUME0].stations[stn_no].client = client;
1393
1394 // Set up selection so the telnet negotiation can find the station.
1395 fnpData.ibm3270ctlr[ASSUME0].selDevChar = addr_map[stn_no];
1396
1397 struct sockaddr name;
1398 int namelen = sizeof (name);
1399 int ret = uv_tcp_getpeername (client, & name, & namelen);
1400 if (ret < 0)
1401 {
1402 sim_printf ("[FNP emulation: CONNECT; addr err %d]\n", ret);
1403 }
1404 else
1405 {
1406 struct sockaddr_in * p = (struct sockaddr_in *) & name;
1407 sim_printf ("[FNP emulation: CONNECT %s]\n", inet_ntoa (p -> sin_addr));
1408 }
1409
1410 uvClientData * p = (uvClientData *) malloc (sizeof (uvClientData));
1411 if (! p)
1412 {
1413 sim_warn ("uvClientData malloc failed\n");
1414 return;
1415 }
1416 client->data = p;
1417 p->assoc = false;
1418 p->fnpno = fnpno;
1419 p->lineno = lineno;
1420 p->nPos = 0;
1421 p->ttype = NULL;
1422 p->read_cb = fnpuv_3270_readcb;
1423 p->write_cb = fnpuv_start_3270_write;
1424 p->write_actual_cb = fnpuv_start_write_3270_actual;
1425 p->stationNo = stn_no;
1426 p->telnetp = ltnConnect3270 (client);
1427
1428 if (! p->telnetp)
1429 {
1430 sim_warn ("ltnConnect3270 failed\n");
1431 return;
1432 }
1433 fnpuv_read_start (client);
1434 fnp3270ConnectPrompt (client);
1435 //uvClientData * p = (uvClientData *) server->data;
1436 //struct t_line * linep = & fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
1437 //linep->accept_new_terminal = true;
1438 //linep->was_CR = false;
1439 ////linep->listen = false;
1440 //linep->inputBufferSize = 0;
1441 //linep->ctrlStrIdx = 0;
1442 //linep->breakAll = false;
1443 //linep->handleQuit = false;
1444 //linep->echoPlex = false;
1445 //linep->crecho = false;
1446 //linep->lfecho = false;
1447 //linep->tabecho = false;
1448 //linep->replay = false;
1449 //linep->polite = false;
1450 //linep->prefixnl = false;
1451 //linep->eight_bit_out = false;
1452 //linep->eight_bit_in = false;
1453 //linep->odd_parity = false;
1454 //linep->output_flow_control = false;
1455 //linep->input_flow_control = false;
1456 //linep->block_xfer_in_frame_sz = 0;
1457 //linep->block_xfer_out_frame_sz = 0;
1458 //memset (linep->delay_table, 0, sizeof (linep->delay_table));
1459 //linep->inputSuspendLen = 0;
1460 //memset (linep->inputSuspendStr, 0, sizeof (linep->inputSuspendStr));
1461 //linep->inputResumeLen = 0;
1462 //memset (linep->inputResumeStr, 0, sizeof (linep->inputResumeStr));
1463 //linep->outputSuspendLen = 0;
1464 //memset (linep->outputSuspendStr, 0, sizeof (linep->outputSuspendStr));
1465 //linep->outputResumeLen = 0;
1466 //memset (linep->outputResumeStr, 0, sizeof (linep->outputResumeStr));
1467 //linep->frame_begin = 0;
1468 //linep->frame_end = 0;
1469 //memset (linep->echnego, 0, sizeof (linep->echnego));
1470 //linep->line_break = false;
1471 }
1472
fnpuv3270Init(int telnet3270_port)1473 void fnpuv3270Init (int telnet3270_port)
1474 {
1475 // Ignore multiple calls; this means that once the listen port is
1476 // opened, it can't be changed. Fixing this requires non-trivial
1477 // changes.
1478 if (fnpData.du3270_server_inited)
1479 return;
1480 fnpData.du3270_server_inited = true;
1481 if (! fnpData.loop)
1482 fnpData.loop = uv_default_loop ();
1483 // Initialize the server socket
1484 uv_tcp_init (fnpData.loop, & fnpData.du3270_server);
1485
1486 // Flag the this server as being a 3270
1487 fnpData.du3270_server.data = NULL;
1488
1489 // Bind and listen
1490 struct sockaddr_in addr;
1491 sim_printf ("[FNP 3270 emulation: listening to %d]\n", telnet3270_port);
1492 uv_ip4_addr (fnpData.telnet_address, telnet3270_port, & addr);
1493 uv_tcp_bind (& fnpData.du3270_server, (const struct sockaddr *) & addr, 0);
1494 int r = uv_listen ((uv_stream_t *) & fnpData.du3270_server, DEFAULT_BACKLOG,
1495 on_new_3270_connection);
1496 if (r)
1497 {
1498 sim_printf ("[FNP 3270 emulation: Listen error %s]\n", uv_strerror (r));
1499 }
1500 fnpuv3270Poll (false);
1501 }
1502