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 preludeHow 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 --> IThe "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:
- If the protocol declined reuse (e.g.
Connection: close, FTP after upload, error) the connection is moved to the shutdown list (lib/cshutdn.c). - 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_SETUPcalls intoCurl_setup_conn(lib/url.c); everyMSTATE_DONEdecides reuse via the protocol handler'sdonecallback and the cache. - Connection filters: each
connectdataowns 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.cso HTTPS reconnects can resume. - HSTS / alt-svc:
lib/hsts.candlib/altsvc.crewrite the destination before the connection key is computed.
Entry points for modification
- Tuning the destination hash →
cpool_buckethashinlib/conncache.c. - Adding a new dimension to "are these two requests poolable?" →
IsMultiplexAllowedandCurl_conn_seems_deadinlib/url.c/lib/connect.c. - Replacing the LRU strategy →
Curl_cpool_*inlib/conncache.c. - New connection-establishment behaviour → consider whether it belongs in a cfilter (see
cf-ip-happy.corcf-dns.cas templates) before adding toconnect.c.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.