Esempio n. 1
0
int
connectToTcpServer(const StaticString &hostname, unsigned int port) {
	struct addrinfo hints, *res;
	int ret, e, fd;
	
	memset(&hints, 0, sizeof(hints));
	hints.ai_family   = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	ret = getaddrinfo(hostname.c_str(), toString(port).c_str(), &hints, &res);
	if (ret != 0) {
		string message = "Cannot resolve IP address '";
		message.append(hostname.toString());
		message.append(":");
		message.append(toString(port));
		message.append("': ");
		message.append(gai_strerror(ret));
		throw IOException(message);
	}
	
	try {
		fd = syscalls::socket(PF_INET, SOCK_STREAM, 0);
	} catch (...) {
		freeaddrinfo(res);
		throw;
	}
	if (fd == -1) {
		e = errno;
		freeaddrinfo(res);
		throw SystemException("Cannot create a TCP socket file descriptor", e);
	}
	
	try {
		ret = syscalls::connect(fd, res->ai_addr, res->ai_addrlen);
	} catch (...) {
		freeaddrinfo(res);
		do {
			ret = close(fd);
		} while (ret == -1 && errno == EINTR);
		throw;
	}
	e = errno;
	freeaddrinfo(res);
	if (ret == -1) {
		string message = "Cannot connect to TCP socket '";
		message.append(hostname.toString());
		message.append(":");
		message.append(toString(port));
		message.append("'");
		do {
			ret = close(fd);
		} while (ret == -1 && errno == EINTR);
		throw SystemException(message, e);
	}
	
	return fd;
}
Esempio n. 2
0
int
createUnixServer(const StaticString &filename, unsigned int backlogSize, bool autoDelete,
	const char *file, unsigned int line)
{
	struct sockaddr_un addr;
	int fd, ret;

	if (filename.size() > sizeof(addr.sun_path) - 1) {
		string message = "Cannot create Unix socket '";
		message.append(filename.toString());
		message.append("': filename is too long.");
		throw RuntimeException(message);
	}

	fd = syscalls::socket(PF_LOCAL, SOCK_STREAM, 0);
	if (fd == -1) {
		int e = errno;
		throw SystemException("Cannot create a Unix socket file descriptor", e);
	}

	FdGuard guard(fd, file, line, true);
	addr.sun_family = AF_LOCAL;
	strncpy(addr.sun_path, filename.c_str(), filename.size());
	addr.sun_path[filename.size()] = '\0';

	if (autoDelete) {
		do {
			ret = unlink(filename.c_str());
		} while (ret == -1 && errno == EINTR);
	}

	ret = syscalls::bind(fd, (const struct sockaddr *) &addr, sizeof(addr));
	if (ret == -1) {
		int e = errno;
		string message = "Cannot bind Unix socket '";
		message.append(filename.toString());
		message.append("'");
		throw SystemException(message, e);
	}

	if (backlogSize == 0) {
		backlogSize = 1024;
	}
	ret = syscalls::listen(fd, backlogSize);
	if (ret == -1) {
		int e = errno;
		string message = "Cannot listen on Unix socket '";
		message.append(filename.toString());
		message.append("'");
		safelyClose(fd, true);
		throw SystemException(message, e);
	}

	guard.clear();
	return fd;
}
Esempio n. 3
0
void
setupNonBlockingTcpSocket(NTCP_State &state, const StaticString &hostname, int port) {
	int ret;

	memset(&state.hints, 0, sizeof(state.hints));
	state.hints.ai_family   = PF_UNSPEC;
	state.hints.ai_socktype = SOCK_STREAM;
	ret = getaddrinfo(hostname.toString().c_str(), toString(port).c_str(),
		&state.hints, &state.res);
	if (ret != 0) {
		string message = "Cannot resolve IP address '";
		message.append(hostname.data(), hostname.size());
		message.append(":");
		message.append(toString(port));
		message.append("': ");
		message.append(gai_strerror(ret));
		throw IOException(message);
	}

	state.fd = syscalls::socket(PF_INET, SOCK_STREAM, 0);
	if (state.fd == -1) {
		int e = errno;
		throw SystemException("Cannot create a TCP socket file descriptor", e);
	}

	state.hostname = hostname;
	state.port = port;
	setNonBlocking(state.fd);
}
Esempio n. 4
0
int
connectToUnixServer(const StaticString &filename, const char *file,
	unsigned int line)
{
	int fd = syscalls::socket(PF_UNIX, SOCK_STREAM, 0);
	if (fd == -1) {
		int e = errno;
		throw SystemException("Cannot create a Unix socket file descriptor", e);
	}

	FdGuard guard(fd, file, line, true);
	int ret;
	struct sockaddr_un addr;

	if (filename.size() > sizeof(addr.sun_path) - 1) {
		string message = "Cannot connect to Unix socket '";
		message.append(filename.data(), filename.size());
		message.append("': filename is too long.");
		throw RuntimeException(message);
	}

	addr.sun_family = AF_UNIX;
	memcpy(addr.sun_path, filename.c_str(), filename.size());
	addr.sun_path[filename.size()] = '\0';

	bool retry = true;
	int counter = 0;
	while (retry) {
		ret = syscalls::connect(fd, (const sockaddr *) &addr, sizeof(addr));
		if (ret == -1) {
			#if defined(sun) || defined(__sun)
				/* Solaris has this nice kernel bug where connecting to
				 * a newly created Unix socket which is obviously
				 * connectable can cause an ECONNREFUSED. So we retry
				 * in a loop.
				 */
				retry = errno == ECONNREFUSED;
			#else
				retry = false;
			#endif
			retry = retry && counter < 9;

			if (retry) {
				syscalls::usleep((useconds_t) (10000 * pow((double) 2, (double) counter)));
				counter++;
			} else {
				int e = errno;
				string message("Cannot connect to Unix socket '");
				message.append(filename.toString());
				message.append("'");
				throw SystemException(message, e);
			}
		} else {
			guard.clear();
			return fd;
		}
	}
	abort();   // Never reached.
	return -1; // Shut up compiler warning.
}