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 
41 static int
42 reply(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 
61 extern bool_t __rpc_control(int, void *);
62 
63 static void
64 onehost(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 
111 static struct timeval 	tout = {1, 0};
112 
113 static void
114 server(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 
148 static int
149 rawtest(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 
184 static int
185 regtest(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
240 static void
241 allhosts(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 
252 int
253 main(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 
305 ATF_TC(get_svc_addr_tcp);
306 ATF_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 
312 ATF_TC_BODY(get_svc_addr_tcp, tc)
313 {
314 	onehost("localhost", "tcp");
315 
316 }
317 
318 ATF_TC(get_svc_addr_udp);
319 ATF_TC_HEAD(get_svc_addr_udp, tc)
320 {
321 	atf_tc_set_md_var(tc, "descr", "Checks CLGET_SVC_ADDR for udp");
322 }
323 
324 ATF_TC_BODY(get_svc_addr_udp, tc)
325 {
326 	onehost("localhost", "udp");
327 
328 }
329 
330 ATF_TC(raw);
331 ATF_TC_HEAD(raw, tc)
332 {
333 	atf_tc_set_md_var(tc, "descr", "Checks svc raw");
334 }
335 
336 ATF_TC_BODY(raw, tc)
337 {
338 	rawtest(NULL);
339 
340 }
341 
342 ATF_TC(tcp);
343 ATF_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 
351 ATF_TC_BODY(tcp, tc)
352 {
353 	regtest("localhost", "tcp", "1", 0);
354 
355 }
356 
357 ATF_TC(udp);
358 ATF_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 
366 ATF_TC_BODY(udp, tc)
367 {
368 	regtest("localhost", "udp", "1", 0);
369 
370 }
371 
372 ATF_TC(tcp_poll);
373 ATF_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 
381 ATF_TC_BODY(tcp_poll, tc)
382 {
383 	regtest("localhost", "tcp", "1", 1);
384 
385 }
386 
387 ATF_TC(udp_poll);
388 ATF_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 
396 ATF_TC_BODY(udp_poll, tc)
397 {
398 	regtest("localhost", "udp", "1", 1);
399 
400 }
401 
402 ATF_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