<< |
Winsock Programmer's FAQ |
>> |
4.1 - How can I open a raw data socket?Under Winsock 1.1, the SOCK_RAW socket type is optional. Some of the non-Microsoft stacks implemented it, but these implementations are increasingly hard to find. SOCK_RAW in Winsock 1.1 is also problematic because the Winsock spec's writers did not try to rigorously define what we should expect from a SOCK_RAW implementation. The Winsock 2 spec gives more details about raw sockets, and Microsoft's Winsock 2 stacks do implement some types of raw sockets. Windows 2000 has by far the best implementation of raw sockets; details below. On all other platforms, raw socket support is fairly sparse: Microsoft only supports raw IGMP and ICMP sockets on these platforms. The latter allows you to send "ping" packets in a standard way. These stacks do not support raw IP or "packet capturing" from the Winsock layer. (See the next two questions for information on capturing packets and changing packet headers.) If you really must have complete raw sockets support and can't use Windows 2000, you might think about a platform change. Most flavors of Unix (including the free BSD flavors and Linux) have good raw socket support. Available raw sockets support in Microsoft stacks:
Notice that raw TCP and UDP aren't possible directly under Winsock 2. Instead, you must use IP_HDRINCL (a.k.a. raw IP) and build your own IP and TCP or UDP headers. 4.2 - How can I capture packets on a LAN with Winsock?You cannot. Winsock (at least as implemented by Microsoft) does not allow promiscuous IP packet captures. So how do Ethernet analyzers work, you ask? They talk straight to the Transport Data Interface (TDI) or Network Device Interface Specification (NDIS) layer. The TDI layer is just above the system's NDIS (network driver) layer. Some of the Windows packet sniffers in the FAQ's debugging resources section include source, which you could pick apart to figure out how this works. PCAUSA sells a package that is supposed to make writing to the TDI and NDIS layers easier. I have, however, not tried this product. They also have several FAQs that talk about various low-level network stack access methods. These FAQs also point you to various bits of sample code, most of it from Microsoft's various DDKs. If all you want is a way to help you debug your Winsock program by showing you what is happening on the network, the Resources section mentioned above has links to many capable network sniffers and other debugging tools. 4.3 - How can I change the IP or TCP header of a packet?That's only possible under Windows 2000 with Winsock, at this time.
A few IP header fields can be set with If that is not enough control for your application, you will have to resort to lower-level techniques. One of these is to add a layer to the network stack with Winsock 2's Layered Service Provider mechanism. That mechanism is not covered in this FAQ, but there is some useful code and documentation on the MSDN site and disks. Another option is to do raw data I/O using the Transport Data Interface (TDI) or the Network Driver Interface Specification (NDIS). Further information is available in PCAUSA's FAQs. Also, don't rule out the option of building your application on a platform that does have easy access to the packet headers. Most Unix flavors (including Linux) offer copious tools for low-level network I/O. For information on raw network programming on Unixlike platforms, see Thamer Al-Herbish's Raw IP Networking FAQ. 4.4 - How can I "ping" another machine with Winsock?The "official" method uses the IPPROTO_ICMP raw socket type defined by Winsock 2. All of Microsoft's Winsock 2 stacks support this. I suspect that this also works on some non-Microsoft Winsock 1.1 stacks, but I don't personally know of any such success. [C++ example] The other method uses ICMP.DLL, which is an extension specific to Microsoft stacks. Though it works on all Windows systems as of this writing, Microsoft discourages its use in the strongest terms possible, claiming that the API will disappear as soon as a better method exists. (It hasn't actually happened yet, despite several years of threats. :) ) ICMP.DLL's main advantage is that it works under Winsock 1.1. It is, however, less flexible than the raw sockets method. [C++ example] I want to point out that many programs misuse ping. Naturally it has good uses, but it's a sign of a broken program or protocol if you find yourself resorting to regular use of ping packets. For example, I'm always seeing people ask about pinging when what they really want is to detect dropped connections. 4.5 - How do I pass a socket from one process to another?This is not possible under Winsock 1.1, because it wasn't considered sufficiently important at the time the spec was created. Winsock 2 provides support for this through the
Another fun feature of the Win32 API is that it allows you to give a
new process different "standard handles" (stdin, stdout and stderr) when
you create it. Article Q190351 in the Microsoft Knowledge
Base addresses this. Note that this feature only allows you to do this
with a child process; you can't redirect your own standard I/O handles
to a socket. Also, the item notes that some processes may behave stangely
when you do this to them. Clearly, this functionality is not as powerful
as the Unix world's 4.6 - Is it possible to create sockets that map to a DLL rather than an application?Under Windows, a DLL's data is actually owned by the application that loads the DLL. If you need the DLL to own a single socket no matter how many processes load the DLL, you need to create a "helper process" which will perform all Winsock operations on behalf of the DLL. Naturally you'll need some kind of interprocess communication channel between the DLL and the helper process. Note that this issue only matters if you're using a DLL to let multiple processes share a socket. If you only have one process using the DLL, or if it's okay for each process to remain ignorant of the other processes using the DLL, this issue won't matter to you. 4.7 - How can I get access to the {route, ARP, interface, etc.} table?Stas Khirman and Raz Galili have written a great tutorial on the art of using the poorly-documented SNMP API. This API allows you to access many "hidden" parts of the Windows networking subsystem, including the network interface list, the route and ARP tables, the list of connected network sockets, your Ethernet cards' hardware addresses, etc. 4.8 - How do I get the MAC (a.k.a. hardware) address of the local Ethernet adapter?This FAQ has example code for two methods, both of which are somewhat kludgey. The first method involves asking the NetBIOS API for the adapter addresses. The primary problem with this method is that it sometimes fails, depending on the system's networking configuration. The second method depends on a property of the Remote Procedure Call specification that says that the last 6 bytes of a UUID will be derived from the hardware address of the local machine's network adapter. In the case of Ethernet (the common case), this is the MAC address. The major problem with this method is that it will only return one address; if there is more than one Ethernet network adapter in the system, this method won't let you get that second adapter's address. The descriptions introducing each example go into these issues further. The SNMP item above links to an article that contains another method for getting MAC addresses. 4.9 - How many simultaneous sockets can I have open with Winsock?On Win9x machines, there's quite-low limit imposed by the kernel: 100 connections. You can increase this limit by editing the registry key HKLM\System\CurrentControlSet\Services\VxD\MSTCP\MaxConnections. On Windows 95, the key is a DWORD; on Windows 98, it's a string. I've seen some reports of instability when this value is increased to more than a few times its default value. The rest of this discussion will cover only Windows NT and Windows 2000. These systems have much higher intrinsic capabilities, and thus allow you to use many more sockets. But, the Winsock specification does not set a particular limit, so the only sure way to tell is to try it on all the Winsock stacks you plan on supporting. Beyond that vague advice, things get more complicated. The simplistic test is to just write a program that just opens sockets, to see where the program stops running: [C++ Example]. The above program isn't terribly realistic. I've seen it grab more than 30,000 sockets before failing on Windows NT 4.0. Anecdotal evidence from the Winsock 2 mailing list puts the real limit much lower, typically 4,000 to 16,000 sockets, even on NT systems with hundreds of megabytes of physical memory. The difference is that the example program just grabs socket handles, but does not actually create connections with them or tie up any network stack buffers. According to people at Microsoft, the WinNT/Win2K kernel allocates sockets out of the non-paged memory pool. (That is, memory that cannot be swapped to the page file by the virtual memory subsystem.) The size of this pool is necessarily fixed, and is dependent on the amount of physical memory in the system. On Intel x86 machines, the non-paged memory pool stops growing at 1/8 the size of physical RAM, with a hard maximum of 128 megabytes. The hard limit is 256 megabytes on Windows 2000. Thus for NT 4, the size of the non-paged pool stops increasing once the machine has 1 GB of RAM. On Win2K, you hit the wall at 2 GB. The amount of data associated with each socket varies depending on how that socket's used, but the minimum size is around 2 KB. Overlapped I/O buffers also eat into the non-paged pool, in blocks of 4 KB. (4 KB is the x86's memory management unit's page size.) Thus a simplistic application that's regularly sending and receiving on a socket will tie up at least 10 KB of non-pageable memory. Assuming that simple case of 10 KB of data per connection, the theoretical maximum number of sockets on NT 4.0 is about 12,800s, and on Win2K 25,600. I have seen reports of a 64 MB Windows NT 4.0 machine hitting the wall at 1,500 connections, a 128 MB machine at around 4,000 connections, and a 192 MB machine maxing out at 4,700 connections. It would appear that on these machines, each connection is using between 4 KB and 6 KB. The discrepancy between these numbers and the 10 KB number above is probably due to the fact that in these servers, not all connections were sending and receiving all the time. The idle connections will only be using about 2 KB each. So, adjusting our "average" size down to 6 KB per socket, NT 4.0 could handle about 21,800 sockets and Win2K about 43,700 sockets. The largest value I've seen reported is 16,000 sockets on Windows NT 4.0. There's one more complication to keep in mind: your server program will not be the only thing running on the machine. If nothing else, there will be core OS services running. These other programs will be competing with yours for space in the non-paged memory pool. 4.10 - Can I change FD_SETSIZE to make select() wait on more than 64 sockets?You can, but in practice it may not work. Several common Winsock
stacks and Layered Service Providers limit themselves internally to the
default value of FD_SETSIZE, 64. However, you can write a test program
to try this on the systems you plan on supporting, to see if they are not
limited. Also, you can always send each group of 64 sockets to a different
thread, so that several calls to 4.11 - How do I make Winsock use a specific network interface?On a machine with multiple network interfaces (a modem for dialup Internet and a LAN card, for example), it can sometimes be useful to force Winsock to use a specific interface. Before I go into how, keep in mind that the routing layer of the stack exists to handle this for you. If your setup isn't working the way you want, maybe you just need to change the routing tables. (This is done with the "route" and "netstat" command-line programs on Microsoft stacks.) There are two common reasons why you might want to force Winsock to use a particular network interface. The first is when you only want your server program to handle incoming connections on a particular interface. For example, if you have an NT machine set up as an Internet gateway, and it also runs a server that you only want internal LAN users to be able to access, you will want to set it to only listen on the LAN interface. The other reason is that you have two or more possible outgoing routes, and you want your client program to connect using a particular one without the routing layer getting in the way. You can do both of these things with the Incidentally, this is how virtual hosting on the Internet works. A single server is set up with a single network card but several IP addresses. Windows NT/2000 can do this, but Win9x cannot. To set this up in NT, go into the TCP/IP area of the Network control panel, and then click the Advanced button. IIRC, you can enter up to five network addresses per interface in NT Workstation, perhaps more in NT Server. Note that this information does not apply to the Windows 95/98
multihomed computer DUN bug. This
problem cannot be fixed by 4.12 - What is the { SYN, ACK, FIN, RST } bit?See the FAQ article Debugging TCP. 4.13 - Is it a bad idea to bind() to a particular port in a client program?It's occasionally justifiable, but most of the time it's a very bad idea. I've only heard of two good uses of this feature. The first is when your program needs to bind to a port in a particular range. Some implementations of the Berkeley "r commands" (e.g. rlogin, rsh, rcp, etc.) do this for security purposes. Because only the superuser on a Unix system can bind to a low-numbered port (1-1023), such an r command tries, sequentially, to bind to one of the ports in this range until it succeeds. This allows the remote server to surmise that if the connection is coming from a low-numbered port, the remote user must be a superuser. (This port range limit also applies to Windows NT and Windows 2000, but not to Windows 9x.) The second justifiable example is FTP in its "receive file" mode:
it binds to a random port and then tells the file server to "send the
file to this port". This is justifiable because it arguably cleans up the
protocol, and the FTP client doesn't need to bind to any particular port,
it just needs to bind to a port. (Incidentally, it does this by
binding to port 0 By contrast, it is almost always an error to bind to a particular port in a client. (Notice that both of the above examples are flexible about the ports they bind to.) To see why this is bad, consider a web browser. They often create several connections to download a single web page, one each to fetch all of the individual pieces of the page: images, applets, sound clips, etc. If they always bound to a particular local port, they could only have one connection going at a time. Also, you couldn't have a second instance of the web browser downloading another page at the same time. That's not the biggest problem, though. When you close a TCP connection, it goes into the TIME_WAIT state for a short period (between 30 and 120 seconds, typically), during which you cannot reuse that connection's "5-tuple:" the combination of {local host, local port, remote host, remote port, transport protocol}. (This timeout period is a feature of all correctly-written TCP/IP stacks, and is covered in RFC 793 and especially RFC 1122.) In practical terms, this means that if you bind to a specific port all the time, you cannot connect to the same host using the same remote port until the TIME_WAIT period expires. I have personally seen anomalous cases where the TIME_WAIT period does not occur, but when this happens, it's a bug in the stack, not something you should count on. For more on this matter, see the Lame List. |
<< Intermediate Winsock Issues | Winsock Resources >> |
Last modified on 29 April 2000 at 15:52 UTC-7 | Please send corrections to tangent@cyberport.com. |
< Go to the main FAQ page |
|
<<< Go to my Home Page |