1 /* 2 * Copyright (c) 2009, Sun Microsystems, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of Sun Microsystems, Inc. nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /* 29 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 30 */ 31 32 /* 33 * Implements a connectionless client side RPC. 34 */ 35 #include <wintirpc.h> 36 //#include <pthread.h> 37 #include <reentrant.h> 38 #include <sys/types.h> 39 //#include <sys/socket.h> 40 //#include <stdint.h> 41 //#include <sys/poll.h> 42 43 //#include <sys/time.h> 44 45 //#include <sys/ioctl.h> 46 #include <rpc/clnt.h> 47 //#include <arpa/inet.h> 48 #include <rpc/rpc.h> 49 #include <rpc/xdr.h> 50 #include <errno.h> 51 #include <stdlib.h> 52 #include <string.h> 53 //#include <signal.h> 54 //#include <unistd.h> 55 //#include <err.h> 56 #include "rpc_com.h" 57 58 #ifdef IP_RECVERR 59 #include <asm/types.h> 60 #include <linux/errqueue.h> 61 #include <sys/uio.h> 62 #endif 63 64 65 #define MAX_DEFAULT_FDS 20000 66 67 static struct clnt_ops *clnt_dg_ops(void); 68 static bool_t time_not_ok(struct timeval *); 69 static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 70 xdrproc_t, void *, struct timeval); 71 static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 72 static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 73 static void clnt_dg_abort(CLIENT *); 74 static bool_t clnt_dg_control(CLIENT *, u_int, void *); 75 static void clnt_dg_destroy(CLIENT *); 76 77 78 /* 79 * This machinery implements per-fd locks for MT-safety. It is not 80 * sufficient to do per-CLIENT handle locks for MT-safety because a 81 * user may create more than one CLIENT handle with the same fd behind 82 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 83 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 84 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 85 * CLIENT handle created for that fd. 86 * The current implementation holds locks across the entire RPC and reply, 87 * including retransmissions. Yes, this is silly, and as soon as this 88 * code is proven to work, this should be the first thing fixed. One step 89 * at a time. 90 */ 91 static int *dg_fd_locks; 92 extern mutex_t clnt_fd_lock; 93 static cond_t *dg_cv; 94 #ifndef _WIN32 95 #define release_fd_lock(fd, mask) { \ 96 mutex_lock(&clnt_fd_lock); \ 97 dg_fd_locks[fd] = 0; \ 98 mutex_unlock(&clnt_fd_lock); \ 99 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 100 cond_signal(&dg_cv[fd]); \ 101 } 102 #else 103 /* XXX Needs Windows signal/event stuff XXX */ 104 #define release_fd_lock(fd, mask) { \ 105 mutex_lock(&clnt_fd_lock); \ 106 dg_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 0; \ 107 mutex_unlock(&clnt_fd_lock); \ 108 \ 109 cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(fd)]); \ 110 } 111 #endif 112 113 static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 114 115 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 116 117 /* 118 * Private data kept per client handle 119 */ 120 struct cu_data { 121 SOCKET cu_fd; /* connections fd */ 122 bool_t cu_closeit; /* opened by library */ 123 struct sockaddr_storage cu_raddr; /* remote address */ 124 int cu_rlen; 125 struct timeval cu_wait; /* retransmit interval */ 126 struct timeval cu_total; /* total time for the call */ 127 struct rpc_err cu_error; 128 XDR cu_outxdrs; 129 u_int cu_xdrpos; 130 u_int cu_sendsz; /* send size */ 131 char *cu_outbuf; 132 u_int cu_recvsz; /* recv size */ 133 int cu_async; 134 int cu_connect; /* Use connect(). */ 135 int cu_connected; /* Have done connect(). */ 136 char cu_inbuf[1]; 137 }; 138 139 /* 140 * Connection less client creation returns with client handle parameters. 141 * Default options are set, which the user can change using clnt_control(). 142 * fd should be open and bound. 143 * NB: The rpch->cl_auth is initialized to null authentication. 144 * Caller may wish to set this something more useful. 145 * 146 * sendsz and recvsz are the maximum allowable packet sizes that can be 147 * sent and received. Normally they are the same, but they can be 148 * changed to improve the program efficiency and buffer allocation. 149 * If they are 0, use the transport default. 150 * 151 * If svcaddr is NULL, returns NULL. 152 */ 153 CLIENT * 154 clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 155 SOCKET fd; /* open file descriptor */ 156 const struct netbuf *svcaddr; /* servers address */ 157 rpcprog_t program; /* program number */ 158 rpcvers_t version; /* version number */ 159 u_int sendsz; /* buffer recv size */ 160 u_int recvsz; /* buffer send size */ 161 { 162 CLIENT *cl = NULL; /* client handle */ 163 struct cu_data *cu = NULL; /* private data */ 164 struct timeval now; 165 struct rpc_msg call_msg; 166 #ifndef _WIN32 167 sigset_t mask; 168 sigset_t newmask; 169 #else 170 /* XXX Need Windows signal/event stuff here XXX */ 171 #endif 172 struct __rpc_sockinfo si; 173 u_long one = 1; 174 175 #ifndef _WIN32 176 sigfillset(&newmask); 177 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 178 #else 179 /* XXX Need Windows signal/event stuff here XXX */ 180 #endif 181 mutex_lock(&clnt_fd_lock); 182 if (dg_fd_locks == (int *) NULL) { 183 int cv_allocsz; 184 size_t fd_allocsz; 185 int dtbsize = __rpc_dtbsize(); 186 187 fd_allocsz = dtbsize * sizeof (int); 188 dg_fd_locks = (int *) mem_alloc(fd_allocsz); 189 if (dg_fd_locks == (int *) NULL) { 190 mutex_unlock(&clnt_fd_lock); 191 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 192 goto err1; 193 } else 194 memset(dg_fd_locks, 0, fd_allocsz); 195 196 cv_allocsz = dtbsize * sizeof (cond_t); 197 dg_cv = (cond_t *) mem_alloc(cv_allocsz); 198 if (dg_cv == (cond_t *) NULL) { 199 mem_free(dg_fd_locks, fd_allocsz); 200 dg_fd_locks = (int *) NULL; 201 mutex_unlock(&clnt_fd_lock); 202 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 203 goto err1; 204 } else { 205 int i; 206 207 for (i = 0; i < dtbsize; i++) 208 cond_init(&dg_cv[i], 0, (void *) 0); 209 } 210 } 211 212 mutex_unlock(&clnt_fd_lock); 213 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 214 215 if (svcaddr == NULL) { 216 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 217 return (NULL); 218 } 219 220 if (!__rpc_fd2sockinfo(fd, &si)) { 221 rpc_createerr.cf_stat = RPC_TLIERROR; 222 rpc_createerr.cf_error.re_errno = 0; 223 return (NULL); 224 } 225 /* 226 * Find the receive and the send size 227 */ 228 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 229 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 230 if ((sendsz == 0) || (recvsz == 0)) { 231 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 232 rpc_createerr.cf_error.re_errno = 0; 233 return (NULL); 234 } 235 236 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 237 goto err1; 238 /* 239 * Should be multiple of 4 for XDR. 240 */ 241 sendsz = ((sendsz + 3) / 4) * 4; 242 recvsz = ((recvsz + 3) / 4) * 4; 243 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 244 if (cu == NULL) 245 goto err1; 246 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 247 cu->cu_rlen = svcaddr->len; 248 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 249 /* Other values can also be set through clnt_control() */ 250 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 251 cu->cu_wait.tv_usec = 0; 252 cu->cu_total.tv_sec = -1; 253 cu->cu_total.tv_usec = -1; 254 cu->cu_sendsz = sendsz; 255 cu->cu_recvsz = recvsz; 256 cu->cu_async = FALSE; 257 cu->cu_connect = FALSE; 258 cu->cu_connected = FALSE; 259 (void) gettimeofday(&now, NULL); 260 // call_msg.rm_xid = __RPC_GETXID(&now); 261 262 call_msg.rm_xid = ((u_int32_t)_getpid() ^ (u_int32_t)(&now)->tv_sec ^ (u_int32_t)(&now)->tv_usec); 263 call_msg.rm_call.cb_prog = program; 264 call_msg.rm_call.cb_vers = version; 265 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 266 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 267 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 268 rpc_createerr.cf_error.re_errno = 0; 269 goto err2; 270 } 271 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 272 273 /* XXX fvdl - do we still want this? */ 274 #if 0 275 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 276 #endif 277 #ifdef IP_RECVERR 278 { 279 int on = 1; 280 setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on)); 281 } 282 #endif 283 ioctlsocket(fd, FIONBIO, &one); 284 /* 285 * By default, closeit is always FALSE. It is users responsibility 286 * to do a close on it, else the user may use clnt_control 287 * to let clnt_destroy do it for him/her. 288 */ 289 cu->cu_closeit = FALSE; 290 cu->cu_fd = fd; 291 cl->cl_ops = clnt_dg_ops(); 292 cl->cl_private = (caddr_t)(void *)cu; 293 cl->cl_auth = authnone_create(); 294 cl->cl_tp = NULL; 295 cl->cl_netid = NULL; 296 297 return (cl); 298 err1: 299 //warnx(mem_err_clnt_dg); 300 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 301 rpc_createerr.cf_error.re_errno = errno; 302 err2: 303 if (cl) { 304 mem_free(cl, sizeof (CLIENT)); 305 if (cu) 306 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 307 } 308 return (NULL); 309 } 310 311 static enum clnt_stat 312 clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 313 CLIENT *cl; /* client handle */ 314 rpcproc_t proc; /* procedure number */ 315 xdrproc_t xargs; /* xdr routine for args */ 316 void *argsp; /* pointer to args */ 317 xdrproc_t xresults; /* xdr routine for results */ 318 void *resultsp; /* pointer to results */ 319 struct timeval utimeout; /* seconds to wait before giving up */ 320 { 321 struct cu_data *cu = (struct cu_data *)cl->cl_private; 322 XDR *xdrs; 323 size_t outlen = 0; 324 struct rpc_msg reply_msg; 325 XDR reply_xdrs; 326 bool_t ok; 327 int nrefreshes = 2; /* number of times to refresh cred */ 328 struct timeval timeout; 329 struct pollfd fd; 330 int total_time, nextsend_time, tv=0; 331 struct sockaddr *sa; 332 #ifndef _WIN32 333 sigset_t mask; 334 sigset_t newmask; 335 #else 336 /* XXX Need Windows signal/event stuff here XXX */ 337 #endif 338 socklen_t inlen, salen; 339 ssize_t recvlen = 0; 340 int rpc_lock_value; 341 u_int32_t xid, inval, outval; 342 #ifdef __REACTOS__ 343 fd_set infd; 344 #endif 345 346 outlen = 0; 347 #ifndef _WIN32 348 sigfillset(&newmask); 349 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 350 #else 351 /* XXX Need Windows signal/event stuff here XXX */ 352 #endif 353 mutex_lock(&clnt_fd_lock); 354 while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) 355 cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); 356 rpc_lock_value = 1; 357 dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)] = rpc_lock_value; 358 mutex_unlock(&clnt_fd_lock); 359 if (cu->cu_total.tv_usec == -1) { 360 timeout = utimeout; /* use supplied timeout */ 361 } else { 362 timeout = cu->cu_total; /* use default timeout */ 363 } 364 total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; 365 nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; 366 367 if (cu->cu_connect && !cu->cu_connected) { 368 if (connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, 369 cu->cu_rlen) < 0) { 370 cu->cu_error.re_errno = errno; 371 cu->cu_error.re_status = RPC_CANTSEND; 372 goto out; 373 } 374 cu->cu_connected = 1; 375 } 376 if (cu->cu_connected) { 377 sa = NULL; 378 salen = 0; 379 } else { 380 sa = (struct sockaddr *)&cu->cu_raddr; 381 salen = cu->cu_rlen; 382 } 383 384 /* Clean up in case the last call ended in a longjmp(3) call. */ 385 call_again: 386 xdrs = &(cu->cu_outxdrs); 387 if (cu->cu_async == TRUE && xargs == NULL) 388 goto get_reply; 389 xdrs->x_op = XDR_ENCODE; 390 XDR_SETPOS(xdrs, cu->cu_xdrpos); 391 /* 392 * the transaction is the first thing in the out buffer 393 * XXX Yes, and it's in network byte order, so we should to 394 * be careful when we increment it, shouldn't we. 395 */ 396 xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); 397 xid++; 398 *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); 399 400 if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 401 (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || 402 (! (*xargs)(xdrs, argsp))) { 403 cu->cu_error.re_status = RPC_CANTENCODEARGS; 404 goto out; 405 } 406 outlen = (size_t)XDR_GETPOS(xdrs); 407 408 /* 409 * Hack to provide rpc-based message passing 410 */ 411 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 412 cu->cu_error.re_status = RPC_TIMEDOUT; 413 goto out; 414 } 415 416 send_again: 417 if (total_time <= 0) { 418 cu->cu_error.re_status = RPC_TIMEDOUT; 419 goto out; 420 } 421 nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; 422 if (sendto(cu->cu_fd, cu->cu_outbuf, (int)outlen, 0, sa, salen) != outlen) { 423 cu->cu_error.re_errno = errno; 424 cu->cu_error.re_status = RPC_CANTSEND; 425 goto out; 426 } 427 428 get_reply: 429 430 /* 431 * sub-optimal code appears here because we have 432 * some clock time to spare while the packets are in flight. 433 * (We assume that this is actually only executed once.) 434 */ 435 reply_msg.acpted_rply.ar_verf = _null_auth; 436 reply_msg.acpted_rply.ar_results.where = resultsp; 437 reply_msg.acpted_rply.ar_results.proc = xresults; 438 439 fd.fd = cu->cu_fd; 440 fd.events = POLLIN; 441 fd.revents = 0; 442 while (total_time > 0) { 443 tv = total_time < nextsend_time ? total_time : nextsend_time; 444 #ifndef __REACTOS__ 445 switch (poll(&fd, 1, tv)) { 446 #else 447 #ifdef IP_RECVERR 448 #error Not supported! 449 #endif 450 /* ReactOS: use select instead of poll */ 451 FD_ZERO(&infd); 452 FD_SET(cu->cu_fd, &infd); 453 454 timeout.tv_sec = 0; 455 timeout.tv_usec = tv * 1000; 456 457 switch (select(0, &infd, NULL, NULL, &timeout)) { 458 #endif 459 case 0: 460 total_time -= tv; 461 goto send_again; 462 // XXX CHECK THIS FOR WINDOWS! 463 case -1: 464 if (errno == EINTR) 465 continue; 466 cu->cu_error.re_status = RPC_CANTRECV; 467 cu->cu_error.re_errno = errno; 468 goto out; 469 } 470 break; 471 } 472 #ifdef IP_RECVERR 473 if (fd.revents & POLLERR) 474 { 475 struct msghdr msg; 476 struct cmsghdr *cmsg; 477 struct sock_extended_err *e; 478 struct sockaddr_in err_addr; 479 struct sockaddr_in *sin = (struct sockaddr_in *)&cu->cu_raddr; 480 struct iovec iov; 481 char *cbuf = (char *) alloca (outlen + 256); 482 int ret; 483 484 iov.iov_base = cbuf + 256; 485 iov.iov_len = outlen; 486 msg.msg_name = (void *) &err_addr; 487 msg.msg_namelen = sizeof (err_addr); 488 msg.msg_iov = &iov; 489 msg.msg_iovlen = 1; 490 msg.msg_flags = 0; 491 msg.msg_control = cbuf; 492 msg.msg_controllen = 256; 493 ret = recvmsg (cu->cu_fd, &msg, MSG_ERRQUEUE); 494 if (ret >= 0 495 && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0 496 && (msg.msg_flags & MSG_ERRQUEUE) 497 && ((msg.msg_namelen == 0 498 && ret >= 12) 499 || (msg.msg_namelen == sizeof (err_addr) 500 && err_addr.sin_family == AF_INET 501 && memcmp (&err_addr.sin_addr, &sin->sin_addr, 502 sizeof (err_addr.sin_addr)) == 0 503 && err_addr.sin_port == sin->sin_port))) 504 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; 505 cmsg = CMSG_NXTHDR (&msg, cmsg)) 506 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) 507 { 508 e = (struct sock_extended_err *) CMSG_DATA(cmsg); 509 cu->cu_error.re_errno = e->ee_errno; 510 release_fd_lock(cu->cu_fd, mask); 511 return (cu->cu_error.re_status = RPC_CANTRECV); 512 } 513 } 514 #endif 515 516 /* We have some data now */ 517 do { 518 recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, 519 cu->cu_recvsz, 0, NULL, NULL); 520 errno = WSAGetLastError(); 521 } while (recvlen == SOCKET_ERROR && errno == WSAEINTR); 522 if (recvlen == SOCKET_ERROR && errno != WSAEWOULDBLOCK) { 523 cu->cu_error.re_errno = errno; 524 cu->cu_error.re_status = RPC_CANTRECV; 525 goto out; 526 } 527 528 if (recvlen < sizeof(u_int32_t)) { 529 total_time -= tv; 530 goto send_again; 531 } 532 533 if (cu->cu_async == TRUE) 534 inlen = (socklen_t)recvlen; 535 else { 536 memcpy(&inval, cu->cu_inbuf, sizeof(u_int32_t)); 537 memcpy(&outval, cu->cu_outbuf, sizeof(u_int32_t)); 538 if (inval != outval) { 539 total_time -= tv; 540 goto send_again; 541 } 542 inlen = (socklen_t)recvlen; 543 } 544 545 /* 546 * now decode and validate the response 547 */ 548 549 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); 550 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 551 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 552 if (ok) { 553 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 554 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 555 cu->cu_error.re_status = RPC_SUCCESS; 556 else 557 _seterr_reply(&reply_msg, &(cu->cu_error)); 558 559 if (cu->cu_error.re_status == RPC_SUCCESS) { 560 if (! AUTH_VALIDATE(cl->cl_auth, 561 &reply_msg.acpted_rply.ar_verf, 0)) { 562 cu->cu_error.re_status = RPC_AUTHERROR; 563 cu->cu_error.re_why = AUTH_INVALIDRESP; 564 } 565 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 566 xdrs->x_op = XDR_FREE; 567 (void) xdr_opaque_auth(xdrs, 568 &(reply_msg.acpted_rply.ar_verf)); 569 } 570 } /* end successful completion */ 571 /* 572 * If unsuccesful AND error is an authentication error 573 * then refresh credentials and try again, else break 574 */ 575 else if (cu->cu_error.re_status == RPC_AUTHERROR) 576 /* maybe our credentials need to be refreshed ... */ 577 if (nrefreshes > 0 && 578 AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 579 nrefreshes--; 580 goto call_again; 581 } 582 /* end of unsuccessful completion */ 583 } /* end of valid reply message */ 584 else { 585 cu->cu_error.re_status = RPC_CANTDECODERES; 586 587 } 588 out: 589 release_fd_lock(cu->cu_fd, mask); 590 return (cu->cu_error.re_status); 591 } 592 593 static void 594 clnt_dg_geterr(cl, errp) 595 CLIENT *cl; 596 struct rpc_err *errp; 597 { 598 struct cu_data *cu = (struct cu_data *)cl->cl_private; 599 600 *errp = cu->cu_error; 601 } 602 603 static bool_t 604 clnt_dg_freeres(cl, xdr_res, res_ptr) 605 CLIENT *cl; 606 xdrproc_t xdr_res; 607 void *res_ptr; 608 { 609 struct cu_data *cu = (struct cu_data *)cl->cl_private; 610 XDR *xdrs = &(cu->cu_outxdrs); 611 bool_t dummy; 612 #ifndef _WIN32 613 sigset_t mask; 614 sigset_t newmask; 615 616 sigfillset(&newmask); 617 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 618 #else 619 /* XXX Need Windows signal/event stuff here XXX */ 620 #endif 621 mutex_lock(&clnt_fd_lock); 622 while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) 623 cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); 624 xdrs->x_op = XDR_FREE; 625 dummy = (*xdr_res)(xdrs, res_ptr); 626 mutex_unlock(&clnt_fd_lock); 627 // thr_sigsetmask(SIG_SETMASK, &mask, NULL); 628 cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)]); 629 return (dummy); 630 } 631 632 /*ARGSUSED*/ 633 static void 634 clnt_dg_abort(h) 635 CLIENT *h; 636 { 637 } 638 639 static bool_t 640 clnt_dg_control(cl, request, info) 641 CLIENT *cl; 642 u_int request; 643 void *info; 644 { 645 struct cu_data *cu = (struct cu_data *)cl->cl_private; 646 struct netbuf *addr; 647 #ifndef _WIN32 648 sigset_t mask; 649 sigset_t newmask; 650 #else 651 /* XXX Need Windows signal/event stuff here XXX */ 652 #endif 653 int rpc_lock_value; 654 655 #ifndef _WIN32 656 sigfillset(&newmask); 657 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 658 #else 659 /* XXX Need Windows signal/event stuff here XXX */ 660 #endif 661 mutex_lock(&clnt_fd_lock); 662 while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) 663 cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); 664 rpc_lock_value = 1; 665 dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)] = rpc_lock_value; 666 mutex_unlock(&clnt_fd_lock); 667 switch (request) { 668 case CLSET_FD_CLOSE: 669 cu->cu_closeit = TRUE; 670 release_fd_lock(cu->cu_fd, mask); 671 return (TRUE); 672 case CLSET_FD_NCLOSE: 673 cu->cu_closeit = FALSE; 674 release_fd_lock(cu->cu_fd, mask); 675 return (TRUE); 676 } 677 678 /* for other requests which use info */ 679 if (info == NULL) { 680 release_fd_lock(cu->cu_fd, mask); 681 return (FALSE); 682 } 683 switch (request) { 684 case CLSET_TIMEOUT: 685 if (time_not_ok((struct timeval *)info)) { 686 release_fd_lock(cu->cu_fd, mask); 687 return (FALSE); 688 } 689 cu->cu_total = *(struct timeval *)info; 690 break; 691 case CLGET_TIMEOUT: 692 *(struct timeval *)info = cu->cu_total; 693 break; 694 case CLGET_SERVER_ADDR: /* Give him the fd address */ 695 /* Now obsolete. Only for backward compatibility */ 696 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 697 break; 698 case CLSET_RETRY_TIMEOUT: 699 if (time_not_ok((struct timeval *)info)) { 700 release_fd_lock(cu->cu_fd, mask); 701 return (FALSE); 702 } 703 cu->cu_wait = *(struct timeval *)info; 704 break; 705 case CLGET_RETRY_TIMEOUT: 706 *(struct timeval *)info = cu->cu_wait; 707 break; 708 case CLGET_FD: 709 *(SOCKET *)info = cu->cu_fd; 710 break; 711 case CLGET_SVC_ADDR: 712 addr = (struct netbuf *)info; 713 addr->buf = &cu->cu_raddr; 714 addr->len = cu->cu_rlen; 715 addr->maxlen = sizeof cu->cu_raddr; 716 break; 717 case CLSET_SVC_ADDR: /* set to new address */ 718 addr = (struct netbuf *)info; 719 if (addr->len < sizeof cu->cu_raddr) { 720 release_fd_lock(cu->cu_fd, mask); 721 return (FALSE); 722 } 723 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 724 cu->cu_rlen = addr->len; 725 break; 726 case CLGET_XID: 727 /* 728 * use the knowledge that xid is the 729 * first element in the call structure *. 730 * This will get the xid of the PREVIOUS call 731 */ 732 *(u_int32_t *)info = 733 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 734 break; 735 736 case CLSET_XID: 737 /* This will set the xid of the NEXT call */ 738 *(u_int32_t *)(void *)cu->cu_outbuf = 739 htonl(*(u_int32_t *)info - 1); 740 /* decrement by 1 as clnt_dg_call() increments once */ 741 break; 742 743 case CLGET_VERS: 744 /* 745 * This RELIES on the information that, in the call body, 746 * the version number field is the fifth field from the 747 * begining of the RPC header. MUST be changed if the 748 * call_struct is changed 749 */ 750 *(u_int32_t *)info = 751 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 752 4 * BYTES_PER_XDR_UNIT)); 753 break; 754 755 case CLSET_VERS: 756 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 757 = htonl(*(u_int32_t *)info); 758 break; 759 760 case CLGET_PROG: 761 /* 762 * This RELIES on the information that, in the call body, 763 * the program number field is the fourth field from the 764 * begining of the RPC header. MUST be changed if the 765 * call_struct is changed 766 */ 767 *(u_int32_t *)info = 768 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 769 3 * BYTES_PER_XDR_UNIT)); 770 break; 771 772 case CLSET_PROG: 773 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 774 = htonl(*(u_int32_t *)info); 775 break; 776 case CLSET_ASYNC: 777 cu->cu_async = *(int *)info; 778 break; 779 case CLSET_CONNECT: 780 cu->cu_connect = *(int *)info; 781 break; 782 default: 783 release_fd_lock(cu->cu_fd, mask); 784 return (FALSE); 785 } 786 release_fd_lock(cu->cu_fd, mask); 787 return (TRUE); 788 } 789 790 static void 791 clnt_dg_destroy(cl) 792 CLIENT *cl; 793 { 794 struct cu_data *cu = (struct cu_data *)cl->cl_private; 795 SOCKET cu_fd = cu->cu_fd; 796 #ifndef _WIN32 797 sigset_t mask; 798 sigset_t newmask; 799 800 sigfillset(&newmask); 801 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 802 #else 803 /* XXX Need Windows signal/event stuff here XXX */ 804 #endif 805 mutex_lock(&clnt_fd_lock); 806 while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu_fd)]) 807 cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu_fd)], &clnt_fd_lock); 808 if (cu->cu_closeit) 809 (void)closesocket(cu_fd); 810 XDR_DESTROY(&(cu->cu_outxdrs)); 811 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 812 if (cl->cl_netid && cl->cl_netid[0]) 813 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 814 if (cl->cl_tp && cl->cl_tp[0]) 815 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 816 mem_free(cl, sizeof (CLIENT)); 817 mutex_unlock(&clnt_fd_lock); 818 // thr_sigsetmask(SIG_SETMASK, &mask, NULL); 819 cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(cu_fd)]); 820 } 821 822 static struct clnt_ops * 823 clnt_dg_ops() 824 { 825 static struct clnt_ops ops; 826 extern mutex_t ops_lock; 827 #ifndef _WIN32 828 sigset_t mask; 829 sigset_t newmask; 830 831 /* VARIABLES PROTECTED BY ops_lock: ops */ 832 833 sigfillset(&newmask); 834 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 835 #else 836 /* XXX Need Windows signal/event stuff here XXX */ 837 #endif 838 mutex_lock(&ops_lock); 839 if (ops.cl_call == NULL) { 840 ops.cl_call = clnt_dg_call; 841 ops.cl_abort = clnt_dg_abort; 842 ops.cl_geterr = clnt_dg_geterr; 843 ops.cl_freeres = clnt_dg_freeres; 844 ops.cl_destroy = clnt_dg_destroy; 845 ops.cl_control = clnt_dg_control; 846 } 847 mutex_unlock(&ops_lock); 848 // thr_sigsetmask(SIG_SETMASK, &mask, NULL); 849 return (&ops); 850 } 851 852 /* 853 * Make sure that the time is not garbage. -1 value is allowed. 854 */ 855 static bool_t 856 time_not_ok(t) 857 struct timeval *t; 858 { 859 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 860 t->tv_usec < -1 || t->tv_usec > 1000000); 861 } 862 863