Merge branch 'master' into interface_cleanup
[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.data.ptr = sock;
345   return epoll_ctl(sel->_epoll_fd, EPOLL_CTL_ADD, sock->fd, &event);
346 }
347
348 /**
349  * Set the read status of a socket in a socket event handler
350  * @param sel socket event handler
351  * @param sock socket representation
352  * @param want_read true if socket should trigger read events,
353  *   false otherwise
354  * @return -1 if an error happened, 0 otherwise
355  */
356 static INLINE int
357 os_fd_event_socket_read(struct os_fd_select *sel,
358     struct os_fd *sock, bool want_read) {
359   if (want_read) {
360     sock->wanted_events |= EPOLLIN;
361   }
362   else {
363     sock->wanted_events &= ~EPOLLIN;
364   }
365   return os_fd_linux_event_socket_modify(sel, sock);
366 }
367
368 /**
369  * Check if a socket triggered a read event
370  * @param sock socket representation
371  * @return true if socket triggered a read event, false otherwise
372  */
373 static INLINE int
374 os_fd_event_is_read(struct os_fd *sock) {
375   return (sock->received_events & EPOLLIN) != 0;
376 }
377
378 /**
379  * Set the write status of a socket in a socket event handler
380  * @param sel socket event handler
381  * @param sock socket representation
382  * @param want_write true if socket should trigger write events,
383  *   false otherwise
384  * @return -1 if an error happened, 0 otherwise
385  */
386 static INLINE int
387 os_fd_event_socket_write(struct os_fd_select *sel,
388     struct os_fd *sock, bool want_write) {
389   if (want_write) {
390     sock->wanted_events |= EPOLLOUT;
391   }
392   else {
393     sock->wanted_events &= ~EPOLLOUT;
394   }
395   return os_fd_linux_event_socket_modify(sel, sock);
396 }
397
398 /**
399  * Check if a socket triggered a write event
400  * @param sock socket representation
401  * @return true if socket triggered a write event, false otherwise
402  */
403 static INLINE int
404 os_fd_event_is_write(struct os_fd *sock) {
405   return (sock->received_events & EPOLLOUT) != 0;
406 }
407
408 /**
409  * Remove a socket fromo a socket event handler
410  * @param sel socket event handler
411  * @param sock socket representation
412  * @return -1 if an error happened, 0 otherwise
413  */
414 static INLINE int
415 os_fd_event_socket_remove(struct os_fd_select *sel, struct os_fd *sock) {
416   return epoll_ctl(sel->_epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL);
417 }
418
419 /**
420  * Set the deadline for the coming socket event wait operations
421  * @param sel socket event handler
422  * @param deadline absolute timestamp when the wait call should return
423  * @return -1 if an error happened, 0 otherwise
424  */
425 static INLINE int
426 os_fd_event_set_deadline(struct os_fd_select *sel, uint64_t deadline) {
427   sel->deadline = deadline;
428   return 0;
429 }
430
431 /**
432  * @param sel socket event handler
433  * @return current deadline for wait call
434  */
435 static INLINE uint64_t
436 os_fd_event_get_deadline(struct os_fd_select *sel) {
437   return sel->deadline;
438 }
439
440 /**
441  * Cleans up a socket event handler
442  * @param sel socket event handler
443  * @return -1 if an error happened, 0 otherwise
444  */
445 static INLINE int
446 os_fd_event_remove(struct os_fd_select *sel) {
447   return close(sel->_epoll_fd);
448 }
449
450 /**
451  * Connect TCP socket to remote server
452  * @param sockfd filedescriptor
453  * @param remote remote socket
454  * @return -1 if an error happened, 0 otherwise
455  */
456 static INLINE int
457 os_fd_connect(struct os_fd *sock, const union netaddr_socket *remote) {
458   return connect(sock->fd, &remote->std, sizeof(*remote));
459 }
460
461 /**
462  * Call posix accept()
463  * @param sockfd server socket to accept a connection from
464  * @param incoming buffer for storing the incoming source IP/port
465  * @return result of accept() call
466  */
467 static INLINE int
468 os_fd_accept(struct os_fd *client,
469     struct os_fd *server, union netaddr_socket *incoming) {
470   socklen_t len = sizeof(*incoming);
471   int fd;
472
473   if ((fd = accept(server->fd, &incoming->std, &len)) < 0) {
474     return -1;
475   }
476   return os_fd_init(client, fd);
477 }
478
479 /**
480  * Get socket error state
481  * @param fd file descriptor of socket
482  * @param value buffer to store error state
483  * @return result of getsockopt() call
484  */
485 static INLINE int
486 os_fd_get_socket_error(struct os_fd *sock, int *value) {
487   socklen_t len = sizeof(*value);
488   return getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, value, &len);
489 }
490
491 /**
492  * Sends data to an UDP socket.
493  * @param fd filedescriptor
494  * @param buf buffer for target data
495  * @param length length of buffer
496  * @param dst pointer to netaddr socket to send packet to
497  * @param dont_route true to suppress routing of data
498  * @return same as sendto()
499  */
500 static INLINE ssize_t
501 os_fd_sendto(struct os_fd *sock, const void *buf, size_t length, const union netaddr_socket *dst, bool dont_route) {
502   return sendto(sock->fd, buf, length,
503       dont_route ? MSG_DONTROUTE : 0,
504       dst ? &dst->std : NULL, sizeof(*dst));
505 }
506
507 /**
508  * Receive data from a socket.
509  * @param fd filedescriptor
510  * @param buf buffer for incoming data
511  * @param length length of buffer
512  * @param source pointer to netaddr socket object to store source of packet
513  * @param interf limit received data to certain interface
514  *   (only used if socket cannot be bound to interface)
515  * @return same as recvfrom()
516  */
517 static INLINE ssize_t
518 os_fd_recvfrom(struct os_fd *sock, void *buf, size_t length, union netaddr_socket *source,
519     const struct os_interface *interf __attribute__((unused))) {
520   socklen_t len = sizeof(*source);
521   return recvfrom(sock->fd, buf, length, 0, &source->std, &len);
522 }
523
524 /**
525  * Binds a socket to a certain interface
526  * @param sock filedescriptor of socket
527  * @param interf name of interface
528  * @return -1 if an error happened, 0 otherwise
529  */
530 static INLINE int
531 os_fd_bindto_interface(struct os_fd *sock, struct os_interface *data) {
532   return setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, data->name, strlen(data->name) + 1);
533 }
534
535 /**
536  * @return name of loopback interface
537  */
538 static INLINE const char *
539 os_fd_get_loopback_name(void) {
540   return "lo";
541 }
542
543 /**
544  * send data from one filedescriptor to another one. Linux compatible API
545  * structure, might need a bit of work for other OS.
546  * @param outfd
547  * @param infd
548  * @param offset
549  * @param count
550  * @return -1 if an error happened, otherwise the number of bytes that
551  *   were sent to outfd
552  */
553 static INLINE ssize_t
554 os_fd_sendfile(struct os_fd *out, struct os_fd *in, size_t offset, size_t count) {
555   off_t int_offset = offset;
556   return sendfile(out->fd, in->fd, &int_offset, count);
557 }
558
559 #endif /* OS_FD_LINUX_H_ */