From: Magnus Hagander <mha@sollentuna.net>

Here's another patch for the libpq backend areas. This patch removes all
usage of "FILE *" on the communications channel. It also cleans up the
comments and headers in the pqcomm.c file - a lot of things were either
missing or incorrect. Finally, it removes a couple of unused functions
(leftovers from the time of shared code between the libpq backend and
frontend).
This commit is contained in:
Marc G. Fournier 1999-01-12 12:49:52 +00:00
parent 3b3ffc8d97
commit d8b96ade81
4 changed files with 138 additions and 289 deletions

View File

@ -5,19 +5,22 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pqcomm.c,v 1.60 1999/01/11 03:56:06 scrappy Exp $
* $Id: pqcomm.c,v 1.61 1999/01/12 12:49:51 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* pq_gettty - return the name of the tty in the given buffer
* pq_init - initialize libpq
* 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
* pq_getnchar - get n characters from connection
* 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
* pq_getint - get an integer from connection
* pq_putchar - send 1 character to connection
* pq_putstr - send a null terminated string to connection
* pq_putnchar - send n characters to connection
* pq_putint - send an integer to connection
@ -26,12 +29,15 @@
* the length)
* pq_getinaddr - initialize address from host and port number
* pq_getinserv - initialize address from host and service name
* pq_connect - create remote input / output connection
* pq_accept - accept remote input / output connection
*
* StreamDoUnlink - Shutdown UNIX socket connectioin
* StreamServerPort - Open sock stream
* StreamConnection - Create new connection with client
* StreamClose - Close a client/backend connection
*
* NOTES
* These functions are used by both frontend applications and
* the postgres backend.
* Frontend is now completey in interfaces/libpq, and no
* functions from this file is used.
*
*/
#include "postgres.h"
@ -71,13 +77,7 @@
#endif
#include "utils/trace.h"
/* ----------------
* declarations
* ----------------
*/
static FILE *Pfout,
*Pfin,
*Pfdebug; /* debugging libpq */
extern FILE * debug_port; /* in util.c */
/* --------------------------------
* pq_init - open portal file descriptors
@ -86,15 +86,9 @@ static FILE *Pfout,
void
pq_init(int fd)
{
Pfin = fdopen(fd, "r");
Pfout = fdopen(dup(fd), "w");
if (!Pfin || !Pfout)
elog(FATAL, "pq_init: Couldn't initialize socket connection");
PQnotifies_init();
if (getenv("LIBPQ_DEBUG"))
Pfdebug = stderr;
else
Pfdebug = NULL;
debug_port = stderr;
}
/* -------------------------
@ -102,19 +96,23 @@ pq_init(int fd)
*
* get a character from the input file,
*
* if Pfdebug is set, also echo the character fetched into Pfdebug
*
* used for debugging libpq
*/
int
pq_getchar(void)
{
int c;
char c;
char isDone = 0;
c = getc(Pfin);
if (Pfdebug && c != EOF)
putc(c, Pfdebug);
do {
if (recv(MyProcPort->sock,&c,1,MSG_WAITALL) != 1) {
if (errno != EINTR)
return EOF; /* Not interrupted, so something went wrong */
}
else
isDone = 1;
} while (!isDone);
return c;
}
@ -124,23 +122,23 @@ pq_getchar(void)
*/
int
pq_peekchar(void) {
char c = getc(Pfin);
ungetc(c,Pfin);
return c;
char c;
char isDone = 0;
do {
if (recv(MyProcPort->sock,&c,1,MSG_WAITALL | MSG_PEEK) != 1) {
if (errno != EINTR)
return EOF; /* Not interrupted, so something went wrong */
}
else
isDone = 1;
} while (!isDone);
return c;
}
/* --------------------------------
* pq_gettty - return the name of the tty in the given buffer
* --------------------------------
*/
void
pq_gettty(char *tp)
{
strncpy(tp, ttyname(0), 19);
}
/* --------------------------------
* pq_getport - return the PGPORT setting
* --------------------------------
@ -162,16 +160,7 @@ pq_getport()
void
pq_close()
{
if (Pfin)
{
fclose(Pfin);
Pfin = NULL;
}
if (Pfout)
{
fclose(Pfout);
Pfout = NULL;
}
close(MyProcPort->sock);
PQnotifies_init();
}
@ -182,8 +171,7 @@ pq_close()
void
pq_flush()
{
if (Pfout)
fflush(Pfout);
/* Not supported/required? */
}
/* --------------------------------
@ -198,13 +186,7 @@ pq_getstr(char *s, int maxlen)
char *p;
#endif
if (Pfin == (FILE *) NULL)
{
/* elog(DEBUG, "Input descriptor is null"); */
return EOF;
}
c = pqGetString(s, maxlen, Pfin);
c = pqGetString(s, maxlen);
#ifdef MULTIBYTE
p = (char*) pg_client_to_server((unsigned char *) s, maxlen);
@ -215,73 +197,16 @@ pq_getstr(char *s, int maxlen)
return c;
}
/*
* USER FUNCTION - gets a newline-terminated string from the backend.
*
* Chiefly here so that applications can use "COPY <rel> to stdout"
* and read the output string. Returns a null-terminated string in s.
*
* PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
* the terminating \n (like gets(3)).
*
* RETURNS:
* EOF if it is detected or invalid arguments are given
* 0 if EOL is reached (i.e., \n has been read)
* (this is required for backward-compatibility -- this
* routine used to always return EOF or 0, assuming that
* the line ended within maxlen bytes.)
* 1 in other cases
*/
int
PQgetline(char *s, int maxlen)
{
if (!Pfin || !s || maxlen <= 1)
return EOF;
if (fgets(s, maxlen - 1, Pfin) == NULL)
return feof(Pfin) ? EOF : 1;
else
{
for (; *s; s++)
{
if (*s == '\n')
{
*s = '\0';
break;
}
}
}
return 0;
}
/*
* USER FUNCTION - sends a string to the backend.
*
* Chiefly here so that applications can use "COPY <rel> from stdin".
*
* RETURNS:
* 0 in all cases.
*/
int
PQputline(char *s)
{
if (Pfout)
{
fputs(s, Pfout);
fflush(Pfout);
}
return 0;
}
/* --------------------------------
* pq_getnchar - get n characters from connection
* pq_getnchar - get n characters from connection, and null terminate
* --------------------------------
*/
int
pq_getnchar(char *s, int off, int maxlen)
{
return pqGetNBytes(s + off, maxlen, Pfin);
int r = pqGetNBytes(s + off, maxlen);
s[off+maxlen] = '\0';
return r;
}
/* --------------------------------
@ -297,9 +222,6 @@ pq_getint(int b)
int n,
status = 1;
if (!Pfin)
return EOF;
/*
* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
* EOF is a valid return value for an int! XXX
@ -308,13 +230,13 @@ pq_getint(int b)
switch (b)
{
case 1:
status = ((n = fgetc(Pfin)) == EOF);
status = ((n = pq_getchar()) == EOF);
break;
case 2:
status = pqGetShort(&n, Pfin);
status = pqGetShort(&n);
break;
case 4:
status = pqGetLong(&n, Pfin);
status = pqGetLong(&n);
break;
default:
fprintf(stderr, "** Unsupported size %d\n", b);
@ -343,9 +265,9 @@ pq_putstr(char *s)
unsigned char *p;
p = pg_server_to_client(s, strlen(s));
if (pqPutString(p, Pfout))
if (pqPutString(p))
#else
if (pqPutString(s, Pfout))
if (pqPutString(s))
#endif
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
@ -362,10 +284,10 @@ pq_putstr(char *s)
void
pq_putnchar(char *s, int n)
{
if (pqPutNBytes(s, n, Pfout))
if (pqPutNBytes(s, n))
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: pq_putnchar: fputc() failed: errno=%d\n",
"FATAL: pq_putnchar: pqPutNBytes() failed: errno=%d\n",
errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
@ -384,20 +306,17 @@ pq_putint(int i, int b)
{
int status;
if (!Pfout)
return;
status = 1;
switch (b)
{
case 1:
status = (fputc(i, Pfout) == EOF);
status = (pq_putchar(i) == EOF);
break;
case 2:
status = pqPutShort(i, Pfout);
status = pqPutShort(i);
break;
case 4:
status = pqPutLong(i, Pfout);
status = pqPutLong(i);
break;
default:
fprintf(stderr, "** Unsupported size %d\n", b);
@ -485,6 +404,19 @@ pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
* Stream functions are used for vanilla TCP connection protocol.
*/
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);
}
/*
* StreamServerPort -- open a sock stream "listening" port.
*
@ -498,19 +430,6 @@ pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
* RETURNS: STATUS_OK or STATUS_ERROR
*/
static char sock_path[MAXPGPATH + 1] = "";
/* do_unlink()
* 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);
}
int
StreamServerPort(char *hostName, short portName, int *fdP)
{
@ -707,81 +626,6 @@ StreamClose(int sock)
close(sock);
}
/* ---------------------------
* StreamOpen -- From client, initiate a connection with the
* server (Postmaster).
*
* RETURNS: STATUS_OK or STATUS_ERROR
*
* NOTE: connection is NOT established just because this
* routine exits. Local state is ok, but we haven't
* spoken to the postmaster yet.
* ---------------------------
*/
int
StreamOpen(char *hostName, short portName, Port *port)
{
SOCKET_SIZE_TYPE len;
int err;
struct hostent *hp;
extern int errno;
/* set up the server (remote) address */
MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
if (hostName)
{
if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: StreamOpen: unknown hostname: %s\n", hostName);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
memmove((char *) &(port->raddr.in.sin_addr),
(char *) hp->h_addr,
hp->h_length);
port->raddr.in.sin_family = AF_INET;
port->raddr.in.sin_port = htons(portName);
len = sizeof(struct sockaddr_in);
}
else
{
port->raddr.un.sun_family = AF_UNIX;
len = UNIXSOCK_PATH(port->raddr.un, portName);
}
/* connect to the server */
if ((port->sock = socket(port->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: StreamOpen: socket() failed: errno=%d\n", errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
err = connect(port->sock, &port->raddr.sa, len);
if (err < 0)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: StreamOpen: connect() failed: errno=%d\n", errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
/* fill in the client address */
if (getsockname(port->sock, &port->laddr.sa, &len) < 0)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: StreamOpen: getsockname() failed: errno=%d\n", errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
return STATUS_OK;
}
#ifdef MULTIBYTE
void
pq_putncharlen(char *s, int n)
@ -798,3 +642,24 @@ pq_putncharlen(char *s, int n)
#endif
/*
* 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;
}

View File

@ -4,7 +4,9 @@
#include <netinet/in.h>
#include "postgres.h"
#include "miscadmin.h"
#include "libpq/pqcomm.h"
#include "libpq/libpq.h"
/*
@ -69,7 +71,7 @@
/* --------------------------------------------------------------------- */
int
pqPutShort(int integer, FILE *f)
pqPutShort(int integer)
{
uint16 n;
@ -79,15 +81,12 @@ pqPutShort(int integer, FILE *f)
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(integer) : htons((uint16) integer));
#endif
if (fwrite(&n, 2, 1, f) != 1)
return EOF;
return 0;
return pqPutNBytes((char *)&n, 2); /* 0 on success, EOF otherwise */
}
/* --------------------------------------------------------------------- */
int
pqPutLong(int integer, FILE *f)
pqPutLong(int integer)
{
uint32 n;
@ -97,20 +96,17 @@ pqPutLong(int integer, FILE *f)
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(integer) : htonl((uint32) integer));
#endif
if (fwrite(&n, 4, 1, f) != 1)
return EOF;
return 0;
return pqPutNBytes((char *)&n,4);
}
/* --------------------------------------------------------------------- */
int
pqGetShort(int *result, FILE *f)
pqGetShort(int *result)
{
uint16 n;
if (fread(&n, 2, 1, f) != 1)
return EOF;
if (pqGetNBytes((char *)&n,2) != 0)
return EOF;
#ifdef FRONTEND
*result = (int) ntohs(n);
@ -123,12 +119,12 @@ pqGetShort(int *result, FILE *f)
/* --------------------------------------------------------------------- */
int
pqGetLong(int *result, FILE *f)
pqGetLong(int *result)
{
uint32 n;
if (fread(&n, 4, 1, f) != 1)
return EOF;
if (pqGetNBytes((char *)&n, 4) != 0)
return EOF;
#ifdef FRONTEND
*result = (int) ntohl(n);
@ -145,47 +141,59 @@ pqGetLong(int *result, FILE *f)
Return 0 if ok.
*/
int
pqGetNBytes(char *s, size_t len, FILE *f)
pqGetNBytes(char *s, size_t len)
{
int cnt;
int bytesDone = 0;
if (f == NULL)
return EOF;
do {
int r = recv(MyProcPort->sock, s+bytesDone, len-bytesDone, MSG_WAITALL);
if (r == 0 || r == -1) {
if (errno != EINTR)
return EOF; /* All other than signal-interrupted is error */
continue; /* Otherwise, try again */
}
/* r contains number of bytes received */
bytesDone += r;
cnt = fread(s, 1, len, f);
s[cnt] = '\0';
return (cnt == len) ? 0 : EOF;
} while (bytesDone < len);
/* Zero-termination now in pq_getnchar() instead */
return 0;
}
/* --------------------------------------------------------------------- */
int
pqPutNBytes(const char *s, size_t len, FILE *f)
pqPutNBytes(const char *s, size_t len)
{
if (f == NULL)
return EOF;
int bytesDone = 0;
if (fwrite(s, 1, len, f) != len)
return EOF;
do {
int r = send(MyProcPort->sock, s+bytesDone, len-bytesDone, 0);
if (r == 0 || r == -1) {
if (errno != EINTR)
return EOF; /* Only signal interruption allowed */
continue; /* If interruped and read nothing, just try again */
}
/* r contains number of bytes sent so far */
bytesDone += r;
} while (bytesDone < len);
return 0;
}
/* --------------------------------------------------------------------- */
int
pqGetString(char *s, size_t len, FILE *f)
pqGetString(char *s, size_t len)
{
int c;
if (f == NULL)
return EOF;
/*
* Keep on reading until we get the terminating '\0' and discard those
* bytes we don't have room for.
*/
while ((c = getc(f)) != EOF && c != '\0')
while ((c = pq_getchar()) != EOF && c != '\0')
if (len > 1)
{
*s++ = c;
@ -202,33 +210,8 @@ pqGetString(char *s, size_t len, FILE *f)
/* --------------------------------------------------------------------- */
int
pqPutString(const char *s, FILE *f)
pqPutString(const char *s)
{
if (f == NULL)
return 0;
if (fputs(s, f) == EOF)
return EOF;
fputc('\0', f); /* important to send an ending \0 since
* backend expects it */
return 0;
return pqPutNBytes(s,strlen(s)+1);
}
/* --------------------------------------------------------------------- */
int
pqGetByte(FILE *f)
{
return getc(f);
}
/* --------------------------------------------------------------------- */
int
pqPutByte(int c, FILE *f)
{
if (!f)
return 0;
return (putc(c, f) == c) ? 0 : EOF;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq.h,v 1.22 1999/01/11 03:56:11 scrappy Exp $
* $Id: libpq.h,v 1.23 1999/01/12 12:49:52 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -262,6 +262,7 @@ extern int pq_getchar(void);
extern int pq_peekchar(void);
extern int pq_getnchar(char *s, int off, int maxlen);
extern int pq_getint(int b);
extern int pq_putchar(char c);
extern void pq_putstr(char *s);
extern void pq_putnchar(char *s, int n);
extern void pq_putint(int i, int b);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pqcomm.h,v 1.29 1998/09/01 04:36:31 momjian Exp $
* $Id: pqcomm.h,v 1.30 1999/01/12 12:49:52 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -152,7 +152,7 @@ typedef struct CancelRequestPacket
} CancelRequestPacket;
/* in pqcompriv.c */
/* in pqcomprim.c */
int pqGetShort(int *, FILE *);
int pqGetLong(int *, FILE *);
int pqGetNBytes(char *, size_t, FILE *);