Packages
hackney
3.0.2
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/quic_conn.h
/**
* quic_conn.h - QUIC connection resource management using lsquic
*
* This file is part of hackney released under the Apache 2 license.
* See the NOTICE for more information.
*
* Copyright (c) 2024-2026 Benoit Chesneau
*/
#ifndef QUIC_CONN_H
#define QUIC_CONN_H
#include "hackney_quic_nif.h"
#include <lsquic.h>
#include <openssl/ssl.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Connection states */
typedef enum {
QUIC_CONN_IDLE,
QUIC_CONN_HANDSHAKING,
QUIC_CONN_CONNECTED,
QUIC_CONN_DRAINING,
QUIC_CONN_CLOSED
} QuicConnState;
/* Stream context for tracking individual HTTP/3 streams */
typedef struct QuicStream {
int64_t stream_id;
lsquic_stream_t *stream; /* lsquic stream handle */
struct QuicConn *conn;
bool headers_sent;
bool headers_received;
bool fin_sent;
bool fin_received;
struct QuicStream *next; /* Linked list */
} QuicStream;
/* Header set for receiving headers */
typedef struct QuicHeaderSet {
ERL_NIF_TERM headers_list; /* Erlang list of {Name, Value} tuples */
ErlNifEnv *env; /* Environment for building the list */
struct QuicConn *conn;
int64_t stream_id;
} QuicHeaderSet;
/* QUIC connection resource */
struct QuicConn {
/* lsquic engine (one per connection for simplicity) */
lsquic_engine_t *engine;
/* lsquic connection handle */
lsquic_conn_t *conn;
/* OpenSSL TLS context */
SSL_CTX *ssl_ctx;
/* UDP socket */
int sockfd;
/* Owner Erlang process */
ErlNifPid owner_pid;
/* Mutex for thread safety */
ErlNifMutex *mutex;
/* Connection state */
QuicConnState state;
/* Remote address info */
struct sockaddr_storage remote_addr;
socklen_t remote_addrlen;
/* Local address info */
struct sockaddr_storage local_addr;
socklen_t local_addrlen;
/* Hostname for SNI */
char *hostname;
/* Port number */
uint16_t port;
/* Timer for retransmission/keep-alive (microseconds) */
uint64_t next_timeout_us;
/* Session ticket for 0-RTT (future use) */
uint8_t *session_ticket;
size_t session_ticket_len;
/* Reference count for cleanup */
int ref_count;
/* Active streams (linked list) */
QuicStream *streams;
/* Self-reference for lsquic callbacks */
ERL_NIF_TERM self_ref;
/* Flag for whether we're currently processing */
bool processing;
/* Select mode support (replaces I/O thread) */
ERL_NIF_TERM select_ref; /* Reference for enif_select messages */
bool select_armed; /* True if waiting for select notification */
/* Flag to prevent double-destroy */
volatile int destroyed;
};
/* Global initialization (call once at NIF load) */
int quic_global_init(void);
/* Global cleanup (call once at NIF unload) */
void quic_global_cleanup(void);
/* Initialize the QUIC connection resource type */
int quic_conn_resource_init(ErlNifEnv *env);
/* Create a new QUIC connection */
QuicConn *quic_conn_create(ErlNifEnv *env, ErlNifPid owner_pid);
/* Start QUIC connection to host:port
* If sockfd >= 0, use the provided socket instead of creating a new one.
* The socket should be a bound, non-blocking UDP socket.
* Ownership of the socket is transferred to QuicConn.
*/
int quic_conn_connect(QuicConn *conn, const char *hostname, uint16_t port,
int sockfd, const struct sockaddr *local_addr, socklen_t local_addrlen);
/* Increment reference count */
void quic_conn_keep(QuicConn *conn);
/* Decrement reference count, destroy if zero */
void quic_conn_release(QuicConn *conn);
/* Destroy a QUIC connection */
void quic_conn_destroy(QuicConn *conn);
/* Resource destructor callback */
void quic_conn_resource_dtor(ErlNifEnv *env, void *obj);
/* Stream operations */
int64_t quic_conn_open_stream(QuicConn *conn);
int quic_conn_send_headers(QuicConn *conn, int64_t stream_id,
ErlNifEnv *env, ERL_NIF_TERM headers_list, bool fin);
int quic_conn_send_data(QuicConn *conn, int64_t stream_id,
const uint8_t *data, size_t len, bool fin);
int quic_conn_reset_stream(QuicConn *conn, int64_t stream_id, uint64_t error_code);
/* Close connection gracefully */
int quic_conn_close(QuicConn *conn);
/* Process timeouts - returns next timeout in ms or -1 for infinity */
int64_t quic_conn_handle_timeout(QuicConn *conn);
/* Process pending I/O - called from dirty scheduler
* Returns next timeout in ms, or -1 for infinity */
int quic_conn_process(QuicConn *conn, ErlNifEnv *env);
/* Get peer/local addresses */
int quic_conn_peername(QuicConn *conn, struct sockaddr_storage *addr, socklen_t *addrlen);
int quic_conn_sockname(QuicConn *conn, struct sockaddr_storage *addr, socklen_t *addrlen);
#endif /* QUIC_CONN_H */