Normalize olsr_clock namespace
[olsrd.git] / src / olsr_socket.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <unistd.h>
43 #include <assert.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47
48 #include "common/avl.h"
49 #include "common/avl_olsr_comp.h"
50 #include "olsr_logging.h"
51 #include "olsr_memcookie.h"
52 #include "olsr_timer.h"
53 #include "os_net.h"
54 #include "olsr_socket.h"
55
56 /* Head of all OLSR used sockets */
57 struct list_entity socket_head;
58
59 static struct olsr_memcookie_info *socket_memcookie;
60
61 /* helper function to free socket entry */
62 static inline void olsr_socket_intfree(struct olsr_socket_entry *sock) {
63   list_remove(&sock->node);
64   olsr_memcookie_free(socket_memcookie, sock);
65 }
66
67 /**
68  * Initialize olsr socket scheduler
69  */
70 void
71 olsr_socket_init(void) {
72   list_init_head(&socket_head);
73
74   socket_memcookie = olsr_memcookie_add("socket entry", sizeof(struct olsr_socket_entry));
75 }
76
77 /**
78  * Cleanup olsr socket scheduler.
79  * This will close and free all sockets.
80  */
81 void
82 olsr_socket_cleanup(void)
83 {
84   struct olsr_socket_entry *entry, *iterator;
85
86   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
87     os_close(entry->fd);
88     olsr_socket_intfree(entry);
89   }
90 }
91
92 /**
93  * Add a socket and handler to the socketset
94  * beeing used in the main select(2) loop
95  *
96  * @param fd file descriptor for socket
97  * @param pf_imm processing callback
98  * @param data custom data
99  * @param flags OLSR_SOCKET_READ/OLSR_SOCKET_WRITE (or both)
100  * @return pointer to socket_entry
101  */
102 struct olsr_socket_entry *
103 olsr_socket_add(int fd, socket_handler_func pf_imm, void *data, unsigned int flags)
104 {
105   struct olsr_socket_entry *new_entry;
106
107   if (fd < 0 || pf_imm == NULL) {
108     OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not registering...");
109     return NULL;
110   }
111   OLSR_DEBUG(LOG_SCHEDULER, "Adding OLSR socket entry %d\n", fd);
112
113   new_entry = olsr_memcookie_malloc(socket_memcookie);
114
115   new_entry->fd = fd;
116   new_entry->process = pf_imm;
117   new_entry->data = data;
118   new_entry->flags = flags;
119
120   /* Queue */
121   list_add_before(&socket_head, &new_entry->node);
122
123   return new_entry;
124 }
125
126 /**
127  * Remove a socket and handler from the socket scheduler
128  * @param sock pointer to socket entry
129  */
130 void
131 olsr_socket_remove(struct olsr_socket_entry *entry)
132 {
133   OLSR_DEBUG(LOG_SCHEDULER, "Removing OLSR socket entry %d\n", entry->fd);
134
135   entry->process = NULL;
136   entry->flags = 0;
137 }
138
139 /**
140  * Handle all incoming socket events until a certain time
141  * @param next_interval
142  */
143 void
144 handle_sockets(uint32_t next_interval)
145 {
146   struct olsr_socket_entry *entry, *iterator;
147   struct timeval tvp;
148   int32_t remaining;
149
150   /* Update time since this is much used by the parsing functions */
151   olsr_clock_update();
152
153   remaining = olsr_clock_getRelative(next_interval);
154   if (remaining <= 0) {
155     /* we are already over the interval */
156     if (list_is_empty(&socket_head)) {
157       /* If there are no registered sockets we do not call select(2) */
158       return;
159     }
160     tvp.tv_sec = 0;
161     tvp.tv_usec = 0;
162   } else {
163     /* we need an absolute time - milliseconds */
164     tvp.tv_sec = remaining / MSEC_PER_SEC;
165     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
166   }
167
168   /* do at least one select */
169   for (;;) {
170     fd_set ibits, obits;
171     int n, hfd = 0, fdsets = 0;
172     FD_ZERO(&ibits);
173     FD_ZERO(&obits);
174
175     /* Adding file-descriptors to FD set */
176     OLSR_FOR_ALL_SOCKETS(entry, iterator) {
177       if (entry->process == NULL) {
178         continue;
179       }
180       if ((entry->flags & OLSR_SOCKET_READ) != 0) {
181         fdsets |= OLSR_SOCKET_READ;
182         FD_SET((unsigned int)entry->fd, &ibits);        /* And we cast here since we get a warning on Win32 */
183       }
184       if ((entry->flags & OLSR_SOCKET_WRITE) != 0) {
185         fdsets |= OLSR_SOCKET_WRITE;
186         FD_SET((unsigned int)entry->fd, &obits);        /* And we cast here since we get a warning on Win32 */
187       }
188       if ((entry->flags & (OLSR_SOCKET_READ | OLSR_SOCKET_WRITE)) != 0 && entry->fd >= hfd) {
189         hfd = entry->fd + 1;
190       }
191     }
192
193     if (hfd == 0 && (long)remaining <= 0) {
194       /* we are over the interval and we have no fd's. Skip the select() etc. */
195       return;
196     }
197
198     do {
199       n = os_select(hfd,
200           fdsets & OLSR_SOCKET_READ ? &ibits : NULL,
201           fdsets & OLSR_SOCKET_WRITE ? &obits : NULL,
202           NULL, &tvp);
203     } while (n == -1 && errno == EINTR);
204
205     if (n == 0) {               /* timeout! */
206       break;
207     }
208     if (n == -1) {              /* Did something go wrong? */
209       OLSR_WARN(LOG_SCHEDULER, "select error: %s (%d)", strerror(errno), errno);
210       break;
211     }
212
213     /* Update time since this is much used by the parsing functions */
214     olsr_clock_update();
215     OLSR_FOR_ALL_SOCKETS(entry, iterator) {
216       int flags;
217       if (entry->process == NULL) {
218         continue;
219       }
220       flags = 0;
221       if (FD_ISSET(entry->fd, &ibits)) {
222         flags |= OLSR_SOCKET_READ;
223       }
224       if (FD_ISSET(entry->fd, &obits)) {
225         flags |= OLSR_SOCKET_WRITE;
226       }
227       if (flags != 0) {
228         entry->process(entry->fd, entry->data, flags);
229       }
230     }
231
232     /* calculate the next timeout */
233     remaining = olsr_clock_getRelative(next_interval);
234     if (remaining <= 0) {
235       /* we are already over the interval */
236       break;
237     }
238     /* we need an absolute time - milliseconds */
239     tvp.tv_sec = remaining / MSEC_PER_SEC;
240     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
241   }
242
243   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
244     if (entry->process == NULL) {
245       olsr_socket_intfree(entry);
246     }
247   }
248 }
249
250 /*
251  * Local Variables:
252  * c-basic-offset: 2
253  * indent-tabs-mode: nil
254  * End:
255  */