proto.c revision 204076
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2009-2010 The FreeBSD Foundation
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * This software was developed by Pawel Jakub Dawidek under sponsorship from
61590Srgrimes * the FreeBSD Foundation.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#include <sys/cdefs.h>
311590Srgrimes__FBSDID("$FreeBSD: head/sbin/hastd/proto.c 204076 2010-02-18 23:16:19Z pjd $");
321590Srgrimes
331590Srgrimes#include <sys/queue.h>
341590Srgrimes
3527919Scharnier#include <assert.h>
361590Srgrimes#include <errno.h>
371590Srgrimes#include <stdint.h>
381590Srgrimes
391590Srgrimes#include "proto.h"
401590Srgrimes#include "proto_impl.h"
4129922Smarkm
4227919Scharnier#define	PROTO_CONN_MAGIC	0x907041c
4350477Speterstruct proto_conn {
441590Srgrimes	int			 pc_magic;
451590Srgrimes	struct hast_proto	*pc_proto;
461590Srgrimes	void			*pc_ctx;
471590Srgrimes	int			 pc_side;
481590Srgrimes#define	PROTO_SIDE_CLIENT		0
491590Srgrimes#define	PROTO_SIDE_SERVER_LISTEN	1
501590Srgrimes#define	PROTO_SIDE_SERVER_WORK		2
511590Srgrimes};
521590Srgrimes
531590Srgrimesstatic LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos);
541590Srgrimes
551590Srgrimesvoid
561590Srgrimesproto_register(struct hast_proto *proto)
571590Srgrimes{
588232Sdg
591590Srgrimes	LIST_INSERT_HEAD(&protos, proto, hp_next);
6027919Scharnier}
611590Srgrimes
621590Srgrimesstatic int
6340103Smarkmproto_common_setup(const char *addr, struct proto_conn **connp, int side)
641590Srgrimes{
651590Srgrimes	struct hast_proto *proto;
661590Srgrimes	struct proto_conn *conn;
671590Srgrimes	void *ctx;
681590Srgrimes	int ret;
691590Srgrimes
701590Srgrimes	assert(side == PROTO_SIDE_CLIENT || side == PROTO_SIDE_SERVER_LISTEN);
711590Srgrimes
721590Srgrimes	conn = malloc(sizeof(*conn));
7329922Smarkm	if (conn == NULL)
741590Srgrimes		return (-1);
751590Srgrimes
7657450Smarkm	LIST_FOREACH(proto, &protos, hp_next) {
7729922Smarkm		if (side == PROTO_SIDE_CLIENT)
781590Srgrimes			ret = proto->hp_client(addr, &ctx);
7934897Smarkm		else /* if (side == PROTO_SIDE_SERVER_LISTEN) */
801590Srgrimes			ret = proto->hp_server(addr, &ctx);
811590Srgrimes		/*
821590Srgrimes		 * ret == 0  - success
831590Srgrimes		 * ret == -1 - addr is not for this protocol
841590Srgrimes		 * ret > 0   - right protocol, but an error occured
851590Srgrimes		 */
861590Srgrimes		if (ret >= 0)
871590Srgrimes			break;
881590Srgrimes	}
891590Srgrimes	if (proto == NULL) {
901590Srgrimes		/* Unrecognized address. */
911590Srgrimes		free(conn);
921590Srgrimes		errno = EINVAL;
931590Srgrimes		return (-1);
941590Srgrimes	}
951590Srgrimes	if (ret > 0) {
961590Srgrimes		/* An error occured. */
971590Srgrimes		free(conn);
9857232Sshin		errno = ret;
991590Srgrimes		return (-1);
1001590Srgrimes	}
1011590Srgrimes	conn->pc_proto = proto;
1021590Srgrimes	conn->pc_ctx = ctx;
1031590Srgrimes	conn->pc_side = side;
1041590Srgrimes	conn->pc_magic = PROTO_CONN_MAGIC;
1059881Sache	*connp = conn;
10617284Spst	return (0);
1071590Srgrimes}
1081590Srgrimes
1091590Srgrimesint
1101590Srgrimesproto_client(const char *addr, struct proto_conn **connp)
1111590Srgrimes{
1121590Srgrimes
1131590Srgrimes	return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT));
1141590Srgrimes}
1151590Srgrimes
1161590Srgrimesint
1171590Srgrimesproto_connect(struct proto_conn *conn)
1181590Srgrimes{
11992921Simp	int ret;
12092921Simp
12192921Simp	assert(conn != NULL);
12292921Simp	assert(conn->pc_magic == PROTO_CONN_MAGIC);
12392921Simp	assert(conn->pc_side == PROTO_SIDE_CLIENT);
12492921Simp	assert(conn->pc_proto != NULL);
12592921Simp
12692921Simp	ret = conn->pc_proto->hp_connect(conn->pc_ctx);
12792921Simp	if (ret != 0) {
12892921Simp		errno = ret;
12992921Simp		return (-1);
13092921Simp	}
13192921Simp
13292921Simp	return (0);
13392921Simp}
13492921Simp
13592921Simpint
13692921Simpproto_server(const char *addr, struct proto_conn **connp)
1371590Srgrimes{
1381590Srgrimes
13992921Simp	return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN));
1401590Srgrimes}
1411590Srgrimes
1421590Srgrimesint
1431590Srgrimesproto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
1441590Srgrimes{
1451590Srgrimes	struct proto_conn *newconn;
1461590Srgrimes	int ret;
1471590Srgrimes
1481590Srgrimes	assert(conn != NULL);
1491590Srgrimes	assert(conn->pc_magic == PROTO_CONN_MAGIC);
1501590Srgrimes	assert(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
1518232Sdg	assert(conn->pc_proto != NULL);
15247549Sbde
15340103Smarkm	newconn = malloc(sizeof(*newconn));
15440103Smarkm	if (newconn == NULL)
15540103Smarkm		return (-1);
15656590Sshin
15756590Sshin	ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx);
1581590Srgrimes	if (ret != 0) {
1598232Sdg		free(newconn);
1601590Srgrimes		errno = ret;
16147549Sbde		return (-1);
1621590Srgrimes	}
16329922Smarkm
1641590Srgrimes	newconn->pc_proto = conn->pc_proto;
1651590Srgrimes	newconn->pc_side = PROTO_SIDE_SERVER_WORK;
1661590Srgrimes	newconn->pc_magic = PROTO_CONN_MAGIC;
1671590Srgrimes	*newconnp = newconn;
1681590Srgrimes
1691590Srgrimes	return (0);
1701590Srgrimes}
1711590Srgrimes
1721590Srgrimesint
1731590Srgrimesproto_send(struct proto_conn *conn, const void *data, size_t size)
1741590Srgrimes{
1751590Srgrimes	int ret;
1761590Srgrimes
1771590Srgrimes	assert(conn != NULL);
17857232Sshin	assert(conn->pc_magic == PROTO_CONN_MAGIC);
1791590Srgrimes	assert(conn->pc_proto != NULL);
18057232Sshin
1811590Srgrimes	ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size);
18224360Simp	if (ret != 0) {
1831590Srgrimes		errno = ret;
18457232Sshin		return (-1);
18557232Sshin	}
18657232Sshin	return (0);
18757232Sshin}
18857232Sshin
18957232Sshinint
19057232Sshinproto_recv(struct proto_conn *conn, void *data, size_t size)
19157232Sshin{
1921590Srgrimes	int ret;
1931590Srgrimes
1941590Srgrimes	assert(conn != NULL);
1958232Sdg	assert(conn->pc_magic == PROTO_CONN_MAGIC);
1968232Sdg	assert(conn->pc_proto != NULL);
1978232Sdg
1981590Srgrimes	ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size);
1991590Srgrimes	if (ret != 0) {
2001590Srgrimes		errno = ret;
2011590Srgrimes		return (-1);
2021590Srgrimes	}
2031590Srgrimes	return (0);
2041590Srgrimes}
2051590Srgrimes
2061590Srgrimesint
2071590Srgrimesproto_descriptor(const struct proto_conn *conn)
2081590Srgrimes{
2091590Srgrimes
2101590Srgrimes	assert(conn != NULL);
2111590Srgrimes	assert(conn->pc_magic == PROTO_CONN_MAGIC);
2121590Srgrimes	assert(conn->pc_proto != NULL);
2131590Srgrimes
2141590Srgrimes	return (conn->pc_proto->hp_descriptor(conn->pc_ctx));
2151590Srgrimes}
21647488Speter
21747549Sbdebool
21847549Sbdeproto_address_match(const struct proto_conn *conn, const char *addr)
21947488Speter{
22047488Speter
2211590Srgrimes	assert(conn != NULL);
2221590Srgrimes	assert(conn->pc_magic == PROTO_CONN_MAGIC);
2231590Srgrimes	assert(conn->pc_proto != NULL);
2241590Srgrimes
2251590Srgrimes	return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr));
2261590Srgrimes}
2271590Srgrimes
2281590Srgrimesvoid
2291590Srgrimesproto_local_address(const struct proto_conn *conn, char *addr, size_t size)
2301590Srgrimes{
2311590Srgrimes
2321590Srgrimes	assert(conn != NULL);
2331590Srgrimes	assert(conn->pc_magic == PROTO_CONN_MAGIC);
2341590Srgrimes	assert(conn->pc_proto != NULL);
2351590Srgrimes
2361590Srgrimes	conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size);
2371590Srgrimes}
2381590Srgrimes
2391590Srgrimesvoid
2401590Srgrimesproto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
2411590Srgrimes{
2421590Srgrimes
2431590Srgrimes	assert(conn != NULL);
24434897Smarkm	assert(conn->pc_magic == PROTO_CONN_MAGIC);
2451590Srgrimes	assert(conn->pc_proto != NULL);
2461590Srgrimes
24734897Smarkm	conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size);
2481590Srgrimes}
2491590Srgrimes
25027919Scharniervoid
25127919Scharnierproto_close(struct proto_conn *conn)
2521590Srgrimes{
2531590Srgrimes
25447488Speter	assert(conn != NULL);
25547488Speter	assert(conn->pc_magic == PROTO_CONN_MAGIC);
2561590Srgrimes	assert(conn->pc_proto != NULL);
2571590Srgrimes
2581590Srgrimes	conn->pc_proto->hp_close(conn->pc_ctx);
25940103Smarkm	conn->pc_magic = 0;
26040103Smarkm	free(conn);
26140103Smarkm}
2621590Srgrimes