1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/queue.h> 34 35 #include <assert.h> 36 #include <errno.h> 37 #include <stdint.h> 38 39 #include "proto.h" 40 #include "proto_impl.h" 41 42 #define PROTO_CONN_MAGIC 0x907041c 43 struct proto_conn { 44 int pc_magic; 45 struct hast_proto *pc_proto; 46 void *pc_ctx; 47 int pc_side; 48 #define PROTO_SIDE_CLIENT 0 49 #define PROTO_SIDE_SERVER_LISTEN 1 50 #define PROTO_SIDE_SERVER_WORK 2 51 }; 52 53 static LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos); 54 55 void 56 proto_register(struct hast_proto *proto) 57 { 58 59 LIST_INSERT_HEAD(&protos, proto, hp_next); 60 } 61 62 static int 63 proto_common_setup(const char *addr, struct proto_conn **connp, int side) 64 { 65 struct hast_proto *proto; 66 struct proto_conn *conn; 67 void *ctx; 68 int ret; 69 70 assert(side == PROTO_SIDE_CLIENT || side == PROTO_SIDE_SERVER_LISTEN); 71 72 conn = malloc(sizeof(*conn)); 73 if (conn == NULL) 74 return (-1); 75 76 LIST_FOREACH(proto, &protos, hp_next) { 77 if (side == PROTO_SIDE_CLIENT) 78 ret = proto->hp_client(addr, &ctx); 79 else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ 80 ret = proto->hp_server(addr, &ctx); 81 /* 82 * ret == 0 - success 83 * ret == -1 - addr is not for this protocol 84 * ret > 0 - right protocol, but an error occured 85 */ 86 if (ret >= 0) 87 break; 88 } 89 if (proto == NULL) { 90 /* Unrecognized address. */ 91 free(conn); 92 errno = EINVAL; 93 return (-1); 94 } 95 if (ret > 0) { 96 /* An error occured. */ 97 free(conn); 98 errno = ret; 99 return (-1); 100 } 101 conn->pc_proto = proto; 102 conn->pc_ctx = ctx; 103 conn->pc_side = side; 104 conn->pc_magic = PROTO_CONN_MAGIC; 105 *connp = conn; 106 return (0); 107 } 108 109 int 110 proto_client(const char *addr, struct proto_conn **connp) 111 { 112 113 return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT)); 114 } 115 116 int 117 proto_connect(struct proto_conn *conn) 118 { 119 int ret; 120 121 assert(conn != NULL); 122 assert(conn->pc_magic == PROTO_CONN_MAGIC); 123 assert(conn->pc_side == PROTO_SIDE_CLIENT); 124 assert(conn->pc_proto != NULL); 125 126 ret = conn->pc_proto->hp_connect(conn->pc_ctx); 127 if (ret != 0) { 128 errno = ret; 129 return (-1); 130 } 131 132 return (0); 133 } 134 135 int 136 proto_server(const char *addr, struct proto_conn **connp) 137 { 138 139 return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN)); 140 } 141 142 int 143 proto_accept(struct proto_conn *conn, struct proto_conn **newconnp) 144 { 145 struct proto_conn *newconn; 146 int ret; 147 148 assert(conn != NULL); 149 assert(conn->pc_magic == PROTO_CONN_MAGIC); 150 assert(conn->pc_side == PROTO_SIDE_SERVER_LISTEN); 151 assert(conn->pc_proto != NULL); 152 153 newconn = malloc(sizeof(*newconn)); 154 if (newconn == NULL) 155 return (-1); 156 157 ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx); 158 if (ret != 0) { 159 free(newconn); 160 errno = ret; 161 return (-1); 162 } 163 164 newconn->pc_proto = conn->pc_proto; 165 newconn->pc_side = PROTO_SIDE_SERVER_WORK; 166 newconn->pc_magic = PROTO_CONN_MAGIC; 167 *newconnp = newconn; 168 169 return (0); 170 } 171 172 int 173 proto_send(struct proto_conn *conn, const void *data, size_t size) 174 { 175 int ret; 176 177 assert(conn != NULL); 178 assert(conn->pc_magic == PROTO_CONN_MAGIC); 179 assert(conn->pc_proto != NULL); 180 181 ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size); 182 if (ret != 0) { 183 errno = ret; 184 return (-1); 185 } 186 return (0); 187 } 188 189 int 190 proto_recv(struct proto_conn *conn, void *data, size_t size) 191 { 192 int ret; 193 194 assert(conn != NULL); 195 assert(conn->pc_magic == PROTO_CONN_MAGIC); 196 assert(conn->pc_proto != NULL); 197 198 ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size); 199 if (ret != 0) { 200 errno = ret; 201 return (-1); 202 } 203 return (0); 204 } 205 206 int 207 proto_descriptor(const struct proto_conn *conn) 208 { 209 210 assert(conn != NULL); 211 assert(conn->pc_magic == PROTO_CONN_MAGIC); 212 assert(conn->pc_proto != NULL); 213 214 return (conn->pc_proto->hp_descriptor(conn->pc_ctx)); 215 } 216 217 bool 218 proto_address_match(const struct proto_conn *conn, const char *addr) 219 { 220 221 assert(conn != NULL); 222 assert(conn->pc_magic == PROTO_CONN_MAGIC); 223 assert(conn->pc_proto != NULL); 224 225 return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr)); 226 } 227 228 void 229 proto_local_address(const struct proto_conn *conn, char *addr, size_t size) 230 { 231 232 assert(conn != NULL); 233 assert(conn->pc_magic == PROTO_CONN_MAGIC); 234 assert(conn->pc_proto != NULL); 235 236 conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size); 237 } 238 239 void 240 proto_remote_address(const struct proto_conn *conn, char *addr, size_t size) 241 { 242 243 assert(conn != NULL); 244 assert(conn->pc_magic == PROTO_CONN_MAGIC); 245 assert(conn->pc_proto != NULL); 246 247 conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size); 248 } 249 250 void 251 proto_close(struct proto_conn *conn) 252 { 253 254 assert(conn != NULL); 255 assert(conn->pc_magic == PROTO_CONN_MAGIC); 256 assert(conn->pc_proto != NULL); 257 258 conn->pc_proto->hp_close(conn->pc_ctx); 259 conn->pc_magic = 0; 260 free(conn); 261 } 262