Open-Source Wikis

/

curl

/

Systems

/

Connection management

curl/curl

Connection management

Active contributors: Stefan Eissing, Daniel Stenberg, Viktor Szakats

Purpose

Connection management is the set of subsystems that decide whether to reuse an existing TCP/QUIC connection or open a new one, that hold idle connections for reuse, and that tear connections down cleanly. The decisions live in lib/url.c, the bookkeeping lives in lib/conncache.c and lib/cshutdn.c, and the actual TCP work lives in lib/connect.c and lib/cf-socket.c.

Key abstractions

Symbol File Description
struct connectdata lib/urldata.h A single connection, its filter chain, the protocol handler, and reuse metadata
struct conncache lib/conncache.h A hash from "destination key" to a list of connectdata
struct connshutdowns lib/cshutdn.h Connections that have gone DONE but still need quiet shutdown
Curl_cpool_* lib/conncache.c The internal connection-pool API
Curl_conncache_find_conn() lib/conncache.c Looks up a reusable existing connection
Curl_attach_connection() lib/url.c Binds an easy handle to a connectdata
Curl_detach_connection() lib/url.c Releases the handle and decides whether the connection goes back to the cache
Curl_close_connect_only() lib/url.c Special-case shutdown for CURLOPT_CONNECT_ONLY users
Curl_setup_conn() lib/url.c Builds a fresh connection record from a parsed URL

Directory layout

lib/
├── url.c          # The big "do I have a usable connection? otherwise build one" function
├── conncache.c    # Hash + LRU of idle connections
├── cshutdn.c      # Shutdown queue (sockets that need a clean close)
├── connect.c      # TCP connection establishment (sync layer over cfilters)
├── cf-socket.c    # The bottom-most cfilter: write/read on a socket
├── cf-ip-happy.c  # Happy Eyeballs (IPv4/IPv6 race)
├── cf-dns.c       # DNS-aware cfilter (re-resolve mid-flight)
├── cf-https-connect.c # CONNECT-tunnelling cfilter
├── cf-h1-proxy.c  # HTTP/1 proxy CONNECT
├── cf-h2-proxy.c  # HTTP/2 proxy CONNECT (tunnelled streams)
└── cf-haproxy.c   # PROXY-protocol prelude

How it works

When a transfer needs a connection:

graph TD
    A[Curl_setup_conn] --> B{cache hit on dest hash?}
    B -- yes --> C[reuse connectdata, attach to easy handle]
    B -- no  --> D[create new connectdata]
    D --> E[build cfilter chain<br/>socket → tls → http2 → proxy]
    E --> F[Curl_resolv]
    F --> G[Curl_connect]
    G --> H[connectdata ready]
    C --> I[transfer proceeds]
    H --> I

The "destination hash" is computed from origin (scheme/host/port), proxy, TLS configuration, HTTP version preference, source address, and a handful of other options that affect socket reuse. Two transfers with mismatched hashes never share a connection. The hash function is cpool_buckethash in lib/conncache.c.

When a transfer leaves MSTATE_DONE:

  1. If the protocol declined reuse (e.g. Connection: close, FTP after upload, error) the connection is moved to the shutdown list (lib/cshutdn.c).
  2. Otherwise it goes back to the conn cache as idle.

Idle connections are evicted by CURLOPT_MAXAGE_CONN and CURLOPT_MAXLIFETIME_CONN, and capped by CURLOPT_MAXCONNECTS (per-easy and per-multi). Eviction happens lazily on lookup or explicitly via curl_easy_pause / curl_multi_remove_handle.

Share handle

Multiple multi/easy handles can share a single connection cache via curl_share_setopt(sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT). The share handle is implemented in lib/curl_share.c and uses application-supplied locks to serialize access. Sharing is also available for DNS, cookies, TLS sessions, HSTS, and PSL state.

Happy Eyeballs

When the resolver returns both IPv4 and IPv6 addresses, lib/cf-ip-happy.c opens parallel connections to each family with a small head-start for IPv6 (configurable via CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS). Whichever connection wins is kept; the other is aborted. This is purely a cfilter — the higher layers see a single connection.

sequenceDiagram
    participant Multi
    participant CF as cf-ip-happy
    participant V6 as IPv6 socket
    participant V4 as IPv4 socket
    Multi->>CF: connect()
    CF->>V6: connect (start)
    Note over CF: 200 ms head-start
    CF->>V4: connect (start)
    V6-->>CF: SYN-ACK first
    CF->>V4: cancel
    CF-->>Multi: connected (v6)

Shutdown

Quiet shutdown matters for protocols where the peer expects an explicit goodbye (TLS close_notify, FTP QUIT, SSH disconnect, HTTP/2 GOAWAY). Connections that need a graceful close go into cshutdowns and are drained by the multi loop in spare cycles. The shutdown timeout is bounded by CURLOPT_QUICK_EXIT and the global multi shutdown timer.

Integration points

  • Transfer engine: every MSTATE_SETUP calls into Curl_setup_conn (lib/url.c); every MSTATE_DONE decides reuse via the protocol handler's done callback and the cache.
  • Connection filters: each connectdata owns a cfilter chain that does the actual I/O. See Connection filters.
  • DNS: connection setup blocks on Curl_resolv (lib/hostip.c) which fans out to the configured resolver backend.
  • TLS-session cache: the conn cache holds TLS sessions in lib/vtls/vtls_scache.c so HTTPS reconnects can resume.
  • HSTS / alt-svc: lib/hsts.c and lib/altsvc.c rewrite the destination before the connection key is computed.

Entry points for modification

  • Tuning the destination hash → cpool_buckethash in lib/conncache.c.
  • Adding a new dimension to "are these two requests poolable?" → IsMultiplexAllowed and Curl_conn_seems_dead in lib/url.c/lib/connect.c.
  • Replacing the LRU strategy → Curl_cpool_* in lib/conncache.c.
  • New connection-establishment behaviour → consider whether it belongs in a cfilter (see cf-ip-happy.c or cf-dns.c as templates) before adding to connect.c.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Connection management – curl wiki | Factory