diff options
author | qrort <qrort@yandex-team.com> | 2022-12-02 11:31:25 +0300 |
---|---|---|
committer | qrort <qrort@yandex-team.com> | 2022-12-02 11:31:25 +0300 |
commit | b1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806 (patch) | |
tree | 2a23209faf0fea5586a6d4b9cee60d1b318d29fe /library/cpp/http/fetch_gpl | |
parent | 559174a9144de40d6bb3997ea4073c82289b4974 (diff) | |
download | ydb-b1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806.tar.gz |
remove kikimr/driver DEPENDS
Diffstat (limited to 'library/cpp/http/fetch_gpl')
-rw-r--r-- | library/cpp/http/fetch_gpl/httpagent.h | 292 | ||||
-rw-r--r-- | library/cpp/http/fetch_gpl/sockhandler.cpp | 135 | ||||
-rw-r--r-- | library/cpp/http/fetch_gpl/sockhandler.h | 557 |
3 files changed, 0 insertions, 984 deletions
diff --git a/library/cpp/http/fetch_gpl/httpagent.h b/library/cpp/http/fetch_gpl/httpagent.h deleted file mode 100644 index b77c246c4f..0000000000 --- a/library/cpp/http/fetch_gpl/httpagent.h +++ /dev/null @@ -1,292 +0,0 @@ -#pragma once - -#include <library/cpp/http/fetch/httpagent.h> - -template <class TSockHndl = TSimpleSocketHandler, - class TDnsClient = TIpResolver, - class TErrorLogger = TSslSocketBase::TFakeLogger, - class TTimer = TNoTimer, - template <class, class> class TSslSocketImpl = TSslSocketHandler> -class THttpsAgent: public TTimer { -public: - typedef TSslSocketImpl<TSockHndl, TErrorLogger> TSocket; - THttpsAgent() - : Socket(new TSocket) - , Scheme(0) - , Persistent(0) - , Timeout(TDuration::MicroSeconds(150)) - , Hostheader(nullptr) - , Footer(nullptr) - , pHostBeg(nullptr) - , pHostEnd(nullptr) - , AltFooter(nullptr) - , PostData(nullptr) - , PostDataLen(0) - , Method(nullptr) - , MethodLen(0) - , HostheaderLen(0) - { - SetIdentification("YandexSomething/1.0", "webadmin@yandex.ru"); - } - - ~THttpsAgent() { - Disconnect(); - delete[] Hostheader; - delete[] Footer; - } - - void SetIdentification(const char* userAgent, const char* httpFrom) { - Y_VERIFY(Socket.Get(), "HttpsAgent: socket is picked out. Can't use until a valid socket is set"); - delete[] Footer; - size_t len = userAgent ? strlen(userAgent) + 15 : 0; - len += httpFrom ? strlen(httpFrom) + 9 : 0; - len += 3; - Footer = new char[len]; - if (userAgent) - strcat(strcat(strcpy(Footer, "User-Agent: "), userAgent), "\r\n"); - if (httpFrom) - strcat(strcat(strcat(Footer, "From: "), httpFrom), "\r\n"); - } - - void SetUserAgentFooter(const char* altFooter) { - AltFooter = altFooter; - } - - void SetPostData(const char* postData, size_t postDataLen) { - PostData = postData; - PostDataLen = postDataLen; - } - - void SetMethod(const char* method, size_t methodLen) { - Method = method; - MethodLen = methodLen; - } - - // deprecated - ui32 GetIp() const { - return Addrs.GetV4Addr().first; - } - - int GetScheme() const { - return Scheme; - } - - void SetTimeout(TDuration tim) { - Timeout = tim; - } - - void SetConnectTimeout(TDuration timeout) { - ConnectTimeout = timeout; - } - - int Disconnected() { - return !Persistent || !Socket.Get() || !Socket->Good(); - } - - int SetHost(const char* hostname, TIpPort port, int scheme = THttpURL::SchemeHTTP) { - TStringBuf host{hostname}; - if (host.StartsWith('[') && host.EndsWith(']')) { - TString tmp = ToString(host.Skip(1).Chop(1)); - TSockAddrInet6 sa(tmp.data(), port); - NAddr::IRemoteAddrRef addr = new NAddr::TIPv6Addr(sa); - SetHost(hostname, port, {addr}, scheme); - return 0; - } - TAddrList addrs = DnsClient.Resolve(hostname, port); - if (!addrs.size()) { - return 1; - } - SetHost(hostname, port, addrs, scheme); - return 0; - } - - int SetHost(const char* hostname, TIpPort port, const TAddrList& addrs, int scheme = THttpURL::SchemeHTTP) { - Disconnect(); - Addrs = addrs; - Scheme = scheme; - size_t reqHostheaderLen = strlen(hostname) + 20; - if (HostheaderLen < reqHostheaderLen) { - delete[] Hostheader; - Hostheader = new char[(HostheaderLen = reqHostheaderLen)]; - } - if (Scheme == THttpURL::SchemeHTTPS && port == 443 || port == 80) - sprintf(Hostheader, "Host: %s\r\n", hostname); - else - sprintf(Hostheader, "Host: %s:%u\r\n", hostname, port); - pHostBeg = strchr(Hostheader, ' ') + 1; - pHostEnd = strchr(pHostBeg, '\r'); - // convert hostname to lower case since some web server don't like - // uppper case (Task ROBOT-562) - for (char* p = pHostBeg; p < pHostEnd; p++) - *p = tolower(*p); - SocketCtx.Host = pHostBeg; - SocketCtx.HostLen = pHostEnd - pHostBeg; - return 0; - } - - // deprecated v4-only version - int SetHost(const char* hostname, TIpPort port, ui32 ip, int scheme = THttpURL::SchemeHTTP, TIpPort connPort = 0) { - connPort = connPort ? connPort : port; - return SetHost(hostname, port, TAddrList::MakeV4Addr(ip, connPort), scheme); - } - - void SetHostHeader(const char* host) { - size_t reqHostheaderLen = strlen(host) + 20; - if (HostheaderLen < reqHostheaderLen) { - delete[] Hostheader; - Hostheader = new char[(HostheaderLen = reqHostheaderLen)]; - } - sprintf(Hostheader, "Host: %s\r\n", host); - pHostBeg = strchr(Hostheader, ' ') + 1; - pHostEnd = strchr(pHostBeg, '\r'); - SocketCtx.Host = pHostBeg; - SocketCtx.HostLen = pHostEnd - pHostBeg; - } - - void SetSocket(TSocket* s) { - Y_VERIFY(s, "HttpsAgent: socket handler is null"); - SocketCtx.FreeBuffers(); - if (s->HasSsl()) - SocketCtx.AllocBuffers(); - Socket.Reset(s); - } - - void SetPersistent(const bool value) { - Persistent = value; - } - - TSocket* PickOutSocket() { - SocketCtx.FreeBuffers(); - SocketCtx.CachedSession.Destroy(); - return Socket.Release(); - } - - void Disconnect() { - if (Socket.Get()) - Socket->Disconnect(); - SocketCtx.FreeBuffers(); - SocketCtx.CachedSession.Destroy(); - } - - ssize_t read(void* buffer, size_t buflen) { - Y_VERIFY(Socket.Get(), "HttpsAgent: socket is picked out. Can't use until a valid socket is set"); - ssize_t ret = Socket->read(&SocketCtx, buffer, buflen); - TTimer::OnAfterRecv(); - return ret; - } - - int RequestGet(const char* url, const char* const* headers, int persistent = 1, bool head_request = false) { - Y_VERIFY(Socket.Get(), "HttpsAgent: socket is picked out. Can't use until a valid socket is set"); - if (!Addrs.size()) - return HTTP_DNS_FAILURE; - char message[MessageMax]; - ssize_t messlen = 0; - if (Method) { - strncpy(message, Method, MethodLen); - message[MethodLen] = ' '; - messlen = MethodLen + 1; - } else if (PostData) { - strcpy(message, "POST "); - messlen = 5; - } else if (head_request) { - strcpy(message, "HEAD "); - messlen = 5; - } else { - strcpy(message, "GET "); - messlen = 4; - } -#define _AppendMessage(mes) messlen += Min(MessageMax - messlen, \ - (ssize_t)strlcpy(message + messlen, (mes), MessageMax - messlen)) - _AppendMessage(url); - _AppendMessage(" HTTP/1.1\r\n"); - _AppendMessage(Hostheader); - _AppendMessage("Connection: "); - _AppendMessage(persistent ? "Keep-Alive\r\n" : "Close\r\n"); - while (headers && *headers) - _AppendMessage(*headers++); - if (AltFooter) - _AppendMessage(AltFooter); - else - _AppendMessage(Footer); - _AppendMessage("\r\n"); -#undef _AppendMessage - if (messlen >= MessageMax) - return HTTP_HEADER_TOO_LARGE; - - if (!Persistent) - Socket->Disconnect(&SocketCtx); - Persistent = persistent; - int connected = Socket->Good(); - SocketCtx.FreeBuffers(); - if (Scheme == THttpURL::SchemeHTTPS) { - SocketCtx.AllocBuffers(); - } - - bool success = false; - Y_SCOPE_EXIT(&success, this) { if (!success) { this->SocketCtx.FreeBuffers(); }; }; - - TTimer::OnBeforeSend(); - for (int attempt = !connected; attempt < 2; attempt++) { - const auto connectTimeout = ConnectTimeout ? ConnectTimeout : Timeout; - if (!Socket->Good() && Socket->Connect(&SocketCtx, Addrs, connectTimeout , Scheme == THttpURL::SchemeHTTPS, true)) { - return SocketCtx.SslError ? HTTP_SSL_ERROR : HTTP_CONNECT_FAILED; - } else { // We successfully connected - connected = true; - } - - int sendOk = Socket->send(&SocketCtx, message, messlen); - if (sendOk && PostData && PostDataLen) - sendOk = Socket->send(&SocketCtx, PostData, PostDataLen); - if (!sendOk) { - int err = errno; - Socket->Disconnect(&SocketCtx); - errno = err; - continue; - } - TTimer::OnAfterSend(); - - if (!Socket->peek(&SocketCtx)) { - int err = errno; - Socket->Disconnect(&SocketCtx); - if (err == EINTR) { - errno = err; - return HTTP_INTERRUPTED; - } - if (err == ETIMEDOUT) { - errno = err; - return HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING; - } - } else { - TTimer::OnBeforeRecv(); - if (!persistent) { - Socket->shutdown(); - } - success = true; - return 0; - } - } - return SocketCtx.SslError ? HTTP_SSL_ERROR : (connected ? HTTP_CONNECTION_LOST : HTTP_CONNECT_FAILED); - } - - ui16 CertCheckErrors() const { - return SocketCtx.CertErrors; - } - -protected: - THolder<TSocket> Socket; - typename TSocket::TSocketCtx SocketCtx; - TIpResolverWrapper<TDnsClient> DnsClient; - TAddrList Addrs; - int Scheme; - int Persistent; - TDuration Timeout; - TDuration ConnectTimeout; - char *Hostheader, *Footer, *pHostBeg, *pHostEnd; - const char* AltFooter; // alternative footer can be set by the caller - const char* PostData; - size_t PostDataLen; - const char* Method; - size_t MethodLen; - unsigned short HostheaderLen; - static const ssize_t MessageMax = 65536; -}; diff --git a/library/cpp/http/fetch_gpl/sockhandler.cpp b/library/cpp/http/fetch_gpl/sockhandler.cpp deleted file mode 100644 index a3fa2e9de1..0000000000 --- a/library/cpp/http/fetch_gpl/sockhandler.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "sockhandler.h" - -#include <util/datetime/base.h> - -bool TSslSocketBase::Initialized = false; -sslKeys_t* TSslSocketBase::Keys = nullptr; -THolder<TSslSocketBase::TBufferAllocator> TSslSocketBase::BufAlloc; - -bool TSslSocketBase::StaticInit(const char* caFile) { - Y_VERIFY(!Initialized, "SslSocket StaticInit: already initialized"); - BufAlloc.Reset(new TSslSocketBase::TBufferAllocator); - if (matrixSslOpen() < 0) - Y_FAIL("SslSocket StaticInit: unable to initialize matrixSsl"); - Y_VERIFY(caFile && caFile[0], "SslSocket StaticInit: no certificate authority file"); - - if (matrixSslReadKeys(&Keys, nullptr, nullptr, nullptr, caFile) < 0) { - Y_FAIL("SslSocket StaticInit: unable to load ssl keys from %s", caFile); - } - Initialized = true; - return Initialized; -} - -bool TSslSocketBase::StaticInit(unsigned char* caBuff, int caLen) { - Y_VERIFY(!Initialized, "SslSocket StaticInit: already initialized"); - BufAlloc.Reset(new TSslSocketBase::TBufferAllocator); - if (matrixSslOpen() < 0) - Y_FAIL("SslSocket StaticInit: unable to initialize matrixSsl"); - Y_VERIFY(caBuff && caBuff[0] && caLen > 0, "SslSocket StaticInit: no certificate authority file"); - - if (matrixSslReadKeysMem(&Keys, nullptr, 0, nullptr, 0, caBuff, caLen) < 0) { - Y_FAIL("SslSocket StaticInit: unable to load ssl keys from memory"); - } - Initialized = true; - return Initialized; -} - -void TSslSocketBase::StaticTerm() { - Y_VERIFY(Initialized, "SslSocket StaticTerm: not initialized"); - matrixSslFreeKeys(Keys); - matrixSslClose(); - Keys = nullptr; - BufAlloc.Reset(nullptr); - Initialized = false; -} - -bool MatchPattern(const char* p, const char* pe, const char* s, const char* se, int maxAsteriskNum) { - if (maxAsteriskNum <= 0) - return false; - while (p < pe && s < se) { - if (*p == '*') { - ++p; - while (p < pe && *p == '*') - ++p; - while (s < se) { - if (MatchPattern(p, pe, s, se, maxAsteriskNum - 1)) - return true; - if (*s == '.') - return false; - ++s; - } - return p == pe; - } else { - if (*p != *s) - return false; - ++p; - ++s; - } - } - while (p < pe && *p == '*') - ++p; - return (p == pe && s == se); -} - -bool MatchHostName(const char* pattern, size_t patternLen, const char* name, size_t nameLen) { - // rfc 2818 says: - // wildcard character * can match any single domain name component or component fragment - Y_VERIFY(name && nameLen, "Ssl certificate check error: hostname is empty"); - if (!pattern || !patternLen) - return false; - const char* ne = strchr(name, ':'); - if (!ne || ne > name + nameLen) - ne = name + nameLen; - return MatchPattern(pattern, pattern + patternLen, name, ne, 5); -} - -bool IsExpired(const char* notBefore, const char* notAfter) { - time_t notbefore, notafter; - if (!ParseX509ValidityDateTimeDeprecated(notBefore, notbefore) || !ParseX509ValidityDateTimeDeprecated(notAfter, notafter)) - return true; - time_t t = Seconds(); - return notbefore > t || t > notafter; -} - -int TSslSocketBase::CertChecker(sslCertInfo_t* cert, void* arg) { - Y_ASSERT(cert); - Y_ASSERT(arg); - TSocketCtx* ctx = (TSocketCtx*)arg; - ctx->CertErrors = 0; - - // matching hostname - if (ctx->Host && ctx->HostLen) { - bool nameMatched = false; - sslSubjectAltNameEntry* an = cert->subjectAltName; - while (an) { - // dNSName id is 2. - if (an->id == 2 && MatchHostName((const char*)an->data, an->dataLen, ctx->Host, ctx->HostLen)) { - nameMatched = true; - break; - } - an = an->next; - } - if (!nameMatched && cert->subject.commonName) { - nameMatched = MatchHostName(cert->subject.commonName, strlen(cert->subject.commonName), ctx->Host, ctx->HostLen); - } - if (!nameMatched) - ctx->CertErrors |= SSL_CERT_HOSTNAME_MISMATCH; - } - - // walk through certificate chain and check if they are signed correctly and not expired - sslCertInfo_t* c = cert; - while (c->next) { - if (IsExpired(c->notBefore, c->notAfter)) - ctx->CertErrors |= SSL_CERT_EXPIRED; - if (c->verified < 0) { - ctx->CertErrors |= SSL_CERT_BAD_CHAIN; - } - c = c->next; - } - if (c->verified < 0) - ctx->CertErrors |= SSL_CERT_UNTRUSTED; - if (IsExpired(c->notBefore, c->notAfter)) - ctx->CertErrors |= SSL_CERT_EXPIRED; - - return SSL_ALLOW_ANON_CONNECTION; -} diff --git a/library/cpp/http/fetch_gpl/sockhandler.h b/library/cpp/http/fetch_gpl/sockhandler.h deleted file mode 100644 index 91d4f67a06..0000000000 --- a/library/cpp/http/fetch_gpl/sockhandler.h +++ /dev/null @@ -1,557 +0,0 @@ -#pragma once - -#include <library/cpp/http/fetch/sockhandler.h> -#include <contrib/libs/matrixssl/matrixSsl.h> - -class TSslSocketBase { -public: - static bool StaticInit(const char* caFile = nullptr); - static bool StaticInit(unsigned char* caBuff, int caLen); - static void StaticTerm(); - static int CertChecker(sslCertInfo_t* cert, void* arg); - enum ECertErrors { - SSL_CERT_UNTRUSTED = 0x01, - SSL_CERT_BAD_CHAIN = 0x02, - SSL_CERT_HOSTNAME_MISMATCH = 0x04, - SSL_CERT_EXPIRED = 0x08 - }; - - struct TSessIdDestructor { - static void Destroy(sslSessionId_t* id) { - matrixSslFreeSessionId(id); - } - }; - -protected: - enum ESslStatus { - SSLSOCKET_EOF = 0x1, - SSLSOCKET_CLOSE_NOTIFY = 0x2 - }; - struct TSocketCtx { - ui16 SslError; - ui16 CertErrors; - const char* Host; - size_t HostLen; - TSocketCtx() - : SslError(0) - , CertErrors(0) - , Host(nullptr) - , HostLen(0) - { - } - }; - -protected: - class TBufferAllocator { - class TChunk; - typedef TIntrusiveSListItem<TChunk> TChunkBase; - - class TChunk: public TChunkBase { - public: - inline unsigned char* ToPointer() { - //shut up clang warning - (void)Buf; - - return (unsigned char*)this; - - static_assert(sizeof(TChunk) >= SSL_MAX_BUF_SIZE, "expect sizeof(TChunk) >= SSL_MAX_BUF_SIZE"); - } - static inline TChunk* FromPointer(unsigned char* ptr) { - return (TChunk*)ptr; - } - - private: - unsigned char Buf[SSL_MAX_BUF_SIZE - sizeof(TChunkBase)]; - }; - - public: - TBufferAllocator() - : NFree(0) - , NAllocated(0) - { - static_assert(InitialItems > 0 && A1 > 0 && A2 > 0 && A1 >= A2, "expect InitialItems > 0 && A1 > 0 && A2 > 0 && A1 >= A2"); - ResizeList(InitialItems); - } - - ~TBufferAllocator() { - Y_VERIFY(!NAllocated, "Ssl bufferAllocator: %" PRISZT " blocks lost!", NAllocated); - ResizeList(0); - } - - unsigned char* Alloc() { - TGuard<TMutex> guard(Lock); - if (Free_.Empty()) - ResizeList(A2 * NAllocated); - - NAllocated++; - NFree--; - return Free_.PopFront()->ToPointer(); - } - - void Free(unsigned char* p) { - if (!p) - return; - TGuard<TMutex> guard(Lock); - Y_VERIFY(NAllocated, "Ssl bufferAllocator: multiple frees?"); - TChunk* ch = TChunk::FromPointer(p); - Free_.PushFront(ch); - NFree++; - NAllocated--; - - // destroy some items if NFree/NAllocated increased too much - size_t newSize = A2 * NAllocated; - if (NAllocated + newSize >= InitialItems && NFree >= A1 * NAllocated) - ResizeList(newSize); - } - - private: - inline void ResizeList(size_t newSize) { - while (NFree < newSize) { - Free_.PushFront(new TChunk); - NFree++; - } - while (NFree > newSize) { - TChunk* ch = Free_.PopFront(); - Y_VERIFY(ch, "Ssl bufferAllocator: internal error"); - delete ch; - NFree--; - } - } - - static const size_t InitialItems = 100; - static const unsigned A1 = 3; // maximum reserved/allocated ratio - static const unsigned A2 = 1; // if ratio A1 is reached, decrease by A2 - - TIntrusiveSList<TChunk> Free_; - size_t NFree; - size_t NAllocated; - TMutex Lock; - }; - - static bool Initialized; - static sslKeys_t* Keys; - static THolder<TBufferAllocator> BufAlloc; - -public: - class TFakeLogger { - public: - static void Write(const char* /*format*/, ...) { - } - }; -}; - -template <class TSocketHandler = TSimpleSocketHandler, class TErrorLogger = TSslSocketBase::TFakeLogger> -class TSslSocketHandler: public TSslSocketBase, protected TSocketHandler, TNonCopyable { -public: - struct TSocketCtx: public TSslSocketBase::TSocketCtx { - sslBuf_t InBuf; - sslBuf_t InSock; - THolder<sslSessionId_t, TSessIdDestructor> CachedSession; - TSocketCtx() { - Zero(InBuf); - Zero(InSock); - } - void AllocBuffers() { - Y_ASSERT(InBuf.size == 0); - InBuf.size = SSL_MAX_BUF_SIZE; - InBuf.start = InBuf.end = InBuf.buf = BufAlloc->Alloc(); - - Y_ASSERT(InSock.size == 0); - InSock.size = SSL_MAX_BUF_SIZE; - InSock.start = InSock.end = InSock.buf = BufAlloc->Alloc(); - } - void FreeBuffers() { - if (InBuf.buf) { - if (InBuf.end - InBuf.start) { - // We had some data read and decrypted. Too sad, nobody needs it now :( - TErrorLogger::Write("TSocketCtx::FreeBuffers: %i bytes of data lost in InBuf (%s)\n", (int)(InBuf.end - InBuf.start), TString(Host, HostLen).data()); - } - BufAlloc->Free(InBuf.buf); - Zero(InBuf); - } - if (InSock.buf) { - if (InSock.end - InSock.start) { - // We had some data read and waiting for decryption. Most likely we disconnected before server's "bye". - TErrorLogger::Write("TSocketCtx::FreeBuffers: %i bytes of data lost in InSock (%s)\n", (int)(InSock.end - InSock.start), TString(Host, HostLen).data()); - } - BufAlloc->Free(InSock.buf); - Zero(InSock); - } - } - void ResetBuffers() { - InBuf.start = InBuf.end = InBuf.buf; - InSock.start = InSock.end = InSock.buf; - } - }; - - TSslSocketHandler() - : TSocketHandler() - , Ssl(nullptr) - { - Y_VERIFY(TSslSocketBase::Initialized, "Ssl library isn't initialized. Call TSslSocketBase::StaticInit() first"); - } - - virtual ~TSslSocketHandler() { - Y_ASSERT(Initialized); - Disconnect(); - } - - int Good() const { - return TSocketHandler::Good(); - } - bool HasSsl() const { - return Ssl; - } - - // set reconnect "true" to try to recover from cached session id - int Connect(TSocketCtx* ctx, const TAddrList& addrs, TDuration timeout, bool isHttps, bool reconnect = false); - - // for debug "file" socket - bool open(const char* name) { - Y_ASSERT(Initialized); - Disconnect(); - return TSocketHandler::open(name); - } - - void Disconnect(TSocketCtx* ctx = nullptr) { // if ctx is non-NULL, cache session id in it. - Y_ASSERT(Initialized); - if (Ssl) { - if (ctx) { - sslSessionId_t* cs; - if (matrixSslGetSessionId(Ssl, &cs) < 0) { - cs = nullptr; - TErrorLogger::Write("TSslSocketHandler::Disconnect: failed to create session id for host %s\n", TString(ctx->Host, ctx->HostLen).data()); - } - ctx->CachedSession.Reset(cs); - } - matrixSslDeleteSession(Ssl); - Ssl = nullptr; - } - TSocketHandler::Disconnect(); - } - - void shutdown() { - TSocketHandler::shutdown(); - } - - ssize_t send(TSocketCtx* ctx, const void* message, size_t messlen) { - Y_ASSERT(TSocketHandler::Good()); - if (!Ssl) - return TSocketHandler::send(message, messlen); - int status; - int rc = SslWrite(ctx, static_cast<const char*>(message), (int)messlen, &status); - if (rc < 0) { - errno = status; - ctx->ResetBuffers(); - Disconnect(); - return false; - } - Y_ASSERT((size_t)rc == messlen); - return true; - } - - bool peek(TSocketCtx* ctx) { - if (!Ssl) - return TSocketHandler::peek(); - int rc; - int status; - while (true) { - rc = SslRead(ctx, nullptr, 0, &status); - if (rc < 0) { - errno = status; - ctx->ResetBuffers(); - Disconnect(); - return false; - } else if (rc > 0) { - return true; - } - // else if (rc == 0) - if (status) { - errno = status; - ctx->ResetBuffers(); - Disconnect(); - return false; - } - } - } - - ssize_t read(TSocketCtx* ctx, void* message, size_t messlen) { - if (!Ssl) - return TSocketHandler::read(message, messlen); - int rc; - int status; - if (!messlen) - return 0; - while (true) { - rc = SslRead(ctx, static_cast<char*>(message), (int)messlen, &status); - if (rc < 0) { - errno = status; - ctx->ResetBuffers(); - Disconnect(); - return rc; - } else if (rc > 0) - return rc; - // else if (rc == 0) - if (status) { - errno = status; - ctx->ResetBuffers(); - Disconnect(); - return 0; - } - } - } - -private: - int SslRead(TSocketCtx* ctx, char* buf, int buflen, int* status); - int SslWrite(TSocketCtx* ctx, const char* buf, int len, int* status); - - ssl_t* Ssl; -}; - -template <typename TSocketHandler, typename TErrorLogger> -int TSslSocketHandler<TSocketHandler, TErrorLogger>::Connect(TSocketCtx* ctx, const TAddrList& addrs, TDuration timeout, bool isHttps, bool reconnect) { - Y_ASSERT(Initialized); - ctx->SslError = 0; - ctx->ResetBuffers(); - Disconnect(); - int res = TSocketHandler::Connect(addrs, timeout); - if (!isHttps || res != 0) { - ctx->CachedSession.Destroy(); - return res; - } - - // create ssl session - if ((res = matrixSslNewSession(&Ssl, Keys, reconnect ? ctx->CachedSession.Get() : nullptr, 0)) < 0) { - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return res; - } - ctx->CachedSession.Destroy(); - - matrixSslSetCertValidator(Ssl, CertChecker, ctx); - - // now it's time to perform handshake - sslBuf_t outsock; - outsock.buf = outsock.start = outsock.end = BufAlloc->Alloc(); - outsock.size = SSL_MAX_BUF_SIZE; - - res = matrixSslEncodeClientHello(Ssl, &outsock, 0); - if (res) { - TErrorLogger::Write("TSslSocketHandler::Connect: internal error %i\n", res); - BufAlloc->Free(outsock.buf); - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } - - if (!TSocketHandler::send(outsock.start, outsock.end - outsock.start)) { - BufAlloc->Free(outsock.buf); - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } - BufAlloc->Free(outsock.buf); - - // SslRead will handle handshake and is suppozed to return 0 - int status, rc; - int ncalls = 10; // FIXME: maybe it's better to check time - while (true) { - rc = SslRead(ctx, nullptr, 0, &status); - if (rc == 0) { - if (status == SSLSOCKET_EOF || status == SSLSOCKET_CLOSE_NOTIFY) { - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } - if (matrixSslHandshakeIsComplete(Ssl)) - break; - if (--ncalls <= 0) { - TErrorLogger::Write("TSslSocketHandler::Connect: handshake too long (server wants multiple handshakes maybe)\n"); - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } - continue; - } else if (rc > 0) { - TErrorLogger::Write("TSslSocketHandler::Connect: server sent data instead of a handshake\n"); - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } else { // rc < 0 - //this is an error - ctx->SslError = 1; - ctx->ResetBuffers(); - Disconnect(); - return -1; - } - } - - return 0; -} - -template <typename TSocketHandler, typename TErrorLogger> -int TSslSocketHandler<TSocketHandler, TErrorLogger>::SslRead(TSocketCtx* ctx, char* buf, int buflen, int* status) { - Y_ASSERT(Initialized); - int remaining, bytes, rc; - - *status = 0; - if (Ssl == nullptr || buflen < 0) - return -1; - - // Return data if we still have cached - if (ctx->InBuf.start < ctx->InBuf.end) { - remaining = (int)(ctx->InBuf.end - ctx->InBuf.start); - if (!buflen) // polling - return remaining; - bytes = Min(buflen, remaining); - memcpy(buf, ctx->InBuf.start, bytes); - ctx->InBuf.start += bytes; - return bytes; - } - - // Pack buffered socket data (if any) so that start is at zero. - if (ctx->InSock.buf < ctx->InSock.start) { - if (ctx->InSock.start == ctx->InSock.end) { - ctx->InSock.start = ctx->InSock.end = ctx->InSock.buf; - } else { - memmove(ctx->InSock.buf, ctx->InSock.start, ctx->InSock.end - ctx->InSock.start); - ctx->InSock.end -= (ctx->InSock.start - ctx->InSock.buf); - ctx->InSock.start = ctx->InSock.buf; - } - } - - bool performRead = false; - bool dontPerformRead = false; - unsigned char error; - unsigned char alertLevel; - unsigned char alertDescription; - - while (true) { - // Read data from socket - if (!dontPerformRead && (performRead || ctx->InSock.end == ctx->InSock.start)) { - performRead = true; - bytes = TSocketHandler::read((void*)ctx->InSock.end, (ctx->InSock.buf + ctx->InSock.size) - ctx->InSock.end); - if (bytes == SOCKET_ERROR) { - *status = errno; - return -1; - } - if (bytes == 0) { - *status = SSLSOCKET_EOF; - return 0; - } - ctx->InSock.end += bytes; - } - dontPerformRead = false; - - error = 0; - alertLevel = 0; - alertDescription = 0; - - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - rc = matrixSslDecode(Ssl, &ctx->InSock, &ctx->InBuf, &error, &alertLevel, &alertDescription); - - switch (rc) { - // Successfully decoded a record that did not return data or require a response. - case SSL_SUCCESS: - return 0; - - case SSL_PROCESS_DATA: - rc = (int)(ctx->InBuf.end - ctx->InBuf.start); - if (!buflen) - return rc; - rc = Min(rc, buflen); - memcpy(buf, ctx->InBuf.start, rc); - ctx->InBuf.start += rc; - return rc; - - case SSL_SEND_RESPONSE: - if (!TSocketHandler::send(ctx->InBuf.start, ctx->InBuf.end - ctx->InBuf.start)) { - *status = errno; - return -1; - } - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - return 0; - - case SSL_ERROR: - if (ctx->InBuf.start < ctx->InBuf.end) - TSocketHandler::send(ctx->InBuf.start, ctx->InBuf.end - ctx->InBuf.start); - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - ctx->SslError = 1; - return -1; - - case SSL_ALERT: - if (alertDescription == SSL_ALERT_CLOSE_NOTIFY) { - *status = SSLSOCKET_CLOSE_NOTIFY; - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - return 0; - } - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - ctx->SslError = 1; - return -1; - - case SSL_PARTIAL: - if (ctx->InSock.start == ctx->InSock.buf && ctx->InSock.end == (ctx->InSock.buf + ctx->InSock.size)) { - ctx->InSock.start = ctx->InSock.end = ctx->InSock.buf; - ctx->SslError = 1; - return -1; - } - if (!performRead) { - performRead = 1; - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - continue; - } else { - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - return 0; - } - - case SSL_FULL: - ctx->InBuf.start = ctx->InBuf.end = ctx->InBuf.buf; - ctx->SslError = 1; - return -1; - } - } - - return 0; -} - -template <typename TSocketHandler, typename TErrorLogger> -int TSslSocketHandler<TSocketHandler, TErrorLogger>::SslWrite(TSocketCtx* ctx, const char* buf, int len, int* status) { - Y_ASSERT(Initialized); - if (len <= 0) - return len ? -1 : 0; - int rc; - *status = 0; - - sslBuf_t outsock; - outsock.size = SSL_MAX_BUF_SIZE; - outsock.start = outsock.end = outsock.buf = BufAlloc->Alloc(); - - size_t remaining = len; - while (remaining) { - size_t l = Min<size_t>(remaining, SSL_MAX_PLAINTEXT_LEN); - rc = matrixSslEncode(Ssl, (const unsigned char*)buf, l, &outsock); - if (rc <= 0) { - TErrorLogger::Write("TSslSocketHandler::SslWrite: internal error: %u\n", rc); - BufAlloc->Free(outsock.buf); - ctx->SslError = 1; - return -1; - } - rc = TSocketHandler::send(outsock.start, outsock.end - outsock.start); - if (!rc) { - *status = errno; - BufAlloc->Free(outsock.buf); - return -1; - } - remaining -= l; - buf += l; - outsock.start = outsock.end = outsock.buf; - } - BufAlloc->Free(outsock.buf); - return len; -} |