Merge pull request #10663 from akallabeth/client-channel-event-process-api
[core,client] add channel poll registration API
This commit is contained in:
commit
fcdbc05979
@ -33,6 +33,9 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @since version 3.9.0 */
|
||||||
|
typedef BOOL (*freerdp_channel_handle_fkt_t)(rdpContext* context, void* userdata);
|
||||||
|
|
||||||
FREERDP_API int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings,
|
FREERDP_API int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings,
|
||||||
PVIRTUALCHANNELENTRY entry, void* data);
|
PVIRTUALCHANNELENTRY entry, void* data);
|
||||||
FREERDP_API int freerdp_channels_client_load_ex(rdpChannels* channels, rdpSettings* settings,
|
FREERDP_API int freerdp_channels_client_load_ex(rdpChannels* channels, rdpSettings* settings,
|
||||||
@ -50,6 +53,40 @@ extern "C"
|
|||||||
FREERDP_API void* freerdp_channels_get_static_channel_interface(rdpChannels* channels,
|
FREERDP_API void* freerdp_channels_get_static_channel_interface(rdpChannels* channels,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
||||||
|
/** @brief A channel may register an event handle and a callback function to be called by \b
|
||||||
|
* freerdp_check_event_handles
|
||||||
|
*
|
||||||
|
* If a channel can not or does not want to use a thread to process data asynchronously it can
|
||||||
|
* register a \b non-blocking function that does this processing. Notification is done with the
|
||||||
|
* \b event-handle which will trigger the RDP loop. So this function is triggered until the \b
|
||||||
|
* event-handle is reset.
|
||||||
|
* @note This function may be called even without the \b event-handle to be set, so it must be
|
||||||
|
* capable of handling these calls properly.
|
||||||
|
*
|
||||||
|
* @param channels A pointer to the channels instance to register with. Must not be \b NULL
|
||||||
|
* @param handle A \b event-handle to be used to notify the RDP main thread that the callback
|
||||||
|
* function should be called again. Must not be \b INVALID_HANDLE_PARAM
|
||||||
|
* @param fkt The callback function responsible to handle the channel specifics. Must not be \b
|
||||||
|
* NULL
|
||||||
|
* @param userdata A pointer to a channel specific context. Most likely the channel context.
|
||||||
|
* May be \b NULL if not required.
|
||||||
|
*
|
||||||
|
* @return \b TRUE if successful, \b FALSE if any error occurs.
|
||||||
|
* @since version 3.9.0 */
|
||||||
|
FREERDP_API BOOL freerdp_client_channel_register(rdpChannels* channels, HANDLE handle,
|
||||||
|
freerdp_channel_handle_fkt_t fkt,
|
||||||
|
void* userdata);
|
||||||
|
|
||||||
|
/** @brief Remove an existing registration for \b event-handle from the channels instance
|
||||||
|
*
|
||||||
|
* @param channels A pointer to the channels instance to register with. Must not be \b NULL
|
||||||
|
* @param handle A \b event-handle to be used to notify the RDP main thread that the callback
|
||||||
|
* function should be called again. Must not be \b INVALID_HANDLE_PARAM
|
||||||
|
*
|
||||||
|
* @return \b TRUE if successful, \b FALSE if any error occurs.
|
||||||
|
* @since version 3.9.0 */
|
||||||
|
FREERDP_API BOOL freerdp_client_channel_unregister(rdpChannels* channels, HANDLE handle);
|
||||||
|
|
||||||
FREERDP_API HANDLE freerdp_channels_get_event_handle(freerdp* instance);
|
FREERDP_API HANDLE freerdp_channels_get_event_handle(freerdp* instance);
|
||||||
FREERDP_API int freerdp_channels_process_pending_messages(freerdp* instance);
|
FREERDP_API int freerdp_channels_process_pending_messages(freerdp* instance);
|
||||||
|
|
||||||
|
@ -33,6 +33,12 @@
|
|||||||
|
|
||||||
#define TAG FREERDP_TAG("core.client")
|
#define TAG FREERDP_TAG("core.client")
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
freerdp_channel_handle_fkt_t fkt;
|
||||||
|
void* userdata;
|
||||||
|
} ChannelEventEntry;
|
||||||
|
|
||||||
/* Use this instance to get access to channels in VirtualChannelInit. It is set during
|
/* Use this instance to get access to channels in VirtualChannelInit. It is set during
|
||||||
* freerdp_connect so channels that use VirtualChannelInit must be initialized from the same thread
|
* freerdp_connect so channels that use VirtualChannelInit must be initialized from the same thread
|
||||||
* as freerdp_connect was called */
|
* as freerdp_connect was called */
|
||||||
@ -131,6 +137,19 @@ static BOOL CALLBACK init_channel_handles_table(PINIT_ONCE once, PVOID param, PV
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* channel_event_entry_clone(const void* data)
|
||||||
|
{
|
||||||
|
const ChannelEventEntry* entry = data;
|
||||||
|
if (!entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ChannelEventEntry* copy = calloc(1, sizeof(ChannelEventEntry));
|
||||||
|
if (!copy)
|
||||||
|
return NULL;
|
||||||
|
*copy = *entry;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
rdpChannels* freerdp_channels_new(freerdp* instance)
|
rdpChannels* freerdp_channels_new(freerdp* instance)
|
||||||
{
|
{
|
||||||
wObject* obj = NULL;
|
wObject* obj = NULL;
|
||||||
@ -156,6 +175,14 @@ rdpChannels* freerdp_channels_new(freerdp* instance)
|
|||||||
obj = MessageQueue_Object(channels->queue);
|
obj = MessageQueue_Object(channels->queue);
|
||||||
obj->fnObjectFree = channel_queue_free;
|
obj->fnObjectFree = channel_queue_free;
|
||||||
|
|
||||||
|
channels->channelEvents = HashTable_New(FALSE);
|
||||||
|
if (!channels->channelEvents)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
obj = HashTable_ValueObject(channels->channelEvents);
|
||||||
|
WINPR_ASSERT(obj);
|
||||||
|
obj->fnObjectFree = free;
|
||||||
|
obj->fnObjectNew = channel_event_entry_clone;
|
||||||
return channels;
|
return channels;
|
||||||
error:
|
error:
|
||||||
WINPR_PRAGMA_DIAG_PUSH
|
WINPR_PRAGMA_DIAG_PUSH
|
||||||
@ -170,13 +197,10 @@ void freerdp_channels_free(rdpChannels* channels)
|
|||||||
if (!channels)
|
if (!channels)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DeleteCriticalSection(&channels->channelsLock);
|
HashTable_Free(channels->channelEvents);
|
||||||
|
MessageQueue_Free(channels->queue);
|
||||||
|
|
||||||
if (channels->queue)
|
DeleteCriticalSection(&channels->channelsLock);
|
||||||
{
|
|
||||||
MessageQueue_Free(channels->queue);
|
|
||||||
channels->queue = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(channels);
|
free(channels);
|
||||||
}
|
}
|
||||||
@ -706,24 +730,45 @@ void* freerdp_channels_get_static_channel_interface(rdpChannels* channels, const
|
|||||||
|
|
||||||
HANDLE freerdp_channels_get_event_handle(freerdp* instance)
|
HANDLE freerdp_channels_get_event_handle(freerdp* instance)
|
||||||
{
|
{
|
||||||
HANDLE event = NULL;
|
WINPR_ASSERT(instance);
|
||||||
rdpChannels* channels = NULL;
|
WINPR_ASSERT(instance->context);
|
||||||
channels = instance->context->channels;
|
|
||||||
event = MessageQueue_Event(channels->queue);
|
rdpChannels* channels = instance->context->channels;
|
||||||
return event;
|
WINPR_ASSERT(channels);
|
||||||
|
|
||||||
|
return MessageQueue_Event(channels->queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL channels_process(const void* key, void* value, void* arg)
|
||||||
|
{
|
||||||
|
ChannelEventEntry* entry = value;
|
||||||
|
rdpContext* context = arg;
|
||||||
|
|
||||||
|
WINPR_UNUSED(key);
|
||||||
|
|
||||||
|
if (!entry->fkt)
|
||||||
|
return FALSE;
|
||||||
|
return entry->fkt(context, entry->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
int freerdp_channels_process_pending_messages(freerdp* instance)
|
int freerdp_channels_process_pending_messages(freerdp* instance)
|
||||||
{
|
{
|
||||||
rdpChannels* channels = NULL;
|
WINPR_ASSERT(instance);
|
||||||
channels = instance->context->channels;
|
WINPR_ASSERT(instance->context);
|
||||||
|
|
||||||
|
rdpChannels* channels = instance->context->channels;
|
||||||
|
WINPR_ASSERT(channels);
|
||||||
|
|
||||||
if (WaitForSingleObject(MessageQueue_Event(channels->queue), 0) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(MessageQueue_Event(channels->queue), 0) == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
return freerdp_channels_process_sync(channels, instance);
|
if (!freerdp_channels_process_sync(channels, instance))
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
if (!HashTable_Foreach(channels->channelEvents, channels_process, instance->context))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -743,6 +788,60 @@ BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL freerdp_client_channel_register(rdpChannels* channels, HANDLE handle,
|
||||||
|
freerdp_channel_handle_fkt_t fkt, void* userdata)
|
||||||
|
{
|
||||||
|
if (!channels || (handle == INVALID_HANDLE_VALUE) || !fkt)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Invalid function arguments (channels=%p, handle=%p, fkt=%p, userdata=%p",
|
||||||
|
channels, handle, fkt, userdata);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelEventEntry entry = { .fkt = fkt, .userdata = userdata };
|
||||||
|
return HashTable_Insert(channels->channelEvents, handle, &entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL freerdp_client_channel_unregister(rdpChannels* channels, HANDLE handle)
|
||||||
|
{
|
||||||
|
if (!channels || (handle == INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Invalid function arguments (channels=%p, handle=%p", channels, handle);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HashTable_Remove(channels->channelEvents, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSIZE_T freerdp_client_channel_get_registered_event_handles(rdpChannels* channels, HANDLE* events,
|
||||||
|
DWORD count)
|
||||||
|
{
|
||||||
|
SSIZE_T rc = -1;
|
||||||
|
|
||||||
|
WINPR_ASSERT(channels);
|
||||||
|
WINPR_ASSERT(events || (count == 0));
|
||||||
|
|
||||||
|
HashTable_Lock(channels->channelEvents);
|
||||||
|
size_t len = HashTable_Count(channels->channelEvents);
|
||||||
|
if (len <= count)
|
||||||
|
{
|
||||||
|
ULONG_PTR* keys = NULL;
|
||||||
|
const size_t nrKeys = HashTable_GetKeys(channels->channelEvents, &keys);
|
||||||
|
if ((nrKeys <= SSIZE_MAX) && (nrKeys == len))
|
||||||
|
{
|
||||||
|
for (size_t x = 0; x < nrKeys; x++)
|
||||||
|
{
|
||||||
|
HANDLE cur = (HANDLE)keys[x];
|
||||||
|
events[x] = cur;
|
||||||
|
}
|
||||||
|
rc = (SSIZE_T)nrKeys;
|
||||||
|
}
|
||||||
|
free(keys);
|
||||||
|
}
|
||||||
|
HashTable_Unlock(channels->channelEvents);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
|
UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
|
||||||
{
|
{
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
@ -759,7 +858,7 @@ UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
|
|||||||
/* tell all libraries we are shutting down */
|
/* tell all libraries we are shutting down */
|
||||||
for (int index = 0; index < channels->clientDataCount; index++)
|
for (int index = 0; index < channels->clientDataCount; index++)
|
||||||
{
|
{
|
||||||
ChannelDisconnectedEventArgs e;
|
ChannelDisconnectedEventArgs e = { 0 };
|
||||||
pChannelClientData = &channels->clientDataList[index];
|
pChannelClientData = &channels->clientDataList[index];
|
||||||
|
|
||||||
if (pChannelClientData->pChannelInitEventProc)
|
if (pChannelClientData->pChannelInitEventProc)
|
||||||
|
@ -107,6 +107,8 @@ struct rdp_channels
|
|||||||
|
|
||||||
DrdynvcClientContext* drdynvc;
|
DrdynvcClientContext* drdynvc;
|
||||||
CRITICAL_SECTION channelsLock;
|
CRITICAL_SECTION channelsLock;
|
||||||
|
|
||||||
|
wHashTable* channelEvents;
|
||||||
};
|
};
|
||||||
|
|
||||||
FREERDP_LOCAL void freerdp_channels_free(rdpChannels* channels);
|
FREERDP_LOCAL void freerdp_channels_free(rdpChannels* channels);
|
||||||
@ -121,4 +123,9 @@ FREERDP_LOCAL void freerdp_channels_register_instance(rdpChannels* channels, fre
|
|||||||
FREERDP_LOCAL UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance);
|
FREERDP_LOCAL UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance);
|
||||||
FREERDP_LOCAL UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance);
|
FREERDP_LOCAL UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance);
|
||||||
|
|
||||||
|
/** @since version 3.9.0 */
|
||||||
|
FREERDP_LOCAL SSIZE_T freerdp_client_channel_get_registered_event_handles(rdpChannels* channels,
|
||||||
|
HANDLE* events,
|
||||||
|
DWORD count);
|
||||||
|
|
||||||
#endif /* FREERDP_LIB_CORE_CLIENT_H */
|
#endif /* FREERDP_LIB_CORE_CLIENT_H */
|
||||||
|
@ -391,7 +391,11 @@ DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return nCount;
|
const SSIZE_T rc = freerdp_client_channel_get_registered_event_handles(
|
||||||
|
context->channels, &events[nCount], count - nCount);
|
||||||
|
if (rc < 0)
|
||||||
|
return 0;
|
||||||
|
return nCount + (DWORD)rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
|
/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
|
||||||
|
Loading…
Reference in New Issue
Block a user