network.c 4.54 KB
Newer Older
Matthew Burket's avatar
Matthew Burket committed
1 2 3 4 5 6 7 8 9 10 11 12
//
// Created by mburket on 4/12/18.
//

#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <memory.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <poll.h>
13 14
#include <sys/stat.h>
#include <time.h>
Matthew Burket's avatar
Matthew Burket committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

#include "network.h"
#include "buffer.h"
#include "http.h"
#include "file.h"

/// Accepts a connect from an open socket
///
/// \param socketfd
/// \return
int accept_connection(int socketfd) {
    struct sockaddr_in client_address;
    socklen_t *client_length = (socklen_t *) sizeof(client_address);
    errno = 0;
    int connection = accept(socketfd, (struct sockaddr *) &client_address, (socklen_t *) &client_length);
    return connection;
}

/// Handles the client from the client file descriptor
///
/// \param clientfd file descriptor of the client
/// \return
int handle_client(int clientfd) {
Matthew Burket's avatar
Matthew Burket committed
38
    /// Fork
Matthew Burket's avatar
Matthew Burket committed
39 40
    int pid = fork();
    if (pid == 0) {
Matthew Burket's avatar
Matthew Burket committed
41
        // Setup memory
Matthew Burket's avatar
Matthew Burket committed
42 43
        GrowthBuffer request;
        getRequest(clientfd, &request);
Matthew Burket's avatar
Matthew Burket committed
44
        // Get verb
Matthew Burket's avatar
Matthew Burket committed
45
        HTTP_VERB verb = get_http_verb(request.array);
Matthew Burket's avatar
Matthew Burket committed
46
        // We don't how to handle stuff other than HEAD and GET
Matthew Burket's avatar
Matthew Burket committed
47 48 49 50 51 52
        if (verb == HTTP_UNKNOWN) {
            char *basicHeader = "HTTP/1.1 400 Bad Request\r\n\r\n";
            write(clientfd, basicHeader, strlen(basicHeader));
            shutdown(clientfd, SHUT_RDWR);
            exit(EXIT_SUCCESS);
        }
Matthew Burket's avatar
Matthew Burket committed
53
        // Get the path
Matthew Burket's avatar
Matthew Burket committed
54 55
        char *path = malloc(sizeof(char) * 1024);
        get_http_path(request.array, path);
56 57 58
        int hasDate;
        struct tm tm;
        parseHeaders(request.array, &tm, &hasDate);
Matthew Burket's avatar
Matthew Burket committed
59
        // Setup for getting the response
Matthew Burket's avatar
Matthew Burket committed
60 61
        GrowthBuffer response;
        initBuffer(&response, 5000);
Matthew Burket's avatar
Matthew Burket committed
62
        // If the exsits return 200
Matthew Burket's avatar
Matthew Burket committed
63
        if (checkFile(path) != -1) {
64 65 66 67 68 69 70 71 72 73 74 75
            if (hasDate == 1) {
                struct stat statbuff;
                stat(path, &statbuff);
                time_t headerTime = mktime(&tm);
                time_t fileTime = statbuff.st_ctime;
                if (difftime(fileTime, headerTime) < 0.0) {
                    char *basicHeader = "HTTP/1.1 304 Not Modified\r\n\r\n";
                    write(clientfd, basicHeader, strlen(basicHeader));
                    shutdown(clientfd, SHUT_RDWR);
                    exit(EXIT_SUCCESS);
                }
            }
Matthew Burket's avatar
Matthew Burket committed
76 77 78
            char *basicHeader = "HTTP/1.1 200 OK\r\n\r\n";
            appendBuffer(&response, basicHeader, strlen(basicHeader));
            write(clientfd, response.array, strlen(response.array));
Matthew Burket's avatar
Matthew Burket committed
79
            // If it is a get request return the contents of the file
Matthew Burket's avatar
Matthew Burket committed
80 81 82 83
            if (verb == HTTP_GET) {
                serveFile(clientfd, path);
            }
        } else {
Matthew Burket's avatar
Matthew Burket committed
84
            // Didn't find the file serve 4040
Matthew Burket's avatar
Matthew Burket committed
85 86 87 88 89
            char *basicHeader = "HTTP/1.1 404 Not Found\r\n\r\n";
            appendBuffer(&response, basicHeader, strlen(basicHeader));
            write(clientfd, response.array, strlen(response.array));
        }

Matthew Burket's avatar
Matthew Burket committed
90
        // Clean up and exit
Matthew Burket's avatar
Matthew Burket committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        shutdown(clientfd, SHUT_RDWR);
        free(path);
        freeBuffer(&request);
        exit(EXIT_SUCCESS);
    }
}

///  This creates and binds the socket
///
/// \return the file descriptor of the socket
int bind_socket() {
    int socketfd;
    errno = 0;
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (errno != 0) {
        fprintf(stderr, "\nUnable to create socket.\n");
        fprintf(stderr, strerror(errno));
        fprintf(stderr, "\n");
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(PORT);
    errno = 0;
    bind(socketfd, (struct sockaddr *) &addr, sizeof(addr));
    if (errno != 0) {
        fprintf(stderr, "Unable to bind: [Error %d]: %s", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    listen(socketfd, 2048);
    return socketfd;
}

Matthew Burket's avatar
Matthew Burket committed
124 125 126 127
///  Get request from client
///
/// \param clientfd client to recive from
/// \param request buffer to send request back in
Matthew Burket's avatar
Matthew Burket committed
128 129 130 131 132 133
void getRequest(int clientfd, GrowthBuffer *request) {
    struct pollfd pollfd = {
                .fd = clientfd,
                .events = POLLIN
        };
    ssize_t readCount;
Matthew Burket's avatar
Matthew Burket committed
134
    // Setup memory
Matthew Burket's avatar
Matthew Burket committed
135 136
    initBuffer(request, 500);
    char *buff = malloc(1024);
Matthew Burket's avatar
Matthew Burket committed
137
    // Poll
Matthew Burket's avatar
Matthew Burket committed
138 139
    poll(&pollfd, 1, 0);
    while (pollfd.revents & POLLIN) {
Matthew Burket's avatar
Matthew Burket committed
140
        // Read
Matthew Burket's avatar
Matthew Burket committed
141
        readCount = read(clientfd, buff, 1024);
Matthew Burket's avatar
Matthew Burket committed
142
        // Append bytes read to the buffer
Matthew Burket's avatar
Matthew Burket committed
143 144
        appendBuffer(request, buff, readCount);

Matthew Burket's avatar
Matthew Burket committed
145
        // Didn't read anything
Matthew Burket's avatar
Matthew Burket committed
146 147 148
        if (readCount <= 0) {
            break;
        }
Matthew Burket's avatar
Matthew Burket committed
149
        // Poll again
Matthew Burket's avatar
Matthew Burket committed
150 151 152
        poll(&pollfd, 1, 0);
    }
}