1998-09-10 06:07:59 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* pqcomm.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Communication functions between the Frontend and the Backend
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-04-25 05:19:27 +02:00
|
|
|
* These routines handle the low-level details of communication between
|
|
|
|
* frontend and backend. They just shove data across the communication
|
|
|
|
* channel, and are ignorant of the semantics of the data --- or would be,
|
|
|
|
* except for major brain damage in the design of the COPY OUT protocol.
|
|
|
|
* Unfortunately, COPY OUT is designed to commandeer the communication
|
|
|
|
* channel (it just transfers data without wrapping it into messages).
|
|
|
|
* No other messages can be sent while COPY OUT is in progress; and if the
|
|
|
|
* copy is aborted by an elog(ERROR), we need to close out the copy so that
|
|
|
|
* the frontend gets back into sync. Therefore, these routines have to be
|
|
|
|
* aware of COPY OUT state.
|
|
|
|
*
|
|
|
|
* NOTE: generally, it's a bad idea to emit outgoing messages directly with
|
|
|
|
* pq_putbytes(), especially if the message would require multiple calls
|
|
|
|
* to send. Instead, use the routines in pqformat.c to construct the message
|
|
|
|
* in a buffer and then emit it in one call to pq_putmessage. This helps
|
|
|
|
* ensure that the channel will not be clogged by an incomplete message
|
|
|
|
* if execution is aborted by elog(ERROR) partway through the message.
|
|
|
|
* The only non-libpq code that should call pq_putbytes directly is COPY OUT.
|
|
|
|
*
|
|
|
|
* At one time, libpq was shared between frontend and backend, but now
|
|
|
|
* the backend's "backend/libpq" is quite separate from "interfaces/libpq".
|
|
|
|
* All that remains is similarities of names to trap the unwary...
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
1999-07-17 22:18:55 +02:00
|
|
|
* $Id: pqcomm.c,v 1.80 1999/07/17 20:17:03 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
/*------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
* INTERFACE ROUTINES
|
|
|
|
*
|
1999-04-25 05:19:27 +02:00
|
|
|
* setup/teardown:
|
|
|
|
* StreamServerPort - Open postmaster's server port
|
1999-01-23 23:27:29 +01:00
|
|
|
* StreamConnection - Create new connection with client
|
|
|
|
* StreamClose - Close a client/backend connection
|
1999-04-25 05:19:27 +02:00
|
|
|
* pq_getport - return the PGPORT setting
|
|
|
|
* pq_init - initialize libpq at backend startup
|
|
|
|
* pq_close - shutdown libpq at backend exit
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-04-25 05:19:27 +02:00
|
|
|
* low-level I/O:
|
|
|
|
* pq_getbytes - get a known number of bytes from connection
|
|
|
|
* pq_getstring - get a null terminated string from connection
|
|
|
|
* pq_peekbyte - peek at next byte from connection
|
|
|
|
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
|
|
|
* pq_flush - flush pending output
|
|
|
|
*
|
|
|
|
* message-level I/O (and COPY OUT cruft):
|
|
|
|
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
|
1999-05-25 18:15:34 +02:00
|
|
|
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
1999-04-25 05:19:27 +02:00
|
|
|
* pq_endcopyout - end a COPY OUT transfer
|
|
|
|
*
|
|
|
|
*------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1996-12-26 23:08:34 +01:00
|
|
|
#include <signal.h>
|
1996-11-06 09:48:33 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
1999-07-16 05:14:30 +02:00
|
|
|
#include <unistd.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <sys/types.h>
|
1997-11-21 19:12:58 +01:00
|
|
|
#include <sys/stat.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
1997-04-16 08:25:13 +02:00
|
|
|
#include <netinet/tcp.h>
|
1996-11-06 09:48:33 +01:00
|
|
|
#include <arpa/inet.h>
|
1998-08-25 23:32:10 +02:00
|
|
|
#include <sys/file.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1999-07-16 05:14:30 +02:00
|
|
|
#include "libpq/libpq.h"
|
1999-07-17 07:16:15 +02:00
|
|
|
#include "utils/trace.h" /* needed for HAVE_FCNTL_SETLK */
|
1998-02-24 05:02:20 +01:00
|
|
|
#include "miscadmin.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 01:12:39 +02:00
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
#ifndef SOMAXCONN
|
|
|
|
#define SOMAXCONN 5 /* from Linux listen(2) man page */
|
|
|
|
#endif /* SOMAXCONN */
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
extern FILE *debug_port; /* in util.c */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-01-23 23:27:29 +01:00
|
|
|
/*
|
1999-04-25 05:19:27 +02:00
|
|
|
* Buffers for low-level I/O
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PQ_BUFFER_SIZE 8192
|
|
|
|
|
|
|
|
static unsigned char PqSendBuffer[PQ_BUFFER_SIZE];
|
1999-05-25 18:15:34 +02:00
|
|
|
static int PqSendPointer; /* Next index to store a byte in
|
|
|
|
* PqSendBuffer */
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
static unsigned char PqRecvBuffer[PQ_BUFFER_SIZE];
|
1999-05-25 18:15:34 +02:00
|
|
|
static int PqRecvPointer; /* Next index to read a byte from
|
|
|
|
* PqRecvBuffer */
|
|
|
|
static int PqRecvLength; /* End of data available in PqRecvBuffer */
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Message status
|
1999-01-23 23:27:29 +01:00
|
|
|
*/
|
1999-04-25 05:19:27 +02:00
|
|
|
static bool DoingCopyOut;
|
1999-01-23 23:27:29 +01:00
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* --------------------------------
|
1999-04-25 05:19:27 +02:00
|
|
|
* pq_init - initialize libpq at backend startup
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
1999-04-25 05:19:27 +02:00
|
|
|
pq_init(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-01-23 23:27:29 +01:00
|
|
|
PqSendPointer = PqRecvPointer = PqRecvLength = 0;
|
1999-04-25 05:19:27 +02:00
|
|
|
DoingCopyOut = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
if (getenv("LIBPQ_DEBUG"))
|
1999-05-25 18:15:34 +02:00
|
|
|
debug_port = stderr;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getport - return the PGPORT setting
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
1999-04-25 05:19:27 +02:00
|
|
|
pq_getport(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char *envport = getenv("PGPORT");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (envport)
|
1998-09-01 05:29:17 +02:00
|
|
|
return atoi(envport);
|
|
|
|
return atoi(DEF_PGPORT);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1999-04-25 05:19:27 +02:00
|
|
|
* pq_close - shutdown libpq at backend exit
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
1999-04-25 05:19:27 +02:00
|
|
|
pq_close(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-01-23 23:27:29 +01:00
|
|
|
close(MyProcPort->sock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-06-16 09:29:54 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Streams -- wrapper around Unix socket system calls
|
|
|
|
*
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Stream functions are used for vanilla TCP connection protocol.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1999-01-12 13:49:52 +01:00
|
|
|
static char sock_path[MAXPGPATH + 1] = "";
|
|
|
|
|
|
|
|
/* StreamDoUnlink()
|
|
|
|
* Shutdown routine for backend connection
|
|
|
|
* If a Unix socket is used for communication, explicitly close it.
|
|
|
|
*/
|
1999-04-25 05:19:27 +02:00
|
|
|
static void
|
1999-01-12 13:49:52 +01:00
|
|
|
StreamDoUnlink()
|
|
|
|
{
|
|
|
|
Assert(sock_path[0]);
|
|
|
|
unlink(sock_path);
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* StreamServerPort -- open a sock stream "listening" port.
|
|
|
|
*
|
1999-04-25 05:19:27 +02:00
|
|
|
* This initializes the Postmaster's connection-accepting port.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* RETURNS: STATUS_OK or STATUS_ERROR
|
|
|
|
*/
|
1997-11-07 21:52:15 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
int
|
1999-07-07 19:17:50 +02:00
|
|
|
StreamServerPort(char *hostName, unsigned short portName, int *fdP)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
SockAddr saddr;
|
1997-11-10 06:16:00 +01:00
|
|
|
int fd,
|
|
|
|
err,
|
|
|
|
family;
|
|
|
|
size_t len;
|
1997-09-08 04:41:22 +02:00
|
|
|
int one = 1;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1998-10-07 05:45:12 +02:00
|
|
|
#ifdef HAVE_FCNTL_SETLK
|
1998-08-25 23:32:10 +02:00
|
|
|
int lock_fd;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1998-10-07 05:45:12 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-11-17 17:17:14 +01:00
|
|
|
family = ((hostName != NULL) ? AF_INET : AF_UNIX);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-11-07 21:52:15 +01:00
|
|
|
if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1999-05-21 03:25:06 +02:00
|
|
|
"FATAL: StreamServerPort: socket() failed: %s\n",
|
|
|
|
strerror(errno));
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1999-05-10 18:10:51 +02:00
|
|
|
|
|
|
|
#ifdef ONLY_REUSE_INET_SOCKETS
|
1999-05-25 18:15:34 +02:00
|
|
|
if (family == AF_INET)
|
|
|
|
{
|
1999-05-10 18:10:51 +02:00
|
|
|
#endif
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
|
|
|
|
sizeof(one))) == -1)
|
|
|
|
{
|
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
|
|
|
"FATAL: StreamServerPort: setsockopt(SO_REUSEADDR) failed: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
1999-05-10 18:10:51 +02:00
|
|
|
|
|
|
|
#ifdef ONLY_REUSE_INET_SOCKETS
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-07-09 05:29:11 +02:00
|
|
|
MemSet((char *) &saddr, 0, sizeof(saddr));
|
1998-01-26 02:42:53 +01:00
|
|
|
saddr.sa.sa_family = family;
|
1997-11-07 21:52:15 +01:00
|
|
|
if (family == AF_UNIX)
|
1997-11-10 06:16:00 +01:00
|
|
|
{
|
|
|
|
len = UNIXSOCK_PATH(saddr.un, portName);
|
|
|
|
strcpy(sock_path, saddr.un.sun_path);
|
1998-08-25 23:32:10 +02:00
|
|
|
|
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* If the socket exists but nobody has an advisory lock on it we
|
|
|
|
* can safely delete the file.
|
1998-08-25 23:32:10 +02:00
|
|
|
*/
|
1998-10-06 04:31:42 +02:00
|
|
|
#ifdef HAVE_FCNTL_SETLK
|
1999-01-17 07:20:06 +01:00
|
|
|
#ifndef __CYGWIN32__
|
1998-10-06 04:31:42 +02:00
|
|
|
if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK, 0666)) >= 0)
|
1999-01-17 07:20:06 +01:00
|
|
|
#else
|
|
|
|
if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK | O_BINARY, 0666)) >= 0)
|
|
|
|
#endif
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
struct flock lck;
|
|
|
|
|
|
|
|
lck.l_whence = SEEK_SET;
|
|
|
|
lck.l_start = lck.l_len = 0;
|
1998-09-10 06:07:59 +02:00
|
|
|
lck.l_type = F_WRLCK;
|
|
|
|
if (fcntl(lock_fd, F_SETLK, &lck) == 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
1998-08-25 23:32:10 +02:00
|
|
|
TPRINTF(TRACE_VERBOSE, "flock on %s, deleting", sock_path);
|
|
|
|
unlink(sock_path);
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
|
|
|
TPRINTF(TRACE_VERBOSE, "flock failed for %s", sock_path);
|
1998-08-25 23:32:10 +02:00
|
|
|
close(lock_fd);
|
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
#endif /* HAVE_FCNTL_SETLK */
|
1997-11-10 06:16:00 +01:00
|
|
|
}
|
1997-11-07 21:52:15 +01:00
|
|
|
else
|
1997-11-10 06:16:00 +01:00
|
|
|
{
|
|
|
|
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
saddr.in.sin_port = htons(portName);
|
1998-02-26 05:46:47 +01:00
|
|
|
len = sizeof(struct sockaddr_in);
|
1997-11-10 06:16:00 +01:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
err = bind(fd, &saddr.sa, len);
|
1997-11-07 21:52:15 +01:00
|
|
|
if (err < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1999-05-21 03:25:06 +02:00
|
|
|
"FATAL: StreamServerPort: bind() failed: %s\n",
|
|
|
|
strerror(errno));
|
1998-08-25 23:32:10 +02:00
|
|
|
strcat(PQerrormsg,
|
|
|
|
"\tIs another postmaster already running on that port?\n");
|
1998-02-26 05:46:47 +01:00
|
|
|
if (family == AF_UNIX)
|
1998-12-14 07:50:32 +01:00
|
|
|
{
|
1999-05-05 01:39:20 +02:00
|
|
|
snprintf(PQerrormsg + strlen(PQerrormsg),
|
|
|
|
ERROR_MSG_LENGTH - strlen(PQerrormsg),
|
|
|
|
"\tIf not, remove socket node (%s) and retry.\n",
|
|
|
|
sock_path);
|
1998-12-14 07:50:32 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
else
|
|
|
|
strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
1999-05-21 03:25:06 +02:00
|
|
|
pqdebug("%s", PQerrormsg);
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
if (family == AF_UNIX)
|
|
|
|
{
|
1998-06-27 06:53:49 +02:00
|
|
|
on_proc_exit(StreamDoUnlink, NULL);
|
1998-05-29 19:00:34 +02:00
|
|
|
|
1998-08-25 23:32:10 +02:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Open the socket file and get an advisory lock on it. The
|
|
|
|
* lock_fd is left open to keep the lock.
|
1998-08-25 23:32:10 +02:00
|
|
|
*/
|
1998-10-06 04:31:42 +02:00
|
|
|
#ifdef HAVE_FCNTL_SETLK
|
1999-01-17 07:20:06 +01:00
|
|
|
#ifndef __CYGWIN32__
|
1998-10-06 04:31:42 +02:00
|
|
|
if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK, 0666)) >= 0)
|
1999-01-17 07:20:06 +01:00
|
|
|
#else
|
|
|
|
if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK | O_BINARY, 0666)) >= 0)
|
|
|
|
#endif
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
struct flock lck;
|
|
|
|
|
|
|
|
lck.l_whence = SEEK_SET;
|
|
|
|
lck.l_start = lck.l_len = 0;
|
1998-09-10 06:07:59 +02:00
|
|
|
lck.l_type = F_WRLCK;
|
|
|
|
if (fcntl(lock_fd, F_SETLK, &lck) != 0)
|
1998-08-25 23:32:10 +02:00
|
|
|
TPRINTF(TRACE_VERBOSE, "flock error for %s", sock_path);
|
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
#endif /* HAVE_FCNTL_SETLK */
|
1998-08-25 23:32:10 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
listen(fd, SOMAXCONN);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MS: I took this code from Dillon's version. It makes the listening
|
|
|
|
* port non-blocking. That is not necessary (and may tickle kernel
|
|
|
|
* bugs).
|
|
|
|
*
|
|
|
|
* fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
|
|
|
|
*/
|
|
|
|
|
|
|
|
*fdP = fd;
|
1997-11-19 19:28:59 +01:00
|
|
|
if (family == AF_UNIX)
|
1998-02-26 05:46:47 +01:00
|
|
|
chmod(sock_path, 0777);
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_OK;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* StreamConnection -- create a new connection with client using
|
1997-09-07 07:04:48 +02:00
|
|
|
* server port.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-04-25 05:19:27 +02:00
|
|
|
* 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().
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* RETURNS: STATUS_OK or STATUS_ERROR
|
|
|
|
*/
|
|
|
|
int
|
1997-09-08 23:56:23 +02:00
|
|
|
StreamConnection(int server_fd, Port *port)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
SOCKET_SIZE_TYPE addrlen;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* accept connection (and fill in the client (remote) address) */
|
1999-01-17 04:10:23 +01:00
|
|
|
addrlen = sizeof(port->raddr);
|
1997-09-07 07:04:48 +02:00
|
|
|
if ((port->sock = accept(server_fd,
|
1997-11-10 06:16:00 +01:00
|
|
|
(struct sockaddr *) & port->raddr,
|
|
|
|
&addrlen)) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "postmaster: StreamConnection: accept: %m");
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-11-10 06:16:00 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* fill in the server (local) address */
|
1999-01-17 04:10:23 +01:00
|
|
|
addrlen = sizeof(port->laddr);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
|
|
|
|
&addrlen) < 0)
|
|
|
|
{
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "postmaster: StreamConnection: getsockname: %m");
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-04-16 08:25:13 +02:00
|
|
|
}
|
1999-01-17 04:10:23 +01:00
|
|
|
|
|
|
|
/* select TCP_NODELAY option if it's a TCP connection */
|
|
|
|
if (port->laddr.sa.sa_family == AF_INET)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
struct protoent *pe;
|
1997-09-08 04:41:22 +02:00
|
|
|
int on = 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pe = getprotobyname("TCP");
|
|
|
|
if (pe == NULL)
|
|
|
|
{
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "postmaster: getprotobyname failed");
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
|
|
|
|
&on, sizeof(on)) < 0)
|
|
|
|
{
|
1999-01-23 23:27:29 +01:00
|
|
|
elog(ERROR, "postmaster: setsockopt failed: %m");
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-04-16 08:25:13 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* reset to non-blocking */
|
|
|
|
fcntl(port->sock, F_SETFL, 1);
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_OK;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1996-07-09 08:22:35 +02:00
|
|
|
* StreamClose -- close a client/backend connection
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
StreamClose(int sock)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
close(sock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* Low-level I/O routines begin here.
|
|
|
|
*
|
|
|
|
* These routines communicate with a frontend client across a connection
|
|
|
|
* already established by the preceding routines.
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_recvbuf - load some bytes into the input buffer
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
pq_recvbuf(void)
|
1998-06-16 09:29:54 +02:00
|
|
|
{
|
1999-04-25 05:19:27 +02:00
|
|
|
if (PqRecvPointer > 0)
|
|
|
|
{
|
|
|
|
if (PqRecvLength > PqRecvPointer)
|
|
|
|
{
|
|
|
|
/* still some unread data, left-justify it in the buffer */
|
1999-05-25 18:15:34 +02:00
|
|
|
memmove(PqRecvBuffer, PqRecvBuffer + PqRecvPointer,
|
|
|
|
PqRecvLength - PqRecvPointer);
|
1999-04-25 05:19:27 +02:00
|
|
|
PqRecvLength -= PqRecvPointer;
|
|
|
|
PqRecvPointer = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
PqRecvLength = PqRecvPointer = 0;
|
|
|
|
}
|
1998-06-16 09:29:54 +02:00
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
/* Can fill buffer from PqRecvLength and upwards */
|
|
|
|
for (;;)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
int r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
|
|
|
|
PQ_BUFFER_SIZE - PqRecvLength, 0);
|
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
if (r < 0)
|
|
|
|
{
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue; /* Ok if interrupted */
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We would like to use elog() here, but dare not because elog
|
|
|
|
* tries to write to the client, which will cause problems if
|
|
|
|
* we have a hard communications failure ... So just write the
|
|
|
|
* message to the postmaster log.
|
1999-04-25 05:19:27 +02:00
|
|
|
*/
|
1999-05-21 03:25:06 +02:00
|
|
|
fprintf(stderr, "pq_recvbuf: recv() failed: %s\n",
|
|
|
|
strerror(errno));
|
1999-04-25 05:19:27 +02:00
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
|
|
|
{
|
|
|
|
/* as above, elog not safe */
|
|
|
|
fprintf(stderr, "pq_recvbuf: unexpected EOF on client connection\n");
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
/* r contains number of bytes read, so just incr length */
|
|
|
|
PqRecvLength += r;
|
|
|
|
return 0;
|
|
|
|
}
|
1998-06-16 09:29:54 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
/* --------------------------------
|
|
|
|
* pq_getbyte - get a single byte from connection, or return EOF
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
pq_getbyte(void)
|
|
|
|
{
|
|
|
|
while (PqRecvPointer >= PqRecvLength)
|
|
|
|
{
|
|
|
|
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
|
|
|
return EOF; /* Failed to recv data */
|
|
|
|
}
|
|
|
|
return PqRecvBuffer[PqRecvPointer++];
|
|
|
|
}
|
1998-09-10 06:07:59 +02:00
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
/* --------------------------------
|
|
|
|
* pq_peekbyte - peek at next byte from connection
|
|
|
|
*
|
|
|
|
* Same as pq_getbyte() except we don't advance the pointer.
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_peekbyte(void)
|
|
|
|
{
|
|
|
|
while (PqRecvPointer >= PqRecvLength)
|
|
|
|
{
|
|
|
|
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
|
|
|
return EOF; /* Failed to recv data */
|
|
|
|
}
|
|
|
|
return PqRecvBuffer[PqRecvPointer];
|
|
|
|
}
|
1998-09-10 06:07:59 +02:00
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
/* --------------------------------
|
|
|
|
* pq_getbytes - get a known number of bytes from connection
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
1999-01-12 13:49:52 +01:00
|
|
|
*/
|
1999-04-25 05:19:27 +02:00
|
|
|
int
|
|
|
|
pq_getbytes(char *s, size_t len)
|
1999-01-12 13:49:52 +01:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
size_t amount;
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_getstring - get a null terminated string from connection
|
|
|
|
*
|
|
|
|
* NOTE: this routine does not do any MULTIBYTE conversion,
|
|
|
|
* even though it is presumably useful only for text, because
|
|
|
|
* no code in this module should depend on MULTIBYTE mode.
|
|
|
|
* See pq_getstr in pqformat.c for that.
|
|
|
|
*
|
|
|
|
* FIXME: we ought to use an expansible StringInfo buffer,
|
|
|
|
* rather than dropping data if the message is too long.
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_getstring(char *s, size_t len)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
/*
|
1999-05-25 18:15:34 +02:00
|
|
|
* Keep on reading until we get the terminating '\0', discarding any
|
|
|
|
* bytes we don't have room for.
|
1999-04-25 05:19:27 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
while ((c = pq_getbyte()) != EOF && c != '\0')
|
|
|
|
{
|
|
|
|
if (len > 1)
|
|
|
|
{
|
|
|
|
*s++ = c;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
if (c == EOF)
|
|
|
|
return EOF;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_putbytes(const char *s, size_t len)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
size_t amount;
|
1999-04-25 05:19:27 +02:00
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
if (PqSendPointer >= PQ_BUFFER_SIZE)
|
|
|
|
if (pq_flush()) /* If buffer is full, then flush it out */
|
|
|
|
return EOF;
|
|
|
|
amount = PQ_BUFFER_SIZE - PqSendPointer;
|
|
|
|
if (amount > len)
|
|
|
|
amount = len;
|
|
|
|
memcpy(PqSendBuffer + PqSendPointer, s, amount);
|
|
|
|
PqSendPointer += amount;
|
|
|
|
s += amount;
|
|
|
|
len -= amount;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_flush - flush pending output
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_flush(void)
|
|
|
|
{
|
|
|
|
unsigned char *bufptr = PqSendBuffer;
|
|
|
|
unsigned char *bufend = PqSendBuffer + PqSendPointer;
|
|
|
|
|
|
|
|
while (bufptr < bufend)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
int r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
|
|
|
|
|
1999-04-25 05:19:27 +02:00
|
|
|
if (r <= 0)
|
|
|
|
{
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue; /* Ok if we were interrupted */
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We would like to use elog() here, but cannot because elog
|
1999-04-25 05:19:27 +02:00
|
|
|
* tries to write to the client, which would cause a recursive
|
|
|
|
* flush attempt! So just write it out to the postmaster log.
|
|
|
|
*/
|
1999-05-21 03:25:06 +02:00
|
|
|
fprintf(stderr, "pq_flush: send() failed: %s\n",
|
|
|
|
strerror(errno));
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We drop the buffered data anyway so that processing can
|
|
|
|
* continue, even though we'll probably quit soon.
|
1999-04-25 05:19:27 +02:00
|
|
|
*/
|
|
|
|
PqSendPointer = 0;
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
bufptr += r;
|
|
|
|
}
|
|
|
|
PqSendPointer = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* Message-level I/O routines begin here.
|
|
|
|
*
|
|
|
|
* These routines understand about COPY OUT protocol.
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
|
|
|
|
*
|
|
|
|
* If msgtype is not '\0', it is a message type code to place before
|
|
|
|
* the message body (len counts only the body size!).
|
|
|
|
* If msgtype is '\0', then the buffer already includes the type code.
|
|
|
|
*
|
|
|
|
* All normal messages are suppressed while COPY OUT is in progress.
|
|
|
|
* (In practice only NOTICE messages might get emitted then; dropping
|
|
|
|
* them is annoying, but at least they will still appear in the
|
|
|
|
* postmaster log.)
|
|
|
|
*
|
|
|
|
* returns 0 if OK, EOF if trouble
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_putmessage(char msgtype, const char *s, size_t len)
|
|
|
|
{
|
|
|
|
if (DoingCopyOut)
|
|
|
|
return 0;
|
|
|
|
if (msgtype)
|
|
|
|
if (pq_putbytes(&msgtype, 1))
|
1999-01-23 23:27:29 +01:00
|
|
|
return EOF;
|
1999-04-25 05:19:27 +02:00
|
|
|
return pq_putbytes(s, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1999-05-25 18:15:34 +02:00
|
|
|
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
1999-04-25 05:19:27 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_startcopyout(void)
|
|
|
|
{
|
|
|
|
DoingCopyOut = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* pq_endcopyout - end a COPY OUT transfer
|
|
|
|
*
|
|
|
|
* If errorAbort is indicated, we are aborting a COPY OUT due to an error,
|
|
|
|
* and must send a terminator line. Since a partial data line might have
|
|
|
|
* been emitted, send a couple of newlines first (the first one could
|
|
|
|
* get absorbed by a backslash...)
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_endcopyout(bool errorAbort)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
if (!DoingCopyOut)
|
1999-04-25 05:19:27 +02:00
|
|
|
return;
|
|
|
|
if (errorAbort)
|
|
|
|
pq_putbytes("\n\n\\.\n", 5);
|
|
|
|
/* in non-error case, copy.c will have emitted the terminator line */
|
|
|
|
DoingCopyOut = false;
|
1999-01-12 13:49:52 +01:00
|
|
|
}
|