Finished separation of shell32 and wsock32.
[wine/multimedia.git] / dlls / wsock32 / socket.c
blob3ed74ee5d42e92fa88e3c3a6d2e59b7c483a4b5d
1 /*
2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5 */
7 #include "config.h"
9 #include <sys/types.h>
10 #include "windef.h"
11 #include "winbase.h"
12 #include "debugtools.h"
13 #include "winsock2.h"
14 #include "winnt.h"
15 #include "wscontrol.h"
16 #include <ctype.h>
17 #include <sys/ioctl.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #ifdef HAVE_SYS_SOCKIO_H
22 # include <sys/sockio.h>
23 #endif
24 #ifdef HAVE_NET_IF_H
25 # include <net/if.h>
26 #endif
28 DEFAULT_DEBUG_CHANNEL(winsock);
30 static INT (WINAPI *WS2_recv)(SOCKET s, char *buf, INT len, INT flags);
32 /***********************************************************************
33 * WsControl()
35 * WsControl seems to be an undocumented Win95 function. A lot of
36 * discussion about WsControl can be found on the net, e.g.
37 * Subject: Re: WSOCK32.DLL WsControl Exported Function
38 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
39 * Date: 1997/08/17
41 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
42 * on observing the behaviour of WsControl with an app in
43 * Windows 98. It is not fully implemented, and there could
44 * be (are?) errors due to incorrect assumptions made.
47 * WsControl returns WSCTL_SUCCESS on success.
48 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
49 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
51 * It doesn't seem to generate errors that can be retrieved by
52 * WSAGetLastError().
56 DWORD WINAPI WsControl(DWORD protocoll,
57 DWORD action,
58 LPVOID pRequestInfo,
59 LPDWORD pcbRequestInfoLen,
60 LPVOID pResponseInfo,
61 LPDWORD pcbResponseInfoLen)
63 /* Get the command structure into a pointer we can use,
64 rather than void */
65 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
67 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
68 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
69 pcommand->toi_class, pcommand->toi_type );
73 switch (action)
75 case WSCNTL_TCPIP_QUERY_INFO:
77 switch (pcommand->toi_id)
79 /*
80 ENTITY_LIST_ID seems to get number of adapters in the system.
81 (almost like an index to be used when calling other WsControl options)
83 case ENTITY_LIST_ID:
85 TDIEntityID *baseptr = pResponseInfo;
86 int numInt = 0, i;
88 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
89 pcommand->toi_type != INFO_TYPE_PROVIDER)
91 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
92 pcommand->toi_class, pcommand->toi_type);
93 return (WSAEOPNOTSUPP);
96 numInt = WSCNTL_GetInterfaceCount();
97 if (numInt < 0)
99 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
100 return (-1);
103 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
105 return (STATUS_BUFFER_TOO_SMALL);
108 /* 0 it out first */
109 memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
111 for (i=0; i<numInt; i++)
113 /* tei_instance is an network interface identifier.
114 I'm not quite sure what the difference is between tei_entity values of
115 CL_NL_ENTITY and IF_ENTITY */
116 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = i; baseptr++;
117 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = i; baseptr++;
120 /* Calculate size of out buffer */
121 *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
123 break;
127 /* ENTITY_TYPE_ID is used to obtain simple information about a
128 network card, such as MAC Address, description, interface type,
129 number of network addresses, etc. */
130 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
132 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
134 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
136 * ((ULONG *)pResponseInfo) = IF_MIB;
138 /* Calculate size of out buffer */
139 *pcbResponseInfoLen = sizeof (ULONG);
142 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
144 * ((ULONG *)pResponseInfo) = CL_NL_IP;
146 /* Calculate size of out buffer */
147 *pcbResponseInfoLen = sizeof (ULONG);
150 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
151 pcommand->toi_type == INFO_TYPE_PROVIDER)
153 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
155 /* In this case, we are requesting specific information about a
156 a particular network adapter. (MAC Address, speed, data transmitted/received,
157 etc.)
159 IFEntry *IntInfo = (IFEntry *) pResponseInfo;
160 char ifName[512];
161 struct ifreq ifInfo;
162 int sock;
165 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
167 ERR ("Unable to parse /proc filesystem!\n");
168 return (-1);
171 /* Get a socket so that we can use ioctl */
172 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
174 ERR ("Error creating socket!\n");
175 return (-1);
178 /* 0 out return structure first */
179 memset (IntInfo, 0, sizeof(IFEntry));
181 /* Interface ID */
182 IntInfo->if_index = pcommand->toi_entity.tei_instance;
184 /* MAC Address - Let's try to do this in a cross-platform way... */
185 #if defined(SIOCGIFHWADDR) /* Linux */
186 strcpy(ifInfo.ifr_name, ifName);
187 if (ioctl(sock, SIOCGIFHWADDR, &ifInfo) < 0)
189 ERR ("Error obtaining MAC Address!\n");
190 close(sock);
191 return (-1);
193 else
195 /* FIXME: Is it correct to assume size of 6? */
196 memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
197 IntInfo->if_physaddrlen=6;
199 #elif defined(SIOCGENADDR) /* Solaris */
200 if (ioctl(sock, SIOCGENADDR, &ifInfo) < 0)
202 ERR ("Error obtaining MAC Address!\n");
203 close(sock);
204 return (-1);
206 else
208 /* FIXME: Is it correct to assume size of 6? */
209 memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
210 IntInfo->if_physaddrlen=6;
212 #else
213 memset (IntInfo->if_physaddr, 0, 6);
214 ERR ("Unable to determine MAC Address on your platform!\n");
215 #endif
218 /* Interface name and length */
219 strcpy (IntInfo->if_descr, ifName);
220 IntInfo->if_descrlen= strlen (IntInfo->if_descr);
222 /* Obtain bytes transmitted/received for interface */
223 if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
224 &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
226 ERR ("Error obtaining transmit/receive stats for the network interface!\n");
227 close(sock);
228 return (-1);
232 /* FIXME: How should the below be properly calculated? ******************/
233 IntInfo->if_type = 0x6; /* Ethernet (?) */
234 IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
235 /************************************************************************/
237 close(sock);
238 *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
240 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
242 IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
243 int numInt;
245 /* This case is used to obtain general statistics about the
246 network */
248 if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
250 return (STATUS_BUFFER_TOO_SMALL);
252 else
254 /* 0 it out first */
255 memset(infoStruc, 0, sizeof(IPSNMPInfo));
257 /* Get the number of interfaces */
258 numInt = WSCNTL_GetInterfaceCount();
259 if (numInt < 0)
261 ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
262 return (-1);
265 infoStruc->ipsi_numif = numInt; /* # of interfaces */
266 infoStruc->ipsi_numaddr = numInt; /* # of addresses */
267 infoStruc->ipsi_numroutes = numInt; /* # of routes ~ FIXME - Is this right? */
269 /* FIXME: How should the below be properly calculated? ******************/
270 infoStruc->ipsi_forwarding = 0x0;
271 infoStruc->ipsi_defaultttl = 0x0;
272 infoStruc->ipsi_inreceives = 0x0;
273 infoStruc->ipsi_inhdrerrors = 0x0;
274 infoStruc->ipsi_inaddrerrors = 0x0;
275 infoStruc->ipsi_forwdatagrams = 0x0;
276 infoStruc->ipsi_inunknownprotos = 0x0;
277 infoStruc->ipsi_indiscards = 0x0;
278 infoStruc->ipsi_indelivers = 0x0;
279 infoStruc->ipsi_outrequests = 0x0;
280 infoStruc->ipsi_routingdiscards = 0x0;
281 infoStruc->ipsi_outdiscards = 0x0;
282 infoStruc->ipsi_outnoroutes = 0x0;
283 infoStruc->ipsi_reasmtimeout = 0x0;
284 infoStruc->ipsi_reasmreqds = 0x0;
285 infoStruc->ipsi_reasmoks = 0x0;
286 infoStruc->ipsi_reasmfails = 0x0;
287 infoStruc->ipsi_fragoks = 0x0;
288 infoStruc->ipsi_fragfails = 0x0;
289 infoStruc->ipsi_fragcreates = 0x0;
290 /************************************************************************/
292 /* Calculate size of out buffer */
293 *pcbResponseInfoLen = sizeof(IPSNMPInfo);
297 else
299 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
300 pcommand->toi_class, pcommand->toi_type);
302 return (WSAEOPNOTSUPP);
305 break;
309 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
310 particular network adapter */
311 case IP_MIB_ADDRTABLE_ENTRY_ID:
313 IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
314 char ifName[512];
315 struct ifreq ifInfo;
316 int sock;
318 if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
320 return (STATUS_BUFFER_TOO_SMALL);
323 if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
325 ERR ("Unable to parse /proc filesystem!\n");
326 return (-1);
330 /* Get a socket so we can use ioctl */
331 if ( (sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
333 ERR ("Error creating socket!\n");
334 return (-1);
337 /* 0 it out first */
338 memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
340 /* Interface Id */
341 baseIPInfo->iae_index = pcommand->toi_entity.tei_instance;
343 /* IP Address */
344 strcpy (ifInfo.ifr_name, ifName);
345 ifInfo.ifr_addr.sa_family = AF_INET;
346 if (ioctl(sock, SIOCGIFADDR, &ifInfo) < 0)
348 baseIPInfo->iae_addr = 0x0;
350 else
352 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
353 baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
356 /* Broadcast Address */
357 strcpy (ifInfo.ifr_name, ifName);
358 if (ioctl(sock, SIOCGIFBRDADDR, &ifInfo) < 0)
360 baseIPInfo->iae_bcastaddr = 0x0;
362 else
364 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_broadaddr;
365 baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
368 /* Subnet Mask */
369 strcpy(ifInfo.ifr_name, ifName);
370 if (ioctl(sock, SIOCGIFNETMASK, &ifInfo) < 0)
372 baseIPInfo->iae_mask = 0x0;
374 else
376 /* Trying to avoid some compile problems across platforms.
377 (Linux, FreeBSD, Solaris...) */
378 #ifndef ifr_netmask
379 #ifndef ifr_addr
380 baseIPInfo->iae_mask = 0;
381 ERR ("Unable to determine Netmask on your platform!\n");
382 #else
383 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_addr;
384 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
385 #endif
386 #else
387 struct ws_sockaddr_in *ipTemp = (struct ws_sockaddr_in *)&ifInfo.ifr_netmask;
388 baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
389 #endif
392 /* FIXME: How should the below be properly calculated? ******************/
393 baseIPInfo->iae_reasmsize = 0x0;
394 baseIPInfo->iae_context = 0x0;
395 baseIPInfo->iae_pad = 0x0;
396 /************************************************************************/
398 /* Calculate size of out buffer */
399 *pcbResponseInfoLen = sizeof(IPAddrEntry);
400 close(sock);
401 break;
405 default:
407 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",
408 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
409 pcommand->toi_class, pcommand->toi_type);
411 return (WSAEOPNOTSUPP);
415 break;
418 case WSCNTL_TCPIP_ICMP_ECHO:
420 unsigned int addr = *(unsigned int*)pRequestInfo;
421 #if 0
422 int timeout= *(unsigned int*)(inbuf+4);
423 short x1 = *(unsigned short*)(inbuf+8);
424 short sendbufsize = *(unsigned short*)(inbuf+10);
425 char x2 = *(unsigned char*)(inbuf+12);
426 char ttl = *(unsigned char*)(inbuf+13);
427 char service = *(unsigned char*)(inbuf+14);
428 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
429 #endif
431 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
432 break;
435 default:
437 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
438 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
440 return (WSAEOPNOTSUPP);
445 return (WSCTL_SUCCESS);
451 Helper function for WsControl - Get count of the number of interfaces
452 by parsing /proc filesystem.
454 int WSCNTL_GetInterfaceCount(void)
456 FILE *procfs;
457 char buf[512]; /* Size doesn't matter, something big */
458 int intcnt=0;
461 /* Open /proc filesystem file for network devices */
462 procfs = fopen(PROCFS_NETDEV_FILE, "r");
463 if (!procfs)
465 /* If we can't open the file, return an error */
466 return (-1);
469 /* Omit first two lines, they are only headers */
470 fgets(buf, sizeof buf, procfs);
471 fgets(buf, sizeof buf, procfs);
473 while (fgets(buf, sizeof buf, procfs))
475 /* Each line in the file represents a network interface */
476 intcnt++;
479 fclose(procfs);
480 return(intcnt);
485 Helper function for WsControl - Get name of device from interface number
486 by parsing /proc filesystem.
488 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
490 FILE *procfs;
491 char buf[512]; /* Size doesn't matter, something big */
492 int i;
494 /* Open /proc filesystem file for network devices */
495 procfs = fopen(PROCFS_NETDEV_FILE, "r");
496 if (!procfs)
498 /* If we can't open the file, return an error */
499 return (-1);
502 /* Omit first two lines, they are only headers */
503 fgets(buf, sizeof(buf), procfs);
504 fgets(buf, sizeof(buf), procfs);
506 for (i=0; i<intNumber; i++)
508 /* Skip the lines that don't interest us. */
509 fgets(buf, sizeof(buf), procfs);
511 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
514 /* Parse out the line, grabbing only the name of the device
515 to the intName variable
517 The Line comes in like this: (we only care about the device name)
518 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
520 i=0;
521 while (isspace(buf[i])) /* Skip initial space(s) */
523 i++;
526 while (buf[i])
528 if (isspace(buf[i]))
530 break;
533 if (buf[i] == ':') /* FIXME: Not sure if this block (alias detection) works properly */
535 /* This interface could be an alias... */
536 int hold = i;
537 char *dotname = intName;
538 *intName++ = buf[i++];
540 while (isdigit(buf[i]))
542 *intName++ = buf[i++];
545 if (buf[i] != ':')
547 /* ... It wasn't, so back up */
548 i = hold;
549 intName = dotname;
552 if (buf[i] == '\0')
554 fclose(procfs);
555 return(FALSE);
558 i++;
559 break;
562 *intName++ = buf[i++];
564 *intName++ = '\0';
566 fclose(procfs);
567 return(TRUE);
572 Helper function for WsControl - This function returns the bytes (octets) transmitted
573 and received for the supplied interface number from the /proc fs.
575 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
577 FILE *procfs;
578 char buf[512], result[512]; /* Size doesn't matter, something big */
579 int i, bufPos, resultPos;
581 /* Open /proc filesystem file for network devices */
582 procfs = fopen(PROCFS_NETDEV_FILE, "r");
583 if (!procfs)
585 /* If we can't open the file, return an error */
586 return (-1);
589 /* Omit first two lines, they are only headers */
590 fgets(buf, sizeof(buf), procfs);
591 fgets(buf, sizeof(buf), procfs);
593 for (i=0; i<intNumber; i++)
595 /* Skip the lines that don't interest us. */
596 fgets(buf, sizeof(buf), procfs);
598 fgets(buf, sizeof(buf), procfs); /* This is the line we want */
602 /* Parse out the line, grabbing the number of bytes transmitted
603 and received on the interface.
605 The Line comes in like this: (we care about columns 2 and 10)
606 lo: 21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
609 /* Start at character 0 in the buffer */
610 bufPos=0;
612 /* Skip initial space(s) */
613 while (isspace(buf[bufPos]))
614 bufPos++;
617 /* Skip the name and its trailing spaces (if any) */
618 while (buf[bufPos])
620 if (isspace(buf[bufPos]))
621 break;
623 if (buf[bufPos] == ':') /* Could be an alias */
625 int hold = bufPos;
627 while(isdigit (buf[bufPos]))
628 bufPos++;
629 if (buf[bufPos] != ':')
630 bufPos = hold;
631 if (buf[bufPos] == '\0')
633 fclose(procfs);
634 return(FALSE);
637 bufPos++;
638 break;
641 bufPos++;
643 while (isspace(buf[bufPos]))
644 bufPos++;
647 /* This column (#2) is the number of bytes received. */
648 resultPos = 0;
649 while (!isspace(buf[bufPos]))
651 result[resultPos] = buf[bufPos];
652 result[resultPos+1]='\0';
653 resultPos++; bufPos++;
655 *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
658 /* Skip columns #3 to #9 (Don't need them) */
659 for (i=0; i<7; i++)
661 while (isspace(buf[bufPos]))
662 bufPos++;
663 while (!isspace(buf[bufPos]))
664 bufPos++;
668 /* This column (#10) is the number of bytes transmitted */
669 while (isspace(buf[bufPos]))
670 bufPos++;
672 resultPos = 0;
673 while (!isspace(buf[bufPos]))
675 result[resultPos] = buf[bufPos];
676 result[resultPos+1]='\0';
677 resultPos++; bufPos++;
679 *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
682 fclose(procfs);
683 return(TRUE);
687 /***********************************************************************
688 * WSARecvEx() (WSOCK32.1107)
690 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
691 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
692 * into the flags parameter when a partial packet is read. This only applies to
693 * sockets using the datagram protocol. This method does not seem to be implemented
694 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
695 * flag when a fragmented packet arrives.
697 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
699 FIXME("(WSARecvEx) partial packet return value not set \n");
700 return WS2_recv(s, buf, len, *flags);
704 /***********************************************************************
705 * WS_s_perror (WSOCK32.1108)
707 void WINAPI WS_s_perror(LPCSTR message)
709 FIXME("(%s): stub\n",message);
710 return;
714 /***********************************************************************
715 * WSOCK_LibMain
717 BOOL WINAPI WSOCK_LibMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
719 static HMODULE ws2_32;
720 switch (reason)
722 case DLL_PROCESS_ATTACH:
723 /* we import ws2_32 by hand, because we don't want to implicitly */
724 /* link to it; otherwise Unix calls like socket() get redirected */
725 /* to ws2_32.dll and this is not what we want. */
727 if (!(ws2_32 = LoadLibraryA( "ws2_32.dll" )))
729 ERR("could not load ws2_32\n" );
730 return FALSE;
732 WS2_recv = (void *)GetProcAddress( ws2_32, "recv" );
733 break;
734 case DLL_PROCESS_DETACH:
735 FreeLibrary( ws2_32 );
736 break;
738 return TRUE;