From 43648b5f488062fc7007e1161312dd36ba48f22f Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Tue, 26 Mar 2013 02:00:36 +0100 Subject: propagate: move to broken/ --- broken/propagate/Makefile | 5 + broken/propagate/README.txt | 101 ++++++ broken/propagate/TODO.txt | 40 +++ broken/propagate/src/Makefile | 15 + broken/propagate/src/atomicio.c | 77 ++++ broken/propagate/src/atomicio.h | 40 +++ broken/propagate/src/base64.c | 575 ++++++++++++++++++++++++++++++ broken/propagate/src/base64.h | 63 ++++ broken/propagate/src/cli_fe_http.py | 34 ++ broken/propagate/src/listener.c | 271 ++++++++++++++ broken/propagate/src/log.c | 108 ++++++ broken/propagate/src/msg.c | 225 ++++++++++++ broken/propagate/src/pg.c | 448 +++++++++++++++++++++++ broken/propagate/src/pg.h | 174 +++++++++ broken/propagate/src/queue.h | 568 +++++++++++++++++++++++++++++ broken/propagate/src/route.c | 138 +++++++ broken/propagate/src/tests/Makefile | 23 ++ broken/propagate/src/tests/test_base64.c | 88 +++++ broken/propagate/src/tests/test_explode.c | 39 ++ broken/propagate/src/util.c | 233 ++++++++++++ 20 files changed, 3265 insertions(+) create mode 100644 broken/propagate/Makefile create mode 100644 broken/propagate/README.txt create mode 100644 broken/propagate/TODO.txt create mode 100644 broken/propagate/src/Makefile create mode 100644 broken/propagate/src/atomicio.c create mode 100644 broken/propagate/src/atomicio.h create mode 100644 broken/propagate/src/base64.c create mode 100644 broken/propagate/src/base64.h create mode 100644 broken/propagate/src/cli_fe_http.py create mode 100644 broken/propagate/src/listener.c create mode 100644 broken/propagate/src/log.c create mode 100644 broken/propagate/src/msg.c create mode 100644 broken/propagate/src/pg.c create mode 100644 broken/propagate/src/pg.h create mode 100644 broken/propagate/src/queue.h create mode 100644 broken/propagate/src/route.c create mode 100644 broken/propagate/src/tests/Makefile create mode 100644 broken/propagate/src/tests/test_base64.c create mode 100644 broken/propagate/src/tests/test_explode.c create mode 100644 broken/propagate/src/util.c (limited to 'broken') diff --git a/broken/propagate/Makefile b/broken/propagate/Makefile new file mode 100644 index 0000000..5722a0d --- /dev/null +++ b/broken/propagate/Makefile @@ -0,0 +1,5 @@ +all: + cd src/; $(MAKE) + +clean: + cd src/; $(MAKE) clean diff --git a/broken/propagate/README.txt b/broken/propagate/README.txt new file mode 100644 index 0000000..97b601c --- /dev/null +++ b/broken/propagate/README.txt @@ -0,0 +1,101 @@ +propagate - run commands and proxyfy connections on firewalled machines + +2012 Laurent 'laurent' Ghigonis + +This tool is not fully functionnal yet +- remote shell works (2012-03-05) + +Some code is from ihf tool i started with warren aka m101. + + +Example of remote interactive shell +=================================== + +Client part addresses are still hardcoded in the software, as we +do not have configuration file handling yet. + +==- server part -== + +./src/pg -l -vv -d + +mkfifo pipe; nc -k -vvv -l 127.0.0.1 3333 < pipe |nc -vvv -U +/tmp/propagate_sock |tee pipe + +==- client part -== + +./src/pg -vv /bin/sh +ls +bak.sh +Makefile +pg.log +pipe +README +src +TODO + + +IDEAS: Usage examples that i want to have in that tool +====================================================== + +Successive example steps that makes you have easy remote shell +from your machine on hosts inside a remote network that you control. +(A) Your machine +(B) Application server running tomcat, where all other connections in/out are blocked +(C) A server behind (B) + +==- I - Remote shell through jsp server running on 1.2.3.4 -== + +-- On the server (B) -- +cat > pg.conf +listen on unix "/tmp/pg.sock" +EOF +pg -l +# deploy fe_srv_http.war to /toto.jsp + +-- On the client (A) -- +cat > pg.conf +route add B using "fe_cli_http.py 1.2.3.4 80 /toto.jsp" async +EOF +pg -t B /bin/sh + +==- II - Remote shell on another server 10.0.0.1 port 3000 living on (B) network -== + +-- On the server (B) -- +cat >> pg.conf +route add C using inet 10.0.0.1 3000 +EOF +pkill -x pg +pg -l + +-- On the server (C) -- +cat > pg.conf +listen on inet 10.0.0.1 3000 +EOF +pg -l + +-- On the client (A) -- +cat >> pg.conf +route add C gw B +EOF +pg -t C /bin/sh + +==- III - Use (B) and (C) from (A) for more than remote shell -== + +-- Connect via ssh to (B) -- +ssh -o ProxyCommand='pg -t B nc 127.0.0.1 22' 127.0.0.1 + +-- Transfer a directory from (C) -- +scp -r -o ProxyCommand='pg -t C nc 127.0.0.1 22' 127.0.0.1:/backups/ . + +-- Use nmap from your machine (A) to scan (B) internal network -== +ssh -D 3333 -o ProxyCommand='pg -t B nc 127.0.0.1 22' 127.0.0.1 +cat > /etc/tsocks.conf + local = 192.168.0.0/255.255.255.0 + server = 127.0.0.1 + server_type = 5 + server_port = 3333 +EOF +tsocks nmap -n 10.0.0.0-255 + +-- Forward a local port on (A) to a port on (C) -- +nc -l 127.0.0.1 4025 |pg -t C nc 127.0.0.1 25 diff --git a/broken/propagate/TODO.txt b/broken/propagate/TODO.txt new file mode 100644 index 0000000..873f9f4 --- /dev/null +++ b/broken/propagate/TODO.txt @@ -0,0 +1,40 @@ +---- FIX ---- + +client does not exit when cmd exits + +second connection makes crash +1330901344 W A is already executing a command +1330901344 exec failed +*** glibc detected *** ./src/pg: double free or corruption (out): 0x00007fff1637b6e0 *** +==> need to cleanup connections / execs + +---- TODO ---- + +cleanup dead connection +cleanup dead execs +cleanup dead route execs + +need to emulate a real terminal + ssh 127.0.0.1 => 'Pseudo-terminal will not be allocated because stdin is not a terminal.' + +async sigalarm() +read all remainingargv as client command + +use base64 + +conf file handling + +---- LONGTERM FIX ---- + +maybe use libevent ... check reality of the following arguments + + less code, cleaner code ... maybe + + maybe more portable because it can use select() if poll() isn't there + - dependency if linked dynamicaly, bigger size if static + +---- LONGTERM FUNCTIONNALITIES ---- + +port forwarding + but we could do it with nc + +socks proxy (write a separate lib in C) + but we could do it with ssh diff --git a/broken/propagate/src/Makefile b/broken/propagate/src/Makefile new file mode 100644 index 0000000..a59af5d --- /dev/null +++ b/broken/propagate/src/Makefile @@ -0,0 +1,15 @@ +TARGET = pg +CFLAGS = -g -Wall +LDFLAGS = + +all: $(TARGET) + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) $(LDFLAGS) + +$(TARGET): pg.o msg.o route.o listener.o log.o util.o atomicio.o + $(CC) pg.o msg.o route.o listener.o log.o util.o atomicio.o -o $(TARGET) $(LDFLAGS) $(CFLAGS) + +clean: + rm -f $(TARGET) *~ *.o + diff --git a/broken/propagate/src/atomicio.c b/broken/propagate/src/atomicio.c new file mode 100644 index 0000000..4ac3a08 --- /dev/null +++ b/broken/propagate/src/atomicio.c @@ -0,0 +1,77 @@ +/* propagate v0.1 laurent */ +/* $OpenBSD: atomicio.c,v 1.10 2011/01/08 00:47:19 jeremy Exp $ */ +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "pg.h" +#include "atomicio.h" + +/* + * ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) +{ + char *s = _s; + size_t pos = 0; + ssize_t res; + struct pollfd pfd; + int try = 0; + + pfd.fd = fd; + pfd.events = f == read ? POLLIN : POLLOUT; + while (n > pos && try < POLL_ATOMIC_RETRY) { + log_debug("atomicio: beg fd %d", fd); + res = (f) (fd, s + pos, n - pos); + log_debug("atomicio: end"); + switch (res) { + case -1: + if (errno == EINTR) + continue; + if ((errno == EAGAIN) || (errno == ENOBUFS)) { + (void)poll(&pfd, 1, POLL_TIMEOUT_ATOMIC); + log_tmp("atomicio: try"); + try++; + continue; + } + return 0; + case 0: + errno = EPIPE; + return pos; + default: + pos += (size_t)res; + } + } + return (pos); +} + diff --git a/broken/propagate/src/atomicio.h b/broken/propagate/src/atomicio.h new file mode 100644 index 0000000..c11e63f --- /dev/null +++ b/broken/propagate/src/atomicio.h @@ -0,0 +1,40 @@ +/* $OpenBSD: atomicio.h,v 1.2 2007/09/07 14:50:44 tobias Exp $ */ + +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ATOMICIO_H +#define _ATOMICIO_H + +/* + * Ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); + +#define vwrite (ssize_t (*)(int, void *, size_t))write + +#endif /* _ATOMICIO_H */ + diff --git a/broken/propagate/src/base64.c b/broken/propagate/src/base64.c new file mode 100644 index 0000000..acf49c8 --- /dev/null +++ b/broken/propagate/src/base64.c @@ -0,0 +1,575 @@ +/* base64.c -- Encode binary data using printable characters. + Copyright (C) 1999-2001, 2004-2006, 2009-2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Simon Josefsson. Partially adapted from GNU MailUtils + * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review + * from Paul Eggert, Bruno Haible, and Stepan Kasal. + * + * See also RFC 4648 . + * + * Be careful with error checking. Here is how you would typically + * use these functions: + * + * bool ok = base64_decode_alloc (in, inlen, &out, &outlen); + * if (!ok) + * FAIL: input was not valid base64 + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN + * + * size_t outlen = base64_encode_alloc (in, inlen, &out); + * if (out == NULL && outlen == 0 && inlen != 0) + * FAIL: input too long + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN. + * + */ + +#include + +/* Get prototype. */ +#include "base64.h" + +/* Get malloc. */ +#include + +/* Get UCHAR_MAX. */ +#include + +#include + +/* C89 compliant way to cast 'char' to 'unsigned char'. */ +static inline unsigned char +to_uchar (char ch) +{ + return ch; +} + +/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. + If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as + possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero + terminate the output buffer. */ +void +base64_encode (const char *restrict in, size_t inlen, + char *restrict out, size_t outlen) +{ + static const char b64str[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + while (inlen && outlen) + { + *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f]; + if (!--outlen) + break; + *out++ = b64str[((to_uchar (in[0]) << 4) + + (--inlen ? to_uchar (in[1]) >> 4 : 0)) + & 0x3f]; + if (!--outlen) + break; + *out++ = + (inlen + ? b64str[((to_uchar (in[1]) << 2) + + (--inlen ? to_uchar (in[2]) >> 6 : 0)) + & 0x3f] + : '='); + if (!--outlen) + break; + *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '='; + if (!--outlen) + break; + if (inlen) + inlen--; + if (inlen) + in += 3; + } + + if (outlen) + *out = '\0'; +} + +/* Allocate a buffer and store zero terminated base64 encoded data + from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e., + the length of the encoded data, excluding the terminating zero. On + return, the OUT variable will hold a pointer to newly allocated + memory that must be deallocated by the caller. If output string + length would overflow, 0 is returned and OUT is set to NULL. If + memory allocation failed, OUT is set to NULL, and the return value + indicates length of the requested memory block, i.e., + BASE64_LENGTH(inlen) + 1. */ +size_t +base64_encode_alloc (const char *in, size_t inlen, char **out) +{ + size_t outlen = 1 + BASE64_LENGTH (inlen); + + /* Check for overflow in outlen computation. + * + * If there is no overflow, outlen >= inlen. + * + * If the operation (inlen + 2) overflows then it yields at most +1, so + * outlen is 0. + * + * If the multiplication overflows, we lose at least half of the + * correct value, so the result is < ((inlen + 2) / 3) * 2, which is + * less than (inlen + 2) * 0.66667, which is less than inlen as soon as + * (inlen > 4). + */ + if (inlen > outlen) + { + *out = NULL; + return 0; + } + + *out = malloc (outlen); + if (!*out) + return outlen; + + base64_encode (in, inlen, *out, outlen); + + return outlen - 1; +} + +/* With this approach this file works independent of the charset used + (think EBCDIC). However, it does assume that the characters in the + Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX + 1003.1-2001 require that char and unsigned char are 8-bit + quantities, though, taking care of that problem. But this may be a + potential problem on non-POSIX C99 platforms. + + IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_" + as the formal parameter rather than "x". */ +#define B64(_) \ + ((_) == 'A' ? 0 \ + : (_) == 'B' ? 1 \ + : (_) == 'C' ? 2 \ + : (_) == 'D' ? 3 \ + : (_) == 'E' ? 4 \ + : (_) == 'F' ? 5 \ + : (_) == 'G' ? 6 \ + : (_) == 'H' ? 7 \ + : (_) == 'I' ? 8 \ + : (_) == 'J' ? 9 \ + : (_) == 'K' ? 10 \ + : (_) == 'L' ? 11 \ + : (_) == 'M' ? 12 \ + : (_) == 'N' ? 13 \ + : (_) == 'O' ? 14 \ + : (_) == 'P' ? 15 \ + : (_) == 'Q' ? 16 \ + : (_) == 'R' ? 17 \ + : (_) == 'S' ? 18 \ + : (_) == 'T' ? 19 \ + : (_) == 'U' ? 20 \ + : (_) == 'V' ? 21 \ + : (_) == 'W' ? 22 \ + : (_) == 'X' ? 23 \ + : (_) == 'Y' ? 24 \ + : (_) == 'Z' ? 25 \ + : (_) == 'a' ? 26 \ + : (_) == 'b' ? 27 \ + : (_) == 'c' ? 28 \ + : (_) == 'd' ? 29 \ + : (_) == 'e' ? 30 \ + : (_) == 'f' ? 31 \ + : (_) == 'g' ? 32 \ + : (_) == 'h' ? 33 \ + : (_) == 'i' ? 34 \ + : (_) == 'j' ? 35 \ + : (_) == 'k' ? 36 \ + : (_) == 'l' ? 37 \ + : (_) == 'm' ? 38 \ + : (_) == 'n' ? 39 \ + : (_) == 'o' ? 40 \ + : (_) == 'p' ? 41 \ + : (_) == 'q' ? 42 \ + : (_) == 'r' ? 43 \ + : (_) == 's' ? 44 \ + : (_) == 't' ? 45 \ + : (_) == 'u' ? 46 \ + : (_) == 'v' ? 47 \ + : (_) == 'w' ? 48 \ + : (_) == 'x' ? 49 \ + : (_) == 'y' ? 50 \ + : (_) == 'z' ? 51 \ + : (_) == '0' ? 52 \ + : (_) == '1' ? 53 \ + : (_) == '2' ? 54 \ + : (_) == '3' ? 55 \ + : (_) == '4' ? 56 \ + : (_) == '5' ? 57 \ + : (_) == '6' ? 58 \ + : (_) == '7' ? 59 \ + : (_) == '8' ? 60 \ + : (_) == '9' ? 61 \ + : (_) == '+' ? 62 \ + : (_) == '/' ? 63 \ + : -1) + +static const signed char b64[0x100] = { + B64 (0), B64 (1), B64 (2), B64 (3), + B64 (4), B64 (5), B64 (6), B64 (7), + B64 (8), B64 (9), B64 (10), B64 (11), + B64 (12), B64 (13), B64 (14), B64 (15), + B64 (16), B64 (17), B64 (18), B64 (19), + B64 (20), B64 (21), B64 (22), B64 (23), + B64 (24), B64 (25), B64 (26), B64 (27), + B64 (28), B64 (29), B64 (30), B64 (31), + B64 (32), B64 (33), B64 (34), B64 (35), + B64 (36), B64 (37), B64 (38), B64 (39), + B64 (40), B64 (41), B64 (42), B64 (43), + B64 (44), B64 (45), B64 (46), B64 (47), + B64 (48), B64 (49), B64 (50), B64 (51), + B64 (52), B64 (53), B64 (54), B64 (55), + B64 (56), B64 (57), B64 (58), B64 (59), + B64 (60), B64 (61), B64 (62), B64 (63), + B64 (64), B64 (65), B64 (66), B64 (67), + B64 (68), B64 (69), B64 (70), B64 (71), + B64 (72), B64 (73), B64 (74), B64 (75), + B64 (76), B64 (77), B64 (78), B64 (79), + B64 (80), B64 (81), B64 (82), B64 (83), + B64 (84), B64 (85), B64 (86), B64 (87), + B64 (88), B64 (89), B64 (90), B64 (91), + B64 (92), B64 (93), B64 (94), B64 (95), + B64 (96), B64 (97), B64 (98), B64 (99), + B64 (100), B64 (101), B64 (102), B64 (103), + B64 (104), B64 (105), B64 (106), B64 (107), + B64 (108), B64 (109), B64 (110), B64 (111), + B64 (112), B64 (113), B64 (114), B64 (115), + B64 (116), B64 (117), B64 (118), B64 (119), + B64 (120), B64 (121), B64 (122), B64 (123), + B64 (124), B64 (125), B64 (126), B64 (127), + B64 (128), B64 (129), B64 (130), B64 (131), + B64 (132), B64 (133), B64 (134), B64 (135), + B64 (136), B64 (137), B64 (138), B64 (139), + B64 (140), B64 (141), B64 (142), B64 (143), + B64 (144), B64 (145), B64 (146), B64 (147), + B64 (148), B64 (149), B64 (150), B64 (151), + B64 (152), B64 (153), B64 (154), B64 (155), + B64 (156), B64 (157), B64 (158), B64 (159), + B64 (160), B64 (161), B64 (162), B64 (163), + B64 (164), B64 (165), B64 (166), B64 (167), + B64 (168), B64 (169), B64 (170), B64 (171), + B64 (172), B64 (173), B64 (174), B64 (175), + B64 (176), B64 (177), B64 (178), B64 (179), + B64 (180), B64 (181), B64 (182), B64 (183), + B64 (184), B64 (185), B64 (186), B64 (187), + B64 (188), B64 (189), B64 (190), B64 (191), + B64 (192), B64 (193), B64 (194), B64 (195), + B64 (196), B64 (197), B64 (198), B64 (199), + B64 (200), B64 (201), B64 (202), B64 (203), + B64 (204), B64 (205), B64 (206), B64 (207), + B64 (208), B64 (209), B64 (210), B64 (211), + B64 (212), B64 (213), B64 (214), B64 (215), + B64 (216), B64 (217), B64 (218), B64 (219), + B64 (220), B64 (221), B64 (222), B64 (223), + B64 (224), B64 (225), B64 (226), B64 (227), + B64 (228), B64 (229), B64 (230), B64 (231), + B64 (232), B64 (233), B64 (234), B64 (235), + B64 (236), B64 (237), B64 (238), B64 (239), + B64 (240), B64 (241), B64 (242), B64 (243), + B64 (244), B64 (245), B64 (246), B64 (247), + B64 (248), B64 (249), B64 (250), B64 (251), + B64 (252), B64 (253), B64 (254), B64 (255) +}; + +#if UCHAR_MAX == 255 +# define uchar_in_range(c) true +#else +# define uchar_in_range(c) ((c) <= 255) +#endif + +/* Return true if CH is a character from the Base64 alphabet, and + false otherwise. Note that '=' is padding and not considered to be + part of the alphabet. */ +bool +isbase64 (char ch) +{ + return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)]; +} + +/* Initialize decode-context buffer, CTX. */ +void +base64_decode_ctx_init (struct base64_decode_context *ctx) +{ + ctx->i = 0; +} + +/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and + none of those four is a newline, then return *IN. Otherwise, copy up to + 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at + index CTX->i and setting CTX->i to reflect the number of bytes copied, + and return CTX->buf. In either case, advance *IN to point to the byte + after the last one processed, and set *N_NON_NEWLINE to the number of + verified non-newline bytes accessible through the returned pointer. */ +static inline char * +get_4 (struct base64_decode_context *ctx, + char const *restrict *in, char const *restrict in_end, + size_t *n_non_newline) +{ + if (ctx->i == 4) + ctx->i = 0; + + if (ctx->i == 0) + { + char const *t = *in; + if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL) + { + /* This is the common case: no newline. */ + *in += 4; + *n_non_newline = 4; + return (char *) t; + } + } + + { + /* Copy non-newline bytes into BUF. */ + char const *p = *in; + while (p < in_end) + { + char c = *p++; + if (c != '\n') + { + ctx->buf[ctx->i++] = c; + if (ctx->i == 4) + break; + } + } + + *in = p; + *n_non_newline = ctx->i; + return ctx->buf; + } +} + +#define return_false \ + do \ + { \ + *outp = out; \ + return false; \ + } \ + while (false) + +/* Decode up to four bytes of base64-encoded data, IN, of length INLEN + into the output buffer, *OUT, of size *OUTLEN bytes. Return true if + decoding is successful, false otherwise. If *OUTLEN is too small, + as many bytes as possible are written to *OUT. On return, advance + *OUT to point to the byte after the last one written, and decrement + *OUTLEN to reflect the number of bytes remaining in *OUT. */ +static inline bool +decode_4 (char const *restrict in, size_t inlen, + char *restrict *outp, size_t *outleft) +{ + char *out = *outp; + if (inlen < 2) + return false; + + if (!isbase64 (in[0]) || !isbase64 (in[1])) + return false; + + if (*outleft) + { + *out++ = ((b64[to_uchar (in[0])] << 2) + | (b64[to_uchar (in[1])] >> 4)); + --*outleft; + } + + if (inlen == 2) + return_false; + + if (in[2] == '=') + { + if (inlen != 4) + return_false; + + if (in[3] != '=') + return_false; + } + else + { + if (!isbase64 (in[2])) + return_false; + + if (*outleft) + { + *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) + | (b64[to_uchar (in[2])] >> 2)); + --*outleft; + } + + if (inlen == 3) + return_false; + + if (in[3] == '=') + { + if (inlen != 4) + return_false; + } + else + { + if (!isbase64 (in[3])) + return_false; + + if (*outleft) + { + *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0) + | b64[to_uchar (in[3])]); + --*outleft; + } + } + } + + *outp = out; + return true; +} + +/* Decode base64-encoded input array IN of length INLEN to output array + OUT that can hold *OUTLEN bytes. The input data may be interspersed + with newlines. Return true if decoding was successful, i.e. if the + input was valid base64 data, false otherwise. If *OUTLEN is too + small, as many bytes as possible will be written to OUT. On return, + *OUTLEN holds the length of decoded bytes in OUT. Note that as soon + as any non-alphabet, non-newline character is encountered, decoding + is stopped and false is returned. If INLEN is zero, then process + only whatever data is stored in CTX. + + Initially, CTX must have been initialized via base64_decode_ctx_init. + Subsequent calls to this function must reuse whatever state is recorded + in that buffer. It is necessary for when a quadruple of base64 input + bytes spans two input buffers. + + If CTX is NULL then newlines are treated as garbage and the input + buffer is processed as a unit. */ + +bool +base64_decode_ctx (struct base64_decode_context *ctx, + const char *restrict in, size_t inlen, + char *restrict out, size_t *outlen) +{ + size_t outleft = *outlen; + bool ignore_newlines = ctx != NULL; + bool flush_ctx = false; + unsigned int ctx_i = 0; + + if (ignore_newlines) + { + ctx_i = ctx->i; + flush_ctx = inlen == 0; + } + + + while (true) + { + size_t outleft_save = outleft; + if (ctx_i == 0 && !flush_ctx) + { + while (true) + { + /* Save a copy of outleft, in case we need to re-parse this + block of four bytes. */ + outleft_save = outleft; + if (!decode_4 (in, inlen, &out, &outleft)) + break; + + in += 4; + inlen -= 4; + } + } + + if (inlen == 0 && !flush_ctx) + break; + + /* Handle the common case of 72-byte wrapped lines. + This also handles any other multiple-of-4-byte wrapping. */ + if (inlen && *in == '\n' && ignore_newlines) + { + ++in; + --inlen; + continue; + } + + /* Restore OUT and OUTLEFT. */ + out -= outleft_save - outleft; + outleft = outleft_save; + + { + char const *in_end = in + inlen; + char const *non_nl; + + if (ignore_newlines) + non_nl = get_4 (ctx, &in, in_end, &inlen); + else + non_nl = in; /* Might have nl in this case. */ + + /* If the input is empty or consists solely of newlines (0 non-newlines), + then we're done. Likewise if there are fewer than 4 bytes when not + flushing context and not treating newlines as garbage. */ + if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines)) + { + inlen = 0; + break; + } + if (!decode_4 (non_nl, inlen, &out, &outleft)) + break; + + inlen = in_end - in; + } + } + + *outlen -= outleft; + + return inlen == 0; +} + +/* Allocate an output buffer in *OUT, and decode the base64 encoded + data stored in IN of size INLEN to the *OUT buffer. On return, the + size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, + if the caller is not interested in the decoded length. *OUT may be + NULL to indicate an out of memory error, in which case *OUTLEN + contains the size of the memory block needed. The function returns + true on successful decoding and memory allocation errors. (Use the + *OUT and *OUTLEN parameters to differentiate between successful + decoding and memory error.) The function returns false if the + input was invalid, in which case *OUT is NULL and *OUTLEN is + undefined. */ +bool +base64_decode_alloc_ctx (struct base64_decode_context *ctx, + const char *in, size_t inlen, char **out, + size_t *outlen) +{ + /* This may allocate a few bytes too many, depending on input, + but it's not worth the extra CPU time to compute the exact size. + The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the + input ends with "=" and minus another 1 if the input ends with "==". + Dividing before multiplying avoids the possibility of overflow. */ + size_t needlen = 3 * (inlen / 4) + 3; + + *out = malloc (needlen); + if (!*out) + return true; + + if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen)) + { + free (*out); + *out = NULL; + return false; + } + + if (outlen) + *outlen = needlen; + + return true; +} diff --git a/broken/propagate/src/base64.h b/broken/propagate/src/base64.h new file mode 100644 index 0000000..8973755 --- /dev/null +++ b/broken/propagate/src/base64.h @@ -0,0 +1,63 @@ +/* base64.h -- Encode binary data using printable characters. + Copyright (C) 2004-2006, 2009-2012 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef BASE64_H +# define BASE64_H + +#include "config.h" + +/* Get size_t. */ +# include + +/* Get bool. */ +# include + +/* This uses that the expression (n+(k-1))/k means the smallest + integer >= n/k, i.e., the ceiling of n/k. */ +# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4) + +struct base64_decode_context +{ + unsigned int i; + char buf[4]; +}; + +extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST; + +extern void base64_encode (const char *restrict in, size_t inlen, + char *restrict out, size_t outlen); + +extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out); + +extern void base64_decode_ctx_init (struct base64_decode_context *ctx); + +extern bool base64_decode_ctx (struct base64_decode_context *ctx, + const char *restrict in, size_t inlen, + char *restrict out, size_t *outlen); + +extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx, + const char *in, size_t inlen, + char **out, size_t *outlen); + +#define base64_decode(in, inlen, out, outlen) \ + base64_decode_ctx (NULL, in, inlen, out, outlen) + +#define base64_decode_alloc(in, inlen, out, outlen) \ + base64_decode_alloc_ctx (NULL, in, inlen, out, outlen) + +#endif /* BASE64_H */ diff --git a/broken/propagate/src/cli_fe_http.py b/broken/propagate/src/cli_fe_http.py new file mode 100644 index 0000000..40b7373 --- /dev/null +++ b/broken/propagate/src/cli_fe_http.py @@ -0,0 +1,34 @@ +import httplib +import urllib +import optparse +import Cookie +""" + Christian + Usage: The following program reads strings from the standard input + and sends them to the server ([host] [port]) in the POST + request on URL [url] in field 'cmd'. + The result is read from the COOKIE "result" and displayed. +""" +def send_cmd_http_post(host, port=80, base64command="base64command", url="/test.php"): + headers = { "Content-type": "application/x-www-form-urlencoded" } + params = urllib.urlencode({'cmd': base64command}) + conn = httplib.HTTPConnection(host, port) + conn.request("POST", url, params, headers) + response = conn.getresponse() + + response_headers = dict(response.getheaders()) + if ('set-cookie' in response_headers): + cookie = Cookie.BaseCookie(response_headers['set-cookie']) + return cookie["result"].value + return "result-cookie-not-found" + +if __name__ == '__main__': + usage = "usage: %prog host port url" + parser = optparse.OptionParser(usage=usage) + (options, args) = parser.parse_args() + if len(args) != 3: + parser.error("incorrect number of arguments") + host, port, url = args + while (True): + base64command = raw_input() + print send_cmd_http_post(host, int(port), base64command, url) diff --git a/broken/propagate/src/listener.c b/broken/propagate/src/listener.c new file mode 100644 index 0000000..782385d --- /dev/null +++ b/broken/propagate/src/listener.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "pg.h" + +#define SOCK_BASENAME "/tmp/propagate_sock" +#define SOCK_NAME_MAXLEN 255 + +static int listener_start(struct listener *); +static int unix_start(struct listener *); +static int inet_start(struct listener *); + +int +listener_add(int type, char *path) { + struct listener *l; + + if (listeners_count >= LISTENERS_MAX) { + log_warn("listeners max reached"); + return -1; + } + l = xcalloc(1, sizeof(struct listener)); + if (!l) + return -1; + + l->type = type; + switch (type) { + case LISTENER_UNIX: + l->sock_unix.path = path; + break; + case LISTENER_INET: + log_warn("listener_add: XXX inet not implemented yet"); + break; + } + LIST_INIT(&(l->conns)); + l->conns_count = 0; + + LIST_INSERT_HEAD(&listeners, l, entry); + listeners_count++; + + listener_start(l); + + return 0; +} + +struct listener * +listener_find(int fd) { + struct listener *l; + + LIST_FOREACH(l, &listeners, entry) { + if (l->sock == fd) + return l; + } + return NULL; +} + +int +listener_conn_add(struct listener *l, int fd) { + struct conn *c; + + if (l->conns_count >= LISTENER_CONN_MAX) { + log_warn("conn max reached"); + return -1; + } + c = xcalloc(1, sizeof(struct conn)); + if (!c) + return -1; + + c->listener = l; + c->fd = fd; + c->state = CONN_OPEN; + + LIST_INSERT_HEAD(&(l->conns), c, entry); + l->conns_count++; + + setnonblock(fd); + + return 0; +} + +void +listener_conn_del(struct conn *c) { + close(c->fd); + if (c->exec.cmd) + listener_conn_exec_kill(c); + LIST_REMOVE(c, entry); + c->listener->conns_count--; + free(c); +} + +void +listener_conn_move(struct conn *oldc, struct conn *newc) { + memcpy(newc, oldc, sizeof(struct conn)); + LIST_REMOVE(oldc, entry); + newc->listener->conns_count--; + free(oldc); +} + +struct conn * +listener_conn_find(int fd) { + struct listener *l; + struct conn *c; + + LIST_FOREACH(l, &listeners, entry) { + LIST_FOREACH(c, &l->conns, entry) { + if (c->fd == fd) + return c; + } + } + return NULL; +} + +struct conn * +listener_conn_find_orig(char orig) { + struct listener *l; + struct conn *c; + + LIST_FOREACH(l, &listeners, entry) { + LIST_FOREACH(c, &l->conns, entry) { + if (c->orig == orig) + return c; + } + } + return NULL; + +} + +/* XXX indicate that we are only looking in input pipe */ +struct conn * +listener_conn_find_exec(int fd) { + struct listener *l; + struct conn *c; + + LIST_FOREACH(l, &listeners, entry) { + LIST_FOREACH(c, &l->conns, entry) { + if (c->exec.fd[0] == fd) + return c; + } + } + return NULL; +} + +int +listener_conn_exec(struct conn *c, char *cmd, char **argv) { + int pid; + + log_debug("listener_conn_exec %s", cmd); + + if (c->exec.cmd) { + log_warn("%c is already executing a command", c->orig); + return -1; + } + c->exec.cmd = cmd; + c->exec.argv = argv; + + pid = execpipe(cmd, argv, c->exec.fd); + if (pid < 0) + return -1; + c->exec.pid = pid; + + // XXX if async then writebuf ? + // XXX if err then MSG_ERR + + return 0; +} + +void +listener_conn_exec_kill(struct conn *c) { + int i; + + if (c->exec.cmd) { + free(c->exec.cmd); + c->exec.cmd = NULL; + } + if (c->exec.argv) { + for (i=0; c->exec.argv[i] != NULL; i++) + free(c->exec.argv[i]); + free(c->exec.argv); + c->exec.argv = NULL; + } + kill(c->exec.pid, SIGTERM); + close(c->exec.fd[0]); + close(c->exec.fd[1]); + if (c->exec.async_writebuf) { + free(c->exec.async_writebuf); + c->exec.async_writebuf = NULL; + } +} + + +int +listener_conn_exec_bufferize(struct conn *c, int fd) { + uint8_t buf[BUFMAX]; + + log_warn("XXX conn exec bufferize not implemented"); + read(fd, buf, sizeof(buf)); + return -1; +} + +static int +listener_start(struct listener *l) { + switch (l->type) { + case LISTENER_UNIX: + if (unix_start(l) < 0) + log_warn("listener socket failed to start"); + break; + case LISTENER_INET: + if (inet_start(l) < 0) + log_warn("listener inet failed to start"); + break; + } + return 0; +} + +static int +unix_start(struct listener *l) { + int s, len; + struct sockaddr_un local; + char *path; + + path = xmalloc(sizeof(SOCK_NAME_MAXLEN)); + if (!path) + return -1; + snprintf(path, SOCK_NAME_MAXLEN, "%s", l->sock_unix.path); + + /* XXX monitor death of the socket, to restart it */ + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + log_warn("unix_start: socket %s: %s", path, strerror(errno)); + free(path); + return -1; + } + + memset(&local, 0, sizeof(struct sockaddr_un)); + local.sun_family = AF_UNIX; + strncpy(local.sun_path, path, sizeof(local.sun_path)); + unlink(local.sun_path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(s, (struct sockaddr *)&local, len) == -1) { + log_warn("unix_start: bind %s: %s", path, strerror(errno)); + free(path); + return -1; + } + + if (listen(s, 5) == -1) { + log_warn("unix_start: listen %s: %s", path, strerror(errno)); + free(path); + return -1; + } + + // XXX setnonblock(s); + + l->sock = s; + l->sock_unix.path = path; + + return 0; +} + +static int +inet_start(struct listener *l) { + log_warn("inet_start: XXX not implemented yet"); + return -1; +} diff --git a/broken/propagate/src/log.c b/broken/propagate/src/log.c new file mode 100644 index 0000000..bf494fe --- /dev/null +++ b/broken/propagate/src/log.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +FILE *logfile = NULL; +int loglevel; + +#define LOG_FATAL 0 +#define LOG_WARN 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +static void logit(int, const char *, va_list); + +void +log_init(int level, int logstdout) +{ + char name[128]; + + if (logstdout == 1) { + logfile = stderr; + } else { + snprintf(name, sizeof(name), "pg.log"); + logfile = fopen(name, "a+"); + if (!logfile) { + printf("cannot open log file %s!\n", name); + exit(1); + } + } + loglevel = level; +} + +void +log_tmp(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vfprintf(logfile, msg, ap); + fprintf(logfile, "\n"); + fflush(logfile); + va_end(ap); +} +void +log_debug(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_DEBUG, msg, ap); + va_end(ap); +} +void +log_info(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_INFO, msg, ap); + va_end(ap); +} +void +log_warn(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_WARN, msg, ap); + va_end(ap); +} +void +fatal(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_FATAL, msg, ap); + va_end(ap); + + exit(1); +} + +static void +logit(int level, const char *msg, va_list ap) +{ + time_t clock; + char type; + + if (level <= loglevel) { + switch (level) { + case LOG_FATAL: type='X'; break; + case LOG_WARN: type='W'; break; + case LOG_INFO: type='.'; break; + case LOG_DEBUG: type=' '; break; + } + time(&clock); + fprintf(logfile, "%d %c ", (int)clock, type); + vfprintf(logfile, msg, ap); + fprintf(logfile, "\n"); + fflush(logfile); + } +} + diff --git a/broken/propagate/src/msg.c b/broken/propagate/src/msg.c new file mode 100644 index 0000000..568ff44 --- /dev/null +++ b/broken/propagate/src/msg.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pg.h" + +static int encode(uint8_t *, uint8_t **, int); +static int decode(uint8_t *, uint8_t **, int); + +int +msg_send(int fd, int type, char dest, uint8_t arg, int datalen, uint8_t *data) { + uint8_t *header = NULL, *data_encoded = NULL; + int len, data_encoded_len; + + log_debug("msg_send"); + + len = writebuf((uint8_t *)MSG_MAGIC, fd, sizeof(MSG_MAGIC)); + if (len < 0) + goto err; + header = msg_pack_header(type, conf.me, dest, arg, datalen); + if (!header) + goto err; + len = writebuf(header, fd, MSG_HEADER_SIZE_ENCODED); + if (len < 0) + goto err; + + if (datalen > 0 && data) { + data_encoded_len = encode(data, &data_encoded, datalen); + if (!data_encoded || data_encoded_len <= 0) + goto err; + len = writebuf(data, fd, data_encoded_len); + if (len < 0) + goto err; + free(data_encoded); + } + free(header); + + return len; + +err: + if (header) + free(header); + if (data_encoded) + free(data_encoded); + log_warn("msg_send: err"); + return -1; +} + +int +msg_send_from_fd(int fd, int type, char dest, uint8_t arg, int datafd) { + uint8_t buf[BUFMAX]; + uint8_t *encoded; + int buflen, encodedlen; + + log_debug("msg_send_from_fd"); + + buflen = read(datafd, buf, sizeof(buf)); + if (buflen < 0) + return -1; + encodedlen = encode(buf, &encoded, buflen); + if (encodedlen < 0) + return -1; + msg_send(fd, type, dest, arg, encodedlen, encoded); + free(encoded); + + return 0; +} + +uint8_t * +msg_pack_header(int type, char orig, char dest, uint8_t arg, int datalen) { + struct msg_header h; + uint8_t *data; + int len; + + if (datalen > MSG_DATALEN_MAX) { + log_warn("msg_pack_header: datalen too big %d", datalen); + return NULL; + } + + h.version = MSG_VERSION; + h.type = type; + h.orig = orig; + h.dest = dest; + h.arg = arg; + h.datalen = datalen; + + len = encode((uint8_t *)&h, &data, MSG_HEADER_SIZE); + if (len != MSG_HEADER_SIZE_ENCODED) { + log_warn("msg_pack_header: encoded header has invalid size %d !" + "This should NOT happend, as MSG_HEADER_SIZE_ENCODED should be fixed !", + len); + return NULL; + } + + return data; +} + +#define ERR(msg...) \ +{ \ + log_warn(msg); \ + return NULL; \ +} +struct msg_header * +msg_unpack_header(uint8_t *data) { + uint8_t *data_decoded; + struct msg_header *h; + int len; + /* keep in sync with pg.h MSG enum */ + int msg_client[] = {MSG_DATA, MSG_OK, MSG_ERR}; + int msg_server[] = {MSG_INIT, MSG_INIT_ASYNC, MSG_KILL, MSG_EXEC, MSG_READ, MSG_WRITE, MSG_DATA}; +#define MSG_CLIENT_COUNT 3 +#define MSG_SERVER_COUNT 7 + + len = decode(data, &data_decoded, MSG_HEADER_SIZE_ENCODED); + if (!data_decoded) + ERR("failed to decode message header") + + h = (struct msg_header *)data_decoded; + + if (h->version <= 0 || h->version > 255) + ERR("msg_unpack_header: invalid version %d", h->version) + if (h->version != MSG_VERSION) + ERR("msg_unpack_header: incompatible version %d", h->version) + if (conf.server && (intab(msg_server, h->type, MSG_SERVER_COUNT) < 0)) + ERR("msg_unpack_header: type %d incorrect for server", h->type) + if (!conf.server && (intab(msg_client, h->type, MSG_CLIENT_COUNT) < 0)) + ERR("msg_unpack_header: type %d incorrect for client", h->type) + if (!isalnum(h->orig)) + ERR("msg_unpack_header: non alphanumeric originator %c", h->orig) + if (h->orig == conf.me) + ERR("msg_unpack_header: message pretends to come from me, ignoring") + if (!isalnum(h->dest)) + ERR("msg_unpack_header: non alphanumeric destination %c", h->dest) + // XXX check dest on routes ? + if (h->datalen < 0) + ERR("msg_unpack_header: datalen < 0") + if (h->datalen > MSG_DATALEN_MAX) + ERR("msg_unpack_header: datalen too big %d", h->datalen) + + return h; +} + +int +msg_read_data(int fd, uint8_t **out, int len) { + uint8_t *buf; + int buflen, decodedlen; + + buflen = readbuf(fd, &buf, len); + if (buflen < 0) + return -1; + decodedlen = decode(buf, out, buflen); + if (decodedlen < 0) + log_warn("msg_read_data: decoding failed"); + + return decodedlen; +} + +/* XXX rename to msg_fw_decode ? */ +int +msg_read_data_to_fd(int ifd, int fd, int len) { + uint8_t *buf; + int buflen, writelen; + + buflen = msg_read_data(ifd, &buf, len); + if (buflen < 0) + goto err; + writelen = writebuf(buf, fd, buflen); + if (writelen < 0) + goto err; + free(buf); + + return writelen; + +err: + if (buf) + free(buf); + return -1; +} + +static int +encode(uint8_t *arg, uint8_t **out, int len) { + uint8_t *res; + int outlen; + + outlen = len; + *out = NULL; + res = xmalloc(sizeof(uint8_t) * outlen); + if (!res) + goto err; + memcpy(res, arg, len); + + *out = res; + return outlen; + +err: + log_warn("encode failed"); + return -1; +} + +static int +decode(uint8_t *arg, uint8_t **out, int len) { + uint8_t *res; + int outlen; + + outlen = len; + *out = NULL; + res = xmalloc(sizeof(uint8_t) * outlen); + if (!res) + goto err; + memcpy(res, arg, len); + + *out = res; + return outlen; + +err: + log_warn("decode failed"); + return -1; +} + diff --git a/broken/propagate/src/pg.c b/broken/propagate/src/pg.c new file mode 100644 index 0000000..f3c3c8d --- /dev/null +++ b/broken/propagate/src/pg.c @@ -0,0 +1,448 @@ +/* XXX + * we should inspire from netcat + * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/nc/ + * see readwrite(), atomicio() + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "pg.h" + +extern char *__progname; + +static int usage(); +static void process(void); +static int pfds_create(struct pollfd *); +static int cmd_init(struct conn *, int, struct msg_header *); +static int cmd_exec(struct conn *, int, struct msg_header *); +static int cmd_kill(struct conn *, int, struct msg_header *); +static int cmd_read(struct conn *, int, struct msg_header *); +static int cmd_write(struct conn *, int, struct msg_header *); +static int cmd_data_conn(struct conn *, int, struct msg_header *); +static int cmd_data_route(struct route *, int, struct msg_header *); +static int cmd_ok(struct route *, int, struct msg_header *); +static int cmd_err(struct route *, int, struct msg_header *); + +int +main(int argc, char *argv[]) { + int opt; + int loglevel = 1, logstdout = 0; + int deamonize = 0; + int server = 0; + char dest = 0; + char *cmd = NULL; + + while ((opt = getopt(argc, argv, "dhltv")) != -1) { + switch (opt) { + case 'd': + logstdout = 1; + deamonize = 0; + break; + case 'h': + usage(); + break; + case 'l': + server = 1; + break; + case 't': + dest = optarg[0]; + break; + case 'v': + loglevel++; + break; + default: + usage(); + break; + } + } + + argc -= optind; + argv += optind; + + if ((server && argc != 0) || + (!server && argc != 1) || + (server && conf.client_dest)) + usage(); + if (!server) { + cmd = argv[0]; + if (dest == 0) + dest = 'B'; + conf.client_dest = dest; + } + + log_init(loglevel, logstdout); + log_warn("** Starting propagate v%.1f", VERSION); + log_warn("** using message version %d", MSG_VERSION); + log_warn("** loglevel %d", loglevel); + + conf.server = server; + LIST_INIT(&routes); + routes_count = 0; + LIST_INIT(&listeners); + listeners_count = 0; + + /* XXX load conf */ + if (server) { + conf.me = 'B'; + listener_add(LISTENER_UNIX, "/tmp/propagate_sock"); + } else { + conf.me = 'A'; + route_add('B', ROUTE_PROC, "nc 127.0.0.1 3333", 0, NULL, 0); + } + + if (server) + log_info("starting server %c", conf.me); + else + log_info("running client %c, dest %c, command %s", conf.me, conf.client_dest, cmd); + + if (deamonize) + log_info("XXX deamonize not implemented yet"); + + if (!server) + send_cmd(conf.client_dest, MSG_EXEC, 0, (uint8_t *)cmd, strlen(cmd)); + + process(); + + return 0; +} + +static int +usage() { + printf("Usage: %s [-dhv] [-t destination] command\n", __progname); + printf(" %s -l [-dhv]\n", __progname); + + exit(1); +} + +static void +process(void) { + struct listener *l; + struct conn *c; + struct route *r; + uint8_t *buf; + struct msg_header *hdr; + struct sockaddr_storage cliaddr; + socklen_t slen = sizeof(cliaddr); + int len, n, fd, cfd; + struct pollfd pfds[POLLER_MAX]; + int pfds_count; + /* keep in sync with pg.h MSG enum */ + int (*cmd_conn[MSG_MAX+1]) + (struct conn *, int, struct msg_header *) = { + &cmd_init, + &cmd_init, + &cmd_kill, + &cmd_exec, + &cmd_read, + &cmd_write, + &cmd_data_conn, + NULL, + NULL + }; + int (*cmd_route[MSG_MAX+1]) + (struct route *, int, struct msg_header *) = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &cmd_data_route, + &cmd_ok, + &cmd_err + }; + + + /* OLD TODO + * fork frontend and open pipe_fe + * poll() + * - pipe_fe input -> write stdout + * - stdin -> append send_buf + * sigalarm() every second + * - MSG_READ and write on stdout + * - if size(send_buf) > 0: MSG_WRITE send_buf + * handle network errors / retransmission in fe + * MSG_[READ|WRITE] do not expect MSG_OK, but warns on MSG_ERROR + * MSG_OK only for MSG_INIT and MSG_EXEC + */ + + for (;;) { + pfds_count = pfds_create(pfds); + n = poll(pfds, pfds_count, POLL_TIMEOUT); + log_tmp("end of poll, %d fds on %d", n, pfds_count); + if (n < 0) { + log_warn("polling error"); // XXX fatal ? + continue; + } + + for (n=0; nasync) + listener_conn_exec_bufferize(c, fd); + else + msg_send_from_fd(c->fd, MSG_DATA, c->orig, 0, fd); + } else if (fd == fileno(stdin)) { + log_debug("got stdin data"); + r = route_find(conf.client_dest); + if (r->proc.async) + route_bufferize(r, fd); + else + msg_send_from_fd(r->proc.fd[1], MSG_DATA, r->dest, 0, fd); + } else { + log_debug("got command"); + len = readbuf(fd, &buf, sizeof(MSG_MAGIC)); + if (len < sizeof(MSG_MAGIC)) { + log_info("Magic number too short"); + continue; + } + if (memcmp(buf, MSG_MAGIC, sizeof(MSG_MAGIC))) { + log_info("Invalid magic number %4x", buf); + continue; + } + len = readbuf(fd, &buf, MSG_HEADER_SIZE_ENCODED); + if (len < MSG_HEADER_SIZE_ENCODED) { + log_warn("Message header too short"); + continue; + } + hdr = msg_unpack_header(buf); + if (!hdr) { + log_warn("Invalid message header"); + continue; + } + + if (hdr->dest != conf.me) { + route_fw(fd, hdr, buf); + free(hdr); + continue; + } + + if ((c = listener_conn_find(fd))) { + cmd_conn[hdr->type](c, fd, hdr); + break; + } else if ((r = route_find(hdr->orig))) { + cmd_route[hdr->type](r, fd, hdr); + break; + } else + log_warn("host %c has no reference ! ignoring command...", + hdr->orig); + free(hdr); + } + } + } +} + +static int +pfds_create(struct pollfd *pfds) { + struct route *r; + struct listener *l; + struct conn *c; + int count = 0; + +#define ADDFD(myfd) { \ +pfds[count].fd = myfd; \ +pfds[count].events = POLLIN; \ +count++; \ +} + + if (!conf.server) + ADDFD(fileno(stdin)) + + LIST_FOREACH(r, &routes, entry) { + switch (r->type) { + case ROUTE_PROC: + ADDFD(r->proc.fd[0]) + } + } + + LIST_FOREACH(l, &listeners, entry) { + ADDFD(l->sock) + LIST_FOREACH(c, &l->conns, entry) { + ADDFD(c->fd) + if (c->exec.cmd) + ADDFD(c->exec.fd[0]) + } + } + + return count; +} + +static int +cmd_init(struct conn *c, int fd, struct msg_header *hdr) { + struct conn *oldc; + + log_debug("received INIT from %c :)", hdr->orig); + if (c->state == CONN_READY) { + log_warn("received INIT on an already open connection !"); + send_cmd(hdr->orig, MSG_ERR, 0, NULL, 0); + return -1; + } + + /* checking if this client already has a connection opened on + * another fd */ + oldc = listener_conn_find_orig(hdr->orig); + if (oldc) + listener_conn_move(oldc, c); + + c->orig = hdr->orig; + c->state = CONN_READY; + + switch (hdr->type) { + case MSG_INIT: + c->async = 0; + break; + case MSG_INIT_ASYNC: + c->async = 1; + break; + } + + send_cmd(hdr->orig, MSG_OK, 0, NULL, 0); + + return 0; +} + +static int +cmd_exec(struct conn *c, int fd, struct msg_header *hdr) { + char *cmd = NULL; + int cmdlen; + char **argv = NULL; + int argc; + + cmdlen = readbuf(fd, (uint8_t **)&cmd, hdr->datalen); + if (cmdlen <= 0 || !cmd) + goto err; + argv = explode(cmd, cmdlen, " ", &argc); + if (!argv) + goto err; + if (listener_conn_exec(c, argv[0], argv) < 0) + goto err; + + send_cmd(hdr->orig, MSG_OK, 0, NULL, 0); + + return 0; + +err: + log_debug("exec failed"); + if (cmd) + free(cmd); + if (argv) + free(argv); + send_cmd(hdr->orig, MSG_ERR, 0, NULL, 0); + + return -1; +} + +static int +cmd_kill(struct conn *c, int fd, struct msg_header *hdr) { + listener_conn_exec_kill(c); + send_cmd(hdr->orig, MSG_OK, 0, NULL, 0); + + return 0; +} + +static int +cmd_read(struct conn *c, int fd, struct msg_header *hdr) { + int len; + + if (!c->exec.cmd) { + log_warn("cmd_read: no exec in progress !"); + goto err; + } + if (c->async == 0) { + log_warn("cmd_read: not in async mode !"); + goto err; + } + + len = send_cmd(c->orig, MSG_DATA, 0, + c->exec.async_writebuf, c->exec.async_writebuf_size); + if (len < 0) + goto err; + c->exec.async_writebuf_size -= len; + c->exec.async_writebuf = realloc(c->exec.async_writebuf, + c->exec.async_writebuf_size); + return 0; + +err: + send_cmd(c->orig, MSG_ERR, 0, NULL, 0); + return -1; +} + +static int +cmd_write(struct conn *c, int fd, struct msg_header *hdr) { + if (!c->exec.cmd) { + log_warn("cmd_write: no exec in progress !"); + goto err; + } + if (c->async == 0) { + log_warn("cmd_write: not in async mode !"); + goto err; + } + + if (msg_read_data_to_fd(fd, c->exec.fd[1], hdr->datalen) < 0) { + goto err; + } + + return 0; + +err: + send_cmd(c->orig, MSG_ERR, 0, NULL, 0); + return -1; +} + +static int +cmd_data_conn(struct conn *c, int fd, struct msg_header *hdr) { + log_debug("received DATA from conn %c !", hdr->orig); + + if (msg_read_data_to_fd(fd, c->exec.fd[1], hdr->datalen) < 0) { + log_warn("cmd_data: recvwrite failed"); + return -1; + } + + return 0; +} + +static int +cmd_data_route(struct route *r, int fd, struct msg_header *hdr) { + log_debug("received DATA from route %c !", hdr->orig); + + if (msg_read_data_to_fd(fd, fileno(stdout), hdr->datalen) < 0) { + log_warn("cmd_data: recvwrite failed"); + return -1; + } + + return 0; +} + +static int +cmd_ok(struct route *r, int fd, struct msg_header *hdr) { + log_info("received OK from %c !", hdr->orig); + + return 0; +} + +static int +cmd_err(struct route *r, int fd, struct msg_header *hdr) { + log_info("received ERROR from %c !", hdr->orig); + + return 0; +} + diff --git a/broken/propagate/src/pg.h b/broken/propagate/src/pg.h new file mode 100644 index 0000000..b671883 --- /dev/null +++ b/broken/propagate/src/pg.h @@ -0,0 +1,174 @@ +#include +#include +#include +#include "queue.h" + +#define VERSION 0.1 + +#define BUFMAX 1024 * 10 +#define READSIZE 1024 +#define WRITESIZE 1024 + +#define POLL_TIMEOUT 1000 +#define POLL_TIMEOUT_ATOMIC 500 +#define POLL_ATOMIC_RETRY 3 + +#define ROUTES_MAX 256 +#define LISTENERS_MAX 16 +#define LISTENER_CONN_MAX 10 +#define POLLER_MAX (ROUTES_MAX + (LISTENERS_MAX + LISTENERS_MAX * LISTENER_CONN_MAX)) +#define EXEC_MAX 10 + +#define MSG_MAGIC "bXl4" +struct msg_header { + uint8_t version; + uint8_t type; + uint8_t orig; + uint8_t dest; + uint8_t arg; /* UNUSED */ + uint16_t datalen; +}; +#define MSG_HEADER_SIZE 7 +// XXX change 8 to 13 when we'll use base64 +#define MSG_HEADER_SIZE_ENCODED 7 +#define MSG_VERSION 1 +#define MSG_DATALEN_MAX 1024 * 100 + +/* keep in sync with pg.c process() cmd */ +/* keep in sync with msg.c msg_unpack_header msg_client and msg_server */ +/* XXX fix that mess, all in one file */ +enum msg_type { + MSG_INIT = 0, + MSG_INIT_ASYNC = 1, + MSG_KILL = 2, + MSG_EXEC = 3, + MSG_READ = 4, + MSG_WRITE = 5, + MSG_DATA = 6, + MSG_OK = 7, + MSG_ERR = 8 +}; +#define MSG_MAX 8 + +struct route { + char dest; + int type; +#define ROUTE_PROC 0 +#define ROUTE_GW 1 + union { + struct { + char *cmd; + char **argv; + int pid; + int fd[2]; + int async; + uint8_t *async_sndbuf; + int async_sndbuf_size; + } proc; + struct { + char dest; + } gw; + }; + LIST_ENTRY(route) entry; +}; + +struct listener { + int sock; + int type; +#define LISTENER_UNIX 0 +#define LISTENER_INET 1 + union { + struct { + char *path; + } sock_unix; + struct { + // XXX TODO + //struct addrinfo *res; + } sock_inet; + }; + LIST_HEAD(, conn) conns; + int conns_count; + LIST_ENTRY(listener) entry; +}; + +enum conn_state { + CONN_OPEN = 0, + CONN_READY = 1 +}; + +struct conn { + struct listener *listener; + int orig; + int fd; + enum conn_state state; + int async; + struct { + char *cmd; + char **argv; + int pid; + int fd[2]; + uint8_t *async_writebuf; + int async_writebuf_size; + } exec; + LIST_ENTRY(conn) entry; +}; + +struct conf { + char me; + int server; + char client_dest; +}; + +struct conf conf; +LIST_HEAD(, route) routes; +int routes_count; +LIST_HEAD(, listener) listeners; +int listeners_count; + +/* msg.c */ +int msg_send(int, int, char, uint8_t, int, uint8_t *); +int msg_send_from_fd(int, int, char, uint8_t, int); +uint8_t *msg_pack_header(int, char, char, uint8_t, int); +struct msg_header *msg_unpack_header(uint8_t *); +int msg_read_data(int, uint8_t **, int); +int msg_read_data_to_fd(int, int, int); + +/* route.c */ +int route_add(char, int, char *, int, char *, char); +int route_fw(int, struct msg_header *, uint8_t *); +struct route *route_find(char); +int route_bufferize(struct route *, int); + +/* listener.c */ +int listener_add(int, char *); +struct listener *listener_find(int); +struct listener *listener_find_orig(char); +int listener_conn_add(struct listener *, int); +void listener_conn_del(struct conn *); +void listener_conn_move(struct conn *, struct conn *); +struct conn *listener_conn_find(int); +struct conn *listener_conn_find_orig(char); +struct conn *listener_conn_find_exec(int); +int listener_conn_exec(struct conn *, char *, char **); +void listener_conn_exec_kill(struct conn *); +int listener_conn_exec_bufferize(struct conn *, int); + +/* log.c */ +void log_init(int, int); +void log_tmp(const char *, ...); +void log_debug(const char *, ...); +void log_info(const char *, ...); +void log_warn(const char *, ...); +void fatal(const char *, ...); + +/* util.c */ +int send_cmd(char, int, uint8_t, uint8_t *, int); +int intab(int *, int, int); +char **explode (char *, int, char *, int *); +void *xmalloc(size_t); +void *xcalloc(size_t, size_t); +int setnonblock(int); +int execpipe(char *, char **, int *); +int readbuf(int, uint8_t **, int); +int writebuf(uint8_t *, int, int); +int readwrite(int, int, int); diff --git a/broken/propagate/src/queue.h b/broken/propagate/src/queue.h new file mode 100644 index 0000000..fb23a72 --- /dev/null +++ b/broken/propagate/src/queue.h @@ -0,0 +1,568 @@ +/* $OpenBSD: queue.h,v 1.35 2012/01/11 00:06:48 bluhm Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_NEXT(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/broken/propagate/src/route.c b/broken/propagate/src/route.c new file mode 100644 index 0000000..99f52ec --- /dev/null +++ b/broken/propagate/src/route.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "pg.h" + +static int route_start(struct route *r); +static int frontend_start(struct route *); + +int +route_add(char dest, int type, char *cmd, int async, char *path, char gw) { + struct route *r; + char **argv; + int argc; + + if (routes_count >= ROUTES_MAX) { + log_warn("routes max reached"); + return -1; + } + + r = xcalloc(1, sizeof(struct route)); + if (!r) + return -1; + + r->dest = dest; + r->type = type; + switch (type) { + case ROUTE_PROC: + argv = explode(cmd, strlen(cmd), " ", &argc); + log_tmp("route_add: explode argv 0 %s 1 %s 2 %s 3 %s argc %d", + argv[0], argv[1], argv[2], argv[3], argc); + if (!argv) + return -1; + r->proc.cmd = argv[0]; + r->proc.argv = argv; + r->proc.async = async; + break; + case ROUTE_GW: + r->gw.dest = gw; + } + + LIST_INSERT_HEAD(&routes, r, entry); + + route_start(r); + + return 0; +} + +int +route_fw(int fd, struct msg_header *hdr, uint8_t *hbuf) { + struct route *r; + int len; + + log_debug("route %c to %c", hdr->orig, hdr->dest); + + r = route_find(hdr->dest); + if (r) { + log_debug("route_fw: no route to %c", hdr->dest); + goto err; + } + + // XXX HERE async bufferize + + len = writebuf(hbuf, r->proc.fd[1], MSG_HEADER_SIZE_ENCODED); + if (len < 0) + goto err; + len = readwrite(fd, r->proc.fd[1], hdr->datalen); + if (len < 0) + goto err; + + return 0; + +err: + log_warn("route_fw: err"); + return -1; +} + +int +route_bufferize(struct route *r, int fd) { + uint8_t buf[BUFMAX]; + + log_warn("XXX route bufferize not implemented"); + read(fd, buf, sizeof(buf)); + return -1; +} + +struct route * +route_find(char dest) { + struct route *r; + + LIST_FOREACH(r, &routes, entry) { + if (r->dest == dest) { + if (r->type == ROUTE_GW) { + dest = r->gw.dest; + continue; + } + return r; + } + } + + return NULL; +} + +static int +route_start(struct route *r) { + switch (r->type) { + case ROUTE_PROC: + if (frontend_start(r) < 0) + log_warn("frontend for dest %c failed to start", r->dest); + break; + } + + send_cmd(r->dest, MSG_INIT, 0, NULL, 0); + + return 0; +} + +static int +frontend_start(struct route *r) { + int pid; + + /* XXX monitor death of fe / broken pipe, to restart it */ + pid = execpipe(r->proc.cmd, r->proc.argv, r->proc.fd); + if (pid > 0) + r->proc.pid = pid; + log_debug("frontend_start: forked pid %d, fd %d %d", pid, r->proc.fd[0], r->proc.fd[1]); + setnonblock(r->proc.fd[0]); + + return pid; +} + diff --git a/broken/propagate/src/tests/Makefile b/broken/propagate/src/tests/Makefile new file mode 100644 index 0000000..6f81535 --- /dev/null +++ b/broken/propagate/src/tests/Makefile @@ -0,0 +1,23 @@ +TEST_EXPLODE = test_explode +TEST_B64 = test_base64 +CFLAGS = -g -Wall -std=c99 +LDFLAGS = + +all: $(TEST_EXPLODE) $(TEST_B64) + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) $(LDFLAGS) -I../ + +$(TEST_EXPLODE): test_explode.o ../libihf.o + $(CC) test_explode.o ../libihf.o -o $(TEST_EXPLODE) $(LDFLAGS) $(CFLAGS) -I../ + +$(TEST_B64): test_base64.o ../base64.o + $(CC) test_base64.o ../base64.o -o $(TEST_B64) $(LDFLAGS) $(CFLAGS) -I../ + +.PHONY: clean mrproper + +mrproper: clean + +clean: + rm -f $(TEST_EXPLODE) $(TEST_B64) *~ *.o + diff --git a/broken/propagate/src/tests/test_base64.c b/broken/propagate/src/tests/test_base64.c new file mode 100644 index 0000000..e32ff65 --- /dev/null +++ b/broken/propagate/src/tests/test_base64.c @@ -0,0 +1,88 @@ +/* + ihf - Tool for bypassing firewalls + Copyright (C) 2012 m_101, laurent + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +#include +#include +#include +#include + +#include "base64.h" + +#define TEST_STR "ag0 arg1 arg2 arg3 arg4\n" + +void print_array_uint8_t (uint8_t *array, int n_elements) { + int idx_array; + + if (!array || n_elements <= 0) + return; + + for (idx_array = 0; idx_array < n_elements; idx_array++) + printf("%02x ", array[idx_array]); + putchar('\n'); +} + +int main(int argc, char *argv[]) { + int idx_buf, sz_buf; + char *buf; + // b64 + struct base64_decode_context dctx; + char *b64_encoded, *b64_decoded; + size_t len_decoded; + + sz_buf = 256 + strlen(TEST_STR) + 1; + + buf = calloc(sz_buf, sizeof(*buf)); + if (!buf) { + fprintf(stderr, "error: Could not alloc buffer\n"); + return -1; + } + + for (idx_buf = 0; idx_buf < 256; idx_buf++) + buf[idx_buf] = idx_buf; + memcpy(buf + 256, TEST_STR, strlen(TEST_STR)); + + printf("printing array...\n"); + print_array_uint8_t (buf, sz_buf - 1); + + printf("\nEncoding buffer ...\n"); + base64_encode_alloc(buf, sz_buf - 1, &b64_encoded); + if (!b64_encoded) { + fprintf(stderr, "error: Could not encode buffer\n"); + return -1; + } + + printf("encoded: %s\n\n", b64_encoded); + + printf("Decoding buffer ...\n"); + base64_decode_ctx_init (&dctx); + base64_decode_alloc_ctx(&dctx, + b64_encoded, strlen(b64_encoded), + &b64_decoded, &len_decoded); + printf("len_decoded: %lu\n\n", len_decoded); + + printf("printing array...\n"); + print_array_uint8_t (b64_decoded, len_decoded); + + printf("comparing arrays...\n"); + if (memcmp(buf, b64_decoded, len_decoded)) + printf("Decoding failed\n"); + else + printf("Decoding succeeded\n"); + + return 0; +} + diff --git a/broken/propagate/src/tests/test_explode.c b/broken/propagate/src/tests/test_explode.c new file mode 100644 index 0000000..0210397 --- /dev/null +++ b/broken/propagate/src/tests/test_explode.c @@ -0,0 +1,39 @@ +/* + ihf - Tool for bypassing firewalls + Copyright (C) 2012 m_101, laurent + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +#include +#include +#include + +#include "libihf.h" + +#define TEST_STR "arg0 arg1 arg2 arg3 arg4\n" + +int main(int argc, char *argv[]) { + char *toxplod = strdup(TEST_STR); + int n_exploded; + char **exploded = explode(toxplod, strlen(toxplod) + 1, " ", &n_exploded); + int idx_exploded; + + printf("\nn_exploded: %d\n", n_exploded); + for (idx_exploded = 0; idx_exploded < n_exploded; idx_exploded++) { + printf("exploded %d: %s\n", idx_exploded, exploded[idx_exploded]); + } + + return 0; +} + diff --git a/broken/propagate/src/util.c b/broken/propagate/src/util.c new file mode 100644 index 0000000..646492a --- /dev/null +++ b/broken/propagate/src/util.c @@ -0,0 +1,233 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "pg.h" +#include "atomicio.h" + +int +send_cmd(char dest, int type, uint8_t arg, uint8_t *data, int data_len) { + struct conn *c; + struct route *r; + int fd = -1, len; + + r = route_find(dest); + if (r) + fd = r->proc.fd[1]; + else { + c = listener_conn_find_orig(dest); + if (c) + fd = c->fd; + else { + log_warn("send_cmd %d: no route to go to dest %c", type, dest); + return -1; + } + } + len = msg_send(fd, type, dest, arg, data_len, data); + + return len; +} + +int +intab(int *tab, int val, int len) { + int n; + + for (n=0; n sizeof(buf)) { + log_warn("readbuf: len too big %d", len); + return -1; + } + if ((outlen = atomicio(read, fd, buf, len)) < 0) { + log_warn("readbuf: atomicio read error"); + return -1; + } + if (outlen != len) + log_warn("readbuf: invalid atomicio read size %d, should be %d", + outlen, len); + + *out = buf; + return outlen; +} + +int +writebuf(uint8_t *buf, int fd, int len) { + int writelen; + + if ((writelen = atomicio(vwrite, fd, buf, len)) < 0) { + log_warn("writebuf: atomicio write error"); + return -1; + } + if (writelen < len) + log_warn("writebuf: incomplete write, %d on %d", + writelen, len); + + return writelen; +} + +int +readwrite(int ifd, int ofd, int len) { + char buf[BUFMAX]; + int red, wrote; + + red = atomicio(read, ifd, buf, len); + if (red < 0) { + log_warn("readwrite: atomicio read error"); + return -1; + } + if (red != len) + log_warn("readbuf: invalid atomicio read size %d, should be %d", + red, len); + + if ((wrote = atomicio(vwrite, ofd, buf, red)) < red) { + log_warn("readwrite: atomicio write error"); + return -1; + } + + return wrote; +} -- cgit v1.2.3-59-g8ed1b