It uses the layered service provider system I wrote about. For any UDP based application (actually with one line of code change it work with TCP too) it will add the desired attributes to the connection.
One big snag is how to implement an incoming bandwidth throttle. There are 3 ways data can come in, nonblocking, blocking, or with IO completion ports. Nonblocking is the easiest, I just stick the data into a buffer and return it when the user later calls recv or recvfrom again. Blocking is harder. I would have to put an infinite loop in the recvfrom call and not return until the required latency has elapsed. However, you can break out of the Windows version of recvfrom with a signaled event, and I have no idea how I’d hook into that event. IO completion ports is similar to nonblocking, but the buffer has to be added to from a worker thread elsewhere. If I can’t figure this out I’d have to drop the incoming bandwidth throttle. This would have been easier if I had implemented it at the NDIS level, although it would have been harder in other ways.
Another problem is the layered transport service provided by windows is DLL and registry based. So if you were to kill the program with end process, the DLL would not be uninstalled automatically when the process shuts down. If you were to then delete the program without uninstalling it that DLL would be stuck in your system, loading up the QoS emulator when you don’t want it. I’m not sure if the DLL can unregister itself in its own startup call. If I can, I will check for the program installation in startup, and have the DLL unregister itself if it looks like the program was uninstalled.
I’m not sure all this will work on Vista either. There was some crap in the Windows SDK documentation about security and various extra things you have to do in the installer, the registry, and the program itself. I only scanned over it in passing while looking for info on the Winsock debug/trace DLL system. I hope there’s code there I can just copy/paste.
This program has been very complicated and difficult to write, partly because I’ve never done anything like it before. It requires knowledge of threads, IO completion ports, sockets and socket properties, the registry, installation settings and permissions, interprocess communication, hooking in and debugging DLLs called by the system, and complicated associations between LSPs, the high level user-code, other LSPs, and the low level transport service provider. That article by Microsoft states “You will probably find that implementing an LSP is no longer a daunting and time-consuming task if you simply extend the layered sample” but if they consider that to be easy I’d hate to see what they consider hard.
Thanks to Jason King for help designing the GUI!