wine/dlls/wsock32/socket.c
2001-07-02 19:59:40 +00:00

964 lines
32 KiB
C

/*
* WSOCK32 specific functions
*
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
*/
/*
FIXME: This hack is fixing a problem in WsControl. When we call socket(),
it is supposed to call into ws2_32's WSOCK32_socket.
The problem is that socket() is predefined in a linux system header that
we are including, which is different from the WINE definition.
(cdecl vs. stdapi) The result is stack corruption.
The correct answer to this problem is to make winsock.h not dependent
on system headers, that way all of our functions are defined consistently.
Until that happens we need this hack.
*/
#define socket linux_socket
/* */
#include "config.h"
#include <string.h>
#include <sys/types.h>
#include "windef.h"
#include "winbase.h"
#include "debugtools.h"
#include "winsock2.h"
#include "winnt.h"
#include "wscontrol.h"
#include <ctype.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
#include <errno.h>
#ifdef __NetBSD__
#undef if_type
#endif
/* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
discussed above. */
#undef socket
extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
/* */
DEFAULT_DEBUG_CHANNEL(winsock);
/***********************************************************************
* WsControl()
*
* WsControl seems to be an undocumented Win95 function. A lot of
* discussion about WsControl can be found on the net, e.g.
* Subject: Re: WSOCK32.DLL WsControl Exported Function
* From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
* Date: 1997/08/17
*
* WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
* on observing the behaviour of WsControl with an app in
* Windows 98. It is not fully implemented, and there could
* be (are?) errors due to incorrect assumptions made.
*
*
* WsControl returns WSCTL_SUCCESS on success.
* STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
* (*pcbResponseInfoLen) is too small, otherwise errors return -1.
*
* It doesn't seem to generate errors that can be retrieved by
* WSAGetLastError().
*
*/
DWORD WINAPI WsControl(DWORD protocoll,
DWORD action,
LPVOID pRequestInfo,
LPDWORD pcbRequestInfoLen,
LPVOID pResponseInfo,
LPDWORD pcbResponseInfoLen)
{
/* Get the command structure into a pointer we can use,
rather than void */
TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
pcommand->toi_class, pcommand->toi_type );
switch (action)
{
case WSCNTL_TCPIP_QUERY_INFO:
{
switch (pcommand->toi_id)
{
/*
ENTITY_LIST_ID seems to get number of adapters in the system.
(almost like an index to be used when calling other WsControl options)
*/
case ENTITY_LIST_ID:
{
TDIEntityID *baseptr = pResponseInfo;
int numInt = 0, i;
if (pcommand->toi_class != INFO_CLASS_GENERIC &&
pcommand->toi_type != INFO_TYPE_PROVIDER)
{
FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
pcommand->toi_class, pcommand->toi_type);
return (WSAEOPNOTSUPP);
}
numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
if (numInt < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
return (-1);
}
if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
{
return (STATUS_BUFFER_TOO_SMALL);
}
/* 0 it out first */
memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
for (i=0; i<numInt; i++)
{
/* tei_instance is an network interface identifier.
I'm not quite sure what the difference is between tei_entity values of
CL_NL_ENTITY and IF_ENTITY */
baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
}
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
break;
}
/* ENTITY_TYPE_ID is used to obtain simple information about a
network card, such as MAC Address, description, interface type,
number of network addresses, etc. */
case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
{
if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
{
if (pcommand->toi_entity.tei_entity == IF_ENTITY)
{
* ((ULONG *)pResponseInfo) = IF_MIB;
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof (ULONG);
}
else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
{
* ((ULONG *)pResponseInfo) = CL_NL_IP;
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof (ULONG);
}
}
else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
pcommand->toi_type == INFO_TYPE_PROVIDER)
{
if (pcommand->toi_entity.tei_entity == IF_ENTITY)
{
/* In this case, we are requesting specific information about a
a particular network adapter. (MAC Address, speed, data transmitted/received,
etc.)
*/
IFEntry *IntInfo = (IFEntry *) pResponseInfo;
char ifName[512];
struct ifreq ifInfo;
SOCKET sock;
if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
{
ERR ("Unable to parse /proc filesystem!\n");
return (-1);
}
/* Get a socket so that we can use ioctl */
if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
ERR ("Error creating socket!\n");
return (-1);
}
/* 0 out return structure first */
memset (IntInfo, 0, sizeof(IFEntry));
/* Interface ID */
IntInfo->if_index = pcommand->toi_entity.tei_instance;
/* MAC Address - Let's try to do this in a cross-platform way... */
#if defined(SIOCGIFHWADDR) /* Linux */
strcpy(ifInfo.ifr_name, ifName);
if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
{
ERR ("Error obtaining MAC Address!\n");
closesocket(sock);
return (-1);
}
else
{
/* FIXME: Is it correct to assume size of 6? */
memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
IntInfo->if_physaddrlen=6;
}
#elif defined(SIOCGENADDR) /* Solaris */
if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
{
ERR ("Error obtaining MAC Address!\n");
closesocket(sock);
return (-1);
}
else
{
/* FIXME: Is it correct to assume size of 6? */
memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
IntInfo->if_physaddrlen=6;
}
#else
memset (IntInfo->if_physaddr, 0, 6);
ERR ("Unable to determine MAC Address on your platform!\n");
#endif
/* Interface name and length */
strcpy (IntInfo->if_descr, ifName);
IntInfo->if_descrlen= strlen (IntInfo->if_descr);
/* Obtain bytes transmitted/received for interface */
if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
&IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
{
ERR ("Error obtaining transmit/receive stats for the network interface!\n");
closesocket(sock);
return (-1);
}
/* FIXME: How should the below be properly calculated? ******************/
IntInfo->if_type = 0x6; /* Ethernet (?) */
IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
/************************************************************************/
closesocket(sock);
*pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
}
else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
{
IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
int numInt, numRoutes;
/* This case is used to obtain general statistics about the
network */
if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
{
return (STATUS_BUFFER_TOO_SMALL);
}
else
{
/* 0 it out first */
memset(infoStruc, 0, sizeof(IPSNMPInfo));
/* Get the number of interfaces */
numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
if (numInt < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
return (-1);
}
/* Get the number of routes */
numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
if (numRoutes < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
return (-1);
}
infoStruc->ipsi_numif = numInt; /* # of interfaces */
infoStruc->ipsi_numaddr = numInt; /* # of addresses */
infoStruc->ipsi_numroutes = numRoutes; /* # of routes */
/* FIXME: How should the below be properly calculated? ******************/
infoStruc->ipsi_forwarding = 0x0;
infoStruc->ipsi_defaultttl = 0x0;
infoStruc->ipsi_inreceives = 0x0;
infoStruc->ipsi_inhdrerrors = 0x0;
infoStruc->ipsi_inaddrerrors = 0x0;
infoStruc->ipsi_forwdatagrams = 0x0;
infoStruc->ipsi_inunknownprotos = 0x0;
infoStruc->ipsi_indiscards = 0x0;
infoStruc->ipsi_indelivers = 0x0;
infoStruc->ipsi_outrequests = 0x0;
infoStruc->ipsi_routingdiscards = 0x0;
infoStruc->ipsi_outdiscards = 0x0;
infoStruc->ipsi_outnoroutes = 0x0;
infoStruc->ipsi_reasmtimeout = 0x0;
infoStruc->ipsi_reasmreqds = 0x0;
infoStruc->ipsi_reasmoks = 0x0;
infoStruc->ipsi_reasmfails = 0x0;
infoStruc->ipsi_fragoks = 0x0;
infoStruc->ipsi_fragfails = 0x0;
infoStruc->ipsi_fragcreates = 0x0;
/************************************************************************/
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(IPSNMPInfo);
}
}
}
else
{
FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
pcommand->toi_class, pcommand->toi_type);
return (WSAEOPNOTSUPP);
}
break;
}
/* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
particular network adapter */
case IP_MIB_ADDRTABLE_ENTRY_ID:
{
IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
char ifName[IFNAMSIZ+1];
struct ifreq ifInfo;
SOCKET sock;
if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
{
return (STATUS_BUFFER_TOO_SMALL);
}
if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
{
ERR ("Unable to parse /proc filesystem!\n");
return (-1);
}
/* Get a socket so we can use ioctl */
if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
ERR ("Error creating socket!\n");
return (-1);
}
/* 0 it out first */
memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
/* Interface Id */
baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
/* IP Address */
strcpy (ifInfo.ifr_name, ifName);
ifInfo.ifr_addr.sa_family = AF_INET;
if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0)
{
baseIPInfo->iae_addr = 0x0;
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
}
/* Broadcast Address */
strcpy (ifInfo.ifr_name, ifName);
if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
{
baseIPInfo->iae_bcastaddr = 0x0;
}
else
{
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
}
/* Subnet Mask */
strcpy(ifInfo.ifr_name, ifName);
if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
{
baseIPInfo->iae_mask = 0x0;
}
else
{
/* Trying to avoid some compile problems across platforms.
(Linux, FreeBSD, Solaris...) */
#ifndef ifr_netmask
#ifndef ifr_addr
baseIPInfo->iae_mask = 0;
ERR ("Unable to determine Netmask on your platform!\n");
#else
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
#endif
#else
struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
#endif
}
/* FIXME: How should the below be properly calculated? ******************/
baseIPInfo->iae_reasmsize = 0x0;
baseIPInfo->iae_context = 0x0;
baseIPInfo->iae_pad = 0x0;
/************************************************************************/
/* Calculate size of out buffer */
*pcbResponseInfoLen = sizeof(IPAddrEntry);
closesocket(sock);
break;
}
/* This call returns the routing table.
* No official documentation found, even the name of the command is unknown.
* Work is based on
* http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
* and testings done with winipcfg.exe, route.exe and ipconfig.exe.
* pcommand->toi_entity.tei_instance seems to be the interface number
* but route.exe outputs only the information for the last interface
* if only the routes for the pcommand->toi_entity.tei_instance
* interface are returned. */
case IP_MIB_ROUTETABLE_ENTRY_ID: /* FIXME: not real name. Value is 0x101 */
{
int numRoutes, foundRoutes;
wscntl_routeentry *routeTable, *routePtr; /* route table */
IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
/* Get the number of routes */
numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
if (numRoutes < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
return (-1);
}
if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
{
return (STATUS_BUFFER_TOO_SMALL);
}
/* malloc space for the routeTable */
routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
if (!routeTable)
{
ERR ("couldn't malloc space for routeTable!\n");
}
/* get the route table */
foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
if (foundRoutes < 0)
{
ERR ("Unable to open /proc filesystem to parse the route entrys!\n");
free(routeTable);
return -1;
}
routePtr = routeTable;
/* first 0 out the output buffer */
memset(winRouteTable, 0, *pcbResponseInfoLen);
/* calculate the length of the data in the output buffer */
*pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
for ( ; foundRoutes > 0; foundRoutes--)
{
winRouteTable->ire_addr = routePtr->wre_dest;
winRouteTable->ire_index = routePtr->wre_intf;
winRouteTable->ire_metric = routePtr->wre_metric;
/* winRouteTable->ire_option4 =
winRouteTable->ire_option5 =
winRouteTable->ire_option6 = */
winRouteTable->ire_gw = routePtr->wre_gw;
/* winRouteTable->ire_option8 =
winRouteTable->ire_option9 =
winRouteTable->ire_option10 = */
winRouteTable->ire_mask = routePtr->wre_mask;
/* winRouteTable->ire_option12 = */
winRouteTable++;
routePtr++;
}
free(routeTable);
break;
}
default:
{
FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx, toi_type=0x%lx\n",
pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
pcommand->toi_class, pcommand->toi_type);
return (WSAEOPNOTSUPP);
}
}
break;
}
case WSCNTL_TCPIP_ICMP_ECHO:
{
unsigned int addr = *(unsigned int*)pRequestInfo;
#if 0
int timeout= *(unsigned int*)(inbuf+4);
short x1 = *(unsigned short*)(inbuf+8);
short sendbufsize = *(unsigned short*)(inbuf+10);
char x2 = *(unsigned char*)(inbuf+12);
char ttl = *(unsigned char*)(inbuf+13);
char service = *(unsigned char*)(inbuf+14);
char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
#endif
FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
break;
}
default:
{
FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
return (WSAEOPNOTSUPP);
}
}
return (WSCTL_SUCCESS);
}
/*
Helper function for WsControl - Get count of the number of interfaces
or routes by parsing /proc filesystem.
*/
int WSCNTL_GetEntryCount(const int entrytype)
{
char *filename;
int fd;
char buf[512]; /* Size optimized for a typical workstation */
char *ptr;
int count;
int chrread;
switch (entrytype)
{
case WSCNTL_COUNT_INTERFACES:
{
filename = PROCFS_NETDEV_FILE;
count = -2; /* two haeder lines */
break;
};
case WSCNTL_COUNT_ROUTES:
{
filename = PROCFS_ROUTE_FILE;
count = -1; /* one haeder line */
break;
};
default:
{
return -1;
};
}
/* open /proc filesystem file */
fd = open(filename, O_RDONLY);
if (fd < 0) {
return -1;
}
/* read the file and count the EOL's */
while ((chrread = read(fd, buf, sizeof(buf))) != 0)
{
ptr = buf;
if (chrread < 0)
{
if (errno == EINTR)
{
continue; /* read interupted by a signal, try to read again */
}
else
{
close(fd);
return -1;
}
}
while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr - buf))) > 0)
{
count++;
ptr++;
}
}
close(fd);
return count;
}
/*
Helper function for WsControl - Get name of device from interface number
by parsing /proc filesystem.
*/
int WSCNTL_GetInterfaceName(int intNumber, char *intName)
{
FILE *procfs;
char buf[512]; /* Size doesn't matter, something big */
int i;
/* Open /proc filesystem file for network devices */
procfs = fopen(PROCFS_NETDEV_FILE, "r");
if (!procfs)
{
/* If we can't open the file, return an error */
return (-1);
}
/* Omit first two lines, they are only headers */
fgets(buf, sizeof(buf), procfs);
fgets(buf, sizeof(buf), procfs);
for (i=0; i<intNumber; i++)
{
/* Skip the lines that don't interest us. */
fgets(buf, sizeof(buf), procfs);
}
fgets(buf, sizeof(buf), procfs); /* This is the line we want */
/* Parse out the line, grabbing only the name of the device
to the intName variable
The Line comes in like this: (we only care about the device name)
lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
*/
i=0;
while (isspace(buf[i])) /* Skip initial space(s) */
{
i++;
}
while (buf[i])
{
if (isspace(buf[i]))
{
break;
}
if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
{
/* This interface could be an alias... */
int hold = i;
char *dotname = intName;
*intName++ = buf[i++];
while (isdigit(buf[i]))
{
*intName++ = buf[i++];
}
if (buf[i] != ':')
{
/* ... It wasn't, so back up */
i = hold;
intName = dotname;
}
if (buf[i] == '\0')
{
fclose(procfs);
return(FALSE);
}
i++;
break;
}
*intName++ = buf[i++];
}
*intName++ = '\0';
fclose(procfs);
return(TRUE);
}
/*
Helper function for WsControl - This function returns the bytes (octets) transmitted
and received for the supplied interface number from the /proc fs.
*/
int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
{
FILE *procfs;
char buf[512], result[512]; /* Size doesn't matter, something big */
int i, bufPos, resultPos;
/* Open /proc filesystem file for network devices */
procfs = fopen(PROCFS_NETDEV_FILE, "r");
if (!procfs)
{
/* If we can't open the file, return an error */
return (-1);
}
/* Omit first two lines, they are only headers */
fgets(buf, sizeof(buf), procfs);
fgets(buf, sizeof(buf), procfs);
for (i=0; i<intNumber; i++)
{
/* Skip the lines that don't interest us. */
fgets(buf, sizeof(buf), procfs);
}
fgets(buf, sizeof(buf), procfs); /* This is the line we want */
/* Parse out the line, grabbing the number of bytes transmitted
and received on the interface.
The Line comes in like this: (we care about columns 2 and 10)
lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
*/
/* Start at character 0 in the buffer */
bufPos=0;
/* Skip initial space(s) */
while (isspace(buf[bufPos]))
bufPos++;
/* Skip the name and its trailing spaces (if any) */
while (buf[bufPos])
{
if (isspace(buf[bufPos]))
break;
if (buf[bufPos] == ':') /* Could be an alias */
{
int hold = bufPos;
while(isdigit (buf[bufPos]))
bufPos++;
if (buf[bufPos] != ':')
bufPos = hold;
if (buf[bufPos] == '\0')
{
fclose(procfs);
return(FALSE);
}
bufPos++;
break;
}
bufPos++;
}
while (isspace(buf[bufPos]))
bufPos++;
/* This column (#2) is the number of bytes received. */
resultPos = 0;
while (!isspace(buf[bufPos]))
{
result[resultPos] = buf[bufPos];
result[resultPos+1]='\0';
resultPos++; bufPos++;
}
*recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
/* Skip columns #3 to #9 (Don't need them) */
for (i=0; i<7; i++)
{
while (isspace(buf[bufPos]))
bufPos++;
while (!isspace(buf[bufPos]))
bufPos++;
}
/* This column (#10) is the number of bytes transmitted */
while (isspace(buf[bufPos]))
bufPos++;
resultPos = 0;
while (!isspace(buf[bufPos]))
{
result[resultPos] = buf[bufPos];
result[resultPos+1]='\0';
resultPos++; bufPos++;
}
*transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
fclose(procfs);
return(TRUE);
}
/* Parse the procfs route file and put the datas into routeTable.
* Return value is the number of found routes */
int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable)
{
int nrIntf; /* total number of interfaces */
char buf[256]; /* temporary buffer */
char *ptr; /* pointer to temporary buffer */
FILE *file; /* file handle for procfs route file */
int foundRoutes = 0; /* number of found routes */
typedef struct interface_t {
char intfName[IFNAMSIZ+1]; /* the name of the interface */
int intfNameLen; /* length of interface name */
} interface_t;
interface_t *interface;
int intfNr; /* the interface number */
wscntl_routeentry *routePtr = routeTable;
/* get the number of interfaces */
nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
if (nrIntf < 0)
{
ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
return (-1);
}
/* malloc space for the interface struct array */
interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
if (!routeTable)
{
ERR ("couldn't malloc space for interface!\n");
}
for (intfNr = 0; intfNr < nrIntf; intfNr++) {
if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
{
ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
free(interface);
return (-1);
}
interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
}
/* Open /proc filesystem file for routes */
file = fopen(PROCFS_ROUTE_FILE, "r");
if (!file)
{
/* If we can't open the file, return an error */
free(interface);
return (-1);
}
/* skip the header line */
fgets(buf, sizeof(buf), file);
/* parse the rest of the file and put the matching entrys into routeTable.
Format of procfs route entry:
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
*/
while (fgets(buf, sizeof(buf), file)) {
intfNr = 0;
/* find the interface of the route */
while ((strncmp(buf, interface[intfNr].intfName, interface[intfNr].intfNameLen) != 0)
&& (intfNr < nrIntf))
{
intfNr++;
}
if (intfNr < nrIntf) {
foundRoutes++;
if (foundRoutes > numRoutes) {
/* output buffer is to small */
ERR("buffer to small to fit all routes found into it!\n");
free(interface);
fclose(file);
return -1;
}
ptr = buf;
ptr += interface[intfNr].intfNameLen;
routePtr->wre_intf = intfNr;
routePtr->wre_dest = strtoul(ptr, &ptr, 16); /* destination */
routePtr->wre_gw = strtoul(ptr, &ptr, 16); /* gateway */
strtoul(ptr, &ptr, 16); /* Flags; unused */
strtoul(ptr, &ptr, 16); /* RefCnt; unused */
strtoul(ptr, &ptr, 16); /* Use; unused */
routePtr->wre_metric = strtoul(ptr, &ptr, 16); /* metric */
routePtr->wre_mask = strtoul(ptr, &ptr, 16); /* mask */
/* strtoul(ptr, &ptr, 16); MTU; unused */
/* strtoul(ptr, &ptr, 16); Window; unused */
/* strtoul(ptr, &ptr, 16); IRTT; unused */
routePtr++;
}
else
{
/* this should never happen */
WARN("Skipping route with unknown interface\n");
}
}
free(interface);
fclose(file);
return foundRoutes;
}
/***********************************************************************
* WSARecvEx (WSOCK32.1107)
*
* WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
* except that has an in/out argument call flags that has the value MSG_PARTIAL ored
* into the flags parameter when a partial packet is read. This only applies to
* sockets using the datagram protocol. This method does not seem to be implemented
* correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
* flag when a fragmented packet arrives.
*/
INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
{
FIXME("(WSARecvEx) partial packet return value not set \n");
return recv(s, buf, len, *flags);
}
/***********************************************************************
* s_perror (WSOCK32.1108)
*/
void WINAPI WS_s_perror(LPCSTR message)
{
FIXME("(%s): stub\n",message);
return;
}