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 at first character in connection
20
+ * pq_getchar - get 1 character from connection
21
+ * pq_peekchar - peek at next character from 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 socket connectioin
34
- * StreamServerPort - Open sock stream
35
- * StreamConnection - Create new connection with client
36
- * StreamClose - Close a client/backend connection
34
+ * StreamDoUnlink - Shutdown UNIX socket connection
35
+ * StreamServerPort - Open socket stream
36
+ * StreamConnection - Create new connection with client
37
+ * StreamClose - Close a client/backend connection
37
38
*
38
39
* NOTES
39
- * Frontend is now completey in interfaces/libpq, and no
40
- * functions from this file is used.
40
+ * Frontend is now completely in interfaces/libpq, and no
41
+ * functions from this file are 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
-
0 commit comments