summaryrefslogtreecommitdiff
path: root/lib/libc/rpc/svc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/rpc/svc.c')
-rw-r--r--lib/libc/rpc/svc.c360
1 files changed, 251 insertions, 109 deletions
diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c
index 05f5ee848e6..efe828394e8 100644
--- a/lib/libc/rpc/svc.c
+++ b/lib/libc/rpc/svc.c
@@ -28,7 +28,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: svc.c,v 1.15 2002/02/16 21:27:24 millert Exp $";
+static char *rcsid = "$OpenBSD: svc.c,v 1.16 2003/12/31 03:27:23 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -70,9 +70,15 @@ static struct svc_callout {
} *svc_head;
static struct svc_callout *svc_find(u_long, u_long, struct svc_callout **);
+static int svc_fd_insert(int);
+static int svc_fd_remove(int);
-int __svc_fdsetsize;
-fd_set *__svc_fdset;
+int __svc_fdsetsize = FD_SETSIZE;
+fd_set *__svc_fdset = &svc_fdset;
+static int svc_pollfd_size; /* number of slots in svc_pollfd */
+static int svc_used_pollfd; /* number of used slots in svc_pollfd */
+static int *svc_pollfd_freelist; /* svc_pollfd free list */
+static int svc_max_free; /* number of used slots in free list */
/* *************** SVCXPRT related stuff **************** */
@@ -96,33 +102,12 @@ __xprt_register(xprt)
{
int sock = xprt->xp_sock;
- if (sock+1 > __svc_fdsetsize) {
- int bytes = howmany(sock+1, NFDBITS) * sizeof(fd_mask);
- fd_set *fds;
-
- fds = (fd_set *)malloc(bytes);
- if (fds == NULL)
- return (0);
- memset(fds, 0, bytes);
- if (__svc_fdset) {
- memcpy(fds, __svc_fdset, howmany(__svc_fdsetsize,
- NFDBITS) * sizeof(fd_mask));
- free(__svc_fdset);
- }
- __svc_fdset = fds;
- __svc_fdsetsize = sock+1;
- }
-
- if (sock < FD_SETSIZE)
- FD_SET(sock, &svc_fdset);
- FD_SET(sock, __svc_fdset);
-
- if (xports == NULL || sock+1 > xportssize) {
+ if (xports == NULL || sock + 1 > xportssize) {
SVCXPRT **xp;
int size = FD_SETSIZE;
- if (sock+1 > size)
- size = sock+1;
+ while (sock + 1 > size)
+ size += FD_SETSIZE;
xp = (SVCXPRT **)mem_alloc(size * sizeof(SVCXPRT *));
if (xp == NULL)
return (0);
@@ -134,12 +119,159 @@ __xprt_register(xprt)
xportssize = size;
xports = xp;
}
+
+ if (!svc_fd_insert(sock))
+ return (0);
xports[sock] = xprt;
+
+ return (1);
+}
+
+/*
+ * Insert a socket into svc_pollfd, svc_fdset and __svc_fdset.
+ * If we are out of space, we allocate ~128 more slots than we
+ * need now for future expansion.
+ * We try to keep svc_pollfd well packed (no holes) as possible
+ * so that poll(2) is efficient.
+ */
+static int
+svc_fd_insert(int sock)
+{
+ int slot;
+
+ /*
+ * Find a slot for sock in svc_pollfd; four possible cases:
+ * 1) need to allocate more space for svc_pollfd
+ * 2) there is an entry on the free list
+ * 3) the free list is empty (svc_used_pollfd is the next slot)
+ */
+ if (svc_pollfd == NULL || svc_used_pollfd == svc_pollfd_size) {
+ struct pollfd *pfd;
+ int new_size, *new_freelist;
+
+ new_size = svc_pollfd ? svc_pollfd_size + 128 : FD_SETSIZE;
+ pfd = realloc(svc_pollfd, sizeof(*svc_pollfd) * new_size);
+ if (pfd == NULL)
+ return (0); /* no changes */
+ new_freelist = realloc(svc_pollfd_freelist, new_size / 2);
+ if (new_freelist == NULL) {
+ free(pfd);
+ return (0); /* no changes */
+ }
+ svc_pollfd = pfd;
+ svc_pollfd_size = new_size;
+ svc_pollfd_freelist = new_freelist;
+ for (slot = svc_used_pollfd; slot < svc_pollfd_size; slot++) {
+ svc_pollfd[slot].fd = -1;
+ svc_pollfd[slot].events = svc_pollfd[slot].revents = 0;
+ }
+ slot = svc_used_pollfd;
+ } else if (svc_max_free != 0) {
+ /* there is an entry on the free list, use it */
+ slot = svc_pollfd_freelist[--svc_max_free];
+ } else {
+ /* nothing on the free list but we have room to grow */
+ slot = svc_used_pollfd;
+ }
+ if (sock + 1 > __svc_fdsetsize) {
+ fd_set *fds;
+ size_t bytes;
+
+ bytes = howmany(sock + 128, NFDBITS) * sizeof(fd_mask);
+ /* realloc() would be nicer but it gets tricky... */
+ if ((fds = (fd_set *)mem_alloc(bytes)) != NULL) {
+ memset(fds, 0, bytes);
+ memcpy(fds, __svc_fdset,
+ howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask));
+ if (__svc_fdset != &svc_fdset)
+ free(__svc_fdset);
+ __svc_fdset = fds;
+ __svc_fdsetsize = bytes / sizeof(fd_mask);
+ }
+ }
+
+ svc_pollfd[slot].fd = sock;
+ svc_pollfd[slot].events = POLLIN;
+ svc_used_pollfd++;
+ if (svc_max_pollfd < slot + 1)
+ svc_max_pollfd = slot + 1;
+ if (sock < FD_SETSIZE)
+ FD_SET(sock, &svc_fdset);
+ else if (sock < __svc_fdsetsize)
+ FD_SET(sock, __svc_fdset);
svc_maxfd = max(svc_maxfd, sock);
+
return (1);
}
/*
+ * Remove a socket from svc_pollfd, svc_fdset and __svc_fdset.
+ * Freed slots are placed on the free list. If the free list fills
+ * up, we compact svc_pollfd (free list size == svc_pollfd_size /2).
+ */
+static int
+svc_fd_remove(int sock)
+{
+ int slot;
+
+ if (svc_pollfd == NULL)
+ return (0);
+
+ for (slot = 0; slot < svc_max_pollfd; slot++) {
+ if (svc_pollfd[slot].fd == sock) {
+ svc_pollfd[slot].fd = -1;
+ svc_pollfd[slot].events = svc_pollfd[slot].revents = 0;
+ svc_used_pollfd--;
+ if (sock < FD_SETSIZE)
+ FD_CLR(sock, &svc_fdset);
+ else if (sock < __svc_fdsetsize)
+ FD_CLR(sock, __svc_fdset);
+ if (sock == svc_maxfd) {
+ for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
+ if (xports[svc_maxfd])
+ break;
+ }
+ if (svc_max_free == svc_pollfd_size / 2) {
+ int i, j;
+
+ /*
+ * Out of space in the free list; this means
+ * that svc_pollfd is half full. Pack things
+ * such that svc_max_pollfd == svc_used_pollfd
+ * and svc_pollfd_freelist is empty.
+ */
+ for (i = svc_used_pollfd, j = 0;
+ i < svc_max_pollfd && j < svc_max_free; i++) {
+ if (svc_pollfd[i].fd == -1)
+ continue;
+ /* be sure to use a low-numbered slot */
+ while (svc_pollfd_freelist[j] >=
+ svc_used_pollfd)
+ j++;
+ svc_pollfd[svc_pollfd_freelist[j++]] =
+ svc_pollfd[i];
+ svc_pollfd[i].fd = -1;
+ svc_pollfd[i].events =
+ svc_pollfd[i].revents = 0;
+ }
+ svc_max_pollfd = svc_used_pollfd;
+ svc_max_free = 0;
+ /* could realloc if svc_pollfd_size is big */
+ } else {
+ /* trim svc_max_pollfd from the end */
+ while (svc_max_pollfd > 0 &&
+ svc_pollfd[svc_max_pollfd - 1].fd == -1)
+ svc_max_pollfd--;
+ }
+ svc_pollfd_freelist[svc_max_free++] = slot;
+
+ return (1);
+ }
+ }
+ return (0); /* not found, shouldn't happen */
+}
+
+/*
* De-activate a transport handle.
*/
void
@@ -149,19 +281,8 @@ xprt_unregister(xprt)
int sock = xprt->xp_sock;
if (xports[sock] == xprt) {
- xports[sock] = (SVCXPRT *)0;
- if (sock < FD_SETSIZE)
- FD_CLR(sock, &svc_fdset);
- FD_CLR(sock, __svc_fdset);
- if (sock == svc_maxfd) {
- for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
- if (xports[svc_maxfd])
- break;
- }
- /*
- * XXX could use svc_maxfd as a hint to
- * decrease the size of __svc_fdset
- */
+ xports[sock] = NULL;
+ svc_fd_remove(sock);
}
}
@@ -409,15 +530,12 @@ void
svc_getreq(rdfds)
int rdfds;
{
- fd_set readfds;
+ int bit;
- FD_ZERO(&readfds);
- readfds.fds_bits[0] = rdfds;
- svc_getreqset(&readfds);
+ for (; (bit = ffs(rdfds)); rdfds ^= (1 << (bit - 1)))
+ svc_getreq_common(bit - 1);
}
-void svc_getreqset2(fd_set *, int);
-
void
svc_getreqset(readfds)
fd_set *readfds;
@@ -430,6 +548,39 @@ svc_getreqset2(readfds, width)
fd_set *readfds;
int width;
{
+ fd_mask mask, *maskp;
+ int bit, sock;
+
+ maskp = readfds->fds_bits;
+ for (sock = 0; sock < width; sock += NFDBITS) {
+ for (mask = *maskp++; (bit = ffs(mask));
+ mask ^= (1 << (bit - 1)))
+ svc_getreq_common(sock + bit - 1);
+ }
+}
+
+void
+svc_getreq_poll(pfd, nready)
+ struct pollfd *pfd;
+ const int nready;
+{
+ int i, n;
+
+ for (n = nready, i = 0; n > 0; i++) {
+ if (pfd[i].fd == -1)
+ continue;
+ if (pfd[i].revents != 0)
+ n--;
+ if ((pfd[i].revents & (POLLIN | POLLHUP)) == 0)
+ continue;
+ svc_getreq_common(pfd[i].fd);
+ }
+}
+
+void
+svc_getreq_common(fd)
+ int fd;
+{
enum xprt_stat stat;
struct rpc_msg msg;
int prog_found;
@@ -437,74 +588,65 @@ svc_getreqset2(readfds, width)
u_long high_vers;
struct svc_req r;
SVCXPRT *xprt;
- int bit;
- fd_mask mask, *maskp;
- int sock;
char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
+
msg.rm_call.cb_cred.oa_base = cred_area;
msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
- maskp = readfds->fds_bits;
- for (sock = 0; sock < width; sock += NFDBITS) {
- for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) {
- /* sock has input waiting */
- xprt = xports[sock + bit - 1];
- if (xprt == NULL)
- /* But do we control sock? */
- continue;
- /* now receive msgs from xprtprt (support batch calls) */
- do {
- if (SVC_RECV(xprt, &msg)) {
-
- /* now find the exported program and call it */
- register struct svc_callout *s;
- enum auth_stat why;
-
- r.rq_xprt = xprt;
- r.rq_prog = msg.rm_call.cb_prog;
- r.rq_vers = msg.rm_call.cb_vers;
- r.rq_proc = msg.rm_call.cb_proc;
- r.rq_cred = msg.rm_call.cb_cred;
- /* first authenticate the message */
- if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
- svcerr_auth(xprt, why);
- goto call_done;
- }
- /* now match message with a registered service*/
- prog_found = FALSE;
- low_vers = (u_long) -1;
- high_vers = 0;
- for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
- if (s->sc_prog == r.rq_prog) {
- if (s->sc_vers == r.rq_vers) {
- (*s->sc_dispatch)(&r, xprt);
- goto call_done;
- } /* found correct version */
- prog_found = TRUE;
- if (s->sc_vers < low_vers)
- low_vers = s->sc_vers;
- if (s->sc_vers > high_vers)
- high_vers = s->sc_vers;
- } /* found correct program */
- }
- /*
- * if we got here, the program or version
- * is not served ...
- */
- if (prog_found)
- svcerr_progvers(xprt,
- low_vers, high_vers);
- else
- svcerr_noprog(xprt);
- /* Fall through to ... */
+ /* sock has input waiting */
+ xprt = xports[fd];
+ if (xprt == NULL)
+ /* But do we control the fd? */
+ return;
+ /* now receive msgs from xprtprt (support batch calls) */
+ do {
+ if (SVC_RECV(xprt, &msg)) {
+ /* find the exported program and call it */
+ struct svc_callout *s;
+ enum auth_stat why;
+
+ r.rq_xprt = xprt;
+ r.rq_prog = msg.rm_call.cb_prog;
+ r.rq_vers = msg.rm_call.cb_vers;
+ r.rq_proc = msg.rm_call.cb_proc;
+ r.rq_cred = msg.rm_call.cb_cred;
+ /* first authenticate the message */
+ if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
+ svcerr_auth(xprt, why);
+ goto call_done;
}
- call_done:
- if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
- SVC_DESTROY(xprt);
- break;
+ /* now match message with a registered service*/
+ prog_found = FALSE;
+ low_vers = (u_long) -1;
+ high_vers = 0;
+ for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
+ if (s->sc_prog == r.rq_prog) {
+ if (s->sc_vers == r.rq_vers) {
+ (*s->sc_dispatch)(&r, xprt);
+ goto call_done;
+ } /* found correct version */
+ prog_found = TRUE;
+ if (s->sc_vers < low_vers)
+ low_vers = s->sc_vers;
+ if (s->sc_vers > high_vers)
+ high_vers = s->sc_vers;
+ } /* found correct program */
}
- } while (stat == XPRT_MOREREQS);
- }
- }
+ /*
+ * if we got here, the program or version
+ * is not served ...
+ */
+ if (prog_found)
+ svcerr_progvers(xprt, low_vers, high_vers);
+ else
+ svcerr_noprog(xprt);
+ /* Fall through to ... */
+ }
+ call_done:
+ if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
+ SVC_DESTROY(xprt);
+ break;
+ }
+ } while (stat == XPRT_MOREREQS);
}