]> andersk Git - moira.git/blobdiff - server/mr_scall.c
punt mrgdb
[moira.git] / server / mr_scall.c
index acf17e470e61c75924971074fecf6c1eebfd48b0..82cfed56e1c6010177b3bfaedf7033fb3bcafa20 100644 (file)
 
 RCSID("$Header$");
 
-extern char buf1[];
 extern int nclients;
+extern client **clients;
 extern char *whoami;
 
 extern int dbms_errno, mr_errcode;
-static int row_count;
 
 void do_call(client *cl);
 void free_rtn_tuples(client *cp);
-int retr_callback(int argc, char **argv, void *p_cp);
-int list_users(int (*callbk)(int, char **, void *), char *callarg);
-void do_retr(client *cl);
-void do_access(client *cl);
+int retr_callback(int argc, char **argv, void *p_cl);
+int list_users(client *cl);
+void do_retr(client *cl, mr_params req);
+void do_access(client *cl, mr_params req);
 void get_motd(client *cl);
 
 /* Put this in a variable so that we can patch it if necessary */
 int max_row_count = 4096;
 
-/*
- * Welcome to the (finite state) machine (highest level).
- */
-void do_client(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, 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, NULL);
-      queue_operation(cp->con, CON_OUTPUT, cp->pending_op);
-      cp->action = CL_SEND;
-      break;
-    }
-}
-
 char *procnames[] = {
   "noop",
   "auth",
@@ -102,33 +53,35 @@ char *procnames[] = {
   "motd",
 };
 
+int newqueries;
 
-void do_call(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))
+  mr_params req;
+  int status, pn;
+
+  status = mr_receive(cl->con, &req);
+  if (status != MR_SUCCESS)
     {
-      com_err(whoami, 0, "procno out of range");
-      cl->reply.mr_status = MR_UNKNOWN_PROC;
+      cl->done = 1;
+      if (status != MR_NOT_CONNECTED)
+       com_err(whoami, status, "while reading from socket");
       return;
     }
-  if (log_flags & LOG_ARGS)
+
+  pn = req.u.mr_procno;
+  if (pn < 0 || pn > MR_MAX_PROC)
     {
-      log_args(procnames[pn], cl->args->mr_version_no,
-              cl->args->mr_argc, cl->args->mr_argv);
+      com_err(whoami, 0, "procno out of range");
+      client_reply(cl, MR_UNKNOWN_PROC);
+      return;
     }
-  else if (log_flags & LOG_REQUESTS)
-    com_err(whoami, 0, "%s", procnames[pn]);
+  log_args(procnames[pn], 2, req.mr_argc, req.mr_argv);
 
-  if ((dormant == ASLEEP || dormant == GROGGY) &&
-      pn != MR_NOOP && pn != MR_MOTD)
+  if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
     {
-      cl->reply.mr_status = MR_DOWN;
-      if (log_flags & LOG_RES)
-       com_err(whoami, MR_DOWN, "(query refused)");
+      client_reply(cl, MR_DOWN);
+      com_err(whoami, MR_DOWN, "(query refused)");
       return;
     }
 
@@ -138,19 +91,19 @@ void do_call(client *cl)
   switch (pn)
     {
     case MR_NOOP:
-      cl->reply.mr_status = 0;
+      client_reply(cl, MR_SUCCESS);
       return;
 
     case MR_AUTH:
-      do_auth(cl);
+      do_auth(cl, req);
       return;
 
     case MR_QUERY:
-      do_retr(cl);
+      do_retr(cl, req);
       return;
 
     case MR_ACCESS:
-      do_access(cl);
+      do_access(cl, req);
       return;
 
     case MR_SHUTDOWN:
@@ -158,7 +111,7 @@ void do_call(client *cl)
       return;
 
     case MR_DO_UPDATE:
-      trigger_dcm(NULL, NULL, cl);
+      client_reply(cl, MR_PERM);
       return;
 
     case MR_MOTD:
@@ -167,223 +120,195 @@ void do_call(client *cl)
     }
 }
 
-void free_rtn_tuples(client *cp)
+/* 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)
 {
-  returned_tuples *temp;
-  for (temp = cp->first; temp && OP_DONE(temp->op); )
-    {
-      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);
-    }
-  cp->first = temp;
+  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++;
 }
 
-int retr_callback(int argc, char **argv, void *p_cp)
+void client_return_tuple(client *cl, int argc, char **argv)
 {
-  client *cp = p_cp;
-  mr_params *arg_tmp;
-  returned_tuples *tp;
-  OPERATION op_tmp;
-  char **nargv;
-  int i;
+  if (cl->done || dbms_errno)
+    return;
 
-  if (row_count++ >= max_row_count)
+  if (cl->ntuples == max_row_count)
     {
       dbms_errno = mr_errcode = MR_NO_MEM;
-      return MR_ABORT;
+      return;
     }
 
-  /*
-   * This takes too much advantage of the fact that
-   * serialization of the data happens during the queue operation.
-   */
-  arg_tmp = malloc(sizeof(mr_params));
-  tp = malloc(sizeof(returned_tuples));
-  nargv = malloc(argc * sizeof(char *));
-
-  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++)
+  if (cl->ntuples == cl->tuplessize - 1)
     {
-      int len = strlen(argv[i]) + 1;
-      nargv[i] = malloc(len);
-      memcpy(nargv[i], argv[i], len);
+      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;
+       }
+      cl->tuplessize = newsize;
+      cl->tuples = newtuples;
     }
-  arg_tmp->mr_flattened = NULL;
-  arg_tmp->mr_argl = 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, NULL);
-  queue_operation(cp->con, CON_OUTPUT, op_tmp);
-  return MR_CONT;
+  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++;
 }
 
-int list_users(int (*callbk)(int, char **, void *), char *callarg)
+void client_write(client *cl)
 {
-  char *argv[6];
-  char buf[30];
-  char buf1[30];
-  int i;
-  extern client **clients;
-  char *cp;
+  int status;
 
-  for (i = 0; i < nclients; i++)
+  status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
+  if (status)
     {
-      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 = strchr(argv[3], '\n');
-      if (cp)
-       *cp = '\0';
-      argv[4] = buf1;
-      sprintf(buf1, "[#%d]", cl->id);
-      (*callbk)(5, argv, callarg);
+      com_err(whoami, status, "writing to socket");
+      cl->done = 1;
+    }
+  else
+    {
+      cl->nexttuple++;
+      if (cl->nexttuple == cl->ntuples)
+       free_rtn_tuples(cl);
     }
-  return 0;
 }
 
-void do_retr(client *cl)
+void free_rtn_tuples(client *cl)
 {
-  char *queryname;
+  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;
+}
 
-  cl->reply.mr_argc = 0;
-  cl->reply.mr_status = 0;
-  row_count = 0;
+void do_retr(client *cl, mr_params req)
+{
+  char *queryname;
+  int status;
 
-  if (cl->args->mr_argc < 1)
+  if (req.mr_argc < 1)
     {
-      cl->reply.mr_status = MR_ARGS;
+      client_reply(cl, MR_ARGS);
       com_err(whoami, MR_ARGS, "got nameless query");
       return;
     }
-  queryname = cl->args->mr_argv[0];
-
-  if (cl->args->mr_version_no == MR_VERSION_2)
-    newqueries++;
-  else
-    oldqueries++;
+  queryname = req.mr_argv[0];
+  newqueries++;
 
   if (!strcmp(queryname, "_list_users"))
-    cl->reply.mr_status = list_users(retr_callback, (char *)cl);
+    status = list_users(cl);
   else
+    status = mr_process_query(cl, queryname, req.mr_argc - 1, req.mr_argv + 1,
+                             retr_callback, cl);
+
+  client_reply(cl, status);
+
+  if (cl->ntuples >= max_row_count)
     {
-      cl->reply.mr_status = mr_process_query(cl, queryname,
-                                            cl->args->mr_argc - 1,
-                                            cl->args->mr_argv + 1,
-                                            retr_callback, cl);
-    }
-  if (row_count >= max_row_count)
-    {
-      critical_alert("moirad", "attempted query %s with %d rows\n",
-                    queryname, row_count);
+      critical_alert("moirad", "attempted query %s with too many rows\n",
+                    queryname);
     }
 
-  if (log_flags & LOG_RES)
-    com_err(whoami, 0, "Query complete.");
+  com_err(whoami, 0, "Query complete.");
+}
+
+int retr_callback(int argc, char **argv, void *p_cl)
+{
+  client *cl = p_cl;
+
+  mr_trim_args(argc, argv);
+  client_return_tuple(cl, argc, argv);
 }
 
-void do_access(client *cl)
+void do_access(client *cl, mr_params req)
 {
-  if (cl->args->mr_argc < 1)
+  int status;
+
+  if (req.mr_argc < 1)
     {
-      cl->reply.mr_status = MR_ARGS;
+      client_reply(cl, MR_ARGS);
       com_err(whoami, MR_ARGS, "got nameless access");
       return;
     }
-  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);
+  status = mr_check_access(cl, req.mr_argv[0], req. mr_argc - 1,
+                          req.mr_argv + 1);
+  client_reply(cl, status);
 
   com_err(whoami, 0, "Access check complete.");
 }
 
-
-/* trigger_dcm is also used as a followup routine to the
- * set_server_host_override query, hence the two dummy arguments.
- */
-
-struct query pseudo_query = {
-  "trigger_dcm",
-  "tdcm",
-};
-
-int trigger_dcm(struct query *q, char *argv[], client *cl)
+void get_motd(client *cl)
 {
-  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;
+  int motd;
+  char *buffer;
+  struct stat statb;
 
-  sprintf(prog, "%s/startdcm", BIN_DIR);
-  pid = vfork();
-  switch (pid)
+  if (stat(MOIRA_MOTD_FILE, &statb) == -1)
     {
-    case 0:
-      execl(prog, "startdcm", 0);
-      exit(1);
-
-    case -1:
-      cl->reply.mr_status = errno;
-      return 0;
+      client_reply(cl, MR_SUCCESS);
+      return;
+    }
+  
+  buffer = malloc(statb.st_size + 1);
+  if (!buffer)
+    {
+      client_reply(cl, MR_NO_MEM);
+      return;
+    }
 
-    default:
-      return 0;
+  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);
+}
 
-void get_motd(client *cl)
+int list_users(client *cl)
 {
-  int motd, len;
-  char buffer[1024];
-  char *arg[1];
+  char *argv[5];
+  char buf[30];
+  char buf1[30];
+  int i;
+  char *cp;
 
-  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;
-  row_count = 0;
-  retr_callback(1, arg, cl);
-  cl->reply.mr_status = 0;
+  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;
 }
+
This page took 0.292741 seconds and 4 git commands to generate.