From d8b96ade8165c37738ffc3e81607140cc9adc506 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Tue, 12 Jan 1999 12:49:52 +0000 Subject: [PATCH] From: Magnus Hagander 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). --- src/backend/libpq/pqcomm.c | 317 ++++++++++------------------------ src/backend/libpq/pqcomprim.c | 111 +++++------- src/include/libpq/libpq.h | 3 +- src/include/libpq/pqcomm.h | 4 +- 4 files changed, 142 insertions(+), 293 deletions(-) diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 9fe835d8b7..e7da8d89a8 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -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; - - 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; } @@ -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 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 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; +} + + + diff --git a/src/backend/libpq/pqcomprim.c b/src/backend/libpq/pqcomprim.c index 17c0a2fba5..8c08adb3fd 100644 --- a/src/backend/libpq/pqcomprim.c +++ b/src/backend/libpq/pqcomprim.c @@ -4,7 +4,9 @@ #include #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; - - 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; @@ -202,33 +210,8 @@ pqGetString(char *s, size_t len, FILE *f) /* --------------------------------------------------------------------- */ 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; -} diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index 4fca9623aa..a315521eb3 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -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); diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 0f36e8e93e..15c123e4b8 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -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 *); -- 2.40.0