Beispiel #1
0
Socket::Socket(struct ev_loop* loop, int fd, int af) :
	loop_(loop),
	watcher_(loop),
	timer_(loop),
	startedAt_(ev_now(loop)),
	lastActivityAt_(ev_now(loop)),
	fd_(fd),
	addressFamily_(af),
	secure_(false),
	state_(Operational),
	mode_(None),
	tcpCork_(false),
	remoteIP_(),
	remotePort_(0),
	localIP_(),
	localPort_(),
	callback_(nullptr),
	callbackData_(0)
{
#ifndef NDEBUG
	setLogging(false);
	static std::atomic<unsigned long long> id(0);
	setLoggingPrefix("Socket(%d, %s:%d)", ++id, remoteIP().c_str(), remotePort());
#endif
	TRACE("created. fd:%d, local(%s:%d)", fd_, localIP().c_str(), localPort());

	watcher_.set<Socket, &Socket::io>(this);
	timer_.set<Socket, &Socket::timeout>(this);
}
Beispiel #2
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();
}
Beispiel #3
0
bool Socket::openUnix(const std::string& unixPath, int flags)
{
#ifndef NDEBUG
	setLoggingPrefix("Socket(unix:%s)", unixPath.c_str());
#endif

	TRACE("connect(unix=%s)", unixPath.c_str());

	flags |= O_NONBLOCK | O_CLOEXEC;

	int typeMask = 0;

#if defined(SOCK_NONBLOCK)
	if (flags & O_NONBLOCK) {
		flags &= ~O_NONBLOCK;
		typeMask |= SOCK_NONBLOCK;
	}
#endif

#if defined(SOCK_CLOEXEC)
	if (flags & O_CLOEXEC) {
		flags &= ~O_CLOEXEC;
		typeMask |= SOCK_CLOEXEC;
	}
#endif

	fd_ = ::socket(PF_UNIX, SOCK_STREAM | typeMask, 0);
	if (fd_ < 0) {
		TRACE("socket creation error: %s",  strerror(errno));
		return false;
	}

	if (flags) {
		if (fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | flags) < 0) {
			// error
		}
	}

	struct sockaddr_un addr;
	addr.sun_family = AF_UNIX;
	size_t addrlen = sizeof(addr.sun_family)
		+ strlen(strncpy(addr.sun_path, unixPath.c_str(), sizeof(addr.sun_path)));

	int rv = ::connect(fd_, (struct sockaddr*) &addr, addrlen);
	if (rv < 0) {
		::close(fd_);
		fd_ = -1;
		TRACE("could not connect to %s: %s", unixPath.c_str(), strerror(errno));
		return false;
	}

	state_ = Operational;

	return true;
}
Beispiel #4
0
// {{{ HttpProxy impl
HttpProxy::HttpProxy(HttpDirector* director, const std::string& name,
		size_t capacity, const std::string& hostname, int port) :
	HttpBackend(director, name, capacity),
	hostname_(hostname),
	port_(port),
	connections_()
{
#ifndef NDEBUG
	setLoggingPrefix("HttpProxy/%s", name.c_str());
#endif
}
Beispiel #5
0
bool Socket::openTcp(const IPAddress& host, int port, int flags)
{
#ifndef NDEBUG
	setLoggingPrefix("Socket(tcp:%s:%d)", host.str().c_str(), port);
#endif

	flags |= O_NONBLOCK | O_CLOEXEC;

	int typeMask = 0;

#if defined(SOCK_NONBLOCK)
	if (flags & O_NONBLOCK) {
		flags &= ~O_NONBLOCK;
		typeMask |= SOCK_NONBLOCK;
	}
#endif

#if defined(SOCK_CLOEXEC)
	if (flags & O_CLOEXEC) {
		flags &= ~O_CLOEXEC;
		typeMask |= SOCK_CLOEXEC;
	}
#endif

	fd_ = ::socket(host.family(), SOCK_STREAM | typeMask, IPPROTO_TCP);
	if (fd_ < 0) {
		TRACE("socket creation error: %s",  strerror(errno));
		return false;
	}

	if (flags) {
		if (fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | flags) < 0) {
			// error
		}
	}

	int rv = ::connect(fd_, (struct sockaddr*) host.data(), host.size());
	if (rv == 0) {
		TRACE("connect: instant success (fd:%d)", fd_);
		state_ = Operational;
		return true;
	} else if (/*rv < 0 &&*/ errno == EINPROGRESS) {
		TRACE("connect: backgrounding (fd:%d)", fd_);
		state_ = Connecting;
		setMode(Write);
		return true;
	} else {
		TRACE("could not connect to %s:%d: %s", host.str().c_str(), port, strerror(errno));
		::close(fd_);
		fd_ = -1;
		return false;
	}
}
Beispiel #6
0
// {{{ HttpProxy::ProxyConnection impl
HttpProxy::ProxyConnection::ProxyConnection(HttpProxy* proxy) :
	HttpMessageProcessor(HttpMessageProcessor::RESPONSE),
	proxy_(proxy),
	refCount_(1),
	request_(nullptr),
	backend_(nullptr),
	cloak_(true),

	connectTimeout_(0),
	readTimeout_(0),
	writeTimeout_(0),
	writeBuffer_(),
	writeOffset_(0),
	writeProgress_(0),
	readBuffer_(),
	processingDone_(false)
{
#ifndef NDEBUG
	setLoggingPrefix("ProxyConnection/%p", this);
#endif
	TRACE("ProxyConnection()");
}
Beispiel #7
0
HttpRequest::HttpRequest(HttpConnection& conn) :
	outputState_(Unhandled),
	connection(conn),
	method(),
	uri(),
	path(),
	fileinfo(),
	pathinfo(),
	query(),
	httpVersionMajor(0),
	httpVersionMinor(0),
	requestHeaders(),
	bytesTransmitted_(0),
	username(),
	documentRoot(),
	expectingContinue(false),
	//customData(),

	status(),
	responseHeaders(),
	outputFilters(),

	hostid_(),
	bodyCallback_(nullptr),
	bodyCallbackData_(nullptr),
	errorHandler_(nullptr)
{
#ifndef NDEBUG
	static std::atomic<unsigned long long> rid(0);
	setLoggingPrefix("HttpRequest(%lld,%s:%d)", ++rid, connection.remoteIP().c_str(), connection.remotePort());
#endif

	responseHeaders.push_back("Date", connection.worker().now().http_str().str());

	if (connection.worker().server().advertise() && !connection.worker().server().tag().empty())
		if (!responseHeaders.contains("Server"))
			responseHeaders.push_back("Server", connection.worker().server().tag());
}
Beispiel #8
0
/*! starts listening on a UNIX domain server socket.
 *
 * \param path the path on the local file system, that this socket is to listen to.
 * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket
 *
 * \retval true successfully initialized
 * \retval false some failure occured during setting up the server socket.
 */
bool ServerSocket::open(const std::string& path, int flags)
{
#ifndef NDEBUG
	setLoggingPrefix("ServerSocket(%s)", path.c_str());
#endif
	TRACE("opening");

	int fd = -1;
	size_t addrlen;
	int sd_fd_count = sd_listen_fds(false);

	typeMask_ = 0;
	flags_ = flags;

	if (flags & O_CLOEXEC) {
		flags_ &= ~O_CLOEXEC;
		typeMask_ |= SOCK_CLOEXEC;
	}

	if (flags & O_NONBLOCK) {
		flags_ &= ~O_NONBLOCK;
		typeMask_ |= SOCK_NONBLOCK;
	}

	// check if passed by parent x0d first
	if ((fd = x0::getSocketUnix(path.c_str())) >= 0) {
		// socket found, but ensure our expected `flags` are set.
		if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) {
			goto syserr;
		} else {
			goto done;
		}
	}

	// check if systemd created the socket for us
	if (sd_fd_count > 0) {
		fd = SD_LISTEN_FDS_START;
		int last = fd + sd_fd_count;

		for (; fd < last; ++fd) {
			if (sd_is_socket_unix(fd, AF_UNIX, SOCK_STREAM, path.c_str(), path.size()) > 0) {
				// socket found, but ensure our expected `flags` are set.
				if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) {
					goto syserr;
				} else {
					goto done;
				}
			}
		}

		errorText_ = "Running under systemd socket unit, but we received no UNIX-socket for \"" + path + "\".";
		goto err;
	}

	// create socket manually
	fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
	if (fd < 0)
		goto syserr;

	if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0)
		goto syserr;

	struct sockaddr_un addr;
	addr.sun_family = AF_UNIX;

	if (path.size() >= sizeof(addr.sun_path)) {
		errno = ENAMETOOLONG;
		goto syserr;
	}

	addrlen = sizeof(addr.sun_family)
		+ strlen(strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path)));

	if (::bind(fd, reinterpret_cast<struct sockaddr*>(&addr), addrlen) < 0)
		goto syserr;

	if (::listen(fd, backlog_))
		goto syserr;

	if (chmod(path.c_str(), 0666) < 0) {
		perror("chmod");
	}

done:
	fd_ = fd;
	addressFamily_ = AF_UNIX;
	address_ = path;
	port_ = 0;

	io_.set<ServerSocket, &ServerSocket::accept>(this);
	start();

	return true;

syserr:
	errorText_ = strerror(errno);

err:
	if (fd >= 0)
		::close(fd);

	return false;
}
Beispiel #9
0
/*! starts listening on a TCP/IP (v4 or v6) address.
 *
 * \param address the IP address to bind to
 * \param port the TCP/IP port number to listen to
 * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket
 *
 * \retval true successfully initialized
 * \retval false some failure occured during setting up the server socket.
 */
bool ServerSocket::open(const std::string& address, int port, int flags)
{
#ifndef NDEBUG
	setLoggingPrefix("ServerSocket(%s:%d)", address.c_str(), port);
#endif
	TRACE("opening");

	int sd_fd_count = sd_listen_fds(false);
	addrinfo* res = nullptr;
	addrinfo hints;

	addrinfo* ri = nullptr;
	int rc;
	int fd = -1;
	in6_addr saddr;

	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_NUMERICSERV;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ((rc = inet_pton(AF_INET, address.c_str(), &saddr)) == 1) {
		hints.ai_family = AF_INET;
		hints.ai_flags |= AI_NUMERICHOST;
	} else if ((rc = inet_pton(AF_INET6, address.c_str(), &saddr)) == 1) {
		hints.ai_family = AF_INET6;
		hints.ai_flags |= AI_NUMERICHOST;
	} else {
		switch (rc) {
			case -1: // errno is set properly
				errorText_ = strerror(errno);
				break;
			case 0: // invalid network addr format
				errorText_ = strerror(EINVAL);
				break;
			default: // unknown error
				errorText_ = strerror(EINVAL);
				break;
		}
		return false;
	}

	char sport[16];
	snprintf(sport, sizeof(sport), "%d", port);

	if ((rc = getaddrinfo(address.c_str(), sport, &hints, &res)) != 0) {
		errorText_ = gai_strerror(rc);
		goto err;
	}

	typeMask_ = 0;
	flags_ = flags;

	if (flags & O_CLOEXEC) {
		flags_ &= ~O_CLOEXEC;
		typeMask_ |= SOCK_CLOEXEC;
	}

	if (flags & O_NONBLOCK) {
		flags_ &= ~O_NONBLOCK;
		typeMask_ |= SOCK_NONBLOCK;
	}

	// check if passed by parent x0d first
	for (ri = res; ri != nullptr; ri = ri->ai_next) {
		if ((fd = x0::getSocketInet(address.c_str(), port)) >= 0) {
			// socket found, but ensure our expected `flags` are set.
			if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0)
				goto syserr;

			if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0)
				goto syserr;

			goto done;
		}
	}

	// check if systemd created the socket for us
	if (sd_fd_count > 0) {
		fd = SD_LISTEN_FDS_START;
		int last = fd + sd_fd_count;

		for (addrinfo* ri = res; ri != nullptr; ri = ri->ai_next) {
			for (; fd < last; ++fd) {
				if (sd_is_socket_inet(fd, ri->ai_family, ri->ai_socktype, true, port) > 0) {
					// socket found, but ensure our expected `flags` are set.
					if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0)
						goto syserr;

					if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0)
						goto syserr;

#if defined(TCP_QUICKACK)
					if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0)
						goto syserr;
#endif

#if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT)
					if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0)
						goto syserr;
#endif
					goto done;
				}
			}
		}

		char buf[256];
		snprintf(buf, sizeof(buf), "Running under systemd socket unit, but we received no socket for %s:%d.", address.c_str(), port);
		errorText_ = buf;
		goto err;
	}

	// create socket manually
	for (ri = res; ri != nullptr; ri = ri->ai_next) {
		fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		if (fd < 0)
			goto syserr;

		if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0)
			goto syserr;

		if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0)
			goto syserr;

		rc = 1;

#if defined(SO_REUSEADDR)
		if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc)) < 0)
			goto syserr;
#endif

#if defined(TCP_QUICKACK)
		if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0)
			goto syserr;
#endif

#if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT)
		if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0)
			goto syserr;
#endif

		// TODO so_linger(false, 0)
		// TODO so_keepalive(true)

		if (::bind(fd, res->ai_addr, res->ai_addrlen) < 0)
			goto syserr;

		if (::listen(fd, backlog_) < 0)
			goto syserr;

		goto done;
	}

done:
	fd_ = fd;
	addressFamily_ = res->ai_family;
	freeaddrinfo(res);
	address_ = address;
	port_ = port;

	io_.set<ServerSocket, &ServerSocket::accept>(this);
	start();

	return true;

syserr:
	errorText_ = strerror(errno);

err:
	if (res)
		freeaddrinfo(res);

	if (fd >= 0)
		::close(fd);

	return false;
}