<commit_before>#include "globals.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

/* TODO: Better return some error codes on failure?
 */

static struct {
    int curr_clients;   // current number of clients 
    int max_clients;    // max number of clients, will not be much
    int backlog;
    int listen_sock;    // socket that the server is listening on
    int daemon;         // are we a daemon? not sure if needed
    char *bind_addr;    // address to bind
    char *bind_port;    // port to bind
} server;

/* TODO: Learn what happens if waitpid() returns -1.
 * May need a fix then.
 */
static void sigchld_handler(int sig)
{
    int old_errno = errno;
    while (waitpid(-1, NULL, WNOHANG) > 0) { // Does not handle errors
        server.curr_clients--;
    }
    errno = old_errno;
}

static void terminate_handler(int sig)
{
    exit(cleanup());
}

/* Assuming that the server struct is filled.
 * Then bind and listen.
 * Set the server's listen_sock accordingly.
 * Return 0 on success, non-zero on error.
 */
static int bind_and_listen(void)
{
    int status;
    int sockfd;
    struct addrinfo *servinfo, *rp;
    struct addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    status = getaddrinfo(server.bind_addr, server.bind_port,
            &hints, &servinfo);
    if (status != 0) {
        fprintf(stderr, "getaddrinfo() error: %s\n", gai_strerror(status));
        return 1;
    }
    for (rp = servinfo; rp; rp = rp->ai_next) {
        sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sockfd == -1) { // could not get socket
            continue; // try the next one
        }
        if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { // we are done
            break;
        }
        close(sockfd); // could not bind, close and try the next one
    }
    freeaddrinfo(servinfo);
    if (!rp) { // no address succeeded
        fprintf(stderr, "Could not bind anywhere!\n");
        return 1;
    }
    // Since bind() has succeeded, we now listen() the socket.
    status = listen(sockfd, server.backlog);
    if (status == -1) {
        perror("listen() error");
        return 1;
    }
    server.listen_sock = sockfd;
    return 0; // YAY
}

/* Main routine for fork()ed child
 * Currently just write()s what it recv()s to stdout
 * TODO: Error checking
 */
static void child_main(int recv_sock)
{
    pid_t pid;
    int pipefd[2];
    char buf[BUFSIZ];
    size_t bufsiz = sizeof buf;
    ssize_t recved;
    // Child will not need the signal handlers of the parent.
    struct sigaction sa;
    memset(&sa, 0, sizeof sa);
    sa.sa_handler = SIG_IGN;
    sigaction(SIGCHLD, &sa, NULL);
    sa.sa_handler = SIG_DFL;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    // Now clean the server stuff, we do not need them
    free(server.bind_addr);
    free(server.bind_port);
    close(server.listen_sock);

    if (pipe(pipefd) == -1) {
        perror("pipe() error");
        exit(1);
    }
    pid = fork();
    if (pid == -1) {
        perror("fork() error");
        exit(1);
    } else if (pid == 0) {
        close(pipefd[0]);
        if (dup2(pipefd[1], 1) == -1) {
            perror("dup2() error");
            exit(1);
        }
        while ((recved = recv(recv_sock, buf, bufsiz, 0)) > 0) {
            write(1, buf, recved);
        }
    } else {
        char *argv[] = { "/usr/bin/aplay", "-f", "cd", NULL };
        close(pipefd[1]);
        close(recv_sock);
        if (dup2(pipefd[0], 0) == -1) {
            perror("dup2() error");
            exit(1);
        }
        execvp("/usr/bin/aplay", argv);
    }
    close(recv_sock);
    exit(0);
}

/* TODO: Daemonizing<commit_msg>server: Print error if exec() returns<commit_after>#include "globals.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

/* TODO: Better return some error codes on failure?
 */

static struct {
    int curr_clients;   // current number of clients 
    int max_clients;    // max number of clients, will not be much
    int backlog;
    int listen_sock;    // socket that the server is listening on
    int daemon;         // are we a daemon? not sure if needed
    char *bind_addr;    // address to bind
    char *bind_port;    // port to bind
} server;

/* TODO: Learn what happens if waitpid() returns -1.
 * May need a fix then.
 */
static void sigchld_handler(int sig)
{
    int old_errno = errno;
    while (waitpid(-1, NULL, WNOHANG) > 0) { // Does not handle errors
        server.curr_clients--;
    }
    errno = old_errno;
}

static void terminate_handler(int sig)
{
    exit(cleanup());
}

/* Assuming that the server struct is filled.
 * Then bind and listen.
 * Set the server's listen_sock accordingly.
 * Return 0 on success, non-zero on error.
 */
static int bind_and_listen(void)
{
    int status;
    int sockfd;
    struct addrinfo *servinfo, *rp;
    struct addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    status = getaddrinfo(server.bind_addr, server.bind_port,
            &hints, &servinfo);
    if (status != 0) {
        fprintf(stderr, "getaddrinfo() error: %s\n", gai_strerror(status));
        return 1;
    }
    for (rp = servinfo; rp; rp = rp->ai_next) {
        sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sockfd == -1) { // could not get socket
            continue; // try the next one
        }
        if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { // we are done
            break;
        }
        close(sockfd); // could not bind, close and try the next one
    }
    freeaddrinfo(servinfo);
    if (!rp) { // no address succeeded
        fprintf(stderr, "Could not bind anywhere!\n");
        return 1;
    }
    // Since bind() has succeeded, we now listen() the socket.
    status = listen(sockfd, server.backlog);
    if (status == -1) {
        perror("listen() error");
        return 1;
    }
    server.listen_sock = sockfd;
    return 0; // YAY
}

/* Main routine for fork()ed child
 * Currently just write()s what it recv()s to stdout
 * TODO: Error checking
 */
static void child_main(int recv_sock)
{
    pid_t pid;
    int pipefd[2];
    char buf[BUFSIZ];
    size_t bufsiz = sizeof buf;
    ssize_t recved;
    // Child will not need the signal handlers of the parent.
    struct sigaction sa;
    memset(&sa, 0, sizeof sa);
    sa.sa_handler = SIG_IGN;
    sigaction(SIGCHLD, &sa, NULL);
    sa.sa_handler = SIG_DFL;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    // Now clean the server stuff, we do not need them
    free(server.bind_addr);
    free(server.bind_port);
    close(server.listen_sock);

    if (pipe(pipefd) == -1) {
        perror("pipe() error");
        exit(1);
    }
    pid = fork();
    if (pid == -1) {
        perror("fork() error");
        exit(1);
    } else if (pid == 0) {
        close(pipefd[0]);
        if (dup2(pipefd[1], 1) == -1) {
            perror("dup2() error");
            exit(1);
        }
        while ((recved = recv(recv_sock, buf, bufsiz, 0)) > 0) {
            write(1, buf, recved);
        }
    } else {
        char *argv[] = { "/usr/bin/aplay", "-f", "cd", NULL };
        close(pipefd[1]);
        close(recv_sock);
        if (dup2(pipefd[0], 0) == -1) {
            perror("dup2() error");
            exit(1);
        }
        execvp("/usr/bin/aplay", argv);
        // ERROR IF WE REACH HERE
        perror("execvp() error");
        exit(1);
    }
    close(recv_sock);
    exit(0);
}

/* TODO: Daemonizing
{'fraction_non_alphanumeric': 0.13926571250777847, 'fraction_numerical': 0.009583074051026758, 'mean_word_length': 2.3165497317375157, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '760941', 'n_tokens_mistral': 2790, 'n_tokens_neox': 2736, 'n_words': 796}