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 <sys/epoll.h>
35 #define MAX_ADDRLEN 128
54 #define ROUTE_MAXHOPS 7
59 struct route_list routes
;
61 struct service_list services
;
67 struct list_head node_list
;
69 __u32 route
[ROUTE_MAXHOPS
+ 1];
73 #define SEARCHQUERY_NEIGHSNOTQUERIED 1
74 #define SEARCHQUERY_NODEBYADDRESS 2
89 struct route_list localneighs
;
90 struct service_list localservices
;
92 struct list_head node_list
;
94 int discover_finished
= 0;
99 #define EPOLL_EVENTS 16
101 #define EPOLLDATA_DISCOVERNETWORK 1
102 #define EPOLLDATA_RDSCONNECT 2
103 #define EPOLLDATA_RDSOCKCMD 3
105 struct nonblock_resumeinfo_connect_to_host_send
{
111 struct route_list
*routes
;
115 struct nonblock_resumeinfo_connect_to_host_recv
{
124 struct nonblock_resumeinfo
{
135 struct route_list
*list
;
136 struct service_list
*service
;
138 struct nonblock_resumeinfo_connect_to_host_send connect_send
;
139 struct nonblock_resumeinfo_connect_to_host_recv connect_recv
;
141 struct libcor_nonblock_resumeinfo lnr
;
150 struct nonblock_resumeinfo_connect_to_host_send connect_send
;
151 struct nonblock_resumeinfo_connect_to_host_recv connect_resp
;
153 struct libcor_nonblock_resumeinfo lnr
;
157 struct libcor_nonblock_resumeinfo lnr
;
162 #define offsetof(type, member) __builtin_offsetof (type, member)
164 #define container_of(ptr, type, member) ({ \
165 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
166 (type *)( (char *)__mptr - offsetof(type,member) );})
169 static void set_nonblock(int fd
, int value
)
173 flags
= fcntl(fd
, F_GETFL
, 0);
175 perror("set_nonblock F_GETFL");
179 flags
= (flags
& (~(O_NONBLOCK
)));
181 flags
= flags
| O_NONBLOCK
;
183 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
184 perror("set_nonblock F_SETFL");
189 static int addr_eq(char *addr1
, __u32 addrlen1
,
190 char *addr2
, __u32 addrlen2
)
192 __u16 cmplen
= addrlen1
;
195 if (addrlen2
< cmplen
)
198 if (cmplen
> MAX_ADDRLEN
)
201 if (memcmp(addr1
, addr2
, cmplen
) != 0)
204 for (u
=cmplen
;u
<addrlen1
;u
++) {
209 for (u
=cmplen
;u
<addrlen2
;u
++) {
217 static int node_matches_searchquery(struct node
*n
, struct search_query
*q
)
219 if (q
->type
== SEARCHQUERY_NEIGHSNOTQUERIED
) {
220 return n
->neighs_queried
== 0;
221 } else if (q
->type
== SEARCHQUERY_NODEBYADDRESS
) {
222 return addr_eq(n
->addr
, n
->addrlen
,
223 q
->query
.nodebyaddress
.addr
,
224 q
->query
.nodebyaddress
.addrlen
);
231 static struct node
* try_find_neigh(struct search_query
*q
)
233 struct list_head
*curr
= node_list
.next
;
235 while (curr
!= &node_list
) {
236 struct node
*currnode
= container_of(curr
, struct node
,
239 if (node_matches_searchquery(currnode
, q
)) {
249 static struct node
* try_find_neigh_byaddr(__u16 addrlen
, char *addr
)
251 struct search_query q
;
252 bzero(&q
, sizeof(struct search_query
));
253 q
.type
= SEARCHQUERY_NODEBYADDRESS
;
254 q
.query
.nodebyaddress
.addrlen
= addrlen
;
255 q
.query
.nodebyaddress
.addr
= addr
;
256 return try_find_neigh(&q
);
259 static int check_rc(int rc
, char *errormsg
)
261 if (rc
!= RC_OK
&& rc
!= RC_WOULDBLOCK
)
262 printf("%s\n", errormsg
);
263 return (rc
!= RC_OK
);
266 static int connect_to_host_recv(int fd
, struct libcor_nonblock_resumeinfo
*lnr
,
267 struct nonblock_resumeinfo_connect_to_host_recv
*rcr
,
270 if (rcr
->state
== 0) {
278 assert(rcr
->fd
= fd
);
279 assert(rcr
->node
= node
);
281 assert(node
->hopcount
!= 0);
283 for (;rcr
->u
< node
->hopcount
;rcr
->u
++) {
284 int rc
= read_resp_nonblock(fd
, lnr
);
288 bzero(rcr
, sizeof(struct nonblock_resumeinfo_connect_to_host_recv
));
292 static int connect_to_host_send(int fd
,
293 struct libcor_nonblock_resumeinfo
*lnr
,
294 struct nonblock_resumeinfo_connect_to_host_send
*cth
,
297 if (cth
->state
== 0) {
301 cth
->routes
= &localneighs
;
307 assert(cth
->fd
= fd
);
308 assert(cth
->node
= node
);
310 assert(node
->hopcount
!= 0);
312 for (;cth
->u
< node
->hopcount
;) {
313 struct node
*n
= cth
->routes
->routes
[node
->route
[cth
->u
]].dst
;
314 int rc
= send_connect_neigh_nonblock(fd
, lnr
, n
->addrlen
,
319 cth
->routes
= &(n
->routes
);
321 bzero(cth
, sizeof(struct nonblock_resumeinfo_connect_to_host_send
));
325 void add_neigh(void *ptr
, __u32 addrlen
, char *addr
)
327 struct route_list
*list
= (struct route_list
*) ptr
;
330 if (addrlen
> MAX_ADDRLEN
)
333 if (list
->numroutes
>= list
->rows_alloc
)
336 assert(list
->routes
[list
->numroutes
].dst
== 0);
338 node
= try_find_neigh_byaddr(addrlen
, addr
);
341 node
= calloc(1, sizeof(struct node
));
343 node
->addr
= malloc(((int) addrlen
));
344 node
->addrlen
= addrlen
;
345 memcpy(node
->addr
, addr
, addrlen
);
347 list_add_tail(&(node
->node_list
), &node_list
);
350 list
->routes
[list
->numroutes
].dst
= node
;
354 void init_neighlist(void *ptr
, __u32 numneighs
)
356 struct route_list
*list
= (struct route_list
*) ptr
;
360 list
->rows_alloc
= (__u16
) numneighs
;
361 list
->routes
= calloc(numneighs
, sizeof(struct route
));
364 void add_service(void *ptr
, __be16 port
)
366 struct service_list
*list
= (struct service_list
*) ptr
;
368 printf("add service %u\n", ntohs(port
));
370 if (list
->numports
>= list
->rows_alloc
)
373 list
->ports
[list
->numports
] = port
;
377 void init_servicelist(void *ptr
, __u32 numservices
)
379 struct service_list
*list
= (struct service_list
*) ptr
;
381 printf("init servicelist %u\n", numservices
);
383 if (numservices
> 16)
385 list
->rows_alloc
= (__u16
) numservices
;
386 list
->ports
= calloc(numservices
, 2);
389 static void print_hex(char *buf
, int len
)
393 printf("%hhx ", buf
[u
]);
397 void neigh_printaddr(__u16 addrlen
, char *addr
)
399 printf("addrlen = %d addr: ", (int) addrlen
);
400 print_hex(addr
, addrlen
);
405 static void __recalc_routes(struct node
*node
)
407 struct list_head
*curr
;
409 curr
= node_list
.next
;
410 while (curr
!= &node_list
) {
411 struct node
*currnode
= container_of(curr
, struct node
,
414 if (currnode
->hopcount
< node
->hopcount
)
420 list_del(&(node
->node_list
));
421 list_add_tail(&(node
->node_list
), curr
);
424 static void _recalc_routes(struct node
*node
)
426 struct route_list
*routes
= (node
== 0 ?
427 &localneighs
: &(node
->routes
));
431 for (u
=0;u
<routes
->numroutes
;u
++) {
432 struct node
*target
= routes
->routes
[u
].dst
;
434 __u32 hopcount
= (node
== 0 ? 0 : node
->hopcount
) + 1;
436 if (target
->hopcount
!= 0 && target
->hopcount
<= hopcount
)
440 bzero(&(target
->route
[0]), sizeof(target
->route
));
442 memcpy(&(target
->route
[0]), &(node
->route
[0]),
443 sizeof(target
->route
));
446 target
->hopcount
= hopcount
;
447 target
->route
[hopcount
-1] = u
;
449 __recalc_routes(target
);
453 static void recalc_routes(void)
455 struct list_head oldnodes
;
456 struct list_head
*curr
;
458 list_add(&oldnodes
, &node_list
);
459 list_del(&node_list
);
460 init_list_head(&node_list
);
463 curr
= oldnodes
.next
;
464 while (curr
!= &oldnodes
) {
465 struct node
*currnode
= container_of(curr
, struct node
,
468 bzero(&(currnode
->route
[0]), sizeof(currnode
->route
));
469 currnode
->hopcount
= 0;
477 curr
= node_list
.next
;
478 while (curr
!= &node_list
) {
479 struct node
*currnode
= container_of(curr
, struct node
,
482 _recalc_routes(currnode
);
488 curr
= oldnodes
.next
;
489 while (curr
!= &oldnodes
) {
490 struct node
*currnode
= container_of(curr
, struct node
,
495 list_del(&(currnode
->node_list
));
497 if (currnode
->addr
!= 0) {
498 free(currnode
->addr
);
506 void load_neigh_list(int fd
, struct nonblock_resumeinfo
*nr
, struct node
*node
)
508 struct libcor_nonblock_resumeinfo
*lnr
;
511 assert((fd
== 0 && nr
== 0) || (fd
!= 0 && nr
!= 0));
513 if (fd
== 0 && nr
== 0) {
514 struct epoll_event epe
;
516 fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RAW
);
522 rc
= connect(fd
, 0, 0);
530 nr
= (struct nonblock_resumeinfo
*)
531 malloc(sizeof(struct nonblock_resumeinfo
));
532 bzero(nr
, sizeof(struct nonblock_resumeinfo
));
534 nr
->type
= EPOLLDATA_DISCOVERNETWORK
;
535 nr
->data
.discover_network
.node
= node
;
537 epe
.events
= (EPOLLIN
| EPOLLOUT
| EPOLLRDHUP
| EPOLLERR
|
540 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, fd
, &epe
);
543 lnr
= &(nr
->data
.discover_network
.lnr
);
545 assert(nr
->type
== EPOLLDATA_DISCOVERNETWORK
);
546 assert(nr
->data
.discover_network
.node
== node
);
548 if (nr
->data
.discover_network
.state
== 1) {
550 } else if (nr
->data
.discover_network
.state
== 2) {
552 } else if (nr
->data
.discover_network
.state
== 3) {
554 } else if (nr
->data
.discover_network
.state
== 4) {
556 } else if (nr
->data
.discover_network
.state
== 5) {
558 } else if (nr
->data
.discover_network
.state
== 6) {
560 } else if (nr
->data
.discover_network
.state
== 7) {
562 } else if (nr
->data
.discover_network
.state
== 8) {
564 } else if (nr
->data
.discover_network
.state
!= 0) {
569 nr
->data
.discover_network
.list
= &localneighs
;
570 nr
->data
.discover_network
.service
= &localservices
;
572 neigh_printaddr(node
->addrlen
,
574 nr
->data
.discover_network
.list
= &(node
->routes
);
575 nr
->data
.discover_network
.service
= &(node
->services
);
577 nr
->data
.discover_network
.state
= 1;
579 rc
= connect_to_host_send(fd
, lnr
,
580 &(nr
->data
.discover_network
.connect_send
),
583 if (check_rc(rc
, "load_neigh_list: connect_to_host_send error"))
587 rc
= send_list_neigh_nonblock(fd
, lnr
);
588 nr
->data
.discover_network
.state
= 2;
589 if (check_rc(rc
, "load_neigh_list: send_list_neigh error"))
593 rc
= send_list_services_nonblock(fd
, lnr
);
594 nr
->data
.discover_network
.state
= 3;
595 if (check_rc(rc
, "load_neigh_list: send_list_services error"))
600 nr
->data
.discover_network
.state
= 4;
602 rc
= connect_to_host_recv(fd
, lnr
,
603 &(nr
->data
.discover_network
.connect_recv
),
605 if (check_rc(rc
, "load_neigh_list: connect_to_host_recv error"))
609 nr
->data
.discover_network
.state
= 5;
611 rc
= read_resp_nonblock(fd
, lnr
);
612 if (check_rc(rc
, "load_neigh_list: read_resp error"))
615 nr
->data
.discover_network
.state
= 6;
617 rc
= read_neigh_list_nonblock(fd
, lnr
, nr
->data
.discover_network
.list
,
618 init_neighlist
, add_neigh
);
619 if (check_rc(rc
, "load_neigh_list: read_neigh_list error"))
622 nr
->data
.discover_network
.state
= 7;
624 rc
= read_resp_nonblock(fd
, lnr
);
625 if (check_rc(rc
, "load_neigh_list: read_resp error"))
628 nr
->data
.discover_network
.state
= 8;
630 rc
= read_service_list_nonblock(fd
, lnr
,
631 nr
->data
.discover_network
.service
,
632 init_servicelist
, add_service
);
633 if (check_rc(rc
, "load_neigh_list: read_service_list error"))
636 #warning todo rollback node->routes and node->services on error
639 //printf("load_neigh_list state %d\n", nr->data.discover_network.state);
640 if (rc
!= RC_WOULDBLOCK
) {
641 printf("load_neigh_list rc %d\n", rc
);
651 static void discover_network(int fd
, struct nonblock_resumeinfo
*nr
)
653 struct search_query q
;
654 bzero(&q
, sizeof(struct search_query
));
655 q
.type
= SEARCHQUERY_NEIGHSNOTQUERIED
;
657 assert((fd
== 0 && nr
== 0) || (fd
!= 0 && nr
!= 0));
659 if (fd
== 0 && nr
== 0)
660 load_neigh_list(fd
, nr
, 0);
665 node
= try_find_neigh(&q
);
669 assert(nr
->type
== EPOLLDATA_DISCOVERNETWORK
);
670 node
= nr
->data
.discover_network
.node
;
673 load_neigh_list(fd
, nr
, node
);
674 node
->neighs_queried
= 1;
678 discover_finished
= 1;
681 struct rdscmd_connect_data
{
683 struct nonblock_resumeinfo
*nr
;
686 //cookie+addr are not passed on nonblocking resume
687 static int rdscmd_void_connect(void *ptr
, __u64 cookie
,
688 struct cor_sockaddr
*addr
)
691 struct rdscmd_connect_data
*rcd
= ((struct rdscmd_connect_data
*) ptr
);
693 struct libcor_nonblock_resumeinfo
*lnr
;
696 struct epoll_event epe
;
699 if (addr
->sin_family
!= AF_COR
) {
700 printf("rds_connect %llu not af_cor\n", cookie
);
704 printf("rds_connect cookie: %llu, addr: ", cookie
);
705 print_hex(&(addr
->addr
[0]), sizeof(addr
->addr
));
706 printf(" port: %u\n", ntohs(addr
->port
));
709 if ((node
= try_find_neigh_byaddr(sizeof(addr
->addr
),
710 &(addr
->addr
[0]))) == 0) {
711 printf("connect_to_host host not found\n");
716 fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RAW
);
722 rc
= connect(fd
, 0, 0);
730 rcd
->nr
= (struct nonblock_resumeinfo
*)
731 malloc(sizeof(struct nonblock_resumeinfo
));
732 bzero(rcd
->nr
, sizeof(struct nonblock_resumeinfo
));
734 rcd
->nr
->type
= EPOLLDATA_RDSCONNECT
;
735 rcd
->nr
->data
.rds_connect
.node
= node
;
737 epe
.events
= (EPOLLIN
| EPOLLOUT
| EPOLLRDHUP
| EPOLLERR
|
739 epe
.data
.ptr
= rcd
->nr
;
740 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, fd
, &epe
);
743 lnr
= &(rcd
->nr
->data
.rds_connect
.lnr
);
745 assert(rcd
->nr
->type
== EPOLLDATA_RDSCONNECT
);
747 if (rcd
->nr
->data
.rds_connect
.state
== 1) {
749 } else if (rcd
->nr
->data
.rds_connect
.state
== 2) {
751 } else if (rcd
->nr
->data
.rds_connect
.state
== 3) {
753 } else if (rcd
->nr
->data
.rds_connect
.state
!= 0) {
757 rc
= connect_to_host_send(fd
, lnr
,
758 &(rcd
->nr
->data
.rds_connect
.connect_send
),
759 rcd
->nr
->data
.rds_connect
.node
);
760 rcd
->nr
->data
.rds_connect
.state
= 1;
762 printf("connect_to_host_send error\n");
767 rc
= send_connect_port_nonblock(fd
, lnr
, addr
->port
);
768 rcd
->nr
->data
.rds_connect
.state
= 2;
770 printf("send_connect_port error\n");
776 rc
= connect_to_host_recv(fd
, lnr
,
777 &(rcd
->nr
->data
.rds_connect
.connect_resp
),
778 rcd
->nr
->data
.rds_connect
.node
);
780 printf("connect_to_host_recv error\n");
784 rcd
->nr
->data
.rds_connect
.state
= 3;
786 rc
= read_resp_nonblock(fd
, lnr
);
788 printf("read_resp error\n");
792 rc
= pass_socket(fd
, cookie
);
794 printf("pass_socket error\n");
801 #warning todo rdsock resumeinfo
803 printf("send_rdsock_connecterror\n");
804 rc
= send_rdsock_connecterror(rdsock_fd
, cookie
,
805 CONNECTERROR_NETUNREACH
);
807 printf("send_rdsock_connecterror returned %d\n", rc
);
815 static int proc_rdsock_cmd(int fd
, struct rdsock_cmd
*cmd
)
817 if (cmd
->cmd
== CRD_KTU_CONNECT
) {
818 struct rdscmd_connect_data data
;
819 return parse_rdsock_connect(&data
, cmd
, rdscmd_void_connect
);
821 printf("error in proc_rdsock_cmd: unknown cmd: %u\n", cmd
->cmd
);
824 return RC_CONNBROKEN
;
828 static void nonblock_resume(struct nonblock_resumeinfo
*nr
)
830 #warning todo call rdscmd_void_connect
831 if (nr
->type
== EPOLLDATA_DISCOVERNETWORK
) {
832 int rc
= resume_send_ifneeded(nr
->fd
,
833 &(nr
->data
.discover_network
.lnr
));
835 //printf("load_neigh_list state = %d rc = %d\n", nr->data.discover_network.state, rc);
840 discover_network(nr
->fd
, nr
);
847 static int parse_hexchar(char c
)
869 else if (c
== 'A' || c
== 'a')
871 else if (c
== 'B' || c
== 'b')
873 else if (c
== 'C' || c
== 'c')
875 else if (c
== 'D' || c
== 'd')
877 else if (c
== 'E' || c
== 'e')
879 else if (c
== 'F' || c
== 'f')
885 static int parse_hex(char *target
, char *src
, int srclen
)
892 assert((srclen
%2) == 0);
894 for(u
=0;u
<(srclen
/2);u
++) {
895 int high
= parse_hexchar(src
[u
*2]);
896 int low
= parse_hexchar(src
[u
*2+1]);
898 if (high
== -1 || low
== -1)
901 target
[u
] = (char) ((high
<< 4) + low
);
907 int parse_addr(char *argv_addr
)
910 int len
= strlen(argv_addr
);
911 char *noaddr
= "noaddr";
913 if (strncmp(argv_addr
, noaddr
, len
) == 0) {
919 if ((len
< 2) || (len
%2) != 0)
922 localaddr
= malloc(len
/2);
923 localaddrlen
= len
/2;
925 rc
= parse_hex(localaddr
, argv_addr
, len
);
932 fprintf(stderr
, "error: argv_addr is not a valid address (contains "
933 "non-hex characters or number of hex characters is not "
934 "a multiple of 2)\n");
938 int main(int argc
, char *argv
[])
941 struct epoll_event rds_epe
;
942 struct nonblock_resumeinfo rds_nr
;
944 discover_finished
= 0;
950 rc
= parse_addr(argv
[1]);
954 init_list_head(&node_list
);
957 epoll_fd
= epoll_create(1);
959 perror("epoll_create");
964 rdsock_fd
= socket(PF_COR
, SOCK_RAW
, PROTO_COR_RDEAMON
);
970 rc
= connect(rdsock_fd
, 0, 0);
977 bzero(&rds_nr
, sizeof(struct nonblock_resumeinfo
));
978 rds_nr
.fd
= rdsock_fd
;
979 rds_nr
.type
= EPOLLDATA_RDSOCKCMD
;
980 rds_epe
.events
= (EPOLLIN
| EPOLLRDHUP
| EPOLLERR
);
981 rds_epe
.data
.ptr
= &rds_nr
;
984 send_rdsock_up(rdsock_fd
, localaddr
, localaddrlen
);
988 discover_network(0, 0);
991 int discover_finished_old
= discover_finished
;
993 struct epoll_event events
[EPOLL_EVENTS
];
995 int rdycnt
= epoll_wait(epoll_fd
, events
, EPOLL_EVENTS
, -1);
997 for (u
=0;u
<rdycnt
;u
++) {
998 struct nonblock_resumeinfo
*nr
= events
[u
].data
.ptr
;
1002 if (discover_finished_old
== 0 && discover_finished
!= 0) {
1003 epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, rdsock_fd
, &rds_epe
);
1009 struct rdsock_cmd cmd
;
1011 rc
= read_rdsock_cmd(rdsock_fd
, &cmd
);
1013 printf("read_rdsock_cmd rc = %d\n", rc
);
1017 rc
= proc_rdsock_cmd(rdsock_fd
, &cmd
);
1018 free_rdsockcmd_data(&cmd
);
1020 printf("proc_rdsock_cmd rc = %d\n", rc
);
1027 fprintf(stderr
, "usage test_routed addr\n");