Documentation fixes.
[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
7
8 /*
9   FIXME: This hack is fixing a problem in WsControl.  When we call socket(),
10          it is supposed to call into ws2_32's WSOCK32_socket.
11          The problem is that socket() is predefined in a linux system header that 
12          we are including, which is different from the WINE definition.
13          (cdecl vs. stdapi)  The result is stack corruption.
14
15          The correct answer to this problem is to make winsock.h not dependent 
16          on system headers, that way all of our functions are defined consistently.
17          Until that happens we need this hack.
18 */
19 #define socket  linux_socket
20 /* */
21
22 #include "config.h"
23
24 #include <string.h>
25 #include <sys/types.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "debugtools.h"
29 #include "winsock2.h"
30 #include "winnt.h"
31 #include "wscontrol.h"
32 #include <ctype.h>
33 #include <sys/ioctl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #ifdef HAVE_SYS_SOCKIO_H
38 # include <sys/sockio.h>
39 #endif
40 #ifdef HAVE_NET_IF_H
41 # include <net/if.h>
42 #endif
43 #include <errno.h>
44
45 #ifdef __NetBSD__
46 #undef if_type
47 #endif
48
49 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
50           discussed above. */
51 #undef socket
52 extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
53 /* */
54
55
56 DEFAULT_DEBUG_CHANNEL(winsock);
57
58
59 /***********************************************************************
60  *      WsControl()
61  *
62  * WsControl seems to be an undocumented Win95 function. A lot of 
63  * discussion about WsControl can be found on the net, e.g.
64  * Subject:      Re: WSOCK32.DLL WsControl Exported Function
65  * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
66  * Date:         1997/08/17
67  *
68  * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
69  * on observing the behaviour of WsControl with an app in 
70  * Windows 98.  It is not fully implemented, and there could
71  * be (are?) errors due to incorrect assumptions made.
72  *
73  *
74  * WsControl returns WSCTL_SUCCESS on success.
75  * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
76  * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
77  *
78  * It doesn't seem to generate errors that can be retrieved by 
79  * WSAGetLastError().
80  *
81  */
82
83 DWORD WINAPI WsControl(DWORD protocoll,
84                        DWORD action,
85                        LPVOID pRequestInfo,
86                        LPDWORD pcbRequestInfoLen,
87                        LPVOID pResponseInfo,
88                        LPDWORD pcbResponseInfoLen) 
89 {
90    /* Get the command structure into a pointer we can use,
91       rather than void */
92    TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
93   
94    TRACE ("   WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
95           pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
96           pcommand->toi_class, pcommand->toi_type );
97   
98
99
100    switch (action) 
101    {
102       case WSCNTL_TCPIP_QUERY_INFO: 
103       {
104          switch (pcommand->toi_id)
105          {
106             /* 
107                ENTITY_LIST_ID seems to get number of adapters in the system.
108                (almost like an index to be used when calling other WsControl options)
109             */
110             case ENTITY_LIST_ID: 
111             {
112                TDIEntityID *baseptr = pResponseInfo;
113                int numInt = 0, i;
114
115                if (pcommand->toi_class != INFO_CLASS_GENERIC &&
116                    pcommand->toi_type != INFO_TYPE_PROVIDER) 
117                { 
118                   FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
119                        pcommand->toi_class, pcommand->toi_type);
120                   return (WSAEOPNOTSUPP); 
121                }
122            
123                numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES); 
124                if (numInt < 0)
125                {
126                   ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
127                   return (-1); 
128                }
129
130                if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) ) 
131                {
132                   return (STATUS_BUFFER_TOO_SMALL);
133                }
134            
135                /* 0 it out first */
136                memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2)); 
137                
138                for (i=0; i<numInt; i++)
139                {
140                   /* tei_instance is an network interface identifier.
141                      I'm not quite sure what the difference is between tei_entity values of 
142                      CL_NL_ENTITY and IF_ENTITY */
143                   baseptr->tei_entity = CL_NL_ENTITY;  baseptr->tei_instance = i; baseptr++;
144                   baseptr->tei_entity = IF_ENTITY;     baseptr->tei_instance = i; baseptr++; 
145                }
146
147                /* Calculate size of out buffer */
148                *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
149             
150                break;
151             }
152           
153           
154             /* ENTITY_TYPE_ID is used to obtain simple information about a 
155                network card, such as MAC Address, description, interface type,
156                number of network addresses, etc. */
157             case ENTITY_TYPE_ID:  /* ALSO: IP_MIB_STATS_ID */
158             {
159                if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER) 
160                {
161                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
162                   {
163                      * ((ULONG *)pResponseInfo) = IF_MIB; 
164
165                      /* Calculate size of out buffer */
166                      *pcbResponseInfoLen = sizeof (ULONG);
167
168                   }
169                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY) 
170                   {
171                      * ((ULONG *)pResponseInfo) = CL_NL_IP;  
172
173                      /* Calculate size of out buffer */
174                      *pcbResponseInfoLen = sizeof (ULONG); 
175                   }
176                }
177                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
178                         pcommand->toi_type == INFO_TYPE_PROVIDER)
179                {
180                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
181                   {
182                      /* In this case, we are requesting specific information about a 
183                         a particular network adapter. (MAC Address, speed, data transmitted/received,
184                         etc.)
185                      */ 
186                      IFEntry *IntInfo = (IFEntry *) pResponseInfo;
187                      char ifName[512];
188                      struct ifreq ifInfo;
189                      SOCKET sock;
190
191                      
192                      if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
193                      {
194                         ERR ("Unable to parse /proc filesystem!\n");
195                         return (-1);
196                      }
197                
198                      /* Get a socket so that we can use ioctl */
199                      if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
200                      {
201                         ERR ("Error creating socket!\n");
202                         return (-1);
203                      }
204                    
205                      /* 0 out return structure first */
206                      memset (IntInfo, 0, sizeof(IFEntry));
207                      
208                      /* Interface ID */
209                      IntInfo->if_index = pcommand->toi_entity.tei_instance;
210                      
211                      /* MAC Address - Let's try to do this in a cross-platform way... */
212                      #if defined(SIOCGIFHWADDR) /* Linux */
213                         strcpy(ifInfo.ifr_name, ifName);
214                         if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
215                         {
216                            ERR ("Error obtaining MAC Address!\n");
217                            closesocket(sock);
218                            return (-1);
219                         }
220                         else
221                         {
222                            /* FIXME: Is it correct to assume size of 6? */
223                            memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
224                            IntInfo->if_physaddrlen=6;
225                         }
226                      #elif defined(SIOCGENADDR) /* Solaris */
227                         if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
228                         {
229                            ERR ("Error obtaining MAC Address!\n");
230                            closesocket(sock);
231                            return (-1);
232                         }
233                         else
234                         {
235                            /* FIXME: Is it correct to assume size of 6? */
236                            memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
237                            IntInfo->if_physaddrlen=6;
238                         }
239                      #else
240                         memset (IntInfo->if_physaddr, 0, 6);
241                         ERR ("Unable to determine MAC Address on your platform!\n");
242                      #endif
243
244                      
245                      /* Interface name and length */
246                      strcpy (IntInfo->if_descr, ifName);
247                      IntInfo->if_descrlen= strlen (IntInfo->if_descr);
248                      
249                      /* Obtain bytes transmitted/received for interface */
250                      if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance, 
251                            &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
252                      {
253                         ERR ("Error obtaining transmit/receive stats for the network interface!\n");
254                         closesocket(sock);
255                         return (-1);
256                      }
257                      
258                      
259                      /* FIXME: How should the below be properly calculated? ******************/
260                      IntInfo->if_type =  0x6; /* Ethernet (?) */
261                      IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
262                      /************************************************************************/
263
264                      closesocket(sock);
265                      *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen; 
266                   }
267                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY) 
268                   {
269                      IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
270                      int numInt, numRoutes;
271                      
272                      /* This case is used to obtain general statistics about the 
273                         network */
274                      
275                      if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
276                      {
277                         return (STATUS_BUFFER_TOO_SMALL);
278                      }
279                      else
280                      {
281                         /* 0 it out first */
282                         memset(infoStruc, 0, sizeof(IPSNMPInfo));
283             
284                         /* Get the number of interfaces */
285                         numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES); 
286                         if (numInt < 0)
287                         {
288                            ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
289                            return (-1); 
290                         }
291                         /* Get the number of routes */
292                         numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES); 
293                         if (numRoutes < 0)
294                         {
295                            ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
296                            return (-1); 
297                         }
298
299                         infoStruc->ipsi_numif           = numInt; /* # of interfaces */
300                         infoStruc->ipsi_numaddr         = numInt; /* # of addresses */
301                         infoStruc->ipsi_numroutes       = numRoutes; /* # of routes */
302
303                         /* FIXME: How should the below be properly calculated? ******************/
304                         infoStruc->ipsi_forwarding      = 0x0;
305                         infoStruc->ipsi_defaultttl      = 0x0;
306                         infoStruc->ipsi_inreceives      = 0x0;
307                         infoStruc->ipsi_inhdrerrors     = 0x0;
308                         infoStruc->ipsi_inaddrerrors    = 0x0;
309                         infoStruc->ipsi_forwdatagrams   = 0x0;
310                         infoStruc->ipsi_inunknownprotos = 0x0;
311                         infoStruc->ipsi_indiscards      = 0x0;
312                         infoStruc->ipsi_indelivers      = 0x0;
313                         infoStruc->ipsi_outrequests     = 0x0;
314                         infoStruc->ipsi_routingdiscards = 0x0;
315                         infoStruc->ipsi_outdiscards     = 0x0;
316                         infoStruc->ipsi_outnoroutes     = 0x0;
317                         infoStruc->ipsi_reasmtimeout    = 0x0;
318                         infoStruc->ipsi_reasmreqds      = 0x0;
319                         infoStruc->ipsi_reasmoks        = 0x0;
320                         infoStruc->ipsi_reasmfails      = 0x0;
321                         infoStruc->ipsi_fragoks         = 0x0;
322                         infoStruc->ipsi_fragfails       = 0x0;
323                         infoStruc->ipsi_fragcreates     = 0x0;
324                         /************************************************************************/
325                       
326                         /* Calculate size of out buffer */
327                         *pcbResponseInfoLen = sizeof(IPSNMPInfo);
328                      }
329                   }
330                }
331                else
332                {
333                   FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
334                        pcommand->toi_class, pcommand->toi_type);
335                   
336                   return (WSAEOPNOTSUPP); 
337                }
338
339                break;
340             }
341
342
343             /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a 
344                particular network adapter */
345             case IP_MIB_ADDRTABLE_ENTRY_ID: 
346             {
347                IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
348                char ifName[IFNAMSIZ+1];
349                struct ifreq ifInfo;
350                SOCKET sock;
351
352                if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
353                {
354                   return (STATUS_BUFFER_TOO_SMALL); 
355                }
356                
357                if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
358                {
359                   ERR ("Unable to parse /proc filesystem!\n");
360                   return (-1);
361                }
362                
363                
364                /* Get a socket so we can use ioctl */
365                if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
366                {
367                   ERR ("Error creating socket!\n");
368                   return (-1);
369                }
370                
371                /* 0 it out first */
372                memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
373                
374                /* Interface Id */
375                baseIPInfo->iae_index     = pcommand->toi_entity.tei_instance;
376                
377                /* IP Address */
378                strcpy (ifInfo.ifr_name, ifName);
379                ifInfo.ifr_addr.sa_family = AF_INET;
380                if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0) 
381                {
382                   baseIPInfo->iae_addr = 0x0;
383                }
384                else
385                {
386                   struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
387                   baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
388                }
389                
390                /* Broadcast Address */
391                strcpy (ifInfo.ifr_name, ifName);
392                if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
393                {
394                   baseIPInfo->iae_bcastaddr = 0x0;
395                }
396                else
397                {
398                   struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
399                   baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr; 
400                }
401
402                /* Subnet Mask */
403                strcpy(ifInfo.ifr_name, ifName);
404                if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
405                {
406                   baseIPInfo->iae_mask = 0x0;
407                }
408                else
409                {
410                   /* Trying to avoid some compile problems across platforms.
411                      (Linux, FreeBSD, Solaris...) */
412                   #ifndef ifr_netmask
413                      #ifndef ifr_addr
414                         baseIPInfo->iae_mask = 0;
415                         ERR ("Unable to determine Netmask on your platform!\n");
416                      #else
417                         struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
418                         baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr; 
419                      #endif
420                   #else  
421                      struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
422                      baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr; 
423                   #endif
424                }
425
426                /* FIXME: How should the below be properly calculated? ******************/
427                baseIPInfo->iae_reasmsize = 0x0;
428                baseIPInfo->iae_context   = 0x0;
429                baseIPInfo->iae_pad       = 0x0;
430                /************************************************************************/
431              
432                /* Calculate size of out buffer */
433                *pcbResponseInfoLen = sizeof(IPAddrEntry);
434                closesocket(sock);
435                break;
436             }
437
438
439             /* This call returns the routing table.
440              * No official documentation found, even the name of the command is unknown.
441              * Work is based on
442              * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
443              * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
444              * pcommand->toi_entity.tei_instance seems to be the interface number
445              * but route.exe outputs only the information for the last interface
446              * if only the routes for the pcommand->toi_entity.tei_instance
447              * interface are returned. */
448             case IP_MIB_ROUTETABLE_ENTRY_ID:    /* FIXME: not real name. Value is 0x101 */
449             {
450                 int numRoutes, foundRoutes;
451                 wscntl_routeentry *routeTable, *routePtr;       /* route table */
452                 
453                 IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
454
455                 /* Get the number of routes */
456                 numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES); 
457                 if (numRoutes < 0)
458                 {
459                     ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
460                     return (-1); 
461                 }
462
463                 if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
464                 {
465                     return (STATUS_BUFFER_TOO_SMALL); 
466                 }
467                 
468                 /* malloc space for the routeTable */
469                 routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
470                 if (!routeTable)
471                 {
472                     ERR ("couldn't malloc space for routeTable!\n");
473                 }
474
475                 /* get the route table */
476                 foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
477                 if (foundRoutes < 0)
478                 {
479                     ERR ("Unable to open /proc filesystem to parse the route entrys!\n");
480                     free(routeTable);
481                     return -1;
482                 }
483                 routePtr = routeTable;
484                     
485                 /* first 0 out the output buffer */
486                 memset(winRouteTable, 0, *pcbResponseInfoLen);
487                
488                 /* calculate the length of the data in the output buffer */
489                 *pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
490                 
491                 for ( ; foundRoutes > 0; foundRoutes--)
492                 {
493                     winRouteTable->ire_addr = routePtr->wre_dest;
494                     winRouteTable->ire_index = routePtr->wre_intf;
495                     winRouteTable->ire_metric = routePtr->wre_metric;
496                     /* winRouteTable->ire_option4 =
497                     winRouteTable->ire_option5 =
498                     winRouteTable->ire_option6 = */
499                     winRouteTable->ire_gw = routePtr->wre_gw;
500                     /* winRouteTable->ire_option8 =
501                     winRouteTable->ire_option9 =
502                     winRouteTable->ire_option10 = */
503                     winRouteTable->ire_mask = routePtr->wre_mask;
504                     /* winRouteTable->ire_option12 = */
505
506                     winRouteTable++;
507                     routePtr++;
508                 }
509                                                     
510                 free(routeTable);
511                 break;
512             }
513             
514
515             default: 
516             {
517                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",
518                        pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance, 
519                        pcommand->toi_class, pcommand->toi_type);
520               
521                return (WSAEOPNOTSUPP); 
522             }
523          }
524       
525          break;
526       }
527     
528       case WSCNTL_TCPIP_ICMP_ECHO:
529       {
530          unsigned int addr = *(unsigned int*)pRequestInfo;
531          #if 0
532             int timeout= *(unsigned int*)(inbuf+4);
533             short x1 = *(unsigned short*)(inbuf+8);
534             short sendbufsize = *(unsigned short*)(inbuf+10);
535             char x2 = *(unsigned char*)(inbuf+12);
536             char ttl = *(unsigned char*)(inbuf+13);
537             char service = *(unsigned char*)(inbuf+14);
538             char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
539          #endif      
540       
541          FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
542          break;
543       }
544
545       default:
546       {
547          FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
548                protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
549       
550          return (WSAEOPNOTSUPP); 
551       }
552    }
553    
554    
555    return (WSCTL_SUCCESS); 
556 }
557
558
559
560 /* 
561   Helper function for WsControl - Get count of the number of interfaces
562   or routes by parsing /proc filesystem.
563 */
564 int WSCNTL_GetEntryCount(const int entrytype)
565 {
566    char *filename;
567    int  fd;
568    char buf[512];  /* Size optimized for a typical workstation */
569    char *ptr;
570    int  count;
571    int  chrread;
572  
573  
574    switch (entrytype)
575    {
576        case WSCNTL_COUNT_INTERFACES:
577        {
578            filename = PROCFS_NETDEV_FILE;
579            count = -2;  /* two haeder lines */
580            break;
581        };
582
583        case WSCNTL_COUNT_ROUTES:
584        {
585            filename = PROCFS_ROUTE_FILE;
586            count = -1;  /* one haeder line */
587            break;
588        };
589
590        default:
591        {
592            return -1;
593        };
594    }
595
596    /* open /proc filesystem file */
597    fd = open(filename, O_RDONLY);
598    if (fd < 0) {
599        return -1;
600    }
601
602    /* read the file and count the EOL's */
603    while ((chrread = read(fd, buf, sizeof(buf))) != 0) 
604    {
605        ptr = buf;
606        if (chrread < 0) 
607        {
608            if (errno == EINTR) 
609            {
610                continue;        /* read interupted by a signal, try to read again */
611            }
612            else
613            {
614                close(fd);
615                return -1;
616            }
617        }
618        while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr -  buf))) > 0)
619        {
620            count++;
621            ptr++;
622        }
623    }
624
625    close(fd);
626    return count;
627 }
628
629
630 /*
631    Helper function for WsControl - Get name of device from interface number
632    by parsing /proc filesystem.
633 */
634 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
635 {
636    FILE *procfs;
637    char buf[512]; /* Size doesn't matter, something big */
638    int  i;
639
640    /* Open /proc filesystem file for network devices */ 
641    procfs = fopen(PROCFS_NETDEV_FILE, "r");
642    if (!procfs) 
643    {
644       /* If we can't open the file, return an error */
645       return (-1);
646    }
647    
648    /* Omit first two lines, they are only headers */
649    fgets(buf, sizeof(buf), procfs);     
650    fgets(buf, sizeof(buf), procfs);
651
652    for (i=0; i<intNumber; i++)
653    {
654       /* Skip the lines that don't interest us. */
655       fgets(buf, sizeof(buf), procfs);
656    }
657    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
658
659    
660    /* Parse out the line, grabbing only the name of the device
661       to the intName variable 
662       
663       The Line comes in like this: (we only care about the device name)
664       lo:   21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
665    */
666    i=0; 
667    while (isspace(buf[i])) /* Skip initial space(s) */
668    {
669       i++;
670    }
671
672    while (buf[i]) 
673    {
674       if (isspace(buf[i]))
675       {
676          break;
677       }
678       
679       if (buf[i] == ':')  /* FIXME: Not sure if this block (alias detection) works properly */
680       {
681          /* This interface could be an alias... */
682          int hold = i;
683          char *dotname = intName;
684          *intName++ = buf[i++];
685          
686          while (isdigit(buf[i]))
687          {
688             *intName++ = buf[i++];
689          }
690          
691          if (buf[i] != ':') 
692          {
693             /* ... It wasn't, so back up */
694             i = hold;
695             intName = dotname;
696          }
697  
698          if (buf[i] == '\0')
699          {
700             fclose(procfs);
701             return(FALSE);
702          }
703          
704          i++;
705          break;
706       }
707       
708       *intName++ = buf[i++];
709    }
710    *intName++ = '\0';
711
712    fclose(procfs);
713    return(TRUE);
714 }
715
716
717 /*
718    Helper function for WsControl - This function returns the bytes (octets) transmitted
719    and received for the supplied interface number from the /proc fs. 
720 */
721 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
722 {
723    FILE *procfs;
724    char buf[512], result[512]; /* Size doesn't matter, something big */
725    int  i, bufPos, resultPos;
726
727    /* Open /proc filesystem file for network devices */ 
728    procfs = fopen(PROCFS_NETDEV_FILE, "r");
729    if (!procfs) 
730    {
731       /* If we can't open the file, return an error */
732       return (-1);
733    }
734    
735    /* Omit first two lines, they are only headers */
736    fgets(buf, sizeof(buf), procfs);     
737    fgets(buf, sizeof(buf), procfs);
738
739    for (i=0; i<intNumber; i++)
740    {
741       /* Skip the lines that don't interest us. */
742       fgets(buf, sizeof(buf), procfs);
743    }
744    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
745
746
747
748    /* Parse out the line, grabbing the number of bytes transmitted
749       and received on the interface.
750       
751       The Line comes in like this: (we care about columns 2 and 10)
752       lo:   21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
753    */
754
755    /* Start at character 0 in the buffer */
756    bufPos=0;
757    
758    /* Skip initial space(s) */ 
759    while (isspace(buf[bufPos])) 
760       bufPos++;
761
762
763    /* Skip the name and its trailing spaces (if any) */
764    while (buf[bufPos]) 
765    {
766       if (isspace(buf[bufPos]))
767          break;
768  
769       if (buf[bufPos] == ':') /* Could be an alias */
770       {
771          int hold = bufPos;
772
773          while(isdigit (buf[bufPos]))
774             bufPos++;
775          if (buf[bufPos] != ':')
776             bufPos = hold;
777          if (buf[bufPos] == '\0')
778          {
779             fclose(procfs);
780             return(FALSE);
781          }
782          
783          bufPos++;
784          break;
785       }
786
787       bufPos++;
788    }
789    while (isspace(buf[bufPos]))
790       bufPos++;
791
792
793    /* This column (#2) is the number of bytes received. */
794    resultPos = 0;
795    while (!isspace(buf[bufPos]))
796    {
797       result[resultPos] = buf[bufPos];
798       result[resultPos+1]='\0';
799       resultPos++; bufPos++;
800    }
801    *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
802
803    
804    /* Skip columns #3 to #9 (Don't need them) */
805    for  (i=0; i<7; i++)
806    {
807       while (isspace(buf[bufPos]))
808          bufPos++;
809       while (!isspace(buf[bufPos])) 
810          bufPos++;
811    }
812
813
814    /* This column (#10) is the number of bytes transmitted */
815    while (isspace(buf[bufPos]))
816        bufPos++;
817
818    resultPos = 0;
819    while (!isspace(buf[bufPos]))
820    {
821       result[resultPos] = buf[bufPos];
822       result[resultPos+1]='\0';
823       resultPos++; bufPos++;
824    }
825    *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
826
827
828    fclose(procfs);
829    return(TRUE);
830 }
831
832
833 /* Parse the procfs route file and put the datas into routeTable.
834  * Return value is the number of found routes */
835 int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable)
836 {
837     int nrIntf;         /* total number of interfaces */
838     char buf[256];      /* temporary buffer */
839     char *ptr;          /* pointer to temporary buffer */
840     FILE *file;         /* file handle for procfs route file */
841     int foundRoutes = 0;        /* number of found routes */
842     typedef struct interface_t {
843         char intfName[IFNAMSIZ+1];      /* the name of the interface */
844         int intfNameLen;        /* length of interface name */
845     } interface_t;
846     interface_t *interface;
847     int intfNr;         /* the interface number */
848
849     wscntl_routeentry *routePtr = routeTable;
850
851     /* get the number of interfaces */
852     nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
853     if (nrIntf < 0)
854     {
855         ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
856         return (-1);
857     }
858
859     /* malloc space for the interface struct array */
860     interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
861     if (!routeTable)
862     {
863         ERR ("couldn't malloc space for interface!\n");
864     }
865
866     for (intfNr = 0; intfNr < nrIntf; intfNr++) {
867         if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
868         {
869             ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
870             free(interface);
871             return (-1);
872         }
873         interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
874     }
875
876     /* Open /proc filesystem file for routes */ 
877     file = fopen(PROCFS_ROUTE_FILE, "r");
878     if (!file) 
879     {
880         /* If we can't open the file, return an error */
881         free(interface);
882         return (-1);
883     }
884     
885     /* skip the header line */
886     fgets(buf, sizeof(buf), file);
887
888     /* parse the rest of the file and put the matching entrys into routeTable.
889        Format of procfs route entry:
890        Iface Destination Gateway Flags RefCnt Use Metric Mask  MTU Window IRTT
891        lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
892     */
893     while (fgets(buf, sizeof(buf), file)) {
894         intfNr = 0;
895         /* find the interface of the route */
896         while ((strncmp(buf, interface[intfNr].intfName, interface[intfNr].intfNameLen) != 0) 
897                 && (intfNr < nrIntf))
898         {
899             intfNr++;
900         }
901         if (intfNr < nrIntf) {
902             foundRoutes++;
903             if (foundRoutes > numRoutes) {
904                 /* output buffer is to small */
905                 ERR("buffer to small to fit all routes found into it!\n");
906                 free(interface);
907                 fclose(file);
908                 return -1;
909             }
910             ptr = buf;
911             ptr += interface[intfNr].intfNameLen;
912             routePtr->wre_intf = intfNr;
913             routePtr->wre_dest = strtoul(ptr, &ptr, 16);        /* destination */
914             routePtr->wre_gw = strtoul(ptr, &ptr, 16);  /* gateway */
915             strtoul(ptr, &ptr, 16);     /* Flags; unused */
916             strtoul(ptr, &ptr, 16);     /* RefCnt; unused */
917             strtoul(ptr, &ptr, 16);     /* Use; unused */
918             routePtr->wre_metric = strtoul(ptr, &ptr, 16);      /* metric */
919             routePtr->wre_mask = strtoul(ptr, &ptr, 16);        /* mask */
920             /* strtoul(ptr, &ptr, 16);  MTU; unused */
921             /* strtoul(ptr, &ptr, 16);  Window; unused */
922             /* strtoul(ptr, &ptr, 16);  IRTT; unused */
923
924             routePtr++;
925         }
926         else
927         {
928             /* this should never happen */
929             WARN("Skipping route with unknown interface\n");
930         }
931     }
932
933     free(interface);
934     fclose(file);
935     return foundRoutes;
936 }
937
938
939 /***********************************************************************
940  *              WSARecvEx                       (WSOCK32.1107)
941  *
942  * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
943  * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
944  * into the flags parameter when a partial packet is read. This only applies to
945  * sockets using the datagram protocol. This method does not seem to be implemented
946  * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
947  * flag when a fragmented packet arrives.
948  */
949 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
950 {
951     FIXME("(WSARecvEx) partial packet return value not set \n");
952     return recv(s, buf, len, *flags);
953 }
954
955
956 /***********************************************************************
957  *       s_perror         (WSOCK32.1108)
958  */
959 void WINAPI WS_s_perror(LPCSTR message)
960 {
961     FIXME("(%s): stub\n",message);
962     return;
963 }