1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD$"); 32204076Spjd 33204076Spjd/* UDS - UNIX Domain Socket */ 34204076Spjd 35218465Spjd#include <sys/types.h> 36219873Spjd#include <sys/socket.h> 37204076Spjd#include <sys/un.h> 38204076Spjd 39204076Spjd#include <errno.h> 40204076Spjd#include <stdbool.h> 41204076Spjd#include <stdint.h> 42204076Spjd#include <stdio.h> 43204076Spjd#include <string.h> 44204076Spjd#include <unistd.h> 45204076Spjd 46210876Spjd#include "pjdlog.h" 47204076Spjd#include "proto_impl.h" 48204076Spjd 49204076Spjd#define UDS_CTX_MAGIC 0xd541c 50204076Spjdstruct uds_ctx { 51204076Spjd int uc_magic; 52204076Spjd struct sockaddr_un uc_sun; 53204076Spjd int uc_fd; 54204076Spjd int uc_side; 55204076Spjd#define UDS_SIDE_CLIENT 0 56204076Spjd#define UDS_SIDE_SERVER_LISTEN 1 57204076Spjd#define UDS_SIDE_SERVER_WORK 2 58218464Spjd pid_t uc_owner; 59204076Spjd}; 60204076Spjd 61204076Spjdstatic void uds_close(void *ctx); 62204076Spjd 63204076Spjdstatic int 64204076Spjduds_addr(const char *addr, struct sockaddr_un *sunp) 65204076Spjd{ 66204076Spjd 67204076Spjd if (addr == NULL) 68204076Spjd return (-1); 69204076Spjd 70204076Spjd if (strncasecmp(addr, "uds://", 6) == 0) 71204076Spjd addr += 6; 72204076Spjd else if (strncasecmp(addr, "unix://", 7) == 0) 73204076Spjd addr += 7; 74204076Spjd else if (addr[0] == '/' && /* If it starts from /... */ 75204076Spjd strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 76204076Spjd ; /* ...we assume its us. */ 77204076Spjd else 78204076Spjd return (-1); 79204076Spjd 80204076Spjd sunp->sun_family = AF_UNIX; 81204076Spjd if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 82204076Spjd sizeof(sunp->sun_path)) { 83204076Spjd return (ENAMETOOLONG); 84204076Spjd } 85204076Spjd sunp->sun_len = SUN_LEN(sunp); 86204076Spjd 87204076Spjd return (0); 88204076Spjd} 89204076Spjd 90204076Spjdstatic int 91204076Spjduds_common_setup(const char *addr, void **ctxp, int side) 92204076Spjd{ 93204076Spjd struct uds_ctx *uctx; 94204076Spjd int ret; 95204076Spjd 96204076Spjd uctx = malloc(sizeof(*uctx)); 97204076Spjd if (uctx == NULL) 98204076Spjd return (errno); 99204076Spjd 100204076Spjd /* Parse given address. */ 101204076Spjd if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) { 102204076Spjd free(uctx); 103204076Spjd return (ret); 104204076Spjd } 105204076Spjd 106204076Spjd uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 107204076Spjd if (uctx->uc_fd == -1) { 108204076Spjd ret = errno; 109204076Spjd free(uctx); 110204076Spjd return (ret); 111204076Spjd } 112204076Spjd 113204076Spjd uctx->uc_side = side; 114218464Spjd uctx->uc_owner = 0; 115204076Spjd uctx->uc_magic = UDS_CTX_MAGIC; 116204076Spjd *ctxp = uctx; 117204076Spjd 118204076Spjd return (0); 119204076Spjd} 120204076Spjd 121204076Spjdstatic int 122219818Spjduds_client(const char *srcaddr, const char *dstaddr, void **ctxp) 123204076Spjd{ 124219818Spjd int ret; 125204076Spjd 126219818Spjd ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT); 127219818Spjd if (ret != 0) 128219818Spjd return (ret); 129219818Spjd 130219818Spjd PJDLOG_ASSERT(srcaddr == NULL); 131219818Spjd 132219818Spjd return (0); 133204076Spjd} 134204076Spjd 135204076Spjdstatic int 136218192Spjduds_connect(void *ctx, int timeout) 137204076Spjd{ 138204076Spjd struct uds_ctx *uctx = ctx; 139204076Spjd 140218138Spjd PJDLOG_ASSERT(uctx != NULL); 141218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 142218138Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 143218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 144218193Spjd PJDLOG_ASSERT(timeout >= -1); 145204076Spjd 146204076Spjd if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 147229945Spjd sizeof(uctx->uc_sun)) == -1) { 148204076Spjd return (errno); 149204076Spjd } 150204076Spjd 151204076Spjd return (0); 152204076Spjd} 153204076Spjd 154204076Spjdstatic int 155218193Spjduds_connect_wait(void *ctx, int timeout) 156218193Spjd{ 157218193Spjd struct uds_ctx *uctx = ctx; 158218193Spjd 159218193Spjd PJDLOG_ASSERT(uctx != NULL); 160218193Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 161218193Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 162218193Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 163218193Spjd PJDLOG_ASSERT(timeout >= 0); 164218193Spjd 165218193Spjd return (0); 166218193Spjd} 167218193Spjd 168218193Spjdstatic int 169204076Spjduds_server(const char *addr, void **ctxp) 170204076Spjd{ 171204076Spjd struct uds_ctx *uctx; 172204076Spjd int ret; 173204076Spjd 174204076Spjd ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN); 175204076Spjd if (ret != 0) 176204076Spjd return (ret); 177204076Spjd 178204076Spjd uctx = *ctxp; 179204076Spjd 180218464Spjd (void)unlink(uctx->uc_sun.sun_path); 181204076Spjd if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 182229945Spjd sizeof(uctx->uc_sun)) == -1) { 183204076Spjd ret = errno; 184204076Spjd uds_close(uctx); 185204076Spjd return (ret); 186204076Spjd } 187218464Spjd uctx->uc_owner = getpid(); 188229945Spjd if (listen(uctx->uc_fd, 8) == -1) { 189204076Spjd ret = errno; 190204076Spjd uds_close(uctx); 191204076Spjd return (ret); 192204076Spjd } 193204076Spjd 194204076Spjd return (0); 195204076Spjd} 196204076Spjd 197204076Spjdstatic int 198204076Spjduds_accept(void *ctx, void **newctxp) 199204076Spjd{ 200204076Spjd struct uds_ctx *uctx = ctx; 201204076Spjd struct uds_ctx *newuctx; 202204076Spjd socklen_t fromlen; 203204076Spjd int ret; 204204076Spjd 205218138Spjd PJDLOG_ASSERT(uctx != NULL); 206218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 207218138Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 208218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 209204076Spjd 210204076Spjd newuctx = malloc(sizeof(*newuctx)); 211204076Spjd if (newuctx == NULL) 212204076Spjd return (errno); 213204076Spjd 214218464Spjd fromlen = sizeof(newuctx->uc_sun); 215218464Spjd newuctx->uc_fd = accept(uctx->uc_fd, 216218464Spjd (struct sockaddr *)&newuctx->uc_sun, &fromlen); 217229945Spjd if (newuctx->uc_fd == -1) { 218204076Spjd ret = errno; 219204076Spjd free(newuctx); 220204076Spjd return (ret); 221204076Spjd } 222204076Spjd 223204076Spjd newuctx->uc_side = UDS_SIDE_SERVER_WORK; 224204076Spjd newuctx->uc_magic = UDS_CTX_MAGIC; 225204076Spjd *newctxp = newuctx; 226204076Spjd 227204076Spjd return (0); 228204076Spjd} 229204076Spjd 230204076Spjdstatic int 231218194Spjduds_send(void *ctx, const unsigned char *data, size_t size, int fd) 232204076Spjd{ 233204076Spjd struct uds_ctx *uctx = ctx; 234204076Spjd 235218138Spjd PJDLOG_ASSERT(uctx != NULL); 236218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 237218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 238204076Spjd 239218194Spjd return (proto_common_send(uctx->uc_fd, data, size, fd)); 240204076Spjd} 241204076Spjd 242204076Spjdstatic int 243218194Spjduds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 244204076Spjd{ 245204076Spjd struct uds_ctx *uctx = ctx; 246204076Spjd 247218138Spjd PJDLOG_ASSERT(uctx != NULL); 248218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 249218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 250204076Spjd 251218194Spjd return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 252204076Spjd} 253204076Spjd 254204076Spjdstatic int 255204076Spjduds_descriptor(const void *ctx) 256204076Spjd{ 257204076Spjd const struct uds_ctx *uctx = ctx; 258204076Spjd 259218138Spjd PJDLOG_ASSERT(uctx != NULL); 260218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 261204076Spjd 262204076Spjd return (uctx->uc_fd); 263204076Spjd} 264204076Spjd 265204076Spjdstatic void 266204076Spjduds_local_address(const void *ctx, char *addr, size_t size) 267204076Spjd{ 268204076Spjd const struct uds_ctx *uctx = ctx; 269204076Spjd struct sockaddr_un sun; 270204076Spjd socklen_t sunlen; 271204076Spjd 272218138Spjd PJDLOG_ASSERT(uctx != NULL); 273218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 274218138Spjd PJDLOG_ASSERT(addr != NULL); 275204076Spjd 276204076Spjd sunlen = sizeof(sun); 277229945Spjd if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 278210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 279204076Spjd return; 280204076Spjd } 281218138Spjd PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 282204076Spjd if (sun.sun_path[0] == '\0') { 283210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 284204076Spjd return; 285204076Spjd } 286210876Spjd PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 287204076Spjd} 288204076Spjd 289204076Spjdstatic void 290204076Spjduds_remote_address(const void *ctx, char *addr, size_t size) 291204076Spjd{ 292204076Spjd const struct uds_ctx *uctx = ctx; 293204076Spjd struct sockaddr_un sun; 294204076Spjd socklen_t sunlen; 295204076Spjd 296218138Spjd PJDLOG_ASSERT(uctx != NULL); 297218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 298218138Spjd PJDLOG_ASSERT(addr != NULL); 299204076Spjd 300204076Spjd sunlen = sizeof(sun); 301229945Spjd if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 302210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 303204076Spjd return; 304204076Spjd } 305218138Spjd PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 306204076Spjd if (sun.sun_path[0] == '\0') { 307210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 308204076Spjd return; 309204076Spjd } 310204076Spjd snprintf(addr, size, "uds://%s", sun.sun_path); 311204076Spjd} 312204076Spjd 313204076Spjdstatic void 314204076Spjduds_close(void *ctx) 315204076Spjd{ 316204076Spjd struct uds_ctx *uctx = ctx; 317204076Spjd 318218138Spjd PJDLOG_ASSERT(uctx != NULL); 319218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 320204076Spjd 321204076Spjd if (uctx->uc_fd >= 0) 322204076Spjd close(uctx->uc_fd); 323218464Spjd /* 324218464Spjd * Unlink the socket only if we are the owner and this is descriptor 325218464Spjd * we listen on. 326218464Spjd */ 327218464Spjd if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 328218464Spjd uctx->uc_owner == getpid()) { 329218474Spjd PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 330218474Spjd if (unlink(uctx->uc_sun.sun_path) == -1) { 331218474Spjd pjdlog_errno(LOG_WARNING, 332218474Spjd "Unable to unlink socket file %s", 333218474Spjd uctx->uc_sun.sun_path); 334218474Spjd } 335218464Spjd } 336218464Spjd uctx->uc_owner = 0; 337204076Spjd uctx->uc_magic = 0; 338204076Spjd free(uctx); 339204076Spjd} 340204076Spjd 341219873Spjdstatic struct proto uds_proto = { 342219873Spjd .prt_name = "uds", 343219873Spjd .prt_client = uds_client, 344219873Spjd .prt_connect = uds_connect, 345219873Spjd .prt_connect_wait = uds_connect_wait, 346219873Spjd .prt_server = uds_server, 347219873Spjd .prt_accept = uds_accept, 348219873Spjd .prt_send = uds_send, 349219873Spjd .prt_recv = uds_recv, 350219873Spjd .prt_descriptor = uds_descriptor, 351219873Spjd .prt_local_address = uds_local_address, 352219873Spjd .prt_remote_address = uds_remote_address, 353219873Spjd .prt_close = uds_close 354204076Spjd}; 355204076Spjd 356204076Spjdstatic __constructor void 357204076Spjduds_ctor(void) 358204076Spjd{ 359204076Spjd 360210869Spjd proto_register(&uds_proto, false); 361204076Spjd} 362