20 #include <freerdp/config.h>
22 #include <freerdp/freerdp.h>
23 #include <freerdp/channels/log.h>
24 #include <freerdp/server/telemetry.h>
26 #define TAG CHANNELS_TAG("telemetry.server")
32 } eTelemetryChannelState;
36 TelemetryServerContext context;
41 void* telemetry_channel;
49 eTelemetryChannelState state;
54 static UINT telemetry_server_initialize(TelemetryServerContext* context, BOOL externalThread)
56 UINT error = CHANNEL_RC_OK;
57 telemetry_server* telemetry = (telemetry_server*)context;
59 WINPR_ASSERT(telemetry);
61 if (telemetry->isOpened)
63 WLog_WARN(TAG,
"Application error: TELEMETRY channel already initialized, "
64 "calling in this state is not possible!");
65 return ERROR_INVALID_STATE;
68 telemetry->externalThread = externalThread;
73 static UINT telemetry_server_open_channel(telemetry_server* telemetry)
75 TelemetryServerContext* context = &telemetry->context;
76 DWORD Error = ERROR_SUCCESS;
78 DWORD BytesReturned = 0;
79 PULONG pSessionId = NULL;
83 WINPR_ASSERT(telemetry);
85 if (WTSQuerySessionInformationA(telemetry->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
86 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
88 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
89 return ERROR_INTERNAL_ERROR;
92 telemetry->SessionId = (DWORD)*pSessionId;
93 WTSFreeMemory(pSessionId);
94 hEvent = WTSVirtualChannelManagerGetEventHandle(telemetry->context.vcm);
96 if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
98 Error = GetLastError();
99 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", Error);
103 telemetry->telemetry_channel = WTSVirtualChannelOpenEx(
104 telemetry->SessionId, TELEMETRY_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
105 if (!telemetry->telemetry_channel)
107 Error = GetLastError();
108 WLog_ERR(TAG,
"WTSVirtualChannelOpenEx failed with error %" PRIu32
"!", Error);
112 channelId = WTSChannelGetIdByHandle(telemetry->telemetry_channel);
114 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
117 WLog_ERR(TAG,
"context->ChannelIdAssigned failed!");
118 return ERROR_INTERNAL_ERROR;
124 static UINT telemetry_server_recv_rdp_telemetry_pdu(TelemetryServerContext* context,
wStream* s)
127 UINT error = CHANNEL_RC_OK;
129 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
130 return ERROR_NO_DATA;
132 Stream_Read_UINT32(s, pdu.PromptForCredentialsMillis);
133 Stream_Read_UINT32(s, pdu.PromptForCredentialsDoneMillis);
134 Stream_Read_UINT32(s, pdu.GraphicsChannelOpenedMillis);
135 Stream_Read_UINT32(s, pdu.FirstGraphicsReceivedMillis);
137 IFCALLRET(context->RdpTelemetry, error, context, &pdu);
139 WLog_ERR(TAG,
"context->RdpTelemetry failed with error %" PRIu32
"", error);
144 static UINT telemetry_process_message(telemetry_server* telemetry)
147 UINT error = ERROR_INTERNAL_ERROR;
148 ULONG BytesReturned = 0;
153 WINPR_ASSERT(telemetry);
154 WINPR_ASSERT(telemetry->telemetry_channel);
156 s = telemetry->buffer;
159 Stream_SetPosition(s, 0);
160 rc = WTSVirtualChannelRead(telemetry->telemetry_channel, 0, NULL, 0, &BytesReturned);
164 if (BytesReturned < 1)
166 error = CHANNEL_RC_OK;
170 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
172 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
173 error = CHANNEL_RC_NO_MEMORY;
177 if (WTSVirtualChannelRead(telemetry->telemetry_channel, 0, Stream_BufferAs(s,
char),
178 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
180 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
184 Stream_SetLength(s, BytesReturned);
185 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
186 return ERROR_NO_DATA;
188 Stream_Read_UINT8(s, MessageId);
189 Stream_Read_UINT8(s, Length);
194 error = telemetry_server_recv_rdp_telemetry_pdu(&telemetry->context, s);
197 WLog_ERR(TAG,
"telemetry_process_message: unknown MessageId %" PRIu8
"", MessageId);
203 WLog_ERR(TAG,
"Response failed with error %" PRIu32
"!", error);
208 static UINT telemetry_server_context_poll_int(TelemetryServerContext* context)
210 telemetry_server* telemetry = (telemetry_server*)context;
211 UINT error = ERROR_INTERNAL_ERROR;
213 WINPR_ASSERT(telemetry);
215 switch (telemetry->state)
217 case TELEMETRY_INITIAL:
218 error = telemetry_server_open_channel(telemetry);
220 WLog_ERR(TAG,
"telemetry_server_open_channel failed with error %" PRIu32
"!",
223 telemetry->state = TELEMETRY_OPENED;
225 case TELEMETRY_OPENED:
226 error = telemetry_process_message(telemetry);
235 static HANDLE telemetry_server_get_channel_handle(telemetry_server* telemetry)
238 DWORD BytesReturned = 0;
239 HANDLE ChannelEvent = NULL;
241 WINPR_ASSERT(telemetry);
243 if (WTSVirtualChannelQuery(telemetry->telemetry_channel, WTSVirtualEventHandle, &buffer,
244 &BytesReturned) == TRUE)
246 if (BytesReturned ==
sizeof(HANDLE))
247 CopyMemory(&ChannelEvent, buffer,
sizeof(HANDLE));
249 WTSFreeMemory(buffer);
255 static DWORD WINAPI telemetry_server_thread_func(LPVOID arg)
258 HANDLE events[2] = { 0 };
259 telemetry_server* telemetry = (telemetry_server*)arg;
260 UINT error = CHANNEL_RC_OK;
263 WINPR_ASSERT(telemetry);
266 events[nCount++] = telemetry->stopEvent;
268 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
270 switch (telemetry->state)
272 case TELEMETRY_INITIAL:
273 error = telemetry_server_context_poll_int(&telemetry->context);
274 if (error == CHANNEL_RC_OK)
276 events[1] = telemetry_server_get_channel_handle(telemetry);
280 case TELEMETRY_OPENED:
281 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
286 case WAIT_OBJECT_0 + 1:
288 error = telemetry_server_context_poll_int(&telemetry->context);
293 error = ERROR_INTERNAL_ERROR;
302 (void)WTSVirtualChannelClose(telemetry->telemetry_channel);
303 telemetry->telemetry_channel = NULL;
305 if (error && telemetry->context.rdpcontext)
306 setChannelError(telemetry->context.rdpcontext, error,
307 "telemetry_server_thread_func reported an error");
313 static UINT telemetry_server_open(TelemetryServerContext* context)
315 telemetry_server* telemetry = (telemetry_server*)context;
317 WINPR_ASSERT(telemetry);
319 if (!telemetry->externalThread && (telemetry->thread == NULL))
321 telemetry->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
322 if (!telemetry->stopEvent)
324 WLog_ERR(TAG,
"CreateEvent failed!");
325 return ERROR_INTERNAL_ERROR;
328 telemetry->thread = CreateThread(NULL, 0, telemetry_server_thread_func, telemetry, 0, NULL);
329 if (!telemetry->thread)
331 WLog_ERR(TAG,
"CreateThread failed!");
332 (void)CloseHandle(telemetry->stopEvent);
333 telemetry->stopEvent = NULL;
334 return ERROR_INTERNAL_ERROR;
337 telemetry->isOpened = TRUE;
339 return CHANNEL_RC_OK;
342 static UINT telemetry_server_close(TelemetryServerContext* context)
344 UINT error = CHANNEL_RC_OK;
345 telemetry_server* telemetry = (telemetry_server*)context;
347 WINPR_ASSERT(telemetry);
349 if (!telemetry->externalThread && telemetry->thread)
351 (void)SetEvent(telemetry->stopEvent);
353 if (WaitForSingleObject(telemetry->thread, INFINITE) == WAIT_FAILED)
355 error = GetLastError();
356 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
360 (void)CloseHandle(telemetry->thread);
361 (void)CloseHandle(telemetry->stopEvent);
362 telemetry->thread = NULL;
363 telemetry->stopEvent = NULL;
365 if (telemetry->externalThread)
367 if (telemetry->state != TELEMETRY_INITIAL)
369 (void)WTSVirtualChannelClose(telemetry->telemetry_channel);
370 telemetry->telemetry_channel = NULL;
371 telemetry->state = TELEMETRY_INITIAL;
374 telemetry->isOpened = FALSE;
379 static UINT telemetry_server_context_poll(TelemetryServerContext* context)
381 telemetry_server* telemetry = (telemetry_server*)context;
383 WINPR_ASSERT(telemetry);
385 if (!telemetry->externalThread)
386 return ERROR_INTERNAL_ERROR;
388 return telemetry_server_context_poll_int(context);
391 static BOOL telemetry_server_context_handle(TelemetryServerContext* context, HANDLE* handle)
393 telemetry_server* telemetry = (telemetry_server*)context;
395 WINPR_ASSERT(telemetry);
396 WINPR_ASSERT(handle);
398 if (!telemetry->externalThread)
400 if (telemetry->state == TELEMETRY_INITIAL)
403 *handle = telemetry_server_get_channel_handle(telemetry);
408 TelemetryServerContext* telemetry_server_context_new(HANDLE vcm)
410 telemetry_server* telemetry = (telemetry_server*)calloc(1,
sizeof(telemetry_server));
415 telemetry->context.vcm = vcm;
416 telemetry->context.Initialize = telemetry_server_initialize;
417 telemetry->context.Open = telemetry_server_open;
418 telemetry->context.Close = telemetry_server_close;
419 telemetry->context.Poll = telemetry_server_context_poll;
420 telemetry->context.ChannelHandle = telemetry_server_context_handle;
422 telemetry->buffer = Stream_New(NULL, 4096);
423 if (!telemetry->buffer)
426 return &telemetry->context;
428 WINPR_PRAGMA_DIAG_PUSH
429 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
430 telemetry_server_context_free(&telemetry->context);
431 WINPR_PRAGMA_DIAG_POP
435 void telemetry_server_context_free(TelemetryServerContext* context)
437 telemetry_server* telemetry = (telemetry_server*)context;
441 telemetry_server_close(context);
442 Stream_Free(telemetry->buffer, TRUE);