rtnl->original_pid = getpid();
+ LIST_HEAD_INIT(rtnl->match_callbacks);
+
/* We guarantee that wqueue always has space for at least
* one entry */
rtnl->wqueue = new(sd_rtnl_message*, 1);
socklen_t addrlen;
int r;
+ assert_return(ret, -EINVAL);
+
r = sd_rtnl_new(&rtnl);
if (r < 0)
return r;
sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
+ struct match_callback *f;
unsigned i;
for (i = 0; i < rtnl->rqueue_size; i++)
hashmap_free_free(rtnl->reply_callbacks);
prioq_free(rtnl->reply_callbacks_prioq);
+ while ((f = rtnl->match_callbacks)) {
+ LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
+ free(f);
+ }
+
if (rtnl->fd >= 0)
close_nointr_nofail(rtnl->fd);
return r;
}
+static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
+ struct match_callback *c;
+ uint16_t type;
+ int r;
+
+ assert(rtnl);
+ assert(m);
+
+ r = sd_rtnl_message_get_type(m, &type);
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
+ if (type == c->type) {
+ r = c->callback(rtnl, m, c->userdata);
+ if (r != 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
int r;
+ assert(rtnl);
+
r = process_timeout(rtnl);
if (r != 0)
goto null_message;
if (r != 0)
goto null_message;
+ r = process_match(rtnl, m);
+ if (r != 0)
+ goto null_message;
+
if (ret) {
*ret = m;
m = NULL;
return 1;
}
-static int quit_callback(sd_event_source *event, void *userdata) {
+static int exit_callback(sd_event_source *event, void *userdata) {
sd_rtnl *rtnl = userdata;
assert(event);
if (r < 0)
goto fail;
- r = sd_event_add_quit(rtnl->event, quit_callback, rtnl, &rtnl->quit_event_source);
+ r = sd_event_add_exit(rtnl->event, exit_callback, rtnl, &rtnl->exit_event_source);
if (r < 0)
goto fail;
if (rtnl->time_event_source)
rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
- if (rtnl->quit_event_source)
- rtnl->quit_event_source = sd_event_source_unref(rtnl->quit_event_source);
+ if (rtnl->exit_event_source)
+ rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
if (rtnl->event)
rtnl->event = sd_event_unref(rtnl->event);
return 0;
}
+
+int sd_rtnl_add_match(sd_rtnl *rtnl,
+ uint16_t type,
+ sd_rtnl_message_handler_t callback,
+ void *userdata) {
+ struct match_callback *c;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(callback, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+ assert_return(message_type_is_link(type) || message_type_is_addr(type) || message_type_is_route(type), -ENOTSUP);
+
+ c = new0(struct match_callback, 1);
+ if (!c)
+ return -ENOMEM;
+
+ c->callback = callback;
+ c->type = type;
+ c->userdata = userdata;
+
+ LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
+
+ return 0;
+}
+
+int sd_rtnl_remove_match(sd_rtnl *rtnl,
+ uint16_t type,
+ sd_rtnl_message_handler_t callback,
+ void *userdata) {
+ struct match_callback *c;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(callback, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+ LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
+ if (c->callback == callback && c->type == type && c->userdata == userdata) {
+ LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
+ free(c);
+
+ return 1;
+ }
+
+ return 0;
+}