Skip to main content
FreeRDP is organized as a layered library stack. Application frontends such as xfreerdp and sdl-freerdp sit on top of libfreerdp (the protocol core), which in turn relies on libwinpr for OS-abstraction primitives. Virtual channel plugins extend the protocol with optional capabilities.

Major Components

libfreerdp implements the full RDP protocol stack: negotiation, capability exchange, input/output, graphics pipeline, licensing, and channel multiplexing. Every public API lives behind the FREERDP_API visibility macro and is declared in include/freerdp/.Key internal modules (libfreerdp/core/):
libwinpr provides Windows API compatibility on Linux, macOS, and BSD: threading primitives (HANDLE, wThread), SSPI for NTLM/Kerberos, stream utilities (wStream), logging (wLog), and more. FreeRDP code uses WinPR types exclusively so that the same source compiles on every platform.
Each virtual channel is a loadable plugin that follows either the static virtual channel (SVC) or dynamic virtual channel (DVC) plugin ABI. Plugins live under channels/ and are built as separate shared libraries (e.g. libfreerdp-client-cliprdr.so). See Channels for a full list.
Frontends are thin wrappers that create a freerdp instance, populate settings, register callbacks, and run an event loop:
  • xfreerdp — X11 frontend (client/X11/)
  • sdl-freerdp — SDL2/SDL3 cross-platform frontend (client/SDL/)
  • wfreerdp — Windows native frontend (client/Windows/)
  • libfreerdp-client — Shared client helper library used by all frontends
libfreerdp also contains a server-side peer API. A freerdp_peer struct (include/freerdp/peer.h) exposes callbacks such as Capabilities, PostConnect, Activate, and Logon that a server application implements. The shadow server (server/shadow/) is a full reference implementation.

Connection Lifecycle

The diagram below shows the sequence a client goes through from freerdp_new() to an active session.
1

TCP connect

freerdp_connect() resolves the hostname from FreeRDP_ServerHostname and opens a TCP connection to FreeRDP_ServerPort (default 3389).
2

Protocol negotiation

nego.c sends a Connection Request with the requested security protocol (PROTOCOL_TLS, PROTOCOL_HYBRID for NLA, etc.) and waits for the server’s Connection Confirm.
3

TLS handshake

The raw TCP socket is upgraded to TLS. Certificate verification fires the VerifyCertificateEx or VerifyX509Certificate callback.
4

NLA / CredSSP

When NLA is negotiated, nla.c performs a CredSSP handshake carrying SPNEGO tokens (NTLM or Kerberos). The AuthenticateEx callback supplies credentials.
5

Capability exchange

MCS and GCC data blocks carry client/server capability sets. FreeRDP creates three rdpSettings instances: initial config, remote peer settings, and merged settings.
6

Active session

After PostConnect returns TRUE, the connection is active. The client drives the event loop with freerdp_check_event_handles() and queries connection state with freerdp_get_state() / freerdp_is_active_state().

The rdpContext Structure

rdpContext (include/freerdp/freerdp.h) is the central hub that ties every subsystem together. It is allocated by freerdp_context_new() and lives for the duration of the connection.
Client applications typically extend rdpContext by setting instance->ContextSize to sizeof(MyClientContext), where MyClientContext embeds rdpContext as its first field:

The rdp_freerdp Instance

The freerdp typedef (struct rdp_freerdp) is the top-level handle passed to every public API. It carries:

Client Frontend Pattern

All bundled frontends follow the same pattern.
The RDP_CLIENT_ENTRY_POINTS struct (include/freerdp/client.h) provides an alternative entry-point mechanism used by the client helper library (libfreerdp-client). Frontends that use RdpClientEntry get GlobalInit, ClientNew, ClientStart, and ClientStop callbacks managed automatically.