Fixed some issues found by winapi_check.
[wine] / dlls / wsock32 / socket.c
1 /*
2  * WSOCK32 specific functions
3  *
4  * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5  *
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.
10  *
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.
15  *
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
19  */
20
21
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.
36  */
37 #define USE_WS_PREFIX
38
39 #define socket  linux_socket
40 #define recv    linux_recv
41 /* */
42
43 #include "config.h"
44
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
57
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
68
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"
75
76 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
77  * discussed above.
78  */
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 /* */
87
88
89 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
90
91
92 /***********************************************************************
93  *              WsControl (WSOCK32.1001)
94  *
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
100  *
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.
105  *
106  *
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.
110  *
111  * It doesn't seem to generate errors that can be retrieved by
112  * WSAGetLastError().
113  *
114  */
115
116 DWORD WINAPI WsControl(DWORD protocoll,
117                        DWORD action,
118                        LPVOID pRequestInfo,
119                        LPDWORD pcbRequestInfoLen,
120                        LPVOID pResponseInfo,
121                        LPDWORD pcbResponseInfoLen)
122 {
123    /* Get the command structure into a pointer we can use,
124       rather than void */
125    TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
126
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 );
130
131
132
133    switch (action)
134    {
135       case WSCNTL_TCPIP_QUERY_INFO:
136       {
137          switch (pcommand->toi_id)
138          {
139             /*
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)
142             */
143             case ENTITY_LIST_ID:
144             {
145                TDIEntityID *baseptr = pResponseInfo;
146                int numInt = 0, i;
147
148                if (pcommand->toi_class != INFO_CLASS_GENERIC &&
149                    pcommand->toi_type != INFO_TYPE_PROVIDER)
150                {
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);
154                }
155
156                numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
157                if (numInt < 0)
158                {
159                   ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
160                   return (-1);
161                }
162
163                if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
164                {
165                   return (STATUS_BUFFER_TOO_SMALL);
166                }
167
168                /* 0 it out first */
169                memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
170
171                for (i=0; i<numInt; i++)
172                {
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++;
178                }
179
180                /* Calculate size of out buffer */
181                *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
182
183                break;
184             }
185
186
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 */
191             {
192                if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
193                {
194                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
195                   {
196                      * ((ULONG *)pResponseInfo) = IF_MIB;
197
198                      /* Calculate size of out buffer */
199                      *pcbResponseInfoLen = sizeof (ULONG);
200
201                   }
202                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
203                   {
204                      * ((ULONG *)pResponseInfo) = CL_NL_IP;
205
206                      /* Calculate size of out buffer */
207                      *pcbResponseInfoLen = sizeof (ULONG);
208                   }
209                }
210                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
211                         pcommand->toi_type == INFO_TYPE_PROVIDER)
212                {
213                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
214                   {
215                      /* In this case, we are requesting specific information about a
216                         a particular network adapter. (MAC Address, speed, data transmitted/received,
217                         etc.)
218                      */
219                      IFEntry *IntInfo = (IFEntry *) pResponseInfo;
220                      char ifName[512];
221 #if defined(SIOCGIFHWADDR) || defined(SIOCGENADDR)
222                      struct ifreq ifInfo;
223 #endif
224                      SOCKET sock;
225
226
227                      if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
228                      {
229                         ERR ("Unable to parse /proc filesystem!\n");
230                         return (-1);
231                      }
232
233                      /* Get a socket so that we can use ioctl */
234                      if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
235                      {
236                         ERR ("Error creating socket!\n");
237                         return (-1);
238                      }
239
240                      /* 0 out return structure first */
241                      memset (IntInfo, 0, sizeof(IFEntry));
242
243                      /* Interface ID */
244                      IntInfo->if_index = pcommand->toi_entity.tei_instance;
245
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)
250                         {
251                            ERR ("Error obtaining MAC Address!\n");
252                            closesocket(sock);
253                            return (-1);
254                         }
255                         else
256                         {
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;
260                         }
261 #elif defined(SIOCGENADDR) /* Solaris */
262                         if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
263                         {
264                            ERR ("Error obtaining MAC Address!\n");
265                            closesocket(sock);
266                            return (-1);
267                         }
268                         else
269                         {
270                            /* FIXME: Is it correct to assume size of 6? */
271                            memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
272                            IntInfo->if_physaddrlen=6;
273                         }
274 #else
275                         memset (IntInfo->if_physaddr, 0, 6);
276                         ERR ("Unable to determine MAC Address on your platform!\n");
277 #endif
278
279
280                      /* Interface name and length */
281                      strcpy (IntInfo->if_descr, ifName);
282                      IntInfo->if_descrlen= strlen (IntInfo->if_descr);
283
284                      /* Obtain bytes transmitted/received for interface */
285                      if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
286                            &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
287                      {
288                         ERR ("Error obtaining transmit/receive stats for the network interface!\n");
289                         closesocket(sock);
290                         return (-1);
291                      }
292
293
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                      /************************************************************************/
298
299                      closesocket(sock);
300                      *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
301                   }
302                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
303                   {
304                      IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
305                      int numInt, numRoutes;
306
307                      /* This case is used to obtain general statistics about the
308                         network */
309
310                      if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
311                      {
312                         return (STATUS_BUFFER_TOO_SMALL);
313                      }
314                      else
315                      {
316                         /* 0 it out first */
317                         memset(infoStruc, 0, sizeof(IPSNMPInfo));
318
319                         /* Get the number of interfaces */
320                         numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
321                         if (numInt < 0)
322                         {
323                            ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
324                            return (-1);
325                         }
326                         /* Get the number of routes */
327                         numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
328                         if (numRoutes < 0)
329                         {
330                            ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
331                            return (-1);
332                         }
333
334                         infoStruc->ipsi_numif           = numInt; /* # of interfaces */
335                         infoStruc->ipsi_numaddr         = numInt; /* # of addresses */
336                         infoStruc->ipsi_numroutes       = numRoutes; /* # of routes */
337
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                         /************************************************************************/
360
361                         /* Calculate size of out buffer */
362                         *pcbResponseInfoLen = sizeof(IPSNMPInfo);
363                      }
364                   }
365                }
366                else
367                {
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);
370
371                   return (WSAEOPNOTSUPP);
372                }
373
374                break;
375             }
376
377
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:
381             {
382                IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
383                char ifName[IFNAMSIZ+1];
384                struct ifreq ifInfo;
385                SOCKET sock;
386
387                if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
388                {
389                   return (STATUS_BUFFER_TOO_SMALL);
390                }
391
392                if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
393                {
394                   ERR ("Unable to parse /proc filesystem!\n");
395                   return (-1);
396                }
397
398
399                /* Get a socket so we can use ioctl */
400                if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
401                {
402                   ERR ("Error creating socket!\n");
403                   return (-1);
404                }
405
406                /* 0 it out first */
407                memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
408
409                /* Interface Id */
410                baseIPInfo->iae_index     = pcommand->toi_entity.tei_instance;
411
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)
416                {
417                   baseIPInfo->iae_addr = 0x0;
418                }
419                else
420                {
421                   struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_addr;
422                   baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
423                }
424
425                /* Broadcast Address */
426                strcpy (ifInfo.ifr_name, ifName);
427                if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
428                {
429                   baseIPInfo->iae_bcastaddr = 0x0;
430                }
431                else
432                {
433                   struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_broadaddr;
434                   baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
435                }
436
437                /* Subnet Mask */
438                strcpy(ifInfo.ifr_name, ifName);
439                if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
440                {
441                   baseIPInfo->iae_mask = 0x0;
442                }
443                else
444                {
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
459                }
460
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                /************************************************************************/
466
467                /* Calculate size of out buffer */
468                *pcbResponseInfoLen = sizeof(IPAddrEntry);
469                closesocket(sock);
470                break;
471             }
472
473
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 */
484             {
485                 int numRoutes, foundRoutes;
486                 wscntl_routeentry *routeTable, *routePtr;       /* route table */
487
488                 IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
489
490                 /* Get the number of routes */
491                 numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
492                 if (numRoutes < 0)
493                 {
494                     ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
495                     return (-1);
496                 }
497
498                 if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
499                 {
500                     return (STATUS_BUFFER_TOO_SMALL);
501                 }
502
503                 /* malloc space for the routeTable */
504                 routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
505                 if (!routeTable)
506                 {
507                     ERR ("couldn't malloc space for routeTable!\n");
508                 }
509
510                 /* get the route table */
511                 foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
512                 if (foundRoutes < 0)
513                 {
514                     ERR ("Unable to open /proc filesystem to parse the route entries!\n");
515                     free(routeTable);
516                     return -1;
517                 }
518                 routePtr = routeTable;
519
520                 /* first 0 out the output buffer */
521                 memset(winRouteTable, 0, *pcbResponseInfoLen);
522
523                 /* calculate the length of the data in the output buffer */
524                 *pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
525
526                 for ( ; foundRoutes > 0; foundRoutes--)
527                 {
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 = */
540
541                     winRouteTable++;
542                     routePtr++;
543                 }
544
545                 free(routeTable);
546                 break;
547             }
548
549
550             default:
551             {
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);
555
556                return (WSAEOPNOTSUPP);
557             }
558          }
559
560          break;
561       }
562
563       case WSCNTL_TCPIP_ICMP_ECHO:
564       {
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
575
576          FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
577          break;
578       }
579
580       default:
581       {
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);
584
585          return (WSAEOPNOTSUPP);
586       }
587    }
588
589
590    return (WSCTL_SUCCESS);
591 }
592
593
594
595 /*
596   Helper function for WsControl - Get count of the number of interfaces
597   or routes by parsing /proc filesystem.
598 */
599 int WSCNTL_GetEntryCount(const int entrytype)
600 {
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;
607
608
609    switch (entrytype)
610    {
611        case WSCNTL_COUNT_INTERFACES:
612        {
613            filename = PROCFS_NETDEV_FILE;
614            count = -2;  /* two haeder lines */
615            break;
616        };
617
618        case WSCNTL_COUNT_ROUTES:
619        {
620            filename = PROCFS_ROUTE_FILE;
621            count = -1;  /* one haeder line */
622            break;
623        };
624
625        default:
626        {
627            return -1;
628        };
629    }
630
631    /* open /proc filesystem file */
632    fd = open(filename, O_RDONLY);
633    if (fd < 0) {
634        return -1;
635    }
636
637    /* read the file and count the EOL's */
638    while ((chrread = read(fd, buf, sizeof(buf))) != 0)
639    {
640        ptr = buf;
641        if (chrread < 0)
642        {
643            if (errno == EINTR)
644            {
645                continue;        /* read interupted by a signal, try to read again */
646            }
647            else
648            {
649                close(fd);
650                return -1;
651            }
652        }
653        while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr -  buf))) > 0)
654        {
655            count++;
656            ptr++;
657        }
658    }
659
660    close(fd);
661    return count;
662 }
663
664
665 /*
666    Helper function for WsControl - Get name of device from interface number
667    by parsing /proc filesystem.
668 */
669 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
670 {
671    FILE *procfs;
672    char buf[512]; /* Size doesn't matter, something big */
673    int  i;
674
675    /* Open /proc filesystem file for network devices */
676    procfs = fopen(PROCFS_NETDEV_FILE, "r");
677    if (!procfs)
678    {
679       /* If we can't open the file, return an error */
680       return (-1);
681    }
682
683    /* Omit first two lines, they are only headers */
684    fgets(buf, sizeof(buf), procfs);
685    fgets(buf, sizeof(buf), procfs);
686
687    for (i=0; i<intNumber; i++)
688    {
689       /* Skip the lines that don't interest us. */
690       fgets(buf, sizeof(buf), procfs);
691    }
692    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
693
694
695    /* Parse out the line, grabbing only the name of the device
696       to the intName variable
697
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
700    */
701    i=0;
702    while (isspace(buf[i])) /* Skip initial space(s) */
703    {
704       i++;
705    }
706
707    while (buf[i])
708    {
709       if (isspace(buf[i]))
710       {
711          break;
712       }
713
714       if (buf[i] == ':')  /* FIXME: Not sure if this block (alias detection) works properly */
715       {
716          /* This interface could be an alias... */
717          int hold = i;
718          char *dotname = intName;
719          *intName++ = buf[i++];
720
721          while (isdigit(buf[i]))
722          {
723             *intName++ = buf[i++];
724          }
725
726          if (buf[i] != ':')
727          {
728             /* ... It wasn't, so back up */
729             i = hold;
730             intName = dotname;
731          }
732
733          if (buf[i] == '\0')
734          {
735             fclose(procfs);
736             return(FALSE);
737          }
738
739          i++;
740          break;
741       }
742
743       *intName++ = buf[i++];
744    }
745    *intName++ = '\0';
746
747    fclose(procfs);
748    return(TRUE);
749 }
750
751
752 /*
753    Helper function for WsControl - This function returns the bytes (octets) transmitted
754    and received for the supplied interface number from the /proc fs.
755 */
756 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
757 {
758    FILE *procfs;
759    char buf[512], result[512]; /* Size doesn't matter, something big */
760    int  i, bufPos, resultPos;
761
762    /* Open /proc filesystem file for network devices */
763    procfs = fopen(PROCFS_NETDEV_FILE, "r");
764    if (!procfs)
765    {
766       /* If we can't open the file, return an error */
767       return (-1);
768    }
769
770    /* Omit first two lines, they are only headers */
771    fgets(buf, sizeof(buf), procfs);
772    fgets(buf, sizeof(buf), procfs);
773
774    for (i=0; i<intNumber; i++)
775    {
776       /* Skip the lines that don't interest us. */
777       fgets(buf, sizeof(buf), procfs);
778    }
779    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
780
781
782
783    /* Parse out the line, grabbing the number of bytes transmitted
784       and received on the interface.
785
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
788    */
789
790    /* Start at character 0 in the buffer */
791    bufPos=0;
792
793    /* Skip initial space(s) */
794    while (isspace(buf[bufPos]))
795       bufPos++;
796
797
798    /* Skip the name and its trailing spaces (if any) */
799    while (buf[bufPos])
800    {
801       if (isspace(buf[bufPos]))
802          break;
803
804       if (buf[bufPos] == ':') /* Could be an alias */
805       {
806          int hold = bufPos;
807
808          while(isdigit (buf[bufPos]))
809             bufPos++;
810          if (buf[bufPos] != ':')
811             bufPos = hold;
812          if (buf[bufPos] == '\0')
813          {
814             fclose(procfs);
815             return(FALSE);
816          }
817
818          bufPos++;
819          break;
820       }
821
822       bufPos++;
823    }
824    while (isspace(buf[bufPos]))
825       bufPos++;
826
827
828    /* This column (#2) is the number of bytes received. */
829    resultPos = 0;
830    while (!isspace(buf[bufPos]))
831    {
832       result[resultPos] = buf[bufPos];
833       result[resultPos+1]='\0';
834       resultPos++; bufPos++;
835    }
836    *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
837
838
839    /* Skip columns #3 to #9 (Don't need them) */
840    for  (i=0; i<7; i++)
841    {
842       while (isspace(buf[bufPos]))
843          bufPos++;
844       while (!isspace(buf[bufPos]))
845          bufPos++;
846    }
847
848
849    /* This column (#10) is the number of bytes transmitted */
850    while (isspace(buf[bufPos]))
851        bufPos++;
852
853    resultPos = 0;
854    while (!isspace(buf[bufPos]))
855    {
856       result[resultPos] = buf[bufPos];
857       result[resultPos+1]='\0';
858       resultPos++; bufPos++;
859    }
860    *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
861
862
863    fclose(procfs);
864    return(TRUE);
865 }
866
867
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)
871 {
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 */
883
884     wscntl_routeentry *routePtr = routeTable;
885
886     /* get the number of interfaces */
887     nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
888     if (nrIntf < 0)
889     {
890         ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
891         return (-1);
892     }
893
894     /* malloc space for the interface struct array */
895     interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
896     if (!routeTable)
897     {
898         ERR ("couldn't malloc space for interface!\n");
899     }
900
901     for (intfNr = 0; intfNr < nrIntf; intfNr++) {
902         if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
903         {
904             ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
905             free(interface);
906             return (-1);
907         }
908         interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
909     }
910
911     /* Open /proc filesystem file for routes */
912     file = fopen(PROCFS_ROUTE_FILE, "r");
913     if (!file)
914     {
915         /* If we can't open the file, return an error */
916         free(interface);
917         return (-1);
918     }
919
920     /* skip the header line */
921     fgets(buf, sizeof(buf), file);
922
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
927     */
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))
933         {
934             intfNr++;
935         }
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;
944             }
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 */
958
959             routePtr++;
960         }
961         else
962         {
963             /* this should never happen */
964             WARN("Skipping route with unknown interface\n");
965         }
966     }
967
968     free(interface);
969     fclose(file);
970     return foundRoutes;
971 }
972
973
974 /***********************************************************************
975  *              WSARecvEx                       (WSOCK32.1107)
976  *
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.
983  */
984 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
985 {
986     FIXME("(WSARecvEx) partial packet return value not set \n");
987     return recv(s, buf, len, *flags);
988 }
989
990
991 /***********************************************************************
992  *       s_perror         (WSOCK32.1108)
993  */
994 void WINAPI s_perror(LPCSTR message)
995 {
996     FIXME("(%s): stub\n",message);
997     return;
998 }