diff options
Diffstat (limited to 'src/backend/libpq/pqcomm.c')
-rw-r--r-- | src/backend/libpq/pqcomm.c | 341 |
1 files changed, 148 insertions, 193 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 757a8a72ce6..c3a95562b13 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -29,7 +29,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.c,v 1.142 2002/12/06 03:46:28 momjian Exp $ + * $Id: pqcomm.c,v 1.143 2002/12/06 04:37:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -85,11 +85,6 @@ extern ssize_t secure_read(Port *, void *, size_t); extern ssize_t secure_write(Port *, const void *, size_t); static void pq_close(void); -#ifdef HAVE_UNIX_SOCKETS -int StreamServerPortSubAFUNIX1(unsigned short portNumber, - char *unixSocketName ); -int StreamServerPortSubAFUNIX2(void); -#endif /* HAVE_UNIX_SOCKETS */ /* @@ -187,198 +182,170 @@ int StreamServerPort(int family, char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP) { - int fd, - err; - int maxconn; - int one = 1; + SockAddr saddr; + int fd, + err; + int maxconn; + size_t len = 0; + int one = 1; - int ret; - struct addrinfo* addrs = NULL; - struct addrinfo hint; - char portNumberStr[64]; - char* service = portNumberStr; - char* hostn = (hostName[0] == '\0')? NULL : hostName; + Assert(family == AF_INET || family == AF_UNIX); - Assert(family == AF_INET6 || family == AF_INET || family == AF_UNIX); + if ((fd = socket(family, SOCK_STREAM, 0)) < 0) + { + elog(LOG, "StreamServerPort: socket() failed: %m"); + return STATUS_ERROR; + } - memset(&hint, 0, sizeof(hint)); - hint.ai_family = family; - hint.ai_flags = AI_PASSIVE; - hint.ai_socktype = SOCK_STREAM; + if (family == AF_INET) + { + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, + sizeof(one))) == -1) + { + elog(LOG, "StreamServerPort: setsockopt(SO_REUSEADDR) failed: %m"); + return STATUS_ERROR; + } + } - snprintf(portNumberStr, sizeof(portNumberStr)/sizeof(char), - "%d", portNumber); + MemSet((char *) &saddr, 0, sizeof(saddr)); + saddr.sa.sa_family = family; #ifdef HAVE_UNIX_SOCKETS - if (family == AF_UNIX) { - if(StreamServerPortSubAFUNIX1(portNumber, unixSocketName) != STATUS_OK){ - return STATUS_ERROR; - } - service = sock_path; - } + if (family == AF_UNIX) + { + UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName); + len = UNIXSOCK_LEN(saddr.un); + strcpy(sock_path, saddr.un.sun_path); + + /* + * Grab an interlock file associated with the socket file. + */ + if (!CreateSocketLockFile(sock_path, true)) + return STATUS_ERROR; + + /* + * Once we have the interlock, we can safely delete any + * pre-existing socket file to avoid failure at bind() time. + */ + unlink(sock_path); + } #endif /* HAVE_UNIX_SOCKETS */ + if (family == AF_INET) + { + /* TCP/IP socket */ + if (hostName[0] == '\0') + saddr.in.sin_addr.s_addr = htonl(INADDR_ANY); + else + { + struct hostent *hp; + hp = gethostbyname(hostName); + if ((hp == NULL) || (hp->h_addrtype != AF_INET)) + { + elog(LOG, "StreamServerPort: gethostbyname(%s) failed", + hostName); + return STATUS_ERROR; + } + memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr, + hp->h_length); + } - ret = getaddrinfo2(hostn, service, &hint, &addrs); - if(ret || addrs == NULL){ - elog(LOG, "FATAL: StreamServerPort: getaddrinfo2() failed: %s\n", - gai_strerror(ret)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } - - - /** YY DEBUG - if(addrs->ai_family == AF_UNIX){ - printf("%s-%s-%s \n", "debug: AF_UNIX!", unixSocketName, hostName); - } - else { - printf("%s", "debug: NOT AF_UNIX!\n"); - } - fflush(stdout); - **/ - - if( (fd = socket(addrs->ai_family, SOCK_STREAM, 0)) < 0){ - elog(LOG, "FATAL: StreamServerPort: socket() failed: %s\n", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } - - if( isAF_INETx2(family) ){ - if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, - sizeof(one) )) == -1 ){ - elog(LOG, "FATAL: StreamServerPort: setsockopt(SO_REUSEADDR) failed: %s\n", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } - } - - - err = bind(fd, addrs->ai_addr, addrs->ai_addrlen); - if(err < 0){ - elog(LOG, "FATAL: StreamServerPort: bind() failed: %s\n" - "\tIs another postmaster already running on port %d?\n", - strerror(errno), (int) portNumber); - if (family == AF_UNIX) - elog(LOG, "\tIf not, remove socket node (%s) and retry.\n", - sock_path); - else - elog(LOG, "\tIf not, wait a few seconds and retry.\n"); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } + saddr.in.sin_port = htons(portNumber); + len = sizeof(struct sockaddr_in); + } -#ifdef HAVE_UNIX_SOCKETS - if (family == AF_UNIX){ - if(StreamServerPortSubAFUNIX2() != STATUS_OK){ - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } - } -#endif + err = bind(fd, (struct sockaddr *) & saddr.sa, len); + if (err < 0) + { + if (family == AF_UNIX) + elog(LOG, "StreamServerPort: bind() failed: %m\n" + "\tIs another postmaster already running on port %d?\n" + "\tIf not, remove socket node (%s) and retry.", + (int) portNumber, sock_path); + else + elog(LOG, "StreamServerPort: bind() failed: %m\n" + "\tIs another postmaster already running on port %d?\n" + "\tIf not, wait a few seconds and retry.", + (int) portNumber); + return STATUS_ERROR; + } - /* - * 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, "FATAL: StreamServerPort: listen() failed: %s\n", - strerror(errno)); - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_ERROR; - } - - *fdP = fd; - freeaddrinfo2(hint.ai_family, addrs); - return STATUS_OK; +#ifdef HAVE_UNIX_SOCKETS + if (family == AF_UNIX) + { + /* Arrange to unlink the socket file at exit */ + on_proc_exit(StreamDoUnlink, 0); + + /* + * Fix socket ownership/permission if requested. Note we must do + * this before we listen() to avoid a window where unwanted + * connections could get accepted. + */ + Assert(Unix_socket_group); + if (Unix_socket_group[0] != '\0') + { + char *endptr; + unsigned long int val; + gid_t gid; -} + val = strtoul(Unix_socket_group, &endptr, 10); + if (*endptr == '\0') + { + /* numeric group id */ + gid = val; + } + else + { + /* convert group name to id */ + struct group *gr; + + gr = getgrnam(Unix_socket_group); + if (!gr) + { + elog(LOG, "No such group as '%s'", + Unix_socket_group); + return STATUS_ERROR; + } + gid = gr->gr_gid; + } + if (chown(sock_path, -1, gid) == -1) + { + elog(LOG, "Could not set group of %s: %m", + sock_path); + return STATUS_ERROR; + } + } -#ifdef HAVE_UNIX_SOCKETS -int StreamServerPortSubAFUNIX1(unsigned short portNumber, - char *unixSocketName ) -{ - SockAddr saddr; - int len; - - MemSet((char *) &saddr, 0, sizeof(saddr)); - - UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName); - len = UNIXSOCK_LEN(saddr.un); - strcpy(sock_path, saddr.un.sun_path); - - /* - * Grab an interlock file associated with the socket file. - */ - if (!CreateSocketLockFile(sock_path, true)) - return STATUS_ERROR; - - /* - * Once we have the interlock, we can safely delete any - * pre-existing socket file to avoid failure at bind() time. - */ - unlink(sock_path); - - return STATUS_OK; -} + if (chmod(sock_path, Unix_socket_permissions) == -1) + { + elog(LOG, "Could not set permissions on %s: %m", + sock_path); + return STATUS_ERROR; + } + } +#endif /* HAVE_UNIX_SOCKETS */ + /* + * 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; -int StreamServerPortSubAFUNIX2(void) -{ - /* Arrange to unlink the socket file at exit */ - on_proc_exit(StreamDoUnlink, 0); - - /* - * Fix socket ownership/permission if requested. Note we must do - * this before we listen() to avoid a window where unwanted - * connections could get accepted. - */ - Assert(Unix_socket_group); - if (Unix_socket_group[0] != '\0') { - char *endptr; - unsigned long int val; - gid_t gid; - - val = strtoul(Unix_socket_group, &endptr, 10); - if (*endptr == '\0'){ /* numeric group id */ - gid = val; - } - else { /* convert group name to id */ - struct group *gr; - gr = getgrnam(Unix_socket_group); - if (!gr) { - elog(LOG, "FATAL: no such group '%s'\n", - Unix_socket_group); - return STATUS_ERROR; - } - gid = gr->gr_gid; - } - if (chown(sock_path, -1, gid) == -1){ - elog(LOG, "FATAL: could not set group of %s: %s\n", - sock_path, strerror(errno)); - return STATUS_ERROR; - } - } - - if (chmod(sock_path, Unix_socket_permissions) == -1){ - elog(LOG, "FATAL: could not set permissions on %s: %s\n", - sock_path, strerror(errno)); - return STATUS_ERROR; - } - return STATUS_OK; -} + err = listen(fd, maxconn); + if (err < 0) + { + elog(LOG, "StreamServerPort: listen() failed: %m"); + return STATUS_ERROR; + } -#endif /* HAVE_UNIX_SOCKETS */ + *fdP = fd; + return STATUS_OK; +} /* * StreamConnection -- create a new connection with client using @@ -424,20 +391,8 @@ StreamConnection(int server_fd, Port *port) return STATUS_ERROR; } - /* DEBUG YY - { - char l_hostinfo[INET6_ADDRSTRLEN]; - char r_hostinfo[INET6_ADDRSTRLEN]; - SockAddr_ntop(&port->laddr, l_hostinfo, INET6_ADDRSTRLEN, 1); - SockAddr_ntop(&port->raddr, r_hostinfo, INET6_ADDRSTRLEN, 1); - printf("StreamConnect() l: %s r: %s\n", l_hostinfo, r_hostinfo); - printf("StreamConnect() l: %d r: %d\n", port->laddr.sa.sa_family, - port->raddr.sa.sa_family); - } - */ - /* select NODELAY and KEEPALIVE options if it's a TCP connection */ - if ( isAF_INETx(&port->laddr) ) + if (port->laddr.sa.sa_family == AF_INET) { int on = 1; |