Rename "subsystems" directory to "base"
[oonf.git] / include / oonf / base / 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 <sys/sendfile.h>
51 #include <sys/socket.h>
52 #include <sys/types.h>
53 #include <unistd.h>
54
55 #include <oonf/base/os_fd.h>
56 #include <oonf/base/os_generic/os_fd_generic_configsocket.h>
57 #include <oonf/base/os_generic/os_fd_generic_getrawsocket.h>
58 #include <oonf/base/os_generic/os_fd_generic_getsocket.h>
59 #include <oonf/base/os_generic/os_fd_generic_join_mcast.h>
60 #include <oonf/base/os_generic/os_fd_generic_set_dscp.h>
61 #include <oonf/base/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 {
68   OS_FD_ACTIVE = 1,
69 };
70
71 /*! linux specific socket definition */
72 struct os_fd {
73   /*! file descriptor of socket */
74   int fd;
75
76   /*! flags for telling epoll which events we are interested in */
77   uint32_t wanted_events;
78
79   /*! flags which were triggered in last epoll */
80   uint32_t received_events;
81
82   /*! flags for socket */
83   enum os_fd_flags _flags;
84 };
85
86 /*! linux specific socket select definition */
87 struct os_fd_select {
88   struct epoll_event _events[16];
89   int _event_count;
90
91   int _epoll_fd;
92
93   uint64_t deadline;
94 };
95
96 /** declare non-inline linux-specific functions */
97 EXPORT int os_fd_linux_event_wait(struct os_fd_select *);
98 EXPORT int os_fd_linux_event_socket_modify(struct os_fd_select *sel, 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, size_t recvbuf,
125   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, size_t recvbuf,
142   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, size_t recvbuf, bool rawip,
159   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(
184   struct os_fd *sock, const struct netaddr *multicast, 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 ttl TTL of the multicast, 0 will be considered as ttl 1
196  * @param log_src logging source for error messages
197  * @return -1 if an error happened, 0 otherwise
198  */
199 static INLINE int
200 os_fd_join_mcast_send(struct os_fd *sock, const struct netaddr *multicast, const struct os_interface *os_if, bool loop,
201   uint8_t ttl, enum oonf_log_source log_src) {
202   return os_fd_generic_join_mcast_send(sock, multicast, os_if, loop, ttl, log_src);
203 }
204 /**
205  * Redirect to generic set_dscp call
206  * @param sock socket representation
207  * @param dscp new dscp value
208  * @param ipv6 true if IPv6, false for IPv4 socket
209  * @return -1 if an error happened, 0 otherwise
210  */
211 static INLINE int
212 os_fd_set_dscp(struct os_fd *sock, int dscp, bool ipv6) {
213   return os_fd_generic_set_dscp(sock, dscp, ipv6);
214 }
215
216 /**
217  * Redirect to linux specific rawsocket prefix call
218  * @param ptr pointer to the beginning of the buffer
219  * @param len pointer to length of buffer
220  * @param af_type address family of data in buffer
221  * @return pointer to transport layer data
222  */
223 static INLINE uint8_t *
224 os_fd_skip_rawsocket_prefix(uint8_t *ptr, ssize_t *len, int af_type) {
225   return os_fd_linux_skip_rawsocket_prefix(ptr, len, af_type);
226 }
227
228 /**
229  * initialize a socket representation with a file descriptor
230  * @param os_fd socket representation
231  * @param fd file descriptor
232  * @return -1 if an error happened, 0 otherwise
233  */
234 static INLINE int
235 os_fd_init(struct os_fd *os_fd, int fd) {
236   os_fd->fd = fd;
237   os_fd->_flags = OS_FD_ACTIVE;
238   return 0;
239 }
240
241 /**
242  * Removes all data from a socket. it is not necessary to
243  * call this function on all sockets.
244  * @param sock socket representation
245  * @return -1 if an error happened, 0 otherwise
246  */
247 static INLINE int
248 os_fd_invalidate(struct os_fd *sock) {
249   memset(sock, 0, sizeof(*sock));
250   return 0;
251 }
252
253 /**
254  * Checks if a socket is initialized
255  * @param sock socket representation
256  * @return true if socket is initialized, false otherwise
257  */
258 static INLINE bool
259 os_fd_is_initialized(struct os_fd *sock) {
260   return (sock->_flags & OS_FD_ACTIVE) != 0;
261 }
262
263 /**
264  * Extract the filedescriptor from a socket
265  * @param sock socket representation
266  * @return file descriptor
267  */
268 static INLINE int
269 os_fd_get_fd(struct os_fd *sock) {
270   return sock->fd;
271 }
272
273 /**
274  * Copy a filedescriptor
275  * @param dst target filedescriptor
276  * @param from source filedescriptor
277  * @return -1 if an error happened, 0 otherwise
278  */
279 static INLINE int
280 os_fd_copy(struct os_fd *dst, struct os_fd *from) {
281   return os_fd_init(dst, from->fd);
282 }
283
284 /**
285  * Close a file descriptor
286  * @param fd filedescriptor
287  * @return -1 if an error happened, 0 otherwise
288  */
289 static INLINE int
290 os_fd_close(struct os_fd *fd) {
291   int result = 0;
292   if (fd->fd != -1) {
293     result = close(fd->fd);
294     fd->fd = -1;
295   }
296   return result;
297 }
298
299 /**
300  * Listen to a TCP socket
301  * @param fd filedescriptor
302  * @param n backlog
303  * @return -1 if an error happened, 0 otherwise
304  */
305 static INLINE int
306 os_fd_listen(struct os_fd *fd, int n) {
307   return listen(fd->fd, n);
308 }
309
310 /**
311  * Initialize a socket event handler
312  * @param sel empty socket event handler
313  * @return -1 if an error happened, 0 otherwise
314  */
315 static INLINE int
316 os_fd_event_add(struct os_fd_select *sel) {
317   memset(sel, 0, sizeof(*sel));
318   sel->_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
319   return sel->_epoll_fd < 0 ? -1 : 0;
320 }
321
322 /**
323  * Get an event from a socket event handler
324  * @param sel socket event handler
325  * @param idx index of event
326  * @return socket responsible for event
327  */
328 static INLINE struct os_fd *
329 os_fd_event_get(struct os_fd_select *sel, int idx) {
330   return sel->_events[idx].data.ptr;
331 }
332
333 /**
334  * Add a socket to a socket event handler
335  * @param sel socket event handler
336  * @param sock socket
337  * @return -1 if an error happened, 0 otherwise
338  */
339 static INLINE int
340 os_fd_event_socket_add(struct os_fd_select *sel, struct os_fd *sock) {
341   struct epoll_event event;
342
343   memset(&event, 0, sizeof(event));
344
345   event.events = 0;
346   event.data.ptr = sock;
347   return epoll_ctl(sel->_epoll_fd, EPOLL_CTL_ADD, sock->fd, &event);
348 }
349
350 /**
351  * Set the read status of a socket in a socket event handler
352  * @param sel socket event handler
353  * @param sock socket representation
354  * @param want_read true if socket should trigger read events,
355  *   false otherwise
356  * @return -1 if an error happened, 0 otherwise
357  */
358 static INLINE int
359 os_fd_event_socket_read(struct os_fd_select *sel, 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, 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 *sockfd, const union netaddr_socket *remote) {
458   return connect(sockfd->fd, &remote->std, sizeof(*remote));
459 }
460
461 /**
462  * Call posix accept()
463  * @param client storage for filedescriptor for incoming session
464  * @param server 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, 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 sockfd 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 *sockfd, int *value) {
487   socklen_t len = sizeof(*value);
488   return getsockopt(sockfd->fd, SOL_SOCKET, SO_ERROR, value, &len);
489 }
490
491 /**
492  * Sends data to an UDP socket.
493  * @param sock filedescriptor of UDP socket
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   if (dst) {
503     return sendto(sock->fd, buf, length, dont_route ? MSG_DONTROUTE : 0, &dst->std, sizeof(*dst));
504   }
505   else {
506     return send(sock->fd, buf, length, dont_route ? MSG_DONTROUTE : 0);
507   }
508 }
509
510 /**
511  * Receive data from an UDP socket.
512  * @param sockfd filedescriptor of UDP socket
513  * @param buf buffer for incoming data
514  * @param length length of buffer
515  * @param source pointer to netaddr socket object to store source of packet
516  * @param interf limit received data to certain interface
517  *   (only used if socket cannot be bound to interface)
518  * @return same as recvfrom()
519  */
520 static INLINE ssize_t
521 os_fd_recvfrom(struct os_fd *sockfd, void *buf, size_t length, union netaddr_socket *source,
522   const struct os_interface *interf __attribute__((unused))) {
523   socklen_t len = sizeof(*source);
524   if (source) {
525     return recvfrom(sockfd->fd, buf, length, 0, &source->std, &len);
526   }
527   else {
528     return recv(sockfd->fd, buf, length, 0);
529   }
530 }
531
532 /**
533  * Binds a socket to a certain interface
534  * @param sock filedescriptor of socket
535  * @param interf interface to bind the socket to
536  * @return -1 if an error happened, 0 otherwise
537  */
538 static INLINE int
539 os_fd_bindto_interface(struct os_fd *sock, struct os_interface *interf) {
540   return setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, interf->name, strlen(interf->name) + 1);
541 }
542
543 /**
544  * @return name of loopback interface
545  */
546 static INLINE const char *
547 os_fd_get_loopback_name(void) {
548   return "lo";
549 }
550
551 /**
552  * send data from one filedescriptor to another one. Linux compatible API
553  * structure, might need a bit of work for other OS.
554  * @param out destination file descriptor
555  * @param in source file descriptor
556  * @param offset offset where to start reading from source
557  * @param count number of bytes to copy
558  * @return -1 if an error happened, otherwise the number of bytes that
559  *   were sent to outfd
560  */
561 static INLINE ssize_t
562 os_fd_sendfile(struct os_fd *out, struct os_fd *in, size_t offset, size_t count) {
563   off_t int_offset = offset;
564   return sendfile(out->fd, in->fd, &int_offset, count);
565 }
566
567 #endif /* OS_FD_LINUX_H_ */