diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 4295eb7ce2..012ce5308c 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -168,6 +168,7 @@ struct VarlinkServer { Hashmap *methods; VarlinkConnect connect_callback; + VarlinkDisconnect disconnect_callback; sd_event *event; int64_t event_priority; @@ -1146,6 +1147,7 @@ int varlink_flush(Varlink *v) { } static void varlink_detach_server(Varlink *v) { + VarlinkServer *saved_server; assert(v); if (!v->server) @@ -1169,8 +1171,15 @@ static void varlink_detach_server(Varlink *v) { v->server->n_connections--; /* If this is a connection associated to a server, then let's disconnect the server and the - * connection from each other. This drops the dangling reference that connect_callback() set up. */ - v->server = varlink_server_unref(v->server); + * connection from each other. This drops the dangling reference that connect_callback() set up. But + * before we release the references, let's call the disconnection callback if it is defined. */ + + saved_server = TAKE_PTR(v->server); + + if (saved_server->disconnect_callback) + saved_server->disconnect_callback(saved_server, v, saved_server->userdata); + + varlink_server_unref(saved_server); varlink_unref(v); } @@ -2413,6 +2422,16 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) { return 0; } +int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect callback) { + assert_return(s, -EINVAL); + + if (callback && s->disconnect_callback && callback != s->disconnect_callback) + return -EBUSY; + + s->disconnect_callback = callback; + return 0; +} + unsigned varlink_server_connections_max(VarlinkServer *s) { int dts; diff --git a/src/shared/varlink.h b/src/shared/varlink.h index 6272b33228..7440f2ca44 100644 --- a/src/shared/varlink.h +++ b/src/shared/varlink.h @@ -51,6 +51,7 @@ typedef enum VarlinkServerFlags { typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata); typedef int (*VarlinkReply)(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata); typedef int (*VarlinkConnect)(VarlinkServer *server, Varlink *link, void *userdata); +typedef void (*VarlinkDisconnect)(VarlinkServer *server, Varlink *link, void *userdata); int varlink_connect_address(Varlink **ret, const char *address); int varlink_connect_fd(Varlink **ret, int fd); @@ -134,6 +135,7 @@ int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMeth int varlink_server_bind_method_many_internal(VarlinkServer *s, ...); #define varlink_server_bind_method_many(s, ...) varlink_server_bind_method_many_internal(s, __VA_ARGS__, NULL) int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect connect); +int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect disconnect); void* varlink_server_set_userdata(VarlinkServer *s, void *userdata); void* varlink_server_get_userdata(VarlinkServer *s);