The listener API provides a lightweight TCP server that binds to a port, accepts incoming RDP connections, and vends freerdp_peer objects via the PeerAccepted callback.
Header: <freerdp/listener.h>
Lifecycle
freerdp_listener_new
freerdp_listener* freerdp_listener_new(void);
Allocates a new listener instance. Returns NULL on failure. Pair with freerdp_listener_free() when done.
freerdp_listener_free
void freerdp_listener_free(freerdp_listener* instance);
Closes any open sockets and releases all resources.
Struct: rdp_freerdp_listener
typedefd as freerdp_listener. All functional members are function pointers set by the implementation.
typedef BOOL (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client);
Callback invoked for each newly accepted connection. The implementation receives a ready-to-use freerdp_peer*. Typically used to spawn a worker thread for the peer. Return FALSE to immediately reject and free the peer.
typedef BOOL (*psListenerOpen)(freerdp_listener* instance,
const char* bind_address, UINT16 port);
Binds and listens on a TCP address/port. bind_address may be NULL to listen on all interfaces. Returns FALSE on error.
typedef BOOL (*psListenerOpenLocal)(freerdp_listener* instance, const char* path);
Binds and listens on a Unix-domain socket at path. Useful for local IPC connections.
typedef BOOL (*psListenerOpenFromSocket)(freerdp_listener* instance, int fd);
Takes ownership of an already-bound, already-listening socket file descriptor. Useful for socket-activation (e.g. systemd).
GetEventHandles
psListenerGetEventHandles
typedef DWORD (*psListenerGetEventHandles)(freerdp_listener* instance,
HANDLE* events, DWORD nCount);
Fills events[] with all waitable handles the listener uses (one per open socket). Returns the number of handles written. Use these with WaitForMultipleObjects in the accept loop.
CheckFileDescriptor
psListenerCheckFileDescriptor
typedef BOOL (*psListenerCheckFileDescriptor)(freerdp_listener* instance);
Processes any pending accepts. For each ready connection a freerdp_peer is created and PeerAccepted is called. Returns FALSE on a fatal listener error.
CheckPeerAcceptRestrictions
psListenerCheckFileDescriptor
psListenerCheckFileDescriptor CheckPeerAcceptRestrictions;
Optional hook. When set, called before PeerAccepted to allow early connection filtering (e.g. rate limiting, IP allow-lists).
typedef void (*psListenerClose)(freerdp_listener* instance);
Closes all listening sockets. New connections will no longer be accepted. In-flight peers are unaffected.
Accept Loop Example
#include <freerdp/listener.h>
#include <freerdp/peer.h>
static DWORD WINAPI peer_thread(LPVOID arg);
static BOOL on_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
{
HANDLE thread = CreateThread(NULL, 0, peer_thread, client, 0, NULL);
if (!thread)
{
freerdp_peer_free(client);
return FALSE;
}
CloseHandle(thread); /* detached */
return TRUE;
}
int main(void)
{
freerdp_listener* listener = freerdp_listener_new();
if (!listener)
return 1;
listener->PeerAccepted = on_peer_accepted;
if (!listener->Open(listener, NULL, 3389))
{
freerdp_listener_free(listener);
return 1;
}
while (TRUE)
{
HANDLE handles[32];
DWORD count = listener->GetEventHandles(listener, handles, 32);
if (count == 0) break;
DWORD status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
if (status == WAIT_FAILED) break;
if (!listener->CheckFileDescriptor(listener))
break;
}
listener->Close(listener);
freerdp_listener_free(listener);
return 0;
}
PeerAccepted is called on the listener thread. Offload long-running work (the entire peer RDP handshake) to a dedicated thread to avoid blocking incoming accepts.
For Unix socket support (e.g. xrdp integration), use listener->OpenLocal(listener, "/tmp/my_rdp.sock") instead of Open.