#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#define _GNU_SOURCE
#include <poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <linux/sockios.h>


#define UNIX_PATH_MAX 108

#define SOCK_PATH "/tmp/sock-server.42"
#define DEFERRED_PATH "/dev/null" // "/tmp/sock-server.raw"

int prep_source(const char *path)
{
     int r;
     int fd;
     struct sockaddr_un sa;

     int val;

     fd = socket(AF_UNIX, SOCK_DGRAM, 0);
     assert(fd >= 0);

     sa.sun_family = AF_UNIX;
     strncpy(&sa.sun_path, path, UNIX_PATH_MAX);

     unlink(path);

     r = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
     assert(!r);

     fcntl(fd, F_SETFL, O_NONBLOCK);

     return fd;
}

int prep_sink(const char *path)
{
     int fd;

     fd = open(path, O_WRONLY);
     assert(fd >= 0);

     return fd;
}


int main(int argc, char *argv[])
{
     int r;
     char buf[4096];
     struct pollfd pfd;

     pfd.fd = prep_source(SOCK_PATH);
     pfd.events = POLLIN;

     while (1) {

	  int bytes = 0;

	  for (;;) {
	       r = poll(&pfd, 1, 100000000);
	       if (r < 0) {
		    if (errno == EAGAIN)
			 continue;

		    perror("poll");
		    abort();
	       }

	       r = ioctl(pfd.fd, SIOCINQ, &bytes);
	       if (r < 0) {
		    if (errno == EAGAIN)
			 continue;

		    perror("poll");
		    abort();
	       } else if (bytes == 0)
		    continue;

	       pfd.revents = 0;

	       while (bytes > 0) {
		    int toread = bytes;

		    if (toread > 4096)
			 toread = 4096;

		    r = recv(pfd.fd, &buf, toread, 0);
		    if (r < 0) {
			 perror("recv");
			 abort();
		    }

		    bytes -= r;
	       }
	  }

     }

     return 0;
}
