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