2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/types.h>
36 #include <sys/queue.h>
37 #include <sys/socket.h>
46 #include "proto_impl.h"
48 #define PROTO_CONN_MAGIC 0x907041c
51 struct proto *pc_proto;
54 #define PROTO_SIDE_CLIENT 0
55 #define PROTO_SIDE_SERVER_LISTEN 1
56 #define PROTO_SIDE_SERVER_WORK 2
59 static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
62 proto_register(struct proto *proto, bool isdefault)
64 static bool seen_default = false;
67 TAILQ_INSERT_HEAD(&protos, proto, prt_next);
69 PJDLOG_ASSERT(!seen_default);
71 TAILQ_INSERT_TAIL(&protos, proto, prt_next);
75 static struct proto_conn *
76 proto_alloc(struct proto *proto, int side)
78 struct proto_conn *conn;
80 PJDLOG_ASSERT(proto != NULL);
81 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
82 side == PROTO_SIDE_SERVER_LISTEN ||
83 side == PROTO_SIDE_SERVER_WORK);
85 conn = malloc(sizeof(*conn));
87 conn->pc_proto = proto;
89 conn->pc_magic = PROTO_CONN_MAGIC;
95 proto_free(struct proto_conn *conn)
98 PJDLOG_ASSERT(conn != NULL);
99 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
100 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
101 conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
102 conn->pc_side == PROTO_SIDE_SERVER_WORK);
103 PJDLOG_ASSERT(conn->pc_proto != NULL);
105 bzero(conn, sizeof(*conn));
110 proto_common_setup(const char *srcaddr, const char *dstaddr,
111 struct proto_conn **connp, int side)
114 struct proto_conn *conn;
118 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
119 side == PROTO_SIDE_SERVER_LISTEN);
121 TAILQ_FOREACH(proto, &protos, prt_next) {
122 if (side == PROTO_SIDE_CLIENT) {
123 if (proto->prt_client == NULL)
126 ret = proto->prt_client(srcaddr, dstaddr, &ctx);
127 } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
128 if (proto->prt_server == NULL)
131 ret = proto->prt_server(dstaddr, &ctx);
135 * ret == -1 - dstaddr is not for this protocol
136 * ret > 0 - right protocol, but an error occurred
142 /* Unrecognized address. */
147 /* An error occurred. */
151 conn = proto_alloc(proto, side);
153 if (proto->prt_close != NULL)
154 proto->prt_close(ctx);
165 proto_client(const char *srcaddr, const char *dstaddr,
166 struct proto_conn **connp)
169 return (proto_common_setup(srcaddr, dstaddr, connp, PROTO_SIDE_CLIENT));
173 proto_connect(struct proto_conn *conn, int timeout)
177 PJDLOG_ASSERT(conn != NULL);
178 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
179 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
180 PJDLOG_ASSERT(conn->pc_proto != NULL);
181 PJDLOG_ASSERT(conn->pc_proto->prt_connect != NULL);
182 PJDLOG_ASSERT(timeout >= -1);
184 ret = conn->pc_proto->prt_connect(conn->pc_ctx, timeout);
194 proto_connect_wait(struct proto_conn *conn, int timeout)
198 PJDLOG_ASSERT(conn != NULL);
199 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
200 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
201 PJDLOG_ASSERT(conn->pc_proto != NULL);
202 PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
203 PJDLOG_ASSERT(timeout >= 0);
205 ret = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
215 proto_server(const char *addr, struct proto_conn **connp)
218 return (proto_common_setup(NULL, addr, connp, PROTO_SIDE_SERVER_LISTEN));
222 proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
224 struct proto_conn *newconn;
227 PJDLOG_ASSERT(conn != NULL);
228 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
229 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
230 PJDLOG_ASSERT(conn->pc_proto != NULL);
231 PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
233 newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
237 ret = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
250 proto_send(const struct proto_conn *conn, const void *data, size_t size)
254 PJDLOG_ASSERT(conn != NULL);
255 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
256 PJDLOG_ASSERT(conn->pc_proto != NULL);
257 PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
259 ret = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
268 proto_recv(const struct proto_conn *conn, void *data, size_t size)
272 PJDLOG_ASSERT(conn != NULL);
273 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
274 PJDLOG_ASSERT(conn->pc_proto != NULL);
275 PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
277 ret = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
286 proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
288 const char *protoname;
291 PJDLOG_ASSERT(conn != NULL);
292 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
293 PJDLOG_ASSERT(conn->pc_proto != NULL);
294 PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
295 PJDLOG_ASSERT(mconn != NULL);
296 PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
297 PJDLOG_ASSERT(mconn->pc_proto != NULL);
298 fd = proto_descriptor(mconn);
299 PJDLOG_ASSERT(fd >= 0);
300 protoname = mconn->pc_proto->prt_name;
301 PJDLOG_ASSERT(protoname != NULL);
303 ret = conn->pc_proto->prt_send(conn->pc_ctx,
304 (const unsigned char *)protoname, strlen(protoname) + 1, fd);
314 proto_connection_recv(const struct proto_conn *conn, bool client,
315 struct proto_conn **newconnp)
319 struct proto_conn *newconn;
322 PJDLOG_ASSERT(conn != NULL);
323 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
324 PJDLOG_ASSERT(conn->pc_proto != NULL);
325 PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
326 PJDLOG_ASSERT(newconnp != NULL);
328 bzero(protoname, sizeof(protoname));
330 ret = conn->pc_proto->prt_recv(conn->pc_ctx, (unsigned char *)protoname,
331 sizeof(protoname) - 1, &fd);
337 PJDLOG_ASSERT(fd >= 0);
339 TAILQ_FOREACH(proto, &protos, prt_next) {
340 if (strcmp(proto->prt_name, protoname) == 0)
348 newconn = proto_alloc(proto,
349 client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
352 PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
353 ret = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
366 proto_descriptor(const struct proto_conn *conn)
369 PJDLOG_ASSERT(conn != NULL);
370 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
371 PJDLOG_ASSERT(conn->pc_proto != NULL);
372 PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
374 return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
378 proto_address_match(const struct proto_conn *conn, const char *addr)
381 PJDLOG_ASSERT(conn != NULL);
382 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
383 PJDLOG_ASSERT(conn->pc_proto != NULL);
384 PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
386 return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
390 proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
393 PJDLOG_ASSERT(conn != NULL);
394 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
395 PJDLOG_ASSERT(conn->pc_proto != NULL);
396 PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
398 conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
402 proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
405 PJDLOG_ASSERT(conn != NULL);
406 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
407 PJDLOG_ASSERT(conn->pc_proto != NULL);
408 PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
410 conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
414 proto_timeout(const struct proto_conn *conn, int timeout)
419 PJDLOG_ASSERT(conn != NULL);
420 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
421 PJDLOG_ASSERT(conn->pc_proto != NULL);
423 fd = proto_descriptor(conn);
429 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1)
431 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
438 proto_close(struct proto_conn *conn)
441 PJDLOG_ASSERT(conn != NULL);
442 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
443 PJDLOG_ASSERT(conn->pc_proto != NULL);
444 PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
446 conn->pc_proto->prt_close(conn->pc_ctx);