示例#1
0
Datum
gp_inject_fault(PG_FUNCTION_ARGS)
{
	char	   *faultName = TextDatumGetCString(PG_GETARG_DATUM(0));
	char	   *type = TextDatumGetCString(PG_GETARG_DATUM(1));
	char	   *ddlStatement = TextDatumGetCString(PG_GETARG_DATUM(2));
	char	   *databaseName = TextDatumGetCString(PG_GETARG_DATUM(3));
	char	   *tableName = TextDatumGetCString(PG_GETARG_DATUM(4));
	int			numOccurrences = PG_GETARG_INT32(5);
	int			sleepTimeSeconds = PG_GETARG_INT32(6);
	int         dbid = PG_GETARG_INT32(7);
	StringInfo  faultmsg = makeStringInfo();

	/* Fast path if injecting fault in our postmaster. */
	if (GpIdentity.dbid == dbid)
	{
		appendStringInfo(faultmsg, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
						 faultName, type, ddlStatement, databaseName,
						 tableName, numOccurrences, sleepTimeSeconds);
		int offset = 0;
		char *response =
			processTransitionRequest_faultInject(
				faultmsg->data, &offset, faultmsg->len);
		if (!response)
			elog(ERROR, "failed to inject fault locally (dbid %d)", dbid);
		if (strncmp(response, "Success:",  strlen("Success:")) != 0)
			elog(ERROR, "%s", response);

		elog(NOTICE, "%s", response);
		PG_RETURN_DATUM(true);
	}

	/* Obtain host and port of the requested dbid */
	HeapTuple tuple;
	Relation rel = heap_open(GpSegmentConfigRelationId, AccessShareLock);
	ScanKeyData scankey;
	SysScanDesc sscan;
	ScanKeyInit(&scankey,
				Anum_gp_segment_configuration_dbid,
				BTEqualStrategyNumber, F_INT2EQ,
				Int16GetDatum((int16) dbid));
	sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true,
							   GetTransactionSnapshot(), 1, &scankey);
	tuple = systable_getnext(sscan);

	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "cannot find dbid %d", dbid);

	bool isnull;
	Datum datum = heap_getattr(tuple, Anum_gp_segment_configuration_hostname,
							   RelationGetDescr(rel), &isnull);
	char *hostname;
	if (!isnull)
		hostname =
				DatumGetCString(DirectFunctionCall1(textout, datum));
	else
		elog(ERROR, "hostname is null for dbid %d", dbid);
	int port = DatumGetInt32(heap_getattr(tuple,
										  Anum_gp_segment_configuration_port,
										  RelationGetDescr(rel), &isnull));
	systable_endscan(sscan);
	heap_close(rel, NoLock);

	struct addrinfo *addrList = NULL;
	struct addrinfo hint;
	int			ret;

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

	char portStr[100];
	if (snprintf(portStr, sizeof(portStr), "%d", port) >= sizeof(portStr))
		elog(ERROR, "port number too long for dbid %d", dbid);

	/* Use pg_getaddrinfo_all() to resolve the address */
	ret = pg_getaddrinfo_all(hostname, portStr, &hint, &addrList);
	if (ret || !addrList)
	{
		if (addrList)
			pg_freeaddrinfo_all(hint.ai_family, addrList);
		elog(ERROR, "could not translate host name \"%s\" to address: %s\n",
			 hostname, gai_strerror(ret));
	}

	PrimaryMirrorTransitionClientInfo client;
	client.receivedDataCallbackFn = transitionReceivedDataFn;
	client.errorLogFn = transitionErrorLogFn;
	client.checkForNeedToExitFn = checkForNeedToExitFn;
	transitionMsgErrors = makeStringInfo();

	appendStringInfo(faultmsg, "%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
					 "faultInject",	faultName, type, ddlStatement,
					 databaseName, tableName, numOccurrences,
					 sleepTimeSeconds);

	if (sendTransitionMessage(&client, addrList, faultmsg->data, faultmsg->len,
							  1 /* retries */, 60 /* timeout */) !=
		TRANS_ERRCODE_SUCCESS)
	{
		pg_freeaddrinfo_all(hint.ai_family, addrList);
		ereport(ERROR, (errmsg("failed to inject %s fault in dbid %d",
							   faultName, dbid),
						errdetail("%s", transitionMsgErrors->data)));
	}

	pg_freeaddrinfo_all(hint.ai_family, addrList);
	PG_RETURN_DATUM(BoolGetDatum(true));
}
static bool
load_rule(int line, const char * dbname, const char * user,
		  const char * ip, const char * mask, int limit)
{
	rule_t * rule;

	/* error if the segment is already full (no space for another rule) */
	if (rules->n_rules == MAX_RULES)
		elog(ERROR, "too many connection limit rules (max: %d)", MAX_RULES);

	/* get space for the next rule */
	rule = &(rules->rules[rules->n_rules]);
	memset(rule, 0, sizeof(rule_t));

	/* reset the rule (no fields) */
	rule->fields = 0;
	rule->limit = limit;
	rule->line = line;

	/* dbname entered */
	if (strcmp("all", dbname) != 0)
	{
		strcpy(rule->database, dbname);
		rule->fields |= CHECK_DBNAME;
	}

	/* username entered */
	if (strcmp("all", user) != 0)
	{
		strcpy(rule->user, user);
		rule->fields |= CHECK_USER;
	}

	/* load the IP (see parse_hba_line in hba.c) */
	if (strcmp("all", ip) != 0)
	{

		int		ret;
		char   *ipcopy ;

		/* IP address parsing */
		struct	addrinfo hints;
		struct	addrinfo * gai_result;

		/* process the IP address (without the mask), or a hostname */

		ipcopy = pstrdup(ip);

		if (strchr(ipcopy, '/'))
			*strchr(ipcopy, '/') = '\0';

		hints.ai_flags = AI_NUMERICHOST;
		hints.ai_family = PF_UNSPEC;
		hints.ai_socktype = 0;
		hints.ai_protocol = 0;
		hints.ai_addrlen = 0;
		hints.ai_canonname = NULL;
		hints.ai_addr = NULL;
		hints.ai_next = NULL;

		/* try to parse the IP address */
		ret = pg_getaddrinfo_all(ipcopy, NULL, &hints, &gai_result);
		if (ret == 0 && gai_result)
		{
			memcpy(&(rule->ip), gai_result->ai_addr, gai_result->ai_addrlen);
			rule->fields |= CHECK_IP;
		}
		else if (ret == EAI_NONAME)
		{
			strcpy(rule->hostname, ipcopy);
			rule->fields |= CHECK_HOST;
		}
		else
		{
			elog(WARNING,
				 "invalid IP address \"%s\": %s", ipcopy, gai_strerror(ret));
			pfree(ipcopy);
			return false;
		}

		pfree(ipcopy);

		if (gai_result)
			pg_freeaddrinfo_all(hints.ai_family, gai_result);

		/* Get the netmask */
		if (strchr(ip, '/'))
		{
			if (strlen(rule->hostname) != 0)
			{
				elog(WARNING,
					 "specifying both host name and CIDR mask is invalid: \"%s\"", ip);
				return false;
			}
			else if (pg_sockaddr_cidr_mask(&(rule->mask), strchr(ip, '/') + 1, rule->ip.ss_family) < 0)
			{
				elog(WARNING,
					 "invalid CIDR mask in address \"%s\"", ip);
				return false;
			}
		}
		else if (strlen(rule->hostname) == 0)
		{
			if (mask == NULL)
			{
				elog(WARNING,
					 "no mask specified for rule %d", rules->n_rules);
				return false;
			}

			ret = pg_getaddrinfo_all(mask, NULL, &hints, &gai_result);
			if (ret || !gai_result)
			{
				elog(WARNING,
					 "invalid IP mask \"%s\": %s",
					 mask, gai_strerror(ret));

				if (gai_result)
					pg_freeaddrinfo_all(hints.ai_family, gai_result);

				return false;
			}

			memcpy(&rule->mask, gai_result->ai_addr, gai_result->ai_addrlen);
			pg_freeaddrinfo_all(hints.ai_family, gai_result);

			if (rule->ip.ss_family != rule->mask.ss_family)
			{
				elog(WARNING,
					 "IP address and mask do not match");
				return false;
			}
		}
	} /* IP address parsing */

	/* successfully parsed - at least one field needs to be set (increment) */
	if (rule->fields == 0)
	{
		elog(WARNING, "rule on line %d is invalid - no value set", line);
		return false;
	} else
		rules->n_rules += 1;

	return true;

}
示例#3
0
/*
 * getDnsAddress
 * 
 * same as getDnsCachedAddress, but without caching. Looks like the
 * non-cached version was used inline inside of cdbgang.c, and since
 * it is needed now elsewhere, it is factored out to this routine.
 */
char *
getDnsAddress(char *hostname, int port, int elevel)
{
	int			ret;
	char		portNumberStr[32];
	char	   *service;
	char	   *result = NULL;
	struct addrinfo *addrs = NULL,
			   *addr;
	struct addrinfo hint;

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

	snprintf(portNumberStr, sizeof(portNumberStr), "%d", port);
	service = portNumberStr;

	ret = pg_getaddrinfo_all(hostname, service, &hint, &addrs);
	if (ret || !addrs)
	{
		if (addrs)
			pg_freeaddrinfo_all(hint.ai_family, addrs);
		ereport(elevel,
				(errmsg("could not translate host name \"%s\", port \"%d\" to address: %s",
						hostname, port, gai_strerror(ret))));
	}
	for (addr = addrs; addr; addr = addr->ai_next)
	{
#ifdef HAVE_UNIX_SOCKETS
		/* Ignore AF_UNIX sockets, if any are returned. */
		if (addr->ai_family == AF_UNIX)
			continue;
#endif
		if (addr->ai_family == AF_INET) /* IPv4 address */
		{
			char		hostinfo[NI_MAXHOST];

			/* Get a text representation of the IP address */
			pg_getnameinfo_all((struct sockaddr_storage *) addr->ai_addr, addr->ai_addrlen,
							   hostinfo, sizeof(hostinfo),
							   NULL, 0,
							   NI_NUMERICHOST);
			result = pstrdup(hostinfo);
			break;
		}
	}

#ifdef HAVE_IPV6
	/*
	 * IPv6 should would work fine, we'd just need to make sure all the data structures are big enough for
	 * the IPv6 address.  And on some broken systems, you can get an IPv6 address, but not be able to bind to it
	 * because IPv6 is disabled or missing in the kernel, so we'd only want to use the IPv6 address if there isn't
	 * an IPv4 address.  All we really need to do is test this.
	 */
	if (result == NULL && addrs->ai_family == AF_INET6)
	{
		char		hostinfo[NI_MAXHOST];
		addr = addrs;
		/* Get a text representation of the IP address */
					pg_getnameinfo_all((struct sockaddr_storage *) addr->ai_addr, addr->ai_addrlen,
									   hostinfo, sizeof(hostinfo),
									   NULL, 0,
									   NI_NUMERICHOST);
					result = pstrdup(hostinfo);
	}
#endif

	pg_freeaddrinfo_all(hint.ai_family, addrs);
	
	return result;
}
示例#4
0
文件: pqcomm.c 项目: agentm/postgres
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;
}
示例#5
0
/*
 * Maintain a cache of names.
 *
 * The keys are all NAMEDATALEN long.
 */
static char *
getDnsCachedAddress(char *name, int port, int elevel)
{
	struct segment_ip_cache_entry *e;

	if (segment_ip_cache_htab == NULL)
	{
		HASHCTL		hash_ctl;

		MemSet(&hash_ctl, 0, sizeof(hash_ctl));

		hash_ctl.keysize = NAMEDATALEN + 1;
		hash_ctl.entrysize = sizeof(struct segment_ip_cache_entry);

		segment_ip_cache_htab = hash_create("segment_dns_cache",
											256,
											&hash_ctl,
											HASH_ELEM);
		Assert(segment_ip_cache_htab != NULL);
	}

	e = (struct segment_ip_cache_entry *)hash_search(segment_ip_cache_htab,
													 name, HASH_FIND, NULL);

	/* not in our cache, we've got to actually do the name lookup. */
	if (e == NULL)
	{
		MemoryContext oldContext;
		int			ret;
		char		portNumberStr[32];
		char	   *service;
		struct addrinfo *addrs = NULL,
			*addr;
		struct addrinfo hint;
			
		/* Initialize hint structure */
		MemSet(&hint, 0, sizeof(hint));
		hint.ai_socktype = SOCK_STREAM;
		hint.ai_family = AF_UNSPEC;
			
		snprintf(portNumberStr, sizeof(portNumberStr), "%d", port);
		service = portNumberStr;
				
		ret = pg_getaddrinfo_all(name, service, &hint, &addrs);
		if (ret || !addrs)
		{
			if (addrs)
				pg_freeaddrinfo_all(hint.ai_family, addrs);

			ereport(elevel,
					(errmsg("could not translate host name \"%s\", port \"%d\" to address: %s",
							name, port, gai_strerror(ret))));

			return NULL;
		}
			
		/* save in the cache context */
		oldContext = MemoryContextSwitchTo(TopMemoryContext);
			
		for (addr = addrs; addr; addr = addr->ai_next)
		{
#ifdef HAVE_UNIX_SOCKETS
			/* Ignore AF_UNIX sockets, if any are returned. */
			if (addr->ai_family == AF_UNIX)
				continue;
#endif
			if (addr->ai_family == AF_INET) /* IPv4 address */
			{
				char		hostinfo[NI_MAXHOST];

				pg_getnameinfo_all((struct sockaddr_storage *)addr->ai_addr, addr->ai_addrlen,
								   hostinfo, sizeof(hostinfo),
								   NULL, 0,
								   NI_NUMERICHOST);

				/* INSERT INTO OUR CACHE HTAB HERE */

				e = (struct segment_ip_cache_entry *)hash_search(segment_ip_cache_htab,
																 name,
																 HASH_ENTER,
																 NULL);
				Assert(e != NULL);
				memcpy(e->hostinfo, hostinfo, sizeof(hostinfo));

				break;
			}
		}

#ifdef HAVE_IPV6
		/*
		 * IPv6 probably would work fine, we'd just need to make sure all the data structures are big enough for
		 * the IPv6 address.  And on some broken systems, you can get an IPv6 address, but not be able to bind to it
		 * because IPv6 is disabled or missing in the kernel, so we'd only want to use the IPv6 address if there isn't
		 * an IPv4 address.  All we really need to do is test this.
		 */
		if (e == NULL && addrs->ai_family == AF_INET6)
		{
			char		hostinfo[NI_MAXHOST];
			addr = addrs;



			pg_getnameinfo_all((struct sockaddr_storage *)addr->ai_addr, addr->ai_addrlen,
							   hostinfo, sizeof(hostinfo),
							   NULL, 0,
							   NI_NUMERICHOST);

			/* INSERT INTO OUR CACHE HTAB HERE */

			e = (struct segment_ip_cache_entry *)hash_search(segment_ip_cache_htab,
															 name,
															 HASH_ENTER,
															 NULL);
			Assert(e != NULL);
			memcpy(e->hostinfo, hostinfo, sizeof(hostinfo));

		}
#endif
			
		MemoryContextSwitchTo(oldContext);
			
		pg_freeaddrinfo_all(hint.ai_family, addrs);
	}

	/* return a pointer to our cache. */
	return e->hostinfo;
}