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