1 /*
2 * Copyright (C) 2019 - 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include <stddef.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <errno.h>
16 #include <usfstl/assert.h>
17 #include <usfstl/loop.h>
18 #include <usfstl/list.h>
19 #include "internal.h"
20
21 struct usfstl_uds_server {
22 struct usfstl_loop_entry entry;
23 void (*connected)(int fd, void *data);
24 void *data;
25 char name[];
26 };
27
usfstl_uds_accept_handler(struct usfstl_loop_entry * entry)28 void usfstl_uds_accept_handler(struct usfstl_loop_entry *entry)
29 {
30 struct usfstl_uds_server *uds;
31 int fd;
32
33 uds = container_of(entry, struct usfstl_uds_server, entry);
34 fd = accept(uds->entry.fd, NULL, NULL);
35
36 uds->connected(fd, uds->data);
37 }
38
usfstl_uds_create(const char * path,void (* connected)(int,void *),void * data)39 void usfstl_uds_create(const char *path, void (*connected)(int, void *),
40 void *data)
41 {
42 struct usfstl_uds_server *uds = malloc(sizeof(*uds) + strlen(path) + 1);
43 struct stat buf;
44 int ret = stat(path, &buf), fd;
45 struct sockaddr_un un = {
46 .sun_family = AF_UNIX,
47 };
48
49 USFSTL_ASSERT(uds);
50 strcpy(uds->name, path);
51 uds->data = data;
52 uds->connected = connected;
53
54 if (ret == 0) {
55 USFSTL_ASSERT_EQ((int)(buf.st_mode & S_IFMT), S_IFSOCK, "%d");
56 USFSTL_ASSERT_EQ(unlink(path), 0, "%d");
57 } else {
58 USFSTL_ASSERT_EQ(errno, ENOENT, "%d");
59 }
60
61 fd = socket(AF_UNIX, SOCK_STREAM, 0);
62 uds->entry.fd = fd;
63
64 strcpy(un.sun_path, path);
65 USFSTL_ASSERT_EQ(bind(fd, (void *)&un, sizeof(un)), 0, "%d");
66
67 USFSTL_ASSERT_EQ(listen(fd, 1000), 0, "%d");
68
69 uds->entry.handler = usfstl_uds_accept_handler;
70
71 usfstl_loop_register(&uds->entry);
72 }
73
usfstl_uds_remove(const char * path)74 void usfstl_uds_remove(const char *path)
75 {
76 struct usfstl_loop_entry *tmp;
77 struct usfstl_uds_server *uds, *found = NULL;
78
79 usfstl_loop_for_each_entry(tmp) {
80 if (tmp->handler != usfstl_uds_accept_handler)
81 continue;
82
83 uds = container_of(tmp, struct usfstl_uds_server, entry);
84 if (strcmp(uds->name, path) == 0) {
85 found = uds;
86 break;
87 }
88 }
89
90 USFSTL_ASSERT(found);
91
92 close(found->entry.fd);
93 usfstl_loop_unregister(&found->entry);
94 unlink(path);
95 free(found);
96 }
97
98 struct usfstl_uds_client {
99 struct usfstl_loop_entry entry;
100 void (*readable)(int fd, void *data);
101 void *data;
102 };
103
usfstl_uds_readable_handler(struct usfstl_loop_entry * entry)104 void usfstl_uds_readable_handler(struct usfstl_loop_entry *entry)
105 {
106 struct usfstl_uds_client *uds;
107
108 uds = container_of(entry, struct usfstl_uds_client, entry);
109
110 uds->readable(uds->entry.fd, uds->data);
111 }
112
usfstl_uds_connect(const char * path,void (* readable)(int,void *),void * data)113 int usfstl_uds_connect(const char *path, void (*readable)(int, void *),
114 void *data)
115 {
116 struct usfstl_uds_client *client;
117 struct sockaddr_un sock;
118 int fd, err;
119
120 client = calloc(1, sizeof(*client));
121 USFSTL_ASSERT(client);
122 client->entry.handler = usfstl_uds_readable_handler;
123 client->readable = readable;
124 client->data = data;
125
126 sock.sun_family = AF_UNIX;
127 strcpy(sock.sun_path, path);
128
129 fd = socket(AF_UNIX, SOCK_STREAM, 0);
130 USFSTL_ASSERT(fd >= 0);
131
132 err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
133 USFSTL_ASSERT(err == 0);
134
135 client->entry.fd = fd;
136 usfstl_loop_register(&client->entry);
137
138 return fd;
139 }
140
usfstl_uds_disconnect(int fd)141 void usfstl_uds_disconnect(int fd)
142 {
143 struct usfstl_loop_entry *tmp;
144 struct usfstl_uds_client *uds, *found = NULL;
145
146 usfstl_loop_for_each_entry(tmp) {
147 if (tmp->handler != usfstl_uds_readable_handler)
148 continue;
149
150 uds = container_of(tmp, struct usfstl_uds_client, entry);
151 if (uds->entry.fd == fd) {
152 found = uds;
153 break;
154 }
155 }
156
157 USFSTL_ASSERT(found);
158
159 close(fd);
160 usfstl_loop_unregister(&found->entry);
161 free(found);
162 }
163