Misc fixes in LISTVIEW_SetImageList, LISTVIEW_SetItemCount,
[wine.git] / dlls / wsock32 / socket.c
blob843b863d0098baf84901e898d1e220f0a991af47
1 /*
2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5 */
8 /*
9 FIXME: This hack is fixing a problem in WsControl. When we call socket(),
10 it is supposed to call into ws2_32's WSOCK32_socket.
11 The problem is that socket() is predefined in a linux system header that
12 we are including, which is different from the WINE definition.
13 (cdecl vs. stdapi) The result is stack corruption.
15 The correct answer to this problem is to make winsock.h not dependent
16 on system headers, that way all of our functions are defined consistently.
17 Until that happens we need this hack.
19 #define socket linux_socket
20 /* */
22 #include "config.h"
24 #include <sys/types.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "debugtools.h"
28 #include "winsock2.h"
29 #include "winnt.h"
30 #include "wscontrol.h"
31 #include <ctype.h>
32 #include <sys/ioctl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #ifdef HAVE_SYS_SOCKIO_H
37 # include <sys/sockio.h>
38 #endif
39 #ifdef HAVE_NET_IF_H
40 # include <net/if.h>
41 #endif
44 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
45 discussed above. */
46 #undef socket
47 extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
48 /* */
51 DEFAULT_DEBUG_CHANNEL(winsock);
54 /***********************************************************************
55 * WsControl()
57 * WsControl seems to be an undocumented Win95 function. A lot of
58 * discussion about WsControl can be found on the net, e.g.
59 * Subject: Re: WSOCK32.DLL WsControl Exported Function
60 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
61 * Date: 1997/08/17
63 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
64 * on observing the behaviour of WsControl with an app in
65 * Windows 98. It is not fully implemented, and there could
66 * be (are?) errors due to incorrect assumptions made.
69 * WsControl returns WSCTL_SUCCESS on success.
70 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
71 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
73 * It doesn't seem to generate errors that can be retrieved by
74 * WSAGetLastError().
78 DWORD WINAPI WsControl(DWORD protocoll,
79 DWORD action,
80 LPVOID pRequestInfo,
81 LPDWORD pcbRequestInfoLen,
82 LPVOID pResponseInfo,
83 LPDWORD pcbResponseInfoLen)
85 /* Get the command structure into a pointer we can use,
86 rather than void */
87 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
89 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
90 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
91 pcommand->toi_class, pcommand->toi_type );
95 switch (action)
97 case WSCNTL_TCPIP_QUERY_INFO:
99 switch (pcommand->toi_id)
102 ENTITY_LIST_ID seems to get number of adapters in the system.
103 (almost like an index to be used when calling other WsControl options)
105 case ENTITY_LIST_ID:
107 TDIEntityID *baseptr = pResponseInfo;
108 int numInt = 0, i;
110 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
111 pcommand->toi_type != INFO_TYPE_PROVIDER)
113 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
114 pcommand->toi_class, pcommand->toi_type);
115 return (WSAEOPNOTSUPP);
118 numInt = WSCNTL_GetInterfaceCount();
119 if (numInt < 0)
121 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
122 return (-1);
125 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
127 return (STATUS_BUFFER_TOO_SMALL);
130 /* 0 it out first */
131 memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
133 for (i=0; i<numInt; i++)
135 /* tei_instance is an network interface identifier.
136 I'm not quite sure what the difference is between tei_entity values of
137 CL_NL_ENTITY and IF_ENTITY */
138 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
139 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
142 /* Calculate size of out buffer */
143 *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
145 break;
149 /* ENTITY_TYPE_ID is used to obtain simple information about a
150 network card, such as MAC Address, description, interface type,
151 number of network addresses, etc. */
152 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
154 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
156 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
158 * ((ULONG *)pResponseInfo) = IF_MIB;
160 /* Calculate size of out buffer */
161 *pcbResponseInfoLen = sizeof (ULONG);
164 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
166 * ((ULONG *)pResponseInfo) = CL_NL_IP;
168 /* Calculate size of out buffer */
169 *pcbResponseInfoLen = sizeof (ULONG);
172 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
173 pcommand->toi_type == INFO_TYPE_PROVIDER)
175 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
177 /* In this case, we are requesting specific information about a
178 a particular network adapter. (MAC Address, speed, data transmitted/received,
179 etc.)
181 IFEntry *IntInfo = (IFEntry *) pResponseInfo;
182 char ifName[512];
183 struct ifreq ifInfo;
184 SOCKET sock;
187 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
189 ERR ("Unable to parse /proc filesystem!\n");
190 return (-1);
193 /* Get a socket so that we can use ioctl */
194 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
196 ERR ("Error creating socket!\n");
197 return (-1);
200 /* 0 out return structure first */
201 memset (IntInfo, 0, sizeof(IFEntry));
203 /* Interface ID */
204 IntInfo->if_index = pcommand->toi_entity.tei_instance;
206 /* MAC Address - Let's try to do this in a cross-platform way... */
207 #if defined(SIOCGIFHWADDR) /* Linux */
208 strcpy(ifInfo.ifr_name, ifName);
209 if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
211 ERR ("Error obtaining MAC Address!\n");
212 closesocket(sock);
213 return (-1);
215 else
217 /* FIXME: Is it correct to assume size of 6? */
218 memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
219 IntInfo->if_physaddrlen=6;
221 #elif defined(SIOCGENADDR) /* Solaris */
222 if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
224 ERR ("Error obtaining MAC Address!\n");
225 closesocket(sock);
226 return (-1);
228 else
230 /* FIXME: Is it correct to assume size of 6? */
231 memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
232 IntInfo->if_physaddrlen=6;
234 #else
235 memset (IntInfo->if_physaddr, 0, 6);
236 ERR ("Unable to determine MAC Address on your platform!\n");
237 #endif
240 /* Interface name and length */
241 strcpy (IntInfo->if_descr, ifName);
242 IntInfo->if_descrlen= strlen (IntInfo->if_descr);
244 /* Obtain bytes transmitted/received for interface */
245 if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
246 &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
248 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
249 closesocket(sock);
250 return (-1);
254 /* FIXME: How should the below be properly calculated? ******************/
255 IntInfo->if_type = 0x6; /* Ethernet (?) */
256 IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
257 /************************************************************************/
259 closesocket(sock);
260 *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
262 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
264 IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
265 int numInt;
267 /* This case is used to obtain general statistics about the
268 network */
270 if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
272 return (STATUS_BUFFER_TOO_SMALL);
274 else
276 /* 0 it out first */
277 memset(infoStruc, 0, sizeof(IPSNMPInfo));
279 /* Get the number of interfaces */
280 numInt = WSCNTL_GetInterfaceCount();
281 if (numInt < 0)
283 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
284 return (-1);
287 infoStruc->ipsi_numif = numInt; /* # of interfaces */
288 infoStruc->ipsi_numaddr = numInt; /* # of addresses */
289 infoStruc->ipsi_numroutes = numInt; /* # of routes ~ FIXME - Is this right? */
291 /* FIXME: How should the below be properly calculated? ******************/
292 infoStruc->ipsi_forwarding = 0x0;
293 infoStruc->ipsi_defaultttl = 0x0;
294 infoStruc->ipsi_inreceives = 0x0;
295 infoStruc->ipsi_inhdrerrors = 0x0;
296 infoStruc->ipsi_inaddrerrors = 0x0;
297 infoStruc->ipsi_forwdatagrams = 0x0;
298 infoStruc->ipsi_inunknownprotos = 0x0;
299 infoStruc->ipsi_indiscards = 0x0;
300 infoStruc->ipsi_indelivers = 0x0;
301 infoStruc->ipsi_outrequests = 0x0;
302 infoStruc->ipsi_routingdiscards = 0x0;
303 infoStruc->ipsi_outdiscards = 0x0;
304 infoStruc->ipsi_outnoroutes = 0x0;
305 infoStruc->ipsi_reasmtimeout = 0x0;
306 infoStruc->ipsi_reasmreqds = 0x0;
307 infoStruc->ipsi_reasmoks = 0x0;
308 infoStruc->ipsi_reasmfails = 0x0;
309 infoStruc->ipsi_fragoks = 0x0;
310 infoStruc->ipsi_fragfails = 0x0;
311 infoStruc->ipsi_fragcreates = 0x0;
312 /************************************************************************/
314 /* Calculate size of out buffer */
315 *pcbResponseInfoLen = sizeof(IPSNMPInfo);
319 else
321 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
322 pcommand->toi_class, pcommand->toi_type);
324 return (WSAEOPNOTSUPP);
327 break;
331 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
332 particular network adapter */
333 case IP_MIB_ADDRTABLE_ENTRY_ID:
335 IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
336 char ifName[512];
337 struct ifreq ifInfo;
338 SOCKET sock;
340 if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
342 return (STATUS_BUFFER_TOO_SMALL);
345 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
347 ERR ("Unable to parse /proc filesystem!\n");
348 return (-1);
352 /* Get a socket so we can use ioctl */
353 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
355 ERR ("Error creating socket!\n");
356 return (-1);
359 /* 0 it out first */
360 memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
362 /* Interface Id */
363 baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
365 /* IP Address */
366 strcpy (ifInfo.ifr_name, ifName);
367 ifInfo.ifr_addr.sa_family = AF_INET;
368 if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0)
370 baseIPInfo->iae_addr = 0x0;
372 else
374 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
375 baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
378 /* Broadcast Address */
379 strcpy (ifInfo.ifr_name, ifName);
380 if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
382 baseIPInfo->iae_bcastaddr = 0x0;
384 else
386 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
387 baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
390 /* Subnet Mask */
391 strcpy(ifInfo.ifr_name, ifName);
392 if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
394 baseIPInfo->iae_mask = 0x0;
396 else
398 /* Trying to avoid some compile problems across platforms.
399 (Linux, FreeBSD, Solaris...) */
400 #ifndef ifr_netmask
401 #ifndef ifr_addr
402 baseIPInfo->iae_mask = 0;
403 ERR ("Unable to determine Netmask on your platform!\n");
404 #else
405 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
406 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
407 #endif
408 #else
409 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
410 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
411 #endif
414 /* FIXME: How should the below be properly calculated? ******************/
415 baseIPInfo->iae_reasmsize = 0x0;
416 baseIPInfo->iae_context = 0x0;
417 baseIPInfo->iae_pad = 0x0;
418 /************************************************************************/
420 /* Calculate size of out buffer */
421 *pcbResponseInfoLen = sizeof(IPAddrEntry);
422 closesocket(sock);
423 break;
426 case 0x101:
427 FIXME ("Command ID Unknown but used by winipcfg.exe\n");
428 break;
431 default:
433 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",
434 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
435 pcommand->toi_class, pcommand->toi_type);
437 return (WSAEOPNOTSUPP);
441 break;
444 case WSCNTL_TCPIP_ICMP_ECHO:
446 unsigned int addr = *(unsigned int*)pRequestInfo;
447 #if 0
448 int timeout= *(unsigned int*)(inbuf+4);
449 short x1 = *(unsigned short*)(inbuf+8);
450 short sendbufsize = *(unsigned short*)(inbuf+10);
451 char x2 = *(unsigned char*)(inbuf+12);
452 char ttl = *(unsigned char*)(inbuf+13);
453 char service = *(unsigned char*)(inbuf+14);
454 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
455 #endif
457 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
458 break;
461 default:
463 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
464 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
466 return (WSAEOPNOTSUPP);
471 return (WSCTL_SUCCESS);
477 Helper function for WsControl - Get count of the number of interfaces
478 by parsing /proc filesystem.
480 int WSCNTL_GetInterfaceCount(void)
482 FILE *procfs;
483 char buf[512]; /* Size doesn't matter, something big */
484 int intcnt=0;
487 /* Open /proc filesystem file for network devices */
488 procfs = fopen(PROCFS_NETDEV_FILE, "r");
489 if (!procfs)
491 /* If we can't open the file, return an error */
492 return (-1);
495 /* Omit first two lines, they are only headers */
496 fgets(buf, sizeof buf, procfs);
497 fgets(buf, sizeof buf, procfs);
499 while (fgets(buf, sizeof buf, procfs))
501 /* Each line in the file represents a network interface */
502 intcnt++;
505 fclose(procfs);
506 return(intcnt);
511 Helper function for WsControl - Get name of device from interface number
512 by parsing /proc filesystem.
514 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
516 FILE *procfs;
517 char buf[512]; /* Size doesn't matter, something big */
518 int i;
520 /* Open /proc filesystem file for network devices */
521 procfs = fopen(PROCFS_NETDEV_FILE, "r");
522 if (!procfs)
524 /* If we can't open the file, return an error */
525 return (-1);
528 /* Omit first two lines, they are only headers */
529 fgets(buf, sizeof(buf), procfs);
530 fgets(buf, sizeof(buf), procfs);
532 for (i=0; i<intNumber; i++)
534 /* Skip the lines that don't interest us. */
535 fgets(buf, sizeof(buf), procfs);
537 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
540 /* Parse out the line, grabbing only the name of the device
541 to the intName variable
543 The Line comes in like this: (we only care about the device name)
544 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
546 i=0;
547 while (isspace(buf[i])) /* Skip initial space(s) */
549 i++;
552 while (buf[i])
554 if (isspace(buf[i]))
556 break;
559 if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
561 /* This interface could be an alias... */
562 int hold = i;
563 char *dotname = intName;
564 *intName++ = buf[i++];
566 while (isdigit(buf[i]))
568 *intName++ = buf[i++];
571 if (buf[i] != ':')
573 /* ... It wasn't, so back up */
574 i = hold;
575 intName = dotname;
578 if (buf[i] == '\0')
580 fclose(procfs);
581 return(FALSE);
584 i++;
585 break;
588 *intName++ = buf[i++];
590 *intName++ = '\0';
592 fclose(procfs);
593 return(TRUE);
598 Helper function for WsControl - This function returns the bytes (octets) transmitted
599 and received for the supplied interface number from the /proc fs.
601 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
603 FILE *procfs;
604 char buf[512], result[512]; /* Size doesn't matter, something big */
605 int i, bufPos, resultPos;
607 /* Open /proc filesystem file for network devices */
608 procfs = fopen(PROCFS_NETDEV_FILE, "r");
609 if (!procfs)
611 /* If we can't open the file, return an error */
612 return (-1);
615 /* Omit first two lines, they are only headers */
616 fgets(buf, sizeof(buf), procfs);
617 fgets(buf, sizeof(buf), procfs);
619 for (i=0; i<intNumber; i++)
621 /* Skip the lines that don't interest us. */
622 fgets(buf, sizeof(buf), procfs);
624 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
628 /* Parse out the line, grabbing the number of bytes transmitted
629 and received on the interface.
631 The Line comes in like this: (we care about columns 2 and 10)
632 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
635 /* Start at character 0 in the buffer */
636 bufPos=0;
638 /* Skip initial space(s) */
639 while (isspace(buf[bufPos]))
640 bufPos++;
643 /* Skip the name and its trailing spaces (if any) */
644 while (buf[bufPos])
646 if (isspace(buf[bufPos]))
647 break;
649 if (buf[bufPos] == ':') /* Could be an alias */
651 int hold = bufPos;
653 while(isdigit (buf[bufPos]))
654 bufPos++;
655 if (buf[bufPos] != ':')
656 bufPos = hold;
657 if (buf[bufPos] == '\0')
659 fclose(procfs);
660 return(FALSE);
663 bufPos++;
664 break;
667 bufPos++;
669 while (isspace(buf[bufPos]))
670 bufPos++;
673 /* This column (#2) is the number of bytes received. */
674 resultPos = 0;
675 while (!isspace(buf[bufPos]))
677 result[resultPos] = buf[bufPos];
678 result[resultPos+1]='\0';
679 resultPos++; bufPos++;
681 *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
684 /* Skip columns #3 to #9 (Don't need them) */
685 for (i=0; i<7; i++)
687 while (isspace(buf[bufPos]))
688 bufPos++;
689 while (!isspace(buf[bufPos]))
690 bufPos++;
694 /* This column (#10) is the number of bytes transmitted */
695 while (isspace(buf[bufPos]))
696 bufPos++;
698 resultPos = 0;
699 while (!isspace(buf[bufPos]))
701 result[resultPos] = buf[bufPos];
702 result[resultPos+1]='\0';
703 resultPos++; bufPos++;
705 *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
708 fclose(procfs);
709 return(TRUE);
713 /***********************************************************************
714 * WSARecvEx() (WSOCK32.1107)
716 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
717 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
718 * into the flags parameter when a partial packet is read. This only applies to
719 * sockets using the datagram protocol. This method does not seem to be implemented
720 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
721 * flag when a fragmented packet arrives.
723 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
725 FIXME("(WSARecvEx) partial packet return value not set \n");
726 return recv(s, buf, len, *flags);
730 /***********************************************************************
731 * WS_s_perror (WSOCK32.1108)
733 void WINAPI WS_s_perror(LPCSTR message)
735 FIXME("(%s): stub\n",message);
736 return;