Browse Source

Handle a pirserver that sends no output (because, for example, it failed to launch)

Ian Goldberg 3 years ago
parent
commit
799037a3b0

+ 12 - 7
src/feature/dircache/dircache.c

@@ -1425,15 +1425,20 @@ void
 dircache_pirserver_reply_params(dir_connection_t *conn,
     const char *params, size_t params_len)
 {
-    log_info(LD_REND, "PIRSERVER Responding with params");
-    write_http_response_header_impl(conn, params_len,
-            "application/octet-stream",
-            compression_method_get_name(NO_METHOD),
-            NULL, 0);
-    connection_buf_add(params, params_len, TO_CONN(conn));
+    if (params_len > 0) {
+        log_info(LD_REND, "PIRSERVER Responding with params");
+        write_http_response_header_impl(conn, params_len,
+                "application/octet-stream",
+                compression_method_get_name(NO_METHOD),
+                NULL, 0);
+        connection_buf_add(params, params_len, TO_CONN(conn));
+    } else {
+        log_info(LD_REND, "PIRSERVER Responding with unsuccessful params");
+        write_short_http_response(conn, 404, "Not found");
+    }
 }
 
-/** Callback function when we have the PIR params to send back to the
+/** Callback function when we have the PIR reply to send back to the
  *  client */
 void
 dircache_pirserver_reply_lookup(dir_connection_t *conn,

+ 24 - 2
src/feature/hs/hs_cache.c

@@ -983,6 +983,12 @@ hs_cache_pirserver_received(const unsigned char *hdrbuf,
 {
     dir_connection_t *conn;
     uint64_t reqid;
+    if (hdrbuf == NULL) {
+        /* The PIR process did not send a response.  Abort all pending
+         * requests. */
+        hs_pirprocess_abort_all();
+        return;
+    }
     log_info(LD_DIRSERV,"PIRSERVER response header %p type %02x body len %ld",
             *(void**)hdrbuf, hdrbuf[8], bodylen);
     memmove(&reqid, hdrbuf, sizeof(reqid));
@@ -1067,6 +1073,22 @@ hs_cache_pirserver_insert_desc(hs_cache_dir_descriptor_t *desc)
     return written;
 }
 
+/* This function is called if the PIR process fails to respond to a
+ * request for PIR paramaters */
+static void
+params_abort(dir_connection_t *conn)
+{
+    dircache_pirserver_reply_params(conn, NULL, 0);
+}
+
+/* This function is called if the PIR process fails to respond to a
+ * request for a PIR lookup */
+static void
+lookup_abort(dir_connection_t *conn)
+{
+    dircache_pirserver_reply_lookup(conn, NULL, 0);
+}
+
 /** Helper function for GET /tor/pironion/params.
  */
 int
@@ -1077,7 +1099,7 @@ hs_cache_pirserver_get_params(dir_connection_t *conn)
     int res;
     unsigned char hdr[PIRPROCESS_HDR_SIZE];
 
-    uint64_t reqid = hs_pirprocess_alloc_reqid(conn);
+    uint64_t reqid = hs_pirprocess_alloc_reqid(conn, params_abort);
     memmove(hdr, &reqid, sizeof(reqid));
     hdr[8] = PIRSERVER_REQUEST_PARAMS;
     memmove(hdr+9, "\0\0\0\0", 4);
@@ -1096,7 +1118,7 @@ hs_cache_pirserver_query(dir_connection_t *conn, const char *body,
     int res;
     unsigned char hdr[PIRPROCESS_HDR_SIZE];
 
-    uint64_t reqid = hs_pirprocess_alloc_reqid(conn);
+    uint64_t reqid = hs_pirprocess_alloc_reqid(conn, lookup_abort);
     memmove(hdr, &reqid, sizeof(reqid));
     hdr[8] = PIRSERVER_REQUEST_LOOKUP;
     *(uint32_t*)(hdr+9) = htonl(body_len);

+ 7 - 1
src/feature/hs/hs_client.c

@@ -1985,6 +1985,12 @@ static void
 hs_client_pirclient_received(const unsigned char *hdrbuf,
     const char *bodybuf, size_t bodylen)
 {
+    if (hdrbuf == NULL) {
+        /* The pirclient died before sending a response.  Abort all
+         * pending requests. */
+        hs_pirprocess_abort_all();
+        return;
+    }
     log_info(LD_REND, "PIRCLIENT response header %p type %02x body len %ld",
         (void *)hdrbuf, hdrbuf[8], bodylen);
     if (hdrbuf[8] == PIRCLIENT_RESPONSE_CREATE && bodylen > 8) {
@@ -2058,7 +2064,7 @@ hs_client_pir_create(dir_connection_t *conn)
     uint64_t reqid;
 
     if (pirparams == NULL) return;
-    reqid = hs_pirprocess_alloc_reqid(conn);
+    reqid = hs_pirprocess_alloc_reqid(conn, NULL);
     memmove(hdr, &reqid, sizeof(reqid));
     hdr[8] = PIRCLIENT_REQUEST_CREATE;
     bodylen = 32 + pirparams->size;

+ 60 - 15
src/feature/hs/hs_pirprocess.c

@@ -52,7 +52,15 @@ pirprocess_stdoutcb(evutil_socket_t fd, short what, void *arg)
 
     if (handle->readstate == PIRPROCESS_READSTATE_HEADER) {
         int res = read(fd, handle->hdrbuf + handle->readoff, handle->readleft);
-        if (res <= 0) return;
+        if (res <= 0) {
+            /* Tell the caller that the PIR process failed to send us any output. */
+            tor_free(handle->bodybuf);
+            handle->readoff = 0;
+            handle->readleft = PIRPROCESS_HDR_SIZE;
+            handle->readstate = PIRPROCESS_READSTATE_HEADER;
+            (handle->msghandler)(NULL, NULL, 0);
+            return;
+        }
         handle->readoff += res;
         handle->readleft -= res;
         if (handle->readleft == 0) {
@@ -74,7 +82,15 @@ pirprocess_stdoutcb(evutil_socket_t fd, short what, void *arg)
     } else if (handle->readstate == PIRPROCESS_READSTATE_BODY) {
         int res = read(fd, handle->bodybuf + handle->readoff,
                         handle->readleft);
-        if (res <= 0) return;
+        if (res <= 0) {
+            /* Tell the caller that the PIR process failed to send us any output. */
+            tor_free(handle->bodybuf);
+            handle->readoff = 0;
+            handle->readleft = PIRPROCESS_HDR_SIZE;
+            handle->readstate = PIRPROCESS_READSTATE_HEADER;
+            (handle->msghandler)(NULL, NULL, 0);
+            return;
+        }
         handle->readoff += res;
         handle->readleft -= res;
         if (handle->readleft == 0) {
@@ -301,7 +317,7 @@ int
 hs_pirprocess_send(pir_process_t handle, const unsigned char *buf,
     size_t len)
 {
-    if (handle->process == NULL ||
+    if (handle == NULL || handle->process == NULL ||
             handle->process->status != PROCESS_STATUS_RUNNING) {
         /* We don't have a process to talk to */
         return -1;
@@ -315,11 +331,16 @@ hs_pirprocess_send(pir_process_t handle, const unsigned char *buf,
     return len;
 }
 
-/* What we really want is a map from uint64_t to dir_connection_t*, but
- * we've got an implementation of char[20] to void*, which we'll
- * repurpose for this use.  Note that the dir_connection_t* pointers in
- * this map are *not* owned by this map, and this map must not free
- * them. */
+typedef struct {
+    dir_connection_t *conn;
+    pir_process_abort_fn abort_fn;
+} pirprocess_digestmap_entry_t;
+
+/* What we really want is a map from uint64_t to
+ * pirprocess_digestmap_entry_t*, but we've got an implementation of
+ * char[20] to void*, which we'll repurpose for this use.  Note that the
+ * dir_connection_t* pointers in this map are *not* owned by this map,
+ * and this map must not free them. */
 static digestmap_t *pirprocess_reqid_map;
 
 /* The last-used request id */
@@ -332,16 +353,35 @@ hs_pirprocess_init(void)
   pirprocess_last_reqid = 0;
 }
 
+static void
+entry_abort_free(void *p)
+{
+  pirprocess_digestmap_entry_t *entry = (pirprocess_digestmap_entry_t *)p;
+  if (entry->abort_fn) {
+    (entry->abort_fn)(entry->conn);
+  }
+  tor_free(entry);
+}
+
+void
+hs_pirprocess_abort_all(void)
+{
+  digestmap_free(pirprocess_reqid_map, entry_abort_free);
+  hs_pirprocess_init();
+}
+
 void
 hs_pirprocess_free_all(void)
 {
-  digestmap_free(pirprocess_reqid_map, NULL);
+  digestmap_free(pirprocess_reqid_map, tor_free_);
 }
 
 uint64_t
-hs_pirprocess_alloc_reqid(dir_connection_t *dir_conn)
+hs_pirprocess_alloc_reqid(dir_connection_t *dir_conn,
+        pir_process_abort_fn abort_fn)
 {
     char mapbuf[DIGEST_LEN];
+    pirprocess_digestmap_entry_t *entry;
     uint64_t reqid = dir_conn->pirprocess_reqid;
     if (reqid > 0) {
         return reqid;
@@ -354,7 +394,10 @@ hs_pirprocess_alloc_reqid(dir_connection_t *dir_conn)
     reqid = pirprocess_last_reqid;
     memset(mapbuf, 0, DIGEST_LEN);
     memmove(mapbuf, &reqid, sizeof(reqid));
-    digestmap_set(pirprocess_reqid_map, mapbuf, dir_conn);
+    entry = tor_malloc(sizeof(*entry));
+    entry->conn = dir_conn;
+    entry->abort_fn = abort_fn;
+    digestmap_set(pirprocess_reqid_map, mapbuf, entry);
     dir_conn->pirprocess_reqid = reqid;
     return dir_conn->pirprocess_reqid;
 }
@@ -364,10 +407,12 @@ hs_pirprocess_dealloc_reqid(dir_connection_t *dir_conn)
 {
     char mapbuf[DIGEST_LEN];
     uint64_t reqid = dir_conn->pirprocess_reqid;
+    pirprocess_digestmap_entry_t *entry;
     if (reqid == 0) return;
     memset(mapbuf, 0, DIGEST_LEN);
     memmove(mapbuf, &reqid, sizeof(reqid));
-    digestmap_remove(pirprocess_reqid_map, mapbuf);
+    entry = digestmap_remove(pirprocess_reqid_map, mapbuf);
+    tor_free(entry);
     dir_conn->pirprocess_reqid = 0;
 }
 
@@ -375,9 +420,9 @@ dir_connection_t *
 hs_pirprocess_lookup_reqid(uint64_t reqid)
 {
     char mapbuf[DIGEST_LEN];
-    dir_connection_t *dir_conn;
+    pirprocess_digestmap_entry_t *entry;
     memset(mapbuf, 0, DIGEST_LEN);
     memmove(mapbuf, &reqid, sizeof(reqid));
-    dir_conn = digestmap_get(pirprocess_reqid_map, mapbuf);
-    return dir_conn;
+    entry = digestmap_get(pirprocess_reqid_map, mapbuf);
+    return entry->conn;
 }

+ 4 - 1
src/feature/hs/hs_pirprocess.h

@@ -14,6 +14,7 @@ typedef void (*pir_process_msghandler_t)(const unsigned char *hdrbuf,
         const char *bodybuf, size_t bodylen);
 
 typedef struct pir_process_st *pir_process_t;
+typedef void (*pir_process_abort_fn)(dir_connection_t *);
 
 void hs_pirprocess_poke(const char *path, const char *loglabel,
     pir_process_msghandler_t msghandler, pir_process_t *handlep);
@@ -24,8 +25,10 @@ int hs_pirprocess_send(pir_process_t handle, const unsigned char *buf,
     size_t len);
 
 void hs_pirprocess_init(void);
+void hs_pirprocess_abort_all(void);
 void hs_pirprocess_free_all(void);
-uint64_t hs_pirprocess_alloc_reqid(dir_connection_t *dir_conn);
+uint64_t hs_pirprocess_alloc_reqid(dir_connection_t *dir_conn,
+        pir_process_abort_fn abort_fn);
 void hs_pirprocess_dealloc_reqid(dir_connection_t *dir_conn);
 dir_connection_t *hs_pirprocess_lookup_reqid(uint64_t reqid);