23a6eb9a4fead902a237f5cf0f4b7f836eef4490
[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.3 2005/03/01 20:16:56 tlopatic 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 static char my_filename_buff[MAX_FILE + 1];
57 char* my_filename = my_filename_buff;
58
59
60 /**
61  * Do initialization
62  */
63 int
64 olsr_plugin_init()
65 {
66         int i;
67 #ifdef WIN32
68         int len;
69 #endif
70
71         /* Init list */
72         for(i = 0; i < HASHSIZE; i++)
73         {
74                 list[i].next = &list[i];
75                 list[i].prev = &list[i];
76         }
77         
78         /* Register functions with olsrd */
79         olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
80         olsr_register_timeout_function(&olsr_timeout);
81         olsr_register_scheduler_event(&olsr_event, NULL, EMISSION_INTERVAL, 0, NULL);
82
83 #ifdef WIN32
84         GetWindowsDirectory(my_filename_buff, MAX_FILE - 12);
85
86         len = strlen(my_filename_buff);
87
88         if (my_filename_buff[len - 1] != '\\')
89                 my_filename_buff[len++] = '\\';
90
91         strcpy(my_filename_buff + len, "olsrd.hosts");
92 #else
93         strcpy(my_filename_buff, "/var/run/hosts_olsr");
94 #endif
95
96         return 1;
97 }
98
99
100 /**
101  * Called at unload
102  */
103 void
104 olsr_plugin_exit()
105 {
106         int i;
107         struct name_entry *tmp_list;
108         struct name_entry *entry_to_delete;
109         
110         /* free list entries */
111         for(i = 0; i < HASHSIZE; i++)
112         {
113                 tmp_list = list[i].next;
114                 while(tmp_list != &list[i])
115                 {
116                         entry_to_delete = tmp_list;
117                         tmp_list = tmp_list->next;
118                         entry_to_delete->prev->next = entry_to_delete->next;
119                         entry_to_delete->next->prev = entry_to_delete->prev;
120                         free(entry_to_delete->name);
121                         free(entry_to_delete);
122                 }
123         }
124 }
125
126
127 /**
128  * A timeout function called every time
129  * the scheduler is polled: time out old list entries
130  */
131 void
132 olsr_timeout()
133 {
134         struct name_entry *tmp_list;
135         struct name_entry *entry_to_delete;
136         int index;
137
138         for(index=0;index<HASHSIZE;index++)
139         {
140                 tmp_list = list[index].next;
141                 while(tmp_list != &list[index])
142                 {
143                         /*Check if the entry is timed out*/
144                         if(olsr_timed_out(&tmp_list->timer))
145                         {
146                                 entry_to_delete = tmp_list;
147                                 tmp_list = tmp_list->next;
148                                 olsr_printf(2, "NAME PLUGIN: %s timed out.. deleting\n", 
149                                         olsr_ip_to_string(&entry_to_delete->originator));
150                                 /* Dequeue */
151                                 entry_to_delete->prev->next = entry_to_delete->next;
152                                 entry_to_delete->next->prev = entry_to_delete->prev;
153
154                                 /* Delete */
155                                 free(entry_to_delete->name);
156                                 free(entry_to_delete);
157                                 
158                                 name_table_changed = 1;
159                         }
160                         else
161                                 tmp_list = tmp_list->next;
162                 }
163         }
164         return;
165 }
166
167
168 /**
169  * Scheduled event: generate and send NAME packet
170  */
171 void
172 olsr_event(void *foo)
173 {
174         union olsr_message *message = (union olsr_message*)buffer;
175         struct interface *ifn;
176         int namesize;
177   
178         olsr_printf(3, "NAME PLUGIN: Generating packet - ");
179
180         /* looping trough interfaces */
181         for (ifn = ifs; ifn ; ifn = ifn->int_next) 
182         {
183                 olsr_printf(3, "[%s]  ", ifn->int_name);
184                 /* Fill message */
185                 if(ipversion == AF_INET)
186                 {
187                         /* IPv4 */
188                         message->v4.olsr_msgtype = MESSAGE_TYPE;
189                         message->v4.olsr_vtime = double_to_me(NAME_VALID_TIME);
190                         memcpy(&message->v4.originator, main_addr, ipsize);
191                         message->v4.ttl = MAX_TTL;
192                         message->v4.hopcnt = 0;
193                         message->v4.seqno = htons(get_msg_seqno());
194                 
195                         namesize = get_namemsg(&message->v4.msg);
196                         namesize = namesize + sizeof(struct olsrmsg);
197                 
198                         message->v4.olsr_msgsize = htons(namesize);
199                 }
200                 else
201                 {
202                         /* IPv6 */
203                         message->v6.olsr_msgtype = MESSAGE_TYPE;
204                         message->v6.olsr_vtime = double_to_me(NAME_VALID_TIME);
205                         memcpy(&message->v6.originator, main_addr, ipsize);
206                         message->v6.ttl = MAX_TTL;
207                         message->v6.hopcnt = 0;
208                         message->v6.seqno = htons(get_msg_seqno());
209           
210                         namesize = get_namemsg(&message->v6.msg);
211                         namesize = namesize + sizeof(struct olsrmsg6);
212           
213                         message->v6.olsr_msgsize = htons(namesize);
214                 }
215         
216                 if (net_outbuffer_push(ifn, buffer, namesize) != namesize)
217                 {
218                         /* Send data and try again */
219                         net_output(ifn);
220                         if (net_outbuffer_push(ifn, buffer, namesize) !=
221                                 namesize)
222                         {
223                                 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
224                         }
225                 }
226         }
227
228         olsr_printf(3, "\n");
229
230         write_name_table();
231 }
232
233
234 /**
235  * Parse name olsr message of NAME type
236  */
237 void
238 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
239 {
240         struct  namemsg *message;
241         union olsr_ip_addr originator;
242         double vtime;
243
244         /* Fetch the originator of the messsage */
245         memcpy(&originator, &m->v4.originator, ipsize);
246                 
247         /* Fetch the message based on IP version */
248         if(ipversion == AF_INET) {
249                 message = &m->v4.msg;
250                 vtime = me_to_double(m->v4.olsr_vtime);
251         }
252         else {
253                 message = &m->v6.msg;
254                 vtime = me_to_double(m->v6.olsr_vtime);
255         }
256
257         /* Check if message originated from this node. 
258         If so - back off */
259         if(memcmp(&originator, main_addr, ipsize) == 0)
260                 return;
261
262         /* Check that the neighbor this message was received from is symmetric. 
263         If not - back off*/
264         if(check_neighbor_link(in_addr) != SYM_LINK) {
265                 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
266                 return;
267         }
268
269         /* Check if this message has been processed before
270         * Remeber that this also registeres the message as
271         * processed if nessecary
272         */
273         if(!check_dup_proc(&originator, ntohs(m->v4.seqno))) {
274                 /* If so - do not process */
275                 goto forward;
276         }
277
278         /* Process */
279         olsr_printf(3, "NAME PLUGIN: Processing NAME info from %s seqno: %d\n",
280                 olsr_ip_to_string(&originator),
281                 ntohs(m->v4.seqno));
282
283         update_name_entry(&originator, message, vtime);
284
285
286 forward:
287         /* Forward the message if nessecary
288         * default_fwd does all the work for us! */
289         default_fwd(m, &originator, ntohs(m->v4.seqno), in_if, in_addr);
290 }
291
292
293 /**
294  * Get a name message. This fills the namemsg struct
295  * AND appends the name after that! 
296  *
297  * It assumed that there is enough space in the buffer to do this!
298  *
299  * Returns: the length of the name that was appended
300  */
301 int
302 get_namemsg(struct namemsg *msg)
303 {
304         int i;
305         char *txt;
306
307         msg->name_len = my_name_len;
308
309         msg->pad[0] = 0;
310         msg->pad[1] = 0;
311         msg->pad[2] = 0;
312
313         // msg + 1 == &msg[1]
314
315         txt = (char *)(msg + 1);
316
317         memcpy(txt, my_name, my_name_len); 
318
319         for (i = my_name_len; (i & 3) != 0; i++)
320                 txt[i] = 0;
321
322         return i;
323 }
324
325
326 /**
327  * Read a name message and update name_entry if necessary
328  *
329  * Return: 1 if entry was changed
330  */
331 int
332 read_namemsg(struct namemsg *msg, struct name_entry *to)
333 {
334         char *txt;
335
336         // msg + 1 == &msg[1]
337
338         txt = (char*)(msg + 1);
339
340         if (to->name == NULL || 
341                 strlen(to->name) != msg->name_len ||
342                 memcmp(to->name, txt, msg->name_len) != 0)
343         {
344                 if (to->name != NULL)
345                         free(to->name);
346
347                 to->name = olsr_malloc(msg->name_len + 1,
348                         "new name_entry name");
349
350                 memcpy(to->name, txt, msg->name_len);
351                 to->name[msg->name_len] = '\0';
352
353                 return 1;
354         }
355
356         return 0;       
357 }
358
359
360 /**
361  * Update or register a new name entry
362  */
363 void
364 update_name_entry(union olsr_ip_addr *originator, struct namemsg *message, double vtime)
365 {
366         int hash;
367         struct name_entry *entry;
368         
369         hash = olsr_hashing(originator);
370         
371         // entry lookup
372
373         for (entry = list[hash].next; entry != &list[hash]; entry = entry->next)
374                 if (memcmp(originator, &entry->originator, ipsize) == 0)
375                         break;
376
377         // no entry found
378
379         if (entry == &list[hash])
380         {
381                 entry = olsr_malloc(sizeof(struct name_entry), "new name_entry");
382                 entry->name = NULL;
383                 memcpy(&entry->originator, originator, ipsize);
384
385                 entry->next = list[hash].next->prev;
386                 entry->prev = &list[hash];
387
388                 list[hash].next->prev = entry;
389                 list[hash].next = entry;
390         }
391
392         // update entry's timestamp
393
394         olsr_get_timestamp(vtime * 1000, &entry->timer);
395
396         // insert name into entry
397
398         if (read_namemsg(message, entry))
399         {
400                 name_table_changed = 1;
401
402                 olsr_printf(2, "NAME PLUGIN: Changed entry %s: %s\n", olsr_ip_to_string(originator), entry->name);
403         }
404 }
405
406
407 /**
408  * write names to a file in /etc/hosts compatible format
409  */
410 void
411 write_name_table()
412 {
413         int hash;
414         struct name_entry *entry;
415         FILE* hosts;
416
417         if(!name_table_changed)
418                 return;
419               
420         olsr_printf(2, "NAME PLUGIN: writing hosts file %s\n", my_filename);
421         
422         hosts = fopen( my_filename, "w" );
423
424         if (hosts == NULL)
425                 return;
426         
427         fprintf(hosts, "# this /etc/hosts file is overwritten regularly by olsrd\n");
428         fprintf(hosts, "# do not edit\n");
429         // add own IP and name
430         fprintf(hosts, "%s\t%s\n", olsr_ip_to_string(main_addr), my_name );
431
432         for(hash = 0; hash < HASHSIZE; hash++) 
433         {
434                 for(entry = list[hash].next; entry != &list[hash]; entry = entry->next) 
435                         fprintf(hosts, "%s\t%s\n", olsr_ip_to_string(&entry->originator), entry->name);
436         }
437         
438         fclose(hosts);
439
440         name_table_changed = 0;
441 }