|
cwist
Modern C web framework with libttak runtime
|
gRPC over HTTP/2 helpers for CWIST. More...
#include <cwist/net/http/http.h>#include <cwist/net/http/http2.h>#include <cwist/net/grpc/protobuf.h>#include <stddef.h>#include <stdint.h>

Go to the source code of this file.
Classes | |
| struct | cwist_grpc_message |
| struct | cwist_grpc_stream |
| struct | cwist_grpc_decoder |
Typedefs | |
| typedef enum cwist_grpc_status | cwist_grpc_status_t |
| typedef struct cwist_grpc_message | cwist_grpc_message |
| typedef struct cwist_grpc_stream | cwist_grpc_stream |
| typedef struct cwist_grpc_decoder | cwist_grpc_decoder |
| typedef int(* | cwist_grpc_message_callback) (void *ctx, const cwist_grpc_message *message) |
| typedef void(* | cwist_grpc_unary_handler_func) (cwist_http_request *req, cwist_http_response *res, const cwist_grpc_message *message, void *user_ctx) |
| typedef void(* | cwist_grpc_stream_handler_func) (cwist_grpc_stream *stream, void *user_ctx) |
Enumerations | |
| enum | cwist_grpc_status { CWIST_GRPC_OK = 0 , CWIST_GRPC_CANCELLED = 1 , CWIST_GRPC_UNKNOWN = 2 , CWIST_GRPC_INVALID_ARGUMENT = 3 , CWIST_GRPC_DEADLINE_EXCEEDED = 4 , CWIST_GRPC_NOT_FOUND = 5 , CWIST_GRPC_ALREADY_EXISTS = 6 , CWIST_GRPC_PERMISSION_DENIED = 7 , CWIST_GRPC_RESOURCE_EXHAUSTED = 8 , CWIST_GRPC_FAILED_PRECONDITION = 9 , CWIST_GRPC_ABORTED = 10 , CWIST_GRPC_OUT_OF_RANGE = 11 , CWIST_GRPC_UNIMPLEMENTED = 12 , CWIST_GRPC_INTERNAL = 13 , CWIST_GRPC_UNAVAILABLE = 14 , CWIST_GRPC_DATA_LOSS = 15 , CWIST_GRPC_UNAUTHENTICATED = 16 } |
Functions | |
| 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_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_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. | |
| 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. | |
| 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 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_parse_timeout (const char *value, uint64_t *out_ms) |
| Parse a gRPC timeout value into milliseconds. | |
| 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. | |
| int | cwist_app_grpc_health (struct cwist_app *app) |
| Register the built-in grpc.health.v1.Health service on an app. | |
| int | cwist_app_grpc_health_set_status (struct cwist_app *app, const char *service, int serving) |
| Set or update the serving status of a named service. | |
| int | cwist_app_grpc_health_watchers (struct cwist_app *app) |
| Count currently active Health/Watch streams. | |
| int | cwist_app_grpc_reflection (struct cwist_app *app) |
| Register the built-in gRPC server reflection service on an app. | |
| int | cwist_app_grpc_unary (struct 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 (struct 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. | |
| const cwist_http2_stream_hooks * | cwist_grpc_http2_hooks (void) |
| Access the gRPC HTTP/2 stream hooks table. | |
| void | cwist_grpc_routes_destroy (struct cwist_app *app) |
| Free all gRPC routes and per-route resources on an app. | |
| int | cwist_grpc_routes_clone (struct cwist_app *dst, const struct cwist_app *src) |
gRPC over HTTP/2 helpers for CWIST.
Definition in file grpc.h.
Incremental gRPC frame decoder for arbitrarily split HTTP/2 DATA payloads.
| typedef int(* cwist_grpc_message_callback) (void *ctx, const cwist_grpc_message *message) |
| typedef void(* cwist_grpc_stream_handler_func) (cwist_grpc_stream *stream, void *user_ctx) |
| typedef void(* cwist_grpc_unary_handler_func) (cwist_http_request *req, cwist_http_response *res, const cwist_grpc_message *message, void *user_ctx) |
Register the built-in grpc.health.v1.Health service on an app.
Register the standard grpc.health.v1.Health Check and Watch methods.
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.
| app | Application to register on; may be NULL. |
| 0 | Both routes registered. |
| -1 | NULL 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().
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.
| app | App whose health service was registered with cwist_app_grpc_health(). |
| service | Service name to update. |
| serving | Non-zero for SERVING, zero for NOT_SERVING. |
| 0 | Status recorded. |
| -1 | No 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().
Count currently active Health/Watch streams.
Number of active streaming Watch calls; -1 when health is not registered.
| app | App whose health service was registered. |
| -1 | No health Watch route registered on app. |
Definition at line 1212 of file grpc.c.
References cap.
Register the built-in gRPC server reflection service on an app.
Register the grpc.reflection.v1alpha.ServerReflection service.
Installs the streaming ServerReflectionInfo route.
| app | Application to register on. |
| 0 | Route registered. |
| -1 | Route registration failed. |
Definition at line 1281 of file grpc.c.
References cap.
Referenced by cwist_grpc_routes_clone().
| 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.
| app | Application to register on. |
| service | gRPC service name. |
| method | Method name. |
| handler | Streaming handler invoked once per call with the stream. |
| user_ctx | Opaque pointer passed to handler. |
| 0 | Registered. |
| -1 | See grpc_register_route(). |
Definition at line 1371 of file grpc.c.
References cap.
Referenced by cwist_grpc_routes_clone().
| 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.
| app | Application to register on. |
| service | gRPC service name. |
| method | Method name. |
| handler | Unary handler invoked per request. |
| user_ctx | Opaque pointer passed to handler. |
| 0 | Registered. |
| -1 | See grpc_register_route(). |
Definition at line 1357 of file grpc.c.
References cap.
Referenced by cwist_grpc_routes_clone().
| int cwist_grpc_decode_message | ( | const void * | frame, |
| size_t | frame_len, | ||
| cwist_grpc_message * | out | ||
| ) |
Decode a single gRPC length-prefixed message frame.
| frame | Frame bytes: 1-byte compression flag + 4-byte big-endian length + payload. |
| frame_len | Total frame length; must be exactly 5 + payload length. |
| out | Receives compression flag and a pointer/length into frame (borrowed; not copied). |
| 0 | Success. |
| -1 | NULL 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.
| 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.
| frames | Buffer holding concatenated length-prefixed messages. |
| frames_len | Total buffer length. |
| offset | In/out cursor into frames; on entry the message start, on exit one past the decoded message. |
| out | Receives the compression flag and a borrowed pointer/length into frames. |
| 0 | Success. |
| -1 | NULL 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.
| 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.
| decoder | Decoder 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().
| 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.
Feed a partial HTTP/2 DATA payload. Calls callback for every complete frame.
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.
| decoder | Decoder state. |
| data | Incoming bytes; may be NULL only when len is 0. |
| len | Number of incoming bytes. |
| callback | Invoked per completed message; a nonzero return aborts. |
| ctx | Opaque pointer passed through to callback. |
| 0 | All input consumed. |
| -1 | Invalid 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.
| void cwist_grpc_decoder_init | ( | cwist_grpc_decoder * | decoder, |
| size_t | max_message_size | ||
| ) |
Initialize an incremental gRPC message decoder.
| decoder | Decoder state to zero and configure. |
| max_message_size | Maximum 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().
| 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.
| payload | Message bytes; may be NULL when payload_len is 0. |
| payload_len | Payload length; must fit in a 32-bit field. |
| compressed | Non-zero to set the compression flag in the frame header. |
| out | Receives a newly allocated frame. |
| out_len | Receives the frame length (5 + payload length). |
| 0 | Success; caller owns *out and must free it with cwist_free(). |
| -1 | NULL 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().
| const cwist_http2_stream_hooks * cwist_grpc_http2_hooks | ( | void | ) |
Access the gRPC HTTP/2 stream hooks table.
HTTP/2 stream hooks that route gRPC streaming calls through the incremental transport path. The hook context is the cwist_app pointer already passed as user_ctx to cwist_http2_serve_connection_ex().
Definition at line 2109 of file grpc.c.
Referenced by cwist_app_http_handler(), and cwist_app_http_handler_async().
| const char * cwist_grpc_metadata_get | ( | cwist_http_request * | req, |
| const char * | key | ||
| ) |
Fetch a metadata header value from a gRPC request.
Normalized request metadata lookup. Header names are matched case-insensitively (HTTP/2 mandates lowercase); textual values are returned as-is. Returns NULL when the key is absent.
| req | Request to search; may be NULL. |
| key | Header name to match; may be NULL. |
| 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.
Binary metadata ("*-bin" keys): base64-decodes the value into out. Returns 0 on success, -1 when absent/undecodable, -2 when out_cap is too small (required size reported in out_len).
| req | Request to search; may be NULL. |
| key | Metadata key; must end in "-bin". |
| out | Output buffer for the decoded bytes. |
| out_cap | Capacity of out in bytes. |
| out_len | Receives the decoded length in bytes. |
| 0 | Decoding succeeded. |
| -1 | NULL 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.
Parse a gRPC timeout value into milliseconds.
Parse a grpc-timeout header value ("100m", "2S", ...) into milliseconds. Returns 0 on success, -1 on malformed input.
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.
| value | Timeout string, e.g. "10S" or "500m"; may be NULL. |
| out_ms | Receives the timeout in milliseconds. |
| 0 | Parsed successfully. |
| -1 | NULL input, malformed value, or unsupported unit. |
Definition at line 146 of file grpc.c.
References cap.
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.
| app | App 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().
| 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.
| res | Response object to fill. |
| status | gRPC status code. |
| message | Status message for the grpc-message header; may be NULL. |
Definition at line 819 of file grpc.c.
References cap, and 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.
| res | Response object to fill; may be NULL (no-op). |
| status | gRPC status code for the grpc-status header. |
| message | Optional status message for the grpc-message header. |
| payload | Message payload bytes; may be NULL for an empty message. |
| payload_len | Payload 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().
| int cwist_grpc_stream_cancelled | ( | cwist_grpc_stream * | stream | ) |
Check whether a stream has been cancelled.
Non-zero when the call was cancelled or the deadline expired.
Reads the session state under the session lock when backed by a transport.
| stream | Stream to check; may be NULL (treated as not cancelled). |
| 1 | Cancelled. |
| 0 | Still active. |
Definition at line 1814 of file grpc.c.
References cwist_grpc_stream::cancelled, cap, and cwist_grpc_stream::session.
| 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.
| stream | Stream to close; may be NULL (no-op). |
| status | Final gRPC status. |
| message | Final 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.
| uint64_t cwist_grpc_stream_deadline_remaining_ms | ( | cwist_grpc_stream * | stream | ) |
Milliseconds remaining until the stream deadline.
Remaining deadline in milliseconds; UINT64_MAX when no grpc-timeout was set.
| stream | Stream to inspect; may be NULL (treated as no deadline). |
Definition at line 1834 of file grpc.c.
References cap, and cwist_grpc_stream::deadline_ms.
| int cwist_grpc_stream_recv | ( | cwist_grpc_stream * | stream, |
| cwist_grpc_message * | out | ||
| ) |
Receive the next inbound message on a stream.
Blocking receive for streaming handlers on the HTTP/2 transport path. Returns 1 and fills out when a message arrived, 0 on client half-close (END_STREAM), and -1 when the call was cancelled (client RST_STREAM, deadline expiry, or transport error). On the buffered (in-process) path this pops from the pre-decoded message array. out->data stays valid until the next recv on the same 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.
| stream | Stream to read from; may be NULL. |
| out | Receives the message (borrowed pointer valid until the next recv on this stream). |
| 1 | A message was delivered. |
| 0 | End of stream (no more messages). |
| -1 | NULL 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.
| 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.
| stream | Open stream to send on; may be NULL. |
| payload | Message bytes; may be NULL when payload_len is 0. |
| payload_len | Message length in bytes. |
| 0 | Message accepted by the transport/buffer. |
| -1 | Encoding 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.
| void cwist_grpc_stream_set_retry_pushback | ( | cwist_grpc_stream * | stream, |
| int32_t | ms | ||
| ) |
Advertise a server-side retry pushback hint to the client.
gRFC A6 server pushback: attach "grpc-retry-pushback-ms" to the response trailers. A non-negative ms asks the client to wait that long before retrying; a negative value asks it not to retry at all. For unary handlers the same effect is available by adding a "grpc-retry-pushback-ms" header to the response.
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.
| stream | Stream to annotate; may be NULL (no-op). |
| ms | Retry 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.
| 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.
Attach a transport writer; subsequent sends are emitted immediately.
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.
| stream | Stream to configure; may be NULL (no-op). |
| write_frame | Callback invoked with each framed message; may be NULL. |
| ctx | Opaque 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.