]> rtime.felk.cvut.cz Git - frescor/forb.git/blob - src/proto_inet.c
forb: Do not compile inet_broadcast if it is not used
[frescor/forb.git] / src / proto_inet.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
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                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
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.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FORB (Frescor Object Request Broker)             */
26 /*                                                                        */
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.                                              */
37 /*                                                                        */
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 /**************************************************************************/
46
47 #include "proto.h"
48 #include <arpa/inet.h>
49 #include <dirent.h>
50 #include <fcntl.h>
51 #include <forb/proto_inet.h>
52 #include <net/if.h>
53 #include <netinet/in.h>
54 #include <stdio.h>
55 #include <sys/epoll.h>
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
58 #include <sys/types.h>
59 #include <ul_log.h>
60 #include <unistd.h>
61 #include <forb/config.h>
62 #include "discovery.h"
63 #include <stdlib.h>
64 #include <netinet/tcp.h>
65 #include "iop.h" /* FIXME: Sending hello should be handled in IOP layer */
66
67 /**
68  * @file   proto_inet.c
69  * @author Michal Sojka <sojkam1@fel.cvut.cz>
70  * @date   Sun Oct 12 16:10:23 2008
71  * 
72  * @brief  FORB transport protocol based on INET family sockets.
73  * 
74  * UDP is used for broadcasts and TCP for requests/replies. There
75  * exist two uni-drectional connections between any two communicating
76  * peers.
77  */
78
79 extern UL_LOG_CUST(ulogd_forb_proto_inet);
80
81 #define MCAST_PORT 15514        /**< Port used for multicasts */
82 #define MCAST_ADDR "225.15.5.14"
83
84 /** Address used by inet protocol. All values are stored in network
85  * byte order. */
86 struct inet_addr {
87         struct in_addr addr;
88         uint16_t port;          /**< TCP listening port */
89 };
90
91 /** INET protocol data for ports. */
92 struct inet_port {
93         int udp_socket;         /**< Socket for sending and receiving broadcasts */
94         int listen_socket;      /*  */
95         int epoll_fd;           /**< File descriptor used by epoll() in inet_receive(). */
96         struct inet_addr addr;  /**< Address of this port */
97         int last_recv_fd;       /**< Used in inet_recv() to read data longer than receiving buffer */
98         struct in_addr multicast_addr;
99         ul_list_head_t new_peers; /**< List of just connected peers which did not send any data yet. */
100 };
101
102 UL_LIST_CUST_DEC(inet_port_new_peer, /* cust_prefix */
103                  struct inet_port,   /* cust_head_t */
104                  forb_peer_t,        /* cust_item_t */
105                  new_peers,          /* cust_head_field */
106                  lnode)              /* cust_node_field */
107
108
109 /** INET protocol data associated with every peer */
110 struct inet_peer {
111         int socket;             /**< Connected socket to the peer */
112 };
113
114 /* static struct inet_port* */
115 /* peer_to_inet_port(forb_peer_t *peer) { return peer->port->desc.proto_priv; } */
116
117 static CORBA_boolean
118 inet_serialize_addr(FORB_CDR_Codec *codec, const void *addr)
119 {
120         const struct inet_addr *a = addr;
121         CORBA_unsigned_long haddr = ntohl(a->addr.s_addr);
122         CORBA_unsigned_short hport = ntohs(a->port);
123         CORBA_boolean ret;
124         ret = CORBA_unsigned_long_serialize(codec, &haddr);
125         if (!ret)
126                 return ret;
127         return CORBA_unsigned_short_serialize(codec, &hport);
128 }
129
130 static CORBA_boolean
131 inet_deserialize_addr(FORB_CDR_Codec *codec, void **addr)
132 {
133         struct inet_addr *a;
134         CORBA_unsigned_long s_addr;
135         CORBA_unsigned_short port;
136         CORBA_boolean ret;
137
138         a = forb_malloc(sizeof(*a));
139         if (!a)
140                 return CORBA_FALSE;
141         ret = CORBA_unsigned_long_deserialize(codec, &s_addr);
142         if (!ret)
143                 return ret;
144         ret = CORBA_unsigned_short_deserialize(codec, &port);
145         a->addr.s_addr = htonl(s_addr);
146         a->port = htons(port);
147         *addr = a;
148         return ret;
149 }
150
151 static int
152 setnonblocking(int fd);
153
154 static int
155 setnodelay(int fd)
156 {
157         int ret = 0;
158 #if 0                           /* For nice graphs in benchmarks */
159         int yes = 1;
160         ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
161         if (ret < 0) {
162                 ul_logerr("setsockopt(TCP_NODELAY): %s\n", strerror(errno));
163         }
164 #endif
165         return ret;
166         
167 }
168
169 static int
170 inet_connect(forb_peer_t *peer)
171 {
172         struct inet_peer *ipeer;
173         struct sockaddr_in sa;
174         struct inet_addr *addr = peer->addr;
175         int ret;
176
177         if (!addr) {
178                 ul_logerr("No address to connect\n");
179                 goto err;
180         }
181         ipeer = forb_malloc(sizeof(*ipeer));
182         if (!ipeer)
183                 goto err;
184         ipeer->socket = socket(PF_INET, SOCK_STREAM, 0);
185         if (!ipeer->socket) {
186                 ul_logerr("socket(): %s\n", strerror(errno));
187                 goto err_free;
188         }
189         sa.sin_family = AF_INET;
190         sa.sin_port = addr->port;
191         sa.sin_addr = addr->addr;
192         ul_logtrash("connect to %s:%u\n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
193         ret = connect(ipeer->socket, (struct sockaddr*)&sa, sizeof(sa));
194         if (ret) {
195                 ul_logerr("connect error: %s\n", strerror(errno));
196                 goto err_close;
197         }
198
199         setnonblocking(ipeer->socket);
200         setnodelay(ipeer->socket);
201
202         struct epoll_event ev;
203         struct inet_port *p = peer->port->desc.proto_priv;
204         memset(&ev, 0, sizeof(ev));
205         ev.events = EPOLLIN | EPOLLET;
206         ev.data.fd = ipeer->socket;
207         ret = epoll_ctl(p->epoll_fd, EPOLL_CTL_ADD, ipeer->socket, &ev);
208         if (ret) {
209                 ul_logerr("epoll_ctl on connect failed: %s\n", strerror(errno));
210                 goto err_close;
211         }
212
213         peer->proto_priv = ipeer;
214
215 #ifndef TEST /* FIXME: Move hello to IOP, introduce proto connect callback */
216         ret = forb_iop_send_hello_to(peer);
217         if (ret) {
218                 goto err_close;
219         }
220 #endif
221
222         return 0;
223 err_close:
224         close(ipeer->socket);
225 err_free:
226         forb_free(ipeer);
227 err:
228         return -1;
229         
230 }
231
232 static ssize_t
233 inet_send(forb_peer_t *peer, const void *buf, size_t len)
234 {
235         struct inet_peer *ipeer = peer->proto_priv;
236         ssize_t ret, sent;
237
238         if (!ipeer) {
239                 ret = inet_connect(peer);
240                 if (ret) {
241                         return ret;
242                 }
243                 ipeer = peer->proto_priv;
244         }
245
246         sent = 0;
247         ul_logtrash("send fd=%d len=%zu\n", ipeer->socket, len);
248         do {
249                 ret = send(ipeer->socket, buf, len, 0);
250                 if (ret < 0) {
251                         ul_logerr("send error: %s\n", strerror(errno));
252                         return ret;
253                 }
254                 sent += ret;
255                 buf += ret;
256                 len -= ret;
257         } while (len > 0);
258
259         return sent;
260 }
261
262 /*----------------------------------------------------------------------
263  Portable function to set a socket into nonblocking mode.
264  Calling this on a socket causes all future read() and write() calls on
265  that socket to do only as much as they can immediately, and return 
266  without waiting.
267  If no data can be read or written, they return -1 and set errno
268  to EAGAIN (or EWOULDBLOCK).
269  Thanks to Bjorn Reese for this code.
270 ----------------------------------------------------------------------*/
271 int setnonblocking(int fd)
272 {
273     int flags;
274
275     /* If they have O_NONBLOCK, use the Posix way to do it */
276 #if defined(O_NONBLOCK)
277     /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
278     if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
279         flags = 0;
280     return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
281 #else
282     /* Otherwise, use the old way of doing it */
283     flags = 1;
284     return ioctl(fd, FIOBIO, &flags);
285 #endif
286 }     
287
288 static int
289 inet_accept_connection(forb_port_t *port)
290 {
291         struct inet_port *p = port->desc.proto_priv;
292         int client;
293         struct sockaddr_in addr;
294         socklen_t addrlen = sizeof(addr);
295         struct epoll_event ev;
296         int ret;
297         forb_peer_t *peer;
298                                 
299         client = accept(p->listen_socket, (struct sockaddr *) &addr, &addrlen);
300         if (client < 0){
301                 //perror("accept");
302                 return -1;
303         }
304         ret = setnonblocking(client);
305         if (ret) {
306                 close(client);
307                 return -1;
308         }
309         setnodelay(client);
310
311         peer = forb_peer_new();
312         if (peer) {
313                 struct inet_peer *ipeer;
314
315                 ipeer = forb_malloc(sizeof(*ipeer));
316                 if (ipeer) {
317                         ipeer->socket = client;
318                         peer->proto_priv = ipeer;
319                         peer->port = port;
320                         peer->state = FORB_PEER_DISCOVERED;
321                         inet_port_new_peer_insert(p, peer);
322                 } else {
323                         forb_peer_put(peer);
324                 }
325         }
326         
327         memset(&ev, 0, sizeof(ev));
328         ev.events = EPOLLIN | EPOLLET;
329         ev.data.fd = client;
330         return epoll_ctl(p->epoll_fd, EPOLL_CTL_ADD, client, &ev);
331 }
332
333 static ssize_t
334 inet_recv(forb_port_t *port, void *buf, size_t len)
335 {
336         struct inet_port *iport = port->desc.proto_priv;
337 #if 1
338         struct epoll_event ev;
339         ssize_t ret;
340         int nfds;
341         forb_peer_t *peer;
342         bool exported_new_peer = false;
343         
344         for (;;) {
345                 if (iport->last_recv_fd == -1) {
346                         nfds = epoll_wait(iport->epoll_fd, &ev, 1, -1);
347                         if (nfds == -1 && errno == EINTR)
348                                 continue;
349                         if (nfds < 1)
350                                 return -1;
351                         if (ev.data.fd == iport->listen_socket) {
352                                 ret = inet_accept_connection(port);
353                                 if (ret) {
354                                         ul_logerr("inet_accept_connection error: %s\n", strerror(errno));
355                                         return -1;
356                                 } else
357                                         continue;
358                         } else {
359                                 iport->last_recv_fd = ev.data.fd;
360                         }
361                 }
362                 /* Check for first reception form a just connected peer */
363                 ul_list_for_each(inet_port_new_peer, iport, peer) {
364                         struct inet_peer *ipeer = peer->proto_priv;
365                         //printf("checking new peer with fd=%d\n", ipeer->socket);
366                         if (ipeer->socket == iport->last_recv_fd) {
367                                 inet_port_new_peer_delete(iport, peer);
368
369                                 if (port->new_peer) forb_peer_put(peer);
370
371                                 /* Let the upper layer assign forb ID
372                                  * to this peer according to the request*/
373                                 port->new_peer = peer;
374                                 exported_new_peer = true;
375                                 break;
376                         }
377                 }
378
379                 //printf("recv fd=%d\n", iport->last_recv_fd);
380                 ret = recv(iport->last_recv_fd, buf, len, 0);
381                 if (ret == -1) {
382                         if (exported_new_peer) {
383                                 forb_peer_put(peer);
384                                 port->new_peer = NULL;
385                         }
386                         if (errno != EAGAIN) {
387                                 ul_logerr("recv fd=%d error: %s\n", iport->last_recv_fd, strerror(errno));
388                         }
389                         iport->last_recv_fd = -1;
390                         continue;
391                 }
392                 if (ret == 0) {
393                         if (exported_new_peer) {
394                                 forb_peer_put(peer);
395                                 port->new_peer = NULL;
396                         }
397                         ul_logtrash("recv fd=%d disconnect\n", iport->last_recv_fd);
398                         ul_list_for_each(forb_port_peer, port, peer) {
399                                 struct inet_peer *ipeer = peer->proto_priv;
400                                 if (ipeer && ipeer->socket == iport->last_recv_fd) {
401                                         forb_peer_disconnected(peer);
402                                         break;
403                                 }
404                         }
405                         iport->last_recv_fd = -1;
406                         continue;
407                 }
408                 ul_logtrash("recv fd=%d len=%zd\n", iport->last_recv_fd, ret);
409                 return ret;
410         }
411 #else
412         return recv(iport->udp_socket, buf, len, 0);    
413 #endif
414 }
415
416 static int
417 inet_port_destroy(forb_port_t * port)
418 {
419         struct inet_port *pd = port->desc.proto_priv;
420         close(pd->epoll_fd);
421         close(pd->udp_socket);
422         close(pd->listen_socket);
423         forb_free(pd);
424         return 0;
425 }
426
427 #ifndef CONFIG_FORB_PROTO_INET_DEFAULT
428 static ssize_t
429 inet_broadcast(forb_port_t *port, const void *buf, size_t len)
430 {
431         struct inet_port *p = port->desc.proto_priv;
432         struct sockaddr_in addr;
433         ssize_t ret;
434         
435         addr.sin_family = AF_INET;
436         addr.sin_port = htons(MCAST_PORT);
437         addr.sin_addr = p->multicast_addr;
438         
439         ret = sendto(p->udp_socket, buf, len, 0,
440                      (struct sockaddr*)&addr, sizeof(addr));
441         return ret;
442 }
443 #endif
444
445 static void
446 inet_peer_destroy(forb_peer_t *peer)
447 {
448         struct inet_peer *ipeer = peer->proto_priv;
449         if (ipeer) {
450                 peer->proto_priv = NULL;
451                 ul_logtrash("destroying peer fd=%d (orb_id=%s)\n",
452                             ipeer->socket, peer->orb_id);
453                 close(ipeer->socket);
454                 free(ipeer);
455         }
456 }
457
458 size_t inet_addr2str(char *dest, size_t maxlen, const void *addr)
459 {
460         const struct inet_addr *a = addr;
461         size_t ret = 0;
462         if (addr) {
463                 snprintf(dest, maxlen, "%s:%d", inet_ntoa(a->addr), ntohs(a->port));
464         }
465         return ret;
466 }
467
468 #if CONFIG_FCB && CONFIG_FORB_PROTO_INET_DEFAULT
469
470 #include <fcb.h>
471 #include <fcb_contact_info.h>
472
473 static void inet_register_cb(forb_port_t *port)
474 {
475         struct inet_addr *ia;
476         
477         ia = malloc(sizeof(*ia));
478         if (!ia) return;
479
480         char *fcb_addr = getenv("FCB_ADDR");
481         if (!fcb_addr) fcb_addr = "127.0.0.1";
482         ia->addr.s_addr = inet_addr(fcb_addr);
483         ia->port = htons(FCB_TCP_PORT);
484         forb_new_peer_discovered(port, NULL, FCB_SERVER_ID, ia, "");
485 }
486 #else
487 #define inet_register_cb NULL
488 #endif
489
490 static const forb_proto_t proto_inet = {
491         .hello_interval = 40 /* seconds */,
492         .port_destroy = inet_port_destroy,
493         .peer_destroy = inet_peer_destroy,
494         .send = inet_send,
495         .recv = inet_recv,
496 #ifndef CONFIG_FORB_PROTO_INET_DEFAULT
497         .broadcast = inet_broadcast,
498 #endif
499         .serialize_addr = inet_serialize_addr,
500         .deserialize_addr = inet_deserialize_addr,
501         .addr2str = inet_addr2str,
502         .register_cb = inet_register_cb,
503 };
504
505 #define MAX_INTERFACES 10
506 int get_local_address(int sock, struct in_addr *addr)
507 {
508         struct ifconf  ifc;
509         struct ifreq   *ifr, req[MAX_INTERFACES];
510         char *env;
511         bool loopback = false;
512         int ret;
513         struct in_addr env_addr;
514         
515         env = getenv("FORB_EXTERNAL_IP");
516         if (env) {
517                 if (inet_aton(env, &env_addr) == 0) {
518                         ul_logerr("Cannot convert FORB_EXTERNAL_IP\n");
519                         errno = EINVAL;
520                         return -1;
521                 }
522         }
523
524         ifc.ifc_len = sizeof(req);
525         ifc.ifc_req = req;
526
527         if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
528                 return -1;
529         for (ifr = req; ifr < &req[MAX_INTERFACES]; ifr++) {
530                 struct sockaddr_in ia;
531                 memcpy(&ia, &ifr->ifr_addr, sizeof(ia));
532                 ret = ioctl(sock, SIOCGIFFLAGS, ifr);
533                 if ((ret == 0) && (ifr->ifr_flags & IFF_UP)) {
534                         if (env && env_addr.s_addr == ia.sin_addr.s_addr) {
535                                 *addr = env_addr;
536                                 return 0;
537                         }
538                         if (!(ifr->ifr_flags & IFF_LOOPBACK)) {
539                                 if (!env) {
540                                         *addr = ia.sin_addr;
541                                         return 0;
542                                 }
543                         } else {
544                                 *addr = ia.sin_addr;
545                                 loopback = true;
546                         }
547                 }
548         }
549         if (env) {
550                 ul_logerr("FORB_EXTERNAL_IP doesn't match local interface\n");
551                 errno = ENODEV;
552                 return -1;
553         }
554         if (loopback)
555                 return 0;
556         else
557                 return -1;
558 }
559
560 /** 
561  * Initializes INET protocol port.
562  * 
563  * @param port_desc Port description to initialize.
564  * @return Zero on success, -1 on error and errno is set
565  * appropriately.
566  */
567 int
568 forb_inet_port_init(struct forb_port_desc *port_desc, struct in_addr listen_on,
569                     uint16_t port)
570 {
571         int ret;       
572         struct inet_port *port_priv;
573         struct sockaddr_in addr;
574         socklen_t len;
575         struct epoll_event ev;
576         
577         port_priv = forb_malloc(sizeof(*port_priv));
578         if (!port_priv)
579                 return -1;
580
581         memset(port_priv, 0, sizeof(*port_priv));
582         port_priv->last_recv_fd = -1;
583         inet_port_new_peer_init_head(port_priv);
584         
585         /* Initialize UDP multicast socket */
586         port_priv->udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
587         if (port_priv->udp_socket == -1) goto err_free;
588         
589         int yes = 1;
590         ret = setsockopt(port_priv->udp_socket, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
591         if (ret)
592                 goto err_close_udp;
593
594         int reuse = 1;
595         setsockopt(port_priv->udp_socket, SOL_SOCKET, SO_REUSEADDR, (int *) &reuse, sizeof(reuse));
596         if (ret)
597                 goto err_close_udp;
598
599         setnonblocking(port_priv->udp_socket);
600
601 #ifndef CONFIG_FORB_PROTO_INET_DEFAULT
602         struct ip_mreq mreq;
603         inet_aton(MCAST_ADDR, &port_priv->multicast_addr);
604         mreq.imr_multiaddr = port_priv->multicast_addr;
605         mreq.imr_interface.s_addr = INADDR_ANY;
606         ret = setsockopt(port_priv->udp_socket, IPPROTO_IP,
607                          IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
608         if (ret)
609                 goto err_close_udp;
610 #endif
611
612         addr.sin_family = AF_INET;
613         addr.sin_port = htons(MCAST_PORT);
614         addr.sin_addr = port_priv->multicast_addr;
615
616         ret = bind(port_priv->udp_socket, (struct sockaddr *)&addr, sizeof(addr));
617         if (ret != 0) goto err_close_udp;
618
619         char loop = 1;
620         unsigned loop_size = sizeof(loop);
621         ret = setsockopt(port_priv->udp_socket, IPPROTO_IP,
622                          IP_MULTICAST_LOOP, &loop, loop_size);
623         if (ret)
624                 goto err_close_udp;
625         
626
627         /* Initialize TCP socket */
628         port_priv->listen_socket = socket(PF_INET, SOCK_STREAM, 0);
629         if (port_priv->listen_socket == -1) goto err_close_udp;
630
631         reuse = 1;
632         setsockopt(port_priv->listen_socket, SOL_SOCKET, SO_REUSEADDR, (int *) &reuse, sizeof(reuse));
633         if (ret)
634                 goto err_close_listen;
635
636         addr.sin_family = AF_INET;
637         addr.sin_port = htons(port);
638         addr.sin_addr = listen_on;
639         ret = bind(port_priv->listen_socket, (struct sockaddr *)&addr, sizeof(addr));
640         if (ret != 0) goto err_close_listen;
641         if (setnonblocking(port_priv->listen_socket))
642                 goto err_close_listen;
643
644         ret = listen(port_priv->listen_socket, 10);
645         if (ret)
646                 goto err_close_listen;
647
648         /* Determine our address and port*/
649         len = sizeof(addr);
650         ret = getsockname(port_priv->listen_socket, (struct sockaddr *)&addr, &len);
651         if (ret) {
652                 ul_logerr("Non-loopback inet address not found\n");
653                 goto err_close_listen;
654         }
655
656         port_priv->addr.port = addr.sin_port;
657         if (listen_on.s_addr == INADDR_ANY) {
658                 if (get_local_address(port_priv->listen_socket, &port_priv->addr.addr)) {
659                         goto err_close_listen;
660                 }
661         } else
662                 port_priv->addr.addr = listen_on;
663
664         /* Initialize epoll descriptor */
665         port_priv->epoll_fd = epoll_create(10);
666         if (port_priv->epoll_fd == -1)
667                 goto err_close_listen;
668
669         memset(&ev, 0, sizeof(ev));
670         ev.events = EPOLLIN | EPOLLET;
671         ev.data.fd = port_priv->listen_socket;
672         ret = epoll_ctl(port_priv->epoll_fd, EPOLL_CTL_ADD,
673                         port_priv->listen_socket, &ev);
674         if (ret)
675                 goto err_close_epoll;
676
677 #ifndef CONFIG_FORB_PROTO_INET_DEFAULT  
678         ev.events = EPOLLIN | EPOLLET;
679         ev.data.fd = port_priv->udp_socket;
680         ret = epoll_ctl(port_priv->epoll_fd, EPOLL_CTL_ADD,
681                         port_priv->udp_socket, &ev);
682         if (ret)
683                 goto err_close_epoll;
684 #endif
685
686         port_desc->proto = &proto_inet;
687         port_desc->proto_priv = port_priv;
688         port_desc->addr = &port_priv->addr;
689         return 0;
690 err_close_epoll:
691         close(port_priv->epoll_fd);
692 err_close_listen:
693         ret = errno;
694         close(port_priv->listen_socket);
695         errno = ret;
696 err_close_udp:
697         ret = errno;
698         close(port_priv->udp_socket);
699         errno = ret;
700 err_free:
701         ret = errno;
702         forb_free(port_priv);
703         errno = ret;
704         return -1;
705 }