*
* 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
* 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"
#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
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;
}
/* -------------------------
*
* 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;
-
- c = getc(Pfin);
- if (Pfdebug && c != EOF)
- putc(c, Pfdebug);
+ char c;
+ char isDone = 0;
+
+ 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;
}
*/
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
* --------------------------------
void
pq_close()
{
- if (Pfin)
- {
- fclose(Pfin);
- Pfin = NULL;
- }
- if (Pfout)
- {
- fclose(Pfout);
- Pfout = NULL;
- }
+ close(MyProcPort->sock);
PQnotifies_init();
}
void
pq_flush()
{
- if (Pfout)
- fflush(Pfout);
+ /* Not supported/required? */
}
/* --------------------------------
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);
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;
}
/* --------------------------------
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
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);
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,
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);
{
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);
* 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.
*
* 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)
{
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)
#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;
+}
+
+
+
#include <netinet/in.h>
#include "postgres.h"
+#include "miscadmin.h"
#include "libpq/pqcomm.h"
+#include "libpq/libpq.h"
/*
/* --------------------------------------------------------------------- */
int
-pqPutShort(int integer, FILE *f)
+pqPutShort(int integer)
{
uint16 n;
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;
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);
/* --------------------------------------------------------------------- */
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);
Return 0 if ok.
*/
int
-pqGetNBytes(char *s, size_t len, FILE *f)
+pqGetNBytes(char *s, size_t len)
{
- int cnt;
-
- if (f == NULL)
- return EOF;
-
- cnt = fread(s, 1, len, f);
- s[cnt] = '\0';
-
- return (cnt == len) ? 0 : EOF;
+ int bytesDone = 0;
+
+ 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;
+
+ } 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;
-
- if (fwrite(s, 1, len, f) != len)
- return EOF;
+ int bytesDone = 0;
+
+ 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;
/* --------------------------------------------------------------------- */
int
-pqPutString(const char *s, FILE *f)
-{
- 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;
-}
-
-/* --------------------------------------------------------------------- */
-int
-pqGetByte(FILE *f)
+pqPutString(const char *s)
{
- return getc(f);
+ return pqPutNBytes(s,strlen(s)+1);
}
-/* --------------------------------------------------------------------- */
-int
-pqPutByte(int c, FILE *f)
-{
- if (!f)
- return 0;
-
- return (putc(c, f) == c) ? 0 : EOF;
-}