Compare commits
25 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
7ccbc81ea4 | ago%!(EXTRA string=2 years) |
|
|
8fdd4be2ac | ago%!(EXTRA string=2 years) |
|
|
750f8002e9 | ago%!(EXTRA string=2 years) |
|
|
a47ef015af | ago%!(EXTRA string=2 years) |
|
|
705a8875ba | ago%!(EXTRA string=2 years) |
|
|
ac99458453 | ago%!(EXTRA string=2 years) |
|
|
3e33fd9729 | ago%!(EXTRA string=2 years) |
|
|
644fada095 | ago%!(EXTRA string=2 years) |
|
|
0884bcaf1c | ago%!(EXTRA string=2 years) |
|
|
71c558d7bf | ago%!(EXTRA string=2 years) |
|
|
0ad9bedec5 | ago%!(EXTRA string=2 years) |
|
|
7a0ef3aca8 | ago%!(EXTRA string=2 years) |
|
|
8195ab166b | ago%!(EXTRA string=2 years) |
|
|
f384c3fbb3 | ago%!(EXTRA string=2 years) |
|
|
05855a2d50 | ago%!(EXTRA string=2 years) |
|
|
9534946adf | ago%!(EXTRA string=2 years) |
|
|
5656e1ddd7 | ago%!(EXTRA string=2 years) |
|
|
0196d77f1e | ago%!(EXTRA string=2 years) |
|
|
9c0f3563a5 | ago%!(EXTRA string=2 years) |
|
|
0f69d3d862 | ago%!(EXTRA string=2 years) |
|
|
7958c9eace | ago%!(EXTRA string=2 years) |
|
|
da0d4cc766 | ago%!(EXTRA string=2 years) |
|
|
afdcfdc9a8 | ago%!(EXTRA string=2 years) |
|
|
652ee8138c | ago%!(EXTRA string=2 years) |
|
|
b5fae8b6e9 | ago%!(EXTRA string=2 years) |
44 changed files with 632 additions and 865 deletions
@ -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 { |
namespace Bk::Net { |
||||||
std::vector<std::string> dns_lookup(const std::string &host_name, IpVersion ipv) |
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 |
#pragma once |
||||||
|
|
||||||
#include <bakanetpch.h> |
#include <sys/socket.h> |
||||||
|
|
||||||
namespace Bk::Net { |
namespace Bk::Net { |
||||||
enum class IpProtocol
|
enum class IpProtocol
|
||||||
{ |
{ |
||||||
TCP = SOCK_STREAM, |
TCP = SOCK_STREAM, |
||||||
UCP = SOCK_DGRAM, |
UCP, |
||||||
}; |
}; |
||||||
} |
} |
||||||
@ -1,9 +1,11 @@ |
|||||||
#pragma once |
#pragma once |
||||||
|
|
||||||
|
#include <sys/socket.h> |
||||||
|
|
||||||
namespace Bk::Net { |
namespace Bk::Net { |
||||||
enum class IpVersion |
enum class IpVersion |
||||||
{ |
{ |
||||||
UNSPEC = AF_UNSPEC, |
UnSpec = AF_UNSPEC, |
||||||
IPv4 = AF_INET, |
IPv4 = AF_INET, |
||||||
IPv6 = AF_INET6, |
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" |
project "bakanet" |
||||||
|
location "./bakanet" |
||||||
kind "StaticLib" |
kind "StaticLib" |
||||||
language "C++" |
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" |
systemversion "latest" |
||||||
staticruntime "on" |
|
||||||
|
|
||||||
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}") |
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}") |
||||||
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}") |
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}") |
||||||
|
|
||||||
includedirs |
includedirs |
||||||
{ |
{ |
||||||
"%{IncludeDirs.spdlog}", |
|
||||||
"%{IncludeDirs.bakanet}", |
"%{IncludeDirs.bakanet}", |
||||||
"%{IncludeDirs.bakatools}" |
"./sandbox/" |
||||||
} |
} |
||||||
|
|
||||||
files |
files |
||||||
{ |
{ |
||||||
"%{prj.location}/src/bakanet/**.h", |
"%{prj.location}/**.h", |
||||||
"%{prj.location}/src/bakanet/**.cpp", |
"%{prj.location}/**.cpp", |
||||||
"%{prj.location}/src/baknetpch.h", |
"./sandbox/commun.h" |
||||||
} |
} |
||||||
|
|
||||||
links |
links |
||||||
{ |
{ |
||||||
"bakatools" |
"bakanet" |
||||||
} |
} |
||||||
|
|
||||||
filter "system:windows" |
|
||||||
buildoptions { "/MT", "/utf-8" } |
|
||||||
defines |
project "client" |
||||||
{ |
location "./sandbox/client" |
||||||
"BK_PLATFORM_WINDOWS" |
kind "ConsoleApp" |
||||||
} |
language "C++" |
||||||
|
cppdialect "C++17" |
||||||
files |
systemversion "latest" |
||||||
{ |
|
||||||
"%{prj.location}/src/platform/windows/**.h", |
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}") |
||||||
"%{prj.location}/src/platform/windows/**.cpp", |
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}") |
||||||
} |
|
||||||
|
includedirs |
||||||
links |
{ |
||||||
{ |
"%{IncludeDirs.bakanet}" |
||||||
"WS2_32.lib" |
} |
||||||
} |
|
||||||
|
files |
||||||
filter "system:linux" |
{ |
||||||
defines |
"%{prj.location}/**.h", |
||||||
{ |
"%{prj.location}/**.cpp", |
||||||
"BK_PLATFORM_LINUX" |
"./sandbox/commun.h" |
||||||
} |
} |
||||||
|
|
||||||
files |
|
||||||
{ |
|
||||||
"%{prj.location}/src/platform/linux/**.h", |
|
||||||
"%{prj.location}/src/platform/linux/**.cpp", |
|
||||||
} |
|
||||||
|
|
||||||
filter "configurations:Debug" |
links |
||||||
defines |
{ |
||||||
{ |
"bakanet" |
||||||
"BK_DEBUG", |
} |
||||||
"DEBUG" |
|
||||||
} |
|
||||||
runtime "Debug" |
|
||||||
symbols "on" |
|
||||||
|
|
||||||
|
|
||||||
filter "configurations:Release" |
|
||||||
defines |
|
||||||
{ |
|
||||||
"BK_RELEASE", |
|
||||||
"NDEBUG" |
|
||||||
} |
|
||||||
runtime "Release" |
|
||||||
optimize "on" |
|
||||||
@ -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…
Reference in New Issue