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

gRPC client channel: name resolution (doc/naming.md), client-side load balancing (doc/load-balancing.md), connection backoff (doc/connection-backoff.md), and the gRFC A6 retry engine. More...

#include <cwist/net/grpc/grpc_channel.h>
#include <cwist/core/mem/alloc.h>
#include <cjson/cJSON.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
Include dependency graph for grpc_channel.c:

Go to the source code of this file.

Macros

#define _POSIX_C_SOURCE   200809L
 
#define GRPC_CHANNEL_MAX_ADDRS   64
 
#define GRPC_CHANNEL_DEFAULT_BUFFER_LIMIT   (256u * 1024u)
 
#define GRPC_CHANNEL_MAX_ATTEMPTS_CAP   5
 
#define GRPC_CHANNEL_CONN_BACKOFF_INITIAL_MS   1000.0
 
#define GRPC_CHANNEL_CONN_BACKOFF_MULTIPLIER   1.6
 
#define GRPC_CHANNEL_CONN_BACKOFF_MAX_MS   120000.0
 
#define GRPC_CHANNEL_CONN_BACKOFF_JITTER   0.2
 

Typedefs

typedef struct cwist_grpc_subchannel cwist_grpc_subchannel
 
typedef struct grpc_method_config grpc_method_config
 

Functions

cwist_grpc_channel_call * cwist_grpc_channel_call_start (cwist_grpc_channel *ch, const char *method, const void *request, size_t request_len, uint64_t timeout_ms)
 Start a unary RPC through the channel, running the gRFC A6 retry engine transparently across attempts.
 
int cwist_grpc_channel_call_recv (cwist_grpc_channel_call *cc, cwist_grpc_message *out)
 Receive the next response message of a channel call.
 
cwist_grpc_status_t cwist_grpc_channel_call_finish (cwist_grpc_channel_call *cc, const char **message)
 Finish a channel call and return its final gRPC status.
 
void cwist_grpc_channel_call_cancel (cwist_grpc_channel_call *cc)
 Cancel the underlying attempt call, if it reached the transport.
 
void cwist_grpc_channel_call_destroy (cwist_grpc_channel_call *cc)
 Destroy a channel call and release its resources.
 
uint32_t cwist_grpc_channel_call_attempts (const cwist_grpc_channel_call *cc)
 Number of policy attempts a channel call used (transparent retries excluded).
 
cwist_grpc_status_t cwist_grpc_channel_unary (cwist_grpc_channel *ch, const char *method, const void *request, size_t request_len, uint64_t timeout_ms, uint8_t **response, size_t *response_len, char **status_message)
 Convenience blocking unary RPC: start, read one response, finish.
 
cwist_grpc_channel * cwist_grpc_channel_connect (const char *target, const cwist_grpc_channel_options *options)
 Create a channel for target and resolve its backend addresses.
 
void cwist_grpc_channel_close (cwist_grpc_channel *ch)
 Close a channel and free all its resources.
 
cwist_grpc_channel_state cwist_grpc_channel_get_state (cwist_grpc_channel *ch)
 Aggregate connectivity state across subchannels (load-balancing.md).
 
int cwist_grpc_channel_apply_service_config_json (cwist_grpc_channel *ch, const char *json)
 Apply a JSON service config (doc/service_config.md subset, gRFC A6).
 

Detailed Description

gRPC client channel: name resolution (doc/naming.md), client-side load balancing (doc/load-balancing.md), connection backoff (doc/connection-backoff.md), and the gRFC A6 retry engine.

Layout mirrors gRPC: channel -> resolver -> subchannels (one per backend address) -> LB policy -> per-call pick. Retries live between the channel and the LB policy so every attempt can use a different subchannel (A6).

Retry engine notes (all gRFC A6):

  • The call deadline spans every attempt; each attempt's grpc-timeout header carries the remaining time.
  • A failed LB pick (TRANSIENT_FAILURE) is handled by the configured retry policy; with wait_for_ready the call waits instead of failing.
  • An RPC that never left the client is transparently retried until the deadline; an RPC refused before reaching server application logic (RST REFUSED_STREAM or GOAWAY last-stream-id below ours) gets one immediate transparent retry, then the configured policy. Transparent retries never count against maxAttempts nor the retry throttle.
  • Once Response-Headers arrive the RPC is committed and no retry happens.
  • Throttle bookkeeping: every failed attempt with a retryable-coded status (or a do-not-retry pushback) costs one token; a successful call refunds token_ratio once. Transparent retries are not counted.

Definition in file grpc_channel.c.

Macro Definition Documentation

◆ _POSIX_C_SOURCE

#define _POSIX_C_SOURCE   200809L

Definition at line 27 of file grpc_channel.c.

◆ GRPC_CHANNEL_CONN_BACKOFF_INITIAL_MS

#define GRPC_CHANNEL_CONN_BACKOFF_INITIAL_MS   1000.0

Definition at line 45 of file grpc_channel.c.

◆ GRPC_CHANNEL_CONN_BACKOFF_JITTER

#define GRPC_CHANNEL_CONN_BACKOFF_JITTER   0.2

Definition at line 48 of file grpc_channel.c.

◆ GRPC_CHANNEL_CONN_BACKOFF_MAX_MS

#define GRPC_CHANNEL_CONN_BACKOFF_MAX_MS   120000.0

Definition at line 47 of file grpc_channel.c.

◆ GRPC_CHANNEL_CONN_BACKOFF_MULTIPLIER

#define GRPC_CHANNEL_CONN_BACKOFF_MULTIPLIER   1.6

Definition at line 46 of file grpc_channel.c.

◆ GRPC_CHANNEL_DEFAULT_BUFFER_LIMIT

#define GRPC_CHANNEL_DEFAULT_BUFFER_LIMIT   (256u * 1024u)

Definition at line 41 of file grpc_channel.c.

◆ GRPC_CHANNEL_MAX_ADDRS

#define GRPC_CHANNEL_MAX_ADDRS   64

Definition at line 40 of file grpc_channel.c.

◆ GRPC_CHANNEL_MAX_ATTEMPTS_CAP

#define GRPC_CHANNEL_MAX_ATTEMPTS_CAP   5

Definition at line 42 of file grpc_channel.c.

Typedef Documentation

◆ cwist_grpc_subchannel

typedef struct cwist_grpc_subchannel cwist_grpc_subchannel

◆ grpc_method_config

typedef struct grpc_method_config grpc_method_config

Function Documentation

◆ cwist_grpc_channel_apply_service_config_json()

int cwist_grpc_channel_apply_service_config_json ( cwist_grpc_channel *  ch,
const char *  json 
)

Apply a JSON service config (doc/service_config.md subset, gRFC A6).

Parses loadBalancingConfig (first supported policy wins; deprecated loadBalancingPolicy string also accepted), retryThrottling, and methodConfig (retryPolicy, waitForReady, timeout per name; hedgingPolicy entries carry no policy, as in gRPC C-core). The whole document is validated before anything is swapped in; on error the channel is left untouched.

Return values
0applied
-1invalid JSON, invalid document, or allocation failure

Definition at line 1140 of file grpc_channel.c.

References cap, cwist_alloc(), cwist_free(), CWIST_GRPC_LB_PICK_FIRST, CWIST_GRPC_LB_ROUND_ROBIN, cwist_grpc_retry_throttle::max_tokens, and cwist_grpc_retry_throttle::token_ratio.

◆ cwist_grpc_channel_call_attempts()

uint32_t cwist_grpc_channel_call_attempts ( const cwist_grpc_channel_call *  call)

Number of policy attempts a channel call used (transparent retries excluded).

Number of RPC attempts made (transparent retries excluded, gRFC A6).

Definition at line 685 of file grpc_channel.c.

References cap.

◆ cwist_grpc_channel_call_cancel()

void cwist_grpc_channel_call_cancel ( cwist_grpc_channel_call *  cc)

Cancel the underlying attempt call, if it reached the transport.

Definition at line 658 of file grpc_channel.c.

References cap, and cwist_grpc_call_cancel().

◆ cwist_grpc_channel_call_destroy()

void cwist_grpc_channel_call_destroy ( cwist_grpc_channel_call *  cc)

Destroy a channel call and release its resources.

Performs the end-of-call throttle accounting first if finish() did not already. Destroys the underlying call, recycles/releases the subchannel, and frees the handle. NULL-safe.

Definition at line 668 of file grpc_channel.c.

References cap, cwist_free(), cwist_grpc_call_destroy(), and cwist_grpc_call_status().

Referenced by cwist_grpc_channel_unary().

◆ cwist_grpc_channel_call_finish()

cwist_grpc_status_t cwist_grpc_channel_call_finish ( cwist_grpc_channel_call *  cc,
const char **  message 
)

Finish a channel call and return its final gRPC status.

Performs the end-of-call throttle accounting once, if not already done by destroy. For synthetic results, returns the pre-dispatch status and message. message is borrowed (valid until the call is destroyed) and may be NULL.

Definition at line 637 of file grpc_channel.c.

References cap, cwist_grpc_call_finish(), and CWIST_GRPC_INTERNAL.

Referenced by cwist_grpc_channel_unary().

◆ cwist_grpc_channel_call_recv()

int cwist_grpc_channel_call_recv ( cwist_grpc_channel_call *  cc,
cwist_grpc_message *  out 
)

Receive the next response message of a channel call.

Synthetic (pre-dispatch failure) results carry no messages.

Return values
1a message was stored in out
0stream ended (or synthetic result), no more messages
-1invalid arguments

Definition at line 624 of file grpc_channel.c.

References cap, and cwist_grpc_call_recv().

Referenced by cwist_grpc_channel_unary().

◆ cwist_grpc_channel_call_start()

cwist_grpc_channel_call * cwist_grpc_channel_call_start ( cwist_grpc_channel *  ch,
const char *  method,
const void *  request,
size_t  request_len,
uint64_t  timeout_ms 
)

Start a unary RPC through the channel, running the gRFC A6 retry engine transparently across attempts.

Applies the most specific JSON method config (retry policy, waitForReady, timeout), clamps attempts to GRPC_CHANNEL_MAX_ATTEMPTS_CAP, and retries only while the request fits the per-RPC buffer limit. Blocks until the RPC is committed (Response-Headers or final result), fails with CWIST_GRPC_DEADLINE_EXCEEDED past the deadline, or waits instead of failing when waitForReady is set and no subchannel is ready.

Parameters
method"/package.Service/Method" path
request,request_lenserialized request (may be NULL when 0)
timeout_msper-call deadline, 0 for none (a method-config timeout may shorten it)
Returns
channel call handle, or NULL on invalid arguments/allocation failure

Definition at line 466 of file grpc_channel.c.

References cwist_grpc_retry_policy::backoff_multiplier, cap, cwist_grpc_call_await_headers(), cwist_grpc_call_destroy(), cwist_grpc_call_refused(), cwist_grpc_call_retry_pushback_ms(), cwist_grpc_call_start_ex(), cwist_grpc_call_status(), CWIST_GRPC_DEADLINE_EXCEEDED, CWIST_GRPC_OK, CWIST_GRPC_STATUS_BIT, CWIST_GRPC_UNAVAILABLE, GRPC_CHANNEL_MAX_ATTEMPTS_CAP, cwist_grpc_retry_policy::initial_backoff_ms, cwist_grpc_retry_policy::max_attempts, cwist_grpc_retry_policy::max_backoff_ms, and cwist_grpc_retry_policy::retryable_status_mask.

Referenced by cwist_grpc_channel_unary().

◆ cwist_grpc_channel_close()

void cwist_grpc_channel_close ( cwist_grpc_channel *  ch)

Close a channel and free all its resources.

Calls handed out must be destroyed before closing the channel. NULL-safe.

Definition at line 979 of file grpc_channel.c.

References cap, cwist_free(), and cwist_grpc_client_close().

Referenced by cwist_grpc_channel_connect().

◆ cwist_grpc_channel_connect()

cwist_grpc_channel * cwist_grpc_channel_connect ( const char *  target,
const cwist_grpc_channel_options *  options 
)

Create a channel for target and resolve its backend addresses.

Supported targets: "dns:name" (a "//authority/" prefix is ignored, as in gRPC C-core), "ipv4:1.2.3.4:port,...", "ipv6:[...]:port,...", and a bare name (treated as dns:). unix:, unix-abstract:, and vsock: are not implemented and fail. round_robin dials every address up front; pick_first stays IDLE until the first RPC.

Parameters
optionsmay be NULL for defaults; see cwist_grpc_channel_options
Returns
the new channel, or NULL on any failure (fully cleaned up)

Definition at line 901 of file grpc_channel.c.

References cwist_grpc_channel_options::authority, cap, cwist_grpc_channel_options::connect_timeout_ms, cwist_alloc(), cwist_free(), cwist_grpc_channel_close(), CWIST_GRPC_LB_PICK_FIRST, CWIST_GRPC_LB_ROUND_ROBIN, GRPC_CHANNEL_DEFAULT_BUFFER_LIMIT, GRPC_CHANNEL_MAX_ADDRS, cwist_grpc_channel_options::lb_policy, cwist_grpc_channel_options::per_rpc_buffer_limit, cwist_grpc_channel_options::retry_policy, cwist_grpc_channel_options::retry_throttle, cwist_grpc_channel_options::use_tls, cwist_grpc_channel_options::verify_peer, and cwist_grpc_channel_options::wait_for_ready.

◆ cwist_grpc_channel_get_state()

cwist_grpc_channel_state cwist_grpc_channel_get_state ( cwist_grpc_channel *  ch)

Aggregate connectivity state across subchannels (load-balancing.md).

READY if any subchannel is connected, else IDLE while any subchannel may dial, else TRANSIENT_FAILURE. NULL maps to SHUTDOWN. Thread-safe: takes ch->mu.

Definition at line 1001 of file grpc_channel.c.

References cap, CWIST_GRPC_CHANNEL_IDLE, CWIST_GRPC_CHANNEL_READY, CWIST_GRPC_CHANNEL_SHUTDOWN, CWIST_GRPC_CHANNEL_TRANSIENT_FAILURE, and cwist_grpc_client_dead().

◆ cwist_grpc_channel_unary()

cwist_grpc_status_t cwist_grpc_channel_unary ( cwist_grpc_channel *  ch,
const char *  method,
const void *  request,
size_t  request_len,
uint64_t  timeout_ms,
uint8_t **  response,
size_t *  response_len,
char **  status_message 
)

Convenience blocking unary RPC: start, read one response, finish.

On CWIST_GRPC_OK the first response message is copied into response (caller-owned; freed with cwist_free) with its length in response_len; extra messages are discarded. On any other status the response is freed and NULL/0 is returned. Output pointers may be NULL to discard the corresponding value. status_message, when non-NULL on entry, receives an allocated copy of the server status message.

Returns
the final gRPC status (CWIST_GRPC_INTERNAL if the call could not start)

Definition at line 700 of file grpc_channel.c.

References cap, cwist_alloc(), cwist_free(), cwist_grpc_channel_call_destroy(), cwist_grpc_channel_call_finish(), cwist_grpc_channel_call_recv(), cwist_grpc_channel_call_start(), CWIST_GRPC_INTERNAL, and CWIST_GRPC_OK.