void Timer::sleep(std::chrono::milliseconds duration) { assert(dispatcher != nullptr); assert(context == nullptr); if (stopped) { throw InterruptedException(); } Dispatcher::OperationContext timerContext; timerContext.context = dispatcher->getCurrentContext(); timerContext.interrupted = false; timer = dispatcher->getTimer(); struct kevent event; EV_SET(&event, timer, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, duration.count(), &timerContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { throw std::runtime_error("Timer::stop, kevent() failed, errno=" + std::to_string(errno)); } context = &timerContext; dispatcher->dispatch(); assert(dispatcher != nullptr); assert(timerContext.context == dispatcher->getCurrentContext()); assert(context == &timerContext); context = nullptr; timerContext.context = nullptr; dispatcher->pushTimer(timer); if (timerContext.interrupted) { throw InterruptedException(); } }
void Timer::sleep(std::chrono::nanoseconds duration) { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } OperationContext timerContext; timerContext.context = dispatcher->getCurrentContext(); timerContext.interrupted = false; timer = dispatcher->getTimer(); struct kevent event; EV_SET(&event, timer, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_NSECONDS, duration.count(), &timerContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage()); } context = &timerContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { assert(dispatcher != nullptr); assert(context != nullptr); OperationContext* timerContext = static_cast<OperationContext*>(context); if (!timerContext->interrupted) { struct kevent event; EV_SET(&event, timer, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage()); } dispatcher->pushContext(timerContext->context); timerContext->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(timerContext.context == dispatcher->getCurrentContext()); assert(context == &timerContext); context = nullptr; timerContext.context = nullptr; dispatcher->pushTimer(timer); if (timerContext.interrupted) { throw InterruptedException(); } }
std::size_t TcpConnection::write(const uint8_t* data, size_t size) { assert(dispatcher != nullptr); assert(writeContext == nullptr); if (stopped) { throw InterruptedException(); } if (size == 0) { if (shutdown(connection, SD_SEND) != 0) { throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(WSAGetLastError())); } return 0; } WSABUF buf{static_cast<ULONG>(size), reinterpret_cast<char*>(const_cast<uint8_t*>(data))}; TcpConnectionContext context; context.hEvent = NULL; if (WSASend(connection, &buf, 1, NULL, 0, &context, NULL) != 0) { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError)); } } context.context = GetCurrentFiber(); context.interrupted = false; writeContext = &context; dispatcher->dispatch(); assert(context.context == GetCurrentFiber()); assert(dispatcher != nullptr); assert(writeContext == &context); writeContext = nullptr; DWORD transferred; DWORD flags; if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) { int lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError)); } assert(context.interrupted); throw InterruptedException(); } assert(transferred == size); assert(flags == 0); return transferred; }
void Thread::sleep(time_t milliseconds) throw (InterruptedException, IllegalArgumentException) { int ret = 0; struct timespec interval; // seconds in the millis interval.tv_sec = milliseconds / 1000L; // remain millis interval.tv_nsec = (milliseconds % 1000L) * 1000000L; struct timespec remainder = {0,0}; do { ret = nanosleep(&interval,&remainder); if(ret) { if(errno == EINVAL) { throw IllegalArgumentException("Thread::sleep()"); } if(errno == EINTR) { throw InterruptedException("Thread::sleep()"); } } } while((remainder.tv_sec > 0) || (remainder.tv_nsec > 100000L)); //while spureous wake-ups: // sleep while the remainder was at least 1 millisecont }
void Condition::wait(Mutex& mutex) throw (IllegalConditionStateException, IllegalArgumentException, InterruptedException, SystemException) { if (m_error) { throw IllegalConditionStateException ("Condition::wait() Invalid Condition:", m_error); } int ret = 0; Thread::preWaitCondition(); ret= pthread_cond_wait(&m_condition, mutex.getDescriptor()); if(Thread::postWaitCondition()) { throw InterruptedException(); } if (ret) { // Error if (ret == EINVAL) { throw IllegalArgumentException("Condition::wait()", ret); } else { throw SystemException("Condition::wait unexpected error: ",ret); } } } // wait
void P2pConnectionProxy::read(P2pMessage& message) { if (!m_readQueue.empty()) { message = std::move(m_readQueue.front()); m_readQueue.pop(); return; } for (;;) { LevinProtocol::Command cmd; if (!m_context.readCommand(cmd)) { throw InterruptedException(); } message.type = cmd.command; if (cmd.command == COMMAND_HANDSHAKE::ID) { handleHandshakeResponse(cmd, message); break; } else if (cmd.command == COMMAND_TIMED_SYNC::ID) { handleTimedSync(cmd); } else { message.data = std::move(cmd.buf); break; } } }
Ipv4Address Ipv4Resolver::resolve(const std::string& host) { assert(dispatcher != nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } addrinfo hints = { 0, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL }; addrinfo* addressInfos; int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos); if (result != 0) { throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result)); } size_t count = 0; for (addrinfo* addressInfo = addressInfos; addressInfo != nullptr; addressInfo = addressInfo->ai_next) { ++count; } std::mt19937 generator{ std::random_device()() }; size_t index = std::uniform_int_distribution<size_t>(0, count - 1)(generator); addrinfo* addressInfo = addressInfos; for (size_t i = 0; i < index; ++i) { addressInfo = addressInfo->ai_next; } Ipv4Address address(ntohl(reinterpret_cast<sockaddr_in*>(addressInfo->ai_addr)->sin_addr.S_un.S_addr)); freeaddrinfo(addressInfo); return address; }
void Event::wait() { assert(dispatcher != nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } if (!state) { EventWaiter waiter = { false, nullptr, nullptr, dispatcher->getCurrentContext() }; waiter.context->interruptProcedure = [&] { if (waiter.next != nullptr) { assert(waiter.next->prev == &waiter); waiter.next->prev = waiter.prev; } else { assert(last == &waiter); last = waiter.prev; } if (waiter.prev != nullptr) { assert(waiter.prev->next == &waiter); waiter.prev->next = waiter.next; } else { assert(first == &waiter); first = waiter.next; } assert(!waiter.interrupted); waiter.interrupted = true; dispatcher->pushContext(waiter.context); }; if (first != nullptr) { static_cast<EventWaiter*>(last)->next = &waiter; waiter.prev = static_cast<EventWaiter*>(last); } else { first = &waiter; } last = &waiter; dispatcher->dispatch(); assert(waiter.context == dispatcher->getCurrentContext()); assert( waiter.context->interruptProcedure == nullptr); assert(dispatcher != nullptr); if (waiter.interrupted) { throw InterruptedException(); } } }
int Condition::wait(Mutex& mutex, time_t millisecs, time_t nanosecs) throw (IllegalConditionStateException, IllegalArgumentException, InterruptedException, SystemException) { // avoid 0 secs wait if((millisecs == 0UL) && (nanosecs == 0UL)) { wait(mutex); return 0; } if (m_error) { throw IllegalConditionStateException ("Condition::wait() Invalid Condition", m_error); } int ret = 0; struct timeval current_time; gettimeofday(¤t_time, NULL); timespec abstime; abstime.tv_sec = current_time.tv_sec + (millisecs / (time_t)1000UL); abstime.tv_nsec = nanosecs + ((millisecs % ((time_t)1000UL)) * ((time_t)1000000UL)) + (current_time.tv_usec * ((time_t)1000UL)); // normalize abstime.tv_sec += (abstime.tv_nsec / ((time_t) 1000000000UL)); abstime.tv_nsec %= ((time_t) 1000000000UL); Thread::preWaitCondition(); ret = pthread_cond_timedwait(&m_condition, mutex.getDescriptor(), &abstime); if(Thread::postWaitCondition()) { throw InterruptedException(); } if (ret) { // Error if (ret == ETIMEDOUT) { return ret; } else if (ret == EINVAL) { throw IllegalArgumentException("Condition::wait()", ret); } else{ throw SystemException("Condition::wait() unexpected error: ",ret); } } return 0; }
bool P2pContext::readCommand(LevinProtocol::Command& cmd) { if (stopped) { throw InterruptedException(); } EventLock lk(readEvent); bool result = LevinProtocol(connection).readCommand(cmd); lastReadTime = Clock::now(); return result; }
void ThreadManager::wait_for_timed_threads() { __interrupt_timed_thread_wait = false; __waitcond_timedthreads->wait(); if ( __interrupt_timed_thread_wait ) { __interrupt_timed_thread_wait = false; throw InterruptedException("Waiting for timed threads was interrupted"); } }
size_t TcpConnection::read(uint8_t* data, size_t size) { assert(dispatcher != nullptr); assert(readContext == nullptr); if (stopped) { throw InterruptedException(); } WSABUF buf{static_cast<ULONG>(size), reinterpret_cast<char*>(data)}; DWORD flags = 0; TcpConnectionContext context; context.hEvent = NULL; if (WSARecv(connection, &buf, 1, NULL, &flags, &context, NULL) != 0) { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError)); } } assert(flags == 0); context.context = GetCurrentFiber(); context.interrupted = false; readContext = &context; dispatcher->dispatch(); assert(context.context == GetCurrentFiber()); assert(dispatcher != nullptr); assert(readContext == &context); readContext = nullptr; DWORD transferred; if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) { int lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError)); } assert(context.interrupted); throw InterruptedException(); } assert(transferred <= size); assert(flags == 0); return transferred; }
std::unique_ptr<IP2pConnection> P2pNode::receiveConnection() { while (m_connectionQueue.empty()) { m_queueEvent.wait(); m_queueEvent.clear(); if (m_stopRequested) { throw InterruptedException(); } } auto connection = std::move(m_connectionQueue.front()); m_connectionQueue.pop_front(); return connection; }
void Timer::sleep(std::chrono::nanoseconds duration) { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } LARGE_INTEGER frequency; LARGE_INTEGER ticks; QueryPerformanceCounter(&ticks); QueryPerformanceFrequency(&frequency); uint64_t currentTime = ticks.QuadPart / (frequency.QuadPart / 1000); uint64_t time = currentTime + duration.count() / 1000000; TimerContext timerContext{ time, dispatcher->getCurrentContext(), false }; context = &timerContext; dispatcher->addTimer(time, dispatcher->getCurrentContext()); dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(context != nullptr); TimerContext* timerContext = static_cast<TimerContext*>(context); if (!timerContext->interrupted) { dispatcher->interruptTimer(timerContext->time, timerContext->context); timerContext->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(timerContext.context == dispatcher->getCurrentContext()); assert(dispatcher != nullptr); assert(context == &timerContext); context = nullptr; if (timerContext.interrupted) { throw InterruptedException(); } }
void P2pContext::writeMessage(const Message& msg) { if (stopped) { throw InterruptedException(); } EventLock lk(writeEvent); LevinProtocol proto(connection); switch (msg.messageType) { case P2pContext::Message::NOTIFY: proto.sendMessage(msg.type, msg.data, false); break; case P2pContext::Message::REQUEST: proto.sendMessage(msg.type, msg.data, true); break; case P2pContext::Message::REPLY: proto.sendReply(msg.type, msg.data, msg.returnCode); break; } }
/** Wait for some event on socket. * @param timeout timeout in miliseconds to wait. A negative value means to * wait forever until an event occurs, zero means just check, don't wait. * @param what what to wait for, a bitwise OR'ed combination of POLL_IN, * POLL_OUT and POLL_PRI. * @return Returns a flag value. Use bit-wise AND with the POLL_* constants * in this class. * @exception InterruptedException thrown, if poll is interrupted by a signal * @exception SocketException thrown for any other error the poll() syscall can cause, * see Exception::errno() for the cause of the error. * @see Socket::POLL_IN * @see Socket::POLL_OUT * @see Socket::POLL_PRI * @see Socket::POLL_RDHUP * @see Socket::POLL_ERR * @see Socket::POLL_HUP * @see Socket::POLL_NVAL */ short Socket::poll(int timeout, short what) { if ( sock_fd == -1 ) { return POLL_ERR; } struct pollfd pfd; pfd.fd = sock_fd; pfd.events = what; pfd.revents = 0; if ( ::poll(&pfd, 1, timeout) == -1 ) { if ( errno == EINTR ) { throw InterruptedException(); } else { throw SocketException("poll() failed", errno); } } else { return pfd.revents; } }
void Thread::join() throw (IllegalThreadStateException, InterruptedException, SystemException) { if(m_thread_state == TIDTHR_ERROR) { throw IllegalThreadStateException("Thread::join() Invalid Object"); } int ret = pthread_join(m_thread_id.value(),NULL); switch(ret) { case 0: return; case ESRCH: throw IllegalThreadStateException("Thread::join() Invalid Object",ret); case EINTR: throw InterruptedException("Thread::join()", ret); default: throw SystemException("Thread::join()",ret); } }
size_t TcpConnection::read(uint8_t* data, size_t size) { assert(dispatcher != nullptr); assert(readContext == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } WSABUF buf{static_cast<ULONG>(size), reinterpret_cast<char*>(data)}; DWORD flags = 0; TcpConnectionContext context; context.hEvent = NULL; if (WSARecv(connection, &buf, 1, NULL, &flags, &context, NULL) != 0) { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { throw std::runtime_error("TcpConnection::read, WSARecv failed, " + errorMessage(lastError)); } } assert(flags == 0); context.context = dispatcher->getCurrentContext(); context.interrupted = false; readContext = &context; dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(readContext != nullptr); TcpConnectionContext* context = static_cast<TcpConnectionContext*>(readContext); if (!context->interrupted) { if (CancelIoEx(reinterpret_cast<HANDLE>(connection), context) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, " + lastErrorMessage()); } context->context->interrupted = true; } context->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(context.context == dispatcher->getCurrentContext()); assert(dispatcher != nullptr); assert(readContext == &context); readContext = nullptr; DWORD transferred; if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) { int lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { throw std::runtime_error("TcpConnection::read, WSAGetOverlappedResult failed, " + errorMessage(lastError)); } assert(context.interrupted); throw InterruptedException(); } assert(transferred <= size); assert(flags == 0); return transferred; }
TcpConnection TcpListener::accept() { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } std::string message; SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == INVALID_SOCKET) { message = "socket failed, " + errorMessage(WSAGetLastError()); } else { uint8_t addresses[sizeof sockaddr_in * 2 + 32]; DWORD received; TcpListenerContext context2; context2.hEvent = NULL; if (acceptEx(listener, connection, addresses, 0, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &received, &context2) == TRUE) { message = "AcceptEx returned immediately, which is not supported."; } else { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { message = "AcceptEx failed, " + errorMessage(lastError); } else { context2.context = dispatcher->getCurrentContext(); context2.interrupted = false; context = &context2; dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(context != nullptr); TcpListenerContext* context2 = static_cast<TcpListenerContext*>(context); if (!context2->interrupted) { if (CancelIoEx(reinterpret_cast<HANDLE>(listener), context2) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { throw std::runtime_error("TcpListener::stop, CancelIoEx failed, " + lastErrorMessage()); } context2->context->interrupted = true; } context2->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(context2.context == dispatcher->getCurrentContext()); assert(dispatcher != nullptr); assert(context == &context2); context = nullptr; DWORD transferred; DWORD flags; if (WSAGetOverlappedResult(listener, &context2, &transferred, FALSE, &flags) != TRUE) { lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { message = "AcceptEx failed, " + errorMessage(lastError); } else { assert(context2.interrupted); if (closesocket(connection) != 0) { throw std::runtime_error("TcpListener::accept, closesocket failed, " + errorMessage(WSAGetLastError())); } else { throw InterruptedException(); } } } else { assert(transferred == 0); assert(flags == 0); if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&listener), sizeof listener) != 0) { message = "setsockopt failed, " + errorMessage(WSAGetLastError()); } else { if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) { message = "CreateIoCompletionPort failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } } } } } int result = closesocket(connection); assert(result == 0); } throw std::runtime_error("TcpListener::accept, " + message); }
size_t TcpConnection::read(uint8_t* data, size_t size) { assert(dispatcher != nullptr); assert(readContext == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } std::string message; ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { message = "recv failed, " + lastErrorMessage(); } else { OperationContext context; context.context = dispatcher->getCurrentContext(); context.interrupted = false; struct kevent event; EV_SET(&event, connection, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT, 0, 0, &context); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { message = "kevent failed, " + lastErrorMessage(); } else { readContext = &context; dispatcher->getCurrentContext()->interruptProcedure = [&] { assert(dispatcher != nullptr); assert(readContext != nullptr); OperationContext* context = static_cast<OperationContext*>(readContext); if (!context->interrupted) { struct kevent event; EV_SET(&event, connection, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { throw std::runtime_error("TcpListener::interruptionProcedure, kevent failed, " + lastErrorMessage()); } context->interrupted = true; dispatcher->pushContext(context->context); } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(context.context == dispatcher->getCurrentContext()); assert(readContext == &context); readContext = nullptr; context.context = nullptr; if (context.interrupted) { throw InterruptedException(); } ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { message = "recv failed, " + lastErrorMessage(); } else { assert(transferred <= static_cast<ssize_t>(size)); return transferred; } } } throw std::runtime_error("TcpConnection::read, " + message); } assert(transferred <= static_cast<ssize_t>(size)); return transferred; }
TcpConnection TcpListener::accept() { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } ContextPair contextPair; OperationContext listenerContext; listenerContext.interrupted = false; listenerContext.context = dispatcher->getCurrentContext(); contextPair.writeContext = nullptr; contextPair.readContext = &listenerContext; epoll_event listenEvent; listenEvent.events = EPOLLIN | EPOLLONESHOT; listenEvent.data.ptr = &contextPair; std::string message; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) { message = "epoll_ctl failed, " + lastErrorMessage(); } else { context = &listenerContext; dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(context != nullptr); OperationContext* listenerContext = static_cast<OperationContext*>(context); if (!listenerContext->interrupted) { epoll_event listenEvent; listenEvent.events = 0; listenEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) { throw std::runtime_error("TcpListener::stop, epoll_ctl failed, " + lastErrorMessage() ); } listenerContext->interrupted = true; dispatcher->pushContext(listenerContext->context); } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(listenerContext.context == dispatcher->getCurrentContext()); assert(contextPair.writeContext == nullptr); assert(context == &listenerContext); context = nullptr; listenerContext.context = nullptr; if (listenerContext.interrupted) { throw InterruptedException(); } if((listenerContext.events & (EPOLLERR | EPOLLHUP)) != 0) { throw std::runtime_error("TcpListener::accept, accepting failed"); } sockaddr inAddr; socklen_t inLen = sizeof(inAddr); int connection = ::accept(listener, &inAddr, &inLen); if (connection == -1) { message = "accept failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { message = "fcntl failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } int result = close(connection); assert(result != -1); } } throw std::runtime_error("TcpListener::accept, " + message); }
/** Connect to remote. * @exception SocketException thrown by Socket::connect() * @exception NullPointerException thrown if hostname has not been set */ void FawkesNetworkClient::connect() { if ( __host == NULL && addr_ == NULL) { throw NullPointerException("Neither hostname nor sockaddr set. Cannot connect."); } if ( s != NULL ) { disconnect(); } connection_died_recently = false; try { s = new StreamSocket(); if (addr_) { s->connect(addr_, addr_len_); } else if (__host) { s->connect(__host, __port); } else { throw NullPointerException("Nothing to connect to!?"); } __send_slave = new FawkesNetworkClientSendThread(s, this); __send_slave->start(); __recv_slave = new FawkesNetworkClientRecvThread(s, this, __recv_mutex); __recv_slave->start(); } catch (SocketException &e) { connection_died_recently = true; if ( __send_slave ) { __send_slave->cancel(); __send_slave->join(); delete __send_slave; __send_slave = NULL; } if ( __recv_slave ) { __recv_slave->cancel(); __recv_slave->join(); delete __recv_slave; __recv_slave = NULL; } __send_slave_alive = false; __recv_slave_alive = false; delete s; s = NULL; throw; } __connest_mutex->lock(); while ( ! __connest && ! __connest_interrupted ) { __connest_waitcond->wait(); } bool interrupted = __connest_interrupted; __connest_interrupted = false; __connest_mutex->unlock(); if ( interrupted ) { throw InterruptedException("FawkesNetworkClient::connect()"); } notify_of_connection_established(); }
TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } std::string message; int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == -1) { message = "socket failed, " + lastErrorMessage(); } else { sockaddr_in bindAddress; bindAddress.sin_family = AF_INET; bindAddress.sin_port = 0; bindAddress.sin_addr.s_addr = INADDR_ANY; if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) { message = "bind failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { message = "fcntl failed, " + lastErrorMessage(); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; addressData.sin_port = htons(port); addressData.sin_addr.s_addr = htonl(address.getValue()); int result = ::connect(connection, reinterpret_cast<sockaddr *>(&addressData), sizeof addressData); if (result == -1) { if (errno == EINPROGRESS) { ConnectorContext connectorContext; connectorContext.context = dispatcher->getCurrentContext(); connectorContext.interrupted = false; connectorContext.connection = connection; struct kevent event; EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, &connectorContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { message = "kevent failed, " + lastErrorMessage(); } else { context = &connectorContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { assert(dispatcher != nullptr); assert(context != nullptr); ConnectorContext* connectorContext = static_cast<ConnectorContext*>(context); if (!connectorContext->interrupted) { if (close(connectorContext->connection) == -1) { throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage()); } dispatcher->pushContext(connectorContext->context); connectorContext->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(connectorContext.context == dispatcher->getCurrentContext()); assert(context == &connectorContext); context = nullptr; connectorContext.context = nullptr; if (connectorContext.interrupted) { throw InterruptedException(); } struct kevent event; EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { message = "kevent failed, " + lastErrorMessage(); } else { int retval = -1; socklen_t retValLen = sizeof(retval); int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen); if (s == -1) { message = "getsockopt failed, " + lastErrorMessage(); } else { if (retval != 0) { message = "getsockopt failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } } } } } } else { return TcpConnection(*dispatcher, connection); } } } int result = close(connection); if (result) {} assert(result != -1);; } throw std::runtime_error("TcpConnector::connect, " + message); }
TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } std::string message; SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == INVALID_SOCKET) { message = "socket failed, result=" + std::to_string(WSAGetLastError()); } else { sockaddr_in bindAddress; bindAddress.sin_family = AF_INET; bindAddress.sin_port = 0; bindAddress.sin_addr.s_addr = INADDR_ANY; if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) { message = "bind failed, result=" + std::to_string(WSAGetLastError()); } else { GUID guidConnectEx = WSAID_CONNECTEX; DWORD read = sizeof connectEx; if (connectEx == nullptr && WSAIoctl(connection, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof guidConnectEx, &connectEx, sizeof connectEx, &read, NULL, NULL) != 0) { message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError()); } else { assert(read == sizeof connectEx); if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) { message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError()); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; addressData.sin_port = htons(port); addressData.sin_addr.S_un.S_addr = htonl(address.getValue()); TcpConnectorContext context2; context2.hEvent = NULL; if (connectEx(connection, reinterpret_cast<sockaddr*>(&addressData), sizeof addressData, NULL, 0, NULL, &context2) == TRUE) { message = "ConnectEx returned immediately, which is not supported."; } else { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { message = "ConnectEx failed, result=" + std::to_string(lastError); } else { context2.context = dispatcher->getCurrentContext(); context2.connection = connection; context2.interrupted = false; context = &context2; dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(context != nullptr); TcpConnectorContext* context2 = static_cast<TcpConnectorContext*>(context); if (!context2->interrupted) { if (CancelIoEx(reinterpret_cast<HANDLE>(context2->connection), context2) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, result=" + std::to_string(GetLastError())); } context2->context->interrupted = true; } context2->interrupted = true; } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(context2.context == dispatcher->getCurrentContext()); assert(context2.connection == connection); assert(dispatcher != nullptr); assert(context == &context2); context = nullptr; DWORD transferred; DWORD flags; if (WSAGetOverlappedResult(connection, &context2, &transferred, FALSE, &flags) != TRUE) { lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { message = "ConnectEx failed, result=" + std::to_string(lastError); } else { assert(context2.interrupted); if (closesocket(connection) != 0) { throw std::runtime_error("TcpConnector::connect, closesocket failed, result=" + std::to_string(WSAGetLastError())); } else { throw InterruptedException(); } } } else { assert(transferred == 0); assert(flags == 0); DWORD value = 1; if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, reinterpret_cast<char*>(&value), sizeof(value)) != 0) { message = "setsockopt failed, result=" + std::to_string(WSAGetLastError()); } else { return TcpConnection(*dispatcher, connection); } } } } } } } int result = closesocket(connection); assert(result == 0); } throw std::runtime_error("TcpConnector::connect, " + message); }
void Timer::sleep(std::chrono::nanoseconds duration) { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } if(duration.count() == 0 ) { dispatcher->yield(); } else { timer = dispatcher->getTimer(); auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration); itimerspec expires; expires.it_interval.tv_nsec = expires.it_interval.tv_sec = 0; expires.it_value.tv_sec = seconds.count(); expires.it_value.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(duration - seconds).count(); timerfd_settime(timer, 0, &expires, NULL); ContextPair contextPair; OperationContext timerContext; timerContext.interrupted = false; timerContext.context = dispatcher->getCurrentContext(); contextPair.writeContext = nullptr; contextPair.readContext = &timerContext; epoll_event timerEvent; timerEvent.events = EPOLLIN | EPOLLONESHOT; timerEvent.data.ptr = &contextPair; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) { throw std::runtime_error("Timer::sleep, epoll_ctl failed, " + lastErrorMessage()); } dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); assert(context != nullptr); OperationContext* timerContext = static_cast<OperationContext*>(context); if (!timerContext->interrupted) { uint64_t value = 0; if(::read(timer, &value, sizeof value) == -1 ){ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wlogical-op" if(errno == EAGAIN || errno == EWOULDBLOCK) { #pragma GCC diagnostic pop timerContext->interrupted = true; dispatcher->pushContext(timerContext->context); } else { throw std::runtime_error("Timer::sleep, interrupt procedure, read failed, " + lastErrorMessage()); } } else { assert(value>0); dispatcher->pushContext(timerContext->context); } epoll_event timerEvent; timerEvent.events = EPOLLONESHOT; timerEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) { throw std::runtime_error("Timer::sleep, interrupt procedure, epoll_ctl failed, " + lastErrorMessage()); } } }; context = &timerContext; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(timerContext.context == dispatcher->getCurrentContext()); assert(contextPair.writeContext == nullptr); assert(context == &timerContext); context = nullptr; timerContext.context = nullptr; dispatcher->pushTimer(timer); if (timerContext.interrupted) { throw InterruptedException(); } } }
TcpConnection TcpListener::accept() { assert(dispatcher != nullptr); assert(context == nullptr); if (dispatcher->interrupted()) { throw InterruptedException(); } std::string message; OperationContext listenerContext; listenerContext.context = dispatcher->getCurrentContext(); listenerContext.interrupted = false; struct kevent event; EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, SOMAXCONN, &listenerContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { message = "kevent() failed, errno=" + std::to_string(errno); } else { context = &listenerContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { assert(dispatcher != nullptr); assert(context != nullptr); OperationContext* listenerContext = static_cast<OperationContext*>(context); if (!listenerContext->interrupted) { struct kevent event; EV_SET(&event, listener, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno)); } listenerContext->interrupted = true; dispatcher->pushContext(listenerContext->context); } }; dispatcher->dispatch(); dispatcher->getCurrentContext()->interruptProcedure = nullptr; assert(dispatcher != nullptr); assert(listenerContext.context == dispatcher->getCurrentContext()); assert(context == &listenerContext); context = nullptr; listenerContext.context = nullptr; if (listenerContext.interrupted) { throw InterruptedException(); } sockaddr inAddr; socklen_t inLen = sizeof(inAddr); int connection = ::accept(listener, &inAddr, &inLen); if (connection == -1) { message = "accept() failed, errno=" + std::to_string(errno); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { message = "fcntl() failed errno=" + std::to_string(errno); } else { return TcpConnection(*dispatcher, connection); } } } throw std::runtime_error("TcpListener::accept, " + message); }