aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2016-05-02 04:21:26 -0400
committerJesse Luehrs <doy@tozt.net>2016-05-02 04:37:17 -0400
commita513d9943fb71607ac8c0f2f3695dec9706f1ebb (patch)
treed55dacb37503fd6749009d61fa84c8866d668f5f
parent957ef4d81438a74d530f2a3890bfcd0145c11fd9 (diff)
downloadrunes-a513d9943fb71607ac8c0f2f3695dec9706f1ebb.tar.gz
runes-a513d9943fb71607ac8c0f2f3695dec9706f1ebb.zip
start working on a client/server model similar to urxvtd/urxvtc
the code is still kind of a mess, and it doesn't quite work properly yet, but it's close enough to be a start, i think
-rw-r--r--.gitignore2
-rw-r--r--Makefile23
-rw-r--r--src/runes.h2
-rw-r--r--src/runesc.c66
-rw-r--r--src/runesd.c28
-rw-r--r--src/socket.c183
-rw-r--r--src/socket.h21
-rw-r--r--src/util.c71
-rw-r--r--src/util.h3
9 files changed, 397 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index c7267e5..306871e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
*.o
.*.d
runes
+runesd
+runesc
diff --git a/Makefile b/Makefile
index 271e681..fe7f69d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,6 @@
OUT = runes
+DOUT = runesd
+COUT = runesc
BUILD = build/
SRC = src/
OBJ = $(BUILD)runes.o \
@@ -9,6 +11,17 @@ OBJ = $(BUILD)runes.o \
$(BUILD)pty-unix.o \
$(BUILD)loop.o \
$(BUILD)util.o
+DOBJ = $(BUILD)runesd.o \
+ $(BUILD)display.o \
+ $(BUILD)term.o \
+ $(BUILD)config.o \
+ $(BUILD)window-xlib.o \
+ $(BUILD)pty-unix.o \
+ $(BUILD)loop.o \
+ $(BUILD)util.o \
+ $(BUILD)socket.o
+COBJ = $(BUILD)runesc.o \
+ $(BUILD)util.o
LIBS = cairo cairo-xlib libuv pangocairo
CFLAGS ?= -g -Wall -Wextra -Werror
LDFLAGS ?= -g -Wall -Wextra -Werror
@@ -18,11 +31,17 @@ ALLLDFLAGS = $(shell pkg-config --libs $(LIBS)) $(LDFLAGS)
MAKEDEPEND = $(CC) $(ALLCFLAGS) -M -MP -MT '$@ $(@:$(BUILD)%.o=$(BUILD).%.d)'
-build: $(OUT)
+build: $(OUT) $(DOUT) $(COUT)
$(OUT): $(OBJ) libvt100/libvt100.a
$(CC) $(ALLLDFLAGS) -o $@ $^
+$(DOUT): $(DOBJ) libvt100/libvt100.a
+ $(CC) $(ALLLDFLAGS) -o $@ $^
+
+$(COUT): $(COBJ)
+ $(CC) $(ALLLDFLAGS) -o $@ $^
+
libvt100/libvt100.a:
cd libvt100 && make static
@@ -41,7 +60,7 @@ $(SRC)%.h: $(SRC)%.l
clean:
cd libvt100 && make clean
- rm -f $(OUT) $(OBJ) $(OBJ:$(BUILD)%.o=$(BUILD).%.d)
+ rm -f $(OUT) $(OBJ) $(OBJ:$(BUILD)%.o=$(BUILD).%.d) $(DOUT) $(DOBJ) $(DOBJ:$(BUILD)%.o=$(BUILD).%.d) $(COUT) $(COBJ) $(COBJ:$(BUILD)%.o=$(BUILD).%.d)
@rmdir -p $(BUILD) > /dev/null 2>&1
-include $(OBJ:$(BUILD)%.o=$(BUILD).%.d)
diff --git a/src/runes.h b/src/runes.h
index 6bdfce1..97a9487 100644
--- a/src/runes.h
+++ b/src/runes.h
@@ -9,6 +9,7 @@ struct runes_pty;
struct runes_config;
struct runes_display;
struct runes_loop;
+struct runes_socket;
typedef struct runes_term RunesTerm;
typedef struct runes_window RunesWindowBackend;
@@ -16,6 +17,7 @@ typedef struct runes_pty RunesPtyBackend;
typedef struct runes_config RunesConfig;
typedef struct runes_display RunesDisplay;
typedef struct runes_loop RunesLoop;
+typedef struct runes_socket RunesSocket;
#include "util.h"
diff --git a/src/runesc.c b/src/runesc.c
new file mode 100644
index 0000000..04fc26b
--- /dev/null
+++ b/src/runesc.c
@@ -0,0 +1,66 @@
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "runes.h"
+#include "socket.h"
+
+static int runes_socket_open_client(char *name);
+
+int main (int argc, char *argv[])
+{
+ char *name, *buf;
+ int s, i;
+ size_t len, offset;
+ uint32_t argc32 = argc, argv_len;
+
+ name = runes_get_socket_name();
+ s = runes_socket_open_client(name);
+
+ len = sizeof(argc32) + sizeof(argv_len);
+ for (i = 0; i < argc; ++i) {
+ len += strlen(argv[i]) + 1;
+ }
+
+ buf = malloc(len);
+ ((uint32_t*)buf)[0] = htonl(argc32);
+ offset = sizeof(argc32) + sizeof(argv_len);
+ ((uint32_t*)buf)[1] = htonl(len - offset);
+
+ for (i = 0; i < argc; ++i) {
+ size_t arg_len = strlen(argv[i]) + 1;
+ memcpy(buf + offset, argv[i], arg_len);
+ offset += arg_len;
+ }
+
+ send(s, buf, offset, 0);
+ free(buf);
+ shutdown(s, SHUT_RDWR);
+}
+
+static int runes_socket_open_client(char *name)
+{
+ int s;
+ struct sockaddr_un client;
+
+ if (strlen(name) + 1 > MAX_SOCKET_PATH_LEN) {
+ runes_die("socket path %s is too long\n", name);
+ }
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ runes_die("couldn't create socket: %s\n", strerror(errno));
+ }
+
+ client.sun_family = AF_UNIX;
+ strcpy(client.sun_path, name);
+ if (connect(s, (struct sockaddr*)(&client), sizeof(struct sockaddr_un))) {
+ runes_die("couldn't connect to socket at %s: %s\n", name,
+ strerror(errno));
+ }
+
+ return s;
+}
diff --git a/src/runesd.c b/src/runesd.c
new file mode 100644
index 0000000..b24eb6f
--- /dev/null
+++ b/src/runesd.c
@@ -0,0 +1,28 @@
+#include <locale.h>
+
+#include "runes.h"
+#include "socket.h"
+
+int main (int argc, char *argv[])
+{
+ RunesLoop loop;
+ RunesSocket socket;
+
+ UNUSED(argv);
+
+ if (argc > 1) {
+ runes_die("runesd takes no arguments; pass them to runesc instead.\n");
+ }
+
+ setlocale(LC_ALL, "");
+
+ runes_loop_init(&loop);
+ runes_socket_init(&socket, &loop);
+
+ runes_loop_run(&loop);
+
+ runes_socket_cleanup(&socket);
+ runes_loop_cleanup(&loop);
+
+ return 0;
+}
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..24f0260
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,183 @@
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "runes.h"
+#include "socket.h"
+
+static int runes_socket_open(RunesSocket *sock);
+static void runes_socket_close(RunesSocket *sock);
+static void runes_socket_accept(RunesTerm *t);
+static int runes_socket_handle_request(RunesTerm *t);
+
+void runes_socket_init(RunesSocket *sock, RunesLoop *loop)
+{
+ sock->loop = loop;
+ sock->name = runes_get_socket_name();
+ sock->sock = runes_socket_open(sock);
+ runes_socket_init_loop(sock, loop);
+}
+
+void runes_socket_init_loop(RunesSocket *sock, RunesLoop *loop)
+{
+ runes_loop_start_work(loop, (RunesTerm *)sock, runes_socket_accept,
+ runes_socket_handle_request);
+}
+
+void runes_socket_cleanup(RunesSocket *sock)
+{
+ runes_socket_close(sock);
+ free(sock->name);
+}
+
+static int runes_socket_open(RunesSocket *sock)
+{
+ char *dir, *slash;
+ int s;
+ struct sockaddr_un server;
+
+ if (strlen(sock->name) + 1 > MAX_SOCKET_PATH_LEN) {
+ runes_die("socket path %s is too long\n", sock->name);
+ }
+
+ dir = strdup(sock->name);
+ slash = strrchr(dir, '/');
+ if (slash == NULL) {
+ runes_die("socket path %s must be an absolute path\n", sock->name);
+ }
+ *slash = '\0';
+ mkdir_p(dir);
+ free(dir);
+
+ unlink(sock->name);
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ runes_die("couldn't create socket: %s\n", strerror(errno));
+ }
+
+ server.sun_family = AF_UNIX;
+ strcpy(server.sun_path, sock->name);
+ if (bind(s, (struct sockaddr*)(&server), sizeof(struct sockaddr_un))) {
+ runes_die("couldn't bind to socket %s: %s\n", sock->name,
+ strerror(errno));
+ }
+
+ if (chmod(sock->name, S_IRUSR|S_IWUSR)) {
+ runes_die("couldn't chmod socket %s: %s\n", sock->name,
+ strerror(errno));
+ }
+
+ if (listen(s, 5)) {
+ runes_die("couldn't listen on socket %s: %s\n", sock->name,
+ strerror(errno));
+ }
+
+ return s;
+}
+
+static void runes_socket_close(RunesSocket *sock)
+{
+ close(sock->sock);
+ unlink(sock->name);
+}
+
+static void runes_socket_accept(RunesTerm *t)
+{
+ RunesSocket *sock = (RunesSocket *)t;
+ struct sockaddr_un client;
+ socklen_t len = sizeof(client);
+
+ sock->client_sock = accept(sock->sock, (struct sockaddr*)(&client), &len);
+}
+
+static int runes_socket_handle_request(RunesTerm *t)
+{
+ RunesSocket *sock = (RunesSocket *)t;
+ ssize_t bytes;
+ uint32_t argc, argv_len;
+ char **argv, *argv_buf;
+
+ if (sock->client_sock < 0) {
+ runes_die("couldn't accept connection: %s", strerror(errno));
+ }
+
+ bytes = recv(sock->client_sock, (void*)(&argc), sizeof(argc), 0);
+ if (bytes < (int)sizeof(argc)) {
+ runes_warn("invalid message received: got %d bytes, expected 4\n",
+ bytes);
+ close(sock->client_sock);
+ return 1;
+ }
+
+ argc = ntohl(argc);
+ if (argc > 1024) {
+ runes_warn("invalid message received: argc = %d, must be < 1024\n",
+ argc);
+ close(sock->client_sock);
+ return 1;
+ }
+ argv = malloc(argc * sizeof(char*));
+
+ bytes = recv(sock->client_sock, (void*)(&argv_len), sizeof(argv_len), 0);
+ if (bytes < (int)sizeof(argc)) {
+ runes_warn("invalid message received: got %d bytes, expected 4\n",
+ bytes);
+ close(sock->client_sock);
+ free(argv);
+ return 1;
+ }
+
+ argv_len = ntohl(argv_len);
+ if (argv_len > 131072) {
+ runes_warn("invalid message received: argv_len = %d, must be < %d\n",
+ argv_len, 131072);
+ close(sock->client_sock);
+ free(argv);
+ return 1;
+ }
+ argv_buf = malloc(argv_len + 1);
+
+ bytes = recv(sock->client_sock, argv_buf, argv_len, 0);
+ if (bytes < argv_len) {
+ runes_warn("invalid message received: got %d bytes, expected %d\n",
+ bytes, argv_len);
+ close(sock->client_sock);
+ free(argv);
+ free(argv_buf);
+ return 1;
+ }
+
+ close(sock->client_sock);
+
+ if (argc > 0) {
+ size_t offset = 0;
+ int i;
+ RunesTerm *t;
+
+ for (i = 0; i < (int)argc; ++i) {
+ char *next_null;
+
+ if (offset >= argv_len) {
+ runes_die("args in argv_buf don't match argc of %d\n", argc);
+ }
+ argv[i] = argv_buf + offset;
+ next_null = memchr(argv_buf + offset, '\0', argv_len - offset);
+ if (!next_null) {
+ runes_die("args in argv_buf don't match argc of %d\n", argc);
+ }
+ offset = next_null - argv_buf + 1;
+ }
+
+ t = calloc(1, sizeof(RunesTerm));
+ runes_term_init(t, sock->loop, argc, argv);
+ }
+
+ free(argv);
+ free(argv_buf);
+
+ return 1;
+}
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..e0c5955
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,21 @@
+#ifndef _RUNES_SOCKET_H
+#define _RUNES_SOCKET_H
+
+#include <sys/un.h>
+
+struct runes_socket {
+ RunesLoop *loop;
+ char *name;
+ int sock;
+ int client_sock;
+};
+
+void runes_socket_init(RunesSocket *sock, RunesLoop *loop);
+void runes_socket_init_loop(RunesSocket *sock, RunesLoop *loop);
+void runes_socket_send_client_message(int argc, char **argv);
+void runes_socket_cleanup(RunesSocket *sock);
+
+#define MAX_SOCKET_PATH_LEN \
+ (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
+
+#endif
diff --git a/src/util.c b/src/util.c
index 686f02d..df99149 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,6 +1,8 @@
+#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "runes.h"
@@ -13,6 +15,37 @@ void runes_warn(const char *fmt, ...)
va_end(ap);
}
+void runes_die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ /* XXX make this do something else on windows */
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+char *runes_get_socket_name()
+{
+ char *home, *runtime_dir, *socket_dir, *socket_file;
+
+ home = getenv("HOME");
+
+ runtime_dir = getenv("XDG_RUNTIME_DIR");
+ if (runtime_dir) {
+ sprintf_dup(&socket_dir, "%s/runes", runtime_dir);
+ }
+ else {
+ sprintf_dup(&socket_dir, "%s/.runes", home);
+ }
+
+ sprintf_dup(&socket_file, "%s/runesd", socket_dir);
+ free(socket_dir);
+
+ return socket_file;
+}
+
int sprintf_dup(char **out, const char *fmt, ...)
{
int outlen = 0;
@@ -30,3 +63,41 @@ int sprintf_dup(char **out, const char *fmt, ...)
return outlen;
}
+
+void mkdir_p(char *dir)
+{
+ char *path_component, *save_ptr, *tok_str, *partial_path;
+ struct stat st;
+
+ dir = strdup(dir);
+ partial_path = strdup("/");
+ tok_str = dir;
+ while ((path_component = strtok_r(tok_str, "/", &save_ptr))) {
+ char *new_path;
+
+ sprintf_dup(&new_path, "%s%s/", partial_path, path_component);
+
+ if (mkdir(new_path, 0755)) {
+ if (errno != EEXIST) {
+ runes_die("couldn't create directory %s: %s\n",
+ new_path, strerror(errno));
+ }
+ }
+
+ free(partial_path);
+ partial_path = new_path;
+ tok_str = NULL;
+ }
+
+ if (stat(partial_path, &st)) {
+ runes_die("couldn't stat %s: %s\n", partial_path, strerror(errno));
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ runes_die("couldn't create directory %s: %s\n",
+ partial_path, strerror(EEXIST));
+ }
+
+ free(partial_path);
+ free(dir);
+}
diff --git a/src/util.h b/src/util.h
index 9432ed1..b2d0a28 100644
--- a/src/util.h
+++ b/src/util.h
@@ -4,6 +4,9 @@
#define UNUSED(x) ((void)x)
void runes_warn(const char *fmt, ...);
+void runes_die(const char *fmt, ...);
+char *runes_get_socket_name();
int sprintf_dup(char **out, const char *fmt, ...);
+void mkdir_p(char *dir);
#endif