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

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_listener

The listener (defined in include/freerdp/listener.h) accepts incoming TCP (or Unix-socket) connections and creates one freerdp_peer per connection.

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

Build flags