info: fix json Content-Type header
[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 "olsrd_plugin.h"
52 #include "info/info_types.h"
53 #include "info/http_headers.h"
54 #include "info/json_helpers.h"
55 #include "common/avl.h"
56 #include "olsr.h"
57 #include "builddata.h"
58 #include "routing_table.h"
59 #include "mid_set.h"
60 #include "link_set.h"
61
62 #define NETJSON_PROTOCOL "olsrv1"
63
64 static struct json_session json_session;
65
66 unsigned long long get_supported_commands_mask(void) {
67   return SIW_NETJSON & ~(SIW_NETJSON_DEVICE_CONFIGURATION | SIW_NETJSON_DEVICE_MONITORING);
68 }
69
70 bool isCommand(const char *str, unsigned long long siw) {
71   const char * cmd = NULL;
72   switch (siw) {
73     case SIW_NETJSON_NETWORK_ROUTES:
74       cmd = "/NetworkRoutes";
75       break;
76
77     case SIW_NETJSON_NETWORK_GRAPH:
78       cmd = "/NetworkGraph";
79       break;
80
81     case SIW_NETJSON_NETWORK_COLLECTION:
82       cmd = "/NetworkCollection";
83       break;
84
85     default:
86       return false;
87   }
88
89   return !strcmp(str, cmd);
90 }
91
92 const char * determine_mime_type(unsigned int send_what __attribute__((unused))) {
93   return "application/vnd.api+json";
94 }
95
96 void output_start(struct autobuf *abuf) {
97   /* global variables for tracking when to put a comma in for JSON */
98   abuf_json_reset_entry_number_and_depth(&json_session, pretty);
99   abuf_json_mark_output(&json_session, true, abuf);
100 }
101
102 void output_end(struct autobuf *abuf) {
103   abuf_json_mark_output(&json_session, false, abuf);
104   abuf_puts(abuf, "\n");
105   abuf_json_reset_entry_number_and_depth(&json_session, pretty);
106 }
107
108 void output_error(struct autobuf *abuf, unsigned int status, const char * req __attribute__((unused)), bool http_headers) {
109   if (http_headers || (status == INFO_HTTP_OK)) {
110     return;
111   }
112
113   /* !http_headers && !INFO_HTTP_OK */
114
115   output_start(abuf);
116
117   if (status == INFO_HTTP_NOCONTENT) {
118     /* do nothing */
119   } else {
120     abuf_json_string(&json_session, abuf, "error", httpStatusToReply(status));
121   }
122
123   output_end(abuf);
124 }
125
126 void ipc_print_network_routes(struct autobuf *abuf) {
127   struct rt_entry *rt;
128
129   /* mandatory */
130   abuf_json_string(&json_session, abuf, "type", "NetworkRoutes");
131   abuf_json_string(&json_session, abuf, "protocol", NETJSON_PROTOCOL);
132   abuf_json_string(&json_session, abuf, "version", release_version);
133   abuf_json_string(&json_session, abuf, "metric", olsr_cnf->lq_algorithm);
134
135   /* optional */
136   abuf_json_string(&json_session, abuf, "revision", olsrd_version);
137   // topology_id
138   abuf_json_ip_address(&json_session, abuf, "router_id", &olsr_cnf->main_addr);
139
140   /* Walk the route table */
141   abuf_json_mark_object(&json_session, true, true, abuf, "routes");
142   OLSR_FOR_ALL_RT_ENTRIES(rt) {
143     if (rt->rt_best) {
144       struct lqtextbuffer lqbuf;
145
146       abuf_json_mark_array_entry(&json_session, true, abuf);
147       /* mandatory */
148       abuf_json_prefix(&json_session, abuf, "destination", &rt->rt_dst);
149       abuf_json_ip_address(&json_session, abuf, "next", &rt->rt_best->rtp_nexthop.gateway);
150       abuf_json_string(&json_session, abuf, "device", if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
151       abuf_json_float(&json_session, abuf, "cost", get_linkcost_scaled(rt->rt_best->rtp_metric.cost, true));
152
153       /* optional */
154       abuf_json_string(&json_session, abuf, "cost_text", get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuf));
155       // source
156
157       abuf_json_mark_array_entry(&json_session, false, abuf);
158     }
159   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
160   abuf_json_mark_object(&json_session, false, true, abuf, NULL);
161 }
162
163 void ipc_print_network_graph(struct autobuf *abuf) {
164   struct avl_tree nodes;
165   struct mid_entry mid_self;
166   struct node_entry * node_self;
167   struct tc_entry * tc;
168   struct link_entry * link_entry;
169   struct neighbor_entry * neighbor;
170   int idx;
171
172   avl_init(&nodes, (olsr_cnf->ip_version == AF_INET) ? avl_comp_ipv4 : avl_comp_ipv6);
173
174   /* mandatory */
175   abuf_json_string(&json_session, abuf, "type", "NetworkGraph");
176   abuf_json_string(&json_session, abuf, "protocol", NETJSON_PROTOCOL);
177   abuf_json_string(&json_session, abuf, "version", release_version);
178   abuf_json_string(&json_session, abuf, "metric", olsr_cnf->lq_algorithm);
179
180   /* optional */
181   abuf_json_string(&json_session, abuf, "revision", olsrd_version);
182   // topology_id
183   abuf_json_ip_address(&json_session, abuf, "router_id", &olsr_cnf->main_addr);
184   // label
185
186   /*
187    * Collect all nodes
188    */
189
190   /* MID Self */
191   node_self = netjson_constructMidSelf(&mid_self);
192   netjson_midIntoNodesTree(&nodes, &mid_self);
193
194   /* MID */
195   for (idx = 0; idx < HASHSIZE; idx++) {
196     struct mid_entry * entry = mid_set[idx].next;
197     while (entry != &mid_set[idx]) {
198       netjson_midIntoNodesTree(&nodes, entry);
199       entry = entry->next;
200     }
201   }
202
203   /* TC */
204   OLSR_FOR_ALL_TC_ENTRIES(tc) {
205     struct tc_edge_entry *tc_edge;
206     netjson_tcIntoNodesTree(&nodes, tc);
207     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
208      netjson_tcEdgeIntoNodesTree(&nodes, tc_edge);
209     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
210   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
211
212   /* LINKS */
213   OLSR_FOR_ALL_LINK_ENTRIES(link_entry) {
214     netjson_linkIntoNodesTree(&nodes, link_entry, &link_entry->local_iface_addr);
215     netjson_linkIntoNodesTree(&nodes, link_entry, &link_entry->neighbor_iface_addr);
216   } OLSR_FOR_ALL_LINK_ENTRIES_END(link_entry);
217
218   /* NEIGHBORS */
219   OLSR_FOR_ALL_NBR_ENTRIES(neighbor) {
220     netjson_neighborIntoNodesTree(&nodes, neighbor);
221   } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor);
222
223   /*
224    * Output Nodes
225    */
226
227   abuf_json_mark_object(&json_session, true, true, abuf, "nodes");
228   while (nodes.count > 0) {
229     struct avl_node *node = avl_walk_first(&nodes);
230     struct node_entry *node_entry = avlnode2node(node);
231
232     if (!node_entry->isAlias) {
233       abuf_json_mark_array_entry(&json_session, true, abuf);
234
235       /* mandatory */
236       abuf_json_ip_address(&json_session, abuf, "id", node->key);
237
238       /* optional */
239       // label
240       if (node_entry->mid) {
241         struct mid_address * alias = node_entry->mid->aliases;
242         if (alias) {
243           abuf_json_mark_object(&json_session, true, true, abuf, "local_addresses");
244           while (alias) {
245             abuf_json_ip_address(&json_session, abuf, NULL, &alias->alias);
246             alias = alias->next_alias;
247           }
248           abuf_json_mark_object(&json_session, false, true, abuf, NULL);
249         }
250       } else if (node_entry->tc) {
251         /* no local_addresses */
252       } else if (node_entry->tc_edge) {
253         /* no local_addresses */
254       } else if (node_entry->link) {
255         /* no local_addresses */
256       } else if (node_entry->neighbor) {
257         /* no local_addresses */
258       }
259       // properties
260
261       abuf_json_mark_array_entry(&json_session, false, abuf);
262     }
263
264     if (node_entry->mid && (node_entry == node_self)) {
265       netjson_cleanup_mid_self(node_self);
266     }
267
268     avl_delete(&nodes, node);
269     free(node);
270   }
271   abuf_json_mark_object(&json_session, false, true, abuf, NULL);
272
273   /*
274    * Links
275    */
276
277   abuf_json_mark_object(&json_session, true, true, abuf, "links");
278
279   OLSR_FOR_ALL_LINK_ENTRIES(link_entry) {
280     struct lqtextbuffer lqbuf;
281     int link_status = lookup_link_status(link_entry);
282
283     if ((link_status != ASYM_LINK) && (link_status != SYM_LINK)) {
284       continue;
285     }
286
287     /*
288      * link from node to neighbor
289      */
290     if (link_status == SYM_LINK) {
291       abuf_json_mark_array_entry(&json_session, true, abuf);
292
293       /* mandatory */
294       abuf_json_ip_address(&json_session, abuf, "source", &link_entry->local_iface_addr);
295       abuf_json_ip_address(&json_session, abuf, "target", &link_entry->neighbor_iface_addr);
296       abuf_json_float(&json_session, abuf, "cost", get_linkcost_scaled(link_entry->linkcost, false));
297
298       /* optional */
299       abuf_json_string(&json_session, abuf, "cost_text", get_linkcost_text(link_entry->linkcost, false, &lqbuf));
300       // properties
301
302       abuf_json_mark_array_entry(&json_session, false, abuf);
303     }
304
305     /*
306      * link from neighbor to node
307      */
308     abuf_json_mark_array_entry(&json_session, true, abuf);
309
310     /* mandatory */
311     abuf_json_ip_address(&json_session, abuf, "source", &link_entry->neighbor_iface_addr);
312     abuf_json_ip_address(&json_session, abuf, "target", &link_entry->local_iface_addr);
313     abuf_json_float(&json_session, abuf, "cost", get_linkcost_scaled(link_entry->linkcost, false));
314
315     /* optional */
316     abuf_json_string(&json_session, abuf, "cost_text", get_linkcost_text(link_entry->linkcost, false, &lqbuf));
317     // properties
318
319     abuf_json_mark_array_entry(&json_session, false, abuf);
320   } OLSR_FOR_ALL_LINK_ENTRIES_END(my_link);
321
322   OLSR_FOR_ALL_TC_ENTRIES(tc) {
323     struct tc_edge_entry *tc_edge;
324     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
325       struct lqtextbuffer lqbuf;
326
327       if (ipequal(&olsr_cnf->main_addr, &tc->addr)) {
328         continue;
329       }
330
331       abuf_json_mark_array_entry(&json_session, true, abuf);
332
333       /* mandatory */
334       abuf_json_ip_address(&json_session, abuf, "source", &tc->addr);
335       abuf_json_ip_address(&json_session, abuf, "target", &tc_edge->T_dest_addr);
336       abuf_json_float(&json_session, abuf, "cost", get_linkcost_scaled(tc_edge->cost, false));
337
338       /* optional */
339       abuf_json_string(&json_session, abuf, "cost_text", get_linkcost_text(tc_edge->cost, false, &lqbuf));
340       // properties
341
342       abuf_json_mark_array_entry(&json_session, false, abuf);
343     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
344   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
345
346   abuf_json_mark_object(&json_session, false, true, abuf, NULL);
347 }
348
349 void ipc_print_network_collection(struct autobuf *abuf) {
350   /* mandatory */
351   abuf_json_string(&json_session, abuf, "type", "NetworkCollection");
352
353   abuf_json_mark_object(&json_session, true, true, abuf, "collection");
354
355   abuf_json_mark_array_entry(&json_session, true, abuf);
356   ipc_print_network_routes(abuf);
357   abuf_json_mark_array_entry(&json_session, false, abuf);
358
359   abuf_json_mark_array_entry(&json_session, true, abuf);
360   ipc_print_network_graph(abuf);
361   abuf_json_mark_array_entry(&json_session, false, abuf);
362
363   abuf_json_mark_object(&json_session, false, true, abuf, NULL);
364 }