22 #include <freerdp/config.h>
29 #include <winpr/wtypes.h>
30 #include <winpr/crt.h>
31 #include <winpr/synch.h>
32 #include <winpr/stream.h>
33 #include <winpr/assert.h>
34 #include <winpr/cast.h>
36 #include <freerdp/log.h>
37 #include <freerdp/constants.h>
38 #include <freerdp/server/channels.h>
39 #include <freerdp/channels/drdynvc.h>
40 #include <freerdp/utils/drdynvc.h>
46 #define TAG FREERDP_TAG("core.server")
48 #define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
50 #define DEBUG_DVC(...) \
56 #define DVC_MAX_DATA_PDU_SIZE 1600
66 static DWORD g_SessionId = 1;
67 static wHashTable* g_ServerHandles = NULL;
72 return HashTable_GetItemValue(vcm->dynamicVirtualChannels, &ChannelId);
75 static BOOL wts_queue_receive_data(rdpPeerChannel* channel,
const BYTE* Buffer, UINT32 Length)
78 wtsChannelMessage* messageCtx = NULL;
80 WINPR_ASSERT(channel);
81 messageCtx = (wtsChannelMessage*)malloc(
sizeof(wtsChannelMessage) + Length);
86 WINPR_ASSERT(channel->channelId <= UINT16_MAX);
87 messageCtx->channelId = (UINT16)channel->channelId;
88 messageCtx->length = Length;
89 messageCtx->offset = 0;
90 buffer = (BYTE*)(messageCtx + 1);
91 CopyMemory(buffer, Buffer, Length);
92 return MessageQueue_Post(channel->queue, messageCtx, 0, NULL, NULL);
95 static BOOL wts_queue_send_item(rdpPeerChannel* channel, BYTE* Buffer, UINT32 Length)
100 WINPR_ASSERT(channel);
101 WINPR_ASSERT(channel->vcm);
105 WINPR_ASSERT(channel->channelId <= UINT16_MAX);
106 const UINT16 channelId = (UINT16)channel->channelId;
107 return MessageQueue_Post(channel->vcm->queue, (
void*)(UINT_PTR)channelId, 0, (
void*)buffer,
108 (
void*)(UINT_PTR)length);
111 static unsigned wts_read_variable_uint(
wStream* s,
int cbLen, UINT32* val)
118 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
121 Stream_Read_UINT8(s, *val);
125 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
128 Stream_Read_UINT16(s, *val);
132 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
135 Stream_Read_UINT32(s, *val);
139 WLog_ERR(TAG,
"invalid wts variable uint len %d", cbLen);
144 static BOOL wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length)
148 WINPR_ASSERT(channel);
149 WINPR_ASSERT(channel->vcm);
153 Stream_Seek_UINT8(channel->receiveData);
154 Stream_Read_UINT16(channel->receiveData, Version);
155 DEBUG_DVC(
"Version: %" PRIu16
"", Version);
159 WLog_ERR(TAG,
"invalid version %" PRIu16
" for DRDYNVC", Version);
164 vcm->drdynvc_state = DRDYNVC_STATE_READY;
167 vcm->dvc_spoken_version = MAX(Version, 1);
169 return SetEvent(MessageQueue_Event(vcm->queue));
172 static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel,
wStream* s, UINT32 length)
174 UINT32 CreationStatus = 0;
177 WINPR_ASSERT(channel);
182 Stream_Read_UINT32(s, CreationStatus);
184 if ((INT32)CreationStatus < 0)
186 DEBUG_DVC(
"ChannelId %" PRIu32
" creation failed (%" PRId32
")", channel->channelId,
187 (INT32)CreationStatus);
188 channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
192 DEBUG_DVC(
"ChannelId %" PRIu32
" creation succeeded", channel->channelId);
193 channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
196 channel->creationStatus = (INT32)CreationStatus;
197 IFCALLRET(channel->vcm->dvc_creation_status, status, channel->vcm->dvc_creation_status_userdata,
198 channel->channelId, (INT32)CreationStatus);
200 WLog_ERR(TAG,
"vcm->dvc_creation_status failed!");
205 static BOOL wts_read_drdynvc_data_first(rdpPeerChannel* channel,
wStream* s,
int cbLen,
208 WINPR_ASSERT(channel);
210 const UINT32 value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length);
219 if (length > channel->dvc_total_length)
222 Stream_SetPosition(channel->receiveData, 0);
224 if (!Stream_EnsureRemainingCapacity(channel->receiveData, channel->dvc_total_length))
227 Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
231 static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel,
wStream* s, UINT32 length)
235 WINPR_ASSERT(channel);
237 if (channel->dvc_total_length > 0)
239 if (Stream_GetPosition(channel->receiveData) + length > channel->dvc_total_length)
241 channel->dvc_total_length = 0;
242 WLog_ERR(TAG,
"incorrect fragment data, discarded.");
246 Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
248 if (Stream_GetPosition(channel->receiveData) >= channel->dvc_total_length)
250 ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
251 channel->dvc_total_length);
252 channel->dvc_total_length = 0;
259 ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length);
265 static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
267 WINPR_ASSERT(channel);
268 DEBUG_DVC(
"ChannelId %" PRIu32
" close response", channel->channelId);
269 channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
270 MessageQueue_PostQuit(channel->queue, 0);
273 static BOOL wts_read_drdynvc_pdu(rdpPeerChannel* channel)
278 UINT32 ChannelId = 0;
279 rdpPeerChannel* dvc = NULL;
281 WINPR_ASSERT(channel);
282 WINPR_ASSERT(channel->vcm);
284 size_t length = Stream_GetPosition(channel->receiveData);
286 if ((length < 1) || (length > UINT32_MAX))
289 Stream_SetPosition(channel->receiveData, 0);
290 const UINT8 value = Stream_Get_UINT8(channel->receiveData);
292 Cmd = (value & 0xf0) >> 4;
293 Sp = (value & 0x0c) >> 2;
294 cbChId = (value & 0x03) >> 0;
296 if (Cmd == CAPABILITY_REQUEST_PDU)
297 return wts_read_drdynvc_capabilities_response(channel, (UINT32)length);
299 if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
301 BOOL haveChannelId = 0;
304 case SOFT_SYNC_REQUEST_PDU:
305 case SOFT_SYNC_RESPONSE_PDU:
306 haveChannelId = FALSE;
309 haveChannelId = TRUE;
315 const unsigned val = wts_read_variable_uint(channel->receiveData, cbChId, &ChannelId);
321 DEBUG_DVC(
"Cmd %s ChannelId %" PRIu32
" length %" PRIuz
"",
322 drdynvc_get_packet_type(Cmd), ChannelId, length);
323 dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
326 DEBUG_DVC(
"ChannelId %" PRIu32
" does not exist.", ChannelId);
333 case CREATE_REQUEST_PDU:
334 return wts_read_drdynvc_create_response(dvc, channel->receiveData, (UINT32)length);
337 if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
340 "ChannelId %" PRIu32
" did not open successfully. "
341 "Ignoring DYNVC_DATA_FIRST PDU",
346 return wts_read_drdynvc_data_first(dvc, channel->receiveData, Sp, (UINT32)length);
349 if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
352 "ChannelId %" PRIu32
" did not open successfully. "
353 "Ignoring DYNVC_DATA PDU",
358 return wts_read_drdynvc_data(dvc, channel->receiveData, (UINT32)length);
360 case CLOSE_REQUEST_PDU:
361 wts_read_drdynvc_close_response(dvc);
364 case DATA_FIRST_COMPRESSED_PDU:
365 case DATA_COMPRESSED_PDU:
366 WLog_ERR(TAG,
"Compressed data not handled");
369 case SOFT_SYNC_RESPONSE_PDU:
370 WLog_ERR(TAG,
"SoftSync response not handled yet(and rather strange to receive "
371 "that packet as our code doesn't send SoftSync requests");
374 case SOFT_SYNC_REQUEST_PDU:
375 WLog_ERR(TAG,
"Not expecting a SoftSyncRequest on the server");
379 WLog_ERR(TAG,
"Cmd %d not recognized.", Cmd);
385 WLog_ERR(TAG,
"received Cmd %d but channel is not ready.", Cmd);
391 static int wts_write_variable_uint(
wStream* s, UINT32 val)
399 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, val));
401 else if (val <= 0xFFFF)
404 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, val));
409 Stream_Write_UINT32(s, val);
415 static void wts_write_drdynvc_header(
wStream* s, BYTE Cmd, UINT32 ChannelId)
422 Stream_GetPointer(s, bm);
423 Stream_Seek_UINT8(s);
424 cbChId = wts_write_variable_uint(s, ChannelId);
425 *bm = (((Cmd & 0x0F) << 4) | cbChId) & 0xFF;
428 static BOOL wts_write_drdynvc_create_request(
wStream* s, UINT32 ChannelId,
const char* ChannelName)
433 WINPR_ASSERT(ChannelName);
435 wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
436 len = strlen(ChannelName) + 1;
438 if (!Stream_EnsureRemainingCapacity(s, len))
441 Stream_Write(s, ChannelName, len);
445 static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId,
const BYTE* data,
446 size_t s, UINT32 flags,
size_t t)
449 const size_t size = s;
450 const size_t totalSize = t;
452 WINPR_ASSERT(channel);
453 WINPR_ASSERT(channel->vcm);
454 WINPR_UNUSED(channelId);
456 if (flags & CHANNEL_FLAG_FIRST)
458 Stream_SetPosition(channel->receiveData, 0);
461 if (!Stream_EnsureRemainingCapacity(channel->receiveData, size))
464 Stream_Write(channel->receiveData, data, size);
466 if (flags & CHANNEL_FLAG_LAST)
468 if (Stream_GetPosition(channel->receiveData) != totalSize)
470 WLog_ERR(TAG,
"read error");
473 if (channel == channel->vcm->drdynvc_channel)
475 ret = wts_read_drdynvc_pdu(channel);
479 const size_t pos = Stream_GetPosition(channel->receiveData);
480 if (pos > UINT32_MAX)
483 ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
487 Stream_SetPosition(channel->receiveData, 0);
493 static BOOL WTSReceiveChannelData(freerdp_peer* client, UINT16 channelId,
const BYTE* data,
494 size_t size, UINT32 flags,
size_t totalSize)
498 WINPR_ASSERT(client);
499 WINPR_ASSERT(client->context);
500 WINPR_ASSERT(client->context->rdp);
502 mcs = client->context->rdp->mcs;
505 for (UINT32 i = 0; i < mcs->channelCount; i++)
507 rdpMcsChannel* cur = &mcs->channels[i];
508 if (cur->ChannelId == channelId)
510 rdpPeerChannel* channel = (rdpPeerChannel*)cur->handle;
513 return WTSProcessChannelData(channel, channelId, data, size, flags, totalSize);
517 WLog_WARN(TAG,
"unknown channelId %" PRIu16
" ignored", channelId);
522 #if defined(WITH_FREERDP_DEPRECATED)
523 void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer,
void** fds,
int* fds_count)
529 WINPR_ASSERT(fds_count);
531 fd = GetEventWaitObject(MessageQueue_Event(vcm->queue));
535 fds[*fds_count] = fd;
541 if (vcm->drdynvc_channel)
543 fd = GetEventWaitObject(vcm->drdynvc_channel->receiveEvent);
547 fds[*fds_count] = fd;
556 BOOL WTSVirtualChannelManagerOpen(HANDLE hServer)
563 if (vcm->drdynvc_state == DRDYNVC_STATE_NONE)
565 rdpPeerChannel* channel = NULL;
568 vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
569 channel = (rdpPeerChannel*)WTSVirtualChannelOpen((HANDLE)vcm, WTS_CURRENT_SESSION,
570 DRDYNVC_SVC_CHANNEL_NAME);
574 BYTE capaBuffer[12] = { 0 };
576 wStream* s = Stream_StaticInit(&staticS, capaBuffer,
sizeof(capaBuffer));
578 vcm->drdynvc_channel = channel;
579 vcm->dvc_spoken_version = 1;
580 Stream_Write_UINT8(s, 0x50);
581 Stream_Write_UINT8(s, 0x00);
582 Stream_Write_UINT16(s, 0x0001);
586 const size_t pos = Stream_GetPosition(s);
587 WINPR_ASSERT(pos <= UINT32_MAX);
589 if (!WTSVirtualChannelWrite(channel, (PCHAR)capaBuffer, (UINT32)pos, &written))
597 BOOL WTSVirtualChannelManagerCheckFileDescriptorEx(HANDLE hServer, BOOL autoOpen)
599 wMessage message = { 0 };
603 if (!hServer || hServer == INVALID_HANDLE_VALUE)
610 if (!WTSVirtualChannelManagerOpen(hServer))
614 while (MessageQueue_Peek(vcm->queue, &message, TRUE))
618 UINT16 channelId = 0;
619 channelId = (UINT16)(UINT_PTR)message.context;
620 buffer = (BYTE*)message.wParam;
621 length = (UINT32)(UINT_PTR)message.lParam;
623 WINPR_ASSERT(vcm->client);
624 WINPR_ASSERT(vcm->client->SendChannelData);
625 if (!vcm->client->SendChannelData(vcm->client, channelId, buffer, length))
639 BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
641 return WTSVirtualChannelManagerCheckFileDescriptorEx(hServer, TRUE);
644 HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
648 return MessageQueue_Event(vcm->queue);
651 static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs,
const char* channel_name)
653 if (!mcs || !channel_name || !strnlen(channel_name, CHANNEL_NAME_LEN + 1))
656 for (UINT32 index = 0; index < mcs->channelCount; index++)
658 rdpMcsChannel* mchannel = &mcs->channels[index];
659 if (mchannel->joined)
661 if (_strnicmp(mchannel->Name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
669 static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs,
const UINT16 channel_id)
671 if (!mcs || !channel_id)
674 WINPR_ASSERT(mcs->channels);
675 for (UINT32 index = 0; index < mcs->channelCount; index++)
677 rdpMcsChannel* mchannel = &mcs->channels[index];
678 if (mchannel->joined)
680 if (mchannel->ChannelId == channel_id)
681 return &mcs->channels[index];
688 BOOL WTSIsChannelJoinedByName(freerdp_peer* client,
const char* channel_name)
690 if (!client || !client->context || !client->context->rdp)
693 return wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) == NULL ? FALSE
697 BOOL WTSIsChannelJoinedById(freerdp_peer* client,
const UINT16 channel_id)
699 if (!client || !client->context || !client->context->rdp)
702 return wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id) == NULL ? FALSE
706 BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer,
const char* name)
710 if (!vcm || !vcm->rdp)
713 return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE;
716 BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
720 return vcm->drdynvc_state;
723 void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, psDVCCreationStatusCallback cb,
730 vcm->dvc_creation_status = cb;
731 vcm->dvc_creation_status_userdata = userdata;
734 UINT16 WTSChannelGetId(freerdp_peer* client,
const char* channel_name)
736 rdpMcsChannel* channel = NULL;
738 WINPR_ASSERT(channel_name);
739 if (!client || !client->context || !client->context->rdp)
742 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
747 return channel->ChannelId;
750 UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle)
752 rdpPeerChannel* channel = hChannelHandle;
754 WINPR_ASSERT(channel);
756 return channel->channelId;
759 BOOL WTSChannelSetHandleByName(freerdp_peer* client,
const char* channel_name,
void* handle)
761 rdpMcsChannel* channel = NULL;
763 WINPR_ASSERT(channel_name);
764 if (!client || !client->context || !client->context->rdp)
767 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
772 channel->handle = handle;
776 BOOL WTSChannelSetHandleById(freerdp_peer* client,
const UINT16 channel_id,
void* handle)
778 rdpMcsChannel* channel = NULL;
780 if (!client || !client->context || !client->context->rdp)
783 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
788 channel->handle = handle;
792 void* WTSChannelGetHandleByName(freerdp_peer* client,
const char* channel_name)
794 rdpMcsChannel* channel = NULL;
796 WINPR_ASSERT(channel_name);
797 if (!client || !client->context || !client->context->rdp)
800 channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
805 return channel->handle;
808 void* WTSChannelGetHandleById(freerdp_peer* client,
const UINT16 channel_id)
810 rdpMcsChannel* channel = NULL;
812 if (!client || !client->context || !client->context->rdp)
815 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
820 return channel->handle;
823 const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id)
825 rdpMcsChannel* channel = NULL;
827 if (!client || !client->context || !client->context->rdp)
830 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
835 return (
const char*)channel->Name;
838 char** WTSGetAcceptedChannelNames(freerdp_peer* client,
size_t* count)
843 if (!client || !client->context || !count)
846 WINPR_ASSERT(client->context->rdp);
847 mcs = client->context->rdp->mcs;
849 *count = mcs->channelCount;
851 names = (
char**)calloc(mcs->channelCount,
sizeof(
char*));
855 for (UINT32 index = 0; index < mcs->channelCount; index++)
857 rdpMcsChannel* mchannel = &mcs->channels[index];
858 names[index] = mchannel->Name;
864 INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id)
866 rdpMcsChannel* channel = NULL;
868 if (!client || !client->context || !client->context->rdp)
871 channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
876 return (INT64)channel->options;
879 BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId,
880 BYTE HotkeyVk, USHORT HotkeyModifiers)
885 BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(LPSTR pTargetServerName, ULONG TargetLogonId,
886 BYTE HotkeyVk, USHORT HotkeyModifiers)
891 BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(LPWSTR pTargetServerName, ULONG TargetLogonId,
892 BYTE HotkeyVk, USHORT HotkeyModifiers,
898 BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(LPSTR pTargetServerName, ULONG TargetLogonId,
899 BYTE HotkeyVk, USHORT HotkeyModifiers,
905 BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(ULONG LogonId)
910 BOOL WINAPI FreeRDP_WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword,
916 BOOL WINAPI FreeRDP_WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword,
922 BOOL WINAPI FreeRDP_WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version,
928 BOOL WINAPI FreeRDP_WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version,
934 HANDLE WINAPI FreeRDP_WTSOpenServerW(LPWSTR pServerName)
936 return INVALID_HANDLE_VALUE;
939 static void wts_virtual_channel_manager_free_message(
void* obj)
941 wMessage* msg = (wMessage*)obj;
945 BYTE* buffer = (BYTE*)msg->wParam;
952 static void channel_free(rdpPeerChannel* channel)
954 server_channel_common_free(channel);
957 static void array_channel_free(
void* ptr)
959 rdpPeerChannel* channel = ptr;
960 channel_free(channel);
963 static BOOL dynChannelMatch(
const void* v1,
const void* v2)
965 const UINT32* p1 = (
const UINT32*)v1;
966 const UINT32* p2 = (
const UINT32*)v2;
970 static UINT32 channelId_Hash(
const void* key)
972 const UINT32* v = (
const UINT32*)key;
976 HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
978 rdpContext* context = NULL;
979 freerdp_peer* client = NULL;
981 HANDLE hServer = INVALID_HANDLE_VALUE;
982 wObject queueCallbacks = { 0 };
984 context = (rdpContext*)pServerName;
987 return INVALID_HANDLE_VALUE;
989 client = context->peer;
993 SetLastError(ERROR_INVALID_DATA);
994 return INVALID_HANDLE_VALUE;
1000 goto error_vcm_alloc;
1002 vcm->client = client;
1003 vcm->rdp = context->rdp;
1004 vcm->SessionId = g_SessionId++;
1006 if (!g_ServerHandles)
1008 g_ServerHandles = HashTable_New(TRUE);
1010 if (!g_ServerHandles)
1014 if (!HashTable_Insert(g_ServerHandles, (
void*)(UINT_PTR)vcm->SessionId, (
void*)vcm))
1017 queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
1018 vcm->queue = MessageQueue_New(&queueCallbacks);
1023 vcm->dvc_channel_id_seq = 0;
1024 vcm->dynamicVirtualChannels = HashTable_New(TRUE);
1026 if (!vcm->dynamicVirtualChannels)
1027 goto error_dynamicVirtualChannels;
1029 if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
1030 goto error_hashFunction;
1033 wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
1035 obj->fnObjectFree = array_channel_free;
1037 obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
1038 obj->fnObjectEquals = dynChannelMatch;
1040 client->ReceiveChannelData = WTSReceiveChannelData;
1041 hServer = (HANDLE)vcm;
1045 HashTable_Free(vcm->dynamicVirtualChannels);
1046 error_dynamicVirtualChannels:
1047 MessageQueue_Free(vcm->queue);
1049 HashTable_Remove(g_ServerHandles, (
void*)(UINT_PTR)vcm->SessionId);
1053 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1054 return INVALID_HANDLE_VALUE;
1057 HANDLE WINAPI FreeRDP_WTSOpenServerExW(LPWSTR pServerName)
1059 return INVALID_HANDLE_VALUE;
1062 HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
1064 return FreeRDP_WTSOpenServerA(pServerName);
1067 VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
1072 if (vcm && (vcm != INVALID_HANDLE_VALUE))
1074 HashTable_Remove(g_ServerHandles, (
void*)(UINT_PTR)vcm->SessionId);
1076 HashTable_Free(vcm->dynamicVirtualChannels);
1078 if (vcm->drdynvc_channel)
1080 (void)WTSVirtualChannelClose(vcm->drdynvc_channel);
1081 vcm->drdynvc_channel = NULL;
1084 MessageQueue_Free(vcm->queue);
1089 BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
1095 BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
1101 BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(HANDLE hServer, DWORD* pLevel, DWORD Filter,
1107 BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(HANDLE hServer, DWORD* pLevel, DWORD Filter,
1113 BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
1119 BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
1125 BOOL WINAPI FreeRDP_WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode)
1130 BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId,
1131 WTS_INFO_CLASS WTSInfoClass, LPWSTR* ppBuffer,
1132 DWORD* pBytesReturned)
1137 BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId,
1138 WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
1139 DWORD* pBytesReturned)
1141 DWORD BytesReturned = 0;
1148 if (WTSInfoClass == WTSSessionId)
1150 ULONG* pBuffer = NULL;
1151 BytesReturned =
sizeof(ULONG);
1152 pBuffer = (ULONG*)malloc(
sizeof(BytesReturned));
1156 SetLastError(E_OUTOFMEMORY);
1160 *pBuffer = vcm->SessionId;
1161 *ppBuffer = (LPSTR)pBuffer;
1162 *pBytesReturned = BytesReturned;
1169 BOOL WINAPI FreeRDP_WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
1170 WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer,
1171 DWORD* pBytesReturned)
1176 BOOL WINAPI FreeRDP_WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName,
1177 WTS_CONFIG_CLASS WTSConfigClass, LPSTR* ppBuffer,
1178 DWORD* pBytesReturned)
1183 BOOL WINAPI FreeRDP_WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
1184 WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer,
1190 BOOL WINAPI FreeRDP_WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName,
1191 WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer,
1197 BOOL WINAPI FreeRDP_WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle,
1198 DWORD TitleLength, LPWSTR pMessage, DWORD MessageLength,
1199 DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait)
1204 BOOL WINAPI FreeRDP_WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle,
1205 DWORD TitleLength, LPSTR pMessage, DWORD MessageLength,
1206 DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait)
1211 BOOL WINAPI FreeRDP_WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
1216 BOOL WINAPI FreeRDP_WTSLogoffSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
1221 BOOL WINAPI FreeRDP_WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag)
1226 BOOL WINAPI FreeRDP_WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags)
1231 static void peer_channel_queue_free_message(
void* obj)
1233 wMessage* msg = (wMessage*)obj;
1238 msg->context = NULL;
1242 UINT32 ChannelId, UINT16 index, UINT16 type,
size_t chunkSize,
1245 wObject queueCallbacks = { 0 };
1246 queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
1248 rdpPeerChannel* channel =
1249 server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
1252 WINPR_ASSERT(client);
1258 channel->channelType = type;
1259 channel->creationStatus =
1260 (type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
1264 channel_free(channel);
1268 HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
1272 rdpMcsChannel* joined_channel = NULL;
1273 freerdp_peer* client = NULL;
1274 rdpPeerChannel* channel = NULL;
1276 HANDLE hChannelHandle = NULL;
1277 rdpContext* context = NULL;
1282 SetLastError(ERROR_INVALID_DATA);
1286 client = vcm->client;
1287 WINPR_ASSERT(client);
1289 context = client->context;
1290 WINPR_ASSERT(context);
1291 WINPR_ASSERT(context->rdp);
1292 WINPR_ASSERT(context->settings);
1294 mcs = context->rdp->mcs;
1297 length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
1299 if (length > CHANNEL_NAME_LEN)
1301 SetLastError(ERROR_NOT_FOUND);
1306 for (; index < mcs->channelCount; index++)
1308 rdpMcsChannel* mchannel = &mcs->channels[index];
1309 if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
1311 joined_channel = mchannel;
1316 if (!joined_channel)
1318 SetLastError(ERROR_NOT_FOUND);
1322 channel = (rdpPeerChannel*)joined_channel->handle;
1326 const UINT32 VCChunkSize =
1329 WINPR_ASSERT(index <= UINT16_MAX);
1330 channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index,
1331 RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName);
1336 joined_channel->handle = channel;
1339 hChannelHandle = (HANDLE)channel;
1340 return hChannelHandle;
1342 channel_free(channel);
1343 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1347 HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
1351 BOOL joined = FALSE;
1352 freerdp_peer* client = NULL;
1353 rdpPeerChannel* channel = NULL;
1357 if (SessionId == WTS_CURRENT_SESSION)
1361 (
void*)(UINT_PTR)SessionId);
1366 if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
1368 return FreeRDP_WTSVirtualChannelOpen((HANDLE)vcm, SessionId, pVirtualName);
1371 client = vcm->client;
1372 mcs = client->context->rdp->mcs;
1374 for (UINT32 index = 0; index < mcs->channelCount; index++)
1376 rdpMcsChannel* mchannel = &mcs->channels[index];
1377 if (mchannel->joined &&
1378 (strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
1387 SetLastError(ERROR_NOT_FOUND);
1391 if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
1393 SetLastError(ERROR_NOT_READY);
1397 WINPR_ASSERT(client);
1398 WINPR_ASSERT(client->context);
1399 WINPR_ASSERT(client->context->settings);
1401 const UINT32 VCChunkSize =
1403 channel = channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName);
1407 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1411 const LONG hdl = InterlockedIncrement(&vcm->dvc_channel_id_seq);
1412 channel->channelId = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1414 if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
1416 channel_free(channel);
1420 s = Stream_New(NULL, 64);
1425 if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
1428 const size_t pos = Stream_GetPosition(s);
1429 WINPR_ASSERT(pos <= UINT32_MAX);
1430 if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s,
char), (UINT32)pos,
1434 Stream_Free(s, TRUE);
1437 Stream_Free(s, TRUE);
1439 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1441 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1445 BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
1450 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1458 WINPR_ASSERT(vcm->client);
1459 WINPR_ASSERT(vcm->client->context);
1460 WINPR_ASSERT(vcm->client->context->rdp);
1461 mcs = vcm->client->context->rdp->mcs;
1463 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1465 if (channel->index < mcs->channelCount)
1467 rdpMcsChannel* cur = &mcs->channels[channel->index];
1468 rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
1469 channel_free(peerChannel);
1475 if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
1478 s = Stream_New(NULL, 8);
1482 WLog_ERR(TAG,
"Stream_New failed!");
1487 wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
1489 const size_t pos = Stream_GetPosition(s);
1490 WINPR_ASSERT(pos <= UINT32_MAX);
1491 ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s,
char),
1492 (UINT32)pos, &written);
1493 Stream_Free(s, TRUE);
1496 HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
1503 BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer,
1504 ULONG BufferSize, PULONG pBytesRead)
1506 BYTE* buffer = NULL;
1507 wMessage message = { 0 };
1508 wtsChannelMessage* messageCtx = NULL;
1509 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1511 WINPR_ASSERT(channel);
1513 if (!MessageQueue_Peek(channel->queue, &message, FALSE))
1515 SetLastError(ERROR_NO_DATA);
1520 messageCtx = message.context;
1522 if (messageCtx == NULL)
1525 buffer = (BYTE*)(messageCtx + 1);
1526 *pBytesRead = messageCtx->length - messageCtx->offset;
1528 if (Buffer == NULL || BufferSize == 0)
1533 if (*pBytesRead > BufferSize)
1534 *pBytesRead = BufferSize;
1536 CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
1537 messageCtx->offset += *pBytesRead;
1539 if (messageCtx->offset >= messageCtx->length)
1541 (void)MessageQueue_Peek(channel->queue, &message, TRUE);
1542 peer_channel_queue_free_message(&message);
1548 BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length,
1549 PULONG pBytesWritten)
1555 BYTE* buffer = NULL;
1556 UINT32 totalWritten = 0;
1557 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1563 EnterCriticalSection(&channel->writeLock);
1564 WINPR_ASSERT(channel->vcm);
1565 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1567 const ULONG length = Length;
1568 buffer = (BYTE*)malloc(length);
1572 SetLastError(E_OUTOFMEMORY);
1576 CopyMemory(buffer, Buffer, length);
1577 totalWritten = Length;
1578 if (!wts_queue_send_item(channel, buffer, length))
1581 else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
1583 DEBUG_DVC(
"drdynvc not ready");
1588 rdpContext* context = NULL;
1591 WINPR_ASSERT(channel->client);
1592 context = channel->client->context;
1593 WINPR_ASSERT(context);
1596 s = Stream_New(NULL, DVC_MAX_DATA_PDU_SIZE);
1600 WLog_ERR(TAG,
"Stream_New failed!");
1601 SetLastError(E_OUTOFMEMORY);
1605 buffer = Stream_Buffer(s);
1606 Stream_Seek_UINT8(s);
1607 cbChId = wts_write_variable_uint(s, channel->channelId);
1609 if (first && (Length > Stream_GetRemainingLength(s)))
1611 cbLen = wts_write_variable_uint(s, Length);
1612 buffer[0] = ((DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId) & 0xFF;
1616 buffer[0] = ((DATA_PDU << 4) | cbChId) & 0xFF;
1620 size_t written = Stream_GetRemainingLength(s);
1622 if (written > Length)
1625 Stream_Write(s, Buffer, written);
1626 const size_t length = Stream_GetPosition(s);
1627 Stream_Free(s, FALSE);
1628 if (length > UINT32_MAX)
1632 totalWritten += written;
1633 if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, (UINT32)length))
1639 *pBytesWritten = totalWritten;
1643 LeaveCriticalSection(&channel->writeLock);
1647 BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
1652 BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
1657 BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
1658 PVOID* ppBuffer, DWORD* pBytesReturned)
1662 void* fds[10] = { 0 };
1663 HANDLE hEvent = NULL;
1665 BOOL status = FALSE;
1666 rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
1668 WINPR_ASSERT(channel);
1670 switch ((UINT32)WtsVirtualClass)
1672 case WTSVirtualFileHandle:
1673 hEvent = MessageQueue_Event(channel->queue);
1674 pfd = GetEventWaitObject(hEvent);
1678 fds[fds_count] = pfd;
1682 *ppBuffer = malloc(
sizeof(
void*));
1686 SetLastError(E_OUTOFMEMORY);
1690 CopyMemory(*ppBuffer, (
void*)&fds[0],
sizeof(
void*));
1691 *pBytesReturned =
sizeof(
void*);
1697 case WTSVirtualEventHandle:
1698 hEvent = MessageQueue_Event(channel->queue);
1700 *ppBuffer = malloc(
sizeof(HANDLE));
1704 SetLastError(E_OUTOFMEMORY);
1708 CopyMemory(*ppBuffer, (
void*)&hEvent,
sizeof(HANDLE));
1709 *pBytesReturned =
sizeof(
void*);
1715 case WTSVirtualChannelReady:
1716 if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
1723 switch (channel->dvc_open_state)
1725 case DVC_OPEN_STATE_NONE:
1730 case DVC_OPEN_STATE_SUCCEEDED:
1737 *pBytesReturned = 0;
1742 *ppBuffer = malloc(
sizeof(BOOL));
1746 SetLastError(E_OUTOFMEMORY);
1751 CopyMemory(*ppBuffer, &bval,
sizeof(BOOL));
1752 *pBytesReturned =
sizeof(BOOL);
1756 case WTSVirtualChannelOpenStatus:
1758 INT32 value = channel->creationStatus;
1761 *ppBuffer = malloc(
sizeof(value));
1764 SetLastError(E_OUTOFMEMORY);
1769 CopyMemory(*ppBuffer, &value,
sizeof(value));
1770 *pBytesReturned =
sizeof(value);
1781 VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
1786 BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
1787 ULONG NumberOfEntries)
1792 BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
1793 ULONG NumberOfEntries)
1798 BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags)
1803 BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(HWND hWnd)
1808 BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd, DWORD dwFlags)
1813 BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd)
1818 BOOL WINAPI FreeRDP_WTSQueryUserToken(ULONG SessionId, PHANDLE phToken)
1823 BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
1824 LPWSTR* ppProcessInfo, DWORD* pCount)
1829 BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
1830 LPSTR* ppProcessInfo, DWORD* pCount)
1835 BOOL WINAPI FreeRDP_WTSEnumerateListenersW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1836 PWTSLISTENERNAMEW pListeners, DWORD* pCount)
1841 BOOL WINAPI FreeRDP_WTSEnumerateListenersA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1842 PWTSLISTENERNAMEA pListeners, DWORD* pCount)
1847 BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1853 BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1859 BOOL WINAPI FreeRDP_WTSCreateListenerW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1866 BOOL WINAPI FreeRDP_WTSCreateListenerA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1872 BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1873 LPWSTR pListenerName,
1874 SECURITY_INFORMATION SecurityInformation,
1875 PSECURITY_DESCRIPTOR pSecurityDescriptor)
1880 BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1881 LPSTR pListenerName,
1882 SECURITY_INFORMATION SecurityInformation,
1883 PSECURITY_DESCRIPTOR pSecurityDescriptor)
1888 BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1889 LPWSTR pListenerName,
1890 SECURITY_INFORMATION SecurityInformation,
1891 PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
1892 LPDWORD lpnLengthNeeded)
1897 BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
1898 LPSTR pListenerName,
1899 SECURITY_INFORMATION SecurityInformation,
1900 PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
1901 LPDWORD lpnLengthNeeded)
1906 BOOL CDECL FreeRDP_WTSEnableChildSessions(BOOL bEnable)
1911 BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(PBOOL pbEnabled)
1916 BOOL CDECL FreeRDP_WTSGetChildSessionId(PULONG pSessionId)
1921 DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(
void)
1925 BOOL WINAPI FreeRDP_WTSLogoffUser(HANDLE hServer)
1930 BOOL WINAPI FreeRDP_WTSLogonUser(HANDLE hServer, LPCSTR username, LPCSTR password, LPCSTR domain)
1935 void server_channel_common_free(rdpPeerChannel* channel)
1939 MessageQueue_Free(channel->queue);
1940 Stream_Free(channel->receiveData, TRUE);
1941 DeleteCriticalSection(&channel->writeLock);
1945 rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index, UINT32 channelId,
1946 size_t chunkSize,
const wObject* callback,
1949 rdpPeerChannel* channel = (rdpPeerChannel*)calloc(1,
sizeof(rdpPeerChannel));
1953 InitializeCriticalSection(&channel->writeLock);
1955 channel->receiveData = Stream_New(NULL, chunkSize);
1956 if (!channel->receiveData)
1959 channel->queue = MessageQueue_New(callback);
1960 if (!channel->queue)
1963 channel->index = index;
1964 channel->client = client;
1965 channel->channelId = channelId;
1966 strncpy(channel->channelName, name, ARRAYSIZE(channel->channelName) - 1);
1969 WINPR_PRAGMA_DIAG_PUSH
1970 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1971 server_channel_common_free(channel);
1972 WINPR_PRAGMA_DIAG_POP
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
This struct contains function pointer to initialize/free objects.