1
0
Files
irix-657m-src/irix/cmd/netman/lib/protocols/sunrpc_pmap.c
2022-09-29 17:59:04 +03:00

199 lines
4.4 KiB
C

/*
* Copyright 1989 Silicon Graphics, Inc. All rights reserved.
*
* Sun RPC portmap caching.
*/
#include <stdio.h>
#include <values.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include "cache.h"
#include "heap.h"
#include "protocols/ip.h"
/*
* Ripped off from Sun's pmap_getmaps, in order to shorten the timeout.
*/
static struct pmaplist *
getpmaplist(struct sockaddr_in *sin)
{
int socket;
struct pmaplist *maps;
struct timeval timeout;
CLIENT *client;
sin->sin_port = htons(PMAPPORT);
socket = RPC_ANYSOCK;
client = clnttcp_create(sin, PMAPPROG, PMAPVERS, &socket, 50, 500);
if (client == 0)
return 0;
maps = 0;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
(void) clnt_call(client, PMAPPROC_DUMP, xdr_void, (caddr_t) 0,
xdr_pmaplist, &maps, timeout);
clnt_destroy(client);
(void) close(socket);
return maps;
}
static void
freepmaplist(struct pmaplist *pml)
{
while (pml) {
struct pmaplist *tmp = pml->pml_next;
mem_free((void *) pml, sizeof *pml);
pml = tmp;
}
}
/*
* A portmapping cache element.
*/
struct pmapinfo {
struct pmaplist *pmaplist;
struct timeval expiration; /* XXX redundant given ent_exptime */
};
static Cache *portmappings;
static int
xdr_pmapinfo(XDR *xdr, struct pmapinfo **pip)
{
struct pmapinfo *pmi;
pmi = *pip;
switch (xdr->x_op) {
case XDR_DECODE:
if (pmi == 0) {
*pip = pmi = new(struct pmapinfo);
pmi->pmaplist = 0;
}
/* FALL THROUGH */
case XDR_ENCODE:
return xdr_pmaplist(xdr, &pmi->pmaplist)
&& xdr_long(xdr, &pmi->expiration.tv_sec)
&& xdr_long(xdr, &pmi->expiration.tv_usec);
case XDR_FREE:
freepmaplist(pmi->pmaplist);
delete(pmi);
*pip = 0;
}
return TRUE;
}
static void
sunrpc_dumpmapent(void *addr, void *info)
{
struct pmaplist *pml;
printf("host %s\n", ip_hostname(*(struct in_addr *)addr, IP_HOST));
for (pml = ((struct pmapinfo *)info)->pmaplist; pml;
pml = pml->pml_next) {
printf("prog %lu vers %lu prot %lu port %lu\n",
pml->pml_map.pm_prog, pml->pml_map.pm_vers,
pml->pml_map.pm_prot, pml->pml_map.pm_port);
}
}
static struct cacheops portmappingops =
{ { ip_hashaddr, ip_cmpaddrs, xdr_pmapinfo }, 0, sunrpc_dumpmapent };
#define UPTIMEOUT (1 HOUR) /* cache mappings up to one hour */
#define DOWNTIMEOUT (2 MINUTES) /* cache non-response this long */
static void
create_portmappings()
{
c_create("sunrpc.portmappings", 31, sizeof(struct in_addr), UPTIMEOUT,
&portmappingops, &portmappings);
}
struct pmaplist *
sunrpc_getmaps(struct in_addr addr)
{
struct timeval now;
Entry **ep, *ent;
struct pmapinfo *pmi;
struct pmaplist *pml;
struct sockaddr_in pmsin;
/*
* Automagically initialize the in_addr-to-pmapinfo cache.
*/
if (portmappings == 0)
create_portmappings();
/*
* Get current time and lookup pmapinfo. If info is stale,
* force a cache miss.
*/
gettimeofday(&now, (struct timezone *) 0);
ep = c_lookup(portmappings, &addr);
ent = *ep;
if (ent) {
pmi = ent->ent_value;
if (pmi && timercmp(&now, &pmi->expiration, <))
return pmi->pmaplist;
}
/*
* Cache miss. Get a new list before freeing the old one, in case
* a signal handler is messing with the cache.
*/
pmsin.sin_family = AF_INET;
pmsin.sin_addr.s_addr = htonl(addr.s_addr);
pml = getpmaplist(&pmsin);
if (ent)
freepmaplist(pmi->pmaplist);
else {
pmi = new(struct pmapinfo);
c_add(portmappings, &addr, pmi, ep);
}
pmi->pmaplist = pml;
pmi->expiration = now;
pmi->expiration.tv_sec += (pml) ? UPTIMEOUT : DOWNTIMEOUT;
return pml;
}
void
sunrpc_addmap(struct in_addr addr, struct pmap *pm)
{
Entry **ep, *ent;
struct pmapinfo *pmi;
struct pmaplist *pml;
if (portmappings == 0)
create_portmappings();
ep = c_lookup(portmappings, &addr);
ent = *ep;
if (ent) {
pmi = ent->ent_value;
for (pml = pmi->pmaplist; pml; pml = pml->pml_next)
if (pml->pml_map.pm_prog == pm->pm_prog
&& pml->pml_map.pm_vers == pm->pm_vers
&& pml->pml_map.pm_prot == pm->pm_prot) {
pml->pml_map.pm_port = pm->pm_port;
return;
}
pml = new(struct pmaplist);
pml->pml_map = *pm;
pml->pml_next = pmi->pmaplist;
pmi->pmaplist = pml;
} else {
pml = new(struct pmaplist);
pml->pml_map = *pm;
pml->pml_next = 0;
pmi = new(struct pmapinfo);
pmi->pmaplist = pml;
pmi->expiration.tv_sec = -1;
pmi->expiration.tv_usec = 0;
c_add(portmappings, &addr, pmi, ep);
}
}