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