3 #include <sys/socket.h>
4 #include <netinet/in.h>
8 #include <openssl/ssl.h>
9 #include <openssl/err.h>
15 #ifndef FS_EXPERIMENTAL
18 #include <experimental/filesystem>
21 Link::Server::Server() {
23 this->multiThreaded
= false;
24 this->sslEnabled
= false;
25 this->debugging
= false;
29 Link::Server
* Link::Server::EnableDebugging() {
30 this->debugging
= true;
34 bool Link::Server::IsDebugging() {
35 return this->debugging
;
38 Link::Server::Server(int port
) {
40 this->multiThreaded
= false;
41 this->sslEnabled
= false;
42 this->debugging
= false;
46 Link::Server
* Link::Server::SetPort(int port
) {
51 Link::Server
* Link::Server::EnableMultiThreading() {
52 this->multiThreaded
= true;
56 Link::Server
* Link::Server::Stop() {
57 this->running
= false;
61 Link::Server
* Link::Server::Use(std::function
<void(Link::Request
*, Link::Response
*, Link::Server
*)> middleware
) {
62 this->middlewares
.push_back(middleware
);
66 std::vector
<std::function
<void(Link::Request
*, Link::Response
*, Link::Server
*)>> Link::Server::GetMiddlewares() {
67 return this->middlewares
;
70 Link::Server
* Link::Server::DisableMultiThreading() {
71 this->multiThreaded
= false;
75 Link::Server
* Link::Server::EnableSSL(std::string certPath
, std::string keyPath
) {
76 this->sslEnabled
= true;
77 this->certPath
= certPath
;
78 this->keyPath
= keyPath
;
80 SSLeay_add_ssl_algorithms();
81 SSL_load_error_strings();
82 SSL_CTX
* ctx
= SSL_CTX_new(TLS_server_method());
84 std::cout
<< "SSL_CTX_new failed" << std::endl
;
87 SSL_CTX_set_ecdh_auto(ctx
, 1);
88 if (SSL_CTX_use_certificate_file(ctx
, this->certPath
.c_str(), SSL_FILETYPE_PEM
) <= 0) {
89 std::cout
<< "SSL_CTX_use_certificate_file failed" << std::endl
;
92 if (SSL_CTX_use_PrivateKey_file(ctx
, this->keyPath
.c_str(), SSL_FILETYPE_PEM
) <= 0) {
93 std::cout
<< "SSL_CTX_use_PrivateKey_file failed" << std::endl
;
100 bool Link::Server::IsRunning() {
101 return this->running
;
104 bool Link::Server::IsMultiThreaded() {
105 return this->multiThreaded
;
108 bool Link::Server::IsSSL() {
109 return this->sslEnabled
;
112 int Link::Server::GetPort() {
117 Link::Thread
* thread
;
120 void HandlerWrapper(void* raw
) {
121 HandlerArgs
* args
= (HandlerArgs
*) raw
;
122 Link::Thread
* thread
= args
->thread
;
126 Link::Server
* Link::Server::Get(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
127 std::vector
<std::string
> key
= {"GET", path
};
128 this->callbacks
[key
] = callback
;
132 Link::Server
* Link::Server::Post(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
133 std::vector
<std::string
> key
= {"POST", path
};
134 this->callbacks
[key
] = callback
;
138 Link::Server
* Link::Server::Route(std::string method
, std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
139 std::vector
<std::string
> key
= {method
, path
};
140 this->callbacks
[key
] = callback
;
144 Link::Server
* Link::Server::Error(int code
, std::function
<void(Request
*, Response
*)> callback
) {
145 this->errors
[code
] = callback
;
149 std::map
<int, std::function
<void(Link::Request
*, Link::Response
*)>> Link::Server::GetErrors() {
153 std::map
<std::vector
<std::string
>, std::function
<void(Link::Request
*, Link::Response
*)>> Link::Server::GetCallbacks() {
154 return this->callbacks
;
157 Link::Server
* Link::Server::SetStaticPages(std::string path
) {
158 this->staticPages
= path
;
162 std::string
Link::Server::GetStaticPagesDirectory() {
163 return this->staticPages
;
166 std::vector
<std::string
> Link::Server::GetStaticPages() {
167 #ifndef FS_EXPERIMENTAL
168 if (this->staticPages
== "" || !std::filesystem::exists(this->staticPages
)) return std::vector
<std::string
>();
170 if (this->staticPages
== "" || !std::experimental::filesystem::exists(this->staticPages
)) return std::vector
<std::string
>();
172 std::vector
<std::string
> pages
;
173 #ifndef FS_EXPERIMENTAL
174 for (std::filesystem::recursive_directory_iterator
i(staticPages
), end
; i
!= end
; ++i
)
175 if (!std::filesystem::is_directory(i
->path())) {
177 for (std::experimental::filesystem::recursive_directory_iterator
i(staticPages
), end
; i
!= end
; ++i
)
178 if(!std::experimental::filesystem::is_directory(i
->path())) {
180 pages
.push_back(i
->path().parent_path().string()+'/'+i
->path().filename().string());
185 Link::Server
* Link::Server::SetStartMessage(std::string msg
) {
186 this->startMessage
= msg
;
190 Link::Server
* Link::Server::Start() {
192 if (this->port
== 0) port
= sslEnabled
? 443 : 80;
194 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
196 if (setsockopt(this->sock
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) < 0) return this;
203 struct sockaddr_in server
;
204 server
.sin_family
= AF_INET
;
205 server
.sin_addr
.s_addr
= INADDR_ANY
;
206 server
.sin_port
= htons(this->port
);
208 if (bind(sock
, (struct sockaddr
*) &server
, sizeof(server
)) < 0) {
213 if (listen(sock
, 128) < 0) {
218 if (startMessage
.length() > 0) std::cout
<< startMessage
<< std::endl
;
220 while (this->running
) {
221 struct sockaddr_in client
;
222 socklen_t clientLen
= sizeof(client
);
223 int clientSock
= accept(sock
, (struct sockaddr
*) &client
, &clientLen
);
224 if (clientSock
< 0) {
230 bool ClientSSL
= false;
234 int bytes
= recv(clientSock
, buffer
, sizeof(buffer
), MSG_PEEK
);
235 if (buffer
[0] == '\x16') {
236 ssl
= (SSL
*) malloc(sizeof(SSL
*));
238 SSL_set_mode(ssl
, SSL_MODE_AUTO_RETRY
);
239 if (SSL_set_fd(ssl
, clientSock
) <= 0) {
240 printf("ERROR: could not set SSL file descriptor\n");
242 int ret
= SSL_accept(ssl
);
244 // int err = SSL_get_error(ssl, ret);
245 // printf("ERROR: could not accept SSL connection: %d\n", err);
256 if (this->multiThreaded
) {
258 std::string ip
= inet_ntoa(client
.sin_addr
);
260 if (ClientSSL
&&sslEnabled
) {
261 t
= Link::Thread(this, ssl
, ClientSSL
);
264 t
= Link::Thread(this, clientSock
, ClientSSL
);
268 HandlerArgs
* args
= new HandlerArgs();
270 pthread_create(&thread
, NULL
, (void* (*)(void*)) HandlerWrapper
, (void*) args
);
271 pthread_join(thread
, NULL
);
273 std::string ip
= inet_ntoa(client
.sin_addr
);
275 Link::Thread
thread(this, ssl
, ClientSSL
);
279 Link::Thread
thread(this, clientSock
, ClientSSL
);
286 shutdown(sock
, SHUT_RDWR
);