blob: fc0fe2ad81f069db13a8cfd39fdf4e3a24e8f92c [file] [log] [blame]
/*
* Copyright (C) 2019 - 2020 Intel Corporation
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <usfstl/assert.h>
#include <usfstl/loop.h>
#include <usfstl/list.h>
#include "internal.h"
struct usfstl_uds_server {
struct usfstl_loop_entry entry;
void (*connected)(int fd, void *data);
void *data;
char name[];
};
void usfstl_uds_accept_handler(struct usfstl_loop_entry *entry)
{
struct usfstl_uds_server *uds;
int fd;
uds = container_of(entry, struct usfstl_uds_server, entry);
fd = accept(uds->entry.fd, NULL, NULL);
uds->connected(fd, uds->data);
}
void usfstl_uds_create(const char *path, void (*connected)(int, void *),
void *data)
{
struct usfstl_uds_server *uds = malloc(sizeof(*uds) + strlen(path) + 1);
struct stat buf;
int ret = stat(path, &buf), fd;
struct sockaddr_un un = {
.sun_family = AF_UNIX,
};
USFSTL_ASSERT(uds);
strcpy(uds->name, path);
uds->data = data;
uds->connected = connected;
if (ret == 0) {
USFSTL_ASSERT_EQ((int)(buf.st_mode & S_IFMT), S_IFSOCK, "%d");
USFSTL_ASSERT_EQ(unlink(path), 0, "%d");
} else {
USFSTL_ASSERT_EQ(errno, ENOENT, "%d");
}
fd = socket(AF_UNIX, SOCK_STREAM, 0);
uds->entry.fd = fd;
strcpy(un.sun_path, path);
USFSTL_ASSERT_EQ(bind(fd, (void *)&un, sizeof(un)), 0, "%d");
USFSTL_ASSERT_EQ(listen(fd, 1000), 0, "%d");
uds->entry.handler = usfstl_uds_accept_handler;
usfstl_loop_register(&uds->entry);
}
void usfstl_uds_remove(const char *path)
{
struct usfstl_loop_entry *tmp;
struct usfstl_uds_server *uds, *found = NULL;
usfstl_loop_for_each_entry(tmp) {
if (tmp->handler != usfstl_uds_accept_handler)
continue;
uds = container_of(tmp, struct usfstl_uds_server, entry);
if (strcmp(uds->name, path) == 0) {
found = uds;
break;
}
}
USFSTL_ASSERT(found);
close(found->entry.fd);
usfstl_loop_unregister(&found->entry);
unlink(path);
free(found);
}
struct usfstl_uds_client {
struct usfstl_loop_entry entry;
void (*readable)(int fd, void *data);
void *data;
};
void usfstl_uds_readable_handler(struct usfstl_loop_entry *entry)
{
struct usfstl_uds_client *uds;
uds = container_of(entry, struct usfstl_uds_client, entry);
uds->readable(uds->entry.fd, uds->data);
}
int usfstl_uds_connect(const char *path, void (*readable)(int, void *),
void *data)
{
struct usfstl_uds_client *client;
struct sockaddr_un sock;
int fd, err;
client = calloc(1, sizeof(*client));
USFSTL_ASSERT(client);
client->entry.handler = usfstl_uds_readable_handler;
client->readable = readable;
client->data = data;
sock.sun_family = AF_UNIX;
strcpy(sock.sun_path, path);
fd = socket(AF_UNIX, SOCK_STREAM, 0);
USFSTL_ASSERT(fd >= 0);
err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
USFSTL_ASSERT(err == 0);
client->entry.fd = fd;
usfstl_loop_register(&client->entry);
return fd;
}
void usfstl_uds_disconnect(int fd)
{
struct usfstl_loop_entry *tmp;
struct usfstl_uds_client *uds, *found = NULL;
usfstl_loop_for_each_entry(tmp) {
if (tmp->handler != usfstl_uds_readable_handler)
continue;
uds = container_of(tmp, struct usfstl_uds_client, entry);
if (uds->entry.fd == fd) {
found = uds;
break;
}
}
USFSTL_ASSERT(found);
close(fd);
usfstl_loop_unregister(&found->entry);
free(found);
}