+static void StaticSSLInfoCallback(const SSL* ssl, int where, int rc)
+{
+ OpenSSLIOHook* hook = static_cast<OpenSSLIOHook*>(SSL_get_ex_data(ssl, exdataindex));
+ hook->SSLInfoCallback(where, rc);
+}
+
+static int OpenSSL::BIOMethod::write(BIO* bio, const char* buffer, int size)
+{
+ BIO_clear_retry_flags(bio);
+
+ StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio));
+ if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
+ {
+ // Writes blocked earlier, don't retry syscall
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+
+ int ret = SocketEngine::Send(sock, buffer, size, 0);
+ if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
+ {
+ // Blocked, set retry flag for OpenSSL
+ SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
+ BIO_set_retry_write(bio);
+ }
+
+ return ret;
+}
+
+static int OpenSSL::BIOMethod::read(BIO* bio, char* buffer, int size)
+{
+ BIO_clear_retry_flags(bio);
+
+ StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio));
+ if (sock->GetEventMask() & FD_READ_WILL_BLOCK)
+ {
+ // Reads blocked earlier, don't retry syscall
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ int ret = SocketEngine::Recv(sock, buffer, size, 0);
+ if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
+ {
+ // Blocked, set retry flag for OpenSSL
+ SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK);
+ BIO_set_retry_read(bio);
+ }
+
+ return ret;
+}
+
+class OpenSSLIOHookProvider : public refcountbase, public IOHookProvider
+{
+ reference<OpenSSL::Profile> profile;
+
+ public:
+ OpenSSLIOHookProvider(Module* mod, reference<OpenSSL::Profile>& prof)
+ : IOHookProvider(mod, "ssl/" + prof->GetName(), IOHookProvider::IOH_SSL)
+ , profile(prof)
+ {
+ ServerInstance->Modules->AddService(*this);
+ }
+
+ ~OpenSSLIOHookProvider()
+ {
+ ServerInstance->Modules->DelService(*this);
+ }
+
+ void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
+ {
+ new OpenSSLIOHook(this, sock, profile->CreateServerSession(), profile);
+ }
+
+ void OnConnect(StreamSocket* sock) CXX11_OVERRIDE
+ {
+ new OpenSSLIOHook(this, sock, profile->CreateClientSession(), profile);
+ }
+};
+
+class ModuleSSLOpenSSL : public Module
+{
+ typedef std::vector<reference<OpenSSLIOHookProvider> > ProfileList;
+
+ ProfileList profiles;
+
+ void ReadProfiles()
+ {
+ ProfileList newprofiles;
+ ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile");
+ if (tags.first == tags.second)