int pq_getkeepalivesinterval(Port *port) { #ifdef TCP_KEEPINTVL if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return 0; if (port->keepalives_interval != 0) return port->keepalives_interval; if (port->default_keepalives_interval == 0) { socklen_t size = sizeof(port->default_keepalives_interval); if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &port->default_keepalives_interval, &size) < 0) { elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); port->default_keepalives_interval = -1; /* don't know */ } } return port->default_keepalives_interval; #else return 0; #endif }
int pq_getkeepalivescount(Port *port) { #ifdef TCP_KEEPCNT if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return 0; if (port->keepalives_count != 0) return port->keepalives_count; if (port->default_keepalives_count == 0) { ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_count); if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT, (char *) &port->default_keepalives_count, &size) < 0) { elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); port->default_keepalives_count = -1; /* don't know */ } } return port->default_keepalives_count; #else return 0; #endif }
int pq_getkeepalivesinterval(Port *port) { #if defined(TCP_KEEPINTVL) || defined(SIO_KEEPALIVE_VALS) if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return 0; if (port->keepalives_interval != 0) return port->keepalives_interval; if (port->default_keepalives_interval == 0) { #ifndef WIN32 ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_interval); if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &port->default_keepalives_interval, &size) < 0) { elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); port->default_keepalives_interval = -1; /* don't know */ } #else /* We can't get the defaults on Windows, so return "don't know" */ port->default_keepalives_interval = -1; #endif /* WIN32 */ } return port->default_keepalives_interval; #else return 0; #endif }
int pq_setkeepalivesidle(int idle, Port *port) { if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return STATUS_OK; #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(SIO_KEEPALIVE_VALS) if (idle == port->keepalives_idle) return STATUS_OK; #ifndef WIN32 if (port->default_keepalives_idle <= 0) { if (pq_getkeepalivesidle(port) < 0) { if (idle == 0) return STATUS_OK; /* default is set but unknown */ else return STATUS_ERROR; } } if (idle == 0) idle = port->default_keepalives_idle; #ifdef TCP_KEEPIDLE if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &idle, sizeof(idle)) < 0) { elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m"); return STATUS_ERROR; } #else if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE, (char *) &idle, sizeof(idle)) < 0) { elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m"); return STATUS_ERROR; } #endif port->keepalives_idle = idle; #else /* WIN32 */ return pq_setkeepaliveswin32(port, idle, port->keepalives_interval); #endif #else /* TCP_KEEPIDLE || SIO_KEEPALIVE_VALS */ if (idle != 0) { elog(LOG, "setting the keepalive idle time is not supported"); return STATUS_ERROR; } #endif return STATUS_OK; }
int pq_setkeepalivesinterval(int interval, Port *port) { if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return STATUS_OK; #if defined(TCP_KEEPINTVL) || defined (SIO_KEEPALIVE_VALS) if (interval == port->keepalives_interval) return STATUS_OK; #ifndef WIN32 if (port->default_keepalives_interval <= 0) { if (pq_getkeepalivesinterval(port) < 0) { if (interval == 0) return STATUS_OK; /* default is set but unknown */ else return STATUS_ERROR; } } if (interval == 0) interval = port->default_keepalives_interval; if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &interval, sizeof(interval)) < 0) { elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m"); return STATUS_ERROR; } port->keepalives_interval = interval; #else /* WIN32 */ return pq_setkeepaliveswin32(port, port->keepalives_idle, interval); #endif #else if (interval != 0) { elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); return STATUS_ERROR; } #endif return STATUS_OK; }
int pq_getkeepalivesidle(Port *port) { #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(WIN32) if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return 0; if (port->keepalives_idle != 0) return port->keepalives_idle; if (port->default_keepalives_idle == 0) { #ifndef WIN32 ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle); #ifdef TCP_KEEPIDLE if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &port->default_keepalives_idle, &size) < 0) { elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); port->default_keepalives_idle = -1; /* don't know */ } #else if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE, (char *) &port->default_keepalives_idle, &size) < 0) { elog(LOG, "getsockopt(TCP_KEEPALIVE) failed: %m"); port->default_keepalives_idle = -1; /* don't know */ } #endif /* TCP_KEEPIDLE */ #else /* WIN32 */ /* We can't get the defaults on Windows, so return "don't know" */ port->default_keepalives_idle = -1; #endif /* WIN32 */ } return port->default_keepalives_idle; #else return 0; #endif }
int pq_setkeepalivescount(int count, Port *port) { if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return STATUS_OK; #ifdef TCP_KEEPCNT if (count == port->keepalives_count) return STATUS_OK; if (port->default_keepalives_count <= 0) { if (pq_getkeepalivescount(port) < 0) { if (count == 0) return STATUS_OK; /* default is set but unknown */ else return STATUS_ERROR; } } if (count == 0) count = port->default_keepalives_count; if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT, (char *) &count, sizeof(count)) < 0) { elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m"); return STATUS_ERROR; } port->keepalives_count = count; #else if (count != 0) { elog(LOG, "setsockopt(TCP_KEEPCNT) not supported"); return STATUS_ERROR; } #endif return STATUS_OK; }
int pq_setkeepalivesidle(int idle, Port *port) { if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return STATUS_OK; #ifdef TCP_KEEPIDLE if (idle == port->keepalives_idle) return STATUS_OK; if (port->default_keepalives_idle <= 0) { if (pq_getkeepalivesidle(port) < 0) { if (idle == 0) return STATUS_OK; /* default is set but unknown */ else return STATUS_ERROR; } } if (idle == 0) idle = port->default_keepalives_idle; if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &idle, sizeof(idle)) < 0) { elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m"); return STATUS_ERROR; } port->keepalives_idle = idle; #else if (idle != 0) { elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported"); return STATUS_ERROR; } #endif return STATUS_OK; }
/* * StreamConnection -- create a new connection with client using * server port. Set port->sock to the FD of the new connection. * * ASSUME: that this doesn't need to be non-blocking because * the Postmaster uses select() to tell when the server master * socket is ready for accept(). * * RETURNS: STATUS_OK or STATUS_ERROR */ int StreamConnection(pgsocket server_fd, Port *port) { /* accept connection and fill in the client (remote) address */ port->raddr.salen = sizeof(port->raddr.addr); if ((port->sock = accept(server_fd, (struct sockaddr *) & port->raddr.addr, &port->raddr.salen)) < 0) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not accept new connection: %m"))); /* * If accept() fails then postmaster.c will still see the server * socket as read-ready, and will immediately try again. To avoid * uselessly sucking lots of CPU, delay a bit before trying again. * (The most likely reason for failure is being out of kernel file * table slots; we can do little except hope some will get freed up.) */ pg_usleep(100000L); /* wait 0.1 sec */ return STATUS_ERROR; } #ifdef SCO_ACCEPT_BUG /* * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it * shouldn't hurt to catch it for all versions of those platforms. */ if (port->raddr.addr.ss_family == 0) port->raddr.addr.ss_family = AF_UNIX; #endif /* fill in the server (local) address */ port->laddr.salen = sizeof(port->laddr.addr); if (getsockname(port->sock, (struct sockaddr *) & port->laddr.addr, &port->laddr.salen) < 0) { elog(LOG, "getsockname() failed: %m"); return STATUS_ERROR; } /* select NODELAY and KEEPALIVE options if it's a TCP connection */ if (!IS_AF_UNIX(port->laddr.addr.ss_family)) { int on; #ifdef TCP_NODELAY on = 1; if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(TCP_NODELAY) failed: %m"); return STATUS_ERROR; } #endif on = 1; if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); return STATUS_ERROR; } #ifdef WIN32 /* * This is a Win32 socket optimization. The ideal size is 32k. * http://support.microsoft.com/kb/823764/EN-US/ */ on = PQ_BUFFER_SIZE * 4; if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(SO_SNDBUF) failed: %m"); return STATUS_ERROR; } #endif /* * Also apply the current keepalive parameters. If we fail to set a * parameter, don't error out, because these aren't universally * supported. (Note: you might think we need to reset the GUC * variables to 0 in such a case, but it's not necessary because the * show hooks for these variables report the truth anyway.) */ (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); (void) pq_setkeepalivescount(tcp_keepalives_count, port); } return STATUS_OK; }
int StreamServerPort(int family, char *hostName, unsigned short portNumber, char *unixSocketName, pgsocket ListenSocket[], int MaxListen) { pgsocket fd; int err; int maxconn; int ret; char portNumberStr[32]; const char *familyDesc; char familyDescBuf[64]; char *service; struct addrinfo *addrs = NULL, *addr; struct addrinfo hint; int listen_index = 0; int added = 0; #if !defined(WIN32) || defined(IPV6_V6ONLY) int one = 1; #endif /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_flags = AI_PASSIVE; hint.ai_socktype = SOCK_STREAM; #ifdef HAVE_UNIX_SOCKETS if (family == AF_UNIX) { /* Lock_AF_UNIX will also fill in sock_path. */ if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK) return STATUS_ERROR; service = sock_path; } else #endif /* HAVE_UNIX_SOCKETS */ { snprintf(portNumberStr, sizeof(portNumberStr), "%d", portNumber); service = portNumberStr; } ret = pg_getaddrinfo_all(hostName, service, &hint, &addrs); if (ret || !addrs) { if (hostName) ereport(LOG, (errmsg("could not translate host name \"%s\", service \"%s\" to address: %s", hostName, service, gai_strerror(ret)))); else ereport(LOG, (errmsg("could not translate service \"%s\" to address: %s", service, gai_strerror(ret)))); if (addrs) pg_freeaddrinfo_all(hint.ai_family, addrs); return STATUS_ERROR; } for (addr = addrs; addr; addr = addr->ai_next) { if (!IS_AF_UNIX(family) && IS_AF_UNIX(addr->ai_family)) { /* * Only set up a unix domain socket when they really asked for it. * The service/port is different in that case. */ continue; } /* See if there is still room to add 1 more socket. */ for (; listen_index < MaxListen; listen_index++) { if (ListenSocket[listen_index] == PGINVALID_SOCKET) break; } if (listen_index >= MaxListen) { ereport(LOG, (errmsg("could not bind to all requested addresses: MAXLISTEN (%d) exceeded", MaxListen))); break; } /* set up family name for possible error messages */ switch (addr->ai_family) { case AF_INET: familyDesc = _("IPv4"); break; #ifdef HAVE_IPV6 case AF_INET6: familyDesc = _("IPv6"); break; #endif #ifdef HAVE_UNIX_SOCKETS case AF_UNIX: familyDesc = _("Unix"); break; #endif default: snprintf(familyDescBuf, sizeof(familyDescBuf), _("unrecognized address family %d"), addr->ai_family); familyDesc = familyDescBuf; break; } if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) < 0) { ereport(LOG, (errcode_for_socket_access(), /* translator: %s is IPv4, IPv6, or Unix */ errmsg("could not create %s socket: %m", familyDesc))); continue; } #ifndef WIN32 /* * Without the SO_REUSEADDR flag, a new postmaster can't be started * right away after a stop or crash, giving "address already in use" * error on TCP ports. * * On win32, however, this behavior only happens if the * SO_EXLUSIVEADDRUSE is set. With SO_REUSEADDR, win32 allows multiple * servers to listen on the same address, resulting in unpredictable * behavior. With no flags at all, win32 behaves as Unix with * SO_REUSEADDR. */ if (!IS_AF_UNIX(addr->ai_family)) { if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one))) == -1) { ereport(LOG, (errcode_for_socket_access(), errmsg("setsockopt(SO_REUSEADDR) failed: %m"))); closesocket(fd); continue; } } #endif #ifdef IPV6_V6ONLY if (addr->ai_family == AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &one, sizeof(one)) == -1) { ereport(LOG, (errcode_for_socket_access(), errmsg("setsockopt(IPV6_V6ONLY) failed: %m"))); closesocket(fd); continue; } } #endif /* * Note: This might fail on some OS's, like Linux older than * 2.4.21-pre3, that don't have the IPV6_V6ONLY socket option, and map * ipv4 addresses to ipv6. It will show ::ffff:ipv4 for all ipv4 * connections. */ err = bind(fd, addr->ai_addr, addr->ai_addrlen); if (err < 0) { ereport(LOG, (errcode_for_socket_access(), /* translator: %s is IPv4, IPv6, or Unix */ errmsg("could not bind %s socket: %m", familyDesc), (IS_AF_UNIX(addr->ai_family)) ? errhint("Is another postmaster already running on port %d?" " If not, remove socket file \"%s\" and retry.", (int) portNumber, sock_path) : errhint("Is another postmaster already running on port %d?" " If not, wait a few seconds and retry.", (int) portNumber))); closesocket(fd); continue; } #ifdef HAVE_UNIX_SOCKETS if (addr->ai_family == AF_UNIX) { if (Setup_AF_UNIX() != STATUS_OK) { closesocket(fd); break; } } #endif /* * Select appropriate accept-queue length limit. PG_SOMAXCONN is only * intended to provide a clamp on the request on platforms where an * overly large request provokes a kernel error (are there any?). */ maxconn = MaxBackends * 2; if (maxconn > PG_SOMAXCONN) maxconn = PG_SOMAXCONN; err = listen(fd, maxconn); if (err < 0) { ereport(LOG, (errcode_for_socket_access(), /* translator: %s is IPv4, IPv6, or Unix */ errmsg("could not listen on %s socket: %m", familyDesc))); closesocket(fd); continue; } ListenSocket[listen_index] = fd; added++; } pg_freeaddrinfo_all(hint.ai_family, addrs); if (!added) return STATUS_ERROR; return STATUS_OK; }
/* ---------------- * GTMPQconnectPoll * * Poll an asynchronous connection. * * Returns a GTMClientPollingStatusType. * Before calling this function, use select(2) to determine when data * has arrived.. * * You must call GTMPQfinish whether or not this fails. */ GTMClientPollingStatusType GTMPQconnectPoll(GTM_Conn *conn) { if (conn == NULL) return PGRES_POLLING_FAILED; /* Get the new data */ switch (conn->status) { /* * We really shouldn't have been polled in these two cases, but we * can handle it. */ case CONNECTION_BAD: return PGRES_POLLING_FAILED; case CONNECTION_OK: return PGRES_POLLING_OK; /* These are reading states */ case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AUTH_OK: { /* Load waiting data */ int n = gtmpqReadData(conn); if (n < 0) goto error_return; if (n == 0) return PGRES_POLLING_READING; break; } /* These are writing states, so we just proceed. */ case CONNECTION_STARTED: case CONNECTION_MADE: break; case CONNECTION_NEEDED: break; default: appendGTMPQExpBuffer(&conn->errorMessage, "invalid connection state, " "probably indicative of memory corruption\n" ); goto error_return; } keep_going: /* We will come back to here until there is * nothing left to do. */ switch (conn->status) { case CONNECTION_NEEDED: { /* * Try to initiate a connection to one of the addresses * returned by gtm_getaddrinfo_all(). conn->addr_cur is the * next one to try. We fail when we run out of addresses * (reporting the error returned for the *last* alternative, * which may not be what users expect :-(). */ while (conn->addr_cur != NULL) { struct addrinfo *addr_cur = conn->addr_cur; /* Remember current address for possible error msg */ 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, 0); if (conn->sock < 0) { /* * ignore socket() failure if we have more addresses * to try */ if (addr_cur->ai_next != NULL) { conn->addr_cur = addr_cur->ai_next; continue; } appendGTMPQExpBuffer(&conn->errorMessage, "could not create socket: \n"); break; } /* * Select socket options: no delay of outgoing data for * TCP sockets, nonblock mode, close-on-exec. Fail if any * of this fails. */ if (!IS_AF_UNIX(addr_cur->ai_family)) { if (!connectNoDelay(conn)) { close(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. */ if (connect(conn->sock, addr_cur->ai_addr, addr_cur->ai_addrlen) < 0) { if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == EINTR || SOCK_ERRNO == 0) { /* * This is fine - we're in non-blocking mode, and * the connection is in progress. Tell caller to * wait for write-ready on socket. */ conn->status = CONNECTION_STARTED; return PGRES_POLLING_WRITING; } /* otherwise, trouble */ } else { /* * Hm, we're connected already --- seems the "nonblock * connection" wasn't. Advance the state machine and * go do the next stuff. */ conn->status = CONNECTION_STARTED; goto keep_going; } /* * This connection failed --- set up error report, then * close socket (do it this way in case close() affects * the value of errno...). We will ignore the connect() * failure and keep going if there are more addresses. */ connectFailureMessage(conn, SOCK_ERRNO); if (conn->sock >= 0) { close(conn->sock); conn->sock = -1; } /* * Try the next address, if any. */ conn->addr_cur = addr_cur->ai_next; } /* loop over addresses */ /* * Ooops, no more addresses. An appropriate error message is * already set up, so just set the right status. */ goto error_return; } case CONNECTION_STARTED: { int optval; size_t optlen = sizeof(optval); /* * Write ready, since we've made it here, so the connection * has been made ... or has failed. */ /* * Now check (using getsockopt) that there is not an error * state waiting for us on the socket. */ if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &optval, (socklen_t *)&optlen) == -1) { appendGTMPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get socket error status: \n")); goto error_return; } else if (optval != 0) { /* * When using a nonblocking connect, we will typically see * connect failures at this point, so provide a friendly * error message. */ connectFailureMessage(conn, optval); /* * If more addresses remain, keep trying, just as in the * case where connect() returned failure immediately. */ if (conn->addr_cur->ai_next != NULL) { if (conn->sock >= 0) { close(conn->sock); conn->sock = -1; } conn->addr_cur = conn->addr_cur->ai_next; conn->status = CONNECTION_NEEDED; goto keep_going; } goto error_return; } /* Fill in the client address */ conn->laddr.salen = sizeof(conn->laddr.addr); if (getsockname(conn->sock, (struct sockaddr *) & conn->laddr.addr, (socklen_t *)&conn->laddr.salen) < 0) { appendGTMPQExpBuffer(&conn->errorMessage, "could not get client address from socket:\n"); goto error_return; } /* * Make sure we can write before advancing to next step. */ conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; } case CONNECTION_MADE: { GTM_StartupPacket sp; /* * Build a startup packet. We tell the GTM server/proxy our * PGXC Node name and whether we are a proxy or not. * * When the connection is made from the proxy, we let the GTM * server know about it so that some special headers are * handled correctly by the server. */ strcpy(sp.sp_node_name, conn->gc_node_name); sp.sp_remotetype = conn->remote_type; sp.sp_ispostmaster = conn->is_postmaster; /* * Send the startup packet. * * Theoretically, this could block, but it really shouldn't * since we only got here if the socket is write-ready. */ if (pqPacketSend(conn, 'A', &sp, sizeof (GTM_StartupPacket)) != STATUS_OK) { appendGTMPQExpBuffer(&conn->errorMessage, "could not send startup packet: \n"); goto error_return; } conn->status = CONNECTION_AWAITING_RESPONSE; return PGRES_POLLING_READING; } /* * Handle authentication exchange: wait for postmaster messages * and respond as necessary. */ case CONNECTION_AWAITING_RESPONSE: { char beresp; /* * Scan the message from current point (note that if we find * the message is incomplete, we will return without advancing * inStart, and resume here next time). */ conn->inCursor = conn->inStart; /* Read type byte */ if (gtmpqGetc(&beresp, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } /* * Validate message type: we expect only an authentication * request or an error here. Anything else probably means * it's not GTM on the other end at all. */ if (!(beresp == 'R' || beresp == 'E')) { appendGTMPQExpBuffer(&conn->errorMessage, "expected authentication request from " "server, but received %c\n", beresp); goto error_return; } /* Handle errors. */ if (beresp == 'E') { if (gtmpqGets_append(&conn->errorMessage, conn)) { /* We'll come back when there is more data */ return PGRES_POLLING_READING; } /* OK, we read the message; mark data consumed */ conn->inStart = conn->inCursor; goto error_return; } { /* * Server sends a dummy message body of size 4 bytes */ int tmp_int; gtmpqGetInt(&tmp_int, 4, conn); } /* * OK, we successfully read the message; mark data consumed */ conn->inStart = conn->inCursor; /* We are done with authentication exchange */ conn->status = CONNECTION_AUTH_OK; /* Look to see if we have more data yet. */ goto keep_going; } case CONNECTION_AUTH_OK: { /* We can release the address list now. */ gtm_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); conn->addrlist = NULL; conn->addr_cur = NULL; /* Otherwise, we are open for business! */ conn->status = CONNECTION_OK; return PGRES_POLLING_OK; } default: appendGTMPQExpBuffer(&conn->errorMessage, "invalid connection state %c, " "probably indicative of memory corruption\n" , conn->status); goto error_return; } /* Unreachable */ error_return: /* * We used to close the socket at this point, but that makes it awkward * for those above us if they wish to remove this socket from their own * records (an fd_set for example). We'll just have this socket closed * when GTMPQfinish is called (which is compulsory even after an error, since * the connection structure must be freed). */ conn->status = CONNECTION_BAD; return PGRES_POLLING_FAILED; }
/* * StreamConnection -- create a new connection with client using * server port. Set port->sock to the FD of the new connection. * * ASSUME: that this doesn't need to be non-blocking because * the Postmaster uses select() to tell when the server master * socket is ready for accept(). * * RETURNS: STATUS_OK or STATUS_ERROR */ int StreamConnection(pgsocket server_fd, Port *port) { /* accept connection and fill in the client (remote) address */ port->raddr.salen = sizeof(port->raddr.addr); if ((port->sock = accept(server_fd, (struct sockaddr *) & port->raddr.addr, &port->raddr.salen)) == PGINVALID_SOCKET) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not accept new connection: %m"))); /* * If accept() fails then postmaster.c will still see the server * socket as read-ready, and will immediately try again. To avoid * uselessly sucking lots of CPU, delay a bit before trying again. * (The most likely reason for failure is being out of kernel file * table slots; we can do little except hope some will get freed up.) */ pg_usleep(100000L); /* wait 0.1 sec */ return STATUS_ERROR; } /* fill in the server (local) address */ port->laddr.salen = sizeof(port->laddr.addr); if (getsockname(port->sock, (struct sockaddr *) & port->laddr.addr, &port->laddr.salen) < 0) { elog(LOG, "getsockname() failed: %m"); return STATUS_ERROR; } /* select NODELAY and KEEPALIVE options if it's a TCP connection */ if (!IS_AF_UNIX(port->laddr.addr.ss_family)) { int on; #ifdef WIN32 int oldopt; int optlen; int newopt; #endif #ifdef TCP_NODELAY on = 1; if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(TCP_NODELAY) failed: %m"); return STATUS_ERROR; } #endif on = 1; if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); return STATUS_ERROR; } #ifdef WIN32 /* * This is a Win32 socket optimization. The OS send buffer should be * large enough to send the whole Postgres send buffer in one go, or * performance suffers. The Postgres send buffer can be enlarged if a * very large message needs to be sent, but we won't attempt to * enlarge the OS buffer if that happens, so somewhat arbitrarily * ensure that the OS buffer is at least PQ_SEND_BUFFER_SIZE * 4. * (That's 32kB with the current default). * * The default OS buffer size used to be 8kB in earlier Windows * versions, but was raised to 64kB in Windows 2012. So it shouldn't * be necessary to change it in later versions anymore. Changing it * unnecessarily can even reduce performance, because setting * SO_SNDBUF in the application disables the "dynamic send buffering" * feature that was introduced in Windows 7. So before fiddling with * SO_SNDBUF, check if the current buffer size is already large enough * and only increase it if necessary. * * See https://support.microsoft.com/kb/823764/EN-US/ and * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx */ optlen = sizeof(oldopt); if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt, &optlen) < 0) { elog(LOG, "getsockopt(SO_SNDBUF) failed: %m"); return STATUS_ERROR; } newopt = PQ_SEND_BUFFER_SIZE * 4; if (oldopt < newopt) { if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt, sizeof(newopt)) < 0) { elog(LOG, "setsockopt(SO_SNDBUF) failed: %m"); return STATUS_ERROR; } } #endif /* * Also apply the current keepalive parameters. If we fail to set a * parameter, don't error out, because these aren't universally * supported. (Note: you might think we need to reset the GUC * variables to 0 in such a case, but it's not necessary because the * show hooks for these variables report the truth anyway.) */ (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); (void) pq_setkeepalivescount(tcp_keepalives_count, port); } return STATUS_OK; }
void body() { /* Initialize hint structure */ #ifdef HAVE_UNIX_SOCKETS if (family == AF_UNIX) { /* Lock_AF_UNIX will also fill in sock_path. */ /* if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK) */ /* return STATUS_ERROR; */ service = sock_path; } else #endif /* HAVE_UNIX_SOCKETS */ { snprintf(1, sizeof(1), "%d", portNumber); service = 1; } ret = getaddrinfo_all(hostName, service, &hint, &addrs); if (ret || !addrs) { if (hostName) { /* ereport(LOG, */ /* (errmsg("could not translate host name \"%s\", service \"%s\" to address: %s", */ /* hostName, service, gai_strerror(ret)))); */ } else { /* ereport(LOG, */ /* (errmsg("could not translate service \"%s\" to address: %s", */ /* service, gai_strerror(ret)))); */ /* if (addrs) */ /* freeaddrinfo_all(hint.ai_family, addrs); */ } //ret = STATUS_ERROR; //while(1) { int qqq; qqq=qqq;} } for (addr = addrs; addr < MAXADDR; addr++) // = addr->ai_next) { if (!IS_AF_UNIX(family) && IS_AF_UNIX(addr_ai_family)) { /* * Only set up a unix domain socket when they really asked for * it. The service/port is different in that case. */ goto loc_continue; } /* See if there is still room to add 1 more socket. */ for (; listen_index < MaxListen; listen_index++) { if (ListenSocket_OF_listen_index == -1) break; } if (listen_index >= MaxListen) { /* ereport(LOG, */ /* (errmsg("could not bind to all requested addresses: MAXLISTEN (%d) exceeded", */ /* MaxListen))); */ break; } /* set up family name for possible error messages */ if(addr_ai_family==AF_INET) { gettext("IPv4"); } else if(addr_ai_family==AF_INET6) { gettext("IPv6"); } else if(addr_ai_family==AF_UNIX) { gettext("Unix"); } else { snprintf(1,/*familyDescBuf*/ 1, //sizeof(familyDescBuf), gettext("unrecognized address family %d"), addr_ai_family); //familyDesc = familyDescBuf; } if ((fd = nondet())) // socket(addr_ai_family, SOCK_STREAM, 0)) < 0) { /* ereport(LOG, */ /* (errcode_for_socket_access(), */ /* /\* translator: %s is IPv4, IPv6, or Unix *\/ */ /* errmsg("could not create %s socket: %m", */ /* familyDesc))); */ goto loc_continue; } if (nondet()) // !IS_AF_UNIX(addr_ai_family)) { if (nondet()) //(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, // (char *) &one, sizeof(one))) == -1) { /* ereport(LOG, */ /* (errcode_for_socket_access(), */ /* errmsg("setsockopt(SO_REUSEADDR) failed: %m"))); */ /* closesocket(fd); */ goto loc_continue; } } #ifdef IPV6_V6ONLY if (nondet()) // addr_ai_family == AF_INET6) { if (nondet()) // setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, // (char *) &one, sizeof(one)) == -1) { /* ereport(LOG, */ /* (errcode_for_socket_access(), */ /* errmsg("setsockopt(IPV6_V6ONLY) failed: %m"))); */ closesocket(fd); goto loc_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 = nondet(); // bind(fd, addr->ai_addr, addr->ai_addrlen); if (err < 0) { /* ereport(LOG, */ /* (errcode_for_socket_access(), */ /* /\* translator: %s is IPv4, IPv6, or Unix *\/ */ /* errmsg("could not bind %s socket: %m", */ /* familyDesc), */ /* (IS_AF_UNIX(addr_ai_family)) ? */ /* errhint("Is another postmaster already running on port %d?" */ /* " If not, remove socket file \"%s\" and retry.", */ /* (int) portNumber, sock_path) : */ /* errhint("Is another postmaster already running on port %d?" */ /* " If not, wait a few seconds and retry.", */ /* (int) portNumber))); */ closesocket(fd); goto loc_continue; } #ifdef HAVE_UNIX_SOCKETS if (addr_ai_family == AF_UNIX) { if (nondet() != 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) { closesocket(fd); goto loc_continue; } ListenSocket_OF_listen_index = fd; added++; if(1) { loc_continue: 0; } } //freeaddrinfo_all(hint.ai_family, addrs); if (!added) { ret = STATUS_ERROR; while(1) { int rrr; rrr=rrr; } } ret = STATUS_OK; while(1) { int ddd; ddd=ddd; } }
/* * StreamConnection -- create a new connection with client using * server port. * * ASSUME: that this doesn't need to be non-blocking because * the Postmaster uses select() to tell when the server master * socket is ready for accept(). * * RETURNS: STATUS_OK or STATUS_ERROR */ int StreamConnection(int server_fd, Port *port) { /* accept connection and fill in the client (remote) address */ port->raddr.salen = sizeof(port->raddr.addr); if ((port->sock = accept(server_fd, (struct sockaddr *) & port->raddr.addr, &port->raddr.salen)) < 0) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not accept new connection: %m"))); return STATUS_ERROR; } #ifdef SCO_ACCEPT_BUG /* * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it * shouldn't hurt to catch it for all versions of those platforms. */ if (port->raddr.addr.ss_family == 0) port->raddr.addr.ss_family = AF_UNIX; #endif /* fill in the server (local) address */ port->laddr.salen = sizeof(port->laddr.addr); if (getsockname(port->sock, (struct sockaddr *) & port->laddr.addr, &port->laddr.salen) < 0) { elog(LOG, "getsockname() failed: %m"); return STATUS_ERROR; } /* select NODELAY and KEEPALIVE options if it's a TCP connection */ if (!IS_AF_UNIX(port->laddr.addr.ss_family)) { int on; #ifdef TCP_NODELAY on = 1; if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(TCP_NODELAY) failed: %m"); return STATUS_ERROR; } #endif on = 1; if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); return STATUS_ERROR; } /* * Also apply the current keepalive parameters. If we fail to set a * parameter, don't error out, because these aren't universally * supported. (Note: you might think we need to reset the GUC * variables to 0 in such a case, but it's not necessary because the * show hooks for these variables report the truth anyway.) */ (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); (void) pq_setkeepalivescount(tcp_keepalives_count, port); } return STATUS_OK; }