示例#1
0
void HttpConnection::io(Socket *, int revents)
{
	TRACE("io(revents=%04x) isHandlingRequest:%d", revents, flags_ & IsHandlingRequest);

	ref();

	if (revents & ev::ERROR) {
		log(Severity::error, "Potential bug in connection I/O watching. Closing.");
		abort();
		goto done;
	}

	if ((revents & Socket::Read) && !readSome())
		goto done;

	if ((revents & Socket::Write) && !writeSome())
		goto done;

	if (!process())
		goto done;

	switch (status()) {
	case ReadingRequest:
		watchInput(worker_->server_.maxReadIdle());
		break;
	case KeepAliveRead:
		watchInput(worker_->server_.maxKeepAlive());
	default:
		break;
	}

done:
	unref();
}
示例#2
0
void HttpConnection::io(Socket *, int revents)
{
	TRACE(1, "io(revents=%04x) isHandlingRequest:%d", revents, isHandlingRequest());

	ref();

	if (revents & ev::ERROR) {
		log(Severity::error, "Potential bug in connection I/O watching. Closing.");
		abort();
		goto done;
	}

	// socket is ready for read?
	if ((revents & Socket::Read) && !readSome())
		goto done;

	// socket is ready for write?
	if ((revents & Socket::Write) && !writeSome())
		goto done;

	switch (status()) {
	case ReadingRequest:
		TRACE(1, "io(): status=%s. Watch for read.", status_str());
		watchInput(worker_->server_.maxReadIdle());
		break;
	case KeepAliveRead:
		if (isInputPending()) {
			do {
				// we're in keep-alive state but have (partial) request in buffer pending
				// so do process it right away
				TRACE(1, "io(): status=%s. Pipelined input pending.", status_str());
				process();
			} while (isInputPending() && status() == KeepAliveRead);

			if (status() == KeepAliveRead) {
				// we're still in keep-alive state but no (partial) request in buffer pending
				// so watch for socket input event.
				TRACE(1, "io(): status=%s. Watch for read (keep-alive).", status_str());
				watchInput(worker_->server_.maxKeepAlive());
			}
		} else {
			// we are in keep-alive state and have no (partial) request in buffer pending
			// so watch for socket input event.
			TRACE(1, "io(): status=%s. Watch for read (keep-alive).", status_str());
			watchInput(worker_->server_.maxKeepAlive());
		}
		break;
	case ProcessingRequest:
	case SendingReplyDone:
	case SendingReply:
	case Undefined: // should never be reached
		TRACE(1, "io(): status=%s. Do not touch I/O watcher.", status_str());
		break;
	}

done:
	unref();
}
示例#3
0
/**
 * 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;
}
示例#4
0
/** start first async operation for this HttpConnection.
 *
 * This is done by simply registering the underlying socket to the the I/O service
 * to watch for available input.
 *
 * \note This method must be invoked right after the object construction.
 *
 * \see stop()
 */
void HttpConnection::start(ServerSocket* listener, Socket* client, const HttpWorker::ConnectionHandle& handle)
{
	handle_ = handle;
	listener_ = listener;

	socket_ = client;
	socket_->setReadyCallback<HttpConnection, &HttpConnection::io>(this);

	sink_.setSocket(socket_);

#if defined(TCP_NODELAY)
	if (worker_->server().tcpNoDelay())
		socket_->setTcpNoDelay(true);
#endif

#if !defined(NDEBUG)
	setLoggingPrefix("HttpConnection[%d,%llu|%s:%d]", worker_->id(), id_, remoteIP().c_str(), remotePort());
#endif

	TRACE("starting (fd=%d)", socket_->handle());

	ref(); // <-- this reference is being decremented in close()

	worker_->server_.onConnectionOpen(this);

	if (isAborted()) {
		// The connection got directly closed (aborted) upon connection instance creation (e.g. within the onConnectionOpen-callback),
		// so delete the object right away.
		close();
		return;
	}

	request_ = new HttpRequest(*this);

	ref();
	if (socket_->state() == Socket::Handshake) {
		TRACE("start: handshake.");
		socket_->handshake<HttpConnection, &HttpConnection::handshakeComplete>(this);
	} else {
#if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT)
		TRACE("start: processing input");

		// it is ensured, that we have data pending, so directly start reading
		if (readSome())
			process();
		else
			close();

		TRACE("start: processing input done");
#else
		TRACE("start: watchInput.");
		// client connected, but we do not yet know if we have data pending
		watchInput(worker_->server_.maxReadIdle());
#endif
	}
	unref();
}
示例#5
0
/** start first async operation for this HttpConnection.
 *
 * This is done by simply registering the underlying socket to the the I/O service
 * to watch for available input.
 *
 * \note This method must be invoked right after the object construction.
 *
 * \see stop()
 */
void HttpConnection::start(ServerSocket* listener, Socket* client)
{
	setStatus(ReadingRequest);

	listener_ = listener;

	socket_ = client;
	socket_->setReadyCallback<HttpConnection, &HttpConnection::io>(this);

	sink_.setSocket(socket_);

#if defined(TCP_NODELAY)
	if (worker_->server().tcpNoDelay())
		socket_->setTcpNoDelay(true);
#endif

	if (worker_->server().lingering())
		socket_->setLingering(worker_->server().lingering());

	TRACE(1, "starting (fd=%d)", socket_->handle());

	ref(); // <-- this reference is being decremented in close()

	worker_->server_.onConnectionOpen(this);

	if (isAborted()) {
		// The connection got directly closed (aborted) upon connection instance creation (e.g. within the onConnectionOpen-callback),
		// so delete the object right away.
		close();
		return;
	}

	if (!request_)
		request_ = new HttpRequest(*this);

	ref();
	if (socket_->state() == Socket::Handshake) {
		TRACE(1, "start: handshake.");
		socket_->handshake<HttpConnection, &HttpConnection::handshakeComplete>(this);
	} else {
#if defined(TCP_DEFER_ACCEPT) && defined(ENABLE_TCP_DEFER_ACCEPT)
		TRACE(1, "start: processing input");

		// it is ensured, that we have data pending, so directly start reading
		io(nullptr, ev::READ);

		TRACE(1, "start: processing input done");
#else
		TRACE(1, "start: watchInput.");
		// client connected, but we do not yet know if we have data pending
		watchInput(worker_->server_.maxReadIdle());
#endif
	}
	unref();
}
示例#6
0
void HttpConnection::handshakeComplete(Socket *)
{
	TRACE("handshakeComplete() socketState=%s", socket_->state_str());

	if (socket_->state() == Socket::Operational)
		watchInput(worker_->server_.maxReadIdle());
	else
	{
		TRACE("handshakeComplete(): handshake failed\n%s", StackTrace().c_str());
		close();
	}
}
示例#7
0
/**
 * This method gets invoked when there is data in our HttpConnection ready to read.
 *
 * We assume, that we are in request-parsing state.
 */
bool HttpConnection::readSome()
{
	TRACE("readSome()");

	ref();

	if (status() == KeepAliveRead) {
		TRACE("readSome: status was keep-alive-read. resetting to reading-request", request_->outputState_);
		status_ = ReadingRequest;
	}

	ssize_t rv = socket_->read(input_);

	if (rv < 0) { // error
		switch (errno) {
		case EINTR:
		case EAGAIN:
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
		case EWOULDBLOCK:
#endif
			watchInput(worker_->server_.maxReadIdle());
			break;
		default:
			//log(Severity::error, "Connection read error: %s", strerror(errno));
			goto err;
		}
	} else if (rv == 0) {
		// EOF
		TRACE("readSome: (EOF)");
		goto err;
	} else {
		TRACE("readSome: read %ld bytes, status:%s, ros:%d", rv, status_str(), request_->outputState_);
		process();
	}

	unref();
	return true;

err:
	abort();
	unref();
	return false;
}