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