From 19537a24acebc0a9a38dd81980c0e46d9cc0655c Mon Sep 17 00:00:00 2001 From: lanstat Date: Sun, 9 Apr 2023 10:05:46 -0400 Subject: [PATCH] Added ssl support --- README.md | 3 +- main.cpp | 2 +- src/Dns.cpp | 3 + src/Http.cpp | 10 +- src/Http.hpp | 1 - src/HttpsClient.cpp | 248 ++++++++++++++++++++++++++------------------ src/HttpsClient.hpp | 3 +- src/Settings.cpp | 2 + src/Settings.hpp | 1 + src/Utils.cpp | 7 +- src/Utils.hpp | 2 +- 11 files changed, 163 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index 874edc7..64fd356 100644 --- a/README.md +++ b/README.md @@ -94,5 +94,4 @@ wget http://localhost/upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg ## TODO - Add perfomance test -- Add ssl support - +- Add error handling on http external request diff --git a/main.cpp b/main.cpp index c2e5de9..fe4ee09 100644 --- a/main.cpp +++ b/main.cpp @@ -51,7 +51,7 @@ void ParserArguments(int argc, char** argv) { continue; } if (strcmp(argv[i], "-hls") == 0) { - Settings::UseCache = false; + Settings::HLSMode = true; continue; } } diff --git a/src/Dns.cpp b/src/Dns.cpp index ecff001..020ba6d 100644 --- a/src/Dns.cpp +++ b/src/Dns.cpp @@ -63,6 +63,9 @@ void Dns::AddFetchAAAARequest(struct Request *request, bool isHttps) { std::size_t pos = host.find("/"); host = host.substr(0, pos); int port = 80; + if (isHttps) { + port = 443; + } if (std::regex_match(host, ipv4_regex_)) { pos = host.find(":"); diff --git a/src/Http.cpp b/src/Http.cpp index b468bbc..637b38a 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -1,7 +1,5 @@ #include "Http.hpp" -#pragma GCC diagnostic ignored "-Wpointer-arith" - #include #include @@ -38,8 +36,7 @@ void Http::SetStream(Stream *stream) { stream_ = stream; } void Http::AddFetchDataRequest(struct Request *req) {} int Http::GetResourceType(char *header, int size) { - // return RESOURCE_TYPE_STREAMING; - return RESOURCE_TYPE_CACHE; + return Settings::HLSMode? RESOURCE_TYPE_STREAMING : RESOURCE_TYPE_CACHE; } int Http::FetchHeaderLength(char *header, int size) { @@ -54,8 +51,3 @@ int Http::FetchHeaderLength(char *header, int size) { } return offset; } - -bool Http::IsLastPacket(void *buffer, int size) { - int result = memcmp(buffer + (size - ZERO_LENGTH), zero_, sizeof(zero_)); - return result == 0; -} diff --git a/src/Http.hpp b/src/Http.hpp index c865d97..b8e4204 100644 --- a/src/Http.hpp +++ b/src/Http.hpp @@ -36,7 +36,6 @@ class Http { int GetResourceType(char *header, int size); int FetchHeaderLength(char *header, int size); - bool IsLastPacket(void *buffer, int size); private: void *zero_; }; diff --git a/src/HttpsClient.cpp b/src/HttpsClient.cpp index be5a484..48061bf 100644 --- a/src/HttpsClient.cpp +++ b/src/HttpsClient.cpp @@ -1,5 +1,7 @@ #include "HttpsClient.hpp" +#pragma GCC diagnostic ignored "-Wpointer-arith" + #include #include #include @@ -15,9 +17,8 @@ HttpsClient::HttpsClient() : Http() { OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); } -bool HttpsClient::HandleFetchRequest(struct Request *request, bool ipv4) { - /* - std::string url((char *)request->iov[0].iov_base); +bool HttpsClient::HandleFetchRequest(struct Request *inner, bool ipv4) { + std::string url((char *)inner->iov[2].iov_base); url = url.substr(1); std::size_t pos = url.find("/"); std::string host = url.substr(0, pos); @@ -25,42 +26,54 @@ bool HttpsClient::HandleFetchRequest(struct Request *request, bool ipv4) { Log(__FILE__, __LINE__) << query; - struct sockaddr_in6 *client = - (struct sockaddr_in6 *)request->iov[4].iov_base; - const SSL_METHOD *method = TLS_client_method(); SSL_CTX *ctx = SSL_CTX_new(method); if (!ctx) { Log(__FILE__, __LINE__, Log::kError) << "Error creating context ssl"; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - return 1; + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; } SSL *ssl = SSL_new(ctx); if (!ssl) { CloseSSL(-1, nullptr, ctx); Log(__FILE__, __LINE__, Log::kError) << "Error creating ssl"; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - Utils::ReleaseRequest(request); - return -1; + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; + } + + int socket_fd = -1; + int is_connected = -1; + + if (ipv4) { + struct sockaddr_in *client = (struct sockaddr_in *)inner->iov[4].iov_base; + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd > 0) { + is_connected = connect(socket_fd, (struct sockaddr *)client, + sizeof(struct sockaddr_in)); + } + } else { + struct sockaddr_in6 *client = + (struct sockaddr_in6 *)inner->iov[4].iov_base; + socket_fd = socket(AF_INET6, SOCK_STREAM, 0); + if (socket_fd > 0) { + is_connected = connect(socket_fd, (struct sockaddr *)client, + sizeof(struct sockaddr_in6)); + } } - int socket_fd = socket(AF_INET6, SOCK_STREAM, 0); if (socket_fd < 0) { - CloseSSL(-1, ssl, ctx); Log(__FILE__, __LINE__, Log::kError) << "Error creating socket"; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - Utils::ReleaseRequest(request); - return 1; + + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; } - if (connect(socket_fd, (struct sockaddr *)client, - sizeof(struct sockaddr_in6)) < 0) { + if (is_connected < 0) { CloseSSL(socket_fd, ssl, ctx); Log(__FILE__, __LINE__, Log::kError) << "Could not connect "; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - Utils::ReleaseRequest(request); - return 1; + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; } SSL_set_fd(ssl, socket_fd); @@ -68,91 +81,132 @@ bool HttpsClient::HandleFetchRequest(struct Request *request, bool ipv4) { if (err < 1) { CloseSSL(socket_fd, ssl, ctx); Log(__FILE__, __LINE__, Log::kError) << "Could not connect "; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - Utils::ReleaseRequest(request); - return 1; + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; } std::stringstream ss; ss << "GET " << query << " HTTP/1.2\r\n" << "Host: " << host << "\r\n" - << "Accept: *//*\r\n" - << "Connection: close\r\n" - << "\r\n\r\n"; + << (char *)inner->iov[3].iov_base; std::string request_data = ss.str(); if (SSL_write(ssl, request_data.c_str(), request_data.length()) < 0) { CloseSSL(socket_fd, ssl, ctx); Log(__FILE__, __LINE__, Log::kError) << "invalid socket"; - cache_->ReleaseErrorAllWaitingRequest(request, 502); - Utils::ReleaseRequest(request); - return 1; + stream_->ReleaseErrorAllWaitingRequest(inner->resource_id, 502); + return false; } - AddReadRequest(request, ssl, ctx, socket_fd); - return 0; - */ - return false; + struct Request *http = Utils::HttpsExternalRequest(inner); + http->event_type = EVENT_TYPE_HTTP_READ_HEADER; + http->client_socket = socket_fd; + http->pivot = RESOURCE_TYPE_UNDEFINED; + http->iov[0].iov_base = malloc(buffer_size_); + http->iov[0].iov_len = buffer_size_; + memset(http->iov[0].iov_base, 0, buffer_size_); + http->iov[1].iov_base = ssl; + http->iov[2].iov_base = ctx; + + struct io_uring_sqe *sqe = io_uring_get_sqe(ring_); + // io_uring_prep_read(sqe, http->client_socket, http->iov[0].iov_base, + // buffer_size_, 0); + io_uring_prep_nop(sqe); + io_uring_sqe_set_data(sqe, http); + io_uring_submit(ring_); + return true; } -void HttpsClient::AddReadRequest(struct Request *request, SSL *ssl, - SSL_CTX *context, int fd) { - // struct io_uring_sqe *sqe = io_uring_get_sqe(ring_); +int HttpsClient::ReadFromSSL(struct Request *http) { + SSL *ssl = (SSL *)http->iov[1].iov_base; + int readed = SSL_read(ssl, http->iov[0].iov_base, buffer_size_); + if (readed < 1) { + if (!ProcessError(ssl, readed)) { + return -1; + } + if (readed == 0) { + return 0; + } + } + return readed; +} + +int HttpsClient::HandleReadHeaderRequest(struct Request *http, int response) { + int readed = ReadFromSSL(http); + if (readed <= 0) { + if (readed < 0) { + stream_->ReleaseErrorAllWaitingRequest(http->resource_id, 502); + } else { + stream_->CloseStream(http->resource_id); + } + ReleaseSocket(http); + return 1; + } + + int type = GetResourceType((char *)http->iov[0].iov_base, readed); - // struct HttpRequest *http_request = new HttpRequest(); - // http_request->has_header = 0; - // std::pair item(fd, http_request); - // waiting_read_.insert(item); + if (type == RESOURCE_TYPE_CACHE) { + int header_length = + FetchHeaderLength((char *)http->iov[0].iov_base, readed); - // struct Request *auxiliar = Utils::HttpsExternalRequest(); - // auxiliar->event_type = EVENT_TYPE_HTTP_READ; - // auxiliar->client_socket = fd; - // auxiliar->iov[0].iov_base = malloc(buffer_size_); - // auxiliar->iov[0].iov_len = buffer_size_; - // auxiliar->iov[1].iov_base = ssl; - // auxiliar->iov[2].iov_base = context; + http->iov[0].iov_len = header_length; + cache_->GenerateNode(http); + + if (header_length < readed) { + cache_->AppendBuffer(http->resource_id, + http->iov[0].iov_base + header_length, + readed - header_length); + } + } else if (type == RESOURCE_TYPE_STREAMING) { + http->iov[0].iov_len = readed; + stream_->SetStreamingResource(http->resource_id, http); + } - // memset(auxiliar->iov[0].iov_base, 0, buffer_size_); + struct io_uring_sqe *sqe = io_uring_get_sqe(ring_); + http->event_type = EVENT_TYPE_HTTP_READ_CONTENT; + http->pivot = type; + io_uring_prep_nop(sqe); + io_uring_sqe_set_data(sqe, http); + io_uring_submit(ring_); - // io_uring_prep_nop(sqe); - // io_uring_sqe_set_data(sqe, auxiliar); - // io_uring_submit(ring_); + return 0; } -int HttpsClient::HandleReadData(struct Request *request, int response) { - // SSL *ssl = (SSL *)request->iov[1].iov_base; - // int err = SSL_read(ssl, request->iov[0].iov_base, buffer_size_); - // if (err < 1) { - // if (!ProcessError(ssl, err)) { - // struct HttpRequest *http_request = - // waiting_read_.at(request->client_socket); - ////TODO(lanstat): verify when is finished - ////cache_->ReleaseErrorAllWaitingRequest(http_request->request, 502); - // ReleaseSocket(request); - // return 1; - //} - //} - - // struct HttpRequest *http_request = - // waiting_read_.at(request->client_socket); int readed = - // FetchHeader(request->iov[0].iov_base); Log(__FILE__, __LINE__, - // Log::kDebug) << "bytes readed: " << readed; if (readed <= 0) { struct - // Request *client_request = UnifyBuffer(request); ReleaseSocket(request); - // cache_->AddWriteRequest(client_request); - // return 1; - //} else { - // struct iovec data; - // data.iov_base = malloc(readed); - // data.iov_len = readed; - // memcpy(data.iov_base, request->iov[0].iov_base, readed); - //} - - // memset(request->iov[0].iov_base, 0, buffer_size_); - - // struct io_uring_sqe *sqe = io_uring_get_sqe(ring_); - // io_uring_prep_nop(sqe); - // io_uring_sqe_set_data(sqe, request); - // io_uring_submit(ring_); +int HttpsClient::HandleReadData(struct Request *http, int response) { + int type = http->pivot; + int readed = ReadFromSSL(http); + if (readed <= 0) { + if (readed < 0) { + stream_->ReleaseErrorAllWaitingRequest(http->resource_id, 502); + } else { + if (type == RESOURCE_TYPE_CACHE) { + cache_->CloseBuffer(http->resource_id); + } else if (type == RESOURCE_TYPE_STREAMING) { + stream_->CloseStream(http->resource_id); + } + } + ReleaseSocket(http); + return 1; + } + + if (type == RESOURCE_TYPE_CACHE) { + cache_->AppendBuffer(http->resource_id, http->iov[0].iov_base, readed); + } else if (type == RESOURCE_TYPE_STREAMING) { + // If there is no listeners + if (stream_->NotifyStream(http->resource_id, http->iov[0].iov_base, + readed) == 1) { + Log(__FILE__, __LINE__) << "HttpClient empty stream listeners"; + ReleaseSocket(http); + return 1; + } + } + + memset(http->iov[0].iov_base, 0, buffer_size_); + + struct io_uring_sqe *sqe = io_uring_get_sqe(ring_); + io_uring_prep_nop(sqe); + io_uring_sqe_set_data(sqe, http); + io_uring_submit(ring_); return 0; } @@ -170,23 +224,17 @@ void HttpsClient::CloseSSL(int socket_fd, SSL *ssl, SSL_CTX *context) { } void HttpsClient::ReleaseSocket(struct Request *request) { - // struct HttpRequest *http_request = - // waiting_read_.at(request->client_socket); - // waiting_read_.erase(request->client_socket); - - // free(request->iov[0].iov_base); - // SSL *ssl = (SSL *)request->iov[1].iov_base; - // SSL_CTX *context = (SSL_CTX *)request->iov[2].iov_base; + free(request->iov[0].iov_base); + SSL *ssl = (SSL *)request->iov[1].iov_base; + SSL_CTX *context = (SSL_CTX *)request->iov[2].iov_base; - // CloseSSL(request->client_socket, ssl, context); + CloseSSL(request->client_socket, ssl, context); - // delete http_request; - // free(request); + free(request); } bool HttpsClient::ProcessError(SSL *ssl, int last_error) { int error = SSL_get_error(ssl, last_error); - Log(__FILE__, __LINE__, Log::kWarning) << "SSL error " << error; if (error == SSL_ERROR_NONE) { // if (last_error == SSL_ERROR_SYSCALL) { // return false; @@ -194,12 +242,10 @@ bool HttpsClient::ProcessError(SSL *ssl, int last_error) { return true; } else if (error == SSL_ERROR_ZERO_RETURN) { SSL_shutdown(ssl); + return true; } else if (error == SSL_ERROR_SYSCALL) { + Log(__FILE__, __LINE__, Log::kWarning) << "SSL error " << error; return ProcessError(ssl, error); } return false; } - -int HttpsClient::HandleReadHeaderRequest(struct Request *http, int readed) { - return 0; -} diff --git a/src/HttpsClient.hpp b/src/HttpsClient.hpp index 0efeae1..29756ed 100644 --- a/src/HttpsClient.hpp +++ b/src/HttpsClient.hpp @@ -22,9 +22,8 @@ class HttpsClient : public Http { int HandleReadHeaderRequest(struct Request *http, int readed) override; private: - void AddReadRequest(struct Request *request, SSL *ssl, SSL_CTX *context, - int fd); void CloseSSL(int socket_fd, SSL *ssl, SSL_CTX *context); + int ReadFromSSL(struct Request *http); protected: void ReleaseSocket(struct Request *request) override; diff --git a/src/Settings.cpp b/src/Settings.cpp index 4a9efe0..21593cd 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -15,3 +15,5 @@ bool Settings::UseCache = true; int Settings::CacheBufferSize = 64; int Settings::StreamingBufferSize = 256; + +bool Settings::HLSMode = false; diff --git a/src/Settings.hpp b/src/Settings.hpp index 6408392..2495851 100644 --- a/src/Settings.hpp +++ b/src/Settings.hpp @@ -13,5 +13,6 @@ class Settings { static bool UseCache; static int CacheBufferSize; static int StreamingBufferSize; + static bool HLSMode; }; #endif diff --git a/src/Utils.cpp b/src/Utils.cpp index 1f3d27b..d7d93d6 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -74,8 +74,11 @@ struct Request *Utils::HttpExternalRequest(struct Request *cache) { * 1 = SSL* ssl pointer * 2 = SSL_CTX* ssl context */ -struct Request *Utils::HttpsExternalRequest() { - return CreateRequest(3); +struct Request *Utils::HttpsExternalRequest(struct Request *inner) { + struct Request *request = CreateRequest(3); + request->resource_id = inner->resource_id; + + return request; } /* diff --git a/src/Utils.hpp b/src/Utils.hpp index bffcf45..bfb1a4b 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -19,7 +19,7 @@ class Utils { static struct Request *CacheRequest(struct Request *entry); static struct Request *HttpErrorRequest(); static struct Request *HttpExternalRequest(struct Request *cache); - static struct Request *HttpsExternalRequest(); + static struct Request *HttpsExternalRequest(struct Request *inner); static void ReleaseRequest(struct Request *request); }; #endif