Merge branch 'master' into mpr_rework
[oonf.git] / src-plugins / subsystems / os_linux / os_fd_linux.h
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 #ifndef OS_FD_LINUX_H_
47 #define OS_FD_LINUX_H_
48
49 #include <sys/epoll.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <sys/sendfile.h>
53 #include <sys/socket.h>
54
55 #include "subsystems/os_fd.h"
56 #include "subsystems/os_generic/os_fd_generic_configsocket.h"
57 #include "subsystems/os_generic/os_fd_generic_getrawsocket.h"
58 #include "subsystems/os_generic/os_fd_generic_getsocket.h"
59 #include "subsystems/os_generic/os_fd_generic_join_mcast.h"
60 #include "subsystems/os_generic/os_fd_generic_set_dscp.h"
61 #include "subsystems/os_generic/os_fd_generic_set_nonblocking.h"
62
63 /*! name of the loopback interface */
64 #define IF_LOOPBACK_NAME "lo"
65
66 enum os_fd_flags {
67   OS_FD_ACTIVE = 1,
68 };
69
70 /*! linux specific socket definition */
71 struct os_fd {
72   /*! file descriptor of socket */
73   int fd;
74
75   /*! flags for telling epoll which events we are interested in */
76   uint32_t wanted_events;
77
78   /*! flags which were triggered in last epoll */
79   uint32_t received_events;
80
81   /*! flags for socket */
82   enum os_fd_flags _flags;
83 };
84
85 /*! linux specific socket select definition */
86 struct os_fd_select {
87   struct epoll_event _events[16];
88   int _event_count;
89
90   int _epoll_fd;
91
92   uint64_t deadline;
93 };
94
95 /** declare non-inline linux-specific functions */
96 EXPORT int os_fd_linux_event_wait(struct os_fd_select *);
97 EXPORT int os_fd_linux_event_socket_modify(struct os_fd_select *sel,
98     struct os_fd *sock);
99 EXPORT uint8_t *os_fd_linux_skip_rawsocket_prefix(uint8_t *ptr, ssize_t *len, int af_type);
100
101 /**
102  * Redirect to linux specific event wait call
103  * @param sel selector instance
104  * @return number of events that happened,
105  *   0 if deadline was reached, -1 if an error happened
106  */
107 static INLINE int
108 os_fd_event_wait(struct os_fd_select *sel) {
109   return os_fd_linux_event_wait(sel);
110 }
111
112 /**
113  * Redirect to generic getsocket call
114  * @param sock empty socket representation
115  * @param bindto bind socket to this address/port
116  * @param tcp true if TCP socket, false if UDP socket
117  * @param recvbuf size of receiver buffer
118  * @param os_if bind socket to this interface,
119  *   NULL to not bind socket to interface
120  * @param log_src logging source for error messages
121  * @return -1 if an error happened, 0 otherwise
122  */
123 static INLINE int
124 os_fd_getsocket(struct os_fd *sock, const union netaddr_socket *bindto, bool tcp,
125     size_t recvbuf, const struct os_interface *os_if, enum oonf_log_source log_src) {
126   return os_fd_generic_getsocket(sock, bindto, tcp, recvbuf, os_if, log_src);
127 }
128
129 /**
130  * Redirect to generic getrawsocket call
131  * @param sock empty socket representation
132  * @param bindto bind socket to this address/port
133  * @param protocol bind socket to this protocol
134  * @param recvbuf size of receiver buffer
135  * @param os_if bind socket to this interface,
136  *   NULL to not bind socket to interface
137  * @param log_src logging source for error messages
138  * @return -1 if an error happened, 0 otherwise
139  */
140 static INLINE int
141 os_fd_getrawsocket(struct os_fd *sock, const union netaddr_socket *bindto, int protocol,
142     size_t recvbuf, const struct os_interface *os_if, enum oonf_log_source log_src) {
143   return os_fd_generic_getrawsocket(sock, bindto, protocol, recvbuf, os_if, log_src);
144 }
145
146 /**
147  * Redirect to generic configsocket call
148  * @param sock empty socket representation
149  * @param bindto bind socket to this address/port
150  * @param recvbuf size of receiver buffer
151  * @param rawip true if this is a raw ip socket, false otherwise
152  * @param os_if bind socket to this interface,
153  *   NULL to not bind socket to interface
154  * @param log_src logging source for error messages
155  * @return -1 if an error happened, 0 otherwise
156  */
157 static INLINE int
158 os_fd_configsocket(struct os_fd *sock, const union netaddr_socket *bindto,
159     size_t recvbuf, bool rawip, const struct os_interface *os_if, enum oonf_log_source log_src) {
160   return os_fd_generic_configsocket(sock, bindto, recvbuf, rawip, os_if, log_src);
161 }
162
163 /**
164  * Redirect to generic set_nonblocking call
165  * @param sock socket representation
166  * @return -1 if an error happened, 0 otherwise
167  */
168 static INLINE int
169 os_fd_set_nonblocking(struct os_fd *sock) {
170   return os_fd_generic_set_nonblocking(sock);
171 }
172
173 /**
174  * Redirect to generic mcast receiver join call
175  * @param sock socket representation
176  * @param multicast multicast group to join
177  * @param os_if outgoing interface for multicast,
178  *   NULL if not interface specific
179  * @param log_src logging source for error messages
180  * @return -1 if an error happened, 0 otherwise
181  */
182 static INLINE int
183 os_fd_join_mcast_recv(struct os_fd *sock, const struct netaddr *multicast,
184     const struct os_interface *os_if, enum oonf_log_source log_src) {
185   return os_fd_generic_join_mcast_recv(sock, multicast, os_if, log_src);
186 }
187
188 /**
189  * Redirect to generic mcast sender join call
190  * @param sock socket representation
191  * @param multicast sending multicast group to join
192  * @param os_if outgoing interface for multicast,
193  *   NULL if not interface specific
194  * @param loop true if multicast should be locally looped
195  * @param log_src logging source for error messages
196  * @return -1 if an error happened, 0 otherwise
197  */
198 static INLINE int
199 os_fd_join_mcast_send(struct os_fd *sock, const struct netaddr *multicast,
200     const struct os_interface *os_if, bool loop, enum oonf_log_source log_src) {
201   return os_fd_generic_join_mcast_send(sock, multicast, os_if, loop, log_src);
202 }
203 /**
204  * Redirect to generic set_dscp call
205  * @param sock socket representation
206  * @param dscp new dscp value
207  * @param ipv6 true if IPv6, false for IPv4 socket
208  * @return -1 if an error happened, 0 otherwise
209  */
210 static INLINE int
211 os_fd_set_dscp(struct os_fd *sock, int dscp, bool ipv6) {
212   return os_fd_generic_set_dscp(sock, dscp, ipv6);
213 }
214
215 /**
216  * Redirect to linux specific rawsocket prefix call
217  * @param ptr pointer to the beginning of the buffer
218  * @param len pointer to length of buffer
219  * @param af_type address family of data in buffer
220  * @return pointer to transport layer data
221  */
222 static INLINE uint8_t *
223 os_fd_skip_rawsocket_prefix(uint8_t *ptr, ssize_t *len, int af_type) {
224   return os_fd_linux_skip_rawsocket_prefix(ptr, len, af_type);
225 }
226
227 /**
228  * initialize a socket representation with a file descriptor
229  * @param os_fd socket representation
230  * @param fd file descriptor
231  * @return -1 if an error happened, 0 otherwise
232  */
233 static INLINE int
234 os_fd_init(struct os_fd *os_fd, int fd) {
235   os_fd->fd = fd;
236   os_fd->_flags = OS_FD_ACTIVE;
237   return 0;
238 }
239
240 /**
241  * Removes all data from a socket. it is not necessary to
242  * call this function on all sockets.
243  * @param sock socket representation
244  * @return -1 if an error happened, 0 otherwise
245  */
246 static INLINE int
247 os_fd_invalidate(struct os_fd *sock) {
248   memset(sock, 0, sizeof(*sock));
249   return 0;
250 }
251
252 /**
253  * Checks if a socket is initialized
254  * @param sock socket representation
255  * @return true if socket is initialized, false otherwise
256  */
257 static INLINE bool
258 os_fd_is_initialized(struct os_fd *sock) {
259   return (sock->_flags & OS_FD_ACTIVE) != 0;
260 }
261
262 /**
263  * Extract the filedescriptor from a socket
264  * @param sock socket representation
265  * @return file descriptor
266  */
267 static INLINE int
268 os_fd_get_fd(struct os_fd *sock) {
269   return sock->fd;
270 }
271
272 /**
273  * Copy a filedescriptor
274  * @param dst target filedescriptor
275  * @param from source filedescriptor
276  * @return
277  */
278 static INLINE int
279 os_fd_copy(struct os_fd *dst, struct os_fd *from) {
280   return os_fd_init(dst, from->fd);
281 }
282
283 /**
284  * Close a file descriptor
285  * @param fd filedescriptor
286  * @return -1 if an error happened, 0 otherwise
287  */
288 static INLINE int
289 os_fd_close(struct os_fd *sock) {
290   int result = 0;
291   if (sock->fd != -1) {
292     result = close(sock->fd);
293     sock->fd = -1;
294   }
295   return result;
296 }
297
298 /**
299  * Listen to a TCP socket
300  * @param fd filedescriptor
301  * @param n backlog
302  * @return -1 if an error happened, 0 otherwise
303  */
304 static INLINE int
305 os_fd_listen(struct os_fd *sock, int n) {
306   return listen(sock->fd, n);
307 }
308
309 /**
310  * Initialize a socket event handler
311  * @param sel empty socket event handler
312  * @return -1 if an error happened, 0 otherwise
313  */
314 static INLINE int
315 os_fd_event_add(struct os_fd_select *sel) {
316   memset (sel, 0, sizeof(*sel));
317   sel->_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
318   return sel->_epoll_fd < 0 ? -1 : 0;
319 }
320
321 /**
322  * Get an event from a socket event handler
323  * @param sel socket event handler
324  * @param idx index of event
325  * @return socket responsible for event
326  */
327 static INLINE struct os_fd *
328 os_fd_event_get(struct os_fd_select *sel, int idx) {
329   return sel->_events[idx].data.ptr;
330 }
331
332 /**
333  * Add a socket to a socket event handler
334  * @param sel socket event handler
335  * @param sock socket
336  * @return -1 if an error happened, 0 otherwise
337  */
338 static INLINE int
339 os_fd_event_socket_add(struct os_fd_select *sel, struct os_fd *sock) {
340   struct epoll_event event;
341
342   memset(&event,0,sizeof(event));
343
344   event.events = 0;
345   event.data.ptr = sock;
346   return epoll_ctl(sel->_epoll_fd, EPOLL_CTL_ADD, sock->fd, &event);
347 }
348
349 /**
350  * Set the read status of a socket in a socket event handler
351  * @param sel socket event handler
352  * @param sock socket representation
353  * @param want_read true if socket should trigger read events,
354  *   false otherwise
355  * @return -1 if an error happened, 0 otherwise
356  */
357 static INLINE int
358 os_fd_event_socket_read(struct os_fd_select *sel,
359     struct os_fd *sock, bool want_read) {
360   if (want_read) {
361     sock->wanted_events |= EPOLLIN;
362   }
363   else {
364     sock->wanted_events &= ~EPOLLIN;
365   }
366   return os_fd_linux_event_socket_modify(sel, sock);
367 }
368
369 /**
370  * Check if a socket triggered a read event
371  * @param sock socket representation
372  * @return true if socket triggered a read event, false otherwise
373  */
374 static INLINE int
375 os_fd_event_is_read(struct os_fd *sock) {
376   return (sock->received_events & EPOLLIN) != 0;
377 }
378
379 /**
380  * Set the write status of a socket in a socket event handler
381  * @param sel socket event handler
382  * @param sock socket representation
383  * @param want_write true if socket should trigger write events,
384  *   false otherwise
385  * @return -1 if an error happened, 0 otherwise
386  */
387 static INLINE int
388 os_fd_event_socket_write(struct os_fd_select *sel,
389     struct os_fd *sock, bool want_write) {
390   if (want_write) {
391     sock->wanted_events |= EPOLLOUT;
392   }
393   else {
394     sock->wanted_events &= ~EPOLLOUT;
395   }
396   return os_fd_linux_event_socket_modify(sel, sock);
397 }
398
399 /**
400  * Check if a socket triggered a write event
401  * @param sock socket representation
402  * @return true if socket triggered a write event, false otherwise
403  */
404 static INLINE int
405 os_fd_event_is_write(struct os_fd *sock) {
406   return (sock->received_events & EPOLLOUT) != 0;
407 }
408
409 /**
410  * Remove a socket fromo a socket event handler
411  * @param sel socket event handler
412  * @param sock socket representation
413  * @return -1 if an error happened, 0 otherwise
414  */
415 static INLINE int
416 os_fd_event_socket_remove(struct os_fd_select *sel, struct os_fd *sock) {
417   return epoll_ctl(sel->_epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL);
418 }
419
420 /**
421  * Set the deadline for the coming socket event wait operations
422  * @param sel socket event handler
423  * @param deadline absolute timestamp when the wait call should return
424  * @return -1 if an error happened, 0 otherwise
425  */
426 static INLINE int
427 os_fd_event_set_deadline(struct os_fd_select *sel, uint64_t deadline) {
428   sel->deadline = deadline;
429   return 0;
430 }
431
432 /**
433  * @param sel socket event handler
434  * @return current deadline for wait call
435  */
436 static INLINE uint64_t
437 os_fd_event_get_deadline(struct os_fd_select *sel) {
438   return sel->deadline;
439 }
440
441 /**
442  * Cleans up a socket event handler
443  * @param sel socket event handler
444  * @return -1 if an error happened, 0 otherwise
445  */
446 static INLINE int
447 os_fd_event_remove(struct os_fd_select *sel) {
448   return close(sel->_epoll_fd);
449 }
450
451 /**
452  * Connect TCP socket to remote server
453  * @param sockfd filedescriptor
454  * @param remote remote socket
455  * @return -1 if an error happened, 0 otherwise
456  */
457 static INLINE int
458 os_fd_connect(struct os_fd *sock, const union netaddr_socket *remote) {
459   return connect(sock->fd, &remote->std, sizeof(*remote));
460 }
461
462 /**
463  * Call posix accept()
464  * @param sockfd server socket to accept a connection from
465  * @param incoming buffer for storing the incoming source IP/port
466  * @return result of accept() call
467  */
468 static INLINE int
469 os_fd_accept(struct os_fd *client,
470     struct os_fd *server, union netaddr_socket *incoming) {
471   socklen_t len = sizeof(*incoming);
472   int fd;
473
474   if ((fd = accept(server->fd, &incoming->std, &len)) < 0) {
475     return -1;
476   }
477   return os_fd_init(client, fd);
478 }
479
480 /**
481  * Get socket error state
482  * @param fd file descriptor of socket
483  * @param value buffer to store error state
484  * @return result of getsockopt() call
485  */
486 static INLINE int
487 os_fd_get_socket_error(struct os_fd *sock, int *value) {
488   socklen_t len = sizeof(*value);
489   return getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, value, &len);
490 }
491
492 /**
493  * Sends data to an UDP socket.
494  * @param fd filedescriptor
495  * @param buf buffer for target data
496  * @param length length of buffer
497  * @param dst pointer to netaddr socket to send packet to
498  * @param dont_route true to suppress routing of data
499  * @return same as sendto()
500  */
501 static INLINE ssize_t
502 os_fd_sendto(struct os_fd *sock, const void *buf, size_t length, const union netaddr_socket *dst, bool dont_route) {
503   return sendto(sock->fd, buf, length,
504       dont_route ? MSG_DONTROUTE : 0,
505       dst ? &dst->std : NULL, sizeof(*dst));
506 }
507
508 /**
509  * Receive data from a socket.
510  * @param fd filedescriptor
511  * @param buf buffer for incoming data
512  * @param length length of buffer
513  * @param source pointer to netaddr socket object to store source of packet
514  * @param interf limit received data to certain interface
515  *   (only used if socket cannot be bound to interface)
516  * @return same as recvfrom()
517  */
518 static INLINE ssize_t
519 os_fd_recvfrom(struct os_fd *sock, void *buf, size_t length, union netaddr_socket *source,
520     const struct os_interface *interf __attribute__((unused))) {
521   socklen_t len = sizeof(*source);
522   return recvfrom(sock->fd, buf, length, 0, &source->std, &len);
523 }
524
525 /**
526  * Binds a socket to a certain interface
527  * @param sock filedescriptor of socket
528  * @param interf name of interface
529  * @return -1 if an error happened, 0 otherwise
530  */
531 static INLINE int
532 os_fd_bindto_interface(struct os_fd *sock, struct os_interface *data) {
533   return setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, data->name, strlen(data->name) + 1);
534 }
535
536 /**
537  * @return name of loopback interface
538  */
539 static INLINE const char *
540 os_fd_get_loopback_name(void) {
541   return "lo";
542 }
543
544 /**
545  * send data from one filedescriptor to another one. Linux compatible API
546  * structure, might need a bit of work for other OS.
547  * @param outfd
548  * @param infd
549  * @param offset
550  * @param count
551  * @return -1 if an error happened, otherwise the number of bytes that
552  *   were sent to outfd
553  */
554 static INLINE ssize_t
555 os_fd_sendfile(struct os_fd *out, struct os_fd *in, size_t offset, size_t count) {
556   off_t int_offset = offset;
557   return sendfile(out->fd, in->fd, &int_offset, count);
558 }
559
560 #endif /* OS_FD_LINUX_H_ */