diff --git a/config/c-library.m4 b/config/c-library.m4 index f482f9936c..bd632ed7cd 100644 --- a/config/c-library.m4 +++ b/config/c-library.m4 @@ -1,5 +1,5 @@ # Macros that test various C library quirks -# $Header: /cvsroot/pgsql/config/c-library.m4,v 1.19 2003/05/22 16:39:26 tgl Exp $ +# $Header: /cvsroot/pgsql/config/c-library.m4,v 1.20 2003/06/12 07:36:51 momjian Exp $ # PGAC_VAR_INT_TIMEZONE @@ -87,11 +87,10 @@ AC_DEFUN([PGAC_UNION_SEMUN], # 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, 1, [Define to 1 if you have unix sockets.])], [], [#include #ifdef HAVE_SYS_UN_H #include @@ -99,6 +98,18 @@ AC_DEFUN([PGAC_STRUCT_SOCKADDR_UN], ])])# 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 # ----------------------- # If `struct addrinfo' exists, define HAVE_STRUCT_ADDRINFO. diff --git a/configure b/configure index 906e9b33b3..2056980885 100755 --- a/configure +++ b/configure @@ -9892,6 +9892,71 @@ cat >>confdefs.h <<_ACEOF _ACEOF +cat >>confdefs.h <<\_ACEOF +#define HAVE_UNIX_SOCKETS 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for struct sockaddr_storage" >&5 +echo $ECHO_N "checking for struct sockaddr_storage... $ECHO_C" >&6 +if test "${ac_cv_type_struct_sockaddr_storage+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +if ((struct sockaddr_storage *) 0) + return 0; +if (sizeof (struct sockaddr_storage)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_struct_sockaddr_storage=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_type_struct_sockaddr_storage=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_storage" >&5 +echo "${ECHO_T}$ac_cv_type_struct_sockaddr_storage" >&6 +if test $ac_cv_type_struct_sockaddr_storage = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +_ACEOF + + fi echo "$as_me:$LINENO: checking for struct addrinfo" >&5 diff --git a/configure.in b/configure.in index 5881542a4c..8ccff55630 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $Header: /cvsroot/pgsql/configure.in,v 1.258 2003/06/11 06:56:06 momjian Exp $ +dnl $Header: /cvsroot/pgsql/configure.in,v 1.259 2003/06/12 07:36:50 momjian Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -789,6 +789,7 @@ PGAC_C_FUNCNAME_SUPPORT 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], [], [], diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 2b0d2d65a8..46965e3bcb 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.101 2003/04/25 03:28:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.102 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -415,15 +415,13 @@ ClientAuthentication(Port *port) * 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", @@ -464,7 +462,7 @@ ClientAuthentication(Port *port) elog(FATAL, "pg_local_sendauth: can't do setsockopt: %m"); } #endif - if (port->raddr.sa.sa_family == AF_UNIX) + if (port->raddr.addr.ss_family == AF_UNIX) sendAuthRequest(port, AUTH_REQ_SCM_CREDS); #endif status = authident(port); diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 4310261a16..c277c90d1b 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.102 2003/06/12 07:00:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.103 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -542,9 +542,14 @@ static void 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 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) 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 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) 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) - goto hba_syntax; - token = lfirst(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; - if(SockAddr_pton(&mask, token) < 0) + /* 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; + } - if(file_ip_addr.sa.sa_family != mask.sa.sa_family) - 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; + } + + /* 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 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) 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 @@ hba_syntax: 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 @@ interpret_ident_response(char *ident_response, * 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 @@ ident_inet(const struct in_addr remote_ip_addr, 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 @@ ident_inet(const struct in_addr remote_ip_addr, } 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 @@ ident_inet(const struct in_addr remote_ip_addr, 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 @@ ident_inet(const struct in_addr remote_ip_addr, 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 @@ ident_inet(const struct in_addr remote_ip_addr, 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 @@ ident_inet(const struct in_addr remote_ip_addr, closesocket(sock_fd); } } + freeaddrinfo2(hints.ai_family, la); + freeaddrinfo2(hints.ai_family, ident_serv); return ident_return; } @@ -1371,13 +1458,13 @@ authident(hbaPort *port) { 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: diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c index 203317be4e..59bee56e21 100644 --- a/src/backend/libpq/ip.c +++ b/src/backend/libpq/ip.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.11 2003/06/12 07:00:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.12 2003/06/12 07:36:51 momjian Exp $ * * This file and the IPV6 implementation were initially provided by * Nigel Kukard , Linux Based Systems Design @@ -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 @@ -127,6 +126,11 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, MemSet(&hints, 0, sizeof(hints)); + if (strlen(path) >= sizeof(unp->sun_path)) + { + return EAI_FAIL; + } + if (hintsp == NULL) { hints.ai_family = AF_UNIX; @@ -141,7 +145,7 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, if (hints.ai_family != AF_UNIX) { /* shouldn't have been called */ - return EAI_ADDRFAMILY; + return EAI_FAIL; } aip = calloc(1, sizeof(struct addrinfo)); @@ -166,8 +170,6 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, 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 @@ -178,121 +180,110 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, } #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: + if (addr->ss_family == AF_INET) + return rangeSockAddrAF_INET((struct sockaddr_in *)addr, + (struct sockaddr_in *)netaddr, + (struct sockaddr_in *)netmask); #ifdef HAVE_IPV6 - inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt); -#else - StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt); + else if (addr->ss_family == AF_INET6) + return rangeSockAddrAF_INET6((struct sockaddr_in6 *)addr, + (struct sockaddr_in6 *)netaddr, + (struct sockaddr_in6 *)netmask); #endif - break; -#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; -#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; - -#ifdef HAVE_IPV6 - if (strchr(src, ':')) - family = AF_INET6; + long bits; + char *endptr; +static struct sockaddr_storage sock; + struct sockaddr_in mask4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 mask6; #endif - sa->sa.sa_family = family; + bits = strtol(numbits, &endptr, 10); + + if (*numbits == '\0' || *endptr != '\0') + { + return -1; + } + + if ((bits < 0) || (family == AF_INET && bits > 32) +#ifdef HAVE_IPV6 + || (family == AF_INET6 && bits > 128) +#endif + ) + { + return -1; + } + + *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); + { + int i; + + 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; } + + sock.ss_family = family; + return 0; } - -/* - * 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; -} - - 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; @@ -300,46 +291,22 @@ rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr, #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 */ diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 1116debbc1..52c0bd4d73 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -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 + diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index ea4ff64468..2cd2c9223f 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -30,7 +30,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.156 2003/06/09 17:59:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.157 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -199,33 +199,30 @@ StreamDoUnlink(void) 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; @@ -246,73 +243,132 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, 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 (isAF_INETx(family)) - { - if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, - sizeof(one))) == -1) + if (!IS_AF_UNIX(family) && IS_AF_UNIX(addr->ai_family)) { - elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s", + /* 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] == -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: 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; - } -#ifdef HAVE_UNIX_SOCKETS - if (family == AF_UNIX) - { - if (Setup_AF_UNIX() != STATUS_OK) + + if (!IS_AF_UNIX(addr->ai_family)) { - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &one, sizeof(one))) == -1) + { + elog(LOG, "server socket failure: " + "setsockopt(SO_REUSEADDR): %s", + strerror(errno)); + closesocket(fd); + continue; + } + } + +#ifdef IPV6_V6ONLY + if (addr->ai_family == AF_INET6) + { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&one, sizeof(one)) == -1) + { + elog(LOG, "server socket failure: " + "setsockopt(IPV6_V6ONLY): %s", + strerror(errno)); + closesocket(fd); + continue; + } } - } #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; + /* + * 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."); + } + closesocket(fd); + continue; + } - err = listen(fd, maxconn); - if (err < 0) - { - elog(LOG, "server socket failure: listen(): %s", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; +#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) + { + elog(LOG, "server socket failure: listen(): %s", + strerror(errno)); + closesocket(fd); + continue; + } + ListenSocket[listen_index] = fd; + added++; } - *fdP = fd; - freeaddrinfo2(hint.ai_family, addrs); + freeaddrinfo(addrs); + + if (!added) + { + return STATUS_ERROR; + } return STATUS_OK; } @@ -325,10 +381,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, 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. @@ -422,13 +475,11 @@ Setup_AF_UNIX(void) 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; @@ -444,25 +495,27 @@ StreamConnection(int server_fd, Port *port) #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) { diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 2b8708fc5d..a0495fff85 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2003, PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.36 2003/05/15 16:35:29 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.37 2003/06/12 07:36:51 momjian Exp $ * ---------- */ #include "postgres.h" @@ -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 @@ bool pgstat_is_running = false; */ 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 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); 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 @@ pgstat_init(void) /* * 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 @@ pgstat_init(void) * 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 @@ pgstat_init(void) return; startup_failed: + if (addr) + { + freeaddrinfo2(hints.ai_family, addr); + } + if (pgStatSock >= 0) closesocket(pgStatSock); pgStatSock = -1; @@ -1496,7 +1523,7 @@ pgstat_recvbuffer(void) 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 @@ pgstat_recvbuffer(void) 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 @@ pgstat_recvbuffer(void) * 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; /* diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 5b16d06a99..e32a668bc7 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.332 2003/06/11 06:56:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.333 2003/06/12 07:36:51 momjian Exp $ * * NOTES * @@ -168,14 +168,9 @@ int ReservedBackends; 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 @@ -384,10 +379,11 @@ reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) 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'; @@ -713,32 +709,53 @@ PostmasterMain(int argc, char *argv[]) /* * 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) + if (VirtualHost && VirtualHost[0]) { - elog(LOG, "IPv6 support disabled --- perhaps the kernel does not support IPv6"); -#endif - status = StreamServerPort(AF_INET, VirtualHost, - (unsigned short) PostPortNumber, - UnixSocketDir, - &ServerSock_INET); + 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 USE_RENDEZVOUS if (service_name != NULL) { @@ -754,10 +771,9 @@ PostmasterMain(int argc, char *argv[]) } #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"); @@ -961,12 +977,11 @@ usage(const char *progname) 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); @@ -1065,40 +1080,22 @@ ServerLoop(void) * 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)) + for (i = 0; i < MAXLISTEN; i++) { - port = ConnCreate(ServerSock_UNIX); - 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); - } - } -#endif - - if (ServerSock_INET != INVALID_SOCK - && FD_ISSET(ServerSock_INET, &rmask)) - { - port = ConnCreate(ServerSock_INET); - 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); + } } } @@ -1118,25 +1115,20 @@ static int 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) + for (i = 0; i < MAXLISTEN; i++) { - FD_SET(ServerSock_UNIX, rmask); - - if (ServerSock_UNIX > nsocks) - nsocks = ServerSock_UNIX; - } -#endif - - if (ServerSock_INET != INVALID_SOCK) - { - 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; @@ -1220,7 +1212,7 @@ ProcessStartupPacket(Port *port, bool SSLdone) #ifdef USE_SSL /* No SSL when disabled or on Unix sockets */ - if (!EnableSSL || port->laddr.sa.sa_family != AF_INET) + if (!EnableSSL || port->laddr.addr.ss_family != AF_INET) SSLok = 'N'; else SSLok = 'S'; /* Support for SSL */ @@ -1560,14 +1552,18 @@ ConnFree(Port *conn) 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(); @@ -2226,19 +2222,20 @@ split_opts(char **argv, int *argcp, char *s) 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 @@ -2286,63 +2283,37 @@ BackendFork(Port *port) /* * Get the remote host name and port for logging and status display. */ - if (isAF_INETx(port->raddr.sa.sa_family)) + 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)) { - 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); - - 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; - } + getnameinfo((struct sockaddr *)&port->raddr.addr, + port->raddr.salen, + remote_host, sizeof(remote_host), + remote_port, sizeof(remote_host), + NI_NUMERICHOST | NI_NUMERICSERV); } - else - { - /* not AF_INET */ - remote_host = "[local]"; - if (Log_connections) - elog(LOG, "connection received: host=%s", - remote_host); + if (Log_connections) + { + elog(LOG, "connection received: host=%s port=%s", + 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:%s", remote_host, remote_port); + strncpy(remote_host, str, sizeof(remote_host)); + remote_host[sizeof(remote_host) - 1] = '\0'; + pfree(str); } /* @@ -2516,14 +2487,8 @@ ExitPostmaster(int status) * * 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); } diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h index 2b47d613e9..416dc65fb1 100644 --- a/src/include/getaddrinfo.h +++ b/src/include/getaddrinfo.h @@ -16,7 +16,7 @@ * * Copyright (c) 2003, PostgreSQL Global Development Group * - * $Id: getaddrinfo.h,v 1.2 2003/04/02 00:49:28 tgl Exp $ + * $Id: getaddrinfo.h,v 1.3 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -40,23 +40,30 @@ struct addrinfo { 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 @@ struct addrinfo { #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 */ diff --git a/src/include/libpq/ip.h b/src/include/libpq/ip.h index b43d997266..b770d33bfe 100644 --- a/src/include/libpq/ip.h +++ b/src/include/libpq/ip.h @@ -5,7 +5,7 @@ * * Copyright (c) 2003, PostgreSQL Global Development Group * - * $Id: ip.h,v 1.7 2003/06/12 07:00:57 momjian Exp $ + * $Id: ip.h,v 1.8 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,12 +21,17 @@ extern int getaddrinfo2(const char *hostname, const char *servname, 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 */ diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index cbe0b646e7..9f72b7e432 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq.h,v 1.57 2003/04/19 00:02:29 tgl Exp $ + * $Id: libpq.h,v 1.58 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -46,7 +46,8 @@ typedef struct * 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); diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index eac9867391..ed41464c2c 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.h,v 1.85 2003/05/08 18:33:32 tgl Exp $ + * $Id: pqcomm.h,v 1.86 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -32,58 +32,60 @@ #include #endif /* not WIN32 */ +#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)) -#ifndef INET_ADDRSTRLEN -#define INET_ADDRSTRLEN 16 +struct sockaddr_storage { +#ifdef SALEN + uint8_t __ss_len; /* address length */ #endif + sa_family_t ss_family; /* address family */ -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 46 -#endif - - -#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. * diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index b20cecf194..a15ca6b6a6 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -411,6 +411,9 @@ /* Define to 1 if the system has the type `struct fcred'. */ #undef HAVE_STRUCT_FCRED +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE + /* Define to 1 if the system has the type `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN @@ -487,6 +490,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have unix sockets. */ +#undef HAVE_UNIX_SOCKETS + /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index e8699c2f4a..3bf316a580 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -6,7 +6,7 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * $Id: pg_config_manual.h,v 1.3 2003/05/15 16:35:29 momjian Exp $ + * $Id: pg_config_manual.h,v 1.4 2003/06/12 07:36:51 momjian Exp $ *------------------------------------------------------------------------ */ @@ -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 /* diff --git a/src/include/port/bsdi.h b/src/include/port/bsdi.h index e5ba051f23..3a2aa59d09 100644 --- a/src/include/port/bsdi.h +++ b/src/include/port/bsdi.h @@ -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 diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 64e39c7baf..4445bd2178 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.243 2003/06/09 17:59:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.244 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -727,6 +727,7 @@ connectMakeNonblocking(PGconn *conn) static int connectNoDelay(PGconn *conn) { +#ifdef TCP_NODELAY int on = 1; if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, @@ -738,6 +739,7 @@ connectNoDelay(PGconn *conn) SOCK_STRERROR(SOCK_ERRNO)); return 0; } +#endif return 1; } @@ -751,15 +753,20 @@ connectNoDelay(PGconn *conn) 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( @@ -788,10 +795,10 @@ static int connectDBStart(PGconn *conn) { int portnum; - char portstr[64]; - struct addrinfo *addrs = NULL; - struct addrinfo hint; - const char *node = NULL; + char portstr[64]; + struct addrinfo *addrs = NULL; + struct addrinfo hint; + const char *node = NULL; int ret; if (!conn) @@ -808,6 +815,7 @@ connectDBStart(PGconn *conn) /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; + hint.ai_family = AF_UNSPEC; /* Set up port number as a string */ if (conn->pgport != NULL && conn->pgport[0] != '\0') @@ -829,17 +837,15 @@ connectDBStart(PGconn *conn) 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 = 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)); -#endif /* HAVE_UNIX_SOCKETS */ + UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); } +#endif /* HAVE_UNIX_SOCKETS */ /* Use getaddrinfo2() to resolve the address */ ret = getaddrinfo2(node, portstr, &hint, &addrs); @@ -1066,12 +1072,11 @@ keep_going: /* We will come back to here until there /* Remember current address for possible error msg */ memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); - conn->raddr_len = addr_cur->ai_addrlen; /* Open a socket */ conn->sock = socket(addr_cur->ai_family, - SOCK_STREAM, - addr_cur->ai_protocol); + addr_cur->ai_socktype, + addr_cur->ai_protocol); if (conn->sock < 0) { /* @@ -1093,13 +1098,23 @@ keep_going: /* We will come back to here until there * Select socket options: no delay of outgoing data for * TCP sockets, and nonblock mode. Fail if this fails. */ - if (isAF_INETx(addr_cur->ai_family)) + if (!IS_AF_UNIX(addr_cur->ai_family)) { if (!connectNoDelay(conn)) - break; + { + closesocket(conn->sock); + conn->sock = -1; + conn->addr_cur = addr_cur->ai_next; + continue; + } } if (connectMakeNonblocking(conn) == 0) - break; + { + closesocket(conn->sock); + conn->sock = -1; + conn->addr_cur = addr_cur->ai_next; + continue; + } /* * Start/make connection. This should not block, since * we are in nonblock mode. If it does, well, too bad. @@ -1163,9 +1178,8 @@ retry_connect: 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 @@ -1212,11 +1226,13 @@ retry_connect: } /* 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; } @@ -1240,7 +1256,7 @@ retry_connect: */ #ifdef HAVE_UNIX_SOCKETS - if (conn->raddr.sa.sa_family == AF_UNIX) + if (conn->raddr.addr.ss_family == AF_UNIX) { /* Don't bother requesting SSL over a Unix socket */ conn->allow_ssl_try = false; @@ -2044,14 +2060,15 @@ PQrequestCancel(PGconn *conn) * 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 */ diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index f710f58b8e..47dbbb4af5 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-int.h,v 1.72 2003/06/09 17:59:19 tgl Exp $ + * $Id: libpq-int.h,v 1.73 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -263,7 +263,6 @@ struct pg_conn 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 */ ProtocolVersion pversion; /* FE/BE protocol version in use */ char sversion[8]; /* The first few bytes of server version */ diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c index 438f578f16..409aef5e9c 100644 --- a/src/port/getaddrinfo.c +++ b/src/port/getaddrinfo.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.3 2003/04/27 23:56:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.4 2003/06/12 07:36:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -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 (!hints || - (hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)) + 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.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 @@ getaddrinfo(const char *node, const char *service, { 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 @@ getaddrinfo(const char *node, const char *service, 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 @@ getaddrinfo(const char *node, const char *service, } } 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 @@ getaddrinfo(const char *node, const char *service, 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 @@ getaddrinfo(const char *node, const char *service, 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 @@ gai_strerror(int errcode) 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 @@ gai_strerror(int errcode) { 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: @@ -171,3 +197,82 @@ gai_strerror(int errcode) #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; +}