chiark / gitweb /
sd-rtnl: rtnl_call - don't dispatch wqueue after timeout has passed
[elogind.git] / src / libsystemd / sd-rtnl / sd-rtnl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <poll.h>
24
25 #include "missing.h"
26 #include "macro.h"
27 #include "util.h"
28 #include "hashmap.h"
29
30 #include "sd-rtnl.h"
31 #include "rtnl-internal.h"
32 #include "rtnl-util.h"
33
34 static int sd_rtnl_new(sd_rtnl **ret) {
35         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
36
37         assert_return(ret, -EINVAL);
38
39         rtnl = new0(sd_rtnl, 1);
40         if (!rtnl)
41                 return -ENOMEM;
42
43         rtnl->n_ref = REFCNT_INIT;
44
45         rtnl->fd = -1;
46
47         rtnl->sockaddr.nl.nl_family = AF_NETLINK;
48
49         rtnl->original_pid = getpid();
50
51         LIST_HEAD_INIT(rtnl->match_callbacks);
52
53         /* We guarantee that wqueue always has space for at least
54          * one entry */
55         if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
56                 return -ENOMEM;
57
58         /* We guarantee that the read buffer has at least space for
59          * a message header */
60         if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
61                             sizeof(struct nlmsghdr), sizeof(uint8_t)))
62                 return -ENOMEM;
63
64         *ret = rtnl;
65         rtnl = NULL;
66
67         return 0;
68 }
69
70 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
71         assert(rtnl);
72
73         /* We don't support people creating an rtnl connection and
74          * keeping it around over a fork(). Let's complain. */
75
76         return rtnl->original_pid != getpid();
77 }
78
79 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
80         uint32_t groups = 0;
81         unsigned i;
82
83         for (i = 0; i < n_groups; i++) {
84                 unsigned group;
85
86                 group = va_arg(ap, unsigned);
87                 assert_return(group < 32, -EINVAL);
88
89                 groups |= group ? (1 << (group - 1)) : 0;
90         }
91
92         *_groups = groups;
93
94         return 0;
95 }
96
97 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
98         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
99         va_list ap;
100         socklen_t addrlen;
101         int r, one = 1;
102
103         assert_return(ret, -EINVAL);
104
105         r = sd_rtnl_new(&rtnl);
106         if (r < 0)
107                 return r;
108
109         rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
110         if (rtnl->fd < 0)
111                 return -errno;
112
113         r = setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
114         if (r < 0)
115                 return -errno;
116
117         r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
118         if (r < 0)
119                 return -errno;
120
121         va_start(ap, n_groups);
122         r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
123         va_end(ap);
124         if (r < 0)
125                 return r;
126
127         addrlen = sizeof(rtnl->sockaddr);
128
129         r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
130         if (r < 0)
131                 return -errno;
132
133         r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
134         if (r < 0)
135                 return r;
136
137         *ret = rtnl;
138         rtnl = NULL;
139
140         return 0;
141 }
142
143 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
144         return fd_inc_rcvbuf(rtnl->fd, size);
145 }
146
147 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
148         assert_return(rtnl, NULL);
149         assert_return(!rtnl_pid_changed(rtnl), NULL);
150
151         if (rtnl)
152                 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
153
154         return rtnl;
155 }
156
157 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
158         if (!rtnl)
159                 return NULL;
160
161         assert_return(!rtnl_pid_changed(rtnl), NULL);
162
163         if (REFCNT_DEC(rtnl->n_ref) <= 0) {
164                 struct match_callback *f;
165                 unsigned i;
166
167                 for (i = 0; i < rtnl->rqueue_size; i++)
168                         sd_rtnl_message_unref(rtnl->rqueue[i]);
169                 free(rtnl->rqueue);
170
171                 for (i = 0; i < rtnl->rqueue_partial_size; i++)
172                         sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
173                 free(rtnl->rqueue_partial);
174
175                 for (i = 0; i < rtnl->wqueue_size; i++)
176                         sd_rtnl_message_unref(rtnl->wqueue[i]);
177                 free(rtnl->wqueue);
178
179                 free(rtnl->rbuffer);
180
181                 hashmap_free_free(rtnl->reply_callbacks);
182                 prioq_free(rtnl->reply_callbacks_prioq);
183
184                 sd_event_source_unref(rtnl->io_event_source);
185                 sd_event_source_unref(rtnl->time_event_source);
186                 sd_event_source_unref(rtnl->exit_event_source);
187                 sd_event_unref(rtnl->event);
188
189                 while ((f = rtnl->match_callbacks)) {
190                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
191                         free(f);
192                 }
193
194                 safe_close(rtnl->fd);
195                 free(rtnl);
196         }
197
198         return NULL;
199 }
200
201 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
202         assert(rtnl);
203         assert(!rtnl_pid_changed(rtnl));
204         assert(m);
205         assert(m->hdr);
206
207         m->hdr->nlmsg_seq = rtnl->serial++;
208
209         rtnl_message_seal(m);
210
211         return;
212 }
213
214 int sd_rtnl_send(sd_rtnl *nl,
215                  sd_rtnl_message *message,
216                  uint32_t *serial) {
217         int r;
218
219         assert_return(nl, -EINVAL);
220         assert_return(!rtnl_pid_changed(nl), -ECHILD);
221         assert_return(message, -EINVAL);
222         assert_return(!message->sealed, -EPERM);
223
224         rtnl_seal_message(nl, message);
225
226         if (nl->wqueue_size <= 0) {
227                 /* send directly */
228                 r = socket_write_message(nl, message);
229                 if (r < 0)
230                         return r;
231                 else if (r == 0) {
232                         /* nothing was sent, so let's put it on
233                          * the queue */
234                         nl->wqueue[0] = sd_rtnl_message_ref(message);
235                         nl->wqueue_size = 1;
236                 }
237         } else {
238                 /* append to queue */
239                 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
240                         log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
241                         return -ENOBUFS;
242                 }
243
244                 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
245                         return -ENOMEM;
246
247                 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
248         }
249
250         if (serial)
251                 *serial = rtnl_message_get_serial(message);
252
253         return 1;
254 }
255
256 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
257         assert(rtnl);
258
259         if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
260                 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
261                 return -ENOBUFS;
262         }
263
264         if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
265                 return -ENOMEM;
266
267         return 0;
268 }
269
270 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
271         assert(rtnl);
272
273         if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
274                 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
275                 return -ENOBUFS;
276         }
277
278         if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
279                             rtnl->rqueue_partial_size + 1))
280                 return -ENOMEM;
281
282         return 0;
283 }
284
285 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
286         int r;
287
288         assert(rtnl);
289         assert(message);
290
291         if (rtnl->rqueue_size <= 0) {
292                 /* Try to read a new message */
293                 r = socket_read_message(rtnl);
294                 if (r <= 0)
295                         return r;
296         }
297
298         /* Dispatch a queued message */
299         *message = rtnl->rqueue[0];
300         rtnl->rqueue_size --;
301         memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
302
303         return 1;
304 }
305
306 static int dispatch_wqueue(sd_rtnl *rtnl) {
307         int r, ret = 0;
308
309         assert(rtnl);
310
311         while (rtnl->wqueue_size > 0) {
312                 r = socket_write_message(rtnl, rtnl->wqueue[0]);
313                 if (r < 0)
314                         return r;
315                 else if (r == 0)
316                         /* Didn't do anything this time */
317                         return ret;
318                 else {
319                         /* see equivalent in sd-bus.c */
320                         sd_rtnl_message_unref(rtnl->wqueue[0]);
321                         rtnl->wqueue_size --;
322                         memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
323
324                         ret = 1;
325                 }
326         }
327
328         return ret;
329 }
330
331 static int process_timeout(sd_rtnl *rtnl) {
332         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
333         struct reply_callback *c;
334         usec_t n;
335         int r;
336
337         assert(rtnl);
338
339         c = prioq_peek(rtnl->reply_callbacks_prioq);
340         if (!c)
341                 return 0;
342
343         n = now(CLOCK_MONOTONIC);
344         if (c->timeout > n)
345                 return 0;
346
347         r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
348         if (r < 0)
349                 return r;
350
351         assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
352         hashmap_remove(rtnl->reply_callbacks, &c->serial);
353
354         r = c->callback(rtnl, m, c->userdata);
355         free(c);
356
357         return r < 0 ? r : 1;
358 }
359
360 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
361         struct reply_callback *c;
362         uint64_t serial;
363         int r;
364
365         assert(rtnl);
366         assert(m);
367
368         if (sd_rtnl_message_is_broadcast(m))
369                 return 0;
370
371         serial = rtnl_message_get_serial(m);
372         c = hashmap_remove(rtnl->reply_callbacks, &serial);
373         if (!c)
374                 return 0;
375
376         if (c->timeout != 0)
377                 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
378
379         r = c->callback(rtnl, m, c->userdata);
380         free(c);
381
382         return r;
383 }
384
385 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
386         struct match_callback *c;
387         uint16_t type;
388         int r;
389
390         assert(rtnl);
391         assert(m);
392
393         r = sd_rtnl_message_get_type(m, &type);
394         if (r < 0)
395                 return r;
396
397         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
398                 if (type == c->type) {
399                         r = c->callback(rtnl, m, c->userdata);
400                         if (r != 0)
401                                 return r;
402                 }
403         }
404
405         return 0;
406 }
407
408 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
409         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
410         int r;
411
412         assert(rtnl);
413
414         r = process_timeout(rtnl);
415         if (r != 0)
416                 goto null_message;
417
418         r = dispatch_wqueue(rtnl);
419         if (r != 0)
420                 goto null_message;
421
422         r = dispatch_rqueue(rtnl, &m);
423         if (r < 0)
424                 return r;
425         if (!m)
426                 goto null_message;
427
428         r = process_reply(rtnl, m);
429         if (r != 0)
430                 goto null_message;
431
432         r = process_match(rtnl, m);
433         if (r != 0)
434                 goto null_message;
435
436         if (ret) {
437                 *ret = m;
438                 m = NULL;
439
440                 return 1;
441         }
442
443         return 1;
444
445 null_message:
446         if (r >= 0 && ret)
447                 *ret = NULL;
448
449         return r;
450 }
451
452 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
453         RTNL_DONT_DESTROY(rtnl);
454         int r;
455
456         assert_return(rtnl, -EINVAL);
457         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
458         assert_return(!rtnl->processing, -EBUSY);
459
460         rtnl->processing = true;
461         r = process_running(rtnl, ret);
462         rtnl->processing = false;
463
464         return r;
465 }
466
467 static usec_t calc_elapse(uint64_t usec) {
468         if (usec == (uint64_t) -1)
469                 return 0;
470
471         if (usec == 0)
472                 usec = RTNL_DEFAULT_TIMEOUT;
473
474         return now(CLOCK_MONOTONIC) + usec;
475 }
476
477 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
478         struct pollfd p[1] = {};
479         struct timespec ts;
480         usec_t m = USEC_INFINITY;
481         int r, e;
482
483         assert(rtnl);
484
485         e = sd_rtnl_get_events(rtnl);
486         if (e < 0)
487                 return e;
488
489         if (need_more)
490                 /* Caller wants more data, and doesn't care about
491                  * what's been read or any other timeouts. */
492                 e |= POLLIN;
493         else {
494                 usec_t until;
495                 /* Caller wants to process if there is something to
496                  * process, but doesn't care otherwise */
497
498                 r = sd_rtnl_get_timeout(rtnl, &until);
499                 if (r < 0)
500                         return r;
501                 if (r > 0) {
502                         usec_t nw;
503                         nw = now(CLOCK_MONOTONIC);
504                         m = until > nw ? until - nw : 0;
505                 }
506         }
507
508         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
509                 m = timeout_usec;
510
511         p[0].fd = rtnl->fd;
512         p[0].events = e;
513
514         r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
515         if (r < 0)
516                 return -errno;
517
518         return r > 0 ? 1 : 0;
519 }
520
521 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
522         assert_return(nl, -EINVAL);
523         assert_return(!rtnl_pid_changed(nl), -ECHILD);
524
525         if (nl->rqueue_size > 0)
526                 return 0;
527
528         return rtnl_poll(nl, false, timeout_usec);
529 }
530
531 static int timeout_compare(const void *a, const void *b) {
532         const struct reply_callback *x = a, *y = b;
533
534         if (x->timeout != 0 && y->timeout == 0)
535                 return -1;
536
537         if (x->timeout == 0 && y->timeout != 0)
538                 return 1;
539
540         if (x->timeout < y->timeout)
541                 return -1;
542
543         if (x->timeout > y->timeout)
544                 return 1;
545
546         return 0;
547 }
548
549 int sd_rtnl_call_async(sd_rtnl *nl,
550                        sd_rtnl_message *m,
551                        sd_rtnl_message_handler_t callback,
552                        void *userdata,
553                        uint64_t usec,
554                        uint32_t *serial) {
555         struct reply_callback *c;
556         uint32_t s;
557         int r, k;
558
559         assert_return(nl, -EINVAL);
560         assert_return(m, -EINVAL);
561         assert_return(callback, -EINVAL);
562         assert_return(!rtnl_pid_changed(nl), -ECHILD);
563
564         r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
565         if (r < 0)
566                 return r;
567
568         if (usec != (uint64_t) -1) {
569                 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
570                 if (r < 0)
571                         return r;
572         }
573
574         c = new0(struct reply_callback, 1);
575         if (!c)
576                 return -ENOMEM;
577
578         c->callback = callback;
579         c->userdata = userdata;
580         c->timeout = calc_elapse(usec);
581
582         k = sd_rtnl_send(nl, m, &s);
583         if (k < 0) {
584                 free(c);
585                 return k;
586         }
587
588         c->serial = s;
589
590         r = hashmap_put(nl->reply_callbacks, &c->serial, c);
591         if (r < 0) {
592                 free(c);
593                 return r;
594         }
595
596         if (c->timeout != 0) {
597                 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
598                 if (r > 0) {
599                         c->timeout = 0;
600                         sd_rtnl_call_async_cancel(nl, c->serial);
601                         return r;
602                 }
603         }
604
605         if (serial)
606                 *serial = s;
607
608         return k;
609 }
610
611 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
612         struct reply_callback *c;
613         uint64_t s = serial;
614
615         assert_return(nl, -EINVAL);
616         assert_return(serial != 0, -EINVAL);
617         assert_return(!rtnl_pid_changed(nl), -ECHILD);
618
619         c = hashmap_remove(nl->reply_callbacks, &s);
620         if (!c)
621                 return 0;
622
623         if (c->timeout != 0)
624                 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
625
626         free(c);
627         return 1;
628 }
629
630 int sd_rtnl_call(sd_rtnl *rtnl,
631                 sd_rtnl_message *message,
632                 uint64_t usec,
633                 sd_rtnl_message **ret) {
634         usec_t timeout;
635         uint32_t serial;
636         unsigned i = 0;
637         int r;
638
639         assert_return(rtnl, -EINVAL);
640         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
641         assert_return(message, -EINVAL);
642
643         r = sd_rtnl_send(rtnl, message, &serial);
644         if (r < 0)
645                 return r;
646
647         timeout = calc_elapse(usec);
648
649         for (;;) {
650                 usec_t left;
651
652                 while (i < rtnl->rqueue_size) {
653                         sd_rtnl_message *incoming;
654                         uint32_t received_serial;
655
656                         incoming = rtnl->rqueue[i];
657                         received_serial = rtnl_message_get_serial(incoming);
658
659                         if (received_serial == serial) {
660                                 /* found a match, remove from rqueue and return it */
661                                 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
662                                         sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
663                                 rtnl->rqueue_size--;
664
665                                 r = sd_rtnl_message_get_errno(incoming);
666                                 if (r < 0) {
667                                         sd_rtnl_message_unref(incoming);
668                                         return r;
669                                 }
670
671                                 if (ret) {
672                                         *ret = incoming;
673                                 } else
674                                         sd_rtnl_message_unref(incoming);
675
676                                 return 1;
677                         }
678
679                         /* Try to read more, right away */
680                         i ++;
681                 }
682
683                 r = socket_read_message(rtnl);
684                 if (r < 0)
685                         return r;
686                 if (r > 0)
687                         /* received message, so try to process straight away */
688                         continue;
689
690                 if (timeout > 0) {
691                         usec_t n;
692
693                         n = now(CLOCK_MONOTONIC);
694                         if (n >= timeout)
695                                 return -ETIMEDOUT;
696
697                         left = timeout - n;
698                 } else
699                         left = (uint64_t) -1;
700
701                 r = rtnl_poll(rtnl, true, left);
702                 if (r < 0)
703                         return r;
704                 else if (r == 0)
705                         return -ETIMEDOUT;
706
707                 r = dispatch_wqueue(rtnl);
708                 if (r < 0)
709                         return r;
710         }
711 }
712
713 int sd_rtnl_flush(sd_rtnl *rtnl) {
714         int r;
715
716         assert_return(rtnl, -EINVAL);
717         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
718
719         if (rtnl->wqueue_size <= 0)
720                 return 0;
721
722         for (;;) {
723                 r = dispatch_wqueue(rtnl);
724                 if (r < 0)
725                         return r;
726
727                 if (rtnl->wqueue_size <= 0)
728                         return 0;
729
730                 r = rtnl_poll(rtnl, false, (uint64_t) -1);
731                 if (r < 0)
732                         return r;
733         }
734 }
735
736 int sd_rtnl_get_events(sd_rtnl *rtnl) {
737         int flags = 0;
738
739         assert_return(rtnl, -EINVAL);
740         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
741
742         if (rtnl->rqueue_size <= 0)
743                 flags |= POLLIN;
744         if (rtnl->wqueue_size > 0)
745                 flags |= POLLOUT;
746
747         return flags;
748 }
749
750 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
751         struct reply_callback *c;
752
753         assert_return(rtnl, -EINVAL);
754         assert_return(timeout_usec, -EINVAL);
755         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
756
757         if (rtnl->rqueue_size > 0) {
758                 *timeout_usec = 0;
759                 return 1;
760         }
761
762         c = prioq_peek(rtnl->reply_callbacks_prioq);
763         if (!c) {
764                 *timeout_usec = (uint64_t) -1;
765                 return 0;
766         }
767
768         *timeout_usec = c->timeout;
769
770         return 1;
771 }
772
773 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
774         sd_rtnl *rtnl = userdata;
775         int r;
776
777         assert(rtnl);
778
779         r = sd_rtnl_process(rtnl, NULL);
780         if (r < 0)
781                 return r;
782
783         return 1;
784 }
785
786 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
787         sd_rtnl *rtnl = userdata;
788         int r;
789
790         assert(rtnl);
791
792         r = sd_rtnl_process(rtnl, NULL);
793         if (r < 0)
794                 return r;
795
796         return 1;
797 }
798
799 static int prepare_callback(sd_event_source *s, void *userdata) {
800         sd_rtnl *rtnl = userdata;
801         int r, e;
802         usec_t until;
803
804         assert(s);
805         assert(rtnl);
806
807         e = sd_rtnl_get_events(rtnl);
808         if (e < 0)
809                 return e;
810
811         r = sd_event_source_set_io_events(rtnl->io_event_source, e);
812         if (r < 0)
813                 return r;
814
815         r = sd_rtnl_get_timeout(rtnl, &until);
816         if (r < 0)
817                 return r;
818         if (r > 0) {
819                 int j;
820
821                 j = sd_event_source_set_time(rtnl->time_event_source, until);
822                 if (j < 0)
823                         return j;
824         }
825
826         r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
827         if (r < 0)
828                 return r;
829
830         return 1;
831 }
832
833 static int exit_callback(sd_event_source *event, void *userdata) {
834         sd_rtnl *rtnl = userdata;
835
836         assert(event);
837
838         sd_rtnl_flush(rtnl);
839
840         return 1;
841 }
842
843 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
844         int r;
845
846         assert_return(rtnl, -EINVAL);
847         assert_return(!rtnl->event, -EBUSY);
848
849         assert(!rtnl->io_event_source);
850         assert(!rtnl->time_event_source);
851
852         if (event)
853                 rtnl->event = sd_event_ref(event);
854         else {
855                 r = sd_event_default(&rtnl->event);
856                 if (r < 0)
857                         return r;
858         }
859
860         r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
861         if (r < 0)
862                 goto fail;
863
864         r = sd_event_source_set_priority(rtnl->io_event_source, priority);
865         if (r < 0)
866                 goto fail;
867
868         r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
869         if (r < 0)
870                 goto fail;
871
872         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
873         if (r < 0)
874                 goto fail;
875
876         r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
877         if (r < 0)
878                 goto fail;
879
880         r = sd_event_source_set_priority(rtnl->time_event_source, priority);
881         if (r < 0)
882                 goto fail;
883
884         r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
885         if (r < 0)
886                 goto fail;
887
888         r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
889         if (r < 0)
890                 goto fail;
891
892         r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
893         if (r < 0)
894                 goto fail;
895
896         return 0;
897
898 fail:
899         sd_rtnl_detach_event(rtnl);
900         return r;
901 }
902
903 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
904         assert_return(rtnl, -EINVAL);
905         assert_return(rtnl->event, -ENXIO);
906
907         if (rtnl->io_event_source)
908                 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
909
910         if (rtnl->time_event_source)
911                 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
912
913         if (rtnl->exit_event_source)
914                 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
915
916         if (rtnl->event)
917                 rtnl->event = sd_event_unref(rtnl->event);
918
919         return 0;
920 }
921
922 int sd_rtnl_add_match(sd_rtnl *rtnl,
923                       uint16_t type,
924                       sd_rtnl_message_handler_t callback,
925                       void *userdata) {
926         struct match_callback *c;
927
928         assert_return(rtnl, -EINVAL);
929         assert_return(callback, -EINVAL);
930         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
931         assert_return(rtnl_message_type_is_link(type) ||
932                       rtnl_message_type_is_addr(type) ||
933                       rtnl_message_type_is_route(type), -ENOTSUP);
934
935         c = new0(struct match_callback, 1);
936         if (!c)
937                 return -ENOMEM;
938
939         c->callback = callback;
940         c->type = type;
941         c->userdata = userdata;
942
943         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
944
945         return 0;
946 }
947
948 int sd_rtnl_remove_match(sd_rtnl *rtnl,
949                          uint16_t type,
950                          sd_rtnl_message_handler_t callback,
951                          void *userdata) {
952         struct match_callback *c;
953
954         assert_return(rtnl, -EINVAL);
955         assert_return(callback, -EINVAL);
956         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
957
958         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
959                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
960                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
961                         free(c);
962
963                         return 1;
964                 }
965
966         return 0;
967 }