Rewrite the main loop to use a timer.
XXX not finished yet, lots of debug information and bugs left.
This commit is contained in:
parent
13437c1076
commit
ca410bd75a
2 changed files with 129 additions and 33 deletions
4
Makefile
4
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 $@ $<
|
||||
|
|
158
echoc.c
158
echoc.c
|
@ -14,6 +14,7 @@
|
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue