From 1ad1390e5663f44bbfe9d93a449018e6a89123d4 Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Tue, 28 Aug 2018 18:06:07 +1200
Subject: Add simple 'alarms' Python module for interfacing with alarmd

---
 inc/pyalarmd_proto.h |  11 +++
 lib/Makefile         |  10 ++-
 lib/python/Makefile  |  19 ++++++
 lib/python/alarms.c  | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 226 insertions(+), 2 deletions(-)
 create mode 100644 inc/pyalarmd_proto.h
 create mode 100644 lib/python/Makefile
 create mode 100644 lib/python/alarms.c

diff --git a/inc/pyalarmd_proto.h b/inc/pyalarmd_proto.h
new file mode 100644
index 0000000..4370bdd
--- /dev/null
+++ b/inc/pyalarmd_proto.h
@@ -0,0 +1,11 @@
+#ifndef PYALARMD_PROTO_H
+#define PYALARMD_PROTO_H
+
+PyObject* pyalarmd_connect(PyObject *self, PyObject *args);
+PyObject* pyalarmd_disconnect(PyObject *self, PyObject *args);
+PyObject* pyalarmd_register(PyObject *self, PyObject *args);
+PyObject* pyalarmd_deregister(PyObject *self, PyObject *args);
+PyObject* pyalarmd_raise(PyObject *self, PyObject *args);
+PyObject* pyalarmd_clear(PyObject *self, PyObject *args);
+
+#endif /* PYALARMD_PROTO_H */
diff --git a/lib/Makefile b/lib/Makefile
index 2c9ccc9..43a9d87 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,11 @@
+CFLAGS += -I../inc/
 
-CFLAGS += "-I../inc/"
+all: libalarm.so python
 
-libalarm.so: libalarm.o
+python:
+	make -C python
+
+%.so: %.o
 	$(CC) -shared -o $@ $< $(LDFLAGS)
 
 %.o: %.c
@@ -9,3 +13,5 @@ libalarm.so: libalarm.o
 
 clean:
 	rm libalarm.{s,}o
+
+.PHONY: python
diff --git a/lib/python/Makefile b/lib/python/Makefile
new file mode 100644
index 0000000..1e2c24a
--- /dev/null
+++ b/lib/python/Makefile
@@ -0,0 +1,19 @@
+PYTHONINC = /usr/include/python3.7m/
+
+LDFLAGS += "-luuid"
+CFLAGS += -fPIC \
+          -I$(PYTHONINC) \
+          -I../../inc/
+
+all: alarms.so
+
+%.so: %.o
+	$(CC) -shared -o $@ $< $(LDFLAGS)
+
+%.o: %.c
+	$(CC) -c -o $@ $< $(LDFLAGS) $(CFLAGS)
+
+.PHONY: clean
+clean:
+	- rm -f alarms.{s,}o
+
diff --git a/lib/python/alarms.c b/lib/python/alarms.c
new file mode 100644
index 0000000..57670e8
--- /dev/null
+++ b/lib/python/alarms.c
@@ -0,0 +1,188 @@
+#include <Python.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <uuid/uuid.h>
+
+#include "alarmd_proto.h"
+#include "pyalarmd_proto.h"
+
+static PyMethodDef ExportedMethods[] = {
+	{"connect"         , pyalarmd_connect   , METH_VARARGS, "FIXME"},
+	{"disconnect"      , pyalarmd_disconnect, METH_VARARGS, "FIXME"},
+	{"register_alarm"  , pyalarmd_register  , METH_VARARGS, "FIXME"},
+	{"deregister_alarm", pyalarmd_deregister, METH_VARARGS, "FIXME"},
+	{"raise_alarm"     , pyalarmd_raise     , METH_VARARGS, "FIXME"},
+	{"clear_alarm"     , pyalarmd_clear     , METH_VARARGS, "FIXME"},
+	{NULL              , NULL               , 0           , NULL   }
+};
+
+
+static struct PyModuleDef alarm_python = {
+	PyModuleDef_HEAD_INIT,
+	"alarms", /* module name */
+	NULL,     /* FIXME reference doc */
+	-1,       /* storage size -1 since state kept in global variables. */
+	ExportedMethods
+};
+
+static PyObject *alarmd_error;
+
+/* Helper function */
+int send_packet_uuid(int sock, uint32_t packet_type, uuid_t uuid)
+{
+	return (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)
+	        || send(sock, uuid, sizeof(uuid_t), 0) != 16);
+}
+
+PyObject* PyInit_alarms(void) {
+	PyObject *module = NULL;
+
+	module = PyModule_Create(&alarm_python);
+	alarmd_error = PyErr_NewException("alarms.error", NULL, NULL);
+	PyModule_AddObject(module, "error", alarmd_error);
+
+	return module;
+}
+
+PyObject* pyalarmd_connect(PyObject *self, PyObject *args) {
+	const char *path = NULL;
+	int sock = 0;
+	struct sockaddr_un server;
+
+	if (!PyArg_ParseTuple(args, "s", &path)) {
+		return NULL;
+	}
+
+	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+
+	server.sun_family = AF_UNIX;
+	strcpy(server.sun_path, path);
+	if (connect(sock, (struct sockaddr *)&server, strlen(server.sun_path) + sizeof(server.sun_family)) < 0) {
+		close(sock);
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+	return PyLong_FromLong(sock);
+}
+
+PyObject* pyalarmd_disconnect(PyObject *self, PyObject *args) {
+	int sock = 0;
+
+	if (!PyArg_ParseTuple(args, "i", &sock)) {
+		return NULL;
+	}
+
+	close(sock);
+
+	Py_RETURN_NONE;
+}
+
+PyObject* pyalarmd_register(PyObject *self, PyObject *args)
+{
+	int sock = 0;
+	char *desc;
+	char uuid_str[37];
+	uuid_t uuid;
+	uint8_t length = 0;
+	uint32_t packet_type = 0;
+
+	if (!PyArg_ParseTuple(args, "is", &sock, &desc)) {
+		return NULL;
+	}
+
+	packet_type = ALARMD_PACKET_TYPE_REGISTER;
+	if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) {
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+
+	length = strlen(desc);
+	if (send(sock, &length, sizeof(length), 0) != sizeof(length)) {
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+
+	if (send(sock, desc, strlen(desc), 0) != strlen(desc)) {
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+
+	if (recv(sock, &uuid, sizeof(uuid), 0) != sizeof(uuid)) {
+		PyErr_SetFromErrno(alarmd_error);
+		return NULL;
+	}
+
+	uuid_unparse(uuid, uuid_str);
+
+	return Py_BuildValue("s", uuid_str);
+}
+
+PyObject* pyalarmd_deregister(PyObject *self, PyObject *args)
+{
+	int sock = 0;
+	char *uuid_str = NULL;
+	uuid_t uuid;
+
+	if (!PyArg_ParseTuple(args, "is", &sock, &uuid_str)) {
+		return NULL;
+	}
+
+	if (uuid_parse(uuid_str, uuid) < 0) {
+		PyErr_SetString(alarmd_error, "Invalid UUID");
+		return NULL;
+	}
+
+	send_packet_uuid(sock, ALARMD_PACKET_TYPE_DEREGISTER, uuid);
+
+	Py_RETURN_NONE;
+}
+
+PyObject* pyalarmd_raise(PyObject *self, PyObject *args)
+{
+	int sock = 0;
+	char *uuid_str = NULL;
+	uuid_t uuid;
+
+	if (!PyArg_ParseTuple(args, "is", &sock, &uuid_str)) {
+		return NULL;
+	}
+
+	if (uuid_parse(uuid_str, uuid) < 0) {
+		PyErr_SetString(alarmd_error, "Invalid UUID");
+		return NULL;
+	}
+
+	send_packet_uuid(sock, ALARMD_PACKET_TYPE_RAISE, uuid);
+
+	Py_RETURN_NONE;
+}
+
+PyObject* pyalarmd_clear(PyObject *self, PyObject *args)
+{
+	int sock = 0;
+	char *uuid_str = NULL;
+	uuid_t uuid;
+
+	if (!PyArg_ParseTuple(args, "is", &sock, &uuid_str)) {
+		return NULL;
+	}
+
+	if (uuid_parse(uuid_str, uuid) < 0) {
+		PyErr_SetString(alarmd_error, "Invalid UUID");
+		return NULL;
+	}
+
+	send_packet_uuid(sock, ALARMD_PACKET_TYPE_CLEAR, uuid);
+
+	Py_RETURN_NONE;
+}
-- 
cgit v1.1