proto.c revision 218191
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 218191 2011-02-02 15:23:07Z pjd $");
32204076Spjd
33207371Spjd#include <sys/types.h>
34204076Spjd#include <sys/queue.h>
35207371Spjd#include <sys/socket.h>
36204076Spjd
37204076Spjd#include <errno.h>
38204076Spjd#include <stdint.h>
39218191Spjd#include <strings.h>
40204076Spjd
41218138Spjd#include "pjdlog.h"
42204076Spjd#include "proto.h"
43204076Spjd#include "proto_impl.h"
44204076Spjd
45204076Spjd#define	PROTO_CONN_MAGIC	0x907041c
46204076Spjdstruct proto_conn {
47204076Spjd	int			 pc_magic;
48204076Spjd	struct hast_proto	*pc_proto;
49204076Spjd	void			*pc_ctx;
50204076Spjd	int			 pc_side;
51204076Spjd#define	PROTO_SIDE_CLIENT		0
52204076Spjd#define	PROTO_SIDE_SERVER_LISTEN	1
53204076Spjd#define	PROTO_SIDE_SERVER_WORK		2
54204076Spjd};
55204076Spjd
56210869Spjdstatic TAILQ_HEAD(, hast_proto) protos = TAILQ_HEAD_INITIALIZER(protos);
57204076Spjd
58204076Spjdvoid
59210869Spjdproto_register(struct hast_proto *proto, bool isdefault)
60204076Spjd{
61210869Spjd	static bool seen_default = false;
62204076Spjd
63210869Spjd	if (!isdefault)
64210869Spjd		TAILQ_INSERT_HEAD(&protos, proto, hp_next);
65210869Spjd	else {
66218138Spjd		PJDLOG_ASSERT(!seen_default);
67210869Spjd		seen_default = true;
68210869Spjd		TAILQ_INSERT_TAIL(&protos, proto, hp_next);
69210869Spjd	}
70204076Spjd}
71204076Spjd
72218191Spjdstatic struct proto_conn *
73218191Spjdproto_alloc(struct hast_proto *proto, int side)
74218191Spjd{
75218191Spjd	struct proto_conn *conn;
76218191Spjd
77218191Spjd	PJDLOG_ASSERT(proto != NULL);
78218191Spjd	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
79218191Spjd	    side == PROTO_SIDE_SERVER_LISTEN ||
80218191Spjd	    side == PROTO_SIDE_SERVER_WORK);
81218191Spjd
82218191Spjd	conn = malloc(sizeof(*conn));
83218191Spjd	if (conn != NULL) {
84218191Spjd		conn->pc_proto = proto;
85218191Spjd		conn->pc_side = side;
86218191Spjd		conn->pc_magic = PROTO_CONN_MAGIC;
87218191Spjd	}
88218191Spjd	return (conn);
89218191Spjd}
90218191Spjd
91218191Spjdstatic void
92218191Spjdproto_free(struct proto_conn *conn)
93218191Spjd{
94218191Spjd
95218191Spjd	PJDLOG_ASSERT(conn != NULL);
96218191Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
97218191Spjd	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
98218191Spjd	    conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
99218191Spjd	    conn->pc_side == PROTO_SIDE_SERVER_WORK);
100218191Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
101218191Spjd
102218191Spjd	bzero(conn, sizeof(*conn));
103218191Spjd	free(conn);
104218191Spjd}
105218191Spjd
106204076Spjdstatic int
107204076Spjdproto_common_setup(const char *addr, struct proto_conn **connp, int side)
108204076Spjd{
109204076Spjd	struct hast_proto *proto;
110204076Spjd	struct proto_conn *conn;
111204076Spjd	void *ctx;
112204076Spjd	int ret;
113204076Spjd
114218191Spjd	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
115218191Spjd	    side == PROTO_SIDE_SERVER_LISTEN);
116204076Spjd
117210869Spjd	TAILQ_FOREACH(proto, &protos, hp_next) {
118218185Spjd		if (side == PROTO_SIDE_CLIENT) {
119218185Spjd			if (proto->hp_client == NULL)
120218185Spjd				ret = -1;
121218185Spjd			else
122218185Spjd				ret = proto->hp_client(addr, &ctx);
123218185Spjd		} else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
124218185Spjd			if (proto->hp_server == NULL)
125218185Spjd				ret = -1;
126218185Spjd			else
127218185Spjd				ret = proto->hp_server(addr, &ctx);
128218185Spjd		}
129204076Spjd		/*
130204076Spjd		 * ret == 0  - success
131204076Spjd		 * ret == -1 - addr is not for this protocol
132204076Spjd		 * ret > 0   - right protocol, but an error occured
133204076Spjd		 */
134204076Spjd		if (ret >= 0)
135204076Spjd			break;
136204076Spjd	}
137204076Spjd	if (proto == NULL) {
138204076Spjd		/* Unrecognized address. */
139204076Spjd		errno = EINVAL;
140204076Spjd		return (-1);
141204076Spjd	}
142204076Spjd	if (ret > 0) {
143204076Spjd		/* An error occured. */
144204076Spjd		errno = ret;
145204076Spjd		return (-1);
146204076Spjd	}
147218191Spjd	conn = proto_alloc(proto, side);
148218191Spjd	if (conn == NULL) {
149218191Spjd		if (proto->hp_close != NULL)
150218191Spjd			proto->hp_close(ctx);
151218191Spjd		errno = ENOMEM;
152218191Spjd		return (-1);
153218191Spjd	}
154204076Spjd	conn->pc_ctx = ctx;
155204076Spjd	*connp = conn;
156218191Spjd
157204076Spjd	return (0);
158204076Spjd}
159204076Spjd
160204076Spjdint
161204076Spjdproto_client(const char *addr, struct proto_conn **connp)
162204076Spjd{
163204076Spjd
164204076Spjd	return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT));
165204076Spjd}
166204076Spjd
167204076Spjdint
168204076Spjdproto_connect(struct proto_conn *conn)
169204076Spjd{
170204076Spjd	int ret;
171204076Spjd
172218138Spjd	PJDLOG_ASSERT(conn != NULL);
173218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
174218138Spjd	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
175218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
176218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_connect != NULL);
177204076Spjd
178204076Spjd	ret = conn->pc_proto->hp_connect(conn->pc_ctx);
179204076Spjd	if (ret != 0) {
180204076Spjd		errno = ret;
181204076Spjd		return (-1);
182204076Spjd	}
183204076Spjd
184204076Spjd	return (0);
185204076Spjd}
186204076Spjd
187204076Spjdint
188204076Spjdproto_server(const char *addr, struct proto_conn **connp)
189204076Spjd{
190204076Spjd
191204076Spjd	return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN));
192204076Spjd}
193204076Spjd
194204076Spjdint
195204076Spjdproto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
196204076Spjd{
197204076Spjd	struct proto_conn *newconn;
198204076Spjd	int ret;
199204076Spjd
200218138Spjd	PJDLOG_ASSERT(conn != NULL);
201218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
202218138Spjd	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
203218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
204218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_accept != NULL);
205204076Spjd
206218191Spjd	newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
207204076Spjd	if (newconn == NULL)
208204076Spjd		return (-1);
209204076Spjd
210204076Spjd	ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx);
211204076Spjd	if (ret != 0) {
212218191Spjd		proto_free(newconn);
213204076Spjd		errno = ret;
214204076Spjd		return (-1);
215204076Spjd	}
216204076Spjd
217204076Spjd	*newconnp = newconn;
218204076Spjd
219204076Spjd	return (0);
220204076Spjd}
221204076Spjd
222204076Spjdint
223212033Spjdproto_send(const struct proto_conn *conn, const void *data, size_t size)
224204076Spjd{
225204076Spjd	int ret;
226204076Spjd
227218138Spjd	PJDLOG_ASSERT(conn != NULL);
228218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
229218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
230218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_send != NULL);
231204076Spjd
232204076Spjd	ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size);
233204076Spjd	if (ret != 0) {
234204076Spjd		errno = ret;
235204076Spjd		return (-1);
236204076Spjd	}
237204076Spjd	return (0);
238204076Spjd}
239204076Spjd
240204076Spjdint
241212033Spjdproto_recv(const struct proto_conn *conn, void *data, size_t size)
242204076Spjd{
243204076Spjd	int ret;
244204076Spjd
245218138Spjd	PJDLOG_ASSERT(conn != NULL);
246218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
247218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
248218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_recv != NULL);
249204076Spjd
250204076Spjd	ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size);
251204076Spjd	if (ret != 0) {
252204076Spjd		errno = ret;
253204076Spjd		return (-1);
254204076Spjd	}
255204076Spjd	return (0);
256204076Spjd}
257204076Spjd
258204076Spjdint
259218139Spjdproto_descriptor_send(const struct proto_conn *conn, int fd)
260218139Spjd{
261218139Spjd	int ret;
262218139Spjd
263218139Spjd	PJDLOG_ASSERT(conn != NULL);
264218139Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
265218139Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
266218139Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_send != NULL);
267218139Spjd
268218139Spjd	ret = conn->pc_proto->hp_descriptor_send(conn->pc_ctx, fd);
269218139Spjd	if (ret != 0) {
270218139Spjd		errno = ret;
271218139Spjd		return (-1);
272218139Spjd	}
273218139Spjd	return (0);
274218139Spjd}
275218139Spjd
276218139Spjdint
277218139Spjdproto_descriptor_recv(const struct proto_conn *conn, int *fdp)
278218139Spjd{
279218139Spjd	int ret;
280218139Spjd
281218139Spjd	PJDLOG_ASSERT(conn != NULL);
282218139Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
283218139Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
284218139Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_descriptor_recv != NULL);
285218139Spjd
286218139Spjd	ret = conn->pc_proto->hp_descriptor_recv(conn->pc_ctx, fdp);
287218139Spjd	if (ret != 0) {
288218139Spjd		errno = ret;
289218139Spjd		return (-1);
290218139Spjd	}
291218139Spjd	return (0);
292218139Spjd}
293218139Spjd
294218139Spjdint
295204076Spjdproto_descriptor(const struct proto_conn *conn)
296204076Spjd{
297204076Spjd
298218138Spjd	PJDLOG_ASSERT(conn != NULL);
299218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
300218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
301218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_descriptor != NULL);
302204076Spjd
303204076Spjd	return (conn->pc_proto->hp_descriptor(conn->pc_ctx));
304204076Spjd}
305204076Spjd
306204076Spjdbool
307204076Spjdproto_address_match(const struct proto_conn *conn, const char *addr)
308204076Spjd{
309204076Spjd
310218138Spjd	PJDLOG_ASSERT(conn != NULL);
311218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
312218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
313218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_address_match != NULL);
314204076Spjd
315204076Spjd	return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr));
316204076Spjd}
317204076Spjd
318204076Spjdvoid
319204076Spjdproto_local_address(const struct proto_conn *conn, char *addr, size_t size)
320204076Spjd{
321204076Spjd
322218138Spjd	PJDLOG_ASSERT(conn != NULL);
323218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
324218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
325218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_local_address != NULL);
326204076Spjd
327204076Spjd	conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size);
328204076Spjd}
329204076Spjd
330204076Spjdvoid
331204076Spjdproto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
332204076Spjd{
333204076Spjd
334218138Spjd	PJDLOG_ASSERT(conn != NULL);
335218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
336218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
337218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_remote_address != NULL);
338204076Spjd
339204076Spjd	conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size);
340204076Spjd}
341204076Spjd
342207371Spjdint
343207371Spjdproto_timeout(const struct proto_conn *conn, int timeout)
344207371Spjd{
345207371Spjd	struct timeval tv;
346207371Spjd	int fd;
347207371Spjd
348218138Spjd	PJDLOG_ASSERT(conn != NULL);
349218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
350218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
351207371Spjd
352207371Spjd	fd = proto_descriptor(conn);
353207371Spjd	if (fd < 0)
354207371Spjd		return (-1);
355207371Spjd
356207371Spjd	tv.tv_sec = timeout;
357207371Spjd	tv.tv_usec = 0;
358207371Spjd	if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
359207371Spjd		return (-1);
360207371Spjd	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
361207371Spjd		return (-1);
362207371Spjd
363207371Spjd	return (0);
364207371Spjd}
365207371Spjd
366204076Spjdvoid
367204076Spjdproto_close(struct proto_conn *conn)
368204076Spjd{
369204076Spjd
370218138Spjd	PJDLOG_ASSERT(conn != NULL);
371218138Spjd	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
372218138Spjd	PJDLOG_ASSERT(conn->pc_proto != NULL);
373218138Spjd	PJDLOG_ASSERT(conn->pc_proto->hp_close != NULL);
374204076Spjd
375204076Spjd	conn->pc_proto->hp_close(conn->pc_ctx);
376218191Spjd	proto_free(conn);
377204076Spjd}
378