How can can I throttle bandwidth on an application domain level in Windows (in user mode)?

3.1k views Asked by At

I would like to make the following happen:

  • My application runs on a Windows machine (call it application A).
  • I can modify the source code of application A to introduce bandwidth throttling.
  • I would like to be able to reuse my bandwidth throttling code and drop it into any other applications that I have (in other words, I would like to try and throttle the bandwidth on an application domain level in order to not have to re-factor existing applications for bandwidth throttling).
  • I want to throttle A's cumulative upload and download speed separately. For example, if A has a maximum of 5 Kbps allotted to upload, then all of A's upload streams will be capped to a cumulative amount of 5 Kbps.

My requirements:

  • I cannot use a kernel-mode driver.
  • I need to add throttling on an application domain level.

I have tried to research into this, especially on Stack Overflow but could not find anything useful for my case:

  • I have seen this example of using a ThrottledStream class wrapper around a Stream object that will introduce throttling when used, but I need this to be at a domain level; taking this approach is problematic because it would require me to refactor a lot of existing code in other applications.
  • I have seen this question who's answer speaks about using the Windows Filtering Platform API. Unfortunately, a requirement I have is that I absolutely can't use a kernel-mode driver to accomplish this, and my understanding is that the WFP API requires one.

Does anyone know a way to implement my specific bandwidth throttling requirements in order to throttle applications on an application domain level?

1

There are 1 answers

2
Alexandru On

I think I have found a solution. With the QOS API, you need to get a handle to your target interface using TcOpenInterface (you can figure out which interface you want to target via a call to TcEnumerateInterfaces). With your interface handle, you need to call TcAddFlow along with a pointer to a TC_GEN_FLOW structure, which allows you to specify both a SendingFlowspec (FLOWSPEC structure) and a ReceivingFlowspec (FLOWSPEC structure) which contains a PeakBandwidth member. Then, to make your interface utilize this flow you've just added to it, you need to add a filter to your interface using a call to TcAddFilter, as MSDN says that the TcAddFilter function associates a new filter with an existing flow that allows packets matching the filter to be directed to the associated flow. I think that to make it application specific, calling TcRegisterClient may do the trick, which you will need to call anyways in order to get a client handle to use with TcEnumerateInterfaces and TcAddFlow from the looks of it (but this remains to be tested). I found this useful example as well (haven't tested it).

Taken from MSDN, the PeakBandwidth member is the upper limit on time-based transmission permission for a given flow, in bytes per second. The PeakBandwidth member restricts flows that may have accrued a significant amount of transmission credits, or tokens from overburdening network resources with one-time or cyclical data bursts, by enforcing a per-second data transmission ceiling. Some intermediate systems can take advantage of this information, resulting in more efficient resource allocation.