Fixed inconsistent socket io.
[tlb/tomd.git] / src / tomd / main.c
index 1b97524..cfbb8b9 100644 (file)
 #include <sys/un.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
+
+#include "../../include/macros.h"
+#include "../../include/manifest.h"
+#include "../../include/job.h"
 
 static void header(void)
 {
-  printf("[tomd] Tom's Daemon, Copyright (C) 2018 Thomas Balzer\n");
-  printf("[tomd] GPL v3 or later license.\n");
+  tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer");
+  tomd_p("GPL v3 or later license.");
 }
 
 static int sfd;
@@ -46,7 +51,7 @@ static void gen_socket_filename(void)
           "/run/user/%d/tomd/socket",
           this_user_id);
 
-  printf("[tomd] making dir '%s'\n", socket_dirname);
+  tomd_p("making dir '%s'", socket_dirname);
   /* lazy way */
   char buf[100];
   sprintf(buf, "mkdir -p %s", socket_dirname);
@@ -56,10 +61,10 @@ static void gen_socket_filename(void)
   /*   exit(EXIT_FAILURE); */
   /* } */
 
-  printf("[tomd] removing file '%s'\n", socket_filename);
+  tomd_p("removing file '%s'", socket_filename);
   if(unlink(socket_filename) != 0){
     if(errno == ENOENT){
-      printf("[tomd] socket file doesn't exist\n");
+      tomd_p("socket file doesn't exist");
     }else{
       perror("[tomd] socket unlink");
       exit(EXIT_FAILURE);
@@ -67,10 +72,10 @@ static void gen_socket_filename(void)
   }
 }
 
-static void init(void)
+static void socket_init(void)
 {
   gen_socket_filename();
-  
+
   /* listen on socket, respond to requests. */
   /* perform all registered 'tick' operations */
   sfd =
@@ -92,7 +97,7 @@ static void init(void)
           sizeof(name.sun_path));
 
   size = SUN_LEN(&name);
-  printf("[tomd] attempting to bind to '%s'\n",
+  tomd_p("attempting to bind to '%s'",
          socket_filename);
   if(bind(sfd,
           (struct sockaddr *) &name,
@@ -101,10 +106,28 @@ static void init(void)
     exit(EXIT_FAILURE);
   }
 
-  printf("[tomd] initialized tomd socket connections\n");
+  tomd_p("initialized tomd socket connections");
 }
 
-/* These defines are here to improve the local readability */
+static void init(void)
+{
+  socket_init();
+  load_jobs();
+}
+
+#define SEND_ACK {                                                      \
+    int size;                                                           \
+    char ACK[4];\
+    ACK[0] = 'A';\
+    ACK[1] = 'C';\
+    ACK[2] = 'K';\
+    ACK[3] = '\0';\
+if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) {            \
+      tomd_p("didn't send as much as we though (%d != %d)",\
+             size, sizeof(ACK));                                        \
+    }                                                                   \
+  }
+
 #define CHDIR            0
 #define DONT_CHDIR       1
 #define CLOSE_PIPES      0
@@ -120,6 +143,142 @@ static void daemonize(void)
   daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
 }
 
+#define READ_SOCKET {\
+    memset(buf, 0, sizeof(buf));                \
+    int size = read(asfd, buf, 100);            \
+    buf[size] = '\0';                           \
+  }
+
+static int validate_sender(int asfd, char *buf)
+{
+  READ_SOCKET;
+  if(strcmp(buf, "client:tomc") == 0){
+    SEND_ACK;
+    return 0;
+  }
+  tomd_p("received '%s' instead of client:tomc", buf);
+  return -1;
+}
+
+enum requests { KILL, STATUS, STOP, START, UNKNOWN};
+#define X(a, b) { a, b }
+static struct {
+  char *str;
+  enum requests request;
+} request_types[] =
+  {
+   X("kill", KILL),
+   X("status", STATUS),
+   X("start", START),
+   X("stop", STOP),
+   X(NULL, -1)
+  };
+#undef X
+
+static void handle_request(int asfd, char *buf)
+{
+  READ_SOCKET;
+  enum requests request = UNKNOWN;
+  int i = 0;
+  while(1){
+    if(request_types[i].str == NULL){
+      break;
+    }
+
+    tomd_p("loop [%d]: comparing '%s' to '%s'",
+           i, buf, request_types[i].str);
+    if(strcmp(buf, request_types[i].str) == 0){
+      request = request_types[i].request;
+      break;
+    }
+
+    i++;
+  }
+
+  if(request == UNKNOWN){
+    tomd_p("unknown request type!");
+    return;
+  }
+
+  SEND_ACK;
+  READ_SOCKET;
+  // cross reference given name against known services
+  tomd_p("looking up '%s'", buf);
+  SEND_ACK;
+  struct job *jp = lookup_job(buf);
+  #define DOUBLE_DUTY(...) {                      \
+      char tmp[100];                            \
+      tomd_p(__VA_ARGS__);                      \
+      sprintf(tmp, __VA_ARGS__);                \
+      int tmplen = strlen(tmp);                 \
+      tomd_p("__debug__:'%s'", tmp);\
+      write(asfd, tmp, tmplen);               \
+    }
+  if(jp == NULL){
+    DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
+  } else {
+
+    tomd_p("-----");
+    DOUBLE_DUTY("found job record for '%s'\n", jp->name);
+
+    if(request == STATUS){
+      if(jp->pid != -1){
+        int status = 0;
+        int n_pid = waitpid(jp->pid, &status, WNOHANG);
+        if(n_pid < 0){
+          perror("[tomd] waitpid");
+        }else if(n_pid == 0){
+          DOUBLE_DUTY("waitpid == 0, check manual\n");
+        }else{
+          DOUBLE_DUTY("running: %s\n",
+                      !WIFEXITED(status) ? "yes"
+                      : "no");
+
+          if(WIFEXITED(status)){
+            DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status));
+            jp->pid = -1;
+            jp->last_status = status;
+          }
+        }
+      }else{
+        DOUBLE_DUTY("running: no\n");
+        DOUBLE_DUTY(" status: %d\n", jp->last_status);
+      }
+
+      if(jp->pid != -1){
+        DOUBLE_DUTY("    pid: %d\n", jp->pid);
+      }
+    }else{
+      DOUBLE_DUTY("don't know how to handle that request.\n");
+    }
+  }
+  tomd_p("-----");
+  tomd_p("sending ack.");
+  SEND_ACK;
+  tomd_p("ack is sent.");
+ get_ack:
+  READ_SOCKET;
+  if(strcmp(buf, "ACK") != 0)
+    goto get_ack;
+  tomd_p("ack was ack'd.");
+}
+
+static void handle_connection(int asfd)
+{
+  char buf[100] = {};
+
+  if(validate_sender(asfd, buf) != 0){
+    tomd_p("invalid sender.");
+    return;
+  }
+
+  tomd_p("validated client");
+  handle_request(asfd, buf);
+
+  shutdown(asfd, SHUT_WR);
+  close(asfd);
+}
+
 static void run(void)
 {
   /* loop: */
@@ -134,30 +293,26 @@ static void run(void)
     exit(EXIT_FAILURE);
   }
 
+  int i = 0;
   for(;;){
     struct sockaddr addr;
-    socklen_t size;
+    /* sometimes gives EINVAL if not initialized. */
+    socklen_t size = sizeof(addr);
+    tomd_p("accept loop [%d]", i++);
+    errno = 0;
     int accept_sfd =
       accept(sfd,
              &addr,             /* requester info */
              &size);            /* len of requester info */
     if(accept_sfd < 0){
+      if(errno == EINVAL){
+        tomd_p("EINVAL");
+      }
       perror("[tomd] accept socket");
       exit(EXIT_FAILURE);
     }
 
-    /* int getsockname(accept_sfd, */
-    /*                 addr, */
-    /*                 size); */
-    
-    printf("[tomd] accepted socket connection from '%s'\n",
-           ((struct sockaddr_un *) &addr)->sun_path);
-
-    char accept_buf[100] = {};
-    
-    read(accept_sfd, accept_buf, 100);
-    printf("[tomd] got message '%s'\n, accept_buf");
-    close(accept_sfd);
+    handle_connection(accept_sfd);
   }
 }
 
@@ -172,9 +327,10 @@ int main(int argc, char **argv)
 {
   header();
   init();
-  daemonize();
+  run_jobs();
+  /* daemonize(); */
   run();
   cleanup();
-  
+
   return EXIT_SUCCESS;
 }