rpc: add very basic client RPC code

The protocol itself is not yet finalized, but it is enough to experiment
with.

Currently, there is only one command implemented - get a HLQ payload by
uuid.

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
3 files changed, 126 insertions(+), 0 deletions(-)

M rpc/CMakeLists.txt
A => rpc/include/hlog-rpc/rpc-client.h
A => rpc/rpc-client.c
M rpc/CMakeLists.txt +1 -0
@@ 30,6 30,7 @@ add_library(hlogrpc SHARED
 	hamlib.c
 	hamlib-quirks.c
 	instance.c
+	rpc-client.c
 	rpc-server.c
 )
 

          
A => rpc/include/hlog-rpc/rpc-client.h +33 -0
@@ 0,0 1,33 @@ 
+/*
+ * Copyright (c) 2024 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __RPC_RPC_CLIENT_H
+#define __RPC_RPC_CLIENT_H
+
+#include <jeffpc/sock.h>
+
+#include <hlog/qso.h>
+
+extern struct qso *rpc_call_get_hlq(const union xsockaddr *addr,
+				    const struct xuuid *uuid);
+
+#endif

          
A => rpc/rpc-client.c +92 -0
@@ 0,0 1,92 @@ 
+/*
+ * Copyright (c) 2024 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <jeffpc/io.h>
+
+#include <hlog/qso.h>
+#include <hlog/qso-pack.h>
+
+#include <hlog-rpc/rpc.h>
+#include <hlog-rpc/rpc-client.h>
+#include <hlog-rpc/announce-sub.h>
+
+struct qso *rpc_call_get_hlq(const union xsockaddr *addr,
+			     const struct xuuid *uuid)
+{
+	char str[8 + XUUID_PRINTABLE_STRING_LENGTH + 1];
+	char uuid_str[XUUID_PRINTABLE_STRING_LENGTH];
+	struct qso *qso;
+	uint32_t sz;
+	void *buf;
+	int sock;
+	int ret;
+
+	xuuid_unparse(uuid, uuid_str);
+
+	snprintf(str, sizeof(str), "GET hlq:%s\n", uuid_str);
+
+	qso = qso_alloc();
+	if (!qso)
+		return ERR_PTR(-ENOMEM);
+
+	sock = connect_addr(addr, IP_TCP);
+	if (sock < 0) {
+		ret = sock;
+		goto err;
+	}
+
+	ret = xwrite(sock, str, strlen(str));
+	if (ret)
+		goto err_sock;
+
+	ret = xread(sock, &sz, sizeof(sz));
+	if (ret)
+		goto err_sock;
+
+	sz = be32_to_cpu(sz);
+
+	buf = malloc(sz);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_sock;
+	}
+
+	ret = xread(sock, buf, sz);
+	if (ret)
+		goto err_free;
+
+	ret = qso_unpack_hlq(qso, buf, sz);
+
+err_free:
+	free(buf);
+
+err_sock:
+	xclose(sock);
+
+err:
+	if (ret) {
+		qso_putref(qso);
+		return ERR_PTR(ret);
+	}
+
+	return qso;
+}