1
0
Files
irix-657m-src/eoe/cmd/ns/nsd/loopback.c
2022-09-29 17:59:04 +03:00

282 lines
6.7 KiB
C

/*
** This file contains a hunk of code to do loopbacks into nsd. This
** passes the thread of control to a different lookup, then returns
** it to the original caller when finished. We setup a pipe into
** nsd during on the first call, and pass state through the pipe.
** Our caller must deal with NSD_CONTINUE, and must free the resulting
** file.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ns_api.h>
#include <ns_daemon.h>
static int pipes[2] = {-1, -1};
typedef struct {
nsd_file_t *rq;
nsd_callout_proc *proc;
} loop_send_t;
/*
** This just writes the address of the file to one end of the pipe and
** falls back to the select loop. The select will wakeup and the callback
** below will be called to start running in the other context again.
*/
static int
loop_send(nsd_file_t *rq)
{
nsd_logprintf(NSD_LOG_LOW, "loop_send:\n");
if (! rq) {
return NSD_ERROR;
}
if (write(pipes[0], &rq, sizeof(&rq)) < 0) {
nsd_logprintf(NSD_LOG_RESOURCE, "loop_send: failed write: %s\n",
strerror(errno));
return NSD_ERROR;
}
return NSD_OK;
}
/*
** We pull the address of the file off of the pipe and call the proceedure
** we were passed in the nsd_loopback routine.
*/
static int
loop_callback(nsd_file_t **rqp, int fd)
{
int len;
nsd_file_t *rq, *fp;
nsd_callout_proc *p;
loop_send_t *sd;
nsd_logprintf(NSD_LOG_MIN, "loop_callback:\n");
*rqp = 0;
len = read(fd, &fp, sizeof(&fp));
if (len < 0) {
nsd_logprintf(NSD_LOG_RESOURCE,
"loop_callback: failed read: %s\n", strerror(errno));
return NSD_ERROR;
}
sd = fp->f_sender;
if (! sd) {
nsd_file_clear(&fp);
return NSD_ERROR;
}
rq = sd->rq;
p = sd->proc;
free(sd);
fp->f_sender = 0;
fp->f_send = 0;
rq->f_loop = fp;
*rqp = rq;
return (*p)(rq);
}
/*
** This routine pulls the address of the file off of the pipe and walks
** it through the callout list. The callout list was setup by nsd_loopback
** below.
*/
static int
loop_dispatch(nsd_file_t **rqp, int fd)
{
int len;
nsd_file_t *rq, *cp;
nsd_logprintf(NSD_LOG_MIN, "loop_dispatch:\n");
*rqp = 0;
len = read(fd, &rq, sizeof(&rq));
if (len < 0) {
nsd_logprintf(NSD_LOG_RESOURCE,
"loop_dispatch: failed read: %s\n", strerror(errno));
return NSD_ERROR;
}
for (cp = nsd_file_getcallout(rq); cp; cp = nsd_file_nextcallout(rq)) {
if (cp->f_lib && cp->f_lib->l_funcs[rq->f_index]) {
nsd_attr_continue(&rq->f_attrs, cp->f_attrs);
*rqp = rq;
rq->f_send = loop_send;
return (*cp->f_lib->l_funcs[rq->f_index])(rq);
}
}
nsd_logprintf(NSD_LOG_LOW, "\tno callbacks supporting function\n");
rq->f_status = NS_NOTFOUND;
write(fd, &rq, sizeof(&rq));
return NSD_CONTINUE;
}
/*
** This is the exported routine. It takes a current request, and a pointer
** to a control structure defining the request. It returns an nsd return
** value which must be dealt with in the caller. We create a new request
** structure based on the information in the control structure and write
** it on the loopback pipe. After our caller has fallen back to the main
** select loop the daemon wakes up and calls the dispatch routine above.
** When the request is complete the send above is called out of the main
** loop which writes the response to the end of the pipe and falls back to
** the select loop again. Finally, the daemon wakes up and calls the callback
** routine above which ends up calling the routine passed in our control
** structure.
*/
int
nsd_loopback(nsd_file_t *rq, nsd_loop_t *lp)
{
nsd_file_t *fp, *cp;
loop_send_t *sd;
char *domain, *key;
nsd_logprintf(NSD_LOG_MIN, "nsd_loopback:\n");
if (pipes[0] < 0) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipes) < 0) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_loopback: failed pipe: %s\n",
strerror(errno));
return NSD_ERROR;
}
nsd_callback_new(pipes[0], loop_dispatch, NSD_READ);
nsd_callback_new(pipes[1], loop_callback, NSD_READ);
}
if (! lp->lb_dir) {
/*
** If table is set then we lookup the right directory
** in the filesystem tree, else we use the request
** structure like a directory.
*/
if (lp->lb_table && ! (lp->lb_flags & NSD_LOOP_SKIP) &&
! (lp->lb_flags & NSD_LOOP_FIRST)) {
if (lp->lb_domain) {
domain = lp->lb_domain;
} else {
domain = nsd_attr_fetch_string(rq->f_attrs,
"domain", ".local");
}
key = (lp->lb_key) ? lp->lb_key : ".all";
if (nsd_file_find(domain, lp->lb_table,
lp->lb_protocol, key, &lp->lb_dir) ==
NSD_OK) {
/*
** Results are already in the tree so we
** just up the reference count and return
** it.
*/
lp->lb_dir->f_nlink++;
rq->f_loop = lp->lb_dir;
nsd_logprintf(NSD_LOG_LOW,
"\talready in tree: %s/%s/%s/%s\n",
domain, lp->lb_table, lp->lb_protocol, key);
return NSD_OK;
}
if (! lp->lb_dir) {
/*
** Not found.
*/
nsd_logprintf(NSD_LOG_LOW,
"\tno directory: %s/%s/%s/%s\n",
domain, lp->lb_table, lp->lb_protocol, key);
return NSD_OK;
}
} else {
lp->lb_dir = rq;
}
}
if (nsd_file_init(&fp, "loopback", sizeof("loopback") - 1, lp->lb_dir,
NFREG, rq->f_cred) != NSD_OK) {
nsd_logprintf(NSD_LOG_LOW, "\tfailed file init\n");
return NSD_ERROR;
}
sd = nsd_calloc(1, sizeof(*sd));
if (! sd) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_loopback: failed malloc\n");
nsd_file_clear(&fp);
return NSD_ERROR;
}
sd->proc = lp->lb_proc;
sd->rq = rq;
fp->f_sender = sd;
/*
** Setup attributes.
*/
nsd_attr_clear(fp->f_attrs);
fp->f_attrs = nsd_attr_copy(rq->f_attrs);
nsd_attr_continue(&fp->f_attrs, lp->lb_dir->f_attrs);
if (lp->lb_key) {
nsd_attr_store(&fp->f_attrs, "key", lp->lb_key);
fp->f_index = LOOKUP;
} else {
fp->f_index = LIST;
}
if (lp->lb_table) {
nsd_attr_store(&fp->f_attrs, "table", lp->lb_table);
}
if (lp->lb_domain) {
nsd_attr_store(&fp->f_attrs, "domain", lp->lb_domain);
}
if (lp->lb_attrs) {
nsd_attr_parse(&fp->f_attrs, lp->lb_attrs, 0, 0);
}
/*
** Setup callout list.
*/
if (lp->lb_flags & NSD_LOOP_FIRST) {
cp = nsd_file_getcallout(rq);
nsd_file_appendcallout(fp, cp, cp->f_name, cp->f_namelen);
} else if (nsd_file_copycallouts(lp->lb_dir, fp, 0) != NSD_OK) {
nsd_logprintf(NSD_LOG_LOW, "\tfailed copycallouts\n");
nsd_file_clear(&fp);
free(sd);
return NSD_ERROR;
}
if (lp->lb_flags & NSD_LOOP_SKIP) {
if (! nsd_file_nextcallout(fp)) {
nsd_logprintf(NSD_LOG_LOW, "\tno callouts\n");
nsd_file_clear(&fp);
free(sd);
return NSD_OK;
}
}
if (write(pipes[1], &fp, sizeof(&fp)) < 0) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_loopback: failed write: %s\n", strerror(errno));
nsd_file_clear(&fp);
free(sd);
return NSD_ERROR;
}
return NSD_CONTINUE;
}