Deleted Added
full compact
proto.c (204076) proto.c (207371)
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>
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: head/sbin/hastd/proto.c 204076 2010-02-18 23:16:19Z pjd $");
31__FBSDID("$FreeBSD: head/sbin/hastd/proto.c 207371 2010-04-29 15:36:32Z pjd $");
32
32
33#include <sys/types.h>
33#include <sys/queue.h>
34#include <sys/queue.h>
35#include <sys/socket.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
43struct 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
53static LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos);
54
55void
56proto_register(struct hast_proto *proto)
57{
58
59 LIST_INSERT_HEAD(&protos, proto, hp_next);
60}
61
62static int
63proto_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
109int
110proto_client(const char *addr, struct proto_conn **connp)
111{
112
113 return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT));
114}
115
116int
117proto_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
135int
136proto_server(const char *addr, struct proto_conn **connp)
137{
138
139 return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN));
140}
141
142int
143proto_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
172int
173proto_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
189int
190proto_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
206int
207proto_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
217bool
218proto_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
228void
229proto_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
239void
240proto_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
36
37#include <assert.h>
38#include <errno.h>
39#include <stdint.h>
40
41#include "proto.h"
42#include "proto_impl.h"
43
44#define PROTO_CONN_MAGIC 0x907041c
45struct proto_conn {
46 int pc_magic;
47 struct hast_proto *pc_proto;
48 void *pc_ctx;
49 int pc_side;
50#define PROTO_SIDE_CLIENT 0
51#define PROTO_SIDE_SERVER_LISTEN 1
52#define PROTO_SIDE_SERVER_WORK 2
53};
54
55static LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos);
56
57void
58proto_register(struct hast_proto *proto)
59{
60
61 LIST_INSERT_HEAD(&protos, proto, hp_next);
62}
63
64static int
65proto_common_setup(const char *addr, struct proto_conn **connp, int side)
66{
67 struct hast_proto *proto;
68 struct proto_conn *conn;
69 void *ctx;
70 int ret;
71
72 assert(side == PROTO_SIDE_CLIENT || side == PROTO_SIDE_SERVER_LISTEN);
73
74 conn = malloc(sizeof(*conn));
75 if (conn == NULL)
76 return (-1);
77
78 LIST_FOREACH(proto, &protos, hp_next) {
79 if (side == PROTO_SIDE_CLIENT)
80 ret = proto->hp_client(addr, &ctx);
81 else /* if (side == PROTO_SIDE_SERVER_LISTEN) */
82 ret = proto->hp_server(addr, &ctx);
83 /*
84 * ret == 0 - success
85 * ret == -1 - addr is not for this protocol
86 * ret > 0 - right protocol, but an error occured
87 */
88 if (ret >= 0)
89 break;
90 }
91 if (proto == NULL) {
92 /* Unrecognized address. */
93 free(conn);
94 errno = EINVAL;
95 return (-1);
96 }
97 if (ret > 0) {
98 /* An error occured. */
99 free(conn);
100 errno = ret;
101 return (-1);
102 }
103 conn->pc_proto = proto;
104 conn->pc_ctx = ctx;
105 conn->pc_side = side;
106 conn->pc_magic = PROTO_CONN_MAGIC;
107 *connp = conn;
108 return (0);
109}
110
111int
112proto_client(const char *addr, struct proto_conn **connp)
113{
114
115 return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT));
116}
117
118int
119proto_connect(struct proto_conn *conn)
120{
121 int ret;
122
123 assert(conn != NULL);
124 assert(conn->pc_magic == PROTO_CONN_MAGIC);
125 assert(conn->pc_side == PROTO_SIDE_CLIENT);
126 assert(conn->pc_proto != NULL);
127
128 ret = conn->pc_proto->hp_connect(conn->pc_ctx);
129 if (ret != 0) {
130 errno = ret;
131 return (-1);
132 }
133
134 return (0);
135}
136
137int
138proto_server(const char *addr, struct proto_conn **connp)
139{
140
141 return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN));
142}
143
144int
145proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
146{
147 struct proto_conn *newconn;
148 int ret;
149
150 assert(conn != NULL);
151 assert(conn->pc_magic == PROTO_CONN_MAGIC);
152 assert(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
153 assert(conn->pc_proto != NULL);
154
155 newconn = malloc(sizeof(*newconn));
156 if (newconn == NULL)
157 return (-1);
158
159 ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx);
160 if (ret != 0) {
161 free(newconn);
162 errno = ret;
163 return (-1);
164 }
165
166 newconn->pc_proto = conn->pc_proto;
167 newconn->pc_side = PROTO_SIDE_SERVER_WORK;
168 newconn->pc_magic = PROTO_CONN_MAGIC;
169 *newconnp = newconn;
170
171 return (0);
172}
173
174int
175proto_send(struct proto_conn *conn, const void *data, size_t size)
176{
177 int ret;
178
179 assert(conn != NULL);
180 assert(conn->pc_magic == PROTO_CONN_MAGIC);
181 assert(conn->pc_proto != NULL);
182
183 ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size);
184 if (ret != 0) {
185 errno = ret;
186 return (-1);
187 }
188 return (0);
189}
190
191int
192proto_recv(struct proto_conn *conn, void *data, size_t size)
193{
194 int ret;
195
196 assert(conn != NULL);
197 assert(conn->pc_magic == PROTO_CONN_MAGIC);
198 assert(conn->pc_proto != NULL);
199
200 ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size);
201 if (ret != 0) {
202 errno = ret;
203 return (-1);
204 }
205 return (0);
206}
207
208int
209proto_descriptor(const struct proto_conn *conn)
210{
211
212 assert(conn != NULL);
213 assert(conn->pc_magic == PROTO_CONN_MAGIC);
214 assert(conn->pc_proto != NULL);
215
216 return (conn->pc_proto->hp_descriptor(conn->pc_ctx));
217}
218
219bool
220proto_address_match(const struct proto_conn *conn, const char *addr)
221{
222
223 assert(conn != NULL);
224 assert(conn->pc_magic == PROTO_CONN_MAGIC);
225 assert(conn->pc_proto != NULL);
226
227 return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr));
228}
229
230void
231proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
232{
233
234 assert(conn != NULL);
235 assert(conn->pc_magic == PROTO_CONN_MAGIC);
236 assert(conn->pc_proto != NULL);
237
238 conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size);
239}
240
241void
242proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
243{
244
245 assert(conn != NULL);
246 assert(conn->pc_magic == PROTO_CONN_MAGIC);
247 assert(conn->pc_proto != NULL);
248
249 conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size);
250}
251
252int
253proto_timeout(const struct proto_conn *conn, int timeout)
254{
255 struct timeval tv;
256 int fd;
257
258 assert(conn != NULL);
259 assert(conn->pc_magic == PROTO_CONN_MAGIC);
260 assert(conn->pc_proto != NULL);
261
262 fd = proto_descriptor(conn);
263 if (fd < 0)
264 return (-1);
265
266 tv.tv_sec = timeout;
267 tv.tv_usec = 0;
268 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
269 return (-1);
270 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
271 return (-1);
272
273 return (0);
274}
275
250void
251proto_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}
276void
277proto_close(struct proto_conn *conn)
278{
279
280 assert(conn != NULL);
281 assert(conn->pc_magic == PROTO_CONN_MAGIC);
282 assert(conn->pc_proto != NULL);
283
284 conn->pc_proto->hp_close(conn->pc_ctx);
285 conn->pc_magic = 0;
286 free(conn);
287}