capabilities cmd
[corutils.git] / test_routed2.c
blob22e8b479e010a4f1a637656b9cff1874610f5a1e
1 /**
2 * Connection oriented routing user space utils
3 * Copyright (C) 2009-2014
4 * Authors:
5 * Michael Blizek
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
20 * 02110-1301, USA.
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/socket.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <arpa/inet.h>
30 #include <errno.h>
31 #include <sys/epoll.h>
33 #include "list.h"
34 #include "libcor.h"
37 #define U32_MAX ((__u32) ((1LL << 32) - 1))
40 #define MAX_ADDRLEN 128
42 #define ASSERT_ERR() \
43 do { \
44 assert(0); \
45 exit(1); \
46 while (1) { \
47 } \
48 } while(0) \
51 #define ASSERT(a) \
52 do { \
53 if (!(a)) { ASSERT_ERR(); } \
54 } while(0) \
57 struct route{
58 struct node *dst;
61 struct route_list{
62 struct route *routes;
63 __u16 rows_alloc;
64 __u16 numroutes;
67 struct service_list{
68 __be16 *ports;
69 __u16 rows_alloc;
70 __u16 numports;
73 #define ROUTE_MAXHOPS 7
75 struct node{
76 char *addr;
78 struct route_list routes;
80 struct service_list services;
82 __u32 addrlen;
83 __u16 minhops;
84 __u8 neighs_queried;
86 struct list_head node_list;
88 __u32 route[ROUTE_MAXHOPS + 1];
89 __u32 hopcount;
92 #define SEARCHQUERY_NEIGHSNOTQUERIED 1
93 #define SEARCHQUERY_NODEBYADDRESS 2
94 #define SEARCHQUERY_NODEBYSERVICEPORT 3
95 struct search_query{
96 int type;
97 union {
98 struct {
99 __u32 addrlen;
100 char *addr;
101 }nodebyaddress;
103 __be16 serviceport;
104 }query;
108 char *localaddr;
109 __u32 localaddrlen;
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;
119 int epoll_fd = 0;
121 int rdsock_fd = 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{
132 int fd;
133 struct node *node;
135 __u8 state;
137 struct route_list *routes;
138 int u;
141 struct nonblock_resumeinfo_connect_to_host_recv{
142 int fd;
143 struct node *node;
145 __u8 state;
147 int u;
150 #define FORWARD_BUF_SIZE 4096
152 struct nonblock_resumeinfo{
153 int fd;
155 __u8 type;
157 union{
158 struct{
159 struct node *node;
161 __u8 state;
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;
170 }discover_network;
172 struct{
173 __u8 state;
175 __u64 cookie;
176 struct node *node;
177 __be16 port;
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;
183 }rds_connect;
185 struct{
186 struct libcor_nonblock_resumeinfo lnr;
187 }rdsock_cmd;
189 struct{
190 __be16 targetport;
191 }fwd_to_rservice;
193 struct{
195 * buf gets filled by reversedir and written into
196 * this fd
198 char *buf;
199 __u32 buffill;
200 __u32 bufwritten;
202 __u8 is_connected;
204 struct nonblock_resumeinfo *reversedir;
205 }forward;
206 }data;
209 struct fwd_to_rservice_item{
210 struct list_head allfwds;
212 int bindfd;
214 __be16 targetport;
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)
228 int flags;
230 flags = fcntl(fd, F_GETFL, 0);
231 if (flags == -1) {
232 perror("set_nonblock F_GETFL");
233 exit(1);
236 flags = (flags & (~(O_NONBLOCK)));
237 if (value)
238 flags = flags | O_NONBLOCK;
240 if (fcntl(fd, F_SETFL, flags) == -1) {
241 perror("set_nonblock F_SETFL");
242 exit(1);
246 static int addr_eq(char *addr1, __u32 addrlen1,
247 char *addr2, __u32 addrlen2)
249 while (addrlen1>0) {
250 if (addr1[addrlen1-1] == 0) {
251 addrlen1--;
252 } else {
253 break;
257 while (addrlen2>0) {
258 if (addr2[addrlen2-1] == 0) {
259 addrlen2--;
260 } else {
261 break;
265 if (addrlen1 != addrlen2)
266 return 0;
268 if (addrlen1 > MAX_ADDRLEN)
269 return 0;
271 if (addrlen1 != 0 && memcmp(addr1, addr2, addrlen1) != 0)
272 return 0;
274 return 1;
277 static int service_list_contains(struct service_list *services, __be16 port)
279 __u32 u;
281 for (u=0;u<services->numports;u++) {
282 if (services->ports[u] == port) {
283 return 1;
287 return 0;
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,
295 localaddrlen) == 0;
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);
303 } else {
304 ASSERT(0);
305 return 0;
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,
315 node_list);
317 if (node_matches_searchquery(currnode, q)) {
318 return currnode;
321 curr = curr->next;
324 return 0;
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,
356 struct node *node)
358 if (rcr->state == 0) {
359 rcr->fd = fd;
360 rcr->node = node;
362 rcr->state = 1;
363 rcr->u=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);
373 if (rc != RC_OK)
374 return rc;
376 bzero(rcr, sizeof(struct nonblock_resumeinfo_connect_to_host_recv));
377 return RC_OK;
380 static int connect_to_host_send(int fd,
381 struct libcor_nonblock_resumeinfo *lnr,
382 struct nonblock_resumeinfo_connect_to_host_send *cth,
383 struct node *node)
385 if (cth->state == 0) {
386 cth->fd = fd;
387 cth->node = node;
389 cth->routes = &localneighs;
391 cth->state = 1;
392 cth->u=0;
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,
403 n->addr);
404 cth->u++;
405 if (rc != RC_OK)
406 return rc;
407 cth->routes = &(n->routes);
409 bzero(cth, sizeof(struct nonblock_resumeinfo_connect_to_host_send));
410 return RC_OK;
413 static void add_neigh(void *ptr, __u32 addrlen, char *addr)
415 struct route_list *list = (struct route_list *) ptr;
416 struct node *node;
418 if (addrlen > MAX_ADDRLEN)
419 return;
421 if (addr_eq(addr, addrlen, 0, 0))
422 return;
424 if (list->numroutes >= list->rows_alloc)
425 return;
427 ASSERT(list->routes[list->numroutes].dst == 0);
429 node = try_find_neigh_byaddr(addrlen, addr);
431 if (node == 0) {
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;
442 list->numroutes++;
445 static void init_neighlist(void *ptr, __u32 numneighs)
447 struct route_list *list = (struct route_list *) ptr;
448 if (numneighs > 16)
449 numneighs = 16;
450 #warning todo limit
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)
462 return;
464 list->ports[list->numports] = port;
465 list->numports++;
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)
475 numservices = 16;
476 list->rows_alloc = (__u16) numservices;
477 list->numports = 0;
478 list->ports = calloc(numservices, 2);
481 static void print_hex(char *buf, __u32 len)
483 __u32 u;
485 ASSERT(len != U32_MAX);
487 for(u=0;u<len;u++) {
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);
496 printf("\n");
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);
509 if (written <= 0) {
510 if (errno == EINTR)
511 continue;
513 perror("export servicelist");
514 return 1;
517 totalwritten += written;
520 return 0;
523 static int _export_servicelist(int fd, char *addr, __u32 addrlen, __u32 cost,
524 struct service_list *services)
526 __u32 u;
527 char buf[24];
528 int rc;
530 for (u=0;u<services->numports;u++) {
531 __u32 v;
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]);
538 else
539 rc = snprintf(&(buf[0]), 20, "%hhx", addr[v]);
540 ASSERT(rc > 0);
541 ASSERT(rc < 20);
543 rc = __export_servicelist(fd, &(buf[0]), rc);
544 if (rc != 0)
545 return 1;
548 rc = snprintf(&(buf[0]), 20, ":%hu:%u\n",
549 ntohs(services->ports[u]), cost);
550 ASSERT(rc > 0);
551 ASSERT(rc < 20);
553 rc = __export_servicelist(fd, &(buf[0]), rc);
554 if (rc != 0)
555 return 1;
558 return 0;
561 static void export_servicelist(void)
563 char *servicelist_txtfile = "/var/lib/cor/services/txt";
564 char *servicelist_tmpfile = "/var/lib/cor/services/tmp";
566 int fd = 0;
567 struct list_head *curr;
569 if (export_servicelist_enabled == 0)
570 return;
572 fd = open(servicelist_tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
573 if (fd <= 0) {
574 perror("export servicelist");
575 return;
578 if (_export_servicelist(fd, 0, 0, 0, &localservices) != 0)
579 goto err;
581 curr = node_list.next;
582 while (curr != &node_list) {
583 struct node *currnode = container_of(curr, struct node,
584 node_list);
586 curr = curr->next;
588 if (addr_eq(currnode->addr, currnode->addrlen, localaddr,
589 localaddrlen) != 0)
590 continue;
592 if (_export_servicelist(fd, currnode->addr, currnode->addrlen,
593 currnode->hopcount, &(currnode->services)) != 0)
594 goto err;
597 fsync(fd);
598 close(fd);
600 if (rename(servicelist_tmpfile, servicelist_txtfile) != 0) {
601 perror("export servicelist");
602 goto err2;
605 if (0) {
606 err:
607 close(fd);
608 err2:
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,
620 node_list);
622 if (currnode->hopcount < node->hopcount)
623 break;
625 curr = curr->next;
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));
637 __u32 u;
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)
645 continue;
647 if (node == 0) {
648 bzero(&(target->route[0]), sizeof(target->route));
649 } else {
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,
674 node_list);
676 bzero(&(currnode->route[0]), sizeof(currnode->route));
677 currnode->hopcount = 0;
679 curr = curr->next;
683 _recalc_routes(0);
685 curr = node_list.next;
686 while (curr != &node_list) {
687 struct node *currnode = container_of(curr, struct node,
688 node_list);
690 _recalc_routes(currnode);
692 curr = curr->next;
696 curr = oldnodes.next;
697 while (curr != &oldnodes) {
698 struct node *currnode = container_of(curr, struct node,
699 node_list);
701 curr = curr->next;
703 list_del(&(currnode->node_list));
705 if (currnode->addr != 0) {
706 free(currnode->addr);
707 currnode->addr = 0;
710 free(currnode);
713 export_servicelist();
716 static int load_neigh_list(int fd, struct nonblock_resumeinfo *nr,
717 struct node *node)
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);
728 if(fd < 0) {
729 perror("socket");
730 goto early_out;
733 rc = connect(fd, 0, 0);
734 if(rc < 0) {
735 perror("connect");
736 goto out;
739 set_nonblock(fd, 1);
741 nr = (struct nonblock_resumeinfo *)
742 malloc(sizeof(struct nonblock_resumeinfo));
743 bzero(nr, sizeof(struct nonblock_resumeinfo));
744 nr->fd = fd;
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 |
750 EPOLLET);
751 epe.data.ptr = nr;
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) {
761 goto state_1;
762 } else if (nr->data.discover_network.state == 2) {
763 goto state_2;
764 } else if (nr->data.discover_network.state == 3) {
765 goto state_3;
766 } else if (nr->data.discover_network.state == 4) {
767 goto state_4;
768 } else if (nr->data.discover_network.state == 5) {
769 goto state_5;
770 } else if (nr->data.discover_network.state == 6) {
771 goto state_6;
772 } else if (nr->data.discover_network.state == 7) {
773 goto state_7;
774 } else if (nr->data.discover_network.state == 8) {
775 goto state_8;
776 } else if (nr->data.discover_network.state != 0) {
777 ASSERT(0);
780 if (node == 0) {
781 nr->data.discover_network.list = &localneighs;
782 nr->data.discover_network.service = &localservices;
783 } else {
784 neigh_printaddr(node->addrlen,
785 node->addr);
786 nr->data.discover_network.list = &(node->routes);
787 nr->data.discover_network.service = &(node->services);
789 nr->data.discover_network.state = 1;
790 state_1:
791 rc = connect_to_host_send(fd, lnr,
792 &(nr->data.discover_network.connect_send),
793 node);
795 if (check_rc(rc, "load_neigh_list: connect_to_host_send error"))
796 goto out;
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"))
802 goto out;
804 state_2:
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"))
808 goto out;
810 state_3:
811 if (node != 0) {
812 nr->data.discover_network.state = 4;
813 state_4:
814 rc = connect_to_host_recv(fd, lnr,
815 &(nr->data.discover_network.connect_recv),
816 node);
817 if (check_rc(rc, "load_neigh_list: connect_to_host_recv error"))
818 goto out;
821 nr->data.discover_network.state = 5;
822 state_5:
823 rc = read_resp_nonblock(fd, lnr);
824 if (check_rc(rc, "load_neigh_list: read_resp error"))
825 goto out;
827 nr->data.discover_network.state = 6;
828 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"))
832 goto out;
834 nr->data.discover_network.state = 7;
835 state_7:
836 rc = read_resp_nonblock(fd, lnr);
837 if (check_rc(rc, "load_neigh_list: read_resp error"))
838 goto out;
840 nr->data.discover_network.state = 8;
841 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"))
846 goto out;
848 #warning todo rollback node->routes and node->services on error
849 recalc_routes();
850 out:
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);
854 close(fd);
855 if (nr != 0)
856 free(nr);
859 early_out:
860 return rc;
863 static void discover_network(int fd, struct nonblock_resumeinfo *nr)
865 int rc;
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)
876 return;
879 while (1) {
880 struct node *node;
881 if (nr == 0) {
882 node = try_find_neigh(&q);
883 if (node == 0)
884 break;
885 } else {
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)
892 return;
893 node->neighs_queried = 1;
894 fd = 0;
895 nr = 0;
897 discover_finished = 1;
900 static void send_unreach_error(__u64 cookie)
902 int rc;
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);
908 ASSERT(rc == RC_OK);
911 //cookie+addr are not passed on nonblocking resume
912 static void _rdscmd_void_connect(struct nonblock_resumeinfo *nr)
914 int rc = RC_OK;
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) {
921 goto state_1;
922 } else if (nr->data.rds_connect.state == 2) {
923 goto state_2;
924 } else if (nr->data.rds_connect.state == 3) {
925 goto state_3;
926 } else if (nr->data.rds_connect.state != 0) {
927 ASSERT(0);
930 if (nr->data.rds_connect.node == 0)
931 rc = RC_OK;
932 else
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"))
938 goto out;
940 state_1:
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"))
944 goto out;
946 state_2:
947 if (nr->data.rds_connect.node == 0)
948 rc = RC_OK;
949 else
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"))
954 goto out;
956 nr->data.rds_connect.state = 3;
957 state_3:
958 rc = read_resp_nonblock(nr->fd, lnr);
959 if (check_rc(rc, "_rdscmd_void_connect: read_resp error"))
960 goto out;
962 rc = pass_socket(nr->fd, nr->data.rds_connect.cookie);
963 if (rc != RC_OK) {
964 printf("pass_socket error\n");
965 goto err;
968 return;
970 out:
971 if (rc == RC_WOULDBLOCK)
972 return;
974 err:
975 close(nr->fd);
976 send_unreach_error(nr->data.rds_connect.cookie);
979 static int rdscmd_void_connect(void *ptr, __u64 cookie,
980 struct cor_sockaddr *addr)
982 int fd, rc;
983 struct nonblock_resumeinfo *nr;
985 struct epoll_event epe;
986 struct node *node;
988 if (addr->sin_family != AF_COR) {
989 printf("rds_connect %llu not af_cor\n", cookie);
990 goto out_noclose;
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) {
1000 node = 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");
1004 goto out_noclose;
1008 fd = socket(PF_COR, SOCK_RAW, PROTO_COR_RAW);
1009 if(fd < 0) {
1010 perror("socket");
1011 goto out_noclose;
1014 rc = connect(fd, 0, 0);
1015 if(rc < 0) {
1016 perror("connect");
1017 goto out;
1020 set_nonblock(fd, 1);
1022 nr = (struct nonblock_resumeinfo *)
1023 malloc(sizeof(struct nonblock_resumeinfo));
1024 bzero(nr, sizeof(struct nonblock_resumeinfo));
1025 nr->fd = fd;
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 |
1033 EPOLLET);
1034 epe.data.ptr = nr;
1035 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &epe);
1037 _rdscmd_void_connect(nr);
1039 if (0) {
1040 out:
1041 close(fd);
1042 out_noclose:
1043 send_unreach_error(cookie);
1045 return 0;
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);
1052 } else {
1053 printf("error in proc_rdsock_cmd: unknown cmd: %u\n", cmd->cmd);
1054 ASSERT(0);
1055 return 1;
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));
1067 nr->fd = fd;
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);
1072 epe.data.ptr = nr;
1074 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, nr->fd, &epe);
1076 return nr;
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)
1090 while (1) {
1091 int localfd;
1092 struct node *node;
1093 struct cor_sockaddr addr;
1094 int remotefd;
1096 localfd = accept(listenerfd, 0, 0);
1097 if (localfd < 0)
1098 return;
1100 set_nonblock(localfd, 1);
1102 if (service_list_contains(&(localservices), targetport) != 0) {
1103 node = 0;
1104 } else if ((node = try_find_neigh_byservice(targetport)) == 0) {
1105 printf("fwd_to_rservice_accept no host with service found\n");
1106 goto failed;
1109 bzero(&addr, sizeof(struct cor_sockaddr));
1110 addr.sin_family = AF_COR;
1111 addr.port = targetport;
1113 if (node != 0) {
1114 if (node->addrlen > MAX_ADDRLEN)
1115 goto failed;
1116 memcpy(&(addr.addr[0]), node->addr, node->addrlen);
1119 remotefd = socket(PF_COR, SOCK_STREAM, 0);
1120 if (remotefd == -1) {
1121 perror("socket");
1122 goto failed;
1125 set_nonblock(remotefd, 1);
1127 if (connect(remotefd, (struct sockaddr *) &addr,
1128 sizeof(struct cor_sockaddr)) != 0) {
1129 perror("connect");
1130 goto failed;
1133 init_fwd(localfd, remotefd);
1135 if (0) {
1136 failed:
1137 close(localfd);
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;
1150 int more = 0;
1152 ASSERT(buffill <= FORWARD_BUF_SIZE);
1153 ASSERT(nr->data.forward.bufwritten <= buffill);
1155 if (buffill == FORWARD_BUF_SIZE) {
1156 buffill -= 1;
1157 more = 1;
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) {
1170 if (errno == EINTR)
1171 continue;
1173 perror("forward_write");
1174 return RC_FORWARD_ERROR;
1175 } else {
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;
1187 int rc;
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);
1211 if (rc == 0) {
1212 #warning todo eof
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) {
1218 continue;
1219 } else {
1220 perror("forward_read");
1221 return RC_FORWARD_ERROR;
1223 } else {
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)
1234 while (1) {
1235 int rc;
1237 rc = forward_read(nr);
1238 if (rc == RC_FORWARD_ERROR)
1239 goto err;
1240 if (nr->data.forward.bufwritten == nr->data.forward.buffill)
1241 break;
1243 rc = forward_write(nr);
1244 if (rc == RC_FORWARD_ERROR)
1245 goto err;
1246 else if (rc == RC_FORWARD_WOULDBLOCK)
1247 return;
1250 #warning todo call EPOLL_CTL_DEL + free where needed (some places calling close do not)
1251 if (0) {
1252 err:
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);
1257 close(nr->fd);
1259 #warning todo free after all events are processed
1260 /* free(nr->data.forward.reversedir);
1261 free(nr); */
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
1277 == 0)
1278 return;
1280 _forward(nr);
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);
1292 if (rc != RC_OK)
1293 return;
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));
1300 if (rc != RC_OK)
1301 return;
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));
1310 if (rc != RC_OK)
1311 return;
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)
1317 return;
1319 rc = proc_rdsock_cmd(rdsock_fd, &cmd);
1320 free_rdsockcmd_data(&cmd);
1321 ASSERT(rc == 0);
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);
1327 } else {
1328 ASSERT(0);
1332 static int rdsock_negotiate_version(void)
1334 struct rdsock_cmd cmd;
1335 __u32 versionmin = 1000;
1336 __u32 versionmax = 0;
1337 int rc;
1339 rc = read_rdsock_cmd(rdsock_fd, &cmd);
1340 if (rc != RC_OK) {
1341 printf("read_rdsock_cmd rc = %d\n", rc);
1342 return 1;
1345 if (cmd.cmd != CRD_KTU_SUPPORTEDVERSIONS) {
1346 printf("rhsock supportedversions not sent\n", rc);
1347 return 1;
1350 rc = parse_rdsock_supported_versions(&cmd, &versionmin, &versionmax);
1351 if (rc != 0) {
1352 printf("parse_rdsock_supported_versions rc = %d\n", rc);
1353 return 1;
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);
1364 return 1;
1367 rc = send_rdsock_version(rdsock_fd, 0);
1368 ASSERT(rc == RC_OK);
1370 return 0;
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,
1379 allfwds);
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);
1394 epe.data.ptr = nr;
1396 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, item->bindfd, &epe);
1398 list_del(&(item->allfwds));
1399 free(item);
1403 static int parse_hexchar(char c)
1405 if (c == '0')
1406 return 0;
1407 else if (c == '1')
1408 return 1;
1409 else if (c == '2')
1410 return 2;
1411 else if (c == '3')
1412 return 3;
1413 else if (c == '4')
1414 return 4;
1415 else if (c == '5')
1416 return 5;
1417 else if (c == '6')
1418 return 6;
1419 else if (c == '7')
1420 return 7;
1421 else if (c == '8')
1422 return 8;
1423 else if (c == '9')
1424 return 9;
1425 else if (c == 'A' || c == 'a')
1426 return 10;
1427 else if (c == 'B' || c == 'b')
1428 return 11;
1429 else if (c == 'C' || c == 'c')
1430 return 12;
1431 else if (c == 'D' || c == 'd')
1432 return 13;
1433 else if (c == 'E' || c == 'e')
1434 return 14;
1435 else if (c == 'F' || c == 'f')
1436 return 15;
1437 else
1438 return -1;
1441 static int parse_hex(char *target, char *src, int srclen)
1443 int u;
1445 ASSERT(src != 0);
1446 ASSERT(target != 0);
1447 ASSERT(srclen > 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)
1455 return -1;
1457 target[u] = (char) ((high << 4) + low);
1460 return 0;
1463 static int parse_addr(char *argv_addr)
1465 int rc;
1466 int len = strlen(argv_addr);
1467 char *noaddr = "noaddr";
1469 if (strncmp(argv_addr, noaddr, len) == 0) {
1470 localaddr = 0;
1471 localaddrlen = 0;
1472 return;
1475 if ((len < 2) || (len%2) != 0)
1476 goto parseerror;
1478 localaddr = malloc(len/2);
1479 localaddrlen = len/2;
1481 rc = parse_hex(localaddr, argv_addr, len);
1482 if (rc != 0)
1483 goto parseerror;
1485 return 0;
1487 parseerror:
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");
1491 return -1;
1494 static int parse_port(char *arg, __u32 len, __u16 *port)
1496 char *tmpbuf;
1497 char *endptr = 0;
1499 long int tmpport = 0;
1501 tmpbuf = malloc(len+1);
1502 memcpy(tmpbuf, arg, len);
1503 tmpbuf[len] = 0;
1505 tmpport = strtol(tmpbuf, &endptr, 10);
1506 if (tmpbuf[0] == 0 || endptr == 0 || endptr != tmpbuf + len) {
1507 free(tmpbuf);
1508 tmpbuf = 0;
1509 return 1;
1511 free(tmpbuf);
1512 tmpbuf = 0;
1514 if (tmpport <= 0 || tmpport >= 65536)
1515 return 1;
1517 *port = (__u16) tmpport;
1518 return 0;
1521 static int parse_inetaddr(char *addr, __u32 len, int *af,
1522 struct sockaddr **saddr, socklen_t *saddrlen)
1524 __u32 idx = len - 1;
1526 __u16 port;
1528 char *host;
1530 struct in_addr inaddr;
1531 struct in6_addr in6addr;
1533 while (idx > 0) {
1534 if (addr[idx] == ':') {
1535 break;
1537 idx--;
1540 if (idx <= 0 || idx >= len - 1)
1541 return 1;
1543 if (parse_port(addr + idx + 1, len - idx - 1, &port) != 0)
1544 return 1;
1546 host = malloc(idx + 1);
1547 memcpy(host, addr, idx);
1548 host[idx] = 0;
1550 if (inet_pton(AF_INET, host, &inaddr) == 1) {
1551 struct sockaddr_in *ret;
1553 free(host);
1554 host = 0;
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));
1563 *af = AF_INET;
1564 *saddr = (struct sockaddr *) ret;
1565 *saddrlen = sizeof(struct sockaddr_in);
1567 return 0;
1568 } else if (inet_pton(AF_INET6, host, &in6addr) == 1) {
1569 free(host);
1570 host = 0;
1572 printf("sorry IPv6 support is not implemented yet\n");
1574 return 1;
1575 } else {
1576 free(host);
1577 host = 0;
1578 return 1;
1582 static int parse_fwd_to_rservice(char *argv_fwd,
1583 struct list_head *rservice_fwds)
1585 struct fwd_to_rservice_item *item;
1586 int af;
1587 struct sockaddr *saddr;
1588 socklen_t saddrlen;
1590 __u16 serviceport;
1592 __u32 idx = 0;
1593 __u32 len = 0;
1595 int optval;
1597 while (1) {
1598 if (argv_fwd[len] == 0) {
1599 break;
1600 } else if (argv_fwd[len] == ':') {
1601 idx = len;
1603 len++;
1606 if (idx <= 0 || idx >= len - 1)
1607 return 1;
1609 if (parse_inetaddr(argv_fwd, idx, &af, &saddr, &saddrlen) != 0)
1610 return 1;
1612 if (parse_port(argv_fwd + idx + 1, len - idx - 1, &serviceport) != 0)
1613 return 1;
1615 item = malloc(sizeof(struct fwd_to_rservice_item));
1616 item->bindfd = socket(af, SOCK_STREAM, 0);
1617 if (item->bindfd < 0) {
1618 perror("socket");
1619 goto err;
1621 optval = 1;
1622 if (setsockopt(item->bindfd, SOL_SOCKET, SO_REUSEADDR, &optval,
1623 sizeof(optval)) != 0) {
1624 perror("setsockopt");
1625 goto err;
1627 if (setsockopt(item->bindfd, SOL_SOCKET, SO_REUSEADDR, &optval,
1628 sizeof(optval)) != 0) {
1629 perror("setsockopt");
1630 goto err;
1632 if (bind(item->bindfd, saddr, saddrlen) != 0) {
1633 perror("bind");
1634 goto err;
1636 if (listen(item->bindfd, 100) != 0) {
1637 perror("listen");
1638 goto err;
1640 item->targetport = htons(serviceport);
1642 list_add_tail(&(item->allfwds), rservice_fwds);
1644 free(saddr);
1646 return 0;
1648 err:
1649 free(item);
1650 free(saddr);
1652 return 1;
1655 static int parse_args(int argc, char *argv[], struct list_head *rservice_fwds)
1657 int rc;
1658 int addrfound = 0;
1659 __u32 argsconsumed = 0;
1661 if (argc > 1000000)
1662 goto usage;
1664 while (1) {
1665 if (argc <= argsconsumed + 1)
1666 break;
1668 if (strcmp(argv[argsconsumed + 1], "--addr") == 0) {
1669 if (argc <= argsconsumed + 2)
1670 goto usage;
1672 if (addrfound != 0)
1673 goto usage;
1675 rc = parse_addr(argv[argsconsumed + 2]);
1676 if (rc != 0)
1677 goto usage;
1679 addrfound = 1;
1681 argsconsumed += 2;
1682 } else if (strcmp(argv[argsconsumed + 1],
1683 "--export-servicelist") == 0) {
1684 export_servicelist_enabled = 1;
1686 argsconsumed += 1;
1687 } else if (strcmp(argv[argsconsumed + 1],
1688 "--fwd-to-rservice") == 0) {
1689 if (argc <= argsconsumed + 2)
1690 goto usage;
1692 rc = parse_fwd_to_rservice(argv[argsconsumed + 2],
1693 rservice_fwds);
1694 if (rc != 0)
1695 goto usage;
1697 argsconsumed += 2;
1698 } else {
1699 goto usage;
1703 if (addrfound == 0)
1704 goto usage;
1706 if (0) {
1707 usage:
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");
1712 rc = 1;
1715 return rc;
1718 int main(int argc, char *argv[])
1720 int rc;
1721 struct list_head rservice_fwds;
1723 struct nonblock_resumeinfo rds_nr;
1725 int discover_finished_executed = 0;
1727 discover_finished = 0;
1728 epoll_fd = 0;
1730 init_list_head(&rservice_fwds);
1732 umask(0);
1734 rc = parse_args(argc, argv, &rservice_fwds);
1735 if (rc != 0)
1736 goto out;
1739 init_list_head(&node_list);
1741 epoll_fd = epoll_create(1);
1742 if (epoll_fd <= 0) {
1743 perror("epoll_create");
1744 goto out;
1748 rdsock_fd = socket(PF_COR, SOCK_RAW, PROTO_COR_RDEAMON);
1749 if (rdsock_fd < 0) {
1750 perror("socket");
1751 goto out;
1754 rc = connect(rdsock_fd, 0, 0);
1755 if (rc < 0) {
1756 perror("connect");
1757 goto out;
1760 rc = rdsock_negotiate_version();
1761 if (rc != 0)
1762 goto out;
1764 rc = send_rdsock_up(rdsock_fd, localaddr, localaddrlen);
1765 ASSERT(rc == RC_OK);
1767 set_nonblock(rdsock_fd, 1);
1769 sleep(30);
1771 discover_network(0, 0);
1773 while (1) {
1774 int u;
1775 struct epoll_event events[EPOLL_EVENTS];
1776 int rdycnt;
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);
1805 out:
1806 return 1;