From b4c639d9ae2b130f9641a970821fea11b6893cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Tue, 29 Mar 2016 08:24:54 +0200 Subject: [PATCH] Socktest: initial commit Using `make sockettest` generetes `snd` and `rcv` binaries. It can be used for testing BIRD's sockets. Based on code by Ondrej Zajicek --- socktest/common.c | 143 ++++++++++++++++++++++++++++++++++++++++++ socktest/common.h | 59 +++++++++++++++++ socktest/rcv.c | 59 +++++++++++++++++ socktest/snd.c | 45 +++++++++++++ tools/Makefile-top.in | 2 +- tools/Makefile.in | 24 +++++-- tools/Rules.in | 4 +- 7 files changed, 329 insertions(+), 7 deletions(-) create mode 100644 socktest/common.c create mode 100644 socktest/common.h create mode 100644 socktest/rcv.c create mode 100644 socktest/snd.c diff --git a/socktest/common.c b/socktest/common.c new file mode 100644 index 00000000..bc29fe46 --- /dev/null +++ b/socktest/common.c @@ -0,0 +1,143 @@ +#include "conf/conf.h" +#include "nest/locks.h" +#include "nest/route.h" +#include "lib/krt.h" + +#include "common.h" + +static void +parse_addr(char *src, ip_addr *dst) +{ + if (!ipa_pton(src, dst)) + { + printf("Invalid address %s\n", src); + exit(-1); + } +} + +static void +parse_int(const char *src, int *dst) +{ + errno = 0; + *dst = strtol(src, NULL, 10); + if (errno) + { + printf("Invalid number %s\n", src); + exit(-1); + } +} + +void +err_hook(sock *s, int err) +{ + if (!err) + { + printf("Sock EOF \n"); + return; + } + + printf("Err(%d): %s \n", err, s->err); + exit(1); +} + +void +skt_open(sock *s) +{ + if (sk_open(s) < 0) + SKT_ERR(s->err); + + sk_set_ttl(s, cf_ttl); + + if (cf_mcast) + sk_setup_multicast(s); + + if (cf_bcast) + sk_setup_broadcast(s); +} + +sock * +skt_parse_args(int argc, char **argv, int is_send) +{ + int is_recv = !is_send; + const char *opt_list = is_send ? "umbRi:l:B:p:v:t:" : "um:bRi:l:B:p:v:t:"; + int c; + + cf_value = PKT_VALUE; + cf_ttl = 1; + uint port = PKT_PORT; + + sock *s = sk_new(&root_pool); + + /* Raw socket is default type */ + s->type = SK_IP; + + s->err_hook = err_hook; + + while ((c = getopt(argc, argv, opt_list)) >= 0) + switch (c) + { + case 'u': + s->type = SK_UDP; + break; + case 'm': + cf_mcast = 1; + if (is_recv) + parse_addr(optarg, &s->daddr); + break; + case 'b': + cf_bcast = 1; + break; + case 'R': + cf_route = 1; + break; + case 'i': + s->iface = if_get_by_name(optarg); + break; + case 'l': + parse_addr(optarg, &s->saddr); /* FIXME: Cannot set local address and bind address together */ + break; + case 'B': + parse_addr(optarg, &s->saddr); /* FIXME: Cannot set local address and bind address together */ + s->flags |= SKF_BIND; + cf_bind = 1; + break; + case 'p': + parse_int(optarg, &port); + break; + case 'v': + parse_int(optarg, &cf_value); + break; + case 't': + parse_int(optarg, &cf_ttl); + break; + + default: + goto usage; + } + + if (is_recv && s->type == SK_UDP) + s->sport = port; + else + s->dport = port; + + if (optind + is_send != argc) + goto usage; + + if (is_send) + parse_addr(argv[optind], &s->daddr); + + return s; + + usage: + printf("Usage: %s [-u] [-m%s|-b] [-B baddr] [-R] [-i iface] [-l addr] [-p port] [-v value] [-t ttl]%s\n", + argv[0], is_recv ? " maddr" : "", is_send ? " daddr" : ""); + exit(1); +} + +void +bird_init(void) +{ + resource_init(); + io_init(); + if_init(); +} diff --git a/socktest/common.h b/socktest/common.h new file mode 100644 index 00000000..ea181093 --- /dev/null +++ b/socktest/common.h @@ -0,0 +1,59 @@ +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nest/bird.h" +#include "lib/lists.h" +#include "lib/resource.h" +#include "lib/timer.h" +#include "lib/socket.h" +#include "lib/event.h" +#include "lib/string.h" +#include "nest/iface.h" +#include "lib/string.h" + +#include "lib/unix.h" + + +//#define PKT_MAGIC 0x12345678 +#define PKT_MAGIC 42 + +#define PKT_PORT 100 +#define PKT_VALUE 0 + +struct my_packet +{ + u32 magic; + u32 value; + u32 count; +}; + +int cf_mcast, cf_bcast, cf_bind, cf_route; +uint cf_value; +uint cf_ttl; + +#define SKT_ERR(x) do { perror(x); exit(-1); } while(0) + +sock *skt_parse_args(int argc, char **argv, int is_send); +void bird_init(void); +void skt_open(sock *s); + +/* implementation in io.c */ +int sk_write(sock *s); +int sk_read(sock *s); diff --git a/socktest/rcv.c b/socktest/rcv.c new file mode 100644 index 00000000..e4d01a96 --- /dev/null +++ b/socktest/rcv.c @@ -0,0 +1,59 @@ +#include "common.h" + +int +rcv_hook(sock *sk, int size) +{ + struct my_packet *raw; + if (sk->type == SK_IP) + raw = (void *) sk_rx_buffer(sk, &size); + else + raw = (void *) sk->rbuf; + + if (size != sizeof(struct my_packet)) + { + printf("Bad size of rcv packet %d \n", size); + return 1; + } + + struct my_packet pkt = { + .magic = ntohl(raw->magic), + .value = ntohl(raw->value), + .count = ntohl(raw->count), + }; + + char *ifa_name = if_find_by_index(sk->lifindex) ? if_find_by_index(sk->lifindex)->name : "UNKNOWN"; + + char buf[1024]; + + bsnprintf(buf, sizeof(buf), "%I:%u -> %I ifa%u %s: ", sk->faddr, sk->fport, sk->laddr, sk->lifindex, ifa_name); + char *pos = buf + strlen(buf); + + if (pkt.magic == (u32)PKT_MAGIC) + bsnprintf(pos, pos-buf, "pkt %d/%d, ttl %d", pkt.value, pkt.count, sk->ttl); + else + bsnprintf(pos, pos-buf, "recv foreign of len %d", size); + + printf("%s\n", buf); + + return 1; /* clear buffer */ +} + +int +main(int argc, char **argv) +{ + bird_init(); + + sock *s = skt_parse_args(argc, argv, 0); + s->rx_hook = rcv_hook; + s->rbsize = 1500; + s->flags |= SKF_LADDR_RX | SKF_TTL_RX | SKF_PKTINFO; + + skt_open(s); + + while (1) + { + sk_read(s); + usleep(20000); + } +} + diff --git a/socktest/snd.c b/socktest/snd.c new file mode 100644 index 00000000..6b3845bb --- /dev/null +++ b/socktest/snd.c @@ -0,0 +1,45 @@ +#include "common.h" + +int +do_sendmsg(sock *s, void *pkt, size_t len) +{ + memcpy(s->ttx, pkt, len); + s->tpos = s->ttx + len; + return sk_write(s); +} + +void +connected_hook(sock *s) +{ + printf("Iface %s \n", s->iface->name, s->iface->addr); + printf("Start sending...\n"); + s->tx_hook = NULL; +} + +int +main(int argc, char **argv) +{ + bird_init(); + + sock *s = skt_parse_args(argc, argv, 1); + s->tx_hook = connected_hook; + s->tbsize = 1500; + s->tos = IP_PREC_INTERNET_CONTROL; + + skt_open(s); + + struct my_packet pkt = { + .magic = htonl(PKT_MAGIC), + .value = htonl(cf_value), + }; + + int count = 0; + while (1) + { + pkt.count = htonl(count); + do_sendmsg(s, &pkt, sizeof(pkt)); + count++; + + usleep(200000); + } +} diff --git a/tools/Makefile-top.in b/tools/Makefile-top.in index d37931e7..8d6fb984 100644 --- a/tools/Makefile-top.in +++ b/tools/Makefile-top.in @@ -3,7 +3,7 @@ objdir=@objdir@ -all depend tags install install-docs tests: +all depend tags install install-docs tests sockettest: $(MAKE) -C $(objdir) $@ docs userdocs progdocs: diff --git a/tools/Makefile.in b/tools/Makefile.in index 46c7d112..fe6fc480 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -5,7 +5,7 @@ root-rel=./ include Rules -.PHONY: all daemon birdc birdcl subdir depend clean distclean tags docs userdocs progdocs +.PHONY: all daemon birdc birdcl subdir depend clean distclean tags docs userdocs progdocs sockettest all: sysdep/paths.h .dep-stamp subdir lib/main.o daemon birdcl @CLIENT@ @@ -29,6 +29,8 @@ birdc: $(exedir)/birdc birdcl: $(exedir)/birdcl +sockettest: $(exedir)/snd $(exedir)/rcv + bird-dep := $(addsuffix /all.o, $(static-dirs)) conf/all.o lib/birdlib.a $(bird-dep): sysdep/paths.h .dep-stamp subdir @@ -41,16 +43,20 @@ birdcl-dep := client/birdcl.o client/all.o lib/birdlib.a $(birdcl-dep): sysdep/paths.h .dep-stamp subdir +socktest-dep := socktest/common.o $(addsuffix /all.o, $(static-dirs)) conf/all.o lib/birdlib.a + +$(socktest-dep): sysdep/paths.h .dep-stamp + export client := @CLIENT@ depend: sysdep/paths.h .dir-stamp set -e ; for a in $(dynamic-dirs) ; do $(MAKE) -C $$a $@ ; done - set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done + set -e ; for a in $(static-dirs) $(client-dirs) $(socktest-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done subdir: sysdep/paths.h .dir-stamp .dep-stamp set -e ; for a in $(dynamic-dirs) ; do $(MAKE) -C $$a $@ ; done - set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done + set -e ; for a in $(static-dirs) $(client-dirs) $(socktest-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done $(exedir)/bird: $(bird-dep) lib/main.o $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) @@ -63,8 +69,16 @@ $(exedir)/birdcl: $(birdcl-dep) @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +$(exedir)/snd: $(socktest-dep) socktest/snd.o + @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) + @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +$(exedir)/rcv: $(socktest-dep) socktest/rcv.o + @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) + @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + .dir-stamp: sysdep/paths.h - mkdir -p $(static-dirs) $(client-dirs) $(doc-dirs) + mkdir -p $(static-dirs) $(client-dirs) $(doc-dirs) $(socktest-dirs) touch .dir-stamp .dep-stamp: @@ -83,7 +97,7 @@ sysdep/paths.h: if test -n "@iproutedir@" ; then echo >>sysdep/paths.h "#define PATH_IPROUTE_DIR \"@iproutedir@\"" ; fi tags: - cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]` + cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) $(socktest-dirs) -name *.[chY]` install: all $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/@runtimedir@ diff --git a/tools/Rules.in b/tools/Rules.in index f2d2dd0b..23646a73 100644 --- a/tools/Rules.in +++ b/tools/Rules.in @@ -15,8 +15,10 @@ client-dirs := client client-dir-paths := $(client-dirs) doc-dirs := doc doc-dir-paths := $(doc-dirs) +socktest-dirs := socktest +socktest-dir-paths := $(socktest-dirs) -all-dirs:=$(static-dirs) $(dynamic-dirs) $(client-dirs) $(doc-dirs) +all-dirs:=$(static-dirs) $(dynamic-dirs) $(client-dirs) $(doc-dirs) $(socktest-dirs) clean-dirs:=$(all-dirs) proto sysdep CPPFLAGS=-I$(root-rel) -I$(srcdir) @CPPFLAGS@