d441258771168c4e3bab82ca9bca38c46d26d062
[olsrd.git] / lib / netjson / src / olsrd_netjson.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "olsrd_netjson.h"
47
48 #include <unistd.h>
49
50 #include "olsrd_netjson_helpers.h"
51 #include "info/info_types.h"
52 #include "info/http_headers.h"
53 #include "info/json_helpers.h"
54 #include "common/avl.h"
55 #include "olsr.h"
56 #include "builddata.h"
57 #include "routing_table.h"
58 #include "mid_set.h"
59 #include "link_set.h"
60
61 #define NETJSON_PROTOCOL "olsrv1"
62
63 unsigned long long get_supported_commands_mask(void) {
64   return SIW_NETJSON & ~(SIW_NETJSON_DEVICE_CONFIGURATION | SIW_NETJSON_DEVICE_MONITORING);
65 }
66
67 bool isCommand(const char *str, unsigned long long siw) {
68   const char * cmd = NULL;
69   switch (siw) {
70     case SIW_NETJSON_NETWORK_ROUTES:
71       cmd = "/NetworkRoutes";
72       break;
73
74     case SIW_NETJSON_NETWORK_GRAPH:
75       cmd = "/NetworkGraph";
76       break;
77
78     case SIW_NETJSON_NETWORK_COLLECTION:
79       cmd = "/NetworkCollection";
80       break;
81
82     default:
83       return false;
84   }
85
86   return !strcmp(str, cmd);
87 }
88
89 const char * determine_mime_type(unsigned int send_what __attribute__((unused))) {
90   return "application/json; charset=utf-8";
91 }
92
93 void output_start(struct autobuf *abuf) {
94   /* global variables for tracking when to put a comma in for JSON */
95   abuf_json_reset_entry_number_and_depth();
96   abuf_json_mark_output(true, abuf);
97 }
98
99 void output_end(struct autobuf *abuf) {
100   abuf_json_mark_output(false, abuf);
101   abuf_puts(abuf, "\n");
102 }
103
104 void output_error(struct autobuf *abuf, unsigned int status, const char * req __attribute__((unused)), bool http_headers) {
105   if (http_headers || (status == INFO_HTTP_OK)) {
106     return;
107   }
108
109   /* !http_headers && !INFO_HTTP_OK */
110
111   output_start(abuf);
112
113   if (status == INFO_HTTP_NOCONTENT) {
114     /* do nothing */
115   } else {
116     abuf_json_string(abuf, "error", httpStatusToReply(status));
117   }
118
119   output_end(abuf);
120 }
121
122 void ipc_print_network_routes(struct autobuf *abuf) {
123   struct rt_entry *rt;
124
125   /* mandatory */
126   abuf_json_string(abuf, "type", "NetworkRoutes");
127   abuf_json_string(abuf, "protocol", NETJSON_PROTOCOL);
128   abuf_json_string(abuf, "version", release_version);
129   abuf_json_string(abuf, "metric", olsr_cnf->lq_algorithm);
130
131   /* optional */
132   abuf_json_string(abuf, "revision", olsrd_version);
133   // topology_id
134   abuf_json_ip_address(abuf, "router_id", &olsr_cnf->main_addr);
135
136   /* Walk the route table */
137   abuf_json_mark_object(true, true, abuf, "routes");
138   OLSR_FOR_ALL_RT_ENTRIES(rt) {
139     if (rt->rt_best) {
140       struct lqtextbuffer lqbuf;
141
142       abuf_json_mark_array_entry(true, abuf);
143       /* mandatory */
144       abuf_json_prefix(abuf, "destination", &rt->rt_dst);
145       abuf_json_ip_address(abuf, "next", &rt->rt_best->rtp_nexthop.gateway);
146       abuf_json_string(abuf, "device", if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
147       abuf_json_float(abuf, "cost", get_linkcost_scaled(rt->rt_best->rtp_metric.cost, true));
148
149       /* optional */
150       abuf_json_string(abuf, "cost_text", get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuf));
151       // source
152
153       abuf_json_mark_array_entry(false, abuf);
154     }
155   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
156   abuf_json_mark_object(false, true, abuf, NULL);
157 }
158
159 void ipc_print_network_graph(struct autobuf *abuf) {
160   struct avl_tree nodes;
161   struct mid_entry mid_self;
162   struct node_entry * node_self;
163   struct link_entry * link_entry;
164   struct neighbor_entry * neighbor;
165   int idx;
166
167   avl_init(&nodes, (olsr_cnf->ip_version == AF_INET) ? avl_comp_ipv4 : avl_comp_ipv6);
168
169   /* mandatory */
170   abuf_json_string(abuf, "type", "NetworkGraph");
171   abuf_json_string(abuf, "protocol", NETJSON_PROTOCOL);
172   abuf_json_string(abuf, "version", release_version);
173   abuf_json_string(abuf, "metric", olsr_cnf->lq_algorithm);
174
175   /* optional */
176   abuf_json_string(abuf, "revision", olsrd_version);
177   // topology_id
178   abuf_json_ip_address(abuf, "router_id", &olsr_cnf->main_addr);
179   // label
180
181   /*
182    * Collect all nodes
183    */
184
185   /* MID Self */
186   node_self = netjson_constructMidSelf(&mid_self);
187   netjson_midIntoNodesTree(&nodes, &mid_self);
188
189   /* MID */
190   for (idx = 0; idx < HASHSIZE; idx++) {
191     struct mid_entry * entry = mid_set[idx].next;
192     while (entry != &mid_set[idx]) {
193       netjson_midIntoNodesTree(&nodes, entry);
194       entry = entry->next;
195     }
196   }
197
198   /* LINKS */
199   OLSR_FOR_ALL_LINK_ENTRIES(link_entry) {
200     netjson_linkIntoNodesTree(&nodes, link_entry, &link_entry->local_iface_addr);
201     netjson_linkIntoNodesTree(&nodes, link_entry, &link_entry->neighbor_iface_addr);
202   } OLSR_FOR_ALL_LINK_ENTRIES_END(link_entry);
203
204   /* NEIGHBORS */
205   OLSR_FOR_ALL_NBR_ENTRIES(neighbor) {
206     netjson_neighborIntoNodesTree(&nodes, neighbor);
207   } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor);
208
209   /*
210    * Output Nodes
211    */
212
213   abuf_json_mark_object(true, true, abuf, "nodes");
214   while (nodes.count > 0) {
215     struct avl_node *node = avl_walk_first(&nodes);
216     struct node_entry *node_entry = avlnode2node(node);
217
218     if (!node_entry->isAlias) {
219       abuf_json_mark_array_entry(true, abuf);
220
221       /* mandatory */
222       abuf_json_ip_address(abuf, "id", node->key);
223
224       /* optional */
225       // label
226       if (node_entry->mid) {
227         struct mid_address * alias = node_entry->mid->aliases;
228         if (alias) {
229           abuf_json_mark_object(true, true, abuf, "local_addresses");
230           while (alias) {
231             abuf_json_ip_address(abuf, NULL, &alias->alias);
232             alias = alias->next_alias;
233           }
234           abuf_json_mark_object(false, true, abuf, NULL);
235         }
236       } else if (node_entry->link) {
237         /* no local_addresses */
238       } else if (node_entry->neighbor) {
239         /* no local_addresses */
240       }
241       // properties
242
243       abuf_json_mark_array_entry(false, abuf);
244     }
245
246     if (node_entry == node_self) {
247       netjson_cleanup_mid_self(node_self);
248     }
249
250     avl_delete(&nodes, node);
251     free(node);
252   }
253   abuf_json_mark_object(false, true, abuf, NULL);
254
255   /*
256    * Output Links
257    */
258
259   abuf_json_mark_object(true, true, abuf, "links");
260   OLSR_FOR_ALL_LINK_ENTRIES(link_entry) {
261     struct lqtextbuffer lqbuf;
262
263     abuf_json_mark_array_entry(true, abuf);
264
265     /* mandatory */
266     abuf_json_ip_address(abuf, "source", &link_entry->local_iface_addr);
267     abuf_json_ip_address(abuf, "target", &link_entry->neighbor_iface_addr);
268     abuf_json_float(abuf, "cost", get_linkcost_scaled(link_entry->linkcost, false));
269
270     /* optional */
271     abuf_json_string(abuf, "cost_text", get_linkcost_text(link_entry->linkcost, false, &lqbuf));
272     // properties
273
274     abuf_json_mark_array_entry(false, abuf);
275   } OLSR_FOR_ALL_LINK_ENTRIES_END(my_link);
276   abuf_json_mark_object(false, true, abuf, NULL);
277 }
278
279 void ipc_print_network_collection(struct autobuf *abuf) {
280   /* mandatory */
281   abuf_json_string(abuf, "type", "NetworkCollection");
282
283   abuf_json_mark_object(true, true, abuf, "collection");
284
285   abuf_json_mark_array_entry(true, abuf);
286   ipc_print_network_routes(abuf);
287   abuf_json_mark_array_entry(false, abuf);
288
289   abuf_json_mark_array_entry(true, abuf);
290   ipc_print_network_graph(abuf);
291   abuf_json_mark_array_entry(false, abuf);
292
293   abuf_json_mark_object(false, true, abuf, NULL);
294 }