From ca410bd75a5f7b0315b97c9a999655b1a8035d4f Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Mon, 30 Jul 2012 20:49:29 +0200 Subject: [PATCH] Rewrite the main loop to use a timer. XXX not finished yet, lots of debug information and bugs left. --- Makefile | 4 +- echoc.c | 158 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 129 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 4f298eb..0446cd6 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,12 @@ SRCS= echoc.c OBJS= $(SRCS:%.c=%.o) +LIBS= -lrt + all: $(PROG) $(PROG): $(OBJS) - $(CC) -o $@ $(OBJS) + $(CC) -o $@ $(OBJS) $(LIBS) .c.o: $(CC) -c $(CFLAGS) -o $@ $< diff --git a/echoc.c b/echoc.c index a9b9419..cef8147 100644 --- a/echoc.c +++ b/echoc.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -33,8 +35,10 @@ int verbose = 0; struct sockaddr *server; socklen_t serverlen; unsigned int seq = 0; +int disconnected; +struct timespec sent; -#define THRESHOLD 10 +#define THRESHOLD 10 static void usage(void) @@ -42,6 +46,50 @@ usage(void) errx(2, "usage: echoc [-v] server"); } +static void +send_packet(bool timestamp) +{ + if (sendto(sock, &seq, sizeof(seq), 0, server, + serverlen) != sizeof(seq)) { + if (verbose) + warn("sendto"); + } + if (timestamp) + clock_gettime(CLOCK_REALTIME, &sent); + if (verbose > 1) + printf("sent %d\n", seq); + seq++; +} + +static void +timer_handler(int unused) +{ + send_packet(!disconnected); +} + +static void +timespec_substract(struct timespec *result, + const struct timespec *x, const struct timespec *y) +{ + struct timespec yy; + + memcpy(&yy, y, sizeof(struct timespec)); + + /* Carry */ + if (x->tv_nsec < y->tv_nsec) { + long sec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; + yy.tv_nsec -= 1000000000 * sec; + yy.tv_sec += sec; + } + if (x->tv_nsec - y->tv_nsec > 1000000000) { + int sec = (x->tv_nsec - y->tv_nsec) / 1000000000; + yy.tv_nsec += 1000000000 * sec; + yy.tv_sec -= sec; + } + + result->tv_sec = x->tv_sec - yy.tv_sec; + result->tv_nsec = x->tv_nsec - yy.tv_nsec; +} int main(int argc, char *argv[]) @@ -51,19 +99,23 @@ main(int argc, char *argv[]) struct sockaddr_storage client; struct addrinfo hints, *res, *res0; struct timeval tv; + struct itimerspec ts; + struct sigevent se; + struct sigaction sa; struct tm *tm; struct pollfd pfd[1]; socklen_t addrlen; + timer_t timer; int ch; int nfds, received = 0; - int error, dropped, buffer, last; + int error, buffer, last; extern int optind; setbuf(stdout, NULL); while ((ch = getopt(argc, argv, "v")) != -1) { switch (ch) { case 'v': - verbose = 1; + verbose++; break; default: usage(); @@ -93,33 +145,75 @@ main(int argc, char *argv[]) if (sock == -1) err(1, "socket"); - dropped = 0; + disconnected = 1; memset(&client, 0, sizeof(client)); gettimeofday(&tv, NULL); + + /* create a timer generating SIGALRM */ + memset(&se, 0, sizeof(struct sigevent)); + se.sigev_signo = SIGALRM; + se.sigev_notify = SIGEV_SIGNAL; + timer_create(CLOCK_REALTIME, &se, &timer); + + /* timer values */ + ts.it_interval.tv_nsec = 100000000; /* 100ms */ + ts.it_interval.tv_sec = 0; + ts.it_value.tv_nsec = 100000000; + ts.it_value.tv_sec = 0; + timer_settime(timer, 0, &ts, NULL); + + /* set SIGALRM handler */ + sa.sa_handler = timer_handler; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGALRM); /* block SIGALRM during handler */ + sigaction(SIGALRM, &sa, NULL); + + /* send initial packet */ + send_packet(true); + while (1) { - if (sendto(sock, &seq, sizeof(seq), 0, server, - serverlen) != sizeof(seq)) { - if (verbose) - warn("sendto"); + struct timespec now, diff; + + while (1) { + pfd[0].fd = sock; + pfd[0].events = POLLIN; + nfds = poll(pfd, 1, 200); + clock_gettime(CLOCK_REALTIME, &now); + timespec_substract(&diff, &now, &sent); + if (nfds > 0) + break; + if (nfds == -1 && errno != EINTR) + warn("poll error"); + if (verbose > 2) + printf("%d %s\n", nfds, strerror(errno)); + if (verbose > 1) + printf("wait %ld.%06ld\n", + (long)diff.tv_sec, diff.tv_nsec/1000); + if (diff.tv_sec > 0 || diff.tv_nsec > 200000000) { + if (verbose) + printf("timeout %ld.%06ld\n", + (long)diff.tv_sec, diff.tv_nsec/1000); + disconnected++; + nfds = 0; + break; + } } - 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)) { - dropped++; - if (dropped == THRESHOLD) { - tm = localtime((time_t *)&tv.tv_sec); + if ((nfds == 0)) { + if (verbose > 1) + printf("!! %d packet(s) dropped\n", seq - last); + if (disconnected == 1) { + tm = localtime((time_t *)&now.tv_sec); strftime(buf, sizeof(buf), "%F %T", tm); - printf("%s.%06ld: lost connection\n", - buf, tv.tv_usec); + printf("%s.%06ld: lost connection\n", + buf, now.tv_nsec * 1000); } continue; } - + if (ioctl(sock, FIONREAD, &received) == -1) + warn("ioctl FIONREAD"); + if (verbose > 1) + printf("received %d bytes ", received); + addrlen = sizeof(client); if ((received = recvfrom(sock, &buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr *) &client, @@ -138,20 +232,20 @@ main(int argc, char *argv[]) name); } } - gettimeofday(&tv, NULL); - if (dropped >= THRESHOLD) { - tm = localtime((time_t *)&tv.tv_sec); + if (disconnected >= THRESHOLD) { + tm = localtime((time_t *)&now.tv_sec); strftime(buf, sizeof(buf), "%F %T", tm); - printf("%s.%06ld: connection is back\n", - buf, tv.tv_usec); + printf("%s.%06ld: connection is back\n", + buf, now.tv_nsec/1000); if (verbose) - printf("dropped %d paquets\n", dropped); - dropped = 0; + printf("dropped %d paquets\n", seq - last); + exit(3); } + disconnected = 0; last = buffer; - if (verbose) - printf("%d %ld.%06ld\n", buffer, tv.tv_sec, tv.tv_usec); - usleep(100000); + if (verbose > 1) + printf("%d %ld.%06ld\n", buffer, (long)diff.tv_sec, + diff.tv_nsec/1000); } close(sock); exit(0);