summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcflip <cflip@cflip.net>2023-03-26 10:21:47 -0600
committercflip <cflip@cflip.net>2023-03-26 10:21:47 -0600
commitf8ac67c943244aa57e5f848ca6b1f66eca32e138 (patch)
tree2bf4f6695393b993ad3a50528304fdb6e6a0b86a /src
parent83fb0b96c94e7f596f81d5bc346150904457ed64 (diff)
Add support for building on Windows
This makes it possible to compile cfws with Visual Studio. Since winsock and POSIX use very similar APIs, porting is mostly just a matter of placing ifdefs around #includes and functions with slightly different names. However, CGI scripts and command line arguments are not available in this port yet, since they used the Unix-exclusive getopt.h and popen.
Diffstat (limited to 'src')
-rw-r--r--src/ClientConnection.cpp23
-rw-r--r--src/ServerConnection.cpp26
-rw-r--r--src/main.cpp18
3 files changed, 56 insertions, 11 deletions
diff --git a/src/ClientConnection.cpp b/src/ClientConnection.cpp
index c434212..e8e6692 100644
--- a/src/ClientConnection.cpp
+++ b/src/ClientConnection.cpp
@@ -3,7 +3,13 @@
#include <cstring>
#include <iostream>
#include <sstream>
-#include <unistd.h>
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #pragma comment(lib, "ws2_32.lib")
+#else
+ #include <unistd.h>
+#endif
ClientConnection::ClientConnection(int socket)
: m_socket_fd(socket)
@@ -19,7 +25,12 @@ HttpRequest ClientConnection::read_request() const
int n = 0;
memset(buffer, 0, BUFFER_SIZE);
- while ((n = read(m_socket_fd, buffer, BUFFER_SIZE - 1)) > 0) {
+#ifdef _WIN32
+ n = recv(m_socket_fd, buffer, BUFFER_SIZE - 1, 0);
+#else
+ n = read(m_socket_fd, buffer, BUFFER_SIZE - 1);
+#endif
+ while (n > 0) {
if (buffer[n - 1] == '\n')
break;
@@ -35,7 +46,11 @@ bool ClientConnection::send(const HttpResponse& response) const
return false;
std::string result = response.to_string();
+#ifdef _WIN32
+ ::send(m_socket_fd, result.c_str(), result.length(), 0);
+#else
write(m_socket_fd, result.c_str(), result.length());
+#endif
return true;
}
@@ -43,5 +58,9 @@ bool ClientConnection::send(const HttpResponse& response) const
void ClientConnection::close_connection()
{
m_is_open = false;
+#ifdef _WIN32
+ closesocket(m_socket_fd);
+#else
close(m_socket_fd);
+#endif
}
diff --git a/src/ServerConnection.cpp b/src/ServerConnection.cpp
index 64692b6..0a47dc3 100644
--- a/src/ServerConnection.cpp
+++ b/src/ServerConnection.cpp
@@ -1,13 +1,17 @@
#include "ServerConnection.h"
-#include <arpa/inet.h>
-#include <csignal>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/time.h>
#include <sys/types.h>
-#include <unistd.h>
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #pragma comment(lib, "ws2_32.lib")
+#else
+ #include <arpa/inet.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <sys/time.h>
+ #include <unistd.h>
+#endif
#include "ClientConnection.h"
@@ -19,14 +23,22 @@ static void error_and_die(const char* message)
ServerConnection::ServerConnection(int port)
{
+#ifdef _WIN32
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
+ error_and_die("Failed to initialize Winsock");
+#endif
+
sockaddr_in address {};
int socket_options = 1;
if ((m_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error_and_die("Failed to create socket");
+#ifndef _WIN32
if (setsockopt(m_socket_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &socket_options, sizeof(socket_options)) != 0)
error_and_die("setsockopt");
+#endif
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
diff --git a/src/main.cpp b/src/main.cpp
index c0c9bb3..4937f0d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,11 +1,15 @@
+#ifndef _WIN32
#include <getopt.h>
+#endif
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
+#ifndef _WIN32
#include "CGIScript.h"
+#endif
#include "ClientConnection.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
@@ -66,6 +70,7 @@ static HttpResponse serve_from_filesystem(const HttpRequest& request)
return response;
}
+#ifndef _WIN32
static HttpResponse serve_from_cgi(const std::string& script_path, const HttpRequest& request)
{
HttpResponse response;
@@ -99,11 +104,14 @@ static HttpResponse serve_from_cgi(const std::string& script_path, const HttpReq
response.add_headers_and_content(script.read_output());
return response;
}
+#endif
+#ifndef _WIN32
static option long_options[] = {
{ "cgi", required_argument, nullptr, 'c' },
{ "port", required_argument, nullptr, 'p' },
};
+#endif
int main(int argc, char** argv)
{
@@ -111,6 +119,8 @@ int main(int argc, char** argv)
bool in_cgi_mode = false;
std::string cgi_program_name;
+ // TODO: getopt.h is not available on Windows, so this part needs to be rewritten.
+#ifndef _WIN32
int c = 0;
int option_index = 0;
while ((c = getopt_long(argc, argv, "c:p:", long_options, &option_index)) != -1) {
@@ -135,6 +145,7 @@ int main(int argc, char** argv)
// script before attempting to start the server.
if (in_cgi_mode)
CGIScript::validate_path(cgi_program_name);
+#endif
ServerConnection server(port);
std::cout << "Serving a " << (in_cgi_mode ? "CGI script" : "directory") << " on port " << port << std::endl;
@@ -144,11 +155,14 @@ int main(int argc, char** argv)
HttpRequest request = client.read_request();
HttpResponse response;
+ // TODO: Support running CGI executables on Windows
+#ifndef _WIN32
if (in_cgi_mode) {
response = serve_from_cgi(cgi_program_name, request);
- } else {
+ } else
+#endif
response = serve_from_filesystem(request);
- }
+
client.send(response);
client.close_connection();