2 * Connection oriented routing user space utils
3 * Copyright (C) 2009-2014
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include <sys/socket.h>
29 #include <arpa/inet.h>
31 #include <sys/epoll.h>
37 #define U32_MAX ((__u32) ((1LL << 32) - 1))
40 #define MAX_ADDRLEN 128
42 #define ASSERT_ERR() \
53 if (!(a)) { ASSERT_ERR(); } \
73 #define ROUTE_MAXHOPS 7
78 struct route_list routes
;
80 struct service_list services
;
86 struct list_head node_list
;
88 __u32 route
[ROUTE_MAXHOPS
+ 1];
92 #define SEARCHQUERY_NEIGHSNOTQUERIED 1
93 #define SEARCHQUERY_NODEBYADDRESS 2
94 #define SEARCHQUERY_NODEBYSERVICEPORT 3
111 __u8 export_servicelist_enabled
= 0;
113 struct route_list localneighs
;
114 struct service_list localservices
;
116 struct list_head node_list
;
118 int discover_finished
= 0;
123 #define EPOLL_EVENTS 16
125 #define EPOLLDATA_DISCOVERNETWORK 1
126 #define EPOLLDATA_RDSCONNECT 2
127 #define EPOLLDATA_RDSOCKCMD 3
128 #define EPOLLDATA_FWD_TO_RSERVICE 4
129 #define EPOLLDATA_FORWARD 5
131 struct nonblock_resumeinfo_connect_to_host_send
{
137 struct route_list
*routes
;
141 struct nonblock_resumeinfo_connect_to_host_recv
{
150 #define FORWARD_BUF_SIZE 4096
152 struct nonblock_resumeinfo
{
163 struct route_list
*list
;
164 struct service_list
*service
;
166 struct nonblock_resumeinfo_connect_to_host_send connect_send
;
167 struct nonblock_resumeinfo_connect_to_host_recv connect_recv
;
169 struct libcor_nonblock_resumeinfo lnr
;
179 struct nonblock_resumeinfo_connect_to_host_send connect_send
;
180 struct nonblock_resumeinfo_connect_to_host_recv connect_resp
;
182 struct libcor_nonblock_resumeinfo lnr
;
186 struct libcor_nonblock_resumeinfo lnr
;
195 * buf gets filled by reversedir and written into
204 struct nonblock_resumeinfo
*reversedir
;
209 struct fwd_to_rservice_item
{
210 struct list_head allfwds
;
219 #define offsetof(type, member) __builtin_offsetof (type, member)
221 #define container_of(ptr, type, member) ({ \
222 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
223 (type *)( (char *)__mptr - offsetof(type,member) );})
226 static void set_nonblock(int fd
, int value
)
230 flags
= fcntl(fd
, F_GETFL
, 0);
232 perror("set_nonblock F_GETFL");
236 flags
= (flags
& (~(O_NONBLOCK
)));
238 flags
= flags
| O_NONBLOCK
;
240 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
241 perror("set_nonblock F_SETFL");
246 static int addr_eq(char *addr1
, __u32 addrlen1
,
247 char *addr2
, __u32 addrlen2
)
250 if (addr1
[addrlen1
-1] == 0) {
258 if (addr2
[addrlen2
-1] == 0) {
265 if (addrlen1
!= addrlen2
)
268 if (addrlen1
> MAX_ADDRLEN
)
271 if (addrlen1
!= 0 && memcmp(addr1
, addr2
, addrlen1
) != 0)
277 static int service_list_contains(struct service_list
*services
, __be16 port
)
281 for (u
=0;u
<services
->numports
;u
++) {
282 if (services
->ports
[u
] == port
) {
290 static int node_matches_searchquery(struct node
*n
, struct search_query
*q
)
292 if (q
->type
== SEARCHQUERY_NEIGHSNOTQUERIED
) {
293 return n
->neighs_queried
== 0 &&
294 addr_eq(n
->addr
, n
->addrlen
, localaddr
,
296 } else if (q
->type
== SEARCHQUERY_NODEBYADDRESS
) {
297 return addr_eq(n
->addr
, n
->addrlen
,
298 q
->query
.nodebyaddress
.addr
,
299 q
->query
.nodebyaddress
.addrlen
);
300 } else if (q
->type
== SEARCHQUERY_NODEBYSERVICEPORT
) {
301 return service_list_contains(&(n
->services
),
302 q
->query
.serviceport
);
309 static struct node
* try_find_neigh(struct search_query
*q
)
311 struct list_head
*curr
= node_list
.next
;
313 while (curr
!= &node_list
) {
314 struct node
*currnode
= container_of(curr
, struct node
,
317 if (node_matches_searchquery(currnode
, q
)) {
327 static struct node
* try_find_neigh_byaddr(__u16 addrlen
, char *addr
)
329 struct search_query q
;
330 bzero(&q
, sizeof(struct search_query
));
331 q
.type
= SEARCHQUERY_NODEBYADDRESS
;
332 q
.query
.nodebyaddress
.addrlen
= addrlen
;
333 q
.query
.nodebyaddress
.addr
= addr
;
334 return try_find_neigh(&q
);
337 static struct node
* try_find_neigh_byservice(__be16 serviceport
)
339 struct search_query q
;
340 bzero(&q
, sizeof(struct search_query
));
341 q
.type
= SEARCHQUERY_NODEBYSERVICEPORT
;
342 q
.query
.serviceport
= serviceport
;
343 return try_find_neigh(&q
);
347 static int check_rc(int rc
, char *errormsg
)
349 if (rc
!= RC_OK
&& rc
!= RC_WOULDBLOCK
)
350 printf("%s\n", errormsg
);
351 return (rc
!= RC_OK
);
354 static int connect_to_host_recv(int fd
, struct libcor_nonblock_resumeinfo
*lnr
,
355 struct nonblock_resumeinfo_connect_to_host_recv
*rcr
,
358 if (rcr
->state
== 0) {
366 ASSERT(rcr
->fd
= fd
);
367 ASSERT(rcr
->node
= node
);
369 ASSERT(node
->hopcount
!= 0);
371 for (;rcr
->u
< node
->hopcount
;rcr
->u
++) {
372 int rc
= read_resp_nonblock(fd
, lnr
);
376 bzero(rcr
, sizeof(struct nonblock_resumeinfo_connect_to_host_recv
));
380 static int connect_to_host_send(int fd
,
381 struct libcor_nonblock_resumeinfo
*lnr
,
382 struct nonblock_resumeinfo_connect_to_host_send
*cth
,
385 if (cth
->state
== 0) {
389 cth
->routes
= &localneighs
;
395 ASSERT(cth
->fd
= fd
);
396 ASSERT(cth
->node
= node
);
398 ASSERT(node
->hopcount
!= 0);
400 for (;cth
->u
< node
->hopcount
;) {
401 struct node
*n
= cth
->routes
->routes
[node
->route
[cth
->u
]].dst
;
402 int rc
= send_connect_neigh_nonblock(fd
, lnr
, n
->addrlen
,
407 cth
->routes
= &(n
->routes
);
409 bzero(cth
, sizeof(struct nonblock_resumeinfo_connect_to_host_send
));
413 static void add_neigh(void *ptr
, __u32 addrlen
, char *addr
)
415 struct route_list
*list
= (struct route_list
*) ptr
;
418 if (addrlen
> MAX_ADDRLEN
)
421 if (addr_eq(addr
, addrlen
, 0, 0))
424 if (list
->numroutes
>= list
->rows_alloc
)
427 ASSERT(list
->routes
[list
->numroutes
].dst
== 0);
429 node
= try_find_neigh_byaddr(addrlen
, addr
);
432 node
= calloc(1, sizeof(struct node
));
434 node
->addr
= malloc(((int) addrlen
));
435 node
->addrlen
= addrlen
;
436 memcpy(node
->addr
, addr
, addrlen
);
438 list_add_tail(&(node
->node_list
), &node_list
);
441 list
->routes
[list
->numroutes
].dst
= node
;
445 static void init_neighlist(void *ptr
, __u32 numneighs
)
447 struct route_list
*list
= (struct route_list
*) ptr
;
451 list
->rows_alloc
= (__u16
) numneighs
;
452 list
->routes
= calloc(numneighs
, sizeof(struct route
));
455 static void add_service(void *ptr
, __be16 port
)
457 struct service_list
*list
= (struct service_list
*) ptr
;
459 printf("add service %u\n", ntohs(port
));
461 if (list
->numports
>= list
->rows_alloc
)
464 list
->ports
[list
->numports
] = port
;
468 static void init_servicelist(void *ptr
, __u32 numservices
)
470 struct service_list
*list
= (struct service_list
*) ptr
;
472 printf("init servicelist %u\n", numservices
);
474 if (numservices
> 16)
476 list
->rows_alloc
= (__u16
) numservices
;
478 list
->ports
= calloc(numservices
, 2);
481 static void print_hex(char *buf
, __u32 len
)
485 ASSERT(len
!= U32_MAX
);
488 printf("%hhx ", buf
[u
]);
492 static void neigh_printaddr(__u16 addrlen
, char *addr
)
494 printf("addrlen = %d addr: ", (int) addrlen
);
495 print_hex(addr
, addrlen
);
500 static int __export_servicelist(int fd
, char *data
, __u32 len
)
502 __u32 totalwritten
= 0;
504 ASSERT(len
!= U32_MAX
);
506 while (totalwritten
< len
) {
507 int written
= write(fd
, data
+ totalwritten
, len
-totalwritten
);
513 perror("export servicelist");
517 totalwritten
+= written
;
523 static int _export_servicelist(int fd
, char *addr
, __u32 addrlen
, __u32 cost
,
524 struct service_list
*services
)
530 for (u
=0;u
<services
->numports
;u
++) {
533 ASSERT(addrlen
!= U32_MAX
);
535 for(v
=0;v
<addrlen
;v
++) {
536 if (((__u8
) addr
[v
]) < 16)
537 rc
= snprintf(&(buf
[0]), 20, "0%hhx", addr
[v
]);
539 rc
= snprintf(&(buf
[0]), 20, "%hhx", addr
[v
]);
543 rc
= __export_servicelist(fd
, &(buf
[0]), rc
);
548 rc
= snprintf(&(buf
[0]), 20, ":%hu:%u\n",
549 ntohs(services
->ports
[u
]), cost
);
553 rc
= __export_servicelist(fd
, &(buf
[0]), rc
);
561 static void export_servicelist(void)
563 char *servicelist_txtfile
= "/var/lib/cor/services/txt";
564 char *servicelist_tmpfile
= "/var/lib/cor/services/tmp";
567 struct list_head
*curr
;
569 if (export_servicelist_enabled
== 0)
572 fd
= open(servicelist_tmpfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
574 perror("export servicelist");
578 if (_export_servicelist(fd
, 0, 0, 0, &localservices
) != 0)
581 curr
= node_list
.next
;
582 while (curr
!= &node_list
) {
583 struct node
*currnode
= container_of(curr
, struct node
,
588 if (addr_eq(currnode
->addr
, currnode
->addrlen
, localaddr
,
592 if (_export_servicelist(fd
, currnode
->addr
, currnode
->addrlen
,
593 currnode
->hopcount
, &(currnode
->services
)) != 0)
600 if (rename(servicelist_tmpfile
, servicelist_txtfile
) != 0) {
601 perror("export servicelist");
609 unlink(servicelist_tmpfile
);
613 static void __recalc_routes(struct node
*node
)
615 struct list_head
*curr
;
617 curr
= node_list
.next
;
618 while (curr
!= &node_list
) {
619 struct node
*currnode
= container_of(curr
, struct node
,
622 if (currnode
->hopcount
< node
->hopcount
)
628 list_del(&(node
->node_list
));
629 list_add_tail(&(node
->node_list
), curr
);
632 static void _recalc_routes(struct node
*node
)
634 struct route_list
*routes
= (node
== 0 ?
635 &localneighs
: &(node
->routes
));
639 for (u
=0;u
<routes
->numroutes
;u
++) {
640 struct node
*target
= routes
->routes
[u
].dst
;
642 __u32 hopcount
= (node
== 0 ? 0 : node
->hopcount
) + 1;
644 if (target
->hopcount
!= 0 && target
->hopcount
<= hopcount
)
648 bzero(&(target
->route
[0]), sizeof(target
->route
));
650 memcpy(&(target
->route
[0]), &(node
->route
[0]),
651 sizeof(target
->route
));
654 target
->hopcount
= hopcount
;
655 target
->route
[hopcount
-1] = u
;
657 __recalc_routes(target
);
661 static void recalc_routes(void)
663 struct list_head oldnodes
;
664 struct list_head
*curr
;
666 list_add(&oldnodes
, &node_list
);
667 list_del(&node_list
);
668 init_list_head(&node_list
);
671 curr
= oldnodes
.next
;
672 while (curr
!= &oldnodes
) {
673 struct node
*currnode
= container_of(curr
, struct node
,
676 bzero(&(currnode
->route
[0]), sizeof(currnode
->route
));
677 currnode
->hopcount
= 0;
685 curr
= node_list
.next
;
686 while (curr
!= &node_list
) {
687 struct node
*currnode
= container_of(curr
, struct node
,
690 _recalc_routes(currnode
);
696 curr
= oldnodes
.next
;
697 while (curr
!= &oldnodes
) {
698 struct node
*currnode
= container_of(curr
, struct node
,
703 list_del(&(currnode
->node_list
));
705 if (currnode
->addr
!= 0) {
706 free(currnode
->addr
);
713 export_servicelist();
716 static int load_neigh_list(int fd
, struct nonblock_resumeinfo
*nr
,
719 struct libcor_nonblock_resumeinfo
*lnr
;
720 int rc
= RC_CONNBROKEN
;
722 ASSERT((fd
== 0 && nr
== 0) || (fd
!= 0 && nr
!= 0));
724 if (fd
== 0 && nr
== 0) {
725 struct epoll_event epe
;
727 fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RAW
);
733 rc
= connect(fd
, 0, 0);
741 nr
= (struct nonblock_resumeinfo
*)
742 malloc(sizeof(struct nonblock_resumeinfo
));
743 bzero(nr
, sizeof(struct nonblock_resumeinfo
));
745 nr
->type
= EPOLLDATA_DISCOVERNETWORK
;
746 nr
->data
.discover_network
.node
= node
;
748 bzero(&epe
, sizeof(struct epoll_event
));
749 epe
.events
= (EPOLLIN
| EPOLLOUT
| EPOLLRDHUP
| EPOLLERR
|
752 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, fd
, &epe
);
755 lnr
= &(nr
->data
.discover_network
.lnr
);
757 ASSERT(nr
->type
== EPOLLDATA_DISCOVERNETWORK
);
758 ASSERT(nr
->data
.discover_network
.node
== node
);
760 if (nr
->data
.discover_network
.state
== 1) {
762 } else if (nr
->data
.discover_network
.state
== 2) {
764 } else if (nr
->data
.discover_network
.state
== 3) {
766 } else if (nr
->data
.discover_network
.state
== 4) {
768 } else if (nr
->data
.discover_network
.state
== 5) {
770 } else if (nr
->data
.discover_network
.state
== 6) {
772 } else if (nr
->data
.discover_network
.state
== 7) {
774 } else if (nr
->data
.discover_network
.state
== 8) {
776 } else if (nr
->data
.discover_network
.state
!= 0) {
781 nr
->data
.discover_network
.list
= &localneighs
;
782 nr
->data
.discover_network
.service
= &localservices
;
784 neigh_printaddr(node
->addrlen
,
786 nr
->data
.discover_network
.list
= &(node
->routes
);
787 nr
->data
.discover_network
.service
= &(node
->services
);
789 nr
->data
.discover_network
.state
= 1;
791 rc
= connect_to_host_send(fd
, lnr
,
792 &(nr
->data
.discover_network
.connect_send
),
795 if (check_rc(rc
, "load_neigh_list: connect_to_host_send error"))
799 rc
= send_list_neigh_nonblock(fd
, lnr
);
800 nr
->data
.discover_network
.state
= 2;
801 if (check_rc(rc
, "load_neigh_list: send_list_neigh error"))
805 rc
= send_list_services_nonblock(fd
, lnr
);
806 nr
->data
.discover_network
.state
= 3;
807 if (check_rc(rc
, "load_neigh_list: send_list_services error"))
812 nr
->data
.discover_network
.state
= 4;
814 rc
= connect_to_host_recv(fd
, lnr
,
815 &(nr
->data
.discover_network
.connect_recv
),
817 if (check_rc(rc
, "load_neigh_list: connect_to_host_recv error"))
821 nr
->data
.discover_network
.state
= 5;
823 rc
= read_resp_nonblock(fd
, lnr
);
824 if (check_rc(rc
, "load_neigh_list: read_resp error"))
827 nr
->data
.discover_network
.state
= 6;
829 rc
= read_neigh_list_nonblock(fd
, lnr
, nr
->data
.discover_network
.list
,
830 init_neighlist
, add_neigh
);
831 if (check_rc(rc
, "load_neigh_list: read_neigh_list error"))
834 nr
->data
.discover_network
.state
= 7;
836 rc
= read_resp_nonblock(fd
, lnr
);
837 if (check_rc(rc
, "load_neigh_list: read_resp error"))
840 nr
->data
.discover_network
.state
= 8;
842 rc
= read_service_list_nonblock(fd
, lnr
,
843 nr
->data
.discover_network
.service
,
844 init_servicelist
, add_service
);
845 if (check_rc(rc
, "load_neigh_list: read_service_list error"))
848 #warning todo rollback node->routes and node->services on error
851 //printf("load_neigh_list state %d\n", nr->data.discover_network.state);
852 if (rc
!= RC_WOULDBLOCK
) {
853 //printf("load_neigh_list rc %d\n", rc);
863 static void discover_network(int fd
, struct nonblock_resumeinfo
*nr
)
866 struct search_query q
;
867 bzero(&q
, sizeof(struct search_query
));
868 q
.type
= SEARCHQUERY_NEIGHSNOTQUERIED
;
870 ASSERT((fd
== 0 && nr
== 0) || (fd
!= 0 && nr
!= 0));
872 #warning todo catch RC_CONNBROKEN
873 if (fd
== 0 && nr
== 0) {
874 rc
= load_neigh_list(fd
, nr
, 0);
875 if (rc
== RC_WOULDBLOCK
)
882 node
= try_find_neigh(&q
);
886 ASSERT(nr
->type
== EPOLLDATA_DISCOVERNETWORK
);
887 node
= nr
->data
.discover_network
.node
;
890 rc
= load_neigh_list(fd
, nr
, node
);
891 if (rc
== RC_WOULDBLOCK
)
893 node
->neighs_queried
= 1;
897 discover_finished
= 1;
900 static void send_unreach_error(__u64 cookie
)
903 // printf("send_rdsock_connecterror\n");
904 set_nonblock(rdsock_fd
, 0);
905 rc
= send_rdsock_connecterror(rdsock_fd
, cookie
,
906 CONNECTERROR_NETUNREACH
);
907 set_nonblock(rdsock_fd
, 1);
911 //cookie+addr are not passed on nonblocking resume
912 static void _rdscmd_void_connect(struct nonblock_resumeinfo
*nr
)
916 struct libcor_nonblock_resumeinfo
*lnr
= &(nr
->data
.rds_connect
.lnr
);
918 ASSERT(nr
->type
== EPOLLDATA_RDSCONNECT
);
920 if (nr
->data
.rds_connect
.state
== 1) {
922 } else if (nr
->data
.rds_connect
.state
== 2) {
924 } else if (nr
->data
.rds_connect
.state
== 3) {
926 } else if (nr
->data
.rds_connect
.state
!= 0) {
930 if (nr
->data
.rds_connect
.node
== 0)
933 rc
= connect_to_host_send(nr
->fd
, lnr
,
934 &(nr
->data
.rds_connect
.connect_send
),
935 nr
->data
.rds_connect
.node
);
936 nr
->data
.rds_connect
.state
= 1;
937 if (check_rc(rc
, "_rdscmd_void_connect: connect_to_host_send error"))
941 rc
= send_connect_port_nonblock(nr
->fd
, lnr
, nr
->data
.rds_connect
.port
);
942 nr
->data
.rds_connect
.state
= 2;
943 if (check_rc(rc
, "_rdscmd_void_connect: send_connect_port error"))
947 if (nr
->data
.rds_connect
.node
== 0)
950 rc
= connect_to_host_recv(nr
->fd
, lnr
,
951 &(nr
->data
.rds_connect
.connect_resp
),
952 nr
->data
.rds_connect
.node
);
953 if (check_rc(rc
, "_rdscmd_void_connect: connect_to_host_recv error"))
956 nr
->data
.rds_connect
.state
= 3;
958 rc
= read_resp_nonblock(nr
->fd
, lnr
);
959 if (check_rc(rc
, "_rdscmd_void_connect: read_resp error"))
962 rc
= pass_socket(nr
->fd
, nr
->data
.rds_connect
.cookie
);
964 printf("pass_socket error\n");
971 if (rc
== RC_WOULDBLOCK
)
976 send_unreach_error(nr
->data
.rds_connect
.cookie
);
979 static int rdscmd_void_connect(void *ptr
, __u64 cookie
,
980 struct cor_sockaddr
*addr
)
983 struct nonblock_resumeinfo
*nr
;
985 struct epoll_event epe
;
988 if (addr
->sin_family
!= AF_COR
) {
989 printf("rds_connect %llu not af_cor\n", cookie
);
993 printf("rds_connect cookie: %llu, addr: ", cookie
);
994 print_hex(&(addr
->addr
[0]), sizeof(addr
->addr
));
995 printf(" port: %u\n", ntohs(addr
->port
));
997 if (addr_eq(addr
->addr
, sizeof(addr
->addr
), 0, 0) != 0 ||
998 addr_eq(addr
->addr
, sizeof(addr
->addr
), localaddr
,
999 localaddrlen
) != 0) {
1001 } else if ((node
= try_find_neigh_byaddr(sizeof(addr
->addr
),
1002 &(addr
->addr
[0]))) == 0) {
1003 printf("connect_to_host host not found\n");
1008 fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RAW
);
1014 rc
= connect(fd
, 0, 0);
1020 set_nonblock(fd
, 1);
1022 nr
= (struct nonblock_resumeinfo
*)
1023 malloc(sizeof(struct nonblock_resumeinfo
));
1024 bzero(nr
, sizeof(struct nonblock_resumeinfo
));
1026 nr
->type
= EPOLLDATA_RDSCONNECT
;
1027 nr
->data
.rds_connect
.cookie
= cookie
;
1028 nr
->data
.rds_connect
.node
= node
;
1029 nr
->data
.rds_connect
.port
= addr
->port
;
1031 bzero(&epe
, sizeof(struct epoll_event
));
1032 epe
.events
= (EPOLLIN
| EPOLLOUT
| EPOLLRDHUP
| EPOLLERR
|
1035 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, fd
, &epe
);
1037 _rdscmd_void_connect(nr
);
1043 send_unreach_error(cookie
);
1048 static int proc_rdsock_cmd(int fd
, struct rdsock_cmd
*cmd
)
1050 if (cmd
->cmd
== CRD_KTU_CONNECT
) {
1051 return parse_rdsock_connect(0, cmd
, rdscmd_void_connect
);
1053 printf("error in proc_rdsock_cmd: unknown cmd: %u\n", cmd
->cmd
);
1059 static struct nonblock_resumeinfo
*_init_fwd(int fd
)
1061 struct nonblock_resumeinfo
*nr
=
1062 malloc(sizeof(struct nonblock_resumeinfo
));
1064 struct epoll_event epe
;
1066 bzero(nr
, sizeof(struct nonblock_resumeinfo
));
1068 nr
->type
= EPOLLDATA_FORWARD
;
1069 nr
->data
.forward
.buf
= malloc(FORWARD_BUF_SIZE
);
1070 bzero(&epe
, sizeof(struct epoll_event
));
1071 epe
.events
= (EPOLLIN
| EPOLLOUT
| EPOLLRDHUP
| EPOLLERR
| EPOLLET
);
1074 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, nr
->fd
, &epe
);
1079 static void init_fwd(int fd0
, int fd1
)
1081 struct nonblock_resumeinfo
*dir0
= _init_fwd(fd0
);
1082 struct nonblock_resumeinfo
*dir1
= _init_fwd(fd1
);
1084 dir0
->data
.forward
.reversedir
= dir1
;
1085 dir1
->data
.forward
.reversedir
= dir0
;
1088 static void fwd_to_rservice_accept(int listenerfd
, __be16 targetport
)
1093 struct cor_sockaddr addr
;
1096 localfd
= accept(listenerfd
, 0, 0);
1100 set_nonblock(localfd
, 1);
1102 if (service_list_contains(&(localservices
), targetport
) != 0) {
1104 } else if ((node
= try_find_neigh_byservice(targetport
)) == 0) {
1105 printf("fwd_to_rservice_accept no host with service found\n");
1109 bzero(&addr
, sizeof(struct cor_sockaddr
));
1110 addr
.sin_family
= AF_COR
;
1111 addr
.port
= targetport
;
1114 if (node
->addrlen
> MAX_ADDRLEN
)
1116 memcpy(&(addr
.addr
[0]), node
->addr
, node
->addrlen
);
1119 remotefd
= socket(PF_COR
, SOCK_STREAM
, 0);
1120 if (remotefd
== -1) {
1125 set_nonblock(remotefd
, 1);
1127 if (connect(remotefd
, (struct sockaddr
*) &addr
,
1128 sizeof(struct cor_sockaddr
)) != 0) {
1133 init_fwd(localfd
, remotefd
);
1143 #define RC_FORWARD_OK 1
1144 #define RC_FORWARD_WOULDBLOCK 2
1145 #define RC_FORWARD_ERROR 3
1147 static int forward_write(struct nonblock_resumeinfo
*nr
)
1149 __u32 buffill
= nr
->data
.forward
.buffill
;
1152 ASSERT(buffill
<= FORWARD_BUF_SIZE
);
1153 ASSERT(nr
->data
.forward
.bufwritten
<= buffill
);
1155 if (buffill
== FORWARD_BUF_SIZE
) {
1160 while (nr
->data
.forward
.bufwritten
< buffill
) {
1161 int rc
= send(nr
->fd
, nr
->data
.forward
.buf
+
1162 nr
->data
.forward
.bufwritten
,
1163 buffill
- nr
->data
.forward
.bufwritten
,
1164 more
== 0 ? 0 : MSG_MORE
);
1166 if (rc
< 0 && (errno
== EAGAIN
||
1167 errno
== EWOULDBLOCK
)) {
1168 return RC_FORWARD_WOULDBLOCK
;
1169 } else if (rc
<= 0) {
1173 perror("forward_write");
1174 return RC_FORWARD_ERROR
;
1176 nr
->data
.forward
.bufwritten
+= rc
;
1177 ASSERT(nr
->data
.forward
.bufwritten
<= buffill
);
1181 return RC_FORWARD_OK
;
1184 static int forward_read(struct nonblock_resumeinfo
*nr
)
1186 int readfd
= nr
->data
.forward
.reversedir
->fd
;
1189 ASSERT(nr
->data
.forward
.bufwritten
<= nr
->data
.forward
.buffill
);
1191 if (nr
->data
.forward
.bufwritten
== nr
->data
.forward
.buffill
) {
1192 nr
->data
.forward
.buffill
= 0;
1193 nr
->data
.forward
.bufwritten
= 0;
1194 } else if (nr
->data
.forward
.bufwritten
* 3 > nr
->data
.forward
.buffill
) {
1195 memmove(nr
->data
.forward
.buf
, nr
->data
.forward
.buf
+
1196 nr
->data
.forward
.bufwritten
,
1197 nr
->data
.forward
.buffill
-
1198 nr
->data
.forward
.bufwritten
);
1199 nr
->data
.forward
.buffill
-= nr
->data
.forward
.bufwritten
;
1200 nr
->data
.forward
.bufwritten
= 0;
1203 if (nr
->data
.forward
.buffill
== FORWARD_BUF_SIZE
)
1204 return RC_FORWARD_OK
;
1206 while (nr
->data
.forward
.buffill
< FORWARD_BUF_SIZE
) {
1207 rc
= recv(readfd
, nr
->data
.forward
.buf
+
1208 nr
->data
.forward
.buffill
,
1209 FORWARD_BUF_SIZE
- nr
->data
.forward
.buffill
, 0);
1213 return RC_FORWARD_OK
;
1214 } else if (rc
< 0) {
1215 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
1216 return RC_FORWARD_WOULDBLOCK
;
1217 } else if (errno
== EINTR
) {
1220 perror("forward_read");
1221 return RC_FORWARD_ERROR
;
1224 nr
->data
.forward
.buffill
+= rc
;
1225 ASSERT(nr
->data
.forward
.buffill
<= FORWARD_BUF_SIZE
);
1229 return RC_FORWARD_OK
;
1232 static void _forward(struct nonblock_resumeinfo
*nr
)
1237 rc
= forward_read(nr
);
1238 if (rc
== RC_FORWARD_ERROR
)
1240 if (nr
->data
.forward
.bufwritten
== nr
->data
.forward
.buffill
)
1243 rc
= forward_write(nr
);
1244 if (rc
== RC_FORWARD_ERROR
)
1246 else if (rc
== RC_FORWARD_WOULDBLOCK
)
1250 #warning todo call EPOLL_CTL_DEL + free where needed (some places calling close do not)
1253 epoll_ctl(epoll_fd
, EPOLL_CTL_DEL
,
1254 nr
->data
.forward
.reversedir
->fd
, 0);
1255 close(nr
->data
.forward
.reversedir
->fd
);
1256 epoll_ctl(epoll_fd
, EPOLL_CTL_DEL
, nr
->fd
, 0);
1259 #warning todo free after all events are processed
1260 /* free(nr->data.forward.reversedir);
1266 static void forward(struct nonblock_resumeinfo
*nr
, __u32 eventflags
)
1268 ASSERT(nr
->type
== EPOLLDATA_FORWARD
);
1269 ASSERT(nr
->data
.forward
.reversedir
->type
== EPOLLDATA_FORWARD
);
1271 if ((eventflags
& EPOLLOUT
) != 0) {
1272 nr
->data
.forward
.is_connected
= 1;
1275 if (nr
->data
.forward
.is_connected
== 0 ||
1276 nr
->data
.forward
.reversedir
->data
.forward
.is_connected
1281 _forward(nr
->data
.forward
.reversedir
);
1284 static void nonblock_resume(struct nonblock_resumeinfo
*nr
, __u32 eventflags
)
1286 if (nr
->type
== EPOLLDATA_DISCOVERNETWORK
) {
1287 int rc
= resume_send_ifneeded(nr
->fd
,
1288 &(nr
->data
.discover_network
.lnr
));
1290 //printf("load_neigh_list state = %d rc = %d\n", nr->data.discover_network.state, rc);
1295 discover_network(nr
->fd
, nr
);
1296 } else if (nr
->type
== EPOLLDATA_RDSCONNECT
) {
1297 int rc
= resume_send_ifneeded(nr
->fd
,
1298 &(nr
->data
.discover_network
.lnr
));
1303 _rdscmd_void_connect(nr
);
1304 } else if (nr
->type
== EPOLLDATA_RDSOCKCMD
) {
1305 struct rdsock_cmd cmd
;
1307 int rc
= resume_send_ifneeded(nr
->fd
,
1308 &(nr
->data
.rdsock_cmd
.lnr
));
1313 rc
= read_rdsock_cmd_nonblock(rdsock_fd
,
1314 &(nr
->data
.rdsock_cmd
.lnr
), &cmd
);
1315 ASSERT(rc
!= RC_CONNBROKEN
);
1316 if (rc
== RC_WOULDBLOCK
)
1319 rc
= proc_rdsock_cmd(rdsock_fd
, &cmd
);
1320 free_rdsockcmd_data(&cmd
);
1322 } else if (nr
->type
== EPOLLDATA_FWD_TO_RSERVICE
) {
1323 fwd_to_rservice_accept(nr
->fd
,
1324 nr
->data
.fwd_to_rservice
.targetport
);
1325 } else if (nr
->type
== EPOLLDATA_FORWARD
) {
1326 forward(nr
, eventflags
);
1332 static int rdsock_negotiate_version(void)
1334 struct rdsock_cmd cmd
;
1335 __u32 versionmin
= 1000;
1336 __u32 versionmax
= 0;
1339 rc
= read_rdsock_cmd(rdsock_fd
, &cmd
);
1341 printf("read_rdsock_cmd rc = %d\n", rc
);
1345 if (cmd
.cmd
!= CRD_KTU_SUPPORTEDVERSIONS
) {
1346 printf("rhsock supportedversions not sent\n", rc
);
1350 rc
= parse_rdsock_supported_versions(&cmd
, &versionmin
, &versionmax
);
1352 printf("parse_rdsock_supported_versions rc = %d\n", rc
);
1356 /* printf("rdsock_negotiate_version versionmin %u versionmax %u\n",
1357 versionmin, versionmax); */
1359 if (versionmin
!= 0) {
1360 printf("rdsock_negotiate_version versionmin of kernel is %u, "
1361 "but needs to be 0\n"
1362 "You probably need to upgrade corutils or "
1363 "downgrade the kernel\n", versionmin
);
1367 rc
= send_rdsock_version(rdsock_fd
, 0);
1368 ASSERT(rc
== RC_OK
);
1373 static void epoll_add_fwd_to_rservice(struct list_head
*rservice_fwds
)
1375 while (list_empty(rservice_fwds
) == 0) {
1376 struct fwd_to_rservice_item
*item
= container_of(
1377 rservice_fwds
->next
,
1378 struct fwd_to_rservice_item
,
1381 struct nonblock_resumeinfo
*nr
;
1383 struct epoll_event epe
;
1385 set_nonblock(item
->bindfd
, 1);
1387 nr
= malloc(sizeof(struct nonblock_resumeinfo
));
1388 bzero(nr
, sizeof(struct nonblock_resumeinfo
));
1389 nr
->fd
= item
->bindfd
;
1390 nr
->type
= EPOLLDATA_FWD_TO_RSERVICE
;
1391 nr
->data
.fwd_to_rservice
.targetport
= item
->targetport
;
1392 bzero(&epe
, sizeof(struct epoll_event
));
1393 epe
.events
= (EPOLLIN
| EPOLLERR
);
1396 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, item
->bindfd
, &epe
);
1398 list_del(&(item
->allfwds
));
1403 static int parse_hexchar(char c
)
1425 else if (c
== 'A' || c
== 'a')
1427 else if (c
== 'B' || c
== 'b')
1429 else if (c
== 'C' || c
== 'c')
1431 else if (c
== 'D' || c
== 'd')
1433 else if (c
== 'E' || c
== 'e')
1435 else if (c
== 'F' || c
== 'f')
1441 static int parse_hex(char *target
, char *src
, int srclen
)
1446 ASSERT(target
!= 0);
1448 ASSERT((srclen
%2) == 0);
1450 for(u
=0;u
<(srclen
/2);u
++) {
1451 int high
= parse_hexchar(src
[u
*2]);
1452 int low
= parse_hexchar(src
[u
*2+1]);
1454 if (high
== -1 || low
== -1)
1457 target
[u
] = (char) ((high
<< 4) + low
);
1463 static int parse_addr(char *argv_addr
)
1466 int len
= strlen(argv_addr
);
1467 char *noaddr
= "noaddr";
1469 if (strncmp(argv_addr
, noaddr
, len
) == 0) {
1475 if ((len
< 2) || (len
%2) != 0)
1478 localaddr
= malloc(len
/2);
1479 localaddrlen
= len
/2;
1481 rc
= parse_hex(localaddr
, argv_addr
, len
);
1488 fprintf(stderr
, "error: argv_addr is not a valid address (contains "
1489 "non-hex characters or number of hex characters is not "
1490 "a multiple of 2)\n");
1494 static int parse_port(char *arg
, __u32 len
, __u16
*port
)
1499 long int tmpport
= 0;
1501 tmpbuf
= malloc(len
+1);
1502 memcpy(tmpbuf
, arg
, len
);
1505 tmpport
= strtol(tmpbuf
, &endptr
, 10);
1506 if (tmpbuf
[0] == 0 || endptr
== 0 || endptr
!= tmpbuf
+ len
) {
1514 if (tmpport
<= 0 || tmpport
>= 65536)
1517 *port
= (__u16
) tmpport
;
1521 static int parse_inetaddr(char *addr
, __u32 len
, int *af
,
1522 struct sockaddr
**saddr
, socklen_t
*saddrlen
)
1524 __u32 idx
= len
- 1;
1530 struct in_addr inaddr
;
1531 struct in6_addr in6addr
;
1534 if (addr
[idx
] == ':') {
1540 if (idx
<= 0 || idx
>= len
- 1)
1543 if (parse_port(addr
+ idx
+ 1, len
- idx
- 1, &port
) != 0)
1546 host
= malloc(idx
+ 1);
1547 memcpy(host
, addr
, idx
);
1550 if (inet_pton(AF_INET
, host
, &inaddr
) == 1) {
1551 struct sockaddr_in
*ret
;
1556 ret
= malloc(sizeof(struct sockaddr_in
));
1557 bzero(ret
, sizeof(struct sockaddr_in
));
1559 ret
->sin_family
= AF_INET
;
1560 ret
->sin_port
= htons(port
);
1561 memcpy(&(ret
->sin_addr
), &inaddr
, sizeof(inaddr
));
1564 *saddr
= (struct sockaddr
*) ret
;
1565 *saddrlen
= sizeof(struct sockaddr_in
);
1568 } else if (inet_pton(AF_INET6
, host
, &in6addr
) == 1) {
1572 printf("sorry IPv6 support is not implemented yet\n");
1582 static int parse_fwd_to_rservice(char *argv_fwd
,
1583 struct list_head
*rservice_fwds
)
1585 struct fwd_to_rservice_item
*item
;
1587 struct sockaddr
*saddr
;
1598 if (argv_fwd
[len
] == 0) {
1600 } else if (argv_fwd
[len
] == ':') {
1606 if (idx
<= 0 || idx
>= len
- 1)
1609 if (parse_inetaddr(argv_fwd
, idx
, &af
, &saddr
, &saddrlen
) != 0)
1612 if (parse_port(argv_fwd
+ idx
+ 1, len
- idx
- 1, &serviceport
) != 0)
1615 item
= malloc(sizeof(struct fwd_to_rservice_item
));
1616 item
->bindfd
= socket(af
, SOCK_STREAM
, 0);
1617 if (item
->bindfd
< 0) {
1622 if (setsockopt(item
->bindfd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
,
1623 sizeof(optval
)) != 0) {
1624 perror("setsockopt");
1627 if (setsockopt(item
->bindfd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
,
1628 sizeof(optval
)) != 0) {
1629 perror("setsockopt");
1632 if (bind(item
->bindfd
, saddr
, saddrlen
) != 0) {
1636 if (listen(item
->bindfd
, 100) != 0) {
1640 item
->targetport
= htons(serviceport
);
1642 list_add_tail(&(item
->allfwds
), rservice_fwds
);
1655 static int parse_args(int argc
, char *argv
[], struct list_head
*rservice_fwds
)
1659 __u32 argsconsumed
= 0;
1665 if (argc
<= argsconsumed
+ 1)
1668 if (strcmp(argv
[argsconsumed
+ 1], "--addr") == 0) {
1669 if (argc
<= argsconsumed
+ 2)
1675 rc
= parse_addr(argv
[argsconsumed
+ 2]);
1682 } else if (strcmp(argv
[argsconsumed
+ 1],
1683 "--export-servicelist") == 0) {
1684 export_servicelist_enabled
= 1;
1687 } else if (strcmp(argv
[argsconsumed
+ 1],
1688 "--fwd-to-rservice") == 0) {
1689 if (argc
<= argsconsumed
+ 2)
1692 rc
= parse_fwd_to_rservice(argv
[argsconsumed
+ 2],
1708 fprintf(stderr
, "usage: test_routed2"
1709 " [--export-servicelist]"
1710 " [--fwd-to-rservice bindaddr:bindport:remoteport]"
1711 " --addr addr (even number of hex digits or noaddr)\n");
1718 int main(int argc
, char *argv
[])
1721 struct list_head rservice_fwds
;
1723 struct nonblock_resumeinfo rds_nr
;
1725 int discover_finished_executed
= 0;
1727 discover_finished
= 0;
1730 init_list_head(&rservice_fwds
);
1734 rc
= parse_args(argc
, argv
, &rservice_fwds
);
1739 init_list_head(&node_list
);
1741 epoll_fd
= epoll_create(1);
1742 if (epoll_fd
<= 0) {
1743 perror("epoll_create");
1748 rdsock_fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RDEAMON
);
1749 if (rdsock_fd
< 0) {
1754 rc
= connect(rdsock_fd
, 0, 0);
1760 rc
= rdsock_negotiate_version();
1764 rc
= send_rdsock_up(rdsock_fd
, localaddr
, localaddrlen
);
1765 ASSERT(rc
== RC_OK
);
1767 set_nonblock(rdsock_fd
, 1);
1771 discover_network(0, 0);
1775 struct epoll_event events
[EPOLL_EVENTS
];
1778 if (discover_finished_executed
== 0 && discover_finished
!= 0) {
1779 struct epoll_event rds_epe
;
1781 bzero(&rds_nr
, sizeof(struct nonblock_resumeinfo
));
1782 rds_nr
.fd
= rdsock_fd
;
1783 rds_nr
.type
= EPOLLDATA_RDSOCKCMD
;
1784 bzero(&rds_epe
, sizeof(struct epoll_event
));
1785 rds_epe
.events
= (EPOLLIN
| EPOLLRDHUP
| EPOLLERR
);
1786 rds_epe
.data
.ptr
= &rds_nr
;
1788 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, rdsock_fd
, &rds_epe
);
1790 epoll_add_fwd_to_rservice(&rservice_fwds
);
1792 discover_finished_executed
= 1;
1793 printf("discover finished\n");
1796 rdycnt
= epoll_wait(epoll_fd
, events
, EPOLL_EVENTS
, -1);
1798 for (u
=0;u
<rdycnt
;u
++) {
1799 struct nonblock_resumeinfo
*nr
= events
[u
].data
.ptr
;
1800 __u32 eventflags
= events
[u
].events
;
1801 nonblock_resume(nr
, eventflags
);