root/src/dps8/dps8_socket_dev.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sk_show_nunits
  2. sk_set_nunits
  3. skc_show_device_name
  4. skc_set_device_name
  5. sk_reset
  6. sk_init
  7. set_error_str
  8. set_error
  9. skt_socket
  10. skt_gethostbyname
  11. skt_bind
  12. skt_listen
  13. skt_accept
  14. skt_close
  15. skt_read8
  16. skt_write8
  17. get_ddcw
  18. sk_cmd
  19. skc_iom_cmd
  20. do_try_accept
  21. do_try_read
  22. sk_process_event

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: eec1f540-f62e-11ec-8889-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2012-2016 Harry Reed
  10  * Copyright (c) 2017 Charles Anthony
  11  * Copyright (c) 2021-2023 The DPS8M Development Team
  12  *
  13  * All rights reserved.
  14  *
  15  * This software is made available under the terms of the ICU
  16  * License, version 1.8.1 or later.  For more details, see the
  17  * LICENSE.md file at the top-level directory of this distribution.
  18  *
  19  * ---------------------------------------------------------------------------
  20  */
  21 
  22 #include <stdio.h>
  23 #include <ctype.h>
  24 #include <netdb.h>
  25 #include <sys/ioctl.h>
  26 #include <unistd.h>
  27 
  28 #if defined(__sun__) || defined(_AIX)
  29 # include <strings.h>
  30 #endif
  31 
  32 #include "dps8.h"
  33 #include "dps8_sys.h"
  34 #include "dps8_faults.h"
  35 #include "dps8_iom.h"
  36 #include "dps8_socket_dev.h"
  37 #include "dps8_cable.h"
  38 #include "dps8_cpu.h"
  39 #include "dps8_utils.h"
  40 
  41 #define DBG_CTR 1
  42 
  43 #ifndef bzero
  44 # define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
  45 #endif /* ifndef bzero */
  46 
  47 static struct {
  48     const char *name;
  49     int code;
  50 } errnos[] = {
  51     {"        ", 0},
  52 #include "errnos.h"
  53 };
  54 #define N_ERRNOS (sizeof (errnos) / sizeof (errnos[0]))
  55 
  56 #ifdef WITH_SOCKET_DEV
  57 # define SKC_UNIT_IDX(uptr) ((uptr) - sk_unit)
  58 
  59 struct skc_state_s
  60   {
  61     char device_name [MAX_DEV_NAME_LEN];
  62   };
  63 static struct skc_state_s skc_state[N_SKC_UNITS_MAX];
  64 
  65 # define N_FDS 1024
  66 
  67 static struct
  68   {
  69     int   fd_unit[N_FDS];     // unit number that a FD is associated with; -1 is free.
  70     word6 fd_dev_code[N_FDS]; // dev_code that a FD is associated with; -1 is free.
  71     bool  fd_nonblock[N_FDS]; // socket() call had NON_BLOCK set
  72     struct
  73       {
  74         enum
  75           {
  76             unit_idle = 0,
  77             unit_accept,
  78             unit_read
  79           } unit_state;
  80          //fd_set accept_fds;
  81          int  accept_fd;
  82          int  read_fd;
  83          uint read_buffer_sz;
  84          uint words_processed;
  85       } unit_data[N_SKC_UNITS_MAX][N_DEV_CODES];
  86   } sk_data;
  87 
  88 # define N_SKC_UNITS 64 // default
  89 
  90 static t_stat sk_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
  91                               UNUSED int val, UNUSED const void * desc)
  92   {
  93     sim_printf("Number of socket units in system is %d\n", skc_dev.numunits);
  94     return SCPE_OK;
  95   }
  96 
  97 static t_stat sk_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
  98                              const char * cptr, UNUSED void * desc)
  99   {
 100     if (! cptr)
 101       return SCPE_ARG;
 102     int n = atoi (cptr);
 103     if (n < 1 || n > N_SKC_UNITS_MAX)
 104       return SCPE_ARG;
 105     skc_dev.numunits = (uint32) n;
 106     return SCPE_OK;
 107   }
 108 
 109 static t_stat skc_show_device_name (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 110                                     UNUSED int val, UNUSED const void * desc)
 111   {
 112     int n = (int) SKC_UNIT_IDX (uptr);
 113     if (n < 0 || n >= N_SKC_UNITS_MAX)
 114       return SCPE_ARG;
 115     if (skc_state[n].device_name[1] != 0)
 116       sim_printf("Name: %s", skc_state[n].device_name);
 117     return SCPE_OK;
 118   }
 119 
 120 static t_stat skc_set_device_name (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 121                                    const char * cptr, UNUSED void * desc)
 122   {
 123     int n = (int) SKC_UNIT_IDX (uptr);
 124     if (n < 0 || n >= N_SKC_UNITS_MAX)
 125       return SCPE_ARG;
 126     if (cptr)
 127       {
 128         strncpy (skc_state[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
 129         skc_state[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
 130       }
 131     else
 132       skc_state[n].device_name[0] = 0;
 133     return SCPE_OK;
 134   }
 135 
 136 static MTAB sk_mod [] =
 137   {
 138     {
 139       MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* Mask               */
 140       0,                                          /* Match              */
 141       "NUNITS",                                   /* Print string       */
 142       "NUNITS",                                   /* Match string       */
 143       sk_set_nunits,                              /* Validation routine */
 144       sk_show_nunits,                             /* Display routine    */
 145       "Number of socket units in the system",     /* Value descriptor   */
 146       NULL                                        /* Help               */
 147     },
 148     {
 149       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* Mask               */
 150       0,                                          /* Match              */
 151       "NAME",                                     /* Print string       */
 152       "NAME",                                     /* Match string       */
 153       skc_set_device_name,                        /* Validation routine */
 154       skc_show_device_name,                       /* Display routine    */
 155       "Set the device name",                      /* Value descriptor   */
 156       NULL                                        /* Help               */
 157     },
 158     MTAB_eol
 159   };
 160 
 161 UNIT sk_unit [N_SKC_UNITS_MAX] = {
 162 # ifdef NO_C_ELLIPSIS
 163   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 164   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 165   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 166   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 167   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 168   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 169   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 170   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 171   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 172   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 173   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 174   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 175   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 176   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 177   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 178   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 179   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 180   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 181   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 182   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 183   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 184   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 185   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 186   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 187   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 188   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 189   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 190   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 191   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 192   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 193   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 194   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 195   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 196   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 197   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 198   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 199   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 200   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 201   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 202   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 203   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 204   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 205   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 206   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 207   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 208   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 209   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 210   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 211   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 212   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 213   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 214   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 215   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 216   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 217   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 218   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 219   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 220   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 221   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 222   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 223   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 224   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 225   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 226   { UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
 227 # else
 228   [0 ... (N_SKC_UNITS_MAX -1)] = {
 229     UDATA ( NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
 230   },
 231 # endif
 232 };
 233 
 234 static DEBTAB sk_dt [] =
 235   {
 236     { "NOTIFY", DBG_NOTIFY, NULL },
 237     {   "INFO",   DBG_INFO, NULL },
 238     {    "ERR",    DBG_ERR, NULL },
 239     {   "WARN",   DBG_WARN, NULL },
 240     {  "DEBUG",  DBG_DEBUG, NULL },
 241     {    "ALL",    DBG_ALL, NULL }, // Don't move as it messes up DBG message
 242     {     NULL,          0, NULL }
 243   };
 244 
 245 static t_stat sk_reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 246   {
 247     return SCPE_OK;
 248   }
 249 
 250 DEVICE skc_dev = {
 251     "SKC",            /* Name                */
 252     sk_unit,          /* Unit                */
 253     NULL,             /* Registers           */
 254     sk_mod,           /* Modifiers           */
 255     N_SKC_UNITS,      /* Number of units     */
 256     10,               /* Address radix       */
 257     31,               /* Address width       */
 258     1,                /* Address increment   */
 259     8,                /* Data radix          */
 260     9,                /* Data width          */
 261     NULL,             /* Examine routine     */
 262     NULL,             /* Deposit routine     */
 263     sk_reset,         /* Reset routine       */
 264     NULL,             /* Boot routine        */
 265     NULL,             /* Attach routine      */
 266     NULL,             /* Detach routine      */
 267     NULL,             /* Context             */
 268     DEV_DEBUG,        /* Flags               */
 269     0,                /* Debug control flags */
 270     sk_dt,            /* Debug flag names    */
 271     NULL,             /* Memory size change  */
 272     NULL,             /* Logical name        */
 273     NULL,             /* Attach help         */
 274     NULL,             /* Help                */
 275     NULL,             /* Help context        */
 276     NULL,             /* Device description  */
 277     NULL              /* End                 */
 278 };
 279 
 280 void sk_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 281   {
 282     // sets unit_state to unit_idle
 283     memset(& sk_data, 0, sizeof(sk_data));
 284     for (uint i = 0; i < N_FDS; i ++)
 285       sk_data.fd_unit[i] = -1;
 286     //for (uint i = 0; i < N_SKC_UNITS_MAX; i ++)
 287       //for (word6 j = 0; j < N_DEV_CODES; j ++)
 288         //FD_ZERO (& sk_data.unit_data[i][j].accept_fds);
 289   }
 290 
 291 static void set_error_str (word36 * error_str, const char * str)
     /* [previous][next][first][last][top][bottom][index][help] */
 292   {
 293     char work [8];
 294     //strncpy (work, "        ", 8);
 295     //strncpy (work, str, 8);
 296     for (uint i = 0; i < 8; i ++)
 297      work[i] = ' ';
 298     size_t l = strlen (str);
 299     if (l > 8)
 300       l = 8;
 301     for (uint i = 0; i < l; i ++)
 302      work[i] = str[i];
 303     error_str[0] = 0;
 304     error_str[1] = 0;
 305     putbits36_8 (error_str + 0,  1, (word8) work [0]);
 306     putbits36_8 (error_str + 0, 10, (word8) work [1]);
 307     putbits36_8 (error_str + 0, 19, (word8) work [2]);
 308     putbits36_8 (error_str + 0, 28, (word8) work [3]);
 309     putbits36_8 (error_str + 1,  1, (word8) work [4]);
 310     putbits36_8 (error_str + 1, 10, (word8) work [5]);
 311     putbits36_8 (error_str + 1, 19, (word8) work [6]);
 312     putbits36_8 (error_str + 1, 28, (word8) work [7]);
 313   }
 314 
 315 static void set_error (word36 * error_str, int _errno)
     /* [previous][next][first][last][top][bottom][index][help] */
 316   {
 317     if (errno == 0)
 318       return;
 319     for (uint i = 0; i < N_ERRNOS; i ++)
 320       {
 321         if (errnos[i].code == _errno)
 322           {
 323             set_error_str (error_str, errnos[i].name);
 324             return;
 325           }
 326       }
 327     char huh [256];
 328     sprintf (huh, "E%d", _errno);
 329     huh[8] = 0;
 330     set_error_str (error_str, huh);
 331   }
 332 
 333 static void skt_socket (uint unit_idx, word5 dev_code, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 334   {
 335 // /* Data block for socket() call */
 336 // dcl 1 SOCKETDEV_socket_data aligned,
 337 //       2 domain fixed bin,   // 0
 338 //       2 type fixed bin,     // 1
 339 //       2 protocol fixed bin; // 2
 340 //       2 fd fixed bin;       // 3
 341 //       2 errno char(8);      // 4,5
 342 
 343     int domain =   (int) buffer[0];
 344     int type =     (int) buffer[1];
 345     int protocol = (int) buffer[2];
 346 
 347 sim_printf ("socket() domain   %d\n", domain);
 348 sim_printf ("socket() type     %d\n", type);
 349 sim_printf ("socket() protocol %d\n", protocol);
 350 
 351     int _errno = 0;
 352     int fd = -1;
 353 
 354     if (domain != AF_INET)       // Only AF_INET
 355       {
 356 sim_printf ("socket() domain EAFNOSUPPORT\n");
 357         _errno = EAFNOSUPPORT;
 358       }
 359 # if defined(__APPLE__) || defined(_AIX) || defined(__HAIKU__)
 360     else if (type != SOCK_STREAM && type != (SOCK_STREAM)) // Only SOCK_STREAM or SOCK_STREAM + SOCK_NONBLOCK
 361 # else
 362     else if (type != SOCK_STREAM && type != (SOCK_STREAM|SOCK_NONBLOCK)) // Only SOCK_STREAM or SOCK_STREAM + SOCK_NONBLOCK
 363 # endif
 364       {
 365 sim_printf ("socket() type EPROTOTYPE\n");
 366         _errno = EPROTOTYPE;
 367       }
 368     else if (protocol != 0) // Only IP
 369       {
 370 sim_printf ("socket() protocol EPROTONOSUPPORT\n");
 371         _errno = EPROTONOSUPPORT;
 372       }
 373     else
 374       {
 375         fd = socket ((int) buffer[0], (int) buffer[1], (int) buffer[2]);
 376 sim_printf ("socket() returned %d\n", fd);
 377         if (fd < 0)
 378           {
 379 sim_printf ("errno %d\n", errno);
 380             _errno = errno;
 381           }
 382         else if (fd < N_FDS)
 383           {
 384             sk_data.fd_unit[fd] = (int) unit_idx;
 385             sk_data.fd_dev_code[fd] = dev_code;
 386 # if defined(__APPLE__) || defined(_AIX) || defined(__HAIKU__)
 387             sk_data.fd_nonblock[fd] = 0;
 388 # else
 389             sk_data.fd_nonblock[fd] = !! (type & SOCK_NONBLOCK);
 390 # endif
 391           }
 392         else
 393           {
 394             close (fd);
 395             fd = -1;
 396             _errno = EMFILE;
 397           }
 398       }
 399     // sign extend int into word36
 400     buffer[3] = ((word36) ((word36s) fd)) & MASK36; // fd
 401     //buffer[5] = ((word36) ((word36s) _errno)) & MASK36; // errno
 402     set_error (& buffer[4], _errno);
 403   }
 404 
 405 static void skt_gethostbyname (word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 406   {
 407 // dcl 1 SOCKETDEV_gethostbyname_data aligned,
 408 //       2 name char varying (255),
 409 //       3 addr fixed uns bin (32),
 410 //       3 errno char(8);
 411 //
 412 //
 413 //       len:36                    //  0
 414 //       c1: 9, c2: 9, c3:9, c4:9  //  1
 415 //       ...
 416 //       c253: 9, c254: 9, c255: 9, pad: 9, //63
 417 //       addr: 32, pad: 4,          // 65
 418 //       errno: 72                   // 66, 67
 419 //
 420 
 421     word9 cnt = getbits36_9 (buffer [0], 27);
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 
 433 
 434 
 435 
 436 
 437 
 438 
 439     if (cnt > 256)
 440       {
 441         sim_warn ("socket$gethostbyname() clipping cnt from %u to 256\n", cnt);
 442         cnt = 256;
 443       }
 444 
 445     unsigned char name [257];
 446     for (uint i = 0; i < cnt; i ++)
 447       {
 448          uint wordno = (i+4) / 4;
 449          uint offset = ((i+4) % 4) * 9;
 450          word9 ch = getbits36_9 (buffer[wordno], offset);
 451          name [i] = (unsigned char) (ch & 255);
 452       }
 453     name[cnt] = 0;
 454 
 455     struct hostent * hostent = gethostbyname ((char *)name);
 456 sim_printf ("gethostbyname returned %p\n", (void *) hostent);
 457     if (hostent)
 458       {
 459 sim_printf ("addr_len %d\n", hostent->h_length);
 460 sim_printf ("%hhu.%hhu.%hhu.%hhu\n", hostent->h_addr_list[0][0],hostent->h_addr_list[0][1], hostent->h_addr_list[0][2],hostent->h_addr_list[0][3]);
 461 
 462         uint32_t addr = * ((uint32_t *) & hostent->h_addr_list[0][0]);
 463 sim_printf ("addr %08x\n", addr);
 464         addr = ntohl (addr);
 465 sim_printf ("addr %08x\n", addr);
 466         buffer[65] = ((word36) addr) << 4;
 467         // Get the octets in the right order
 468         //putbits36_8 (& buffer[65],  0, (word8) (((unsigned char) (hostent->h_addr_list[0][0])) & 0xff));
 469         //putbits36_8 (& buffer[65],  8, (word8) (((unsigned char) (hostent->h_addr_list[0][1])) & 0xff));
 470         //putbits36_8 (& buffer[65], 16, (word8) (((unsigned char) (hostent->h_addr_list[0][2])) & 0xff));
 471         //putbits36_8 (& buffer[65], 24, (word8) (((unsigned char) (hostent->h_addr_list[0][3])) & 0xff));
 472         set_error (& buffer[66], 0);
 473       }
 474     else
 475       {
 476 sim_printf ("h_errno %d\n", h_errno);
 477         switch (h_errno)
 478           {
 479             case HOST_NOT_FOUND: set_error_str (& buffer[66], "HOST_NOT_FOUND"); break;
 480             case NO_DATA: set_error_str (& buffer[66], "NO_DATA"); break;
 481             case NO_RECOVERY: set_error_str (& buffer[66], "NO_RECOVERY"); break;
 482             case TRY_AGAIN: set_error_str (& buffer[66], "TRY_AGAIN"); break;
 483             default: set_error_str (& buffer[66], "EHUH"); break;
 484           }
 485       }
 486   }
 487 
 488 static void skt_bind (uint unit_idx, word6 dev_code, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 489   {
 490 // dcl 1 SOCKETDEV_bind_data aligned,
 491 //       2 socket fixed bin,              // 0
 492 //       2 sockaddr_in,
 493 //         3 sin_family fixed bin,        // 1
 494 //         3 sin_port fixed uns bin (16), // 2
 495 //         3 sin_addr,                    // 3
 496 //           4 octets (4) fixed bin(8) unsigned unal,
 497 //       2 errno char(8);               // 4,5
 498 
 499 // /* Expecting tally to be 6 */
 500 // /* sockaddr is from the API parameter */
 501 // /* errno, errno are the values returned by the host socket() call */
 502 
 503     int socket_fd = (int) buffer[0];
 504     int sin_family = (int) buffer[1];
 505     unsigned short sin_port = (unsigned short) getbits36_16 (buffer [2], 0);
 506     word8 octet [4] = { getbits36_8 (buffer [3], 0),
 507                         getbits36_8 (buffer [3], 8),
 508                         getbits36_8 (buffer [3], 16),
 509                         getbits36_8 (buffer [3], 24)};
 510     uint32_t addr = (uint32_t) octet[0];
 511     addr <<= 8;
 512     addr |= (uint32_t) octet[1];
 513     addr <<= 8;
 514     addr |= (uint32_t) octet[2];
 515     addr <<= 8;
 516     addr |= (uint32_t) octet[3];
 517 
 518 sim_printf ("bind() socket     %d\n",                  socket_fd);
 519 sim_printf ("bind() sin_family %d\n",                  sin_family);
 520 sim_printf ("bind() sin_port   %u\n",                  sin_port);
 521 sim_printf ("bind() s_addr     %hhu.%hhu.%hhu.%hhu\n", octet[0], octet[1], octet[2], octet[3]);
 522 sim_printf ("bind() s_addr     %08x\n",                addr);
 523   //(buffer [3] >> (36 - 1 * 8)) & MASK8,
 524   //(buffer [3] >> (36 - 2 * 8)) & MASK8,
 525   //(buffer [3] >> (36 - 3 * 8)) & MASK8,
 526   //(buffer [3] >> (36 - 4 * 8)) & MASK8),
 527 
 528     // Does this socket belong to us?
 529     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 530       {
 531         set_error (& buffer[4], EBADF);
 532         return;
 533       }
 534 
 535     struct sockaddr_in serv_addr;
 536     bzero ((char *) & serv_addr, sizeof(serv_addr));
 537     serv_addr.sin_family      = AF_INET;
 538     serv_addr.sin_addr.s_addr = htonl (addr);
 539     serv_addr.sin_port        = htons (sin_port);
 540 
 541     int _errno = 0;
 542     int rc = bind (socket_fd, (struct sockaddr *) & serv_addr, sizeof (serv_addr));
 543 sim_printf ("bind() returned %d\n", rc);
 544 
 545     if (rc < 0)
 546       {
 547 sim_printf ("errno %d\n", errno);
 548         _errno = errno;
 549       }
 550     set_error (& buffer[4], _errno);
 551   }
 552 
 553 static void skt_listen (uint unit_idx, word6 dev_code, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 554   {
 555 // dcl 1 SOCKETDEV_listen_data aligned,
 556 //       2 sockfd fixed bin,  // 0
 557 //       3 backlog fixed bin, // 1
 558 //       2 rc fixed bin;      // 2
 559 //       2 errno char(8);     // 3, 4
 560 //
 561 // /* Tally 5   */
 562 // /* In:       */
 563 // /*   sockfd  */
 564 // /*   backlog */
 565 // /* Out:      */
 566 // /*   rc      */
 567 // /*   errno   */
 568 
 569     int socket_fd = (int) buffer[0];
 570     int backlog = (int) buffer[1];
 571 sim_printf ("listen() socket     %d\n", socket_fd);
 572 sim_printf ("listen() backlog    %d\n", backlog   );
 573 
 574     int rc = 0;
 575     int _errno = 0;
 576     // Does this socket belong to us?
 577     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 578       {
 579 sim_printf ("listen() socket doesn't belong to us\n");
 580 sim_printf ("socket_fd %u fd_unit %d fd_dev_code %u unit_idx %u dev_code %u\n", socket_fd, sk_data.fd_unit[socket_fd], sk_data.fd_dev_code[socket_fd], unit_idx, dev_code);
 581         _errno = EBADF;
 582         goto done;
 583       }
 584 
 585     int on = 1;
 586     rc = setsockopt (socket_fd, SOL_SOCKET,  SO_REUSEADDR,
 587                    (char *) & on, sizeof (on));
 588 sim_printf ("listen() setsockopt returned %d\n", rc);
 589     if (rc < 0)
 590       {
 591         _errno = errno;
 592         goto done;
 593       }
 594 
 595 # ifdef FIONBIO
 596     rc = ioctl (socket_fd, FIONBIO, (char *) & on);
 597 sim_printf ("listen() ioctl returned %d\n", rc);
 598     if (rc < 0)
 599       {
 600         _errno = errno;
 601         goto done;
 602       }
 603 # endif
 604 
 605     rc = listen (socket_fd, backlog);
 606 sim_printf ("listen() returned %d\n", rc);
 607 
 608     if (rc < 0)
 609       {
 610 sim_printf ("errno %d\n", errno);
 611         _errno = errno;
 612         goto done;
 613       }
 614 
 615 done:
 616     buffer[2] = ((word36) ((word36s) rc)) & MASK36; // rc
 617     set_error (& buffer[3], _errno);
 618   }
 619 
 620 static int skt_accept (uint unit_idx, word6 dev_code, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 621   {
 622 // dcl 1 SOCKETDEV_accept_data aligned,
 623 //       2 sockfd fixed bin,                           // 0
 624 //       2 rc fixed bin,                               // 1
 625 //       2 sockaddr_in,
 626 //         3 sin_family fixed bin,                     // 2
 627 //         3 sin_port fixed uns bin (16),              // 3
 628 //         3 sin_addr,
 629 //           4 octets (4) fixed bin(8) unsigned unal,  // 4
 630 //       2 errno char(8);                              // 5, 6
 631 
 632     int socket_fd = (int) buffer[0];
 633 sim_printf ("accept() socket     %d\n", socket_fd);
 634     // Does this socket belong to us?
 635     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 636       {
 637         set_error (& buffer[4], EBADF);
 638         return IOM_CMD_DISCONNECT; // send terminate interrupt
 639       }
 640     //FD_SET (socket_fd, & sk_data.unit_data[unit_idx][dev_code].accept_fds);
 641     sk_data.unit_data[unit_idx][dev_code].accept_fd  = socket_fd;
 642     sk_data.unit_data[unit_idx][dev_code].unit_state = unit_accept;
 643     return IOM_CMD_DISCONNECT; // don't send terminate interrupt
 644   }
 645 
 646 static void skt_close (uint unit_idx, word6 dev_code, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 647   {
 648 // dcl 1 SOCKETDEV_close_data aligned,
 649 //       2 sockfd fixed bin,  // 0
 650 //       2 rc fixed bin,      // 1
 651 //       2 errno char(8);     // 2, 3
 652 //
 653 // /* Tally 4  */
 654 // /* In:      */
 655 // /*   sockfd */
 656 // /* Out:     */
 657 // /*   rc     */
 658 // /*   errno  */
 659 
 660     int socket_fd = (int) buffer[0];
 661 sim_printf ("close() socket     %d\n", socket_fd);
 662 
 663     int rc     = 0;
 664     int _errno = 0;
 665     // Does this socket belong to us?
 666     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 667       {
 668 sim_printf ("close() socket doesn't belong to us\n");
 669         _errno = EBADF;
 670         goto done;
 671       }
 672     sk_data.fd_unit[socket_fd] = -1;
 673 
 674     if (sk_data.unit_data[unit_idx][dev_code].unit_state == unit_accept &&
 675         sk_data.unit_data[unit_idx][dev_code].accept_fd == socket_fd)
 676       {
 677         sk_data.unit_data[unit_idx][dev_code].unit_state = unit_idle;
 678         sk_data.unit_data[unit_idx][dev_code].accept_fd = -1;
 679       }
 680     rc = close (socket_fd);
 681 
 682 sim_printf ("close() close returned %d\n", rc);
 683     if (rc < 0)
 684       {
 685         _errno = errno;
 686         goto done;
 687       }
 688 
 689 done:
 690     buffer[1] = ((word36) ((word36s) rc)) & MASK36; // rc
 691     set_error (& buffer[2], _errno);
 692   }
 693 
 694 static int skt_read8 (uint unit_idx, word6 dev_code, UNUSED uint tally, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 695   {
 696 // dcl 1 SOCKETDEV_read_data8 aligned,
 697 //       2 sockfd fixed bin,                                  // 0
 698 //       2 count  fixed bin, /* buffer size */                // 1
 699 //       2 rc     fixed bin,                                  // 2
 700 //       2 errno  char(8),                                    // 3,4
 701 //       2 buffer char (0 refer (SOCKETDEV_read_data9.count); // 5,....
 702 
 703 /* Tally >= 5 */
 704 /* In:        */
 705 /*   sockfd   */
 706 /*   count    */
 707 /* Out:       */
 708 /*   rc       */
 709 /*   buffer   */
 710 
 711     int socket_fd = (int) buffer[0];
 712     uint count = (uint) buffer[1];
 713 sim_printf ("read8() socket     %d\n", socket_fd);
 714 
 715     // Does this socket belong to us?
 716     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 717       {
 718 sim_printf ("read8() socket doesn't belong to us\n");
 719         set_error (& buffer[4], EBADF);
 720         return IOM_CMD_DISCONNECT; // send terminate interrupt
 721       }
 722     sk_data.unit_data[unit_idx][dev_code].read_fd        = socket_fd;
 723     sk_data.unit_data[unit_idx][dev_code].read_buffer_sz = count;
 724     sk_data.unit_data[unit_idx][dev_code].unit_state     = unit_read;
 725     return IOM_CMD_DISCONNECT; // don't send terminate interrupt
 726   }
 727 
 728 static int skt_write8 (uint iom_unit_idx, uint chan, uint unit_idx, word6 dev_code, uint tally, word36 * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 729   {
 730     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 731 // dcl 1 SOCKETDEV_write_data8 aligned,
 732 //       2 sockfd fixed bin,                                  // 0
 733 //       2 count  fixed bin, /* buffer size */                // 1
 734 //       2 rc     fixed bin,                                  // 2
 735 //       2 errno  char(8),                                    // 3,4
 736 //       2 buffer char (0 refer (SOCKETDEV_read_data9.count); // 5,....
 737 
 738     if (tally < 5)
 739       {
 740         p->stati = 050012; // BUG: arbitrary error code; config switch
 741         return IOM_CMD_ERROR;
 742       }
 743 
 744 /* Tally >= 5 */
 745 /* In:        */
 746 /*   sockfd   */
 747 /*   count    */
 748 /* Out:       */
 749 /*   rc       */
 750 /*   errno    */
 751 /*   buffer   */
 752 
 753     int socket_fd = (int) buffer[0];
 754 sim_printf ("write8() socket     %d\n", socket_fd);
 755 
 756     ssize_t rc = 0;
 757     int _errno = 0;
 758     // Does this socket belong to us?
 759     if (sk_data.fd_unit[socket_fd] != (int) unit_idx || sk_data.fd_dev_code[socket_fd] != dev_code)
 760       {
 761 sim_printf ("write8() socket doesn't belong to us\n");
 762         set_error (& buffer[3], EBADF);
 763         return IOM_CMD_DISCONNECT; // send terminate interrupt
 764       }
 765 
 766    // Tally is at most 4096, so buffer words is at most 4096 - 5 => 4091
 767    // count (4 chars/word) is at most 4091 * 4
 768     word36 count36 = buffer[1];
 769     if (count36 > (4091 * 4))
 770       {
 771         p->stati = 050012; // BUG: arbitrary error code; config switch
 772         return IOM_CMD_ERROR;
 773       }
 774     uint count = (uint) count36;
 775 
 776     uint count_words = (count + 3) / 4;
 777     if ((count_words + 5) > tally)
 778       {
 779         p->stati = 050012; // BUG: arbitrary error code; config switch
 780         return IOM_CMD_ERROR;
 781       }
 782 
 783     uint8_t netdata [count];
 784     for (uint n = 0; n < count; n ++)
 785       {
 786          uint wordno = (uint) n / 4;
 787          uint charno = (uint) n % 4;
 788          netdata[n] = getbits36_8 (buffer [5 + wordno], charno * 9 + 1);
 789 //sim_printf ("%012llo %u %u %u %03u\n", buffer [5 + wordno], n, wordno, charno, netdata[n]);
 790       }
 791 
 792     rc = write (socket_fd, netdata, count);
 793     if (rc == -1)
 794       _errno = errno;
 795 
 796     buffer[2] = ((word36) ((word36s) rc)) & MASK36; // rc
 797     set_error (& buffer[3], _errno);
 798     return IOM_CMD_DISCONNECT; // send terminate interrupt
 799   }
 800 
 801 static int get_ddcw (iom_chan_data_t * p, uint iom_unit_idx, uint chan, bool * ptro, uint expected_tally, uint * tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 802   {
 803     bool send, uff;
 804     int rc = iom_list_service (iom_unit_idx, chan, ptro, & send, & uff);
 805     if (rc < 0)
 806       {
 807         p->stati = 05001; // BUG: arbitrary error code; config switch
 808         sim_warn ("%s list service failed\n", __func__);
 809         return IOM_CMD_ERROR;
 810       }
 811     if (uff)
 812       {
 813         sim_warn ("%s ignoring uff\n", __func__); // XXX
 814       }
 815     if (! send)
 816       {
 817         sim_warn ("%s nothing to send\n", __func__);
 818         p->stati = 05001; // BUG: arbitrary error code; config switch
 819         return IOM_CMD_ERROR;
 820       }
 821     if (IS_IDCW (p) || IS_TDCW (p))
 822       {
 823         sim_warn ("%s expected DDCW\n", __func__);
 824         p->stati = 05001; // BUG: arbitrary error code; config switch
 825         return IOM_CMD_ERROR;
 826       }
 827 
 828     * tally = p->DDCW_TALLY;
 829     if (* tally == 0)
 830       {
 831         sim_debug (DBG_DEBUG, & skc_dev,
 832                    "%s: Tally of zero interpreted as 010000(4096)\n",
 833                    __func__);
 834         * tally = 4096;
 835       }
 836 
 837     sim_debug (DBG_DEBUG, & skc_dev,
 838                "%s: Tally %d (%o)\n", __func__, * tally, * tally);
 839 
 840     if (expected_tally && * tally && * tally != expected_tally) //-V560
 841       {
 842         sim_warn ("socket_dev socket call expected tally of %d; got %d\n", expected_tally, * tally);
 843         p->stati = 05001; // BUG: arbitrary error code; config switch
 844         return IOM_CMD_ERROR;
 845       }
 846     return IOM_CMD_PROCEED;
 847   }
 848 
 849 static int sk_cmd (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 850   {
 851     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 852 
 853     sim_debug (DBG_DEBUG, & skc_dev, "IDCW_DEV_CODE %d\n", p->IDCW_DEV_CODE);
 854     uint unit_idx = get_ctlr_idx (iom_unit_idx, chan);
 855 sim_printf ("device %u\n", p->IDCW_DEV_CODE);
 856     bool ptro;
 857     switch (p->IDCW_DEV_CMD)
 858       {
 859         case 0: // CMD 00 Request status -- controller status, not device
 860           {
 861             p->stati = 04000; // have_status = 1
 862             sim_debug (DBG_DEBUG, & skc_dev,
 863                        "%s: Request status: %04o\n", __func__, p->stati);
 864             sim_debug (DBG_DEBUG, & skc_dev,
 865                        "%s: Request status control: %o\n", __func__, p->IDCW_CHAN_CTRL);
 866             sim_debug (DBG_DEBUG, & skc_dev,
 867                        "%s: Request status channel command: %o\n", __func__, p->IDCW_CHAN_CMD);
 868           }
 869           break;
 870 
 871         case 01:               // CMD 01 -- socket()
 872           {
 873             sim_debug (DBG_DEBUG, & skc_dev,
 874                        "%s: socket_dev_$socket\n", __func__);
 875             const uint expected_tally = 6;
 876             uint tally;
 877             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
 878             if (rc)
 879               return rc;
 880 
 881             // Fetch parameters from core into buffer
 882 
 883             word36 buffer [expected_tally];
 884             uint words_processed;
 885             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 886                                        & words_processed, false);
 887 
 888             skt_socket (unit_idx, p->IDCW_DEV_CODE, buffer);
 889 
 890             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 891                                        & words_processed, true);
 892           }
 893           break;
 894 
 895         case 02:               // CMD 02 -- bind()
 896           {
 897             sim_debug (DBG_DEBUG, & skc_dev,
 898                        "%s: socket_dev_$bind\n", __func__);
 899 
 900             const uint expected_tally = 6;
 901             uint tally;
 902             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
 903             if (rc)
 904               return rc;
 905 
 906             // Fetch parameters from core into buffer
 907 
 908             word36 buffer [expected_tally];
 909             uint words_processed;
 910             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 911                                        & words_processed, false);
 912 
 913             skt_bind (unit_idx, p->IDCW_DEV_CODE, buffer);
 914 
 915             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 916                                        & words_processed, true);
 917 
 918           }
 919           break;
 920 
 921         case 03:               // CMD 03 -- Debugging
 922           {
 923             sim_printf ("socket_dev received command 3\r\n");
 924             p->stati = 04000;
 925           }
 926           break;
 927 
 928         case 04:               // CMD 04 -- gethostbyname()
 929           {
 930             sim_debug (DBG_DEBUG, & skc_dev,
 931                        "%s: socket_dev_$gethostbyname\n", __func__);
 932 
 933             const uint expected_tally = 68;
 934             uint tally;
 935             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
 936             if (rc)
 937               return rc;
 938 
 939             // Fetch parameters from core into buffer
 940 
 941             word36 buffer [expected_tally];
 942             uint words_processed;
 943             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 944                                        & words_processed, false);
 945 
 946             skt_gethostbyname (buffer);
 947 
 948             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 949                                        & words_processed, true);
 950 
 951           }
 952           break;
 953 
 954         case 05:               // CMD 05 -- listen()
 955           {
 956             sim_debug (DBG_DEBUG, & skc_dev,
 957                        "%s: socket_dev_$listen\n", __func__);
 958 
 959             const uint expected_tally = 5;
 960             uint tally;
 961             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
 962             if (rc)
 963               return rc;
 964 
 965             // Fetch parameters from core into buffer
 966 
 967             word36 buffer [expected_tally];
 968             uint words_processed;
 969             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 970                                        & words_processed, false);
 971 
 972             skt_listen (unit_idx, p->IDCW_DEV_CODE, buffer);
 973 
 974             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 975                                        & words_processed, true);
 976 
 977           }
 978           break;
 979 
 980         case 06:               // CMD 06 -- accept()
 981           {
 982             sim_debug (DBG_DEBUG, & skc_dev,
 983                        "%s: socket_dev_$accept\n", __func__);
 984 
 985             const uint expected_tally = 7;
 986             uint tally;
 987             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
 988             if (rc)
 989               return rc;
 990 
 991             // Fetch parameters from core into buffer
 992 
 993             word36 buffer [expected_tally];
 994             uint words_processed;
 995             iom_indirect_data_service (iom_unit_idx, chan, buffer,
 996                                        & words_processed, false);
 997             sk_data.unit_data[unit_idx][p->IDCW_DEV_CODE].words_processed = words_processed;
 998 
 999             rc = skt_accept (unit_idx, p->IDCW_DEV_CODE, buffer);
1000 
1001             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1002                                        & words_processed, true);
1003 
1004             return rc; // 3:command pending, don't send terminate interrupt, or
1005                        // 2:sent terminate interrupt
1006           }
1007           /*NOTREACHED*/ /* unreachable */
1008           break;
1009 
1010         case 07:               // CMD 07 -- close()
1011           {
1012             sim_debug (DBG_DEBUG, & skc_dev,
1013                        "%s: socket_dev_$close\n", __func__);
1014 
1015             const uint expected_tally = 4;
1016             uint tally;
1017             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
1018             if (rc)
1019               return rc;
1020 
1021             // Fetch parameters from core into buffer
1022 
1023             word36 buffer [expected_tally];
1024             uint words_processed;
1025             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1026                                        & words_processed, false);
1027 
1028             skt_close (unit_idx, p->IDCW_DEV_CODE, buffer);
1029 
1030             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1031                                        & words_processed, true);
1032           }
1033           break;
1034 
1035         case 8:               // CMD 8 -- read8()
1036           {
1037             sim_debug (DBG_DEBUG, & skc_dev,
1038                        "%s: socket_dev_$read8\n", __func__);
1039 
1040             const uint expected_tally = 0;
1041             uint tally;
1042             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
1043             if (rc)
1044               return rc;
1045 
1046             // Fetch parameters from core into buffer
1047 
1048             word36 buffer[4096];  /* tally size is max 4096 bytes */
1049             uint words_processed;
1050             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1051                                        & words_processed, false);
1052             sk_data.unit_data[unit_idx][p->IDCW_DEV_CODE].words_processed = words_processed;
1053 
1054             rc = skt_read8 (unit_idx, p->IDCW_DEV_CODE, tally, buffer);
1055 
1056             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1057                                        & words_processed, true);
1058             return rc; // 3:command pending, don't send terminate interrupt, or
1059                        // 2:sent terminate interrupt
1060           }
1061           /*NOTREACHED*/ /* unreachable */
1062           break;
1063 
1064         case 9:               // CMD 9 -- write8()
1065           {
1066             sim_debug (DBG_DEBUG, & skc_dev,
1067                        "%s: socket_dev_$write8\n", __func__);
1068 
1069             const uint expected_tally = 0;
1070             uint tally;
1071             int rc = get_ddcw (p, iom_unit_idx, chan, & ptro, expected_tally, & tally);
1072             if (rc)
1073               return rc;
1074 
1075             // Fetch parameters from core into buffer
1076 
1077             word36 buffer[4096];  /* tally size is max 4096 bytes */
1078             uint words_processed;
1079             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1080                                        & words_processed, false);
1081 
1082             rc = skt_write8 (iom_unit_idx, chan, unit_idx, p->IDCW_DEV_CODE, tally, buffer);
1083 
1084             iom_indirect_data_service (iom_unit_idx, chan, buffer,
1085                                        & words_processed, true);
1086           return rc;
1087           }
1088           /*NOTREACHED*/ /* unreachable */
1089           break;
1090 
1091         case 040:               // CMD 040 -- Reset Status
1092           {
1093             p->stati = 04000;
1094             sim_debug (DBG_DEBUG, & skc_dev,
1095                        "%s: Reset status is %04o.\n",
1096                        __func__, p->stati);
1097             return IOM_CMD_PROCEED;
1098           }
1099 
1100         default:
1101           {
1102             p->stati = 04501;
1103             p->chanStatus = chanStatIncorrectDCW;
1104             if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1105               sim_warn ("%s: Unknown command 0%o\n", __func__, p->IDCW_DEV_CMD);
1106           }
1107           return IOM_CMD_ERROR;
1108 
1109       } // IDCW_DEV_CMD
1110 
1111     sim_debug (DBG_DEBUG, & skc_dev, "stati %04o\n", p->stati);
1112 
1113 
1114 
1115 
1116 
1117 
1118 
1119     return IOM_CMD_DISCONNECT; // don't continue down the dcw list.
1120   }
1121 
1122 iom_cmd_rc_t skc_iom_cmd (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1123   {
1124     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx] [chan];
1125 // Is it an IDCW?
1126 
1127     int rc = 0;
1128     if (IS_IDCW (p))
1129       {
1130         rc = sk_cmd (iom_unit_idx, chan);
1131       }
1132     else // DDCW/TDCW
1133       {
1134         sim_warn ("%s expected IDCW\n", __func__);
1135         return IOM_CMD_ERROR;
1136       }
1137     return rc; //  Don't continue down the dcw list.
1138   }
1139 
1140 static void do_try_accept (uint unit_idx, word6 dev_code)
     /* [previous][next][first][last][top][bottom][index][help] */
1141   {
1142     struct sockaddr_in from = { .sin_family = AF_INET };
1143     socklen_t size = sizeof (from);
1144     int _errno = 0;
1145     int fd = accept (sk_data.unit_data[unit_idx][dev_code].accept_fd, (struct sockaddr *) & from, & size);
1146     if (fd == -1)
1147       {
1148         if (errno == EAGAIN || errno == EWOULDBLOCK)
1149           return;
1150         _errno = errno;
1151       }
1152     else if (fd < N_FDS)
1153       {
1154         sk_data.fd_unit[fd] = (int) unit_idx;
1155         sk_data.fd_dev_code[fd] = dev_code;
1156         sk_data.fd_nonblock[fd] = false ; // !! (type & SOCK_NONBLOCK);
1157       }
1158     else
1159       {
1160         close (fd);
1161         fd = -1;
1162         _errno = EMFILE;
1163       }
1164     word36 buffer [7];
1165     // sign extend int into word36
1166     buffer[0] = ((word36) ((word36s) sk_data.unit_data[unit_idx][dev_code].accept_fd)) & MASK36;
1167     buffer[1] = ((word36) ((word36s) fd)) & MASK36;
1168     buffer[2] = ((word36) ((word36s) from.sin_family)) & MASK36;
1169     uint16_t port = ntohs (from.sin_port);
1170     putbits36_16 (& buffer[3], 0, port);
1171     uint32_t addr = ntohl (from.sin_addr.s_addr);
1172     buffer[4]     = ((word36) addr) << 4;
1173     set_error (& buffer[5], _errno);
1174     // This makes me nervous; it is assuming that the decoded channel control
1175     // list data for the channel is intact, and that buffer is still in place.
1176     uint iom_unit_idx    = (uint) cables->sk_to_iom[unit_idx][0].iom_unit_idx;
1177     uint chan            = (uint) cables->sk_to_iom[unit_idx][0].chan_num;
1178     uint words_processed = sk_data.unit_data[unit_idx][dev_code].words_processed;
1179     iom_indirect_data_service (iom_unit_idx, chan, buffer,
1180                                & words_processed, true);
1181     iom_chan_data_t * p  = & iom_chan_data[iom_unit_idx][chan];
1182     p->stati = 04000; // -V536
1183     sk_data.unit_data[unit_idx][dev_code].unit_state = unit_idle;
1184     send_terminate_interrupt (iom_unit_idx, chan);
1185   }
1186 
1187 static void do_try_read (uint unit_idx, word6 dev_code)
     /* [previous][next][first][last][top][bottom][index][help] */
1188   {
1189     int _errno = 0;
1190     uint count           = sk_data.unit_data[unit_idx][dev_code].read_buffer_sz;
1191     uint buffer_size_wds = (count + 3) / 4;
1192     word36 buffer [buffer_size_wds];
1193     // Make clang analyzer happy
1194     memset (buffer, 0, sizeof (word36) * buffer_size_wds);
1195     uint8_t netdata [count];
1196     ssize_t nread = read (sk_data.unit_data[unit_idx][dev_code].read_fd, & netdata, count);
1197     if (nread == -1)
1198       {
1199         if (errno == EAGAIN || errno == EWOULDBLOCK)
1200           return;
1201         _errno = errno;
1202         nread = 0;
1203       }
1204 
1205     // sign extend int into word36
1206     buffer[0] = ((word36) ((word36s) sk_data.unit_data[unit_idx][dev_code].read_fd)) & MASK36;
1207     buffer[1] = ((word36) (sk_data.unit_data[unit_idx][dev_code].read_buffer_sz)) & MASK36;
1208     buffer[2] = ((word36) ((word36s) nread)) & MASK36;
1209     set_error (& buffer[3], _errno);
1210 
1211     for (ssize_t n = 0; n < nread; n ++)
1212       {
1213          uint wordno = (uint) n / 4;
1214          uint charno = (uint) n % 4;
1215          putbits36_9 (& buffer [5 + wordno], charno * 9, (word9) netdata [n]);
1216       }
1217 
1218     // This makes me nervous; it is assuming that the decoded channel control
1219     // list data for the channel is intact, and that buffer is still in place.
1220     uint iom_unit_idx    = (uint) cables->sk_to_iom[unit_idx][0].iom_unit_idx;
1221     uint chan            = (uint) cables->sk_to_iom[unit_idx][0].chan_num;
1222     uint words_processed = sk_data.unit_data[unit_idx][dev_code].words_processed;
1223     iom_indirect_data_service (iom_unit_idx, chan, buffer,
1224                                & words_processed, true);
1225     sk_data.unit_data[unit_idx][dev_code].unit_state = unit_idle;
1226     send_terminate_interrupt (iom_unit_idx, chan);
1227   }
1228 
1229 void sk_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1230   {
1231 // Accepts
1232     for (uint unit_idx = 0; unit_idx < N_SKC_UNITS_MAX; unit_idx ++)
1233       {
1234         for (word6 dev_code = 0; dev_code < N_DEV_CODES; dev_code ++)
1235           {
1236             if (sk_data.unit_data[unit_idx][dev_code].unit_state == unit_accept)
1237               {
1238                 do_try_accept (unit_idx, dev_code);
1239               }
1240             else if (sk_data.unit_data[unit_idx][dev_code].unit_state == unit_read)
1241               {
1242                 do_try_read (unit_idx, dev_code);
1243               }
1244           }
1245       }
1246   }
1247 #endif /* ifdef WITH_SOCKET_DEV */

/* [previous][next][first][last][top][bottom][index][help] */