Added include protection for unistd.h and sys/time.h.
[wine/multimedia.git] / dlls / wsock32 / socket.c
blob611151dd9318e16838dda075b781743662c6c02c
1 /*
2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* FIXME: This hack is fixing a problem in WsControl. When we call socket(),
23 * it will call into ws2_32's WSOCK32_socket (because of the redirection in
24 * our own .spec file).
25 * The problem is that socket() is predefined in a linux system header that
26 * we are including, which is different from the WINE definition.
27 * (cdecl vs. stdapi). The result is stack corruption.
28 * Furthermore WsControl uses Unix macros and types. This forces us to include
29 * the Unix headers which then conflict with the winsock headers. This forces
30 * us to use USE_WS_PREFIX but then ioctlsocket is called WS_ioctlsocket,
31 * which causes link problems. The correct solution is to implement
32 * WsControl using calls to WSAIoctl. Then we should no longer need to use the
33 * Unix headers. This would also have the advantage of reducing code
34 * duplication.
35 * Until that happens we need this ugly hack.
37 #define USE_WS_PREFIX
39 #define socket linux_socket
40 #define recv linux_recv
41 /* */
43 #include "config.h"
45 #include <errno.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <fcntl.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_SYS_IOCTL_H
55 # include <sys/ioctl.h>
56 #endif
58 #include <sys/types.h>
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
61 #endif
62 #ifdef HAVE_SYS_SOCKIO_H
63 # include <sys/sockio.h>
64 #endif
65 #ifdef HAVE_NET_IF_H
66 # include <net/if.h>
67 #endif
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wine/debug.h"
72 #include "winsock2.h"
73 #include "winnt.h"
74 #include "wscontrol.h"
76 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
77 * discussed above.
79 #undef socket
80 #undef recv
81 extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
82 extern SOCKET WINAPI recv(SOCKET,char*,int,int);
83 /* Plus some missing prototypes, due to the WS_ prefixing */
84 extern int WINAPI closesocket(SOCKET);
85 extern int WINAPI ioctlsocket(SOCKET,long,u_long*);
86 /* */
89 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
92 /***********************************************************************
93 * WsControl (WSOCK32.1001)
95 * WsControl seems to be an undocumented Win95 function. A lot of
96 * discussion about WsControl can be found on the net, e.g.
97 * Subject: Re: WSOCK32.DLL WsControl Exported Function
98 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
99 * Date: 1997/08/17
101 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
102 * on observing the behaviour of WsControl with an app in
103 * Windows 98. It is not fully implemented, and there could
104 * be (are?) errors due to incorrect assumptions made.
107 * WsControl returns WSCTL_SUCCESS on success.
108 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
109 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
111 * It doesn't seem to generate errors that can be retrieved by
112 * WSAGetLastError().
116 DWORD WINAPI WsControl(DWORD protocoll,
117 DWORD action,
118 LPVOID pRequestInfo,
119 LPDWORD pcbRequestInfoLen,
120 LPVOID pResponseInfo,
121 LPDWORD pcbResponseInfoLen)
123 /* Get the command structure into a pointer we can use,
124 rather than void */
125 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
127 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
128 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
129 pcommand->toi_class, pcommand->toi_type );
133 switch (action)
135 case WSCNTL_TCPIP_QUERY_INFO:
137 switch (pcommand->toi_id)
140 ENTITY_LIST_ID seems to get number of adapters in the system.
141 (almost like an index to be used when calling other WsControl options)
143 case ENTITY_LIST_ID:
145 TDIEntityID *baseptr = pResponseInfo;
146 int numInt = 0, i;
148 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
149 pcommand->toi_type != INFO_TYPE_PROVIDER)
151 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
152 pcommand->toi_class, pcommand->toi_type);
153 return (WSAEOPNOTSUPP);
156 numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
157 if (numInt < 0)
159 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
160 return (-1);
163 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
165 return (STATUS_BUFFER_TOO_SMALL);
168 /* 0 it out first */
169 memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
171 for (i=0; i<numInt; i++)
173 /* tei_instance is an network interface identifier.
174 I'm not quite sure what the difference is between tei_entity values of
175 CL_NL_ENTITY and IF_ENTITY */
176 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
177 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
180 /* Calculate size of out buffer */
181 *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
183 break;
187 /* ENTITY_TYPE_ID is used to obtain simple information about a
188 network card, such as MAC Address, description, interface type,
189 number of network addresses, etc. */
190 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
192 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
194 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
196 * ((ULONG *)pResponseInfo) = IF_MIB;
198 /* Calculate size of out buffer */
199 *pcbResponseInfoLen = sizeof (ULONG);
202 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
204 * ((ULONG *)pResponseInfo) = CL_NL_IP;
206 /* Calculate size of out buffer */
207 *pcbResponseInfoLen = sizeof (ULONG);
210 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
211 pcommand->toi_type == INFO_TYPE_PROVIDER)
213 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
215 /* In this case, we are requesting specific information about a
216 a particular network adapter. (MAC Address, speed, data transmitted/received,
217 etc.)
219 IFEntry *IntInfo = (IFEntry *) pResponseInfo;
220 char ifName[512];
221 #if defined(SIOCGIFHWADDR) || defined(SIOCGENADDR)
222 struct ifreq ifInfo;
223 #endif
224 SOCKET sock;
227 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
229 ERR ("Unable to parse /proc filesystem!\n");
230 return (-1);
233 /* Get a socket so that we can use ioctl */
234 if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
236 ERR ("Error creating socket!\n");
237 return (-1);
240 /* 0 out return structure first */
241 memset (IntInfo, 0, sizeof(IFEntry));
243 /* Interface ID */
244 IntInfo->if_index = pcommand->toi_entity.tei_instance;
246 /* MAC Address - Let's try to do this in a cross-platform way... */
247 #if defined(SIOCGIFHWADDR) /* Linux */
248 strcpy(ifInfo.ifr_name, ifName);
249 if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
251 ERR ("Error obtaining MAC Address!\n");
252 closesocket(sock);
253 return (-1);
255 else
257 /* FIXME: Is it correct to assume size of 6? */
258 memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
259 IntInfo->if_physaddrlen=6;
261 #elif defined(SIOCGENADDR) /* Solaris */
262 if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
264 ERR ("Error obtaining MAC Address!\n");
265 closesocket(sock);
266 return (-1);
268 else
270 /* FIXME: Is it correct to assume size of 6? */
271 memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
272 IntInfo->if_physaddrlen=6;
274 #else
275 memset (IntInfo->if_physaddr, 0, 6);
276 ERR ("Unable to determine MAC Address on your platform!\n");
277 #endif
280 /* Interface name and length */
281 strcpy (IntInfo->if_descr, ifName);
282 IntInfo->if_descrlen= strlen (IntInfo->if_descr);
284 /* Obtain bytes transmitted/received for interface */
285 if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
286 &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
288 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
289 closesocket(sock);
290 return (-1);
294 /* FIXME: How should the below be properly calculated? ******************/
295 IntInfo->if_type = 0x6; /* Ethernet (?) */
296 IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
297 /************************************************************************/
299 closesocket(sock);
300 *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
302 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
304 IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
305 int numInt, numRoutes;
307 /* This case is used to obtain general statistics about the
308 network */
310 if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
312 return (STATUS_BUFFER_TOO_SMALL);
314 else
316 /* 0 it out first */
317 memset(infoStruc, 0, sizeof(IPSNMPInfo));
319 /* Get the number of interfaces */
320 numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
321 if (numInt < 0)
323 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
324 return (-1);
326 /* Get the number of routes */
327 numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
328 if (numRoutes < 0)
330 ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
331 return (-1);
334 infoStruc->ipsi_numif = numInt; /* # of interfaces */
335 infoStruc->ipsi_numaddr = numInt; /* # of addresses */
336 infoStruc->ipsi_numroutes = numRoutes; /* # of routes */
338 /* FIXME: How should the below be properly calculated? ******************/
339 infoStruc->ipsi_forwarding = 0x0;
340 infoStruc->ipsi_defaultttl = 0x0;
341 infoStruc->ipsi_inreceives = 0x0;
342 infoStruc->ipsi_inhdrerrors = 0x0;
343 infoStruc->ipsi_inaddrerrors = 0x0;
344 infoStruc->ipsi_forwdatagrams = 0x0;
345 infoStruc->ipsi_inunknownprotos = 0x0;
346 infoStruc->ipsi_indiscards = 0x0;
347 infoStruc->ipsi_indelivers = 0x0;
348 infoStruc->ipsi_outrequests = 0x0;
349 infoStruc->ipsi_routingdiscards = 0x0;
350 infoStruc->ipsi_outdiscards = 0x0;
351 infoStruc->ipsi_outnoroutes = 0x0;
352 infoStruc->ipsi_reasmtimeout = 0x0;
353 infoStruc->ipsi_reasmreqds = 0x0;
354 infoStruc->ipsi_reasmoks = 0x0;
355 infoStruc->ipsi_reasmfails = 0x0;
356 infoStruc->ipsi_fragoks = 0x0;
357 infoStruc->ipsi_fragfails = 0x0;
358 infoStruc->ipsi_fragcreates = 0x0;
359 /************************************************************************/
361 /* Calculate size of out buffer */
362 *pcbResponseInfoLen = sizeof(IPSNMPInfo);
366 else
368 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
369 pcommand->toi_class, pcommand->toi_type);
371 return (WSAEOPNOTSUPP);
374 break;
378 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
379 particular network adapter */
380 case IP_MIB_ADDRTABLE_ENTRY_ID:
382 IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
383 char ifName[IFNAMSIZ+1];
384 struct ifreq ifInfo;
385 SOCKET sock;
387 if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
389 return (STATUS_BUFFER_TOO_SMALL);
392 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
394 ERR ("Unable to parse /proc filesystem!\n");
395 return (-1);
399 /* Get a socket so we can use ioctl */
400 if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
402 ERR ("Error creating socket!\n");
403 return (-1);
406 /* 0 it out first */
407 memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
409 /* Interface Id */
410 baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
412 /* IP Address */
413 strcpy (ifInfo.ifr_name, ifName);
414 ifInfo.ifr_addr.sa_family = AF_INET;
415 if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0)
417 baseIPInfo->iae_addr = 0x0;
419 else
421 struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_addr;
422 baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
425 /* Broadcast Address */
426 strcpy (ifInfo.ifr_name, ifName);
427 if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
429 baseIPInfo->iae_bcastaddr = 0x0;
431 else
433 struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_broadaddr;
434 baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
437 /* Subnet Mask */
438 strcpy(ifInfo.ifr_name, ifName);
439 if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
441 baseIPInfo->iae_mask = 0x0;
443 else
445 /* Trying to avoid some compile problems across platforms.
446 (Linux, FreeBSD, Solaris...) */
447 #ifndef ifr_netmask
448 #ifndef ifr_addr
449 baseIPInfo->iae_mask = 0;
450 ERR ("Unable to determine Netmask on your platform!\n");
451 #else
452 struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_addr;
453 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
454 #endif
455 #else
456 struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_netmask;
457 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
458 #endif
461 /* FIXME: How should the below be properly calculated? ******************/
462 baseIPInfo->iae_reasmsize = 0x0;
463 baseIPInfo->iae_context = 0x0;
464 baseIPInfo->iae_pad = 0x0;
465 /************************************************************************/
467 /* Calculate size of out buffer */
468 *pcbResponseInfoLen = sizeof(IPAddrEntry);
469 closesocket(sock);
470 break;
474 /* This call returns the routing table.
475 * No official documentation found, even the name of the command is unknown.
476 * Work is based on
477 * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
478 * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
479 * pcommand->toi_entity.tei_instance seems to be the interface number
480 * but route.exe outputs only the information for the last interface
481 * if only the routes for the pcommand->toi_entity.tei_instance
482 * interface are returned. */
483 case IP_MIB_ROUTETABLE_ENTRY_ID: /* FIXME: not real name. Value is 0x101 */
485 int numRoutes, foundRoutes;
486 wscntl_routeentry *routeTable, *routePtr; /* route table */
488 IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
490 /* Get the number of routes */
491 numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
492 if (numRoutes < 0)
494 ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
495 return (-1);
498 if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
500 return (STATUS_BUFFER_TOO_SMALL);
503 /* malloc space for the routeTable */
504 routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
505 if (!routeTable)
507 ERR ("couldn't malloc space for routeTable!\n");
510 /* get the route table */
511 foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
512 if (foundRoutes < 0)
514 ERR ("Unable to open /proc filesystem to parse the route entries!\n");
515 free(routeTable);
516 return -1;
518 routePtr = routeTable;
520 /* first 0 out the output buffer */
521 memset(winRouteTable, 0, *pcbResponseInfoLen);
523 /* calculate the length of the data in the output buffer */
524 *pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
526 for ( ; foundRoutes > 0; foundRoutes--)
528 winRouteTable->ire_addr = routePtr->wre_dest;
529 winRouteTable->ire_index = routePtr->wre_intf;
530 winRouteTable->ire_metric = routePtr->wre_metric;
531 /* winRouteTable->ire_option4 =
532 winRouteTable->ire_option5 =
533 winRouteTable->ire_option6 = */
534 winRouteTable->ire_gw = routePtr->wre_gw;
535 /* winRouteTable->ire_option8 =
536 winRouteTable->ire_option9 =
537 winRouteTable->ire_option10 = */
538 winRouteTable->ire_mask = routePtr->wre_mask;
539 /* winRouteTable->ire_option12 = */
541 winRouteTable++;
542 routePtr++;
545 free(routeTable);
546 break;
550 default:
552 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",
553 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
554 pcommand->toi_class, pcommand->toi_type);
556 return (WSAEOPNOTSUPP);
560 break;
563 case WSCNTL_TCPIP_ICMP_ECHO:
565 unsigned int addr = *(unsigned int*)pRequestInfo;
566 #if 0
567 int timeout= *(unsigned int*)(inbuf+4);
568 short x1 = *(unsigned short*)(inbuf+8);
569 short sendbufsize = *(unsigned short*)(inbuf+10);
570 char x2 = *(unsigned char*)(inbuf+12);
571 char ttl = *(unsigned char*)(inbuf+13);
572 char service = *(unsigned char*)(inbuf+14);
573 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
574 #endif
576 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
577 break;
580 default:
582 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
583 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
585 return (WSAEOPNOTSUPP);
590 return (WSCTL_SUCCESS);
596 Helper function for WsControl - Get count of the number of interfaces
597 or routes by parsing /proc filesystem.
599 int WSCNTL_GetEntryCount(const int entrytype)
601 char *filename;
602 int fd;
603 char buf[512]; /* Size optimized for a typical workstation */
604 char *ptr;
605 int count;
606 int chrread;
609 switch (entrytype)
611 case WSCNTL_COUNT_INTERFACES:
613 filename = PROCFS_NETDEV_FILE;
614 count = -2; /* two haeder lines */
615 break;
618 case WSCNTL_COUNT_ROUTES:
620 filename = PROCFS_ROUTE_FILE;
621 count = -1; /* one haeder line */
622 break;
625 default:
627 return -1;
631 /* open /proc filesystem file */
632 fd = open(filename, O_RDONLY);
633 if (fd < 0) {
634 return -1;
637 /* read the file and count the EOL's */
638 while ((chrread = read(fd, buf, sizeof(buf))) != 0)
640 ptr = buf;
641 if (chrread < 0)
643 if (errno == EINTR)
645 continue; /* read interupted by a signal, try to read again */
647 else
649 close(fd);
650 return -1;
653 while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr - buf))) > 0)
655 count++;
656 ptr++;
660 close(fd);
661 return count;
666 Helper function for WsControl - Get name of device from interface number
667 by parsing /proc filesystem.
669 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
671 FILE *procfs;
672 char buf[512]; /* Size doesn't matter, something big */
673 int i;
675 /* Open /proc filesystem file for network devices */
676 procfs = fopen(PROCFS_NETDEV_FILE, "r");
677 if (!procfs)
679 /* If we can't open the file, return an error */
680 return (-1);
683 /* Omit first two lines, they are only headers */
684 fgets(buf, sizeof(buf), procfs);
685 fgets(buf, sizeof(buf), procfs);
687 for (i=0; i<intNumber; i++)
689 /* Skip the lines that don't interest us. */
690 fgets(buf, sizeof(buf), procfs);
692 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
695 /* Parse out the line, grabbing only the name of the device
696 to the intName variable
698 The Line comes in like this: (we only care about the device name)
699 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
701 i=0;
702 while (isspace(buf[i])) /* Skip initial space(s) */
704 i++;
707 while (buf[i])
709 if (isspace(buf[i]))
711 break;
714 if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
716 /* This interface could be an alias... */
717 int hold = i;
718 char *dotname = intName;
719 *intName++ = buf[i++];
721 while (isdigit(buf[i]))
723 *intName++ = buf[i++];
726 if (buf[i] != ':')
728 /* ... It wasn't, so back up */
729 i = hold;
730 intName = dotname;
733 if (buf[i] == '\0')
735 fclose(procfs);
736 return(FALSE);
739 i++;
740 break;
743 *intName++ = buf[i++];
745 *intName++ = '\0';
747 fclose(procfs);
748 return(TRUE);
753 Helper function for WsControl - This function returns the bytes (octets) transmitted
754 and received for the supplied interface number from the /proc fs.
756 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
758 FILE *procfs;
759 char buf[512], result[512]; /* Size doesn't matter, something big */
760 int i, bufPos, resultPos;
762 /* Open /proc filesystem file for network devices */
763 procfs = fopen(PROCFS_NETDEV_FILE, "r");
764 if (!procfs)
766 /* If we can't open the file, return an error */
767 return (-1);
770 /* Omit first two lines, they are only headers */
771 fgets(buf, sizeof(buf), procfs);
772 fgets(buf, sizeof(buf), procfs);
774 for (i=0; i<intNumber; i++)
776 /* Skip the lines that don't interest us. */
777 fgets(buf, sizeof(buf), procfs);
779 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
783 /* Parse out the line, grabbing the number of bytes transmitted
784 and received on the interface.
786 The Line comes in like this: (we care about columns 2 and 10)
787 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
790 /* Start at character 0 in the buffer */
791 bufPos=0;
793 /* Skip initial space(s) */
794 while (isspace(buf[bufPos]))
795 bufPos++;
798 /* Skip the name and its trailing spaces (if any) */
799 while (buf[bufPos])
801 if (isspace(buf[bufPos]))
802 break;
804 if (buf[bufPos] == ':') /* Could be an alias */
806 int hold = bufPos;
808 while(isdigit (buf[bufPos]))
809 bufPos++;
810 if (buf[bufPos] != ':')
811 bufPos = hold;
812 if (buf[bufPos] == '\0')
814 fclose(procfs);
815 return(FALSE);
818 bufPos++;
819 break;
822 bufPos++;
824 while (isspace(buf[bufPos]))
825 bufPos++;
828 /* This column (#2) is the number of bytes received. */
829 resultPos = 0;
830 while (!isspace(buf[bufPos]))
832 result[resultPos] = buf[bufPos];
833 result[resultPos+1]='\0';
834 resultPos++; bufPos++;
836 *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
839 /* Skip columns #3 to #9 (Don't need them) */
840 for (i=0; i<7; i++)
842 while (isspace(buf[bufPos]))
843 bufPos++;
844 while (!isspace(buf[bufPos]))
845 bufPos++;
849 /* This column (#10) is the number of bytes transmitted */
850 while (isspace(buf[bufPos]))
851 bufPos++;
853 resultPos = 0;
854 while (!isspace(buf[bufPos]))
856 result[resultPos] = buf[bufPos];
857 result[resultPos+1]='\0';
858 resultPos++; bufPos++;
860 *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
863 fclose(procfs);
864 return(TRUE);
868 /* Parse the procfs route file and put the datas into routeTable.
869 * Return value is the number of found routes */
870 int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable)
872 int nrIntf; /* total number of interfaces */
873 char buf[256]; /* temporary buffer */
874 char *ptr; /* pointer to temporary buffer */
875 FILE *file; /* file handle for procfs route file */
876 int foundRoutes = 0; /* number of found routes */
877 typedef struct interface_t {
878 char intfName[IFNAMSIZ+1]; /* the name of the interface */
879 int intfNameLen; /* length of interface name */
880 } interface_t;
881 interface_t *interface;
882 int intfNr; /* the interface number */
884 wscntl_routeentry *routePtr = routeTable;
886 /* get the number of interfaces */
887 nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
888 if (nrIntf < 0)
890 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
891 return (-1);
894 /* malloc space for the interface struct array */
895 interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
896 if (!routeTable)
898 ERR ("couldn't malloc space for interface!\n");
901 for (intfNr = 0; intfNr < nrIntf; intfNr++) {
902 if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
904 ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
905 free(interface);
906 return (-1);
908 interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
911 /* Open /proc filesystem file for routes */
912 file = fopen(PROCFS_ROUTE_FILE, "r");
913 if (!file)
915 /* If we can't open the file, return an error */
916 free(interface);
917 return (-1);
920 /* skip the header line */
921 fgets(buf, sizeof(buf), file);
923 /* parse the rest of the file and put the matching entries into routeTable.
924 Format of procfs route entry:
925 Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
926 lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
928 while (fgets(buf, sizeof(buf), file)) {
929 intfNr = 0;
930 /* find the interface of the route */
931 while ((strncmp(buf, interface[intfNr].intfName, interface[intfNr].intfNameLen) != 0)
932 && (intfNr < nrIntf))
934 intfNr++;
936 if (intfNr < nrIntf) {
937 foundRoutes++;
938 if (foundRoutes > numRoutes) {
939 /* output buffer is to small */
940 ERR("buffer to small to fit all routes found into it!\n");
941 free(interface);
942 fclose(file);
943 return -1;
945 ptr = buf;
946 ptr += interface[intfNr].intfNameLen;
947 routePtr->wre_intf = intfNr;
948 routePtr->wre_dest = strtoul(ptr, &ptr, 16); /* destination */
949 routePtr->wre_gw = strtoul(ptr, &ptr, 16); /* gateway */
950 strtoul(ptr, &ptr, 16); /* Flags; unused */
951 strtoul(ptr, &ptr, 16); /* RefCnt; unused */
952 strtoul(ptr, &ptr, 16); /* Use; unused */
953 routePtr->wre_metric = strtoul(ptr, &ptr, 16); /* metric */
954 routePtr->wre_mask = strtoul(ptr, &ptr, 16); /* mask */
955 /* strtoul(ptr, &ptr, 16); MTU; unused */
956 /* strtoul(ptr, &ptr, 16); Window; unused */
957 /* strtoul(ptr, &ptr, 16); IRTT; unused */
959 routePtr++;
961 else
963 /* this should never happen */
964 WARN("Skipping route with unknown interface\n");
968 free(interface);
969 fclose(file);
970 return foundRoutes;
974 /***********************************************************************
975 * WSARecvEx (WSOCK32.1107)
977 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
978 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
979 * into the flags parameter when a partial packet is read. This only applies to
980 * sockets using the datagram protocol. This method does not seem to be implemented
981 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
982 * flag when a fragmented packet arrives.
984 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
986 FIXME("(WSARecvEx) partial packet return value not set \n");
987 return recv(s, buf, len, *flags);
991 /***********************************************************************
992 * s_perror (WSOCK32.1108)
994 void WINAPI s_perror(LPCSTR message)
996 FIXME("(%s): stub\n",message);
997 return;