mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2025-12-20 06:30:04 +01:00
Simple library that uses sockets for inter-process communication. It provides an API to create server and client objects. Users can add custom handlers in the server, and clients can send requests for those custom handlers.
217 lines
5.1 KiB
C
217 lines
5.1 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2021 Collabora Ltd.
|
|
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include <spa/pod/builder.h>
|
|
#include <spa/pod/parser.h>
|
|
|
|
#include "protocol.h"
|
|
|
|
#define SIZE_PADDING 128
|
|
|
|
enum wpipc_protocol_reply_code {
|
|
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
|
|
wpipc_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
|
|
wpipc_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;
|
|
|
|
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
|
|
wpipc_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
|
|
wpipc_protocol_calculate_reply_ok_size (const struct spa_pod *value)
|
|
{
|
|
return (value ? SPA_POD_SIZE(value) : 8) + SIZE_PADDING;
|
|
}
|
|
|
|
size_t
|
|
wpipc_protocol_calculate_reply_error_size (const char *msg)
|
|
{
|
|
assert (msg);
|
|
return strlen(msg) + SIZE_PADDING;
|
|
}
|
|
|
|
void
|
|
wpipc_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;
|
|
|
|
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
|
|
wpipc_protocol_build_reply_error (uint8_t *buffer,
|
|
size_t size,
|
|
const char *msg)
|
|
{
|
|
struct spa_pod_builder b;
|
|
struct spa_pod_frame f;
|
|
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
|
|
wpipc_protocol_is_reply_ok (const uint8_t *buffer, size_t size)
|
|
{
|
|
return is_reply (buffer, size, REPLY_CODE_OK);
|
|
}
|
|
|
|
bool
|
|
wpipc_protocol_is_reply_error (const uint8_t *buffer, size_t size)
|
|
{
|
|
return is_reply (buffer, size, REPLY_CODE_ERROR);
|
|
}
|
|
|
|
bool
|
|
wpipc_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
|
|
wpipc_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;
|
|
}
|