gvanem / Watt-32

Watt-32 TCP/IP library and samples.
https://www.watt-32.net/
18 stars 8 forks source link

Fixed Watcom W135 when compiling for 16-bit processors #113

Closed Lethja closed 5 months ago

Lethja commented 5 months ago

This pull request fixed #112

gvanem commented 5 months ago

But after this change, there are lots of these new warnings from clang-cl:

ioctl.c(128,10): warning: overflow converting case value to switch condition type (18446744071562356350 to 2147772030) [-Wswitch]
  128 |     case FIONBIO:                 /* set nonblocking I/O on/off */
      |          ^
../inc\sys/ioctl.h(77,25): note: expanded from macro 'FIONBIO'
   77 | #define FIONBIO         _IOW('f', 126, int)    /* set/clear non-blocking i/o */
      |                         ^
../inc\sys/ioctl.h(67,21): note: expanded from macro '_IOW'
   67 | #define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
      |                     ^
gvanem commented 5 months ago

But these new warnings are for x64 only. Like here; https://ci.appveyor.com/project/gvanem/watt-32/builds/49490611/job/dlvjwucjl4xm1bpt#L72

I fixed these in: https://github.com/gvanem/Watt-32/commit/e3d473ffca030ba643b2e375cc5fd340155d4b76.

gvanem commented 5 months ago

I'm sorry but this PR caused a lot of warnings for most other targets. Will have to revert and create a special case for Watcom + 16-bit. Is this the best way to check for this:

/* Watcom / 16-bit targets need special handling:
 */
#if defined(__WATCOMC__) && !defined(__386__)
  #define IOCPARM_MASK (long) 0x7f        /* parameters must be < 128 bytes */
  ...
#else
  #define IOCPARM_MASK  0x7f        
  ...
#endif
jmalak commented 5 months ago
The issue is because long type on some 64-bit system is 64-bit. By example C type 16-bit arch 32-bit arch 64-bit Microsoft Windows 64-bit *NIX
short 16-bit 16-bit 16-bit 16-bit 16-bit
int 16-bit 32-bit 32-bit 32-bit 32-bit
long 32-bit 32-bit 32-bit 64-bit
long long 64-bit 64-bit 64-bit 64-bit

that for code common for 16/32/64-bit platform for 32-bit variable you need use conditional type or use C99 int32_t type independent on platform or modify code to use long type and be independent on such type size. Open Watcom use long type with 32-bit size.

Anyway following definition is wrong and will cause a problems

#if defined(__WATCOMC__) && !defined(__386__)
  #define IOCPARM_MASK (long) 0x7f        /* parameters must be < 128 bytes */
  ...
#else
  #define IOCPARM_MASK  0x7f        
  ...
#endif

it should be #define IOCPARM_MASK 0x7f for every platform. The issue is caused by other macros definition and 64-bit type size. The macros should be corrected to work properly with all possible types or you need to add macros specialized for appropriate types. simplest method is mask value to be in 32-bit range even if used type is 64-bit, but it depends on use, there can be signed value problem etc.

gvanem commented 5 months ago

The issue is caused by other macros definition and 64-bit type size.

So what's the fix? I reverted the previous fix in https://github.com/gvanem/Watt-32/commit/e1accb26464f9b0b9a3c7f803b1ad9ba83ec3db0 to fix the original Watcom/16-bit warnings. Not sure it's correct. Have a look.

Lethja commented 5 months ago

Perhaps it's best to define our own int_least32_t equivalent that can be used throughout the codebase. This will keep the code C89 compliant yet keep the preprocessors minimal in the actual code

#if defined(__WATCOMC__) && !defined(__386__)
typedef long least_int32_t
/* Can add more #elif conditions for different compilers and targets here if required */
#else
typedef int least_int32_t
#endif
jmalak commented 5 months ago

I think the cast in constant definition is source of problem. You should always minimise C casting and you should relate on standard C language automatic type conversion (type promotion). It needs much bigger revision of your code, because you mixed Windows, POSIX and ISO C types in your code. The main problem looks like 32-bit size variable because it is platform and architecture dependent. It also depend on C standard which you are using because C90 standard doesn't know int32_t type. It was introduced by C99. If you want compatibility with C90 then best solution is define your own global type for 32-bit size as conditional type. You need to properly detect compiler type mode, it means if long type size is 64-bit. It should be something as

#if COMPILER_64BIT_LPP
#define INT32TYPE  int
#define UINT32TYPE  unsigned int
#else 
#define INT32TYPE  long
#define UINT32TYPE  unsigned long
#endif 

and use this type where it has sense (where it is necessary) otherwise use long type.

jmalak commented 5 months ago

Perhaps it's best to define our own int_least32_t equivalent that can be used throughout the codebase. This will keep the code C89 compliant yet keep the preprocessors minimal in the actual code

#if defined(__WATCOMC__) && !defined(__386__)
typedef long least_int32_t
/* Can add more #elif conditions for different compilers and targets here if required */
#else
typedef int least_int32_t
#endif

Don't do it as watcom specific, because same problem with other compilers. Correct is detect if long type is 64-bit. Most of *NIX compilers has this mode by default, but they can be switched to Windows model then long type is 32-bit that it can not be detected by compiler only. This issue is related to 64-bit platform mainly not with 16-bit platform any way. your least_int32_t can be replaced by long type doesn't need such construct, because long type is >= 32-bit on any platform.

Lethja commented 5 months ago

I tested Watcom DOS 16-bit and DOS 4G builds at e1accb26464f9b0b9a3c7f803b1ad9ba83ec3db0. All is well

gvanem commented 5 months ago

All is well

So we can leave src/ioctl.c and inc/sys/ioctl.h like it is now?

Lethja commented 5 months ago

So we can leave src/ioctl.c and inc/sys/ioctl.h like it is now?

Yes while @jmalak has given the technically correct solution that would make code exactly the same across different platform builds and could allow compilers to do a tiny optimization for i486 and later architectures (including 64-bit), e1accb2 is enough to fix Watcom W135 when building for DOS 16-bit.

If we want to pursue making ioctl options explicitly 32-bit then we can make another issue later

jmalak commented 5 months ago

I am not able to check build of Watt-32, but inc/sys/ioctl.h should be returned back to following old version. there is no reason to change it.

/*!\file sys/ioctl.h
 * BSD socket I/O control.
 */

/*
 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the University of
 *    California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if !defined(__SYS_IOCTL_H) && !defined(__SYS_SO_IOCTL_H)
#define __SYS_IOCTL_H

/*
 * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.
 *
 * Ioctl's have the command encoded in the lower word,
 * and the size of any in or out parameters in the upper
 * word.  The high 2 bits of the upper word are used
 * to encode the in/out status of the parameter; for now
 * we restrict parameters to at most 128 bytes.
 */

#define IOCPARM_MASK    0x7f                   /* parameters must be < 128 bytes */

#define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
#define IOCBASECMD(x)   ((x) & ~IOCPARM_MASK)
#define IOCGROUP(x)     (((x) >> 8) & 0xff)

#define IOCPARM_MAX     4096                   /* max size of ioctl */
#define IOC_VOID        0x20000000             /* no parameters */
#define IOC_OUT         0x40000000             /* copy out parameters */
#define IOC_IN          0x80000000             /* copy in parameters */
#define IOC_INOUT       (IOC_IN|IOC_OUT)       /* 0x20000000 distinguishes new &
                                                  old ioctl's */
#define IOC_DIRMASK     0xe0000000             /* mask for IN/OUT/VOID */

#define _IO(x,y)        (IOC_VOID|(x<<8)|y)
#define _IOR(x,y,t)     (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
#define _IOW(x,y,t)     (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
/* this should be _IORW, but stdio got there first */
#define _IOWR(x,y,t)    (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)

/*
 * file i/o controls
 */
#define FIOCLEX         _IO('f', 1)            /* set close on exec on fd */
#define FIONCLEX        _IO('f', 2)            /* remove close on exec */
#define FIONREAD        _IOR('f', 127, int)    /* get # bytes to read */
#define FIONBIO         _IOW('f', 126, int)    /* set/clear non-blocking i/o */
#define FIOASYNC        _IOW('f', 125, int)    /* set/clear async i/o */
#define FIOSETOWN       _IOW('f', 124, int)    /* set owner (struct Task *) */
#define FIOGETOWN       _IOR('f', 123, int)    /* get owner (struct Task *) */

/*
 * socket i/o controls
 *
 * SIOCSPGRP and SIOCGPGRP are identical to the FIOSETOWN and FIOGETOWN,
 * respectively.
 */
#define SIOCSPGRP       _IOW('s',  8, int)    /* set process group */
#define SIOCGPGRP       _IOR('s',  9, int)    /* get process group */

/* #ifdef BSD */
#define SIOCADDRT       _IOW('r', 10, struct ortentry) /* add route */
#define SIOCDELRT       _IOW('r', 11, struct ortentry) /* delete route */

#define SIOCSIFADDR     _IOW('I', 12, struct ifreq)    /* set ifnet address */
#define OSIOCGIFADDR    _IOWR('I',13, struct ifreq)    /* get ifnet address */
#define SIOCGIFADDR     _IOWR('I',33, struct ifreq)    /* get ifnet address */
#define SIOCSIFDSTADDR  _IOW('I', 14, struct ifreq)    /* set p-p address */
#define OSIOCGIFDSTADDR _IOWR('I',15, struct ifreq)    /* get p-p address */
#define SIOCGIFDSTADDR  _IOWR('I',34, struct ifreq)    /* get p-p address */
#define SIOCSIFFLAGS    _IOW('I', 16, struct ifreq)    /* set ifnet flags */
#define SIOCGIFFLAGS    _IOWR('I',17, struct ifreq)    /* get ifnet flags */
#define OSIOCGIFBRDADDR _IOWR('I',18, struct ifreq)    /* get broadcast addr */
#define SIOCGIFBRDADDR  _IOWR('I',35, struct ifreq)    /* get broadcast addr */
#define SIOCSIFBRDADDR  _IOW('I',19, struct ifreq)     /* set broadcast addr */
#define OSIOCGIFCONF    _IOWR('I',20, struct ifconf)   /* get ifnet list */
#define SIOCGIFCONF     _IOWR('I',36, struct ifconf)   /* get ifnet list */
#define OSIOCGIFNETMASK _IOWR('I',21, struct ifreq)    /* get net addr mask */
#define SIOCGIFNETMASK  _IOWR('I',37, struct ifreq)    /* get net addr mask */
#define SIOCSIFNETMASK  _IOW('I',22, struct ifreq)     /* set net addr mask */
#define SIOCGIFMETRIC   _IOWR('I',23, struct ifreq)    /* get IF metric */
#define SIOCSIFMETRIC   _IOW('I',24, struct ifreq)     /* set IF metric */
#define SIOCDIFADDR     _IOW('I',25, struct ifreq)     /* delete IF addr */
#define SIOCAIFADDR     _IOW('I',26, struct ifaliasreq)/* add/chg IF alias */
#define SIOCGIFMTU      _IOWR('I',27, struct ifreq)    /* get IF mtu */
#define SIOCGIFHWADDR   _IOWR('I',28, struct ifconf)   /* get hardware addr */
#define OSIOCGIFHWADDR  SIOCGIFHWADDR

#define SIOCSARP        _IOW('I', 30, struct arpreq)   /* set arp entry */
#define OSIOCGARP       _IOWR('I',31, struct arpreq)   /* get arp entry */
#define SIOCGARP        _IOWR('I',38, struct arpreq)   /* get arp entry */
#define SIOCDARP        _IOW('I', 32, struct arpreq)   /* delete arp entry */
/* #endif */ /* BSD */

/* MS-DOS */
#define SIOCSHIWAT  _IOW('s',  0, int)    /* set high watermark */
#define SIOCGHIWAT  _IOR('s',  1, int)    /* get high watermark */
#define SIOCSLOWAT  _IOW('s',  2, int)    /* set low watermark */
#define SIOCGLOWAT  _IOR('s',  3, int)    /* get low watermark */
#define SIOCATMARK  _IOR('s',  7, int)    /* at oob mark? */

#endif /* !__SYS_IOCTL_H */

/* Since this file shadows the normal djgpp <sys/ioctl.h>, we include
 * that last.
 */
#if defined(__DJGPP__)
  #include_next <sys/ioctl.h>                    /* ioctl() */
#endif

and src/ioctl.c to something like follows, but there are several strange constructs.

  1. why is structure search_list defined as
    struct search_list {
      DWORD       type;
      const char *name;
    };

instead of

  struct search_list {
      long       type;
      const char *name;
  };

because this structure is internal you can change it to use C types only. Next you can remove lot of useless casts related to this structure.

  1. why you use Windows types for Watt-32 internal types instead of C language types. by example DWORD instead unsigned long or long C type?

  2. any relation to some platform for Watt-32 internals cause problem with portability. if you define API for Windows then it is specific for Windows and cannot be used for other platform then you define only public API for such single platform with platform specific types but internaly you should use your own types which is portable.

/*!\file ioctl.c
 * BSD ioctlsocket().
 */

/*  BSD sockets functionality for Watt-32 TCP/IP
 *
 *  Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. All advertising materials mentioning features or use of this software
 *     must display the following acknowledgement:
 *       This product includes software developed by Gisle Vanem
 *       Bergen, Norway.
 *
 *  THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  Version
 *
 *  0.5 : Dec 18, 1997 : G. Vanem - created
 */

#define BSD    /* in order to include SIOxx macros in <sys/ioctl.h> */

#include "socket.h"

#if defined(USE_BSD_API)

static int file_ioctrl  (Socket *socket, long cmd, void *argp);
static int iface_ioctrl (Socket *socket, long cmd, void *argp);
static int arp_ioctrl   (Socket *socket, long cmd, void *argp);
static int waterm_ioctrl(Socket *socket, long cmd, void *argp);

#define NO_CMD(cmd) SOCK_DEBUGF ((", unsupported cmd %d, group %c", \
                                  (int)((cmd) & IOCPARM_MASK),      \
                                  (char)IOCGROUP(cmd)))
#ifdef USE_DEBUG
static const char *get_ioctl_cmd (long cmd);
#endif

#ifndef NUM_IFACES
#define NUM_IFACES 1
#endif

#ifndef ARPHRD_FDDI
#define ARPHRD_FDDI 10
#endif

int W32_CALL ioctlsocket (int s, long cmd, void *argp)
{
  Socket *socket = _socklist_find (s);

  SOCK_PROLOGUE (socket, "\nioctlsocket:%d", s);

  SOCK_DEBUGF ((", %s", get_ioctl_cmd(cmd)));

  switch (IOCGROUP(cmd))
  {
    case 'f':
         return file_ioctrl (socket, cmd, argp);

    case 'I':
         return iface_ioctrl (socket, cmd, argp);

    case 's':
         return waterm_ioctrl (socket, cmd, argp);

    default:
         NO_CMD (cmd);
         SOCK_ERRNO (ESOCKTNOSUPPORT);
  }
  return (-1);
}

/*
 * IO-control for "file" handles (i.e. stream/datagram sockets)
 */
static int file_ioctrl (Socket *socket, long cmd, void *argp)
{
  int len;

  switch (cmd)
  {
    case FIONREAD:
         VERIFY_RW (argp, sizeof(u_long));

         if (socket->so_type != SOCK_DGRAM &&
             socket->so_type != SOCK_STREAM)
         {
           SOCK_ERRNO (EBADF);
           return (-1);
         }
         if (socket->so_type == SOCK_DGRAM)
         {
           if (socket->so_state & SS_PRIV)
                len = sock_recv_used ((sock_type*)socket->udp_sock);
           else len = sock_rbused ((sock_type*)socket->udp_sock);
         }
         else
           len = sock_rbused ((sock_type*)socket->tcp_sock);

         if (len < 0)
         {
           SOCK_ERRNO (EBADF);
           return (-1);
         }

         SOCK_DEBUGF ((" %d", len));
         if (len >= 0)
            *(u_long*)argp = len;
         break;

    case FIONBIO:                 /* set nonblocking I/O on/off */
         VERIFY_RW (argp, sizeof(char));

         if (*(char*)argp)
         {
           socket->so_state |= SS_NBIO;
           socket->timeout = 0;
           if (socket->tcp_sock)
              socket->tcp_sock->timeout = 0;
         }
         else
         {
           socket->so_state &= ~SS_NBIO;
           if (socket->tcp_sock)  /* Only TCP sockets timeout on inactivety */
              socket->timeout = sock_delay;
         }
         SOCK_DEBUGF ((" %d", (socket->so_state & SS_NBIO) ? 1 : 0));
         break;

#if 0
    case FIOASYNC:
    case FIOCLEX:
    case FIONCLEX:
    case FIONREAD:
    case FIOSETOWN:
    case FIOGETOWN:
#endif

    default:
         NO_CMD (cmd);
         SOCK_ERRNO (ESOCKTNOSUPPORT);
         return (-1);
  }
  return (0);
}

/*
 * Return name of this interface.
 * We only support a single interface at a time.
 */
static char eth_ifname [IFNAMSIZ] = "eth0";
static char arc_ifname [IFNAMSIZ] = "arch0";
static char tok_ifname [IFNAMSIZ] = "tr0";
static char fddi_ifname[IFNAMSIZ] = "fddi0";
static char ppp_ifname [IFNAMSIZ] = "ppp0";
static char slp_ifname [IFNAMSIZ] = "slp0";

void __get_ifname (char *if_name)
{
  switch (_pktdevclass)
  {
    case PDCLASS_ETHER:
         strcpy (if_name, eth_ifname);
         break;
    case PDCLASS_TOKEN:
         strcpy (if_name, tok_ifname);
         break;
    case PDCLASS_FDDI:
         strcpy (if_name, fddi_ifname);
         break;
    case PDCLASS_ARCNET:
         strcpy (if_name, arc_ifname);
         break;
    case PDCLASS_SLIP:
         strcpy (if_name, slp_ifname);
         break;
    case PDCLASS_PPP:
         strcpy (if_name, ppp_ifname);
         break;
    default:
         strcpy (if_name, "??");
         break;
  }
}

#ifdef NOT_USED_YET
/*
 * Set a new name for this interface.
 */
void __set_ifname (const char *if_name)
{
  switch (_pktdevclass)
  {
    case PDCLASS_ETHER:
         strcpy (eth_ifname, if_name);
         break;
    case PDCLASS_TOKEN:
         strcpy (tok_ifname, if_name);
         break;
    case PDCLASS_FDDI:
         strcpy (fddi_name, if_ifname);
         break;
    case PDCLASS_ARCNET:
         strcpy (arc_name, if_ifname);
         break;
    case PDCLASS_SLIP:
         strcpy (slp_ifname, if_name);
         break;
    case PDCLASS_PPP:
         strcpy (ppp_ifname, if_name);
         break;
    default:
         break;
  }
}

static struct ifnet *eth_ifnet (void)
{
  static struct ifnet net;

  /** \todo fill info */
  return (&net);
}

static struct ifnet *tok_ifnet (void)
{
  static struct ifnet net;

  /** \todo fill info */
  return (&net);
}
#endif

/*
 * Ensure we do not 'memcpy()' too much from a '_eth_addr' which is only 6 bytes.
 * The size of 'ifr_hwaddr.sa_data[]' could be 16.
 *
 * With gcc 7.x, a warning for:
 *   memcpy (&ifr->ifr_hwaddr.sa_data[0], &_eth_addr,
 *           sizeof(ifr->ifr_hwaddr.sa_data));
 *
 * was issued:
 *   ioctl.c:466:17: warning: 'memcpy' forming offset [7, 14] is out of the bounds [0, 6] of object
 *   '_eth_addr' with type 'eth_address' {aka 'unsigned char[6]'} [-Warray-bounds]
 */
#define FILL_hwaddr_sa_data(data, eth)       \
        memset (& data, '\0', sizeof(data)); \
        memcpy (& data, & eth, sizeof(eth))

/*
 * Handler for interface request get/set commands
 */
static int iface_ioctrl (Socket *socket, long cmd, void *argp)
{
  struct ifreq       *ifr = (struct ifreq *) argp;
  struct ifconf      *ifc = (struct ifconf*) argp;
  struct sockaddr_in *sin;
#if defined(USE_IPV6)
  struct sockaddr_in6 *sin6;
#endif
  const eth_address  *eth;
  int   len, i;

  VERIFY_RW (argp, sizeof(*ifr));

  switch (cmd)
  {
    case SIOCSARP:
    case SIOCGARP:
    case SIOCDARP:
         return arp_ioctrl (socket, cmd, argp);

    case SIOCGIFADDR:                /* get interface address */
    case OSIOCGIFADDR:
         __get_ifname (ifr->ifr_name);

         if (ifr->ifr_addr.sa_family == AF_INET)
         {
           sin = (struct sockaddr_in*) &ifr->ifr_addr;
           sin->sin_addr.s_addr = htonl (my_ip_addr);
           break;
         }
#if defined(USE_IPV6)
         if (ifr->ifr_addr.sa_family == AF_INET6)
         {
           sin6 = (struct sockaddr_in6*) &ifr->ifr_addr;
           memcpy (&sin6->sin6_addr, &in6addr_my_ip, sizeof(sin6->sin6_addr));
           break;
         }
#endif
         if (_pktdevclass == PDCLASS_TOKEN  || /* otherwise return MAC addr? */
             _pktdevclass == PDCLASS_ETHER  ||
             _pktdevclass == PDCLASS_ARCNET ||
             _pktdevclass == PDCLASS_FDDI)
              memcpy (&ifr->ifr_addr.sa_data[0], &_eth_addr, sizeof(_eth_addr));
         else memset (&ifr->ifr_addr.sa_data[0], '\0', sizeof(ifr->ifr_addr.sa_data));
         break;

    case SIOCGIFMTU:                 /* get interface MTU */
         ifr->ifr_mtu = _mtu;
         break;

#if 0
    case SIOCGIFNAME:                /* get interface name */
         break;
#endif

    case SIOCSIFADDR:                /* set interface address */
         if (ifr->ifr_addr.sa_family == AF_INET)
         {
           sin = (struct sockaddr_in*) &ifr->ifr_addr;
           my_ip_addr = ntohl (sin->sin_addr.s_addr);
           break;
         }
#if defined(USE_IPV6)
         if (ifr->ifr_addr.sa_family == AF_INET6)
         {
           sin6 = (struct sockaddr_in6*) &ifr->ifr_addr;
           memcpy ((void*)&in6addr_my_ip, &sin6->sin6_addr, sizeof(in6addr_my_ip));
           break;
         }
#endif
         eth = (const eth_address*) ifr->ifr_addr.sa_data;  /* ?? */
         if (!_eth_set_addr(eth))
         {
           SOCK_ERRNO (EINVAL);
           return (-1);
         }
         break;

    case OSIOCGIFDSTADDR:
    case SIOCGIFDSTADDR:
         /** \todo Get point-to-point address */
         break;

    case SIOCSIFDSTADDR:
         /** \todo Set point-to-point address */
         break;

    case SIOCSIFFLAGS:   /* set iface flags */
         /* Allow other socket types to do this?
          */
         if (socket->so_type == SOCK_PACKET)
         {
           BOOL rc;

           if (ifr->ifr_flags & IFF_PROMISC)
                rc = _sock_set_promisc_rx_mode();
           else if (ifr->ifr_flags & IFF_ALLMULTI)
                rc = _sock_set_mcast_rx_mode();
           else rc = _sock_set_normal_rx_mode (socket);
           if (!rc)
           {
             SOCK_ERRNO (ENETDOWN);
             return (-1);
           }
         }
         break;

    case SIOCGIFFLAGS:               /* get iface flags */
         ifr->ifr_flags = 0;
         if (_eth_is_init)
         {
           ifr->ifr_flags |= (IFF_UP | IFF_RUNNING);

           if (_pkt_rxmode == RXMODE_PROMISCOUS)
              ifr->ifr_flags |= IFF_PROMISC;

           if (_pkt_rxmode >= RXMODE_MULTICAST2)
              ifr->ifr_flags |= IFF_ALLMULTI;

           if (_pktdevclass == PDCLASS_PPP  ||
               _pktdevclass == PDCLASS_SLIP ||
               _pktdevclass == PDCLASS_AX25)
                ifr->ifr_flags |= IFF_POINTOPOINT;
           else ifr->ifr_flags |= IFF_BROADCAST;  /* ARCNET broadcast? */

#if defined(USE_MULTICAST)
           if (_multicast_on)
              ifr->ifr_flags |= IFF_MULTICAST;
#endif
         }
         break;

    case SIOCGIFBRDADDR:             /* get IP broadcast address */
    case OSIOCGIFBRDADDR:
         sin = (struct sockaddr_in*) &ifr->ifr_broadaddr;
         sin->sin_addr.s_addr = htonl (my_ip_addr | ~sin_mask);
         sin->sin_family      = AF_INET;
         __get_ifname (ifr->ifr_name);
         break;

    case SIOCSIFBRDADDR:             /* set IP broadcast address */
         break;

    case SIOCGIFMETRIC:              /* get interface metric */
         ifr->ifr_metric = 1;
         __get_ifname (ifr->ifr_name);
         break;

    case SIOCSIFMETRIC:
         /** \todo Set interface metric */
         break;

    case SIOCDIFADDR:                /* delete interface addr */
#if defined(USE_IPV6)
         if (ifr->ifr_addr.sa_family == AF_INET6)
         {
           memset ((void*)&in6addr_my_ip, 0, sizeof(in6addr_my_ip));
           break;
         }
#endif
         if (ifr->ifr_addr.sa_family == AF_INET)
         {
           my_ip_addr = 0;
           break;
         }

         /** \todo Handle deleting interface address */
         break;

    case SIOCAIFADDR:
         /** \todo Handle add/change interface alias */
         break;

    case SIOCGIFNETMASK:             /* get interface net-mask */
    case OSIOCGIFNETMASK:
         sin = (struct sockaddr_in*) &ifr->ifr_addr;
         sin->sin_addr.s_addr = htonl (sin_mask);
         sin->sin_family      = AF_INET;
         __get_ifname (ifr->ifr_name);
         break;

    case SIOCSIFNETMASK:             /* set interface net-mask */
         sin = (struct sockaddr_in*) &ifr->ifr_addr;
         sin_mask = ntohl (sin->sin_addr.s_addr);
         break;

    case SIOCGIFCONF:                /* get interfaces config */
    case OSIOCGIFCONF:
         len = ifc->ifc_len = min (ifc->ifc_len, NUM_IFACES*SIZEOF(*ifr));
         ifc = (struct ifconf*) ifc->ifc_buf; /* user's buffer */
         VERIFY_RW (ifc, len);

         i = 0;
         for (ifr = (struct ifreq*)ifc; i < len; ifr++, i += sizeof(*ifr))
         {
           __get_ifname (ifr->ifr_name);
           sin = (struct sockaddr_in*) &ifr->ifr_addr;
           sin->sin_addr.s_addr = htonl (my_ip_addr);
           sin->sin_family      = AF_INET;
         }
         break;

    case SIOCGIFHWADDR:
         switch (_pktdevclass)
         {
           case PDCLASS_ETHER:
                ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;
                FILL_hwaddr_sa_data (ifr->ifr_hwaddr.sa_data, _eth_addr);
                break;
           case PDCLASS_TOKEN:
                ifr->ifr_hwaddr.sa_family = ARPHRD_TOKEN;
                FILL_hwaddr_sa_data (ifr->ifr_hwaddr.sa_data, _eth_addr);
                break;
           case PDCLASS_FDDI:
                ifr->ifr_hwaddr.sa_family = ARPHRD_FDDI;
                FILL_hwaddr_sa_data (ifr->ifr_hwaddr.sa_data, _eth_addr);
                break;
           case PDCLASS_ARCNET:
                ifr->ifr_hwaddr.sa_family  = ARPHRD_ARCNET;
                ifr->ifr_hwaddr.sa_data[0] = _eth_addr[0];
                break;
           case PDCLASS_SLIP:
           case PDCLASS_PPP:
                ifr->ifr_hwaddr.sa_family = 0;
                memset (ifr->ifr_hwaddr.sa_data, '\0',
                        sizeof(ifr->ifr_hwaddr.sa_data));
                break;
           default:
                return (-1);
         }
         break;

    default:
         NO_CMD (cmd);
         SOCK_ERRNO (ESOCKTNOSUPPORT);
         return (-1);
  }
  ARGSUSED (len);
  return (0);
}

/*
 * Handler for buffer hi/lo watermark and urgent data (OOB)
 */
static int waterm_ioctrl (Socket *socket, long cmd, void *argp)
{
  switch (cmd)
  {
    case SIOCSHIWAT:
         /** \todo set high watermark */
         break;

    case SIOCGHIWAT:
         /** \todo get high watermark */
         break;

    case SIOCSLOWAT:
         /** \todo set low watermark */
         break;

    case SIOCGLOWAT:
         /** \todo get low watermark */
         break;

    case SIOCATMARK:
         /** \todo OOB data available? */
         break;

    default:
         NO_CMD (cmd);
         SOCK_ERRNO (ESOCKTNOSUPPORT);
         return (-1);
  }
  ARGSUSED (socket);
  ARGSUSED (argp);
  return (0);
}

/*
 * Handler for ARP-cache interface commands
 */
static int arp_ioctrl (Socket *socket, long cmd, void *argp)
{
  struct arpreq *arp = (struct arpreq*) argp;
  eth_address   *eth;
  DWORD  ip;

  switch (cmd)
  {
    case SIOCSARP:      /* add given IP/MAC-addr pair to ARP cache */
         ip  = intel (*(DWORD*)arp->arp_pa.sa_data);
         eth = (eth_address*) arp->arp_ha.sa_data;
         if (!_arp_cache_add (ip, (const eth_address*)eth, FALSE))
         {
           SOCK_ERRNO (EINVAL);
           return (-1);
         }
         break;

    case SIOCGARP:      /* return ARP entry for given ip */
    case OSIOCGARP:
         ip  = intel (*(DWORD*)arp->arp_pa.sa_data);
         eth = (eth_address*) arp->arp_ha.sa_data;
         if (_arp_lookup_fixed (ip, eth))
         {
           arp->arp_flags |= (ATF_INUSE | ATF_COM | ATF_PERM);  /* fixed addr */
         }
         else if (_arp_lookup (ip, eth))
         {
           arp->arp_flags |= (ATF_INUSE | ATF_COM);   /* dynamic addr */
         }
         else
         {
           arp->arp_flags = 0;
           SOCK_ERRNO (ENOENT);
           return (-1);
         }
         break;

    case SIOCDARP:      /* delete ARP-entry for given ip */
         ip = intel (*(DWORD*)arp->arp_pa.sa_data);
         if (!_arp_cache_del(ip))
         {
           SOCK_ERRNO (ENOENT);
           return (-1);
         }
         break;

    default:
         NO_CMD (cmd);
         SOCK_ERRNO (ESOCKTNOSUPPORT);
         return (-1);
  }
  ARGSUSED (socket);
  return (0);
}

/*
 * Return string for ioctlsocket() command
 */
#if defined(USE_DEBUG)
static const struct search_list commands[] = {
                  { FIOCLEX,         "FIOCLEX"         },
                  { FIONCLEX,        "FIONCLEX"        },
                  { FIONREAD,        "FIONREAD"        },
                  { FIONBIO,         "FIONBIO"         },
                  { FIOASYNC,        "FIOASYNC"        },
                  { FIOSETOWN,       "FIOSETOWN"       },
                  { FIOGETOWN,       "FIOGETOWN"       },
                  { SIOCSPGRP,       "SIOCSPGRP"       },
                  { SIOCGPGRP,       "SIOCGPGRP"       },
                  { SIOCADDRT,       "SIOCADDRT"       },
                  { SIOCDELRT,       "SIOCDELRT"       },
                  { SIOCSIFADDR,     "SIOCSIFADDR"     },
                  { OSIOCGIFADDR,    "OSIOCGIFADDR"    },
                  { SIOCGIFADDR,     "SIOCGIFADDR"     },
                  { SIOCSIFDSTADDR,  "SIOCSIFDSTADDR"  },
                  { OSIOCGIFDSTADDR, "OSIOCGIFDSTADDR" },
                  { SIOCGIFDSTADDR,  "SIOCGIFDSTADDR"  },
                  { SIOCSIFFLAGS,    "SIOCSIFFLAGS"    },
                  { SIOCGIFFLAGS,    "SIOCGIFFLAGS"    },
                  { OSIOCGIFBRDADDR, "OSIOCGIFBRDADDR" },
                  { SIOCGIFBRDADDR,  "SIOCGIFBRDADDR"  },
                  { SIOCSIFBRDADDR,  "SIOCSIFBRDADDR"  },
                  { OSIOCGIFCONF,    "OSIOCGIFCONF"    },
                  { SIOCGIFCONF,     "SIOCGIFCONF"     },
                  { OSIOCGIFNETMASK, "OSIOCGIFNETMASK" },
                  { SIOCGIFNETMASK,  "SIOCGIFNETMASK"  },
                  { SIOCSIFNETMASK,  "SIOCSIFNETMASK"  },
                  { SIOCGIFMETRIC,   "SIOCGIFMETRIC"   },
                  { SIOCSIFMETRIC,   "SIOCSIFMETRIC"   },
                  { SIOCDIFADDR,     "SIOCDIFADDR"     },
                  { SIOCAIFADDR,     "SIOCAIFADDR"     },
                  { SIOCGIFMTU,      "SIOCGIFMTU"      },
                  { SIOCSARP,        "SIOCSARP"        },
                  { OSIOCGARP,       "OSIOCGARP"       },
                  { SIOCGARP,        "SIOCGARP"        },
                  { SIOCDARP,        "SIOCDARP"        },
                  { SIOCSHIWAT,      "SIOCSHIWAT"      },
                  { SIOCGHIWAT,      "SIOCGHIWAT"      },
                  { SIOCSLOWAT,      "SIOCSLOWAT"      },
                  { SIOCGLOWAT,      "SIOCGLOWAT"      },
                  { SIOCATMARK,      "SIOCATMARK"      },
                  { SIOCGIFHWADDR,   "SIOCGIFHWADDR"   }
                };

static const char *get_ioctl_cmd (long cmd)
{
  static char buf [50];

  switch (IOCGROUP(cmd))
  {
    case 'f':
         strcpy (buf, "file cmd: ");
         break;

    case 'I':
         strcpy (buf, "iface cmd: ");
         break;

    case 's':
         strcpy (buf, "waterm cmd: ");
         break;

    default:
         return ("??unknown");
  }
  strcat (buf, list_lookup(cmd, commands, DIM(commands)));
  return (buf);
}
#endif /* USE_DEBUG */
#endif /* USE_BSD_API */

/*
 * A small test program for above functions.
 */
#if defined(TEST_PROG)
#if !defined(USE_BSD_API)
int main (void)
{
  puts ("This program needs '#define USE_BSD_API'");
  return (1);
}
#else  /* rest of file */

#undef  assert
#define assert(x) ((x) ? (void)0 : __assert_fail(__LINE__))

void __assert_fail (unsigned line)
{
  fprintf (stderr, "\nAssert failed at line %d, errno = %d (%s)\n",
           line, errno, strerror(errno));
  exit (-1);
}

const char *eth_addr_string (struct ether_addr *eth)
{
  static char buf [20];

  sprintf (buf, "%02X:%02X:%02X:%02X:%02X:%02X",
           eth->ether_addr_octet[0],
           eth->ether_addr_octet[1],
           eth->ether_addr_octet[2],
           eth->ether_addr_octet[3],
           eth->ether_addr_octet[4],
           eth->ether_addr_octet[5]);
  return (buf);
}

const char *if_flags_string (unsigned short flags)
{
  static char buf [200];

  buf[0] = '\0';

  if (flags & IFF_UP)
     strcat (buf, "up,");
  if (flags & IFF_BROADCAST)
     strcat (buf, "broadcast,");
  if (flags & IFF_DEBUG)
     strcat (buf, "debug,");
  if (flags & IFF_LOOPBACK)
     strcat (buf, "loopback,");
  if (flags & IFF_POINTOPOINT)
     strcat (buf, "p-to-p,");
  if (flags & IFF_NOTRAILERS)
     strcat (buf, "no-trail,");
  if (flags & IFF_RUNNING)
     strcat (buf, "running,");
  if (flags & IFF_NOARP)
     strcat (buf, "no-arp,");
  if (flags & IFF_PROMISC)
     strcat (buf, "promisc,");
  if (flags & IFF_ALLMULTI)
     strcat (buf, "all-multi,");
  if (flags & IFF_OACTIVE)
     strcat (buf, "out-act,");
  if (flags & IFF_SIMPLEX)
     strcat (buf, "simplex,");
  if (flags & IFF_LINK0)
     strcat (buf, "link0,");
  if (flags & IFF_LINK1)
     strcat (buf, "link1,");
  if (flags & IFF_LINK2)
     strcat (buf, "link2,");
  if (flags & IFF_MULTICAST)
     strcat (buf, "mcast,");

  if (buf[0])
     buf [strlen(buf)-1] = '\0';
  return (buf);
}

int main (void)
{
  struct ifreq ifr;
  struct sockaddr_in *sin;
  int    sock, on = 1;

  dbug_init();

  sock = socket (AF_INET, SOCK_DGRAM, 0);
  assert (sock > 0);
  assert (setsockopt(sock, SOL_SOCKET, SO_DEBUG, &on,sizeof(on)) == 0);

  ifr.ifr_addr.sa_family = AF_UNSPEC;  /* get MAC-address */

  assert (ioctlsocket (sock, SIOCGIFADDR, (char*)&ifr) == 0);
  printf ("Interface `%s':\n\t ether-addr: %s\n",
          ifr.ifr_name,
          eth_addr_string ((struct ether_addr*)&ifr.ifr_hwaddr.sa_data));

  assert (ioctlsocket (sock, SIOCGIFBRDADDR, (char*)&ifr) == 0);
  sin = (struct sockaddr_in*) &ifr.ifr_broadaddr;
  printf ("\t bcast-addr: %s\n", inet_ntoa (sin->sin_addr));

  ifr.ifr_addr.sa_family = AF_INET;

  assert (ioctlsocket (sock, SIOCGIFADDR, (char*)&ifr) == 0);
  sin = (struct sockaddr_in*) &ifr.ifr_addr;
  printf ("\t inet-addr:  %s\n", inet_ntoa (sin->sin_addr));

  assert (ioctlsocket (sock, SIOCGIFNETMASK, (char*)&ifr) == 0);
  sin = (struct sockaddr_in*) &ifr.ifr_addr;
  printf ("\t net-mask :  %s\n", inet_ntoa (sin->sin_addr));

  assert (ioctlsocket (sock, SIOCGIFMTU, (char*)&ifr) == 0);
  printf ("\t MTU      :  %u\n",ifr.ifr_mtu);

  assert (ioctlsocket (sock, SIOCGIFFLAGS, (char*)&ifr) == 0);
  printf ("\t Flags    :  0x%04X: %s\n",
          ifr.ifr_flags, if_flags_string(ifr.ifr_flags));

  assert (close_s(sock) >= 0);
  return (0);
}
#endif  /* USE_BSD_API */
#endif  /* TEST_PROG */
gvanem commented 4 months ago

why you use Windows types for Watt-32 internal types instead of C language types. by example DWORD instead unsigned long or long C type?

Many projects use BYTE and WORD internally. E.g. FatFs for embedded systems. No relation to Windows.

jmalak commented 4 months ago

why you use Windows types for Watt-32 internal types instead of C language types. by example DWORD instead unsigned long or long C type?

Many projects use BYTE and WORD internally. E.g. FatFs for embedded systems. No relation to Windows.

Such projects are operating system independent and do not use any operating system header files and thus these types are in global namespace. But if you include such a project in some OS-specific application, you may have the same problem. Once you support multiple operating systems (like Watt-32) and need to include any OS header file, you have a problem with such types. So it's better to use your own namespace for example prefixed with W32_... for Watt-32 and not mix your code with these OS specific types. Such Watt-32 types do not conflict with any types of any OS, and if you need to, you can simply map between Watt-32 types and OS specific types without problems. I think main rule should be to use of C standard type where possible.