diff options
Diffstat (limited to 'src/socket.c')
-rw-r--r-- | src/socket.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..3d0a3ae --- /dev/null +++ b/src/socket.c @@ -0,0 +1,117 @@ +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <unistd.h> + +#include "runes.h" +#include "socket.h" + +#define MAX_SOCKET_PATH_LEN \ + (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) + +static void runes_socket_populate_sockaddr( + char *path, struct sockaddr_un *addr); + +int runes_socket_client_open(char *path) +{ + int s; + struct sockaddr_un client; + + runes_socket_populate_sockaddr(path, &client); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + runes_die("couldn't create socket: %s", strerror(errno)); + } + + if (connect(s, (struct sockaddr*)(&client), sizeof(struct sockaddr_un))) { + runes_die( + "couldn't connect to socket at %s: %s", path, strerror(errno)); + } + + return s; +} + +int runes_socket_server_open(char *path) +{ + char *dir, *slash; + int s; + struct sockaddr_un server; + + runes_socket_populate_sockaddr(path, &server); + + dir = strdup(path); + slash = strrchr(dir, '/'); + if (slash == NULL) { + runes_die("socket path %s must be an absolute path", path); + } + *slash = '\0'; + runes_mkdir_p(dir); + free(dir); + + unlink(path); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + runes_die("couldn't create socket: %s", strerror(errno)); + } + + if (bind(s, (struct sockaddr*)(&server), sizeof(struct sockaddr_un))) { + runes_die( + "couldn't bind to socket %s: %s", path, strerror(errno)); + } + + if (chmod(path, S_IRUSR|S_IWUSR)) { + runes_die( + "couldn't chmod socket %s: %s", path, strerror(errno)); + } + + if (listen(s, 5)) { + runes_die( + "couldn't listen on socket %s: %s", path, strerror(errno)); + } + + return s; +} + +int runes_socket_server_accept(int ss) +{ + struct sockaddr_un client; + socklen_t len = sizeof(client); + int cs; + + cs = accept(ss, (struct sockaddr*)(&client), &len); + if (cs < 0) { + runes_die("couldn't accept connection: %s", strerror(errno)); + } + + return cs; +} + +void runes_socket_client_close(int s) +{ + close(s); +} + +void runes_socket_server_close(int s, char *path) +{ + close(s); + unlink(path); +} + +static void runes_socket_populate_sockaddr( + char *path, struct sockaddr_un *addr) +{ + size_t name_len = strlen(path) + 1; // including the nul byte + + if (name_len > MAX_SOCKET_PATH_LEN) { + runes_die("socket path %s is too long", path); + } + + addr->sun_family = AF_UNIX; + strncpy(addr->sun_path, path, name_len); +} |