Refactoring of olsr_interface data to if_index instead of name
[oonf.git] / src-api / core / os_net_generic.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2012, 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 <errno.h>
43 #include <fcntl.h>
44
45 #include "common/common_types.h"
46 #include "common/netaddr.h"
47 #include "common/string.h"
48 #include "olsr_logging.h"
49 #include "olsr_interface.h"
50 #include "os_net.h"
51
52 #if OS_NET_CONFIGSOCKET == OS_GENERIC
53 /**
54  * Configure a network socket
55  * @param sock filedescriptor
56  * @param bindto ip/port to bind the socket to
57  * @param flags type of socket (udp/tcp, blocking, multicast)
58  * @param recvbuf size of input buffer for socket
59  * @param log_src logging source for error messages
60  * @return -1 if an error happened, 0 otherwise
61  */
62 int
63 os_net_configsocket(int sock, union netaddr_socket *bindto,
64     enum olsr_socket_opt flags, int recvbuf,
65     enum log_source log_src __attribute__((unused))) {
66   int yes;
67   socklen_t addrlen;
68
69 #if !defined(REMOVE_LOG_WARN)
70   struct netaddr_str buf;
71 #endif
72
73   if ((flags & OS_SOCKET_BLOCKING) == 0) {
74     if (os_net_set_nonblocking(sock)) {
75       return 0;
76     }
77   }
78
79 #if defined(SO_REUSEADDR)
80   /* allow to reuse address */
81   yes = 1;
82   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
83     OLSR_WARN(log_src, "Cannot reuse address for %s: %s (%d)\n",
84         netaddr_socket_to_string(&buf, bindto), strerror(errno), errno);
85     return -1;
86   }
87 #endif
88
89 #if defined(IP_RECVIF)
90   if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, (char *)&yes, sizeof(yes)) < 0) {
91     OLSR_WARN(log_src, "Cannot apply IP_RECVIF for %s: %s (%d)\n",
92         netaddr_socket_to_string(&buf, bindto), strerror(errno), errno);
93     return -1;
94   }
95 #endif
96
97 #if defined(SO_RCVBUF)
98   if (recvbuf > 0) {
99     while (recvbuf > 8192) {
100       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
101           (char *)&recvbuf, sizeof(recvbuf)) == 0) {
102         break;
103       }
104
105       recvbuf -= 1024;
106     }
107
108     if (recvbuf < 8192) {
109       OLSR_WARN(log_src, "Cannot setup receive buffer size for %s: %s (%d)\n",
110           netaddr_socket_to_string(&buf, bindto), strerror(errno), errno);
111       return -1;
112     }
113   }
114 #endif
115
116   if ((flags & OS_SOCKET_MULTICAST) != 0) {
117 #ifdef SO_BROADCAST
118     if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0) {
119       OLSR_WARN(log_src, "Cannot setup SO_BROADCAST for %s: %s (%d)\n",
120           netaddr_socket_to_string(&buf, bindto), strerror(errno), errno);
121       return -1;
122     }
123 #endif
124   }
125
126   /* bind the socket to the port number */
127   addrlen = sizeof(*bindto);
128   if (bind(sock, &bindto->std, addrlen) < 0) {
129     OLSR_WARN(log_src, "Cannot bind socket to %s: %s (%d)\n",
130         netaddr_socket_to_string(&buf, bindto), strerror(errno), errno);
131     return -1;
132   }
133   return 0;
134 }
135 #endif
136
137 #if OS_NET_GETSOCKET == OS_GENERIC
138 /**
139  * Creates a new socket and configures it
140  * @param bindto address to bind the socket to
141  * @param flags type of socket (udp/tcp, blocking, multicast)
142  * @param recvbuf size of input buffer for socket
143  * @param log_src logging source for error messages
144  * @return socket filedescriptor, -1 if an error happened
145  */
146 int
147 os_net_getsocket(union netaddr_socket *bindto,
148     enum olsr_socket_opt flags, int recvbuf,
149     enum log_source log_src __attribute__((unused))) {
150
151   int sock;
152
153   sock = socket(bindto->std.sa_family,
154       ((flags & OS_SOCKET_TCP) != 0)? SOCK_STREAM : SOCK_DGRAM, 0);
155   if (sock < 0) {
156     OLSR_WARN(log_src, "Cannot open socket: %s (%d)", strerror(errno), errno);
157     return -1;
158   }
159
160   if (os_net_configsocket(sock, bindto, flags, recvbuf, log_src)) {
161     os_close(sock);
162     return -1;
163   }
164   return sock;
165 }
166 #endif
167
168 #if OS_NET_JOINMCAST == OS_GENERIC
169 /**
170  * Join a socket into a multicast group
171  * @param sock filedescriptor of socket
172  * @param multicast multicast ip/port to join
173  * @param oif pointer to outgoing interface data for multicast
174  * @param log_src logging source for error messages
175  * @return -1 if an error happened, 0 otherwise
176  */
177 int
178 net_os_join_mcast(int sock, union netaddr_socket *multicast,
179     struct olsr_interface *oif,
180     enum log_source log_src __attribute__((unused))) {
181 #if !defined (REMOVE_LOG_DEBUG)
182   struct netaddr_str buf1, buf2;
183 #endif
184   struct ip_mreq   v4_mreq;
185   struct ipv6_mreq v6_mreq;
186   char p;
187
188   if (multicast->std.sa_family == AF_INET) {
189     OLSR_DEBUG(log_src,
190         "Socket on interface %s joining multicast %s (src %s)\n",
191         oif->data.name,
192         netaddr_socket_to_string(&buf2, multicast),
193         netaddr_to_string(&buf1, &oif->data.if_v4));
194
195     v4_mreq.imr_multiaddr = multicast->v4.sin_addr;
196     netaddr_to_binary(&v4_mreq.imr_interface, &oif->data.if_v4, 4);
197
198     if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
199         &v4_mreq, sizeof(v4_mreq)) < 0) {
200       OLSR_WARN(log_src, "Cannot join multicast group: %s (%d)\n", strerror(errno), errno);
201       return -1;
202     }
203
204     if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, oif->data.if_v4.addr, 4) < 0) {
205       OLSR_WARN(log_src, "Cannot set multicast interface: %s (%d)\n",
206           strerror(errno), errno);
207       return -1;
208     }
209
210     p = 0;
211     if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&p, sizeof(p)) < 0) {
212       OLSR_WARN(log_src, "Cannot deactivate local loop of multicast interface: %s (%d)\n",
213           strerror(errno), errno);
214       return -1;
215     }
216   }
217   else {
218     OLSR_DEBUG(log_src,
219         "Socket on interface %s joining multicast %s (src %s)\n",
220         oif->data.name,
221         netaddr_socket_to_string(&buf2, multicast),
222         netaddr_to_string(&buf1, &oif->data.linklocal_v6));
223
224     v6_mreq.ipv6mr_multiaddr = multicast->v6.sin6_addr;
225     v6_mreq.ipv6mr_interface = oif->data.index;
226
227     /* Send multicast */
228     if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
229         &v6_mreq, sizeof(v6_mreq)) < 0) {
230       OLSR_WARN(log_src, "Cannot join multicast group: %s (%d)\n",
231           strerror(errno), errno);
232       return -1;
233     }
234     if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
235         &oif->data.index, sizeof(oif->data.index)) < 0) {
236       OLSR_WARN(log_src, "Cannot set multicast interface: %s (%d)\n",
237           strerror(errno), errno);
238       return -1;
239     }
240     p = 0;
241     if(setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&p, sizeof(p)) < 0) {
242       OLSR_WARN(log_src, "Cannot deactivate local loop of multicast interface: %s (%d)\n",
243           strerror(errno), errno);
244       return -1;
245     }
246   }
247   return 0;
248 }
249 #endif
250
251 #if OS_NET_SETNONBLOCK == OS_GENERIC
252 /**
253  * Set a socket to non-blocking mode
254  * @param sock filedescriptor of socket
255  * @return -1 if an error happened, 0 otherwise
256  */
257 int
258 os_net_set_nonblocking(int sock) {
259   int state;
260
261   /* put socket into non-blocking mode */
262   if ((state = fcntl(sock, F_GETFL)) == -1) {
263     return -1;
264   }
265
266   if (fcntl(sock, F_SETFL, state | O_NONBLOCK) < 0) {
267     return -1;
268   }
269   return 0;
270 }
271 #endif
272
273 // TODO: use recvmsg and PKTINFO to get source interface and destination IP
274 /**
275  * Receive data from an UDP socket.
276  * @param fd filedescriptor
277  * @param buf buffer for incoming data
278  * @param length length of buffer
279  * @param source pointer to netaddr socket object to store source of packet
280  * @return same as recvfrom()
281  */
282 int
283 os_recvfrom(int fd, void *buf, size_t length, union netaddr_socket *source) {
284   socklen_t sock_len;
285
286   sock_len = sizeof(*source);
287   return recvfrom(fd, buf, length, 0, &source->std, &sock_len);
288 }
289
290 // TODO: use sendmsg and PKTINFO to define outgoing source IP and interface
291 /**
292  * Sends data to an UDP socket.
293  * @param fd filedescriptor
294  * @param buf buffer for target data
295  * @param length length of buffer
296  * @param dst pointer to netaddr socket to send packet to
297  * @return same as sendto()
298  */
299 int
300 os_sendto(int fd, const void *buf, size_t length, union netaddr_socket *dst) {
301   return sendto(fd, buf, length, 0, &dst->std, sizeof(*dst));
302 }