pmap_rmt.c revision 1901
11901Swollman/* 21901Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 31901Swollman * unrestricted use provided that this legend is included on all tape 41901Swollman * media and as a part of the software program in whole or part. Users 51901Swollman * may copy or modify Sun RPC without charge, but are not authorized 61901Swollman * to license or distribute it to anyone else except as part of a product or 71901Swollman * program developed by the user. 81901Swollman * 91901Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 101901Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 111901Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 121901Swollman * 131901Swollman * Sun RPC is provided with no support and without any obligation on the 141901Swollman * part of Sun Microsystems, Inc. to assist in its use, correction, 151901Swollman * modification or enhancement. 161901Swollman * 171901Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 181901Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 191901Swollman * OR ANY PART THEREOF. 201901Swollman * 211901Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 221901Swollman * or profits or other special, indirect and consequential damages, even if 231901Swollman * Sun has been advised of the possibility of such damages. 241901Swollman * 251901Swollman * Sun Microsystems, Inc. 261901Swollman * 2550 Garcia Avenue 271901Swollman * Mountain View, California 94043 281901Swollman */ 291901Swollman 301901Swollman#if defined(LIBC_SCCS) && !defined(lint) 311901Swollman/*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/ 321901Swollman/*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/ 331901Swollmanstatic char *rcsid = "$Id: pmap_rmt.c,v 1.1 1993/10/27 05:40:40 paul Exp $"; 341901Swollman#endif 351901Swollman 361901Swollman/* 371901Swollman * pmap_rmt.c 381901Swollman * Client interface to pmap rpc service. 391901Swollman * remote call and broadcast service 401901Swollman * 411901Swollman * Copyright (C) 1984, Sun Microsystems, Inc. 421901Swollman */ 431901Swollman 441901Swollman#include <rpc/rpc.h> 451901Swollman#include <rpc/pmap_prot.h> 461901Swollman#include <rpc/pmap_clnt.h> 471901Swollman#include <rpc/pmap_rmt.h> 481901Swollman#include <sys/socket.h> 491901Swollman#include <stdio.h> 501901Swollman#include <errno.h> 511901Swollman#include <net/if.h> 521901Swollman#include <sys/ioctl.h> 531901Swollman#include <arpa/inet.h> 541901Swollman#define MAX_BROADCAST_SIZE 1400 551901Swollman 561901Swollmanextern int errno; 571901Swollmanstatic struct timeval timeout = { 3, 0 }; 581901Swollman 591901Swollman 601901Swollman/* 611901Swollman * pmapper remote-call-service interface. 621901Swollman * This routine is used to call the pmapper remote call service 631901Swollman * which will look up a service program in the port maps, and then 641901Swollman * remotely call that routine with the given parameters. This allows 651901Swollman * programs to do a lookup and call in one step. 661901Swollman*/ 671901Swollmanenum clnt_stat 681901Swollmanpmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) 691901Swollman struct sockaddr_in *addr; 701901Swollman u_long prog, vers, proc; 711901Swollman xdrproc_t xdrargs, xdrres; 721901Swollman caddr_t argsp, resp; 731901Swollman struct timeval tout; 741901Swollman u_long *port_ptr; 751901Swollman{ 761901Swollman int socket = -1; 771901Swollman register CLIENT *client; 781901Swollman struct rmtcallargs a; 791901Swollman struct rmtcallres r; 801901Swollman enum clnt_stat stat; 811901Swollman 821901Swollman addr->sin_port = htons(PMAPPORT); 831901Swollman client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); 841901Swollman if (client != (CLIENT *)NULL) { 851901Swollman a.prog = prog; 861901Swollman a.vers = vers; 871901Swollman a.proc = proc; 881901Swollman a.args_ptr = argsp; 891901Swollman a.xdr_args = xdrargs; 901901Swollman r.port_ptr = port_ptr; 911901Swollman r.results_ptr = resp; 921901Swollman r.xdr_results = xdrres; 931901Swollman stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, 941901Swollman xdr_rmtcallres, &r, tout); 951901Swollman CLNT_DESTROY(client); 961901Swollman } else { 971901Swollman stat = RPC_FAILED; 981901Swollman } 991901Swollman (void)close(socket); 1001901Swollman addr->sin_port = 0; 1011901Swollman return (stat); 1021901Swollman} 1031901Swollman 1041901Swollman 1051901Swollman/* 1061901Swollman * XDR remote call arguments 1071901Swollman * written for XDR_ENCODE direction only 1081901Swollman */ 1091901Swollmanbool_t 1101901Swollmanxdr_rmtcall_args(xdrs, cap) 1111901Swollman register XDR *xdrs; 1121901Swollman register struct rmtcallargs *cap; 1131901Swollman{ 1141901Swollman u_int lenposition, argposition, position; 1151901Swollman 1161901Swollman if (xdr_u_long(xdrs, &(cap->prog)) && 1171901Swollman xdr_u_long(xdrs, &(cap->vers)) && 1181901Swollman xdr_u_long(xdrs, &(cap->proc))) { 1191901Swollman lenposition = XDR_GETPOS(xdrs); 1201901Swollman if (! xdr_u_long(xdrs, &(cap->arglen))) 1211901Swollman return (FALSE); 1221901Swollman argposition = XDR_GETPOS(xdrs); 1231901Swollman if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) 1241901Swollman return (FALSE); 1251901Swollman position = XDR_GETPOS(xdrs); 1261901Swollman cap->arglen = (u_long)position - (u_long)argposition; 1271901Swollman XDR_SETPOS(xdrs, lenposition); 1281901Swollman if (! xdr_u_long(xdrs, &(cap->arglen))) 1291901Swollman return (FALSE); 1301901Swollman XDR_SETPOS(xdrs, position); 1311901Swollman return (TRUE); 1321901Swollman } 1331901Swollman return (FALSE); 1341901Swollman} 1351901Swollman 1361901Swollman/* 1371901Swollman * XDR remote call results 1381901Swollman * written for XDR_DECODE direction only 1391901Swollman */ 1401901Swollmanbool_t 1411901Swollmanxdr_rmtcallres(xdrs, crp) 1421901Swollman register XDR *xdrs; 1431901Swollman register struct rmtcallres *crp; 1441901Swollman{ 1451901Swollman caddr_t port_ptr; 1461901Swollman 1471901Swollman port_ptr = (caddr_t)crp->port_ptr; 1481901Swollman if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), 1491901Swollman xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { 1501901Swollman crp->port_ptr = (u_long *)port_ptr; 1511901Swollman return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); 1521901Swollman } 1531901Swollman return (FALSE); 1541901Swollman} 1551901Swollman 1561901Swollman 1571901Swollman/* 1581901Swollman * The following is kludged-up support for simple rpc broadcasts. 1591901Swollman * Someday a large, complicated system will replace these trivial 1601901Swollman * routines which only support udp/ip . 1611901Swollman */ 1621901Swollman 1631901Swollmanstatic int 1641901Swollmangetbroadcastnets(addrs, sock, buf) 1651901Swollman struct in_addr *addrs; 1661901Swollman int sock; /* any valid socket will do */ 1671901Swollman char *buf; /* why allocxate more when we can use existing... */ 1681901Swollman{ 1691901Swollman struct ifconf ifc; 1701901Swollman struct ifreq ifreq, *ifr; 1711901Swollman struct sockaddr_in *sin; 1721901Swollman char *cp, *cplim; 1731901Swollman int n, i = 0; 1741901Swollman 1751901Swollman ifc.ifc_len = UDPMSGSIZE; 1761901Swollman ifc.ifc_buf = buf; 1771901Swollman if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 1781901Swollman perror("broadcast: ioctl (get interface configuration)"); 1791901Swollman return (0); 1801901Swollman } 1811901Swollman#define max(a, b) (a > b ? a : b) 1821901Swollman#define size(p) max((p).sa_len, sizeof(p)) 1831901Swollman cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 1841901Swollman for (cp = buf; cp < cplim; 1851901Swollman cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 1861901Swollman ifr = (struct ifreq *)cp; 1871901Swollman if (ifr->ifr_addr.sa_family != AF_INET) 1881901Swollman continue; 1891901Swollman ifreq = *ifr; 1901901Swollman if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 1911901Swollman perror("broadcast: ioctl (get interface flags)"); 1921901Swollman continue; 1931901Swollman } 1941901Swollman if ((ifreq.ifr_flags & IFF_BROADCAST) && 1951901Swollman (ifreq.ifr_flags & IFF_UP)) { 1961901Swollman sin = (struct sockaddr_in *)&ifr->ifr_addr; 1971901Swollman#ifdef SIOCGIFBRDADDR /* 4.3BSD */ 1981901Swollman if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 1991901Swollman addrs[i++] = 2001901Swollman inet_makeaddr(inet_netof(sin->sin_addr), 2011901Swollman INADDR_ANY); 2021901Swollman } else { 2031901Swollman addrs[i++] = ((struct sockaddr_in*) 2041901Swollman &ifreq.ifr_addr)->sin_addr; 2051901Swollman } 2061901Swollman#else /* 4.2 BSD */ 2071901Swollman addrs[i++] = inet_makeaddr(inet_netof(sin->sin_addr), 2081901Swollman INADDR_ANY); 2091901Swollman#endif 2101901Swollman } 2111901Swollman } 2121901Swollman return (i); 2131901Swollman} 2141901Swollman 2151901Swollmantypedef bool_t (*resultproc_t)(); 2161901Swollman 2171901Swollmanenum clnt_stat 2181901Swollmanclnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 2191901Swollman u_long prog; /* program number */ 2201901Swollman u_long vers; /* version number */ 2211901Swollman u_long proc; /* procedure number */ 2221901Swollman xdrproc_t xargs; /* xdr routine for args */ 2231901Swollman caddr_t argsp; /* pointer to args */ 2241901Swollman xdrproc_t xresults; /* xdr routine for results */ 2251901Swollman caddr_t resultsp; /* pointer to results */ 2261901Swollman resultproc_t eachresult; /* call with each result obtained */ 2271901Swollman{ 2281901Swollman enum clnt_stat stat; 2291901Swollman AUTH *unix_auth = authunix_create_default(); 2301901Swollman XDR xdr_stream; 2311901Swollman register XDR *xdrs = &xdr_stream; 2321901Swollman int outlen, inlen, fromlen, nets; 2331901Swollman register int sock; 2341901Swollman int on = 1; 2351901Swollman#ifdef FD_SETSIZE 2361901Swollman fd_set mask; 2371901Swollman fd_set readfds; 2381901Swollman#else 2391901Swollman int readfds; 2401901Swollman register int mask; 2411901Swollman#endif /* def FD_SETSIZE */ 2421901Swollman register int i; 2431901Swollman bool_t done = FALSE; 2441901Swollman register u_long xid; 2451901Swollman u_long port; 2461901Swollman struct in_addr addrs[20]; 2471901Swollman struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ 2481901Swollman struct rmtcallargs a; 2491901Swollman struct rmtcallres r; 2501901Swollman struct rpc_msg msg; 2511901Swollman struct timeval t; 2521901Swollman char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; 2531901Swollman 2541901Swollman /* 2551901Swollman * initialization: create a socket, a broadcast address, and 2561901Swollman * preserialize the arguments into a send buffer. 2571901Swollman */ 2581901Swollman if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 2591901Swollman perror("Cannot create socket for broadcast rpc"); 2601901Swollman stat = RPC_CANTSEND; 2611901Swollman goto done_broad; 2621901Swollman } 2631901Swollman#ifdef SO_BROADCAST 2641901Swollman if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 2651901Swollman perror("Cannot set socket option SO_BROADCAST"); 2661901Swollman stat = RPC_CANTSEND; 2671901Swollman goto done_broad; 2681901Swollman } 2691901Swollman#endif /* def SO_BROADCAST */ 2701901Swollman#ifdef FD_SETSIZE 2711901Swollman FD_ZERO(&mask); 2721901Swollman FD_SET(sock, &mask); 2731901Swollman#else 2741901Swollman mask = (1 << sock); 2751901Swollman#endif /* def FD_SETSIZE */ 2761901Swollman nets = getbroadcastnets(addrs, sock, inbuf); 2771901Swollman bzero((char *)&baddr, sizeof (baddr)); 2781901Swollman baddr.sin_family = AF_INET; 2791901Swollman baddr.sin_port = htons(PMAPPORT); 2801901Swollman baddr.sin_addr.s_addr = htonl(INADDR_ANY); 2811901Swollman/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ 2821901Swollman (void)gettimeofday(&t, (struct timezone *)0); 2831901Swollman msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; 2841901Swollman t.tv_usec = 0; 2851901Swollman msg.rm_direction = CALL; 2861901Swollman msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 2871901Swollman msg.rm_call.cb_prog = PMAPPROG; 2881901Swollman msg.rm_call.cb_vers = PMAPVERS; 2891901Swollman msg.rm_call.cb_proc = PMAPPROC_CALLIT; 2901901Swollman msg.rm_call.cb_cred = unix_auth->ah_cred; 2911901Swollman msg.rm_call.cb_verf = unix_auth->ah_verf; 2921901Swollman a.prog = prog; 2931901Swollman a.vers = vers; 2941901Swollman a.proc = proc; 2951901Swollman a.xdr_args = xargs; 2961901Swollman a.args_ptr = argsp; 2971901Swollman r.port_ptr = &port; 2981901Swollman r.xdr_results = xresults; 2991901Swollman r.results_ptr = resultsp; 3001901Swollman xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); 3011901Swollman if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { 3021901Swollman stat = RPC_CANTENCODEARGS; 3031901Swollman goto done_broad; 3041901Swollman } 3051901Swollman outlen = (int)xdr_getpos(xdrs); 3061901Swollman xdr_destroy(xdrs); 3071901Swollman /* 3081901Swollman * Basic loop: broadcast a packet and wait a while for response(s). 3091901Swollman * The response timeout grows larger per iteration. 3101901Swollman */ 3111901Swollman for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { 3121901Swollman for (i = 0; i < nets; i++) { 3131901Swollman baddr.sin_addr = addrs[i]; 3141901Swollman if (sendto(sock, outbuf, outlen, 0, 3151901Swollman (struct sockaddr *)&baddr, 3161901Swollman sizeof (struct sockaddr)) != outlen) { 3171901Swollman perror("Cannot send broadcast packet"); 3181901Swollman stat = RPC_CANTSEND; 3191901Swollman goto done_broad; 3201901Swollman } 3211901Swollman } 3221901Swollman if (eachresult == NULL) { 3231901Swollman stat = RPC_SUCCESS; 3241901Swollman goto done_broad; 3251901Swollman } 3261901Swollman recv_again: 3271901Swollman msg.acpted_rply.ar_verf = _null_auth; 3281901Swollman msg.acpted_rply.ar_results.where = (caddr_t)&r; 3291901Swollman msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 3301901Swollman readfds = mask; 3311901Swollman switch (select(_rpc_dtablesize(), &readfds, (int *)NULL, 3321901Swollman (int *)NULL, &t)) { 3331901Swollman 3341901Swollman case 0: /* timed out */ 3351901Swollman stat = RPC_TIMEDOUT; 3361901Swollman continue; 3371901Swollman 3381901Swollman case -1: /* some kind of error */ 3391901Swollman if (errno == EINTR) 3401901Swollman goto recv_again; 3411901Swollman perror("Broadcast select problem"); 3421901Swollman stat = RPC_CANTRECV; 3431901Swollman goto done_broad; 3441901Swollman 3451901Swollman } /* end of select results switch */ 3461901Swollman try_again: 3471901Swollman fromlen = sizeof(struct sockaddr); 3481901Swollman inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, 3491901Swollman (struct sockaddr *)&raddr, &fromlen); 3501901Swollman if (inlen < 0) { 3511901Swollman if (errno == EINTR) 3521901Swollman goto try_again; 3531901Swollman perror("Cannot receive reply to broadcast"); 3541901Swollman stat = RPC_CANTRECV; 3551901Swollman goto done_broad; 3561901Swollman } 3571901Swollman if (inlen < sizeof(u_long)) 3581901Swollman goto recv_again; 3591901Swollman /* 3601901Swollman * see if reply transaction id matches sent id. 3611901Swollman * If so, decode the results. 3621901Swollman */ 3631901Swollman xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 3641901Swollman if (xdr_replymsg(xdrs, &msg)) { 3651901Swollman if ((msg.rm_xid == xid) && 3661901Swollman (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 3671901Swollman (msg.acpted_rply.ar_stat == SUCCESS)) { 3681901Swollman raddr.sin_port = htons((u_short)port); 3691901Swollman done = (*eachresult)(resultsp, &raddr); 3701901Swollman } 3711901Swollman /* otherwise, we just ignore the errors ... */ 3721901Swollman } else { 3731901Swollman#ifdef notdef 3741901Swollman /* some kind of deserialization problem ... */ 3751901Swollman if (msg.rm_xid == xid) 3761901Swollman fprintf(stderr, "Broadcast deserialization problem"); 3771901Swollman /* otherwise, just random garbage */ 3781901Swollman#endif 3791901Swollman } 3801901Swollman xdrs->x_op = XDR_FREE; 3811901Swollman msg.acpted_rply.ar_results.proc = xdr_void; 3821901Swollman (void)xdr_replymsg(xdrs, &msg); 3831901Swollman (void)(*xresults)(xdrs, resultsp); 3841901Swollman xdr_destroy(xdrs); 3851901Swollman if (done) { 3861901Swollman stat = RPC_SUCCESS; 3871901Swollman goto done_broad; 3881901Swollman } else { 3891901Swollman goto recv_again; 3901901Swollman } 3911901Swollman } 3921901Swollmandone_broad: 3931901Swollman (void)close(sock); 3941901Swollman AUTH_DESTROY(unix_auth); 3951901Swollman return (stat); 3961901Swollman} 3971901Swollman 398