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