3 #include <sys/socket.h>
4 #include <netinet/in.h>
8 #include <openssl/ssl.h>
9 #include <openssl/err.h>
16 Link::Server::Server() {
18 this->multiThreaded
= true;
19 this->sslEnabled
= false;
20 this->debugging
= false;
23 Link::Server
* Link::Server::EnableDebugging() {
24 this->debugging
= true;
28 bool Link::Server::IsDebugging() {
29 return this->debugging
;
32 Link::Server::Server(int port
) {
34 this->multiThreaded
= true;
35 this->sslEnabled
= false;
36 this->debugging
= false;
39 Link::Server
* Link::Server::SetPort(int port
) {
41 this->multiThreaded
= true;
42 this->sslEnabled
= false;
46 Link::Server
* Link::Server::EnableMultiThreading() {
47 this->multiThreaded
= true;
51 Link::Server
* Link::Server::Stop() {
52 this->running
= false;
56 Link::Server
* Link::Server::DisableMultiThreading() {
57 this->multiThreaded
= false;
61 Link::Server
* Link::Server::EnableSSL(std::string certPath
, std::string keyPath
) {
62 this->sslEnabled
= true;
63 this->certPath
= certPath
;
64 this->keyPath
= keyPath
;
66 SSLeay_add_ssl_algorithms();
67 SSL_load_error_strings();
68 SSL_CTX
* ctx
= SSL_CTX_new(TLS_server_method());
70 std::cout
<< "SSL_CTX_new failed" << std::endl
;
73 SSL_CTX_set_ecdh_auto(ctx
, 1);
74 if (SSL_CTX_use_certificate_file(ctx
, this->certPath
.c_str(), SSL_FILETYPE_PEM
) <= 0) {
75 std::cout
<< "SSL_CTX_use_certificate_file failed" << std::endl
;
78 if (SSL_CTX_use_PrivateKey_file(ctx
, this->keyPath
.c_str(), SSL_FILETYPE_PEM
) <= 0) {
79 std::cout
<< "SSL_CTX_use_PrivateKey_file failed" << std::endl
;
86 bool Link::Server::IsRunning() {
90 bool Link::Server::IsMultiThreaded() {
91 return this->multiThreaded
;
94 bool Link::Server::IsSSL() {
95 return this->sslEnabled
;
98 int Link::Server::GetPort() {
103 Link::Thread
* thread
;
106 void HandlerWrapper(void* raw
) {
107 HandlerArgs
* args
= (HandlerArgs
*) raw
;
108 Link::Thread
* thread
= args
->thread
;
112 Link::Server
* Link::Server::Get(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
113 std::vector
<std::string
> key
= {"GET", path
};
114 this->callbacks
[key
] = callback
;
118 Link::Server
* Link::Server::Post(std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
119 std::vector
<std::string
> key
= {"POST", path
};
120 this->callbacks
[key
] = callback
;
124 Link::Server
* Link::Server::Route(std::string method
, std::string path
, std::function
<void(Request
*, Response
*)> callback
) {
125 std::vector
<std::string
> key
= {method
, path
};
126 this->callbacks
[key
] = callback
;
130 Link::Server
* Link::Server::Error(int code
, std::function
<void(Request
*, Response
*)> callback
) {
131 this->errors
[code
] = callback
;
135 std::map
<int, std::function
<void(Link::Request
*, Link::Response
*)>> Link::Server::GetErrors() {
139 std::map
<std::vector
<std::string
>, std::function
<void(Link::Request
*, Link::Response
*)>> Link::Server::GetCallbacks() {
140 return this->callbacks
;
143 Link::Server
* Link::Server::SetStaticPages(std::string path
) {
144 this->staticPages
= path
;
148 std::string
Link::Server::GetStaticPagesDirectory() {
149 return this->staticPages
;
152 std::vector
<std::string
> Link::Server::GetStaticPages() {
153 if (this->staticPages
== "" || !std::filesystem::exists(this->staticPages
)) return std::vector
<std::string
>();
154 std::vector
<std::string
> pages
;
155 for (std::filesystem::recursive_directory_iterator
i(staticPages
), end
; i
!= end
; ++i
)
156 if (!std::filesystem::is_directory(i
->path())) {
157 pages
.push_back(i
->path().parent_path().string()+'/'+i
->path().filename().string());
162 Link::Server
* Link::Server::SetStartMessage(std::string msg
) {
163 this->startMessage
= msg
;
167 Link::Server
* Link::Server::Start() {
169 if (this->port
== 0) port
= sslEnabled
? 443 : 80;
171 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
173 if (setsockopt(this->sock
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) < 0) return this;
176 perror("Socket error");
180 struct sockaddr_in server
;
181 server
.sin_family
= AF_INET
;
182 server
.sin_addr
.s_addr
= INADDR_ANY
;
183 server
.sin_port
= htons(this->port
);
185 if (bind(sock
, (struct sockaddr
*) &server
, sizeof(server
)) < 0) {
186 perror("Bind error");
190 if (listen(sock
, 128) < 0) {
191 perror("Listen error");
195 if (startMessage
.length() > 0) std::cout
<< startMessage
<< std::endl
;
197 while (this->running
) {
198 struct sockaddr_in client
;
199 socklen_t clientLen
= sizeof(client
);
200 int clientSock
= accept(sock
, (struct sockaddr
*) &client
, &clientLen
);
201 if (clientSock
< 0) {
202 perror("Accept error");
207 bool ClientSSL
= false;
211 int bytes
= recv(clientSock
, buffer
, sizeof(buffer
), MSG_PEEK
);
212 if (buffer
[0] == '\x16') {
213 ssl
= (SSL
*) malloc(sizeof(SSL
*));
215 SSL_set_mode(ssl
, SSL_MODE_AUTO_RETRY
);
216 if (SSL_set_fd(ssl
, clientSock
) <= 0) {
217 printf("ERROR: could not set SSL file descriptor\n");
219 int ret
= SSL_accept(ssl
);
221 // int err = SSL_get_error(ssl, ret);
222 // printf("ERROR: could not accept SSL connection: %d\n", err);
233 if (this->multiThreaded
) {
235 std::string ip
= inet_ntoa(client
.sin_addr
);
237 if (ClientSSL
&&sslEnabled
) {
238 t
= Link::Thread(this, ssl
, ClientSSL
);
241 t
= Link::Thread(this, clientSock
, ClientSSL
);
245 HandlerArgs
* args
= new HandlerArgs();
247 pthread_create(&thread
, NULL
, (void* (*)(void*)) HandlerWrapper
, (void*) args
);
248 pthread_join(thread
, NULL
);
250 std::string ip
= inet_ntoa(client
.sin_addr
);
252 Link::Thread
thread(this, ssl
, ClientSSL
);
256 Link::Thread
thread(this, clientSock
, ClientSSL
);
262 if (sslEnabled
&&ClientSSL
) {
271 shutdown(sock
, SHUT_RDWR
);