Rewrite the main loop to use a timer.

XXX not finished yet, lots of debug information and bugs left.
This commit is contained in:
Matthieu Herrb 2012-07-30 20:49:29 +02:00
parent 13437c1076
commit ca410bd75a
2 changed files with 129 additions and 33 deletions

View file

@ -5,10 +5,12 @@ SRCS= echoc.c
OBJS= $(SRCS:%.c=%.o) OBJS= $(SRCS:%.c=%.o)
LIBS= -lrt
all: $(PROG) all: $(PROG)
$(PROG): $(OBJS) $(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(CC) -o $@ $(OBJS) $(LIBS)
.c.o: .c.o:
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -c $(CFLAGS) -o $@ $<

144
echoc.c
View file

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
@ -22,6 +23,7 @@
#include <netdb.h> #include <netdb.h>
#include <poll.h> #include <poll.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -33,6 +35,8 @@ int verbose = 0;
struct sockaddr *server; struct sockaddr *server;
socklen_t serverlen; socklen_t serverlen;
unsigned int seq = 0; unsigned int seq = 0;
int disconnected;
struct timespec sent;
#define THRESHOLD 10 #define THRESHOLD 10
@ -42,6 +46,50 @@ usage(void)
errx(2, "usage: echoc [-v] server"); 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
@ -51,19 +99,23 @@ main(int argc, char *argv[])
struct sockaddr_storage client; struct sockaddr_storage client;
struct addrinfo hints, *res, *res0; struct addrinfo hints, *res, *res0;
struct timeval tv; struct timeval tv;
struct itimerspec ts;
struct sigevent se;
struct sigaction sa;
struct tm *tm; struct tm *tm;
struct pollfd pfd[1]; struct pollfd pfd[1];
socklen_t addrlen; socklen_t addrlen;
timer_t timer;
int ch; int ch;
int nfds, received = 0; int nfds, received = 0;
int error, dropped, buffer, last; int error, buffer, last;
extern int optind; extern int optind;
setbuf(stdout, NULL); setbuf(stdout, NULL);
while ((ch = getopt(argc, argv, "v")) != -1) { while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) { switch (ch) {
case 'v': case 'v':
verbose = 1; verbose++;
break; break;
default: default:
usage(); usage();
@ -93,33 +145,75 @@ main(int argc, char *argv[])
if (sock == -1) if (sock == -1)
err(1, "socket"); err(1, "socket");
dropped = 0; disconnected = 1;
memset(&client, 0, sizeof(client)); memset(&client, 0, sizeof(client));
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
while (1) {
if (sendto(sock, &seq, sizeof(seq), 0, server,
serverlen) != sizeof(seq)) {
if (verbose)
warn("sendto");
}
seq++;
/* 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) {
struct timespec now, diff;
while (1) {
pfd[0].fd = sock; pfd[0].fd = sock;
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
nfds = poll(pfd, 1, 200); nfds = poll(pfd, 1, 200);
clock_gettime(CLOCK_REALTIME, &now);
timespec_substract(&diff, &now, &sent);
if (nfds > 0)
break;
if (nfds == -1 && errno != EINTR) if (nfds == -1 && errno != EINTR)
warn("poll error"); warn("poll error");
if ((nfds == 0) || (nfds == -1 && errno == EINTR)) { if (verbose > 2)
dropped++; printf("%d %s\n", nfds, strerror(errno));
if (dropped == THRESHOLD) { if (verbose > 1)
tm = localtime((time_t *)&tv.tv_sec); 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;
}
}
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); strftime(buf, sizeof(buf), "%F %T", tm);
printf("%s.%06ld: lost connection\n", printf("%s.%06ld: lost connection\n",
buf, tv.tv_usec); buf, now.tv_nsec * 1000);
} }
continue; 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), if ((received = recvfrom(sock, &buffer, sizeof(buffer),
MSG_DONTWAIT, MSG_DONTWAIT,
(struct sockaddr *) &client, (struct sockaddr *) &client,
@ -138,20 +232,20 @@ main(int argc, char *argv[])
name); name);
} }
} }
gettimeofday(&tv, NULL); if (disconnected >= THRESHOLD) {
if (dropped >= THRESHOLD) { tm = localtime((time_t *)&now.tv_sec);
tm = localtime((time_t *)&tv.tv_sec);
strftime(buf, sizeof(buf), "%F %T", tm); strftime(buf, sizeof(buf), "%F %T", tm);
printf("%s.%06ld: connection is back\n", printf("%s.%06ld: connection is back\n",
buf, tv.tv_usec); buf, now.tv_nsec/1000);
if (verbose) if (verbose)
printf("dropped %d paquets\n", dropped); printf("dropped %d paquets\n", seq - last);
dropped = 0; exit(3);
} }
disconnected = 0;
last = buffer; last = buffer;
if (verbose) if (verbose > 1)
printf("%d %ld.%06ld\n", buffer, tv.tv_sec, tv.tv_usec); printf("%d %ld.%06ld\n", buffer, (long)diff.tv_sec,
usleep(100000); diff.tv_nsec/1000);
} }
close(sock); close(sock);
exit(0); exit(0);