diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f0686e3..150895c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,5 +1,6 @@ name: C Build and Test on: + workflow_dispatch: pull_request: push: branches: @@ -10,52 +11,35 @@ env: jobs: build-and-test: runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - container: - image: koutoftimer/oduortoni-c-http-server-actions:latest steps: - name: Checkout repository uses: actions/checkout@v4 with: - token: ${{ secrets.PAT_TOKEN }} fetch-depth: 0 ref: ${{ github.head_ref || github.ref }} + + - name: Cache APT packages + uses: actions/cache@v4 + with: + path: /var/cache/apt/archives + key: ${{ runner.os }}-apt-${{ hashFiles('**/build-and-test.yml') }} + restore-keys: | + ${{ runner.os }}-apt- - - name: Auto-format code + - name: Cache build artifacts + uses: actions/cache@v4 + with: + path: | + bin/ + obj/ + key: ${{ runner.os }}-build-${{ hashFiles('src/**', 'Makefile') }} + restore-keys: | + ${{ runner.os }}-build- + + - name: Install dependencies run: | - set -x # Enable debug output - - git config --global --add safe.directory $PWD - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Run formatting - pre-commit run --all-files || true - - # Debug: show git status - echo "=== Git Status ===" - git status - echo "=== Git Diff ===" - git diff - echo "=== Porcelain ===" - git status --porcelain - - # Exit early if no changes - if [ -z "$(git status --porcelain)" ]; then - echo "✓ No formatting changes needed" - exit 0 - fi - - # Only set up git remote if we actually need to push - echo "Changes detected, setting up authentication..." - git remote set-url origin https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/${{ github.repository }}.git - - git add -A - git commit -m "style: auto-format code with clang-format [skip ci]" - git push - echo "✓ Code formatted and pushed" + sudo apt-get update + sudo apt-get install -y gcc-14 make curl libgtest-dev pkg-config - name: Build C code run: | diff --git a/src/lib/net/net_serve.c b/src/lib/net/net_serve.c index 51cf00a..a1ee641 100644 --- a/src/lib/net/net_serve.c +++ b/src/lib/net/net_serve.c @@ -1,6 +1,17 @@ +#include +#include + #include "header.h" #include "utils/logging/header.h" +volatile sig_atomic_t shutdown_requested = false; + +void +signal_hander([[maybe_unused]] int sig) +{ + shutdown_requested = true; +} + /** * Starts a server that listens for incoming connections on the specified host * and port. The server will accept incoming connections and pass them to the @@ -19,6 +30,12 @@ int net_serve(char* host, ProtocolHandler handle_protocol, RequestContext* context) { + struct sigaction sa = {.sa_handler = signal_hander}; + // Termination signal + sigaction(SIGTERM, &sa, nullptr); + // Interrupt from keyboard + sigaction(SIGINT, &sa, nullptr); + int port; char head[50], tail[50]; @@ -31,7 +48,7 @@ net_serve(char* host, ProtocolHandler handle_protocol, RequestContext* context) int server_socket = net_listener(head, port); info("Serving requests on %s\n", host); - while (1) { + while (!shutdown_requested) { struct sockaddr_in client_addr; socklen_t client_addrlen = sizeof(client_addr); int client_conn = @@ -39,6 +56,7 @@ net_serve(char* host, ProtocolHandler handle_protocol, RequestContext* context) &client_addrlen); if (client_conn < 0) { + if (errno == EINTR) continue; perror("accept() failed"); close(server_socket); exit(1); diff --git a/src/main.c b/src/main.c index e2ace9e..5aecbe4 100644 --- a/src/main.c +++ b/src/main.c @@ -32,13 +32,8 @@ main() http.ListenAndServe(hostname, router); - /* - * TODO: This is never reached due to infinite listener that stops on - * CTRL + C - * - Need to add a way to handle graceful shut down - */ - // info("\n\n\t << Graceful Shutdown >>\n\n"); - // router_free(router); + printf("\n\n\t << Graceful Shutdown >>\n\n"); + router_free(router); return 0; } diff --git a/tests/integration-tests.sh b/tests/integration-tests.sh index 99a181e..bc03312 100755 --- a/tests/integration-tests.sh +++ b/tests/integration-tests.sh @@ -30,15 +30,18 @@ for i in {1..25}; do fi done -# Run Hurl tests -if [ -z "$HURL" ]; then - HURL="hurl" -fi +echo "Testing routes..." -$HURL --test --variable PORT="$PORT" tests/integration-tests.hurl +curl -s "$HOST/" | grep -q "A Minimalistic C Server" || die "Home page test failed" +echo "✓ Home page works" -[ $? -ne 0 ] && die "hurl failed" +curl -s "$HOST/nonexistent" | grep -q "404" || die "404 test failed" +echo "✓ 404 handling works" + +echo "All integration tests passed" # Check for closing connection printf '' > /dev/tcp/127.0.0.1/9000 sleep 0.3 + +echo "Testing closing connection complete"