cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
grpc_client.c File Reference

HTTP/2-based gRPC client (h2c cleartext, or TLS with ALPN "h2"). More...

#include <cwist/net/grpc/grpc_client.h>
#include <cwist/core/mem/alloc.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include <openssl/ssl.h>
Include dependency graph for grpc_client.c:

Go to the source code of this file.

Macros

#define _POSIX_C_SOURCE   200809L
 
#define GRPC_CLIENT_FRAME_HEADER   9
 
#define GRPC_CLIENT_MAX_FRAME   (16u * 1024u * 1024u)
 
#define GRPC_CLIENT_DEFAULT_WINDOW   65535
 
#define GRPC_CLIENT_HEADER_TABLE   4096
 
#define H2_FRAME_DATA   0x00
 
#define H2_FRAME_HEADERS   0x01
 
#define H2_FRAME_RST_STREAM   0x03
 
#define H2_FRAME_SETTINGS   0x04
 
#define H2_FRAME_PUSH_PROMISE   0x05
 
#define H2_FRAME_PING   0x06
 
#define H2_FRAME_GOAWAY   0x07
 
#define H2_FRAME_WINDOW_UPDATE   0x08
 
#define H2_FRAME_CONTINUATION   0x09
 
#define H2_FLAG_END_STREAM   0x01
 
#define H2_FLAG_END_HEADERS   0x04
 
#define H2_FLAG_ACK   0x01
 

Typedefs

typedef struct grpc_client_hpack_entry grpc_client_hpack_entry
 
typedef struct grpc_client_msg grpc_client_msg
 
typedef struct grpc_client_frame grpc_client_frame
 
typedef void(* grpc_client_header_cb) (void *ctx, const char *name, const char *value)
 
typedef struct grpc_client_headers_ctx grpc_client_headers_ctx
 

Functions

cwist_grpc_client * cwist_grpc_client_connect (const char *host, uint16_t port, const cwist_grpc_client_options *options)
 Connect to a gRPC server and complete the HTTP/2 handshake.
 
void cwist_grpc_client_close (cwist_grpc_client *c)
 Close the client: send GOAWAY, tear down TLS and the socket, free all state.
 
cwist_grpc_call * cwist_grpc_call_start (cwist_grpc_client *c, const char *method, const void *request, size_t request_len, uint64_t timeout_ms)
 Start a unary call (no previous-attempt marker).
 
cwist_grpc_call * cwist_grpc_call_start_ex (cwist_grpc_client *c, const char *method, const void *request, size_t request_len, uint64_t timeout_ms, uint32_t previous_attempts)
 Start a unary call, with a gRFC A6 retry-attempt marker.
 
int cwist_grpc_call_recv (cwist_grpc_call *call, cwist_grpc_message *out)
 Receive the next response message of a call.
 
int cwist_grpc_call_await_headers (cwist_grpc_call *call)
 Block until response headers arrive or the stream ends.
 
int cwist_grpc_call_committed (const cwist_grpc_call *call)
 Whether response headers have committed the RPC (gRFC A6).
 
int cwist_grpc_call_refused (const cwist_grpc_call *call)
 Whether the call failed before commit in a retryable way (gRFC A6 case 3: REFUSED_STREAM before headers, or GOAWAY below our stream id).
 
int cwist_grpc_call_retry_pushback_ms (const cwist_grpc_call *call, int32_t *out_ms)
 Report the server-provided retry pushback delay, if any.
 
int cwist_grpc_client_dead (cwist_grpc_client *c)
 Whether the client connection is unusable.
 
cwist_grpc_status_t cwist_grpc_call_status (const cwist_grpc_call *call)
 Current gRPC status code of a call.
 
cwist_grpc_status_t cwist_grpc_call_finish (cwist_grpc_call *call, const char **message)
 Drain the call to completion and return its final status.
 
void cwist_grpc_call_cancel (cwist_grpc_call *call)
 Cancel a call: send RST_STREAM(CANCEL), mark it failed with CWIST_GRPC_CANCELLED, and end its stream.
 
void cwist_grpc_call_destroy (cwist_grpc_call *call)
 Destroy a call: cancel it if still open, release it as the client's active call, and free all queued and buffered state.
 

Detailed Description

HTTP/2-based gRPC client (h2c cleartext, or TLS with ALPN "h2").

The client speaks a minimal but complete HTTP/2 subset: client preface, SETTINGS exchange, HEADERS/DATA framing with HPACK (encoding reuses the shared h2_encode_* helpers from net/http/http2.c; decoding keeps a small per-connection dynamic table), coarse flow control (WINDOW_UPDATE in both directions), PING ACKs, and GOAWAY tolerance. gRPC message framing reuses cwist_grpc_encode_message / cwist_grpc_decoder from grpc.c.

One active call per connection; the mutex serializes call setup.

Definition in file grpc_client.c.

Macro Definition Documentation

◆ _POSIX_C_SOURCE

#define _POSIX_C_SOURCE   200809L

Definition at line 15 of file grpc_client.c.

◆ GRPC_CLIENT_DEFAULT_WINDOW

#define GRPC_CLIENT_DEFAULT_WINDOW   65535

Definition at line 35 of file grpc_client.c.

◆ GRPC_CLIENT_FRAME_HEADER

#define GRPC_CLIENT_FRAME_HEADER   9

Definition at line 33 of file grpc_client.c.

◆ GRPC_CLIENT_HEADER_TABLE

#define GRPC_CLIENT_HEADER_TABLE   4096

Definition at line 36 of file grpc_client.c.

◆ GRPC_CLIENT_MAX_FRAME

#define GRPC_CLIENT_MAX_FRAME   (16u * 1024u * 1024u)

Definition at line 34 of file grpc_client.c.

◆ H2_FLAG_ACK

#define H2_FLAG_ACK   0x01

Definition at line 49 of file grpc_client.c.

◆ H2_FLAG_END_HEADERS

#define H2_FLAG_END_HEADERS   0x04

Definition at line 48 of file grpc_client.c.

◆ H2_FLAG_END_STREAM

#define H2_FLAG_END_STREAM   0x01

Definition at line 47 of file grpc_client.c.

◆ H2_FRAME_CONTINUATION

#define H2_FRAME_CONTINUATION   0x09

Definition at line 46 of file grpc_client.c.

◆ H2_FRAME_DATA

#define H2_FRAME_DATA   0x00

Definition at line 38 of file grpc_client.c.

◆ H2_FRAME_GOAWAY

#define H2_FRAME_GOAWAY   0x07

Definition at line 44 of file grpc_client.c.

◆ H2_FRAME_HEADERS

#define H2_FRAME_HEADERS   0x01

Definition at line 39 of file grpc_client.c.

◆ H2_FRAME_PING

#define H2_FRAME_PING   0x06

Definition at line 43 of file grpc_client.c.

◆ H2_FRAME_PUSH_PROMISE

#define H2_FRAME_PUSH_PROMISE   0x05

Definition at line 42 of file grpc_client.c.

◆ H2_FRAME_RST_STREAM

#define H2_FRAME_RST_STREAM   0x03

Definition at line 40 of file grpc_client.c.

◆ H2_FRAME_SETTINGS

#define H2_FRAME_SETTINGS   0x04

Definition at line 41 of file grpc_client.c.

◆ H2_FRAME_WINDOW_UPDATE

#define H2_FRAME_WINDOW_UPDATE   0x08

Definition at line 45 of file grpc_client.c.

Typedef Documentation

◆ grpc_client_frame

typedef struct grpc_client_frame grpc_client_frame

◆ grpc_client_header_cb

typedef void(* grpc_client_header_cb) (void *ctx, const char *name, const char *value)

Definition at line 394 of file grpc_client.c.

◆ grpc_client_headers_ctx

typedef struct grpc_client_headers_ctx grpc_client_headers_ctx

◆ grpc_client_hpack_entry

typedef struct grpc_client_hpack_entry grpc_client_hpack_entry

◆ grpc_client_msg

typedef struct grpc_client_msg grpc_client_msg

Function Documentation

◆ cwist_grpc_call_await_headers()

int cwist_grpc_call_await_headers ( cwist_grpc_call *  call)

Block until response headers arrive or the stream ends.

Parameters
callThe call.
Return values
0Response headers received (the RPC is committed).
1The stream ended before any response headers (retryable).
-1Invalid call, error, or deadline.

Definition at line 1228 of file grpc_client.c.

Referenced by cwist_grpc_channel_call_start().

◆ cwist_grpc_call_cancel()

void cwist_grpc_call_cancel ( cwist_grpc_call *  call)

Cancel a call: send RST_STREAM(CANCEL), mark it failed with CWIST_GRPC_CANCELLED, and end its stream.

Parameters
callThe call; NULL or an already-ended call is a no-op.

Definition at line 1308 of file grpc_client.c.

References cap, CWIST_GRPC_CANCELLED, and H2_FRAME_RST_STREAM.

Referenced by cwist_grpc_call_destroy(), and cwist_grpc_channel_call_cancel().

◆ cwist_grpc_call_committed()

int cwist_grpc_call_committed ( const cwist_grpc_call *  call)

Whether response headers have committed the RPC (gRFC A6).

Returns
Nonzero if committed; 0 for a NULL call or not yet committed.

Definition at line 1241 of file grpc_client.c.

◆ cwist_grpc_call_destroy()

void cwist_grpc_call_destroy ( cwist_grpc_call *  call)

Destroy a call: cancel it if still open, release it as the client's active call, and free all queued and buffered state.

Parameters
callThe call; NULL is a no-op.

Definition at line 1323 of file grpc_client.c.

References cap, cwist_free(), cwist_grpc_call_cancel(), and cwist_grpc_decoder_destroy().

Referenced by cwist_grpc_channel_call_destroy(), cwist_grpc_channel_call_start(), and cwist_grpc_client_close().

◆ cwist_grpc_call_finish()

cwist_grpc_status_t cwist_grpc_call_finish ( cwist_grpc_call *  call,
const char **  message 
)

Drain the call to completion and return its final status.

Parameters
callThe call.
messageWhen non-NULL, set to the status message text; the pointer is owned by the call and stays valid until cwist_grpc_call_destroy.
Returns
The final gRPC status code; CWIST_GRPC_INTERNAL for a NULL call.

Definition at line 1291 of file grpc_client.c.

References cap, and CWIST_GRPC_INTERNAL.

Referenced by cwist_grpc_channel_call_finish().

◆ cwist_grpc_call_recv()

int cwist_grpc_call_recv ( cwist_grpc_call *  call,
cwist_grpc_message *  out 
)

Receive the next response message of a call.

Parameters
callThe call.
outFilled with the next message; out->data is owned by the call and stays valid until the next recv or cwist_grpc_call_destroy.
Return values
1A message was returned.
0The stream ended cleanly and no more messages will arrive.
-1The call failed (see cwist_grpc_call_status).

Definition at line 1203 of file grpc_client.c.

References cap, cwist_grpc_message::compressed, cwist_free(), cwist_grpc_message::data, and cwist_grpc_message::len.

Referenced by cwist_grpc_channel_call_recv().

◆ cwist_grpc_call_refused()

int cwist_grpc_call_refused ( const cwist_grpc_call *  call)

Whether the call failed before commit in a retryable way (gRFC A6 case 3: REFUSED_STREAM before headers, or GOAWAY below our stream id).

Returns
Nonzero if retryable; 0 otherwise (NULL, committed, or trailers seen).

Definition at line 1250 of file grpc_client.c.

Referenced by cwist_grpc_channel_call_start().

◆ cwist_grpc_call_retry_pushback_ms()

int cwist_grpc_call_retry_pushback_ms ( const cwist_grpc_call *  call,
int32_t *  out_ms 
)

Report the server-provided retry pushback delay, if any.

Parameters
callThe call.
out_msSet to the pushback delay in ms (negative = do not retry) when present.
Returns
Nonzero if the grpc-retry-pushback-ms trailer arrived; 0 otherwise.

Definition at line 1261 of file grpc_client.c.

References cap.

Referenced by cwist_grpc_channel_call_start().

◆ cwist_grpc_call_start()

cwist_grpc_call * cwist_grpc_call_start ( cwist_grpc_client *  c,
const char *  method,
const void *  request,
size_t  request_len,
uint64_t  timeout_ms 
)

Start a unary call (no previous-attempt marker).

Parameters
cClient; must be connected and have no active call.
methodgRPC method path (e.g. "/pkg.Service/Method").
requestRequest message bytes; may be NULL when request_len is 0.
request_lenRequest length in bytes.
timeout_msPer-call deadline in ms; 0 means no deadline.
Returns
The started call, or NULL on invalid arguments, a busy/dead client, or a transport error while sending.
See also
cwist_grpc_call_start_ex

Definition at line 1094 of file grpc_client.c.

References cap, and cwist_grpc_call_start_ex().

◆ cwist_grpc_call_start_ex()

cwist_grpc_call * cwist_grpc_call_start_ex ( cwist_grpc_client *  c,
const char *  method,
const void *  request,
size_t  request_len,
uint64_t  timeout_ms,
uint32_t  previous_attempts 
)

Start a unary call, with a gRFC A6 retry-attempt marker.

Sends HEADERS (:method POST, :scheme, :path, :authority, content-type, te) followed by the framed request message, then commits the call as the client's active call. Serialized by the client mutex: one active call per connection.

Parameters
previous_attemptsValue for grpc-previous-rpc-attempts; 0 omits the header.
Returns
The started call, or NULL on invalid arguments, a busy/dead client, or a transport error while sending (state is cleaned up).

Definition at line 1112 of file grpc_client.c.

References cap, cwist_alloc(), cwist_free(), cwist_grpc_decoder_destroy(), cwist_grpc_decoder_init(), cwist_grpc_encode_message(), CWIST_GRPC_OK, H2_FLAG_END_HEADERS, and H2_FRAME_HEADERS.

Referenced by cwist_grpc_call_start(), and cwist_grpc_channel_call_start().

◆ cwist_grpc_call_status()

cwist_grpc_status_t cwist_grpc_call_status ( const cwist_grpc_call *  call)

Current gRPC status code of a call.

Parameters
callThe call.
Returns
The status code; CWIST_GRPC_INTERNAL for a NULL call.

Definition at line 1280 of file grpc_client.c.

References CWIST_GRPC_INTERNAL.

Referenced by cwist_grpc_channel_call_destroy(), and cwist_grpc_channel_call_start().

◆ cwist_grpc_client_close()

void cwist_grpc_client_close ( cwist_grpc_client *  c)

Close the client: send GOAWAY, tear down TLS and the socket, free all state.

Parameters
cClient to close; NULL is a no-op.

Definition at line 701 of file grpc_client.c.

References cap, cwist_free(), cwist_grpc_call_destroy(), H2_FRAME_GOAWAY, SSL_CTX_free, SSL_free, and SSL_shutdown.

Referenced by cwist_grpc_channel_close(), and cwist_grpc_client_connect().

◆ cwist_grpc_client_connect()

cwist_grpc_client * cwist_grpc_client_connect ( const char *  host,
uint16_t  port,
const cwist_grpc_client_options *  options 
)

Connect to a gRPC server and complete the HTTP/2 handshake.

Parameters
hostServer hostname or address.
portTCP port number.
optionsOptional TLS/timeout/authority options; NULL for defaults (no TLS, 10 s connect timeout, authority "host:port").
Returns
Connected client on success; NULL on any failure (partially built state is cleaned up before returning).
Note
Performs TCP connect, optional TLS with ALPN "h2", sends the client preface and SETTINGS, and waits for the server SETTINGS and the ACK of our own SETTINGS.

Definition at line 624 of file grpc_client.c.

References cwist_grpc_client_options::authority, cap, cwist_grpc_client_options::connect_timeout_ms, cwist_alloc(), cwist_free(), cwist_grpc_client_close(), GRPC_CLIENT_DEFAULT_WINDOW, GRPC_CLIENT_HEADER_TABLE, H2_FLAG_ACK, H2_FRAME_GOAWAY, H2_FRAME_PING, H2_FRAME_SETTINGS, cwist_grpc_client_options::tls_server_name, cwist_grpc_client_options::use_tls, and cwist_grpc_client_options::verify_peer.

◆ cwist_grpc_client_dead()

int cwist_grpc_client_dead ( cwist_grpc_client *  c)

Whether the client connection is unusable.

Returns
Nonzero if the client is NULL, the transport died, or GOAWAY arrived.

Definition at line 1271 of file grpc_client.c.

References cap.

Referenced by cwist_grpc_channel_get_state().