Rename "subsystems" directory to "base"
[oonf.git] / src / base / oonf_socket.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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 /**
43  * @file
44  */
45
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include <oonf/libcommon/avl.h>
52 #include <oonf/libcommon/avl_comp.h>
53 #include <oonf/libcore/oonf_logging.h>
54 #include <oonf/libcore/oonf_main.h>
55 #include <oonf/libcore/oonf_subsystem.h>
56 #include <oonf/base/oonf_clock.h>
57 #include <oonf/base/oonf_socket.h>
58 #include <oonf/base/oonf_timer.h>
59 #include <oonf/base/os_clock.h>
60 #include <oonf/base/os_fd.h>
61
62 /* Definitions */
63 #define LOG_SOCKET _oonf_socket_subsystem.logging
64
65 /* prototypes */
66 static int _init(void);
67 static void _cleanup(void);
68 static void _initiate_shutdown(void);
69
70 static bool _shall_end_scheduler(void);
71 static int _handle_scheduling(void);
72
73 /* time until the scheduler should run */
74 static uint64_t _scheduler_time_limit;
75
76 /* List of all active sockets in scheduler */
77 static struct list_entity _socket_head;
78
79 /* socket event scheduler */
80 struct os_fd_select _socket_events;
81
82 /* subsystem definition */
83 static const char *_dependencies[] = {
84   OONF_TIMER_SUBSYSTEM,
85   OONF_OS_FD_SUBSYSTEM,
86 };
87
88 static struct oonf_subsystem _oonf_socket_subsystem = {
89   .name = OONF_SOCKET_SUBSYSTEM,
90   .dependencies = _dependencies,
91   .dependencies_count = ARRAYSIZE(_dependencies),
92   .init = _init,
93   .cleanup = _cleanup,
94   .initiate_shutdown = _initiate_shutdown,
95 };
96 DECLARE_OONF_PLUGIN(_oonf_socket_subsystem);
97
98 /**
99  * Initialize olsr socket scheduler
100  * @return always returns 0
101  */
102 static int
103 _init(void) {
104   if (oonf_main_set_scheduler(_handle_scheduling)) {
105     return -1;
106   }
107
108   list_init_head(&_socket_head);
109   os_fd_event_add(&_socket_events);
110
111   _scheduler_time_limit = ~0ull;
112   return 0;
113 }
114
115 /**
116  * Cleanup olsr socket scheduler.
117  * This will close and free all sockets.
118  */
119 static void
120 _cleanup(void) {
121   struct oonf_socket_entry *entry, *iterator;
122
123   list_for_each_element_safe(&_socket_head, entry, _node, iterator) {
124     list_remove(&entry->_node);
125     os_fd_close(&entry->fd);
126   }
127
128   os_fd_event_remove(&_socket_events);
129 }
130
131 static void
132 _initiate_shutdown(void) {
133   /* stop within 500 ms */
134   _scheduler_time_limit = oonf_clock_get_absolute(500);
135   OONF_INFO(LOG_SOCKET, "Stop within 500 ms");
136 }
137
138 /**
139  * Add a socket handler to the scheduler
140  *
141  * @param entry pointer to initialized socket entry
142  */
143 void
144 oonf_socket_add(struct oonf_socket_entry *entry) {
145   OONF_DEBUG(LOG_SOCKET, "Adding socket entry %s (%d) to scheduler\n", entry->name, os_fd_get_fd(&entry->fd));
146
147   list_add_before(&_socket_head, &entry->_node);
148   os_fd_event_socket_add(&_socket_events, &entry->fd);
149 }
150
151 /**
152  * Remove a socket from the socket scheduler
153  * @param entry pointer to socket entry
154  */
155 void
156 oonf_socket_remove(struct oonf_socket_entry *entry) {
157   if (list_is_node_added(&entry->_node)) {
158     OONF_DEBUG(LOG_SOCKET, "Removing socket entry %s (%d)\n", entry->name, os_fd_get_fd(&entry->fd));
159
160     list_remove(&entry->_node);
161     os_fd_event_socket_remove(&_socket_events, &entry->fd);
162   }
163 }
164
165 /**
166  * @return list of all registered sockets
167  */
168 struct list_entity *
169 oonf_socket_get_list(void) {
170   return &_socket_head;
171 }
172
173 /**
174  * @param entry socket entry
175  * @param event_read true to enable read events, false to disable
176  */
177 void
178 oonf_socket_set_read(struct oonf_socket_entry *entry, bool event_read) {
179   os_fd_event_socket_read(&_socket_events, &entry->fd, event_read);
180 }
181
182 /**
183  * @param entry socket entry
184  * @param event_write true to enable write events, false to disable
185  */
186 void
187 oonf_socket_set_write(struct oonf_socket_entry *entry, bool event_write) {
188   os_fd_event_socket_write(&_socket_events, &entry->fd, event_write);
189 }
190
191 /**
192  * @return true if scheduler should stop
193  */
194 static bool
195 _shall_end_scheduler(void) {
196   return _scheduler_time_limit == ~0ull && oonf_main_shall_stop_scheduler();
197 }
198
199 /**
200  * Handle all incoming socket events and timer events
201  * @return -1 if an error happened, 0 otherwise
202  */
203 int
204 _handle_scheduling(void) {
205   struct oonf_socket_entry *sock_entry = NULL;
206   struct os_fd *sock;
207   uint64_t next_event;
208   uint64_t start_time, end_time;
209   int i, n;
210
211   while (true) {
212     /* Update time since this is much used by the parsing functions */
213     if (oonf_clock_update()) {
214       return -1;
215     }
216
217     if (oonf_clock_getNow() >= _scheduler_time_limit) {
218       return -1;
219     }
220
221     oonf_timer_walk();
222
223     if (_shall_end_scheduler()) {
224       return 0;
225     }
226
227     next_event = oonf_timer_getNextEvent();
228     if (next_event > _scheduler_time_limit) {
229       next_event = _scheduler_time_limit;
230     }
231
232     if (os_fd_event_get_deadline(&_socket_events) != next_event) {
233       os_fd_event_set_deadline(&_socket_events, next_event);
234     }
235
236     do {
237       if (_shall_end_scheduler()) {
238         return 0;
239       }
240
241       n = os_fd_event_wait(&_socket_events);
242     } while (n == -1 && errno == EINTR);
243
244     if (n == 0) { /* timeout! */
245       return 0;
246     }
247     if (n < 0) { /* Did something go wrong? */
248       OONF_WARN(LOG_SOCKET, "select error: %s (%d)", strerror(errno), errno);
249       return -1;
250     }
251
252     /* Update time since this is much used by the parsing functions */
253     if (oonf_clock_update()) {
254       return -1;
255     }
256
257     OONF_DEBUG(LOG_SOCKET, "Got %d events", n);
258
259     for (i = 0; i < n; i++) {
260       sock = os_fd_event_get(&_socket_events, i);
261
262       if (os_fd_event_is_read(sock) || os_fd_event_is_write(sock)) {
263         sock_entry = container_of(sock, typeof(*sock_entry), fd);
264         if (sock_entry->process == NULL) {
265           continue;
266         }
267
268         OONF_DEBUG(LOG_SOCKET, "Socket '%s' (%d) triggered (read=%s, write=%s)", sock_entry->name,
269           os_fd_get_fd(&sock_entry->fd), os_fd_event_is_read(sock) ? "true" : "false",
270           os_fd_event_is_write(sock) ? "true" : "false");
271
272         /* handle statistics */
273         if (os_fd_event_is_read(sock)) {
274           sock_entry->_stat_recv++;
275         }
276         if (os_fd_event_is_write(sock)) {
277           sock_entry->_stat_send++;
278         }
279         os_clock_gettime64(&start_time);
280         sock_entry->process(sock_entry);
281         os_clock_gettime64(&end_time);
282
283         if (end_time - start_time > OONF_TIMER_SLICE) {
284           OONF_WARN(LOG_SOCKET, "Socket '%s' (%d) scheduling took %" PRIu64 " ms", sock_entry->name,
285             os_fd_get_fd(&sock_entry->fd), end_time - start_time);
286           sock_entry->_stat_long++;
287         }
288       }
289     }
290   }
291   return 0;
292 }