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