/** Decrements the internal reference count, marking the end of the section using this connection. * * \note After the unref()-call, the connection object MUST NOT be used any more. * If the unref()-call results into a reference-count of zero <b>AND</b> the connection * has been closed during this time, the connection will be released / destructed. * * \see ref() */ void HttpConnection::unref() { --refCount_; TRACE("unref() %ld (closed:%d, outputPending:%d)", refCount_, isClosed(), isOutputPending()); if (refCount_ == 0 && isClosed() && !isOutputPending()) { worker_->release(handle_); } }
/*! Invokes the abort-callback (if set) and closes/releases this connection. * * \see close() * \see HttpRequest::finish() */ void HttpConnection::abort() { TRACE("abort()"); if (isAborted()) return; //assert(!isAborted() && "The connection may be only aborted once."); flags_ |= IsAborted; if (isOutputPending()) { TRACE("abort: clearing pending output (%ld)", output_.size()); output_.clear(); } if (abortHandler_) { assert(request_ != nullptr); // the client aborted the connection, so close the client-socket right away to safe resources socket_->close(); abortHandler_(abortData_); } else { request_->clearCustomData(); close(); } }
/** * Writes as much as it wouldn't block of the response stream into the underlying socket. * */ bool HttpConnection::writeSome() { TRACE("writeSome()"); ref(); ssize_t rv = output_.sendto(sink_); TRACE("writeSome(): sendto().rv=%ld %s", rv, rv < 0 ? strerror(errno) : ""); if (rv > 0) { // output chunk written request_->bytesTransmitted_ += rv; goto done; } if (rv == 0) { // output fully written watchInput(); if (request_->isFinished()) { // finish() got invoked before reply was fully sent out, thus, // finalize() was delayed. request_->finalize(); } TRACE("writeSome: output fully written. closed:%d, outputPending:%ld, refCount:%d", isClosed(), output_.size(), refCount_); if (isClosed() && !isOutputPending() && refCount_ == 0) { worker_->release(handle_); } goto done; } // sendto() failed switch (errno) { case EINTR: break; case EAGAIN: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif // complete write would block, so watch write-ready-event and be called back watchOutput(); break; default: //log(Severity::error, "Connection write error: %s", strerror(errno)); goto err; } done: unref(); return true; err: abort(); unref(); return false; }
void HttpConnection::flush() { if (!isOutputPending()) return; #if defined(ENABLE_OPPORTUNISTIC_WRITE) writeSome(); #else watchOutput(); #endif }
/** Decrements the internal reference count, marking the end of the section using this connection. * * \note After the unref()-call, the connection object MUST NOT be used any more. * If the unref()-call results into a reference-count of zero <b>AND</b> the connection * has been closed during this time, the connection will be released / destructed. * * \see ref() */ void HttpConnection::unref() { --refCount_; TRACE(1, "unref() %u (closed:%d, outputPending:%d)", refCount_, isClosed(), isOutputPending()); if (refCount_ == 0) { clear(); worker_->release(this); } }
/** Closes this HttpConnection, possibly deleting this object (or propagating delayed delete). */ void HttpConnection::close() { TRACE("close()"); //TRACE("Stack Trace:%s\n", StackTrace().c_str()); if (isClosed()) return; if (isInsideSocketCallback()) { // we're currently in io() -> readSome(), so just mark socket as closed flags_ |= IsClosed; if (!isOutputPending()) socket_->setMode(Socket::None); } else { // we're outside io() -> readSome(), so destruct right away worker_->release(handle_); } }