proto.c revision 204076
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 204076 2010-02-18 23:16:19Z pjd $"); 32204076Spjd 33204076Spjd#include <sys/queue.h> 34204076Spjd 35204076Spjd#include <assert.h> 36204076Spjd#include <errno.h> 37204076Spjd#include <stdint.h> 38204076Spjd 39204076Spjd#include "proto.h" 40204076Spjd#include "proto_impl.h" 41204076Spjd 42204076Spjd#define PROTO_CONN_MAGIC 0x907041c 43204076Spjdstruct proto_conn { 44204076Spjd int pc_magic; 45204076Spjd struct hast_proto *pc_proto; 46204076Spjd void *pc_ctx; 47204076Spjd int pc_side; 48204076Spjd#define PROTO_SIDE_CLIENT 0 49204076Spjd#define PROTO_SIDE_SERVER_LISTEN 1 50204076Spjd#define PROTO_SIDE_SERVER_WORK 2 51204076Spjd}; 52204076Spjd 53204076Spjdstatic LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos); 54204076Spjd 55204076Spjdvoid 56204076Spjdproto_register(struct hast_proto *proto) 57204076Spjd{ 58204076Spjd 59204076Spjd LIST_INSERT_HEAD(&protos, proto, hp_next); 60204076Spjd} 61204076Spjd 62204076Spjdstatic int 63204076Spjdproto_common_setup(const char *addr, struct proto_conn **connp, int side) 64204076Spjd{ 65204076Spjd struct hast_proto *proto; 66204076Spjd struct proto_conn *conn; 67204076Spjd void *ctx; 68204076Spjd int ret; 69204076Spjd 70204076Spjd assert(side == PROTO_SIDE_CLIENT || side == PROTO_SIDE_SERVER_LISTEN); 71204076Spjd 72204076Spjd conn = malloc(sizeof(*conn)); 73204076Spjd if (conn == NULL) 74204076Spjd return (-1); 75204076Spjd 76204076Spjd LIST_FOREACH(proto, &protos, hp_next) { 77204076Spjd if (side == PROTO_SIDE_CLIENT) 78204076Spjd ret = proto->hp_client(addr, &ctx); 79204076Spjd else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ 80204076Spjd ret = proto->hp_server(addr, &ctx); 81204076Spjd /* 82204076Spjd * ret == 0 - success 83204076Spjd * ret == -1 - addr is not for this protocol 84204076Spjd * ret > 0 - right protocol, but an error occured 85204076Spjd */ 86204076Spjd if (ret >= 0) 87204076Spjd break; 88204076Spjd } 89204076Spjd if (proto == NULL) { 90204076Spjd /* Unrecognized address. */ 91204076Spjd free(conn); 92204076Spjd errno = EINVAL; 93204076Spjd return (-1); 94204076Spjd } 95204076Spjd if (ret > 0) { 96204076Spjd /* An error occured. */ 97204076Spjd free(conn); 98204076Spjd errno = ret; 99204076Spjd return (-1); 100204076Spjd } 101204076Spjd conn->pc_proto = proto; 102204076Spjd conn->pc_ctx = ctx; 103204076Spjd conn->pc_side = side; 104204076Spjd conn->pc_magic = PROTO_CONN_MAGIC; 105204076Spjd *connp = conn; 106204076Spjd return (0); 107204076Spjd} 108204076Spjd 109204076Spjdint 110204076Spjdproto_client(const char *addr, struct proto_conn **connp) 111204076Spjd{ 112204076Spjd 113204076Spjd return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT)); 114204076Spjd} 115204076Spjd 116204076Spjdint 117204076Spjdproto_connect(struct proto_conn *conn) 118204076Spjd{ 119204076Spjd int ret; 120204076Spjd 121204076Spjd assert(conn != NULL); 122204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 123204076Spjd assert(conn->pc_side == PROTO_SIDE_CLIENT); 124204076Spjd assert(conn->pc_proto != NULL); 125204076Spjd 126204076Spjd ret = conn->pc_proto->hp_connect(conn->pc_ctx); 127204076Spjd if (ret != 0) { 128204076Spjd errno = ret; 129204076Spjd return (-1); 130204076Spjd } 131204076Spjd 132204076Spjd return (0); 133204076Spjd} 134204076Spjd 135204076Spjdint 136204076Spjdproto_server(const char *addr, struct proto_conn **connp) 137204076Spjd{ 138204076Spjd 139204076Spjd return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN)); 140204076Spjd} 141204076Spjd 142204076Spjdint 143204076Spjdproto_accept(struct proto_conn *conn, struct proto_conn **newconnp) 144204076Spjd{ 145204076Spjd struct proto_conn *newconn; 146204076Spjd int ret; 147204076Spjd 148204076Spjd assert(conn != NULL); 149204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 150204076Spjd assert(conn->pc_side == PROTO_SIDE_SERVER_LISTEN); 151204076Spjd assert(conn->pc_proto != NULL); 152204076Spjd 153204076Spjd newconn = malloc(sizeof(*newconn)); 154204076Spjd if (newconn == NULL) 155204076Spjd return (-1); 156204076Spjd 157204076Spjd ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx); 158204076Spjd if (ret != 0) { 159204076Spjd free(newconn); 160204076Spjd errno = ret; 161204076Spjd return (-1); 162204076Spjd } 163204076Spjd 164204076Spjd newconn->pc_proto = conn->pc_proto; 165204076Spjd newconn->pc_side = PROTO_SIDE_SERVER_WORK; 166204076Spjd newconn->pc_magic = PROTO_CONN_MAGIC; 167204076Spjd *newconnp = newconn; 168204076Spjd 169204076Spjd return (0); 170204076Spjd} 171204076Spjd 172204076Spjdint 173204076Spjdproto_send(struct proto_conn *conn, const void *data, size_t size) 174204076Spjd{ 175204076Spjd int ret; 176204076Spjd 177204076Spjd assert(conn != NULL); 178204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 179204076Spjd assert(conn->pc_proto != NULL); 180204076Spjd 181204076Spjd ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size); 182204076Spjd if (ret != 0) { 183204076Spjd errno = ret; 184204076Spjd return (-1); 185204076Spjd } 186204076Spjd return (0); 187204076Spjd} 188204076Spjd 189204076Spjdint 190204076Spjdproto_recv(struct proto_conn *conn, void *data, size_t size) 191204076Spjd{ 192204076Spjd int ret; 193204076Spjd 194204076Spjd assert(conn != NULL); 195204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 196204076Spjd assert(conn->pc_proto != NULL); 197204076Spjd 198204076Spjd ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size); 199204076Spjd if (ret != 0) { 200204076Spjd errno = ret; 201204076Spjd return (-1); 202204076Spjd } 203204076Spjd return (0); 204204076Spjd} 205204076Spjd 206204076Spjdint 207204076Spjdproto_descriptor(const struct proto_conn *conn) 208204076Spjd{ 209204076Spjd 210204076Spjd assert(conn != NULL); 211204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 212204076Spjd assert(conn->pc_proto != NULL); 213204076Spjd 214204076Spjd return (conn->pc_proto->hp_descriptor(conn->pc_ctx)); 215204076Spjd} 216204076Spjd 217204076Spjdbool 218204076Spjdproto_address_match(const struct proto_conn *conn, const char *addr) 219204076Spjd{ 220204076Spjd 221204076Spjd assert(conn != NULL); 222204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 223204076Spjd assert(conn->pc_proto != NULL); 224204076Spjd 225204076Spjd return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr)); 226204076Spjd} 227204076Spjd 228204076Spjdvoid 229204076Spjdproto_local_address(const struct proto_conn *conn, char *addr, size_t size) 230204076Spjd{ 231204076Spjd 232204076Spjd assert(conn != NULL); 233204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 234204076Spjd assert(conn->pc_proto != NULL); 235204076Spjd 236204076Spjd conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size); 237204076Spjd} 238204076Spjd 239204076Spjdvoid 240204076Spjdproto_remote_address(const struct proto_conn *conn, char *addr, size_t size) 241204076Spjd{ 242204076Spjd 243204076Spjd assert(conn != NULL); 244204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 245204076Spjd assert(conn->pc_proto != NULL); 246204076Spjd 247204076Spjd conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size); 248204076Spjd} 249204076Spjd 250204076Spjdvoid 251204076Spjdproto_close(struct proto_conn *conn) 252204076Spjd{ 253204076Spjd 254204076Spjd assert(conn != NULL); 255204076Spjd assert(conn->pc_magic == PROTO_CONN_MAGIC); 256204076Spjd assert(conn->pc_proto != NULL); 257204076Spjd 258204076Spjd conn->pc_proto->hp_close(conn->pc_ctx); 259204076Spjd conn->pc_magic = 0; 260204076Spjd free(conn); 261204076Spjd} 262