RPC server -- How to detect death of client? -- (a tad long)
Mike Hoegeman
mh at roger.imsd.contel.com
Sat Mar 23 06:20:20 AEST 1991
In article <1972 at brchh104.bnr.ca> anund at idt.unit.no (Anund Lie) writes:
>When running Sun RPC over TCP (or other connection-oriented services, for
>that matter), how can the server detect that a client process has died?
>(More precisely: That no process has the other end of the connection
>open.)
I've seen a couple of questions like this so i'll post below an example of
how I deal with client management in a tcp based RPC service. The comments
explain things fairly well but if anyone has any questions go ahead and
drop me a line
mike hoegeman, mh at awds.imsd.contel.com
------ example below -------
#include <stdio.h>
#include <rpc/rpc.h>
#include "db.h" /* your service.h goes here */
#define LogM fprintf
#define AS_ERROR stderr
#define AS_DEBUG stderr
#define LogInit(X)
#include <sys/errno.h>
extern void db_program_1();
SVCXPRT *transp;
main()
{
LogInit();
(void) pmap_unset(DB_PROGRAM, DB_VERSION);
if (!svc_register(transp,
DB_PROGRAM, DB_VERSION, db_program_1, IPPROTO_UDP))
{
fprintf(stderr, "unable to register (DB_PROGRAM, DB_VERSION, udp).\n");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL)
{
(void) fprintf(stderr, "cannot create tcp service.\n");
exit(1);
}
if (!svc_register(transp,
DB_PROGRAM, DB_VERSION, db_program_1, IPPROTO_TCP))
{
fprintf(stderr, "unable to register (DB_PROGRAM, DB_VERSION, tcp).\n");
exit(1);
}
run(); /* like svc_run() but does client management callbacks */
(void) fprintf(stderr, "run returned\n");
exit(1);
}
run()
{
extern int errno;
#ifdef FD_SETSIZE
fd_set readfds;
static fd_set oldfds;
oldfds = svc_fdset;
#else
int readfds;
static int oldfds;
oldfds = svc_fds;
#endif /* def FD_SETSIZE */
for (;;)
{
register int setsize;
setsize = _rpc_dtablesize();
#ifdef FD_SETSIZE
readfds = svc_fdset;
#else
readfds = svc_fds;
#endif /* def FD_SETSIZE */
switch (select(setsize, &readfds, (int *) 0, (int *) 0,
(struct timeval *) 0))
{
case -1:
if (errno == EINTR)
continue;
perror("svc_run: - select failed");
return;
case 0:
continue;
default:
{
/*
at the start of each go round in the select loop we can
detect when a new connection has been made or broken this is
were we do our client management
*/
register int chunk;
register int bit;
register unsigned long mask;
register unsigned long *maskp;
int fd;
/* for each bit in the new mask */
maskp = (unsigned long *) (svc_fdset.fds_bits);
for (chunk = 0; chunk < setsize; chunk += NFDBITS)
for (mask = *maskp++;
bit = ffs(mask); mask ^= (1 << (bit - 1)))
{
fd = chunk+bit-1;
/*
if fd is not in the old mask, then we have a
new connection
*/
if (FD_ISSET(fd, &svc_fdset) && !FD_ISSET(fd, &oldfds))
if (c_add(fd))
LogM(AS_ERROR, "add error");
}
/* for each bit in the old mask... */
maskp = (unsigned long *) (oldfds.fds_bits);
for (chunk = 0; chunk < setsize; chunk += NFDBITS)
for (mask = *maskp++;
bit = ffs(mask); mask ^= (1 << (bit - 1)))
{
fd = chunk+bit-1;
/*
if fd is not in the new mask then we have lost
a connection
*/
if (FD_ISSET(fd, &oldfds) && !FD_ISSET(fd, &svc_fdset))
if (c_delete(fd))
LogM(AS_ERROR, "delete error");
}
oldfds = svc_fdset; /* should have a better scheme for
copying fd sets here */
svc_getreqset(&readfds);
}
}
}
}
/* client 'close' callback */
c_delete(n)
int n;
{
LogM(AS_DEBUG,"c_delete: %d <-----\n", n);
return 0;
}
/* client 'open' callback */
c_add(n)
int n;
{
LogM(AS_DEBUG,"c_add: %d <-----\n", n);
return 0;
}
More information about the Comp.sys.sun
mailing list