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; }
/* * 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; }
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; }
/* * 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; }