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

Unary gRPC over HTTP/2 support. More...

#include <cwist/net/grpc/grpc.h>
#include <cwist/sys/app/app.h>
#include <cwist/core/mem/alloc.h>
#include <ctype.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <zlib.h>
Include dependency graph for grpc.c:

Go to the source code of this file.

Macros

#define _POSIX_C_SOURCE   200809L
 

Typedefs

typedef struct cwist_grpc_route cwist_grpc_route
 
typedef struct cwist_grpc_health_state cwist_grpc_health_state
 
typedef struct cwist_grpc_health_registry cwist_grpc_health_registry
 
typedef struct grpc_qnode grpc_qnode
 
typedef struct cwist_grpc_session cwist_grpc_session
 
typedef struct cwist_grpc_h2_conn_ctx cwist_grpc_h2_conn_ctx
 

Functions

int cwist_grpc_parse_timeout (const char *value, uint64_t *out_ms)
 Parse a gRPC timeout value into milliseconds.
 
const char * cwist_grpc_metadata_get (cwist_http_request *req, const char *key)
 Fetch a metadata header value from a gRPC request.
 
int cwist_grpc_metadata_get_binary (cwist_http_request *req, const char *key, uint8_t *out, size_t out_cap, size_t *out_len)
 Decode a binary ("-bin" suffixed) metadata header from base64.
 
int cwist_grpc_decode_message (const void *frame, size_t frame_len, cwist_grpc_message *out)
 Decode a single gRPC length-prefixed message frame.
 
int cwist_grpc_decode_next_message (const void *frames, size_t frames_len, size_t *offset, cwist_grpc_message *out)
 Decode the next message in a concatenated gRPC frame buffer.
 
int cwist_grpc_encode_message (const void *payload, size_t payload_len, uint8_t compressed, uint8_t **out, size_t *out_len)
 Wrap a payload in a gRPC length-prefixed message frame.
 
void cwist_grpc_decoder_init (cwist_grpc_decoder *decoder, size_t max_message_size)
 Initialize an incremental gRPC message decoder.
 
void cwist_grpc_decoder_destroy (cwist_grpc_decoder *decoder)
 Release all resources held by a decoder and reset it to zero.
 
int cwist_grpc_decoder_feed (cwist_grpc_decoder *decoder, const void *data, size_t len, cwist_grpc_message_callback callback, void *ctx)
 Feed bytes into an incremental gRPC message decoder.
 
void cwist_grpc_set_response (cwist_http_response *res, cwist_grpc_status_t status, const char *message, const void *payload, size_t payload_len)
 Build a complete buffered unary gRPC response.
 
void cwist_grpc_set_error (cwist_http_response *res, cwist_grpc_status_t status, const char *message)
 Build a buffered gRPC error response with an empty message.
 
int cwist_grpc_stream_send (cwist_grpc_stream *stream, const void *payload, size_t payload_len)
 Send one message on an open gRPC stream.
 
void cwist_grpc_stream_set_writer (cwist_grpc_stream *stream, int(*write_frame)(void *, const uint8_t *, size_t, int), void *ctx)
 Install a custom frame writer on a stream.
 
void cwist_grpc_stream_close (cwist_grpc_stream *stream, cwist_grpc_status_t status, const char *message)
 Close a gRPC stream with a final status.
 
void cwist_grpc_stream_set_retry_pushback (cwist_grpc_stream *stream, int32_t ms)
 Advertise a server-side retry pushback hint to the client.
 
int cwist_app_grpc_health (cwist_app *app)
 Register the built-in grpc.health.v1.Health service on an app.
 
int cwist_app_grpc_health_set_status (cwist_app *app, const char *service, int serving)
 Set or update the serving status of a named service.
 
int cwist_app_grpc_health_watchers (cwist_app *app)
 Count currently active Health/Watch streams.
 
int cwist_app_grpc_reflection (cwist_app *app)
 Register the built-in gRPC server reflection service on an app.
 
int cwist_app_grpc_unary (cwist_app *app, const char *service, const char *method, cwist_grpc_unary_handler_func handler, void *user_ctx)
 Register a unary gRPC method on an app.
 
int cwist_app_grpc_stream (cwist_app *app, const char *service, const char *method, cwist_grpc_stream_handler_func handler, void *user_ctx)
 Register a client-streaming gRPC method on an app.
 
void cwist_grpc_routes_destroy (cwist_app *app)
 Free all gRPC routes and per-route resources on an app.
 
int cwist_grpc_routes_clone (cwist_app *dst, const cwist_app *src)
 Copy all gRPC routes (and built-in service state) to another app.
 
int cwist_grpc_stream_recv (cwist_grpc_stream *stream, cwist_grpc_message *out)
 Receive the next inbound message on a stream.
 
int cwist_grpc_stream_cancelled (cwist_grpc_stream *stream)
 Check whether a stream has been cancelled.
 
uint64_t cwist_grpc_stream_deadline_remaining_ms (cwist_grpc_stream *stream)
 Milliseconds remaining until the stream deadline.
 
const cwist_http2_stream_hooks * cwist_grpc_http2_hooks (void)
 Access the gRPC HTTP/2 stream hooks table.
 

Detailed Description

Unary gRPC over HTTP/2 support.

Definition in file grpc.c.

Macro Definition Documentation

◆ _POSIX_C_SOURCE

#define _POSIX_C_SOURCE   200809L

Definition at line 6 of file grpc.c.

Typedef Documentation

◆ cwist_grpc_h2_conn_ctx

typedef struct cwist_grpc_h2_conn_ctx cwist_grpc_h2_conn_ctx

◆ cwist_grpc_health_registry

typedef struct cwist_grpc_health_registry cwist_grpc_health_registry

◆ cwist_grpc_health_state

typedef struct cwist_grpc_health_state cwist_grpc_health_state

◆ cwist_grpc_route

typedef struct cwist_grpc_route cwist_grpc_route

◆ cwist_grpc_session

typedef struct cwist_grpc_session cwist_grpc_session

Definition at line 58 of file grpc.c.

◆ grpc_qnode

typedef struct grpc_qnode grpc_qnode

Function Documentation

◆ cwist_app_grpc_health()

int cwist_app_grpc_health ( cwist_app *  app)

Register the built-in grpc.health.v1.Health service on an app.

Installs the Check (unary) and Watch (streaming) routes backed by a single newly allocated health registry. On failure the registry is freed and no routes remain half-installed.

Parameters
appApplication to register on; may be NULL.
Return values
0Both routes registered.
-1NULL app, allocation failure, or route registration failure.

Definition at line 1137 of file grpc.c.

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

Referenced by cwist_grpc_routes_clone().

◆ cwist_app_grpc_health_set_status()

int cwist_app_grpc_health_set_status ( cwist_app *  app,
const char *  service,
int  serving 
)

Set or update the serving status of a named service.

Records the status in the health registry and wakes all active Watch streams. Thread-safe; takes the registry lock internally.

Parameters
appApp whose health service was registered with cwist_app_grpc_health().
serviceService name to update.
servingNon-zero for SERVING, zero for NOT_SERVING.
Return values
0Status recorded.
-1No health service registered, NULL arguments, or allocation failure.

Definition at line 1173 of file grpc.c.

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

Referenced by cwist_grpc_routes_clone().

◆ cwist_app_grpc_health_watchers()

int cwist_app_grpc_health_watchers ( cwist_app *  app)

Count currently active Health/Watch streams.

Parameters
appApp whose health service was registered.
Returns
Number of active watchers (atomic snapshot).
Return values
-1No health Watch route registered on app.

Definition at line 1212 of file grpc.c.

References cap.

◆ cwist_app_grpc_reflection()

int cwist_app_grpc_reflection ( cwist_app *  app)

Register the built-in gRPC server reflection service on an app.

Installs the streaming ServerReflectionInfo route.

Parameters
appApplication to register on.
Return values
0Route registered.
-1Route registration failed.

Definition at line 1281 of file grpc.c.

References cap.

Referenced by cwist_grpc_routes_clone().

◆ cwist_app_grpc_stream()

int cwist_app_grpc_stream ( cwist_app *  app,
const char *  service,
const char *  method,
cwist_grpc_stream_handler_func  handler,
void *  user_ctx 
)

Register a client-streaming gRPC method on an app.

Parameters
appApplication to register on.
servicegRPC service name.
methodMethod name.
handlerStreaming handler invoked once per call with the stream.
user_ctxOpaque pointer passed to handler.
Return values
0Registered.
-1See grpc_register_route().

Definition at line 1371 of file grpc.c.

References cap.

Referenced by cwist_grpc_routes_clone().

◆ cwist_app_grpc_unary()

int cwist_app_grpc_unary ( cwist_app *  app,
const char *  service,
const char *  method,
cwist_grpc_unary_handler_func  handler,
void *  user_ctx 
)

Register a unary gRPC method on an app.

Parameters
appApplication to register on.
servicegRPC service name.
methodMethod name.
handlerUnary handler invoked per request.
user_ctxOpaque pointer passed to handler.
Return values
0Registered.
-1See grpc_register_route().

Definition at line 1357 of file grpc.c.

References cap.

Referenced by cwist_grpc_routes_clone().

◆ cwist_grpc_decode_message()

int cwist_grpc_decode_message ( const void *  frame,
size_t  frame_len,
cwist_grpc_message *  out 
)

Decode a single gRPC length-prefixed message frame.

Parameters
frameFrame bytes: 1-byte compression flag + 4-byte big-endian length + payload.
frame_lenTotal frame length; must be exactly 5 + payload length.
outReceives compression flag and a pointer/length into frame (borrowed; not copied).
Return values
0Success.
-1NULL input, frame shorter than 5 bytes, or length mismatch.

Definition at line 622 of file grpc.c.

References cap, cwist_grpc_message::compressed, cwist_grpc_message::data, and cwist_grpc_message::len.

◆ cwist_grpc_decode_next_message()

int cwist_grpc_decode_next_message ( const void *  frames,
size_t  frames_len,
size_t *  offset,
cwist_grpc_message *  out 
)

Decode the next message in a concatenated gRPC frame buffer.

Advances *offset past the decoded message so it can be called again to iterate.

Parameters
framesBuffer holding concatenated length-prefixed messages.
frames_lenTotal buffer length.
offsetIn/out cursor into frames; on entry the message start, on exit one past the decoded message.
outReceives the compression flag and a borrowed pointer/length into frames.
Return values
0Success.
-1NULL input, offset out of range, or truncated frame.

Definition at line 649 of file grpc.c.

References cap, cwist_grpc_message::compressed, cwist_grpc_message::data, and cwist_grpc_message::len.

◆ cwist_grpc_decoder_destroy()

void cwist_grpc_decoder_destroy ( cwist_grpc_decoder *  decoder)

Release all resources held by a decoder and reset it to zero.

Safe to call on a decoder that was only ever initialized or already destroyed. Afterwards the decoder must not be used without re-init.

Parameters
decoderDecoder to destroy; may be NULL.

Definition at line 713 of file grpc.c.

References cap, cwist_free(), and cwist_grpc_decoder::payload.

Referenced by cwist_grpc_call_destroy(), and cwist_grpc_call_start_ex().

◆ cwist_grpc_decoder_feed()

int cwist_grpc_decoder_feed ( cwist_grpc_decoder *  decoder,
const void *  data,
size_t  len,
cwist_grpc_message_callback  callback,
void *  ctx 
)

Feed bytes into an incremental gRPC message decoder.

Buffers partial frames internally and invokes callback with each fully decoded message. The message payload pointer passed to the callback is owned by the decoder and is only valid for the duration of the call.

Parameters
decoderDecoder state.
dataIncoming bytes; may be NULL only when len is 0.
lenNumber of incoming bytes.
callbackInvoked per completed message; a nonzero return aborts.
ctxOpaque pointer passed through to callback.
Return values
0All input consumed.
-1Invalid argument, frame too large or malformed, allocation failure, or the callback returned nonzero (decoder state is then unusable).

Definition at line 734 of file grpc.c.

References cap, cwist_grpc_decoder::compressed, cwist_alloc(), cwist_free(), cwist_grpc_decoder::header, cwist_grpc_decoder::header_len, cwist_grpc_decoder::max_message_size, cwist_grpc_decoder::payload, cwist_grpc_decoder::payload_len, and cwist_grpc_decoder::payload_used.

◆ cwist_grpc_decoder_init()

void cwist_grpc_decoder_init ( cwist_grpc_decoder *  decoder,
size_t  max_message_size 
)

Initialize an incremental gRPC message decoder.

Parameters
decoderDecoder state to zero and configure.
max_message_sizeMaximum accepted payload in bytes; 0 selects the default of 16 MiB.

Definition at line 701 of file grpc.c.

References cap, and cwist_grpc_decoder::max_message_size.

Referenced by cwist_grpc_call_start_ex().

◆ cwist_grpc_encode_message()

int cwist_grpc_encode_message ( const void *  payload,
size_t  payload_len,
uint8_t  compressed,
uint8_t **  out,
size_t *  out_len 
)

Wrap a payload in a gRPC length-prefixed message frame.

Parameters
payloadMessage bytes; may be NULL when payload_len is 0.
payload_lenPayload length; must fit in a 32-bit field.
compressedNon-zero to set the compression flag in the frame header.
outReceives a newly allocated frame.
out_lenReceives the frame length (5 + payload length).
Return values
0Success; caller owns *out and must free it with cwist_free().
-1NULL output pointers, NULL payload with nonzero length, payload too large, or allocation failure.

Definition at line 677 of file grpc.c.

References cap, and cwist_alloc().

Referenced by cwist_grpc_call_start_ex(), cwist_grpc_set_response(), and cwist_grpc_stream_send().

◆ cwist_grpc_http2_hooks()

const cwist_http2_stream_hooks * cwist_grpc_http2_hooks ( void  )

Access the gRPC HTTP/2 stream hooks table.

Returns
Static hooks structure wiring the incremental gRPC streaming engine into the HTTP/2 transport.

Definition at line 2109 of file grpc.c.

Referenced by cwist_app_http_handler(), and cwist_app_http_handler_async().

◆ cwist_grpc_metadata_get()

const char * cwist_grpc_metadata_get ( cwist_http_request *  req,
const char *  key 
)

Fetch a metadata header value from a gRPC request.

Parameters
reqRequest to search; may be NULL.
keyHeader name to match; may be NULL.
Returns
Header value, or NULL when absent or on NULL input.

Definition at line 371 of file grpc.c.

◆ cwist_grpc_metadata_get_binary()

int cwist_grpc_metadata_get_binary ( cwist_http_request *  req,
const char *  key,
uint8_t *  out,
size_t  out_cap,
size_t *  out_len 
)

Decode a binary ("-bin" suffixed) metadata header from base64.

Parameters
reqRequest to search; may be NULL.
keyMetadata key; must end in "-bin".
outOutput buffer for the decoded bytes.
out_capCapacity of out in bytes.
out_lenReceives the decoded length in bytes.
Return values
0Decoding succeeded.
-1NULL input, key without "-bin" suffix, missing header, or decode failure (see grpc_base64_decode for -2 overflow).

Definition at line 385 of file grpc.c.

References cap.

◆ cwist_grpc_parse_timeout()

int cwist_grpc_parse_timeout ( const char *  value,
uint64_t *  out_ms 
)

Parse a gRPC timeout value into milliseconds.

Accepts the gRPC "TimeoutValue Unit" form with units H, M, S, m, u, n (hours down to nanoseconds); sub-millisecond values round up so a positive timeout never becomes zero.

Parameters
valueTimeout string, e.g. "10S" or "500m"; may be NULL.
out_msReceives the timeout in milliseconds.
Return values
0Parsed successfully.
-1NULL input, malformed value, or unsupported unit.

Definition at line 146 of file grpc.c.

References cap.

◆ cwist_grpc_routes_clone()

int cwist_grpc_routes_clone ( cwist_app *  dst,
const cwist_app *  src 
)

Copy all gRPC routes (and built-in service state) to another app.

Re-registers every route from src on dst. The built-in health service is re-created on dst with its recorded statuses, and the reflection service is re-registered. Routes already present on dst with the same path are replaced by grpc_register_route().

Return values
0All routes cloned.
-1NULL argument, allocation failure, malformed route path, or a registration failure part-way through (dst may hold partial state).

Definition at line 1417 of file grpc.c.

References cap, cwist_alloc(), cwist_app_grpc_health(), cwist_app_grpc_health_set_status(), cwist_app_grpc_reflection(), cwist_app_grpc_stream(), cwist_app_grpc_unary(), CWIST_DEFER_FREE, and cwist_app::grpc_routes.

◆ cwist_grpc_routes_destroy()

void cwist_grpc_routes_destroy ( cwist_app *  app)

Free all gRPC routes and per-route resources on an app.

Also tears down the health registry owned by the built-in health Check route (states, mutex, condvar). Leaves app->grpc_routes NULL.

Parameters
appApp to clean up; may be NULL (no-op).

Definition at line 1382 of file grpc.c.

References cap, cwist_free(), and cwist_app::grpc_routes.

Referenced by cwist_app_destroy().

◆ cwist_grpc_set_error()

void cwist_grpc_set_error ( cwist_http_response *  res,
cwist_grpc_status_t  status,
const char *  message 
)

Build a buffered gRPC error response with an empty message.

Convenience wrapper over cwist_grpc_set_response() with no payload.

Parameters
resResponse object to fill.
statusgRPC status code.
messageStatus message for the grpc-message header; may be NULL.

Definition at line 819 of file grpc.c.

References cap, and cwist_grpc_set_response().

◆ cwist_grpc_set_response()

void cwist_grpc_set_response ( cwist_http_response *  res,
cwist_grpc_status_t  status,
const char *  message,
const void *  payload,
size_t  payload_len 
)

Build a complete buffered unary gRPC response.

Sets the HTTP 200 status, gRPC content-type headers, grpc-status/grpc-message headers, and a single length-prefixed message frame from payload.

Parameters
resResponse object to fill; may be NULL (no-op).
statusgRPC status code for the grpc-status header.
messageOptional status message for the grpc-message header.
payloadMessage payload bytes; may be NULL for an empty message.
payload_lenPayload length in bytes.

Definition at line 784 of file grpc.c.

References cwist_http_response::body, cap, cwist_free(), cwist_grpc_encode_message(), cwist_http_header_add(), CWIST_HTTP_INTERNAL_ERROR, CWIST_HTTP_OK, cwist_sstring_assign(), cwist_sstring_assign_len(), cwist_http_response::headers, and cwist_http_response::status_code.

Referenced by cwist_grpc_set_error().

◆ cwist_grpc_stream_cancelled()

int cwist_grpc_stream_cancelled ( cwist_grpc_stream *  stream)

Check whether a stream has been cancelled.

Reads the session state under the session lock when backed by a transport.

Parameters
streamStream to check; may be NULL (treated as not cancelled).
Return values
1Cancelled.
0Still active.

Definition at line 1814 of file grpc.c.

References cwist_grpc_stream::cancelled, cap, and cwist_grpc_stream::session.

◆ cwist_grpc_stream_close()

void cwist_grpc_stream_close ( cwist_grpc_stream *  stream,
cwist_grpc_status_t  status,
const char *  message 
)

Close a gRPC stream with a final status.

Idempotent: a second call is a no-op. Emits grpc-status/grpc-message trailers through the transport session when present, otherwise adds them as response headers on the buffered path.

Parameters
streamStream to close; may be NULL (no-op).
statusFinal gRPC status.
messageFinal status message; may be NULL.

Definition at line 933 of file grpc.c.

References cap, cwist_grpc_stream::closed, cwist_http_header_add(), cwist_http_response::headers, cwist_grpc_stream::res, cwist_grpc_stream::session, cwist_grpc_stream::status, and cwist_grpc_stream::status_message.

◆ cwist_grpc_stream_deadline_remaining_ms()

uint64_t cwist_grpc_stream_deadline_remaining_ms ( cwist_grpc_stream *  stream)

Milliseconds remaining until the stream deadline.

Parameters
streamStream to inspect; may be NULL (treated as no deadline).
Returns
Milliseconds left, 0 when the deadline has passed, or UINT64_MAX when no deadline was set.

Definition at line 1834 of file grpc.c.

References cap, and cwist_grpc_stream::deadline_ms.

◆ cwist_grpc_stream_recv()

int cwist_grpc_stream_recv ( cwist_grpc_stream *  stream,
cwist_grpc_message *  out 
)

Receive the next inbound message on a stream.

Buffered path: pops the next pre-decoded message, enforcing the deadline first. Transport path: blocks on the session queue until a message arrives, the call is cancelled, EOF is reached, or the deadline expires.

Parameters
streamStream to read from; may be NULL.
outReceives the message (borrowed pointer valid until the next recv on this stream).
Return values
1A message was delivered.
0End of stream (no more messages).
-1NULL argument, cancellation, or deadline exceeded (stream status set to DEADLINE_EXCEEDED in the latter case).

Definition at line 1740 of file grpc.c.

References cwist_grpc_stream::cancelled, cap, cwist_grpc_message::compressed, cwist_free(), CWIST_GRPC_DEADLINE_EXCEEDED, cwist_grpc_message::data, cwist_grpc_stream::deadline_ms, cwist_grpc_message::len, cwist_grpc_stream::message_count, cwist_grpc_stream::messages, cwist_grpc_stream::recv_pos, cwist_grpc_stream::session, cwist_grpc_stream::status, and cwist_grpc_stream::status_message.

◆ cwist_grpc_stream_send()

int cwist_grpc_stream_send ( cwist_grpc_stream *  stream,
const void *  payload,
size_t  payload_len 
)

Send one message on an open gRPC stream.

Frames the payload (gzip-compressing it when the peer negotiated gzip and deflation succeeds) and delivers it either to the transport-backed write_frame hook or by appending to the buffered response body. On any failure the stream status and status message are set to describe the error.

Parameters
streamOpen stream to send on; may be NULL.
payloadMessage bytes; may be NULL when payload_len is 0.
payload_lenMessage length in bytes.
Return values
0Message accepted by the transport/buffer.
-1Encoding or write failure; stream->status is updated.

Definition at line 836 of file grpc.c.

References cwist_http_response::body, cap, cwist_error_dispose(), cwist_free(), cwist_grpc_encode_message(), CWIST_GRPC_INTERNAL, CWIST_GRPC_UNAVAILABLE, cwist_sstring_append_len(), cwist_grpc_stream::req, cwist_grpc_stream::res, cwist_grpc_stream::session, cwist_grpc_stream::status, cwist_grpc_stream::status_message, cwist_grpc_stream::write_frame, and cwist_grpc_stream::write_frame_ctx.

◆ cwist_grpc_stream_set_retry_pushback()

void cwist_grpc_stream_set_retry_pushback ( cwist_grpc_stream *  stream,
int32_t  ms 
)

Advertise a server-side retry pushback hint to the client.

Records the hint on the stream; on the buffered path it is also emitted as the grpc-retry-pushback-ms header for the HTTP/2 layer to move into the trailers.

Parameters
streamStream to annotate; may be NULL (no-op).
msRetry delay hint in milliseconds.

Definition at line 963 of file grpc.c.

References cap, cwist_http_header_add(), cwist_http_response::headers, cwist_grpc_stream::res, cwist_grpc_stream::retry_pushback_ms, cwist_grpc_stream::retry_pushback_set, and cwist_grpc_stream::session.

◆ cwist_grpc_stream_set_writer()

void cwist_grpc_stream_set_writer ( cwist_grpc_stream *  stream,
int(*)(void *, const uint8_t *, size_t, int)  write_frame,
void *  ctx 
)

Install a custom frame writer on a stream.

Overrides where cwist_grpc_stream_send() delivers frames (and, for the buffered path, cwist_grpc_stream_close() trailers are still used). May be NULL to clear the hook.

Parameters
streamStream to configure; may be NULL (no-op).
write_frameCallback invoked with each framed message; may be NULL.
ctxOpaque pointer passed as the first callback argument.

Definition at line 916 of file grpc.c.

References cwist_grpc_stream::write_frame, and cwist_grpc_stream::write_frame_ctx.