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);
190 if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
191 return ERROR_NO_DATA;
196 error = telemetry_server_recv_rdp_telemetry_pdu(&telemetry->context, s);
199 WLog_ERR(TAG,
"telemetry_process_message: unknown MessageId %" PRIu8
"", MessageId);
205 WLog_ERR(TAG,
"Response failed with error %" PRIu32
"!", error);
210 static UINT telemetry_server_context_poll_int(TelemetryServerContext* context)
212 telemetry_server* telemetry = (telemetry_server*)context;
213 UINT error = ERROR_INTERNAL_ERROR;
215 WINPR_ASSERT(telemetry);
217 switch (telemetry->state)
219 case TELEMETRY_INITIAL:
220 error = telemetry_server_open_channel(telemetry);
222 WLog_ERR(TAG,
"telemetry_server_open_channel failed with error %" PRIu32
"!",
225 telemetry->state = TELEMETRY_OPENED;
227 case TELEMETRY_OPENED:
228 error = telemetry_process_message(telemetry);
237 static HANDLE telemetry_server_get_channel_handle(telemetry_server* telemetry)
240 DWORD BytesReturned = 0;
241 HANDLE ChannelEvent = NULL;
243 WINPR_ASSERT(telemetry);
245 if (WTSVirtualChannelQuery(telemetry->telemetry_channel, WTSVirtualEventHandle, &buffer,
246 &BytesReturned) == TRUE)
248 if (BytesReturned ==
sizeof(HANDLE))
249 ChannelEvent = *(HANDLE*)buffer;
251 WTSFreeMemory(buffer);
257 static DWORD WINAPI telemetry_server_thread_func(LPVOID arg)
260 HANDLE events[2] = { 0 };
261 telemetry_server* telemetry = (telemetry_server*)arg;
262 UINT error = CHANNEL_RC_OK;
265 WINPR_ASSERT(telemetry);
268 events[nCount++] = telemetry->stopEvent;
270 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
272 switch (telemetry->state)
274 case TELEMETRY_INITIAL:
275 error = telemetry_server_context_poll_int(&telemetry->context);
276 if (error == CHANNEL_RC_OK)
278 events[1] = telemetry_server_get_channel_handle(telemetry);
282 case TELEMETRY_OPENED:
283 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
288 case WAIT_OBJECT_0 + 1:
290 error = telemetry_server_context_poll_int(&telemetry->context);
295 error = ERROR_INTERNAL_ERROR;
304 (void)WTSVirtualChannelClose(telemetry->telemetry_channel);
305 telemetry->telemetry_channel = NULL;
307 if (error && telemetry->context.rdpcontext)
308 setChannelError(telemetry->context.rdpcontext, error,
309 "telemetry_server_thread_func reported an error");
315 static UINT telemetry_server_open(TelemetryServerContext* context)
317 telemetry_server* telemetry = (telemetry_server*)context;
319 WINPR_ASSERT(telemetry);
321 if (!telemetry->externalThread && (telemetry->thread == NULL))
323 telemetry->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
324 if (!telemetry->stopEvent)
326 WLog_ERR(TAG,
"CreateEvent failed!");
327 return ERROR_INTERNAL_ERROR;
330 telemetry->thread = CreateThread(NULL, 0, telemetry_server_thread_func, telemetry, 0, NULL);
331 if (!telemetry->thread)
333 WLog_ERR(TAG,
"CreateThread failed!");
334 (void)CloseHandle(telemetry->stopEvent);
335 telemetry->stopEvent = NULL;
336 return ERROR_INTERNAL_ERROR;
339 telemetry->isOpened = TRUE;
341 return CHANNEL_RC_OK;
344 static UINT telemetry_server_close(TelemetryServerContext* context)
346 UINT error = CHANNEL_RC_OK;
347 telemetry_server* telemetry = (telemetry_server*)context;
349 WINPR_ASSERT(telemetry);
351 if (!telemetry->externalThread && telemetry->thread)
353 (void)SetEvent(telemetry->stopEvent);
355 if (WaitForSingleObject(telemetry->thread, INFINITE) == WAIT_FAILED)
357 error = GetLastError();
358 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
362 (void)CloseHandle(telemetry->thread);
363 (void)CloseHandle(telemetry->stopEvent);
364 telemetry->thread = NULL;
365 telemetry->stopEvent = NULL;
367 if (telemetry->externalThread)
369 if (telemetry->state != TELEMETRY_INITIAL)
371 (void)WTSVirtualChannelClose(telemetry->telemetry_channel);
372 telemetry->telemetry_channel = NULL;
373 telemetry->state = TELEMETRY_INITIAL;
376 telemetry->isOpened = FALSE;
381 static UINT telemetry_server_context_poll(TelemetryServerContext* context)
383 telemetry_server* telemetry = (telemetry_server*)context;
385 WINPR_ASSERT(telemetry);
387 if (!telemetry->externalThread)
388 return ERROR_INTERNAL_ERROR;
390 return telemetry_server_context_poll_int(context);
393 static BOOL telemetry_server_context_handle(TelemetryServerContext* context, HANDLE* handle)
395 telemetry_server* telemetry = (telemetry_server*)context;
397 WINPR_ASSERT(telemetry);
398 WINPR_ASSERT(handle);
400 if (!telemetry->externalThread)
402 if (telemetry->state == TELEMETRY_INITIAL)
405 *handle = telemetry_server_get_channel_handle(telemetry);
410 TelemetryServerContext* telemetry_server_context_new(HANDLE vcm)
412 telemetry_server* telemetry = (telemetry_server*)calloc(1,
sizeof(telemetry_server));
417 telemetry->context.vcm = vcm;
418 telemetry->context.Initialize = telemetry_server_initialize;
419 telemetry->context.Open = telemetry_server_open;
420 telemetry->context.Close = telemetry_server_close;
421 telemetry->context.Poll = telemetry_server_context_poll;
422 telemetry->context.ChannelHandle = telemetry_server_context_handle;
424 telemetry->buffer = Stream_New(NULL, 4096);
425 if (!telemetry->buffer)
428 return &telemetry->context;
430 WINPR_PRAGMA_DIAG_PUSH
431 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
432 telemetry_server_context_free(&telemetry->context);
433 WINPR_PRAGMA_DIAG_POP
437 void telemetry_server_context_free(TelemetryServerContext* context)
439 telemetry_server* telemetry = (telemetry_server*)context;
443 telemetry_server_close(context);
444 Stream_Free(telemetry->buffer, TRUE);