/* *Copewiththevariousplatform-specificwaystospellTCPkeepalivesocket *options.Thisdoesn'tcoverWindows,whichasusualdoesitsownthing.
*/ #ifdefined(TCP_KEEPIDLE) /* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE" #elifdefined(TCP_KEEPALIVE_THRESHOLD) /* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */ #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD" #elifdefined(TCP_KEEPALIVE) && defined(__darwin__) /* TCP_KEEPALIVE is the name of this option on macOS */ /* Caution: Solaris has this symbol but it means something different */ #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE" #endif
/* *Configurationoptions
*/ int Unix_socket_permissions; char *Unix_socket_group;
/* Where the Unix socket files are (list of palloc'd strings) */ static List *sock_paths = NIL;
staticchar *PqSendBuffer; staticint PqSendBufferSize; /* Size send buffer */ static size_t PqSendPointer; /* Next index to store a byte in PqSendBuffer */ static size_t PqSendStart; /* Next index to send a byte in PqSendBuffer */
staticchar PqRecvBuffer[PQ_RECV_BUFFER_SIZE]; staticint PqRecvPointer; /* Next index to read a byte from PqRecvBuffer */ staticint PqRecvLength; /* End of data available in PqRecvBuffer */
/* *Messagestatus
*/ staticbool PqCommBusy; /* busy sending data to the client */ staticbool PqCommReadingMsg; /* in the middle of reading a message */
/* -------------------------------- *pq_init-initializelibpqatbackendstartup *--------------------------------
*/
Port *
pq_init(ClientSocket *client_sock)
{
Port *port; int socket_pos PG_USED_FOR_ASSERTS_ONLY; int latch_pos PG_USED_FOR_ASSERTS_ONLY;
/* allocate the Port struct and copy the ClientSocket contents to it */
port = palloc0(sizeof(Port));
port->sock = client_sock->sock;
memcpy(&port->raddr.addr, &client_sock->raddr.addr, client_sock->raddr.salen);
port->raddr.salen = client_sock->raddr.salen;
/* 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)
{
ereport(FATAL,
(errmsg("%s() failed: %m", "getsockname")));
}
/* select NODELAY and KEEPALIVE options if it's a TCP connection */ if (port->laddr.addr.ss_family != AF_UNIX)
{ int on; #ifdef WIN32 int oldopt; int optlen; int newopt; #endif
/* set up process-exit hook to close the socket */
on_proc_exit(socket_close, 0);
/* *Inbackends(assoonasforked)weoperatetheunderlyingsocketin *nonblockingmodeanduselatchestoimplementblockingsemanticsif *needed.Thatallowsustoprovidesafelyinterruptiblereadsand *writes.
*/ #ifndef WIN32 if (!pg_set_noblock(port->sock))
ereport(FATAL,
(errmsg("could not set socket to nonblocking mode: %m"))); #endif
#ifndef WIN32
/* Don't give the socket to any subprograms we execute. */ if (fcntl(port->sock, F_SETFD, FD_CLOEXEC) < 0)
elog(FATAL, "fcntl(F_SETFD) failed on socket: %m"); #endif
/* -------------------------------- *socket_comm_reset-resetlibpqduringerrorrecovery * *Thisiscalledfromerrorrecoveryattheouteridleloop.It's *justtogetusoutoftroubleifwesomehowmanagetoelog()from *insideapqcomm.croutine(whichideallywillneverhappen,but...) *--------------------------------
*/ staticvoid
socket_comm_reset(void)
{ /* Do not throw away pending data, but do reset the busy flag */
PqCommBusy = false;
}
/* -------------------------------- *socket_close-shutdownlibpqatbackendexit * *Thisistheonepg_on_exit_callbackinplaceduringBackendInitialize(). *Thatfunction'sunusualsignalhandlingconstrainsthatthiscallbackbe *safetorunatanyinstant. *--------------------------------
*/ staticvoid
socket_close(int code, Datum arg)
{ /* Nothing to do in a standalone backend, where MyProcPort is NULL. */ if (MyProcPort != NULL)
{ #ifdef ENABLE_GSS /* *ShutdownGSSAPIlayer.Thissectiondoesnothingwheninterrupting *BackendInitialize(),becausepg_GSS_recvauth()makesfirstuseof *"ctx"and"cred". * *Notethatwedon'tbothertofreeMyProcPort->gss,sincewe're *abouttoexitanyway.
*/ if (MyProcPort->gss)
{
OM_uint32 min_s;
if (MyProcPort->gss->ctx != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_s, &MyProcPort->gss->ctx, NULL);
if (MyProcPort->gss->cred != GSS_C_NO_CREDENTIAL)
gss_release_cred(&min_s, &MyProcPort->gss->cred);
} #endif/* ENABLE_GSS */
if (family == AF_UNIX)
{ /* *CreateunixSocketPathfromportNumberandunixSocketDirandlock *thatfilepath
*/
UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir); if (strlen(unixSocketPath) >= UNIXSOCK_PATH_BUFLEN)
{
ereport(LOG,
(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
unixSocketPath,
(int) (UNIXSOCK_PATH_BUFLEN - 1)))); return STATUS_ERROR;
} if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK) return STATUS_ERROR;
service = unixSocketPath;
} else
{
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;
}
/* See if there is still room to add 1 more socket. */ if (*NumListenSockets == MaxListen)
{
ereport(LOG,
(errmsg("could not bind to all requested addresses: MAXLISTEN (%d) exceeded",
MaxListen))); break;
}
/* set up address family name for log messages */ switch (addr->ai_family)
{ case AF_INET:
familyDesc = _("IPv4"); break; case AF_INET6:
familyDesc = _("IPv6"); break; case AF_UNIX:
familyDesc = _("Unix"); break; default:
snprintf(familyDescBuf, sizeof(familyDescBuf),
_("unrecognized address family %d"),
addr->ai_family);
familyDesc = familyDescBuf; break;
}
/* set up text form of address for log messages */ if (addr->ai_family == AF_UNIX)
addrDesc = unixSocketPath; else
{
pg_getnameinfo_all((conststruct sockaddr_storage *) addr->ai_addr,
addr->ai_addrlen,
addrBuf, sizeof(addrBuf),
NULL, 0,
NI_NUMERICHOST);
addrDesc = addrBuf;
}
if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
{
ereport(LOG,
(errcode_for_socket_access(), /* translator: first %s is IPv4, IPv6, or Unix */
errmsg("could not create %s socket for address \"%s\": %m",
familyDesc, addrDesc))); continue;
}
#ifndef WIN32 /* Don't give the listen socket to any subprograms we execute. */ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
elog(FATAL, "fcntl(F_SETFD) failed on socket: %m");
/* *WithouttheSO_REUSEADDRflag,anewpostmastercan'tbestarted *rightawayafterastoporcrash,giving"addressalreadyinuse" *erroronTCPports. * *Onwin32,however,thisbehavioronlyhappensifthe *SO_EXCLUSIVEADDRUSEisset.WithSO_REUSEADDR,win32allows *multipleserverstolistenonthesameaddress,resultingin *unpredictablebehavior.Withnoflagsatall,win32behavesasUnix *withSO_REUSEADDR.
*/ if (addr->ai_family != AF_UNIX)
{ if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &one, sizeof(one))) == -1)
{
ereport(LOG,
(errcode_for_socket_access(), /* translator: third %s is IPv4 or IPv6 */
errmsg("%s(%s) failed for %s address \"%s\": %m", "setsockopt", "SO_REUSEADDR",
familyDesc, addrDesc)));
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(), /* translator: third %s is IPv6 */
errmsg("%s(%s) failed for %s address \"%s\": %m", "setsockopt", "IPV6_V6ONLY",
familyDesc, addrDesc)));
closesocket(fd); continue;
}
} #endif
/* *Note:ThismightfailonsomeOS's,likeLinuxolderthan *2.4.21-pre3,thatdon'thavetheIPV6_V6ONLYsocketoption,andmap *ipv4addressestoipv6.Itwillshow::ffff:ipv4forallipv4 *connections.
*/
err = bind(fd, addr->ai_addr, addr->ai_addrlen); if (err < 0)
{ int saved_errno = errno;
ereport(LOG,
(errcode_for_socket_access(), /* translator: first %s is IPv4, IPv6, or Unix */
errmsg("could not bind %s address \"%s\": %m",
familyDesc, addrDesc),
saved_errno == EADDRINUSE ?
(addr->ai_family == AF_UNIX ?
errhint("Is another postmaster already running on port %d?",
(int) portNumber) :
errhint("Is another postmaster already running on port %d?" " If not, wait a few seconds and retry.",
(int) portNumber)) : 0));
closesocket(fd); continue;
}
if (addr->ai_family == AF_UNIX)
{ if (Setup_AF_UNIX(service) != STATUS_OK)
{
closesocket(fd); break;
}
}
err = listen(fd, maxconn); if (err < 0)
{
ereport(LOG,
(errcode_for_socket_access(), /* translator: first %s is IPv4, IPv6, or Unix */
errmsg("could not listen on %s address \"%s\": %m",
familyDesc, addrDesc)));
closesocket(fd); continue;
}
if (addr->ai_family == AF_UNIX)
ereport(LOG,
(errmsg("listening on Unix socket \"%s\"",
addrDesc))); else
ereport(LOG, /* translator: first %s is IPv4 or IPv6 */
(errmsg("listening on %s address \"%s\", port %d",
familyDesc, addrDesc, (int) portNumber)));
/* *Setup_AF_UNIX--configureunixsocketpermissions
*/ staticint
Setup_AF_UNIX(constchar *sock_path)
{ /* no file system permissions for abstract sockets */ if (sock_path[0] == '@') return STATUS_OK;
/* *Fixsocketownership/permissionifrequested.Notewemustdothis *beforewelisten()toavoidawindowwhereunwantedconnectionscould *getaccepted.
*/
Assert(Unix_socket_group); if (Unix_socket_group[0] != '\0')
{ #ifdef WIN32
elog(WARNING, "configuration item \"unix_socket_group\" is not supported on this platform"); #else char *endptr; unsignedlong 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)
{
ereport(LOG,
(errmsg("group \"%s\" does not exist",
Unix_socket_group))); return STATUS_ERROR;
}
gid = gr->gr_gid;
} if (chown(sock_path, -1, gid) == -1)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not set group of file \"%s\": %m",
sock_path))); return STATUS_ERROR;
} #endif
}
if (chmod(sock_path, Unix_socket_permissions) == -1)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not set permissions of file \"%s\": %m",
sock_path))); return STATUS_ERROR;
} return STATUS_OK;
}
/* *AcceptConnection--acceptanewconnectionwithclientusing *serverport.Fills*client_sockwiththeFDandendpointinfo *ofthenewconnection. * *ASSUME:thatthisdoesn'tneedtobenon-blockingbecause *thePostmasterwaitsforthesockettobereadytoaccept(). * *RETURNS:STATUS_OKorSTATUS_ERROR
*/ int
AcceptConnection(pgsocket server_fd, ClientSocket *client_sock)
{ /* accept connection and fill in the client (remote) address */
client_sock->raddr.salen = sizeof(client_sock->raddr.addr); if ((client_sock->sock = accept(server_fd,
(struct sockaddr *) &client_sock->raddr.addr,
&client_sock->raddr.salen)) == PGINVALID_SOCKET)
{
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not accept new connection: %m")));
/* -------------------------------- *socket_set_nonblocking-setsocketblocking/non-blocking * *Setsthesocketnon-blockingifnonblockingistrue,orsetsit *blockingotherwise. *--------------------------------
*/ staticvoid
socket_set_nonblocking(bool nonblocking)
{ if (MyProcPort == NULL)
ereport(ERROR,
(errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
errmsg("there is no client connection")));
MyProcPort->noblock = nonblocking;
}
/* -------------------------------- *pq_recvbuf-loadsomebytesintotheinputbuffer * *returns0ifOK,EOFiftrouble *--------------------------------
*/ staticint
pq_recvbuf(void)
{ if (PqRecvPointer > 0)
{ if (PqRecvLength > PqRecvPointer)
{ /* still some unread data, left-justify it in the buffer */
memmove(PqRecvBuffer, PqRecvBuffer + PqRecvPointer,
PqRecvLength - PqRecvPointer);
PqRecvLength -= PqRecvPointer;
PqRecvPointer = 0;
} else
PqRecvLength = PqRecvPointer = 0;
}
/* Ensure that we're in blocking mode */
socket_set_nonblocking(false);
/* Can fill buffer from PqRecvLength and upwards */ for (;;)
{ int r;
errno = 0;
r = secure_read(MyProcPort, PqRecvBuffer + PqRecvLength,
PQ_RECV_BUFFER_SIZE - PqRecvLength);
if (r < 0)
{ if (errno == EINTR) continue; /* Ok if interrupted */
/* *Careful:anereport()thattriestowritetotheclientwould *causerecursiontohere,leadingtostackoverflowandcore *dump!Thismessagemustgo*only*tothepostmasterlog. * *Iferrnoiszero,assumeit'sEOFandletthecallercomplain.
*/ if (errno != 0)
ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not receive data from client: %m"))); return EOF;
} if (r == 0)
{ /* *EOFdetected.Weusedtowritealogmessagehere,butit's *bettertoexpecttheultimatecallertodothat.
*/ return EOF;
} /* r contains number of bytes read, so just incr length */
PqRecvLength += r; return0;
}
}
/* -------------------------------- *pq_getbyte-getasinglebytefromconnection,orreturnEOF *--------------------------------
*/ int
pq_getbyte(void)
{
Assert(PqCommReadingMsg);
while (PqRecvPointer >= PqRecvLength)
{ if (pq_recvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */
} return (unsignedchar) PqRecvBuffer[PqRecvPointer++];
}
while (PqRecvPointer >= PqRecvLength)
{ if (pq_recvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */
} return (unsignedchar) PqRecvBuffer[PqRecvPointer];
}
/* -------------------------------- *pq_getbyte_if_available-getasinglebytefromconnection, *ifavailable * *Thereceivedbyteisstoredin*c.Returns1ifabytewasread, *0ifnodatawasavailable,orEOFiftrouble. *--------------------------------
*/ int
pq_getbyte_if_available(unsignedchar *c)
{ int r;
Assert(PqCommReadingMsg);
if (PqRecvPointer < PqRecvLength)
{
*c = PqRecvBuffer[PqRecvPointer++]; return1;
}
/* Put the socket into non-blocking mode */
socket_set_nonblocking(true);
errno = 0;
r = secure_read(MyProcPort, c, 1); if (r < 0)
{ /* *Okifnodataavailablewithoutblockingorinterrupted(though *EINTRreallyshouldn'thappenwithanon-blockingsocket).Report *othererrors.
*/ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
r = 0; else
{ /* *Careful:anereport()thattriestowritetotheclientwould *causerecursiontohere,leadingtostackoverflowandcore *dump!Thismessagemustgo*only*tothepostmasterlog. * *Iferrnoiszero,assumeit'sEOFandletthecallercomplain.
*/ if (errno != 0)
ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not receive data from client: %m")));
r = EOF;
}
} elseif (r == 0)
{ /* EOF detected */
r = EOF;
}
while (len > 0)
{ while (PqRecvPointer >= PqRecvLength)
{ if (pq_recvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */
}
amount = PqRecvLength - PqRecvPointer; if (amount > len)
amount = len;
memcpy(s, PqRecvBuffer + PqRecvPointer, amount);
PqRecvPointer += amount;
s += amount;
len -= amount;
} return0;
}
while (len > 0)
{ while (PqRecvPointer >= PqRecvLength)
{ if (pq_recvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */
}
amount = PqRecvLength - PqRecvPointer; if (amount > len)
amount = len;
PqRecvPointer += amount;
len -= amount;
} return0;
}
while (len > 0)
{ /* If buffer is full, then flush it out */ if (PqSendPointer >= PqSendBufferSize)
{
socket_set_nonblocking(false); if (internal_flush()) return EOF;
}
int
pq_setkeepalivesidle(int idle, Port *port)
{ if (port == NULL || port->laddr.addr.ss_family == AF_UNIX) return STATUS_OK;
/* check SIO_KEEPALIVE_VALS here, not just WIN32, as some toolchains lack it */ #ifdefined(PG_TCP_KEEPALIVE_IDLE) || 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;
int
pq_setkeepalivesinterval(int interval, Port *port)
{ if (port == NULL || port->laddr.addr.ss_family == AF_UNIX) return STATUS_OK;
#ifdefined(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;
int
pq_setkeepalivescount(int count, Port *port)
{ if (port == NULL || port->laddr.addr.ss_family == AF_UNIX) 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;
int
pq_settcpusertimeout(int timeout, Port *port)
{ if (port == NULL || port->laddr.addr.ss_family == AF_UNIX) return STATUS_OK;
#ifdef TCP_USER_TIMEOUT if (timeout == port->tcp_user_timeout) return STATUS_OK;
if (port->default_tcp_user_timeout <= 0)
{ if (pq_gettcpusertimeout(port) < 0)
{ if (timeout == 0) return STATUS_OK; /* default is set but unknown */ else return STATUS_ERROR;
}
}
if (timeout == 0)
timeout = port->default_tcp_user_timeout;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.