X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Fsd-rtnl.c;h=2ab9d90aa790d4f76360d6adc45111d2b6a6fe1b;hb=0a827d105de9d3d502f22e77fb3ff83da479c2e7;hp=08b82ab2a94f3f6dca6bb5e21934d90cbb48cfcc;hpb=607553f9306286fdccf0b356bc3d1087adfe21c4;p=elogind.git diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c index 08b82ab2a..2ab9d90aa 100644 --- a/src/libsystemd/sd-rtnl/sd-rtnl.c +++ b/src/libsystemd/sd-rtnl/sd-rtnl.c @@ -31,7 +31,7 @@ #include "rtnl-util.h" static int sd_rtnl_new(sd_rtnl **ret) { - sd_rtnl *rtnl; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; assert_return(ret, -EINVAL); @@ -52,12 +52,12 @@ static int sd_rtnl_new(sd_rtnl **ret) { /* We guarantee that wqueue always has space for at least * one entry */ rtnl->wqueue = new(sd_rtnl_message*, 1); - if (!rtnl->wqueue) { - free(rtnl); + if (!rtnl->wqueue) return -ENOMEM; - } *ret = rtnl; + rtnl = NULL; + return 0; } @@ -70,8 +70,8 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) { return rtnl->original_pid != getpid(); } -int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) { - _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL; +int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; socklen_t addrlen; int r; @@ -104,6 +104,9 @@ int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) { } sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) { + assert_return(rtnl, NULL); + assert_return(!rtnl_pid_changed(rtnl), NULL); + if (rtnl) assert_se(REFCNT_INC(rtnl->n_ref) >= 2); @@ -111,8 +114,12 @@ sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) { } sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) { + if (!rtnl) + return NULL; - if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) { + assert_return(!rtnl_pid_changed(rtnl), NULL); + + if (REFCNT_DEC(rtnl->n_ref) <= 0) { struct match_callback *f; unsigned i; @@ -127,20 +134,36 @@ sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) { hashmap_free_free(rtnl->reply_callbacks); prioq_free(rtnl->reply_callbacks_prioq); + sd_event_source_unref(rtnl->io_event_source); + sd_event_source_unref(rtnl->time_event_source); + sd_event_source_unref(rtnl->exit_event_source); + sd_event_unref(rtnl->event); + while ((f = rtnl->match_callbacks)) { LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); free(f); } - if (rtnl->fd >= 0) - close_nointr_nofail(rtnl->fd); - + safe_close(rtnl->fd); free(rtnl); } return NULL; } +static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) { + assert(rtnl); + assert(!rtnl_pid_changed(rtnl)); + assert(m); + assert(m->hdr); + + m->hdr->nlmsg_seq = rtnl->serial++; + + rtnl_message_seal(m); + + return; +} + int sd_rtnl_send(sd_rtnl *nl, sd_rtnl_message *message, uint32_t *serial) { @@ -149,10 +172,9 @@ int sd_rtnl_send(sd_rtnl *nl, assert_return(nl, -EINVAL); assert_return(!rtnl_pid_changed(nl), -ECHILD); assert_return(message, -EINVAL); + assert_return(!message->sealed, -EPERM); - r = message_seal(nl, message); - if (r < 0) - return r; + rtnl_seal_message(nl, message); if (nl->wqueue_size <= 0) { /* send directly */ @@ -181,7 +203,7 @@ int sd_rtnl_send(sd_rtnl *nl, } if (serial) - *serial = message_get_serial(message); + *serial = rtnl_message_get_serial(message); return 1; } @@ -205,10 +227,8 @@ static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) { /* Try to read a new message */ r = socket_read_message(rtnl, &z); - if (r < 0) + if (r <= 0) return r; - if (r == 0) - return 0; *message = z; @@ -241,7 +261,7 @@ static int dispatch_wqueue(sd_rtnl *rtnl) { } static int process_timeout(sd_rtnl *rtnl) { - _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; struct reply_callback *c; usec_t n; int r; @@ -256,7 +276,7 @@ static int process_timeout(sd_rtnl *rtnl) { if (c->timeout > n) return 0; - r = message_new_synthetic_error(-ETIMEDOUT, c->serial, &m); + r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m); if (r < 0) return r; @@ -277,7 +297,10 @@ static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) { assert(rtnl); assert(m); - serial = message_get_serial(m); + if (sd_rtnl_message_is_broadcast(m)) + return 0; + + serial = rtnl_message_get_serial(m); c = hashmap_remove(rtnl->reply_callbacks, &serial); if (!c) return 0; @@ -315,7 +338,7 @@ static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) { } static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) { - _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; int r; assert(rtnl); @@ -557,7 +580,7 @@ int sd_rtnl_call(sd_rtnl *nl, for (;;) { usec_t left; - _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *incoming = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL; if (!room) { sd_rtnl_message **q; @@ -580,7 +603,7 @@ int sd_rtnl_call(sd_rtnl *nl, if (r < 0) return r; if (incoming) { - uint32_t received_serial = message_get_serial(incoming); + uint32_t received_serial = rtnl_message_get_serial(incoming); if (received_serial == serial) { r = sd_rtnl_message_get_errno(incoming); @@ -774,7 +797,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { return r; } - r = sd_event_add_io(rtnl->event, rtnl->fd, 0, io_callback, rtnl, &rtnl->io_event_source); + r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl); if (r < 0) goto fail; @@ -786,7 +809,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { if (r < 0) goto fail; - r = sd_event_add_monotonic(rtnl->event, 0, 0, time_callback, rtnl, &rtnl->time_event_source); + r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl); if (r < 0) goto fail; @@ -794,7 +817,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { if (r < 0) goto fail; - r = sd_event_add_exit(rtnl->event, exit_callback, rtnl, &rtnl->exit_event_source); + r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl); if (r < 0) goto fail; @@ -833,7 +856,9 @@ int sd_rtnl_add_match(sd_rtnl *rtnl, 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); + assert_return(rtnl_message_type_is_link(type) || + rtnl_message_type_is_addr(type) || + rtnl_message_type_is_route(type), -ENOTSUP); c = new0(struct match_callback, 1); if (!c)