added lwes-filter-listener
[lwes.git] / src / lwes_net_functions.c
blob4b136ba9659eb9c5b303e7321f80c6c91a388182
1 /*======================================================================*
2 * Copyright (C) 2008 Light Weight Event System *
3 * All rights reserved. *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
18 * Boston, MA 02110-1301 USA. *
19 *======================================================================*/
20 #include "lwes_net_functions.h"
22 #include <string.h>
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 int
28 lwes_net_open
29 (struct lwes_net_connection *conn,
30 const char *address,
31 const char *iface,
32 int port)
34 int i;
35 int arg;
37 /* error out on a NULL connection */
38 if (conn == NULL)
40 return -1;
43 /* set up the address structure */
44 memset((char *) &conn->mcast_addr, 0, sizeof(conn->mcast_addr));
45 conn->mcast_addr.sin_family = AF_INET;
46 conn->mcast_addr.sin_addr.s_addr = inet_addr (address);
47 conn->mcast_addr.sin_port = htons ((short)port);
48 conn->hasJoined = 0;
50 /* and the multicast structure (which may not be used if this is a unicast
51 connection) */
52 conn->mreq.imr_multiaddr = conn->mcast_addr.sin_addr;
53 if ( iface == NULL || strcmp("",iface) == 0 )
55 conn->mreq.imr_interface.s_addr = htonl (INADDR_ANY);
57 else
59 conn->mreq.imr_interface.s_addr = inet_addr (iface);
62 /* construct the socket */
63 if ( (conn->socketfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0 )
65 return -2;
68 /* if the address we are emitting on is a multicast address we
69 set the sockopt which uses that interface to emit on, this doesn't
70 work for unicast */
71 if (IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
73 if (iface)
75 struct in_addr mcastAddr;
77 mcastAddr.s_addr = inet_addr (iface);
78 if (setsockopt(conn->socketfd, IPPROTO_IP, IP_MULTICAST_IF,
79 (char *)&mcastAddr, sizeof(mcastAddr)) < 0 )
81 return -3;
86 /* Setting the value for SO_SNDBF , trying for 10*MAX_MSG_SIZE */
87 for ( i = 10 ; i > 0 ; i-- )
89 arg = MAX_MSG_SIZE*i;
90 if (setsockopt (conn->socketfd, SOL_SOCKET, SO_SNDBUF,
91 (void*)&arg,sizeof(arg)) == 0)
93 break;
96 if ( i == 0 )
98 return -4;
101 /* set the size for use below */
102 conn->sender_ip_socket_size = (socklen_t)sizeof(conn->sender_ip_addr);
104 return 0;
108 lwes_net_close
109 (struct lwes_net_connection *conn)
111 if (conn == NULL)
113 return -1;
116 /* check hasJoined first, as we also "join" a unicast channel, so may
117 need to do cleanup here someday */
118 if ( conn->hasJoined == 1 )
120 /* if we are using a multicast address we need to drop the membership
121 so that upstream routers get the message */
122 if (IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
124 /* drop the multicast channel */
125 if (setsockopt
126 (conn->socketfd,
127 IPPROTO_IP,
128 IP_DROP_MEMBERSHIP,
129 (void*)&(conn->mreq),
130 sizeof(conn->mreq)) < 0 )
132 return -2;
137 return close(conn->socketfd);
141 lwes_net_get_ttl
142 (struct lwes_net_connection *conn)
144 if (conn != NULL)
146 unsigned char ttl = 0;
147 socklen_t len;
149 len = sizeof (ttl);
151 if (IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
153 if (getsockopt (conn->socketfd,
154 IPPROTO_IP,
155 IP_MULTICAST_TTL,
156 &ttl,
157 &len) < 0)
159 return -2;
163 return ttl;
166 return -1;
170 lwes_net_set_ttl
171 (struct lwes_net_connection *conn, int new_ttl)
173 if (conn != NULL)
175 unsigned char ttl;
177 ttl = new_ttl;
178 if (IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
180 if (setsockopt (conn->socketfd,
181 IPPROTO_IP,
182 IP_MULTICAST_TTL,
183 (void*)&ttl,
184 sizeof (ttl)) < 0)
186 return -2;
190 return 0;
193 return -1;
197 lwes_net_get_sock_fd
198 (struct lwes_net_connection *conn)
200 if (conn == NULL)
202 return -1;
204 return conn->socketfd;
208 lwes_net_send_bytes
209 (struct lwes_net_connection *conn,
210 LWES_BYTE_P bytes,
211 size_t len)
213 int size = 0;
215 if (conn == NULL || bytes == NULL)
217 return -1;
220 size =
221 sendto
222 (conn->socketfd,
223 bytes,
224 len,
226 (struct sockaddr * )&(conn->mcast_addr),
227 sizeof(conn->mcast_addr));
229 return size;
233 lwes_net_sendto_bytes
234 (struct lwes_net_connection *conn,
235 char *address,
236 char *iface,
237 int port,
238 LWES_BYTE_P bytes,
239 size_t len)
241 struct lwes_net_connection new_conn;
242 int size;
244 if (conn == NULL || bytes == NULL)
246 return -1;
249 if (lwes_net_open (&new_conn, address, iface, port) < 0)
251 return -2;
254 if ((size = lwes_net_send_bytes (&new_conn, bytes, len)) < 0)
256 return -3;
259 /* There's not much we can do about a close error, and it would mask a
260 successful send, so just ignore a bad return value */
261 (void) lwes_net_close (&new_conn);
263 return size;
267 lwes_net_recv_bind
268 (struct lwes_net_connection *conn)
270 int arg = -1;
272 if (conn == NULL)
274 return -1;
277 if ( conn->hasJoined != 1 )
279 int i = 0;
281 /* set a socket option such that the socket can be reused */
282 if ( setsockopt (conn->socketfd,
283 SOL_SOCKET,
284 SO_REUSEADDR,
285 (void*)&arg,
286 sizeof(arg)) < 0 )
288 return -2;
291 /* try for as big a buffer as possible, start at 100*MAX_MSG_SIZE
292 * and work down, if you can't get a buffer of at least one max
293 * message, error out */
294 for ( i = 100 ; i > 0 ; i-- )
296 arg = MAX_MSG_SIZE*i;
297 if (setsockopt(conn->socketfd, SOL_SOCKET, SO_RCVBUF,
298 (void*)&arg,sizeof(arg)) == 0)
300 break;
303 if ( i == 0 )
305 return -3;
308 /* if we are not in a multicast connection, then the address we are
309 using to receive on will be wrong, so we will have to set
310 it to INADDR_ANY */
311 if (!IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
313 conn->mcast_addr.sin_addr.s_addr = htonl (INADDR_ANY);
314 conn->hasJoined = 1;
317 /* bind to the socket */
318 if (bind (conn->socketfd,
319 (struct sockaddr * )&(conn->mcast_addr),
320 sizeof(conn->mcast_addr) ) < 0 )
322 return -4;
325 /* add the multicast channel given */
326 if (IN_MULTICAST (ntohl (conn->mcast_addr.sin_addr.s_addr)))
328 if (setsockopt (conn->socketfd,
329 IPPROTO_IP,
330 IP_ADD_MEMBERSHIP,
331 (void*)&(conn->mreq),
332 sizeof(conn->mreq)) < 0 )
334 return -5;
336 conn->hasJoined = 1;
340 return 0;
344 lwes_net_recv_bytes
345 (struct lwes_net_connection *conn,
346 LWES_BYTE_P bytes,
347 size_t len)
349 int ret = 0;
350 int flags = 0;
352 if (conn == NULL || bytes == NULL)
354 return -1;
357 if ( (ret = lwes_net_recv_bind (conn)) < 0)
359 return ret;
362 ret = recvfrom (conn->socketfd,
363 bytes,
364 len,
365 flags,
366 (struct sockaddr *)&(conn->sender_ip_addr),
367 (socklen_t *)&(conn->sender_ip_socket_size));
368 return ret;
372 lwes_net_recv_bytes_by
373 (struct lwes_net_connection *conn,
374 LWES_BYTE_P bytes,
375 size_t len,
376 unsigned int timeout_ms)
378 int ret = 0;
379 int flags = 0;
380 struct timeval timeout;
381 fd_set read_sel;
383 if (conn == NULL || bytes == NULL)
385 return -1;
388 if ((ret = lwes_net_recv_bind (conn)) < 0)
390 return ret;
393 timeout.tv_sec=timeout_ms/1000;
394 timeout.tv_usec=(timeout_ms%1000)*1000;
396 FD_ZERO(&read_sel);
397 FD_SET(conn->socketfd, &read_sel);
399 /* Just wait once, as we *should* get the packet as a chunk */
400 ret = select (conn->socketfd+1, &read_sel, NULL, NULL, &timeout);
401 if (ret <= 0)
403 return -2;
406 ret = recvfrom (conn->socketfd,
407 bytes,
408 len,
409 flags,
410 (struct sockaddr *)&(conn->sender_ip_addr),
411 (socklen_t *)&(conn->sender_ip_socket_size));
412 return ret;