aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/http/fetch_gpl
diff options
context:
space:
mode:
authorqrort <qrort@yandex-team.com>2022-12-02 11:31:25 +0300
committerqrort <qrort@yandex-team.com>2022-12-02 11:31:25 +0300
commitb1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806 (patch)
tree2a23209faf0fea5586a6d4b9cee60d1b318d29fe /library/cpp/http/fetch_gpl
parent559174a9144de40d6bb3997ea4073c82289b4974 (diff)
downloadydb-b1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806.tar.gz
remove kikimr/driver DEPENDS
Diffstat (limited to 'library/cpp/http/fetch_gpl')
-rw-r--r--library/cpp/http/fetch_gpl/httpagent.h292
-rw-r--r--library/cpp/http/fetch_gpl/sockhandler.cpp135
-rw-r--r--library/cpp/http/fetch_gpl/sockhandler.h557
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;
-}