summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile12
-rw-r--r--src/ClientConnection.cpp49
-rw-r--r--src/ClientConnection.h16
-rw-r--r--src/HttpResponse.cpp16
-rw-r--r--src/HttpResponse.h18
-rw-r--r--src/ServerConnection.cpp43
-rw-r--r--src/ServerConnection.h12
-rw-r--r--src/main.cpp25
9 files changed, 193 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..512d52b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Ignore executable binary
+cfws
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8a44899
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+CC=clang++
+CFLAGS=-pedantic -Wall --std=c++11
+
+SRC=src/main.cpp \
+ src/ClientConnection.cpp \
+ src/ServerConnection.cpp \
+ src/HttpResponse.cpp
+
+OUT=cfws
+
+$(OUT): $(SRC)
+ $(CC) $(CFLAGS) -o $(OUT) $(SRC)
diff --git a/src/ClientConnection.cpp b/src/ClientConnection.cpp
new file mode 100644
index 0000000..3bf93c3
--- /dev/null
+++ b/src/ClientConnection.cpp
@@ -0,0 +1,49 @@
+#include "ClientConnection.h"
+
+#include <unistd.h>
+#include <iostream>
+#include <sstream>
+
+ClientConnection::ClientConnection(int socket)
+ : m_socket_fd(socket)
+{
+}
+
+void ClientConnection::dump_request_data()
+{
+ constexpr int BUFFER_SIZE = 4096;
+ char buffer[BUFFER_SIZE+1];
+ int n;
+
+ memset(buffer, 0, BUFFER_SIZE);
+ while ((n = read(m_socket_fd, buffer, BUFFER_SIZE-1)) > 0) {
+ std::cout << buffer;
+
+ if (buffer[n-1] == '\n')
+ break;
+
+ memset(buffer, 0, BUFFER_SIZE);
+ }
+}
+
+bool ClientConnection::send(const HttpResponse& response, const char* message)
+{
+ if (!m_is_open)
+ return false;
+
+ std::stringstream ss;
+ ss << response.to_string()
+ << "\r\n\r\n"
+ << message;
+
+ std::string result = ss.str();
+ write(m_socket_fd, result.c_str(), result.length());
+
+ return true;
+}
+
+void ClientConnection::close()
+{
+ m_is_open = false;
+ ::close(m_socket_fd);
+}
diff --git a/src/ClientConnection.h b/src/ClientConnection.h
new file mode 100644
index 0000000..6fdf99e
--- /dev/null
+++ b/src/ClientConnection.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "HttpResponse.h"
+
+class ClientConnection {
+public:
+ ClientConnection(int socket);
+
+ void dump_request_data();
+
+ bool send(const HttpResponse&, const char*);
+ void close();
+private:
+ int m_socket_fd;
+ bool m_is_open { true };
+};
diff --git a/src/HttpResponse.cpp b/src/HttpResponse.cpp
new file mode 100644
index 0000000..c9c5ff4
--- /dev/null
+++ b/src/HttpResponse.cpp
@@ -0,0 +1,16 @@
+#include "HttpResponse.h"
+
+HttpResponse::HttpResponse(ResponseCode response_code)
+{
+ m_string_stream << "HTTP/1.0 200 OK";
+}
+
+void HttpResponse::add_header(std::string header)
+{
+ m_string_stream << '\n' << header;
+}
+
+std::string HttpResponse::to_string() const
+{
+ return m_string_stream.str();
+}
diff --git a/src/HttpResponse.h b/src/HttpResponse.h
new file mode 100644
index 0000000..33148da
--- /dev/null
+++ b/src/HttpResponse.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <sstream>
+#include <string>
+
+enum class ResponseCode {
+ OK = 200
+};
+
+class HttpResponse {
+public:
+ HttpResponse(ResponseCode);
+
+ void add_header(std::string header);
+ std::string to_string() const;
+private:
+ std::stringstream m_string_stream;
+};
diff --git a/src/ServerConnection.cpp b/src/ServerConnection.cpp
new file mode 100644
index 0000000..dd4fe86
--- /dev/null
+++ b/src/ServerConnection.cpp
@@ -0,0 +1,43 @@
+#include "ServerConnection.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+
+#include "ClientConnection.h"
+
+static void error_and_die(const char* message)
+{
+ perror(message);
+ exit(1);
+}
+
+ServerConnection::ServerConnection(int port)
+{
+ sockaddr_in address;
+
+ if ((m_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ error_and_die("Failed to create socket");
+
+ bzero(&address, sizeof(address));
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+ address.sin_port = htons(port);
+
+ if ((bind(m_socket_fd, (sockaddr*)&address, sizeof(address))) < 0)
+ error_and_die("bind");
+
+ if ((listen(m_socket_fd, 10)) < 0)
+ error_and_die("listen");
+}
+
+ClientConnection ServerConnection::accept_client_connection()
+{
+ int client_socket = accept(m_socket_fd, (sockaddr*)nullptr, nullptr);
+ return ClientConnection(client_socket);
+}
diff --git a/src/ServerConnection.h b/src/ServerConnection.h
new file mode 100644
index 0000000..0359b5e
--- /dev/null
+++ b/src/ServerConnection.h
@@ -0,0 +1,12 @@
+#pragma once
+
+class ClientConnection;
+
+class ServerConnection {
+public:
+ ServerConnection(int port);
+
+ ClientConnection accept_client_connection();
+private:
+ int m_socket_fd;
+};
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..60c7b4f
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,25 @@
+#include <iostream>
+
+#include "ClientConnection.h"
+#include "HttpResponse.h"
+#include "ServerConnection.h"
+
+int main(int argc, char** argv)
+{
+ ServerConnection server(8080);
+
+ std::cout << "cfws v0.1.0]\n";
+
+ while (true) {
+ std::cout << "Waiting for connections on port 8080" << std::endl;
+ ClientConnection client = server.accept_client_connection();
+ client.dump_request_data();
+
+ HttpResponse http_response(ResponseCode::OK);
+ http_response.add_header("Server: cfws");
+
+ const char* message = "Welcome to the page.";
+ client.send(http_response, message);
+ client.close();
+ }
+}