mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Second round of FE/BE protocol changes. Frontend->backend messages now
have length counts, and COPY IN data is packetized into messages.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.98 2003/04/17 22:26:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.99 2003/04/19 00:02:29 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
static void sendAuthRequest(Port *port, AuthRequest areq);
|
||||
static void auth_failed(Port *port, int status);
|
||||
static char *recv_password_packet(Port *port);
|
||||
static int recv_and_check_password_packet(Port *port);
|
||||
|
||||
char *pg_krb_server_keyfile;
|
||||
@@ -539,11 +540,9 @@ sendAuthRequest(Port *port, AuthRequest areq)
|
||||
*/
|
||||
|
||||
static int
|
||||
pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr)
|
||||
pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
|
||||
struct pam_response ** resp, void *appdata_ptr)
|
||||
{
|
||||
StringInfoData buf;
|
||||
int32 len;
|
||||
|
||||
if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
|
||||
{
|
||||
switch (msg[0]->msg_style)
|
||||
@@ -574,23 +573,20 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
|
||||
*/
|
||||
if (strlen(appdata_ptr) == 0)
|
||||
{
|
||||
char *passwd;
|
||||
|
||||
sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
|
||||
if (pq_eof() == EOF || pq_getint(&len, 4) == EOF)
|
||||
passwd = recv_password_packet(pam_port_cludge);
|
||||
|
||||
if (passwd == NULL)
|
||||
return PAM_CONV_ERR; /* client didn't want to send password */
|
||||
|
||||
initStringInfo(&buf);
|
||||
if (pq_getstr_bounded(&buf, 1000) == EOF)
|
||||
return PAM_CONV_ERR; /* EOF while reading password */
|
||||
|
||||
/* Do not echo failed password to logs, for security. */
|
||||
elog(DEBUG5, "received PAM packet");
|
||||
|
||||
if (strlen(buf.data) == 0)
|
||||
if (strlen(passwd) == 0)
|
||||
{
|
||||
elog(LOG, "pam_passwd_conv_proc: no password");
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
appdata_ptr = buf.data;
|
||||
appdata_ptr = passwd;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -601,8 +597,6 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
|
||||
if (!*resp)
|
||||
{
|
||||
elog(LOG, "pam_passwd_conv_proc: Out of memory!");
|
||||
if (buf.data)
|
||||
pfree(buf.data);
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
@@ -708,42 +702,87 @@ CheckPAMAuth(Port *port, char *user, char *password)
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have received the password packet.
|
||||
* Collect password response packet from frontend.
|
||||
*
|
||||
* Returns NULL if couldn't get password, else palloc'd string.
|
||||
*/
|
||||
static int
|
||||
recv_and_check_password_packet(Port *port)
|
||||
static char *
|
||||
recv_password_packet(Port *port)
|
||||
{
|
||||
StringInfoData buf;
|
||||
int32 len;
|
||||
int result;
|
||||
|
||||
if (pq_eof() == EOF || pq_getint(&len, 4) == EOF)
|
||||
return STATUS_EOF; /* client didn't want to send password */
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
|
||||
{
|
||||
/* Expect 'p' message type */
|
||||
int mtype;
|
||||
|
||||
mtype = pq_getbyte();
|
||||
if (mtype != 'p')
|
||||
{
|
||||
/*
|
||||
* If the client just disconnects without offering a password,
|
||||
* don't make a log entry. This is legal per protocol spec and
|
||||
* in fact commonly done by psql, so complaining just clutters
|
||||
* the log.
|
||||
*/
|
||||
if (mtype != EOF)
|
||||
elog(COMMERROR, "Expected password response, got %c", mtype);
|
||||
return NULL; /* EOF or bad message type */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For pre-3.0 clients, avoid log entry if they just disconnect */
|
||||
if (pq_peekbyte() == EOF)
|
||||
return NULL; /* EOF */
|
||||
}
|
||||
|
||||
initStringInfo(&buf);
|
||||
if (pq_getstr_bounded(&buf, 1000) == EOF) /* receive password */
|
||||
if (pq_getmessage(&buf, 1000)) /* receive password */
|
||||
{
|
||||
/* EOF - pq_getmessage already logged a suitable message */
|
||||
pfree(buf.data);
|
||||
return STATUS_EOF;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't actually use the password packet length the frontend sent
|
||||
* us; however, it's a reasonable sanity check to ensure that we
|
||||
* actually read as much data as we expected to.
|
||||
*
|
||||
* The password packet size is the length of the buffer, plus the size
|
||||
* field itself (4 bytes), plus a 1-byte terminator.
|
||||
* Apply sanity check: password packet length should agree with length
|
||||
* of contained string. Note it is safe to use strlen here because
|
||||
* StringInfo is guaranteed to have an appended '\0'.
|
||||
*/
|
||||
if (len != (buf.len + 4 + 1))
|
||||
elog(LOG, "unexpected password packet size: read %d, expected %d",
|
||||
buf.len + 4 + 1, len);
|
||||
if (strlen(buf.data) + 1 != buf.len)
|
||||
elog(COMMERROR, "bogus password packet size");
|
||||
|
||||
/* Do not echo password to logs, for security. */
|
||||
elog(DEBUG5, "received password packet");
|
||||
|
||||
result = md5_crypt_verify(port, port->user_name, buf.data);
|
||||
/*
|
||||
* Return the received string. Note we do not attempt to do any
|
||||
* character-set conversion on it; since we don't yet know the
|
||||
* client's encoding, there wouldn't be much point.
|
||||
*/
|
||||
return buf.data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have sent an authorization request for a password.
|
||||
* Get the response and check it.
|
||||
*/
|
||||
static int
|
||||
recv_and_check_password_packet(Port *port)
|
||||
{
|
||||
char *passwd;
|
||||
int result;
|
||||
|
||||
passwd = recv_password_packet(port);
|
||||
|
||||
if (passwd == NULL)
|
||||
return STATUS_EOF; /* client wouldn't send password */
|
||||
|
||||
result = md5_crypt_verify(port, port->user_name, passwd);
|
||||
|
||||
pfree(passwd);
|
||||
|
||||
pfree(buf.data);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.29 2003/04/10 23:03:08 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.30 2003/04/19 00:02:29 tgl Exp $
|
||||
*
|
||||
* Since the server static private key ($DataDir/server.key)
|
||||
* will normally be stored unencrypted so that the database
|
||||
@@ -110,13 +110,6 @@
|
||||
extern void ExitPostmaster(int);
|
||||
extern void postmaster_error(const char *fmt,...);
|
||||
|
||||
int secure_initialize(void);
|
||||
void secure_destroy(void);
|
||||
int secure_open_server(Port *);
|
||||
void secure_close(Port *);
|
||||
ssize_t secure_read(Port *, void *ptr, size_t len);
|
||||
ssize_t secure_write(Port *, void *ptr, size_t len);
|
||||
|
||||
#ifdef USE_SSL
|
||||
static DH *load_dh_file(int keylength);
|
||||
static DH *load_dh_buffer(const char *, size_t);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* These routines handle the low-level details of communication between
|
||||
* frontend and backend. They just shove data across the communication
|
||||
* channel, and are ignorant of the semantics of the data --- or would be,
|
||||
* except for major brain damage in the design of the COPY OUT protocol.
|
||||
* Unfortunately, COPY OUT is designed to commandeer the communication
|
||||
* except for major brain damage in the design of the old COPY OUT protocol.
|
||||
* Unfortunately, COPY OUT was designed to commandeer the communication
|
||||
* channel (it just transfers data without wrapping it into messages).
|
||||
* No other messages can be sent while COPY OUT is in progress; and if the
|
||||
* copy is aborted by an elog(ERROR), we need to close out the copy so that
|
||||
@@ -29,7 +29,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.c,v 1.149 2003/04/02 00:49:28 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.150 2003/04/19 00:02:29 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -48,12 +48,13 @@
|
||||
* low-level I/O:
|
||||
* pq_getbytes - get a known number of bytes from connection
|
||||
* pq_getstring - get a null terminated string from connection
|
||||
* pq_getmessage - get a message with length word from connection
|
||||
* pq_getbyte - get next byte from connection
|
||||
* pq_peekbyte - peek at next byte from connection
|
||||
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
||||
* pq_flush - flush pending output
|
||||
*
|
||||
* message-level I/O (and COPY OUT cruft):
|
||||
* message-level I/O (and old-style-COPY-OUT cruft):
|
||||
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
|
||||
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
||||
* pq_endcopyout - end a COPY OUT transfer
|
||||
@@ -85,9 +86,6 @@
|
||||
#include "miscadmin.h"
|
||||
#include "storage/ipc.h"
|
||||
|
||||
extern void secure_close(Port *);
|
||||
extern ssize_t secure_read(Port *, void *, size_t);
|
||||
extern ssize_t secure_write(Port *, const void *, size_t);
|
||||
|
||||
static void pq_close(void);
|
||||
|
||||
@@ -562,8 +560,10 @@ pq_recvbuf(void)
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
/* as above, only write to postmaster log */
|
||||
elog(COMMERROR, "pq_recvbuf: unexpected EOF on client connection");
|
||||
/*
|
||||
* EOF detected. We used to write a log message here, but it's
|
||||
* better to expect the ultimate caller to do that.
|
||||
*/
|
||||
return EOF;
|
||||
}
|
||||
/* r contains number of bytes read, so just incr length */
|
||||
@@ -636,35 +636,29 @@ pq_getbytes(char *s, size_t len)
|
||||
/* --------------------------------
|
||||
* pq_getstring - get a null terminated string from connection
|
||||
*
|
||||
* The return value is placed in an expansible StringInfo.
|
||||
* Note that space allocation comes from the current memory context!
|
||||
* The return value is placed in an expansible StringInfo, which has
|
||||
* already been initialized by the caller.
|
||||
*
|
||||
* If maxlen is not zero, it is an upper limit on the length of the
|
||||
* string we are willing to accept. We abort the connection (by
|
||||
* returning EOF) if client tries to send more than that. Note that
|
||||
* since we test maxlen in the outer per-bufferload loop, the limit
|
||||
* is fuzzy: we might accept up to PQ_BUFFER_SIZE more bytes than
|
||||
* specified. This is fine for the intended purpose, which is just
|
||||
* to prevent DoS attacks from not-yet-authenticated clients.
|
||||
*
|
||||
* NOTE: this routine does not do any character set conversion,
|
||||
* even though it is presumably useful only for text, because
|
||||
* no code in this module should depend on the encoding.
|
||||
* See pq_getstr_bounded in pqformat.c for that.
|
||||
* This is used only for dealing with old-protocol clients. The idea
|
||||
* is to produce a StringInfo that looks the same as we would get from
|
||||
* pq_getmessage() with a newer client; we will then process it with
|
||||
* pq_getmsgstring. Therefore, no character set conversion is done here,
|
||||
* even though this is presumably useful only for text.
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getstring(StringInfo s, int maxlen)
|
||||
pq_getstring(StringInfo s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Reset string to empty */
|
||||
s->len = 0;
|
||||
s->data[0] = '\0';
|
||||
s->cursor = 0;
|
||||
|
||||
/* Read until we get the terminating '\0' or overrun maxlen */
|
||||
/* Read until we get the terminating '\0' */
|
||||
for (;;)
|
||||
{
|
||||
while (PqRecvPointer >= PqRecvLength)
|
||||
@@ -677,9 +671,9 @@ pq_getstring(StringInfo s, int maxlen)
|
||||
{
|
||||
if (PqRecvBuffer[i] == '\0')
|
||||
{
|
||||
/* does not copy the \0 */
|
||||
/* include the '\0' in the copy */
|
||||
appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
|
||||
i - PqRecvPointer);
|
||||
i - PqRecvPointer + 1);
|
||||
PqRecvPointer = i + 1; /* advance past \0 */
|
||||
return 0;
|
||||
}
|
||||
@@ -689,14 +683,73 @@ pq_getstring(StringInfo s, int maxlen)
|
||||
appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
|
||||
PqRecvLength - PqRecvPointer);
|
||||
PqRecvPointer = PqRecvLength;
|
||||
|
||||
/* If maxlen is specified, check for overlength input. */
|
||||
if (maxlen > 0 && s->len > maxlen)
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getmessage - get a message with length word from connection
|
||||
*
|
||||
* The return value is placed in an expansible StringInfo, which has
|
||||
* already been initialized by the caller.
|
||||
* Only the message body is placed in the StringInfo; the length word
|
||||
* is removed. Also, s->cursor is initialized to zero for convenience
|
||||
* in scanning the message contents.
|
||||
*
|
||||
* If maxlen is not zero, it is an upper limit on the length of the
|
||||
* message we are willing to accept. We abort the connection (by
|
||||
* returning EOF) if client tries to send more than that.
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getmessage(StringInfo s, int maxlen)
|
||||
{
|
||||
int32 len;
|
||||
|
||||
/* Reset message buffer to empty */
|
||||
s->len = 0;
|
||||
s->data[0] = '\0';
|
||||
s->cursor = 0;
|
||||
|
||||
/* Read message length word */
|
||||
if (pq_getbytes((char *) &len, 4) == EOF)
|
||||
{
|
||||
elog(COMMERROR, "unexpected EOF within message length word");
|
||||
return EOF;
|
||||
}
|
||||
|
||||
len = ntohl(len);
|
||||
len -= 4; /* discount length itself */
|
||||
|
||||
if (len < 0 ||
|
||||
(maxlen > 0 && len > maxlen))
|
||||
{
|
||||
elog(COMMERROR, "invalid message length");
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* Allocate space for message */
|
||||
enlargeStringInfo(s, len);
|
||||
|
||||
/* And grab the message */
|
||||
if (pq_getbytes(s->data, len) == EOF)
|
||||
{
|
||||
elog(COMMERROR, "incomplete client message");
|
||||
return EOF;
|
||||
}
|
||||
s->len = len;
|
||||
/* Place a trailing null per StringInfo convention */
|
||||
s->data[len] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
||||
*
|
||||
@@ -781,34 +834,10 @@ pq_flush(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return EOF if the connection has been broken, else 0.
|
||||
*/
|
||||
int
|
||||
pq_eof(void)
|
||||
{
|
||||
char x;
|
||||
int res;
|
||||
|
||||
res = recv(MyProcPort->sock, &x, 1, MSG_PEEK);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
/* can log to postmaster log only */
|
||||
elog(COMMERROR, "pq_eof: recv() failed: %m");
|
||||
return EOF;
|
||||
}
|
||||
if (res == 0)
|
||||
return EOF;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* Message-level I/O routines begin here.
|
||||
*
|
||||
* These routines understand about COPY OUT protocol.
|
||||
* These routines understand about the old-style COPY OUT protocol.
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
@@ -840,7 +869,8 @@ pq_putmessage(char msgtype, const char *s, size_t len)
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
||||
* pq_startcopyout - inform libpq that an old-style COPY OUT transfer
|
||||
* is beginning
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
|
||||
@@ -8,15 +8,17 @@
|
||||
* formatting/conversion routines that are needed to produce valid messages.
|
||||
* Note in particular the distinction between "raw data" and "text"; raw data
|
||||
* is message protocol characters and binary values that are not subject to
|
||||
* character set conversion, while text is converted by character encoding rules.
|
||||
* character set conversion, while text is converted by character encoding
|
||||
* rules.
|
||||
*
|
||||
* Incoming messages are read directly off the wire, as it were, but there
|
||||
* are still data-conversion tasks to be performed.
|
||||
* Incoming messages are similarly read into a StringInfo buffer, via
|
||||
* pq_getmessage, and then parsed and converted from that using the routines
|
||||
* in this module.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqformat.c,v 1.26 2003/04/02 00:49:28 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.27 2003/04/19 00:02:29 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,12 +39,13 @@
|
||||
* Special-case message output:
|
||||
* pq_puttextmessage - generate a character set-converted message in one step
|
||||
*
|
||||
* Message input:
|
||||
* pq_getint - get an integer from connection
|
||||
* pq_getstr_bounded - get a null terminated string from connection
|
||||
* pq_getstr_bounded performs character set conversion on the collected
|
||||
* string. Use the raw pqcomm.c routines pq_getstring or pq_getbytes
|
||||
* to fetch data without conversion.
|
||||
* Message parsing after input:
|
||||
* pq_getmsgbyte - get a raw byte from a message buffer
|
||||
* pq_getmsgint - get a binary integer from a message buffer
|
||||
* pq_getmsgbytes - get raw data from a message buffer
|
||||
* pq_copymsgbytes - copy raw data from a message buffer
|
||||
* pq_getmsgstring - get a null-terminated text string (with conversion)
|
||||
* pq_getmsgend - verify message fully consumed
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
@@ -206,16 +209,29 @@ pq_puttextmessage(char msgtype, const char *str)
|
||||
return pq_putmessage(msgtype, str, slen + 1);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getint - get an integer from connection
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* pq_getmsgbyte - get a raw byte from a message buffer
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getint(int *result, int b)
|
||||
pq_getmsgbyte(StringInfo msg)
|
||||
{
|
||||
int status;
|
||||
if (msg->cursor >= msg->len)
|
||||
elog(ERROR, "pq_getmsgbyte: no data left in message");
|
||||
return (unsigned char) msg->data[msg->cursor++];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getmsgint - get a binary integer from a message buffer
|
||||
*
|
||||
* Values are treated as unsigned.
|
||||
* --------------------------------
|
||||
*/
|
||||
unsigned int
|
||||
pq_getmsgint(StringInfo msg, int b)
|
||||
{
|
||||
unsigned int result;
|
||||
unsigned char n8;
|
||||
uint16 n16;
|
||||
uint32 n32;
|
||||
@@ -223,59 +239,93 @@ pq_getint(int *result, int b)
|
||||
switch (b)
|
||||
{
|
||||
case 1:
|
||||
status = pq_getbytes((char *) &n8, 1);
|
||||
*result = (int) n8;
|
||||
pq_copymsgbytes(msg, (char *) &n8, 1);
|
||||
result = n8;
|
||||
break;
|
||||
case 2:
|
||||
status = pq_getbytes((char *) &n16, 2);
|
||||
*result = (int) (ntohs(n16));
|
||||
pq_copymsgbytes(msg, (char *) &n16, 2);
|
||||
result = ntohs(n16);
|
||||
break;
|
||||
case 4:
|
||||
status = pq_getbytes((char *) &n32, 4);
|
||||
*result = (int) (ntohl(n32));
|
||||
pq_copymsgbytes(msg, (char *) &n32, 4);
|
||||
result = ntohl(n32);
|
||||
break;
|
||||
default:
|
||||
|
||||
/*
|
||||
* if we elog(ERROR) here, we will lose sync with the
|
||||
* frontend, so just complain to postmaster log instead...
|
||||
*/
|
||||
elog(COMMERROR, "pq_getint: unsupported size %d", b);
|
||||
status = EOF;
|
||||
*result = 0;
|
||||
elog(ERROR, "pq_getmsgint: unsupported size %d", b);
|
||||
result = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getstr_bounded - get a null terminated string from connection
|
||||
* pq_getmsgbytes - get raw data from a message buffer
|
||||
*
|
||||
* The return value is placed in an expansible StringInfo.
|
||||
* Note that space allocation comes from the current memory context!
|
||||
*
|
||||
* The maxlen parameter is interpreted as per pq_getstring.
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* Returns a pointer directly into the message buffer; note this
|
||||
* may not have any particular alignment.
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getstr_bounded(StringInfo s, int maxlen)
|
||||
const char *
|
||||
pq_getmsgbytes(StringInfo msg, int datalen)
|
||||
{
|
||||
int result;
|
||||
char *p;
|
||||
|
||||
result = pq_getstring(s, maxlen);
|
||||
|
||||
p = (char *) pg_client_to_server((unsigned char *) s->data, s->len);
|
||||
if (p != s->data) /* actual conversion has been done? */
|
||||
{
|
||||
/* reset s to empty, and append the new string p */
|
||||
s->len = 0;
|
||||
s->data[0] = '\0';
|
||||
appendBinaryStringInfo(s, p, strlen(p));
|
||||
pfree(p);
|
||||
}
|
||||
const char *result;
|
||||
|
||||
if (datalen > (msg->len - msg->cursor))
|
||||
elog(ERROR, "pq_getmsgbytes: insufficient data left in message");
|
||||
result = &msg->data[msg->cursor];
|
||||
msg->cursor += datalen;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_copymsgbytes - copy raw data from a message buffer
|
||||
*
|
||||
* Same as above, except data is copied to caller's buffer.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
|
||||
{
|
||||
if (datalen > (msg->len - msg->cursor))
|
||||
elog(ERROR, "pq_copymsgbytes: insufficient data left in message");
|
||||
memcpy(buf, &msg->data[msg->cursor], datalen);
|
||||
msg->cursor += datalen;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getmsgstring - get a null-terminated text string (with conversion)
|
||||
*
|
||||
* May return a pointer directly into the message buffer, or a pointer
|
||||
* to a palloc'd conversion result.
|
||||
* --------------------------------
|
||||
*/
|
||||
const char *
|
||||
pq_getmsgstring(StringInfo msg)
|
||||
{
|
||||
char *str;
|
||||
int slen;
|
||||
|
||||
str = &msg->data[msg->cursor];
|
||||
/*
|
||||
* It's safe to use strlen() here because a StringInfo is guaranteed
|
||||
* to have a trailing null byte. But check we found a null inside
|
||||
* the message.
|
||||
*/
|
||||
slen = strlen(str);
|
||||
if (msg->cursor + slen >= msg->len)
|
||||
elog(ERROR, "pq_getmsgstring: invalid string in message");
|
||||
msg->cursor += slen + 1;
|
||||
|
||||
return (const char *) pg_client_to_server((unsigned char *) str, slen);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getmsgend - verify message fully consumed
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_getmsgend(StringInfo msg)
|
||||
{
|
||||
if (msg->cursor != msg->len)
|
||||
elog(ERROR, "pq_getmsgend: invalid message format");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user