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

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