55 *
66 * Copyright (c) 1994, Regents of the University of California
77 *
8- * $Id: pqcomm.c,v 1.63 1999/01/17 06:18:26 momjian Exp $
8+ * $Id: pqcomm.c,v 1.64 1999/01/23 22:27:28 tgl Exp $
99 *
1010 *-------------------------------------------------------------------------
1111 */
1212/*
1313 * INTERFACE ROUTINES
14- * pq_init - initialize libpq
14+ * pq_init - initialize libpq
1515 *pq_getport- return the PGPORT setting
1616 *pq_close- close input / output connections
1717 *pq_flush- flush pending output
18+ *pq_recvbuf- load some bytes into the input buffer
1819 *pq_getstr- get a null terminated string from connection
19- * pq_getchar - get 1 character from connection
20- * pq_peekchar - peek atfirst characterin connection
20+ * pq_getchar - get 1 character from connection
21+ * pq_peekchar - peek atnext characterfrom connection
2122 *pq_getnchar- get n characters from connection, and null-terminate
2223 *pq_getint- get an integer from connection
23- * pq_putchar - send 1 character to connection
24+ * pq_putchar - send 1 character to connection
2425 *pq_putstr- send a null terminated string to connection
2526 *pq_putnchar- send n characters to connection
2627 *pq_putint- send an integer to connection
27- *pq_putncharlen - send n characters to connection
28+ *pq_putncharlen- send n characters to connection
2829 * (also send an int header indicating
2930 * the length)
3031 *pq_getinaddr- initialize address from host and port number
3132 *pq_getinserv- initialize address from host and service name
3233 *
33- * StreamDoUnlink - Shutdown UNIX socketconnectioin
34- * StreamServerPort - Opensock stream
35- * StreamConnection - Create new connection with client
36- * StreamClose - Close a client/backend connection
34+ * StreamDoUnlink - Shutdown UNIX socketconnection
35+ * StreamServerPort - Opensocket stream
36+ * StreamConnection - Create new connection with client
37+ * StreamClose - Close a client/backend connection
3738 *
3839 * NOTES
39- * Frontend is nowcompletey in interfaces/libpq, and no
40- * functions from this fileis used.
40+ * Frontend is nowcompletely in interfaces/libpq, and no
41+ * functions from this fileare used there .
4142 *
4243 */
4344#include "postgres.h"
7980
8081extern FILE * debug_port ;/* in util.c */
8182
83+ /*
84+ * Buffers
85+ */
86+ char PqSendBuffer [PQ_BUFFER_SIZE ];
87+ char PqRecvBuffer [PQ_BUFFER_SIZE ];
88+ int PqSendPointer ,PqRecvPointer ,PqRecvLength ;
89+
90+
8291/* --------------------------------
8392 *pq_init - open portal file descriptors
8493 * --------------------------------
8594 */
8695void
8796pq_init (int fd )
8897{
98+ PqSendPointer = PqRecvPointer = PqRecvLength = 0 ;
8999PQnotifies_init ();
90100if (getenv ("LIBPQ_DEBUG" ))
91101debug_port = stderr ;
@@ -94,40 +104,40 @@ pq_init(int fd)
94104/* -------------------------
95105 * pq_getchar()
96106 *
97- * get a character from the input file,
98- *
107+ * get a character from the input file, or EOF if trouble
108+ * --------------------------------
99109 */
100110
101111int
102112pq_getchar (void )
103113{
104- char c ;
105-
106- while (recv (MyProcPort -> sock ,& c ,1 ,0 )!= 1 ) {
107- if (errno != EINTR )
108- return EOF ;/* Not interrupted, so something went wrong */
114+ while (PqRecvPointer >=PqRecvLength )
115+ {
116+ if (pq_recvbuf ())/* If nothing in buffer, then recv some */
117+ return EOF ;/* Failed to recv data */
109118}
110-
111- return c ;
119+ return PqRecvBuffer [PqRecvPointer ++ ];
112120}
113121
114- /*
122+ /* -------------------------
123+ * pq_peekchar()
124+ *
125+ * get a character from the connection, but leave it in the buffer
126+ * to be read again
115127 * --------------------------------
116- * pq_peekchar - get 1 character from connection, but leave it in the stream
117128 */
118- int
119- pq_peekchar (void ) {
120- char c ;
121129
122- while (recv (MyProcPort -> sock ,& c ,1 ,MSG_PEEK )!= 1 ) {
123- if (errno != EINTR )
124- return EOF ;/* Not interrupted, so something went wrong */
130+ int
131+ pq_peekchar (void )
132+ {
133+ while (PqRecvPointer >=PqRecvLength )
134+ {
135+ if (pq_recvbuf ())/* If nothing in buffer, then recv some */
136+ return EOF ;/* Failed to recv data */
125137}
126-
127- return c ;
138+ /* Note we don't bump the pointer... */
139+ return PqRecvBuffer [ PqRecvPointer ] ;
128140}
129-
130-
131141
132142/* --------------------------------
133143 *pq_getport - return the PGPORT setting
@@ -150,18 +160,91 @@ pq_getport()
150160void
151161pq_close ()
152162{
153- close (MyProcPort -> sock );
163+ close (MyProcPort -> sock );
154164PQnotifies_init ();
155165}
156166
157167/* --------------------------------
158168 *pq_flush - flush pending output
169+ *
170+ *returns 0 if OK, EOF if trouble
159171 * --------------------------------
160172 */
161- void
173+ int
162174pq_flush ()
163175{
164- /* Not supported/required? */
176+ char * bufptr = PqSendBuffer ;
177+ char * bufend = PqSendBuffer + PqSendPointer ;
178+
179+ while (bufptr < bufend )
180+ {
181+ int r = send (MyProcPort -> sock ,bufptr ,bufend - bufptr ,0 );
182+ if (r <=0 )
183+ {
184+ if (errno == EINTR )
185+ continue ;/* Ok if we were interrupted */
186+ /* We would like to use elog() here, but cannot because elog
187+ * tries to write to the client, which would cause a recursive
188+ * flush attempt! So just write it out to the postmaster log.
189+ */
190+ fprintf (stderr ,"pq_flush: send() failed, errno %d\n" ,errno );
191+ /* We drop the buffered data anyway so that processing
192+ * can continue, even though we'll probably quit soon.
193+ */
194+ PqSendPointer = 0 ;
195+ return EOF ;
196+ }
197+ bufptr += r ;
198+ }
199+ PqSendPointer = 0 ;
200+ return 0 ;
201+ }
202+
203+ /* --------------------------------
204+ *pq_recvbuf - load some bytes into the input buffer
205+ *
206+ *returns 0 if OK, EOF if trouble
207+ * --------------------------------
208+ */
209+
210+ int
211+ pq_recvbuf ()
212+ {
213+ if (PqRecvPointer > 0 )
214+ {
215+ if (PqRecvLength > PqRecvPointer )
216+ {
217+ /* still some unread data, left-justify it in the buffer */
218+ memmove (PqRecvBuffer ,PqRecvBuffer + PqRecvPointer ,
219+ PqRecvLength - PqRecvPointer );
220+ PqRecvLength -= PqRecvPointer ;
221+ PqRecvPointer = 0 ;
222+ }
223+ else
224+ PqRecvLength = PqRecvPointer = 0 ;
225+ }
226+
227+ /* Can fill buffer from PqRecvLength and upwards */
228+ for (;;)
229+ {
230+ int r = recv (MyProcPort -> sock ,PqRecvBuffer + PqRecvLength ,
231+ PQ_BUFFER_SIZE - PqRecvLength ,0 );
232+ if (r <=0 )
233+ {
234+ if (errno == EINTR )
235+ continue ;/* Ok if interrupted */
236+ /* We would like to use elog() here, but dare not because elog
237+ * tries to write to the client, which will cause problems
238+ * if we have a hard communications failure ...
239+ * So just write the message to the postmaster log.
240+ */
241+ fprintf (stderr ,"pq_recvbuf: recv() failed, errno %d\n" ,errno );
242+ return EOF ;
243+ }
244+ /* r contains number of bytes read, so just incr length */
245+ PqRecvLength += r ;
246+ return 0 ;
247+ }
165248}
166249
167250/* --------------------------------
@@ -194,7 +277,7 @@ pq_getstr(char *s, int maxlen)
194277int
195278pq_getnchar (char * s ,int off ,int maxlen )
196279{
197- int r = pqGetNBytes (s + off ,maxlen );
280+ int r = pqGetNBytes (s + off ,maxlen );
198281s [off + maxlen ]= '\0' ;
199282return r ;
200283}
@@ -602,7 +685,7 @@ StreamConnection(int server_fd, Port *port)
602685if (setsockopt (port -> sock ,pe -> p_proto ,TCP_NODELAY ,
603686& on ,sizeof (on ))< 0 )
604687{
605- elog (ERROR ,"postmaster: setsockopt failed" );
688+ elog (ERROR ,"postmaster: setsockopt failed: %m " );
606689return STATUS_ERROR ;
607690}
608691}
@@ -644,18 +727,9 @@ pq_putncharlen(char *s, int n)
644727 */
645728int pq_putchar (char c )
646729{
647- char isDone = 0 ;
648-
649- do {
650- if (send (MyProcPort -> sock ,& c ,1 ,0 )!= 1 ) {
651- if (errno != EINTR )
652- return EOF ;/* Anything other than interrupt is error! */
653- }
654- else
655- isDone = 1 ;/* Done if we sent one char */
656- }while (!isDone );
657- return c ;
730+ if (PqSendPointer >=PQ_BUFFER_SIZE )
731+ if (pq_flush ())/* If buffer is full, then flush it out */
732+ return EOF ;
733+ PqSendBuffer [PqSendPointer ++ ]= c ;/* Put in buffer */
734+ return c ;
658735}
659-
660-
661-