/*
 * Listen on a raw socket until a timer timeout occurs; break out,
 *   and then go back to listening.
 * 
 * Compile with "gcc -Wall -o tcp-timer tcp-timer.c -lrt"  
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <netinet/ip.h>
#include <netinet/tcp.h>

#include <poll.h>

#include <sys/timerfd.h>

#define handle_error(msg)                                               \
     do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(){
     int sockfd, n;
     socklen_t clilen = sizeof(struct sockaddr_in);    
     const int on = 1;
     struct sockaddr_in cliaddr;
     char buf[IP_MAXPACKET];
     int i;
     
     struct itimerspec itspec;
     struct pollfd pd[2];

     int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
     if (tfd == -1)
          handle_error("timerfd_create");
           
     // expire in 3 sec
     itspec.it_value.tv_sec = 3;
     itspec.it_value.tv_nsec = 0;
     // ...then every 3 seconds
     itspec.it_interval.tv_sec = 3;
     itspec.it_interval.tv_nsec = 0;

     if (timerfd_settime(tfd, 0, &itspec, NULL) == -1)
          handle_error("timerfd_settime");

     sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
     if (sockfd < 0)
	  handle_error("sock_raw:");

     // Set flag so socket expects us to provide IPv4 header.
     if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) 
	  handle_error("setsockopt() failed to set IP_HDRINCL ");
     
     pd[0].fd = sockfd;
     pd[0].events = POLLIN;

     pd[1].fd = tfd;
     pd[1].events = POLLIN;

     while(1){
          printf(" at poll\n");
          int rv = poll( pd, 2, 5000 ); 
          if (rv == -1) {
               perror("poll:"); // error occurred in poll()
          } else if (rv == 0) {
               printf("Timeout occurred!  No data after 5 seconds.\n");
          } else {
               // check for events on 1:
               if (pd[0].revents & POLLIN) {
                    n = recvfrom(sockfd, buf, 10000, 0, (struct sockaddr *)&cliaddr, &clilen);
		    if( n < 0 )
			 handle_error("recv error:");
		    
                    printf(" rec'd %d bytes\n",n);
                    for (i = 0; i < n; i++) {
                         printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n");
                    }
                    printf("\n");
               }
               if(pd[1].revents & POLLIN) {
                    uint64_t exp;
                    int s = read(tfd, &exp, sizeof(uint64_t));
                    if (s != sizeof(uint64_t))
                         handle_error("read");
                    printf( "Timeout of interval timer: %lu\n", exp);
               } 
	  }
     }
}

