Skip to main content
FreeRDP can act as an RDP server in three distinct ways. Each mode targets a different use case and exposes a different level of API surface.

Sample server

Build a fully custom RDP server using the freerdp_peer API. The sample server in server/Sample/ is the canonical starting point.

Shadow server

Share the host’s physical or virtual screen over RDP. Ships as the freerdp-shadow-cli binary.

RDP proxy

Sit between an RDP client and a real RDP server, inspecting or modifying traffic. Ships as the freerdp-proxy binary.

Choosing a mode

GoalMode
Write a custom RDP server that generates its own contentSample server / freerdp_peer API
Share your desktop or a virtual desktop with remote usersShadow server
Inspect, record, or filter traffic between a client and an existing serverRDP proxy

Common concepts

freerdp_peer

Every incoming RDP connection on the server side is represented by a freerdp_peer object (defined in include/freerdp/peer.h). A peer holds:
  • A pointer to rdpContext (settings, input, update interfaces)
  • State fields: connected, activated, authenticated
  • Function pointers for the connection lifecycle callbacks (PostConnect, Activate, Logon, …)
  • Method pointers for I/O (Initialize, GetEventHandles, CheckFileDescriptor, Close, Disconnect)
freerdp_peer* peer = freerdp_peer_new(sockfd);
// configure callbacks and settings …
peer->Initialize(peer); // start the RDP handshake

freerdp_listener

The listener (defined in include/freerdp/listener.h) accepts incoming TCP (or Unix-socket) connections and creates one freerdp_peer per connection.
freerdp_listener* listener = freerdp_listener_new();
listener->PeerAccepted = my_peer_accepted_callback;
listener->Open(listener, NULL, 3389); // bind port
// run main loop …
freerdp_listener_free(listener);

rdpContext on the server side

On the client side rdpContext is embedded inside a freerdp (client instance) struct. On the server side it is embedded inside a freerdp_peer struct. You access it through peer->context. The context carries:
  • context->settingsrdpSettings* controlling protocol behaviour
  • context->inputrdpInput* for registering input event callbacks (keyboard, mouse)
  • context->updaterdpUpdate* for sending graphics updates to the client
  • context->peer — back-pointer to the owning freerdp_peer
Server-side code must use peer->context->settings (or client->context->settings inside a callback, where client is the freerdp_peer*). The deprecated direct peer->settings alias was removed in FreeRDP 3.x.

Server-side vs client-side context differences

AspectClient sideServer side
Top-level structfreerdpfreerdp_peer
Context accessinstance->contextpeer->context
Connection initiationClient calls freerdp_connect()Peer calls peer->Initialize()
Graphics flowReceives rdpUpdate callbacksCalls update->SurfaceBits() etc. to send
Input flowSends input PDUsRegisters input->KeyboardEvent etc. to receive
Lifecyclefreerdp_new / freerdp_freefreerdp_peer_new / freerdp_peer_free

Build flags

ComponentCMake flag
Sample serverAlways built (part of default targets)
Shadow server-DWITH_SHADOW=ON
RDP proxy-DWITH_PROXY=ON