TempStream::TempStream(const std::string &prefix, bool deleteOnClose, IOManager *ioManager, Scheduler *scheduler) { std::string tempdir; bool absolutePath = #ifdef WINDOWS (prefix.size() >= 2 && (prefix[1] == ':' || prefix[1] == '\\')) || (!prefix.empty() && prefix[0] == '\\'); #else !prefix.empty() && prefix[0] == '/'; #endif if (!absolutePath) tempdir = g_tempDir->val(); #ifdef WINDOWS std::wstring wtempdir = toUtf16(tempdir); if (!absolutePath && wtempdir.empty()) { wtempdir.resize(MAX_PATH); DWORD len = GetTempPathW(MAX_PATH, &wtempdir[0]); if (len == 0) wtempdir = L"."; else wtempdir.resize(len); } std::wstring prefixW = toUtf16(prefix); size_t backslash = prefixW.rfind(L'\\'); if (backslash != std::wstring::npos) { wtempdir += prefixW.substr(0, backslash); prefixW = prefixW.substr(backslash + 1); } std::wstring tempfile; tempfile.resize(MAX_PATH); UINT len = GetTempFileNameW(wtempdir.c_str(), prefixW.c_str(), 0, &tempfile[0]); if (len == 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("GetTempFileNameW"); init(tempfile, FileStream::READWRITE, (FileStream::CreateFlags)(FileStream::OPEN | (deleteOnClose ? FileStream::DELETE_ON_CLOSE : 0)), ioManager, scheduler); #else if (!absolutePath && tempdir.empty()) tempdir = "/tmp/" + prefix + "XXXXXX"; else if (!absolutePath) tempdir += prefix + "XXXXXX"; else tempdir = prefix + "XXXXXX"; int fd = mkstemp(&tempdir[0]); if (fd < 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("mkstemp"); init(fd, ioManager, scheduler); if (deleteOnClose) { int rc = unlink(tempdir.c_str()); if (rc != 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("unlink"); } m_path = tempdir; #endif }
unsigned long long TimerManager::now() { if (ms_clockDg) return ms_clockDg(); #ifdef WINDOWS LARGE_INTEGER count; if (!QueryPerformanceCounter(&count)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("QueryPerformanceCounter"); unsigned long long countUll = (unsigned long long)count.QuadPart; if (g_frequency == 0) g_frequency = queryFrequency(); return muldiv64(countUll, 1000000, g_frequency); #elif defined(OSX) unsigned long long absoluteTime = mach_absolute_time(); if (g_timebase.denom == 0) g_timebase = queryTimebase(); return muldiv64(absoluteTime, g_timebase.numer, (uint64_t)g_timebase.denom * 1000); #else struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("clock_gettime"); return ts.tv_sec * 1000000ull + ts.tv_nsec / 1000; #endif }
EventLoop::EventLoop() : Scheduler(1, true, 1) { m_messageWindow = NULL; m_messageWindow = CreateWindowW(L"MordorEventLoop", L"Mordor Event Loop", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), this); if (!m_messageWindow) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CreateWindowW"); m_idleHook = SetWindowsHookExW(WH_FOREGROUNDIDLE, &EventLoop::foregroundIdleProc, NULL, GetCurrentThreadId()); if (!m_idleHook) { DestroyWindow(m_messageWindow); MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetWindowsHookEx"); } start(); }
IOManagerEPoll::IOManagerEPoll(int threads, bool useCaller) : Scheduler(threads, useCaller) { m_epfd = epoll_create(5000); MORDOR_LOG_LEVEL(g_log, m_epfd <= 0 ? Log::ERROR : Log::TRACE) << this << " epoll_create(5000): " << m_epfd; if (m_epfd <= 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_create"); int rc = pipe(m_tickleFds); MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this << " pipe(): " << rc << " (" << errno << ")"; if (rc) { close(m_epfd); MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("pipe"); } MORDOR_ASSERT(m_tickleFds[0] > 0); MORDOR_ASSERT(m_tickleFds[1] > 0); epoll_event event; event.events = EPOLLIN; event.data.fd = m_tickleFds[0]; rc = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_tickleFds[0], &event); MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this << " epoll_ctl(" << m_epfd << ", EPOLL_CTL_ADD, " << m_tickleFds[0] << ", EPOLLIN): " << rc << " (" << errno << ")"; if (rc) { close(m_tickleFds[0]); close(m_tickleFds[1]); close(m_epfd); MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl"); } }
void EventLoop::tickle() { MORDOR_LOG_TRACE(g_log) << m_messageWindow << " tickling"; if (!PostMessage(m_messageWindow, g_tickleMessage, 0, 0)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("PostMessage"); }
size_t SSLStream::read(void *buffer, size_t length) { const int toRead = (int)std::min<size_t>(0x0fffffff, length); while (true) { unsigned long error = SSL_ERROR_NONE; const int result = sslCallWithLock(std::bind(SSL_read, m_ssl.get(), buffer, toRead), &error); if (result > 0) { return result; } MORDOR_LOG_DEBUG(g_log) << this << " SSL_read(" << m_ssl.get() << ", " << toRead << "): " << result << " (" << error << ")"; switch (error) { case SSL_ERROR_NONE: return result; case SSL_ERROR_ZERO_RETURN: // Received close_notify message MORDOR_ASSERT(result == 0); return 0; case SSL_ERROR_WANT_READ: wantRead(); continue; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: MORDOR_NOTREACHED(); case SSL_ERROR_SYSCALL: if (hasOpenSSLError()) { std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_read(" << m_ssl.get() << ", " << toRead << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_read"); ; } MORDOR_LOG_WARNING(g_log) << this << " SSL_read(" << m_ssl.get() << ", " << toRead << "): " << result << " (" << error << ")"; if (result == 0) { return 0; } MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_read"); case SSL_ERROR_SSL: { MORDOR_ASSERT(hasOpenSSLError()); std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_read(" << m_ssl.get() << ", " << toRead << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_read"); ; } default: MORDOR_NOTREACHED(); } } }
EventLoop::Initializer::Initializer() { WNDCLASSW wndClass; memset(&wndClass, 0, sizeof(wndClass)); wndClass.lpfnWndProc = &EventLoop::wndProc; wndClass.hInstance = GetModuleHandleW(NULL); wndClass.lpszClassName = L"MordorEventLoop"; if (!RegisterClassW(&wndClass)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("RegisterClassW"); }
void HandleStream::cancelRead() { m_cancelRead = true; if (m_ioManager) { m_ioManager->cancelEvent(m_hFile, &m_readEvent); } else { if (!pCancelIoEx(m_hFile, NULL)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CancelIoEx"); } }
void EventLoop::onTimerInsertedAtFront() { unsigned long long next = nextTimer(); MORDOR_ASSERT(next != ~0ull); UINT uElapse = (UINT)((next / 1000) + 1); uElapse = std::max<UINT>(USER_TIMER_MINIMUM, uElapse); uElapse = std::min<UINT>(USER_TIMER_MAXIMUM, uElapse); if (!SetTimer(m_messageWindow, 1, uElapse, NULL)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetTimer"); }
size_t HandleStream::write(const void *buffer, size_t length) { if (m_cancelWrite) MORDOR_THROW_EXCEPTION(OperationAbortedException()); SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler); DWORD written; OVERLAPPED *overlapped = NULL; if (m_ioManager) { MORDOR_ASSERT(Scheduler::getThis()); m_ioManager->registerEvent(&m_writeEvent); overlapped = &m_writeEvent.overlapped; if (supportsSeek()) { overlapped->Offset = (DWORD)m_pos; overlapped->OffsetHigh = (DWORD)(m_pos >> 32); } } length = (std::min)(length, m_maxOpSize); BOOL ret = WriteFile(m_hFile, buffer, (DWORD)length, &written, overlapped); Log::Level level = Log::DEBUG; if (!ret) { if (m_ioManager && GetLastError() == ERROR_IO_PENDING) level = Log::TRACE; else level = Log::ERROR; } DWORD error = GetLastError(); MORDOR_LOG_LEVEL(g_log, level) << this << " WriteFile(" << m_hFile << ", " << length << "): " << ret << " - " << written << " (" << error << ")"; if (m_ioManager) { if (!ret && error != ERROR_IO_PENDING) { m_ioManager->unregisterEvent(&m_writeEvent); MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("WriteFile"); } if (m_skipCompletionPortOnSuccess && ret) m_ioManager->unregisterEvent(&m_writeEvent); else Scheduler::yieldTo(); DWORD error = pRtlNtStatusToDosError((NTSTATUS)m_writeEvent.overlapped.Internal); MORDOR_LOG_LEVEL(g_log, error ? Log::ERROR : Log::VERBOSE) << this << " WriteFile(" << m_hFile << ", " << length << "): " << m_writeEvent.overlapped.InternalHigh << " (" << error << ")"; if (error) MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile"); if (supportsSeek()) { m_pos = ((long long)overlapped->Offset | ((long long)overlapped->OffsetHigh << 32)) + m_writeEvent.overlapped.InternalHigh; } return m_writeEvent.overlapped.InternalHigh; } if (!ret) MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile"); return written; }
void HandleStream::cancelWrite() { m_cancelWrite = true; if (m_ioManager) { m_ioManager->cancelEvent(m_hFile, &m_writeEvent); } else { MORDOR_ASSERT(supportsCancel()); if (!pCancelIoEx(m_hFile, NULL)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CancelIoEx"); } }
LRESULT CALLBACK EventLoop::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { EventLoop *self = (EventLoop *)Scheduler::getThis(); MORDOR_ASSERT(self->m_messageWindow == hWnd || self->m_messageWindow == NULL); if (uMsg == g_tickleMessage) { MORDOR_LOG_TRACE(g_log) << hWnd << " received tickle"; Scheduler::yield(); return 0; } switch (uMsg) { case WM_TIMER: { MORDOR_LOG_TRACE(g_log) << hWnd << " processing timers"; std::vector<boost::function<void ()> > expired = self->processTimers(); if (!expired.empty()) self->schedule(expired.begin(), expired.end()); unsigned long long nextTimer = self->nextTimer(); if (nextTimer != ~0ull) { UINT uElapse = (UINT)((nextTimer / 1000) + 1); uElapse = std::max<UINT>(USER_TIMER_MINIMUM, uElapse); uElapse = std::min<UINT>(USER_TIMER_MAXIMUM, uElapse); if (!SetTimer(hWnd, 1, uElapse, NULL)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetTimer"); } else { if (!KillTimer(hWnd, 1)) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("KillTimer"); } return 0; } default: return DefWindowProcW(hWnd, uMsg, wParam, lParam); } }
void IOManagerEPoll::cancelEvent(int fd, Event events) { boost::mutex::scoped_lock lock(m_mutex); std::map<int, AsyncEvent>::iterator it = m_pendingEvents.find(fd); if (it == m_pendingEvents.end()) return; AsyncEvent &e = it->second; if ((events & EPOLLIN) && (e.event.events & EPOLLIN)) { if (e.m_dgIn) e.m_schedulerIn->schedule(e.m_dgIn); else e.m_schedulerIn->schedule(e.m_fiberIn); e.m_dgIn = NULL; e.m_fiberIn.reset(); } if ((events & EPOLLOUT) && (e.event.events & EPOLLOUT)) { if (e.m_dgOut) e.m_schedulerOut->schedule(e.m_dgOut); else e.m_schedulerOut->schedule(e.m_fiberOut); e.m_dgOut = NULL; e.m_fiberOut.reset(); } if ((events & EPOLLHUP) && (e.event.events & EPOLLHUP)) { if (e.m_dgClose) e.m_schedulerClose->schedule(e.m_dgClose); else e.m_schedulerClose->schedule(e.m_fiberClose); e.m_dgClose = NULL; e.m_fiberClose.reset(); } if ((events & EPOLLERR) && (e.event.events & EPOLLERR)) { if (e.m_dgError) e.m_schedulerError->schedule(e.m_dgError); else e.m_schedulerError->schedule(e.m_fiberError); e.m_dgError = NULL; e.m_fiberError.reset(); } e.event.events &= ~events; int op = e.event.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; int rc = epoll_ctl(m_epfd, op, fd, &e.event); MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", " << fd << ", " << (epoll_events_t)e.event.events << "): " << rc << " (" << errno << ")"; if (op == EPOLL_CTL_DEL) m_pendingEvents.erase(it); if (rc) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl"); }
void EventLoop::messagePump() { MORDOR_LOG_DEBUG(g_log) << m_messageWindow << " starting message pump"; while (!hasWorkToDo() && !stopping()) { MSG msg; BOOL bRet = GetMessageW(&msg, NULL, 0, 0); if (bRet < 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("GetMessageW"); if (bRet == 0) { stop(); return; } TranslateMessage(&msg); DispatchMessageW(&msg); } MORDOR_LOG_DEBUG(g_log) << m_messageWindow << " exiting message pump"; }
void sleep(unsigned long long us) { #ifdef WINDOWS Sleep((DWORD)(us / 1000)); #else struct timespec ts; ts.tv_sec = us / 1000000; ts.tv_nsec = (us % 1000) * 1000; while (true) { if (nanosleep(&ts, &ts) == -1) { if (errno == EINTR) continue; MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("nanosleep"); } break; } #endif }
void IOManagerEPoll::registerEvent(int fd, Event events, boost::function<void ()> dg) { MORDOR_ASSERT(fd > 0); MORDOR_ASSERT(Scheduler::getThis()); MORDOR_ASSERT(Fiber::getThis()); int epollevents = (int)events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR); MORDOR_ASSERT(epollevents != 0); boost::mutex::scoped_lock lock(m_mutex); int op; std::map<int, AsyncEvent>::iterator it = m_pendingEvents.find(fd); AsyncEvent *event; if (it == m_pendingEvents.end()) { op = EPOLL_CTL_ADD; event = &m_pendingEvents[fd]; event->event.data.fd = fd; event->event.events = epollevents; } else { op = EPOLL_CTL_MOD; event = &it->second; // OR == XOR means that none of the same bits were set MORDOR_ASSERT((event->event.events | epollevents) == (event->event.events ^ epollevents)); event->event.events |= epollevents; } if (epollevents & EPOLLIN) { event->m_schedulerIn = Scheduler::getThis(); if (dg) { event->m_dgIn = dg; event->m_fiberIn.reset(); } else { event->m_dgIn = NULL; event->m_fiberIn = Fiber::getThis(); } } if (epollevents & EPOLLOUT) { event->m_schedulerOut = Scheduler::getThis(); if (dg) { event->m_dgOut = dg; event->m_fiberOut.reset(); } else { event->m_dgOut = NULL; event->m_fiberOut = Fiber::getThis(); } } if (epollevents & EPOLLHUP) { event->m_schedulerClose = Scheduler::getThis(); if (dg) { event->m_dgClose = dg; event->m_fiberClose.reset(); } else { event->m_dgClose = NULL; event->m_fiberClose = Fiber::getThis(); } } if (epollevents & EPOLLERR) { event->m_schedulerError = Scheduler::getThis(); if (dg) { event->m_dgError = dg; event->m_fiberError.reset(); } else { event->m_dgError = NULL; event->m_fiberError = Fiber::getThis(); } } int rc = epoll_ctl(m_epfd, op, event->event.data.fd, &event->event); MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", " << event->event.data.fd << ", " << (epoll_events_t)event->event.events << "): " << rc << " (" << errno << ")"; if (rc) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl"); }
void IOManagerEPoll::idle() { epoll_event events[64]; while (true) { unsigned long long nextTimeout; if (stopping(nextTimeout)) return; int rc = -1; errno = EINTR; while (rc < 0 && errno == EINTR) { int timeout = -1; if (nextTimeout != ~0ull) timeout = (int)(nextTimeout / 1000) + 1; rc = epoll_wait(m_epfd, events, 64, timeout); if (rc < 0 && errno == EINTR) nextTimeout = nextTimer(); } MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::VERBOSE) << this << " epoll_wait(" << m_epfd << "): " << rc << " (" << errno << ")"; if (rc < 0) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_wait"); std::vector<boost::function<void ()> > expired = processTimers(); schedule(expired.begin(), expired.end()); for(int i = 0; i < rc; ++i) { epoll_event &event = events[i]; if (event.data.fd == m_tickleFds[0]) { unsigned char dummy; int rc2 = read(m_tickleFds[0], &dummy, 1); MORDOR_VERIFY(rc2 == 1); MORDOR_LOG_VERBOSE(g_log) << this << " received tickle"; continue; } bool err = event.events & (EPOLLERR | EPOLLHUP); boost::mutex::scoped_lock lock(m_mutex); std::map<int, AsyncEvent>::iterator it = m_pendingEvents.find(event.data.fd); if (it == m_pendingEvents.end()) continue; AsyncEvent &e = it->second; MORDOR_LOG_TRACE(g_log) << " epoll_event {" << (epoll_events_t)event.events << ", " << event.data.fd << "}, registered for " << (epoll_events_t)e.event.events; if ((event.events & EPOLLERR) && (e.event.events & EPOLLERR)) { if (e.m_dgError) e.m_schedulerError->schedule(e.m_dgError); else e.m_schedulerError->schedule(e.m_fiberError); // Block other events from firing e.m_dgError = NULL; e.m_fiberError.reset(); e.m_dgIn = NULL; e.m_fiberIn.reset(); e.m_dgOut = NULL; e.m_fiberOut.reset(); event.events = 0; e.event.events = 0; } if ((event.events & EPOLLHUP) && (e.event.events & EPOLLHUP)) { if (e.m_dgClose) e.m_schedulerError->schedule(e.m_dgClose); else e.m_schedulerError->schedule(e.m_fiberClose); // Block write event from firing e.m_dgOut = NULL; e.m_fiberOut.reset(); e.m_dgClose = NULL; e.m_fiberClose.reset(); event.events &= EPOLLOUT; e.event.events &= EPOLLOUT; err = false; } if (((event.events & EPOLLIN) || err) && (e.event.events & EPOLLIN)) { if (e.m_dgIn) e.m_schedulerIn->schedule(e.m_dgIn); else e.m_schedulerIn->schedule(e.m_fiberIn); e.m_dgIn = NULL; e.m_fiberIn.reset(); event.events |= EPOLLIN; } if (((event.events & EPOLLOUT) || err) && (e.event.events & EPOLLOUT)) { if (e.m_dgOut) e.m_schedulerOut->schedule(e.m_dgOut); else e.m_schedulerOut->schedule(e.m_fiberOut); e.m_dgOut = NULL; e.m_fiberOut.reset(); event.events |= EPOLLOUT; } e.event.events &= ~event.events; int op = e.event.events == 0 ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; int rc2 = epoll_ctl(m_epfd, op, event.data.fd, &e.event); MORDOR_LOG_LEVEL(g_log, rc2 ? Log::ERROR : Log::VERBOSE) << this << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", " << event.data.fd << ", " << (epoll_events_t)e.event.events << "): " << rc2 << " (" << errno << ")"; if (rc2) MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl"); if (op == EPOLL_CTL_DEL) m_pendingEvents.erase(it); } Fiber::yield(); } }
void SSLStream::connect() { while (true) { unsigned long error = SSL_ERROR_NONE; const int result = sslCallWithLock(std::bind(SSL_connect, m_ssl.get()), &error); MORDOR_LOG_DEBUG(g_log) << this << " SSL_connect(" << m_ssl.get() << "): " << result << " (" << error << ")"; if (result > 0) { flush(false); return; } switch (error) { case SSL_ERROR_NONE: flush(false); return; case SSL_ERROR_ZERO_RETURN: // Received close_notify message return; case SSL_ERROR_WANT_READ: flush(); wantRead(); continue; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: MORDOR_NOTREACHED(); case SSL_ERROR_SYSCALL: if (hasOpenSSLError()) { std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_connect(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_connect"); ; } MORDOR_LOG_ERROR(g_log) << this << " SSL_connect(" << m_ssl.get() << "): " << result << " (" << error << ")"; if (result == 0) { MORDOR_THROW_EXCEPTION(UnexpectedEofException()); } MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_connect"); case SSL_ERROR_SSL: { MORDOR_ASSERT(hasOpenSSLError()); std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_connect(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_connect"); ; } default: MORDOR_NOTREACHED(); } } }
void SSLStream::close(CloseType type) { MORDOR_ASSERT(type == BOTH); if (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_SENT_SHUTDOWN)) { unsigned long error = SSL_ERROR_NONE; const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error); if (result <= 0) { MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ")"; switch (error) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: MORDOR_NOTREACHED(); case SSL_ERROR_SYSCALL: if (hasOpenSSLError()) { std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_shutdown"); ; } MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ")"; if (result == 0) break; MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown"); case SSL_ERROR_SSL: { MORDOR_ASSERT(hasOpenSSLError()); std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_shutdown"); ; } default: MORDOR_NOTREACHED(); } } flush(false); } while (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_RECEIVED_SHUTDOWN)) { unsigned long error = SSL_ERROR_NONE; const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error); MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ")"; if (result > 0) { break; } switch (error) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: break; case SSL_ERROR_WANT_READ: flush(); wantRead(); continue; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: MORDOR_NOTREACHED(); case SSL_ERROR_SYSCALL: if (hasOpenSSLError()) { std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_shutdown"); ; } MORDOR_LOG_WARNING(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ")"; if (result == 0) { break; } MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown"); case SSL_ERROR_SSL: { MORDOR_ASSERT(hasOpenSSLError()); std::string message = getOpenSSLErrorMessage(); MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown(" << m_ssl.get() << "): " << result << " (" << error << ", " << message << ")"; MORDOR_THROW_EXCEPTION(OpenSSLException(message)) // << boost::errinfo_api_function("SSL_shutdown"); ; } default: MORDOR_NOTREACHED(); } break; } parent()->close(); }