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