1/*	$NetBSD: t_rpc.c,v 1.10 2016/08/27 14:36:22 christos Exp $	*/
2
3#include <sys/cdefs.h>
4__RCSID("$NetBSD: t_rpc.c,v 1.10 2016/08/27 14:36:22 christos Exp $");
5
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <rpc/rpc.h>
9#include <stdlib.h>
10#include <string.h>
11#include <err.h>
12#include <netdb.h>
13#include <stdio.h>
14#include <errno.h>
15#include <unistd.h>
16
17#ifndef TEST
18#include <atf-c.h>
19
20#define ERRX(ev, msg, ...)	ATF_REQUIRE_MSG(0, msg, __VA_ARGS__)
21
22#define SKIPX(ev, msg, ...)	do {			\
23	atf_tc_skip(msg, __VA_ARGS__);			\
24	return ev;					\
25} while(/*CONSTCOND*/0)
26
27#else
28#define ERRX(ev, msg, ...)	errx(EXIT_FAILURE, msg, __VA_ARGS__)
29#define SKIPX(ev, msg, ...)	errx(EXIT_FAILURE, msg, __VA_ARGS__)
30#endif
31
32#ifdef DEBUG
33#define DPRINTF(...)	printf(__VA_ARGS__)
34#else
35#define DPRINTF(...)
36#endif
37
38
39#define RPCBPROC_NULL 0
40
41static int
42reply(caddr_t replyp, struct netbuf * raddrp, struct netconfig * nconf)
43{
44	char host[NI_MAXHOST];
45	struct sockaddr *sock = raddrp->buf;
46	int error;
47
48
49	error = getnameinfo(sock, sock->sa_len, host, sizeof(host), NULL, 0, 0);
50	if (error)
51		warnx("Cannot resolve address (%s)", gai_strerror(error));
52	else
53		printf("response from: %s\n", host);
54	return 0;
55}
56
57#ifdef __FreeBSD__
58#define	__rpc_control	rpc_control
59#endif
60
61extern bool_t __rpc_control(int, void *);
62
63static void
64onehost(const char *host, const char *transp)
65{
66	CLIENT         *clnt;
67	struct netbuf   addr;
68	struct timeval  tv;
69
70	/*
71	 * Magic!
72	 */
73	tv.tv_sec = 0;
74	tv.tv_usec = 500000;
75#ifdef __FreeBSD__
76	/*
77	 * FreeBSD does not allow setting the timeout using __rpc_control,
78	 * but does have clnt_create_timed() that allows passing a timeout.
79	 */
80	if ((clnt = clnt_create_timed(host, RPCBPROG, RPCBVERS, transp,
81	     &tv)) == NULL)
82		SKIPX(, "clnt_create (%s)", clnt_spcreateerror(""));
83#else
84#define CLCR_SET_RPCB_TIMEOUT   2
85	__rpc_control(CLCR_SET_RPCB_TIMEOUT, &tv);
86
87	if ((clnt = clnt_create(host, RPCBPROG, RPCBVERS, transp)) == NULL)
88		SKIPX(, "clnt_create (%s)", clnt_spcreateerror(""));
89#endif
90
91	tv.tv_sec = 1;
92	tv.tv_usec = 0;
93#ifdef __FreeBSD__
94	if (clnt_call(clnt, RPCBPROC_NULL, (xdrproc_t)xdr_void, NULL,
95	    (xdrproc_t)xdr_void, NULL, tv)
96	    != RPC_SUCCESS)
97#else
98	if (clnt_call(clnt, RPCBPROC_NULL, xdr_void, NULL, xdr_void, NULL, tv)
99	    != RPC_SUCCESS)
100#endif
101		ERRX(, "clnt_call (%s)", clnt_sperror(clnt, ""));
102	clnt_control(clnt, CLGET_SVC_ADDR, (char *) &addr);
103	reply(NULL, &addr, NULL);
104}
105
106#define PROGNUM 0x81
107#define VERSNUM 0x01
108#define PLUSONE 1
109#define DESTROY 2
110
111static struct timeval 	tout = {1, 0};
112
113static void
114server(struct svc_req *rqstp, SVCXPRT *transp)
115{
116	int num;
117
118	DPRINTF("Starting server\n");
119
120	switch (rqstp->rq_proc) {
121	case NULLPROC:
122		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
123			ERRX(, "svc_sendreply failed %d", 0);
124		return;
125	case PLUSONE:
126		break;
127	case DESTROY:
128		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
129			ERRX(, "svc_sendreply failed %d", 0);
130		svc_destroy(transp);
131		exit(0);
132	default:
133		svcerr_noproc(transp);
134		return;
135	}
136
137	if (!svc_getargs(transp, (xdrproc_t)xdr_int, (void *)&num)) {
138		svcerr_decode(transp);
139		return;
140	}
141	DPRINTF("About to increment\n");
142	num++;
143	if (!svc_sendreply(transp, (xdrproc_t)xdr_int, (void *)&num))
144		ERRX(, "svc_sendreply failed %d", 1);
145	DPRINTF("Leaving server procedure.\n");
146}
147
148static int
149rawtest(const char *arg)
150{
151	CLIENT         *clnt;
152	SVCXPRT        *svc;
153	int 		num, resp;
154	enum clnt_stat  rv;
155
156	if (arg)
157		num = atoi(arg);
158	else
159		num = 0;
160
161	svc = svc_raw_create();
162	if (svc == NULL)
163		ERRX(EXIT_FAILURE, "Cannot create server %d", num);
164	if (!svc_reg(svc, PROGNUM, VERSNUM, server, NULL))
165		ERRX(EXIT_FAILURE, "Cannot register server %d", num);
166
167	clnt = clnt_raw_create(PROGNUM, VERSNUM);
168	if (clnt == NULL)
169		ERRX(EXIT_FAILURE, "%s",
170		    clnt_spcreateerror("clnt_raw_create"));
171	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
172	    (xdrproc_t)xdr_int, (void *)&resp, tout);
173	if (rv != RPC_SUCCESS)
174		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
175	DPRINTF("Got %d\n", resp);
176	clnt_destroy(clnt);
177	svc_destroy(svc);
178	if (++num != resp)
179		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
180
181	return EXIT_SUCCESS;
182}
183
184static int
185regtest(const char *hostname, const char *transp, const char *arg, int p)
186{
187	CLIENT         *clnt;
188	int 		num, resp;
189	enum clnt_stat  rv;
190	pid_t		pid;
191
192	if (arg)
193		num = atoi(arg);
194	else
195		num = 0;
196
197#ifdef __NetBSD__
198	svc_fdset_init(p ? SVC_FDSET_POLL : 0);
199#endif
200	if (!svc_create(server, PROGNUM, VERSNUM, transp))
201	{
202		SKIPX(EXIT_FAILURE, "Cannot create server %d", num);
203	}
204
205	switch ((pid = fork())) {
206	case 0:
207		DPRINTF("Calling svc_run\n");
208		svc_run();
209		ERRX(EXIT_FAILURE, "svc_run returned %d!", num);
210	case -1:
211		ERRX(EXIT_FAILURE, "Fork failed (%s)", strerror(errno));
212	default:
213		sleep(1);
214		break;
215	}
216
217	DPRINTF("Initializing client\n");
218	clnt = clnt_create(hostname, PROGNUM, VERSNUM, transp);
219	if (clnt == NULL)
220		ERRX(EXIT_FAILURE, "%s",
221		    clnt_spcreateerror("clnt_raw_create"));
222	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
223	    (xdrproc_t)xdr_int, (void *)&resp, tout);
224	if (rv != RPC_SUCCESS)
225		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
226	DPRINTF("Got %d\n", resp);
227	if (++num != resp)
228		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
229	rv = clnt_call(clnt, DESTROY, (xdrproc_t)xdr_void, NULL,
230	    (xdrproc_t)xdr_void, NULL, tout);
231	if (rv != RPC_SUCCESS)
232		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
233	clnt_destroy(clnt);
234
235	return EXIT_SUCCESS;
236}
237
238
239#ifdef TEST
240static void
241allhosts(const char *transp)
242{
243	enum clnt_stat  clnt_stat;
244
245	clnt_stat = rpc_broadcast(RPCBPROG, RPCBVERS, RPCBPROC_NULL,
246	    (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void,
247	    NULL, (resultproc_t)reply, transp);
248	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
249		ERRX(EXIT_FAILURE, "%s", clnt_sperrno(clnt_stat));
250}
251
252int
253main(int argc, char *argv[])
254{
255	int             ch;
256	int		s, p;
257	const char     *transp = "udp";
258
259	p = s = 0;
260	while ((ch = getopt(argc, argv, "prstu")) != -1)
261		switch (ch) {
262		case 'p':
263			p = 1;
264			break;
265		case 's':
266			s = 1;
267			break;
268		case 't':
269			transp = "tcp";
270			break;
271		case 'u':
272			transp = "udp";
273			break;
274		case 'r':
275			transp = NULL;
276			break;
277		default:
278			fprintf(stderr,
279			    "Usage: %s -[r|s|t|u] [<hostname>...]\n",
280			    getprogname());
281			return EXIT_FAILURE;
282		}
283
284	if (argc == optind) {
285		if  (transp)
286			allhosts(transp);
287		else
288			rawtest(NULL);
289	} else {
290		for (; optind < argc; optind++) {
291			if (transp)
292				s == 0 ?
293				    onehost(argv[optind], transp) :
294				    regtest(argv[optind], transp, "1", p);
295			else
296				rawtest(argv[optind]);
297		}
298	}
299
300	return EXIT_SUCCESS;
301}
302
303#else
304
305ATF_TC(get_svc_addr_tcp);
306ATF_TC_HEAD(get_svc_addr_tcp, tc)
307{
308	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for tcp");
309
310}
311
312ATF_TC_BODY(get_svc_addr_tcp, tc)
313{
314	onehost("localhost", "tcp");
315
316}
317
318ATF_TC(get_svc_addr_udp);
319ATF_TC_HEAD(get_svc_addr_udp, tc)
320{
321	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for udp");
322}
323
324ATF_TC_BODY(get_svc_addr_udp, tc)
325{
326	onehost("localhost", "udp");
327
328}
329
330ATF_TC(raw);
331ATF_TC_HEAD(raw, tc)
332{
333	atf_tc_set_md_var(tc, "descr", "Checks svc raw");
334}
335
336ATF_TC_BODY(raw, tc)
337{
338	rawtest(NULL);
339
340}
341
342ATF_TC(tcp);
343ATF_TC_HEAD(tcp, tc)
344{
345	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (select)");
346#ifdef __FreeBSD__
347	atf_tc_set_md_var(tc, "require.user", "root");
348#endif
349}
350
351ATF_TC_BODY(tcp, tc)
352{
353	regtest("localhost", "tcp", "1", 0);
354
355}
356
357ATF_TC(udp);
358ATF_TC_HEAD(udp, tc)
359{
360	atf_tc_set_md_var(tc, "descr", "Checks svc udp (select)");
361#ifdef __FreeBSD__
362	atf_tc_set_md_var(tc, "require.user", "root");
363#endif
364}
365
366ATF_TC_BODY(udp, tc)
367{
368	regtest("localhost", "udp", "1", 0);
369
370}
371
372ATF_TC(tcp_poll);
373ATF_TC_HEAD(tcp_poll, tc)
374{
375	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (poll)");
376#ifdef __FreeBSD__
377	atf_tc_set_md_var(tc, "require.user", "root");
378#endif
379}
380
381ATF_TC_BODY(tcp_poll, tc)
382{
383	regtest("localhost", "tcp", "1", 1);
384
385}
386
387ATF_TC(udp_poll);
388ATF_TC_HEAD(udp_poll, tc)
389{
390	atf_tc_set_md_var(tc, "descr", "Checks svc udp (poll)");
391#ifdef __FreeBSD__
392	atf_tc_set_md_var(tc, "require.user", "root");
393#endif
394}
395
396ATF_TC_BODY(udp_poll, tc)
397{
398	regtest("localhost", "udp", "1", 1);
399
400}
401
402ATF_TP_ADD_TCS(tp)
403{
404	ATF_TP_ADD_TC(tp, get_svc_addr_udp);
405	ATF_TP_ADD_TC(tp, get_svc_addr_tcp);
406	ATF_TP_ADD_TC(tp, raw);
407	ATF_TP_ADD_TC(tp, tcp);
408	ATF_TP_ADD_TC(tp, udp);
409	ATF_TP_ADD_TC(tp, tcp_poll);
410	ATF_TP_ADD_TC(tp, udp_poll);
411
412	return atf_no_error();
413}
414
415#endif
416