SO_LINGER test
[corutils.git] / libcor.c
blobbd67c6d6391a92747a83c067721d9e9dc0515fc7
1 /**
2 * Connection oriented routing user space utils
3 * Copyright (C) 2009-2011
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>
29 #include "libcor.h"
31 #define likely(x) __builtin_expect((x), 1)
32 #define unlikely(x) __builtin_expect((x), 0)
35 #define CD_CONNECT_NB 1
36 #define CD_CONNECT_PORT 2
37 #define CD_LIST_NEIGH 3
38 #define CD_LIST_SERVICES 4
40 #define CDR_EXECOK 1
42 #define CDR_EXECFAILED 2
43 #define CDR_EXECFAILED_INVALID_COMMAND 1
44 #define CDR_EXECFAILED_TEMPORARILY_OUT_OF_RESSOURCES 2
45 #define CDR_EXECFAILED_NB_DOESNTEXIST 3
46 #define CDR_EXECFAILED_PORTCLOSED 4
48 #define CDR_BINDATA 3
50 #define LIST_NEIGH_FIELD_ADDR 1
51 #define LIST_NEIGH_FIELD_LATENCY 2
54 static int bzero_nr_iffinished(struct libcor_nonblock_resumeinfo *nr, int rc)
56 /*if (rc == RC_WOULDBLOCK) {
57 printf("wouldblock\n");
58 }*/
60 if (rc != RC_WOULDBLOCK) {
61 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
63 return rc;
66 #define LIBCOR_ASSERT_ERR() \
67 do { \
68 assert(0); \
69 exit(1); \
70 while (1) { \
71 } \
72 } while(0) \
75 static __u64 htonll(__u64 in)
77 __u64 out = 0;
78 char *p_out = (char *) &out;
80 p_out[7] = in & 255;
81 in = in >> 8;
82 p_out[6] = in & 255;
83 in = in >> 8;
84 p_out[5] = in & 255;
85 in = in >> 8;
86 p_out[4] = in & 255;
87 in = in >> 8;
88 p_out[3] = in & 255;
89 in = in >> 8;
90 p_out[2] = in & 255;
91 in = in >> 8;
92 p_out[1] = in & 255;
93 in = in >> 8;
94 p_out[0] = in & 255;
96 return out;
99 static __u64 ntohll(__u64 in)
101 __u64 out = 0;
102 char *p_in = (char *) &in;
104 out += p_in[7];
105 out << 8;
106 out += p_in[6];
107 out << 8;
108 out += p_in[5];
109 out << 8;
110 out += p_in[4];
111 out << 8;
112 out += p_in[3];
113 out << 8;
114 out += p_in[2];
115 out << 8;
116 out += p_in[1];
117 out << 8;
118 out += p_in[0];
120 return out;
123 #warning todo commands are sent via multiple packets
124 int resume_send(int fd, struct libcor_nonblock_resumeinfo *nr)
126 if (unlikely(nr->type != RESUME_TYPE_WRITE || nr->data.write.fd !=fd))
127 LIBCOR_ASSERT_ERR();
129 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE ||
130 unlikely(nr->data.write.len > WRITE_BUF_SIZE))
131 LIBCOR_ASSERT_ERR();
133 while (nr->data.write.totalsent < nr->data.write.len) {
134 char *buf = &(nr->data.write.buf[0]);
135 int sent = send(fd, buf + nr->data.write.totalsent,
136 nr->data.write.len - nr->data.write.totalsent,
139 if (sent < 0 && (errno == EAGAIN ||
140 errno == EWOULDBLOCK))
141 return bzero_nr_iffinished(nr, RC_WOULDBLOCK);
143 if (sent <= 0) {
144 if (errno == EINTR)
145 continue;
147 perror("send");
148 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
151 nr->data.write.totalsent += sent;
154 return bzero_nr_iffinished(nr, RC_OK);
157 static int read_fully(int fd, struct libcor_nonblock_resumeinfo *nr,
158 char *buf, __u32 len, __u32 *maxread)
160 int rc = RC_OK;
162 if (unlikely(nr->type != RESUME_TYPE_READ))
163 LIBCOR_ASSERT_ERR();
165 if (unlikely(nr->data.read.read_fully.state != 0 && (
166 nr->data.read.read_fully.fd != fd ||
167 nr->data.read.read_fully.buf != buf ||
168 nr->data.read.read_fully.len != len ||
169 nr->data.read.read_fully.maxread != maxread)))
170 LIBCOR_ASSERT_ERR();
172 if (nr->data.read.read_fully.state == 1) {
173 goto state_1;
174 } else if (unlikely(nr->data.read.read_fully.state != 0)) {
175 LIBCOR_ASSERT_ERR();
178 nr->data.read.read_fully.fd = fd;
179 nr->data.read.read_fully.buf = buf;
180 nr->data.read.read_fully.len = len;
181 nr->data.read.read_fully.maxread = maxread;
182 nr->data.read.read_fully.totalread = 0;
184 nr->data.read.read_fully.state = 1;
185 state_1:
187 if (maxread != 0) {
188 if (len > (*maxread)) {
189 printf("error in read_fully: maxread reached\n");
190 rc = RC_CONNBROKEN;
191 goto out;
193 (*maxread) -= len;
196 while (len > nr->data.read.read_fully.totalread) {
197 int rcvd = recv(fd, buf + nr->data.read.read_fully.totalread,
198 len - nr->data.read.read_fully.totalread, 0);
199 int u;
201 if (rcvd < 0 && (errno == EAGAIN ||
202 errno == EWOULDBLOCK)) {
203 rc = RC_WOULDBLOCK;
204 /* printf("wouldblock\n"); */
205 goto out;
208 if (rcvd <= 0) {
209 if (errno == EINTR)
210 continue;
212 perror("recv");
213 rc = RC_CONNBROKEN;
214 goto out;
217 /*printf("rcvd: %d:", rcvd);
218 for(u=0;u<rcvd;u++) {
219 printf(" %d, ", (__s32) ((__u8) buf[totalread+u]));
221 printf("\n");*/
223 nr->data.read.read_fully.totalread += (__u32) rcvd;
226 out:
227 if (rc != RC_WOULDBLOCK) {
228 bzero(&(nr->data.read.read_fully),
229 sizeof(nr->data.read.read_fully));
232 return rc;
235 static int read_discard(int fd, struct libcor_nonblock_resumeinfo *nr,
236 __u32 len)
238 char buf[128];
239 int rc = RC_OK;
241 if (unlikely(nr->type != RESUME_TYPE_READ))
242 LIBCOR_ASSERT_ERR();
244 if (unlikely(nr->data.read.read_discard.state != 0 && (
245 nr->data.read.read_discard.fd != fd ||
246 nr->data.read.read_discard.len != len)))
247 LIBCOR_ASSERT_ERR();
249 if (nr->data.read.read_discard.state == 1) {
250 goto state_1;
251 } else if (unlikely(nr->data.read.read_discard.state != 0)) {
252 LIBCOR_ASSERT_ERR();
255 nr->data.read.read_discard.fd = fd;
256 nr->data.read.read_discard.len = len;
257 nr->data.read.read_discard.discarded = 0;
260 nr->data.read.read_discard.state = 1;
261 state_1:
263 while (len > 0) {
264 int rcvd;
266 __u32 rcvlen = len - nr->data.read.read_discard.discarded;
267 if (rcvlen > 128)
268 rcvlen = 128;
270 rcvd = recv(fd, buf, rcvlen, 0);
272 if (rcvd < 0 && (errno == EAGAIN ||
273 errno == EWOULDBLOCK)) {
274 rc = RC_WOULDBLOCK;
275 break;
278 if (rcvd <= 0) {
279 if (errno == EINTR)
280 continue;
282 perror("recv");
283 rc = RC_CONNBROKEN;
284 goto out;
287 nr->data.read.read_discard.discarded -= rcvd;
290 out:
291 if (rc != RC_WOULDBLOCK) {
292 bzero(&(nr->data.read.read_discard),
293 sizeof(nr->data.read.read_discard));
296 return rc;
299 static int encode_len(char *buf, int buflen, __u32 len)
301 if (unlikely(buf == 0))
302 return -1;
304 if (unlikely(buflen < 4))
305 return -1;
307 if (len <= 127) {
308 buf[0] = (__u8) len;
309 return 1;
312 if (len <= 16511) {
313 buf[0] = (__u8) ((len - 128) /256 + 128);
314 buf[1] = (__u8) ((len- 128) & 255);
315 return 2;
318 if (len < 1073741951) {
319 __u32 len_be = htonl(len - 16511);
320 char *len_p = (char *) &len_be;
322 buf[0] = len_p[0] + 192;
323 buf[1] = len_p[1];
324 buf[2] = len_p[2];
325 buf[3] = len_p[3];
326 return 4;
329 return -1;
332 static int decode_len(char *buf, int buflen, __u32 *len)
334 if (unlikely(buflen < 1))
335 return 0;
337 if ((__u8) buf[0] <= 127) {
338 *len = (__u8) buf[0];
339 return 1;
342 if (buflen < 2)
343 return 0;
345 if ((__u8) buf[0] <= 191) {
346 *len = 128 + ((__u32) ((__u8) buf[0]) - 128) * 256 +
347 ((__u8) buf[1]);
348 return 2;
351 if (buflen < 4)
352 return 0;
354 ((char *) len)[0] = buf[0] - 192;
355 ((char *) len)[1] = buf[1];
356 ((char *) len)[2] = buf[2];
357 ((char *) len)[3] = buf[3];
359 *len = ntohl(*len) + 16511;
361 return 4;
364 static int read_len(int fd, struct libcor_nonblock_resumeinfo *nr,
365 __u32 *len, __u32 *maxread)
367 int rc = RC_CONNBROKEN;
369 if (unlikely(nr->type != RESUME_TYPE_READ))
370 LIBCOR_ASSERT_ERR();
372 if (unlikely(nr->data.read.read_len.state != 0 && (
373 nr->data.read.read_len.fd != fd ||
374 nr->data.read.read_len.len != len ||
375 nr->data.read.read_len.maxread != maxread)))
376 LIBCOR_ASSERT_ERR();
378 if (sizeof(nr->data.read.read_len.buf) != 4)
379 LIBCOR_ASSERT_ERR();
381 if (nr->data.read.read_len.state == 1) {
382 goto state_1;
383 } else if (unlikely(nr->data.read.read_len.state != 0)) {
384 LIBCOR_ASSERT_ERR();
387 nr->data.read.read_len.fd = fd;
388 nr->data.read.read_len.len = len;
389 nr->data.read.read_len.maxread = maxread;
390 bzero(&(nr->data.read.read_len.buf[0]), 4);
391 nr->data.read.read_len.read = 0;
394 while(1) {
395 nr->data.read.read_len.state = 1;
396 state_1:
397 if (nr->data.read.read_len.read >= 4) {
398 printf("error in readlen: read to high\n");
399 rc = RC_CONNBROKEN;
400 goto out;
403 rc = read_fully(fd, nr, &(nr->data.read.read_len.buf[0]) +
404 nr->data.read.read_len.read, 1, maxread);
405 if (rc != RC_OK)
406 return rc;
408 nr->data.read.read_len.read++;
410 rc = decode_len(&(nr->data.read.read_len.buf[0]),
411 nr->data.read.read_len.read, len);
412 if (rc > 0) {
413 if (unlikely(rc < nr->data.read.read_len.read)) {
414 printf("error in readlen: decode_len has not "
415 "consumed the whole buffer\n");
416 rc = RC_CONNBROKEN;
417 goto out;
419 rc = RC_OK;
420 break;
424 out:
425 if (rc != RC_WOULDBLOCK) {
426 bzero(&(nr->data.read.read_len),
427 sizeof(nr->data.read.read_len));
430 return rc;
433 static int _send_cmd(int fd, struct libcor_nonblock_resumeinfo *nr, __u16 cmd)
435 char buf[6];
436 int rc;
437 __u32 hdrlen = 0;
440 if (unlikely(nr->type != RESUME_TYPE_WRITE || nr->data.write.fd != fd))
441 LIBCOR_ASSERT_ERR();
443 cmd = htons(cmd);
444 buf[0] = ((char *) &cmd)[0];
445 buf[1] = ((char *) &cmd)[1];
447 rc = encode_len(&(buf[2]), 4, nr->data.write.len);
448 if (rc <= 0 || rc > 4)
449 LIBCOR_ASSERT_ERR();
451 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
452 LIBCOR_ASSERT_ERR();
454 hdrlen = 2 + ((__u32) rc);
456 if (unlikely(nr->data.write.len + hdrlen < nr->data.write.len ||
457 nr->data.write.len + hdrlen > WRITE_BUF_SIZE))
458 LIBCOR_ASSERT_ERR();
460 memmove(&(nr->data.write.buf[hdrlen]), &(nr->data.write.buf[0]),
461 nr->data.write.len);
462 memcpy(&(nr->data.write.buf[0]), &(buf[0]), hdrlen);
463 nr->data.write.len += hdrlen;
465 return resume_send(fd, nr);
468 static int send_cmd(int fd, struct libcor_nonblock_resumeinfo *nr,
469 __u16 cmd, char *buf, __u32 len)
471 if (unlikely(nr->type != RESUME_TYPE_NONE))
472 LIBCOR_ASSERT_ERR();
474 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
475 nr->type = RESUME_TYPE_WRITE;
476 nr->data.write.fd = fd;
478 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
479 LIBCOR_ASSERT_ERR();
481 if (unlikely(WRITE_BUF_SIZE < len))
482 LIBCOR_ASSERT_ERR();
484 if (len != 0) {
485 memcpy(&(nr->data.write.buf[0]), buf, len);
486 nr->data.write.len = len;
489 return _send_cmd(fd, nr, cmd);
492 int read_resp_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr)
494 int rc;
496 struct libcor_nonblock_resumeinfo_resp *nr_resp =
497 &(nr->data.read.funcdata.resp);
499 if (nr->type == RESUME_TYPE_NONE) {
500 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
501 nr->type = RESUME_TYPE_READ;
502 nr->data.read.functype = RESUME_READ_FUNC_RESP;
503 nr_resp->fd = fd;
504 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
505 nr->data.read.functype != RESUME_READ_FUNC_RESP)) {
506 LIBCOR_ASSERT_ERR();
507 } else if (unlikely(nr_resp->fd != fd)) {
508 LIBCOR_ASSERT_ERR();
509 } else {
510 __u8 state = nr_resp->state;
512 if (state == 1) {
513 goto state_1;
514 } else if (unlikely(state != 0)) {
515 LIBCOR_ASSERT_ERR();
519 nr_resp->respcode = 0;
520 rc = read_fully(fd, nr, (char *) &(nr_resp->respcode), 1, 0);
522 if (rc != RC_OK)
523 return bzero_nr_iffinished(nr, rc);
525 if (nr_resp->respcode == CDR_EXECFAILED) {
526 /* printf("crd_execfailed\n"); */
528 nr_resp->reasoncode = 0;
530 nr_resp->state = 1;
531 state_1:
532 rc = read_fully(fd, nr, (char *) &(nr_resp->reasoncode), 2, 0);
533 if (rc != RC_OK)
534 return bzero_nr_iffinished(nr, rc);
536 nr_resp->reasoncode = ntohs(nr_resp->reasoncode);
538 printf("execfailed: reasoncode = %d\n", (__s32)
539 nr_resp->reasoncode);
542 //printf("read_resp: respcode = %d\n", nr_resp->respcode);
544 if (nr_resp->respcode == CDR_EXECOK)
545 return bzero_nr_iffinished(nr, RC_OK);
547 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
550 int read_resp(int fd)
552 int rc = RC_WOULDBLOCK;
553 struct libcor_nonblock_resumeinfo nr;
554 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
556 rc = read_resp_nonblock(fd, &nr);
557 if (unlikely(rc == RC_WOULDBLOCK)) {
558 LIBCOR_ASSERT_ERR();
559 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
561 return rc;
565 int send_connect_neigh_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
566 __u32 addrlen, char *addr)
568 __u32 hdrlen = 0;
569 int rc;
571 if (unlikely(nr->type != RESUME_TYPE_NONE))
572 LIBCOR_ASSERT_ERR();
574 if (unlikely(addrlen > (1024 * 1024 * 1024) ||
575 addrlen + 4 > WRITE_BUF_SIZE))
576 LIBCOR_ASSERT_ERR();
578 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
579 nr->type = RESUME_TYPE_WRITE;
580 nr->data.write.fd = fd;
582 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
583 LIBCOR_ASSERT_ERR();
585 if (unlikely(WRITE_BUF_SIZE < 4))
586 LIBCOR_ASSERT_ERR();
588 rc = encode_len(&(nr->data.write.buf[nr->data.write.len]), 4, addrlen);
589 if (unlikely(rc <= 0 || rc > 4))
590 LIBCOR_ASSERT_ERR();
592 nr->data.write.len += (__u32) rc;
594 if (unlikely(nr->data.write.len > WRITE_BUF_SIZE ||
595 WRITE_BUF_SIZE - nr->data.write.len < addrlen))
596 LIBCOR_ASSERT_ERR();
598 memcpy(&(nr->data.write.buf[nr->data.write.len]), addr, addrlen);
599 nr->data.write.len += addrlen;
601 if (unlikely(nr->data.write.len > WRITE_BUF_SIZE))
602 LIBCOR_ASSERT_ERR();
604 return _send_cmd(fd, nr, CD_CONNECT_NB);
607 int send_connect_neigh(int fd, __u32 addrlen, char *addr)
609 int rc = RC_WOULDBLOCK;
610 struct libcor_nonblock_resumeinfo nr;
611 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
613 rc = send_connect_neigh_nonblock(fd, &nr, addrlen, addr);
614 if (unlikely(rc == RC_WOULDBLOCK)) {
615 LIBCOR_ASSERT_ERR();
616 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
618 return rc;
621 int send_connect_port_nonblock(int fd,
622 struct libcor_nonblock_resumeinfo *nr, __be16 port)
624 return send_cmd(fd, nr, CD_CONNECT_PORT, (char *) &port, 2);
627 int send_connect_port(int fd, __be16 port)
629 int rc = RC_WOULDBLOCK;
630 struct libcor_nonblock_resumeinfo nr;
631 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
633 rc = send_connect_port_nonblock(fd, &nr, port);
634 if (unlikely(rc == RC_WOULDBLOCK)) {
635 LIBCOR_ASSERT_ERR();
636 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
638 return rc;
641 int send_list_services_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr)
643 return send_cmd(fd, nr, CD_LIST_SERVICES, 0, 0);
646 int send_list_services(int fd)
648 int rc = RC_WOULDBLOCK;
649 struct libcor_nonblock_resumeinfo nr;
650 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
652 rc = send_list_services_nonblock(fd, &nr);
653 if (unlikely(rc == RC_WOULDBLOCK)) {
654 LIBCOR_ASSERT_ERR();
655 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
657 return rc;
660 int read_service_list_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
661 void *ptr,
662 void (*init)(void *ptr, __u32 numservices),
663 void (*next_service)(void *ptr, __be16 port))
665 int rc;
667 struct libcor_nonblock_resumeinfo_servicelist *nr_sl =
668 &(nr->data.read.funcdata.servicelist);
670 if (nr->type == RESUME_TYPE_NONE) {
671 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
672 nr->type = RESUME_TYPE_READ;
673 nr->data.read.functype = RESUME_READ_FUNC_SERVICELIST;
674 nr_sl->fd = fd;
675 nr_sl->ptr = ptr;
676 nr_sl->init = init;
677 nr_sl->next_service = next_service;
678 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
679 nr->data.read.functype !=
680 RESUME_READ_FUNC_SERVICELIST)) {
681 LIBCOR_ASSERT_ERR();
682 } else if (unlikely(nr_sl->fd != fd ||
683 nr_sl->ptr != ptr ||
684 nr_sl->init != init ||
685 nr_sl->next_service != next_service)) {
686 LIBCOR_ASSERT_ERR();
687 } else {
688 __u8 state = nr_sl->state;
689 if (state == 1) {
690 goto state_1;
691 } else if (state == 2) {
692 goto state_2;
693 } else if (state == 3) {
694 goto state_3;
695 } else if (unlikely(state != 0)) {
696 LIBCOR_ASSERT_ERR();
700 nr_sl->respcode = 0;
702 rc = read_fully(fd, nr, (char *) &(nr_sl->respcode), 1, 0);
703 if (rc != RC_OK)
704 return bzero_nr_iffinished(nr, rc);
706 if (unlikely(nr_sl->respcode != CDR_BINDATA))
707 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
709 nr_sl->state = 1;
710 state_1:
711 rc = read_len(fd, nr, &(nr_sl->len), 0);
712 if (rc != RC_OK)
713 return bzero_nr_iffinished(nr, rc);
715 nr_sl->state = 2;
716 state_2:
717 rc = read_len(fd, nr, &(nr_sl->numservices), &(nr_sl->len));
718 if (rc != RC_OK)
719 return bzero_nr_iffinished(nr, rc);
721 init(ptr, nr_sl->numservices);
723 for(nr_sl->q=0; nr_sl->q < nr_sl->numservices; nr_sl->q++) {
724 nr_sl->port = 0;
726 nr_sl->state = 3;
727 state_3:
728 rc = read_fully(fd, nr, (char *) &(nr_sl->port), 2,
729 &(nr_sl->len));
730 if (rc != RC_OK)
731 return bzero_nr_iffinished(nr, rc);
733 next_service(ptr, nr_sl->port);
734 nr_sl->port = 0;
737 return bzero_nr_iffinished(nr, rc);
740 int read_service_list(int fd, void *ptr,
741 void (*init)(void *ptr, __u32 numservices),
742 void (*next_service)(void *ptr, __be16 port))
744 int rc = RC_WOULDBLOCK;
745 struct libcor_nonblock_resumeinfo nr;
746 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
748 rc = read_service_list_nonblock(fd, &nr, ptr, init, next_service);
749 if (unlikely(rc == RC_WOULDBLOCK)) {
750 LIBCOR_ASSERT_ERR();
751 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
753 return rc;
757 int send_list_neigh_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr)
759 return send_cmd(fd, nr, CD_LIST_NEIGH, 0, 0);
762 int send_list_neigh(int fd)
764 int rc = RC_WOULDBLOCK;
765 struct libcor_nonblock_resumeinfo nr;
766 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
768 rc = send_list_neigh_nonblock(fd, &nr);
769 if (unlikely(rc == RC_WOULDBLOCK)) {
770 LIBCOR_ASSERT_ERR();
771 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
773 return rc;
776 static int field_present(struct listneigh_field *fields, __u32 numfields,
777 __u16 field)
779 __u64 u;
780 for(u=0;u<numfields;u++) {
781 if (fields[u].field == field)
782 return 1;
784 return 0;
787 int read_neigh_list_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
788 void *ptr,
789 void (*init)(void *ptr, __u32 numneigh),
790 void (*next_neigh)(void *ptr, __u32 addrlen, char *addr))
792 int rc;
794 struct libcor_nonblock_resumeinfo_neighlist *nr_nl =
795 &(nr->data.read.funcdata.neighlist);
797 if (nr->type == RESUME_TYPE_NONE) {
798 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
799 nr->type = RESUME_TYPE_READ;
800 nr->data.read.functype = RESUME_READ_FUNC_NEIGHLIST;
801 nr_nl->fd = fd;
802 nr_nl->ptr = ptr;
803 nr_nl->init = init;
804 nr_nl->next_neigh = next_neigh;
805 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
806 nr->data.read.functype != RESUME_READ_FUNC_NEIGHLIST)) {
807 LIBCOR_ASSERT_ERR();
808 } else if (unlikely(nr_nl->fd != fd ||
809 nr_nl->ptr != ptr ||
810 nr_nl->init != init ||
811 nr_nl->next_neigh != next_neigh)) {
812 LIBCOR_ASSERT_ERR();
813 } else {
814 __u8 state = nr_nl->state;
815 if (state == 1) {
816 goto state_1;
817 } else if (state == 2) {
818 goto state_2;
819 } else if (state == 3) {
820 goto state_3;
821 } else if (state == 4) {
822 goto state_4;
823 } else if (state == 5) {
824 goto state_5;
825 } else if (state == 6) {
826 goto state_6;
827 } else if (state == 7) {
828 goto state_7;
829 } else if (state == 8) {
830 goto state_8;
831 } else if (state == 9) {
832 goto state_9;
833 } else if (unlikely(state != 0)) {
834 LIBCOR_ASSERT_ERR();
838 nr_nl->respcode = 0;
840 rc = read_fully(fd, nr, (char *) &(nr_nl->respcode), 1, 0);
841 if (rc != RC_OK)
842 return bzero_nr_iffinished(nr, rc);
844 if (unlikely(nr_nl->respcode != CDR_BINDATA))
845 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
847 nr_nl->state = 1;
848 state_1:
849 rc = read_len(fd, nr, &(nr_nl->len), 0);
850 if (rc != RC_OK)
851 return bzero_nr_iffinished(nr, rc);
853 nr_nl->state = 2;
854 state_2:
855 rc = read_len(fd, nr, &(nr_nl->numneighs), &(nr_nl->len));
856 if (rc != RC_OK)
857 return bzero_nr_iffinished(nr, rc);
859 nr_nl->state = 3;
860 state_3:
861 rc = read_len(fd, nr, &(nr_nl->numfields), &(nr_nl->len));
862 if (rc != RC_OK)
863 return bzero_nr_iffinished(nr, rc);
865 if (unlikely(nr_nl->numfields > NEIGHLIST_MAX_FIELDS))
866 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
868 for(nr_nl->u=0; nr_nl->u < nr_nl->numfields; nr_nl->u++) {
869 nr_nl->fields[nr_nl->u].field = 0;
871 nr_nl->state = 4;
872 state_4:
873 rc = read_fully(fd, nr,
874 (char *) &(nr_nl->fields[nr_nl->u].field),
875 2, &(nr_nl->len));
876 if (rc != RC_OK)
877 return bzero_nr_iffinished(nr, rc);
878 nr_nl->fields[nr_nl->u].field =
879 ntohs(nr_nl->fields[nr_nl->u].field);
881 nr_nl->state = 5;
882 state_5:
883 nr_nl->fieldlen = 0;
884 rc = read_len(fd, nr, &(nr_nl->fieldlen), &(nr_nl->len));
885 if (rc != RC_OK)
886 return bzero_nr_iffinished(nr, rc);
888 if (unlikely(nr_nl->fieldlen > 65535))
889 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
891 nr_nl->fields[nr_nl->u].len = (__u16) nr_nl->fieldlen;
892 nr_nl->fieldlen = 0;
895 if (unlikely(field_present(nr_nl->fields, nr_nl->numfields,
896 LIST_NEIGH_FIELD_ADDR) == 0))
897 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
899 init(ptr, nr_nl->numneighs);
901 for (nr_nl->u=0; nr_nl->u < nr_nl->numneighs; nr_nl->u++) {
902 bzero(&(nr_nl->addr[0]), ADDR_MAX_LEN);
903 nr_nl->addrlen = 0;
904 nr_nl->latency = 0;
906 for(nr_nl->v=0; nr_nl->v < nr_nl->numfields; nr_nl->v++) {
907 nr_nl->fieldlen = nr_nl->fields[nr_nl->v].len;
908 if (nr_nl->fieldlen == 0) {
909 nr_nl->state = 6;
910 state_6:
911 rc = read_len(fd, nr, &(nr_nl->fieldlen),
912 &(nr_nl->len));
913 if (rc != RC_OK)
914 return bzero_nr_iffinished(nr, rc);
917 if (nr_nl->fieldlen > nr_nl->len)
918 return bzero_nr_iffinished(nr, RC_CONNBROKEN);
920 nr_nl->len -= nr_nl->fieldlen;
922 if (field_present(nr_nl->fields, nr_nl->v,
923 nr_nl->fields[nr_nl->v].field)) {
924 goto discard_field;
925 } else if (nr_nl->fields[nr_nl->v].field ==
926 LIST_NEIGH_FIELD_ADDR) {
928 nr_nl->addrlen = nr_nl->fieldlen;
930 if (unlikely(nr_nl->addrlen > ADDR_MAX_LEN))
931 goto discard_field;
933 if (sizeof(nr_nl->addr) != ADDR_MAX_LEN)
934 LIBCOR_ASSERT_ERR();
936 bzero(&(nr_nl->addr[0]), ADDR_MAX_LEN);
938 nr_nl->state = 7;
939 state_7:
940 rc = read_fully(fd, nr, &(nr_nl->addr[0]),
941 nr_nl->addrlen,
942 &(nr_nl->fieldlen));
943 if (rc != RC_OK)
944 return bzero_nr_iffinished(nr, rc);
945 } else if (nr_nl->fields[nr_nl->v].field ==
946 LIST_NEIGH_FIELD_LATENCY) {
947 nr_nl->latency = 0;
949 nr_nl->state = 8;
950 state_8:
951 rc = read_fully(fd, nr, &nr_nl->latency, 1,
952 &(nr_nl->fieldlen));
953 if (rc != RC_OK)
954 return bzero_nr_iffinished(nr, rc);
956 printf("latency %d\n", (int) nr_nl->latency);
959 discard_field:
960 if (nr_nl->fieldlen > 0) {
961 nr_nl->state = 9;
962 state_9:
963 rc = read_discard(fd, nr, nr_nl->fieldlen);
964 if (rc != RC_OK)
965 return bzero_nr_iffinished(nr, rc);
968 nr_nl->fieldlen = 0;
971 if (nr_nl->addrlen > ADDR_MAX_LEN)
972 LIBCOR_ASSERT_ERR();
974 next_neigh(ptr, nr_nl->addrlen, &(nr_nl->addr[0]));
975 bzero(&(nr_nl->addr[0]), ADDR_MAX_LEN);
976 nr_nl->addrlen = 0;
977 nr_nl->latency = 0;
980 return bzero_nr_iffinished(nr, rc);
983 int read_neigh_list(int fd, void *ptr,
984 void (*init)(void *ptr, __u32 numneighs),
985 void (*next_neigh)(void *ptr, __u32 addrlen, char *addr))
987 int rc = RC_WOULDBLOCK;
988 struct libcor_nonblock_resumeinfo nr;
989 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
991 rc = read_neigh_list_nonblock(fd, &nr, ptr, init, next_neigh);
992 if (unlikely(rc == RC_WOULDBLOCK)) {
993 LIBCOR_ASSERT_ERR();
994 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
996 return rc;
999 int pass_socket(int fd, __u64 cookie)
1001 int rc;
1003 rc = setsockopt(fd, SOL_COR, COR_PASS_ON_CLOSE, &cookie, 8);
1004 if (rc != 0) {
1005 perror("pass_socket");
1006 return RC_CONNBROKEN;
1009 close(fd);
1011 return RC_OK;
1014 static int send_rdsock_cmd(int fd, struct libcor_nonblock_resumeinfo *nr,
1015 __u32 cmd, char *data, __u32 datalen)
1017 __u32 be_cmd = htonl(cmd);
1018 __u32 be_datalen = htonl(datalen);
1020 if (unlikely(nr->type != RESUME_TYPE_NONE))
1021 LIBCOR_ASSERT_ERR();
1023 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
1024 nr->type = RESUME_TYPE_WRITE;
1025 nr->data.write.fd = fd;
1027 if (sizeof(nr->data.write.buf) != WRITE_BUF_SIZE)
1028 LIBCOR_ASSERT_ERR();
1030 if (unlikely(datalen + 8 < datalen || WRITE_BUF_SIZE < (datalen + 8)))
1031 LIBCOR_ASSERT_ERR();
1033 memcpy(&(nr->data.write.buf[0]), (char *) &be_cmd, 4);
1034 memcpy(&(nr->data.write.buf[4]), (char *) &be_datalen, 4);
1035 memcpy(&(nr->data.write.buf[8]), data, datalen);
1036 nr->data.write.len = datalen + 8;
1038 return resume_send(fd, nr);
1041 int send_rdsock_version_nonblock(int fd,
1042 struct libcor_nonblock_resumeinfo *nr,
1043 __u32 version)
1045 char data[4];
1047 version = htonl(version);
1049 memcpy(&(data[0]), (char *) &version, 4);
1051 return send_rdsock_cmd(fd, nr, CRD_UTK_VERSION, &(data[0]), 4);
1054 int send_rdsock_version(int fd, __u32 version)
1056 int rc = RC_WOULDBLOCK;
1057 struct libcor_nonblock_resumeinfo nr;
1058 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1060 rc = send_rdsock_version_nonblock(fd, &nr, version);
1061 if (unlikely(rc == RC_WOULDBLOCK)) {
1062 LIBCOR_ASSERT_ERR();
1063 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1065 return rc;
1068 int send_rdsock_up_nonblock(int fd, struct libcor_nonblock_resumeinfo *nr,
1069 char *addr, __u32 addrlen)
1071 char data[72];
1073 __u64 flags = 0;
1075 __u32 addrlenbe;
1077 if (addr == 0 && addrlen != 0)
1078 return RC_CONNBROKEN;
1080 if (addrlen > 64)
1081 return RC_CONNBROKEN;
1083 flags = htonll(flags);
1084 addrlenbe = htonl(addrlen);
1086 memcpy(&(data[0]), (char *) &flags, 8);
1087 memcpy(&(data[8]), (char *) &addrlenbe, 4);
1088 if (addrlen > 0)
1089 memcpy(&(data[12]), addr, addrlen);
1091 return send_rdsock_cmd(fd, nr, CRD_UTK_UP, &(data[0]), 12 + addrlen);
1094 int send_rdsock_up(int fd, char *addr, __u32 addrlen)
1096 int rc = RC_WOULDBLOCK;
1097 struct libcor_nonblock_resumeinfo nr;
1098 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1100 rc = send_rdsock_up_nonblock(fd, &nr, addr, addrlen);
1101 if (unlikely(rc == RC_WOULDBLOCK)) {
1102 LIBCOR_ASSERT_ERR();
1103 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1105 return rc;
1108 int send_rdsock_connecterror_nonblock(int fd,
1109 struct libcor_nonblock_resumeinfo *nr,
1110 __u64 cookie, __u32 error)
1112 char data[12];
1114 error = htonl(error);
1116 memcpy(&(data[0]), (char *) &cookie, 8);
1117 memcpy(&(data[8]), (char *) &error, 4);
1119 return send_rdsock_cmd(fd, nr, CRD_UTK_CONNECTERROR, &(data[0]), 12);
1122 int send_rdsock_connecterror(int fd, __u64 cookie, __u32 error)
1124 int rc = RC_WOULDBLOCK;
1125 struct libcor_nonblock_resumeinfo nr;
1126 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1128 rc = send_rdsock_connecterror_nonblock(fd, &nr, cookie, error);
1129 if (unlikely(rc == RC_WOULDBLOCK)) {
1130 LIBCOR_ASSERT_ERR();
1131 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1133 return rc;
1136 int parse_rdsock_supported_versions(struct rdsock_cmd *cmd,
1137 __u32 *versionmin, __u32 *versionmax)
1139 if (cmd->cmddatalen != 8)
1140 return 1;
1142 memcpy((char *) versionmin, cmd->cmddata, 4);
1143 *versionmin = htonl(*versionmin);
1144 memcpy((char *) versionmax, cmd->cmddata + 4, 4);
1145 *versionmax = htonl(*versionmax);
1147 return 0;
1150 int parse_rdsock_connect(void *ptr, struct rdsock_cmd *cmd,
1151 int (*proc_connect)(void *ptr, __u64 cookie,
1152 struct cor_sockaddr *addr))
1154 __u64 cookie;
1155 struct cor_sockaddr addr;
1157 memcpy((char *) &cookie, cmd->cmddata, 8);
1159 if ((sizeof(struct cor_sockaddr) + 8) != cmd->cmddatalen)
1160 return 1;
1162 memcpy((char *) &addr, cmd->cmddata + 8, sizeof(struct cor_sockaddr));
1164 return proc_connect(ptr, cookie, &addr);
1167 int read_rdsock_cmd_nonblock(int fd,
1168 struct libcor_nonblock_resumeinfo *nr,
1169 struct rdsock_cmd *cmd)
1171 int rc;
1173 struct libcor_nonblock_resumeinfo_rdsockcmd *nr_rd =
1174 &(nr->data.read.funcdata.rdsock_cmd);
1176 bzero(cmd, sizeof(struct rdsock_cmd));
1178 if (nr->type == RESUME_TYPE_NONE) {
1179 bzero(nr, sizeof(struct libcor_nonblock_resumeinfo));
1180 nr->type = RESUME_TYPE_READ;
1181 nr->data.read.functype = RESUME_READ_FUNC_RDSOCK_CMD;
1182 nr_rd->fd = fd;
1183 } else if (unlikely(nr->type != RESUME_TYPE_READ ||
1184 nr->data.read.functype != RESUME_READ_FUNC_RDSOCK_CMD)){
1185 LIBCOR_ASSERT_ERR();
1186 } else if (unlikely(nr_rd->fd != fd)) {
1187 LIBCOR_ASSERT_ERR();
1188 } else {
1189 __u8 state = nr_rd->state;
1191 if (state == 1) {
1192 goto state_1;
1193 } else if (state == 2) {
1194 goto state_2;
1195 } else if (unlikely(state != 0)) {
1196 LIBCOR_ASSERT_ERR();
1200 if (sizeof(nr_rd->buf) != 8)
1201 LIBCOR_ASSERT_ERR();
1203 rc = read_fully(fd, nr, (char *) &(nr_rd->buf[0]), 8, 0);
1204 if (rc != RC_OK)
1205 return bzero_nr_iffinished(nr, rc);
1207 ((char *) &(nr_rd->cmd))[0] = nr_rd->buf[0];
1208 ((char *) &(nr_rd->cmd))[1] = nr_rd->buf[1];
1209 ((char *) &(nr_rd->cmd))[2] = nr_rd->buf[2];
1210 ((char *) &(nr_rd->cmd))[3] = nr_rd->buf[3];
1211 ((char *) &(nr_rd->cmddatalen))[0] = nr_rd->buf[4];
1212 ((char *) &(nr_rd->cmddatalen))[1] = nr_rd->buf[5];
1213 ((char *) &(nr_rd->cmddatalen))[2] = nr_rd->buf[6];
1214 ((char *) &(nr_rd->cmddatalen))[3] = nr_rd->buf[7];
1216 nr_rd->cmd = ntohl(nr_rd->cmd);
1217 nr_rd->cmddatalen = ntohl(nr_rd->cmddatalen);
1219 if (nr_rd->cmddatalen > 65536)
1220 goto discard;
1222 nr_rd->cmddata = malloc(nr_rd->cmddatalen);
1223 if (nr_rd->cmddata == 0)
1224 goto discard;
1226 nr_rd->state = 1;
1227 state_1:
1228 rc = read_fully(fd, nr, nr_rd->cmddata, nr_rd->cmddatalen, 0);
1229 if (rc != RC_OK) {
1230 if (rc != RC_WOULDBLOCK) {
1231 free(nr_rd->cmddata);
1232 nr_rd->cmddata = 0;
1234 return bzero_nr_iffinished(nr, rc);
1237 cmd->cmd = nr_rd->cmd;
1238 cmd->cmddata = nr_rd->cmddata;
1239 cmd->cmddatalen = nr_rd->cmddatalen;
1241 if (0) {
1242 discard:
1243 nr_rd->state = 2;
1244 state_2:
1245 rc = read_discard(fd, nr, nr_rd->cmddatalen);
1246 if (rc != RC_OK)
1247 return bzero_nr_iffinished(nr, rc);
1249 return bzero_nr_iffinished(nr, rc);
1252 int read_rdsock_cmd(int fd, struct rdsock_cmd *cmd)
1254 int rc = RC_WOULDBLOCK;
1255 struct libcor_nonblock_resumeinfo nr;
1256 bzero(&nr, sizeof(struct libcor_nonblock_resumeinfo));
1258 rc = read_rdsock_cmd_nonblock(fd, &nr, cmd);
1259 if (unlikely(rc == RC_WOULDBLOCK)) {
1260 LIBCOR_ASSERT_ERR();
1261 return bzero_nr_iffinished(&nr, RC_CONNBROKEN);
1263 return rc;