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; }
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; }
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); }
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. }