proto.c revision 218192
180709Sjake/*- 280709Sjake * Copyright (c) 2009-2010 The FreeBSD Foundation 380709Sjake * All rights reserved. 480709Sjake * 580709Sjake * This software was developed by Pawel Jakub Dawidek under sponsorship from 680709Sjake * the FreeBSD Foundation. 780709Sjake * 880709Sjake * Redistribution and use in source and binary forms, with or without 980709Sjake * modification, are permitted provided that the following conditions 1080709Sjake * are met: 1180709Sjake * 1. Redistributions of source code must retain the above copyright 1280709Sjake * notice, this list of conditions and the following disclaimer. 1380709Sjake * 2. Redistributions in binary form must reproduce the above copyright 1481337Sobrien * notice, this list of conditions and the following disclaimer in the 1580709Sjake * documentation and/or other materials provided with the distribution. 1680709Sjake * 1781337Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1880709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1980709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2080709Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2180709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2280709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2380709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2480709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2580709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2680709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2780709Sjake * SUCH DAMAGE. 2880709Sjake */ 2980709Sjake 3080709Sjake#include <sys/cdefs.h> 3180709Sjake__FBSDID("$FreeBSD: head/sbin/hastd/proto.c 218192 2011-02-02 15:42:00Z pjd $"); 3280709Sjake 3382910Sjake#include <sys/types.h> 3480709Sjake#include <sys/queue.h> 3580709Sjake#include <sys/socket.h> 3686527Sjake 3791613Sjake#include <errno.h> 3891613Sjake#include <stdint.h> 3980709Sjake#include <strings.h> 4091176Sjake 4184186Sjake#include "pjdlog.h" 4280709Sjake#include "proto.h" 4380709Sjake#include "proto_impl.h" 4481381Sjake 4581381Sjake#define PROTO_CONN_MAGIC 0x907041c 4681381Sjakestruct proto_conn { 4781381Sjake int pc_magic; 4888657Sjake struct hast_proto *pc_proto; 4980709Sjake void *pc_ctx; 5080709Sjake int pc_side; 5180709Sjake#define PROTO_SIDE_CLIENT 0 5280709Sjake#define PROTO_SIDE_SERVER_LISTEN 1 5381135Stmm#define PROTO_SIDE_SERVER_WORK 2 5480709Sjake}; 5586527Sjake 5681614Sjakestatic TAILQ_HEAD(, hast_proto) protos = TAILQ_HEAD_INITIALIZER(protos); 5788657Sjake 5880709Sjakevoid 5980709Sjakeproto_register(struct hast_proto *proto, bool isdefault) 6080709Sjake{ 6182910Sjake static bool seen_default = false; 6289052Sjake 6380709Sjake if (!isdefault) 6480709Sjake TAILQ_INSERT_HEAD(&protos, proto, hp_next); 6580709Sjake else { 6680709Sjake PJDLOG_ASSERT(!seen_default); 6782010Sjake seen_default = true; 6888788Sjake TAILQ_INSERT_TAIL(&protos, proto, hp_next); 6980709Sjake } 7083756Sjake} 7183756Sjake 7280709Sjakestatic struct proto_conn * 7380709Sjakeproto_alloc(struct hast_proto *proto, int side) 7480709Sjake{ 7583366Sjulian struct proto_conn *conn; 7684186Sjake 7791360Sjake PJDLOG_ASSERT(proto != NULL); 7883366Sjulian PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT || 7980709Sjake side == PROTO_SIDE_SERVER_LISTEN || 8080709Sjake side == PROTO_SIDE_SERVER_WORK); 8182910Sjake 8280709Sjake conn = malloc(sizeof(*conn)); 8381135Stmm if (conn != NULL) { 8481135Stmm conn->pc_proto = proto; 8581135Stmm conn->pc_side = side; 8681135Stmm conn->pc_magic = PROTO_CONN_MAGIC; 8788657Sjake } 8888657Sjake return (conn); 8991224Sjake} 9091224Sjake 9181381Sjakestatic void 9289052Sjakeproto_free(struct proto_conn *conn) 9389052Sjake{ 9488657Sjake 9581381Sjake PJDLOG_ASSERT(conn != NULL); 9689052Sjake PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 9789052Sjake PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT || 9889052Sjake conn->pc_side == PROTO_SIDE_SERVER_LISTEN || 9988657Sjake conn->pc_side == PROTO_SIDE_SERVER_WORK); 10088657Sjake PJDLOG_ASSERT(conn->pc_proto != NULL); 10191224Sjake 10280709Sjake bzero(conn, sizeof(*conn)); 10391336Sjake free(conn); 10491336Sjake} 10591336Sjake 10680709Sjakestatic int 10780709Sjakeproto_common_setup(const char *addr, struct proto_conn **connp, int side) 10880709Sjake{ 10989052Sjake struct hast_proto *proto; 11089052Sjake struct proto_conn *conn; 11189052Sjake void *ctx; 11289052Sjake int ret; 11389052Sjake 11489052Sjake PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT || 11589052Sjake side == PROTO_SIDE_SERVER_LISTEN); 11689052Sjake 11785244Sjake TAILQ_FOREACH(proto, &protos, hp_next) { 11884186Sjake if (side == PROTO_SIDE_CLIENT) { 11989052Sjake if (proto->hp_client == NULL) 12084186Sjake ret = -1; 12184186Sjake else 12282910Sjake ret = proto->hp_client(addr, &ctx); 12385244Sjake } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ { 12485244Sjake if (proto->hp_server == NULL) 12585244Sjake ret = -1; 12691532Sjake else 12791532Sjake ret = proto->hp_server(addr, &ctx); 12891532Sjake } 12991532Sjake /* 13082910Sjake * ret == 0 - success 13182910Sjake * ret == -1 - addr is not for this protocol 13282910Sjake * ret > 0 - right protocol, but an error occured 13382910Sjake */ 13482910Sjake if (ret >= 0) 13582910Sjake break; 13682910Sjake } 13782910Sjake if (proto == NULL) { 13888657Sjake /* Unrecognized address. */ 13982910Sjake errno = EINVAL; 14091224Sjake return (-1); 14180709Sjake } 14281381Sjake if (ret > 0) { 14380709Sjake /* An error occured. */ 14481614Sjake errno = ret; 14580709Sjake return (-1); 14688657Sjake } 14788657Sjake conn = proto_alloc(proto, side); 14880709Sjake if (conn == NULL) { 14980709Sjake if (proto->hp_close != NULL) 15084186Sjake proto->hp_close(ctx); 15184186Sjake errno = ENOMEM; 15287702Sjhb return (-1); 15387702Sjhb } 15487702Sjhb conn->pc_ctx = ctx; 15591337Sjake *connp = conn; 15689052Sjake 15789052Sjake return (0); 15891613Sjake} 15991613Sjake 16091613Sjakeint 16189052Sjakeproto_client(const char *addr, struct proto_conn **connp) 16280709Sjake{ 16384186Sjake 16484186Sjake return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT)); 16581614Sjake} 16681614Sjake 16781614Sjakeint 16881614Sjakeproto_connect(struct proto_conn *conn, int timeout) 16981614Sjake{ 17081614Sjake int ret; 17181614Sjake 17281614Sjake PJDLOG_ASSERT(conn != NULL); 17381614Sjake PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 17481614Sjake PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT); 17581614Sjake PJDLOG_ASSERT(conn->pc_proto != NULL); 17689052Sjake PJDLOG_ASSERT(conn->pc_proto->hp_connect != NULL); 17789052Sjake PJDLOG_ASSERT(timeout >= 0); 17889052Sjake 17989052Sjake ret = conn->pc_proto->hp_connect(conn->pc_ctx, timeout); 18089052Sjake if (ret != 0) { 18189052Sjake errno = ret; 18289052Sjake return (-1); 18389052Sjake } 18481614Sjake 18581614Sjake return (0); 18681614Sjake} 18781614Sjake 18881614Sjakeint 18985244Sjakeproto_server(const char *addr, struct proto_conn **connp) 19085244Sjake{ 19183366Sjulian 19283366Sjulian return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN)); 19382910Sjake} 19488788Sjake 19588788Sjakeint 19691613Sjakeproto_accept(struct proto_conn *conn, struct proto_conn **newconnp) 19791613Sjake{ 19882910Sjake struct proto_conn *newconn; 19988657Sjake int ret; 20088657Sjake 20182910Sjake PJDLOG_ASSERT(conn != NULL); 20280709Sjake PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 20380709Sjake PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN); 20488657Sjake PJDLOG_ASSERT(conn->pc_proto != NULL); 20588657Sjake PJDLOG_ASSERT(conn->pc_proto->hp_accept != NULL); 20683366Sjulian 20783366Sjulian newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK); 20883366Sjulian if (newconn == NULL) 20983366Sjulian return (-1); 21083366Sjulian 21183366Sjulian ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx); 21283366Sjulian if (ret != 0) { 21383366Sjulian proto_free(newconn); 21484186Sjake errno = ret; 21581135Stmm return (-1); 21680709Sjake } 21780709Sjake 21882010Sjake *newconnp = newconn; 21980709Sjake 22082910Sjake return (0); 22182910Sjake} 22282910Sjake 22380709Sjakeint 22481381Sjakeproto_send(const struct proto_conn *conn, const void *data, size_t size) 22588657Sjake{ 22681381Sjake int ret; 22788657Sjake 22881381Sjake PJDLOG_ASSERT(conn != NULL); 22981135Stmm PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 23081135Stmm PJDLOG_ASSERT(conn->pc_proto != NULL); 23181135Stmm PJDLOG_ASSERT(conn->pc_proto->hp_send != NULL); 23281135Stmm 23381135Stmm ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size); 23480709Sjake if (ret != 0) { 23580709Sjake errno = ret; 23680709Sjake return (-1); 23782910Sjake } 23882010Sjake return (0); 23988657Sjake} 24088657Sjake 24188657Sjakeint 24288657Sjakeproto_recv(const struct proto_conn *conn, void *data, size_t size) 24388657Sjake{ 24480709Sjake int ret; 24580709Sjake 24680709Sjake PJDLOG_ASSERT(conn != NULL); 24780709Sjake PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 24880709Sjake PJDLOG_ASSERT(conn->pc_proto != NULL); 24980709Sjake PJDLOG_ASSERT(conn->pc_proto->hp_recv != NULL); 25080709Sjake 25180709Sjake ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size); 25280709Sjake if (ret != 0) { 25380709Sjake errno = ret; 25480709Sjake return (-1); 25580709Sjake } 25680709Sjake return (0); 25780709Sjake} 25880709Sjake 25980709Sjakeint 26080709Sjakeproto_descriptor_send(const struct proto_conn *conn, int fd) 26188657Sjake{ 26288657Sjake int ret; 26388657Sjake 26488657Sjake PJDLOG_ASSERT(conn != NULL); 26588657Sjake PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 26688657Sjake PJDLOG_ASSERT(conn->pc_proto != NULL); 26780709Sjake PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_send != NULL); 26888657Sjake 26980709Sjake ret = conn->pc_proto->hp_descriptor_send(conn->pc_ctx, fd); 27088657Sjake if (ret != 0) { 27188657Sjake errno = ret; 27288657Sjake return (-1); 27382910Sjake } 27480709Sjake return (0); 27588788Sjake} 27688788Sjake 277int 278proto_descriptor_recv(const struct proto_conn *conn, int *fdp) 279{ 280 int ret; 281 282 PJDLOG_ASSERT(conn != NULL); 283 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 284 PJDLOG_ASSERT(conn->pc_proto != NULL); 285 PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_recv != NULL); 286 287 ret = conn->pc_proto->hp_descriptor_recv(conn->pc_ctx, fdp); 288 if (ret != 0) { 289 errno = ret; 290 return (-1); 291 } 292 return (0); 293} 294 295int 296proto_descriptor(const struct proto_conn *conn) 297{ 298 299 PJDLOG_ASSERT(conn != NULL); 300 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 301 PJDLOG_ASSERT(conn->pc_proto != NULL); 302 PJDLOG_ASSERT(conn->pc_proto->hp_descriptor != NULL); 303 304 return (conn->pc_proto->hp_descriptor(conn->pc_ctx)); 305} 306 307bool 308proto_address_match(const struct proto_conn *conn, const char *addr) 309{ 310 311 PJDLOG_ASSERT(conn != NULL); 312 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 313 PJDLOG_ASSERT(conn->pc_proto != NULL); 314 PJDLOG_ASSERT(conn->pc_proto->hp_address_match != NULL); 315 316 return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr)); 317} 318 319void 320proto_local_address(const struct proto_conn *conn, char *addr, size_t size) 321{ 322 323 PJDLOG_ASSERT(conn != NULL); 324 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 325 PJDLOG_ASSERT(conn->pc_proto != NULL); 326 PJDLOG_ASSERT(conn->pc_proto->hp_local_address != NULL); 327 328 conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size); 329} 330 331void 332proto_remote_address(const struct proto_conn *conn, char *addr, size_t size) 333{ 334 335 PJDLOG_ASSERT(conn != NULL); 336 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 337 PJDLOG_ASSERT(conn->pc_proto != NULL); 338 PJDLOG_ASSERT(conn->pc_proto->hp_remote_address != NULL); 339 340 conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size); 341} 342 343int 344proto_timeout(const struct proto_conn *conn, int timeout) 345{ 346 struct timeval tv; 347 int fd; 348 349 PJDLOG_ASSERT(conn != NULL); 350 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 351 PJDLOG_ASSERT(conn->pc_proto != NULL); 352 353 fd = proto_descriptor(conn); 354 if (fd < 0) 355 return (-1); 356 357 tv.tv_sec = timeout; 358 tv.tv_usec = 0; 359 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) 360 return (-1); 361 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) 362 return (-1); 363 364 return (0); 365} 366 367void 368proto_close(struct proto_conn *conn) 369{ 370 371 PJDLOG_ASSERT(conn != NULL); 372 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC); 373 PJDLOG_ASSERT(conn->pc_proto != NULL); 374 PJDLOG_ASSERT(conn->pc_proto->hp_close != NULL); 375 376 conn->pc_proto->hp_close(conn->pc_ctx); 377 proto_free(conn); 378} 379