commit 1cf6c3b02bc9d72cb437805d7ca90250b52fcdee Author: Matthieu Herrb Date: Sun Jul 15 09:54:00 2012 +0200 Echoc: a simple udb based link monitoriing application. Uses the echo service on the other end to send back paquets. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4f298eb --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +# + +PROG= echoc +SRCS= echoc.c + +OBJS= $(SRCS:%.c=%.o) + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) -o $@ $(OBJS) + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< diff --git a/echoc.c b/echoc.c new file mode 100644 index 0000000..ddc4ac9 --- /dev/null +++ b/echoc.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2012 Matthieu Herrb + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sock = -1; +int verbose = 0; +struct sockaddr *server; +socklen_t serverlen; +unsigned int seq = 0; + +#define THRESHOLD 10 + +static void +usage(void) +{ + errx(2, "usage: echoc [-v] server"); +} + + +int +main(int argc, char *argv[]) +{ + char name[NI_MAXHOST]; + struct sockaddr_storage client; + struct addrinfo hints, *res, *res0; + struct timeval tv; + struct pollfd pfd[1]; + socklen_t addrlen; + int ch; + int nfds, received = 0; + int error, dropped, buffer, last; + extern int optind; + + setbuf(stdout, NULL); + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + verbose = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc != 1) + usage(); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(argv[0], "echo", &hints, &res0); + if (error) + errx(1, "%s", gai_strerror(error)); + + for (res = res0; res != NULL; res = res->ai_next) { + sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (sock != -1) { + server = res->ai_addr; + serverlen = res->ai_addrlen; + break; + } + } + if (sock == -1) + err(1, "socket"); + + dropped = 0; + memset(&client, 0, sizeof(client)); + gettimeofday(&tv, NULL); + while (1) { + if (sendto(sock, &seq, sizeof(seq), 0, server, + serverlen) != sizeof(seq)) { + if (verbose) + warn("sendto"); + } + seq++; + + pfd[0].fd = sock; + pfd[0].events = POLLIN; + nfds = poll(pfd, 1, 200); + if (nfds == -1 && errno != EINTR) + warn("poll error"); + if ((nfds == 0) || (nfds == -1 && errno == EINTR)) { + if (dropped == THRESHOLD) { + struct tm *tm = localtime((time_t *)&tv.tv_sec); + char buf[80]; + strftime(buf, sizeof(buf), "%F %T", tm); + printf("%s.%06ld: lost connection\n", + buf, tv.tv_usec); + } + dropped++; + continue; + } + + if ((received = recvfrom(sock, &buffer, sizeof(buffer), + MSG_DONTWAIT, + (struct sockaddr *) &client, + &addrlen)) != sizeof(buffer)) { + warn("recvfrom"); + } + + if (verbose && (serverlen != addrlen || + memcmp(&client, server, addrlen) != 0)) { + if ((error = getnameinfo((struct sockaddr *)&client, + addrlen, name, sizeof(name), + NULL, 0, NI_DGRAM)) != 0) { + warnx("%s", gai_strerror(error)); + } else { + warnx("received data from unknown host %s", + name); + } + } + gettimeofday(&tv, NULL); + if (dropped >= THRESHOLD) { + struct tm *tm = localtime((time_t *)&tv.tv_sec); + char buf[80]; + strftime(buf, sizeof(buf), "%F %T", tm); + printf("%s.%02ld: connection is back\n", + buf, tv.tv_usec); + dropped = 0; + } + last = buffer; + if (verbose) + printf("%d %ld.%06ld\n", buffer, tv.tv_sec, tv.tv_usec); + usleep(100000); + } + close(sock); + exit(0); +}