Ejemplo n.º 1
0
int
pq_getkeepalivesinterval(Port *port)
{
#ifdef TCP_KEEPINTVL
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return 0;

	if (port->keepalives_interval != 0)
		return port->keepalives_interval;

	if (port->default_keepalives_interval == 0)
	{
		socklen_t	size = sizeof(port->default_keepalives_interval);

		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
					   (char *) &port->default_keepalives_interval,
					   &size) < 0)
		{
			elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m");
			port->default_keepalives_interval = -1;		/* don't know */
		}
	}

	return port->default_keepalives_interval;
#else
	return 0;
#endif
}
Ejemplo n.º 2
0
int
pq_getkeepalivescount(Port *port)
{
#ifdef TCP_KEEPCNT
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return 0;

	if (port->keepalives_count != 0)
		return port->keepalives_count;

	if (port->default_keepalives_count == 0)
	{
		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_count);

		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT,
					   (char *) &port->default_keepalives_count,
					   &size) < 0)
		{
			elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m");
			port->default_keepalives_count = -1;		/* don't know */
		}
	}

	return port->default_keepalives_count;
#else
	return 0;
#endif
}
Ejemplo n.º 3
0
int
pq_getkeepalivesinterval(Port *port)
{
#if defined(TCP_KEEPINTVL) || defined(SIO_KEEPALIVE_VALS)
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return 0;

	if (port->keepalives_interval != 0)
		return port->keepalives_interval;

	if (port->default_keepalives_interval == 0)
	{
#ifndef WIN32
		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_interval);

		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
					   (char *) &port->default_keepalives_interval,
					   &size) < 0)
		{
			elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m");
			port->default_keepalives_interval = -1;		/* don't know */
		}
#else
		/* We can't get the defaults on Windows, so return "don't know" */
		port->default_keepalives_interval = -1;
#endif /* WIN32 */
	}

	return port->default_keepalives_interval;
#else
	return 0;
#endif
}
Ejemplo n.º 4
0
int
pq_setkeepalivesidle(int idle, Port *port)
{
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return STATUS_OK;

#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(SIO_KEEPALIVE_VALS)
	if (idle == port->keepalives_idle)
		return STATUS_OK;

#ifndef WIN32
	if (port->default_keepalives_idle <= 0)
	{
		if (pq_getkeepalivesidle(port) < 0)
		{
			if (idle == 0)
				return STATUS_OK;		/* default is set but unknown */
			else
				return STATUS_ERROR;
		}
	}

	if (idle == 0)
		idle = port->default_keepalives_idle;

#ifdef TCP_KEEPIDLE
	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
				   (char *) &idle, sizeof(idle)) < 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
		return STATUS_ERROR;
	}
#else
	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
				   (char *) &idle, sizeof(idle)) < 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m");
		return STATUS_ERROR;
	}
#endif

	port->keepalives_idle = idle;
#else /* WIN32 */
	return pq_setkeepaliveswin32(port, idle, port->keepalives_interval);
#endif
#else /* TCP_KEEPIDLE || SIO_KEEPALIVE_VALS */
	if (idle != 0)
	{
		elog(LOG, "setting the keepalive idle time is not supported");
		return STATUS_ERROR;
	}
#endif

	return STATUS_OK;
}
Ejemplo n.º 5
0
int
pq_setkeepalivesinterval(int interval, Port *port)
{
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return STATUS_OK;

#if defined(TCP_KEEPINTVL) || defined (SIO_KEEPALIVE_VALS)
	if (interval == port->keepalives_interval)
		return STATUS_OK;

#ifndef WIN32
	if (port->default_keepalives_interval <= 0)
	{
		if (pq_getkeepalivesinterval(port) < 0)
		{
			if (interval == 0)
				return STATUS_OK;		/* default is set but unknown */
			else
				return STATUS_ERROR;
		}
	}

	if (interval == 0)
		interval = port->default_keepalives_interval;

	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
				   (char *) &interval, sizeof(interval)) < 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m");
		return STATUS_ERROR;
	}

	port->keepalives_interval = interval;
#else /* WIN32 */
	return pq_setkeepaliveswin32(port, port->keepalives_idle, interval);
#endif
#else
	if (interval != 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported");
		return STATUS_ERROR;
	}
#endif

	return STATUS_OK;
}
Ejemplo n.º 6
0
int
pq_getkeepalivesidle(Port *port)
{
#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(WIN32)
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return 0;

	if (port->keepalives_idle != 0)
		return port->keepalives_idle;

	if (port->default_keepalives_idle == 0)
	{
#ifndef WIN32
		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle);

#ifdef TCP_KEEPIDLE
		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
					   (char *) &port->default_keepalives_idle,
					   &size) < 0)
		{
			elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m");
			port->default_keepalives_idle = -1; /* don't know */
		}
#else
		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
					   (char *) &port->default_keepalives_idle,
					   &size) < 0)
		{
			elog(LOG, "getsockopt(TCP_KEEPALIVE) failed: %m");
			port->default_keepalives_idle = -1; /* don't know */
		}
#endif /* TCP_KEEPIDLE */
#else /* WIN32 */
		/* We can't get the defaults on Windows, so return "don't know" */
		port->default_keepalives_idle = -1;
#endif /* WIN32 */
	}

	return port->default_keepalives_idle;
#else
	return 0;
#endif
}
Ejemplo n.º 7
0
int
pq_setkeepalivescount(int count, Port *port)
{
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return STATUS_OK;

#ifdef TCP_KEEPCNT
	if (count == port->keepalives_count)
		return STATUS_OK;

	if (port->default_keepalives_count <= 0)
	{
		if (pq_getkeepalivescount(port) < 0)
		{
			if (count == 0)
				return STATUS_OK;		/* default is set but unknown */
			else
				return STATUS_ERROR;
		}
	}

	if (count == 0)
		count = port->default_keepalives_count;

	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT,
				   (char *) &count, sizeof(count)) < 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m");
		return STATUS_ERROR;
	}

	port->keepalives_count = count;
#else
	if (count != 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPCNT) not supported");
		return STATUS_ERROR;
	}
#endif

	return STATUS_OK;
}
Ejemplo n.º 8
0
int
pq_setkeepalivesidle(int idle, Port *port)
{
	if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
		return STATUS_OK;

#ifdef TCP_KEEPIDLE
	if (idle == port->keepalives_idle)
		return STATUS_OK;

	if (port->default_keepalives_idle <= 0)
	{
		if (pq_getkeepalivesidle(port) < 0)
		{
			if (idle == 0)
				return STATUS_OK;		/* default is set but unknown */
			else
				return STATUS_ERROR;
		}
	}

	if (idle == 0)
		idle = port->default_keepalives_idle;

	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
				   (char *) &idle, sizeof(idle)) < 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
		return STATUS_ERROR;
	}

	port->keepalives_idle = idle;
#else
	if (idle != 0)
	{
		elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported");
		return STATUS_ERROR;
	}
#endif

	return STATUS_OK;
}
Ejemplo n.º 9
0
/*
 * StreamConnection -- create a new connection with client using
 *		server port.  Set port->sock to the FD of the new connection.
 *
 * ASSUME: that this doesn't need to be non-blocking because
 *		the Postmaster uses select() to tell when the server master
 *		socket is ready for accept().
 *
 * RETURNS: STATUS_OK or STATUS_ERROR
 */
int
StreamConnection(pgsocket server_fd, Port *port)
{
	/* accept connection and fill in the client (remote) address */
	port->raddr.salen = sizeof(port->raddr.addr);
	if ((port->sock = accept(server_fd,
							 (struct sockaddr *) & port->raddr.addr,
							 &port->raddr.salen)) < 0)
	{
		ereport(LOG,
				(errcode_for_socket_access(),
				 errmsg("could not accept new connection: %m")));

		/*
		 * If accept() fails then postmaster.c will still see the server
		 * socket as read-ready, and will immediately try again.  To avoid
		 * uselessly sucking lots of CPU, delay a bit before trying again.
		 * (The most likely reason for failure is being out of kernel file
		 * table slots; we can do little except hope some will get freed up.)
		 */
		pg_usleep(100000L);		/* wait 0.1 sec */
		return STATUS_ERROR;
	}

#ifdef SCO_ACCEPT_BUG

	/*
	 * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it
	 * shouldn't hurt to catch it for all versions of those platforms.
	 */
	if (port->raddr.addr.ss_family == 0)
		port->raddr.addr.ss_family = AF_UNIX;
#endif

	/* fill in the server (local) address */
	port->laddr.salen = sizeof(port->laddr.addr);
	if (getsockname(port->sock,
					(struct sockaddr *) & port->laddr.addr,
					&port->laddr.salen) < 0)
	{
		elog(LOG, "getsockname() failed: %m");
		return STATUS_ERROR;
	}

	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
	if (!IS_AF_UNIX(port->laddr.addr.ss_family))
	{
		int			on;

#ifdef	TCP_NODELAY
		on = 1;
		if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
			return STATUS_ERROR;
		}
#endif
		on = 1;
		if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
			return STATUS_ERROR;
		}

#ifdef WIN32

		/*
		 * This is a Win32 socket optimization.  The ideal size is 32k.
		 * http://support.microsoft.com/kb/823764/EN-US/
		 */
		on = PQ_BUFFER_SIZE * 4;
		if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &on,
					   sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(SO_SNDBUF) failed: %m");
			return STATUS_ERROR;
		}
#endif

		/*
		 * Also apply the current keepalive parameters.  If we fail to set a
		 * parameter, don't error out, because these aren't universally
		 * supported.  (Note: you might think we need to reset the GUC
		 * variables to 0 in such a case, but it's not necessary because the
		 * show hooks for these variables report the truth anyway.)
		 */
		(void) pq_setkeepalivesidle(tcp_keepalives_idle, port);
		(void) pq_setkeepalivesinterval(tcp_keepalives_interval, port);
		(void) pq_setkeepalivescount(tcp_keepalives_count, port);
	}

	return STATUS_OK;
}
Ejemplo n.º 10
0
int
StreamServerPort(int family, char *hostName, unsigned short portNumber,
				 char *unixSocketName,
				 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;

#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)
	{
		/* Lock_AF_UNIX will also fill in sock_path. */
		if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
			return STATUS_ERROR;
		service = sock_path;
	}
	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)) < 0)
		{
			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, sock_path) :
				  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() != 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;
}
Ejemplo n.º 11
0
/* ----------------
 *		GTMPQconnectPoll
 *
 * Poll an asynchronous connection.
 *
 * Returns a GTMClientPollingStatusType.
 * Before calling this function, use select(2) to determine when data
 * has arrived..
 *
 * You must call GTMPQfinish whether or not this fails.
 */
GTMClientPollingStatusType
GTMPQconnectPoll(GTM_Conn *conn)
{
	if (conn == NULL)
		return PGRES_POLLING_FAILED;

	/* Get the new data */
	switch (conn->status)
	{
			/*
			 * We really shouldn't have been polled in these two cases, but we
			 * can handle it.
			 */
		case CONNECTION_BAD:
			return PGRES_POLLING_FAILED;
		case CONNECTION_OK:
			return PGRES_POLLING_OK;

			/* These are reading states */
		case CONNECTION_AWAITING_RESPONSE:
		case CONNECTION_AUTH_OK:
			{
				/* Load waiting data */
				int			n = gtmpqReadData(conn);

				if (n < 0)
					goto error_return;
				if (n == 0)
					return PGRES_POLLING_READING;

				break;
			}

			/* These are writing states, so we just proceed. */
		case CONNECTION_STARTED:
		case CONNECTION_MADE:
			break;

		case CONNECTION_NEEDED:
			break;

		default:
			appendGTMPQExpBuffer(&conn->errorMessage,
											"invalid connection state, "
								 "probably indicative of memory corruption\n"
											);
			goto error_return;
	}


keep_going:						/* We will come back to here until there is
								 * nothing left to do. */
	switch (conn->status)
	{
		case CONNECTION_NEEDED:
			{
				/*
				 * Try to initiate a connection to one of the addresses
				 * returned by gtm_getaddrinfo_all().  conn->addr_cur is the
				 * next one to try. We fail when we run out of addresses
				 * (reporting the error returned for the *last* alternative,
				 * which may not be what users expect :-().
				 */
				while (conn->addr_cur != NULL)
				{
					struct addrinfo *addr_cur = conn->addr_cur;

					/* Remember current address for possible error msg */
					memcpy(&conn->raddr.addr, addr_cur->ai_addr,
						   addr_cur->ai_addrlen);
					conn->raddr.salen = addr_cur->ai_addrlen;

					/* Open a socket */
					conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
					if (conn->sock < 0)
					{
						/*
						 * ignore socket() failure if we have more addresses
						 * to try
						 */
						if (addr_cur->ai_next != NULL)
						{
							conn->addr_cur = addr_cur->ai_next;
							continue;
						}
						appendGTMPQExpBuffer(&conn->errorMessage,
							  "could not create socket: \n");
						break;
					}

					/*
					 * Select socket options: no delay of outgoing data for
					 * TCP sockets, nonblock mode, close-on-exec. Fail if any
					 * of this fails.
					 */
					if (!IS_AF_UNIX(addr_cur->ai_family))
					{
						if (!connectNoDelay(conn))
						{
							close(conn->sock);
							conn->sock = -1;
							conn->addr_cur = addr_cur->ai_next;
							continue;
						}
					}

					/*
					 * Start/make connection.  This should not block, since we
					 * are in nonblock mode.  If it does, well, too bad.
					 */
					if (connect(conn->sock, addr_cur->ai_addr,
								addr_cur->ai_addrlen) < 0)
					{
						if (SOCK_ERRNO == EINPROGRESS ||
							SOCK_ERRNO == EWOULDBLOCK ||
							SOCK_ERRNO == EINTR ||
							SOCK_ERRNO == 0)
						{
							/*
							 * This is fine - we're in non-blocking mode, and
							 * the connection is in progress.  Tell caller to
							 * wait for write-ready on socket.
							 */
							conn->status = CONNECTION_STARTED;
							return PGRES_POLLING_WRITING;
						}
						/* otherwise, trouble */
					}
					else
					{
						/*
						 * Hm, we're connected already --- seems the "nonblock
						 * connection" wasn't.  Advance the state machine and
						 * go do the next stuff.
						 */
						conn->status = CONNECTION_STARTED;
						goto keep_going;
					}

					/*
					 * This connection failed --- set up error report, then
					 * close socket (do it this way in case close() affects
					 * the value of errno...).	We will ignore the connect()
					 * failure and keep going if there are more addresses.
					 */
					connectFailureMessage(conn, SOCK_ERRNO);
					if (conn->sock >= 0)
					{
						close(conn->sock);
						conn->sock = -1;
					}

					/*
					 * Try the next address, if any.
					 */
					conn->addr_cur = addr_cur->ai_next;
				}				/* loop over addresses */

				/*
				 * Ooops, no more addresses.  An appropriate error message is
				 * already set up, so just set the right status.
				 */
				goto error_return;
			}

		case CONNECTION_STARTED:
			{
				int			optval;
				size_t optlen = sizeof(optval);

				/*
				 * Write ready, since we've made it here, so the connection
				 * has been made ... or has failed.
				 */

				/*
				 * Now check (using getsockopt) that there is not an error
				 * state waiting for us on the socket.
				 */

				if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
						       (char *) &optval, (socklen_t *)&optlen) == -1)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
					libpq_gettext("could not get socket error status: \n"));
					goto error_return;
				}
				else if (optval != 0)
				{
					/*
					 * When using a nonblocking connect, we will typically see
					 * connect failures at this point, so provide a friendly
					 * error message.
					 */
					connectFailureMessage(conn, optval);

					/*
					 * If more addresses remain, keep trying, just as in the
					 * case where connect() returned failure immediately.
					 */
					if (conn->addr_cur->ai_next != NULL)
					{
						if (conn->sock >= 0)
						{
							close(conn->sock);
							conn->sock = -1;
						}
						conn->addr_cur = conn->addr_cur->ai_next;
						conn->status = CONNECTION_NEEDED;
						goto keep_going;
					}
					goto error_return;
				}

				/* Fill in the client address */
				conn->laddr.salen = sizeof(conn->laddr.addr);
				if (getsockname(conn->sock,
								(struct sockaddr *) & conn->laddr.addr,
								(socklen_t *)&conn->laddr.salen) < 0)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
									  "could not get client address from socket:\n");
					goto error_return;
				}

				/*
				 * Make sure we can write before advancing to next step.
				 */
				conn->status = CONNECTION_MADE;
				return PGRES_POLLING_WRITING;
			}

		case CONNECTION_MADE:
			{
				GTM_StartupPacket sp;

				/*
				 * Build a startup packet. We tell the GTM server/proxy our
				 * PGXC Node name and whether we are a proxy or not.
				 *
				 * When the connection is made from the proxy, we let the GTM
				 * server know about it so that some special headers are
				 * handled correctly by the server.
				 */
				strcpy(sp.sp_node_name, conn->gc_node_name);
				sp.sp_remotetype = conn->remote_type;
				sp.sp_ispostmaster = conn->is_postmaster;

				/*
				 * Send the startup packet.
				 *
				 * Theoretically, this could block, but it really shouldn't
				 * since we only got here if the socket is write-ready.
				 */
				if (pqPacketSend(conn, 'A', &sp, sizeof (GTM_StartupPacket)) != STATUS_OK)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
						"could not send startup packet: \n");
					goto error_return;
				}

				conn->status = CONNECTION_AWAITING_RESPONSE;
				return PGRES_POLLING_READING;
			}

			/*
			 * Handle authentication exchange: wait for postmaster messages
			 * and respond as necessary.
			 */
		case CONNECTION_AWAITING_RESPONSE:
			{
				char		beresp;

				/*
				 * Scan the message from current point (note that if we find
				 * the message is incomplete, we will return without advancing
				 * inStart, and resume here next time).
				 */
				conn->inCursor = conn->inStart;

				/* Read type byte */
				if (gtmpqGetc(&beresp, conn))
				{
					/* We'll come back when there is more data */
					return PGRES_POLLING_READING;
				}

				/*
				 * Validate message type: we expect only an authentication
				 * request or an error here.  Anything else probably means
				 * it's not GTM on the other end at all.
				 */
				if (!(beresp == 'R' || beresp == 'E'))
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
									  "expected authentication request from "
												"server, but received %c\n",
									  beresp);
					goto error_return;
				}


				/* Handle errors. */
				if (beresp == 'E')
				{
					if (gtmpqGets_append(&conn->errorMessage, conn))
					{
						/* We'll come back when there is more data */
						return PGRES_POLLING_READING;
					}
					/* OK, we read the message; mark data consumed */
					conn->inStart = conn->inCursor;
					goto error_return;
				}

				{
					/*
					 * Server sends a dummy message body of size 4 bytes
					 */
					int tmp_int;
					gtmpqGetInt(&tmp_int, 4, conn);
				}

				/*
				 * OK, we successfully read the message; mark data consumed
				 */
				conn->inStart = conn->inCursor;

				/* We are done with authentication exchange */
				conn->status = CONNECTION_AUTH_OK;

				/* Look to see if we have more data yet. */
				goto keep_going;
			}

		case CONNECTION_AUTH_OK:
			{
				/* We can release the address list now. */
				gtm_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
				conn->addrlist = NULL;
				conn->addr_cur = NULL;

				/* Otherwise, we are open for business! */
				conn->status = CONNECTION_OK;
				return PGRES_POLLING_OK;
			}


		default:
			appendGTMPQExpBuffer(&conn->errorMessage,
											"invalid connection state %c, "
								 "probably indicative of memory corruption\n"
											,
							  conn->status);
			goto error_return;
	}

	/* Unreachable */

error_return:

	/*
	 * We used to close the socket at this point, but that makes it awkward
	 * for those above us if they wish to remove this socket from their own
	 * records (an fd_set for example).  We'll just have this socket closed
	 * when GTMPQfinish is called (which is compulsory even after an error, since
	 * the connection structure must be freed).
	 */
	conn->status = CONNECTION_BAD;
	return PGRES_POLLING_FAILED;
}
Ejemplo n.º 12
0
/*
 * StreamConnection -- create a new connection with client using
 *		server port.  Set port->sock to the FD of the new connection.
 *
 * ASSUME: that this doesn't need to be non-blocking because
 *		the Postmaster uses select() to tell when the server master
 *		socket is ready for accept().
 *
 * RETURNS: STATUS_OK or STATUS_ERROR
 */
int
StreamConnection(pgsocket server_fd, Port *port)
{
	/* accept connection and fill in the client (remote) address */
	port->raddr.salen = sizeof(port->raddr.addr);
	if ((port->sock = accept(server_fd,
							 (struct sockaddr *) & port->raddr.addr,
							 &port->raddr.salen)) == PGINVALID_SOCKET)
	{
		ereport(LOG,
				(errcode_for_socket_access(),
				 errmsg("could not accept new connection: %m")));

		/*
		 * If accept() fails then postmaster.c will still see the server
		 * socket as read-ready, and will immediately try again.  To avoid
		 * uselessly sucking lots of CPU, delay a bit before trying again.
		 * (The most likely reason for failure is being out of kernel file
		 * table slots; we can do little except hope some will get freed up.)
		 */
		pg_usleep(100000L);		/* wait 0.1 sec */
		return STATUS_ERROR;
	}

	/* fill in the server (local) address */
	port->laddr.salen = sizeof(port->laddr.addr);
	if (getsockname(port->sock,
					(struct sockaddr *) & port->laddr.addr,
					&port->laddr.salen) < 0)
	{
		elog(LOG, "getsockname() failed: %m");
		return STATUS_ERROR;
	}

	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
	if (!IS_AF_UNIX(port->laddr.addr.ss_family))
	{
		int			on;
#ifdef WIN32
		int			oldopt;
		int			optlen;
		int			newopt;
#endif

#ifdef	TCP_NODELAY
		on = 1;
		if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
			return STATUS_ERROR;
		}
#endif
		on = 1;
		if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
			return STATUS_ERROR;
		}

#ifdef WIN32

		/*
		 * This is a Win32 socket optimization.  The OS send buffer should be
		 * large enough to send the whole Postgres send buffer in one go, or
		 * performance suffers.  The Postgres send buffer can be enlarged if a
		 * very large message needs to be sent, but we won't attempt to
		 * enlarge the OS buffer if that happens, so somewhat arbitrarily
		 * ensure that the OS buffer is at least PQ_SEND_BUFFER_SIZE * 4.
		 * (That's 32kB with the current default).
		 *
		 * The default OS buffer size used to be 8kB in earlier Windows
		 * versions, but was raised to 64kB in Windows 2012.  So it shouldn't
		 * be necessary to change it in later versions anymore.  Changing it
		 * unnecessarily can even reduce performance, because setting
		 * SO_SNDBUF in the application disables the "dynamic send buffering"
		 * feature that was introduced in Windows 7.  So before fiddling with
		 * SO_SNDBUF, check if the current buffer size is already large enough
		 * and only increase it if necessary.
		 *
		 * See https://support.microsoft.com/kb/823764/EN-US/ and
		 * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx
		 */
		optlen = sizeof(oldopt);
		if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt,
					   &optlen) < 0)
		{
			elog(LOG, "getsockopt(SO_SNDBUF) failed: %m");
			return STATUS_ERROR;
		}
		newopt = PQ_SEND_BUFFER_SIZE * 4;
		if (oldopt < newopt)
		{
			if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt,
						   sizeof(newopt)) < 0)
			{
				elog(LOG, "setsockopt(SO_SNDBUF) failed: %m");
				return STATUS_ERROR;
			}
		}
#endif

		/*
		 * Also apply the current keepalive parameters.  If we fail to set a
		 * parameter, don't error out, because these aren't universally
		 * supported.  (Note: you might think we need to reset the GUC
		 * variables to 0 in such a case, but it's not necessary because the
		 * show hooks for these variables report the truth anyway.)
		 */
		(void) pq_setkeepalivesidle(tcp_keepalives_idle, port);
		(void) pq_setkeepalivesinterval(tcp_keepalives_interval, port);
		(void) pq_setkeepalivescount(tcp_keepalives_count, port);
	}

	return STATUS_OK;
}
Ejemplo n.º 13
0
void body()
{
        /* Initialize hint structure */

#ifdef HAVE_UNIX_SOCKETS
        if (family == AF_UNIX)
        {
                /* Lock_AF_UNIX will also fill in sock_path. */
                /* if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK) */
                /*         return STATUS_ERROR; */
                service = sock_path;
        }
        else
#endif   /* HAVE_UNIX_SOCKETS */
        {
                snprintf(1, sizeof(1), "%d", portNumber);
                service = 1;
        }

        ret = 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) */
                /*         freeaddrinfo_all(hint.ai_family, addrs); */
	  }
	  //ret = STATUS_ERROR;
	  //while(1) { int qqq; qqq=qqq;}
        }

        for (addr = addrs; addr < MAXADDR; 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.
                         */
                        goto loc_continue;
                }

                /* See if there is still room to add 1 more socket. */
                for (; listen_index < MaxListen; listen_index++)
                {
                        if (ListenSocket_OF_listen_index == -1)
                                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 */
		  if(addr_ai_family==AF_INET) {
                                gettext("IPv4");
		  } else if(addr_ai_family==AF_INET6) {
                                gettext("IPv6");
		  } else if(addr_ai_family==AF_UNIX) {
                                gettext("Unix");
		  } else {
			  snprintf(1,/*familyDescBuf*/ 1, //sizeof(familyDescBuf),
                                                 gettext("unrecognized address family %d"),
                                                 addr_ai_family);
                                //familyDesc = familyDescBuf;
		  }

                if ((fd = nondet())) // socket(addr_ai_family, SOCK_STREAM, 0)) < 0)
                {
                        /* ereport(LOG, */
                        /*                 (errcode_for_socket_access(), */
                        /* /\* translator: %s is IPv4, IPv6, or Unix *\/ */
                        /*                  errmsg("could not create %s socket: %m", */
                        /*                                 familyDesc))); */
                        goto loc_continue;
                }

                if (nondet()) // !IS_AF_UNIX(addr_ai_family))
                {
		  if (nondet()) //(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); */
                                goto loc_continue;
                        }
                }

#ifdef IPV6_V6ONLY
                if (nondet()) // addr_ai_family == AF_INET6)
                {
		  if (nondet()) // 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);
                                goto loc_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 = nondet(); // 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, sock_path) : */
                        /*   errhint("Is another postmaster already running on port %d?" */
                        /*                   " If not, wait a few seconds and retry.", */
                        /*                   (int) portNumber))); */
                        closesocket(fd);
                        goto loc_continue;
                }

#ifdef HAVE_UNIX_SOCKETS
                if (addr_ai_family == AF_UNIX)
                {
		  if (nondet() != 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)
                {

                        closesocket(fd);
                        goto loc_continue;
                }
                ListenSocket_OF_listen_index = fd;
		added++;

		if(1) { loc_continue: 0; }

        }

        //freeaddrinfo_all(hint.ai_family, addrs);

        if (!added) {
                ret = STATUS_ERROR;
		while(1) { int rrr; rrr=rrr; }
	}

        ret = STATUS_OK;
	while(1) { int ddd; ddd=ddd; }
}
Ejemplo n.º 14
0
/*
 * StreamConnection -- create a new connection with client using
 *		server port.
 *
 * ASSUME: that this doesn't need to be non-blocking because
 *		the Postmaster uses select() to tell when the server master
 *		socket is ready for accept().
 *
 * RETURNS: STATUS_OK or STATUS_ERROR
 */
int
StreamConnection(int server_fd, Port *port)
{
	/* accept connection and fill in the client (remote) address */
	port->raddr.salen = sizeof(port->raddr.addr);
	if ((port->sock = accept(server_fd,
							 (struct sockaddr *) & port->raddr.addr,
							 &port->raddr.salen)) < 0)
	{
		ereport(LOG,
				(errcode_for_socket_access(),
				 errmsg("could not accept new connection: %m")));
		return STATUS_ERROR;
	}

#ifdef SCO_ACCEPT_BUG

	/*
	 * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it
	 * shouldn't hurt to catch it for all versions of those platforms.
	 */
	if (port->raddr.addr.ss_family == 0)
		port->raddr.addr.ss_family = AF_UNIX;
#endif

	/* fill in the server (local) address */
	port->laddr.salen = sizeof(port->laddr.addr);
	if (getsockname(port->sock,
					(struct sockaddr *) & port->laddr.addr,
					&port->laddr.salen) < 0)
	{
		elog(LOG, "getsockname() failed: %m");
		return STATUS_ERROR;
	}

	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
	if (!IS_AF_UNIX(port->laddr.addr.ss_family))
	{
		int			on;

#ifdef	TCP_NODELAY
		on = 1;
		if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
			return STATUS_ERROR;
		}
#endif
		on = 1;
		if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
					   (char *) &on, sizeof(on)) < 0)
		{
			elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
			return STATUS_ERROR;
		}

		/*
		 * Also apply the current keepalive parameters.  If we fail to set a
		 * parameter, don't error out, because these aren't universally
		 * supported.  (Note: you might think we need to reset the GUC
		 * variables to 0 in such a case, but it's not necessary because the
		 * show hooks for these variables report the truth anyway.)
		 */
		(void) pq_setkeepalivesidle(tcp_keepalives_idle, port);
		(void) pq_setkeepalivesinterval(tcp_keepalives_interval, port);
		(void) pq_setkeepalivescount(tcp_keepalives_count, port);
	}

	return STATUS_OK;
}