X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/d548a4e78f42896b6f13f382f0ba32c4c05a0e45..ec761008bcc198a52ce73c0fd1d16a0e7656222c:/server/mr_scall.c?ds=sidebyside diff --git a/server/mr_scall.c b/server/mr_scall.c index a42f6df5..a3f1fa84 100644 --- a/server/mr_scall.c +++ b/server/mr_scall.c @@ -1,355 +1,334 @@ -/* - * $Source$ - * $Author$ - * $Header$ +/* $Id$ * - * Copyright (C) 1987 by the Massachusetts Institute of Technology - * For copying and distribution information, please see the file - * . + * Do RPC + * + * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology + * For copying and distribution information, please see the file + * . * */ -#ifndef lint -static char *rcsid_sms_scall_c = "$Header$"; -#endif lint - #include -#include +#include "mr_server.h" +#include "query.h" + #include -#include -#include +#include + +#include +#include + #include -#include "query.h" -#include "mr_server.h" -extern char buf1[]; +#include +#include +#include +#include + +RCSID("$Header$"); + extern int nclients; +extern client **clients; extern char *whoami; -extern char *malloc(); -extern int errno; -extern void clist_delete(), do_auth(), do_shutdown(); -void do_call(); +extern int dbms_errno, mr_errcode; -/* - * Welcome to the (finite state) machine (highest level). - */ -void -do_client(cp) - client *cp; -{ - struct stat stbuf; - - free_rtn_tuples(cp); - if (OP_STATUS(cp->pending_op) == OP_CANCELLED) { - com_err(whoami, 0, "Closed connection (now %d client%s, %d new queries, %d old)", - nclients-1, - nclients!=2?"s":"", - newqueries, - oldqueries); - clist_delete(cp); - /* if we no longer have any clients, and we're supposed to - * go down, then go down now. - */ - if ((dormant == AWAKE) && (nclients == 0) && - (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) { - com_err(whoami, 0, "motd file exists, slumbertime"); - dormant = SLEEPY; - } - return; - } - switch (cp->action) { - case CL_ACCEPT: - case CL_SEND: - /* Start recieving next request */ - initialize_operation(cp->pending_op, mr_start_recv, - (char *)&cp->args, (int (*)())NULL); - queue_operation(cp->con, CON_INPUT, cp->pending_op); - cp->action = CL_RECEIVE; - break; - case CL_RECEIVE: - /* Data is here. Process it & start it heading back */ - do_call(cp); /* This may block for a while. */ - mr_destroy_reply(cp->args); - cp->args = NULL; - initialize_operation(cp->pending_op, mr_start_send, - (char *)&cp->reply, (int (*)())NULL); - queue_operation(cp->con, CON_OUTPUT, cp->pending_op); - cp->action = CL_SEND; - break; - } -} +int max_version; + +void do_call(client *cl); +void free_rtn_tuples(client *cp); +int retr_callback(int argc, char **argv, void *p_cl); +int list_users(client *cl); +void do_retr(client *cl); +void do_access(client *cl); +void get_motd(client *cl); +void do_version(client *cl); char *procnames[] = { - "noop", - "auth", - "shutdown", - "query", - "access", - "dcm", - "motd", + "noop", + "auth", + "shutdown", + "query", + "access", + "dcm", + "motd", + "proxy", + "version", }; +int newqueries; -void -do_call(cl) - client *cl; +void client_read(client *cl) { - int pn; - cl->reply.mr_argc = 0; - cl->reply.mr_status = 0; - cl->reply.mr_version_no = cl->args->mr_version_no; - if (((pn = cl->args->mr_procno) < 0) || - (pn > MR_MAX_PROC)) { - com_err(whoami, 0, "procno out of range"); - cl->reply.mr_status = MR_UNKNOWN_PROC; - return; - } - if (log_flags & LOG_ARGS) - log_args(procnames[pn], cl->args->mr_version_no, - cl->args->mr_argc, cl->args->mr_argv); - else if (log_flags & LOG_REQUESTS) - com_err(whoami, 0, "%s", procnames[pn]); - - if ((dormant == ASLEEP || dormant == GROGGY) && - pn != MR_NOOP && pn != MR_MOTD) { - cl->reply.mr_status = MR_DOWN; - if (log_flags & LOG_RES) - com_err(whoami, MR_DOWN, "(query refused)"); - return; - } + int status, pn; + + status = mr_cont_receive(cl->con, &cl->req); + if (status == -1) + return; + else if (status != MR_SUCCESS) + { + cl->state = CL_CLOSING; + if (status != MR_NOT_CONNECTED) + com_err(whoami, status, "while reading from socket"); + return; + } + + pn = cl->req.u.mr_procno; + if (pn < 0 || pn > MR_MAX_PROC) + { + com_err(whoami, 0, "procno out of range"); + client_reply(cl, MR_UNKNOWN_PROC); + goto out; + } + log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv); + + if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD) + { + client_reply(cl, MR_DOWN); + com_err(whoami, MR_DOWN, "(query refused)"); + goto out; + } + + /* make sure this gets cleared before every operation */ + dbms_errno = 0; + + switch (pn) + { + case MR_NOOP: + client_reply(cl, MR_SUCCESS); + break; + + case MR_AUTH: + do_auth(cl); + break; + + case MR_QUERY: + do_retr(cl); + break; + + case MR_ACCESS: + do_access(cl); + break; + + case MR_SHUTDOWN: + do_shutdown(cl); + break; + + case MR_DO_UPDATE: + client_reply(cl, MR_PERM); + break; + + case MR_MOTD: + get_motd(cl); + break; + + case MR_PROXY: + do_proxy(cl); + break; + + case MR_SETVERSION: + do_version(cl); + break; + } + +out: + mr_destroy_reply(cl->req); + memset(&cl->req, 0, sizeof(mr_params)); +} - switch(pn) { - case MR_NOOP: - cl->reply.mr_status = 0; - return; - - case MR_AUTH: - do_auth(cl); - return; - - case MR_QUERY: - do_retr(cl); - return; - - case MR_ACCESS: - do_access(cl); - return; - - case MR_SHUTDOWN: - do_shutdown(cl); - return; - - case MR_DO_UPDATE: - trigger_dcm(0, 0, cl); - return; - - case MR_MOTD: - get_motd(cl); - return; - } +/* Set the final return status for a query. We always keep one more + free slot in cl->tuples[] than we're using so that this can't fail */ +void client_reply(client *cl, long status) +{ + cl->tuples[cl->ntuples].u.mr_status = status; + cl->tuples[cl->ntuples].mr_argc = 0; + cl->tuples[cl->ntuples].mr_argl = NULL; + cl->tuples[cl->ntuples].mr_argv = NULL; + cl->ntuples++; } -free_rtn_tuples(cp) - client *cp; +void client_return_tuple(client *cl, int argc, char **argv) { - register returned_tuples *temp; - for (temp=cp->first; temp && OP_DONE(temp->op); ) { - register returned_tuples *t1=temp; - temp = t1->next; - if (t1 == cp->last) cp->last = NULL; - - mr_destroy_reply(t1->retval); - delete_operation(t1->op); - free(t1); + if (cl->state == CL_CLOSING || dbms_errno) + return; + + if (cl->ntuples == cl->tuplessize - 1) + { + int newsize = (cl->tuplessize + 4) * 2; + mr_params *newtuples; + + newtuples = realloc(cl->tuples, newsize * sizeof(mr_params)); + if (!newtuples) + { + free_rtn_tuples(cl); + dbms_errno = mr_errcode = MR_NO_MEM; + return; } - cp->first = temp; -} + cl->tuplessize = newsize; + cl->tuples = newtuples; + } + + cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA; + cl->tuples[cl->ntuples].mr_argc = argc; + cl->tuples[cl->ntuples].mr_argl = NULL; + cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc); + cl->ntuples++; +} -retr_callback(argc, argv, p_cp) - register int argc; - register char **argv; - char *p_cp; +void client_write(client *cl) { - register client *cp = (client *)p_cp; - /* - * This takes too much advantage of the fact that - * serialization of the data happens during the queue operation. - */ - mr_params *arg_tmp = (mr_params *)db_alloc(sizeof(mr_params)); - returned_tuples *tp = (returned_tuples *) - db_alloc(sizeof(returned_tuples)); - register char **nargv = (char **)malloc(argc * sizeof(char *)); - register int i; - - OPERATION op_tmp = create_operation(); - - if (mr_trim_args(argc, argv) == MR_NO_MEM) { - com_err(whoami, MR_NO_MEM, "while trimming args"); - } - if (log_flags & LOG_RESP) - log_args("return: ", cp->args->mr_version_no, argc, argv); - - tp->op = op_tmp; - tp->retval = arg_tmp; - tp->next = NULL; - - arg_tmp->mr_status = MR_MORE_DATA; - arg_tmp->mr_version_no = cp->args->mr_version_no; - arg_tmp->mr_argc = argc; - arg_tmp->mr_argv = nargv; - for (i = 0; i < argc; i++) { - register int len = strlen(argv[i]) + 1; - nargv[i] = malloc(len); - bcopy(argv[i], nargv[i], len); - } - arg_tmp->mr_flattened = (char *)NULL; - arg_tmp->mr_argl = (int *)NULL; - - if (cp->last) { - cp->last->next = tp; - cp->last = tp; - } else { - cp->last = cp->first = tp; - } - - reset_operation(op_tmp); - initialize_operation(op_tmp, mr_start_send, (char *)arg_tmp, - (int (*)())NULL); - queue_operation(cp->con, CON_OUTPUT, op_tmp); + int status; + + status = mr_send(cl->con, &cl->tuples[cl->nexttuple]); + if (status) + { + com_err(whoami, status, "writing to socket"); + cl->state = CL_CLOSING; + } + else + { + cl->nexttuple++; + if (cl->nexttuple == cl->ntuples) + free_rtn_tuples(cl); + } } -list_users(callbk, callarg) - int (*callbk)(); - char *callarg; +void free_rtn_tuples(client *cl) { - char *argv[6]; - char buf[30]; - char buf1[30]; - int i; - extern client **clients; - extern char *inet_ntoa(); - char *cp; - char *index(); - char *ctime(); - - for (i = 0; i < nclients; i++) { - register client *cl = clients[i]; - if (cl->clname) - argv[0] = cl->clname; - else argv[0] = "unauthenticated"; - - argv[1] = inet_ntoa(cl->haddr.sin_addr); - argv[2] = buf; - sprintf(buf, "port %d", ntohs(cl->haddr.sin_port)); - argv[3] = ctime(&cl->last_time_used); - cp = index(argv[3], '\n'); - if (cp) *cp = '\0'; - argv[4] = buf1; - sprintf(buf1, "[#%d]", cl->id); - (*callbk)(5, argv, callarg); - } - return 0; + for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--) + free_argv(cl->tuples[cl->ntuples].mr_argv, + cl->tuples[cl->ntuples].mr_argc); + free(cl->tuples); + + cl->tuples = xmalloc(sizeof(mr_params)); + cl->tuplessize = 1; + cl->ntuples = cl->nexttuple = 0; } -do_retr(cl) - register client *cl; +void do_retr(client *cl) { - register char *queryname; - - cl->reply.mr_argc = 0; - cl->reply.mr_status = 0; - - queryname = cl->args->mr_argv[0]; - - if (cl->args->mr_version_no == MR_VERSION_2) - newqueries++; - else - oldqueries++; - - if (strcmp(queryname, "_list_users") == 0) - cl->reply.mr_status = list_users(retr_callback, (char *)cl); - else { - cl->reply.mr_status = - mr_process_query(cl, - cl->args->mr_argv[0], - cl->args->mr_argc-1, - cl->args->mr_argv+1, - retr_callback, - (char *)cl); - } - if (log_flags & LOG_RES) - com_err(whoami, 0, "Query complete."); + char *queryname; + int status; + + if (cl->req.mr_argc < 1) + { + client_reply(cl, MR_ARGS); + com_err(whoami, MR_ARGS, "got nameless query"); + return; + } + queryname = cl->req.mr_argv[0]; + newqueries++; + + if (!strcmp(queryname, "_list_users")) + status = list_users(cl); + else + status = mr_process_query(cl, queryname, cl->req.mr_argc - 1, + cl->req.mr_argv + 1, retr_callback, cl); + + client_reply(cl, status); + + com_err(whoami, 0, "Query complete."); } -do_access(cl) - client *cl; +int retr_callback(int argc, char **argv, void *p_cl) { - cl->reply.mr_argc = 0; - - cl->reply.mr_status = - mr_check_access(cl, - cl->args->mr_argv[0], - cl->args->mr_argc-1, - cl->args->mr_argv+1); - - com_err(whoami, 0, "Access check complete."); + client *cl = p_cl; + + mr_trim_args(argc, argv); + client_return_tuple(cl, argc, argv); } +void do_access(client *cl) +{ + int status; -/* trigger_dcm is also used as a followup routine to the - * set_server_host_override query, hence the two dummy arguments. - */ + if (cl->req.mr_argc < 1) + { + client_reply(cl, MR_ARGS); + com_err(whoami, MR_ARGS, "got nameless access"); + return; + } -struct query pseudo_query = { - "trigger_dcm", - "tdcm", -}; + status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1, + cl->req.mr_argv + 1); + client_reply(cl, status); + + com_err(whoami, 0, "Access check complete."); +} -trigger_dcm(dummy0, dummy1, cl) - int dummy0, dummy1; - client *cl; +void do_version(client *cl) { - register int pid; - char prog[128]; - - cl->reply.mr_argc = 0; - - if (cl->reply.mr_status = check_query_access(&pseudo_query, 0, cl) ) - return(cl->reply.mr_status); - - sprintf(prog, "%s/startdcm", BIN_DIR); - pid = vfork(); - switch (pid) { - case 0: - for (dummy0 = getdtablesize() - 1; dummy0 > 2; dummy0--) - close(dummy0); - execl(prog, "startdcm", 0); - exit(1); - - case -1: - cl->reply.mr_status = errno; - return(0); - - default: - return(0); - } + if (cl->req.mr_argc != 1) + { + client_reply(cl, MR_ARGS); + com_err(whoami, MR_ARGS, "incorrect number of arguments"); + return; + } + + cl->version = atoi(cl->req.mr_argv[0]); + if (cl->version == -1) + cl->version = max_version; + + client_reply(cl, cl->version == max_version ? MR_SUCCESS : + cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH); } +void get_motd(client *cl) +{ + int motd; + char *buffer; + struct stat statb; + + if (stat(MOIRA_MOTD_FILE, &statb) == -1) + { + client_reply(cl, MR_SUCCESS); + return; + } + + buffer = malloc(statb.st_size + 1); + if (!buffer) + { + client_reply(cl, MR_NO_MEM); + return; + } + + motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY); + if (motd) + { + read(motd, buffer, statb.st_size); + close(motd); + buffer[statb.st_size] = '\0'; + client_return_tuple(cl, 1, &buffer); + client_reply(cl, MR_SUCCESS); + } + else + client_reply(cl, errno); + + free(buffer); +} -get_motd(cl) -client *cl; +int list_users(client *cl) { - int motd, len; - char buffer[1024]; - char *arg[1]; - - arg[0] = buffer; - cl->reply.mr_status = 0; - motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY); - if (motd < 0) return; - len = read(motd, buffer, sizeof(buffer) - 1); - close(motd); - buffer[len] = 0; - retr_callback(1, arg, cl); - cl->reply.mr_status = 0; + char *argv[5]; + char buf[30]; + char buf1[30]; + int i; + char *cp; + + for (i = 0; i < nclients; i++) + { + client *c = clients[i]; + argv[0] = c->clname; + argv[1] = inet_ntoa(c->haddr.sin_addr); + argv[2] = buf; + sprintf(buf, "port %d", ntohs(c->haddr.sin_port)); + argv[3] = ctime(&c->last_time_used); + cp = strchr(argv[3], '\n'); + if (cp) + *cp = '\0'; + argv[4] = buf1; + sprintf(buf1, "[#%d]", c->id); + client_return_tuple(cl, 5, argv); + } + return MR_SUCCESS; } +