1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
5 /* Universidad de Cantabria, SPAIN */
6 /* University of York, UK */
7 /* Scuola Superiore Sant'Anna, ITALY */
8 /* Kaiserslautern University, GERMANY */
9 /* Univ. Politécnica Valencia, SPAIN */
10 /* Czech Technical University in Prague, CZECH REPUBLIC */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
19 /* FRESCOR project (FP6/2005/IST/5-034026) is funded */
20 /* in part by the European Union Sixth Framework Programme */
21 /* The European Union is not liable of any use that may be */
22 /* made of this code. */
25 /* This file is part of FORB (Frescor Object Request Broker) */
27 /* FORB is free software; you can redistribute it and/or modify it */
28 /* under terms of the GNU General Public License as published by the */
29 /* Free Software Foundation; either version 2, or (at your option) any */
30 /* later version. FORB is distributed in the hope that it will be */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
33 /* General Public License for more details. You should have received a */
34 /* copy of the GNU General Public License along with FORB; see file */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
36 /* Cambridge, MA 02139, USA. */
38 /* As a special exception, including FORB header files in a file, */
39 /* instantiating FORB generics or templates, or linking other files */
40 /* with FORB objects to produce an executable application, does not */
41 /* by itself cause the resulting executable application to be covered */
42 /* by the GNU General Public License. This exception does not */
43 /* however invalidate any other reasons why the executable file might be */
44 /* covered by the GNU Public License. */
45 /**************************************************************************/
48 #include <arpa/inet.h>
51 #include <forb/proto_inet.h>
53 #include <netinet/in.h>
55 #include <sys/epoll.h>
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
58 #include <sys/types.h>
64 * @author Michal Sojka <sojkam1@fel.cvut.cz>
65 * @date Sun Oct 12 16:10:23 2008
67 * @brief FORB transport protocol based on INET family sockets.
69 * UDP is used for broadcasts and TCP for requests/replies. There
70 * exist two uni-drectional connections between any two communicating
74 extern UL_LOG_CUST(ulogd_forb_proto_inet);
77 #define MCAST_ADDR "225.15.5.14"
79 /** Address used by inet protocol. */
84 /** INET protocol data for ports. */
86 int udp_socket; /**< Socket for sending and receiving broadcasts */
87 int listen_socket; /* */
88 int epoll_fd; /**< File descriptor used by epoll() in inet_receive(). */
89 struct inet_addr addr; /**< Address of this port */
90 int last_recv_fd; /**< Used in inet_recv() to read data longer than receiving buffer */
91 struct in_addr multicast_addr;
94 /** INET protocol data associated with every peer */
96 int socket; /**< Connected socket to the peer */
99 /* static struct inet_port* */
100 /* peer_to_inet_port(forb_peer_t *peer) { return peer->port->desc.proto_priv; } */
103 inet_serialize_addr(FORB_CDR_Codec *codec, const void *addr)
105 const struct inet_addr *a = addr;
106 CORBA_long haddr = ntohl(a->addr.s_addr);
107 return CORBA_long_serialize(codec, &haddr);
111 inet_deserialize_addr(FORB_CDR_Codec *codec, void **addr)
117 a = forb_malloc(sizeof(*a));
120 ret = CORBA_long_deserialize(codec, &s_addr);
121 a->addr.s_addr = htonl(s_addr);
126 static struct inet_peer *
127 inet_connect(forb_peer_t *peer)
129 struct inet_peer *ipeer;
130 struct sockaddr_in sa;
131 struct inet_addr *addr = peer->addr;
136 ipeer = forb_malloc(sizeof(*ipeer));
139 ipeer->socket = socket(PF_INET, SOCK_STREAM, 0);
142 sa.sin_family = AF_INET;
143 sa.sin_port = htons(PORT);
144 sa.sin_addr = addr->addr;
145 ret = connect(ipeer->socket, (struct sockaddr*)&sa, sizeof(sa));
151 close(ipeer->socket);
160 inet_send(forb_peer_t *peer, const void *buf, size_t len)
162 struct inet_peer *ipeer = peer->proto_priv;
165 ipeer = inet_connect(peer);
168 peer->proto_priv = ipeer;
172 return send(ipeer->socket, buf, len, 0);
175 /*----------------------------------------------------------------------
176 Portable function to set a socket into nonblocking mode.
177 Calling this on a socket causes all future read() and write() calls on
178 that socket to do only as much as they can immediately, and return
180 If no data can be read or written, they return -1 and set errno
181 to EAGAIN (or EWOULDBLOCK).
182 Thanks to Bjorn Reese for this code.
183 ----------------------------------------------------------------------*/
184 int setnonblocking(int fd)
188 /* If they have O_NONBLOCK, use the Posix way to do it */
189 #if defined(O_NONBLOCK)
190 /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
191 if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
193 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
195 /* Otherwise, use the old way of doing it */
197 return ioctl(fd, FIOBIO, &flags);
201 int inet_accept_connection(struct inet_port *p)
204 struct sockaddr_in addr;
206 struct epoll_event ev;
209 client = accept(p->listen_socket, (struct sockaddr *) &addr, &addrlen);
214 ret = setnonblocking(client);
219 ev.events = EPOLLIN | EPOLLET;
221 return epoll_ctl(p->epoll_fd, EPOLL_CTL_ADD, client, &ev);
225 inet_recv(forb_port_t *port, void *buf, size_t len)
227 struct inet_port *iport = port->desc.proto_priv;
229 struct epoll_event ev;
232 if (iport->last_recv_fd == -1) {
233 nfds = epoll_wait(iport->epoll_fd, &ev, 1, -1);
236 if (ev.data.fd == iport->listen_socket) {
237 ret = inet_accept_connection(iport);
243 iport->last_recv_fd = ev.data.fd;
246 ret = recv(iport->last_recv_fd, buf, len, 0);
247 if (ret == -1 && errno == EAGAIN) {
248 iport->last_recv_fd = -1;
254 return recv(iport->udp_socket, buf, len, 0);
259 inet_port_destroy(forb_port_t * port)
261 struct inet_port *pd = port->desc.proto_priv;
263 close(pd->udp_socket);
264 close(pd->listen_socket);
270 inet_broadcast(forb_port_t *port, const void *buf, size_t len)
272 struct inet_port *p = port->desc.proto_priv;
273 struct sockaddr_in addr;
276 addr.sin_family = AF_INET;
277 addr.sin_port = htons(PORT);
278 addr.sin_addr = p->multicast_addr;
280 ret = sendto(p->udp_socket, buf, len, 0,
281 (struct sockaddr*)&addr, sizeof(addr));
286 inet_peer_destroy(forb_peer_t *peer)
288 struct inet_peer *ipeer = peer->proto_priv;
289 peer->proto_priv = NULL;
290 close(ipeer->socket);
294 static const forb_proto_t proto_inet = {
295 .hello_interval = 40 /* seconds */,
296 .port_destroy = inet_port_destroy,
297 .peer_destroy = inet_peer_destroy,
300 .broadcast = inet_broadcast,
301 .serialize_addr = inet_serialize_addr,
302 .deserialize_addr = inet_deserialize_addr,
305 #define MAX_INTERFACES 10
306 int get_local_address(int sock, struct inet_addr *addr)
309 struct ifreq *ifr, req[MAX_INTERFACES];
312 ifc.ifc_len = sizeof(req);
315 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
317 for (ifr = req; ifr < &req[MAX_INTERFACES]; ifr++) {
318 struct sockaddr_in ia;
319 memcpy(&ia, &ifr->ifr_addr, sizeof(ia));
320 ioctl(sock, SIOCGIFFLAGS, ifr);
321 if ((ifr->ifr_flags & IFF_UP) && !(ifr->ifr_flags & IFF_LOOPBACK)) {
322 addr->addr = ia.sin_addr;
330 * Initializes INET protocol port.
332 * @param port_desc Port description to initialize.
333 * @return Zero on success, -1 on error and errno is set
337 forb_inet_port_init(struct forb_port_desc *port_desc, struct in_addr listen_on)
341 struct inet_port *port_priv;
342 struct sockaddr_in addr;
344 struct epoll_event ev;
346 port_priv = forb_malloc(sizeof(*port_priv));
350 memset(port_priv, 0, sizeof(*port_priv));
351 port_priv->last_recv_fd = -1;
353 port_priv->udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
354 if (port_priv->udp_socket == -1) goto err_free;
355 port_priv->listen_socket = socket(PF_INET, SOCK_STREAM, 0);
356 if (port_priv->listen_socket == -1) goto err_close_udp;
359 ret = setsockopt(port_priv->udp_socket, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
361 goto err_close_listen;
363 addr.sin_family = AF_INET;
364 addr.sin_port = htons(PORT);
365 addr.sin_addr = listen_on;
367 ret = bind(port_priv->listen_socket, (struct sockaddr *)&addr, sizeof(addr));
368 if (ret != 0) goto err_close_listen;
369 if (setnonblocking(port_priv->listen_socket))
370 goto err_close_listen;
372 ret = bind(port_priv->udp_socket, (struct sockaddr *)&addr, sizeof(addr));
373 if (ret != 0) goto err_close_listen;
374 setnonblocking(port_priv->udp_socket);
375 inet_aton(MCAST_ADDR, &port_priv->multicast_addr);
377 mreq.imr_multiaddr = port_priv->multicast_addr;
378 mreq.imr_interface.s_addr = INADDR_ANY;
379 ret = setsockopt(port_priv->udp_socket, IPPROTO_IP,
380 IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
382 goto err_close_listen;
385 unsigned loop_size = sizeof(loop);
386 ret = setsockopt(port_priv->udp_socket, IPPROTO_IP,
387 IP_MULTICAST_LOOP, &loop, loop_size);
389 goto err_close_listen;
392 ret = listen(port_priv->listen_socket, 10);
394 goto err_close_listen;
397 ret = getsockname(port_priv->listen_socket, (struct sockaddr *)&addr, &len);
399 ul_logerr("Non-loopback inet address not found\n");
400 goto err_close_listen;
403 port_priv->epoll_fd = epoll_create(10);
404 if (port_priv->epoll_fd == -1)
405 goto err_close_listen;
407 memset(&ev, 0, sizeof(ev));
408 ev.events = EPOLLIN | EPOLLET;
409 ev.data.fd = port_priv->listen_socket;
410 ret = epoll_ctl(port_priv->epoll_fd, EPOLL_CTL_ADD,
411 port_priv->listen_socket, &ev);
413 goto err_close_epoll;
415 ev.events = EPOLLIN | EPOLLET;
416 ev.data.fd = port_priv->udp_socket;
417 ret = epoll_ctl(port_priv->epoll_fd, EPOLL_CTL_ADD,
418 port_priv->udp_socket, &ev);
420 goto err_close_epoll;
422 if (listen_on.s_addr == INADDR_ANY)
423 get_local_address(port_priv->listen_socket, &port_priv->addr);
425 port_priv->addr.addr = listen_on;
428 port_desc->proto = &proto_inet;
429 port_desc->proto_priv = port_priv;
430 port_desc->addr = &port_priv->addr;
433 close(port_priv->epoll_fd);
436 close(port_priv->listen_socket);
440 close(port_priv->udp_socket);
444 forb_free(port_priv);