#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/un.h>
#include <thread>
#include <future>
#include <sys/time.h>
#include <chrono>
#include <poll.h>

#define MY_SOCK_PATH "/tmp/thesocket"
#define LISTEN_BACKLOG 5

using namespace std::chrono_literals;

int main (){

    int sfd, cfd;
    struct sockaddr_un my_addr = {};

    // create a socket
    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd == -1){
        std::cout<<"ERROR opening socket\n";
        return 1;
    }
    
    my_addr.sun_family = AF_UNIX;
    strncpy(my_addr.sun_path, MY_SOCK_PATH,
                   sizeof(my_addr.sun_path) - 1);

    // bind the socket
    unlink(MY_SOCK_PATH);
    if (bind(sfd,  (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1){ 
         std::cout<<"ERROR on binding\n";
        return 1;
    }

    // listen
    std::cout<<"listening...\n";
    if (listen(sfd, LISTEN_BACKLOG) == -1) {
         std::cout<<"ERROR listening\n";
        return 1;
    }
    std::cout<<"listening done!\n";

    // thread to shutdown the socket
    // this_sleep 100 ms
    auto fut = std::async(std::launch::async, [&sfd]() {
        std::cout<<"shutting down socket...\n";
        std::this_thread::sleep_for(5000ms);
        close(sfd);//, SHUT_RDWR);//shutdown
        std::cout<<"socket shut down!\n";
    });

    if (false) { // seems to be same blocking behaviour in both poll/accept
    struct pollfd pfd{};
    pfd.fd = sfd;
    pfd.events = POLLIN;

    int ret = poll(&pfd, 1, -1);
    if (ret < 0) {
        std::cout<<"ERROR poll: " << strerror(errno) <<"\n";
    }else if (ret == 1) {
        std::cout << "poll returns revents: " << pfd.revents;
        if (pfd.revents & POLLERR){ std::cout << " (POLLERR is set)"; }
        if (pfd.revents & POLLIN){ std::cout << " (POLLIN is set)"; }
        if (pfd.revents & POLLHUP){ std::cout << " (POLLHUP is set)"; }
        if (pfd.revents & POLLNVAL){ std::cout << " (POLLNVAL is set)"; }
        if (pfd.revents & POLLPRI){ std::cout << " (POLLPRI is set)"; }
        std::cout << "\n";
    }
    }


    // main thread: accept
    std::cout<<"accepting...\n";
    cfd = accept(sfd, nullptr, nullptr);
    if (cfd == -1)
    {
        std::cout<<"ERROR accepting" << strerror(errno) <<"\n";
        return 1;
    }
    std::cout<<"accepting done\n";
    
    return 0;
}