xref: /freebsd/sbin/hastd/proto.c (revision 4ed925457ab06e83238a5db33e89ccc94b99a713)
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