]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Add support for SIOCIFCONF and more.
authorToni Wilen <twilen@winuae.net>
Sun, 8 Aug 2021 11:27:04 +0000 (14:27 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 8 Aug 2021 11:27:04 +0000 (14:27 +0300)
od-win32/bsdsock.cpp

index 152c143068c76fea0d7b8b46f0cd72d0ef6000a4..f942abb806b7dbd2a22f15d3fc255ddd919d0766 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <stddef.h>
 #include <process.h>
+#include <iphlpapi.h>
 
 #include "options.h"
 #include "memory.h"
@@ -112,6 +113,17 @@ static unsigned int __stdcall sock_thread(void *);
 #define FIOSETOWN _IOW('f', 124, long)   /* set owner (struct Task *) */
 #define FIOGETOWN _IOR('f', 123, long)   /* get owner (struct Task *) */
 
+#define _IOWR(x,y,t)     (IOC_OUT|IOC_IN|(((long)(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define SIOCGIFADDR            _IOWR('i', 33, 16)              /* get ifnet address */
+#define SIOCGIFFLAGS   _IOWR('i', 17, 32)              /* get ifnet flags */
+#define SIOCGIFBRDADDR _IOWR('i', 35, 16)              /* get broadcast addr */
+#define SIOCGIFCONF            _IOWR('i', 36, 8)               /* get ifnet list */
+#define SIOCGIFNETMASK _IOWR('i', 37, 16)              /* get net addr mask */
+#define SIOCGIFMETRIC  _IOWR('i', 23, 32)              /* get IF metric */
+#define SIOCGIFMTU             _IOWR('i', 51, 32)              /* get IF mtu */
+#define SIOCGIFPHYS            _IOWR('i', 53, 32)              /* get IF wire */
+
 #define BEGINBLOCKING if (sb->ftable[sd - 1] & SF_BLOCKING) sb->ftable[sd - 1] |= SF_BLOCKINGINPROGRESS
 #define ENDBLOCKING sb->ftable[sd - 1] &= ~SF_BLOCKINGINPROGRESS
 
@@ -129,6 +141,7 @@ static LRESULT CALLBACK SocketWindowProc(HWND hwnd, UINT message, WPARAM wParam,
 #define SF_RAW_RICMP   0x02000000
 #define SF_RAW_HDR             0x01000000
 
+#if 0
 typedef        struct ip_option_information {
        u_char Ttl;             /* Time To Live (used for traceroute) */
        u_char Tos;     /* Type Of Service (usually 0) */
@@ -136,6 +149,7 @@ typedef     struct ip_option_information {
        u_char OptionsSize; /* Size of options data (usually 0, max 40) */
        u_char FAR *OptionsData;   /* Options data buffer */
 } IPINFO, *PIPINFO, FAR *LPIPINFO;
+#endif
 
 static void bsdsetpriority (HANDLE thread)
 {
@@ -152,6 +166,9 @@ static int mySockStartup(void)
 
        if (!bsd) {
                bsd = xcalloc (struct bsdsockdata, 1);
+               if (!bsd) {
+                       return 0;
+               }
                for (i = 0; i < MAX_GET_THREADS; i++)
                        threadindextable[i] = i;
        }
@@ -192,6 +209,8 @@ int init_socket_layer (void)
        deinit_socket_layer ();
        if (currprefs.socket_emu) {
                if((result = mySockStartup())) {
+                       if (!bsd)
+                               return 0;
                        if(bsd->hSockThread == NULL) {
                                WNDCLASS wc;    // Set up an invisible window and dummy wndproc
 
@@ -274,7 +293,7 @@ void deinit_socket_layer(void)
                DeleteCriticalSection(&bsd->SockThreadCS);
                bsd->hSockThread = NULL;
                SetEvent (bsd->hSockReq);
-               WaitForSingleObject(bsd->hSockThread, INFINITE);
+               WaitForSingleObject(t, INFINITE);
                CloseHandle(t);
                CloseHandle(bsd->hSockReq);
                CloseHandle(bsd->hSockReqHandled);
@@ -1630,6 +1649,93 @@ uae_u32 host_getpeername(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32
        return -1;
 }
 
+#define MAX_NET_INTERFACES 30
+struct bsdsock_interface_info {
+       bool inuse;
+       int mtu;
+       int metric;
+       uae_u8 mac[6];
+       bool hasmac;
+};
+static INTERFACE_INFO *net_interfaces;
+static bsdsock_interface_info *net_interfaces2;
+static int net_interfaces_num;
+
+static void get_net_if_extra(void)
+{
+       xfree(net_interfaces2);
+       net_interfaces2 = NULL;
+       DWORD ret = 16 * 1024;
+       DWORD gaaFlags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS;
+       IP_ADAPTER_ADDRESSES *ipaa = (IP_ADAPTER_ADDRESSES*)malloc(ret);
+       if (GetAdaptersAddresses(AF_INET, gaaFlags, NULL, ipaa, &ret) == ERROR_BUFFER_OVERFLOW) {
+               xfree(ipaa);
+               ipaa = (IP_ADAPTER_ADDRESSES*)malloc(ret);
+               if (GetAdaptersAddresses(AF_INET, gaaFlags, NULL, ipaa, &ret) != ERROR_SUCCESS) {
+                       xfree(ipaa);
+                       ipaa = NULL;
+               }
+       }
+       if (ipaa) {
+               net_interfaces2 = xcalloc(struct bsdsock_interface_info, MAX_NET_INTERFACES);
+               if (net_interfaces2) {
+                       for (int i = 0; i < net_interfaces_num; i++) {
+                               INTERFACE_INFO* ii = &net_interfaces[i];
+                               struct bsdsock_interface_info *ii2 = &net_interfaces2[i];
+                               IP_ADAPTER_ADDRESSES *ipa = ipaa;
+                               while (ipa && ii2->inuse == false) {
+                                       if (ipa->Ipv4Enabled && (ipa->IfType == IF_TYPE_ETHERNET_CSMACD || ipa->IfType == IF_TYPE_IEEE80211)) {
+                                               PIP_ADAPTER_UNICAST_ADDRESS pua = ipa->FirstUnicastAddress;
+                                               while (pua) {
+                                                       if (pua->Address.iSockaddrLength == 16 && !memcmp(pua->Address.lpSockaddr, &ii->iiAddress.Address, 16)) {
+                                                               ii2->mtu = ipa->Mtu;
+                                                               if (ipa->PhysicalAddressLength == 6) {
+                                                                       memcpy(ii2->mac, ipa->PhysicalAddress, 6);
+                                                                       ii2->hasmac = true;
+                                                               }
+                                                               ii2->metric = ipa->Ipv4Metric;
+                                                               ii2->inuse = true;
+                                                       }
+                                                       pua = pua->Next;
+                                               }
+                                       }
+                                       ipa = ipa->Next;
+                               }
+                       }
+               }
+               xfree(ipaa);
+       }
+}
+
+static int get_net_if(TrapContext *ctx, uaecptr addr, bool extra)
+{
+       char name[17];
+       trap_get_bytes(ctx, name, addr, 16);
+       name[16] = 0;
+       if (name[0] == 'l' && name[1] == 'o' && name[2] == 0) {
+               for (int i = 0; i < net_interfaces_num; i++) {
+                       if (net_interfaces[i].iiFlags & IFF_LOOPBACK) {
+                               return i;
+                       }
+               }
+       }
+       if (name[0] == 'e' && name[1] == 't' && name[2] == 'h') {
+               int num = atoi(name + 3);
+               if (num == 0 && name[3] != '0') {
+                       return -1;
+               }
+               if (num >= net_interfaces_num) {
+                       return -1;
+               }
+               // query extra information only if needed (MTU, Metric, MAC)
+               if (extra && !net_interfaces2) {
+                       get_net_if_extra();
+               }
+               return num;
+       }
+       return -1;
+}
+
 uae_u32 host_IoctlSocket(TrapContext *ctx, SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
 {
        SOCKET s;
@@ -1665,7 +1771,7 @@ uae_u32 host_IoctlSocket(TrapContext *ctx, SB, uae_u32 sd, uae_u32 request, uae_
                case FIONREAD:
                        ioctlsocket(s,request,(u_long *)&data);
                        BSDTRACE((_T("[FIONREAD] -> %d\n"),data));
-                       trap_put_long(ctx, arg,data);
+                       trap_put_long(ctx, arg, data);
                        success = 0;
                        break;
                case FIOASYNC:
@@ -1685,6 +1791,121 @@ uae_u32 host_IoctlSocket(TrapContext *ctx, SB, uae_u32 sd, uae_u32 request, uae_
 
                        success = -1;
                        break;
+
+               case SIOCGIFFLAGS:
+                       {
+                               int idx = get_net_if(ctx, arg, false);
+                               if (idx >= 0) {
+                                       INTERFACE_INFO *ii = &net_interfaces[idx];
+                                       uae_u16 flags = 0;
+                                       if (ii->iiFlags & IFF_UP) {
+                                               flags |= 1;
+                                               flags |= 0x40; // IFF_RUNNING
+                                       }
+                                       if (ii->iiFlags & IFF_BROADCAST) {
+                                               flags |= 2;
+                                       }
+                                       if (ii->iiFlags & IFF_LOOPBACK) {
+                                               flags |= 8;
+                                       }
+                                       if (ii->iiFlags & IFF_POINTTOPOINT) {
+                                               flags |= 0x10;
+                                       }
+                                       if (ii->iiFlags & IFF_MULTICAST) {
+                                               flags |= 0x8000;
+                                       }
+                                       trap_put_word(ctx, arg + 16, flags);
+                                       success = 0;
+                               }
+                       }
+               break;
+               case SIOCGIFMTU:
+               case SIOCGIFMETRIC:
+               case SIOCGIFPHYS:
+                       {
+                               int idx = get_net_if(ctx, arg, true);
+                               if (idx >= 0) {
+                                       struct bsdsock_interface_info *ii2 = &net_interfaces2[idx];
+                                       if (ii2->inuse) {
+                                               if (request == SIOCGIFMETRIC) {
+                                                       trap_put_long(ctx, arg + 16, ii2->metric);
+                                                       success = 0;
+                                               } else if (request == SIOCGIFMTU) {
+                                                       trap_put_long(ctx, arg + 16, ii2->mtu);
+                                                       success = 0;
+                                               } else if (request == SIOCGIFPHYS) {
+                                                       if (ii2->hasmac) {
+                                                               trap_put_bytes(ctx, ii2->mac, arg + 16, 6);
+                                                               success = 0;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               break;
+               case SIOCGIFADDR:
+               case SIOCGIFNETMASK:
+               case SIOCGIFBRDADDR:
+                       {
+                               int idx = get_net_if(ctx, arg, false);
+                               if (idx >= 0) {
+                                       INTERFACE_INFO *ii = &net_interfaces[idx];
+                                       sockaddr_gen *sa = &ii->iiAddress;
+                                       if (request == SIOCGIFNETMASK) {
+                                               sa = &ii->iiNetmask;
+                                       } else if (request == SIOCGIFBRDADDR) {
+                                               sa = &ii->iiBroadcastAddress;
+                                       }
+                                       trap_put_byte(ctx, arg + 16, 16);
+                                       trap_put_byte(ctx, arg + 17, (uae_u8)sa->Address.sa_family);
+                                       trap_put_bytes(ctx, sa->Address.sa_data, arg + 16 + 2, 14);
+                                       success = 0;
+                               }
+                       }
+               break;
+               case SIOCGIFCONF:
+                       {
+                               xfree(net_interfaces);
+                               xfree(net_interfaces2);
+                               net_interfaces2 = NULL;
+                               net_interfaces_num = 0;
+                               net_interfaces = xcalloc(INTERFACE_INFO, MAX_NET_INTERFACES);
+                               if (net_interfaces) {
+                                       DWORD ret;
+                                       if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, (LPVOID*)net_interfaces, MAX_NET_INTERFACES * sizeof(INTERFACE_INFO), &ret, NULL, NULL) != SOCKET_ERROR) {
+                                               net_interfaces_num = ret / sizeof(INTERFACE_INFO);
+                                               int cnt = 0;
+                                               int bytes = trap_get_long(ctx, arg);
+                                               uaecptr ptr = trap_get_long(ctx, arg + 4);
+                                               int ethcnt = 0;
+                                               int bytecnt = 0;
+                                               for (int i = 0; i < net_interfaces_num; i++) {
+                                                       INTERFACE_INFO *ii = &net_interfaces[i];
+                                                       if (bytes < 32) {
+                                                               break;
+                                                       }
+                                                       // fake names
+                                                       if (ii->iiFlags & IFF_LOOPBACK) {
+                                                               trap_put_string(ctx, "lo", ptr, 16);
+                                                       } else {
+                                                               char tmp[10];
+                                                               sprintf(tmp, "eth%d", ethcnt++);
+                                                               trap_put_string(ctx, tmp, ptr, 16);
+                                                       }
+                                                       trap_put_byte(ctx, ptr + 16, 16);
+                                                       trap_put_byte(ctx, ptr + 17, (uae_u8)ii->iiAddress.Address.sa_family);
+                                                       trap_put_bytes(ctx, ii->iiAddress.Address.sa_data, ptr + 16 + 2, 14);
+                                                       ptr += 32;
+                                                       bytes -= 32;
+                                                       bytecnt += 32;
+                                               }
+                                               trap_put_long(ctx, arg, bytecnt);
+                                               success = 0;
+                                       }
+                               }
+                       }
+                       break;
+
                default:
                        write_log (_T("BSDSOCK: WARNING - Unknown IoctlSocket request: 0x%08lx\n"), request);
                        bsdsocklib_seterrno(ctx, sb, 22); // EINVAL