]> git.meshlink.io Git - catta/blob - avahi-core/netlink.c
add rlist.h and llist.h to doxygen docs
[catta] / avahi-core / netlink.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <assert.h>
31
32 #include <avahi-common/malloc.h>
33 #include "netlink.h"
34 #include "log.h"
35
36 struct AvahiNetlink {
37     int fd;
38     unsigned seq;
39     AvahiNetlinkCallback callback;
40     void* userdata;
41     uint8_t* buffer;
42     size_t buffer_length;
43
44     const AvahiPoll *poll_api;
45     AvahiWatch *watch;
46 };
47
48 int avahi_netlink_work(AvahiNetlink *nl, int block) {
49     assert(nl);
50
51     for (;;) {
52         ssize_t bytes;
53         struct nlmsghdr *p;
54
55         for (;;) {
56             if ((bytes = recv(nl->fd, nl->buffer, nl->buffer_length, block ? 0 : MSG_DONTWAIT)) < 0) {
57
58                 if (errno == EAGAIN || errno == EINTR)
59                     return 1;
60                 
61                 avahi_log_error(__FILE__": recv() failed: %s", strerror(errno));
62                 return 0;
63             }
64
65             break;
66         }
67
68         p = (struct nlmsghdr *) nl->buffer;
69         
70         if (nl->callback) {
71             for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
72                 if (!NLMSG_OK(p, (size_t) bytes)) {
73                     avahi_log_warn(__FILE__": packet truncated");
74                     return 0;
75                 }
76
77                 nl->callback(nl, p, nl->userdata);
78             }
79         }
80
81         if (block)
82             return 1;
83     }
84 }
85
86 static void socket_event(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata) {
87     AvahiNetlink *nl = userdata;
88
89     assert(w);
90     assert(nl);
91     assert(fd == nl->fd);
92
93     avahi_netlink_work(nl, 0);
94 }
95
96 AvahiNetlink *avahi_netlink_new(const AvahiPoll *poll_api, uint32_t groups, void (*cb) (AvahiNetlink *nl, struct nlmsghdr *n, void* userdata), void* userdata) {
97     int fd = -1;
98     struct sockaddr_nl addr;
99     AvahiNetlink *nl = NULL;
100
101     assert(poll_api);
102     assert(cb);
103
104     if ((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
105         avahi_log_error(__FILE__": socket(PF_NETLINK): %s", strerror(errno));
106         return NULL;
107     }
108     
109     memset(&addr, 0, sizeof(addr));
110     addr.nl_family = AF_NETLINK;
111     addr.nl_groups = groups;
112     addr.nl_pid = getpid();
113
114     if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
115         avahi_log_error(__FILE__": bind(): %s", strerror(errno));
116         goto fail;
117     }
118
119     if (!(nl = avahi_new(AvahiNetlink, 1))) {
120         avahi_log_error(__FILE__": avahi_new() failed.");
121         goto fail;
122     }
123
124     nl->poll_api = poll_api;
125     nl->fd = fd;
126     nl->seq = 0;
127     nl->callback = cb;
128     nl->userdata = userdata;
129
130     if (!(nl->buffer = avahi_new(uint8_t, nl->buffer_length = 64*1024))) {
131         avahi_log_error(__FILE__": avahi_new() failed.");
132         goto fail;
133     }
134
135     if (!(nl->watch = poll_api->watch_new(poll_api, fd, AVAHI_WATCH_IN, socket_event, nl))) {
136         avahi_log_error(__FILE__": Failed to create watch.");
137         goto fail;
138     }
139     
140     return nl;
141
142 fail:
143
144     if (fd >= 0)
145         close(fd);
146
147     if (nl) {
148         if (nl->buffer)
149             avahi_free(nl);
150         
151         avahi_free(nl);
152     }
153
154     return NULL;
155 }
156
157 void avahi_netlink_free(AvahiNetlink *nl) {
158     assert(nl);
159
160     if (nl->watch)
161         nl->poll_api->watch_free(nl->watch);
162
163     if (nl->fd >= 0)
164         close(nl->fd);
165     
166     avahi_free(nl->buffer);
167     avahi_free(nl);
168 }
169
170 int avahi_netlink_send(AvahiNetlink *nl, struct nlmsghdr *m, unsigned *ret_seq) {
171     assert(nl);
172     assert(m);
173     
174     m->nlmsg_seq = nl->seq++;
175     m->nlmsg_flags |= NLM_F_ACK;
176
177     if (send(nl->fd, m, m->nlmsg_len, 0) < 0) {
178         avahi_log_error(__FILE__": send(): %s\n", strerror(errno));
179         return -1;
180     }
181
182     if (ret_seq)
183         *ret_seq = m->nlmsg_seq;
184
185     return 0;
186 }