sd_netlink_message, sd_netlink_message_unref);
static int netlink_queue_received_message(sd_netlink *nl, sd_netlink_message *m) {
+ uint32_t serial;
int r;
assert(nl);
if (r < 0)
return r;
+ sd_netlink_message_ref(m);
+
+ if (sd_netlink_message_is_broadcast(m))
+ return 0;
+
+ serial = message_get_serial(m);
+ if (serial == 0)
+ return 0;
+
+ if (sd_netlink_message_get_errno(m) < 0) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *old = NULL;
+
+ old = hashmap_remove(nl->rqueue_by_serial, UINT32_TO_PTR(serial));
+ if (old)
+ log_debug("sd-netlink: received error message with serial %"PRIu32", but another message with "
+ "the same serial is already stored in the read queue, replacing.", serial);
+ }
+
+ r = hashmap_ensure_put(&nl->rqueue_by_serial, &netlink_message_hash_ops, UINT32_TO_PTR(serial), m);
+ if (r == -EEXIST) {
+ if (!sd_netlink_message_is_error(m))
+ log_debug("sd-netlink: received message with serial %"PRIu32", but another message with "
+ "the same serial is already stored in the read queue, ignoring.", serial);
+ return 0;
+ }
+ if (r < 0) {
+ sd_netlink_message_unref(ordered_set_remove(nl->rqueue, m));
+ return r;
+ }
+
sd_netlink_message_ref(m);
return 0;
}
assert(nl);
ordered_set_free(nl->rqueue);
+ hashmap_free(nl->rqueue_by_serial);
hashmap_free(nl->rqueue_partial_by_serial);
free(nl->rbuffer);
/* Dispatch a queued message */
m = ordered_set_steal_first(nl->rqueue);
+ sd_netlink_message_unref(hashmap_remove_value(nl->rqueue_by_serial, UINT32_TO_PTR(message_get_serial(m)), m));
*ret = m;
return !!m;
}
timeout = calc_elapse(usec);
for (;;) {
- sd_netlink_message *m;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
usec_t left;
- ORDERED_SET_FOREACH(m, nl->rqueue) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
- uint32_t received_serial;
+ m = hashmap_remove(nl->rqueue_by_serial, UINT32_TO_PTR(serial));
+ if (m) {
uint16_t type;
- received_serial = message_get_serial(m);
- if (received_serial != serial)
- continue;
-
/* found a match, remove from rqueue and return it */
- ordered_set_remove(nl->rqueue, m);
- incoming = TAKE_PTR(m);
+ sd_netlink_message_unref(ordered_set_remove(nl->rqueue, m));
- r = sd_netlink_message_get_errno(incoming);
+ r = sd_netlink_message_get_errno(m);
if (r < 0)
return r;
- r = sd_netlink_message_get_type(incoming, &type);
+ r = sd_netlink_message_get_type(m, &type);
if (r < 0)
return r;
}
if (ret)
- *ret = TAKE_PTR(incoming);
+ *ret = TAKE_PTR(m);
return 1;
}