/* PipeWire AGL Cluster IPC * * Copyright © 2021 Collabora Ltd. * @author Julian Bouzas * * SPDX-License-Identifier: MIT */ #include #include #include #include "protocol.h" #define SIZE_PADDING 128 enum { REPLY_CODE_ERROR = 0, REPLY_CODE_OK, }; static bool is_reply(const uint8_t *buffer, size_t size, int code) { const struct spa_pod *pod = (const struct spa_pod *)buffer; struct spa_pod_parser p; struct spa_pod_frame f; int parsed_code = 0; /* check if struct */ if (!spa_pod_is_struct(pod)) return false; /* parse */ spa_pod_parser_pod(&p, pod); spa_pod_parser_push_struct(&p, &f); spa_pod_parser_get_int(&p, &parsed_code); return parsed_code == code; } /* API */ size_t icipc_protocol_calculate_request_size( const char *name, const struct spa_pod *args) { assert (name); return strlen(name) + (args ? SPA_POD_SIZE(args) : 8) + SIZE_PADDING; } void icipc_protocol_build_request( uint8_t *buffer, size_t size, const char *name, const struct spa_pod *args) { const struct spa_pod none = SPA_POD_INIT_None(); struct spa_pod_builder b; struct spa_pod_frame f; memset(buffer, 0, size); if (args == NULL) args = &none; spa_pod_builder_init(&b, buffer, size); spa_pod_builder_push_struct(&b, &f); spa_pod_builder_string(&b, name); spa_pod_builder_primitive (&b, args); spa_pod_builder_pop(&b, &f); } bool icipc_protocol_parse_request( const uint8_t *buffer, size_t size, const char **name, const struct spa_pod **args) { const struct spa_pod *pod = (const struct spa_pod *)buffer; struct spa_pod_parser p; struct spa_pod_frame f; const char *parsed_name = NULL; struct spa_pod *parsed_args = NULL; /* check if struct */ if (!spa_pod_is_struct(pod)) return false; /* parse */ spa_pod_parser_pod(&p, pod); spa_pod_parser_push_struct(&p, &f); spa_pod_parser_get_string(&p, &parsed_name); spa_pod_parser_get_pod(&p, &parsed_args); spa_pod_parser_pop(&p, &f); /* check name and args */ if (name == NULL || args == NULL) return false; if (name != NULL) *name = parsed_name; if (args != NULL) *args = parsed_args; return true; } size_t icipc_protocol_calculate_reply_ok_size(const struct spa_pod *value) { return (value ? SPA_POD_SIZE(value) : 8) + SIZE_PADDING; } size_t icipc_protocol_calculate_reply_error_size(const char *msg) { assert (msg); return strlen(msg) + SIZE_PADDING; } void icipc_protocol_build_reply_ok( uint8_t *buffer, size_t size, const struct spa_pod *value) { const struct spa_pod none = SPA_POD_INIT_None(); struct spa_pod_builder b; struct spa_pod_frame f; memset(buffer, 0, size); if (value == NULL) value = &none; spa_pod_builder_init(&b, buffer, size); spa_pod_builder_push_struct(&b, &f); spa_pod_builder_int(&b, REPLY_CODE_OK); spa_pod_builder_primitive(&b, value); spa_pod_builder_pop(&b, &f); } void icipc_protocol_build_reply_error( uint8_t *buffer, size_t size, const char *msg) { struct spa_pod_builder b; struct spa_pod_frame f; memset(buffer, 0, size); spa_pod_builder_init(&b, buffer, size); spa_pod_builder_push_struct(&b, &f); spa_pod_builder_int(&b, REPLY_CODE_ERROR); spa_pod_builder_string (&b, msg); spa_pod_builder_pop(&b, &f); } bool icipc_protocol_is_reply_ok(const uint8_t *buffer, size_t size) { return is_reply (buffer, size, REPLY_CODE_OK); } bool icipc_protocol_is_reply_error(const uint8_t *buffer, size_t size) { return is_reply (buffer, size, REPLY_CODE_ERROR); } bool icipc_protocol_parse_reply_ok ( const uint8_t *buffer, size_t size, const struct spa_pod **value) { const struct spa_pod *pod = (const struct spa_pod *)buffer; struct spa_pod_parser p; struct spa_pod_frame f; int parsed_code = 0; struct spa_pod *parsed_value = NULL; /* check if struct */ if (!spa_pod_is_struct(pod)) return false; /* parse */ spa_pod_parser_pod(&p, pod); spa_pod_parser_push_struct(&p, &f); spa_pod_parser_get_int(&p, &parsed_code); spa_pod_parser_get_pod(&p, &parsed_value); spa_pod_parser_pop(&p, &f); if (value != NULL) *value = parsed_value; return true; } bool icipc_protocol_parse_reply_error ( const uint8_t *buffer, size_t size, const char **msg) { const struct spa_pod *pod = (const struct spa_pod *)buffer; struct spa_pod_parser p; struct spa_pod_frame f; int parsed_code = 0; const char *parsed_msg = NULL; /* check if struct */ if (!spa_pod_is_struct(pod)) return false; /* parse */ spa_pod_parser_pod(&p, pod); spa_pod_parser_push_struct(&p, &f); spa_pod_parser_get_int(&p, &parsed_code); spa_pod_parser_get_string(&p, &parsed_msg); spa_pod_parser_pop(&p, &f); if (msg != NULL) *msg = parsed_msg; return true; }