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)
|
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
144
echoc.c
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue