Added nameservice plugin
[olsrd.git] / lib / nameservice / src / nameservice.c
1 /*
2  * Copyright (c) 2005, Bruno Randolf <bruno.randolf@4g-systems.biz>
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto-at-olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, 
11  *   this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright notice, 
13  *   this list of conditions and the following disclaimer in the documentation 
14  *   and/or other materials provided with the distribution.
15  * * Neither the name of the UniK olsr daemon nor the names of its contributors 
16  *   may be used to endorse or promote products derived from this software 
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
22  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32 /* $Id: nameservice.c,v 1.1 2005/01/16 13:06:00 kattemat Exp $ */
33
34 /*
35  * Dynamic linked library for UniK OLSRd
36  */
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include "nameservice.h"
43 #include "olsrd_copy.h"
44
45
46 /* The database - (using hashing) */
47 struct name_entry list[HASHSIZE];
48
49 /* send buffer: size of IPv6 message + the maximum size of the name */
50 static char buffer[sizeof(struct olsrmsg6) + MAX_NAME];
51
52 olsr_u8_t name_table_changed=0;
53
54 char* my_name = "";
55 olsr_u8_t my_name_len = 0;
56 char* my_filename = "/var/run/hosts_olsr";
57
58
59 /**
60  * Do initialization
61  */
62 int
63 olsr_plugin_init()
64 {
65         int i;
66         /* Init list */
67         for(i = 0; i < HASHSIZE; i++)
68         {
69                 list[i].next = &list[i];
70                 list[i].prev = &list[i];
71         }
72         
73         /* Register functions with olsrd */
74         olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
75         olsr_register_timeout_function(&olsr_timeout);
76         olsr_register_scheduler_event(&olsr_event, NULL, EMISSION_INTERVAL, 0, NULL);
77
78         return 1;
79 }
80
81
82 /**
83  * Called at unload
84  */
85 void
86 olsr_plugin_exit()
87 {
88         int i;
89         struct name_entry *tmp_list;
90         struct name_entry *entry_to_delete;
91         
92         /* free list entries */
93         for(i = 0; i < HASHSIZE; i++)
94         {
95                 tmp_list = list[i].next;
96                 while(tmp_list != &list[i])
97                 {
98                         entry_to_delete = tmp_list;
99                         tmp_list = tmp_list->next;
100                         entry_to_delete->prev->next = entry_to_delete->next;
101                         entry_to_delete->next->prev = entry_to_delete->prev;
102                         free(entry_to_delete->name);
103                         free(entry_to_delete);
104                 }
105         }
106 }
107
108
109 /**
110  * A timeout function called every time
111  * the scheduler is polled: time out old list entries
112  */
113 void
114 olsr_timeout()
115 {
116         struct name_entry *tmp_list;
117         struct name_entry *entry_to_delete;
118         int index;
119
120         for(index=0;index<HASHSIZE;index++)
121         {
122                 tmp_list = list[index].next;
123                 while(tmp_list != &list[index])
124                 {
125                         /*Check if the entry is timed out*/
126                         if(olsr_timed_out(&tmp_list->timer))
127                         {
128                                 entry_to_delete = tmp_list;
129                                 tmp_list = tmp_list->next;
130                                 olsr_printf(2, "NAME PLUGIN: %s timed out.. deleting\n", 
131                                         olsr_ip_to_string(&entry_to_delete->originator));
132                                 /* Dequeue */
133                                 entry_to_delete->prev->next = entry_to_delete->next;
134                                 entry_to_delete->next->prev = entry_to_delete->prev;
135
136                                 /* Delete */
137                                 free(entry_to_delete->name);
138                                 free(entry_to_delete);
139                                 
140                                 name_table_changed = 1;
141                         }
142                         else
143                                 tmp_list = tmp_list->next;
144                 }
145         }
146         return;
147 }
148
149
150 /**
151  * Scheduled event: generate and send NAME packet
152  */
153 void
154 olsr_event(void *foo)
155 {
156         union olsr_message *message = (union olsr_message*)buffer;
157         struct interface *ifn;
158         int namesize;
159   
160         olsr_printf(3, "NAME PLUGIN: Generating packet - ");
161
162         /* looping trough interfaces */
163         for (ifn = ifs; ifn ; ifn = ifn->int_next) 
164         {
165                 olsr_printf(3, "[%s]  ", ifn->int_name);
166                 /* Fill message */
167                 if(ipversion == AF_INET)
168                 {
169                         /* IPv4 */
170                         message->v4.olsr_msgtype = MESSAGE_TYPE;
171                         message->v4.olsr_vtime = double_to_me(NAME_VALID_TIME);
172                         memcpy(&message->v4.originator, main_addr, ipsize);
173                         message->v4.ttl = MAX_TTL;
174                         message->v4.hopcnt = 0;
175                         message->v4.seqno = htons(get_msg_seqno());
176                 
177                         namesize = get_namemsg(&message->v4.msg);
178                         namesize = namesize + sizeof(struct olsrmsg);
179                 
180                         message->v4.olsr_msgsize = htons(namesize);
181                 }
182                 else
183                 {
184                         /* IPv6 */
185                         message->v6.olsr_msgtype = MESSAGE_TYPE;
186                         message->v6.olsr_vtime = double_to_me(NAME_VALID_TIME);
187                         memcpy(&message->v6.originator, main_addr, ipsize);
188                         message->v6.ttl = MAX_TTL;
189                         message->v6.hopcnt = 0;
190                         message->v6.seqno = htons(get_msg_seqno());
191           
192                         namesize = get_namemsg(&message->v6.msg);
193                         namesize = namesize + sizeof(struct olsrmsg6);
194           
195                         message->v6.olsr_msgsize = htons(namesize);
196                 }
197         
198                 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
199                         /* Send data and try again */
200                         net_output(ifn);
201                         if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
202                                 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
203                         }
204                 }
205         }
206         olsr_printf(3, "\n");
207         write_name_table();
208         return;
209 }
210
211
212 /**
213  * Parse name olsr message of NAME type
214  */
215 void
216 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
217 {
218         struct  namemsg *message;
219         union olsr_ip_addr originator;
220         double vtime;
221
222         /* Fetch the originator of the messsage */
223         memcpy(&originator, &m->v4.originator, ipsize);
224                 
225         /* Fetch the message based on IP version */
226         if(ipversion == AF_INET) {
227                 message = &m->v4.msg;
228                 vtime = me_to_double(m->v4.olsr_vtime);
229         }
230         else {
231                 message = &m->v6.msg;
232                 vtime = me_to_double(m->v6.olsr_vtime);
233         }
234
235         /* Check if message originated from this node. 
236         If so - back off */
237         if(memcmp(&originator, main_addr, ipsize) == 0)
238                 return;
239
240         /* Check that the neighbor this message was received from is symmetric. 
241         If not - back off*/
242         if(check_neighbor_link(in_addr) != SYM_LINK) {
243                 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
244                 return;
245         }
246
247         /* Check if this message has been processed before
248         * Remeber that this also registeres the message as
249         * processed if nessecary
250         */
251         if(!check_dup_proc(&originator, ntohs(m->v4.seqno))) {
252                 /* If so - do not process */
253                 goto forward;
254         }
255
256         /* Process */
257         olsr_printf(3, "NAME PLUGIN: Processing NAME info from %s seqno: %d\n",
258                 olsr_ip_to_string(&originator),
259                 ntohs(m->v4.seqno));
260
261         update_name_entry(&originator, message, vtime);
262
263
264 forward:
265         /* Forward the message if nessecary
266         * default_fwd does all the work for us! */
267         default_fwd(m, &originator, ntohs(m->v4.seqno), in_if, in_addr);
268 }
269
270
271 /**
272  * Get a name message. This fills the namemsg struct
273  * AND appends the name after that! 
274  *
275  * It assumed that there is enough space in the buffer to do this!
276  *
277  * Returns: the length of the name that was appended
278  */
279 int
280 get_namemsg(struct namemsg *msg)
281 {
282         msg->name_len = my_name_len;
283         char* txt = (char*)(msg + sizeof(struct namemsg));
284         strncpy(txt, my_name, MAX_NAME); 
285         return my_name_len;
286 }
287
288
289 /**
290  * Read a name message and update name_entry if necessary
291  *
292  * Return: 1 if entry was changed
293  */
294 int
295 read_namemsg(struct namemsg *msg, struct name_entry *to)
296 {
297         char* txt = (char*)(msg + sizeof(struct namemsg));
298         if (to->name == NULL || strncmp(to->name, txt, MAX_NAME) != 0) {
299                 if (to->name != NULL) {
300                         free( to->name );
301                 }
302                 to->name = olsr_malloc(msg->name_len, "new name_entry name");
303                 strncpy(to->name, txt, msg->name_len);
304                 return 1;
305         }
306         return 0;       
307 }
308
309
310 /**
311  * Update or register a new name entry
312  */
313 int
314 update_name_entry(union olsr_ip_addr *originator, struct namemsg *message, double vtime)
315 {
316         int hash;
317         struct name_entry *entry;
318         
319         hash = olsr_hashing(originator);
320         
321         /* Check for the entry */
322         for(entry = list[hash].next; entry != &list[hash]; entry = entry->next)
323         {
324                 if(memcmp(originator, &entry->originator, ipsize) == 0) {
325                         if (read_namemsg( message, entry )) {
326                                 name_table_changed = 1;
327                         }
328                         olsr_get_timestamp(vtime * 1000, &entry->timer);
329                         return 0;
330                 }
331         }
332
333         entry = olsr_malloc(sizeof(struct name_entry), "new name_entry");
334         entry->name = NULL;
335         memcpy(&entry->originator, originator, ipsize);
336         olsr_get_timestamp(vtime * 1000, &entry->timer);
337         
338         read_namemsg( message, entry );
339
340         olsr_printf(2, "NAME PLUGIN: New entry %s: %s\n", olsr_ip_to_string(originator), entry->name);
341                 
342         /* Queue */
343         entry->next = list[hash].next->prev;
344         entry->prev = &list[hash];
345         list[hash].next->prev = entry;
346         list[hash].next = entry;
347
348         name_table_changed = 1;
349         return 1;
350 }
351
352
353 /**
354  * write names to a file in /etc/hosts compatible format
355  */
356 void
357 write_name_table()
358 {
359         int hash;
360         struct name_entry *entry;
361         char buf[MAX_NAME+17];
362         FILE* hosts;
363
364         olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
365         
366         if(!name_table_changed)
367                 return;
368               
369         hosts = fopen( my_filename, "w" );
370         
371         fprintf(hosts, "# this /etc/hosts file is overwritten regularly by olsrd\n");
372         fprintf(hosts, "# do not edit\n");
373         // add own IP and name
374         fprintf(hosts, "%s\t%s\n", olsr_ip_to_string(main_addr), my_name );
375
376         for(hash = 0; hash < HASHSIZE; hash++) 
377         {
378                 for(entry = list[hash].next; entry != &list[hash]; entry = entry->next) 
379                 {
380                         sprintf(buf, "%s\t%s\n", olsr_ip_to_string(&entry->originator), entry->name);
381                         fprintf(hosts, "%s", buf);
382                 }
383         }
384         
385         fclose(hosts);
386         name_table_changed = 0;
387 }