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