Difference between revisions of "User:Lone Rifle/kjk on ws2"

From ReactOS Wiki
Jump to: navigation, search
(New page: [00:43] <@kjk_hyperion> Winsock is a framework for user mode transport protocol drivers [00:43] <@kjk_hyperion> drivers are called providers [00:44] <@kjk_hyperion> in Winsock version 1...)
 
(Edit from IRC transcript to article)
Line 1: Line 1:
[00:43] <@kjk_hyperion> Winsock is a framework for user mode transport protocol drivers
+
Winsock is a framework for user mode transport protocol drivers.
[00:43] <@kjk_hyperion> drivers are called providers
+
 
[00:44] <@kjk_hyperion> in Winsock version 1, sockets weren't even guaranteed, or even expected, to be valid files
+
== Background ==
[00:44] * @dangerground_ (n=dangergr@reactos/developer/dangerground) Quit
+
 
[00:44] * +Russell opens up the gnu with a scalpel
+
In this framework, drivers are called providers. In Winsock version 1, sockets weren't even guaranteed, or even expected, to be valid files. However, in Winsock version 2, thanks to AFD, all sockets are files.
[00:44] <@kjk_hyperion> in Winsock version 2, thanks to a little help from our friend AFD, all sockets are files
+
 
[00:44] <@kjk_hyperion> Winsock calls are still routed in user mode, though
+
Despite this, Winsock calls are still routed in user mode. For each public API there is a corresponding provider callback. To further understand this in context, Winsock is a standard. There used to be third-party implementations, but eventually, Microsoft extended the Winsock specification with high performance APIs. This was long before epoll/kpoll et al., when all one could count on for asynchronous I/O was select or maybe poll. While the high performance APIs were never standardized, an extension mechanism, the [http://en.wikipedia.org/wiki/Layered_Service_Provider Layered Service Provider] (LSP) was.
[00:45] <@kjk_hyperion> for each public API there is a corresponding provider callback
+
 
[00:45] <@kjk_hyperion> Winsock is a standard
+
== Layered Service Provider extension mechanism ==
[00:45] <@kjk_hyperion> yes, there used to be third-party implementations
+
 
[00:45] <@kjk_hyperion> Microsoft extended the Winsock specification with high performance APIs
+
LSPs work by intercepting Winsock 2 commands before they are processed by ws2_32.dll. They can intercept and modify inbound and outbound network traffic, which makes them a powerful tool for network filters and stream based sniffers. As an example, Quality of Service (QoS) on Windows 98 and Windows 2000 is implemented as an LSP over the TCP/IP protocol stack. <cite>Reference: [http://en.wikipedia.org/wiki/Layered_Service_Provider Wikipedia article]</cite>
[00:46] <@kjk_hyperion> (this was long before epoll/kpoll/etc., all you could count on for asynchronous I/O was select or maybe poll)
+
 
[00:46] <@kjk_hyperion> the high performance APIs were never standardized
+
The mechanism that allows for insertion of LSPs is a special IOCTL that let you get the address of provider functions that couldn't be exported through the public API. Among these is ConnectEx. Traditional BSD connect has, among other things, no way to specify a connection timeout. Also, the BSD API wasn't very friendly to the Windows NT asynchronous I/O model, hence the need for ConnectEx. Generally speaking, ConnectEx is to connect what WriteFileEx is to WriteFile.
[00:46] <@kjk_hyperion> but an extension mechanism was standardized
+
 
[00:47] <@Stefan100> good night
+
=== Extension example: ConnectEx ===
[00:47] <@kjk_hyperion> a special IOCTL that let you get the address of provider functions that couldn't be exported through the public API
+
The grand unified Microsoft Winsock provider, MSAFD, does export from its DLL (mswsock.dll) a ConnectEx function. However, it's not specific to msafd but an extension of the high-level API. One might as well pretend ConnectEx was actually exported from ws2_32.dll because it has no knowledge of AFD (In reality, it is of course not exported from ws2_32.dll since it is not a Winsock 2 API).
[00:47] <@kjk_hyperion> among these, ConnectEx
+
 
[00:47] <@kjk_hyperion> goodnight Stefan100
+
What this extension does is query the provider of a socket for the ConnectEx implementation and then call it, just like connect queries the provider of the socket for the connect implementation and then calls it. This way, a non-MSAFD provider is free to implement the ConnectEx extension. This is why there's a ConnectEx function exported from mswsock.dll: to abstract the process from the application, so it doesn't have to query the provider itself, at the cost of lost efficiency if the application does it on its own, since it can safely cache the return value.
[00:47] <+Caemyr> bye Stefan100
+
 
[00:47] <@kjk_hyperion> traditional BSD connect has, among other things, no way to specify a connection timeout
+
In contrast, while libisc does handle this on its own, it has a few problems. It assumes a single provider, but all code that uses select or WSAPoll does. While incorrect, it is done in good company and in good faith. If it is to be done properly however, you should query each and every socket separately since each could come from a different provider, each with its own implementation, hence the whole model in the first place. However, different providers would break programs built around select. This might not be a problem at all if the program does NOT use select and uses I/O completion queues instead, but such programs are rare especially since there is no widely used event handling library that supports I/O completion queues as well.
[00:48] <@kjk_hyperion> also, the BSD API wasn't very friendly to the Windows NT asynchronous I/O model
+
 
[00:48] <@kjk_hyperion> thus, ConnectEx
+
== Layered Service Provider implementation ==
[00:48] * @Stefan100 (n=stefan__@1-1-13-45a.spa.sth.bostream.se) Quit ("zZz")
+
 
[00:48] <@kjk_hyperion> ConnectEx is to connect pretty much what WriteFileEx is to WriteFile
+
LSPs are function pointers retrieved with a Win32-style IOCTL, with separate input and output (as opposed to a BSD-style IOCTL, which typically has a single argument). The input of the IOCTL is a GUID that identifies the function to be returned, while the output is a function pointer.
[00:48] <@kjk_hyperion> now
+
 
[00:49] * Bungle (n=bungle@92-234-181-213.cable.ubr20.live.blueyonder.co.uk) Quit ("Pheanzis, Behold.. something about tissues..")
+
As mentioned earlier, MSAFD has a single, global implementation of the ConnectEx extension. This, like all MSAFD functions, is just a wrapper around an IOCTL handled by AFD in kernel mode. Winsock ioctls are strictly user mode-only because the "drivers" that handle them, providers, run in user mode. Providers can have an associated kernel mode driver, but that is left to their own discretion.
[00:49] <@kjk_hyperion> the grand unified Microsoft Winsock provider, msafd, does export from its DLL (mswsock.dll) a ConnectEx function
+
 
[00:49] <@kjk_hyperion> but it's not specific to msafd
+
== Using sockets ==
[00:49] <@kjk_hyperion> it's an extension of the high-level API
+
 
[00:50] <@kjk_hyperion> you might as well pretend ConnectEx was actually exported from ws2_32.dll
+
While Winsock v2 treats all sockets as files, sockets should be opened with CreateNamedPipe instead of CreateFile. Windows only has three kinds of files, files, pipes and mailslots (multicast pipes), four if you count devices. The closest one can get to a "socket" file type is "pipe". This ensures the socket cannot be used for anything else than I/O and ioctls. Using CreateFile on the other hand will break [http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx GetFileType].
[00:50] <@kjk_hyperion> because it has no knowledge of AFD
+
 
[00:50] <@kjk_hyperion> but of course, it's not exported from ws2_32.dll because it's not a Winsock 2 API
+
GetFileType is more of a framework-related item, to be used by libraries that wrap file handles in classes. It's usually very important for those libraries to distinguish between real files and everything else
[00:51] <@kjk_hyperion> it's an extension
+
 
[00:51] <@kjk_hyperion> what this extension does is query the provider of a socket for the ConnectEx implementation
+
== Suggestions and further work ==
[00:51] <@kjk_hyperion> and then call it
+
 
[00:51] <@kjk_hyperion> just like connect queries the provider of the socket for the connect implementation and then calls it
+
* Completion ports/queues. the counterintuitive part of completion queues is that you have to begin the operation to have a notification. Most event models notify you ''before'' the operation to tell you when the operation can be performed
[00:52] <@kjk_hyperion> this way, a non-MSAFD provider is free to implement the ConnectEx extension
+
* An epoll API, for compatibility
[00:52] <@kjk_hyperion> this is why there's a ConnectEx function exported from mswsock.dll
 
[00:53] <@anakha> To abstract the process from the application, so it doesn't have to query the provider itself
 
[00:53] <@kjk_hyperion> yes
 
[00:53] <@kjk_hyperion> but it sucks
 
[00:53] <@kjk_hyperion> it's more efficient if the application does it on its own
 
[00:53] <@anakha> which libisc does
 
[00:53] <@kjk_hyperion> because it can safely cache the return value
 
[00:53] <@kjk_hyperion> libisc gets it wrong
 
[00:54] <@kjk_hyperion> well
 
[00:54] <@kjk_hyperion> not really
 
[00:54] <@kjk_hyperion> it assumes a single provider, but all code that uses select or WSAPoll does
 
[00:54] <@kjk_hyperion> and that's a lot of code
 
[00:54] <@kjk_hyperion> it's wrong, but in good company and in good faith
 
[00:54] <@kjk_hyperion> actually, you should query each and every socket separately
 
[00:55] <@kjk_hyperion> because each could come from a different provider
 
[00:55] <@anakha> right
 
[00:55] * +elhoir|laptop (n=elhoir@84.pool85-49-181.dynamic.orange.es) has left #reactos
 
[00:55] <@kjk_hyperion> each with its own implementation
 
[00:55] <@anakha> Hence the whole model in the first place
 
[00:55] * elhoir|laptop (n=elhoir@84.pool85-49-181.dynamic.orange.es) has joined #reactos
 
  [00:55] * ChanServ sets mode: +v elhoir|laptop
 
[00:55] <@kjk_hyperion> but different providers would break programs built around select
 
[00:55] <@kjk_hyperion> no problem at all if the program does NOT use select and uses I/O completion queues instead, though
 
[00:55] <@kjk_hyperion> but they are rare
 
[00:56] <@kjk_hyperion> especially since there is no widely used event handling library that supports I/O completion queues as well
 
[00:56] <@kjk_hyperion> anyway
 
[00:56] <@kjk_hyperion> let's leave libisc alone for now
 
[00:56] <@anakha> sure
 
[00:57] <@kjk_hyperion> extensions are function pointers
 
[00:57] <@kjk_hyperion> they are retrieved with an ioctl
 
[00:57] * @Collibri (n=maku@reactos/developer/mkupfer) Quit (Read error: 110 (Connection timed out))
 
[00:57] <@kjk_hyperion> a Win32-style IOCTL, with separate input and output (as opposed to a BSD-style IOCTL, which typically has a single argument)
 
[00:58] <@kjk_hyperion> the input of the IOCTL (don't make me look up the code of the IOCTL, it's easy to find) is a GUID
 
[00:58] <@kjk_hyperion> that identifies the function to be returned
 
[00:58] <@kjk_hyperion> the output is a function pointer
 
[00:58] * szczur_ (n=szczur@dynamic-78-8-55-161.ssp.dialog.net.pl) has joined #reactos
 
[00:59] <@kjk_hyperion> MSAFD has a single, global implementation of the connectEx extension
 
[01:00] <@kjk_hyperion> that, like all MSAFD functions, is just a wrapper around an IOCTL handled by AFD in kernel mode
 
[01:00] <@kjk_hyperion> (Winsock ioctls are strictly user mode-only)
 
[01:00] <@kjk_hyperion> (because the "drivers" that handle them, providers, run in user mode)
 
[01:01] <@kjk_hyperion> (providers can have an associated kernel mode driver, but that's their own business)
 
[01:01] <@kjk_hyperion> that's all, I think
 
[01:01] <@kjk_hyperion> don't forget sockets should be opened with CreateNamedPipe instead of CreateFile
 
[01:01] * @Fireball (n=aleksey@reactos/coordinator) Quit
 
[01:02] <@kjk_hyperion> but I don't think you want to get so deep into winsock right now
 
[01:02] <rendar> mmm CreateNamedPipe? why?
 
[01:02] <@kjk_hyperion> because windows only has three kinds of files
 
[01:02] <@kjk_hyperion> files, pipes and mailslots (multicast pipes)
 
[01:03] <@kjk_hyperion> plus console buffers and console inputs, emulated in user mode by Win32
 
[01:03] <@kjk_hyperion> well, add "device" as well
 
[01:03] <rendar> CONOUT$
 
[01:03] <@kjk_hyperion> closest you can get to "socket" file type is "pipe"
 
[01:03] <rendar> i see
 
[01:03] <@anakha> ok, well thanks for the quick dump
 
[01:04] <rendar> but is not an error to open a socket with CreateFile, i mean, the opening succeeds
 
[01:04] <@kjk_hyperion> this also ensures the socket cannot be used for anything else than I/O and ioctls
 
[01:04] * Dounet (n=massoubr@88-107-237-160.dynamic.dsl.as9105.com) has joined #reactos
 
[01:04] <@anakha> makes a bit more sense and reaffirms some things that the windows internals book was saying
 
[01:04] <@kjk_hyperion> you're welcome
 
[01:04] <@kjk_hyperion> I have actually used this shit, a lot
 
[01:04] <@anakha> I shall do some more poking around and then take a crack at the Ioctl function for tcpip
 
[01:05] <@kjk_hyperion> so if you need more hands-on help, don't hesitate
 
[01:05] <@anakha> I shall keep the offer in mind :D
 
[01:05] * @anakha -> make pigs-in-a-blanket
 
[01:05] <@kjk_hyperion> I know quite a few things about I/O drivers
 
[01:05] <@kjk_hyperion> too
 
[01:05] <@kjk_hyperion> should you wish to venture as far as AFD
 
[01:06] <@kjk_hyperion> rendar: it will break GetFileType though
 
[01:06] <@kjk_hyperion> http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx
 
[01:06] <rendar> ok
 
[01:06] <@kjk_hyperion> FILE_TYPE_PIPE
 
[01:06] <@kjk_hyperion> 0x0003
 
[01:06] <@kjk_hyperion> The specified file is a socket, a named pipe, or an anonymous pipe.
 
[01:07] <rendar> well, until now i've always used bsd sockets interface in windows
 
[01:07] <@kjk_hyperion> I rarely use that
 
[01:07] <@kjk_hyperion> I'm an I/O completion queues guy
 
[01:07] <rendar> heeheheheheh
 
[01:08] <rendar> yes i should use it too, and use completion ports
 
[01:08] * dodddummy (n=dodddumm@74-129-146-53.dhcp.insightbb.com) has joined #reactos
 
[01:08] <@kjk_hyperion> it takes a while to get used to
 
[01:08] <@kjk_hyperion> you have to think upside down
 
[01:09] <rendar> time ago i was reading a book which describes completion ports as the better mechanism for Async I/O
 
[01:09] <@kjk_hyperion> GetFileType is more of a framework thing, though
 
[01:09] <@kjk_hyperion> it will be used by libraries that wrap file handles in classes
 
[01:09] <rendar> i think so
 
[01:10] <@kjk_hyperion> and it's usually very important for those library to distinguish between real files and everything else
 
[01:10] <@kjk_hyperion> libraries
 
[01:10] <rendar> yes, sure
 
[01:10] <@kjk_hyperion> completion ports are really nice
 
[01:10] * TiKu [P3D] (n=Timo@ppp-88-217-23-116.dynamic.mnet-online.de) Quit ("Leaving.")
 
[01:10] <@kjk_hyperion> well, I'd like an epoll API too
 
[01:10] <@kjk_hyperion> at least for compatibility
 
[01:10] <@kjk_hyperion> I think it can be done
 
[01:11] <@kjk_hyperion> maybe not
 
[01:12] <@kjk_hyperion> the counterintuitive part of completion queues is that you have to begin the operation to have a notification
 
[01:12] <@kjk_hyperion> most event models notify you BEFORE the operation
 
[01:12] <@kjk_hyperion> to tell you when the operation can be performed
 
[01:12] <rendar> yes
 
[01:13] <@kjk_hyperion> so it's a little um
 
[01:13] <@kjk_hyperion> different
 
[01:13] <@kjk_hyperion> now I really should go to bed
 
[01:13] <rendar> eheheh...me too...good night mate..see yah tomorrow
 
[01:13] <rendar> :D
 
[01:13] <@kjk_hyperion> nite
 
[01:13] <rendar> and thanks you for explaining
 
[01:13] <@kjk_hyperion> I love this shit
 
[01:14] <@kjk_hyperion> ask me any time
 
[01:14] <@kjk_hyperion> I will explain anything
 
[01:14] <@kjk_hyperion> for free
 
[01:14] <@kjk_hyperion> I could talk for hours
 
[01:14] <rendar> ok :D thanks
 
[01:14] <rendar> eheheh
 
[01:14] <@kjk_hyperion> it's best to ask on weekends
 
[01:14] <rendar> haahah, sure... :)
 
[01:15] * szczur (n=szczur@dynamic-78-8-51-206.ssp.dialog.net.pl) Quit (Read error: 110 (Connection timed out))
 
[01:16] * szczur_ is now known as szczur
 

Revision as of 10:09, 13 November 2009

Winsock is a framework for user mode transport protocol drivers.

Background

In this framework, drivers are called providers. In Winsock version 1, sockets weren't even guaranteed, or even expected, to be valid files. However, in Winsock version 2, thanks to AFD, all sockets are files.

Despite this, Winsock calls are still routed in user mode. For each public API there is a corresponding provider callback. To further understand this in context, Winsock is a standard. There used to be third-party implementations, but eventually, Microsoft extended the Winsock specification with high performance APIs. This was long before epoll/kpoll et al., when all one could count on for asynchronous I/O was select or maybe poll. While the high performance APIs were never standardized, an extension mechanism, the Layered Service Provider (LSP) was.

Layered Service Provider extension mechanism

LSPs work by intercepting Winsock 2 commands before they are processed by ws2_32.dll. They can intercept and modify inbound and outbound network traffic, which makes them a powerful tool for network filters and stream based sniffers. As an example, Quality of Service (QoS) on Windows 98 and Windows 2000 is implemented as an LSP over the TCP/IP protocol stack. Reference: Wikipedia article

The mechanism that allows for insertion of LSPs is a special IOCTL that let you get the address of provider functions that couldn't be exported through the public API. Among these is ConnectEx. Traditional BSD connect has, among other things, no way to specify a connection timeout. Also, the BSD API wasn't very friendly to the Windows NT asynchronous I/O model, hence the need for ConnectEx. Generally speaking, ConnectEx is to connect what WriteFileEx is to WriteFile.

Extension example: ConnectEx

The grand unified Microsoft Winsock provider, MSAFD, does export from its DLL (mswsock.dll) a ConnectEx function. However, it's not specific to msafd but an extension of the high-level API. One might as well pretend ConnectEx was actually exported from ws2_32.dll because it has no knowledge of AFD (In reality, it is of course not exported from ws2_32.dll since it is not a Winsock 2 API).

What this extension does is query the provider of a socket for the ConnectEx implementation and then call it, just like connect queries the provider of the socket for the connect implementation and then calls it. This way, a non-MSAFD provider is free to implement the ConnectEx extension. This is why there's a ConnectEx function exported from mswsock.dll: to abstract the process from the application, so it doesn't have to query the provider itself, at the cost of lost efficiency if the application does it on its own, since it can safely cache the return value.

In contrast, while libisc does handle this on its own, it has a few problems. It assumes a single provider, but all code that uses select or WSAPoll does. While incorrect, it is done in good company and in good faith. If it is to be done properly however, you should query each and every socket separately since each could come from a different provider, each with its own implementation, hence the whole model in the first place. However, different providers would break programs built around select. This might not be a problem at all if the program does NOT use select and uses I/O completion queues instead, but such programs are rare especially since there is no widely used event handling library that supports I/O completion queues as well.

Layered Service Provider implementation

LSPs are function pointers retrieved with a Win32-style IOCTL, with separate input and output (as opposed to a BSD-style IOCTL, which typically has a single argument). The input of the IOCTL is a GUID that identifies the function to be returned, while the output is a function pointer.

As mentioned earlier, MSAFD has a single, global implementation of the ConnectEx extension. This, like all MSAFD functions, is just a wrapper around an IOCTL handled by AFD in kernel mode. Winsock ioctls are strictly user mode-only because the "drivers" that handle them, providers, run in user mode. Providers can have an associated kernel mode driver, but that is left to their own discretion.

Using sockets

While Winsock v2 treats all sockets as files, sockets should be opened with CreateNamedPipe instead of CreateFile. Windows only has three kinds of files, files, pipes and mailslots (multicast pipes), four if you count devices. The closest one can get to a "socket" file type is "pipe". This ensures the socket cannot be used for anything else than I/O and ioctls. Using CreateFile on the other hand will break GetFileType.

GetFileType is more of a framework-related item, to be used by libraries that wrap file handles in classes. It's usually very important for those libraries to distinguish between real files and everything else

Suggestions and further work

  • Completion ports/queues. the counterintuitive part of completion queues is that you have to begin the operation to have a notification. Most event models notify you before the operation to tell you when the operation can be performed
  • An epoll API, for compatibility