]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - nhrpd/nhrp_event.c
New upstream release and new maintainer
[quagga-debian.git] / nhrpd / nhrp_event.c
1 /* NHRP event manager
2  * Copyright (c) 2014-2015 Timo Teräs
3  *
4  * This file is free software: you may copy, redistribute and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  */
9
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13
14 #include "thread.h"
15 #include "zbuf.h"
16 #include "log.h"
17 #include "nhrpd.h"
18
19 const char *nhrp_event_socket_path;
20 struct nhrp_reqid_pool nhrp_event_reqid;
21
22 struct event_manager {
23         struct thread *t_reconnect, *t_read, *t_write;
24         struct zbuf ibuf;
25         struct zbuf_queue obuf;
26         int fd;
27         uint8_t ibuf_data[4*1024];
28 };
29
30 static int evmgr_reconnect(struct thread *t);
31
32 static void evmgr_connection_error(struct event_manager *evmgr)
33 {
34         THREAD_OFF(evmgr->t_read);
35         THREAD_OFF(evmgr->t_write);
36         zbuf_reset(&evmgr->ibuf);
37         zbufq_reset(&evmgr->obuf);
38
39         if (evmgr->fd >= 0)
40                 close(evmgr->fd);
41         evmgr->fd = -1;
42         if (nhrp_event_socket_path)
43                 THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect,
44                                      evmgr, 10);
45 }
46
47 static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb)
48 {
49         struct zbuf zl;
50         uint32_t eventid = 0;
51         size_t len;
52         char buf[256], result[64] = "";
53
54         while (zbuf_may_pull_until(zb, "\n", &zl)) {
55                 len = zbuf_used(&zl) - 1;
56                 if (len >= sizeof(buf)-1)
57                         continue;
58                 memcpy(buf, zbuf_pulln(&zl, len), len);
59                 buf[len] = 0;
60
61                 debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf);
62                 sscanf(buf, "eventid=%d", &eventid);
63                 sscanf(buf, "result=%63s", result);
64         }
65         debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s", eventid, result);
66         if (eventid && result[0]) {
67                 struct nhrp_reqid *r = nhrp_reqid_lookup(&nhrp_event_reqid, eventid);
68                 if (r) r->cb(r, result);
69         }
70 }
71
72 static int evmgr_read(struct thread *t)
73 {
74         struct event_manager *evmgr = THREAD_ARG(t);
75         struct zbuf *ibuf = &evmgr->ibuf;
76         struct zbuf msg;
77
78         evmgr->t_read = NULL;
79         if (zbuf_read(ibuf, evmgr->fd, (size_t) -1) < 0) {
80                 evmgr_connection_error(evmgr);
81                 return 0;
82         }
83
84         /* Process all messages in buffer */
85         while (zbuf_may_pull_until(ibuf, "\n\n", &msg))
86                 evmgr_recv_message(evmgr, &msg);
87
88         THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd);
89         return 0;
90 }
91
92 static int evmgr_write(struct thread *t)
93 {
94         struct event_manager *evmgr = THREAD_ARG(t);
95         int r;
96
97         evmgr->t_write = NULL;
98         r = zbufq_write(&evmgr->obuf, evmgr->fd);
99         if (r > 0) {
100                 THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd);
101         } else if (r < 0) {
102                 evmgr_connection_error(evmgr);
103         }
104
105         return 0;
106 }
107
108 static void evmgr_hexdump(struct zbuf *zb, const uint8_t *val, size_t vallen)
109 {
110         static const char xd[] = "0123456789abcdef";
111         size_t i;
112         char *ptr;
113
114         ptr  = zbuf_pushn(zb, 2*vallen);
115         if (!ptr) return;
116
117         for (i = 0; i < vallen; i++) {
118                 uint8_t b = val[i];
119                 *(ptr++) = xd[b >> 4];
120                 *(ptr++) = xd[b & 0xf];
121         }
122 }
123
124 static void evmgr_put(struct zbuf *zb, const char *fmt, ...)
125 {
126         const char *pos, *nxt, *str;
127         const uint8_t *bin;
128         const union sockunion *su;
129         int len;
130         va_list va;
131
132         va_start(va, fmt);
133         for (pos = fmt; (nxt = strchr(pos, '%')) != NULL; pos = nxt + 2) {
134                 zbuf_put(zb, pos, nxt-pos);
135                 switch (nxt[1]) {
136                 case '%':
137                         zbuf_put8(zb, '%');
138                         break;
139                 case 'u':
140                         zb->tail += snprintf((char *) zb->tail, zbuf_tailroom(zb), "%u", va_arg(va, uint32_t));
141                         break;
142                 case 's':
143                         str = va_arg(va, const char *);
144                         zbuf_put(zb, str, strlen(str));
145                         break;
146                 case 'U':
147                         su = va_arg(va, const union sockunion *);
148                         if (sockunion2str(su, (char *) zb->tail, zbuf_tailroom(zb)))
149                                 zb->tail += strlen((char *) zb->tail);
150                         else
151                                 zbuf_set_werror(zb);
152                         break;
153                 case 'H':
154                         bin = va_arg(va, const uint8_t *);
155                         len = va_arg(va, int);
156                         evmgr_hexdump(zb, bin, len);
157                         break;
158                 }
159         }
160         va_end(va);
161         zbuf_put(zb, pos, strlen(pos));
162 }
163
164 static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf)
165 {
166         if (obuf->error) {
167                 zbuf_free(obuf);
168                 return;
169         }
170         zbuf_put(obuf, "\n", 1);
171         zbufq_queue(&evmgr->obuf, obuf);
172         if (evmgr->fd >= 0)
173                 THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd);
174 }
175
176 static int evmgr_reconnect(struct thread *t)
177 {
178         struct event_manager *evmgr = THREAD_ARG(t);
179         int fd;
180
181         evmgr->t_reconnect = NULL;
182         if (evmgr->fd >= 0 || !nhrp_event_socket_path) return 0;
183
184         fd = sock_open_unix(nhrp_event_socket_path);
185         if (fd < 0) {
186                 zlog_warn("%s: failure connecting nhrp-event socket: %s",
187                         __PRETTY_FUNCTION__, strerror(errno));
188                 zbufq_reset(&evmgr->obuf);
189                 THREAD_TIMER_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10);
190                 return 0;
191         }
192
193         zlog_info("Connected to Event Manager");
194         evmgr->fd = fd;
195         THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd);
196
197         return 0;
198 }
199
200 static struct event_manager evmgr_connection;
201
202 void evmgr_init(void)
203 {
204         struct event_manager *evmgr = &evmgr_connection;
205
206         evmgr->fd = -1;
207         zbuf_init(&evmgr->ibuf, evmgr->ibuf_data, sizeof(evmgr->ibuf_data), 0);
208         zbufq_init(&evmgr->obuf);
209         THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10);
210 }
211
212 void evmgr_set_socket(const char *socket)
213 {
214         if (nhrp_event_socket_path) {
215                 free((char *) nhrp_event_socket_path);
216                 nhrp_event_socket_path = NULL;
217         }
218         if (socket)
219                 nhrp_event_socket_path = strdup(socket);
220         evmgr_connection_error(&evmgr_connection);
221 }
222
223 void evmgr_terminate(void)
224 {
225 }
226
227 void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *))
228 {
229         struct event_manager *evmgr = &evmgr_connection;
230         struct nhrp_vc *vc;
231         struct nhrp_interface *nifp = c->ifp->info;
232         struct zbuf *zb;
233         afi_t afi = family2afi(sockunion_family(&c->remote_addr));
234
235         if (!nhrp_event_socket_path) {
236                 cb(&c->eventid, (void*) "accept");
237                 return;
238         }
239
240         debugf(NHRP_DEBUG_EVENT, "evmgr: sending event %s", name);
241
242         vc = c->new.peer ? c->new.peer->vc : NULL;
243         zb = zbuf_alloc(1024 + (vc ? (vc->local.certlen + vc->remote.certlen) * 2 : 0));
244
245         if (cb) {
246                 nhrp_reqid_free(&nhrp_event_reqid, &c->eventid);
247                 evmgr_put(zb,
248                         "eventid=%u\n",
249                         nhrp_reqid_alloc(&nhrp_event_reqid, &c->eventid, cb));
250         }
251
252         evmgr_put(zb,
253                 "event=%s\n"
254                 "type=%s\n"
255                 "old_type=%s\n"
256                 "num_nhs=%u\n"
257                 "interface=%s\n"
258                 "local_addr=%U\n",
259                 name,
260                 nhrp_cache_type_str[c->new.type],
261                 nhrp_cache_type_str[c->cur.type],
262                 (unsigned int) nhrp_cache_counts[NHRP_CACHE_NHS],
263                 c->ifp->name,
264                 &nifp->afi[afi].addr);
265
266         if (vc) {
267                 evmgr_put(zb,
268                         "vc_initiated=%s\n"
269                         "local_nbma=%U\n"
270                         "local_cert=%H\n"
271                         "remote_addr=%U\n"
272                         "remote_nbma=%U\n"
273                         "remote_cert=%H\n",
274                         c->new.peer->requested ? "yes" : "no",
275                         &vc->local.nbma,
276                         vc->local.cert, vc->local.certlen,
277                         &c->remote_addr, &vc->remote.nbma,
278                         vc->remote.cert, vc->remote.certlen);
279         }
280
281         evmgr_submit(evmgr, zb);
282 }
283