-char (*request_name[]) = {
- "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
- "STATUS", "ERROR", "TERMREQ",
- "PING", "PONG",
-// "ADD_NODE", "DEL_NODE",
- "ADD_SUBNET", "DEL_SUBNET",
- "ADD_EDGE", "DEL_EDGE",
- "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
- "PACKET",
-};
+static const int request_timeout = 60;
+
+static void age_past_requests(event_loop_t *loop, void *data) {
+ (void)data;
+ meshlink_handle_t *mesh = loop->data;
+ int left = 0, deleted = 0;
+
+ for splay_each(past_request_t, p, mesh->past_request_tree) {
+ if(p->firstseen + request_timeout <= mesh->loop.now.tv_sec) {
+ splay_delete_node(mesh->past_request_tree, node), deleted++;
+ } else {
+ left++;
+ }
+ }
+
+ if(left || deleted) {
+ logger(mesh, MESHLINK_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left);
+ }
+
+ if(left) {
+ timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
+ 10, prng(mesh, TIMER_FUDGE)
+ });
+ }
+}
+
+bool seen_request(meshlink_handle_t *mesh, const char *request) {
+ assert(request);
+ assert(*request);
+
+ past_request_t *new, p = {.request = request};
+
+ if(splay_search(mesh->past_request_tree, &p)) {
+ logger(mesh, MESHLINK_DEBUG, "Already seen request");
+ return true;
+ } else {
+ new = xmalloc(sizeof(*new));
+ new->request = xstrdup(request);
+ new->firstseen = mesh->loop.now.tv_sec;
+
+ if(!mesh->past_request_tree->head) {
+ timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
+ 10, prng(mesh, TIMER_FUDGE)
+ });
+ }
+
+ splay_insert(mesh->past_request_tree, new);
+ return false;
+ }
+}
+
+void init_requests(meshlink_handle_t *mesh) {
+ assert(!mesh->past_request_tree);
+
+ mesh->past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request);
+ timeout_add(&mesh->loop, &mesh->past_request_timeout, age_past_requests, NULL, &(struct timeval) {
+ 0, 0
+ });
+}
+
+void exit_requests(meshlink_handle_t *mesh) {
+ if(mesh->past_request_tree) {
+ splay_delete_tree(mesh->past_request_tree);
+ }
+
+ mesh->past_request_tree = NULL;
+
+ timeout_del(&mesh->loop, &mesh->past_request_timeout);
+}