int main (int argc, char *argv[]) { iphb_t hb; int hbsock = -1; int period; if (argc < 2) { printf("Usage: %s period_in_secs [-d]\n", argv[0]); exit(1); } period = atoi(argv[1]); if (argc >= 3 && strcmp(argv[2], "-d") == 0) debugmode = 1; signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGPIPE, SIG_IGN); printf(ME "running\n"); hb = iphb_open(0); if (!hb) { perror(ME "\aERROR, iphb_open()"); run = 0; } else { struct iphb_stats stats; printf(ME "iphb service opened\n"); if (iphb_get_stats(hb, &stats) == -1) fprintf(stderr, ME "\aERROR, iphb_get_stats() failed %s\n", strerror(errno)); else printf(ME "iphb_get_stats(): clients=%u, waiting=%u, next hb=%u secs\n", stats.clients, stats.waiting, stats.next_hb); } if (run) { hbsock = iphb_get_fd(hb); if (hbsock == -1) { perror(ME "\aERROR, iphb_get_fd()"); run = 0; } } for (;run;) { time_t now; time_t went_to_sleep; struct timeval timeout; fd_set readfds; int st; went_to_sleep = time(0); if (iphb_wait(hb, period, period, 0) != 0) { perror(ME "\aERROR, iphb_wait()"); run = 0; continue; } printf(ME "waiting for iphbd wakeup...\n"); timeout.tv_sec = period + 2; timeout.tv_usec = 0; FD_ZERO(&readfds); FD_SET(hbsock, &readfds); st = select(hbsock + 1, &readfds, NULL, NULL, &timeout); now = time(0); if (st == -1) { if (errno == EINTR) continue; else { perror(ME "\aERROR, select()"); run = 0; } } else if (st >= 0) { if (now - went_to_sleep > period + 1) /* allow 1 sec slippage */ fprintf(stderr, ME "\aERROR, select() did not fire as expected, took %d secs\n", (int)(now - went_to_sleep)); if (debugmode) printf(ME "slept %d secs\n", (int)(now - went_to_sleep)); if (FD_ISSET(hbsock, &readfds)) { printf(ME "select() woken by iphbd, waited %d secs\n", (int)(now - went_to_sleep)); } if (st == 0) { fprintf(stderr, ME "\aERROR, select() did not fire at all!\n"); } printf(ME "woke up, last heartbeat happened %d secs ago, now is %s", (int)(now - went_to_sleep), ctime(&now)); } } printf(ME "bye\n"); if (hb) iphb_close(hb); return 0; }
int main (int argc, char *argv[]) { iphb_t hb = 0; int sock = -1; struct sockaddr_in addr; char buf_data; int hbsock; unsigned long packets_sent = 0; int randomsleep = 0; int first = 1; if (argc < 4) { printf("Usage: %s IPAddress port TCP_keepalive_period [-d]\n", argv[0]); exit(1); } if (argc >= 5 && strcmp(argv[4], "-d") == 0) debugmode = 1; signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGPIPE, SIG_IGN); /* We open TCP socket where we send data to emulate real life app */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { perror(ME "socket()"); run = 0; } else { int optval; memset(&addr, 0, (size_t)sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(atoi(argv[2])); if (inet_aton(argv[1], &addr.sin_addr) == 0) { fprintf(stderr, ME "\nERROR invalid address '%s'\n", argv[1]); goto close_sock_and_exit; } if (debugmode) printf(ME "connecting to %s:%d, TCP keepalive period is %d\n", inet_ntoa(addr.sin_addr), (int)ntohs(addr.sin_port), atoi(argv[3])); if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { perror(ME "connect()"); run = 0; } else { optval = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int)); optval = 1; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int)); /* grace period before sending first keepalive */ optval = atoi(argv[3]); if (optval > 0) { printf(ME "setting TCP keepalive timers to %d secs\n", optval); setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (char *)&optval, sizeof(int)); /* we can loose this many keepalives before connection is reset */ optval = 10; setsockopt(sock, SOL_TCP, TCP_KEEPCNT, (char *)&optval, sizeof(int)); /* time between keepalives */ optval = atoi(argv[3]); setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, (char *)&optval, sizeof(int)); } } } if (run) { printf(ME "running\n"); if (!hb) { hb = iphb_open(0); if (!hb) perror(ME "\aERROR, iphb_open()"); else { struct iphb_stats stats; printf(ME "iphb service opened\n"); if (iphb_get_stats(hb, &stats) == -1) fprintf(stderr, ME "\aERROR, iphb_get_stats() failed %s\n", strerror(errno)); else printf(ME "iphb_get_stats(): clients=%u, waiting=%u, next hb=%u secs\n", stats.clients, stats.waiting, stats.next_hb); } } } buf_data = '!' + getpid() % (126 - '!'); srand(time(0)); hbsock = iphb_get_fd(hb); /* Generate data, sleep */ for (;run;) { fd_set readfds; struct timeval timeout; int st, i; time_t now; time_t then; time_t went_to_sleep; char buf[BUFLEN]; if (debugmode) printf(ME "sending data to server and sleep %d msecs...\n", randomsleep*30); for (i = 0; i < BUFLEN; i++) buf[i] = buf_data; for (i = 0; i < 4; i++) { usleep(10*1000); /* sleep 10 millisecs */ if (send(sock, buf, BUFLEN, 0) < 0) { perror(ME "send()"); run = 0; break; } packets_sent++; } /* sleep 30 - 90 msecs secs to get randomness to TCP keep-alives (not in the first round, though) */ if (!randomsleep) randomsleep = (rand() % 3) + 1; /* get random value 1..3 */ else { randomsleep++; if (randomsleep > 3) randomsleep = 1; usleep(randomsleep*30*1000); /* 30-90 msecs */ randomsleep = (rand() % 3) + 1; /* get random value 1..3 */ } if (send(sock, buf, BUFLEN, 0) < 0) { perror(ME "send()"); run = 0; continue; } packets_sent++; then = went_to_sleep = time(0); /* indicate iphbd that I want a wakeup */ if (hb) { if (iphb_wait(hb, first ? 0 : SLEEP_TIME - 15, SLEEP_TIME, 0) != 0) { perror(ME "\aERROR, iphb_wait()"); hb = iphb_close(hb); } first = 0; } if (debugmode) printf(ME "waiting for iphbd wakeup or server data...\n"); timeout.tv_sec = SLEEP_TIME; timeout.tv_usec = 0; /* Wait events from "server" and iphbd */ FD_ZERO(&readfds); if (hbsock != -1) FD_SET(hbsock, &readfds); FD_SET(sock, &readfds); st = select(sock > hbsock ? sock + 1 : hbsock + 1, &readfds, NULL, NULL, &timeout); if (hb) { int st; if (iphb_I_woke_up(hb) == -1) fprintf(stderr, ME "\aERROR, iphb_I_woke_up() %s\n", strerror(errno)); st = iphb_discard_wakeups(hb); if (st == -1) fprintf(stderr, ME "\aERROR, iphb_discard_wakeups() %s\n", strerror(errno)); else if (debugmode) printf(ME "discarded %d bytes\n", st); } now = time(0); if (st == -1) { if (errno == EINTR) continue; else { perror(ME "\aERROR, select()"); run = 0; } } else if (st >= 0) { if (now - then > SLEEP_TIME + 1) /* allow 1 sec slippage */ fprintf(stderr, ME "\aERROR, select() did not fire as expected, took %d secs\n", (int)(now - then)); if (debugmode) printf(ME "slept %d secs\n", (int)(now - then)); if (hbsock != -1 && FD_ISSET(hbsock, &readfds)) { if (debugmode) printf(ME "select() woken by iphbd, waited %d secs\n", (int)(now - then)); } if (FD_ISSET(sock, &readfds)) { if (debugmode) printf(ME "got data from server\n"); if (recv(sock, buf, sizeof(buf), 0) < 0) { perror(ME "\aERROR, recv()"); run = 0; continue; } } if (debugmode) printf(ME "has to wake up, cause time since last keep-alive happened %d secs ago\n", (int)(now - went_to_sleep)); } } printf(ME "bye, sent %lu packets!\n", packets_sent); if (hb) iphb_close(hb); close_sock_and_exit: if (sock != -1) close(sock); return 0; }