#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

#include "protocol.h"

void advertise(int fd, char *msg, int len, struct sockaddr_in *addr)
{
	if(sendto(fd, msg, len, 0, (struct sockaddr *)addr, sizeof(*addr)) < 0){
		perror("sendto");
	}
}

int rtsleep(struct timespec *time, struct timespec *rem)
{
	return clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, time, rem);
}

int main()
{
	struct timespec interval, remain;
	clock_gettime(CLOCK_MONOTONIC, &interval);
	/* Align intervals:
	 * If aligned with another app, a CPU wakeup is saved per interval.
	 * Such alignment hurts schedulability if deadline < interval, but
	 * the uncertainty of not aligning is no better. Better add offset.
	 */
	interval.tv_sec -= interval.tv_sec % INTERVAL_ADVERTISE_SECONDS;
	interval.tv_nsec = 0;

	struct sockaddr_in addr;
	int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(fd < 0){
		perror("Failed to init socket");
		return EXIT_FAILURE;
	}
	memset(&addr, '\0', sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(MCAST_IP);
	addr.sin_port = htons(MCAST_PORT);

	for(;;){
		advertise(fd, "hei", 3, &addr);
		/* If advertising is an important service,
		 * check deadline miss with clock_gettime.
		 * Firm deadline: Ignore occational misses,
		 * repeated misses signify system overload,
		 * in which case we want to be detected!
		 */
		interval.tv_sec += INTERVAL_ADVERTISE_SECONDS;
		while(rtsleep(&interval, &remain)){
			perror("sleep interrupted");
			interval.tv_sec  += remain.tv_sec;
			interval.tv_nsec += remain.tv_nsec;
		}
	}
	return 0;//We never return, we get killed.
}

