proto_uds.c revision 219818
1167465Smp/*- 259243Sobrien * Copyright (c) 2009-2010 The FreeBSD Foundation 359243Sobrien * All rights reserved. 459243Sobrien * 559243Sobrien * This software was developed by Pawel Jakub Dawidek under sponsorship from 659243Sobrien * the FreeBSD Foundation. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 11100616Smp * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 1659243Sobrien * 1759243Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1859243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1959243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2059243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2159243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2259243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2359243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2459243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2559243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2659243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2759243Sobrien * SUCH DAMAGE. 2859243Sobrien */ 2959243Sobrien 3059243Sobrien#include <sys/cdefs.h> 3159243Sobrien__FBSDID("$FreeBSD: head/sbin/hastd/proto_uds.c 219818 2011-03-21 08:54:59Z pjd $"); 3259243Sobrien 3359243Sobrien/* UDS - UNIX Domain Socket */ 3459243Sobrien 3559243Sobrien#include <sys/types.h> 3659243Sobrien#include <sys/un.h> 3759243Sobrien 3859243Sobrien#include <errno.h> 3959243Sobrien#include <stdbool.h> 4059243Sobrien#include <stdint.h> 4159243Sobrien#include <stdio.h> 4259243Sobrien#include <string.h> 4359243Sobrien#include <unistd.h> 4459243Sobrien 4559243Sobrien#include "hast.h" 4659243Sobrien#include "pjdlog.h" 4759243Sobrien#include "proto_impl.h" 4859243Sobrien 4959243Sobrien#define UDS_CTX_MAGIC 0xd541c 5059243Sobrienstruct uds_ctx { 5159243Sobrien int uc_magic; 5259243Sobrien struct sockaddr_un uc_sun; 5359243Sobrien int uc_fd; 5459243Sobrien int uc_side; 5559243Sobrien#define UDS_SIDE_CLIENT 0 5659243Sobrien#define UDS_SIDE_SERVER_LISTEN 1 5759243Sobrien#define UDS_SIDE_SERVER_WORK 2 5859243Sobrien pid_t uc_owner; 5959243Sobrien}; 6059243Sobrien 6159243Sobrienstatic void uds_close(void *ctx); 6259243Sobrien 6359243Sobrienstatic int 6459243Sobrienuds_addr(const char *addr, struct sockaddr_un *sunp) 6559243Sobrien{ 6659243Sobrien 6759243Sobrien if (addr == NULL) 6859243Sobrien return (-1); 6959243Sobrien 7059243Sobrien if (strncasecmp(addr, "uds://", 6) == 0) 7159243Sobrien addr += 6; 7259243Sobrien else if (strncasecmp(addr, "unix://", 7) == 0) 7359243Sobrien addr += 7; 7459243Sobrien else if (addr[0] == '/' && /* If it starts from /... */ 7559243Sobrien strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 7659243Sobrien ; /* ...we assume its us. */ 7759243Sobrien else 7859243Sobrien return (-1); 7959243Sobrien 8059243Sobrien sunp->sun_family = AF_UNIX; 8159243Sobrien if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 8259243Sobrien sizeof(sunp->sun_path)) { 8359243Sobrien return (ENAMETOOLONG); 8459243Sobrien } 8559243Sobrien sunp->sun_len = SUN_LEN(sunp); 8659243Sobrien 8759243Sobrien return (0); 8859243Sobrien} 8959243Sobrien 9059243Sobrienstatic int 9159243Sobrienuds_common_setup(const char *addr, void **ctxp, int side) 9259243Sobrien{ 9359243Sobrien struct uds_ctx *uctx; 9459243Sobrien int ret; 9559243Sobrien 9659243Sobrien uctx = malloc(sizeof(*uctx)); 9759243Sobrien if (uctx == NULL) 9859243Sobrien return (errno); 9959243Sobrien 10059243Sobrien /* Parse given address. */ 10159243Sobrien if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) { 10259243Sobrien free(uctx); 10359243Sobrien return (ret); 10459243Sobrien } 10559243Sobrien 10659243Sobrien uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 10759243Sobrien if (uctx->uc_fd == -1) { 10859243Sobrien ret = errno; 10959243Sobrien free(uctx); 11059243Sobrien return (ret); 11159243Sobrien } 11259243Sobrien 11369408Sache uctx->uc_side = side; 11469408Sache uctx->uc_owner = 0; 11569408Sache uctx->uc_magic = UDS_CTX_MAGIC; 11659243Sobrien *ctxp = uctx; 11759243Sobrien 11859243Sobrien return (0); 11959243Sobrien} 12059243Sobrien 12159243Sobrienstatic int 12259243Sobrienuds_client(const char *srcaddr, const char *dstaddr, void **ctxp) 12359243Sobrien{ 12459243Sobrien int ret; 12559243Sobrien 12659243Sobrien ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT); 12759243Sobrien if (ret != 0) 12859243Sobrien return (ret); 12959243Sobrien 13059243Sobrien PJDLOG_ASSERT(srcaddr == NULL); 13159243Sobrien 13259243Sobrien return (0); 13359243Sobrien} 13459243Sobrien 13559243Sobrienstatic int 13659243Sobrienuds_connect(void *ctx, int timeout) 13759243Sobrien{ 13859243Sobrien struct uds_ctx *uctx = ctx; 13959243Sobrien 14059243Sobrien PJDLOG_ASSERT(uctx != NULL); 14159243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 14259243Sobrien PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 14359243Sobrien PJDLOG_ASSERT(uctx->uc_fd >= 0); 14459243Sobrien PJDLOG_ASSERT(timeout >= -1); 14559243Sobrien 14659243Sobrien if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 14759243Sobrien sizeof(uctx->uc_sun)) < 0) { 14859243Sobrien return (errno); 14959243Sobrien } 15059243Sobrien 15159243Sobrien return (0); 15259243Sobrien} 15359243Sobrien 15459243Sobrienstatic int 15559243Sobrienuds_connect_wait(void *ctx, int timeout) 15659243Sobrien{ 15759243Sobrien struct uds_ctx *uctx = ctx; 15859243Sobrien 15959243Sobrien PJDLOG_ASSERT(uctx != NULL); 16059243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 16159243Sobrien PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 16259243Sobrien PJDLOG_ASSERT(uctx->uc_fd >= 0); 16359243Sobrien PJDLOG_ASSERT(timeout >= 0); 16459243Sobrien 16559243Sobrien return (0); 16659243Sobrien} 16759243Sobrien 16859243Sobrienstatic int 16959243Sobrienuds_server(const char *addr, void **ctxp) 17059243Sobrien{ 17159243Sobrien struct uds_ctx *uctx; 17259243Sobrien int ret; 17359243Sobrien 17459243Sobrien ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN); 17559243Sobrien if (ret != 0) 17659243Sobrien return (ret); 17759243Sobrien 17859243Sobrien uctx = *ctxp; 17959243Sobrien 18059243Sobrien (void)unlink(uctx->uc_sun.sun_path); 18159243Sobrien if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 18259243Sobrien sizeof(uctx->uc_sun)) < 0) { 18359243Sobrien ret = errno; 18459243Sobrien uds_close(uctx); 18559243Sobrien return (ret); 18659243Sobrien } 18759243Sobrien uctx->uc_owner = getpid(); 18859243Sobrien if (listen(uctx->uc_fd, 8) < 0) { 18959243Sobrien ret = errno; 19059243Sobrien uds_close(uctx); 19159243Sobrien return (ret); 19259243Sobrien } 19359243Sobrien 19459243Sobrien return (0); 19559243Sobrien} 19659243Sobrien 19759243Sobrienstatic int 19859243Sobrienuds_accept(void *ctx, void **newctxp) 19959243Sobrien{ 20059243Sobrien struct uds_ctx *uctx = ctx; 20159243Sobrien struct uds_ctx *newuctx; 20259243Sobrien socklen_t fromlen; 20359243Sobrien int ret; 20459243Sobrien 20559243Sobrien PJDLOG_ASSERT(uctx != NULL); 20659243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 20759243Sobrien PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 20859243Sobrien PJDLOG_ASSERT(uctx->uc_fd >= 0); 20959243Sobrien 21059243Sobrien newuctx = malloc(sizeof(*newuctx)); 21159243Sobrien if (newuctx == NULL) 21259243Sobrien return (errno); 21359243Sobrien 21459243Sobrien fromlen = sizeof(newuctx->uc_sun); 21559243Sobrien newuctx->uc_fd = accept(uctx->uc_fd, 21659243Sobrien (struct sockaddr *)&newuctx->uc_sun, &fromlen); 21759243Sobrien if (newuctx->uc_fd < 0) { 21859243Sobrien ret = errno; 21959243Sobrien free(newuctx); 22059243Sobrien return (ret); 22159243Sobrien } 22259243Sobrien 22359243Sobrien newuctx->uc_side = UDS_SIDE_SERVER_WORK; 22459243Sobrien newuctx->uc_magic = UDS_CTX_MAGIC; 22559243Sobrien *newctxp = newuctx; 22659243Sobrien 22759243Sobrien return (0); 22859243Sobrien} 22959243Sobrien 23059243Sobrienstatic int 23159243Sobrienuds_send(void *ctx, const unsigned char *data, size_t size, int fd) 23259243Sobrien{ 23359243Sobrien struct uds_ctx *uctx = ctx; 23459243Sobrien 23559243Sobrien PJDLOG_ASSERT(uctx != NULL); 23659243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 23759243Sobrien PJDLOG_ASSERT(uctx->uc_fd >= 0); 23859243Sobrien 23959243Sobrien return (proto_common_send(uctx->uc_fd, data, size, fd)); 24059243Sobrien} 24159243Sobrien 24259243Sobrienstatic int 24359243Sobrienuds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 24459243Sobrien{ 24559243Sobrien struct uds_ctx *uctx = ctx; 24659243Sobrien 24759243Sobrien PJDLOG_ASSERT(uctx != NULL); 24859243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 24959243Sobrien PJDLOG_ASSERT(uctx->uc_fd >= 0); 25059243Sobrien 25159243Sobrien return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 25259243Sobrien} 25359243Sobrien 25459243Sobrienstatic int 25559243Sobrienuds_descriptor(const void *ctx) 25659243Sobrien{ 25759243Sobrien const struct uds_ctx *uctx = ctx; 25859243Sobrien 25959243Sobrien PJDLOG_ASSERT(uctx != NULL); 26059243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 26159243Sobrien 26259243Sobrien return (uctx->uc_fd); 26359243Sobrien} 26459243Sobrien 26559243Sobrienstatic void 26659243Sobrienuds_local_address(const void *ctx, char *addr, size_t size) 26759243Sobrien{ 26859243Sobrien const struct uds_ctx *uctx = ctx; 26959243Sobrien struct sockaddr_un sun; 27059243Sobrien socklen_t sunlen; 27159243Sobrien 27259243Sobrien PJDLOG_ASSERT(uctx != NULL); 27359243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 27459243Sobrien PJDLOG_ASSERT(addr != NULL); 27559243Sobrien 27659243Sobrien sunlen = sizeof(sun); 27759243Sobrien if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 27859243Sobrien PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 27959243Sobrien return; 28059243Sobrien } 28159243Sobrien PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 28259243Sobrien if (sun.sun_path[0] == '\0') { 28359243Sobrien PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 28459243Sobrien return; 28559243Sobrien } 28659243Sobrien PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 28759243Sobrien} 28859243Sobrien 28959243Sobrienstatic void 29059243Sobrienuds_remote_address(const void *ctx, char *addr, size_t size) 29159243Sobrien{ 29259243Sobrien const struct uds_ctx *uctx = ctx; 29359243Sobrien struct sockaddr_un sun; 294100616Smp socklen_t sunlen; 295100616Smp 296100616Smp PJDLOG_ASSERT(uctx != NULL); 297100616Smp PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 298100616Smp PJDLOG_ASSERT(addr != NULL); 29959243Sobrien 30059243Sobrien sunlen = sizeof(sun); 30159243Sobrien if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 30259243Sobrien PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 30359243Sobrien return; 30459243Sobrien } 30559243Sobrien PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 30659243Sobrien if (sun.sun_path[0] == '\0') { 30759243Sobrien PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 30859243Sobrien return; 30959243Sobrien } 31059243Sobrien snprintf(addr, size, "uds://%s", sun.sun_path); 311145479Smp} 31259243Sobrien 31359243Sobrienstatic void 31459243Sobrienuds_close(void *ctx) 315145479Smp{ 31659243Sobrien struct uds_ctx *uctx = ctx; 31759243Sobrien 31859243Sobrien PJDLOG_ASSERT(uctx != NULL); 31959243Sobrien PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 32059243Sobrien 32159243Sobrien if (uctx->uc_fd >= 0) 32259243Sobrien close(uctx->uc_fd); 32359243Sobrien /* 32459243Sobrien * Unlink the socket only if we are the owner and this is descriptor 32559243Sobrien * we listen on. 32659243Sobrien */ 32759243Sobrien if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 32859243Sobrien uctx->uc_owner == getpid()) { 32959243Sobrien PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 33059243Sobrien if (unlink(uctx->uc_sun.sun_path) == -1) { 33159243Sobrien pjdlog_errno(LOG_WARNING, 33259243Sobrien "Unable to unlink socket file %s", 33359243Sobrien uctx->uc_sun.sun_path); 33459243Sobrien } 33559243Sobrien } 33659243Sobrien uctx->uc_owner = 0; 33759243Sobrien uctx->uc_magic = 0; 33859243Sobrien free(uctx); 33959243Sobrien} 34059243Sobrien 34159243Sobrienstatic struct hast_proto uds_proto = { 34259243Sobrien .hp_name = "uds", 34359243Sobrien .hp_client = uds_client, 34459243Sobrien .hp_connect = uds_connect, 34559243Sobrien .hp_connect_wait = uds_connect_wait, 34659243Sobrien .hp_server = uds_server, 34759243Sobrien .hp_accept = uds_accept, 34859243Sobrien .hp_send = uds_send, 34959243Sobrien .hp_recv = uds_recv, 35059243Sobrien .hp_descriptor = uds_descriptor, 35159243Sobrien .hp_local_address = uds_local_address, 35259243Sobrien .hp_remote_address = uds_remote_address, 35359243Sobrien .hp_close = uds_close 35459243Sobrien}; 35559243Sobrien 35659243Sobrienstatic __constructor void 35759243Sobrienuds_ctor(void) 35859243Sobrien{ 35959243Sobrien 36059243Sobrien proto_register(&uds_proto, false); 36159243Sobrien} 36259243Sobrien