chiark / gitweb /
prefork-interp: New protocol: C: more negotiation-ness etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 15 Aug 2022 17:34:50 +0000 (18:34 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 21 Aug 2022 20:21:10 +0000 (21:21 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
cprogs/prefork-interp.c
cprogs/prefork.c

index 338e60ef58b84b6924a73a2c18698335f4ade920..4883a2dd684e7b01f224824dfa9bd9361f6b3acb 100644 (file)
@@ -280,15 +280,36 @@ static bool was_eof(FILE *call_sock) {
   return feof(call_sock) || errno==ECONNRESET;
 }
 
-// Does protocol exchange.  Returns 0 if OK, error msg if peer was garbage.
-static const char *protocol_exchange(FILE *call_sock) {
-  char ack;
-  size_t sr = fread(&ack, sizeof(ack), 1, call_sock);
+// Returns -1 on EOF
+static int protocol_read_maybe(FILE *call_sock, void *data, size_t sz) {
+  size_t sr = fread(data, sz, 1, call_sock);
   if (sr != 1) {
-    if (was_eof(call_sock)) return "initial monitor process quit";
-    diee("read() ack byte");
+    if (was_eof(call_sock)) return -1;
+    diee("read() on monitor call socket");
   }
-  if (ack != '\n') die("got ack byte 0x%02x, not '\n'", ack);
+  return 0;
+}
+
+static void protocol_read(FILE *call_sock, void *data, size_t sz) {
+  if (protocol_read_maybe(call_sock, data, sz) < 0)
+    die("monitor process quit unexpectedly");
+}
+
+// Does protocol exchange.  Returns 0 if OK, error msg if peer was garbage.
+static const char *protocol_exchange(FILE *call_sock) {
+  char magic[sizeof(header_magic)];
+
+  if (protocol_read_maybe(&magic, sizeof(magic)) < 0)
+    return "initial monitor process quit";
+
+  if (memcmp(header, header_magic, sizeof(header_magic)))
+    die("got unexpected protocol magic 0x%04lx",
+       header[0], header[1], header[2], header[3]);
+
+  uint32_t xdata_len;
+  protocol_read(&xdata_len, sizeof(xdata_len));
+  void *xdata = xmalloc(xdata_len);
+  protocol_read(xdata, xdata_len);
 
   // We're committed now, send the request (or bail out)
   send_request(call_sock);
@@ -336,6 +357,12 @@ void become_setup(int sfd, int fake_pair[2]) {
   if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
   if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
 
+  // Extension could work like this:
+  //
+  // We advertise a new protocol (perhaps one which is nearly entirely
+  // different after the connect) by putting a name for it comma-separated
+  // next to "v1".  Simple extension can be done by having the script
+  // side say something about it in the ack xdata, which we currently ignore.
   putenv(m_asprintf("PREFORK_INTERP=v1 %d,%d %s",
                    sfd, call_fd, socket_path));
 
@@ -441,11 +468,7 @@ int main(int argc_unused, const char *const *argv) {
 
   FILE *call_sock = connect_or_spawn();
   uint32_t status;
-  ssize_t sr = fread(&status, sizeof(status), 1, call_sock);
-  if (sr != 1) {
-    if (was_eof(call_sock)) die("per-call server monitor process quit");
-    diee("read status from call socket");
-  }
+  protocol_read(&status, sizeof(status);
 
   status = ntohl(status);
   if (status > INT_MAX) die("status 0x%lx does not fit in an int",
index 909d0658ebf7f407f317f32164299b8306ff7101..08958ce8a66e338da5c168a9e64a244f4e513d8c 100644 (file)
@@ -10,6 +10,8 @@ static uid_t us;
 static const char *run_base;
 static const char *run_base_mkdir_p;
 
+static const char header_magic[4] = "PFI\n";
+
 void common_diee(const char *m) { diee("%s", m); }
 void common_die (const char *m) { die ("%s", m); }