OpenVPN 3 Core Library
Loading...
Searching...
No Matches
udplink.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// Low-level UDP transport object.
13
14#ifndef OPENVPN_TRANSPORT_UDPLINK_H
15#define OPENVPN_TRANSPORT_UDPLINK_H
16
17#include <memory>
18
19#include <openvpn/io/io.hpp>
20
22#include <openvpn/common/rc.hpp>
25
26#ifdef OPENVPN_GREMLIN
28#endif
29
30#if defined(OPENVPN_DEBUG_UDPLINK) && OPENVPN_DEBUG_UDPLINK >= 1
31#define OPENVPN_LOG_UDPLINK_ERROR(x) OPENVPN_LOG(x)
32#else
33#define OPENVPN_LOG_UDPLINK_ERROR(x)
34#endif
35
36#if defined(OPENVPN_DEBUG_UDPLINK) && OPENVPN_DEBUG_UDPLINK >= 3
37#define OPENVPN_LOG_UDPLINK_VERBOSE(x) OPENVPN_LOG(x)
38#else
39#define OPENVPN_LOG_UDPLINK_VERBOSE(x)
40#endif
41
42namespace openvpn::UDPTransport {
43
44typedef openvpn_io::ip::udp::endpoint AsioEndpoint;
45
46enum
47{
50};
51
53{
54 typedef std::unique_ptr<PacketFrom> SPtr;
57};
58
59template <typename ReadHandler>
60class UDPLink : public RC<thread_unsafe_refcount>
61{
62 public:
64
65 UDPLink(ReadHandler read_handler_arg,
66 openvpn_io::ip::udp::socket &socket_arg,
67 const Frame::Context &frame_context_arg,
68 const SessionStats::Ptr &stats_arg)
69 : socket(socket_arg),
70 halt(false),
71 read_handler(read_handler_arg),
72 frame_context(frame_context_arg),
73 stats(stats_arg)
74 {
75 }
76
77#ifdef OPENVPN_GREMLIN
78 void gremlin_config(const Gremlin::Config::Ptr &config)
79 {
80 if (config)
81 gremlin.reset(new Gremlin::SendRecvQueue(socket.get_executor().context(), config, false));
82 }
83#endif
84
85 // Returns 0 on success, or a system error code on error.
86 // May also return SEND_PARTIAL or SEND_SOCKET_HALTED.
87 int send(const Buffer &buf, const AsioEndpoint *endpoint)
88 {
89#ifdef OPENVPN_GREMLIN
90 if (gremlin)
91 {
92 gremlin_send(buf, endpoint);
93 return 0;
94 }
95 else
96#endif
97 return do_send(buf, endpoint);
98 }
99
100 void start(const int n_parallel)
101 {
102 if (!halt)
103 {
104 for (int i = 0; i < n_parallel; i++)
105 queue_read(nullptr);
106 }
107 }
108
109 void stop()
110 {
111 halt = true;
112#ifdef OPENVPN_GREMLIN
113 if (gremlin)
114 gremlin->stop();
115#endif
116 }
117
118 void reset_align_adjust(const size_t align_adjust)
119 {
120 frame_context.reset_align_adjust(align_adjust);
121 }
122
124 {
125 stop();
126 }
127
128 private:
129 void queue_read(PacketFrom *udpfrom)
130 {
131 OPENVPN_LOG_UDPLINK_VERBOSE("UDPLink::queue_read");
132 if (!udpfrom)
133 udpfrom = new PacketFrom();
134 frame_context.prepare(udpfrom->buf);
135 socket.async_receive_from(frame_context.mutable_buffer(udpfrom->buf),
136 udpfrom->sender_endpoint,
137 [self = Ptr(this), udpfrom = PacketFrom::SPtr(udpfrom)](const openvpn_io::error_code &error, const size_t bytes_recvd) mutable
138 {
140 self->handle_read(std::move(udpfrom), error, bytes_recvd);
141 });
142 }
143
144 void handle_read(PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
145 {
146 OPENVPN_LOG_UDPLINK_VERBOSE("UDPLink::handle_read: " << error.message());
147 if (!halt)
148 {
149 if (bytes_recvd)
150 {
151 if (!error)
152 {
153 OPENVPN_LOG_UDPLINK_VERBOSE("UDP[" << bytes_recvd << "] from " << pfp->sender_endpoint);
154 pfp->buf.set_size(bytes_recvd);
157#ifdef OPENVPN_GREMLIN
158 if (gremlin)
159 gremlin_recv(pfp);
160 else
161#endif
162 read_handler->udp_read_handler(pfp);
163 }
164 else
165 {
166 OPENVPN_LOG_UDPLINK_ERROR("UDP recv error: " << error.message());
168 }
169 }
170 if (!halt)
171 queue_read(pfp.release()); // reuse PacketFrom object if still available
172 }
173 }
174
175 int do_send(const Buffer &buf, const AsioEndpoint *endpoint)
176 {
177 if (!halt)
178 {
179 try
180 {
181 const size_t wrote = endpoint
182 ? socket.send_to(buf.const_buffer(), *endpoint)
183 : socket.send(buf.const_buffer());
186 if (wrote == buf.size())
187 return 0;
188 else
189 {
190 OPENVPN_LOG_UDPLINK_ERROR("UDP partial send error");
192 return SEND_PARTIAL;
193 }
194 }
195 catch (openvpn_io::system_error &e)
196 {
197 OPENVPN_LOG_UDPLINK_ERROR("UDP send exception: " << e.what());
199 return e.code().value();
200 }
201 }
202 else
203 return SEND_SOCKET_HALTED;
204 }
205
206#ifdef OPENVPN_GREMLIN
207 void gremlin_send(const Buffer &buf, const AsioEndpoint *endpoint)
208 {
209 std::unique_ptr<AsioEndpoint> ep;
210 if (endpoint)
211 ep.reset(new AsioEndpoint(*endpoint));
212 gremlin->send_queue([self = Ptr(this), buf = BufferAllocated(buf), ep = std::move(ep)]() mutable
213 {
214 if (!self->halt)
215 self->do_send(buf, ep.get()); });
216 }
217
218 void gremlin_recv(PacketFrom::SPtr &pfp)
219 {
220 gremlin->recv_queue([self = Ptr(this), pfp = std::move(pfp)]() mutable
221 {
222 if (!self->halt)
223 self->read_handler->udp_read_handler(pfp); });
224 }
225#endif
226
227 openvpn_io::ip::udp::socket &socket;
228 bool halt;
229 ReadHandler read_handler;
232
233#ifdef OPENVPN_GREMLIN
234 std::unique_ptr<Gremlin::SendRecvQueue> gremlin;
235#endif
236};
237} // namespace openvpn::UDPTransport
238
239#endif
#define OPENVPN_ASYNC_HANDLER
Definition bigmutex.hpp:36
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
Definition buffer.hpp:1312
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
size_t prepare(Buffer &buf) const
Definition frame.hpp:116
void reset_align_adjust(const size_t align_adjust)
Definition frame.hpp:88
openvpn_io::mutable_buffer mutable_buffer(Buffer &buf) const
Definition frame.hpp:190
The smart pointer class.
Definition rc.hpp:119
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
virtual void error(const size_t type, const std::string *text=nullptr)
void inc_stat(const size_t type, const count_t value)
@ NETWORK_SEND_ERROR
Definition error.hpp:26
@ NETWORK_RECV_ERROR
Definition error.hpp:24
openvpn_io::ip::udp::endpoint AsioEndpoint
Definition udplink.hpp:44
BufferAllocatedType< unsigned char > BufferAllocated
Definition buffer.hpp:1897
std::unique_ptr< PacketFrom > SPtr
Definition udplink.hpp:54
static const char config[]