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#include <sys/types.h> 34204076Spjd#include <sys/socket.h> 35204076Spjd 36204076Spjd#include <errno.h> 37204076Spjd#include <stdbool.h> 38204076Spjd#include <stdint.h> 39204076Spjd#include <stdio.h> 40204076Spjd#include <string.h> 41204076Spjd#include <unistd.h> 42204076Spjd 43218138Spjd#include "pjdlog.h" 44204076Spjd#include "proto_impl.h" 45204076Spjd 46204076Spjd#define SP_CTX_MAGIC 0x50c3741 47204076Spjdstruct sp_ctx { 48204076Spjd int sp_magic; 49204076Spjd int sp_fd[2]; 50204076Spjd int sp_side; 51204076Spjd#define SP_SIDE_UNDEF 0 52204076Spjd#define SP_SIDE_CLIENT 1 53204076Spjd#define SP_SIDE_SERVER 2 54204076Spjd}; 55204076Spjd 56204076Spjdstatic void sp_close(void *ctx); 57204076Spjd 58204076Spjdstatic int 59219818Spjdsp_client(const char *srcaddr, const char *dstaddr, void **ctxp) 60204076Spjd{ 61204076Spjd struct sp_ctx *spctx; 62204076Spjd int ret; 63204076Spjd 64219818Spjd if (strcmp(dstaddr, "socketpair://") != 0) 65204076Spjd return (-1); 66204076Spjd 67219818Spjd PJDLOG_ASSERT(srcaddr == NULL); 68219818Spjd 69204076Spjd spctx = malloc(sizeof(*spctx)); 70204076Spjd if (spctx == NULL) 71204076Spjd return (errno); 72204076Spjd 73231017Strociny if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) { 74204076Spjd ret = errno; 75204076Spjd free(spctx); 76204076Spjd return (ret); 77204076Spjd } 78204076Spjd 79204076Spjd spctx->sp_side = SP_SIDE_UNDEF; 80204076Spjd spctx->sp_magic = SP_CTX_MAGIC; 81204076Spjd *ctxp = spctx; 82204076Spjd 83204076Spjd return (0); 84204076Spjd} 85204076Spjd 86204076Spjdstatic int 87218194Spjdsp_send(void *ctx, const unsigned char *data, size_t size, int fd) 88204076Spjd{ 89204076Spjd struct sp_ctx *spctx = ctx; 90218194Spjd int sock; 91204076Spjd 92218138Spjd PJDLOG_ASSERT(spctx != NULL); 93218138Spjd PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 94204076Spjd 95204076Spjd switch (spctx->sp_side) { 96204076Spjd case SP_SIDE_UNDEF: 97204076Spjd /* 98204076Spjd * If the first operation done by the caller is proto_send(), 99218194Spjd * we assume this is the client. 100204076Spjd */ 101204076Spjd /* FALLTHROUGH */ 102204076Spjd spctx->sp_side = SP_SIDE_CLIENT; 103204076Spjd /* Close other end. */ 104204076Spjd close(spctx->sp_fd[1]); 105218138Spjd spctx->sp_fd[1] = -1; 106204076Spjd case SP_SIDE_CLIENT: 107218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 108218194Spjd sock = spctx->sp_fd[0]; 109204076Spjd break; 110204076Spjd case SP_SIDE_SERVER: 111218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 112218194Spjd sock = spctx->sp_fd[1]; 113204076Spjd break; 114204076Spjd default: 115218138Spjd PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 116204076Spjd } 117204076Spjd 118212036Spjd /* Someone is just trying to decide about side. */ 119212036Spjd if (data == NULL) 120212036Spjd return (0); 121212036Spjd 122218194Spjd return (proto_common_send(sock, data, size, fd)); 123204076Spjd} 124204076Spjd 125204076Spjdstatic int 126218194Spjdsp_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 127204076Spjd{ 128204076Spjd struct sp_ctx *spctx = ctx; 129204076Spjd int fd; 130204076Spjd 131218138Spjd PJDLOG_ASSERT(spctx != NULL); 132218138Spjd PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 133204076Spjd 134204076Spjd switch (spctx->sp_side) { 135204076Spjd case SP_SIDE_UNDEF: 136204076Spjd /* 137204076Spjd * If the first operation done by the caller is proto_recv(), 138218194Spjd * we assume this is the server. 139204076Spjd */ 140204076Spjd /* FALLTHROUGH */ 141204076Spjd spctx->sp_side = SP_SIDE_SERVER; 142204076Spjd /* Close other end. */ 143204076Spjd close(spctx->sp_fd[0]); 144218138Spjd spctx->sp_fd[0] = -1; 145204076Spjd case SP_SIDE_SERVER: 146218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 147204076Spjd fd = spctx->sp_fd[1]; 148204076Spjd break; 149204076Spjd case SP_SIDE_CLIENT: 150218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 151204076Spjd fd = spctx->sp_fd[0]; 152204076Spjd break; 153204076Spjd default: 154218138Spjd PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 155204076Spjd } 156204076Spjd 157212036Spjd /* Someone is just trying to decide about side. */ 158212036Spjd if (data == NULL) 159212036Spjd return (0); 160212036Spjd 161218194Spjd return (proto_common_recv(fd, data, size, fdp)); 162204076Spjd} 163204076Spjd 164204076Spjdstatic int 165204076Spjdsp_descriptor(const void *ctx) 166204076Spjd{ 167204076Spjd const struct sp_ctx *spctx = ctx; 168204076Spjd 169218138Spjd PJDLOG_ASSERT(spctx != NULL); 170218138Spjd PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 171218138Spjd PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT || 172204076Spjd spctx->sp_side == SP_SIDE_SERVER); 173204076Spjd 174204076Spjd switch (spctx->sp_side) { 175204076Spjd case SP_SIDE_CLIENT: 176218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 177204076Spjd return (spctx->sp_fd[0]); 178204076Spjd case SP_SIDE_SERVER: 179218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 180204076Spjd return (spctx->sp_fd[1]); 181204076Spjd } 182204076Spjd 183218138Spjd PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 184204076Spjd} 185204076Spjd 186204076Spjdstatic void 187204076Spjdsp_close(void *ctx) 188204076Spjd{ 189204076Spjd struct sp_ctx *spctx = ctx; 190204076Spjd 191218138Spjd PJDLOG_ASSERT(spctx != NULL); 192218138Spjd PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 193204076Spjd 194204076Spjd switch (spctx->sp_side) { 195204076Spjd case SP_SIDE_UNDEF: 196218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 197204076Spjd close(spctx->sp_fd[0]); 198218138Spjd spctx->sp_fd[0] = -1; 199218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 200204076Spjd close(spctx->sp_fd[1]); 201218138Spjd spctx->sp_fd[1] = -1; 202204076Spjd break; 203204076Spjd case SP_SIDE_CLIENT: 204218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 205204076Spjd close(spctx->sp_fd[0]); 206218138Spjd spctx->sp_fd[0] = -1; 207218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] == -1); 208204076Spjd break; 209204076Spjd case SP_SIDE_SERVER: 210218138Spjd PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 211204076Spjd close(spctx->sp_fd[1]); 212218138Spjd spctx->sp_fd[1] = -1; 213218138Spjd PJDLOG_ASSERT(spctx->sp_fd[0] == -1); 214204076Spjd break; 215204076Spjd default: 216218138Spjd PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 217204076Spjd } 218204076Spjd 219204076Spjd spctx->sp_magic = 0; 220204076Spjd free(spctx); 221204076Spjd} 222204076Spjd 223219873Spjdstatic struct proto sp_proto = { 224219873Spjd .prt_name = "socketpair", 225219873Spjd .prt_client = sp_client, 226219873Spjd .prt_send = sp_send, 227219873Spjd .prt_recv = sp_recv, 228219873Spjd .prt_descriptor = sp_descriptor, 229219873Spjd .prt_close = sp_close 230204076Spjd}; 231204076Spjd 232204076Spjdstatic __constructor void 233204076Spjdsp_ctor(void) 234204076Spjd{ 235204076Spjd 236210869Spjd proto_register(&sp_proto, false); 237204076Spjd} 238