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
reply(caddr_t replyp,struct netbuf * raddrp,struct netconfig * nconf)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
onehost(const char * host,const char * transp)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
server(struct svc_req * rqstp,SVCXPRT * transp)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
rawtest(const char * arg)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
regtest(const char * hostname,const char * transp,const char * arg,int p)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
allhosts(const char * transp)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
main(int argc,char * argv[])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);
ATF_TC_HEAD(get_svc_addr_tcp,tc)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
ATF_TC_BODY(get_svc_addr_tcp,tc)312 ATF_TC_BODY(get_svc_addr_tcp, tc)
313 {
314 onehost("localhost", "tcp");
315
316 }
317
318 ATF_TC(get_svc_addr_udp);
ATF_TC_HEAD(get_svc_addr_udp,tc)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
ATF_TC_BODY(get_svc_addr_udp,tc)324 ATF_TC_BODY(get_svc_addr_udp, tc)
325 {
326 onehost("localhost", "udp");
327
328 }
329
330 ATF_TC(raw);
ATF_TC_HEAD(raw,tc)331 ATF_TC_HEAD(raw, tc)
332 {
333 atf_tc_set_md_var(tc, "descr", "Checks svc raw");
334 }
335
ATF_TC_BODY(raw,tc)336 ATF_TC_BODY(raw, tc)
337 {
338 rawtest(NULL);
339
340 }
341
342 ATF_TC(tcp);
ATF_TC_HEAD(tcp,tc)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
ATF_TC_BODY(tcp,tc)351 ATF_TC_BODY(tcp, tc)
352 {
353 regtest("localhost", "tcp", "1", 0);
354
355 }
356
357 ATF_TC(udp);
ATF_TC_HEAD(udp,tc)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
ATF_TC_BODY(udp,tc)366 ATF_TC_BODY(udp, tc)
367 {
368 regtest("localhost", "udp", "1", 0);
369
370 }
371
372 ATF_TC(tcp_poll);
ATF_TC_HEAD(tcp_poll,tc)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
ATF_TC_BODY(tcp_poll,tc)381 ATF_TC_BODY(tcp_poll, tc)
382 {
383 regtest("localhost", "tcp", "1", 1);
384
385 }
386
387 ATF_TC(udp_poll);
ATF_TC_HEAD(udp_poll,tc)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
ATF_TC_BODY(udp_poll,tc)396 ATF_TC_BODY(udp_poll, tc)
397 {
398 regtest("localhost", "udp", "1", 1);
399
400 }
401
ATF_TP_ADD_TCS(tp)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