xref: /freebsd/contrib/openbsm/bin/auditdistd/proto.c (revision aa77200569e397d6ff1fdb4d255d0fa254d0a128)
1*aa772005SRobert Watson /*-
2*aa772005SRobert Watson  * Copyright (c) 2009-2010 The FreeBSD Foundation
3*aa772005SRobert Watson  * All rights reserved.
4*aa772005SRobert Watson  *
5*aa772005SRobert Watson  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6*aa772005SRobert Watson  * the FreeBSD Foundation.
7*aa772005SRobert Watson  *
8*aa772005SRobert Watson  * Redistribution and use in source and binary forms, with or without
9*aa772005SRobert Watson  * modification, are permitted provided that the following conditions
10*aa772005SRobert Watson  * are met:
11*aa772005SRobert Watson  * 1. Redistributions of source code must retain the above copyright
12*aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer.
13*aa772005SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
14*aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
15*aa772005SRobert Watson  *    documentation and/or other materials provided with the distribution.
16*aa772005SRobert Watson  *
17*aa772005SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18*aa772005SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*aa772005SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*aa772005SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21*aa772005SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*aa772005SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*aa772005SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*aa772005SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*aa772005SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*aa772005SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*aa772005SRobert Watson  * SUCH DAMAGE.
28*aa772005SRobert Watson  *
29*aa772005SRobert Watson  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto.c#1 $
30*aa772005SRobert Watson  */
31*aa772005SRobert Watson 
32*aa772005SRobert Watson #include <sys/types.h>
33*aa772005SRobert Watson #include <sys/queue.h>
34*aa772005SRobert Watson #include <sys/socket.h>
35*aa772005SRobert Watson 
36*aa772005SRobert Watson #include <errno.h>
37*aa772005SRobert Watson #include <stdint.h>
38*aa772005SRobert Watson #include <string.h>
39*aa772005SRobert Watson #include <strings.h>
40*aa772005SRobert Watson 
41*aa772005SRobert Watson #include "pjdlog.h"
42*aa772005SRobert Watson #include "proto.h"
43*aa772005SRobert Watson #include "proto_impl.h"
44*aa772005SRobert Watson 
45*aa772005SRobert Watson #define	PROTO_CONN_MAGIC	0x907041c
46*aa772005SRobert Watson struct proto_conn {
47*aa772005SRobert Watson 	int		 pc_magic;
48*aa772005SRobert Watson 	struct proto	*pc_proto;
49*aa772005SRobert Watson 	void		*pc_ctx;
50*aa772005SRobert Watson 	int		 pc_side;
51*aa772005SRobert Watson #define	PROTO_SIDE_CLIENT		0
52*aa772005SRobert Watson #define	PROTO_SIDE_SERVER_LISTEN	1
53*aa772005SRobert Watson #define	PROTO_SIDE_SERVER_WORK		2
54*aa772005SRobert Watson };
55*aa772005SRobert Watson 
56*aa772005SRobert Watson static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
57*aa772005SRobert Watson 
58*aa772005SRobert Watson void
59*aa772005SRobert Watson proto_register(struct proto *proto, bool isdefault)
60*aa772005SRobert Watson {
61*aa772005SRobert Watson 	static bool seen_default = false;
62*aa772005SRobert Watson 
63*aa772005SRobert Watson 	if (!isdefault)
64*aa772005SRobert Watson 		TAILQ_INSERT_HEAD(&protos, proto, prt_next);
65*aa772005SRobert Watson 	else {
66*aa772005SRobert Watson 		PJDLOG_ASSERT(!seen_default);
67*aa772005SRobert Watson 		seen_default = true;
68*aa772005SRobert Watson 		TAILQ_INSERT_TAIL(&protos, proto, prt_next);
69*aa772005SRobert Watson 	}
70*aa772005SRobert Watson }
71*aa772005SRobert Watson 
72*aa772005SRobert Watson static struct proto_conn *
73*aa772005SRobert Watson proto_alloc(struct proto *proto, int side)
74*aa772005SRobert Watson {
75*aa772005SRobert Watson 	struct proto_conn *conn;
76*aa772005SRobert Watson 
77*aa772005SRobert Watson 	PJDLOG_ASSERT(proto != NULL);
78*aa772005SRobert Watson 	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
79*aa772005SRobert Watson 	    side == PROTO_SIDE_SERVER_LISTEN ||
80*aa772005SRobert Watson 	    side == PROTO_SIDE_SERVER_WORK);
81*aa772005SRobert Watson 
82*aa772005SRobert Watson 	conn = malloc(sizeof(*conn));
83*aa772005SRobert Watson 	if (conn != NULL) {
84*aa772005SRobert Watson 		conn->pc_proto = proto;
85*aa772005SRobert Watson 		conn->pc_side = side;
86*aa772005SRobert Watson 		conn->pc_magic = PROTO_CONN_MAGIC;
87*aa772005SRobert Watson 	}
88*aa772005SRobert Watson 	return (conn);
89*aa772005SRobert Watson }
90*aa772005SRobert Watson 
91*aa772005SRobert Watson static void
92*aa772005SRobert Watson proto_free(struct proto_conn *conn)
93*aa772005SRobert Watson {
94*aa772005SRobert Watson 
95*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
96*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
97*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
98*aa772005SRobert Watson 	    conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
99*aa772005SRobert Watson 	    conn->pc_side == PROTO_SIDE_SERVER_WORK);
100*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
101*aa772005SRobert Watson 
102*aa772005SRobert Watson 	bzero(conn, sizeof(*conn));
103*aa772005SRobert Watson 	free(conn);
104*aa772005SRobert Watson }
105*aa772005SRobert Watson 
106*aa772005SRobert Watson static int
107*aa772005SRobert Watson proto_common_setup(const char *srcaddr, const char *dstaddr, int timeout,
108*aa772005SRobert Watson     int side, struct proto_conn **connp)
109*aa772005SRobert Watson {
110*aa772005SRobert Watson 	struct proto *proto;
111*aa772005SRobert Watson 	struct proto_conn *conn;
112*aa772005SRobert Watson 	void *ctx;
113*aa772005SRobert Watson 	int ret;
114*aa772005SRobert Watson 
115*aa772005SRobert Watson 	PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
116*aa772005SRobert Watson 	    side == PROTO_SIDE_SERVER_LISTEN);
117*aa772005SRobert Watson 
118*aa772005SRobert Watson 	TAILQ_FOREACH(proto, &protos, prt_next) {
119*aa772005SRobert Watson 		if (side == PROTO_SIDE_CLIENT) {
120*aa772005SRobert Watson 			if (proto->prt_connect == NULL) {
121*aa772005SRobert Watson 				ret = -1;
122*aa772005SRobert Watson 			} else {
123*aa772005SRobert Watson 				ret = proto->prt_connect(srcaddr, dstaddr,
124*aa772005SRobert Watson 				    timeout, &ctx);
125*aa772005SRobert Watson 			}
126*aa772005SRobert Watson 		} else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
127*aa772005SRobert Watson 			if (proto->prt_server == NULL)
128*aa772005SRobert Watson 				ret = -1;
129*aa772005SRobert Watson 			else
130*aa772005SRobert Watson 				ret = proto->prt_server(dstaddr, &ctx);
131*aa772005SRobert Watson 		}
132*aa772005SRobert Watson 		/*
133*aa772005SRobert Watson 		 * ret == 0  - success
134*aa772005SRobert Watson 		 * ret == -1 - dstaddr is not for this protocol
135*aa772005SRobert Watson 		 * ret > 0   - right protocol, but an error occured
136*aa772005SRobert Watson 		 */
137*aa772005SRobert Watson 		if (ret >= 0)
138*aa772005SRobert Watson 			break;
139*aa772005SRobert Watson 	}
140*aa772005SRobert Watson 	if (proto == NULL) {
141*aa772005SRobert Watson 		/* Unrecognized address. */
142*aa772005SRobert Watson 		errno = EINVAL;
143*aa772005SRobert Watson 		return (-1);
144*aa772005SRobert Watson 	}
145*aa772005SRobert Watson 	if (ret > 0) {
146*aa772005SRobert Watson 		/* An error occured. */
147*aa772005SRobert Watson 		errno = ret;
148*aa772005SRobert Watson 		return (-1);
149*aa772005SRobert Watson 	}
150*aa772005SRobert Watson 	conn = proto_alloc(proto, side);
151*aa772005SRobert Watson 	if (conn == NULL) {
152*aa772005SRobert Watson 		if (proto->prt_close != NULL)
153*aa772005SRobert Watson 			proto->prt_close(ctx);
154*aa772005SRobert Watson 		errno = ENOMEM;
155*aa772005SRobert Watson 		return (-1);
156*aa772005SRobert Watson 	}
157*aa772005SRobert Watson 	conn->pc_ctx = ctx;
158*aa772005SRobert Watson 	*connp = conn;
159*aa772005SRobert Watson 
160*aa772005SRobert Watson 	return (0);
161*aa772005SRobert Watson }
162*aa772005SRobert Watson 
163*aa772005SRobert Watson int
164*aa772005SRobert Watson proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
165*aa772005SRobert Watson     struct proto_conn **connp)
166*aa772005SRobert Watson {
167*aa772005SRobert Watson 
168*aa772005SRobert Watson 	PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
169*aa772005SRobert Watson 	PJDLOG_ASSERT(dstaddr != NULL);
170*aa772005SRobert Watson 	PJDLOG_ASSERT(timeout >= -1);
171*aa772005SRobert Watson 
172*aa772005SRobert Watson 	return (proto_common_setup(srcaddr, dstaddr, timeout,
173*aa772005SRobert Watson 	    PROTO_SIDE_CLIENT, connp));
174*aa772005SRobert Watson }
175*aa772005SRobert Watson 
176*aa772005SRobert Watson int
177*aa772005SRobert Watson proto_connect_wait(struct proto_conn *conn, int timeout)
178*aa772005SRobert Watson {
179*aa772005SRobert Watson 	int error;
180*aa772005SRobert Watson 
181*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
182*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
183*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
184*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
185*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
186*aa772005SRobert Watson 	PJDLOG_ASSERT(timeout >= 0);
187*aa772005SRobert Watson 
188*aa772005SRobert Watson 	error = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
189*aa772005SRobert Watson 	if (error != 0) {
190*aa772005SRobert Watson 		errno = error;
191*aa772005SRobert Watson 		return (-1);
192*aa772005SRobert Watson 	}
193*aa772005SRobert Watson 
194*aa772005SRobert Watson 	return (0);
195*aa772005SRobert Watson }
196*aa772005SRobert Watson 
197*aa772005SRobert Watson int
198*aa772005SRobert Watson proto_server(const char *addr, struct proto_conn **connp)
199*aa772005SRobert Watson {
200*aa772005SRobert Watson 
201*aa772005SRobert Watson 	PJDLOG_ASSERT(addr != NULL);
202*aa772005SRobert Watson 
203*aa772005SRobert Watson 	return (proto_common_setup(NULL, addr, -1, PROTO_SIDE_SERVER_LISTEN,
204*aa772005SRobert Watson 	    connp));
205*aa772005SRobert Watson }
206*aa772005SRobert Watson 
207*aa772005SRobert Watson int
208*aa772005SRobert Watson proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
209*aa772005SRobert Watson {
210*aa772005SRobert Watson 	struct proto_conn *newconn;
211*aa772005SRobert Watson 	int error;
212*aa772005SRobert Watson 
213*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
214*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
215*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
216*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
217*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
218*aa772005SRobert Watson 
219*aa772005SRobert Watson 	newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
220*aa772005SRobert Watson 	if (newconn == NULL)
221*aa772005SRobert Watson 		return (-1);
222*aa772005SRobert Watson 
223*aa772005SRobert Watson 	error = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
224*aa772005SRobert Watson 	if (error != 0) {
225*aa772005SRobert Watson 		proto_free(newconn);
226*aa772005SRobert Watson 		errno = error;
227*aa772005SRobert Watson 		return (-1);
228*aa772005SRobert Watson 	}
229*aa772005SRobert Watson 
230*aa772005SRobert Watson 	*newconnp = newconn;
231*aa772005SRobert Watson 
232*aa772005SRobert Watson 	return (0);
233*aa772005SRobert Watson }
234*aa772005SRobert Watson 
235*aa772005SRobert Watson int
236*aa772005SRobert Watson proto_send(const struct proto_conn *conn, const void *data, size_t size)
237*aa772005SRobert Watson {
238*aa772005SRobert Watson 	int error;
239*aa772005SRobert Watson 
240*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
241*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
242*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
243*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
244*aa772005SRobert Watson 
245*aa772005SRobert Watson 	error = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
246*aa772005SRobert Watson 	if (error != 0) {
247*aa772005SRobert Watson 		errno = error;
248*aa772005SRobert Watson 		return (-1);
249*aa772005SRobert Watson 	}
250*aa772005SRobert Watson 	return (0);
251*aa772005SRobert Watson }
252*aa772005SRobert Watson 
253*aa772005SRobert Watson int
254*aa772005SRobert Watson proto_recv(const struct proto_conn *conn, void *data, size_t size)
255*aa772005SRobert Watson {
256*aa772005SRobert Watson 	int error;
257*aa772005SRobert Watson 
258*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
259*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
260*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
261*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
262*aa772005SRobert Watson 
263*aa772005SRobert Watson 	error = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
264*aa772005SRobert Watson 	if (error != 0) {
265*aa772005SRobert Watson 		errno = error;
266*aa772005SRobert Watson 		return (-1);
267*aa772005SRobert Watson 	}
268*aa772005SRobert Watson 	return (0);
269*aa772005SRobert Watson }
270*aa772005SRobert Watson 
271*aa772005SRobert Watson int
272*aa772005SRobert Watson proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
273*aa772005SRobert Watson {
274*aa772005SRobert Watson 	const char *protoname;
275*aa772005SRobert Watson 	int error, fd;
276*aa772005SRobert Watson 
277*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
278*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
279*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
280*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
281*aa772005SRobert Watson 	PJDLOG_ASSERT(mconn != NULL);
282*aa772005SRobert Watson 	PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
283*aa772005SRobert Watson 	PJDLOG_ASSERT(mconn->pc_proto != NULL);
284*aa772005SRobert Watson 	fd = proto_descriptor(mconn);
285*aa772005SRobert Watson 	PJDLOG_ASSERT(fd >= 0);
286*aa772005SRobert Watson 	protoname = mconn->pc_proto->prt_name;
287*aa772005SRobert Watson 	PJDLOG_ASSERT(protoname != NULL);
288*aa772005SRobert Watson 
289*aa772005SRobert Watson 	error = conn->pc_proto->prt_send(conn->pc_ctx,
290*aa772005SRobert Watson 	    (const unsigned char *)protoname, strlen(protoname) + 1, fd);
291*aa772005SRobert Watson 	proto_close(mconn);
292*aa772005SRobert Watson 	if (error != 0) {
293*aa772005SRobert Watson 		errno = error;
294*aa772005SRobert Watson 		return (-1);
295*aa772005SRobert Watson 	}
296*aa772005SRobert Watson 	return (0);
297*aa772005SRobert Watson }
298*aa772005SRobert Watson 
299*aa772005SRobert Watson int
300*aa772005SRobert Watson proto_wrap(const char *protoname, bool client, int fd,
301*aa772005SRobert Watson     struct proto_conn **newconnp)
302*aa772005SRobert Watson {
303*aa772005SRobert Watson 	struct proto *proto;
304*aa772005SRobert Watson 	struct proto_conn *newconn;
305*aa772005SRobert Watson 	int error;
306*aa772005SRobert Watson 
307*aa772005SRobert Watson 	TAILQ_FOREACH(proto, &protos, prt_next) {
308*aa772005SRobert Watson 		if (strcmp(proto->prt_name, protoname) == 0)
309*aa772005SRobert Watson 			break;
310*aa772005SRobert Watson 	}
311*aa772005SRobert Watson 	if (proto == NULL) {
312*aa772005SRobert Watson 		errno = EINVAL;
313*aa772005SRobert Watson 		return (-1);
314*aa772005SRobert Watson 	}
315*aa772005SRobert Watson 
316*aa772005SRobert Watson 	newconn = proto_alloc(proto,
317*aa772005SRobert Watson 	    client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
318*aa772005SRobert Watson 	if (newconn == NULL)
319*aa772005SRobert Watson 		return (-1);
320*aa772005SRobert Watson 	PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
321*aa772005SRobert Watson 	error = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
322*aa772005SRobert Watson 	if (error != 0) {
323*aa772005SRobert Watson 		proto_free(newconn);
324*aa772005SRobert Watson 		errno = error;
325*aa772005SRobert Watson 		return (-1);
326*aa772005SRobert Watson 	}
327*aa772005SRobert Watson 
328*aa772005SRobert Watson 	*newconnp = newconn;
329*aa772005SRobert Watson 
330*aa772005SRobert Watson 	return (0);
331*aa772005SRobert Watson }
332*aa772005SRobert Watson 
333*aa772005SRobert Watson int
334*aa772005SRobert Watson proto_connection_recv(const struct proto_conn *conn, bool client,
335*aa772005SRobert Watson     struct proto_conn **newconnp)
336*aa772005SRobert Watson {
337*aa772005SRobert Watson 	char protoname[128];
338*aa772005SRobert Watson 	int error, fd;
339*aa772005SRobert Watson 
340*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
341*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
342*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
343*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
344*aa772005SRobert Watson 	PJDLOG_ASSERT(newconnp != NULL);
345*aa772005SRobert Watson 
346*aa772005SRobert Watson 	bzero(protoname, sizeof(protoname));
347*aa772005SRobert Watson 
348*aa772005SRobert Watson 	error = conn->pc_proto->prt_recv(conn->pc_ctx,
349*aa772005SRobert Watson 	    (unsigned char *)protoname, sizeof(protoname) - 1, &fd);
350*aa772005SRobert Watson 	if (error != 0) {
351*aa772005SRobert Watson 		errno = error;
352*aa772005SRobert Watson 		return (-1);
353*aa772005SRobert Watson 	}
354*aa772005SRobert Watson 
355*aa772005SRobert Watson 	PJDLOG_ASSERT(fd >= 0);
356*aa772005SRobert Watson 
357*aa772005SRobert Watson 	return (proto_wrap(protoname, client, fd, newconnp));
358*aa772005SRobert Watson }
359*aa772005SRobert Watson 
360*aa772005SRobert Watson int
361*aa772005SRobert Watson proto_descriptor(const struct proto_conn *conn)
362*aa772005SRobert Watson {
363*aa772005SRobert Watson 
364*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
365*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
366*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
367*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
368*aa772005SRobert Watson 
369*aa772005SRobert Watson 	return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
370*aa772005SRobert Watson }
371*aa772005SRobert Watson 
372*aa772005SRobert Watson bool
373*aa772005SRobert Watson proto_address_match(const struct proto_conn *conn, const char *addr)
374*aa772005SRobert Watson {
375*aa772005SRobert Watson 
376*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
377*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
378*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
379*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
380*aa772005SRobert Watson 
381*aa772005SRobert Watson 	return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
382*aa772005SRobert Watson }
383*aa772005SRobert Watson 
384*aa772005SRobert Watson void
385*aa772005SRobert Watson proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
386*aa772005SRobert Watson {
387*aa772005SRobert Watson 
388*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
389*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
390*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
391*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
392*aa772005SRobert Watson 
393*aa772005SRobert Watson 	conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
394*aa772005SRobert Watson }
395*aa772005SRobert Watson 
396*aa772005SRobert Watson void
397*aa772005SRobert Watson proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
398*aa772005SRobert Watson {
399*aa772005SRobert Watson 
400*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
401*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
402*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
403*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
404*aa772005SRobert Watson 
405*aa772005SRobert Watson 	conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
406*aa772005SRobert Watson }
407*aa772005SRobert Watson 
408*aa772005SRobert Watson int
409*aa772005SRobert Watson proto_timeout(const struct proto_conn *conn, int timeout)
410*aa772005SRobert Watson {
411*aa772005SRobert Watson 	struct timeval tv;
412*aa772005SRobert Watson 	int fd;
413*aa772005SRobert Watson 
414*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
415*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
416*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
417*aa772005SRobert Watson 
418*aa772005SRobert Watson 	fd = proto_descriptor(conn);
419*aa772005SRobert Watson 	if (fd < 0)
420*aa772005SRobert Watson 		return (-1);
421*aa772005SRobert Watson 
422*aa772005SRobert Watson 	tv.tv_sec = timeout;
423*aa772005SRobert Watson 	tv.tv_usec = 0;
424*aa772005SRobert Watson 	if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
425*aa772005SRobert Watson 		return (-1);
426*aa772005SRobert Watson 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
427*aa772005SRobert Watson 		return (-1);
428*aa772005SRobert Watson 
429*aa772005SRobert Watson 	return (0);
430*aa772005SRobert Watson }
431*aa772005SRobert Watson 
432*aa772005SRobert Watson void
433*aa772005SRobert Watson proto_close(struct proto_conn *conn)
434*aa772005SRobert Watson {
435*aa772005SRobert Watson 
436*aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
437*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
438*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto != NULL);
439*aa772005SRobert Watson 	PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
440*aa772005SRobert Watson 
441*aa772005SRobert Watson 	conn->pc_proto->prt_close(conn->pc_ctx);
442*aa772005SRobert Watson 	proto_free(conn);
443*aa772005SRobert Watson }
444*aa772005SRobert Watson 
445*aa772005SRobert Watson int
446*aa772005SRobert Watson proto_exec(int argc, char *argv[])
447*aa772005SRobert Watson {
448*aa772005SRobert Watson 	struct proto *proto;
449*aa772005SRobert Watson 	int error;
450*aa772005SRobert Watson 
451*aa772005SRobert Watson 	if (argc == 0) {
452*aa772005SRobert Watson 		errno = EINVAL;
453*aa772005SRobert Watson 		return (-1);
454*aa772005SRobert Watson 	}
455*aa772005SRobert Watson 	TAILQ_FOREACH(proto, &protos, prt_next) {
456*aa772005SRobert Watson 		if (strcmp(proto->prt_name, argv[0]) == 0)
457*aa772005SRobert Watson 			break;
458*aa772005SRobert Watson 	}
459*aa772005SRobert Watson 	if (proto == NULL) {
460*aa772005SRobert Watson 		errno = EINVAL;
461*aa772005SRobert Watson 		return (-1);
462*aa772005SRobert Watson 	}
463*aa772005SRobert Watson 	if (proto->prt_exec == NULL) {
464*aa772005SRobert Watson 		errno = EOPNOTSUPP;
465*aa772005SRobert Watson 		return (-1);
466*aa772005SRobert Watson 	}
467*aa772005SRobert Watson 	error = proto->prt_exec(argc, argv);
468*aa772005SRobert Watson 	if (error != 0) {
469*aa772005SRobert Watson 		errno = error;
470*aa772005SRobert Watson 		return (-1);
471*aa772005SRobert Watson 	}
472*aa772005SRobert Watson 	/* NOTREACHED */
473*aa772005SRobert Watson 	return (0);
474*aa772005SRobert Watson }
475*aa772005SRobert Watson 
476*aa772005SRobert Watson struct proto_nvpair {
477*aa772005SRobert Watson 	char	*pnv_name;
478*aa772005SRobert Watson 	char	*pnv_value;
479*aa772005SRobert Watson 	TAILQ_ENTRY(proto_nvpair) pnv_next;
480*aa772005SRobert Watson };
481*aa772005SRobert Watson 
482*aa772005SRobert Watson static TAILQ_HEAD(, proto_nvpair) proto_nvpairs =
483*aa772005SRobert Watson     TAILQ_HEAD_INITIALIZER(proto_nvpairs);
484*aa772005SRobert Watson 
485*aa772005SRobert Watson int
486*aa772005SRobert Watson proto_set(const char *name, const char *value)
487*aa772005SRobert Watson {
488*aa772005SRobert Watson 	struct proto_nvpair *pnv;
489*aa772005SRobert Watson 
490*aa772005SRobert Watson 	TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
491*aa772005SRobert Watson 		if (strcmp(pnv->pnv_name, name) == 0)
492*aa772005SRobert Watson 			break;
493*aa772005SRobert Watson 	}
494*aa772005SRobert Watson 	if (pnv != NULL) {
495*aa772005SRobert Watson 		TAILQ_REMOVE(&proto_nvpairs, pnv, pnv_next);
496*aa772005SRobert Watson 		free(pnv->pnv_value);
497*aa772005SRobert Watson 	} else {
498*aa772005SRobert Watson 		pnv = malloc(sizeof(*pnv));
499*aa772005SRobert Watson 		if (pnv == NULL)
500*aa772005SRobert Watson 			return (-1);
501*aa772005SRobert Watson 		pnv->pnv_name = strdup(name);
502*aa772005SRobert Watson 		if (pnv->pnv_name == NULL) {
503*aa772005SRobert Watson 			free(pnv);
504*aa772005SRobert Watson 			return (-1);
505*aa772005SRobert Watson 		}
506*aa772005SRobert Watson 	}
507*aa772005SRobert Watson 	pnv->pnv_value = strdup(value);
508*aa772005SRobert Watson 	if (pnv->pnv_value == NULL) {
509*aa772005SRobert Watson 		free(pnv->pnv_name);
510*aa772005SRobert Watson 		free(pnv);
511*aa772005SRobert Watson 		return (-1);
512*aa772005SRobert Watson 	}
513*aa772005SRobert Watson 	TAILQ_INSERT_TAIL(&proto_nvpairs, pnv, pnv_next);
514*aa772005SRobert Watson 	return (0);
515*aa772005SRobert Watson }
516*aa772005SRobert Watson 
517*aa772005SRobert Watson const char *
518*aa772005SRobert Watson proto_get(const char *name)
519*aa772005SRobert Watson {
520*aa772005SRobert Watson 	struct proto_nvpair *pnv;
521*aa772005SRobert Watson 
522*aa772005SRobert Watson 	TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
523*aa772005SRobert Watson 		if (strcmp(pnv->pnv_name, name) == 0)
524*aa772005SRobert Watson 			break;
525*aa772005SRobert Watson 	}
526*aa772005SRobert Watson 	if (pnv != NULL)
527*aa772005SRobert Watson 		return (pnv->pnv_value);
528*aa772005SRobert Watson 	return (NULL);
529*aa772005SRobert Watson }
530