#include #include #include #include #include #include void die(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); exit(1); } std::string craftHttpAnswer(); int main(int argc, char **argv) { if (argc != 2) die("Usage: %s \n", argv[0]); // Wybiera konfigurację dla serwera SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); // Ładuje klucz prywatny serwera if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) != 1) die("Loading Private Key from \"server.key\" failed\n"); // Ładuje certyfikaty if (SSL_CTX_use_certificate_chain_file(ctx, "chain.pem") != 1) die("Loading certs from \"chain.pem\" failed\n"); // Tworzy gniazdo i rozpoczyna nasłuchiwanie - zwykły kod z API gniazd int serv = socket(AF_INET, SOCK_STREAM, 0); const int one = 1; setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); sockaddr_in sa = {}; sa.sin_family = AF_INET; sa.sin_port = htons(atoi(argv[1])); if (bind(serv, (sockaddr *)&sa, sizeof(sa)) != 0) die("bind failed: %s\n", strerror(errno)); listen(serv, 1); while (1) { // przyjmuje nowe połączenie int cli = accept(serv, 0, 0); // tworzy warstwę szyfrującą i wykonuje handshake SSL *encryption_layer = SSL_new(ctx); SSL_set_fd(encryption_layer, cli); if (SSL_accept(encryption_layer) != 1) { fprintf(stderr, "TLS handshake failed!\n"); continue; } std::string answer = craftHttpAnswer(); // przesyła odpowiedź if (SSL_write(encryption_layer, answer.c_str(), answer.length()) <= 0) { fprintf(stderr, "Problems with write!\n"); continue; } // zamyka warstwę szyfrującą SSL_shutdown(encryption_layer); // zamyka gniazdo shutdown(cli, SHUT_RDWR); close(cli); SSL_free(encryption_layer); } } #include #include std::string craftHttpAnswer(void) { std::string content = std::format( "{:%Y.%m.%d %H:%M:%S}\r\n", std::chrono::system_clock::now()); return std::format( "HTTP/2 200\r\n" "content-type: text/plain\r\n" "content-length: {}\r\n" "\r\n" "{}", content.length(), content); }