Skip to content

Mona-Roza/WIND_USB

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WIND_USB Library - Complete Documentation

A high-performance Windows USB packet capture library using the USBPcap driver. No Npcap/WinPcap required only Windows system libraries.

Table of Contents


Quick Start (5 Minutes)

1. Prerequisites

2. Install USBPcap

1. Download from: https://desowin.org/usbpcap/
2. Run installer and reboot
3. Verify installation

3. Build the Library

cd usbPcap_trial
mkdir build
cd build
cmake -B . -G "Ninja"
ninja

4. Your First Program

#include <iostream>
#include "WIND_USB/wind_usb.hpp"
using namespace WIND_USB;

int main() {
    auto& usb = USBCapture::instance();
    auto devices = usb.list_devices();
    
    for (const auto& dev : devices) {
        if (dev.address == 0) continue;
        std::cout << dev.friendlyName << " at " << (int)dev.address << "\n";
    }
    return 0;
}

5. Capture Traffic

void on_packet(const USBPacket& pkt) {
    ++packet_count;
    std::cout << "Packet: " << pkt.payload.size() << " bytes\n";
}

auto& usb = USBCapture::instance();
usb.start_capture(ifaces[0], on_packet);
std::this_thread::sleep_for(std::chrono::seconds(30));
usb.stop_capture();

Features

  • Real-time USB Packet Capture: Capture all USB traffic on a system
  • Device Enumeration: Detect and list all connected USB devices with full details
  • Flexible Filtering: Filter by device address, endpoint, transfer type, direction, and status codes
  • Multi-threaded: Producer-consumer architecture for non-blocking packet processing
  • Zero External Dependencies: Uses only Windows APIs and C++17 standard library
  • Singleton Pattern: Thread-safe global instance management
  • PCAP Format Support: Packets in standard libpcap format with USBPcap extensions
  • Comprehensive Packet Metadata: Transfer type, direction, endpoint, control stage, status codes

Requirements

Hardware & OS

  • Windows 7/8/10/11 (32-bit or 64-bit)
  • Administrator Privileges required for packet capture

Software

System Libraries (automatically linked)

  • setupapi.lib � Windows device enumeration API
  • ws2_32.lib � Windows Sockets
  • cfgmgr32.lib � Configuration Manager

Building

Option 1: Standalone Build

mkdir build
cd build
cmake -B . -G "Ninja"
ninja

Option 2: As Part of Your Project

In CMakeLists.txt:

add_subdirectory(path/to/WIND_USB)
target_link_libraries(your_app PRIVATE wind_usb)

Option 3: With Examples

cmake -B build -G Ninja
cmake --build build

API Reference

USBCapture Class (Singleton)

Main interface. Access via USBCapture::instance().

Device Enumeration

std::vector<USBDevice> list_devices() const

Returns all detected USB devices.

std::vector<std::string> list_capture_interfaces() const

Returns available USBPcap interfaces.

Capture Control

bool start_capture(const std::string& iface, PacketCallback cb, bool autoThread = true)

Start capturing packets.

  • iface: USBPcap interface name (e.g., "\\.\USBPcap1")
  • cb: Callback function invoked for each packet
  • autoThread: If true (default), automatically spawn producer/consumer threads. If false, you must call producer_loop() and consumer_loop() from your own threads
  • Returns: true on success, false on failure

Automatic threading (default):

usb.start_capture(ifaces[0], on_packet);  // Threads started automatically

Manual threading:

usb.start_capture(ifaces[0], on_packet, false);  // No threads started
std::thread prod([&]() { usb.producer_loop(ifaces[0]); });
std::thread cons([&]() { usb.consumer_loop(); });
// ... do work ...
usb.stop_capture();
prod.join(); cons.join();
void producer_loop(const std::string& iface)

Read packets from USBPcap device. Blocks until stop_capture() is called. Only use when autoThread=false in start_capture(). Call from your own thread.

void consumer_loop()

Process packets from queue and invoke callback. Blocks until stop_capture() is called. Only use when autoThread=false in start_capture(). Call from your own thread.

void stop_capture()

Stop capture and wait for threads. Safe to call from signal handlers. If you started producer/consumer manually, you must call stop_capture() and then join() your threads.

bool is_running() const

Returns true if currently capturing.

Filter Management

void set_filter(const USBFilter& f)

Set filter for packets. Thread-safe, applies immediately.

USBFilter get_filter() const

Get current filter settings.

void filter_by_device(uint16_t address)

Filter by device address only.

void filter_by_endpoint(uint8_t endpoint)

Filter by endpoint only.


Data Structures

USBPacket

struct USBPacket {
    std::chrono::system_clock::time_point timestamp;
    USBDirection direction;           // Up or Down
    USBTransferType transferType;     // Bulk, Control, Interrupt, Iso
    uint16_t deviceAddress;           // 1-127
    uint8_t endpoint;                 // 0-15
    bool endpointIn;
    USBControlStage controlStage;
    bool isSetup;
    USB_SETUP_PACKET setup;
    uint32_t usbd_status;
    bool isSuccess, isACK, isSTALL, isNAK, isHandshake;
    std::vector<uint8_t> payload;
};

USBDevice

struct USBDevice {
    std::string friendlyName;
    std::string description;
    std::string manufacturer;
    std::string hardwareId;
    uint16_t vendorId;
    uint16_t productId;
    uint16_t address;              // USB address 1-127
    uint8_t miNumber;              // 0xFF if not composite
    std::vector<uint8_t> endpoints;
    
    std::string vidPidString() const;
    std::string vidPidMiString() const;
    std::string endpointListString() const;
};

USBFilter

struct USBFilter {
    bool showUpstream = true;
    bool showDownstream = true;
    bool showACK = true;
    bool showSTALL = true;
    bool showNAK = true;
    bool showHandshake = true;
    bool showControl = true;
    bool showBulk = true;
    bool showInterrupt = true;
    bool showIsochronous = true;
    uint16_t filterDeviceAddress = 0;        // 0=all
    uint8_t filterEndpoint = 0xFF;           // 0xFF=all
};

USB_SETUP_PACKET

struct USB_SETUP_PACKET {
    uint8_t bmRequestType;
    uint8_t bRequest;
    uint16_t wValue;
    uint16_t wIndex;
    uint16_t wLength;
};

Enumerations

USBDirection

enum class USBDirection {
    Down,  // Host ? Device
    Up     // Device ? Host
};

USBTransferType

enum class USBTransferType : uint8_t {
    Isochronous = 0,
    Interrupt = 1,
    Control = 2,
    Bulk = 3
};

USBControlStage

enum class USBControlStage : uint8_t {
    Setup = 0,
    Data = 1,
    Status = 2,
    Complete = 3
};

Code Examples

Example 1: List Devices

#include "WIND_USB/wind_usb.hpp"
using namespace WIND_USB;

int main() {
    auto& usb = USBCapture::instance();
    for (const auto& dev : usb.list_devices()) {
        if (dev.address == 0) continue;
        std::cout << dev.friendlyName << " at " << (int)dev.address << "\n";
    }
    return 0;
}

Example 2: Capture All

std::atomic<int> count{0};

void on_packet(const USBPacket& pkt) {
    ++count;
}

auto& usb = USBCapture::instance();
usb.start_capture(ifaces[0], on_packet);
std::this_thread::sleep_for(std::chrono::seconds(10));
usb.stop_capture();
std::cout << "Packets: " << count << "\n";

Example 3: Filter Device & Endpoint

USBFilter filter;
filter.filterDeviceAddress = 5;
filter.filterEndpoint = 0x81;
usb.set_filter(filter);

usb.start_capture(ifaces[0], on_packet);

Example 4: Control Transfers

void track_control(const USBPacket& pkt) {
    if (pkt.transferType != USBTransferType::Control) return;
    if (pkt.isSetup) {
        std::cout << "SETUP request: 0x" << std::hex 
                  << (int)pkt.setup.bRequest << "\n";
    }
}

USBFilter f;
f.showControl = true;
f.showBulk = false;
usb.set_filter(f);
usb.start_capture(ifaces[0], track_control);

Manual Threading

By default, start_capture() automatically spawns producer and consumer threads. For advanced use cases, you can take full control over thread management.

When to Use Manual Threading

  • Custom Thread Pools: Integrate capture into existing thread pool infrastructure
  • CPU Affinity: Pin producer/consumer to specific cores
  • Thread Priority: Set higher priority for producer thread
  • Priority Scheduling: Control scheduling with other components
  • Multi-Capture: Manage multiple captures with coordinated threads
  • Integration: Embed capture in larger multi-threaded applications

Basic Manual Threading

#include "WIND_USB/wind_usb.hpp"
using namespace WIND_USB;

auto& usb = USBCapture::instance();
auto devices = usb.list_devices();
auto ifaces = usb.list_capture_interfaces();

// Define callback
void on_packet(const USBPacket& pkt) {
    std::cout << "Packet: " << pkt.payload.size() << " bytes\n";
}

// Start capture WITHOUT automatic threads
usb.start_capture(ifaces[0], on_packet, false);  // autoThread=false

// Create your own threads
std::thread producer([&ifaces]() {
    USBCapture::instance().producer_loop(ifaces[0]);
});

std::thread consumer([]() {
    USBCapture::instance().consumer_loop();
});

// Application runs...
std::this_thread::sleep_for(std::chrono::seconds(30));

// Stop capture
usb.stop_capture();

// Wait for threads to finish
producer.join();
consumer.join();

With CPU Affinity (Windows-specific)

#include <windows.h>

void set_thread_affinity(std::thread& t, int core) {
    HANDLE h = (HANDLE)(t.native_handle());
    SetThreadAffinityMask(h, 1LL << core);
}

// Start capture manually
usb.start_capture(ifaces[0], on_packet, false);

// Create threads with affinity control
std::thread producer([&]() {
    USBCapture::instance().producer_loop(ifaces[0]);
});
std::thread consumer([]() {
    USBCapture::instance().consumer_loop();
});

// Pin threads to specific cores (requires CPU >= 2 cores)
set_thread_affinity(producer, 0);   // Core 0
set_thread_affinity(consumer, 1);   // Core 1

// Rest of application...
usb.stop_capture();
producer.join();
consumer.join();

API Methods for Manual Threading

Method Purpose Thread-Safe?
start_capture(..., false) Prepare capture without spawning threads Yes
producer_loop(iface) Read from device, parse packets, queue them No (call once)
consumer_loop() Process queue, filter, invoke callback No (call once)
stop_capture() Stop capture and signal threads to exit Yes
is_running() Check if capture is active Yes (atomic)
set_filter(f) Change filter live (works with manual threading) Yes

Complete Example

See examples/manual_threading/main.cpp for a full working example with:

  • Thread naming for debuggers
  • CPU affinity demonstration
  • Statistics tracking
  • Graceful shutdown
  • 30-second auto-stop

Build and run:

cmake -B build -G Ninja
cmake --build build
./build/examples/usb_manual_threading_example.exe

Advanced Filtering

Only Successful Transfers

USBFilter f;
f.showACK = true;
f.showNAK = f.showSTALL = false;
usb.set_filter(f);

Only Bulk Transfers

USBFilter f;
f.showBulk = true;
f.showControl = f.showInterrupt = f.showIsochronous = false;
usb.set_filter(f);

Only Device ? Host

USBFilter f;
f.showUpstream = true;
f.showDownstream = false;
usb.set_filter(f);

Dynamic Filter Changes

usb.start_capture(iface, callback);
std::this_thread::sleep_for(std::chrono::seconds(5));
usb.filter_by_device(10);  // Switch to device 10
std::this_thread::sleep_for(std::chrono::seconds(5));
usb.stop_capture();

Quick API Reference (Cheat Sheet)

Common Patterns

// Access singleton
auto& usb = USBCapture::instance();

// List devices
auto devices = usb.list_devices();

// Get interfaces
auto ifaces = usb.list_capture_interfaces();

// Define callback
void callback(const USBPacket& pkt) {
    // Process packet
}

// Start capturing
usb.start_capture(ifaces[0], callback);

// While capturing, change filter
USBFilter f;
f.filterDeviceAddress = 5;
usb.set_filter(f);

// Stop capture
usb.stop_capture();

Filter Examples

Goal Code
Device 5 only usb.filter_by_device(5);
Endpoint 1 IN only usb.filter_by_endpoint(0x81);
Bulk only f.showBulk=true; f.showControl=f.showInterrupt=f.showIsochronous=false;
Success only f.showACK=true; f.showNAK=f.showSTALL=false;
Upstream only f.showUpstream=true; f.showDownstream=false;

Info

  • Device address: 0=root hub, 1-127=actual devices
  • Endpoint bit 7: 1=IN, 0=OUT
  • Endpoint 0: Control (always bidirectional)
  • Filter 0: Means "no filter" (all)
  • Filter 0xFF: Means "all" (no restriction)

Troubleshooting

"No USBPcap interfaces found"

Causes: Not installed, not admin, not enabled

Fix:

"Permission denied"

Cause: Not running as Administrator

Fix: Right-click app ? Run as Administrator

No packets captured

Checks:

  • is_running() returns true?
  • Filter blocking packets?
  • Device generating traffic?

Debug:

auto devices = usb.list_devices();
for (const auto& d : devices)
    std::cout << d.friendlyName << " at " << (int)d.address << "\n";

Callback not triggered

Causes:

  • Capture not running
  • Filter too restrictive
  • No traffic on device

Solution: Reset filter to defaults

High CPU usage

Cause: Callback too slow or packet rate very high

Solution: Optimize callback or add batching


Architecture

Threading

  • Producer: Reads USBPcap, parses PCAP, queues packets
  • Consumer: Filters, invokes callback, backpressure (max 4096)
  • Main: Calls start/stop/filter

Memory

  • No packet storage (only callback)
  • User responsible if callback saves packets
  • Internal queue: max 4096 packets

Packet Format

  • Standard PCAP with USBPcap extensions
  • pcap_global_hdr (magic 0xa1b2c3d4)
  • pcap_rec_hdr with timestamps
  • USBPCAP_BUFFER_PACKET_HEADER
  • Raw packet data

Examples

For a complete real-world USB capture application, see examples/auto_threading/main.cpp.

Build:

cmake -B build -G Ninja
cmake --build build

Run:

./build/examples/usb_console_example.exe  # As Administrator

License & Attribution

WIND_USB Library License

WIND_USB is licensed under the BSD 2-Clause License.

See LICENSE file for full text.

Third-Party Dependencies

This library interfaces with and depends on:

1. USBPcap Driver

2. USBPcapCMD Tools (reference implementation)

Compliance Requirements

When using WIND_USB library:

  1. The WIND_USB library code itself is provided under the permissive BSD 2-Clause license
  2. The USBPcap driver (distributed separately by the USBPcap project) is licensed under GPLv2

If you redistribute or use this library in a distribution:

  • Include the LICENSE file with the library
  • Document the use of the GPLv2-licensed USBPcap driver
  • Provide information about how to obtain the USBPcap source
  • Acknowledge the USBPcap project in your documentation

For proprietary/commercial use:

  • The BSD 2-Clause license permits commercial use
  • Review GPLv2 terms if you're distributing the USBPcap driver with your application
  • Consider consulting legal counsel regarding GPLv2 compliance

Attribution

WIND_USB Library
©2025 WIND_USB Contributors
Uses USBPcap driver by Tomáš Kopeček (desowin)
https://desowin.org/usbpcap/

License Links


Your WIND_USB library is production-ready! ??

About

Windows USB packet capture library using USBPcap

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors