Index: configure.in =================================================================== RCS file: /projects/cvsroot/pgsql-server/configure.in,v retrieving revision 1.254 diff -u -r1.254 configure.in --- configure.in 27 May 2003 16:36:50 -0000 1.254 +++ configure.in 1 Jun 2003 17:33:54 -0000 @@ -765,6 +765,7 @@ PGAC_STRUCT_TIMEZONE PGAC_UNION_SEMUN PGAC_STRUCT_SOCKADDR_UN +PGAC_STRUCT_SOCKADDR_STORAGE PGAC_STRUCT_ADDRINFO AC_CHECK_TYPES([struct cmsgcred, struct fcred, struct sockcred], [], [], Index: config/c-library.m4 =================================================================== RCS file: /projects/cvsroot/pgsql-server/config/c-library.m4,v retrieving revision 1.19 diff -u -r1.19 c-library.m4 --- config/c-library.m4 22 May 2003 16:39:26 -0000 1.19 +++ config/c-library.m4 1 Jun 2003 17:33:54 -0000 @@ -87,16 +87,27 @@ # PGAC_STRUCT_SOCKADDR_UN # ----------------------- -# If `struct sockaddr_un' exists, define HAVE_STRUCT_SOCKADDR_UN. If -# it is missing then one could define it as { short int sun_family; -# char sun_path[108]; }. (Requires test for !) +# If `struct sockaddr_un' exists, define HAVE_UNIX_SOCKETS. +# (Requires test for !) AC_DEFUN([PGAC_STRUCT_SOCKADDR_UN], -[AC_CHECK_TYPES([struct sockaddr_un], [], [], +[AC_CHECK_TYPES([struct sockaddr_un], [AC_DEFINE(HAVE_UNIX_SOCKETS)], [], [#include #ifdef HAVE_SYS_UN_H #include #endif ])])# PGAC_STRUCT_SOCKADDR_UN + + +# PGAC_STRUCT_SOCKADDR_STORAGE +# ---------------------------- +# If `struct sockaddr_storage' exists, define HAVE_STRUCT_SOCKADDR_STORAGE. If +# it is missing then one could define it. +AC_DEFUN([PGAC_STRUCT_SOCKADDR_STORAGE], +[AC_CHECK_TYPES([struct sockaddr_storage], [], [], +[#ifdef HAVE_SYS_SOCKET_H +#include +#endif +])])# PGAC_STRUCT_SOCKADDR_STORAGE # PGAC_STRUCT_ADDRINFO Index: src/backend/libpq/auth.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/auth.c,v retrieving revision 1.101 diff -u -r1.101 auth.c --- src/backend/libpq/auth.c 25 Apr 2003 03:28:55 -0000 1.101 +++ src/backend/libpq/auth.c 1 Jun 2003 17:33:55 -0000 @@ -415,15 +415,13 @@ * out the less clueful good guys. */ { - const char *hostinfo = "localhost"; -#ifdef HAVE_IPV6 - char ip_hostinfo[INET6_ADDRSTRLEN]; -#else - char ip_hostinfo[INET_ADDRSTRLEN]; -#endif - if (isAF_INETx(port->raddr.sa.sa_family) ) - hostinfo = SockAddr_ntop(&port->raddr, ip_hostinfo, - sizeof(ip_hostinfo), 1); + char hostinfo[NI_MAXHOST]; + + getnameinfo( + (struct sockaddr *)&port->raddr.addr, + port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, NI_NUMERICHOST); elog(FATAL, "No pg_hba.conf entry for host %s, user %s, database %s", Index: src/backend/libpq/hba.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v retrieving revision 1.100 diff -u -r1.100 hba.c --- src/backend/libpq/hba.c 25 Apr 2003 01:24:00 -0000 1.100 +++ src/backend/libpq/hba.c 1 Jun 2003 17:33:56 -0000 @@ -542,9 +542,14 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) { int line_number; - char *token; - char *db; - char *user; + char *token; + char *db; + char *user; + struct addrinfo *file_ip_addr = NULL, *file_ip_mask = NULL; + struct addrinfo hints; + struct sockaddr_storage *mask; + char *cidr_slash; + int ret; Assert(line != NIL); line_number = lfirsti(line); @@ -582,12 +587,11 @@ port->auth_method == uaKrb5) goto hba_syntax; - if (port->raddr.sa.sa_family != AF_UNIX) + if (port->raddr.addr.ss_family != AF_UNIX) return; } else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0) { - SockAddr file_ip_addr, mask; if (strcmp(token, "hostssl") == 0) { @@ -618,26 +622,77 @@ goto hba_syntax; user = lfirst(line); - /* Read the IP address field. */ + /* Read the IP address field. (with or without CIDR netmask) */ line = lnext(line); if (!line) goto hba_syntax; token = lfirst(line); - if(SockAddr_pton(&file_ip_addr, token) < 0) - goto hba_syntax; + /* Check if it has a CIDR suffix and if so isolate it */ + cidr_slash = index(token,'/'); + if (cidr_slash) + { + *cidr_slash = '\0'; + } - /* Read the mask field. */ - line = lnext(line); - if (!line) + 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; + + /* Get the IP address either way */ + ret = getaddrinfo2(token, NULL, &hints, &file_ip_addr); + if (ret) + { + elog(LOG, "getaddrinfo2() returned %d", ret); + if (cidr_slash) + { + *cidr_slash = '/'; + } goto hba_syntax; - token = lfirst(line); + } - if(SockAddr_pton(&mask, token) < 0) - goto hba_syntax; + if (file_ip_addr->ai_family != port->raddr.addr.ss_family) + { + /* Wrong address family. */ + freeaddrinfo2(hints.ai_family, file_ip_addr); + return; + } - if(file_ip_addr.sa.sa_family != mask.sa.sa_family) - goto hba_syntax; + /* Get the netmask */ + if (cidr_slash) + { + *cidr_slash = '/'; + if (SockAddr_cidr_mask(&mask, cidr_slash + 1, + file_ip_addr->ai_family) < 0) + { + goto hba_syntax; + } + } + else + { + /* Read the mask field. */ + line = lnext(line); + if (!line) + goto hba_syntax; + token = lfirst(line); + + ret = getaddrinfo2(token, NULL, &hints, &file_ip_mask); + if (ret) + { + goto hba_syntax; + } + mask = (struct sockaddr_storage *)file_ip_mask->ai_addr; + + if(file_ip_addr->ai_family != mask->ss_family) + { + goto hba_syntax; + } + } /* Read the rest of the line. */ line = lnext(line); @@ -648,9 +703,16 @@ goto hba_syntax; /* Must meet network restrictions */ - if (!isAF_INETx(port->raddr.sa.sa_family) || - !rangeSockAddr(&port->raddr, &file_ip_addr, &mask)) - return; + if (!rangeSockAddr(&port->raddr.addr, + (struct sockaddr_storage *)file_ip_addr->ai_addr, mask)) + { + goto hba_freeaddr; + } + freeaddrinfo2(hints.ai_family, file_ip_addr); + if (file_ip_mask) + { + freeaddrinfo2(hints.ai_family, file_ip_mask); + } } else goto hba_syntax; @@ -670,6 +732,16 @@ line ? (const char *) lfirst(line) : "(end of line)"); *error_p = true; + +hba_freeaddr: + if (file_ip_addr) + { + freeaddrinfo2(hints.ai_family, file_ip_addr); + } + if (file_ip_mask) + { + freeaddrinfo2(hints.ai_family, file_ip_mask); + } return; } @@ -1106,10 +1178,8 @@ * But iff we're unable to get the information from ident, return false. */ static bool -ident_inet(const struct in_addr remote_ip_addr, - const struct in_addr local_ip_addr, - const ushort remote_port, - const ushort local_port, +ident_inet(const SockAddr remote_addr, + const SockAddr local_addr, char *ident_user) { int sock_fd, /* File descriptor for socket on which we @@ -1117,8 +1187,39 @@ rc; /* Return code from a locally called * function */ bool ident_return; + char remote_addr_s[NI_MAXHOST]; + char remote_port[NI_MAXSERV]; + char local_addr_s[NI_MAXHOST]; + char local_port[NI_MAXSERV]; + char ident_port[NI_MAXSERV]; + struct addrinfo *ident_serv = NULL, *la = NULL, hints; + + /* Might look a little weird to first convert it to text and + * then back to sockaddr, but it's protocol indepedant. */ + getnameinfo((struct sockaddr *)&remote_addr.addr, + remote_addr.salen, remote_addr_s, sizeof(remote_addr_s), + remote_port, sizeof(remote_port), + NI_NUMERICHOST|NI_NUMERICSERV); + getnameinfo((struct sockaddr *)&local_addr.addr, + local_addr.salen, local_addr_s, sizeof(local_addr_s), + local_port, sizeof(local_port), + NI_NUMERICHOST|NI_NUMERICSERV); + + snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = remote_addr.addr.ss_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + getaddrinfo2(remote_addr_s, ident_port, &hints, &ident_serv); + getaddrinfo2(local_addr_s, NULL, &hints, &la); + + sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype, + ident_serv->ai_protocol); - sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sock_fd == -1) { elog(LOG, "Failed to create socket on which to talk to Ident server: %m"); @@ -1126,42 +1227,27 @@ } else { - struct sockaddr_in ident_server; - struct sockaddr_in la; - - /* - * Socket address of Ident server on the system from which client - * is attempting to connect to us. - */ - ident_server.sin_family = AF_INET; - ident_server.sin_port = htons(IDENT_PORT); - ident_server.sin_addr = remote_ip_addr; - /* * Bind to the address which the client originally contacted, * otherwise the ident server won't be able to match up the right * connection. This is necessary if the PostgreSQL server is * running on an IP alias. */ - memset(&la, 0, sizeof(la)); - la.sin_family = AF_INET; - la.sin_addr = local_ip_addr; - rc = bind(sock_fd, (struct sockaddr *) & la, sizeof(la)); + + rc = bind(sock_fd, la->ai_addr, la->ai_addrlen); if (rc == 0) { - rc = connect(sock_fd, - (struct sockaddr *) & ident_server, sizeof(ident_server)); + rc = connect(sock_fd, ident_serv->ai_addr, + ident_serv->ai_addrlen); } if (rc != 0) { - /* save_errno is in case inet_ntoa changes errno */ - int save_errno = errno; + int save_errno = errno; elog(LOG, "Unable to connect to Ident server on the host which is " "trying to connect to Postgres " - "(IP address %s, Port %d): %s", - inet_ntoa(remote_ip_addr), IDENT_PORT, - strerror(save_errno)); + "(Address %s, Port %s): %s", remote_addr_s, + ident_port, strerror(save_errno)); ident_return = false; } else @@ -1169,8 +1255,8 @@ char ident_query[80]; /* The query we send to the Ident server */ - snprintf(ident_query, sizeof(ident_query), "%d,%d\n", - ntohs(remote_port), ntohs(local_port)); + snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n", + remote_port, local_port); /* loop in case send is interrupted */ do { @@ -1181,10 +1267,9 @@ int save_errno = errno; elog(LOG, "Unable to send query to Ident server on the host which is " - "trying to connect to Postgres (Host %s, Port %d), " + "trying to connect to Postgres (Host %s, Port %s), " "even though we successfully connected to it: %s", - inet_ntoa(remote_ip_addr), IDENT_PORT, - strerror(save_errno)); + remote_addr_s, ident_port, strerror(save_errno)); ident_return = false; } else @@ -1199,9 +1284,9 @@ elog(LOG, "Unable to receive response from Ident server " "on the host which is " - "trying to connect to Postgres (Host %s, Port %d), " + "trying to connect to Postgres (Host %s, Port %s), " "even though we successfully sent our query to it: %s", - inet_ntoa(remote_ip_addr), IDENT_PORT, + remote_addr_s, ident_port, strerror(save_errno)); ident_return = false; } @@ -1215,6 +1300,8 @@ closesocket(sock_fd); } } + freeaddrinfo2(hints.ai_family, la); + freeaddrinfo2(hints.ai_family, ident_serv); return ident_return; } @@ -1371,13 +1458,13 @@ { char ident_user[IDENT_USERNAME_MAX + 1]; - switch (port->raddr.sa.sa_family) + switch (port->raddr.addr.ss_family) { case AF_INET: - if (!ident_inet(port->raddr.in.sin_addr, - port->laddr.in.sin_addr, - port->raddr.in.sin_port, - port->laddr.in.sin_port, ident_user)) +#ifdef HAVE_IPV6 + case AF_INET6: +#endif + if (!ident_inet(port->raddr, port->laddr, ident_user)) return STATUS_ERROR; break; case AF_UNIX: Index: src/backend/libpq/ip.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/ip.c,v retrieving revision 1.7 diff -u -r1.7 ip.c --- src/backend/libpq/ip.c 22 Apr 2003 03:52:56 -0000 1.7 +++ src/backend/libpq/ip.c 1 Jun 2003 17:33:56 -0000 @@ -36,20 +36,19 @@ #include "libpq/ip.h" -static int rangeSockAddrAF_INET(const SockAddr *addr, - const SockAddr *netaddr, - const SockAddr *netmask); - +static int rangeSockAddrAF_INET(const struct sockaddr_in *addr, + const struct sockaddr_in *netaddr, + const struct sockaddr_in *netmask); #ifdef HAVE_IPV6 -static int rangeSockAddrAF_INET6(const SockAddr *addr, - const SockAddr *netaddr, - const SockAddr *netmask); -static void convSockAddr6to4(const SockAddr *src, SockAddr *dst); +static int rangeSockAddrAF_INET6(const struct sockaddr_in6 *addr, + const struct sockaddr_in6 *netaddr, + const struct sockaddr_in6 *netmask); #endif -#ifdef HAVE_UNIX_SOCKETS -static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, - struct addrinfo **result); +#ifdef HAVE_UNIX_SOCKETS +static int getaddrinfo_unix(const char *path, + const struct addrinfo *hintsp, + struct addrinfo **result); #endif @@ -72,7 +71,7 @@ /* - * freeaddrinfo2 - free IPv6 addrinfo structures + * freeaddrinfo2 - free addrinfo structures */ void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai) @@ -113,6 +112,11 @@ struct addrinfo *aip; struct sockaddr_un *unp; + if (strlen(path) >= sizeof(unp->sun_path)) + { + return EAI_FAIL; + } + MemSet(&hints, 0, sizeof(hints)); if (hintsp == NULL) @@ -129,7 +133,7 @@ if (hints.ai_family != AF_UNIX) { /* shouldn't have been called */ - return EAI_ADDRFAMILY; + return EAI_FAIL; } aip = calloc(1, sizeof(struct addrinfo)); @@ -144,15 +148,16 @@ *result = aip; unp = calloc(1, sizeof(struct sockaddr_un)); - if (aip == NULL) + if (unp == NULL) + { + free(aip); return EAI_MEMORY; + } unp->sun_family = AF_UNIX; aip->ai_addr = (struct sockaddr *) unp; aip->ai_addrlen = sizeof(struct sockaddr_un); - if (strlen(path) >= sizeof(unp->sun_path)) - return EAI_SERVICE; strcpy(unp->sun_path, path); #if SALEN @@ -163,121 +168,106 @@ } #endif /* HAVE_UNIX_SOCKETS */ -/* ---------- - * SockAddr_ntop - set IP address string from SockAddr - * - * parameters... sa : SockAddr union - * dst : buffer for address string - * cnt : sizeof dst - * v4conv: non-zero: if address is IPv4 mapped IPv6 address then - * convert to IPv4 address. - * returns... pointer to dst - * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string. - * ---------- - */ -char * -SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv) + +int +rangeSockAddr(const struct sockaddr_storage *addr, + const struct sockaddr_storage *netaddr, + const struct sockaddr_storage *netmask) { - switch (sa->sa.sa_family) - { - case AF_INET: -#ifdef HAVE_IPV6 - inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt); -#else - StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt); -#endif - break; + if (addr->ss_family == AF_INET) + return rangeSockAddrAF_INET((struct sockaddr_in *)addr, + (struct sockaddr_in *)netaddr, + (struct sockaddr_in *)netmask); #ifdef HAVE_IPV6 - case AF_INET6: - inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt); - if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) - strcpy(dst, dst + 7); - break; + else if (addr->ss_family == AF_INET6) + return rangeSockAddrAF_INET6((struct sockaddr_in6 *)addr, + (struct sockaddr_in6 *)netaddr, + (struct sockaddr_in6 *)netmask); #endif - default: - dst[0] = '\0'; - break; - } - return dst; + else + return 0; } - /* - * SockAddr_pton - IPv6 pton + * SockAddr_cidr_mask - make a network mask of the appropriate family + * and required number of significant bits + * + * Note: Returns a static pointer for the mask, so it's not thread safe, + * and a second call will overwrite the data. */ int -SockAddr_pton(SockAddr *sa, const char *src) +SockAddr_cidr_mask(struct sockaddr_storage **mask, char *numbits, int family) { - int family = AF_INET; + long bits; + char *endptr; +static struct sockaddr_storage sock; + struct sockaddr_in mask4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 mask6; +#endif + bits = strtol(numbits, &endptr, 10); + + if (*numbits == '\0' || *endptr != '\0') + { + return -1; + } + + if ((bits < 0) || (family == AF_INET && bits > 32) #ifdef HAVE_IPV6 - if (strchr(src, ':')) - family = AF_INET6; + || (family == AF_INET6 && bits > 128) #endif + ) + { + return -1; + } - sa->sa.sa_family = family; + *mask = &sock; switch (family) { case AF_INET: -#ifdef HAVE_IPV6 - return inet_pton(AF_INET, src, &sa->in.sin_addr); -#else - return inet_aton(src, &sa->in.sin_addr); -#endif - + mask4.sin_addr.s_addr = + htonl((0xffffffffUL << (32 - bits)) + & 0xffffffffUL); + memcpy(&sock, &mask4, sizeof(mask4)); + break; #ifdef HAVE_IPV6 case AF_INET6: - return inet_pton(AF_INET6, src, &sa->in6.sin6_addr); + for (i = 0; i < 16; i++) + { + if (bits <= 0) + { + mask6.sin6_addr.s6_addr[i] = 0; + } + else if (bits >= 8) + { + mask6.sin6_addr.s6_addr[i] = 0xff; + } + else + { + mask6.sin6_addr.s6_addr[i] = + (0xff << (8 - bits)) & 0xff; + } + bits -= 8; + } + memcpy(&sock, &mask6, sizeof(mask6)); break; #endif default: return -1; } -} - -/* - * isAF_INETx - check to see if sa is AF_INET or AF_INET6 - */ -int -isAF_INETx(const int family) -{ - if (family == AF_INET -#ifdef HAVE_IPV6 - || family == AF_INET6 -#endif - ) - return 1; - else - return 0; + sock.ss_family = family; + return 0; } - int -rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, - const SockAddr *netmask) +rangeSockAddrAF_INET(const struct sockaddr_in *addr, const struct sockaddr_in *netaddr, + const struct sockaddr_in *netmask) { - if (addr->sa.sa_family == AF_INET) - return rangeSockAddrAF_INET(addr, netaddr, netmask); -#ifdef HAVE_IPV6 - else if (addr->sa.sa_family == AF_INET6) - return rangeSockAddrAF_INET6(addr, netaddr, netmask); -#endif - else - return 0; -} - -static int -rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr, - const SockAddr *netmask) -{ - if (addr->sa.sa_family != AF_INET || - netaddr->sa.sa_family != AF_INET || - netmask->sa.sa_family != AF_INET) - return 0; - if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) & - netmask->in.sin_addr.s_addr) == 0) + if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & + netmask->sin_addr.s_addr) == 0) return 1; else return 0; @@ -285,46 +275,22 @@ #ifdef HAVE_IPV6 - -static int -rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr, - const SockAddr *netmask) +int +rangeSockAddrAF_INET6(const struct sockaddr_in6 *addr, + const struct sockaddr_in6 *netaddr, + const struct sockaddr_in6 *netmask) { int i; - if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr)) - { - SockAddr addr4; - - convSockAddr6to4(addr, &addr4); - if (rangeSockAddrAF_INET(&addr4, netaddr, netmask)) - return 1; - } - - if (netaddr->sa.sa_family != AF_INET6 || - netmask->sa.sa_family != AF_INET6) - return 0; - for (i = 0; i < 16; i++) { - if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) & - netmask->in6.sin6_addr.s6_addr[i]) != 0) + if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & + netmask->sin6_addr.s6_addr[i]) != 0) return 0; } return 1; } +#endif -static void -convSockAddr6to4(const SockAddr *src, SockAddr *dst) -{ - MemSet(dst, 0, sizeof(*dst)); - dst->in.sin_family = AF_INET; - /* both src and dst are assumed to be in network byte order */ - dst->in.sin_port = src->in6.sin6_port; - memcpy(&dst->in.sin_addr.s_addr, - ((char *) (&src->in6.sin6_addr.s6_addr)) + 12, - sizeof(struct in_addr)); -} -#endif /* HAVE_IPV6 */ Index: src/backend/libpq/pg_hba.conf.sample =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/pg_hba.conf.sample,v retrieving revision 1.41 diff -u -r1.41 pg_hba.conf.sample --- src/backend/libpq/pg_hba.conf.sample 6 Jan 2003 03:18:26 -0000 1.41 +++ src/backend/libpq/pg_hba.conf.sample 1 Jun 2003 17:33:56 -0000 @@ -46,4 +46,6 @@ local all all trust host all all 127.0.0.1 255.255.255.255 trust -host all all ::1 ffff:ffff:ffff:ffff:ffff:ffff trust +host all all ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff trust +host all all ::ffff:127.0.0.1/128 trust + Index: src/backend/libpq/pqcomm.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/pqcomm.c,v retrieving revision 1.154 diff -u -r1.154 pqcomm.c --- src/backend/libpq/pqcomm.c 29 May 2003 19:15:34 -0000 1.154 +++ src/backend/libpq/pqcomm.c 1 Jun 2003 17:33:56 -0000 @@ -199,33 +199,30 @@ int StreamServerPort(int family, char *hostName, unsigned short portNumber, - char *unixSocketName, int *fdP) + char *unixSocketName, int ListenSocket[], int MaxListen) { int fd, err; int maxconn; int one = 1; int ret; - char portNumberStr[64]; - char *service; - struct addrinfo *addrs = NULL; - struct addrinfo hint; - -#ifdef HAVE_UNIX_SOCKETS - Assert(family == AF_UNIX || isAF_INETx(family)); -#else - Assert(isAF_INETx(family)); -#endif + char portNumberStr[64]; + char *service; + struct addrinfo *addrs = NULL, *addr; + struct addrinfo hint; + int listen_index = 0; + int added = 0; /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_family = family; - hint.ai_flags = AI_PASSIVE; + hint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 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; @@ -247,75 +244,133 @@ return STATUS_ERROR; } - if ((fd = socket(family, SOCK_STREAM, 0)) < 0) + for (addr = addrs; addr; addr = addr->ai_next) { - elog(LOG, "server socket failure: socket(): %s", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } + 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; + } - if (isAF_INETx(family)) - { - if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, - sizeof(one))) == -1) + /* See if there is still room to add 1 more socket. */ + for (; listen_index < MaxListen; listen_index++) + { + if (ListenSocket[listen_index] == -1) + { + break; + } + } + if (listen_index == MaxListen) + { + /* Nothing found. */ + break; + } + if ((fd = socket(addr->ai_family, addr->ai_socktype, + addr->ai_protocol)) < 0) { - elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s", + elog(LOG, "server socket failure: socket(): %s", strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; + continue; } - } - Assert(addrs->ai_next == NULL && addrs->ai_family == family); - err = bind(fd, addrs->ai_addr, addrs->ai_addrlen); - if (err < 0) - { - elog(LOG, "server socket failure: bind(): %s\n" - "\tIs another postmaster already running on port %d?", - strerror(errno), (int) portNumber); - if (family == AF_UNIX) - elog(LOG, "\tIf not, remove socket node (%s) and retry.", - sock_path); - else - elog(LOG, "\tIf not, wait a few seconds and retry."); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } + + + if (!IS_AF_UNIX(addr->ai_family)) + { + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &one, sizeof(one))) == -1) + { + elog(LOG, "server socket failure: " + "setsockopt(SO_REUSEADDR): %s", + strerror(errno)); + close(fd); + continue; + } + } + +#ifdef IPV6_V6ONLY + if (addr->ai_family == AF_INET6) + { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&one, sizeof(on)) == -1) + { + elog(LOG, "server socket failure: " + "setsockopt(IPV6_V6ONLY): %s", + strerror(errno)); + close(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) + { + elog(LOG, "server socket failure: bind(): %s\n" + "\tIs another postmaster already running on " + "port %d?", strerror(errno), (int) portNumber); + if (addr->ai_family == AF_UNIX) + { + elog(LOG, "\tIf not, remove socket node (%s) " + "and retry.", sock_path); + } + else + { + elog(LOG, "\tIf not, wait a few seconds and " + "retry."); + } + close(fd); + continue; + } #ifdef HAVE_UNIX_SOCKETS - if (family == AF_UNIX) - { - if (Setup_AF_UNIX() != STATUS_OK) + if (addr->ai_family == AF_UNIX) { - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; + if (Setup_AF_UNIX() != STATUS_OK) + { + close(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; + /* + * 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) + err = listen(fd, maxconn); + if (err < 0) + { + elog(LOG, "server socket failure: listen(): %s", + strerror(errno)); + close(fd); + continue; + } + ListenSocket[listen_index] = fd; + added++; + } + + freeaddrinfo(addrs); + + if (!added) { - elog(LOG, "server socket failure: listen(): %s", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } - - *fdP = fd; - freeaddrinfo2(hint.ai_family, addrs); return STATUS_OK; - } @@ -327,10 +382,7 @@ static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName) { - SockAddr saddr; /* just used to get socket path */ - - UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName); - strcpy(sock_path, saddr.un.sun_path); + UNIXSOCK_PATH(sock_path, portNumber, unixSocketName); /* * Grab an interlock file associated with the socket file. @@ -424,13 +476,11 @@ int StreamConnection(int server_fd, Port *port) { - ACCEPT_TYPE_ARG3 addrlen; - /* accept connection (and fill in the client (remote) address) */ - addrlen = sizeof(port->raddr); + port->raddr.salen = sizeof(port->raddr.addr); if ((port->sock = accept(server_fd, - (struct sockaddr *) &port->raddr, - &addrlen)) < 0) + (struct sockaddr *) &port->raddr.addr, + &port->raddr.salen)) < 0) { elog(LOG, "StreamConnection: accept() failed: %m"); return STATUS_ERROR; @@ -446,25 +496,27 @@ #endif /* fill in the server (local) address */ - addrlen = sizeof(port->laddr); - if (getsockname(port->sock, (struct sockaddr *) & port->laddr, - &addrlen) < 0) + port->laddr.salen = sizeof(port->laddr.addr); + if (getsockname(port->sock, (struct sockaddr *) & port->laddr.addr, + &port->laddr.salen) < 0) { elog(LOG, "StreamConnection: getsockname() failed: %m"); return STATUS_ERROR; } /* select NODELAY and KEEPALIVE options if it's a TCP connection */ - if (isAF_INETx(port->laddr.sa.sa_family)) + if (!IS_AF_UNIX(port->laddr.addr.ss_family)) { int on = 1; +#ifdef TCP_NODELAY if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { elog(LOG, "StreamConnection: setsockopt(TCP_NODELAY) failed: %m"); return STATUS_ERROR; } +#endif if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { Index: src/backend/postmaster/pgstat.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/pgstat.c,v retrieving revision 1.36 diff -u -r1.36 pgstat.c --- src/backend/postmaster/pgstat.c 15 May 2003 16:35:29 -0000 1.36 +++ src/backend/postmaster/pgstat.c 1 Jun 2003 17:34:06 -0000 @@ -22,7 +22,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -36,6 +38,7 @@ #include "catalog/pg_shadow.h" #include "catalog/pg_database.h" #include "libpq/pqsignal.h" +#include "libpq/libpq.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "utils/memutils.h" @@ -69,7 +72,7 @@ */ static int pgStatSock = -1; static int pgStatPipe[2]; -static struct sockaddr_in pgStatAddr; +static struct sockaddr_storage pgStatAddr; static int pgStatPmPipe[2] = {-1, -1}; static int pgStatPid; @@ -141,7 +144,9 @@ void pgstat_init(void) { - int alen; + ACCEPT_TYPE_ARG3 alen; + struct addrinfo *addr, hints; + int ret; /* * Force start of collector daemon if something to collect @@ -174,7 +179,24 @@ /* * Create the UDP socket for sending and receiving statistic messages */ - if ((pgStatSock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + ret = getaddrinfo2("localhost", NULL, &hints, &addr); + if (ret || !addr) + { + elog(LOG, "PGSTAT: getaddrinfo2() failed: %s", + gai_strerror(ret)); + goto startup_failed; + } + + if ((pgStatSock = socket(addr->ai_family, + addr->ai_socktype, addr->ai_protocol)) < 0) { elog(LOG, "PGSTAT: socket() failed: %m"); goto startup_failed; @@ -184,16 +206,16 @@ * Bind it to a kernel assigned port on localhost and get the assigned * port via getsockname(). */ - pgStatAddr.sin_family = AF_INET; - pgStatAddr.sin_port = htons(0); - inet_aton("127.0.0.1", &(pgStatAddr.sin_addr)); - alen = sizeof(pgStatAddr); - if (bind(pgStatSock, (struct sockaddr *) & pgStatAddr, alen) < 0) + if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0) { - elog(LOG, "PGSTAT: bind(127.0.0.1) failed: %m"); + elog(LOG, "PGSTAT: bind() failed: %m"); goto startup_failed; } - if (getsockname(pgStatSock, (struct sockaddr *) & pgStatAddr, &alen) < 0) + freeaddrinfo2(hints.ai_family, addr); + addr = NULL; + + alen = sizeof(pgStatAddr); + if (getsockname(pgStatSock, (struct sockaddr *)&pgStatAddr, &alen) < 0) { elog(LOG, "PGSTAT: getsockname() failed: %m"); goto startup_failed; @@ -235,6 +257,11 @@ return; startup_failed: + if (addr) + { + freeaddrinfo2(hints.ai_family, addr); + } + if (pgStatSock >= 0) closesocket(pgStatSock); pgStatSock = -1; @@ -1496,7 +1523,7 @@ int msg_send = 0; /* next send index in buffer */ int msg_recv = 0; /* next receive index */ int msg_have = 0; /* number of bytes stored */ - struct sockaddr_in fromaddr; + struct sockaddr_storage fromaddr; int fromlen; bool overflow = false; @@ -1601,9 +1628,9 @@ if (FD_ISSET(pgStatSock, &rfds)) { fromlen = sizeof(fromaddr); - len = recvfrom(pgStatSock, - (char *) &input_buffer, sizeof(PgStat_Msg), 0, - (struct sockaddr *) &fromaddr, &fromlen); + len = recvfrom(pgStatSock, (char *) &input_buffer, + sizeof(PgStat_Msg), 0, + (struct sockaddr *) &fromaddr, &fromlen); if (len < 0) { elog(LOG, "PGSTATBUFF: recvfrom() failed: %m"); @@ -1629,9 +1656,7 @@ * kernel-level check due to having used connect(), but let's * do it anyway.) */ - if (fromaddr.sin_addr.s_addr != pgStatAddr.sin_addr.s_addr) - continue; - if (fromaddr.sin_port != pgStatAddr.sin_port) + if (memcmp(&fromaddr, &pgStatAddr, fromlen)) continue; /* Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v retrieving revision 1.331 diff -u -r1.331 postmaster.c --- src/backend/postmaster/postmaster.c 28 May 2003 19:36:28 -0000 1.331 +++ src/backend/postmaster/postmaster.c 1 Jun 2003 17:34:06 -0000 @@ -164,14 +164,9 @@ static char *progname = (char *) NULL; -/* - * Default Values - */ -static int ServerSock_INET = INVALID_SOCK; /* stream socket server */ - -#ifdef HAVE_UNIX_SOCKETS -static int ServerSock_UNIX = INVALID_SOCK; /* stream socket server */ -#endif +/* The sockets we're listening to. */ +#define MAXLISTEN 10 +int ListenSocket[MAXLISTEN]; /* Used to reduce macros tests */ #ifdef EXEC_BACKEND @@ -369,10 +364,11 @@ int PostmasterMain(int argc, char *argv[]) { - int opt; - int status; + int opt; + int status; char original_extraoptions[MAXPGPATH]; - char *potential_DataDir = NULL; + char *potential_DataDir = NULL; + int i; *original_extraoptions = '\0'; @@ -698,39 +694,59 @@ /* * Establish input sockets. */ + for (i = 0; i < MAXLISTEN; i++) + { + ListenSocket[i] = -1; + } if (NetServer) { -#ifdef HAVE_IPV6 - /* Try INET6 first. May fail if kernel doesn't support IP6 */ - status = StreamServerPort(AF_INET6, VirtualHost, - (unsigned short) PostPortNumber, - UnixSocketDir, - &ServerSock_INET); - if (status != STATUS_OK) - { - elog(LOG, "IPv6 support disabled --- perhaps the kernel does not support IPv6"); -#endif - status = StreamServerPort(AF_INET, VirtualHost, - (unsigned short) PostPortNumber, - UnixSocketDir, - &ServerSock_INET); + if (VirtualHost && VirtualHost[0]) + { + char *p, *q; + char c = 0; + + q = VirtualHost; + do + { + p = strchr(q, ' '); + if (p) + { + c = *p; + *p = '\0'; + } + status = StreamServerPort(AF_UNSPEC, q, + (unsigned short) PostPortNumber, + UnixSocketDir, ListenSocket, MAXLISTEN); + if (status != STATUS_OK) + { + postmaster_error("cannot create tcpip " + "listen socket for: %s", p); + } + if (p) + { + *p = c; + q = p + 1; + } + } + while (p); + } + else + { + status = StreamServerPort(AF_UNSPEC, NULL, + (unsigned short) PostPortNumber, + UnixSocketDir, ListenSocket, MAXLISTEN); if (status != STATUS_OK) { - postmaster_error("cannot create INET stream port"); - ExitPostmaster(1); + postmaster_error("cannot create tcpip listen " + "socket."); } -#ifdef HAVE_IPV6 - else - elog(LOG, "IPv4 socket created"); } -#endif } #ifdef HAVE_UNIX_SOCKETS - status = StreamServerPort(AF_UNIX, VirtualHost, - (unsigned short) PostPortNumber, - UnixSocketDir, - &ServerSock_UNIX); + status = StreamServerPort(AF_UNIX, NULL, + (unsigned short) PostPortNumber, + UnixSocketDir, ListenSocket, MAXLISTEN); if (status != STATUS_OK) { postmaster_error("cannot create UNIX stream port"); @@ -934,12 +950,11 @@ static int ServerLoop(void) { - fd_set readmask, - writemask; + fd_set readmask, writemask; int nSockets; - struct timeval now, - later; - struct timezone tz; + struct timeval now, later; + struct timezone tz; + int i; gettimeofday(&now, &tz); @@ -1038,40 +1053,22 @@ * New connection pending on our well-known port's socket? If so, * fork a child process to deal with it. */ - -#ifdef HAVE_UNIX_SOCKETS - if (ServerSock_UNIX != INVALID_SOCK - && FD_ISSET(ServerSock_UNIX, &rmask)) - { - port = ConnCreate(ServerSock_UNIX); - if (port) - { - BackendStartup(port); - - /* - * We no longer need the open socket or port structure in - * this process - */ - StreamClose(port->sock); - ConnFree(port); - } - } -#endif - - if (ServerSock_INET != INVALID_SOCK - && FD_ISSET(ServerSock_INET, &rmask)) + for (i = 0; i < MAXLISTEN; i++) { - port = ConnCreate(ServerSock_INET); - if (port) + if (ListenSocket[i] != -1 && FD_ISSET(ListenSocket[i], &rmask)) { - BackendStartup(port); + port = ConnCreate(ListenSocket[i]); + if (port) + { + BackendStartup(port); - /* - * We no longer need the open socket or port structure in - * this process - */ - StreamClose(port->sock); - ConnFree(port); + /* + * We no longer need the open socket + * or port structure in this process + */ + StreamClose(port->sock); + ConnFree(port); + } } } @@ -1091,25 +1088,20 @@ initMasks(fd_set *rmask, fd_set *wmask) { int nsocks = -1; + int i; FD_ZERO(rmask); FD_ZERO(wmask); -#ifdef HAVE_UNIX_SOCKETS - if (ServerSock_UNIX != INVALID_SOCK) - { - FD_SET(ServerSock_UNIX, rmask); - - if (ServerSock_UNIX > nsocks) - nsocks = ServerSock_UNIX; - } -#endif - - if (ServerSock_INET != INVALID_SOCK) + for (i = 0; i < MAXLISTEN; i++) { - FD_SET(ServerSock_INET, rmask); - if (ServerSock_INET > nsocks) - nsocks = ServerSock_INET; + int fd = ListenSocket[i]; + if (fd != -1) + { + FD_SET(fd, rmask); + if (fd > nsocks) + nsocks = fd; + } } return nsocks + 1; @@ -1533,14 +1525,18 @@ void ClosePostmasterPorts(bool pgstat_too) { + int i; + /* Close the listen sockets */ - if (NetServer) - StreamClose(ServerSock_INET); - ServerSock_INET = INVALID_SOCK; -#ifdef HAVE_UNIX_SOCKETS - StreamClose(ServerSock_UNIX); - ServerSock_UNIX = INVALID_SOCK; -#endif + for (i = 0; i < MAXLISTEN; i++) + { + if (ListenSocket[i] != -1) + { + StreamClose(ListenSocket[i]); + ListenSocket[i] = -1; + } + } + /* Close pgstat control sockets, unless we're starting pgstat itself */ if (pgstat_too) pgstat_close_sockets(); @@ -2199,19 +2195,20 @@ static int BackendFork(Port *port) { - char *remote_host; - char **av; - int maxac; - int ac; + char **av; + int maxac; + int ac; char debugbuf[32]; char protobuf[32]; #ifdef EXEC_BACKEND char pbuf[NAMEDATALEN + 256]; #endif - int i; - int status; - struct timeval now; - struct timezone tz; + int i; + int status; + struct timeval now; + struct timezone tz; + char remote_host[NI_MAXHOST]; + char remote_port[NI_MAXSERV]; /* * Let's clean up ourselves as the postmaster child @@ -2259,63 +2256,37 @@ /* * Get the remote host name and port for logging and status display. */ - if (isAF_INETx(port->raddr.sa.sa_family)) - { - unsigned short remote_port; - char *host_addr; -#ifdef HAVE_IPV6 - char ip_hostinfo[INET6_ADDRSTRLEN]; -#else - char ip_hostinfo[INET_ADDRSTRLEN]; -#endif - - remote_port = ntohs(port->raddr.in.sin_port); - host_addr = SockAddr_ntop(&port->raddr, ip_hostinfo, - sizeof(ip_hostinfo), 1); - - remote_host = NULL; - - if (log_hostname) - { - struct hostent *host_ent; - - host_ent = gethostbyaddr((char *) &port->raddr.in.sin_addr, - sizeof(port->raddr.in.sin_addr), - AF_INET); - - if (host_ent) - { - remote_host = palloc(strlen(host_addr) + strlen(host_ent->h_name) + 3); - sprintf(remote_host, "%s[%s]", host_ent->h_name, host_addr); - } - } - - if (remote_host == NULL) - remote_host = pstrdup(host_addr); + remote_host[0] = '\0'; + remote_port[0] = '\0'; + if (!getnameinfo((struct sockaddr *)&port->raddr.addr, + port->raddr.salen, + remote_host, sizeof(remote_host), + remote_port, sizeof(remote_host), + (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) + { + getnameinfo((struct sockaddr *)&port->raddr.addr, + port->raddr.salen, + remote_host, sizeof(remote_host), + remote_port, sizeof(remote_host), + NI_NUMERICHOST | NI_NUMERICSERV); + } - if (Log_connections) - elog(LOG, "connection received: host=%s port=%hu", - remote_host, remote_port); - - if (LogSourcePort) - { - /* modify remote_host for use in ps status */ - int slen = strlen(remote_host) + 10; - char *str = palloc(slen); - - snprintf(str, slen, "%s:%hu", remote_host, remote_port); - pfree(remote_host); - remote_host = str; - } + if (Log_connections) + { + elog(LOG, "connection received: host=%s port=%s", + remote_host, remote_port); } - else + + if (LogSourcePort) { - /* not AF_INET */ - remote_host = "[local]"; + /* modify remote_host for use in ps status */ + int slen = strlen(remote_host) + 10; + char *str = palloc(slen); - if (Log_connections) - elog(LOG, "connection received: host=%s", - remote_host); + snprintf(str, slen, "%s:%s", remote_host, remote_port); + strncpy(remote_host, str, sizeof(remote_host)); + remote_host[sizeof(remote_host) - 1] = '\0'; + pfree(str); } /* @@ -2489,14 +2460,8 @@ * * MUST -- vadim 05-10-1999 */ - if (ServerSock_INET != INVALID_SOCK) - StreamClose(ServerSock_INET); - ServerSock_INET = INVALID_SOCK; -#ifdef HAVE_UNIX_SOCKETS - if (ServerSock_UNIX != INVALID_SOCK) - StreamClose(ServerSock_UNIX); - ServerSock_UNIX = INVALID_SOCK; -#endif + /* Should I use true instead? */ + ClosePostmasterPorts(false); proc_exit(status); } Index: src/include/getaddrinfo.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/getaddrinfo.h,v retrieving revision 1.2 diff -u -r1.2 getaddrinfo.h --- src/include/getaddrinfo.h 2 Apr 2003 00:49:28 -0000 1.2 +++ src/include/getaddrinfo.h 1 Jun 2003 17:34:07 -0000 @@ -40,23 +40,30 @@ struct addrinfo *ai_next; }; -#define EAI_BADFLAGS -1 +#define EAI_BADFLAGS -1 #define EAI_NONAME -2 #define EAI_AGAIN -3 #define EAI_FAIL -4 -#define EAI_NODATA -5 #define EAI_FAMILY -6 -#define EAI_SOCKTYPE -7 +#define EAI_SOCKTYPE -7 #define EAI_SERVICE -8 -#define EAI_ADDRFAMILY -9 #define EAI_MEMORY -10 #define EAI_SYSTEM -11 #define AI_PASSIVE 0x0001 #define AI_NUMERICHOST 0x0004 +#define NI_NUMERICHOST 1 +#define NI_NUMERICSERV 2 + #endif /* HAVE_STRUCT_ADDRINFO */ +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 +#endif + + #ifndef HAVE_GETADDRINFO @@ -76,10 +83,18 @@ #endif #define gai_strerror pg_gai_strerror +#ifdef getnameinfo +#undef getnameinfo +#endif +#define getnameinfo pg_getnameinfo + extern int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); extern void freeaddrinfo(struct addrinfo *res); extern const char *gai_strerror(int errcode); +extern int getnameinfo(const struct sockaddr *sa, int salen, + char *node, int nodelen, + char *service, int servicelen, int flags); #endif /* HAVE_GETADDRINFO */ Index: src/include/pg_config.h.in =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/pg_config.h.in,v retrieving revision 1.48 diff -u -r1.48 pg_config.h.in --- src/include/pg_config.h.in 27 May 2003 16:36:50 -0000 1.48 +++ src/include/pg_config.h.in 1 Jun 2003 17:34:07 -0000 @@ -412,7 +412,7 @@ #undef HAVE_STRUCT_FCRED /* Define to 1 if the system has the type `struct sockaddr_un'. */ -#undef HAVE_STRUCT_SOCKADDR_UN +#undef HAVE_UNIX_SOCKETS /* Define to 1 if the system has the type `struct sockcred'. */ #undef HAVE_STRUCT_SOCKCRED @@ -458,6 +458,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have struct sockaddr_storage */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H Index: src/include/pg_config_manual.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/pg_config_manual.h,v retrieving revision 1.3 diff -u -r1.3 pg_config_manual.h --- src/include/pg_config_manual.h 15 May 2003 16:35:29 -0000 1.3 +++ src/include/pg_config_manual.h 1 Jun 2003 17:34:07 -0000 @@ -127,11 +127,10 @@ #define BITS_PER_BYTE 8 /* - * Define this if your operating system supports AF_UNIX family - * sockets. + * Disable UNIX sockets for those operating system. */ -#if !defined(__QNX__) && !defined(__BEOS__) && !defined(WIN32) -# define HAVE_UNIX_SOCKETS 1 +#if defined(__QNX__) || defined(__BEOS__) || defined(WIN32) +# undef HAVE_UNIX_SOCKETS #endif /* Index: src/include/libpq/ip.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/libpq/ip.h,v retrieving revision 1.3 diff -u -r1.3 ip.h --- src/include/libpq/ip.h 2 Apr 2003 00:49:28 -0000 1.3 +++ src/include/libpq/ip.h 1 Jun 2003 17:34:07 -0000 @@ -21,12 +21,17 @@ struct addrinfo **result); extern void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai); -extern char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, - int v4conv); -extern int SockAddr_pton(SockAddr *sa, const char *src); +extern int rangeSockAddr(const struct sockaddr_storage *addr, + const struct sockaddr_storage *netaddr, + const struct sockaddr_storage *netmask); -extern int isAF_INETx(const int family); -extern int rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, - const SockAddr *netmask); +extern int SockAddr_cidr_mask(struct sockaddr_storage **mask, + char *numbits, int family); + +#ifdef HAVE_UNIX_SOCKETS +#define IS_AF_UNIX(fam) (fam == AF_UNIX) +#else +#define IS_AF_UNIX(fam) (0) +#endif #endif /* IP_H */ Index: src/include/libpq/libpq.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/libpq/libpq.h,v retrieving revision 1.57 diff -u -r1.57 libpq.h --- src/include/libpq/libpq.h 19 Apr 2003 00:02:29 -0000 1.57 +++ src/include/libpq/libpq.h 1 Jun 2003 17:34:07 -0000 @@ -46,7 +46,8 @@ * prototypes for functions in pqcomm.c */ extern int StreamServerPort(int family, char *hostName, - unsigned short portNumber, char *unixSocketName, int *fdP); + unsigned short portNumber, char *unixSocketName, int ListenSocket[], + int MaxListen); extern int StreamConnection(int server_fd, Port *port); extern void StreamClose(int sock); extern void TouchSocketFile(void); Index: src/include/libpq/pqcomm.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/libpq/pqcomm.h,v retrieving revision 1.85 diff -u -r1.85 pqcomm.h --- src/include/libpq/pqcomm.h 8 May 2003 18:33:32 -0000 1.85 +++ src/include/libpq/pqcomm.h 1 Jun 2003 17:34:07 -0000 @@ -32,57 +32,59 @@ #include #endif /* not WIN32 */ - -#ifndef INET_ADDRSTRLEN -#define INET_ADDRSTRLEN 16 -#endif - -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 46 +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE +/* Define a struct sockaddr_storage if we don't have one. */ +/* + * Desired design of maximum size and alignment + */ +#define _SS_MAXSIZE 128 /* Implementation specific max size */ +#define _SS_ALIGNSIZE (sizeof (int64_t)) + /* Implementation specific desired alignment */ +/* + * Definitions used for sockaddr_storage structure paddings design. + */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t) + \ + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + +struct sockaddr_storage { +#ifdef SALEN + uint8_t __ss_len; /* address length */ #endif + sa_family_t ss_family; /* address family */ - -#ifndef HAVE_STRUCT_SOCKADDR_UN -struct sockaddr_un -{ - short int sun_family; /* AF_UNIX */ - char sun_path[108]; /* path name (gag) */ + char __ss_pad1[_SS_PAD1SIZE]; + /* 6 byte pad, this is to make implementation + * specific pad up to alignment field that + * follows explicit in the data structure */ + int64_t __ss_align; + /* field to force desired structure + * storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; + /* 112 byte pad to achieve desired size, + * _SS_MAXSIZE value minus size of ss_family + * __ss_pad1, __ss_align fields is 112 */ }; #endif -/* Define a generic socket address type. */ - -typedef union SockAddr -{ - struct sockaddr sa; - struct sockaddr_in in; -#ifdef HAVE_IPV6 - struct sockaddr_in6 in6; -#endif - struct sockaddr_un un; +typedef struct { + struct sockaddr_storage addr; + ACCEPT_TYPE_ARG3 salen; } SockAddr; +/* Some systems don't have it, so default it to 0 so it doesn't + * have any effect on those systems. */ +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif /* Configure the UNIX socket location for the well known port. */ -#define UNIXSOCK_PATH(sun,port,defpath) \ - snprintf((sun).sun_path, sizeof((sun).sun_path), "%s/.s.PGSQL.%d", \ +#define UNIXSOCK_PATH(path,port,defpath) \ + snprintf(path, sizeof(path), "%s/.s.PGSQL.%d", \ ((defpath) && *(defpath) != '\0') ? (defpath) : \ DEFAULT_PGSOCKET_DIR, \ (port)) - -/* - * We do this because sun_len is in BSD's struct, while others don't. - * We never actually set BSD's sun_len, and I can't think of a - * platform-safe way of doing it, but the code still works. bjm - */ -#if defined(SUN_LEN) -#define UNIXSOCK_LEN(sun) \ - (SUN_LEN(&(sun))) -#else -#define UNIXSOCK_LEN(sun) \ - (strlen((sun).sun_path) + offsetof(struct sockaddr_un, sun_path)) -#endif /* * These manipulate the frontend/backend protocol version number. Index: src/include/port/bsdi.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/port/bsdi.h,v retrieving revision 1.6 diff -u -r1.6 bsdi.h --- src/include/port/bsdi.h 22 May 2003 19:14:25 -0000 1.6 +++ src/include/port/bsdi.h 1 Jun 2003 17:34:07 -0000 @@ -9,7 +9,3 @@ typedef unsigned char slock_t; -/* This is marked as obsoleted in BSD/OS 4.3. */ -#ifndef EAI_ADDRFAMILY -#define EAI_ADDRFAMILY 1 -#endif Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.241 diff -u -r1.241 fe-connect.c --- src/interfaces/libpq/fe-connect.c 15 May 2003 16:35:30 -0000 1.241 +++ src/interfaces/libpq/fe-connect.c 1 Jun 2003 17:34:07 -0000 @@ -739,6 +739,7 @@ static int connectNoDelay(PGconn *conn) { +#ifdef TCP_NODELAY int on = 1; if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, @@ -750,6 +751,7 @@ SOCK_STRERROR(SOCK_ERRNO)); return 0; } +#endif return 1; } @@ -763,15 +765,20 @@ static void connectFailureMessage(PGconn *conn, int errorno) { - if (conn->raddr.sa.sa_family == AF_UNIX) + char hostname[NI_MAXHOST]; + char service[NI_MAXHOST]; + + getnameinfo((struct sockaddr *)&conn->raddr.addr, conn->raddr.salen, + hostname, sizeof(hostname), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + if (conn->raddr.addr.ss_family == AF_UNIX) printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "could not connect to server: %s\n" "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n" ), - SOCK_STRERROR(errorno), - conn->raddr.un.sun_path); + SOCK_STRERROR(errorno), service); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext( @@ -800,12 +807,11 @@ connectDBStart(PGconn *conn) { int portnum; - char portstr[64]; - struct addrinfo *addrs = NULL; - struct addrinfo *addr_cur = NULL; - struct addrinfo hint; - const char *node = NULL; - const char *unix_node = "unix"; + char portstr[64]; + struct addrinfo *addrs = NULL; + struct addrinfo *addr_cur = NULL; + struct addrinfo hint; + const char *node = NULL; int ret; if (!conn) @@ -814,6 +820,7 @@ /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; + hint.ai_family = AF_UNSPEC; /* Ensure our buffers are empty */ conn->inStart = conn->inCursor = conn->inEnd = 0; @@ -823,8 +830,6 @@ * Set up the connection to postmaster/backend. */ - MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr)); - /* Set port number */ if (conn->pgport != NULL && conn->pgport[0] != '\0') portnum = atoi(conn->pgport); @@ -845,30 +850,28 @@ node = conn->pghost; hint.ai_family = AF_UNSPEC; } +#ifdef HAVE_UNIX_SOCKETS else { /* pghostaddr and pghost are NULL, so use Unix domain socket */ -#ifdef HAVE_UNIX_SOCKETS - node = unix_node; + node = NULL; hint.ai_family = AF_UNIX; - UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket); - conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un); - StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr)); + UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); #ifdef USE_SSL /* Don't bother requesting SSL over a Unix socket */ conn->allow_ssl_try = false; conn->require_ssl = false; #endif -#endif /* HAVE_UNIX_SOCKETS */ } +#endif /* HAVE_UNIX_SOCKETS */ /* Use getaddrinfo2() to resolve the address */ ret = getaddrinfo2(node, portstr, &hint, &addrs); if (ret || addrs == NULL) { printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("getaddrinfo() failed: %s\n"), - gai_strerror(ret)); + libpq_gettext("failed to getaddrinfo2(): %s\n"), + gai_strerror(ret)); goto connect_errReturn; } @@ -877,25 +880,23 @@ * and fail only when they all fail (reporting the error returned * for the *last* alternative, which may not be what users expect * :-(). - * - * Notice we never actually fall out of the loop; the only exits are - * via "break" or "goto connect_errReturn". Thus, there is no exit - * test in the for(). */ - for (addr_cur = addrs; ; addr_cur = addr_cur->ai_next) + for (addr_cur = addrs; addr_cur; addr_cur = addr_cur->ai_next) { + /* Save this now, so we can properly report an error. */ + 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, + conn->sock = socket(addr_cur->ai_family, addr_cur->ai_socktype, addr_cur->ai_protocol); if (conn->sock < 0) { - /* ignore socket() failure if we have more addrs to try */ - if (addr_cur->ai_next != NULL) - continue; printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not create socket: %s\n"), - SOCK_STRERROR(SOCK_ERRNO)); - goto connect_errReturn; + libpq_gettext("could not create socket: %s\n"), + SOCK_STRERROR(SOCK_ERRNO)); + continue; } /* @@ -904,10 +905,14 @@ * using SSL, then we need the blocking I/O (XXX Can this be fixed?). */ - if (isAF_INETx(addr_cur->ai_family)) + if (!IS_AF_UNIX(addr_cur->ai_family)) { if (!connectNoDelay(conn)) - goto connect_errReturn; + { + closesocket(conn->sock); + conn->sock = -1; + continue; + } } #if !defined(USE_SSL) @@ -940,7 +945,14 @@ conn->status = CONNECTION_STARTED; break; } - /* otherwise, trouble */ + else + { + /* Something's gone wrong */ + connectFailureMessage(conn, SOCK_ERRNO); + closesocket(conn->sock); + conn->sock = -1; + continue; + } } else { @@ -952,24 +964,15 @@ * This connection failed. We need to close the socket, * and either loop to try the next address or report an error. */ - /* ignore connect() failure if we have more addrs to try */ - if (addr_cur->ai_next != NULL) - { - closesocket(conn->sock); - conn->sock = -1; - continue; - } - /* copy failed address for error report */ - memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); - conn->raddr_len = addr_cur->ai_addrlen; - connectFailureMessage(conn, SOCK_ERRNO); - goto connect_errReturn; + closesocket(conn->sock); + conn->sock = -1; } /* loop over addrs */ - /* Remember the successfully opened address alternative */ - memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); - conn->raddr_len = addr_cur->ai_addrlen; - /* and release the address list */ + if (conn->sock == -1) + { + goto connect_errReturn; + } + /* Release the address list */ freeaddrinfo2(hint.ai_family, addrs); addrs = NULL; @@ -1222,9 +1225,8 @@ { case CONNECTION_STARTED: { - ACCEPT_TYPE_ARG3 laddrlen; int optval; - ACCEPT_TYPE_ARG3 optlen = sizeof(optval); + ACCEPT_TYPE_ARG3 optlen = sizeof(optval); /* * Write ready, since we've made it here, so the @@ -1256,11 +1258,13 @@ } /* Fill in the client address */ - laddrlen = sizeof(conn->laddr); - if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0) + conn->laddr.salen = sizeof(conn->laddr.addr); + if (getsockname(conn->sock, + (struct sockaddr *)&conn->laddr.addr, + &conn->laddr.salen) < 0) { printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get client address from socket: %s\n"), + libpq_gettext("could not get client address from socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO)); goto error_return; } @@ -1859,14 +1863,15 @@ * We need to open a temporary connection to the postmaster. Use the * information saved by connectDB to do this with only kernel calls. */ - if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0) + if ((tmpsock = socket(conn->raddr.addr.ss_family, SOCK_STREAM, 0)) < 0) { strcpy(conn->errorMessage.data, "PQrequestCancel() -- socket() failed: "); goto cancel_errReturn; } retry3: - if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0) + if (connect(tmpsock, (struct sockaddr *)&conn->raddr.addr, + conn->raddr.salen) < 0) { if (SOCK_ERRNO == EINTR) /* Interrupted system call - we'll just try again */ Index: src/interfaces/libpq/libpq-int.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-int.h,v retrieving revision 1.70 diff -u -r1.70 libpq-int.h --- src/interfaces/libpq/libpq-int.h 8 May 2003 18:33:39 -0000 1.70 +++ src/interfaces/libpq/libpq-int.h 1 Jun 2003 17:34:07 -0000 @@ -253,7 +253,6 @@ int sock; /* Unix FD for socket, -1 if not connected */ SockAddr laddr; /* Local address */ SockAddr raddr; /* Remote address */ - int raddr_len; /* Length of remote address */ /* Miscellaneous stuff */ int be_pid; /* PID of backend --- needed for cancels */ Index: src/port/getaddrinfo.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/port/getaddrinfo.c,v retrieving revision 1.3 diff -u -r1.3 getaddrinfo.c --- src/port/getaddrinfo.c 27 Apr 2003 23:56:53 -0000 1.3 +++ src/port/getaddrinfo.c 1 Jun 2003 17:34:08 -0000 @@ -16,28 +16,50 @@ /* This is intended to be used in both frontend and backend, so use c.h */ #include "c.h" +#include #include #include #include #include +#ifdef HAVE_UNIX_SOCKETS +#include +#endif #include "getaddrinfo.h" - +/* + * get address info for ipv4 sockets. + * + * Bugs: - only one addrinfo is set even though hintp is NULL or + * ai_socktype is 0 + * - AI_CANONNAME is not supported. + * - servname can only be a number, not text. + */ int getaddrinfo(const char *node, const char *service, - const struct addrinfo *hints, + const struct addrinfo *hintp, struct addrinfo **res) { - struct addrinfo *ai; - struct sockaddr_in sin, *psin; + struct addrinfo *ai; + struct sockaddr_in sin, *psin; + struct addrinfo hints; + + if (hintp == NULL) + { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + } + else + { + memcpy(&hints, hintp, sizeof(hints)); + } - if (!hints || - (hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)) + if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) return EAI_FAMILY; - if (hints->ai_socktype != SOCK_STREAM) - return EAI_SOCKTYPE; + if (hints.ai_socktype == 0) + hints.ai_socktype = SOCK_STREAM; if (!node && !service) return EAI_NONAME; @@ -50,9 +72,12 @@ { if (node[0] == '\0') sin.sin_addr.s_addr = htonl(INADDR_ANY); - else if (hints->ai_flags & AI_NUMERICHOST) + else if (hints.ai_flags & AI_NUMERICHOST) { - inet_aton(node, &sin.sin_addr); + if (!inet_aton(node, &sin.sin_addr)) + { + return EAI_FAIL; + } } else { @@ -64,9 +89,8 @@ switch (h_errno) { case HOST_NOT_FOUND: - return EAI_NONAME; case NO_DATA: - return EAI_NODATA; + return EAI_NONAME; case TRY_AGAIN: return EAI_AGAIN; case NO_RECOVERY: @@ -75,14 +99,14 @@ } } if (hp->h_addrtype != AF_INET) - return EAI_ADDRFAMILY; + return EAI_FAIL; memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length); } } else { - if (hints->ai_flags & AI_PASSIVE) + if (hints.ai_flags & AI_PASSIVE) sin.sin_addr.s_addr = htonl(INADDR_ANY); else sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -90,10 +114,16 @@ if (service) sin.sin_port = htons((unsigned short) atoi(service)); +#if SALEN + sin.sin_len = sizeof(sin); +#endif ai = malloc(sizeof(*ai)); if (!ai) + { return EAI_MEMORY; + } + psin = malloc(sizeof(*psin)); if (!psin) { @@ -103,9 +133,10 @@ memcpy(psin, &sin, sizeof(*psin)); + ai->ai_flags = 0; ai->ai_family = AF_INET; - ai->ai_socktype = SOCK_STREAM; - ai->ai_protocol = IPPROTO_TCP; + ai->ai_socktype = hints.ai_socktype; + ai->ai_protocol = hints.ai_protocol; ai->ai_addrlen = sizeof(*psin); ai->ai_addr = (struct sockaddr *) psin; ai->ai_canonname = NULL; @@ -140,9 +171,6 @@ case EAI_NONAME: hcode = HOST_NOT_FOUND; break; - case EAI_NODATA: - hcode = NO_DATA; - break; case EAI_AGAIN: hcode = TRY_AGAIN; break; @@ -160,8 +188,6 @@ { case EAI_NONAME: return "Unknown host"; - case EAI_NODATA: - return "No address associated with name"; case EAI_AGAIN: return "Host name lookup failure"; case EAI_FAIL: @@ -170,4 +196,83 @@ } #endif /* HAVE_HSTRERROR */ +} + +/* + * Convert an address to a hostname. + * + * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV + * It will never resolv a hostname. + * - No IPv6 support. + */ +int +getnameinfo(const struct sockaddr *sa, int salen, + char *node, int nodelen, + char *service, int servicelen, int flags) +{ + sa_family_t family; + int ret = -1; + + /* Invalid arguments. */ + if (sa == NULL || (node == NULL && service == NULL)) + { + return EAI_FAIL; + } + + /* We don't support those. */ + if ((node && !(flags & NI_NUMERICHOST)) + || (service && !(flags & NI_NUMERICSERV))) + { + return EAI_FAIL; + } + + family = sa->sa_family; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + { + return EAI_FAMILY; + } +#endif + + if (service) + { + if (family == AF_INET) + { + ret = snprintf(service, servicelen, "%d", + ntohs(((struct sockaddr_in *)sa)->sin_port)); + } +#ifdef HAVE_UNIX_SOCKETS + else if (family == AF_UNIX) + { + ret = snprintf(service, servicelen, "%s", + ((struct sockaddr_un *)sa)->sun_path); + } +#endif + if (ret == -1 || ret > servicelen) + { + return EAI_MEMORY; + } + } + + if (node) + { + if (family == AF_INET) + { + char *p; + p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); + ret = snprintf(node, nodelen, "%s", p); + } +#ifdef HAVE_UNIX_SOCKETS + else if (family == AF_UNIX) + { + ret = snprintf(node, nodelen, "%s", "localhost"); + } +#endif + if (ret == -1 || ret > nodelen) + { + return EAI_MEMORY; + } + } + + return 0; }