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