X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/e12ebbe8100dfbfea12b2797e89c0e362eff0aa3..8d513103f66617e96234d19813ab655ed9d5d13d:/uslip/uslip.c
diff --git a/uslip/uslip.c b/uslip/uslip.c
index dee9f94d..629da123 100644
--- a/uslip/uslip.c
+++ b/uslip/uslip.c
@@ -9,19 +9,18 @@
*
* This file is part of Trivial IP Encryption (TrIPE).
*
- * TrIPE 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 2 of the License, or
- * (at your option) any later version.
+ * TrIPE 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 of the License, or (at your
+ * option) any later version.
*
- * TrIPE 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.
+ * TrIPE 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 TrIPE; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with TrIPE. If not, see .
*/
/*----- Header files ------------------------------------------------------*/
@@ -47,13 +46,17 @@
#include
#include
+#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
+#include
#include "slip.h"
@@ -132,16 +135,15 @@ static void socketaddr(struct sockaddr_un *sun, size_t *sz)
static void initqueue(pkq *q) { q->head = 0; q->tail = &q->head; }
-static pkq_node *make_pkqnode(void *p, size_t n)
+static pkq_node *make_pkqnode(const void *p, size_t n)
{
pkq_node *pn;
- if (!n)
- return (0);
+ if (!n) return (0);
pn = CREATE(pkq_node);
pn->next = 0;
pn->buf = xmalloc(n);
- memcpy(pn->buf, p, n);
+ if (p) memcpy(pn->buf, p, n);
pn->sz = n;
pn->n = 0;
return (pn);
@@ -151,8 +153,7 @@ static int enqueue(pkq *q, pkq_node *pn)
{
int rc = 0;
- if (!pn)
- return (0);
+ if (!pn) return (0);
rc = !q->head;
pn->next = 0;
*q->tail = pn;
@@ -194,10 +195,10 @@ static void destroy_pkq(pkq *q)
* calls a user-supplied calback function, and quits.
*/
-static void gobbler_close(gobbler *g)
+static void close_gobbler(gobbler *g)
{ if (g->f.fd != -1) { sel_rmfile(&g->f); close(g->f.fd); g->f.fd = -1; } }
-static void gobbler_destroy(gobbler *g) { gobbler_close(g); DESTROY(g); }
+static void destroy_gobbler(gobbler *g) { close_gobbler(g); DESTROY(g); }
static void do_gobble_in(int fd, unsigned mode, void *p)
{
@@ -212,12 +213,12 @@ static void do_gobble_in(int fd, unsigned mode, void *p)
else {
moan("read (gobble): %s", strerror(errno));
if (g->done) g->done(g, errno, g->p);
- gobbler_close(g);
+ close_gobbler(g);
break;
}
} else if (n == 0) {
if (g->done) g->done(g, 0, g->p);
- gobbler_close(g);
+ close_gobbler(g);
break;
}
}
@@ -319,7 +320,7 @@ static void done_client_dribble(dribbler *d, int err, void *p)
{
if (err)
moan("write (client): %s", strerror(err));
- gobbler_destroy(p);
+ destroy_gobbler(p);
destroy_dribbler(d);
reasons--;
}
@@ -344,7 +345,7 @@ static void dequeue_to_waiter(void)
}
}
-static void client_destroy(client *c)
+static void destroy_client(client *c)
{
sel_rmfile(&c->f);
close(c->f.fd);
@@ -373,7 +374,7 @@ static void do_client_in(int fd, unsigned mode, void *p)
break;
else {
moan("read (client): %s", strerror(errno));
- client_destroy(c);
+ destroy_client(c);
return;
}
} else if (n == 0) {
@@ -382,7 +383,7 @@ static void do_client_in(int fd, unsigned mode, void *p)
if (enqueue_dribble(dribble_out, make_pkqnode(c->d.buf, c->d.len)))
reasons++;
}
- client_destroy(c);
+ destroy_client(c);
return;
}
if (c->mode == '?') {
@@ -404,7 +405,7 @@ static void do_client_in(int fd, unsigned mode, void *p)
return;
default:
moan("bad client mode `%c'", buf[0]);
- client_destroy(c);
+ destroy_client(c);
return;
}
}
@@ -450,7 +451,7 @@ static void do_accept(int fd, unsigned mode, void *hunoz)
/*----- Main daemon -------------------------------------------------------*/
-static void done_slip_dribble(dribbler *d, int err, void *p)
+static void done_slip_dribble(dribbler *d, int err, void *hunoz)
{
if (!err)
reasons--;
@@ -460,6 +461,16 @@ static void done_slip_dribble(dribbler *d, int err, void *p)
cripple_dribbler(d);
}
+static void close_slip(int fd)
+{
+ switch (slipstate) {
+ case SYNC1: case SYNC2: case START: case BAD: break;
+ default: moan("eof found while processing packet (discarding)"); break;
+ }
+ close(fd); sel_rmfile(&slip_in);
+ reasons--;
+}
+
static void do_slip_in(int fd, unsigned mode, void *hunoz)
{
ssize_t i, n;
@@ -476,19 +487,7 @@ static void do_slip_in(int fd, unsigned mode, void *hunoz)
for (;;) {
n = read(fd, buf, sizeof(buf));
if (n == 0) {
- switch (slipstate) {
- case SYNC1:
- case SYNC2:
- case START:
- case BAD:
- break;
- default:
- moan("eof found while processing packet (discarding)");
- break;
- }
- close(fd);
- sel_rmfile(&slip_in);
- reasons--;
+ close_slip(fd);
return;
} else if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
@@ -571,11 +570,15 @@ static void do_slip_in(int fd, unsigned mode, void *hunoz)
}
}
+static void slip_term(int n, void *fdp)
+ { close_slip(*(int *)fdp); }
+
static void slipif(void)
{
int fd;
dstr d = DSTR_INIT;
struct sockaddr_un sun;
+ sig term;
size_t sz;
/* --- Make the socket --- */
@@ -600,6 +603,11 @@ static void slipif(void)
dribble_out = make_dribbler(STDOUT_FILENO, done_slip_dribble, 0);
sel_addfile(&slip_in);
+ sig_init(&sel);
+ sig_add(&term, SIGTERM, slip_term, &fd);
+ sig_add(&term, SIGHUP, slip_term, &fd);
+ sig_add(&term, SIGINT, slip_term, &fd);
+
initqueue(&q_in);
reasons++;
@@ -613,7 +621,7 @@ static void slipif(void)
/* --- Main loop --- */
while (reasons) {
- if (sel_select(&sel))
+ if (sel_select(&sel) && errno != EINTR)
die(EXIT_FAILURE, "select: %s", strerror(errno));
}
@@ -679,9 +687,163 @@ static void shovel(int from, int to)
static void put(void) { shovel(STDIN_FILENO, make_sock('>')); }
static void get(void) { shovel(make_sock('<'), STDOUT_FILENO); }
+/*----- Flooding and sinking ----------------------------------------------*/
+
+/* --- Connection jobs --- */
+
+typedef struct conninfo {
+ struct conninfo *next;
+ conn c;
+} conninfo;
+
+#define MAXCONN 32
+static conninfo conns[MAXCONN], *freeconns;
+
+static void (*connhook)(int, conninfo *);
+
+static void connrecycle(conninfo *c) { c->next = freeconns; freeconns = c; }
+
+static void connerr(conninfo *c)
+{
+ if (errno == EAGAIN) connrecycle(c);
+ else die(EXIT_FAILURE, "connect: %s", strerror(errno));
+}
+
+static void connected(int fd, void *p)
+ { if (fd == -1) connerr(p); else connhook(fd, p); }
+
+static void conndoconnect(conninfo *c)
+{
+ int fd;
+ struct sockaddr_un sun;
+ size_t sz;
+
+ if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ die(EXIT_FAILURE, "socket: %s", strerror(errno));
+ socketaddr(&sun, &sz);
+ if (conn_init(&c->c, &sel, fd, (struct sockaddr *)&sun, sz, connected, c))
+ connerr(c);
+}
+
+static int timerflag;
+
+static void conndrip(struct timeval *tv, void *hunoz)
+{
+ conninfo *c, *cc;
+
+ timerflag = 0;
+ while (freeconns) {
+ c = freeconns; freeconns = 0;
+ while (c) { cc = c->next; conndoconnect(c); c = cc; }
+ }
+}
+
+static void connloop(void (*connected)(int, conninfo *))
+{
+ int i;
+ conninfo **cc;
+ sel_timer t;
+ struct timeval tv;
+
+ connhook = connected;
+ for (i = 0, cc = &freeconns; i < MAXCONN; i++) {
+ *cc = &conns[i];
+ cc = &conns[i].next;
+ }
+ *cc = 0;
+
+ for (;;) {
+ if (freeconns && !timerflag) {
+ gettimeofday(&tv, 0);
+ TV_ADDL(&tv, &tv, 0, 10000);
+ sel_addtimer(&sel, &t, &tv, conndrip, 0);
+ timerflag = 1;
+ }
+ if (sel_select(&sel))
+ die(EXIT_FAILURE, "select: %s", strerror(errno));
+ }
+}
+
+/* --- Sinking (glug glug) --- */
+
+static void close_sink(gobbler *g, int err, void *p)
+{
+ static char baton[4] = "/-\\|";
+ static int pos = 0;
+ static int count = 0;
+ static int state = '?';
+
+ conninfo *c = p;
+
+ if (!err) {
+ if (state == '?')
+ state = isatty(STDOUT_FILENO) ? 'y' : 'n';
+ if (state == 'y') {
+ if (count) count--;
+ else {
+ putchar(baton[pos]);
+ putchar('\b');
+ fflush(stdout);
+ pos++;
+ if (pos >= sizeof(baton)) pos = 0;
+ count = 128;
+ }
+ }
+ }
+ connrecycle(c);
+}
+
+static void sink_connected(int fd, conninfo *c)
+{
+ char dir = '<';
+
+ if (write(fd, &dir, 1) != 1) {
+ moan("write: %s (continuing)", strerror(errno));
+ close(fd);
+ connrecycle(c);
+ return;
+ }
+ make_gobbler(fd, close_sink, c);
+}
+
+static void sink(void) { connloop(sink_connected); }
+
+/* --- Flooding --- */
+
+static void close_flood(dribbler *d, int err, void *p)
+{
+ conninfo *c = p;
+
+ if (err) moan("write: %s (continuing)\n", strerror(errno));
+ destroy_dribbler(d);
+ connrecycle(c);
+}
+
+static void flood_connected(int fd, conninfo *c)
+{
+ static uint32 seq;
+
+ dribbler *d;
+ pkq_node *pn;
+ int i;
+
+#define FLOOD_PKSZ 1024
+
+ pn = make_pkqnode(0, 1 + FLOOD_PKSZ);
+ pn->buf[0] = '>';
+ STORE32(pn->buf + 1, seq);
+ for (i = 4; i < FLOOD_PKSZ; i++)
+ pn->buf[i + 1] = i & 0xff;
+ seq++;
+ d = make_dribbler(fd, close_flood, c);
+ enqueue_dribble(d, pn);
+}
+
+static void flood(void) { connloop(flood_connected); }
+
/*----- Main code ---------------------------------------------------------*/
-static void usage(FILE *fp) { pquis(fp, "Usage: $ [-pg] SOCKET\n"); }
+static void usage(FILE *fp) { pquis(fp, "Usage: $ [-fgps] SOCKET\n"); }
static void version(void)
{ pquis(stdout, "$ (" PACKAGE " version " VERSION")\n"); }
@@ -695,8 +857,10 @@ static void help(void)
With no options, provides a SLIP interface for TrIPE.\n\
\n\
Options:\n\
+ -f, --flood Send packets to TrIPE as fast as possible.\n\
+ -g, --get Receive packet from TrIPE and write to stdout.\n\
-p, --put Send packet on stdin to TrIPE.\n\
- -g, --get Receive packet from TrIPE and write to stdout.");
+ -s, --sink Slurp packets out of TrIPE and display progress.");
}
int main(int argc, char *argv[])
@@ -711,15 +875,17 @@ int main(int argc, char *argv[])
{ "version", 0, 0, 'v' },
{ "put", 0, 0, 'p' },
{ "get", 0, 0, 'g' },
+ { "flood", 0, 0, 'f' },
+ { "sink", 0, 0, 's' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "hvpg", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "hvpgfs", opt, 0, 0, 0);
if (i < 0)
break;
switch (i) {
case 'h': help(); return (0);
case 'v': version(); return (0);
- case 'p': case 'g': mode = i; break;
+ case 'p': case 'g': case 's': case 'f': mode = i; break;
default: usage(stderr); exit(EXIT_FAILURE); break;
}
}
@@ -730,6 +896,8 @@ int main(int argc, char *argv[])
case 'd': slipif(); break;
case 'p': put(); break;
case 'g': get(); break;
+ case 'f': flood(); break;
+ case 's': sink(); break;
}
return (0);
}