reduce overhead
[corutils.git] / src / demo / libcor.c
blob40eb63886a6bfc83201f410baf5d6fdb771fabb0
1 /**
2 * Connection oriented routing user space utils
3 * Copyright (C) 2009-2019
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 <linux/types.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <arpa/inet.h>
29 #include <unistd.h>
31 #include "../cor.h"
32 #include "../utils.h"
33 #include "libcor.h"
35 #define likely(x) __builtin_expect((x), 1)
36 #define unlikely(x) __builtin_expect((x), 0)
38 #define CD_CONTINUE_ON_ERROR_FLAG 32768
40 #define CD_CONNECT_NB 1
41 #define CD_CONNECT_PORT 2
42 #define CD_LIST_NEIGH 3
43 #define CD_LIST_SERVICES 4
45 #define CDR_EXECOK 1
47 #define CDR_EXECOK_BINDATA 2
48 #define CDR_EXECOK_BINDATA_NORESP 3
50 #define CDR_EXECFAILED 4
51 #define CDR_EXECFAILED_INVALID_COMMAND 1
52 #define CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESOURCES 2
53 #define CDR_EXECFAILED_NB_DOESNTEXIST 3
54 #define CDR_EXECFAILED_UNKNOWN_L4PROTOCOL 4
55 #define CDR_EXECFAILED_PORTCLOSED 5
57 #define CDR_BINDATA 3
59 #define LIST_NEIGH_FIELD_ADDR 1
60 #define LIST_NEIGH_FIELD_LATENCY 2
62 #define L4PROTO_STREAM 42399
65 static int bzero_nr_iffinished(struct libcor_nonblock_resumeinfo *nr, int rc)
67 /*if (rc == RC_WOULDBLOCK) {
68 printf("wouldblock\n");
69 }*/
71 if (rc != RC_WOULDBLOCK) {
72 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
74 return rc;
77 #define LIBCOR_ASSERT_ERR() \
78 do { \
79 assert(0); \
80 exit(1); \
81 while (1) { \
82 } \
83 } while(0) \
86 #warning todo commands are sent via multiple packets
87 int resume_send(int fd, struct libcor_nonblock_resumeinfo *nr)
89 if (unlikely(nr->type != RESUME_TYPE_WRITE || nr->data.write.fd !=fd))
90 LIBCOR_ASSERT_ERR();
92 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE ||
93 unlikely(nr->data.write.len > WRITE_BUF_SIZE))
94 LIBCOR_ASSERT_ERR();
96 while (nr->data.write.totalsent < nr->data.write.len) {
97 char *buf = &(nr->data.write.buf[0]);
98 #warning todo use ssize_t (other places too?)
99 int sent = send(fd, buf + nr->data.write.totalsent,
100 nr->data.write.len - nr->data.write.totalsent,
103 if (sent < 0 && (errno == EAGAIN ||
104 errno == EWOULDBLOCK))
105 return bzero_nr_iffinished(nr, RC_WOULDBLOCK);
107 if (sent <= 0) {
108 if (errno == EINTR)
109 continue;
111 perror("send");
112 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
115 nr->data.write.totalsent += sent;
118 return bzero_nr_iffinished(nr, RC_OK);
121 static int read_fully(int fd, struct libcor_nonblock_resumeinfo *nr,
122 char *buf, __u32 len, __u32 *maxread)
124 int rc = RC_OK;
126 if (unlikely(nr->type != RESUME_TYPE_READ))
127 LIBCOR_ASSERT_ERR();
129 if (unlikely(nr->data.read.read_fully.state != 0 && (
130 nr->data.read.read_fully.fd != fd ||
131 nr->data.read.read_fully.buf != buf ||
132 nr->data.read.read_fully.len != len ||
133 nr->data.read.read_fully.maxread != maxread)))
134 LIBCOR_ASSERT_ERR();
136 if (nr->data.read.read_fully.state == 1) {
137 goto state_1;
138 } else if (unlikely(nr->data.read.read_fully.state != 0)) {
139 LIBCOR_ASSERT_ERR();
142 nr->data.read.read_fully.fd = fd;
143 nr->data.read.read_fully.buf = buf;
144 nr->data.read.read_fully.len = len;
145 nr->data.read.read_fully.maxread = maxread;
146 nr->data.read.read_fully.totalread = 0;
148 nr->data.read.read_fully.state = 1;
149 state_1:
151 if (maxread != 0) {
152 if (len > (*maxread)) {
153 printf("error in read_fully: maxread reached\n");
154 rc = RC_CONNBROKEN;
155 goto out;
157 (*maxread) -= len;
160 while (len > nr->data.read.read_fully.totalread) {
161 int rcvd = recv(fd, buf + nr->data.read.read_fully.totalread,
162 len - nr->data.read.read_fully.totalread, 0);
163 int u;
165 if (rcvd < 0 && (errno == EAGAIN ||
166 errno == EWOULDBLOCK)) {
167 /* printf("wouldblock\n"); */
168 rc = RC_WOULDBLOCK;
169 goto out;
172 if (rcvd <= 0) {
173 if (errno == EINTR)
174 continue;
176 perror("recv");
177 rc = RC_CONNBROKEN;
178 goto out;
181 /*printf("rcvd: %d:", rcvd);
182 for(u=0;u<rcvd;u++) {
183 printf(" %d, ", (__s32) ((__u8) buf[totalread+u]));
185 printf("\n");*/
187 nr->data.read.read_fully.totalread += (__u32) rcvd;
190 out:
191 if (rc != RC_WOULDBLOCK) {
192 bzero(&(nr->data.read.read_fully),
193 sizeof(nr->data.read.read_fully));
196 return rc;
199 static int read_discard(int fd, struct libcor_nonblock_resumeinfo *nr,
200 __u32 len)
202 char buf[128];
203 int rc = RC_OK;
205 if (unlikely(nr->type != RESUME_TYPE_READ))
206 LIBCOR_ASSERT_ERR();
208 if (unlikely(nr->data.read.read_discard.state != 0 && (
209 nr->data.read.read_discard.fd != fd ||
210 nr->data.read.read_discard.len != len)))
211 LIBCOR_ASSERT_ERR();
213 if (nr->data.read.read_discard.state == 1) {
214 goto state_1;
215 } else if (unlikely(nr->data.read.read_discard.state != 0)) {
216 LIBCOR_ASSERT_ERR();
219 nr->data.read.read_discard.fd = fd;
220 nr->data.read.read_discard.len = len;
221 nr->data.read.read_discard.discarded = 0;
224 nr->data.read.read_discard.state = 1;
225 state_1:
227 while (len > 0) {
228 int rcvd;
230 __u32 rcvlen = len - nr->data.read.read_discard.discarded;
231 if (rcvlen > 128)
232 rcvlen = 128;
234 rcvd = recv(fd, buf, rcvlen, 0);
236 if (rcvd < 0 && (errno == EAGAIN ||
237 errno == EWOULDBLOCK)) {
238 rc = RC_WOULDBLOCK;
239 break;
242 if (rcvd <= 0) {
243 if (errno == EINTR)
244 continue;
246 perror("recv");
247 rc = RC_CONNBROKEN;
248 goto out;
251 nr->data.read.read_discard.discarded -= rcvd;
254 out:
255 if (rc != RC_WOULDBLOCK) {
256 bzero(&(nr->data.read.read_discard),
257 sizeof(nr->data.read.read_discard));
260 return rc;
263 int encode_len(char *buf, int buflen, __u32 len)
265 if (unlikely(buf == 0))
266 LIBCOR_ASSERT_ERR();
267 if (unlikely(buflen < 4))
268 LIBCOR_ASSERT_ERR();
270 if (len < 128) {
271 buf[0] = (__u8) len;
272 return 1;
273 } else if (len < 16512) {
274 __u16 len_be = htons(len - 128);
275 char *len_p = (char *) &len_be;
277 buf[0] = len_p[0] + 128;
278 buf[1] = len_p[1];
279 return 2;
280 } else if (len < 1073758336) {
281 __u32 len_be = htonl(len - 16512);
282 char *len_p = (char *) &len_be;
284 buf[0] = len_p[0] + 192;
285 buf[1] = len_p[1];
286 buf[2] = len_p[2];
287 buf[3] = len_p[3];
288 return 4;
289 } else {
290 return -1;
294 int decode_len(char *buf, int buflen, __u32 *len)
296 __u8 b0 = (__u8) buf[0];
298 *len = 0;
300 if (buflen >= 1 && b0 < 128) {
301 *len = (__u8) buf[0];
302 return 1;
303 } else if (buflen >= 2 && b0 >= 128 && b0 < 192) {
304 ((char *) len)[0] = buf[0] - 128;
305 ((char *) len)[1] = buf[1];
307 *len = ntohs(*len) + 128;
308 return 2;
309 } else if (buflen >= 4 && b0 >= 192) {
310 ((char *) len)[0] = buf[0] - 192;
311 ((char *) len)[1] = buf[1];
312 ((char *) len)[2] = buf[2];
313 ((char *) len)[3] = buf[3];
315 *len = ntohl(*len) + 16512;
316 return 4;
317 } else {
318 return 0;
322 static int read_len(int fd, struct libcor_nonblock_resumeinfo *nr,
323 __u32 *len, __u32 *maxread)
325 int rc = RC_CONNBROKEN;
327 if (unlikely(nr->type != RESUME_TYPE_READ))
328 LIBCOR_ASSERT_ERR();
330 if (unlikely(nr->data.read.read_len.state != 0 && (
331 nr->data.read.read_len.fd != fd ||
332 nr->data.read.read_len.len != len ||
333 nr->data.read.read_len.maxread != maxread)))
334 LIBCOR_ASSERT_ERR();
336 if (sizeof(nr->data.read.read_len.buf) != 4)
337 LIBCOR_ASSERT_ERR();
339 if (nr->data.read.read_len.state == 1) {
340 goto state_1;
341 } else if (unlikely(nr->data.read.read_len.state != 0)) {
342 LIBCOR_ASSERT_ERR();
345 nr->data.read.read_len.fd = fd;
346 nr->data.read.read_len.len = len;
347 nr->data.read.read_len.maxread = maxread;
348 bzero(&(nr->data.read.read_len.buf[0]), 4);
349 nr->data.read.read_len.read = 0;
352 while(1) {
353 nr->data.read.read_len.state = 1;
354 state_1:
355 if (nr->data.read.read_len.read >= 4) {
356 printf("error in readlen: read to high\n");
357 rc = RC_CONNBROKEN;
358 goto out;
361 rc = read_fully(fd, nr, &(nr->data.read.read_len.buf[0]) +
362 nr->data.read.read_len.read, 1, maxread);
363 if (rc != RC_OK)
364 return rc;
366 nr->data.read.read_len.read++;
368 rc = decode_len(&(nr->data.read.read_len.buf[0]),
369 nr->data.read.read_len.read, len);
370 if (rc > 0) {
371 if (unlikely(rc < nr->data.read.read_len.read)) {
372 printf("error in readlen: decode_len has not "
373 "consumed the whole buffer\n");
374 rc = RC_CONNBROKEN;
375 goto out;
377 rc = RC_OK;
378 break;
382 out:
383 if (rc != RC_WOULDBLOCK) {
384 bzero(&(nr->data.read.read_len),
385 sizeof(nr->data.read.read_len));
388 return rc;
391 static int _send_cmd(int fd, struct libcor_nonblock_resumeinfo *nr, __u16 cmd)
393 char buf[6];
394 int rc;
395 __u32 hdrlen = 0;
398 if (unlikely(nr->type != RESUME_TYPE_WRITE || nr->data.write.fd != fd))
399 LIBCOR_ASSERT_ERR();
401 cmd = htons(cmd);
402 buf[0] = ((char *) &cmd)[0];
403 buf[1] = ((char *) &cmd)[1];
405 rc = encode_len(&(buf[2]), 4, nr->data.write.len);
406 if (rc <= 0 || rc > 4)
407 LIBCOR_ASSERT_ERR();
409 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
410 LIBCOR_ASSERT_ERR();
412 hdrlen = 2 + ((__u32) rc);
414 if (unlikely(nr->data.write.len + hdrlen < nr->data.write.len ||
415 nr->data.write.len + hdrlen > WRITE_BUF_SIZE))
416 LIBCOR_ASSERT_ERR();
418 memmove(&(nr->data.write.buf[hdrlen]), &(nr->data.write.buf[0]),
419 nr->data.write.len);
420 memcpy(&(nr->data.write.buf[0]), &(buf[0]), hdrlen);
421 nr->data.write.len += hdrlen;
423 return resume_send(fd, nr);
426 static int send_cmd(int fd, struct libcor_nonblock_resumeinfo *nr,
427 __u16 cmd, char *buf, __u32 len)
429 if (unlikely(nr->type != RESUME_TYPE_NONE))
430 LIBCOR_ASSERT_ERR();
432 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
433 nr->type = RESUME_TYPE_WRITE;
434 nr->data.write.fd = fd;
436 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
437 LIBCOR_ASSERT_ERR();
439 if (unlikely(WRITE_BUF_SIZE < len))
440 LIBCOR_ASSERT_ERR();
442 if (len != 0) {
443 memcpy(&(nr->data.write.buf[0]), buf, len);
444 nr->data.write.len = len;
447 return _send_cmd(fd, nr, cmd);
450 int read_resp_nonblock(int fd, int expect_bindata,
451 struct libcor_nonblock_resumeinfo *nr)
453 int rc;
455 struct libcor_nonblock_resumeinfo_resp *nr_resp =
456 &(nr->data.read.funcdata.resp);
458 if (nr->type == RESUME_TYPE_NONE) {
459 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
460 nr->type = RESUME_TYPE_READ;
461 nr->data.read.functype = RESUME_READ_FUNC_RESP;
462 nr_resp->fd = fd;
463 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
464 nr->data.read.functype != RESUME_READ_FUNC_RESP)) {
465 LIBCOR_ASSERT_ERR();
466 } else if (unlikely(nr_resp->fd != fd)) {
467 LIBCOR_ASSERT_ERR();
468 } else {
469 __u8 state = nr_resp->state;
471 if (state == 1) {
472 goto state_1;
473 } else if (unlikely(state != 0)) {
474 LIBCOR_ASSERT_ERR();
478 nr_resp->respcode = 0;
479 rc = read_fully(fd, nr, (char *) &(nr_resp->respcode), 1, 0);
481 if (rc != RC_OK)
482 return bzero_nr_iffinished(nr, rc);
484 //printf("read_resp: respcode = %d\n", nr_resp->respcode);
486 if (nr_resp->respcode == CDR_EXECFAILED) {
487 /* printf("crd_execfailed\n"); */
489 nr_resp->reasoncode = 0;
491 nr_resp->state = 1;
492 state_1:
493 rc = read_fully(fd, nr, (char *) &(nr_resp->reasoncode), 2, 0);
494 if (rc != RC_OK)
495 return bzero_nr_iffinished(nr, rc);
497 nr_resp->reasoncode = ntohs(nr_resp->reasoncode);
499 printf("execfailed: reasoncode = %d\n", (__s32)
500 nr_resp->reasoncode);
503 if (expect_bindata) {
504 if (nr_resp->respcode == CDR_EXECOK)
505 printf("execfailed: received execok, expected execok_bindata\n");
506 else if (nr_resp->respcode == CDR_EXECOK_BINDATA)
507 return bzero_nr_iffinished(nr, RC_OK);
508 } else {
509 eue CDR_EXECOK_BINDATA
510 if (nr_resp->respcode == CDR_EXECOK)
511 return bzero_nr_iffinished(nr, RC_OK);
512 else if (nr_resp->respcode == CDR_EXECOK_BINDATA)
513 printf("execfailed: received execok_bindata, expected execok\n");
516 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
519 int read_resp(int fd, int expect_bindata)
521 int rc = RC_WOULDBLOCK;
522 struct libcor_nonblock_resumeinfo nr;
523 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
525 rc = read_resp_nonblock(fd, expect_bindata, &nr);
526 if (unlikely(rc == RC_WOULDBLOCK)) {
527 LIBCOR_ASSERT_ERR();
528 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
530 return rc;
533 #warning todo replace LIBCOR_ASSERT_ERR
534 int send_connect_neigh_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
535 __be64 addr)
537 __u32 hdrlen = 0;
538 int rc;
540 if (unlikely(nr->type != RESUME_TYPE_NONE))
541 LIBCOR_ASSERT_ERR();
543 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
544 nr->type = RESUME_TYPE_WRITE;
545 nr->data.write.fd = fd;
547 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
548 LIBCOR_ASSERT_ERR();
550 if (unlikely(WRITE_BUF_SIZE < 8))
551 LIBCOR_ASSERT_ERR();
553 memcpy(&(nr->data.write.buf[0]), (char *) &addr, 8);
554 nr->data.write.len = 8;
556 if (unlikely(nr->data.write.len > WRITE_BUF_SIZE))
557 LIBCOR_ASSERT_ERR();
559 return _send_cmd(fd, nr, CD_CONNECT_NB);
562 int send_connect_neigh(int fd, __be64 addr)
564 int rc = RC_WOULDBLOCK;
565 struct libcor_nonblock_resumeinfo nr;
566 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
568 rc = send_connect_neigh_nonblock(fd, &nr, addr);
569 if (unlikely(rc == RC_WOULDBLOCK)) {
570 LIBCOR_ASSERT_ERR();
571 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
573 return rc;
576 int send_connect_port_nonblock(int fd,
577 struct libcor_nonblock_resumeinfo *nr, __be32 port)
579 char *p_port = (char *) &port;
580 char cmd[6];
581 cmd[0] = L4PROTO_STREAM / 256;
582 cmd[1] = L4PROTO_STREAM % 256;
583 cmd[2] = p_port[0];
584 cmd[3] = p_port[1];
585 cmd[4] = p_port[2];
586 cmd[5] = p_port[3];
587 return send_cmd(fd, nr, CD_CONNECT_PORT, &(cmd[0]), 6);
590 int send_connect_port(int fd, __be32 port)
592 int rc = RC_WOULDBLOCK;
593 struct libcor_nonblock_resumeinfo nr;
594 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
596 rc = send_connect_port_nonblock(fd, &nr, port);
597 if (unlikely(rc == RC_WOULDBLOCK)) {
598 LIBCOR_ASSERT_ERR();
599 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
601 return rc;
604 int send_list_services_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr)
606 return send_cmd(fd, nr, CD_LIST_SERVICES | CD_CONTINUE_ON_ERROR_FLAG,
607 0, 0);
610 int send_list_services(int fd)
612 int rc = RC_WOULDBLOCK;
613 struct libcor_nonblock_resumeinfo nr;
614 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
616 rc = send_list_services_nonblock(fd, &nr);
617 if (unlikely(rc == RC_WOULDBLOCK)) {
618 LIBCOR_ASSERT_ERR();
619 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
621 return rc;
624 int read_service_list_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
625 void *ptr,
626 void (*init)(void *ptr, __u32 numservices),
627 void (*next_service)(void *ptr, __be32 port))
629 int rc;
631 struct libcor_nonblock_resumeinfo_servicelist *nr_sl =
632 &(nr->data.read.funcdata.servicelist);
634 if (nr->type == RESUME_TYPE_NONE) {
635 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
636 nr->type = RESUME_TYPE_READ;
637 nr->data.read.functype = RESUME_READ_FUNC_SERVICELIST;
638 nr_sl->fd = fd;
639 nr_sl->ptr = ptr;
640 nr_sl->init = init;
641 nr_sl->next_service = next_service;
642 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
643 nr->data.read.functype !=
644 RESUME_READ_FUNC_SERVICELIST)) {
645 LIBCOR_ASSERT_ERR();
646 } else if (unlikely(nr_sl->fd != fd ||
647 nr_sl->ptr != ptr ||
648 nr_sl->init != init ||
649 nr_sl->next_service != next_service)) {
650 LIBCOR_ASSERT_ERR();
651 } else {
652 __u8 state = nr_sl->state;
653 if (state == 1) {
654 goto state_1;
655 } else if (state == 2) {
656 goto state_2;
657 } else if (unlikely(state != 0)) {
658 LIBCOR_ASSERT_ERR();
662 rc = read_len(fd, nr, &(nr_sl->len), 0);
663 if (rc != RC_OK)
664 return bzero_nr_iffinished(nr, rc);
666 nr_sl->state = 1;
667 state_1:
668 rc = read_len(fd, nr, &(nr_sl->numservices), &(nr_sl->len));
669 if (rc != RC_OK)
670 return bzero_nr_iffinished(nr, rc);
672 init(ptr, nr_sl->numservices);
674 for(nr_sl->q=0; nr_sl->q < nr_sl->numservices; nr_sl->q++) {
675 nr_sl->port = 0;
677 nr_sl->state = 2;
678 state_2:
679 rc = read_fully(fd, nr, (char *) &(nr_sl->port), 4,
680 &(nr_sl->len));
681 if (rc != RC_OK)
682 return bzero_nr_iffinished(nr, rc);
684 next_service(ptr, nr_sl->port);
685 nr_sl->port = 0;
688 return bzero_nr_iffinished(nr, rc);
691 int read_service_list(int fd, void *ptr,
692 void (*init)(void *ptr, __u32 numservices),
693 void (*next_service)(void *ptr, __be32 port))
695 int rc = RC_WOULDBLOCK;
696 struct libcor_nonblock_resumeinfo nr;
697 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
699 rc = read_service_list_nonblock(fd, &nr, ptr, init, next_service);
700 if (unlikely(rc == RC_WOULDBLOCK)) {
701 LIBCOR_ASSERT_ERR();
702 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
704 return rc;
708 int send_list_neigh_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr)
710 return send_cmd(fd, nr, CD_LIST_NEIGH | CD_CONTINUE_ON_ERROR_FLAG,
711 0, 0);
714 int send_list_neigh(int fd)
716 int rc = RC_WOULDBLOCK;
717 struct libcor_nonblock_resumeinfo nr;
718 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
720 rc = send_list_neigh_nonblock(fd, &nr);
721 if (unlikely(rc == RC_WOULDBLOCK)) {
722 LIBCOR_ASSERT_ERR();
723 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
725 return rc;
728 static int field_present(struct listneigh_field *fields, __u32 numfields,
729 __u16 field)
731 __u64 u;
732 for(u=0;u<numfields;u++) {
733 if (fields[u].field == field)
734 return 1;
736 return 0;
739 int read_neigh_list_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
740 void *ptr,
741 void (*init)(void *ptr, __u32 numneigh),
742 void (*next_neigh)(void *ptr, __be64 addr))
744 int rc;
746 struct libcor_nonblock_resumeinfo_neighlist *nr_nl =
747 &(nr->data.read.funcdata.neighlist);
749 if (nr->type == RESUME_TYPE_NONE) {
750 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
751 nr->type = RESUME_TYPE_READ;
752 nr->data.read.functype = RESUME_READ_FUNC_NEIGHLIST;
753 nr_nl->fd = fd;
754 nr_nl->ptr = ptr;
755 nr_nl->init = init;
756 nr_nl->next_neigh = next_neigh;
757 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
758 nr->data.read.functype != RESUME_READ_FUNC_NEIGHLIST)) {
759 LIBCOR_ASSERT_ERR();
760 } else if (unlikely(nr_nl->fd != fd ||
761 nr_nl->ptr != ptr ||
762 nr_nl->init != init ||
763 nr_nl->next_neigh != next_neigh)) {
764 LIBCOR_ASSERT_ERR();
765 } else {
766 __u8 state = nr_nl->state;
767 if (state == 1) {
768 goto state_1;
769 } else if (state == 2) {
770 goto state_2;
771 } else if (state == 3) {
772 goto state_3;
773 } else if (state == 4) {
774 goto state_4;
775 } else if (state == 5) {
776 goto state_5;
777 } else if (state == 6) {
778 goto state_6;
779 } else if (state == 7) {
780 goto state_7;
781 } else if (state == 8) {
782 goto state_8;
783 } else if (unlikely(state != 0)) {
784 LIBCOR_ASSERT_ERR();
788 rc = read_len(fd, nr, &(nr_nl->len), 0);
789 if (rc != RC_OK)
790 return bzero_nr_iffinished(nr, rc);
792 nr_nl->state = 1;
793 state_1:
794 rc = read_len(fd, nr, &(nr_nl->numneighs), &(nr_nl->len));
795 if (rc != RC_OK)
796 return bzero_nr_iffinished(nr, rc);
798 nr_nl->state = 2;
799 state_2:
800 rc = read_len(fd, nr, &(nr_nl->numfields), &(nr_nl->len));
801 if (rc != RC_OK)
802 return bzero_nr_iffinished(nr, rc);
804 if (unlikely(nr_nl->numfields > NEIGHLIST_MAX_FIELDS))
805 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
807 for(nr_nl->u=0; nr_nl->u < nr_nl->numfields; nr_nl->u++) {
808 nr_nl->fields[nr_nl->u].field = 0;
810 nr_nl->state = 3;
811 state_3:
812 rc = read_fully(fd, nr,
813 (char *) &(nr_nl->fields[nr_nl->u].field),
814 2, &(nr_nl->len));
815 if (rc != RC_OK)
816 return bzero_nr_iffinished(nr, rc);
817 nr_nl->fields[nr_nl->u].field =
818 ntohs(nr_nl->fields[nr_nl->u].field);
820 nr_nl->state = 4;
821 state_4:
822 nr_nl->fieldlen = 0;
823 rc = read_len(fd, nr, &(nr_nl->fieldlen), &(nr_nl->len));
824 if (rc != RC_OK)
825 return bzero_nr_iffinished(nr, rc);
827 if (unlikely(nr_nl->fieldlen > 65535))
828 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
830 nr_nl->fields[nr_nl->u].len = (__u16) nr_nl->fieldlen;
831 nr_nl->fieldlen = 0;
834 if (unlikely(field_present(nr_nl->fields, nr_nl->numfields,
835 LIST_NEIGH_FIELD_ADDR) == 0))
836 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
838 init(ptr, nr_nl->numneighs);
840 for (nr_nl->u=0; nr_nl->u < nr_nl->numneighs; nr_nl->u++) {
841 nr_nl->addr = 0;
842 nr_nl->latency = 0;
844 for(nr_nl->v=0; nr_nl->v < nr_nl->numfields; nr_nl->v++) {
845 nr_nl->fieldlen = nr_nl->fields[nr_nl->v].len;
846 if (nr_nl->fieldlen == 0) {
847 nr_nl->state = 5;
848 state_5:
849 rc = read_len(fd, nr, &(nr_nl->fieldlen),
850 &(nr_nl->len));
851 if (rc != RC_OK)
852 return bzero_nr_iffinished(nr, rc);
855 if (nr_nl->fieldlen > nr_nl->len)
856 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
858 nr_nl->len -= nr_nl->fieldlen;
860 if (field_present(nr_nl->fields, nr_nl->v,
861 nr_nl->fields[nr_nl->v].field)) {
862 goto discard_field;
863 } else if (nr_nl->fields[nr_nl->v].field ==
864 LIST_NEIGH_FIELD_ADDR) {
865 if (unlikely(nr_nl->fieldlen != 8))
866 goto discard_field;
868 ASSERT(sizeof(nr_nl->addr) == 8);
870 nr_nl->state = 6;
871 state_6:
872 rc = read_fully(fd, nr, (char *) &(nr_nl->addr),
873 8, &(nr_nl->fieldlen));
874 if (rc != RC_OK)
875 return bzero_nr_iffinished(nr, rc);
877 if (unlikely(ntohll(nr_nl->addr) == 0))
878 return RC_CONNBROKEN;
879 } else if (nr_nl->fields[nr_nl->v].field ==
880 LIST_NEIGH_FIELD_LATENCY) {
881 nr_nl->latency = 0;
883 nr_nl->state = 7;
884 state_7:
885 rc = read_fully(fd, nr, &nr_nl->latency, 1,
886 &(nr_nl->fieldlen));
887 if (rc != RC_OK)
888 return bzero_nr_iffinished(nr, rc);
890 printf("latency %d\n", (int) nr_nl->latency);
893 discard_field:
894 if (nr_nl->fieldlen > 0) {
895 nr_nl->state = 8;
896 state_8:
897 rc = read_discard(fd, nr, nr_nl->fieldlen);
898 if (rc != RC_OK)
899 return bzero_nr_iffinished(nr, rc);
902 nr_nl->fieldlen = 0;
905 next_neigh(ptr, nr_nl->addr);
906 nr_nl->addr = 0;
907 nr_nl->latency = 0;
910 return bzero_nr_iffinished(nr, rc);
913 int read_neigh_list(int fd, void *ptr,
914 void (*init)(void *ptr, __u32 numneighs),
915 void (*next_neigh)(void *ptr, __be64 addr))
917 int rc = RC_WOULDBLOCK;
918 struct libcor_nonblock_resumeinfo nr;
919 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
921 rc = read_neigh_list_nonblock(fd, &nr, ptr, init, next_neigh);
922 if (unlikely(rc == RC_WOULDBLOCK)) {
923 LIBCOR_ASSERT_ERR();
924 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
926 return rc;
929 int pass_socket(int fd, __u64 cookie)
931 int rc;
933 rc = setsockopt(fd, SOL_COR, COR_PASS_ON_CLOSE, &cookie, 8);
934 if (rc != 0) {
935 perror("pass_socket");
936 return RC_CONNBROKEN;
939 close(fd);
941 return RC_OK;
944 static int send_rdsock_cmd(int fd, struct libcor_nonblock_resumeinfo *nr,
945 __u32 cmd, char *data, __u32 datalen)
947 __u32 be_cmd = htonl(cmd);
948 __u32 be_datalen = htonl(datalen);
950 if (unlikely(nr->type != RESUME_TYPE_NONE))
951 LIBCOR_ASSERT_ERR();
953 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
954 nr->type = RESUME_TYPE_WRITE;
955 nr->data.write.fd = fd;
957 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
958 LIBCOR_ASSERT_ERR();
960 if (unlikely(datalen + 8 < datalen || WRITE_BUF_SIZE < (datalen + 8)))
961 LIBCOR_ASSERT_ERR();
963 memcpy(&(nr->data.write.buf[0]), (char *) &be_cmd, 4);
964 memcpy(&(nr->data.write.buf[4]), (char *) &be_datalen, 4);
965 memcpy(&(nr->data.write.buf[8]), data, datalen);
966 nr->data.write.len = datalen + 8;
968 return resume_send(fd, nr);
971 int send_rdsock_version_nonblock(int fd,
972 struct libcor_nonblock_resumeinfo *nr,
973 __u32 version)
975 char data[4];
977 version = htonl(version);
979 memcpy(&(data[0]), (char *) &version, 4);
981 return send_rdsock_cmd(fd, nr, CRD_UTK_VERSION, &(data[0]), 4);
984 int send_rdsock_version(int fd, __u32 version)
986 int rc = RC_WOULDBLOCK;
987 struct libcor_nonblock_resumeinfo nr;
988 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
990 rc = send_rdsock_version_nonblock(fd, &nr, version);
991 if (unlikely(rc == RC_WOULDBLOCK)) {
992 LIBCOR_ASSERT_ERR();
993 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
995 return rc;
998 int send_rdsock_up_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
999 int has_addr, __be64 addr)
1001 char data[16];
1003 __u64 flags = 0;
1005 __u32 addrlenbe;
1007 if (has_addr == 0 && addr != 0)
1008 return RC_CONNBROKEN;
1010 if (has_addr) {
1011 flags |= CRD_UTK_UP_FLAGS_ADDR;
1013 flags = htonll(flags);
1015 memcpy(&(data[0]), (char *) &flags, 8);
1016 memcpy(&(data[8]), (char *) &addr, 8);
1018 return send_rdsock_cmd(fd, nr, CRD_UTK_UP, &(data[0]), 16);
1019 } else {
1020 flags = htonll(flags);
1022 memcpy(&(data[0]), (char *) &flags, 8);
1024 return send_rdsock_cmd(fd, nr, CRD_UTK_UP, &(data[0]), 8);
1028 int send_rdsock_up(int fd, int has_addr, __be64 addr)
1030 int rc = RC_WOULDBLOCK;
1031 struct libcor_nonblock_resumeinfo nr;
1032 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1034 rc = send_rdsock_up_nonblock(fd, &nr, has_addr, addr);
1035 if (unlikely(rc == RC_WOULDBLOCK)) {
1036 LIBCOR_ASSERT_ERR();
1037 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1039 return rc;
1042 int send_rdsock_connecterror_nonblock(int fd,
1043 struct libcor_nonblock_resumeinfo *nr,
1044 __u64 cookie, __u32 error)
1046 char data[12];
1048 error = htonl(error);
1050 memcpy(&(data[0]), (char *) &cookie, 8);
1051 memcpy(&(data[8]), (char *) &error, 4);
1053 return send_rdsock_cmd(fd, nr, CRD_UTK_CONNECTERROR, &(data[0]), 12);
1056 int send_rdsock_connecterror(int fd, __u64 cookie, __u32 error)
1058 int rc = RC_WOULDBLOCK;
1059 struct libcor_nonblock_resumeinfo nr;
1060 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1062 rc = send_rdsock_connecterror_nonblock(fd, &nr, cookie, error);
1063 if (unlikely(rc == RC_WOULDBLOCK)) {
1064 LIBCOR_ASSERT_ERR();
1065 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1067 return rc;
1070 int parse_rdsock_supported_versions(struct rdsock_cmd *cmd,
1071 __u32 *versionmin, __u32 *versionmax)
1073 if (cmd->cmddatalen != 8)
1074 return 1;
1076 memcpy((char *) versionmin, cmd->cmddata, 4);
1077 *versionmin = htonl(*versionmin);
1078 memcpy((char *) versionmax, cmd->cmddata + 4, 4);
1079 *versionmax = htonl(*versionmax);
1081 return 0;
1084 int parse_rdsock_connect(void *ptr, struct rdsock_cmd *cmd,
1085 int (*proc_connect)(void *ptr, __u64 cookie,
1086 struct cor_sockaddr *addr, __u32 tos))
1088 __u64 cookie;
1089 struct cor_sockaddr addr;
1090 __u32 tos;
1092 if ((sizeof(struct cor_sockaddr) + 12) != cmd->cmddatalen)
1093 return 1;
1095 memcpy((char *) &cookie, cmd->cmddata, 8);
1097 memcpy((char *) &addr, cmd->cmddata + 8, sizeof(struct cor_sockaddr));
1099 memcpy((char *) &tos, cmd->cmddata + 8 + sizeof(struct cor_sockaddr),
1101 tos = htonl(tos);
1103 return proc_connect(ptr, cookie, &addr, tos);
1106 int read_rdsock_cmd_nonblock(int fd,
1107 struct libcor_nonblock_resumeinfo *nr,
1108 struct rdsock_cmd *cmd)
1110 int rc;
1112 struct libcor_nonblock_resumeinfo_rdsockcmd *nr_rd =
1113 &(nr->data.read.funcdata.rdsock_cmd);
1115 bzero(cmd, sizeof(struct rdsock_cmd));
1117 if (nr->type == RESUME_TYPE_NONE) {
1118 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
1119 nr->type = RESUME_TYPE_READ;
1120 nr->data.read.functype = RESUME_READ_FUNC_RDSOCK_CMD;
1121 nr_rd->fd = fd;
1122 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
1123 nr->data.read.functype != RESUME_READ_FUNC_RDSOCK_CMD)){
1124 LIBCOR_ASSERT_ERR();
1125 } else if (unlikely(nr_rd->fd != fd)) {
1126 LIBCOR_ASSERT_ERR();
1127 } else {
1128 __u8 state = nr_rd->state;
1130 if (state == 1) {
1131 goto state_1;
1132 } else if (state == 2) {
1133 goto state_2;
1134 } else if (unlikely(state != 0)) {
1135 LIBCOR_ASSERT_ERR();
1139 if (sizeof(nr_rd->buf) != 8)
1140 LIBCOR_ASSERT_ERR();
1142 rc = read_fully(fd, nr, (char *) &(nr_rd->buf[0]), 8, 0);
1143 if (rc != RC_OK)
1144 return bzero_nr_iffinished(nr, rc);
1146 ((char *) &(nr_rd->cmd))[0] = nr_rd->buf[0];
1147 ((char *) &(nr_rd->cmd))[1] = nr_rd->buf[1];
1148 ((char *) &(nr_rd->cmd))[2] = nr_rd->buf[2];
1149 ((char *) &(nr_rd->cmd))[3] = nr_rd->buf[3];
1150 ((char *) &(nr_rd->cmddatalen))[0] = nr_rd->buf[4];
1151 ((char *) &(nr_rd->cmddatalen))[1] = nr_rd->buf[5];
1152 ((char *) &(nr_rd->cmddatalen))[2] = nr_rd->buf[6];
1153 ((char *) &(nr_rd->cmddatalen))[3] = nr_rd->buf[7];
1155 nr_rd->cmd = ntohl(nr_rd->cmd);
1156 nr_rd->cmddatalen = ntohl(nr_rd->cmddatalen);
1158 if (nr_rd->cmddatalen > 65536)
1159 goto discard;
1161 nr_rd->cmddata = malloc(nr_rd->cmddatalen);
1162 if (nr_rd->cmddata == 0)
1163 goto discard;
1165 nr_rd->state = 1;
1166 state_1:
1167 rc = read_fully(fd, nr, nr_rd->cmddata, nr_rd->cmddatalen, 0);
1168 if (rc != RC_OK) {
1169 if (rc != RC_WOULDBLOCK) {
1170 free(nr_rd->cmddata);
1171 nr_rd->cmddata = 0;
1173 return bzero_nr_iffinished(nr, rc);
1176 cmd->cmd = nr_rd->cmd;
1177 cmd->cmddata = nr_rd->cmddata;
1178 cmd->cmddatalen = nr_rd->cmddatalen;
1180 if (0) {
1181 discard:
1182 nr_rd->state = 2;
1183 state_2:
1184 rc = read_discard(fd, nr, nr_rd->cmddatalen);
1185 if (rc != RC_OK)
1186 return bzero_nr_iffinished(nr, rc);
1188 return bzero_nr_iffinished(nr, rc);
1191 int read_rdsock_cmd(int fd, struct rdsock_cmd *cmd)
1193 int rc = RC_WOULDBLOCK;
1194 struct libcor_nonblock_resumeinfo nr;
1195 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1197 rc = read_rdsock_cmd_nonblock(fd, &nr, cmd);
1198 if (unlikely(rc == RC_WOULDBLOCK)) {
1199 LIBCOR_ASSERT_ERR();
1200 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1202 return rc;