1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009-2010 The FreeBSD Foundation 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 34 #include <errno.h> 35 #include <stdbool.h> 36 #include <stdint.h> 37 #include <stdio.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "pjdlog.h" 42 #include "proto_impl.h" 43 44 #define SP_CTX_MAGIC 0x50c3741 45 struct sp_ctx { 46 int sp_magic; 47 int sp_fd[2]; 48 int sp_side; 49 #define SP_SIDE_UNDEF 0 50 #define SP_SIDE_CLIENT 1 51 #define SP_SIDE_SERVER 2 52 }; 53 54 static void sp_close(void *ctx); 55 56 static int 57 sp_client(const char *srcaddr, const char *dstaddr, void **ctxp) 58 { 59 struct sp_ctx *spctx; 60 int ret; 61 62 if (strcmp(dstaddr, "socketpair://") != 0) 63 return (-1); 64 65 PJDLOG_ASSERT(srcaddr == NULL); 66 67 spctx = malloc(sizeof(*spctx)); 68 if (spctx == NULL) 69 return (errno); 70 71 if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) { 72 ret = errno; 73 free(spctx); 74 return (ret); 75 } 76 77 spctx->sp_side = SP_SIDE_UNDEF; 78 spctx->sp_magic = SP_CTX_MAGIC; 79 *ctxp = spctx; 80 81 return (0); 82 } 83 84 static int 85 sp_send(void *ctx, const unsigned char *data, size_t size, int fd) 86 { 87 struct sp_ctx *spctx = ctx; 88 int sock; 89 90 PJDLOG_ASSERT(spctx != NULL); 91 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 92 93 switch (spctx->sp_side) { 94 case SP_SIDE_UNDEF: 95 /* 96 * If the first operation done by the caller is proto_send(), 97 * we assume this is the client. 98 */ 99 /* FALLTHROUGH */ 100 spctx->sp_side = SP_SIDE_CLIENT; 101 /* Close other end. */ 102 close(spctx->sp_fd[1]); 103 spctx->sp_fd[1] = -1; 104 case SP_SIDE_CLIENT: 105 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 106 sock = spctx->sp_fd[0]; 107 break; 108 case SP_SIDE_SERVER: 109 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 110 sock = spctx->sp_fd[1]; 111 break; 112 default: 113 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 114 } 115 116 /* Someone is just trying to decide about side. */ 117 if (data == NULL) 118 return (0); 119 120 return (proto_common_send(sock, data, size, fd)); 121 } 122 123 static int 124 sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 125 { 126 struct sp_ctx *spctx = ctx; 127 int fd; 128 129 PJDLOG_ASSERT(spctx != NULL); 130 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 131 132 switch (spctx->sp_side) { 133 case SP_SIDE_UNDEF: 134 /* 135 * If the first operation done by the caller is proto_recv(), 136 * we assume this is the server. 137 */ 138 /* FALLTHROUGH */ 139 spctx->sp_side = SP_SIDE_SERVER; 140 /* Close other end. */ 141 close(spctx->sp_fd[0]); 142 spctx->sp_fd[0] = -1; 143 case SP_SIDE_SERVER: 144 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 145 fd = spctx->sp_fd[1]; 146 break; 147 case SP_SIDE_CLIENT: 148 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 149 fd = spctx->sp_fd[0]; 150 break; 151 default: 152 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 153 } 154 155 /* Someone is just trying to decide about side. */ 156 if (data == NULL) 157 return (0); 158 159 return (proto_common_recv(fd, data, size, fdp)); 160 } 161 162 static int 163 sp_descriptor(const void *ctx) 164 { 165 const struct sp_ctx *spctx = ctx; 166 167 PJDLOG_ASSERT(spctx != NULL); 168 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 169 PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT || 170 spctx->sp_side == SP_SIDE_SERVER); 171 172 switch (spctx->sp_side) { 173 case SP_SIDE_CLIENT: 174 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 175 return (spctx->sp_fd[0]); 176 case SP_SIDE_SERVER: 177 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 178 return (spctx->sp_fd[1]); 179 } 180 181 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 182 } 183 184 static void 185 sp_close(void *ctx) 186 { 187 struct sp_ctx *spctx = ctx; 188 189 PJDLOG_ASSERT(spctx != NULL); 190 PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 191 192 switch (spctx->sp_side) { 193 case SP_SIDE_UNDEF: 194 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 195 close(spctx->sp_fd[0]); 196 spctx->sp_fd[0] = -1; 197 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 198 close(spctx->sp_fd[1]); 199 spctx->sp_fd[1] = -1; 200 break; 201 case SP_SIDE_CLIENT: 202 PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 203 close(spctx->sp_fd[0]); 204 spctx->sp_fd[0] = -1; 205 PJDLOG_ASSERT(spctx->sp_fd[1] == -1); 206 break; 207 case SP_SIDE_SERVER: 208 PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 209 close(spctx->sp_fd[1]); 210 spctx->sp_fd[1] = -1; 211 PJDLOG_ASSERT(spctx->sp_fd[0] == -1); 212 break; 213 default: 214 PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 215 } 216 217 spctx->sp_magic = 0; 218 free(spctx); 219 } 220 221 static struct proto sp_proto = { 222 .prt_name = "socketpair", 223 .prt_client = sp_client, 224 .prt_send = sp_send, 225 .prt_recv = sp_recv, 226 .prt_descriptor = sp_descriptor, 227 .prt_close = sp_close 228 }; 229 230 static __constructor void 231 sp_ctor(void) 232 { 233 234 proto_register(&sp_proto, false); 235 } 236