t_rpc.c revision 314818
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#define CLCR_SET_RPCB_TIMEOUT   2
76	__rpc_control(CLCR_SET_RPCB_TIMEOUT, &tv);
77
78	if ((clnt = clnt_create(host, RPCBPROG, RPCBVERS, transp)) == NULL)
79		SKIPX(, "clnt_create (%s)", clnt_spcreateerror(""));
80
81	tv.tv_sec = 1;
82	tv.tv_usec = 0;
83#ifdef __FreeBSD__
84	if (clnt_call(clnt, RPCBPROC_NULL, (xdrproc_t)xdr_void, NULL,
85	    (xdrproc_t)xdr_void, NULL, tv)
86	    != RPC_SUCCESS)
87#else
88	if (clnt_call(clnt, RPCBPROC_NULL, xdr_void, NULL, xdr_void, NULL, tv)
89	    != RPC_SUCCESS)
90#endif
91		ERRX(, "clnt_call (%s)", clnt_sperror(clnt, ""));
92	clnt_control(clnt, CLGET_SVC_ADDR, (char *) &addr);
93	reply(NULL, &addr, NULL);
94}
95
96#define PROGNUM 0x81
97#define VERSNUM 0x01
98#define PLUSONE 1
99#define DESTROY 2
100
101static struct timeval 	tout = {1, 0};
102
103static void
104server(struct svc_req *rqstp, SVCXPRT *transp)
105{
106	int num;
107
108	DPRINTF("Starting server\n");
109
110	switch (rqstp->rq_proc) {
111	case NULLPROC:
112		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
113			ERRX(, "svc_sendreply failed %d", 0);
114		return;
115	case PLUSONE:
116		break;
117	case DESTROY:
118		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
119			ERRX(, "svc_sendreply failed %d", 0);
120		svc_destroy(transp);
121		exit(0);
122	default:
123		svcerr_noproc(transp);
124		return;
125	}
126
127	if (!svc_getargs(transp, (xdrproc_t)xdr_int, (void *)&num)) {
128		svcerr_decode(transp);
129		return;
130	}
131	DPRINTF("About to increment\n");
132	num++;
133	if (!svc_sendreply(transp, (xdrproc_t)xdr_int, (void *)&num))
134		ERRX(, "svc_sendreply failed %d", 1);
135	DPRINTF("Leaving server procedure.\n");
136}
137
138static int
139rawtest(const char *arg)
140{
141	CLIENT         *clnt;
142	SVCXPRT        *svc;
143	int 		num, resp;
144	enum clnt_stat  rv;
145
146	if (arg)
147		num = atoi(arg);
148	else
149		num = 0;
150
151	svc = svc_raw_create();
152	if (svc == NULL)
153		ERRX(EXIT_FAILURE, "Cannot create server %d", num);
154	if (!svc_reg(svc, PROGNUM, VERSNUM, server, NULL))
155		ERRX(EXIT_FAILURE, "Cannot register server %d", num);
156
157	clnt = clnt_raw_create(PROGNUM, VERSNUM);
158	if (clnt == NULL)
159		ERRX(EXIT_FAILURE, "%s",
160		    clnt_spcreateerror("clnt_raw_create"));
161	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
162	    (xdrproc_t)xdr_int, (void *)&resp, tout);
163	if (rv != RPC_SUCCESS)
164		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
165	DPRINTF("Got %d\n", resp);
166	clnt_destroy(clnt);
167	svc_destroy(svc);
168	if (++num != resp)
169		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
170
171	return EXIT_SUCCESS;
172}
173
174static int
175regtest(const char *hostname, const char *transp, const char *arg, int p)
176{
177	CLIENT         *clnt;
178	int 		num, resp;
179	enum clnt_stat  rv;
180	pid_t		pid;
181
182	if (arg)
183		num = atoi(arg);
184	else
185		num = 0;
186
187#ifdef __NetBSD__
188	svc_fdset_init(p ? SVC_FDSET_POLL : 0);
189#endif
190	if (!svc_create(server, PROGNUM, VERSNUM, transp))
191	{
192		SKIPX(EXIT_FAILURE, "Cannot create server %d", num);
193	}
194
195	switch ((pid = fork())) {
196	case 0:
197		DPRINTF("Calling svc_run\n");
198		svc_run();
199		ERRX(EXIT_FAILURE, "svc_run returned %d!", num);
200	case -1:
201		ERRX(EXIT_FAILURE, "Fork failed (%s)", strerror(errno));
202	default:
203		sleep(1);
204		break;
205	}
206
207	DPRINTF("Initializing client\n");
208	clnt = clnt_create(hostname, PROGNUM, VERSNUM, transp);
209	if (clnt == NULL)
210		ERRX(EXIT_FAILURE, "%s",
211		    clnt_spcreateerror("clnt_raw_create"));
212	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
213	    (xdrproc_t)xdr_int, (void *)&resp, tout);
214	if (rv != RPC_SUCCESS)
215		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
216	DPRINTF("Got %d\n", resp);
217	if (++num != resp)
218		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
219	rv = clnt_call(clnt, DESTROY, (xdrproc_t)xdr_void, NULL,
220	    (xdrproc_t)xdr_void, NULL, tout);
221	if (rv != RPC_SUCCESS)
222		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
223	clnt_destroy(clnt);
224
225	return EXIT_SUCCESS;
226}
227
228
229#ifdef TEST
230static void
231allhosts(const char *transp)
232{
233	enum clnt_stat  clnt_stat;
234
235	clnt_stat = rpc_broadcast(RPCBPROG, RPCBVERS, RPCBPROC_NULL,
236	    (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void,
237	    NULL, (resultproc_t)reply, transp);
238	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
239		ERRX(EXIT_FAILURE, "%s", clnt_sperrno(clnt_stat));
240}
241
242int
243main(int argc, char *argv[])
244{
245	int             ch;
246	int		s, p;
247	const char     *transp = "udp";
248
249	p = s = 0;
250	while ((ch = getopt(argc, argv, "prstu")) != -1)
251		switch (ch) {
252		case 'p':
253			p = 1;
254			break;
255		case 's':
256			s = 1;
257			break;
258		case 't':
259			transp = "tcp";
260			break;
261		case 'u':
262			transp = "udp";
263			break;
264		case 'r':
265			transp = NULL;
266			break;
267		default:
268			fprintf(stderr,
269			    "Usage: %s -[r|s|t|u] [<hostname>...]\n",
270			    getprogname());
271			return EXIT_FAILURE;
272		}
273
274	if (argc == optind) {
275		if  (transp)
276			allhosts(transp);
277		else
278			rawtest(NULL);
279	} else {
280		for (; optind < argc; optind++) {
281			if (transp)
282				s == 0 ?
283				    onehost(argv[optind], transp) :
284				    regtest(argv[optind], transp, "1", p);
285			else
286				rawtest(argv[optind]);
287		}
288	}
289
290	return EXIT_SUCCESS;
291}
292
293#else
294
295ATF_TC(get_svc_addr_tcp);
296ATF_TC_HEAD(get_svc_addr_tcp, tc)
297{
298	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for tcp");
299
300}
301
302ATF_TC_BODY(get_svc_addr_tcp, tc)
303{
304	onehost("localhost", "tcp");
305
306}
307
308ATF_TC(get_svc_addr_udp);
309ATF_TC_HEAD(get_svc_addr_udp, tc)
310{
311	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for udp");
312}
313
314ATF_TC_BODY(get_svc_addr_udp, tc)
315{
316	onehost("localhost", "udp");
317
318}
319
320ATF_TC(raw);
321ATF_TC_HEAD(raw, tc)
322{
323	atf_tc_set_md_var(tc, "descr", "Checks svc raw");
324}
325
326ATF_TC_BODY(raw, tc)
327{
328#ifdef __FreeBSD__
329	atf_tc_expect_fail("fails with: clnt_call: "
330	    "RPC: Can't decode result -- PR # 211804");
331#endif
332	rawtest(NULL);
333
334}
335
336ATF_TC(tcp);
337ATF_TC_HEAD(tcp, tc)
338{
339	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (select)");
340#ifdef __FreeBSD__
341	atf_tc_set_md_var(tc, "require.user", "root");
342#endif
343}
344
345ATF_TC_BODY(tcp, tc)
346{
347	regtest("localhost", "tcp", "1", 0);
348
349}
350
351ATF_TC(udp);
352ATF_TC_HEAD(udp, tc)
353{
354	atf_tc_set_md_var(tc, "descr", "Checks svc udp (select)");
355#ifdef __FreeBSD__
356	atf_tc_set_md_var(tc, "require.user", "root");
357#endif
358}
359
360ATF_TC_BODY(udp, tc)
361{
362	regtest("localhost", "udp", "1", 0);
363
364}
365
366ATF_TC(tcp_poll);
367ATF_TC_HEAD(tcp_poll, tc)
368{
369	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (poll)");
370#ifdef __FreeBSD__
371	atf_tc_set_md_var(tc, "require.user", "root");
372#endif
373}
374
375ATF_TC_BODY(tcp_poll, tc)
376{
377	regtest("localhost", "tcp", "1", 1);
378
379}
380
381ATF_TC(udp_poll);
382ATF_TC_HEAD(udp_poll, tc)
383{
384	atf_tc_set_md_var(tc, "descr", "Checks svc udp (poll)");
385#ifdef __FreeBSD__
386	atf_tc_set_md_var(tc, "require.user", "root");
387#endif
388}
389
390ATF_TC_BODY(udp_poll, tc)
391{
392	regtest("localhost", "udp", "1", 1);
393
394}
395
396ATF_TP_ADD_TCS(tp)
397{
398	ATF_TP_ADD_TC(tp, get_svc_addr_udp);
399	ATF_TP_ADD_TC(tp, get_svc_addr_tcp);
400	ATF_TP_ADD_TC(tp, raw);
401	ATF_TP_ADD_TC(tp, tcp);
402	ATF_TP_ADD_TC(tp, udp);
403	ATF_TP_ADD_TC(tp, tcp_poll);
404	ATF_TP_ADD_TC(tp, udp_poll);
405
406	return atf_no_error();
407}
408
409#endif
410