From 206263dce88a08d20609feeff3a448203fd07717 Mon Sep 17 00:00:00 2001 From: dexter Date: Tue, 22 Apr 2025 04:46:52 +0530 Subject: [PATCH 1/3] chore: remove setup script --- setup.sh | 58 -------------------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 setup.sh diff --git a/setup.sh b/setup.sh deleted file mode 100644 index a5743b2..0000000 --- a/setup.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# Create the html directory in the project root -mkdir -p html - -# Create a basic index.html file if it doesn't exist -if [ ! -f html/index.html ]; then - cat > html/index.html << 'EOF' - - - - - - - Template Test - - - - -

Hello {{user}}!

- - {% if is_logged_in %} -

Welcome back, {{user}}! We're glad to see you again.

- {% else %} -

Please log in to access your account.

- {% endif %} - -

Your Items:

- - - - -EOF - echo "Created sample index.html file" -fi - -echo "Setup complete. The html directory is ready for use." -echo "You can now build and run your server." \ No newline at end of file From 6963021e341b7683b113690418f481b82f5a12b1 Mon Sep 17 00:00:00 2001 From: dexter Date: Tue, 22 Apr 2025 06:37:11 +0530 Subject: [PATCH 2/3] fix: server error --- src/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.c b/src/server.c index dcb3bc3..931e711 100644 --- a/src/server.c +++ b/src/server.c @@ -109,7 +109,7 @@ void* ws_monitor_thread(void* args) { pthread_mutex_unlock(monitor_args->mutex); if (should_notify) { - usleep(RELOAD_DELAY_MS * 1000);ts + usleep(RELOAD_DELAY_MS * 1000); printf("%s%s[HOT RELOAD] %sNotifying %s%d%s client(s) to reload%s\n", BOLD, COLOR_MAGENTA, COLOR_RESET, COLOR_YELLOW, monitor_args->clients->count, COLOR_RESET, COLOR_RESET); From 2c78b473b24d0764f9b05ad019fa32710a043f7f Mon Sep 17 00:00:00 2001 From: Robert Bergman Date: Tue, 22 Apr 2025 09:02:55 -0700 Subject: [PATCH 3/3] Add macOS compatibility to the TCP server implementation --- README.md | 15 +++++++++++++- include/file_watcher.h | 11 +++++++--- include/socket_utils.h | 2 ++ src/file_watcher.c | 46 ++++++++++++++++++++++++++---------------- src/socket_utils.c | 15 +++++++++++--- src/websocket.c | 17 ++++++++++++---- 6 files changed, 78 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 052acba..11cdda8 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ project/ - **CMake** (version 3.10 or higher) - **GCC** or another compatible C compiler - **OpenSSL** development libraries -- **Linux** or **WSL** (Windows Subsystem for Linux) recommended for running this server +- **Linux**, **macOS**, or **WSL** (Windows Subsystem for Linux) supported for running this server ## Setup Instructions @@ -57,6 +57,9 @@ project/ # On Debian/Ubuntu sudo apt update sudo apt install build-essential cmake libssl-dev + +# On macOS using Homebrew +brew install cmake openssl ``` ### 2. Clone the Repository @@ -103,6 +106,16 @@ If port 8080 is already in use, you can specify a different port using the `--po This will start the server on port 8081 instead of the default port. +### macOS-Specific Notes + +When running on macOS, the following modifications have been made to ensure compatibility: + +1. The file watcher implementation uses polling instead of Linux's inotify API +2. Socket options are configured differently to be compatible with macOS networking APIs +3. Cross-platform endian handling for WebSocket implementation + +These changes ensure the server runs properly on macOS while maintaining Linux compatibility. + ## Hot Reload Feature The server includes a hot reload feature that automatically refreshes connected browsers when HTML files are modified: diff --git a/include/file_watcher.h b/include/file_watcher.h index d157487..f23b157 100644 --- a/include/file_watcher.h +++ b/include/file_watcher.h @@ -1,13 +1,18 @@ #ifndef FILE_WATCHER_H #define FILE_WATCHER_H -#include #include #include #include -#define EVENT_SIZE (sizeof(struct inotify_event)) -#define BUF_LEN (1024 * (EVENT_SIZE + 16)) +#ifdef __linux__ + #include + #define EVENT_SIZE (sizeof(struct inotify_event)) + #define BUF_LEN (1024 * (EVENT_SIZE + 16)) +#else + // macOS and other non-Linux platforms + #define BUF_LEN 4096 +#endif typedef struct { char* path; diff --git a/include/socket_utils.h b/include/socket_utils.h index c5b974f..3b48b24 100644 --- a/include/socket_utils.h +++ b/include/socket_utils.h @@ -7,7 +7,9 @@ #include #include #include +#ifdef __linux__ #include +#endif #define PORT 8080 #define BUFFER_SIZE 1024 diff --git a/src/file_watcher.c b/src/file_watcher.c index c623414..37df631 100644 --- a/src/file_watcher.c +++ b/src/file_watcher.c @@ -209,32 +209,35 @@ static void rescan_directory_if_needed(const char* directory, html_files_t* file void* watch_files(void* args) { watcher_args_t* watcher_args = (watcher_args_t*)args; - int fd, wd; char buffer[BUF_LEN]; time_t last_notification_time = 0; const int DEBOUNCE_TIME_MS = 300; + +#ifdef __linux__ + int fd, wd; fd = inotify_init(); if (fd < 0) { - fprintf(stderr, "%s%s[ERROR] %sinotify_init failed: %s%s\n", + fprintf(stderr, "%s%s[ERROR] %sinotify_init failed: %s%s\n", BOLD, COLOR_RED, COLOR_RESET, strerror(errno), COLOR_RESET); free(watcher_args->directory); free(watcher_args); return NULL; } - wd = inotify_add_watch(fd, watcher_args->directory, - IN_MODIFY | IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB); + wd = inotify_add_watch(fd, watcher_args->directory, + IN_MODIFY | IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB); if (wd < 0) { - fprintf(stderr, "%s%s[ERROR] %sinotify_add_watch failed: %s%s\n", + fprintf(stderr, "%s%s[ERROR] %sinotify_add_watch failed: %s%s\n", BOLD, COLOR_RED, COLOR_RESET, strerror(errno), COLOR_RESET); close(fd); free(watcher_args->directory); free(watcher_args); return NULL; } +#endif - printf("%s%s[FILE WATCHER] %sActive - watching directory: %s%s%s\n", + printf("%s%s[FILE WATCHER] %sActive - watching directory: %s%s%s\n", BOLD, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, watcher_args->directory, COLOR_RESET); while (1) { @@ -243,9 +246,10 @@ void* watch_files(void* args) { change_detected = true; } +#ifdef __linux__ fd_set read_fds; FD_ZERO(&read_fds); - FD_SET(fd, &read_fds); + FD_SET(fd, &read_fds); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; @@ -262,11 +266,11 @@ void* watch_files(void* args) { if (event->len > 0) { char* dot = strrchr(event->name, '.'); if (dot && (strcmp(dot, ".html") == 0)) { - printf("%s%s[FILE WATCHER] %sEvent detected: %s%s%s (mask: 0x%08x)\n", + printf("%s%s[FILE WATCHER] %sEvent detected: %s%s%s (mask: 0x%08x)\n", BOLD, COLOR_BLUE, COLOR_RESET, COLOR_CYAN, event->name, COLOR_RESET, event->mask); change_detected = true; char full_path[512]; - snprintf(full_path, sizeof(full_path), "%s/%s", + snprintf(full_path, sizeof(full_path), "%s/%s", watcher_args->directory, event->name); add_html_file(html_files, full_path); } @@ -276,9 +280,13 @@ void* watch_files(void* args) { } } } else if (ret < 0 && errno != EINTR) { - fprintf(stderr, "%s%s[FILE WATCHER] %sSelect error: %s%s\n", + fprintf(stderr, "%s%s[FILE WATCHER] %sSelect error: %s%s\n", BOLD, COLOR_RED, COLOR_RESET, strerror(errno), COLOR_RESET); } +#else + // On macOS and other platforms, we rely on polling with check_all_files_for_changes + // which was already called above +#endif rescan_directory_if_needed(watcher_args->directory, html_files); if (change_detected) { @@ -291,29 +299,33 @@ void* watch_files(void* args) { pthread_mutex_unlock(watcher_args->mutex); if (!already_signaled) { - usleep(100000); + usleep(100000); pthread_mutex_lock(watcher_args->mutex); *(watcher_args->file_changed) = true; - pthread_mutex_unlock(watcher_args->mutex); - printf("%s%s[FILE WATCHER] %sSignaled main thread about file changes%s\n", + pthread_mutex_unlock(watcher_args->mutex); + printf("%s%s[FILE WATCHER] %sSignaled main thread about file changes%s\n", BOLD, COLOR_BLUE, COLOR_YELLOW, COLOR_RESET); last_notification_time = current_time; } else { - printf("%s%s[FILE WATCHER] %sSkipping notification - one already pending%s\n", + printf("%s%s[FILE WATCHER] %sSkipping notification - one already pending%s\n", BOLD, COLOR_BLUE, COLOR_CYAN, COLOR_RESET); } } else { - printf("%s%s[FILE WATCHER] %sDebouncing - %d ms since last notification%s\n", + printf("%s%s[FILE WATCHER] %sDebouncing - %d ms since last notification%s\n", BOLD, COLOR_BLUE, COLOR_CYAN, (int)ms_since_last, COLOR_RESET); } } - usleep(50000); + usleep(50000); } + +#ifdef __linux__ inotify_rm_watch(fd, wd); close(fd); +#endif + free(watcher_args->directory); free(watcher_args); free_html_files(html_files); return NULL; -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/socket_utils.c b/src/socket_utils.c index 71c2ffc..5a89042 100644 --- a/src/socket_utils.c +++ b/src/socket_utils.c @@ -13,11 +13,20 @@ int initialize_server(struct sockaddr_in* address) { return -1; } - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) { - perror("setsockopt failed"); - close(server_fd); + // Set SO_REUSEADDR on all platforms + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) != 0) { + perror("setsockopt SO_REUSEADDR failed"); + close(server_fd); return -1; } + +#ifdef __linux__ + // SO_REUSEPORT is only set on Linux + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) != 0) { + perror("setsockopt SO_REUSEPORT failed"); + // Continue anyway, this is not critical + } +#endif address->sin_family = AF_INET; address->sin_addr.s_addr = INADDR_ANY; diff --git a/src/websocket.c b/src/websocket.c index 18e4b80..59143b1 100644 --- a/src/websocket.c +++ b/src/websocket.c @@ -8,8 +8,17 @@ #include #include #include -#include -#include "request_handler.h" +#ifdef __linux__ + #include +#elif defined(__APPLE__) + #include + #include + // Define Linux-compatible macros + #define __BYTE_ORDER BYTE_ORDER + #define __LITTLE_ENDIAN LITTLE_ENDIAN + #define __BIG_ENDIAN BIG_ENDIAN +#endif +#include "request_handler.h" // Function declarations static char* base64_encode(const unsigned char* input, int length); @@ -640,8 +649,8 @@ int process_ws_frame(int client_socket, ws_clients_t* clients) { break; case WS_BINARY: - printf("%s%s[WebSocket] %sReceived binary message (%s%zu%s bytes)\n", - BOLD, COLOR_BLUE, COLOR_RESET, COLOR_YELLOW, payload_len, COLOR_RESET); + printf("%s%s[WebSocket] %sReceived binary message (%s%llu%s bytes)\n", + BOLD, COLOR_BLUE, COLOR_RESET, COLOR_YELLOW, (unsigned long long)payload_len, COLOR_RESET); break; case WS_CLOSE: