1998-09-10 06:07:59 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
1996-07-09 08:22:35 +02: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
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
1999-01-17 07:20:06 +01:00
|
|
|
* $Id: pqcomm.c,v 1.63 1999/01/17 06:18:26 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* INTERFACE ROUTINES
|
1999-01-12 13:49:52 +01:00
|
|
|
* pq_init - initialize libpq
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getport - return the PGPORT setting
|
|
|
|
* pq_close - close input / output connections
|
|
|
|
* pq_flush - flush pending output
|
|
|
|
* pq_getstr - get a null terminated string from connection
|
1999-01-12 13:49:52 +01:00
|
|
|
* pq_getchar - get 1 character from connection
|
|
|
|
* pq_peekchar - peek at first character in connection
|
|
|
|
* pq_getnchar - get n characters from connection, and null-terminate
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getint - get an integer from connection
|
1999-01-12 13:49:52 +01:00
|
|
|
* pq_putchar - send 1 character to connection
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_putstr - send a null terminated string to connection
|
|
|
|
* pq_putnchar - send n characters to connection
|
|
|
|
* pq_putint - send an integer to connection
|
1998-06-16 09:29:54 +02:00
|
|
|
* pq_putncharlen - send n characters to connection
|
|
|
|
* (also send an int header indicating
|
|
|
|
* the length)
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getinaddr - initialize address from host and port number
|
|
|
|
* pq_getinserv - initialize address from host and service name
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-01-12 13:49:52 +01:00
|
|
|
* StreamDoUnlink - Shutdown UNIX socket connectioin
|
|
|
|
* StreamServerPort - Open sock stream
|
|
|
|
* StreamConnection - Create new connection with client
|
|
|
|
* StreamClose - Close a client/backend connection
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* NOTES
|
1999-01-12 13:49:52 +01:00
|
|
|
* Frontend is now completey in interfaces/libpq, and no
|
|
|
|
* functions from this file is used.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1998-02-24 05:02:20 +01:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <stdio.h>
|
1998-02-24 05:02:20 +01:00
|
|
|
#if defined(HAVE_STRING_H)
|
1998-02-26 05:46:47 +01:00
|
|
|
#include <string.h>
|
1998-02-24 05:02:20 +01:00
|
|
|
#else
|
1998-02-26 05:46:47 +01:00
|
|
|
#include <strings.h>
|
1998-02-24 05:02:20 +01:00
|
|
|
#endif
|
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>
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <unistd.h> /* for ttyname() */
|
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
|
|
|
|
1996-10-31 11:17:09 +01:00
|
|
|
#if defined(linux)
|
1996-07-09 08:22:35 +02:00
|
|
|
#ifndef SOMAXCONN
|
1997-09-07 07:04:48 +02:00
|
|
|
#define SOMAXCONN 5 /* from Linux listen(2) man page */
|
1998-09-01 06:40:42 +02:00
|
|
|
#endif /* SOMAXCONN */
|
|
|
|
#endif /* linux */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-02-24 05:02:20 +01:00
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "libpq/pqsignal.h"
|
|
|
|
#include "libpq/auth.h"
|
|
|
|
#include "libpq/libpq.h" /* where the declarations go */
|
|
|
|
#include "storage/ipc.h"
|
1998-07-18 20:34:34 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-07-26 06:31:41 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
1998-06-16 09:29:54 +02:00
|
|
|
#endif
|
1998-08-25 23:32:10 +02:00
|
|
|
#include "utils/trace.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-01-12 13:49:52 +01:00
|
|
|
extern FILE * debug_port; /* in util.c */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_init - open portal file descriptors
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_init(int fd)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
PQnotifies_init();
|
|
|
|
if (getenv("LIBPQ_DEBUG"))
|
1999-01-12 13:49:52 +01:00
|
|
|
debug_port = stderr;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------
|
1999-01-11 04:56:11 +01:00
|
|
|
* pq_getchar()
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
|
|
|
* get a character from the input file,
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1998-11-29 02:47:42 +01:00
|
|
|
|
1999-01-11 04:56:11 +01:00
|
|
|
int
|
|
|
|
pq_getchar(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-01-12 13:49:52 +01:00
|
|
|
char c;
|
|
|
|
|
1999-01-17 04:10:23 +01:00
|
|
|
while (recv(MyProcPort->sock, &c, 1, 0) != 1) {
|
1999-01-12 13:49:52 +01:00
|
|
|
if (errno != EINTR)
|
1999-01-17 04:10:23 +01:00
|
|
|
return EOF; /* Not interrupted, so something went wrong */
|
|
|
|
}
|
1999-01-12 13:49:52 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return c;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1999-01-11 04:56:11 +01:00
|
|
|
/*
|
|
|
|
* --------------------------------
|
|
|
|
* pq_peekchar - get 1 character from connection, but leave it in the stream
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_peekchar(void) {
|
1999-01-12 13:49:52 +01:00
|
|
|
char c;
|
|
|
|
|
1999-01-17 04:10:23 +01:00
|
|
|
while (recv(MyProcPort->sock, &c, 1, MSG_PEEK) != 1) {
|
1999-01-12 13:49:52 +01:00
|
|
|
if (errno != EINTR)
|
1999-01-17 04:10:23 +01:00
|
|
|
return EOF; /* Not interrupted, so something went wrong */
|
|
|
|
}
|
|
|
|
|
1999-01-12 13:49:52 +01:00
|
|
|
return c;
|
1999-01-11 04:56:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-11-29 02:47:42 +01:00
|
|
|
|
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
|
|
|
|
pq_getport()
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_close - close input / output connections
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_close()
|
|
|
|
{
|
1999-01-12 13:49:52 +01:00
|
|
|
close(MyProcPort->sock);
|
1997-09-07 07:04:48 +02:00
|
|
|
PQnotifies_init();
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_flush - flush pending output
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_flush()
|
|
|
|
{
|
1999-01-12 13:49:52 +01:00
|
|
|
/* Not supported/required? */
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getstr - get a null terminated string from connection
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_getstr(char *s, int maxlen)
|
|
|
|
{
|
1998-11-29 02:47:42 +01:00
|
|
|
int c;
|
1998-07-18 20:34:34 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-11-29 02:47:42 +01:00
|
|
|
char *p;
|
1998-06-16 09:29:54 +02:00
|
|
|
#endif
|
|
|
|
|
1999-01-12 13:49:52 +01:00
|
|
|
c = pqGetString(s, maxlen);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-07-18 20:34:34 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-11-29 02:47:42 +01:00
|
|
|
p = (char*) pg_client_to_server((unsigned char *) s, maxlen);
|
|
|
|
if (s != p) /* actual conversion has been done? */
|
|
|
|
strcpy(s, p);
|
1998-06-16 09:29:54 +02:00
|
|
|
#endif
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-11-29 02:47:42 +01:00
|
|
|
return c;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1999-01-12 13:49:52 +01:00
|
|
|
* pq_getnchar - get n characters from connection, and null terminate
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_getnchar(char *s, int off, int maxlen)
|
|
|
|
{
|
1999-01-12 13:49:52 +01:00
|
|
|
int r = pqGetNBytes(s + off, maxlen);
|
|
|
|
s[off+maxlen] = '\0';
|
|
|
|
return r;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getint - get an integer from connection
|
|
|
|
* we receive an integer a byte at a type and reconstruct it so that
|
|
|
|
* machines with different ENDIAN representations can talk to each
|
|
|
|
* other
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pq_getint(int b)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int n,
|
|
|
|
status = 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
|
|
|
|
* EOF is a valid return value for an int! XXX
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (b)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case 1:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = ((n = pq_getchar()) == EOF);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = pqGetShort(&n);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = pqGetLong(&n);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "** Unsupported size %d\n", b);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status)
|
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: pq_getint failed: errno=%d\n", errno);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_putstr - send a null terminated string to connection
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_putstr(char *s)
|
|
|
|
{
|
1998-07-18 20:34:34 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-09-01 06:40:42 +02:00
|
|
|
unsigned char *p;
|
1998-06-16 09:29:54 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
p = pg_server_to_client(s, strlen(s));
|
1999-01-12 13:49:52 +01:00
|
|
|
if (pqPutString(p))
|
1998-06-16 09:29:54 +02:00
|
|
|
#else
|
1999-01-12 13:49:52 +01:00
|
|
|
if (pqPutString(s))
|
1998-06-16 09:29:54 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_putnchar - send n characters to connection
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_putnchar(char *s, int n)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1999-01-12 13:49:52 +01:00
|
|
|
if (pqPutNBytes(s, n))
|
1997-03-18 21:15:39 +01:00
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1999-01-12 13:49:52 +01:00
|
|
|
"FATAL: pq_putnchar: pqPutNBytes() failed: errno=%d\n",
|
1997-09-07 07:04:48 +02:00
|
|
|
errno);
|
1996-07-09 08:22:35 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_putint - send an integer to connection
|
|
|
|
* we chop an integer into bytes and send individual bytes
|
|
|
|
* machines with different ENDIAN representations can still talk to each
|
|
|
|
* other
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pq_putint(int i, int b)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int status;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
status = 1;
|
|
|
|
switch (b)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case 1:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = (pq_putchar(i) == EOF);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = pqPutShort(i);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
1999-01-12 13:49:52 +01:00
|
|
|
status = pqPutLong(i);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "** Unsupported size %d\n", b);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status)
|
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: pq_putint failed: errno=%d\n", errno);
|
1996-07-09 08:22:35 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getinaddr - initialize address from host and port number
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
1997-09-07 07:04:48 +02:00
|
|
|
pq_getinaddr(struct sockaddr_in * sin,
|
|
|
|
char *host,
|
|
|
|
int port)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
struct hostent *hs;
|
|
|
|
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet((char *) sin, 0, sizeof(*sin));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (host)
|
|
|
|
{
|
|
|
|
if (*host >= '0' && *host <= '9')
|
|
|
|
sin->sin_addr.s_addr = inet_addr(host);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(hs = gethostbyname(host)))
|
|
|
|
{
|
|
|
|
perror(host);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
if (hs->h_addrtype != AF_INET)
|
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: pq_getinaddr: %s not on Internet\n",
|
|
|
|
host);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
memmove((char *) &sin->sin_addr,
|
|
|
|
hs->h_addr,
|
|
|
|
hs->h_length);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_port = htons(port);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 0;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pq_getinserv - initialize address from host and servive name
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
int
|
1997-09-07 07:04:48 +02:00
|
|
|
pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
struct servent *ss;
|
|
|
|
|
|
|
|
if (*serv >= '0' && *serv <= '9')
|
1998-09-01 05:29:17 +02:00
|
|
|
return pq_getinaddr(sin, host, atoi(serv));
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!(ss = getservbyname(serv, NULL)))
|
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: pq_getinserv: unknown service: %s\n",
|
|
|
|
serv);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1998-09-01 05:29:17 +02:00
|
|
|
return 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
return pq_getinaddr(sin, host, ntohs(ss->s_port));
|
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.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
StreamDoUnlink()
|
|
|
|
{
|
|
|
|
Assert(sock_path[0]);
|
|
|
|
unlink(sock_path);
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* StreamServerPort -- open a sock stream "listening" port.
|
|
|
|
*
|
|
|
|
* This initializes the Postmaster's connection
|
1997-09-07 07:04:48 +02:00
|
|
|
* accepting port.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ASSUME: that this doesn't need to be non-blocking because
|
1997-09-07 07:04:48 +02:00
|
|
|
* the Postmaster uses select() to tell when the socket
|
|
|
|
* is ready.
|
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
|
|
|
|
StreamServerPort(char *hostName, short portName, int *fdP)
|
|
|
|
{
|
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;
|
1998-10-07 05:45:12 +02:00
|
|
|
#ifdef HAVE_FCNTL_SETLK
|
1998-08-25 23:32:10 +02:00
|
|
|
int lock_fd;
|
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,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: StreamServerPort: socket() failed: errno=%d\n",
|
|
|
|
errno);
|
|
|
|
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
|
|
|
}
|
|
|
|
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
|
|
|
|
sizeof(one))) == -1)
|
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
|
|
|
|
errno);
|
|
|
|
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
|
|
|
}
|
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
|
|
|
{
|
1998-09-10 06:07:59 +02:00
|
|
|
struct flock lck;
|
|
|
|
|
|
|
|
lck.l_whence = SEEK_SET; lck.l_start = lck.l_len = 0;
|
|
|
|
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);
|
|
|
|
}
|
1998-10-06 04:31:42 +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,
|
|
|
|
"FATAL: StreamServerPort: bind() failed: errno=%d\n", errno);
|
1998-02-26 05:46:47 +01:00
|
|
|
pqdebug("%s", PQerrormsg);
|
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
|
|
|
{
|
|
|
|
snprintf(PQerrormsg + strlen(PQerrormsg), ERROR_MSG_LENGTH,
|
|
|
|
"\tIf not, remove socket node (%s) and retry.\n", sock_path);
|
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
else
|
1998-12-14 07:50:32 +01:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
|
1998-12-14 07:50:32 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
fputs(PQerrormsg, stderr);
|
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
|
|
|
{
|
1998-09-10 06:07:59 +02:00
|
|
|
struct flock lck;
|
|
|
|
|
|
|
|
lck.l_whence = SEEK_SET; lck.l_start = lck.l_len = 0;
|
|
|
|
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);
|
|
|
|
}
|
1998-10-06 04:31:42 +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
|
|
|
*
|
|
|
|
* This one should be non-blocking.
|
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
|
|
|
{
|
1998-10-13 22:44:49 +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)
|
|
|
|
{
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "postmaster: setsockopt failed");
|
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
|
|
|
}
|
|
|
|
|
1998-07-18 20:34:34 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-06-16 09:29:54 +02:00
|
|
|
void
|
|
|
|
pq_putncharlen(char *s, int n)
|
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
unsigned char *p;
|
|
|
|
int len;
|
1998-06-16 09:29:54 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
p = pg_server_to_client(s, n);
|
|
|
|
len = strlen(p);
|
|
|
|
pq_putint(len, sizeof(int));
|
|
|
|
pq_putnchar(p, len);
|
1998-06-16 09:29:54 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-06-16 09:29:54 +02:00
|
|
|
#endif
|
1998-09-10 06:07:59 +02:00
|
|
|
|
|
|
|
|
1999-01-12 13:49:52 +01:00
|
|
|
/*
|
|
|
|
* Act like the stdio putc() function. Write one character
|
|
|
|
* to the stream. Return this character, or EOF on error.
|
|
|
|
*/
|
|
|
|
int pq_putchar(char c)
|
|
|
|
{
|
|
|
|
char isDone = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (send(MyProcPort->sock, &c, 1, 0) != 1) {
|
|
|
|
if (errno != EINTR)
|
|
|
|
return EOF; /* Anything other than interrupt is error! */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
isDone = 1; /* Done if we sent one char */
|
|
|
|
} while (!isDone);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|