Compare commits
3 Commits
main
...
winsock_te
Author | SHA1 | Date |
---|---|---|
|
861bbd0a4c | ago%!(EXTRA string=1 year) |
|
45aab99712 | ago%!(EXTRA string=1 year) |
|
be52ba2285 | ago%!(EXTRA string=1 year) |
34 changed files with 248 additions and 951 deletions
@ -1,10 +1,7 @@ |
||||
docs/ |
||||
**.log |
||||
bin/ |
||||
bin-int/ |
||||
.vscode/ |
||||
.vs/ |
||||
**.sln |
||||
.vs |
||||
**Makefile |
||||
**.make |
||||
**.vcxproj* |
||||
**vcxproj |
||||
**.vcxproj.filters |
||||
*sln |
||||
bin |
||||
bin-int |
@ -0,0 +1,13 @@ |
||||
project "bakanet" |
||||
kind "StaticLib" |
||||
language "C++" |
||||
cppdialect "C++17" |
||||
systemversion "latest" |
||||
|
||||
targetdir ("bin/" .. outputdir .. "/%{prj.name}") |
||||
objdir ("bin-int/" .. outputdir .. "/%{prj.name}") |
||||
|
||||
files { |
||||
"src/**.h", |
||||
"src/**.cpp" |
||||
} |
@ -0,0 +1 @@ |
||||
#pragma once |
@ -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,32 @@ |
||||
project "bakanet" |
||||
kind "StaticLib" |
||||
language "C++" |
||||
cppdialect "C++20" |
||||
systemversion "latest" |
||||
staticruntime "on" |
||||
workspace "winsock_test" |
||||
architecture "x64" |
||||
|
||||
targetdir("%{wks.location}/bin/" .. outputdir .. "/%{prj.name}") |
||||
objdir("%{wks.location}/bin-int/" .. outputdir .. "/%{prj.name}") |
||||
|
||||
includedirs |
||||
{ |
||||
"%{IncludeDirs.spdlog}", |
||||
"%{IncludeDirs.bakanet}", |
||||
"%{IncludeDirs.bakatools}" |
||||
} |
||||
|
||||
files |
||||
{ |
||||
"%{prj.location}/src/bakanet/**.h", |
||||
"%{prj.location}/src/bakanet/**.cpp", |
||||
"%{prj.location}/src/baknetpch.h", |
||||
} |
||||
|
||||
links |
||||
configurations |
||||
{ |
||||
"bakatools" |
||||
"Debug", |
||||
"Release" |
||||
} |
||||
|
||||
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", |
||||
} |
||||
|
||||
filter "configurations:Debug" |
||||
defines |
||||
{ |
||||
"BK_DEBUG", |
||||
"DEBUG" |
||||
} |
||||
runtime "Debug" |
||||
symbols "on" |
||||
|
||||
|
||||
filter "configurations:Release" |
||||
defines |
||||
{ |
||||
"BK_RELEASE", |
||||
"NDEBUG" |
||||
} |
||||
runtime "Release" |
||||
optimize "on" |
||||
-- startproject "winsock_test" |
||||
|
||||
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}" |
||||
|
||||
-- Include projects |
||||
include "bakanet" |
||||
include "sandbox/client" |
||||
include "sandbox/server" |
||||
|
||||
newaction { |
||||
trigger = "clean", |
||||
description = "Clean the build", |
||||
execute = function() |
||||
print("Cleaning...") |
||||
os.rmdir("./bin") |
||||
os.rmdir("./bin-int") |
||||
os.remove("**.sln") |
||||
os.remove("**.vcxproj") |
||||
os.remove("**.vcxproj.filters") |
||||
print("Done.") |
||||
end |
||||
} |
||||
|
@ -0,0 +1,15 @@ |
||||
project "client" |
||||
kind "ConsoleApp" |
||||
language "C++" |
||||
cppdialect "C++17" |
||||
systemversion "latest" |
||||
|
||||
targetdir ("bin/" .. outputdir .. "/%{prj.name}") |
||||
objdir ("bin-int/" .. outputdir .. "/%{prj.name}") |
||||
|
||||
files { |
||||
"src/**.h", |
||||
"src/**.cpp" |
||||
} |
||||
|
||||
links { "bakanet"} |
@ -0,0 +1,68 @@ |
||||
#include <iostream> |
||||
#include <Ws2tcpip.h> |
||||
#include <WinSock2.h> |
||||
#include <tchar.h> |
||||
|
||||
|
||||
#pragma comment(lib,"WS2_32.lib") |
||||
|
||||
int main() |
||||
{ |
||||
WSADATA wsaData; |
||||
int err; |
||||
|
||||
err = WSAStartup(MAKEWORD(2, 2), &wsaData); |
||||
|
||||
if (err != 0) |
||||
{ |
||||
std::cout << "Winsock DDL not found!" << std::endl; |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//client socket
|
||||
SOCKET sock; |
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
||||
|
||||
if (sock == INVALID_SOCKET) |
||||
{ |
||||
std::cout << "Invalid client socker: " + WSAGetLastError() << std::endl; |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//conf socket
|
||||
sockaddr_in service; |
||||
service.sin_family = AF_INET; |
||||
InetPton(AF_INET, _T("127.0.0.1"), &service.sin_addr.s_addr); |
||||
service.sin_port = htons(25580); |
||||
|
||||
//connect to serv
|
||||
if (connect(sock, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) |
||||
{ |
||||
std::cout << "Failed to connect to the server: " + WSAGetLastError() << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//send message to serv
|
||||
std::string message = "Hello server!"; |
||||
if (send(sock, message.c_str(), message.length(), 0) == SOCKET_ERROR) |
||||
{ |
||||
std::cout << "Failed to send messaage to the server: " + WSAGetLastError() << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
std::cout << "All good :)" << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
@ -0,0 +1,15 @@ |
||||
project "server" |
||||
kind "ConsoleApp" |
||||
language "C++" |
||||
cppdialect "C++17" |
||||
systemversion "latest" |
||||
|
||||
targetdir ("bin/" .. outputdir .. "/%{prj.name}") |
||||
objdir ("bin-int/" .. outputdir .. "/%{prj.name}") |
||||
|
||||
files { |
||||
"src/**.h", |
||||
"src/**.cpp" |
||||
} |
||||
|
||||
links { "bakanet"} |
@ -0,0 +1,97 @@ |
||||
#include <iostream> |
||||
#include <Ws2tcpip.h> |
||||
#include <WinSock2.h> |
||||
#include <tchar.h> |
||||
|
||||
#pragma comment(lib, "WS2_32.lib") |
||||
|
||||
int main() |
||||
{ |
||||
WSADATA wsaData; |
||||
int err; |
||||
|
||||
err = WSAStartup(MAKEWORD(2, 2), &wsaData); |
||||
|
||||
if (err != 0) |
||||
{ |
||||
std::cout << "Winsock DLL not found!" << std::endl; |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//server socket
|
||||
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
||||
|
||||
if (sock == INVALID_SOCKET) |
||||
{ |
||||
std::cout << "Invalid server socket: " << WSAGetLastError() << std::endl; |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//conf socket
|
||||
sockaddr_in service; |
||||
service.sin_family = AF_INET; |
||||
service.sin_addr.s_addr = INADDR_ANY; |
||||
service.sin_port = htons(25580); |
||||
|
||||
//bind
|
||||
if (bind(sock, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) |
||||
{ |
||||
std::cout << "Bind failed: " << WSAGetLastError() << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
//listen
|
||||
if (listen(sock, SOMAXCONN) == SOCKET_ERROR) |
||||
{ |
||||
std::cout << "Listen failed: " << WSAGetLastError() << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
std::cout << "Waiting for connection..." << std::endl; |
||||
|
||||
//Accept client socket
|
||||
SOCKET clientSocket = accept(sock, NULL, NULL); |
||||
|
||||
if (clientSocket == INVALID_SOCKET) |
||||
{ |
||||
std::cout << "Accept failed: " << WSAGetLastError() << std::endl; |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
return 0; |
||||
} |
||||
|
||||
std::cout << "Client connected" << std::endl; |
||||
|
||||
char buffer[256]; |
||||
int bytesRead; |
||||
|
||||
do |
||||
{ |
||||
bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0); |
||||
|
||||
if (bytesRead > 0)
|
||||
{ |
||||
buffer[bytesRead] = '\0'; |
||||
std::cout << buffer << std::endl; |
||||
} |
||||
|
||||
} while (bytesRead > 0); |
||||
|
||||
closesocket(clientSocket); |
||||
closesocket(sock); |
||||
WSACleanup(); |
||||
system("pause"); |
||||
|
||||
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,11 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <bakanetpch.h> |
||||
|
||||
namespace Bk::Net { |
||||
enum class IpProtocol
|
||||
{ |
||||
TCP = SOCK_STREAM, |
||||
UCP = SOCK_DGRAM, |
||||
}; |
||||
} |
@ -1,10 +0,0 @@ |
||||
#pragma once |
||||
|
||||
namespace Bk::Net { |
||||
enum class IpVersion |
||||
{ |
||||
UNSPEC = AF_UNSPEC, |
||||
IPv4 = AF_INET, |
||||
IPv6 = AF_INET6, |
||||
}; |
||||
} |
@ -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,43 +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; |
||||
int status, ai_family; |
||||
char ip_address[INET6_ADDRSTRLEN]; |
||||
|
||||
ai_family = (int)ipv; |
||||
memset(&hints, 0, sizeof hints); |
||||
hints.ai_family = ai_family;
|
||||
hints.ai_socktype = SOCK_STREAM; |
||||
|
||||
if ((status = 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,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