2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/types.h>
31 #include <sys/queue.h>
32 #include <sys/socket.h>
41 #include "proto_impl.h"
43 #define PROTO_CONN_MAGIC 0x907041c
46 struct proto *pc_proto;
49 #define PROTO_SIDE_CLIENT 0
50 #define PROTO_SIDE_SERVER_LISTEN 1
51 #define PROTO_SIDE_SERVER_WORK 2
54 static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
57 proto_register(struct proto *proto, bool isdefault)
59 static bool seen_default = false;
62 TAILQ_INSERT_HEAD(&protos, proto, prt_next);
64 PJDLOG_ASSERT(!seen_default);
66 TAILQ_INSERT_TAIL(&protos, proto, prt_next);
70 static struct proto_conn *
71 proto_alloc(struct proto *proto, int side)
73 struct proto_conn *conn;
75 PJDLOG_ASSERT(proto != NULL);
76 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
77 side == PROTO_SIDE_SERVER_LISTEN ||
78 side == PROTO_SIDE_SERVER_WORK);
80 conn = malloc(sizeof(*conn));
82 conn->pc_proto = proto;
84 conn->pc_magic = PROTO_CONN_MAGIC;
90 proto_free(struct proto_conn *conn)
93 PJDLOG_ASSERT(conn != NULL);
94 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
95 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
96 conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
97 conn->pc_side == PROTO_SIDE_SERVER_WORK);
98 PJDLOG_ASSERT(conn->pc_proto != NULL);
100 bzero(conn, sizeof(*conn));
105 proto_common_setup(const char *srcaddr, const char *dstaddr, int timeout,
106 int side, struct proto_conn **connp)
109 struct proto_conn *conn;
113 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
114 side == PROTO_SIDE_SERVER_LISTEN);
116 TAILQ_FOREACH(proto, &protos, prt_next) {
117 if (side == PROTO_SIDE_CLIENT) {
118 if (proto->prt_connect == NULL) {
121 ret = proto->prt_connect(srcaddr, dstaddr,
124 } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
125 if (proto->prt_server == NULL)
128 ret = proto->prt_server(dstaddr, &ctx);
132 * ret == -1 - dstaddr is not for this protocol
133 * ret > 0 - right protocol, but an error occured
139 /* Unrecognized address. */
144 /* An error occured. */
148 conn = proto_alloc(proto, side);
150 if (proto->prt_close != NULL)
151 proto->prt_close(ctx);
162 proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
163 struct proto_conn **connp)
166 PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
167 PJDLOG_ASSERT(dstaddr != NULL);
168 PJDLOG_ASSERT(timeout >= -1);
170 return (proto_common_setup(srcaddr, dstaddr, timeout,
171 PROTO_SIDE_CLIENT, connp));
175 proto_connect_wait(struct proto_conn *conn, int timeout)
179 PJDLOG_ASSERT(conn != NULL);
180 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
181 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
182 PJDLOG_ASSERT(conn->pc_proto != NULL);
183 PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
184 PJDLOG_ASSERT(timeout >= 0);
186 error = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
196 proto_server(const char *addr, struct proto_conn **connp)
199 PJDLOG_ASSERT(addr != NULL);
201 return (proto_common_setup(NULL, addr, -1, PROTO_SIDE_SERVER_LISTEN,
206 proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
208 struct proto_conn *newconn;
211 PJDLOG_ASSERT(conn != NULL);
212 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
213 PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
214 PJDLOG_ASSERT(conn->pc_proto != NULL);
215 PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
217 newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
221 error = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
234 proto_send(const struct proto_conn *conn, const void *data, size_t size)
238 PJDLOG_ASSERT(conn != NULL);
239 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
240 PJDLOG_ASSERT(conn->pc_proto != NULL);
241 PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
243 error = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
252 proto_recv(const struct proto_conn *conn, void *data, size_t size)
256 PJDLOG_ASSERT(conn != NULL);
257 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
258 PJDLOG_ASSERT(conn->pc_proto != NULL);
259 PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
261 error = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
270 proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
272 const char *protoname;
275 PJDLOG_ASSERT(conn != NULL);
276 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
277 PJDLOG_ASSERT(conn->pc_proto != NULL);
278 PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
279 PJDLOG_ASSERT(mconn != NULL);
280 PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
281 PJDLOG_ASSERT(mconn->pc_proto != NULL);
282 fd = proto_descriptor(mconn);
283 PJDLOG_ASSERT(fd >= 0);
284 protoname = mconn->pc_proto->prt_name;
285 PJDLOG_ASSERT(protoname != NULL);
287 error = conn->pc_proto->prt_send(conn->pc_ctx,
288 (const unsigned char *)protoname, strlen(protoname) + 1, fd);
298 proto_wrap(const char *protoname, bool client, int fd,
299 struct proto_conn **newconnp)
302 struct proto_conn *newconn;
305 TAILQ_FOREACH(proto, &protos, prt_next) {
306 if (strcmp(proto->prt_name, protoname) == 0)
314 newconn = proto_alloc(proto,
315 client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
318 PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
319 error = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
332 proto_connection_recv(const struct proto_conn *conn, bool client,
333 struct proto_conn **newconnp)
338 PJDLOG_ASSERT(conn != NULL);
339 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
340 PJDLOG_ASSERT(conn->pc_proto != NULL);
341 PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
342 PJDLOG_ASSERT(newconnp != NULL);
344 bzero(protoname, sizeof(protoname));
346 error = conn->pc_proto->prt_recv(conn->pc_ctx,
347 (unsigned char *)protoname, sizeof(protoname) - 1, &fd);
353 PJDLOG_ASSERT(fd >= 0);
355 return (proto_wrap(protoname, client, fd, newconnp));
359 proto_descriptor(const struct proto_conn *conn)
362 PJDLOG_ASSERT(conn != NULL);
363 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
364 PJDLOG_ASSERT(conn->pc_proto != NULL);
365 PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
367 return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
371 proto_address_match(const struct proto_conn *conn, const char *addr)
374 PJDLOG_ASSERT(conn != NULL);
375 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
376 PJDLOG_ASSERT(conn->pc_proto != NULL);
377 PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
379 return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
383 proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
386 PJDLOG_ASSERT(conn != NULL);
387 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
388 PJDLOG_ASSERT(conn->pc_proto != NULL);
389 PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
391 conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
395 proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
398 PJDLOG_ASSERT(conn != NULL);
399 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
400 PJDLOG_ASSERT(conn->pc_proto != NULL);
401 PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
403 conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
407 proto_timeout(const struct proto_conn *conn, int timeout)
412 PJDLOG_ASSERT(conn != NULL);
413 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
414 PJDLOG_ASSERT(conn->pc_proto != NULL);
416 fd = proto_descriptor(conn);
422 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
424 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
431 proto_close(struct proto_conn *conn)
434 PJDLOG_ASSERT(conn != NULL);
435 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
436 PJDLOG_ASSERT(conn->pc_proto != NULL);
437 PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
439 conn->pc_proto->prt_close(conn->pc_ctx);
444 proto_exec(int argc, char *argv[])
453 TAILQ_FOREACH(proto, &protos, prt_next) {
454 if (strcmp(proto->prt_name, argv[0]) == 0)
461 if (proto->prt_exec == NULL) {
465 error = proto->prt_exec(argc, argv);
474 struct proto_nvpair {
477 TAILQ_ENTRY(proto_nvpair) pnv_next;
480 static TAILQ_HEAD(, proto_nvpair) proto_nvpairs =
481 TAILQ_HEAD_INITIALIZER(proto_nvpairs);
484 proto_set(const char *name, const char *value)
486 struct proto_nvpair *pnv;
488 TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
489 if (strcmp(pnv->pnv_name, name) == 0)
493 TAILQ_REMOVE(&proto_nvpairs, pnv, pnv_next);
494 free(pnv->pnv_value);
496 pnv = malloc(sizeof(*pnv));
499 pnv->pnv_name = strdup(name);
500 if (pnv->pnv_name == NULL) {
505 pnv->pnv_value = strdup(value);
506 if (pnv->pnv_value == NULL) {
511 TAILQ_INSERT_TAIL(&proto_nvpairs, pnv, pnv_next);
516 proto_get(const char *name)
518 struct proto_nvpair *pnv;
520 TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
521 if (strcmp(pnv->pnv_name, name) == 0)
525 return (pnv->pnv_value);