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