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/types.h> 36 #include <sys/socket.h> 37 #include <sys/un.h> 38 39 #include <errno.h> 40 #include <stdbool.h> 41 #include <stdint.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "pjdlog.h" 47 #include "proto_impl.h" 48 49 #define UDS_CTX_MAGIC 0xd541c 50 struct uds_ctx { 51 int uc_magic; 52 struct sockaddr_un uc_sun; 53 int uc_fd; 54 int uc_side; 55 #define UDS_SIDE_CLIENT 0 56 #define UDS_SIDE_SERVER_LISTEN 1 57 #define UDS_SIDE_SERVER_WORK 2 58 pid_t uc_owner; 59 }; 60 61 static void uds_close(void *ctx); 62 63 static int 64 uds_addr(const char *addr, struct sockaddr_un *sunp) 65 { 66 67 if (addr == NULL) 68 return (-1); 69 70 if (strncasecmp(addr, "uds://", 6) == 0) 71 addr += 6; 72 else if (strncasecmp(addr, "unix://", 7) == 0) 73 addr += 7; 74 else if (addr[0] == '/' && /* If it starts from /... */ 75 strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 76 ; /* ...we assume its us. */ 77 else 78 return (-1); 79 80 sunp->sun_family = AF_UNIX; 81 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 82 sizeof(sunp->sun_path)) { 83 return (ENAMETOOLONG); 84 } 85 sunp->sun_len = SUN_LEN(sunp); 86 87 return (0); 88 } 89 90 static int 91 uds_common_setup(const char *addr, void **ctxp, int side) 92 { 93 struct uds_ctx *uctx; 94 int ret; 95 96 uctx = malloc(sizeof(*uctx)); 97 if (uctx == NULL) 98 return (errno); 99 100 /* Parse given address. */ 101 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) { 102 free(uctx); 103 return (ret); 104 } 105 106 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 107 if (uctx->uc_fd == -1) { 108 ret = errno; 109 free(uctx); 110 return (ret); 111 } 112 113 uctx->uc_side = side; 114 uctx->uc_owner = 0; 115 uctx->uc_magic = UDS_CTX_MAGIC; 116 *ctxp = uctx; 117 118 return (0); 119 } 120 121 static int 122 uds_client(const char *srcaddr, const char *dstaddr, void **ctxp) 123 { 124 int ret; 125 126 ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT); 127 if (ret != 0) 128 return (ret); 129 130 PJDLOG_ASSERT(srcaddr == NULL); 131 132 return (0); 133 } 134 135 static int 136 uds_connect(void *ctx, int timeout) 137 { 138 struct uds_ctx *uctx = ctx; 139 140 PJDLOG_ASSERT(uctx != NULL); 141 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 142 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 143 PJDLOG_ASSERT(uctx->uc_fd >= 0); 144 PJDLOG_ASSERT(timeout >= -1); 145 146 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 147 sizeof(uctx->uc_sun)) == -1) { 148 return (errno); 149 } 150 151 return (0); 152 } 153 154 static int 155 uds_connect_wait(void *ctx, int timeout) 156 { 157 struct uds_ctx *uctx = ctx; 158 159 PJDLOG_ASSERT(uctx != NULL); 160 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 161 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 162 PJDLOG_ASSERT(uctx->uc_fd >= 0); 163 PJDLOG_ASSERT(timeout >= 0); 164 165 return (0); 166 } 167 168 static int 169 uds_server(const char *addr, void **ctxp) 170 { 171 struct uds_ctx *uctx; 172 int ret; 173 174 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN); 175 if (ret != 0) 176 return (ret); 177 178 uctx = *ctxp; 179 180 (void)unlink(uctx->uc_sun.sun_path); 181 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 182 sizeof(uctx->uc_sun)) == -1) { 183 ret = errno; 184 uds_close(uctx); 185 return (ret); 186 } 187 uctx->uc_owner = getpid(); 188 if (listen(uctx->uc_fd, 8) == -1) { 189 ret = errno; 190 uds_close(uctx); 191 return (ret); 192 } 193 194 return (0); 195 } 196 197 static int 198 uds_accept(void *ctx, void **newctxp) 199 { 200 struct uds_ctx *uctx = ctx; 201 struct uds_ctx *newuctx; 202 socklen_t fromlen; 203 int ret; 204 205 PJDLOG_ASSERT(uctx != NULL); 206 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 207 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 208 PJDLOG_ASSERT(uctx->uc_fd >= 0); 209 210 newuctx = malloc(sizeof(*newuctx)); 211 if (newuctx == NULL) 212 return (errno); 213 214 fromlen = sizeof(newuctx->uc_sun); 215 newuctx->uc_fd = accept(uctx->uc_fd, 216 (struct sockaddr *)&newuctx->uc_sun, &fromlen); 217 if (newuctx->uc_fd == -1) { 218 ret = errno; 219 free(newuctx); 220 return (ret); 221 } 222 223 newuctx->uc_side = UDS_SIDE_SERVER_WORK; 224 newuctx->uc_magic = UDS_CTX_MAGIC; 225 *newctxp = newuctx; 226 227 return (0); 228 } 229 230 static int 231 uds_send(void *ctx, const unsigned char *data, size_t size, int fd) 232 { 233 struct uds_ctx *uctx = ctx; 234 235 PJDLOG_ASSERT(uctx != NULL); 236 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 237 PJDLOG_ASSERT(uctx->uc_fd >= 0); 238 239 return (proto_common_send(uctx->uc_fd, data, size, fd)); 240 } 241 242 static int 243 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 244 { 245 struct uds_ctx *uctx = ctx; 246 247 PJDLOG_ASSERT(uctx != NULL); 248 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 249 PJDLOG_ASSERT(uctx->uc_fd >= 0); 250 251 return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 252 } 253 254 static int 255 uds_descriptor(const void *ctx) 256 { 257 const struct uds_ctx *uctx = ctx; 258 259 PJDLOG_ASSERT(uctx != NULL); 260 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 261 262 return (uctx->uc_fd); 263 } 264 265 static void 266 uds_local_address(const void *ctx, char *addr, size_t size) 267 { 268 const struct uds_ctx *uctx = ctx; 269 struct sockaddr_un sun; 270 socklen_t sunlen; 271 272 PJDLOG_ASSERT(uctx != NULL); 273 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 274 PJDLOG_ASSERT(addr != NULL); 275 276 sunlen = sizeof(sun); 277 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 278 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 279 return; 280 } 281 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 282 if (sun.sun_path[0] == '\0') { 283 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 284 return; 285 } 286 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 287 } 288 289 static void 290 uds_remote_address(const void *ctx, char *addr, size_t size) 291 { 292 const struct uds_ctx *uctx = ctx; 293 struct sockaddr_un sun; 294 socklen_t sunlen; 295 296 PJDLOG_ASSERT(uctx != NULL); 297 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 298 PJDLOG_ASSERT(addr != NULL); 299 300 sunlen = sizeof(sun); 301 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 302 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 303 return; 304 } 305 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 306 if (sun.sun_path[0] == '\0') { 307 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 308 return; 309 } 310 snprintf(addr, size, "uds://%s", sun.sun_path); 311 } 312 313 static void 314 uds_close(void *ctx) 315 { 316 struct uds_ctx *uctx = ctx; 317 318 PJDLOG_ASSERT(uctx != NULL); 319 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 320 321 if (uctx->uc_fd >= 0) 322 close(uctx->uc_fd); 323 /* 324 * Unlink the socket only if we are the owner and this is descriptor 325 * we listen on. 326 */ 327 if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 328 uctx->uc_owner == getpid()) { 329 PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 330 if (unlink(uctx->uc_sun.sun_path) == -1) { 331 pjdlog_errno(LOG_WARNING, 332 "Unable to unlink socket file %s", 333 uctx->uc_sun.sun_path); 334 } 335 } 336 uctx->uc_owner = 0; 337 uctx->uc_magic = 0; 338 free(uctx); 339 } 340 341 static struct proto uds_proto = { 342 .prt_name = "uds", 343 .prt_client = uds_client, 344 .prt_connect = uds_connect, 345 .prt_connect_wait = uds_connect_wait, 346 .prt_server = uds_server, 347 .prt_accept = uds_accept, 348 .prt_send = uds_send, 349 .prt_recv = uds_recv, 350 .prt_descriptor = uds_descriptor, 351 .prt_local_address = uds_local_address, 352 .prt_remote_address = uds_remote_address, 353 .prt_close = uds_close 354 }; 355 356 static __constructor void 357 uds_ctor(void) 358 { 359 360 proto_register(&uds_proto, false); 361 } 362