Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why socket descriptors on Windows get such values?

Not sure if it's the right place to ask, anyway.
I'm writing a simple chat with c++, where a client gets socket value as nickname for beginning.
On linux sockets are just file descriptors and they get their 3, 4, 5... that follow stdin, stdout, stderr.
But I've noticed that on Win the first client socket always gets value 192, while the others differs by 20 (almost always).
g
So here goes my question, why the sockets get such values on win platform (mine is win7 x64)? Little googling didn't help.
Thanks in advance :D

like image 904
Aenry Avatar asked Jul 31 '14 20:07

Aenry


2 Answers

In POSIX file descriptors are integer values, and requires that open return a value "that is the lowest file descriptor not currently open for that process". This rule doesn't actually seem to apply to socket but I don't now of any Unix system that doesn't apply this rule to it as well.

Windows however doesn't use POSIX sockets. It uses Windows sockets, which it is free to define in a way that's not compatible with POSIX or the original BSD implementation. There are in fact a lot of incompatibilities with Windows sockets. Having larger than you'd expect socket values is a relatively minor incompatibility as these things go.

With Windows Sockets 2 all socket "file descriptors" are actually Windows handles. This means they can be cast to HANDLE and used in many of the Windows API functions that accept handles as arguments. It also means that they share the same value space as a whole bunch of different types of objects that Windows supports. Things like files, threads, registry keys, semaphores, and so on and so on. Windows allocates a lot these behind the scenes for a process, the Winsock DLL itself uses a fair number of them, so by the time you allocate your first socket your process has already allocated a significant number of other handles.

If you use Process Explorer to look at running processes and turn on the Show Unnamed Handles and Mappings option, you'll see that even the simplest of processes have quite a number of open handles. If you enable the Handle column and use it to sort the list, you'll also see that the lowest handle value is 4 and that they're all a multiple of 4. Most if not all the multiples of 4 between 4 and the highest number on the list will allocated.

While he doesn't explain why exactly, Raymond Chen in his Old New Thing blog on Why are kernel HANDLEs always a multiple of four? does say that handles being a multiple of 4 is guaranteed:

Not very well known is that the bottom two bits of kernel HANDLEs are always zero; in other words, their numeric value is always a multiple of 4. Note that this applies only to kernel HANDLEs; it does not apply to pseudo-handles or to any other type of handle (USER >handles, GDI handles, multimedia handles...) Kernel handles are things you can pass to the >CloseHandle function.

The availability of the bottom two bits is buried in the ntdef.h header file: // // Low order two bits of a handle are ignored by the system and available // for use by application code as tag bits. The remaining bits are opaque // and used to store a serial number and table index. //

Mark Russinovich’s blog on Pushing the Limits of Windows: Handles discusses some of the internals on how handles are implemented on Windows. Unfortunately it doesn't describe how the handle values are actually allocated, but I think I can surmise some of the details. The blog entry describes a "three level-scheme". Handles are used as index into a per-process handle table, which contains pointers to a per-process handle entry table, which in turn contains a pointer to the kernel object for the handle. Windows grows these tables as necessary, and presumably it will try to save memory by reusing handles after they're closed.

It's also probably not a a coincidence that the list of handles in Process Explorer has few gaps. Since processes open and close handle all of the time (often done behind the scenes by some system DLL), if Windows wasn't aggressively reusing closed handles then the list would be much sparser. But does Windows reuse the lowest handle first?

Testing reveals that it doesn't. I wrote a program that creates three handles, closes the first, third and second in that order, and repeats all that in a loop. If Windows followed POSIX rules, then each loop iteration would create the same handles values in the same order, smallest to largest. But what happened instead was that it created the same handle values in the reverse order that they were closed. This suggests that Windows probably reuses handles in most-recently-closed order. My guess is that it implements this by keeping a linked list of unallocated handles in handle table.

So why do your socket values start at 192? Probably because your process already had 47 open handles at that point. Why do your sockets differ by 20? Probably because you're creating 4 other handles in between creating each socket. Winsock itself maybe creating multiple handles behind the scenes each time you create a socket.

like image 186
Ross Ridge Avatar answered Sep 21 '22 04:09

Ross Ridge


More info that you could ever want about Winsock: (Which means you should read and absorb all of it ;-)

http://www.tenouk.com/Winsock/Winsock2story.html

Jeremy is correct, the ID can be a file HANDLE, window HANDLE, or just a non-used int value. I've seen what appears to be mangled pointers when doing IO Completion Ports, so it may actually vary depending on what part of windows networking you're using. (Winsock, Winsock2, etc)

like image 31
Caladain Avatar answered Sep 18 '22 04:09

Caladain