OpenVPN 3 Core Library
Loading...
Searching...
No Matches
ringbuffer.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11//
12
13#pragma once
14
15#include <windows.h>
16
17#include <string>
18#include <type_traits>
19
21#include <openvpn/common/rc.hpp>
23#include <openvpn/win/event.hpp>
24
25#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
26#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
27
28#define WINTUN_RING_CAPACITY 0x800000
29#define WINTUN_RING_TRAILING_BYTES 0x10000
30#define WINTUN_RING_FRAMING_SIZE 12
31#define WINTUN_MAX_PACKET_SIZE 0xffff
32#define WINTUN_PACKET_ALIGN 4
33
34namespace openvpn::TunWin {
36{
37 std::atomic_ulong head;
38 std::atomic_ulong tail;
39 std::atomic_long alertable;
41};
42
44{
45 struct
46 {
47 ULONG ring_size;
49 HANDLE tail_moved;
51};
52
53typedef openvpn_io::windows::object_handle AsioEvent;
54
55class RingBuffer : public RC<thread_unsafe_refcount>
56{
57 public:
59
60 RingBuffer(openvpn_io::io_context &io_context)
61 : send_ring_hmem(CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TUN_RING), NULL)),
62 receive_ring_hmem(CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TUN_RING), NULL)),
64 {
65 // sanity checks
66 static_assert((sizeof(TUN_RING) - sizeof(TUN_RING::data)) == 12, "sizeof(TUN_RING) is expected to be 12");
67#if !defined(ATOMIC_LONG_LOCK_FREE) || (ATOMIC_LONG_LOCK_FREE != 2)
68#error Atomic long is expected to be always lock-free
69#endif
70
71 send_ring_ = (TUN_RING *)MapViewOfFile(send_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
72 receive_ring_ = (TUN_RING *)MapViewOfFile(receive_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
73
74 HANDLE handle;
75 DuplicateHandle(GetCurrentProcess(),
77 GetCurrentProcess(),
78 &handle,
79 0,
80 FALSE,
81 DUPLICATE_SAME_ACCESS);
82 send_tail_moved_asio_event_.assign(handle);
83 }
84
85 RingBuffer(openvpn_io::io_context &io_context,
86 HANDLE client_process,
87 const std::string &send_ring_hmem_hex,
88 const std::string &receive_ring_hmem_hex,
89 const std::string &send_ring_tail_moved_hex,
90 const std::string &receive_ring_tail_moved_hex)
91 : send_tail_moved_asio_event_(io_context)
92 {
93 HANDLE remote_handle = BufHex::parse<HANDLE>(send_ring_hmem_hex, "send_ring_hmem");
94 HANDLE handle;
95 DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
96 send_ring_hmem.reset(handle);
97
98 remote_handle = BufHex::parse<HANDLE>(receive_ring_hmem_hex, "receive_ring_hmem");
99 DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
100 receive_ring_hmem.reset(handle);
101
102 remote_handle = BufHex::parse<HANDLE>(send_ring_tail_moved_hex, "send_ring_tail_moved");
103 DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
105
106 remote_handle = BufHex::parse<HANDLE>(receive_ring_tail_moved_hex, "receive_ring_tail_moved");
107 DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
109
110 send_ring_ = (TUN_RING *)MapViewOfFile(send_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
111 receive_ring_ = (TUN_RING *)MapViewOfFile(receive_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
112 }
113
114 RingBuffer(RingBuffer const &) = delete;
115 RingBuffer &operator=(RingBuffer const &) = delete;
116
118 {
119 UnmapViewOfFile(send_ring_);
120 UnmapViewOfFile(receive_ring_);
121 }
122
124 {
125 return send_ring_tail_moved_();
126 }
127
129 {
131 }
132
134 {
135 return send_ring_;
136 }
137
139 {
140 return receive_ring_;
141 }
142
147
148#ifdef HAVE_JSON
149 void serialize(Json::Value &json)
150 {
151 json["send_ring_hmem"] = BufHex::render(send_ring_hmem());
152 json["receive_ring_hmem"] = BufHex::render(receive_ring_hmem());
153 json["send_ring_tail_moved"] = BufHex::render(send_ring_tail_moved());
154 json["receive_ring_tail_moved"] = BufHex::render(receive_ring_tail_moved());
155 }
156#endif
157
158 protected:
164
167};
168} // namespace openvpn::TunWin
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
Win::ScopedHANDLE send_ring_hmem
Win::ScopedHANDLE receive_ring_hmem
RingBuffer(openvpn_io::io_context &io_context, HANDLE client_process, const std::string &send_ring_hmem_hex, const std::string &receive_ring_hmem_hex, const std::string &send_ring_tail_moved_hex, const std::string &receive_ring_tail_moved_hex)
void serialize(Json::Value &json)
RingBuffer(openvpn_io::io_context &io_context)
AsioEvent & send_tail_moved_asio_event()
RingBuffer & operator=(RingBuffer const &)=delete
RingBuffer(RingBuffer const &)=delete
RCPtr< RingBuffer > Ptr
void reset(HANDLE h)
Definition event.hpp:76
std::string render(const T obj)
Definition bufhex.hpp:24
DNS utilities for Windows.
openvpn_io::windows::object_handle AsioEvent
#define WINTUN_RING_TRAILING_BYTES
#define WINTUN_RING_CAPACITY
#define WINTUN_RING_FRAMING_SIZE
struct openvpn::TunWin::TUN_REGISTER_RINGS::@116 receive
struct openvpn::TunWin::TUN_REGISTER_RINGS::@116 send
std::atomic_ulong head
std::atomic_ulong tail
std::atomic_long alertable
UCHAR data[WINTUN_RING_CAPACITY+WINTUN_RING_TRAILING_BYTES+WINTUN_RING_FRAMING_SIZE]