// Server Process

#include <stdio.h>
#include <sys/types.h>              // socket
#include <sys/socket.h>             // socket
#include <unistd.h>                 // fork()
#include <netinet/in.h>             // socket
#include <signal.h>                 // sigaction()
#include <fcntl.h>                  // open()
#include <string.h>                 // strlen()
#include <arpa/inet.h>              // inet_ntoa()

#define DEFAULT_PORT 9876
#define BUF_MAX 256

// Define if logging of IPs is enabled
int log_ip = 1;

// Signal handler for worker
void handler_usr1(int signal) {
    // SIGUSR1 switches logging on or off
    if (signal == SIGUSR1) {
        log_ip = !log_ip;
        printf("Changing logger to %d\n", log_ip);
    }
}

int main(int argc, const char **argv) {
    int sock, port;
    struct sockaddr_in srv_addr, cli_addr;
    socklen_t cli_len;
    struct sigaction sa;
            
    sa.sa_handler = handler_usr1;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // Install signal handler
    if (sigaction(SIGUSR1, &sa, NULL) < 0) {
        perror("sigaction");
        return 1;
    }

    // Set port
    port = DEFAULT_PORT;

    // Create socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (!sock) { 
        perror("socket");
        return 1; 
    }

    int opt = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { 
        perror("setsockopt");
        return 1; 
    }

    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = INADDR_ANY;
    srv_addr.sin_port = htons(port);

    // Bind
    if (bind(sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
        perror("bind");
        return 1;
    } 

    // Listen
    if (listen(sock, 5) < 0) {
        perror("listen");
        return 1;
    }

    // Accept, create workers
    while(1) {
        int connection = accept(sock, (struct sockaddr *)&cli_addr, &cli_len);

        // If a signal is handled, the system call gets lost
        if (connection < 0) continue;

        // If logger enabled, write IPs in log file
        if (log_ip) {
            int fp = open("logip.txt", O_RDWR|O_CREAT|O_APPEND);
            if (!fp) {
                perror("open log");
                return 1;
            }
            char buffer[BUF_MAX];
            snprintf(buffer, BUF_MAX, "%s\n", inet_ntoa(cli_addr.sin_addr));
            printf("logged %s\n", buffer);
            write(fp, buffer, strlen(buffer) + 1);
            close(fp);
        }

        if (fork() == 0) {
            // WORKER PROCESS
            printf("Incoming connection\n");


            // Read command
            // Parse pipe, create channel
            // Redirect stdout
            // Execute commands
            return 0;
        }

        // SERVER
        close(connection);

    }
    // TODO handler for ctrl-c, close socket
    // TODO wait for child processes?

    return 0;
}
