t_rpc.c revision 318327
1193267Sjkim/*	$NetBSD: t_rpc.c,v 1.10 2016/08/27 14:36:22 christos Exp $	*/
2193267Sjkim
3193267Sjkim#include <sys/cdefs.h>
4193267Sjkim__RCSID("$NetBSD: t_rpc.c,v 1.10 2016/08/27 14:36:22 christos Exp $");
5193267Sjkim
6193267Sjkim#include <sys/types.h>
7316303Sjkim#include <sys/socket.h>
8316303Sjkim#include <rpc/rpc.h>
9316303Sjkim#include <stdlib.h>
10316303Sjkim#include <string.h>
11316303Sjkim#include <err.h>
12193267Sjkim#include <netdb.h>
13193267Sjkim#include <stdio.h>
14316303Sjkim#include <errno.h>
15316303Sjkim#include <unistd.h>
16316303Sjkim
17316303Sjkim#ifndef TEST
18316303Sjkim#include <atf-c.h>
19316303Sjkim
20316303Sjkim#define ERRX(ev, msg, ...)	ATF_REQUIRE_MSG(0, msg, __VA_ARGS__)
21316303Sjkim
22316303Sjkim#define SKIPX(ev, msg, ...)	do {			\
23316303Sjkim	atf_tc_skip(msg, __VA_ARGS__);			\
24316303Sjkim	return ev;					\
25316303Sjkim} while(/*CONSTCOND*/0)
26316303Sjkim
27316303Sjkim#else
28316303Sjkim#define ERRX(ev, msg, ...)	errx(EXIT_FAILURE, msg, __VA_ARGS__)
29316303Sjkim#define SKIPX(ev, msg, ...)	errx(EXIT_FAILURE, msg, __VA_ARGS__)
30316303Sjkim#endif
31316303Sjkim
32316303Sjkim#ifdef DEBUG
33316303Sjkim#define DPRINTF(...)	printf(__VA_ARGS__)
34316303Sjkim#else
35316303Sjkim#define DPRINTF(...)
36316303Sjkim#endif
37316303Sjkim
38316303Sjkim
39316303Sjkim#define RPCBPROC_NULL 0
40316303Sjkim
41316303Sjkim/* XXX (ngie): for clarity on what needs to be reverted later. */
42316303Sjkim#define	__FreeBSD_bug_216954__
43316303Sjkim#ifdef	__FreeBSD_bug_216954__
44316303Sjkim#include <signal.h>
45316303Sjkim#endif
46316303Sjkim
47316303Sjkimstatic int
48316303Sjkimreply(caddr_t replyp, struct netbuf * raddrp, struct netconfig * nconf)
49316303Sjkim{
50316303Sjkim	char host[NI_MAXHOST];
51316303Sjkim	struct sockaddr *sock = raddrp->buf;
52316303Sjkim	int error;
53316303Sjkim
54316303Sjkim
55316303Sjkim	error = getnameinfo(sock, sock->sa_len, host, sizeof(host), NULL, 0, 0);
56316303Sjkim	if (error)
57316303Sjkim		warnx("Cannot resolve address (%s)", gai_strerror(error));
58316303Sjkim	else
59316303Sjkim		printf("response from: %s\n", host);
60316303Sjkim	return 0;
61316303Sjkim}
62316303Sjkim
63316303Sjkim#ifdef __FreeBSD__
64316303Sjkim#define	__rpc_control	rpc_control
65316303Sjkim#endif
66316303Sjkim
67316303Sjkimextern bool_t __rpc_control(int, void *);
68316303Sjkim
69316303Sjkimstatic void
70316303Sjkimonehost(const char *host, const char *transp)
71316303Sjkim{
72316303Sjkim	CLIENT         *clnt;
73316303Sjkim	struct netbuf   addr;
74316303Sjkim	struct timeval  tv;
75316303Sjkim
76316303Sjkim	/*
77316303Sjkim	 * Magic!
78316303Sjkim	 */
79316303Sjkim	tv.tv_sec = 0;
80316303Sjkim	tv.tv_usec = 500000;
81316303Sjkim#define CLCR_SET_RPCB_TIMEOUT   2
82316303Sjkim	__rpc_control(CLCR_SET_RPCB_TIMEOUT, &tv);
83316303Sjkim
84316303Sjkim	if ((clnt = clnt_create(host, RPCBPROG, RPCBVERS, transp)) == NULL)
85316303Sjkim		SKIPX(, "clnt_create (%s)", clnt_spcreateerror(""));
86316303Sjkim
87316303Sjkim	tv.tv_sec = 1;
88316303Sjkim	tv.tv_usec = 0;
89316303Sjkim#ifdef __FreeBSD__
90316303Sjkim	if (clnt_call(clnt, RPCBPROC_NULL, (xdrproc_t)xdr_void, NULL,
91316303Sjkim	    (xdrproc_t)xdr_void, NULL, tv)
92316303Sjkim	    != RPC_SUCCESS)
93316303Sjkim#else
94316303Sjkim	if (clnt_call(clnt, RPCBPROC_NULL, xdr_void, NULL, xdr_void, NULL, tv)
95316303Sjkim	    != RPC_SUCCESS)
96316303Sjkim#endif
97316303Sjkim		ERRX(, "clnt_call (%s)", clnt_sperror(clnt, ""));
98316303Sjkim	clnt_control(clnt, CLGET_SVC_ADDR, (char *) &addr);
99316303Sjkim	reply(NULL, &addr, NULL);
100316303Sjkim}
101316303Sjkim
102316303Sjkim#define PROGNUM 0x81
103316303Sjkim#define VERSNUM 0x01
104316303Sjkim#define PLUSONE 1
105316303Sjkim#define DESTROY 2
106316303Sjkim
107316303Sjkimstatic struct timeval 	tout = {1, 0};
108316303Sjkim
109316303Sjkimstatic void
110316303Sjkimserver(struct svc_req *rqstp, SVCXPRT *transp)
111316303Sjkim{
112316303Sjkim	int num;
113316303Sjkim
114316303Sjkim	DPRINTF("Starting server\n");
115316303Sjkim
116316303Sjkim	switch (rqstp->rq_proc) {
117316303Sjkim	case NULLPROC:
118316303Sjkim		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
119217365Sjkim			ERRX(, "svc_sendreply failed %d", 0);
120217365Sjkim		return;
121217365Sjkim	case PLUSONE:
122217365Sjkim		break;
123217365Sjkim	case DESTROY:
124217365Sjkim		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
125217365Sjkim			ERRX(, "svc_sendreply failed %d", 0);
126217365Sjkim		svc_destroy(transp);
127217365Sjkim		exit(0);
128217365Sjkim	default:
129217365Sjkim		svcerr_noproc(transp);
130217365Sjkim		return;
131217365Sjkim	}
132217365Sjkim
133193267Sjkim	if (!svc_getargs(transp, (xdrproc_t)xdr_int, (void *)&num)) {
134316303Sjkim		svcerr_decode(transp);
135316303Sjkim		return;
136316303Sjkim	}
137316303Sjkim	DPRINTF("About to increment\n");
138316303Sjkim	num++;
139316303Sjkim	if (!svc_sendreply(transp, (xdrproc_t)xdr_int, (void *)&num))
140316303Sjkim		ERRX(, "svc_sendreply failed %d", 1);
141316303Sjkim	DPRINTF("Leaving server procedure.\n");
142316303Sjkim}
143316303Sjkim
144316303Sjkimstatic int
145316303Sjkimrawtest(const char *arg)
146316303Sjkim{
147217365Sjkim	CLIENT         *clnt;
148217365Sjkim	SVCXPRT        *svc;
149193267Sjkim	int 		num, resp;
150316303Sjkim	enum clnt_stat  rv;
151193267Sjkim
152193267Sjkim	if (arg)
153193267Sjkim		num = atoi(arg);
154193267Sjkim	else
155193267Sjkim		num = 0;
156193267Sjkim
157193267Sjkim	svc = svc_raw_create();
158193267Sjkim	if (svc == NULL)
159193267Sjkim		ERRX(EXIT_FAILURE, "Cannot create server %d", num);
160272444Sjkim	if (!svc_reg(svc, PROGNUM, VERSNUM, server, NULL))
161193267Sjkim		ERRX(EXIT_FAILURE, "Cannot register server %d", num);
162193267Sjkim
163193267Sjkim	clnt = clnt_raw_create(PROGNUM, VERSNUM);
164193267Sjkim	if (clnt == NULL)
165193267Sjkim		ERRX(EXIT_FAILURE, "%s",
166193267Sjkim		    clnt_spcreateerror("clnt_raw_create"));
167193267Sjkim	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
168249112Sjkim	    (xdrproc_t)xdr_int, (void *)&resp, tout);
169193267Sjkim	if (rv != RPC_SUCCESS)
170193267Sjkim		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
171193267Sjkim	DPRINTF("Got %d\n", resp);
172193267Sjkim	clnt_destroy(clnt);
173193267Sjkim	svc_destroy(svc);
174193267Sjkim	if (++num != resp)
175272444Sjkim		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
176272444Sjkim
177193267Sjkim	return EXIT_SUCCESS;
178249112Sjkim}
179249112Sjkim
180193267Sjkimstatic int
181193267Sjkimregtest(const char *hostname, const char *transp, const char *arg, int p)
182193267Sjkim{
183193267Sjkim	CLIENT         *clnt;
184193267Sjkim	int 		num, resp;
185193267Sjkim	enum clnt_stat  rv;
186249112Sjkim	pid_t		pid;
187249112Sjkim
188193267Sjkim	if (arg)
189193267Sjkim		num = atoi(arg);
190193267Sjkim	else
191193267Sjkim		num = 0;
192193267Sjkim
193193267Sjkim#ifdef __NetBSD__
194193267Sjkim	svc_fdset_init(p ? SVC_FDSET_POLL : 0);
195193267Sjkim#endif
196193267Sjkim	if (!svc_create(server, PROGNUM, VERSNUM, transp))
197193267Sjkim	{
198249112Sjkim		SKIPX(EXIT_FAILURE, "Cannot create server %d", num);
199249112Sjkim	}
200193267Sjkim
201193267Sjkim	switch ((pid = fork())) {
202249112Sjkim	case 0:
203249112Sjkim		DPRINTF("Calling svc_run\n");
204193267Sjkim		svc_run();
205193267Sjkim		ERRX(EXIT_FAILURE, "svc_run returned %d!", num);
206197104Sjkim	case -1:
207197104Sjkim		ERRX(EXIT_FAILURE, "Fork failed (%s)", strerror(errno));
208197104Sjkim	default:
209228110Sjkim		sleep(1);
210249112Sjkim		break;
211228110Sjkim	}
212228110Sjkim
213228110Sjkim	DPRINTF("Initializing client\n");
214228110Sjkim	clnt = clnt_create(hostname, PROGNUM, VERSNUM, transp);
215228110Sjkim	if (clnt == NULL)
216228110Sjkim		ERRX(EXIT_FAILURE, "%s",
217283092Sjkim		    clnt_spcreateerror("clnt_raw_create"));
218283092Sjkim	rv = clnt_call(clnt, PLUSONE, (xdrproc_t)xdr_int, (void *)&num,
219283092Sjkim	    (xdrproc_t)xdr_int, (void *)&resp, tout);
220283092Sjkim	if (rv != RPC_SUCCESS)
221283092Sjkim		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
222272444Sjkim	DPRINTF("Got %d\n", resp);
223272444Sjkim	if (++num != resp)
224272444Sjkim		ERRX(EXIT_FAILURE, "expected %d got %d", num, resp);
225272444Sjkim	rv = clnt_call(clnt, DESTROY, (xdrproc_t)xdr_void, NULL,
226272444Sjkim	    (xdrproc_t)xdr_void, NULL, tout);
227193267Sjkim	if (rv != RPC_SUCCESS)
228193267Sjkim		ERRX(EXIT_FAILURE, "clnt_call: %s", clnt_sperrno(rv));
229193267Sjkim	clnt_destroy(clnt);
230193267Sjkim
231193267Sjkim	return EXIT_SUCCESS;
232193267Sjkim}
233193267Sjkim
234193267Sjkim
235193267Sjkim#ifdef TEST
236193267Sjkimstatic void
237193267Sjkimallhosts(const char *transp)
238197104Sjkim{
239228110Sjkim	enum clnt_stat  clnt_stat;
240272444Sjkim
241283092Sjkim	clnt_stat = rpc_broadcast(RPCBPROG, RPCBVERS, RPCBPROC_NULL,
242298714Sjkim	    (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void,
243298714Sjkim	    NULL, (resultproc_t)reply, transp);
244193267Sjkim	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
245193267Sjkim		ERRX(EXIT_FAILURE, "%s", clnt_sperrno(clnt_stat));
246193267Sjkim}
247249112Sjkim
248249112Sjkimint
249249112Sjkimmain(int argc, char *argv[])
250249112Sjkim{
251249112Sjkim	int             ch;
252249112Sjkim	int		s, p;
253249112Sjkim	const char     *transp = "udp";
254249112Sjkim
255249663Sjkim	p = s = 0;
256249663Sjkim	while ((ch = getopt(argc, argv, "prstu")) != -1)
257249112Sjkim		switch (ch) {
258249112Sjkim		case 'p':
259249112Sjkim			p = 1;
260249112Sjkim			break;
261249112Sjkim		case 's':
262249112Sjkim			s = 1;
263249112Sjkim			break;
264249112Sjkim		case 't':
265249112Sjkim			transp = "tcp";
266249112Sjkim			break;
267249112Sjkim		case 'u':
268249112Sjkim			transp = "udp";
269249112Sjkim			break;
270249112Sjkim		case 'r':
271249112Sjkim			transp = NULL;
272249112Sjkim			break;
273249112Sjkim		default:
274249112Sjkim			fprintf(stderr,
275249112Sjkim			    "Usage: %s -[r|s|t|u] [<hostname>...]\n",
276249112Sjkim			    getprogname());
277249112Sjkim			return EXIT_FAILURE;
278249112Sjkim		}
279249112Sjkim
280249112Sjkim	if (argc == optind) {
281249112Sjkim		if  (transp)
282249112Sjkim			allhosts(transp);
283249112Sjkim		else
284249112Sjkim			rawtest(NULL);
285249112Sjkim	} else {
286249112Sjkim		for (; optind < argc; optind++) {
287197104Sjkim			if (transp)
288249112Sjkim				s == 0 ?
289249112Sjkim				    onehost(argv[optind], transp) :
290193267Sjkim				    regtest(argv[optind], transp, "1", p);
291193267Sjkim			else
292193267Sjkim				rawtest(argv[optind]);
293193267Sjkim		}
294193267Sjkim	}
295283092Sjkim
296193267Sjkim	return EXIT_SUCCESS;
297193267Sjkim}
298193267Sjkim
299197104Sjkim#else
300249112Sjkim
301193267SjkimATF_TC(get_svc_addr_tcp);
302193267SjkimATF_TC_HEAD(get_svc_addr_tcp, tc)
303193267Sjkim{
304193267Sjkim	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for tcp");
305193267Sjkim
306193267Sjkim}
307193267Sjkim
308193267SjkimATF_TC_BODY(get_svc_addr_tcp, tc)
309193267Sjkim{
310193267Sjkim	onehost("localhost", "tcp");
311249112Sjkim
312249112Sjkim}
313249112Sjkim
314249112SjkimATF_TC(get_svc_addr_udp);
315193267SjkimATF_TC_HEAD(get_svc_addr_udp, tc)
316193267Sjkim{
317193267Sjkim	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for udp");
318193267Sjkim}
319193267Sjkim
320193267SjkimATF_TC_BODY(get_svc_addr_udp, tc)
321193267Sjkim{
322193267Sjkim	onehost("localhost", "udp");
323193267Sjkim
324249112Sjkim}
325249112Sjkim
326249112SjkimATF_TC(raw);
327249112SjkimATF_TC_HEAD(raw, tc)
328249112Sjkim{
329249112Sjkim	atf_tc_set_md_var(tc, "descr", "Checks svc raw");
330249112Sjkim}
331249112Sjkim
332249112SjkimATF_TC_BODY(raw, tc)
333249112Sjkim{
334193267Sjkim#ifdef __FreeBSD__
335249112Sjkim#ifdef __FreeBSD_bug_216954__
336249112Sjkim	atf_tc_expect_signal(SIGSEGV,
337193267Sjkim	    "fails with SIGSEGV only on ^/stable/10 -- bug # 216954");
338249112Sjkim#endif
339249112Sjkim#endif
340193267Sjkim	rawtest(NULL);
341249112Sjkim
342249112Sjkim}
343193267Sjkim
344249112SjkimATF_TC(tcp);
345249112SjkimATF_TC_HEAD(tcp, tc)
346193267Sjkim{
347249112Sjkim	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (select)");
348249112Sjkim#ifdef __FreeBSD__
349193267Sjkim	atf_tc_set_md_var(tc, "require.user", "root");
350249112Sjkim#endif
351249112Sjkim}
352193267Sjkim
353249112SjkimATF_TC_BODY(tcp, tc)
354249112Sjkim{
355193267Sjkim	regtest("localhost", "tcp", "1", 0);
356249112Sjkim
357249112Sjkim}
358193267Sjkim
359249112SjkimATF_TC(udp);
360249112SjkimATF_TC_HEAD(udp, tc)
361193267Sjkim{
362249112Sjkim	atf_tc_set_md_var(tc, "descr", "Checks svc udp (select)");
363249112Sjkim#ifdef __FreeBSD__
364193267Sjkim	atf_tc_set_md_var(tc, "require.user", "root");
365249112Sjkim#endif
366249112Sjkim}
367193267Sjkim
368249112SjkimATF_TC_BODY(udp, tc)
369249112Sjkim{
370197104Sjkim	regtest("localhost", "udp", "1", 0);
371249112Sjkim
372249112Sjkim}
373249112Sjkim
374193267SjkimATF_TC(tcp_poll);
375249112SjkimATF_TC_HEAD(tcp_poll, tc)
376249112Sjkim{
377249112Sjkim	atf_tc_set_md_var(tc, "descr", "Checks svc tcp (poll)");
378193267Sjkim#ifdef __FreeBSD__
379249112Sjkim	atf_tc_set_md_var(tc, "require.user", "root");
380249112Sjkim#endif
381249112Sjkim}
382197104Sjkim
383249112SjkimATF_TC_BODY(tcp_poll, tc)
384249112Sjkim{
385249112Sjkim	regtest("localhost", "tcp", "1", 1);
386193267Sjkim
387249112Sjkim}
388249112Sjkim
389249112SjkimATF_TC(udp_poll);
390193267SjkimATF_TC_HEAD(udp_poll, tc)
391249112Sjkim{
392249112Sjkim	atf_tc_set_md_var(tc, "descr", "Checks svc udp (poll)");
393249112Sjkim#ifdef __FreeBSD__
394193267Sjkim	atf_tc_set_md_var(tc, "require.user", "root");
395249112Sjkim#endif
396249112Sjkim}
397249112Sjkim
398228110SjkimATF_TC_BODY(udp_poll, tc)
399249112Sjkim{
400249112Sjkim	regtest("localhost", "udp", "1", 1);
401249112Sjkim
402228110Sjkim}
403249112Sjkim
404249112SjkimATF_TP_ADD_TCS(tp)
405249112Sjkim{
406193267Sjkim	ATF_TP_ADD_TC(tp, get_svc_addr_udp);
407249112Sjkim	ATF_TP_ADD_TC(tp, get_svc_addr_tcp);
408249112Sjkim	ATF_TP_ADD_TC(tp, raw);
409249112Sjkim	ATF_TP_ADD_TC(tp, tcp);
410193267Sjkim	ATF_TP_ADD_TC(tp, udp);
411249112Sjkim	ATF_TP_ADD_TC(tp, tcp_poll);
412249112Sjkim	ATF_TP_ADD_TC(tp, udp_poll);
413228110Sjkim
414249112Sjkim	return atf_no_error();
415249112Sjkim}
416228110Sjkim
417249112Sjkim#endif
418249112Sjkim