summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@armlinux.org.uk>2021-09-11 13:57:42 +0100
committerRussell King <rmk@armlinux.org.uk>2021-09-11 13:57:42 +0100
commit2f45bcf78b77193ad6107fbb92ad0f93eb1ad4fc (patch)
tree18b115356a92e67e2276a2dbe97139d2237c0f24
parentacc52e700121120726b42a6dadd8c12f030ba349 (diff)
Restrict updates to the newest updater
Prevent old update connections from providing updates, closing them if they attempt an update. In doing so, this also limits resource usage when we have multiple updaters connected (which should never happen.) Signed-off-by: Russell King <rmk@armlinux.org.uk>
-rw-r--r--event-httpd.c14
-rw-r--r--resource.c34
-rw-r--r--resource.h3
3 files changed, 44 insertions, 7 deletions
diff --git a/event-httpd.c b/event-httpd.c
index 27590dd..865f82f 100644
--- a/event-httpd.c
+++ b/event-httpd.c
@@ -97,19 +97,28 @@ static void update(GObject *source, GAsyncResult *res, gpointer user_data)
GError *error = NULL;
char *line;
gsize len;
+ int r;
line = g_data_input_stream_read_line_finish(c->data, res, &len, &error);
if (error || !line) {
+ if (c->resource->ops->update_close)
+ c->resource->ops->update_close(c, c->resource);
+
if (error)
g_free(error);
close_client(c);
return;
}
- c->resource->ops->update(c, c->resource, line);
+ r = c->resource->ops->update(c, c->resource, line);
g_free(line);
+ // If the update function returns an error, close this connection.
+ // This could be because we have a "newer" updater, or an error.
+ if (r == -1)
+ close_client(c);
+
g_data_input_stream_read_line_async(c->data, 0, NULL, update, c);
}
@@ -257,6 +266,9 @@ static void receive(GObject *source, GAsyncResult *res, gpointer user_data)
return;
}
+ if (resource->ops->update_open)
+ resource->ops->update_open(c, resource);
+
g_data_input_stream_read_line_async(c->data, 0, NULL,
update, c);
break;
diff --git a/resource.c b/resource.c
index bc5dfdd..8c67635 100644
--- a/resource.c
+++ b/resource.c
@@ -73,6 +73,20 @@ static int object_v1_get(struct client *c, struct resource *r)
return 1;
}
+static void object_v1_close(struct client *c, struct resource *r)
+{
+ struct resource_object *obj = r->data;
+
+ // Remove this client from the object list
+ resource_obj_del_client(obj, c);
+}
+
+static void object_v1_update_open(struct client *c, struct resource *r)
+{
+ // Keep track of the latest updater
+ r->updater = c;
+}
+
// Update all attached clients with the new resource object data
static int object_v1_update(struct client *c, struct resource *r, const char *m)
{
@@ -80,6 +94,12 @@ static int object_v1_update(struct client *c, struct resource *r, const char *m)
GString *string;
char *n;
+ // Only allow the latest updater to provide updates, in case we
+ // end up with multiple connections. This also allows us to quickly
+ // release the resources of a stale connection.
+ if (r->updater != c)
+ return -1;
+
// Remove any trailing whitespace.
n = g_strchomp(g_strdup(m));
@@ -97,18 +117,20 @@ static int object_v1_update(struct client *c, struct resource *r, const char *m)
return 0;
}
-static void object_v1_close(struct client *c, struct resource *r)
+static void object_v1_update_close(struct client *c, struct resource *r)
{
- struct resource_object *obj = r->data;
-
- // Remove this client from the object list
- resource_obj_del_client(obj, c);
+ // If the updater goes away, clear the data so we don't serve
+ // stale data.
+ if (r->updater == c)
+ r->updater = NULL;
}
static const struct resource_ops resource_v1_ops = {
.get = object_v1_get,
- .update = object_v1_update,
.close = object_v1_close,
+ .update_open = object_v1_update_open,
+ .update = object_v1_update,
+ .update_close = object_v1_update_close,
};
static struct resource resource_position1 = {
diff --git a/resource.h b/resource.h
index c3a1907..657397b 100644
--- a/resource.h
+++ b/resource.h
@@ -9,11 +9,14 @@ struct resource;
struct resource_ops {
int (*get)(struct client *c, struct resource *r);
void (*close)(struct client *c, struct resource *r);
+ void (*update_open)(struct client *c, struct resource *r);
int (*update)(struct client *c, struct resource *r, const char *m);
+ void (*update_close)(struct client *c, struct resource *r);
};
struct resource {
const struct resource_ops *ops;
+ struct client *updater;
void *data;
};