5
5
*
6
6
* Copyright (c) 1994, Regents of the University of California
7
7
*
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 $
9
9
*
10
10
*-------------------------------------------------------------------------
11
11
*/
12
12
/*
13
13
* INTERFACE ROUTINES
14
- * pq_init - initialize libpq
14
+ * pq_init - initialize libpq
15
15
*pq_getport- return the PGPORT setting
16
16
*pq_close- close input / output connections
17
17
*pq_flush- flush pending output
18
+ *pq_recvbuf- load some bytes into the input buffer
18
19
*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
21
22
*pq_getnchar- get n characters from connection, and null-terminate
22
23
*pq_getint- get an integer from connection
23
- * pq_putchar - send 1 character to connection
24
+ * pq_putchar - send 1 character to connection
24
25
*pq_putstr- send a null terminated string to connection
25
26
*pq_putnchar- send n characters to connection
26
27
*pq_putint- send an integer to connection
27
- *pq_putncharlen - send n characters to connection
28
+ *pq_putncharlen- send n characters to connection
28
29
* (also send an int header indicating
29
30
* the length)
30
31
*pq_getinaddr- initialize address from host and port number
31
32
*pq_getinserv- initialize address from host and service name
32
33
*
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
37
38
*
38
39
* 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 .
41
42
*
42
43
*/
43
44
#include "postgres.h"
79
80
80
81
extern FILE * debug_port ;/* in util.c */
81
82
83
+ /*
84
+ * Buffers
85
+ */
86
+ char PqSendBuffer [PQ_BUFFER_SIZE ];
87
+ char PqRecvBuffer [PQ_BUFFER_SIZE ];
88
+ int PqSendPointer ,PqRecvPointer ,PqRecvLength ;
89
+
90
+
82
91
/* --------------------------------
83
92
*pq_init - open portal file descriptors
84
93
* --------------------------------
85
94
*/
86
95
void
87
96
pq_init (int fd )
88
97
{
98
+ PqSendPointer = PqRecvPointer = PqRecvLength = 0 ;
89
99
PQnotifies_init ();
90
100
if (getenv ("LIBPQ_DEBUG" ))
91
101
debug_port = stderr ;
@@ -94,40 +104,40 @@ pq_init(int fd)
94
104
/* -------------------------
95
105
* pq_getchar()
96
106
*
97
- * get a character from the input file,
98
- *
107
+ * get a character from the input file, or EOF if trouble
108
+ * --------------------------------
99
109
*/
100
110
101
111
int
102
112
pq_getchar (void )
103
113
{
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 */
109
118
}
110
-
111
- return c ;
119
+ return PqRecvBuffer [PqRecvPointer ++ ];
112
120
}
113
121
114
- /*
122
+ /* -------------------------
123
+ * pq_peekchar()
124
+ *
125
+ * get a character from the connection, but leave it in the buffer
126
+ * to be read again
115
127
* --------------------------------
116
- * pq_peekchar - get 1 character from connection, but leave it in the stream
117
128
*/
118
- int
119
- pq_peekchar (void ) {
120
- char c ;
121
129
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 */
125
137
}
126
-
127
- return c ;
138
+ /* Note we don't bump the pointer... */
139
+ return PqRecvBuffer [ PqRecvPointer ] ;
128
140
}
129
-
130
-
131
141
132
142
/* --------------------------------
133
143
*pq_getport - return the PGPORT setting
@@ -150,18 +160,91 @@ pq_getport()
150
160
void
151
161
pq_close ()
152
162
{
153
- close (MyProcPort -> sock );
163
+ close (MyProcPort -> sock );
154
164
PQnotifies_init ();
155
165
}
156
166
157
167
/* --------------------------------
158
168
*pq_flush - flush pending output
169
+ *
170
+ *returns 0 if OK, EOF if trouble
159
171
* --------------------------------
160
172
*/
161
- void
173
+ int
162
174
pq_flush ()
163
175
{
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
+ }
165
248
}
166
249
167
250
/* --------------------------------
@@ -194,7 +277,7 @@ pq_getstr(char *s, int maxlen)
194
277
int
195
278
pq_getnchar (char * s ,int off ,int maxlen )
196
279
{
197
- int r = pqGetNBytes (s + off ,maxlen );
280
+ int r = pqGetNBytes (s + off ,maxlen );
198
281
s [off + maxlen ]= '\0' ;
199
282
return r ;
200
283
}
@@ -602,7 +685,7 @@ StreamConnection(int server_fd, Port *port)
602
685
if (setsockopt (port -> sock ,pe -> p_proto ,TCP_NODELAY ,
603
686
& on ,sizeof (on ))< 0 )
604
687
{
605
- elog (ERROR ,"postmaster: setsockopt failed" );
688
+ elog (ERROR ,"postmaster: setsockopt failed: %m " );
606
689
return STATUS_ERROR ;
607
690
}
608
691
}
@@ -644,18 +727,9 @@ pq_putncharlen(char *s, int n)
644
727
*/
645
728
int pq_putchar (char c )
646
729
{
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 ;
658
735
}
659
-
660
-
661
-