Coverage Report

Created: 2026-10-28 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/rdpemt.h
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Multitransport tunnel ([MS-RDPEMT]) over reliable RDP-UDP
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#ifndef FREERDP_LIB_CORE_RDPEMT_H
19
#define FREERDP_LIB_CORE_RDPEMT_H
20
21
#include <winpr/wtypes.h>
22
#include <winpr/winsock.h>
23
#include <winpr/wlog.h>
24
#include <winpr/stream.h>
25
#include <winpr/collections.h>
26
27
#include <freerdp/config.h>
28
#include <freerdp/api.h>
29
30
/** @brief A client side multitransport tunnel.
31
 *
32
 * Runs its own thread: it brings up a reliable RDP-UDP connection, a TLS session inside it, and
33
 * the [MS-RDPEMT] tunnel inside that, and then carries tunnel data both ways.
34
 */
35
typedef struct rdp_emt rdpEmt;
36
37
typedef enum
38
{
39
  RDPEMT_EVENT_READY,             /**< the server accepted the Tunnel Create Request */
40
  RDPEMT_EVENT_FAILED,            /**< the tunnel could not be set up, or broke down */
41
  RDPEMT_EVENT_DATA,              /**< HigherLayerData of one Tunnel Data PDU */
42
  RDPEMT_EVENT_AUTODETECT_REQUEST /**< one RDP_TUNNEL_SUBHEADER of type
43
                                       TYPE_ID_AUTODETECT_REQUEST, from SubHeaderLength on */
44
} RDPEMT_EVENT;
45
46
/** Called on the tunnel thread. The data of RDPEMT_EVENT_DATA and
47
 * RDPEMT_EVENT_AUTODETECT_REQUEST is only valid during the call. */
48
typedef void (*rdpEmtEventFn)(void* custom, rdpEmt* emt, RDPEMT_EVENT event, const BYTE* data,
49
                              size_t length);
50
51
/** Called on the tunnel thread instead of RDPEMT_EVENT_DATA, see rdpemt_set_receiver(). It owns
52
 * \b s, sealed and at position 0. \b FALSE fails the tunnel. */
53
typedef BOOL (*rdpEmtReceiverFn)(void* custom, wStream* s);
54
55
#if defined(WITH_RDPEUDP)
56
57
/** UDP multitransport is compiled in (-DWITH_RDPEUDP=ON, which requires OpenSSL). */
58
WINPR_ATTR_NODISCARD
59
FREERDP_LOCAL BOOL rdpemt_is_supported(void);
60
61
FREERDP_LOCAL void rdpemt_free(rdpEmt* emt);
62
63
/**
64
 * @param requestId the requestId of the Initiate Multitransport Request PDU
65
 * @param cookie the 16 byte securityCookie of that request
66
 * @param hostname the server name, used for SNI
67
 * @param publicKey the public key of the server certificate on the main connection. The TLS
68
 *        session inside the tunnel is only accepted when it presents the same key.
69
 */
70
WINPR_ATTR_MALLOC(rdpemt_free, 1)
71
WINPR_ATTR_NODISCARD
72
FREERDP_LOCAL rdpEmt* rdpemt_new(wLog* log, UINT32 requestId, const BYTE* cookie,
73
                                 const char* hostname, const BYTE* publicKey,
74
                                 size_t publicKeyLength, rdpEmtEventFn callback, void* custom);
75
76
WINPR_ATTR_NODISCARD
77
FREERDP_LOCAL BOOL rdpemt_start(rdpEmt* emt, const struct sockaddr* addr, size_t addrlen);
78
79
/** Sends one Tunnel Data PDU. Thread safe. */
80
WINPR_ATTR_NODISCARD
81
FREERDP_LOCAL BOOL rdpemt_send_data(rdpEmt* emt, const BYTE* data, size_t length);
82
83
/** Sends one RDP_TUNNEL_SUBHEADER, from SubHeaderLength on, in a Tunnel Data PDU without
84
 * HigherLayerData. Thread safe. */
85
WINPR_ATTR_NODISCARD
86
FREERDP_LOCAL BOOL rdpemt_send_subheader(rdpEmt* emt, const BYTE* subHeader, size_t length);
87
88
WINPR_ATTR_NODISCARD
89
FREERDP_LOCAL UINT32 rdpemt_get_request_id(const rdpEmt* emt);
90
91
/** Hands tunnel data to \b receiver from now on, instead of raising RDPEMT_EVENT_DATA. Thread
92
 * safe.
93
 * @param pending the queue the events go to. Without a receiver set already, it is only set
94
 *        while pending is empty, so data does not overtake data still waiting there.
95
 * @return \b FALSE if data may still wait in pending */
96
WINPR_ATTR_NODISCARD
97
FREERDP_LOCAL BOOL rdpemt_set_receiver(rdpEmt* emt, rdpEmtReceiverFn receiver, void* custom,
98
                                       wQueue* pending);
99
100
/** Raises RDPEMT_EVENT_DATA again. Once this returns, the tunnel thread is out of the receiver
101
 * it had. Thread safe. */
102
FREERDP_LOCAL void rdpemt_clear_receiver(rdpEmt* emt);
103
104
/** The tunnel data handed to the receiver since the last call, after the tunnel headers. Thread
105
 * safe. */
106
WINPR_ATTR_NODISCARD
107
FREERDP_LOCAL UINT32 rdpemt_take_direct_bytes(rdpEmt* emt);
108
109
#else
110
111
/* Built without UDP multitransport: requests are declined and no tunnel ever exists. */
112
WINPR_ATTR_NODISCARD
113
static inline BOOL rdpemt_is_supported(void)
114
83
{
115
83
  return FALSE;
116
83
}
117
118
static inline void rdpemt_free(WINPR_ATTR_UNUSED rdpEmt* emt)
119
26.2k
{
120
26.2k
}
121
122
WINPR_ATTR_NODISCARD
123
static inline rdpEmt*
124
rdpemt_new(WINPR_ATTR_UNUSED wLog* log, WINPR_ATTR_UNUSED UINT32 requestId,
125
           WINPR_ATTR_UNUSED const BYTE* cookie, WINPR_ATTR_UNUSED const char* hostname,
126
           WINPR_ATTR_UNUSED const BYTE* publicKey, WINPR_ATTR_UNUSED size_t publicKeyLength,
127
           WINPR_ATTR_UNUSED rdpEmtEventFn callback, WINPR_ATTR_UNUSED void* custom)
128
0
{
129
0
  return nullptr;
130
0
}
131
132
WINPR_ATTR_NODISCARD
133
static inline BOOL rdpemt_start(WINPR_ATTR_UNUSED rdpEmt* emt,
134
                                WINPR_ATTR_UNUSED const struct sockaddr* addr,
135
                                WINPR_ATTR_UNUSED size_t addrlen)
136
0
{
137
0
  return FALSE;
138
0
}
139
140
WINPR_ATTR_NODISCARD
141
static inline BOOL rdpemt_send_data(WINPR_ATTR_UNUSED rdpEmt* emt,
142
                                    WINPR_ATTR_UNUSED const BYTE* data,
143
                                    WINPR_ATTR_UNUSED size_t length)
144
0
{
145
0
  return FALSE;
146
0
}
147
148
WINPR_ATTR_NODISCARD
149
static inline BOOL rdpemt_send_subheader(WINPR_ATTR_UNUSED rdpEmt* emt,
150
                                         WINPR_ATTR_UNUSED const BYTE* subHeader,
151
                                         WINPR_ATTR_UNUSED size_t length)
152
0
{
153
0
  return FALSE;
154
0
}
155
156
WINPR_ATTR_NODISCARD
157
static inline UINT32 rdpemt_get_request_id(WINPR_ATTR_UNUSED const rdpEmt* emt)
158
0
{
159
0
  return 0;
160
0
}
161
162
WINPR_ATTR_NODISCARD
163
static inline BOOL rdpemt_set_receiver(WINPR_ATTR_UNUSED rdpEmt* emt,
164
                                       WINPR_ATTR_UNUSED rdpEmtReceiverFn receiver,
165
                                       WINPR_ATTR_UNUSED void* custom,
166
                                       WINPR_ATTR_UNUSED wQueue* pending)
167
0
{
168
0
  return FALSE;
169
0
}
170
171
static inline void rdpemt_clear_receiver(WINPR_ATTR_UNUSED rdpEmt* emt)
172
0
{
173
0
}
174
175
#endif
176
177
#endif /* FREERDP_LIB_CORE_RDPEMT_H */