proto.c revision 218191
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: head/sbin/hastd/proto.c 218191 2011-02-02 15:23:07Z pjd $"); 32204076Spjd 33207371Spjd#include <sys/types.h> 34204076Spjd#include <sys/queue.h> 35207371Spjd#include <sys/socket.h> 36204076Spjd 37204076Spjd#include <errno.h> 38204076Spjd#include <stdint.h> 39218191Spjd#include <strings.h> 40204076Spjd 41218138Spjd#include "pjdlog.h" 42204076Spjd#include "proto.h" 43204076Spjd#include "proto_impl.h" 44204076Spjd 45204076Spjd#define PROTO_CONN_MAGIC 0x907041c 46204076Spjdstruct proto_conn { 47204076Spjd int pc_magic; 48204076Spjd struct hast_proto *pc_proto; 49204076Spjd void *pc_ctx; 50204076Spjd int pc_side; 51204076Spjd#define PROTO_SIDE_CLIENT 0 52204076Spjd#define PROTO_SIDE_SERVER_LISTEN 1 53204076Spjd#define PROTO_SIDE_SERVER_WORK 2 54204076Spjd}; 55204076Spjd 56210869Spjdstatic TAILQ_HEAD(, hast_proto) protos = TAILQ_HEAD_INITIALIZER(protos); 57204076Spjd 58204076Spjdvoid 59210869Spjdproto_register(struct hast_proto *proto, bool isdefault) 60204076Spjd{ 61210869Spjd static bool seen_default = false; 62204076Spjd 63210869Spjd if (!isdefault) 64210869Spjd TAILQ_INSERT_HEAD(&protos, proto, hp_next); 65210869Spjd else { 66218138Spjd PJDLOG_ASSERT(!seen_default); 67210869Spjd seen_default = true; 68210869Spjd TAILQ_INSERT_TAIL(&protos, proto, hp_next); 69210869Spjd } 70204076Spjd} 71204076Spjd 72218191Spjdstatic struct proto_conn * 73218191Spjdproto_alloc(struct hast_proto *proto, int side) 74218191Spjd{ 75218191Spjd struct proto_conn *conn; 76218191Spjd 77218191Spjd PJDLOG_ASSERT(proto != NULL); 78218191Spjd PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT || 79218191Spjd side == PROTO_SIDE_SERVER_LISTEN || 80218191Spjd side == PROTO_SIDE_SERVER_WORK); 81218191Spjd 82218191Spjd conn = malloc(sizeof(*conn)); 83218191Spjd if (conn != NULL) { 84218191Spjd conn->pc_proto = proto; 85218191Spjd conn->pc_side = side; 86218191Spjd conn->pc_magic = PROTO_CONN_MAGIC; 87218191Spjd } 88218191Spjd return (conn); 89218191Spjd} 90218191Spjd 91218191Spjdstatic void 92218191Spjdproto_free(struct proto_conn *conn) 93218191Spjd{ 94218191Spjd 95218191Spjd PJDLOG_ASSERT(conn != NULL); 96218191Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 97218191Spjd PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT || 98218191Spjd conn->pc_side == PROTO_SIDE_SERVER_LISTEN || 99218191Spjd conn->pc_side == PROTO_SIDE_SERVER_WORK); 100218191Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 101218191Spjd 102218191Spjd bzero(conn, sizeof(*conn)); 103218191Spjd free(conn); 104218191Spjd} 105218191Spjd 106204076Spjdstatic int 107204076Spjdproto_common_setup(const char *addr, struct proto_conn **connp, int side) 108204076Spjd{ 109204076Spjd struct hast_proto *proto; 110204076Spjd struct proto_conn *conn; 111204076Spjd void *ctx; 112204076Spjd int ret; 113204076Spjd 114218191Spjd PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT || 115218191Spjd side == PROTO_SIDE_SERVER_LISTEN); 116204076Spjd 117210869Spjd TAILQ_FOREACH(proto, &protos, hp_next) { 118218185Spjd if (side == PROTO_SIDE_CLIENT) { 119218185Spjd if (proto->hp_client == NULL) 120218185Spjd ret = -1; 121218185Spjd else 122218185Spjd ret = proto->hp_client(addr, &ctx); 123218185Spjd } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ { 124218185Spjd if (proto->hp_server == NULL) 125218185Spjd ret = -1; 126218185Spjd else 127218185Spjd ret = proto->hp_server(addr, &ctx); 128218185Spjd } 129204076Spjd /* 130204076Spjd * ret == 0 - success 131204076Spjd * ret == -1 - addr is not for this protocol 132204076Spjd * ret > 0 - right protocol, but an error occured 133204076Spjd */ 134204076Spjd if (ret >= 0) 135204076Spjd break; 136204076Spjd } 137204076Spjd if (proto == NULL) { 138204076Spjd /* Unrecognized address. */ 139204076Spjd errno = EINVAL; 140204076Spjd return (-1); 141204076Spjd } 142204076Spjd if (ret > 0) { 143204076Spjd /* An error occured. */ 144204076Spjd errno = ret; 145204076Spjd return (-1); 146204076Spjd } 147218191Spjd conn = proto_alloc(proto, side); 148218191Spjd if (conn == NULL) { 149218191Spjd if (proto->hp_close != NULL) 150218191Spjd proto->hp_close(ctx); 151218191Spjd errno = ENOMEM; 152218191Spjd return (-1); 153218191Spjd } 154204076Spjd conn->pc_ctx = ctx; 155204076Spjd *connp = conn; 156218191Spjd 157204076Spjd return (0); 158204076Spjd} 159204076Spjd 160204076Spjdint 161204076Spjdproto_client(const char *addr, struct proto_conn **connp) 162204076Spjd{ 163204076Spjd 164204076Spjd return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT)); 165204076Spjd} 166204076Spjd 167204076Spjdint 168204076Spjdproto_connect(struct proto_conn *conn) 169204076Spjd{ 170204076Spjd int ret; 171204076Spjd 172218138Spjd PJDLOG_ASSERT(conn != NULL); 173218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 174218138Spjd PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT); 175218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 176218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_connect != NULL); 177204076Spjd 178204076Spjd ret = conn->pc_proto->hp_connect(conn->pc_ctx); 179204076Spjd if (ret != 0) { 180204076Spjd errno = ret; 181204076Spjd return (-1); 182204076Spjd } 183204076Spjd 184204076Spjd return (0); 185204076Spjd} 186204076Spjd 187204076Spjdint 188204076Spjdproto_server(const char *addr, struct proto_conn **connp) 189204076Spjd{ 190204076Spjd 191204076Spjd return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN)); 192204076Spjd} 193204076Spjd 194204076Spjdint 195204076Spjdproto_accept(struct proto_conn *conn, struct proto_conn **newconnp) 196204076Spjd{ 197204076Spjd struct proto_conn *newconn; 198204076Spjd int ret; 199204076Spjd 200218138Spjd PJDLOG_ASSERT(conn != NULL); 201218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 202218138Spjd PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN); 203218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 204218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_accept != NULL); 205204076Spjd 206218191Spjd newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK); 207204076Spjd if (newconn == NULL) 208204076Spjd return (-1); 209204076Spjd 210204076Spjd ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx); 211204076Spjd if (ret != 0) { 212218191Spjd proto_free(newconn); 213204076Spjd errno = ret; 214204076Spjd return (-1); 215204076Spjd } 216204076Spjd 217204076Spjd *newconnp = newconn; 218204076Spjd 219204076Spjd return (0); 220204076Spjd} 221204076Spjd 222204076Spjdint 223212033Spjdproto_send(const struct proto_conn *conn, const void *data, size_t size) 224204076Spjd{ 225204076Spjd int ret; 226204076Spjd 227218138Spjd PJDLOG_ASSERT(conn != NULL); 228218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 229218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 230218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_send != NULL); 231204076Spjd 232204076Spjd ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size); 233204076Spjd if (ret != 0) { 234204076Spjd errno = ret; 235204076Spjd return (-1); 236204076Spjd } 237204076Spjd return (0); 238204076Spjd} 239204076Spjd 240204076Spjdint 241212033Spjdproto_recv(const struct proto_conn *conn, void *data, size_t size) 242204076Spjd{ 243204076Spjd int ret; 244204076Spjd 245218138Spjd PJDLOG_ASSERT(conn != NULL); 246218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 247218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 248218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_recv != NULL); 249204076Spjd 250204076Spjd ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size); 251204076Spjd if (ret != 0) { 252204076Spjd errno = ret; 253204076Spjd return (-1); 254204076Spjd } 255204076Spjd return (0); 256204076Spjd} 257204076Spjd 258204076Spjdint 259218139Spjdproto_descriptor_send(const struct proto_conn *conn, int fd) 260218139Spjd{ 261218139Spjd int ret; 262218139Spjd 263218139Spjd PJDLOG_ASSERT(conn != NULL); 264218139Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 265218139Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 266218139Spjd PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_send != NULL); 267218139Spjd 268218139Spjd ret = conn->pc_proto->hp_descriptor_send(conn->pc_ctx, fd); 269218139Spjd if (ret != 0) { 270218139Spjd errno = ret; 271218139Spjd return (-1); 272218139Spjd } 273218139Spjd return (0); 274218139Spjd} 275218139Spjd 276218139Spjdint 277218139Spjdproto_descriptor_recv(const struct proto_conn *conn, int *fdp) 278218139Spjd{ 279218139Spjd int ret; 280218139Spjd 281218139Spjd PJDLOG_ASSERT(conn != NULL); 282218139Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 283218139Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 284218139Spjd PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_recv != NULL); 285218139Spjd 286218139Spjd ret = conn->pc_proto->hp_descriptor_recv(conn->pc_ctx, fdp); 287218139Spjd if (ret != 0) { 288218139Spjd errno = ret; 289218139Spjd return (-1); 290218139Spjd } 291218139Spjd return (0); 292218139Spjd} 293218139Spjd 294218139Spjdint 295204076Spjdproto_descriptor(const struct proto_conn *conn) 296204076Spjd{ 297204076Spjd 298218138Spjd PJDLOG_ASSERT(conn != NULL); 299218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 300218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 301218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_descriptor != NULL); 302204076Spjd 303204076Spjd return (conn->pc_proto->hp_descriptor(conn->pc_ctx)); 304204076Spjd} 305204076Spjd 306204076Spjdbool 307204076Spjdproto_address_match(const struct proto_conn *conn, const char *addr) 308204076Spjd{ 309204076Spjd 310218138Spjd PJDLOG_ASSERT(conn != NULL); 311218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 312218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 313218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_address_match != NULL); 314204076Spjd 315204076Spjd return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr)); 316204076Spjd} 317204076Spjd 318204076Spjdvoid 319204076Spjdproto_local_address(const struct proto_conn *conn, char *addr, size_t size) 320204076Spjd{ 321204076Spjd 322218138Spjd PJDLOG_ASSERT(conn != NULL); 323218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 324218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 325218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_local_address != NULL); 326204076Spjd 327204076Spjd conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size); 328204076Spjd} 329204076Spjd 330204076Spjdvoid 331204076Spjdproto_remote_address(const struct proto_conn *conn, char *addr, size_t size) 332204076Spjd{ 333204076Spjd 334218138Spjd PJDLOG_ASSERT(conn != NULL); 335218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 336218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 337218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_remote_address != NULL); 338204076Spjd 339204076Spjd conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size); 340204076Spjd} 341204076Spjd 342207371Spjdint 343207371Spjdproto_timeout(const struct proto_conn *conn, int timeout) 344207371Spjd{ 345207371Spjd struct timeval tv; 346207371Spjd int fd; 347207371Spjd 348218138Spjd PJDLOG_ASSERT(conn != NULL); 349218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 350218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 351207371Spjd 352207371Spjd fd = proto_descriptor(conn); 353207371Spjd if (fd < 0) 354207371Spjd return (-1); 355207371Spjd 356207371Spjd tv.tv_sec = timeout; 357207371Spjd tv.tv_usec = 0; 358207371Spjd if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) 359207371Spjd return (-1); 360207371Spjd if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) 361207371Spjd return (-1); 362207371Spjd 363207371Spjd return (0); 364207371Spjd} 365207371Spjd 366204076Spjdvoid 367204076Spjdproto_close(struct proto_conn *conn) 368204076Spjd{ 369204076Spjd 370218138Spjd PJDLOG_ASSERT(conn != NULL); 371218138Spjd PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 372218138Spjd PJDLOG_ASSERT(conn->pc_proto != NULL); 373218138Spjd PJDLOG_ASSERT(conn->pc_proto->hp_close != NULL); 374204076Spjd 375204076Spjd conn->pc_proto->hp_close(conn->pc_ctx); 376218191Spjd proto_free(conn); 377204076Spjd} 378