libwinpr-winsock: implement interface listing with WSAIoctl
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Wed, 18 Feb 2015 18:35:33 +0000 (13:35 -0500)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Wed, 18 Feb 2015 18:35:33 +0000 (13:35 -0500)
winpr/include/winpr/winsock.h
winpr/libwinpr/error/test/TestErrorSetLastError.c
winpr/libwinpr/winsock/winsock.c

index bf13e97..59a8939 100644 (file)
 #define _getprotobynumber      getprotobynumber
 #define _getprotobyname                getprotobyname
 
+#define _IFF_UP                        IFF_UP
+#define _IFF_BROADCAST         IFF_BROADCAST
+#define _IFF_LOOPBACK          IFF_LOOPBACK
+#define _IFF_POINTTOPOINT      IFF_POINTTOPOINT
+#define _IFF_MULTICAST         IFF_MULTICAST
+
 #if (_WIN32_WINNT < 0x0600)
 
 PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize);
@@ -155,6 +161,123 @@ typedef struct WSAData
 #define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xFF)) | (((WORD)((BYTE)((DWORD_PTR)(b) & 0xFF))) << 8)))
 #endif
 
+typedef struct in6_addr IN6_ADDR;
+typedef struct in6_addr* PIN6_ADDR;
+typedef struct in6_addr* LPIN6_ADDR;
+
+struct sockaddr_in6_old
+{
+       SHORT sin6_family;
+       USHORT sin6_port;
+       ULONG sin6_flowinfo;
+       IN6_ADDR sin6_addr;
+};
+
+typedef union sockaddr_gen
+{
+       struct sockaddr Address;
+       struct sockaddr_in AddressIn;
+       struct sockaddr_in6_old AddressIn6;
+} sockaddr_gen;
+
+#define _IFF_UP                        0x00000001
+#define _IFF_BROADCAST         0x00000002
+#define _IFF_LOOPBACK          0x00000004
+#define _IFF_POINTTOPOINT      0x00000008
+#define _IFF_MULTICAST         0x00000010
+
+struct _INTERFACE_INFO
+{
+       ULONG iiFlags;
+       sockaddr_gen iiAddress;
+       sockaddr_gen iiBroadcastAddress;
+       sockaddr_gen iiNetmask;
+};
+typedef struct _INTERFACE_INFO INTERFACE_INFO;
+typedef INTERFACE_INFO* LPINTERFACE_INFO;
+
+#define MAX_PROTOCOL_CHAIN     7
+#define WSAPROTOCOL_LEN                255
+
+typedef struct _WSAPROTOCOLCHAIN
+{
+       int ChainLen;
+       DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
+}
+WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
+
+typedef struct _WSAPROTOCOL_INFOA
+{
+       DWORD dwServiceFlags1;
+       DWORD dwServiceFlags2;
+       DWORD dwServiceFlags3;
+       DWORD dwServiceFlags4;
+       DWORD dwProviderFlags;
+       GUID ProviderId;
+       DWORD dwCatalogEntryId;
+       WSAPROTOCOLCHAIN ProtocolChain;
+       int iVersion;
+       int iAddressFamily;
+       int iMaxSockAddr;
+       int iMinSockAddr;
+       int iSocketType;
+       int iProtocol;
+       int iProtocolMaxOffset;
+       int iNetworkByteOrder;
+       int iSecurityScheme;
+       DWORD dwMessageSize;
+       DWORD dwProviderReserved;
+       CHAR szProtocol[WSAPROTOCOL_LEN+1];
+}
+WSAPROTOCOL_INFOA, *LPWSAPROTOCOL_INFOA;
+
+typedef struct _WSAPROTOCOL_INFOW
+{
+       DWORD dwServiceFlags1;
+       DWORD dwServiceFlags2;
+       DWORD dwServiceFlags3;
+       DWORD dwServiceFlags4;
+       DWORD dwProviderFlags;
+       GUID ProviderId;
+       DWORD dwCatalogEntryId;
+       WSAPROTOCOLCHAIN ProtocolChain;
+       int iVersion;
+       int iAddressFamily;
+       int iMaxSockAddr;
+       int iMinSockAddr;
+       int iSocketType;
+       int iProtocol;
+       int iProtocolMaxOffset;
+       int iNetworkByteOrder;
+       int iSecurityScheme;
+       DWORD dwMessageSize;
+       DWORD dwProviderReserved;
+       WCHAR szProtocol[WSAPROTOCOL_LEN+1];
+}
+WSAPROTOCOL_INFOW, *LPWSAPROTOCOL_INFOW;
+
+typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,
+               DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
+
+typedef UINT32 GROUP;
+#define SG_UNCONSTRAINED_GROUP         0x01
+#define SG_CONSTRAINED_GROUP           0x02
+
+#define SIO_GET_INTERFACE_LIST         _IOR('t', 127, ULONG)
+#define SIO_GET_INTERFACE_LIST_EX      _IOR('t', 126, ULONG)
+#define SIO_SET_MULTICAST_FILTER       _IOW('t', 125, ULONG)
+#define SIO_GET_MULTICAST_FILTER       _IOW('t', 124 | IOC_IN, ULONG)
+#define SIOCSIPMSFILTER                        SIO_SET_MULTICAST_FILTER
+#define SIOCGIPMSFILTER                        SIO_GET_MULTICAST_FILTER
+
+#ifdef UNICODE
+#define WSAPROTOCOL_INFO       WSAPROTOCOL_INFOW
+#define LPWSAPROTOCOL_INFO     LPWSAPROTOCOL_INFOW
+#else
+#define WSAPROTOCOL_INFO       WSAPROTOCOL_INFOA
+#define LPWSAPROTOCOL_INFO     LPWSAPROTOCOL_INFOA
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -175,6 +298,14 @@ WINPR_API int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, LONG lNetworkEvent
 WINPR_API DWORD WSAWaitForMultipleEvents(DWORD cEvents,
                const HANDLE* lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable);
 
+WINPR_API SOCKET WSASocketA(int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags);
+WINPR_API SOCKET WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags);
+
+WINPR_API int WSAIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
+               DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
+               LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
+               LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+
 WINPR_API SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen);
 WINPR_API int _bind(SOCKET s, const struct sockaddr* addr, int namelen);
 WINPR_API int closesocket(SOCKET s);
@@ -210,6 +341,12 @@ WINPR_API struct protoent* _getprotobyname(const char* name);
 }
 #endif
 
+#ifdef UNICODE
+#define WSASocket      WSASocketW
+#else
+#define WSASocket      WSASocketA
+#endif
+
 #endif /* _WIN32 */
 
 #endif /* WINPR_WINSOCK_H */
index 4452646..b1fbbab 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <winpr/crt.h>
+#include <winpr/wlog.h>
 #include <winpr/synch.h>
 #include <winpr/thread.h>
 #include <winpr/interlocked.h>
index 7443b53..ff0708b 100644 (file)
@@ -650,6 +650,151 @@ DWORD WSAWaitForMultipleEvents(DWORD cEvents, const HANDLE* lphEvents, BOOL fWai
        return WaitForMultipleObjectsEx(cEvents, lphEvents, fWaitAll, dwTimeout, fAlertable);
 }
 
+SOCKET WSASocketA(int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags)
+{
+       SOCKET s;
+
+       s = _socket(af, type, protocol);
+
+       return s;
+}
+
+SOCKET WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags)
+{
+       return WSASocketA(af, type, protocol, (LPWSAPROTOCOL_INFOA) lpProtocolInfo, g, dwFlags);
+}
+
+int WSAIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
+               DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
+               LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
+               LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
+{
+       int fd;
+       int index;
+       ULONG nFlags;
+       size_t offset;
+       size_t ifreq_len;
+       struct ifreq* ifreq;
+       struct ifconf ifconf;
+       char address[128];
+       char broadcast[128];
+       char netmask[128];
+       char buffer[4096];
+       int numInterfaces;
+       int maxNumInterfaces;
+       INTERFACE_INFO* pInterface;
+       INTERFACE_INFO* pInterfaces;
+       struct sockaddr_in* pAddress;
+       struct sockaddr_in* pBroadcast;
+       struct sockaddr_in* pNetmask;
+
+       if ((dwIoControlCode != SIO_GET_INTERFACE_LIST) ||
+               (!lpvOutBuffer || !cbOutBuffer || !lpcbBytesReturned))
+       {
+               WSASetLastError(WSAEINVAL);
+               return SOCKET_ERROR;
+       }
+
+       fd = (int) s;
+       pInterfaces = (INTERFACE_INFO*) lpvOutBuffer;
+       maxNumInterfaces = cbOutBuffer / sizeof(INTERFACE_INFO);
+
+       ifconf.ifc_len = sizeof(buffer);
+       ifconf.ifc_buf = buffer;
+
+       if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0)
+       {
+               WSASetLastError(WSAENETDOWN);
+               return SOCKET_ERROR;
+       }
+
+       index = 0;
+       offset = 0;
+       numInterfaces = 0;
+       ifreq = ifconf.ifc_req;
+
+       while ((offset < ifconf.ifc_len) && (numInterfaces < maxNumInterfaces))
+       {
+               pInterface = &pInterfaces[index];
+               pAddress = (struct sockaddr_in*) &pInterface->iiAddress;
+               pBroadcast = (struct sockaddr_in*) &pInterface->iiBroadcastAddress;
+               pNetmask = (struct sockaddr_in*) &pInterface->iiNetmask;
+
+               if (ioctl(fd, SIOCGIFFLAGS, ifreq) != 0)
+                       goto next_ifreq;
+
+               nFlags = 0;
+
+               if (ifreq->ifr_flags & IFF_UP)
+                       nFlags |= _IFF_UP;
+
+               if (ifreq->ifr_flags & IFF_BROADCAST)
+                       nFlags |= _IFF_BROADCAST;
+
+               if (ifreq->ifr_flags & IFF_LOOPBACK)
+                       nFlags |= _IFF_LOOPBACK;
+
+               if (ifreq->ifr_flags & IFF_POINTOPOINT)
+                       nFlags |= _IFF_POINTTOPOINT;
+
+               if (ifreq->ifr_flags & IFF_MULTICAST)
+                       nFlags |= _IFF_MULTICAST;
+
+               pInterface->iiFlags = nFlags;
+
+               if (ioctl(fd, SIOCGIFADDR, ifreq) != 0)
+                       goto next_ifreq;
+
+               if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
+                       goto next_ifreq;
+
+               getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
+                               address, sizeof(address), 0, 0, NI_NUMERICHOST);
+
+               inet_pton(ifreq->ifr_addr.sa_family, address, (void*) &pAddress->sin_addr);
+
+               if (ioctl(fd, SIOCGIFBRDADDR, ifreq) != 0)
+                       goto next_ifreq;
+
+               if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
+                       goto next_ifreq;
+
+               getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
+                               broadcast, sizeof(broadcast), 0, 0, NI_NUMERICHOST);
+
+               inet_pton(ifreq->ifr_addr.sa_family, broadcast, (void*) &pBroadcast->sin_addr);
+
+               if (ioctl(fd, SIOCGIFNETMASK, ifreq) != 0)
+                       goto next_ifreq;
+
+               if ((ifreq->ifr_addr.sa_family != AF_INET) && (ifreq->ifr_addr.sa_family != AF_INET6))
+                       goto next_ifreq;
+
+               getnameinfo(&ifreq->ifr_addr, sizeof(ifreq->ifr_addr),
+                               netmask, sizeof(netmask), 0, 0, NI_NUMERICHOST);
+
+               inet_pton(ifreq->ifr_addr.sa_family, netmask, (void*) &pNetmask->sin_addr);
+
+               numInterfaces++;
+
+next_ifreq:
+
+#ifndef __linux__
+               ifreq_len = IFNAMSIZ + ifreq->ifr_addr.sa_len;
+#else
+               ifreq_len = sizeof(*ifreq);
+#endif
+
+               ifreq = (struct ifreq*) &((BYTE*) ifreq)[ifreq_len];
+               offset += ifreq_len;
+               index++;
+       }
+
+       *lpcbBytesReturned = (DWORD) (numInterfaces * sizeof(INTERFACE_INFO));
+
+       return 0;
+}
+
 SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen)
 {
        int status;