Compare commits

..

25 Commits

Author SHA1 Message Date
anulax1225 7ccbc81ea4 Fixed http parsing ago%!(EXTRA string=1 year)
anulax1225 8fdd4be2ac Added a to_lower_case function ago%!(EXTRA string=1 year)
anulax1225 750f8002e9 Removed all code from main.cpp ago%!(EXTRA string=1 year)
anulax1225 a47ef015af Reorgenised http code ago%!(EXTRA string=1 year)
anulax1225 705a8875ba Client updated ago%!(EXTRA string=1 year)
anulax1225 ac99458453 Added commun.h to the include dirs ago%!(EXTRA string=1 year)
anulax1225 3e33fd9729 Prepering for basic http ago%!(EXTRA string=1 year)
anulax1225 644fada095 Continuing client/server http ago%!(EXTRA string=1 year)
anulax1225 0884bcaf1c Cleaned File ago%!(EXTRA string=1 year)
anulax1225 71c558d7bf Created a simple http client/server ago%!(EXTRA string=1 year)
anulax1225 0ad9bedec5 Added more features needed for more complexe portocols ago%!(EXTRA string=1 year)
anulax1225 7a0ef3aca8 Created a new exemple with a server client interface ago%!(EXTRA string=1 year)
anulax1225 8195ab166b Changed Premake config ago%!(EXTRA string=1 year)
anulax1225 f384c3fbb3 Cleaned ip_address file ago%!(EXTRA string=1 year)
anulax1225 05855a2d50 Removed dns lookup function from file ago%!(EXTRA string=1 year)
anulax1225 9534946adf Added new files to the headers file ago%!(EXTRA string=1 year)
anulax1225 5656e1ddd7 Created a file for the dns lookup function ago%!(EXTRA string=1 year)
anulax1225 0196d77f1e Created a container for packet management ago%!(EXTRA string=1 year)
anulax1225 9c0f3563a5 Changed premake config by adding two new projects for the client and the server. and making bakanet a staticlib ago%!(EXTRA string=1 year)
anulax1225 0f69d3d862 Created a client server test program ago%!(EXTRA string=1 year)
anulax1225 7958c9eace Refactored project folder ago%!(EXTRA string=1 year)
anulax1225 da0d4cc766 Added an exemple with the simple web server ago%!(EXTRA string=1 year)
anulax1225 afdcfdc9a8 Created simple abstraction for socket usage ago%!(EXTRA string=1 year)
anulax1225 652ee8138c Added build script for linux ago%!(EXTRA string=1 year)
anulax1225 b5fae8b6e9 Basic hello world web serveur ago%!(EXTRA string=1 year)
  1. 0
      .gitignore
  2. 2
      LICENSE
  3. 10
      README.md
  4. 6
      bakanet/src/bakanet.h
  5. 2
      bakanet/src/bakanet/dns_lookup.cpp
  6. 15
      bakanet/src/bakanet/dns_lookup.h
  7. 10
      bakanet/src/bakanet/ip_address.cpp
  8. 23
      bakanet/src/bakanet/ip_address.h
  9. 4
      bakanet/src/bakanet/ip_protocol.h
  10. 4
      bakanet/src/bakanet/ip_version.h
  11. 62
      bakanet/src/bakanet/packet.h
  12. 87
      bakanet/src/bakanet/socket.cpp
  13. 45
      bakanet/src/bakanet/socket.h
  14. 9
      build
  15. 5
      dependencies
  16. 23
      examples/httpserver.cpp
  17. 20
      package.json
  18. 127
      premake5.lua
  19. 32
      sandbox/client/client.cpp
  20. 12
      sandbox/commun.h
  21. 91
      sandbox/server/http/http_packet.cpp
  22. 44
      sandbox/server/http/http_packet.h
  23. 38
      sandbox/server/http/http_server.cpp
  24. 8
      sandbox/server/http/http_server.h
  25. 43
      sandbox/server/http/http_tools.cpp
  26. 9
      sandbox/server/http/http_tools.h
  27. 11
      sandbox/server/main.cpp
  28. 15
      src/bakanet.h
  29. 9
      src/bakanet/core/dns_lookup.h
  30. 17
      src/bakanet/core/ip_address.h
  31. 37
      src/bakanet/core/socket.h
  32. 30
      src/bakanet/core/socket_options.h
  33. 73
      src/bakanet/http/packet.cpp
  34. 60
      src/bakanet/http/packet.h
  35. 98
      src/bakanet/http/server.cpp
  36. 34
      src/bakanet/http/server.h
  37. 33
      src/bakanetpch.h
  38. 13
      src/platform/linux/linux_ip_address.cpp
  39. 104
      src/platform/linux/linux_socket.cpp
  40. 35
      src/platform/linux/linux_socket.h
  41. 40
      src/platform/windows/windows_dns_lookup.cpp
  42. 16
      src/platform/windows/windows_ip_adress.cpp
  43. 107
      src/platform/windows/windows_socket.cpp
  44. 34
      src/platform/windows/windows_socket.h

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2024] [anulax1225]
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

@ -1 +1,9 @@
# Baka net module
# Unix socket test
## Prerequisite
Use a linux distro
## Build and Run
```
premake5 gmake
make
./bin/path_to_executable/sandbox
```

@ -0,0 +1,6 @@
#pragma once
#include <bakanet/ip_address.h>
#include <bakanet/packet.h>
#include <bakanet/socket.h>
#include <bakanet/dns_lookup.h>

@ -1,4 +1,4 @@
#include <bakanet/core/dns_lookup.h>
#include "dns_lookup.h"
namespace Bk::Net {
std::vector<std::string> dns_lookup(const std::string &host_name, IpVersion ipv)

@ -0,0 +1,15 @@
#pragma once
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
#include <netdb.h>
#include <arpa/inet.h>
#include "ip_version.h"
#include "ip_address.h"
namespace Bk::Net {
std::vector<std::string> dns_lookup(const std::string &host_name, IpVersion ipv);
}

@ -0,0 +1,10 @@
#include "ip_address.h"
#include <string.h>
namespace Bk::Net {
IpAddress::IpAddress(const char* ip, IpVersion ipv)
: str(ip), version(ipv)
{
if (inet_pton(AF_INET, str, &bytes) <= 0) perror("Bad IP");
}
}

@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <exception>
#include <cctype>
#include "ip_version.h"
namespace Bk::Net {
class IpAddress
{
public:
IpAddress(const char* ip, IpVersion ipv = IpVersion::IPv4);
static void from_dns(char* dns);
const char* str;
in_addr bytes;
IpVersion version;
};
}

@ -1,11 +1,11 @@
#pragma once
#include <bakanetpch.h>
#include <sys/socket.h>
namespace Bk::Net {
enum class IpProtocol
{
TCP = SOCK_STREAM,
UCP = SOCK_DGRAM,
UCP,
};
}

@ -1,9 +1,11 @@
#pragma once
#include <sys/socket.h>
namespace Bk::Net {
enum class IpVersion
{
UNSPEC = AF_UNSPEC,
UnSpec = AF_UNSPEC,
IPv4 = AF_INET,
IPv6 = AF_INET6,
};

@ -0,0 +1,62 @@
#include <vector>
#include <array>
#include <memory>
#include <cstdint>
#include <cstring>
namespace Bk::Net {
class Packet
{
public:
Packet() = default;
Packet(std::vector<char> data)
: payload(data) {}
int size() { return payload.size(); }
template <typename T>
void push(const T& data)
{
static_assert(std::is_standard_layout<T>::value, "Data is too complex to be pushed into vector");
size_t i = payload.size();
payload.resize(i + sizeof(T));
std::memcpy(payload.data() + i, &data, sizeof(T));
}
template <typename T>
void push(const T* data, int size)
{
for(int i = 0; i < size; i++) push<T>(data[i]);
}
template <typename T>
T pull()
{
static_assert(std::is_standard_layout<T>::value, "Data is too complex to be pulled from vector");
T data;
size_t i = payload.size() - sizeof(T);
std::memcpy(&data, payload.data() + i, sizeof(T));
payload.resize(i);
return data;
}
template <typename T>
std::unique_ptr<T[]> pull(int size)
{
std::unique_ptr<T[]> data(new T[size]);
for(int i = size - 1; i >= 0; i--) data[i] = pull<T>();
return data;
}
bool append_data(std::vector<char> data)
{
if (!data.size()) return false;
size_t i = payload.size();
payload.resize(i + data.size());
std::memcpy(payload.data() + i, data.data(), sizeof(char) * data.size());
return true;
}
std::vector<char> payload;
};
}

@ -0,0 +1,87 @@
#include "socket.h"
#include <iostream>
namespace Bk::Net {
Socket::Socket(IpAddress ip, int port,IpProtocol proto)
: ip_addr(ip), ip_proto(proto)
{
//Socket creation step
if ((socket_id = socket((int)ip_addr.version, (int)ip_proto, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
addr.sin_addr = ip_addr.bytes;
addr.sin_family = (int)ip_addr.version;
addr.sin_port = htons(port);
}
Socket::~Socket()
{
close(socket_id);
}
bool Socket::init()
{
//Binding step
int status;
if ((status = bind(socket_id, (struct sockaddr*)&addr, sizeof(addr)) < 0))
{
perror("bind failed");
return false;
}
return true;
}
bool Socket::start(int cpt_conn)
{
//Listening step
if (listen(socket_id, cpt_conn) < 0)
{
return false;
}
return true;
}
Connection Socket::ack()
{
socklen_t addrlen = sizeof(addr);
return accept(socket_id, (struct sockaddr*)&addr, &addrlen);
}
bool Socket::conn()
{
if (connect(socket_id, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
return false;
}
return true;
}
void Socket::send(std::vector<char> packet)
{
write(socket_id, packet.data(), packet.size());
}
void Socket::send(Connection conn, std::vector<char> packet)
{
write(conn, packet.data(), packet.size());
}
std::vector<char> Socket::recv(int size)
{
std::vector<char> buffer;
buffer.resize(size);
int status = read(socket_id, buffer.data(), buffer.size() - 1);
return status > 0 ? buffer : std::vector<char>();
}
std::vector<char> Socket::recv(Connection conn, int size)
{
std::vector<char> buffer;
buffer.resize(size);
int status = read(conn, buffer.data(), buffer.size() - 1);
return status > 0 ? buffer : std::vector<char>();
}
}

@ -0,0 +1,45 @@
#pragma once
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <cstring>
#include <vector>
#include <string>
#include "ip_address.h"
#include "ip_protocol.h"
namespace Bk::Net {
using Connection = int;
class Socket
{
public:
Socket(IpAddress ip, int port, IpProtocol proto);
~Socket();
bool init();
bool start(int cpt_conn);
Connection ack();
bool conn();
void send(std::vector<char> packet);
void send(Connection socket, std::vector<char> packet);
std::vector<char> recv(int size);
std::vector<char> recv(Connection socket, int size);
private:
Socket(int socket_id);
int socket_id;
struct sockaddr_in addr;
IpAddress ip_addr;
IpProtocol ip_proto;
};
}

@ -0,0 +1,9 @@
clear
rm -rf ./bin/linux-x86_64-Debug/server
premake5 gmake2
make
if [ "$1" == "-exec" ]; then
echo STARTING PROGRAM
./bin/linux-x86_64-Debug/server/server
fi

@ -1,5 +0,0 @@
IncludeDirs["bakanet"] = "%{wks.location}/vendor/bakanet/src/"
group "Bakanet"
include "vendor/bakanet"
group ""

@ -1,23 +0,0 @@
#include <bakatools.h>
#include <bakanet.h>
#define PORT 80
using namespace Bk::Net;
int main()
{
Bk::Log::init("Bakanet");
IpAddress ip;
HttpServer server(ip, PORT);
server.get("/", [](HttpRequest& req)
{
HttpReponse res(HTTP_RES_200, req.version);
res.body = "<h1>Bakanet</h1>";
res.body += "<p>Working http server</p>";
res.body += "\n<p>URL /</p>";
return res;
});
server.start();
return 0;
}

@ -1,20 +0,0 @@
{
"name": "Bakanet",
"author": "Anulax",
"git": "https://github.com/anulax1225/bakanet",
"links":
[
"bakanet"
],
"includes":
[
"bakanet"
],
"packages":
[
{
"author": "anulax",
"name": "bakatools"
}
]
}

@ -1,77 +1,92 @@
workspace "socket_unix"
architecture "x64"
configurations { "Debug", "Release" }
startproject "server"
flags
{
"MultiProcessorCompile"
}
outputdir = "%{cfg.system}-%{cfg.architecture}-%{cfg.buildcfg}"
IncludeDirs = {}
IncludeDirs["bakanet"] = "%{wks.location}/bakanet/src/"
project "bakanet"
location "./bakanet"
kind "StaticLib"
language "C++"
cppdialect "C++20"
cppdialect "C++17"
systemversion "latest"
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}")
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}")
includedirs
{
"%{IncludeDirs.bakanet}"
}
files
{
"%{prj.location}/src/**.h",
"%{prj.location}/src/**.cpp"
}
project "server"
location "./sandbox/server"
kind "ConsoleApp"
language "C++"
cppdialect "C++17"
systemversion "latest"
staticruntime "on"
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}")
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}")
includedirs
{
"%{IncludeDirs.spdlog}",
"%{IncludeDirs.bakanet}",
"%{IncludeDirs.bakatools}"
"./sandbox/"
}
files
{
"%{prj.location}/src/bakanet/**.h",
"%{prj.location}/src/bakanet/**.cpp",
"%{prj.location}/src/baknetpch.h",
"%{prj.location}/**.h",
"%{prj.location}/**.cpp",
"./sandbox/commun.h"
}
links
links
{
"bakatools"
"bakanet"
}
filter "system:windows"
buildoptions { "/MT", "/utf-8" }
defines
{
"BK_PLATFORM_WINDOWS"
}
files
{
"%{prj.location}/src/platform/windows/**.h",
"%{prj.location}/src/platform/windows/**.cpp",
}
links
{
"WS2_32.lib"
}
filter "system:linux"
defines
{
"BK_PLATFORM_LINUX"
}
files
{
"%{prj.location}/src/platform/linux/**.h",
"%{prj.location}/src/platform/linux/**.cpp",
}
project "client"
location "./sandbox/client"
kind "ConsoleApp"
language "C++"
cppdialect "C++17"
systemversion "latest"
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}")
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}")
includedirs
{
"%{IncludeDirs.bakanet}"
}
files
{
"%{prj.location}/**.h",
"%{prj.location}/**.cpp",
"./sandbox/commun.h"
}
filter "configurations:Debug"
defines
{
"BK_DEBUG",
"DEBUG"
}
runtime "Debug"
symbols "on"
filter "configurations:Release"
defines
{
"BK_RELEASE",
"NDEBUG"
}
runtime "Release"
optimize "on"
links
{
"bakanet"
}

@ -0,0 +1,32 @@
#include <sstream>
#include "../commun.h"
using namespace Bk::Net;
void http_client();
int main()
{
http_client();
return 0;
}
void http_client()
{
IpAddress ip("127.0.0.1");
Socket sock(ip, PORT, IpProtocol::TCP);
if(!sock.conn())
{
perror("Couldn't connect to the end point.");
exit(1);
}
Packet packet;
std::string str = "GET / HTTP/1.1 \r\n"
"Host: 127.0.0.1:10001 \r\n\r\n"
"Body jylkdkjlkjlkjlkjlkj";
packet.push<char>(str.c_str(), str.length());
sock.send(packet.payload);
}

@ -0,0 +1,12 @@
#pragma once
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>
#include <bakanet.h>
#define log(str) std::cout << str << "\n";
#define input(ref) std::cin >> ref;
#define PORT 8080

@ -0,0 +1,91 @@
#include "http_packet.h"
#include <iomanip>
HttpRequest::HttpRequest(std::string method,
std::string url,
std::string version,
HttpParams params,
std::string body)
: method(method), url(url), version(version), params(params), body(body) {}
HttpRequest::HttpRequest(std::string data)
{
log(data)
auto lines = string_split(data, "\n");
auto first_line = std::string(lines->at(0));
auto req_data = string_split(first_line, " ");
method = req_data->at(0);
url = req_data->at(1);
version = req_data->at(2);
body = std::string(lines->at(lines->size() - 1));
lines->erase(lines->begin());
lines->erase(lines->end());
int i = 0;
for (auto line : *lines)
{
log(i << "|" << line)
i++;
}
log(method << url << version)
log("BODY|" << body)
for (auto line : *lines)
{
auto param = string_split(line, ":", 1);
if (param->size() >= 2)
{
string_trim(param->at(1));
params.insert({param->at(0), param->at(1)});
}
}
for (auto pair : params)
{
log(pair.second)
}
}
std::string HttpRequest::to_string()
{
std::string request = "";
request += method + " " + url + " " + version;
std::string param_order[] =
{
"Host",
"User-Agent",
"Accept",
"Accept-Language",
"Accept-Encoding",
"Connection",
"Upgrade-Insecure-Request",
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site"
};
if (params.size()) for ( const auto& param : param_order) if (params[param].length()) request += param + ": " + params[param] + "\r\n";
request += "\r\n";
if (body.length()) request += body;
return request;
}
HttpReponse::HttpReponse(std::string status,
std::string version,
HttpParams params,
std::string body)
: status(status), version(version), params(params), body(body) {}
HttpReponse::HttpReponse(std::string data)
{
status = "";
version = "";
body = "";
}
std::string HttpReponse::to_string()
{
std::string reponse = "";
reponse = version + " " + status + " \r\n";
if (params.size()) for ( const auto& pair : params) reponse += pair.first + ": " + pair.second + " \r\n";
reponse += "\r\n";
if (body.length()) reponse += body;
return reponse;
}

@ -0,0 +1,44 @@
#pragma once
#include <commun.h>
#include "http_tools.h"
using HttpParams = std::unordered_map<std::string, std::string>;
class HttpRequest
{
public:
HttpRequest(std::string method,
std::string url,
std::string version,
HttpParams params,
std::string body);
HttpRequest(std::string data);
std::string to_string();
std::string method;
std::string url;
std::string version;
HttpParams params;
std::string body;
};
class HttpReponse
{
public:
HttpReponse(std::string status,
std::string version,
HttpParams params,
std::string body);
HttpReponse(std::string data);
std::string to_string();
std::string status;
std::string version;
HttpParams params;
std::string body;
};

@ -0,0 +1,38 @@
#include "http_server.h"
void http_server()
{
IpAddress ip("127.0.0.1");
Socket sock(ip, PORT, IpProtocol::TCP);
bool running = sock.init() && sock.start(5);
char input = 'n';
do
{
Connection conn = sock.ack();
if (conn >= 0)
{
log("New Conn")
std::string http_request(http_handler(sock, conn));
if (http_request == "") continue;
HttpRequest req(http_request);
log("to string")
log(req.to_string())
close(conn);
}
log("Close?")
input(input);
} while (input != 'y');
}
std::string http_handler(Socket& sock, Connection conn)
{
Packet req;
while(req.append_data(sock.recv(conn, 4)));
int req_size = req.size();
std::unique_ptr<char[]> req_test = req.pull<char>(req_size);
if (req_size) return std::string(req_test.release(), req_size);
return "";
}

@ -0,0 +1,8 @@
#pragma once
#include <commun.h>
#include "http_packet.h"
using namespace Bk::Net;
void http_server();
std::string http_handler(Socket& sock, Connection conn);

@ -0,0 +1,43 @@
#include "http_tools.h"
std::string string_to_lower(std::string& str)
{
for (int i = 0; i < str.length(); i++)
{
str[i] = std::tolower(str[i]);
}
return str;
}
std::string string_to_upper(std::string& str)
{
for (int i = 0; i < str.length(); i++)
{
str[i] = std::toupper(str[i]);
}
return str;
}
std::unique_ptr<std::vector<std::string>> string_split(std::string& str, std::string delimiter, int cpt)
{
std::string s(str);
std::unique_ptr<std::vector<std::string>> splits(new std::vector<std::string>(0));
size_t pos = 0;
while (((pos = s.find(delimiter)) != std::string::npos) && cpt-- != 0)
{
splits->push_back(s.substr(0, pos));
s.erase(0, pos + delimiter.length());
}
if (s.length()) splits->push_back(s);
return splits;
}
void string_trim(std::string& str, const std::string& whitespace)
{
const auto strBegin = str.find_first_not_of(whitespace);
const auto strEnd = str.find_last_not_of(whitespace);
if (strBegin != std::string::npos)
{
str.erase(0, strBegin);
}
}

@ -0,0 +1,9 @@
#pragma once
#include <cstring>
#include <commun.h>
std::string string_to_lower(std::string& str);
std::string string_to_upper(std::string& str);
std::unique_ptr<std::vector<std::string>> string_split(std::string& str, std::string delimiter, int cpt = -1);
void string_trim(std::string& str, const std::string& whitespace = " \b\0");

@ -0,0 +1,11 @@
#include "commun.h"
#include "http/http_server.h"
int main()
{
http_server();
return 0;
}

@ -1,15 +0,0 @@
#pragma once
#include <bakanet/core/ip_address.h>
#include <bakanet/core/socket.h>
#if defined(BK_PLATFORM_WINDOWS)
#include <platform/windows/windows_socket.h>
#elif defined(BK_PLATFORM_LINUX)
#include <platform/linux/linux_socket.h>
#else
#error "Plaform not supported"
#endif
#include <bakanet/core/dns_lookup.h>
#include <bakanet/http/server.h>

@ -1,9 +0,0 @@
#pragma once
#include <bakanetpch.h>
#include "ip_version.h"
#include "ip_address.h"
namespace Bk::Net {
std::vector<std::string> dns_lookup(const std::string& host_name, IpVersion ipv);
}

@ -1,17 +0,0 @@
#pragma once
#include <bakanetpch.h>
#include "ip_version.h"
namespace Bk::Net {
class IpAddress
{
public:
IpAddress(std::string ip = "", IpVersion ipv = IpVersion::IPv4)
: str(ip), version(ipv) { }
struct in_addr get_data();
std::string str;
IpVersion version;
};
}

@ -1,37 +0,0 @@
#pragma once
#include <bakanetpch.h>
#include "ip_address.h"
#include "ip_protocol.h"
#include "socket_options.h"
namespace Bk::Net {
using Connection = int;
class Socket
{
public:
virtual ~Socket() {}
virtual bool init() = 0;
virtual bool start(int cpt_conn) = 0;
virtual Socket* ack() = 0;
virtual bool conn() = 0;
virtual bool isConnected() = 0;
virtual int get_raw_socket() = 0;
virtual const std::string get_ip() = 0;
virtual void emit(std::vector<char> packet) = 0;
virtual std::vector<char> obtain(int size) = 0;
template<typename T>
static bool set_option(Socket& socket, OptionLayer level, SocketOption option_name, const T* option_value) { return setsockopt(socket.get_raw_socket(), (int)level, (int)option_name, (void*)option_value, sizeof(T)) == 0 ? true : false; }
static Socket* create(IpAddress ip, int port, IpProtocol proto);
protected:
static Socket* create(int id, IpVersion ver, IpProtocol proto);
};
}

@ -1,30 +0,0 @@
#include <bakanetpch.h>
namespace Bk::Net {
enum class OptionLayer
{
IP = IPPROTO_IP,
IPv6 = IPPROTO_IPV6,
RawIP = IPPROTO_ICMP,
TCP = IPPROTO_TCP,
UDP = IPPROTO_UDP,
Socket = SOL_SOCKET,
};
enum class SocketOption
{
Debug = SO_DEBUG,
Broadcast = SO_BROADCAST,
ReuseAddr = SO_REUSEADDR,
KeepAlive = SO_KEEPALIVE,
Linger = SO_LINGER,
OutOfBandInline = SO_OOBINLINE,
SendBuffer = SO_SNDBUF,
ReceiveBuffer = SO_RCVBUF,
DontRoute = SO_DONTROUTE,
ReceiveMin = SO_RCVLOWAT,
ReceiveTimeOut = SO_RCVTIMEO,
SendMin = SO_SNDLOWAT,
SendTimeOut = SO_SNDTIMEO,
};
}

@ -1,73 +0,0 @@
#include "packet.h"
namespace Bk::Net {
HttpRequest::HttpRequest(std::string method,
std::string url,
std::string version,
HttpParams params,
std::string body)
: method(method), url(url), version(version), params(params), body(body) {}
HttpRequest::HttpRequest(std::string data)
{
auto lines = Tools::string_split(data, "\n");
auto req_data = Tools::string_split(lines->at(0), " ");
if(req_data->size() > 0) method = req_data->at(0);
if(req_data->size() > 1) url = req_data->at(1);
if(req_data->size() > 2) version = req_data->at(2);
lines->erase(lines->begin());
for (auto line = lines->begin(); line != lines->end(); line++)
{
if (*line != "\r")
{
auto param = Tools::string_split(*line, ":", 1);
if (param->size() >= 2)
{
Tools::string_trim(param->at(1));
params.insert({param->at(0), param->at(1)});
}
}
else
{
for (auto body_line = ++line; body_line != lines->end(); body_line++)
body += *body_line + "\n";
break;
}
}
}
std::string HttpRequest::to_string()
{
std::string request = "";
request += method + " " + url + " " + version + "\r\n";
if (params.size()) for ( const auto& param : params) request += param.first + ": " + param.second + "\r\n";
request += "\r\n";
if (body.length()) request += body;
return request;
}
HttpReponse::HttpReponse(std::string status,
std::string version,
HttpParams params,
std::string body)
: status(status), version(version), params(params), body(body) {}
HttpReponse::HttpReponse(std::string data)
{
//To do
status = "";
version = "";
params = HttpParams(0);
body = "";
}
std::string HttpReponse::to_string()
{
std::string reponse = "";
reponse = version + " " + status + " \r\n";
if (params.size()) for ( const auto& pair : params) reponse += pair.first + ": " + pair.second + " \r\n";
reponse += "\r\n";
if (body.length()) reponse += body;
return reponse;
}
}

@ -1,60 +0,0 @@
#pragma once
#include <bakanetpch.h>
#define HTTP_RES_200 "200 OK"
#define HTTP_RES_303 "303 See Other"
#define HTTP_RES_400 "400 Bad Request"
#define HTTP_RES_401 "401 Unauthorized"
#define HTTP_RES_402 "402 Payment Required"
#define HTTP_RES_403 "403 Forbidden"
#define HTTP_RES_404 "404 Not Found"
#define HTTP_RES_405 "405 Method Not Allowed"
#define HTTP_RES_406 "406 Not Acceptable"
#define HTTP_RES_408 "408 Request Timeout"
#define HTTPv1_1 "HTTP/1.1"
namespace Bk::Net {
using HttpParams = std::unordered_map<std::string, std::string>;
class HttpRequest
{
public:
HttpRequest(std::string method,
std::string url,
std::string version,
HttpParams params = HttpParams(0),
std::string body = "");
HttpRequest(std::string data);
std::string to_string();
std::string method;
std::string url;
std::string version;
HttpParams params;
std::string body;
};
class HttpReponse
{
public:
HttpReponse(std::string status,
std::string version,
HttpParams params = HttpParams(0),
std::string body = "");
HttpReponse(std::string data);
std::string to_string();
std::string status;
std::string version;
HttpParams params;
std::string body;
};
}

@ -1,98 +0,0 @@
#include "server.h"
namespace Bk::Net {
HttpServer::HttpServer(IpAddress ip, int port)
{
socket = Socket::create(ip, port, IpProtocol::TCP);
radix = RadixTree();
}
HttpServer::~HttpServer()
{
delete socket;
}
void HttpServer::start()
{
bool running = socket->init() && socket->start(5);
while (running)
{
Socket* conn = socket->ack();
pool.queue([this, conn]()
{
route_request(conn, recv_request(conn));
delete conn;
});
}
pool.stop();
}
void HttpServer::get(std::string url, RequestHandler req_handler)
{
RadixTree* tree;
Tools::string_trim(url, " /");
auto splits = Tools::string_split(url, "/");
if ((tree = radix.get_node(splits->data(), splits->size()))) tree->value["GET"] = req_handler;
else radix.add_nodes(splits->data(), splits->size(), HttpMethodArray({{ "GET", req_handler }}));
}
void HttpServer::post(std::string url, RequestHandler req_handler)
{
RadixTree* tree;
Tools::string_trim(url, " /");
auto splits = Tools::string_split(url, "/");
if ((tree = radix.get_node(splits->data(), splits->size()))) tree->value["POST"] = req_handler;
else radix.add_nodes(splits->data(), splits->size(), HttpMethodArray({{ "POST", req_handler }}));
}
void HttpServer::del(std::string url, RequestHandler req_handler)
{
RadixTree* tree;
Tools::string_trim(url, " /");
auto splits = Tools::string_split(url, "/");
if ((tree = radix.get_node(splits->data(), splits->size()))) tree->value["DELETE"] = req_handler;
else radix.add_nodes(splits->data(), splits->size(), HttpMethodArray({{ "DELETE", req_handler }}));
}
void HttpServer::put(std::string url, RequestHandler req_handler)
{
RadixTree* tree;
Tools::string_trim(url, " /");
auto splits = Tools::string_split(url, "/");
if ((tree = radix.get_node(splits->data(), splits->size()))) tree->value["PUT"] = req_handler;
else radix.add_nodes(splits->data(), splits->size(), HttpMethodArray({{ "PUT", req_handler }}));
}
HttpRequest HttpServer::recv_request(Socket* conn)
{
Type::DataStream req;
std::vector<char> data;
do
{
data = conn->obtain(1024);
req.append_data(data);
} while(data.size() >= 1024);
int req_size = req.size();
if (req_size) return HttpRequest(std::string(req.pull<char>(req_size).release(), req_size));
return HttpRequest("", "", "");
}
void HttpServer::send_reponse(Socket* conn, HttpReponse res)
{
Type::DataStream res_packet;
std::string str_res = res.to_string();
res_packet.push<char>(str_res.c_str(), str_res.length());
conn->emit(res_packet.payload);
}
void HttpServer::route_request(Socket* conn, HttpRequest req)
{
std::string url = std::string(req.url);
Tools::string_trim(url, " /");
Tools::string_to_upper(req.method);
auto urls = Tools::string_split(url, "/");
auto handlers = radix.get_node(urls->data(), urls->size());
if (handlers && (handlers->value.find(req.method) != handlers->value.end())) { send_reponse(conn, handlers->value[req.method](req)); }
else send_reponse(conn, HttpReponse(HTTP_RES_404, "HTTP/1.1"));
}
}

@ -1,34 +0,0 @@
#pragma once
#include <bakanetpch.h>
#include <bakanet/core/ip_address.h>
#include <bakatools/thread/task_pool.h>
#include <bakanet/core/socket.h>
#include "packet.h"
namespace Bk::Net {
using RequestHandler = std::function<HttpReponse(HttpRequest& req)>;
using HttpMethodArray = std::unordered_map<std::string, RequestHandler>;
using RadixTree = Type::Trie<std::string, HttpMethodArray>;
class HttpServer
{
public:
HttpServer(IpAddress ip, int port);
~HttpServer();
void start();
void get(std::string url, RequestHandler req_handler);
void post(std::string url, RequestHandler req_handler);
void del(std::string url, RequestHandler req_handler);
void put(std::string url, RequestHandler req_handler);
private:
Socket* socket;
ThreadPool pool;
RadixTree radix;
HttpRequest recv_request(Socket* conn);
void send_reponse(Socket* conn, HttpReponse res);
void route_request(Socket* conn, HttpRequest req);
};
}

@ -1,33 +0,0 @@
#pragma once
#include <iostream>
#include <cstring>
#include <vector>
#include <string>
#include <exception>
#include <memory>
#include <cstdint>
#include <cctype>
#include <unordered_map>
#include <functional>
#include <thread>
#include <iterator>
#include <bakatools.h>
#if defined(BK_PLATFORM_WINDOWS)
#include <ws2tcpip.h>
#include <winsock2.h>
#include <tchar.h>
#pragma comment(lib,"WS2_32.lib")
#elif defined(BK_PLATFORM_LINUX)
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/time.h>
#else
#error "Plaform not supported"
#endif

@ -1,13 +0,0 @@
#include <bakanet/core/ip_address.h>
namespace Bk::Net {
struct in_addr IpAddress::get_data()
{
struct in_addr addr;
if (!str.length()) {
addr.s_addr = INADDR_ANY;
return addr;
}
else if (inet_pton(AF_INET, str.c_str(), &addr) <= 0) BK_CORE_ERROR("IP processing failed ({0})", str);
return addr;
}
}

@ -1,104 +0,0 @@
#include "linux_socket.h"
#include <cstddef>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
namespace Bk::Net {
LinuxSocket::LinuxSocket(int id, struct sockaddr_in client_addr, IpVersion ver, IpProtocol proto)
: id(id), ip_proto(proto), addr(client_addr)
{
char* myIP = inet_ntoa(addr.sin_addr);
ip_addr = IpAddress(std::string(myIP), ver);
}
LinuxSocket::LinuxSocket(IpAddress ip, int port, IpProtocol proto)
: ip_addr(ip), ip_proto(proto)
{
//LinuxSocket creation step
if ((id = socket((int)ip_addr.version, (int)ip_proto, 0)) < 0)
{
BK_CORE_ERROR("Socket failed");
exit(EXIT_FAILURE);
}
addr.sin_addr = ip_addr.get_data();
addr.sin_family = (int)ip_addr.version;
addr.sin_port = htons(port);
}
LinuxSocket::~LinuxSocket()
{
if(id > 0) close(id);
}
bool LinuxSocket::init()
{
//Binding step
int status;
if ((status = bind(id, (struct sockaddr*)&addr, sizeof(addr)) < 0))
{
BK_CORE_ERROR("Binding failed");
return false;
}
return true;
}
bool LinuxSocket::start(int cpt_conn)
{
//Listening step
if (listen(id, cpt_conn) < 0)
{
BK_CORE_ERROR("Listening failed");
return false;
}
return true;
}
Socket* LinuxSocket::ack()
{
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
return new LinuxSocket(accept(id, (struct sockaddr*)&client_addr, &addrlen), client_addr, ip_addr.version, ip_proto);
}
bool LinuxSocket::conn()
{
if (connect(id, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
BK_CORE_ERROR("Connection failed");
return false;
}
return true;
}
bool LinuxSocket::isConnected()
{
char data = 0;
int read_size = recv(id, &data, 1, MSG_PEEK);
return (bool)read_size;
}
void LinuxSocket::emit(std::vector<char> packet)
{
size_t size = send(id, packet.data(), packet.size(), 0);
}
std::vector<char> LinuxSocket::obtain(int size)
{
if(size > this->size)
{
delete [] buffer;
buffer = new char[size];
this->size = size;
}
int read_size = recv(id, buffer, this->size - 1, 0);
if(read_size == -1) return std::vector<char>(0);
std::vector<char> packet(buffer, buffer + read_size);
return packet;
}
Socket* Socket::create(IpAddress ip, int port, IpProtocol proto)
{
return new LinuxSocket(ip, port, proto);
}
}

@ -1,35 +0,0 @@
#pragma once
#include <bakatools.h>
#include <bakanet/core/socket.h>
namespace Bk::Net {
class LinuxSocket : public Socket
{
public:
LinuxSocket(IpAddress ip, int port, IpProtocol proto);
LinuxSocket(int id, struct sockaddr_in client_addr, IpVersion ver, IpProtocol proto);
virtual ~LinuxSocket();
bool init() override;
bool start(int cpt_conn) override;
Socket* ack() override;
bool conn() override;
bool isConnected() override;
int get_raw_socket() override { return id; }
const std::string get_ip() override { return ip_addr.str; }
void emit(std::vector<char> packet) override;
std::vector<char> obtain(int size) override;
private:
Connection id;
int size = 1024;
char* buffer = new char[size];
struct sockaddr_in addr;
IpAddress ip_addr;
IpProtocol ip_proto;
};
}

@ -1,40 +0,0 @@
#include <bakanet/core/dns_lookup.h>
namespace Bk::Net {
std::vector<std::string> dns_lookup(const std::string& host_name, IpVersion ipv)
{
std::vector<std::string> output;
struct addrinfo hints, *res, *p;
char ip_address[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = (int)ipv;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host_name.c_str(), NULL, &hints, &res) != 0)
{
output.push_back("");
return output;
}
for (p = res;p != NULL; p = p->ai_next)
{
void* addr;
if (p->ai_family == AF_INET)
{
struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else
{
struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
inet_ntop(p->ai_family, addr, ip_address, sizeof ip_address);
output.push_back(ip_address);
}
freeaddrinfo(res); // free the linked list
return output;
}
}

@ -1,16 +0,0 @@
#include <bakanet/core/ip_address.h>
#include <string.h>
namespace Bk::Net {
struct in_addr IpAddress::get_data()
{
struct in_addr addr;
if (!str.length()) {
addr.s_addr = INADDR_ANY;
return addr;
}
int result = InetPtonW(AF_INET, std::wstring(str.begin(), str.end()).c_str(), &addr);
if (result <= 0) BK_CORE_ERROR("Bad IP {0}", result);
return addr;
}
}

@ -1,107 +0,0 @@
#include "windows_socket.h"
#include <iostream>
namespace Bk::Net {
int WindowsSocket::socket_count = 0;
WindowsSocket::WindowsSocket(int id, IpVersion ver, IpProtocol proto)
: id(id), ip_proto(proto), main(false)
{
char myIP[16] = " ";
socklen_t len = sizeof(addr);
getsockname(id, (struct sockaddr*)&addr, &len);
inet_ntop((int)ver, &addr, myIP, sizeof(myIP));
ip_addr = IpAddress(std::string(myIP, 16), ver);
}
WindowsSocket::WindowsSocket(IpAddress ip, int port, IpProtocol proto)
: ip_addr(ip), ip_proto(proto), main(true)
{
if (socket_count++ < 1)
{
WSADATA wsa_data;
int err;
err = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (err != 0)
{
BK_CORE_TRACE("WSA failed : {0}", WSAGetLastError());
WSACleanup();
exit(EXIT_FAILURE);
}
}
//WindowsSocket creation step
if ((id = (int)socket((int)ip_addr.version, (int)ip_proto, 0)) < 0)
{
BK_CORE_TRACE("Socket failed : {0}", WSAGetLastError());
exit(EXIT_FAILURE);
}
addr.sin_addr = ip_addr.get_data();
addr.sin_family = (int)ip_addr.version;
addr.sin_port = htons(port);
}
WindowsSocket::~WindowsSocket()
{
if (main && socket_count-- < 1) WSACleanup();
closesocket(id);
}
bool WindowsSocket::init()
{
//Binding step
int status;
if ((status = bind((SOCKET)id, (struct sockaddr*)&addr, sizeof(addr)) < 0))
{
BK_CORE_TRACE("Binding failed : {0}", WSAGetLastError());
return false;
}
return true;
}
bool WindowsSocket::start(int cpt_conn = SOMAXCONN)
{
//Listening step
if (listen(id, cpt_conn) == SOCKET_ERROR) { BK_CORE_TRACE("Listening failed : {0}", WSAGetLastError()); return false; }
return true;
}
Socket* WindowsSocket::ack()
{
socklen_t addrlen = sizeof(addr);
return new WindowsSocket(accept((SOCKET)id, (struct sockaddr*)&addr, &addrlen), ip_addr.version, ip_proto));
}
bool WindowsSocket::conn()
{
if (connect(id, (struct sockaddr*)&addr, sizeof(addr)) < 0) { return false; }
return true;
}
bool WindowsSocket::hasConnection(int seconds, int microseconds) {
struct timeval tv = { seconds, microseconds };
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(id, &rfds);
return select(id + 1, &rfds, (fd_set*)0, (fd_set*)0, &tv) > 0;
};
void WindowsSocket::emit(std::vector<char> packet)
{
send((SOCKET)id, packet.data(), packet.size(), 0);
}
std::vector<char> WindowsSocket::obtain(int size)
{
std::vector<char> buffer;
buffer.resize(size);
int read_size = recv((SOCKET)id, buffer.data(), buffer.size() - 1, 0);
buffer.resize(read_size);
return buffer;
}
Socket* Socket::create(IpAddress ip, int port, IpProtocol proto)
{
return new WindowsSocket(ip, port, proto);
}
}

@ -1,34 +0,0 @@
#pragma once
#include <bakanet/core/socket.h>
namespace Bk::Net {
class WindowsSocket : public Socket
{
public:
static int socket_count;
WindowsSocket(IpAddress ip, int port, IpProtocol proto);
WindowsSocket(int id, IpVersion ver, IpProtocol proto);
virtual ~WindowsSocket();
bool init() override;
bool start(int cpt_conn) override;
Socket* ack() override;
bool conn() override;
bool hasConnection(int seconds = 0, int microseconds = 0) override;
int get_raw_socket() override { return id; }
const std::string get_ip() override { return ip_addr.str; }
void emit(std::vector<char> packet) override;
std::vector<char> obtain(int size) override;
private:
Connection id;
struct sockaddr_in addr;
IpAddress ip_addr;
IpProtocol ip_proto;
bool main;
};
}
Loading…
Cancel
Save