FreeRDP
Loading...
Searching...
No Matches
TestDrdynvcUnknownChannel.c
1
19#include <stdio.h>
20#include <string.h>
21
22#include <winpr/crt.h>
23#include <winpr/stream.h>
24#include <winpr/wlog.h>
25
26#include <freerdp/addin.h>
27#include <freerdp/client.h>
28#include <freerdp/client/channels.h>
29#include <freerdp/channels/drdynvc.h>
30#include <freerdp/dvc.h>
31#include <freerdp/svc.h>
32
33#include "../drdynvc_main.h"
34
35#define TEST_LISTENER_NAME "test"
36#define TEST_OPEN_HANDLE 1
37
38typedef struct
39{
40 PCHANNEL_INIT_EVENT_EX_FN initEvent;
41 PCHANNEL_OPEN_EVENT_EX_FN openEvent;
42 LPVOID userParam;
43 INT32 lastCreateStatus;
44 BOOL haveCreateStatus;
45} test_vc;
46
47static test_vc g_vc = WINPR_C_ARRAY_INIT;
48static int g_initHandle = 0;
49
50static UINT VCAPITYPE test_init_ex(LPVOID lpUserParam, WINPR_ATTR_UNUSED LPVOID clientContext,
51 WINPR_ATTR_UNUSED LPVOID pInitHandle,
52 WINPR_ATTR_UNUSED PCHANNEL_DEF pChannel,
53 WINPR_ATTR_UNUSED INT channelCount,
54 WINPR_ATTR_UNUSED ULONG versionRequested,
55 PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
56{
57 g_vc.userParam = lpUserParam;
58 g_vc.initEvent = pChannelInitEventProcEx;
59 return CHANNEL_RC_OK;
60}
61
62static UINT VCAPITYPE test_open_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle, LPDWORD pOpenHandle,
63 WINPR_ATTR_UNUSED PCHAR pChannelName,
64 PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx)
65{
66 *pOpenHandle = TEST_OPEN_HANDLE;
67 g_vc.openEvent = pChannelOpenEventProcEx;
68 return CHANNEL_RC_OK;
69}
70
71static UINT VCAPITYPE test_close_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle,
72 WINPR_ATTR_UNUSED DWORD openHandle)
73{
74 return CHANNEL_RC_OK;
75}
76
77static UINT VCAPITYPE test_write_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle, DWORD openHandle,
78 LPVOID pData, ULONG dataLength, LPVOID pUserData)
79{
80 /* CREATE_RESPONSE_PDU with a 1 byte ChannelId: header, ChannelId, CreationStatus */
81 const BYTE* data = pData;
82 if (data && (dataLength == 6) && ((data[0] >> 4) == CREATE_REQUEST_PDU))
83 {
84 g_vc.lastCreateStatus =
85 (INT32)(data[2] | (data[3] << 8) | (data[4] << 16) | ((UINT32)data[5] << 24));
86 g_vc.haveCreateStatus = TRUE;
87 }
88
89 /* the channel releases the written stream on CHANNEL_EVENT_WRITE_COMPLETE */
90 if (g_vc.openEvent)
91 g_vc.openEvent(g_vc.userParam, openHandle, CHANNEL_EVENT_WRITE_COMPLETE, pUserData, 0, 0,
92 0);
93 else
94 Stream_Release((wStream*)pUserData);
95 return CHANNEL_RC_OK;
96}
97
98static UINT test_dvc_on_data_received(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pCallback,
99 WINPR_ATTR_UNUSED wStream* data)
100{
101 return CHANNEL_RC_OK;
102}
103
104static UINT test_dvc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
105{
106 free(pChannelCallback);
107 return CHANNEL_RC_OK;
108}
109
110static UINT test_on_new_channel_connection(WINPR_ATTR_UNUSED IWTSListenerCallback* pListener,
111 WINPR_ATTR_UNUSED IWTSVirtualChannel* pChannel,
112 WINPR_ATTR_UNUSED BYTE* Data, BOOL* pbAccept,
113 IWTSVirtualChannelCallback** ppCallback)
114{
115 IWTSVirtualChannelCallback* callback = calloc(1, sizeof(IWTSVirtualChannelCallback));
116 if (!callback)
117 return CHANNEL_RC_NO_MEMORY;
118
119 callback->OnDataReceived = test_dvc_on_data_received;
120 callback->OnClose = test_dvc_on_close;
121 *pbAccept = TRUE;
122 *ppCallback = callback;
123 return CHANNEL_RC_OK;
124}
125
126static IWTSListenerCallback g_listener = { test_on_new_channel_connection, nullptr };
127
128/* Sends a CREATE_REQUEST_PDU (1 byte ChannelId) and returns the client's CreationStatus. */
129static BOOL send_create_request(BYTE channelId, const char* name, INT32* status)
130{
131 BYTE pdu[64] = WINPR_C_ARRAY_INIT;
132 const size_t nameLength = strlen(name) + 1;
133 if (nameLength + 2 > sizeof(pdu))
134 return FALSE;
135
136 pdu[0] = CREATE_REQUEST_PDU << 4;
137 pdu[1] = channelId;
138 memcpy(&pdu[2], name, nameLength);
139
140 g_vc.haveCreateStatus = FALSE;
141 g_vc.openEvent(g_vc.userParam, TEST_OPEN_HANDLE, CHANNEL_EVENT_DATA_RECEIVED, pdu,
142 (UINT32)(nameLength + 2), (UINT32)(nameLength + 2),
143 CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST);
144 if (!g_vc.haveCreateStatus)
145 return FALSE;
146 *status = g_vc.lastCreateStatus;
147 return TRUE;
148}
149
150int TestDrdynvcUnknownChannel(int argc, char* argv[])
151{
152 int rc = -1;
153 WINPR_UNUSED(argc);
154 WINPR_UNUSED(argv);
155
156 RDP_CLIENT_ENTRY_POINTS entry = WINPR_C_ARRAY_INIT;
157 entry.Version = RDP_CLIENT_INTERFACE_VERSION;
158 entry.Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
159 entry.ContextSize = sizeof(rdpContext);
160
161 rdpContext* context = freerdp_client_context_new(&entry);
162 if (!context)
163 return -1;
164
165 /* process PDUs on the calling thread instead of the channel worker thread */
166 if (!freerdp_settings_set_bool(context->settings, FreeRDP_SynchronousDynamicChannels, TRUE))
167 goto fail;
168
169 {
170 PVIRTUALCHANNELENTRYEX entryEx =
171 WINPR_FUNC_PTR_CAST(freerdp_channels_load_static_addin_entry(
172 DRDYNVC_SVC_CHANNEL_NAME, nullptr, nullptr,
173 FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX),
174 PVIRTUALCHANNELENTRYEX);
175 if (!entryEx)
176 goto fail;
177
178 CHANNEL_ENTRY_POINTS_FREERDP_EX entryPoints = WINPR_C_ARRAY_INIT;
179 entryPoints.cbSize = sizeof(entryPoints);
180 entryPoints.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000;
181 entryPoints.pVirtualChannelInitEx = test_init_ex;
182 entryPoints.pVirtualChannelOpenEx = test_open_ex;
183 entryPoints.pVirtualChannelCloseEx = test_close_ex;
184 entryPoints.pVirtualChannelWriteEx = test_write_ex;
185 entryPoints.MagicNumber = FREERDP_CHANNEL_MAGIC_NUMBER;
186 entryPoints.context = context;
187
188 if (!entryEx((PCHANNEL_ENTRY_POINTS_EX)&entryPoints, &g_initHandle) || !g_vc.initEvent)
189 goto fail;
190 }
191
192 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_INITIALIZED, nullptr, 0);
193 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_CONNECTED, nullptr, 0);
194
195 {
196 drdynvcPlugin* drdynvc = (drdynvcPlugin*)g_vc.userParam;
197 IWTSVirtualChannelManager* mgr = drdynvc->channel_mgr;
198 INT32 status = 0;
199
200 if (!mgr || !g_vc.openEvent ||
201 (mgr->CreateListener(mgr, TEST_LISTENER_NAME, 0, &g_listener, nullptr) !=
202 CHANNEL_RC_OK))
203 goto disconnect;
204
205 /* Unsupported channel: refused, repeatedly, with the same answer. */
206 for (size_t x = 0; x < 2; x++)
207 {
208 if (!send_create_request(5, "unsupported", &status) || (status != STATUS_NOT_FOUND))
209 {
210 (void)fprintf(stderr, "unsupported channel #%" PRIuz ": status 0x%08" PRIx32 "\n",
211 x, (UINT32)status);
212 goto disconnect;
213 }
214 }
215
216 /* The server may reuse that ChannelId for a channel the client supports. */
217 if (!send_create_request(5, TEST_LISTENER_NAME, &status) || (status != 0))
218 {
219 (void)fprintf(stderr, "supported channel after reuse: status 0x%08" PRIx32 "\n",
220 (UINT32)status);
221 goto disconnect;
222 }
223 rc = 0;
224 }
225
226disconnect:
227 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_DISCONNECTED, nullptr, 0);
228 /* frees the plugin */
229 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_TERMINATED, nullptr, 0);
230
231fail:
232 freerdp_client_context_free(context);
233 return rc;
234}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
Definition svc.h:60