]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/hastd/proto_uds.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sbin / hastd / proto_uds.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 /* UDS - UNIX Domain Socket */
34
35 #include <sys/un.h>
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <stdbool.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #include "hast.h"
46 #include "proto_impl.h"
47
48 #define UDS_CTX_MAGIC   0xd541c
49 struct uds_ctx {
50         int                     uc_magic;
51         struct sockaddr_un      uc_sun;
52         int                     uc_fd;
53         int                     uc_side;
54 #define UDS_SIDE_CLIENT         0
55 #define UDS_SIDE_SERVER_LISTEN  1
56 #define UDS_SIDE_SERVER_WORK    2
57 };
58
59 static void uds_close(void *ctx);
60
61 static int
62 uds_addr(const char *addr, struct sockaddr_un *sunp)
63 {
64
65         if (addr == NULL)
66                 return (-1);
67
68         if (strncasecmp(addr, "uds://", 6) == 0)
69                 addr += 6;
70         else if (strncasecmp(addr, "unix://", 7) == 0)
71                 addr += 7;
72         else if (addr[0] == '/' &&      /* If it starts from /... */
73             strstr(addr, "://") == NULL)/* ...and there is no prefix... */
74                 ;                       /* ...we assume its us. */
75         else
76                 return (-1);
77
78         sunp->sun_family = AF_UNIX;
79         if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
80             sizeof(sunp->sun_path)) {
81                 return (ENAMETOOLONG);
82         }
83         sunp->sun_len = SUN_LEN(sunp);
84
85         return (0);
86 }
87
88 static int
89 uds_common_setup(const char *addr, void **ctxp, int side)
90 {
91         struct uds_ctx *uctx;
92         int ret;
93
94         uctx = malloc(sizeof(*uctx));
95         if (uctx == NULL)
96                 return (errno);
97
98         /* Parse given address. */
99         if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
100                 free(uctx);
101                 return (ret);
102         }
103
104         uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
105         if (uctx->uc_fd == -1) {
106                 ret = errno;
107                 free(uctx);
108                 return (ret);
109         }
110
111         uctx->uc_side = side;
112         uctx->uc_magic = UDS_CTX_MAGIC;
113         *ctxp = uctx;
114
115         return (0);
116 }
117
118 static int
119 uds_client(const char *addr, void **ctxp)
120 {
121
122         return (uds_common_setup(addr, ctxp, UDS_SIDE_CLIENT));
123 }
124
125 static int
126 uds_connect(void *ctx)
127 {
128         struct uds_ctx *uctx = ctx;
129
130         assert(uctx != NULL);
131         assert(uctx->uc_magic == UDS_CTX_MAGIC);
132         assert(uctx->uc_side == UDS_SIDE_CLIENT);
133         assert(uctx->uc_fd >= 0);
134
135         if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
136             sizeof(uctx->uc_sun)) < 0) {
137                 return (errno);
138         }
139
140         return (0);
141 }
142
143 static int
144 uds_server(const char *addr, void **ctxp)
145 {
146         struct uds_ctx *uctx;
147         int ret;
148
149         ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
150         if (ret != 0)
151                 return (ret);
152
153         uctx = *ctxp;
154
155         unlink(uctx->uc_sun.sun_path);
156         if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
157             sizeof(uctx->uc_sun)) < 0) {
158                 ret = errno;
159                 uds_close(uctx);
160                 return (ret);
161         }
162         if (listen(uctx->uc_fd, 8) < 0) {
163                 ret = errno;
164                 uds_close(uctx);
165                 return (ret);
166         }
167
168         return (0);
169 }
170
171 static int
172 uds_accept(void *ctx, void **newctxp)
173 {
174         struct uds_ctx *uctx = ctx;
175         struct uds_ctx *newuctx;
176         socklen_t fromlen;
177         int ret;
178
179         assert(uctx != NULL);
180         assert(uctx->uc_magic == UDS_CTX_MAGIC);
181         assert(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
182         assert(uctx->uc_fd >= 0);
183
184         newuctx = malloc(sizeof(*newuctx));
185         if (newuctx == NULL)
186                 return (errno);
187
188         fromlen = sizeof(uctx->uc_sun);
189         newuctx->uc_fd = accept(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
190             &fromlen);
191         if (newuctx->uc_fd < 0) {
192                 ret = errno;
193                 free(newuctx);
194                 return (ret);
195         }
196
197         newuctx->uc_side = UDS_SIDE_SERVER_WORK;
198         newuctx->uc_magic = UDS_CTX_MAGIC;
199         *newctxp = newuctx;
200
201         return (0);
202 }
203
204 static int
205 uds_send(void *ctx, const unsigned char *data, size_t size)
206 {
207         struct uds_ctx *uctx = ctx;
208
209         assert(uctx != NULL);
210         assert(uctx->uc_magic == UDS_CTX_MAGIC);
211         assert(uctx->uc_fd >= 0);
212
213         return (proto_common_send(uctx->uc_fd, data, size));
214 }
215
216 static int
217 uds_recv(void *ctx, unsigned char *data, size_t size)
218 {
219         struct uds_ctx *uctx = ctx;
220
221         assert(uctx != NULL);
222         assert(uctx->uc_magic == UDS_CTX_MAGIC);
223         assert(uctx->uc_fd >= 0);
224
225         return (proto_common_recv(uctx->uc_fd, data, size));
226 }
227
228 static int
229 uds_descriptor(const void *ctx)
230 {
231         const struct uds_ctx *uctx = ctx;
232
233         assert(uctx != NULL);
234         assert(uctx->uc_magic == UDS_CTX_MAGIC);
235
236         return (uctx->uc_fd);
237 }
238
239 static bool
240 uds_address_match(const void *ctx __unused, const char *addr __unused)
241 {
242
243         assert(!"proto_address_match() not supported on UNIX domain sockets");
244         abort();
245 }
246
247 static void
248 uds_local_address(const void *ctx, char *addr, size_t size)
249 {
250         const struct uds_ctx *uctx = ctx;
251         struct sockaddr_un sun;
252         socklen_t sunlen;
253
254         assert(uctx != NULL);
255         assert(uctx->uc_magic == UDS_CTX_MAGIC);
256         assert(addr != NULL);
257
258         sunlen = sizeof(sun);
259         if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
260                 strlcpy(addr, "N/A", size);
261                 return;
262         }
263         assert(sun.sun_family == AF_UNIX);
264         if (sun.sun_path[0] == '\0') {
265                 strlcpy(addr, "N/A", size);
266                 return;
267         }
268         snprintf(addr, size, "uds://%s", sun.sun_path);
269 }
270
271 static void
272 uds_remote_address(const void *ctx, char *addr, size_t size)
273 {
274         const struct uds_ctx *uctx = ctx;
275         struct sockaddr_un sun;
276         socklen_t sunlen;
277
278         assert(uctx != NULL);
279         assert(uctx->uc_magic == UDS_CTX_MAGIC);
280         assert(addr != NULL);
281
282         sunlen = sizeof(sun);
283         if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
284                 strlcpy(addr, "N/A", size);
285                 return;
286         }
287         assert(sun.sun_family == AF_UNIX);
288         if (sun.sun_path[0] == '\0') {
289                 strlcpy(addr, "N/A", size);
290                 return;
291         }
292         snprintf(addr, size, "uds://%s", sun.sun_path);
293 }
294
295 static void
296 uds_close(void *ctx)
297 {
298         struct uds_ctx *uctx = ctx;
299
300         assert(uctx != NULL);
301         assert(uctx->uc_magic == UDS_CTX_MAGIC);
302
303         if (uctx->uc_fd >= 0)
304                 close(uctx->uc_fd);
305         unlink(uctx->uc_sun.sun_path);
306         uctx->uc_magic = 0;
307         free(uctx);
308 }
309
310 static struct hast_proto uds_proto = {
311         .hp_name = "uds",
312         .hp_client = uds_client,
313         .hp_connect = uds_connect,
314         .hp_server = uds_server,
315         .hp_accept = uds_accept,
316         .hp_send = uds_send,
317         .hp_recv = uds_recv,
318         .hp_descriptor = uds_descriptor,
319         .hp_address_match = uds_address_match,
320         .hp_local_address = uds_local_address,
321         .hp_remote_address = uds_remote_address,
322         .hp_close = uds_close
323 };
324
325 static __constructor void
326 uds_ctor(void)
327 {
328
329         proto_register(&uds_proto);
330 }