libwinpr-winsock: implement interface listing with WSAIoctl

This commit is contained in:
Marc-André Moreau 2015-02-18 13:35:33 -05:00
parent f9885da81c
commit a6c292742e
3 changed files with 283 additions and 0 deletions

View File

@ -56,6 +56,12 @@
#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 */

View 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>

View 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;