Example #1
0
/*
 * Lock_AF_UNIX -- configure unix socket file path
 */
static int
Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
{
	UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);
	if (strlen(sock_path) >= UNIXSOCK_PATH_BUFLEN)
	{
		ereport(LOG,
				(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
						sock_path,
						(int) (UNIXSOCK_PATH_BUFLEN - 1))));
		return STATUS_ERROR;
	}

	/*
	 * Grab an interlock file associated with the socket file.
	 *
	 * Note: there are two reasons for using a socket lock file, rather than
	 * trying to interlock directly on the socket itself.  First, it's a lot
	 * more portable, and second, it lets us remove any pre-existing socket
	 * file without race conditions.
	 */
	CreateSocketLockFile(sock_path, true);

	/*
	 * Once we have the interlock, we can safely delete any pre-existing
	 * socket file to avoid failure at bind() time.
	 */
	unlink(sock_path);

	return STATUS_OK;
}
Example #2
0
/*
 * Lock_AF_UNIX -- configure unix socket file path
 */
static int
Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
{
	UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);

	/*
	 * Grab an interlock file associated with the socket file.
	 */
	CreateSocketLockFile(sock_path, true);

	/*
	 * Once we have the interlock, we can safely delete any pre-existing
	 * socket file to avoid failure at bind() time.
	 */
	unlink(sock_path);

	return STATUS_OK;
}
Example #3
0
/*
 * Lock_AF_UNIX -- configure unix socket file path
 */
static int
Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
{
	UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);

	/*
	 * Grab an interlock file associated with the socket file.
	 *
	 * Note: there are two reasons for using a socket lock file, rather than
	 * trying to interlock directly on the socket itself.  First, it's a lot
	 * more portable, and second, it lets us remove any pre-existing socket
	 * file without race conditions.
	 */
	CreateSocketLockFile(sock_path, true);

	/*
	 * Once we have the interlock, we can safely delete any pre-existing
	 * socket file to avoid failure at bind() time.
	 */
	unlink(sock_path);

	return STATUS_OK;
}
Example #4
0
char
SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout)
{
	struct addrinfo	rest, *addrs = NULL, *curadr = NULL;
	int	family = 0; 
	char	retval = 0;
	int	gerrno;

	if (self->socket != (SOCKETFD) -1)
	{
		SOCK_set_error(self, SOCKET_ALREADY_CONNECTED, "Socket is already connected");
		return 0;
	}

#if defined(_MSC_VER) && (_MSC_VER < 1300)
	if (ws2_hnd == NULL)
		ws2_hnd = GetModuleHandle("ws2_32.dll");
	if (freeaddrinfo_ptr == NULL)
		freeaddrinfo_ptr = (freeaddrinfo_func)GetProcAddress(ws2_hnd, "freeaddrinfo"); 
	if (getaddrinfo_ptr == NULL)
		getaddrinfo_ptr = (getaddrinfo_func)GetProcAddress(ws2_hnd, "getaddrinfo"); 
	if (getnameinfo_ptr == NULL)
		getnameinfo_ptr = (getnameinfo_func)GetProcAddress(ws2_hnd, "getnameinfo"); 
#endif
	/*
	 * Hostname lookup.
	 */
	if (hostname && hostname[0]
#ifndef	WIN32
	    && '/' != hostname[0]
#endif /* WIN32 */
	   )
	{
		char	portstr[16];
		int	ret;

		memset(&rest, 0, sizeof(rest));
		rest.ai_socktype = SOCK_STREAM;
		rest.ai_family = AF_UNSPEC;
		snprintf(portstr, sizeof(portstr), "%d", port);
		if (inet_addr(hostname) != INADDR_NONE)
			rest.ai_flags |= AI_NUMERICHOST;	
		ret = getaddrinfo_ptr(hostname, portstr, &rest, &addrs);
		if (ret || !addrs)
		{
			SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
			if (addrs)
				freeaddrinfo_ptr(addrs);
			return 0;
		}
		curadr = addrs;
	}
	else
#ifdef	HAVE_UNIX_SOCKETS
	{
		struct sockaddr_un *un = (struct sockaddr_un *) &(self->sadr_area);
		family = un->sun_family = AF_UNIX;
		/* passing NULL or '' means pg default "/tmp" */
		UNIXSOCK_PATH(un, port, hostname);
		self->sadr_len = UNIXSOCK_LEN(un);
	}
#else
	{
		SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Hostname isn't specified.");
		return 0;
	}
#endif /* HAVE_UNIX_SOCKETS */

retry:
	if (curadr)
		family = curadr->ai_family;
	self->socket = socket(family, SOCK_STREAM, 0);
	if (self->socket == (SOCKETFD) -1)
	{
		SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "Could not create Socket.");
		goto cleanup;
	}
#ifdef	TCP_NODELAY
	if (family != AF_UNIX)
	{
		int i;
		socklen_t	len;

		i = 1;
		len = sizeof(i);
		if (setsockopt(self->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &i, len) < 0)
		{
			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not set socket to NODELAY.");
			goto cleanup;
		}
	}
#endif /* TCP_NODELAY */
#ifdef	WIN32
	{
		long	ioctlsocket_ret = 1;

		/* Returns non-0 on failure, while fcntl() returns -1 on failure */
		ioctlsocket(self->socket, FIONBIO, &ioctlsocket_ret);
	}
#else
        fcntl(self->socket, F_SETFL, O_NONBLOCK);
#endif

	if (curadr)
	{
		struct sockaddr *in = (struct sockaddr *) &(self->sadr_area);
		memset((char *) in, 0, sizeof(self->sadr_area));
		memcpy(in, curadr->ai_addr, curadr->ai_addrlen);
		self->sadr_len = (int) curadr->ai_addrlen;
	}
	if (connect(self->socket, (struct sockaddr *) &(self->sadr_area), self->sadr_len) < 0)
	{
		int	ret, optval;
		int	wait_sec = 0;
#ifdef	HAVE_POLL
		struct pollfd	fds;
#else
		fd_set	fds, except_fds;
		struct	timeval	tm;
#endif /* HAVE_POLL */
		socklen_t	optlen = sizeof(optval);
		time_t	t_now, t_finish = 0;
		BOOL	tm_exp = FALSE;

		gerrno = SOCK_ERRNO;
		switch (gerrno)
		{
			case 0:
			case EINPROGRESS:
			case EINTR:
#ifdef EAGAIN
			case EAGAIN:
#endif /* EAGAIN */
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
			case EWOULDBLOCK:
#endif /* EWOULDBLOCK */
		    		break;
			default:
				SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket immedaitely");
				goto cleanup;
		}
		if (timeout > 0)
		{
			t_now = time(NULL);
			t_finish = t_now + timeout;
			wait_sec = timeout;
		}
		do {
#ifdef	HAVE_POLL
			fds.fd = self->socket;
			fds.events = POLLOUT;
			fds.revents = 0;
			ret = poll(&fds, 1, timeout > 0 ? wait_sec * 1000 : -1);
#else
			tm.tv_sec = wait_sec;
			tm.tv_usec = 0;
			FD_ZERO(&fds);
			FD_ZERO(&except_fds);
			FD_SET(self->socket, &fds);
			FD_SET(self->socket, &except_fds);
			ret = select((int) self->socket + 1, NULL, &fds, &except_fds, timeout > 0 ? &tm : NULL);
#endif /* HAVE_POLL */
			gerrno = SOCK_ERRNO;
			if (0 < ret)
				break;
			else if (0 == ret)
				tm_exp = TRUE;
			else if (EINTR != gerrno)
				break;
			else if (timeout > 0)
			{
				if (t_now = time(NULL), t_now >= t_finish)
					tm_exp = TRUE;
				else
					wait_sec = (int) (t_finish - t_now);
			}
		} while (!tm_exp);
		if (tm_exp)
		{
			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. timeout occured.");
			goto cleanup;
		}
		else if (0 > ret)
		{
			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. select error occured.");
			mylog("select error ret=%d ERROR=%d\n", ret, gerrno);
			goto cleanup;
		}
		if (getsockopt(self->socket, SOL_SOCKET, SO_ERROR,
				(char *) &optval, &optlen) == -1)
		{
			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. getsockopt error.");
		}
		else if (optval != 0)
		{
			char	errmsg[256], host[64];

			host[0] = '\0';
#if defined(_MSC_VER) && (_MSC_VER < 1300)
			getnameinfo_ptr
#else
			getnameinfo
#endif
				((struct sockaddr *) &(self->sadr_area),
					self->sadr_len, host, sizeof(host),
					NULL, 0, NI_NUMERICHOST);
			/* snprintf(errmsg, sizeof(errmsg), "connect getsockopt val %d addr=%s\n", optval, host); */
			format_sockerr(errmsg, sizeof(errmsg), optval, "connect", host, port);
			mylog(errmsg);
			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, errmsg);
		}
		else
			retval = 1;
	}
	else
		retval = 1;

cleanup:
	if (0 == retval)
	{
		if (self->socket >= 0)
		{
			closesocket(self->socket);
			self->socket = (SOCKETFD) -1;
		}
		if (curadr && curadr->ai_next)
		{
			curadr = curadr->ai_next;
			goto retry;
		}
	}
	else
		SOCK_set_error(self, 0, NULL);
	
	if (addrs)
		freeaddrinfo_ptr(addrs);
	return retval;
}
Example #5
0
int
StreamServerPort(int family, char *hostName, unsigned short portNumber,
				 char *unixSocketDir,
				 pgsocket ListenSocket[], int MaxListen)
{
	pgsocket	fd;
	int			err;
	int			maxconn;
	int			ret;
	char		portNumberStr[32];
	const char *familyDesc;
	char		familyDescBuf[64];
	char	   *service;
	struct addrinfo *addrs = NULL,
			   *addr;
	struct addrinfo hint;
	int			listen_index = 0;
	int			added = 0;

#ifdef HAVE_UNIX_SOCKETS
	char		unixSocketPath[MAXPGPATH];
#endif
#if !defined(WIN32) || defined(IPV6_V6ONLY)
	int			one = 1;
#endif

	/* Initialize hint structure */
	MemSet(&hint, 0, sizeof(hint));
	hint.ai_family = family;
	hint.ai_flags = AI_PASSIVE;
	hint.ai_socktype = SOCK_STREAM;

#ifdef HAVE_UNIX_SOCKETS
	if (family == AF_UNIX)
	{
		/*
		 * Create unixSocketPath from portNumber and unixSocketDir and lock
		 * that file path
		 */
		UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir);
		if (strlen(unixSocketPath) >= UNIXSOCK_PATH_BUFLEN)
		{
			ereport(LOG,
					(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
							unixSocketPath,
							(int) (UNIXSOCK_PATH_BUFLEN - 1))));
			return STATUS_ERROR;
		}
		if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK)
			return STATUS_ERROR;
		service = unixSocketPath;
	}
	else
#endif   /* HAVE_UNIX_SOCKETS */
	{
		snprintf(portNumberStr, sizeof(portNumberStr), "%d", portNumber);
		service = portNumberStr;
	}

	ret = pg_getaddrinfo_all(hostName, service, &hint, &addrs);
	if (ret || !addrs)
	{
		if (hostName)
			ereport(LOG,
					(errmsg("could not translate host name \"%s\", service \"%s\" to address: %s",
							hostName, service, gai_strerror(ret))));
		else
			ereport(LOG,
				 (errmsg("could not translate service \"%s\" to address: %s",
						 service, gai_strerror(ret))));
		if (addrs)
			pg_freeaddrinfo_all(hint.ai_family, addrs);
		return STATUS_ERROR;
	}

	for (addr = addrs; addr; addr = addr->ai_next)
	{
		if (!IS_AF_UNIX(family) && IS_AF_UNIX(addr->ai_family))
		{
			/*
			 * Only set up a unix domain socket when they really asked for it.
			 * The service/port is different in that case.
			 */
			continue;
		}

		/* See if there is still room to add 1 more socket. */
		for (; listen_index < MaxListen; listen_index++)
		{
			if (ListenSocket[listen_index] == PGINVALID_SOCKET)
				break;
		}
		if (listen_index >= MaxListen)
		{
			ereport(LOG,
					(errmsg("could not bind to all requested addresses: MAXLISTEN (%d) exceeded",
							MaxListen)));
			break;
		}

		/* set up family name for possible error messages */
		switch (addr->ai_family)
		{
			case AF_INET:
				familyDesc = _("IPv4");
				break;
#ifdef HAVE_IPV6
			case AF_INET6:
				familyDesc = _("IPv6");
				break;
#endif
#ifdef HAVE_UNIX_SOCKETS
			case AF_UNIX:
				familyDesc = _("Unix");
				break;
#endif
			default:
				snprintf(familyDescBuf, sizeof(familyDescBuf),
						 _("unrecognized address family %d"),
						 addr->ai_family);
				familyDesc = familyDescBuf;
				break;
		}

		if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
		{
			ereport(LOG,
					(errcode_for_socket_access(),
			/* translator: %s is IPv4, IPv6, or Unix */
					 errmsg("could not create %s socket: %m",
							familyDesc)));
			continue;
		}

#ifndef WIN32

		/*
		 * Without the SO_REUSEADDR flag, a new postmaster can't be started
		 * right away after a stop or crash, giving "address already in use"
		 * error on TCP ports.
		 *
		 * On win32, however, this behavior only happens if the
		 * SO_EXLUSIVEADDRUSE is set. With SO_REUSEADDR, win32 allows multiple
		 * servers to listen on the same address, resulting in unpredictable
		 * behavior. With no flags at all, win32 behaves as Unix with
		 * SO_REUSEADDR.
		 */
		if (!IS_AF_UNIX(addr->ai_family))
		{
			if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
							(char *) &one, sizeof(one))) == -1)
			{
				ereport(LOG,
						(errcode_for_socket_access(),
						 errmsg("setsockopt(SO_REUSEADDR) failed: %m")));
				closesocket(fd);
				continue;
			}
		}
#endif

#ifdef IPV6_V6ONLY
		if (addr->ai_family == AF_INET6)
		{
			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
						   (char *) &one, sizeof(one)) == -1)
			{
				ereport(LOG,
						(errcode_for_socket_access(),
						 errmsg("setsockopt(IPV6_V6ONLY) failed: %m")));
				closesocket(fd);
				continue;
			}
		}
#endif

		/*
		 * Note: This might fail on some OS's, like Linux older than
		 * 2.4.21-pre3, that don't have the IPV6_V6ONLY socket option, and map
		 * ipv4 addresses to ipv6.  It will show ::ffff:ipv4 for all ipv4
		 * connections.
		 */
		err = bind(fd, addr->ai_addr, addr->ai_addrlen);
		if (err < 0)
		{
			ereport(LOG,
					(errcode_for_socket_access(),
			/* translator: %s is IPv4, IPv6, or Unix */
					 errmsg("could not bind %s socket: %m",
							familyDesc),
					 (IS_AF_UNIX(addr->ai_family)) ?
				  errhint("Is another postmaster already running on port %d?"
						  " If not, remove socket file \"%s\" and retry.",
						  (int) portNumber, service) :
				  errhint("Is another postmaster already running on port %d?"
						  " If not, wait a few seconds and retry.",
						  (int) portNumber)));
			closesocket(fd);
			continue;
		}

#ifdef HAVE_UNIX_SOCKETS
		if (addr->ai_family == AF_UNIX)
		{
			if (Setup_AF_UNIX(service) != STATUS_OK)
			{
				closesocket(fd);
				break;
			}
		}
#endif

		/*
		 * Select appropriate accept-queue length limit.  PG_SOMAXCONN is only
		 * intended to provide a clamp on the request on platforms where an
		 * overly large request provokes a kernel error (are there any?).
		 */
		maxconn = MaxBackends * 2;
		if (maxconn > PG_SOMAXCONN)
			maxconn = PG_SOMAXCONN;

		err = listen(fd, maxconn);
		if (err < 0)
		{
			ereport(LOG,
					(errcode_for_socket_access(),
			/* translator: %s is IPv4, IPv6, or Unix */
					 errmsg("could not listen on %s socket: %m",
							familyDesc)));
			closesocket(fd);
			continue;
		}
		ListenSocket[listen_index] = fd;
		added++;
	}

	pg_freeaddrinfo_all(hint.ai_family, addrs);

	if (!added)
		return STATUS_ERROR;

	return STATUS_OK;
}