summaryrefslogtreecommitdiff
path: root/src/ipc.c
blob: 2e92097bb142486a562e4fe2eadf9a8ae7744531 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <json-c/json_object.h>
#include <json-c/json_tokener.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "ipc.h"
#include "log.h"

static int ipc_open(void);
static int ipc_send(int socket, struct json_object *request);
static struct json_object *ipc_receive(int socket);

struct json_object *ipc_submit(struct json_object *request)
{
	int sock = ipc_open();
	if (sock == -1) {
		return NULL;
	}

	if (ipc_send(sock, request) == -1) {
		close(sock);
		return NULL;
	}

	struct json_object *resp = ipc_receive(sock);
	close(sock);
	return resp;
}

/*
 * Open a connection to the UNIX socket specified by
 * the environment variable GREETD_SOCK.
 *
 * Returns the socket file descriptor on success, or -1 on failure.
 */
int ipc_open(void)
{
	char *greetd_sock = getenv("GREETD_SOCK");

	if (greetd_sock == NULL) {
		log_error("GREETD_SOCK not set.\n");
		return -1;
	}

	int sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sock == -1) {
		log_error("Unable to create socket: %s\n", strerror(errno));
		return -1;
	}

	struct sockaddr_un remote = { .sun_family = AF_UNIX };
	strncpy(remote.sun_path, greetd_sock, sizeof(remote.sun_path));

	if (connect(sock, (struct sockaddr *)&remote, sizeof(remote)) == -1) {
		log_error("Unable to connect to greetd: %s\n", strerror(errno));
		close(sock);
		return -1;
	}
	return sock;
}

/*
 * Send an IPC request to the specified socket.
 *
 * Returns 0 on success, or -1 on failure.
 */
int ipc_send(int sock, struct json_object *request)
{
	const char *str = json_object_to_json_string(request);
	uint32_t len = strlen(str);

	if (send(sock, &len, sizeof(len), 0) == -1) {
		log_error("Error sending request size: %s\n", strerror(errno));
		return -1;
	}

	if (send(sock, str, len, 0) == -1) {
		log_error("Error sending request: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

/*
 * Receive an IPC response on the specified socket.
 *
 * Returns the response on success, or NULL on failure.
 */
struct json_object *ipc_receive(int sock)
{
	uint32_t len = 0;

	if (recv(sock, &len, sizeof(len), 0) != sizeof(len)) {
		log_error("Error receiving response size: %s\n", strerror(errno));
		return NULL;
	}

	char *buf = malloc(len + 1);
	if (recv(sock, buf, len, 0) != len) {
		log_error("Error receiving response: %s\n", strerror(errno));
		free(buf);
		return NULL;
	}

	buf[len] = '\0';

	enum json_tokener_error error;
	struct json_object *resp = json_tokener_parse_verbose(buf, &error);
	free(buf);

	if (resp == NULL) {
		log_error("Error parsing response: %s\n", json_tokener_error_desc(error));
	}
	return resp;

}