diff --git a/include/rpc/client.h b/include/rpc/client.h new file mode 100644 index 0000000..65066c3 --- /dev/null +++ b/include/rpc/client.h @@ -0,0 +1,27 @@ +#ifndef RPC_CLIENT_H +#define RPC_CLIENT_H + +#include "rpc/protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rpc_client rpc_client; + +int rpc_client_connect(rpc_client **out_client, const char *host, + const char *port); +void rpc_client_close(rpc_client *client); + +int rpc_client_ping(rpc_client *client); +int rpc_client_call(rpc_client *client, uint32_t proc_id, + const rpc_writer *args, rpc_value **out_values, + size_t *out_count); + +const char *rpc_client_error(const rpc_client *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/rpc/protocol.h b/include/rpc/protocol.h new file mode 100644 index 0000000..6c4b962 --- /dev/null +++ b/include/rpc/protocol.h @@ -0,0 +1,92 @@ +#ifndef RPC_PROTOCOL_H +#define RPC_PROTOCOL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RPC_HEADER_SIZE 18u +#define RPC_MAX_PAYLOAD_SIZE (1024u * 1024u) + +typedef enum rpc_op { + RPC_OP_RPC = 1, + RPC_OP_PING = 2, + RPC_OP_DISCONNECT = 3, + RPC_OP_RESPONSE = 4, + RPC_OP_ERROR = 5, +} rpc_op; + +typedef enum rpc_flag { + RPC_FLAG_NONE = 0u, + RPC_FLAG_MORE = 1u << 0u, +} rpc_flag; + +typedef enum rpc_type { + RPC_TYPE_NULL = 0, + RPC_TYPE_BOOL = 1, + RPC_TYPE_I64 = 2, + RPC_TYPE_U64 = 3, + RPC_TYPE_F64 = 4, + RPC_TYPE_BYTES = 5, + RPC_TYPE_STRING = 6, +} rpc_type; + +typedef struct rpc_value { + rpc_type type; + union { + bool boolean; + int64_t i64; + uint64_t u64; + double f64; + struct { + const uint8_t *data; + uint32_t len; + } bytes; + struct { + const char *data; + uint32_t len; + } string; + } as; +} rpc_value; + +typedef struct rpc_header { + rpc_op op; + uint8_t flags; + uint32_t proc_id; + uint32_t size; + uint64_t call_id; +} rpc_header; + +typedef struct rpc_writer { + uint8_t *data; + size_t len; + size_t cap; +} rpc_writer; + +int rpc_header_encode(const rpc_header *header, uint8_t out[RPC_HEADER_SIZE]); +int rpc_header_decode(const uint8_t in[RPC_HEADER_SIZE], rpc_header *out); + +void rpc_writer_init(rpc_writer *writer); +void rpc_writer_reset(rpc_writer *writer); +void rpc_writer_free(rpc_writer *writer); +int rpc_writer_null(rpc_writer *writer); +int rpc_writer_bool(rpc_writer *writer, bool value); +int rpc_writer_i64(rpc_writer *writer, int64_t value); +int rpc_writer_u64(rpc_writer *writer, uint64_t value); +int rpc_writer_f64(rpc_writer *writer, double value); +int rpc_writer_bytes(rpc_writer *writer, const void *data, uint32_t len); +int rpc_writer_string(rpc_writer *writer, const char *data, uint32_t len); + +int rpc_payload_decode(const uint8_t *data, size_t len, rpc_value **out_values, + size_t *out_count); +void rpc_values_free(rpc_value *values); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/rpc/server.h b/include/rpc/server.h new file mode 100644 index 0000000..a1236cd --- /dev/null +++ b/include/rpc/server.h @@ -0,0 +1,36 @@ +#ifndef RPC_SERVER_H +#define RPC_SERVER_H + +#include "rpc/protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rpc_ctx rpc_ctx; +typedef struct rpc_server rpc_server; + +typedef int (*rpc_handler_fn)(rpc_ctx *ctx, const rpc_value *args, size_t argc, + rpc_writer *out, void *user_data); + +uint64_t rpc_ctx_call_id(const rpc_ctx *ctx); +uint32_t rpc_ctx_proc_id(const rpc_ctx *ctx); +void rpc_ctx_yield(rpc_ctx *ctx); + +int rpc_server_init(rpc_server **out_server); +int rpc_server_bind(rpc_server *server, const char *host, const char *port); +uint16_t rpc_server_port(const rpc_server *server); +int rpc_server_listen(rpc_server *server); +int rpc_server_run(rpc_server *server); +void rpc_server_stop(rpc_server *server); +void rpc_server_destroy(rpc_server *server); + +int rpc_server_add_route(rpc_server *server, uint32_t proc_id, + rpc_handler_fn handler, void *user_data); +int rpc_server_remove_route(rpc_server *server, uint32_t proc_id); + +#ifdef __cplusplus +} +#endif + +#endif