209 lines
4.0 KiB
C
209 lines
4.0 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* pqpacket.c
|
|
* routines for reading and writing data packets sent/received by
|
|
* POSTGRES clients and servers
|
|
*
|
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.26 2000/04/12 17:15:14 momjian Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include "postgres.h"
|
|
#include "libpq/libpq.h"
|
|
|
|
|
|
/*
|
|
* Set up a packet read for the postmaster event loop.
|
|
*/
|
|
|
|
void
|
|
PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg)
|
|
{
|
|
pkt->nrtodo = sizeof(pkt->len);
|
|
pkt->ptr = (char *) &pkt->len;
|
|
pkt->iodone = iodone;
|
|
pkt->arg = arg;
|
|
pkt->state = ReadingPacketLength;
|
|
|
|
/* Clear the destination. */
|
|
|
|
MemSet(&pkt->pkt, 0, sizeof(pkt->pkt));
|
|
}
|
|
|
|
|
|
/*
|
|
* Read a packet fragment. Return STATUS_OK if the connection should stay
|
|
* open.
|
|
*/
|
|
|
|
int
|
|
PacketReceiveFragment(Port *port)
|
|
{
|
|
int got;
|
|
Packet *pkt = &port->pktInfo;
|
|
|
|
#ifdef USE_SSL
|
|
if (port->ssl)
|
|
got = SSL_read(port->ssl, pkt->ptr, pkt->nrtodo);
|
|
else
|
|
#endif
|
|
got = read(port->sock, pkt->ptr, pkt->nrtodo);
|
|
if (got > 0)
|
|
{
|
|
pkt->nrtodo -= got;
|
|
pkt->ptr += got;
|
|
|
|
/* See if we have got what we need for the packet length. */
|
|
|
|
if (pkt->nrtodo == 0 && pkt->state == ReadingPacketLength)
|
|
{
|
|
pkt->len = ntohl(pkt->len);
|
|
|
|
if (pkt->len < sizeof(pkt->len) ||
|
|
pkt->len > sizeof(pkt->len) + sizeof(pkt->pkt))
|
|
{
|
|
PacketSendError(pkt, "Invalid packet length");
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
/* Set up for the rest of the packet. */
|
|
|
|
pkt->nrtodo = pkt->len - sizeof(pkt->len);
|
|
pkt->ptr = (char *) &pkt->pkt;
|
|
pkt->state = ReadingPacket;
|
|
}
|
|
|
|
/* See if we have got what we need for the packet. */
|
|
|
|
if (pkt->nrtodo == 0 && pkt->state == ReadingPacket)
|
|
{
|
|
pkt->state = Idle;
|
|
|
|
/* Special case to close the connection. */
|
|
|
|
if (pkt->iodone == NULL)
|
|
return STATUS_ERROR;
|
|
|
|
return (*pkt->iodone) (pkt->arg, pkt->len - sizeof(pkt->len),
|
|
(void *) &pkt->pkt);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (got == 0)
|
|
return STATUS_ERROR;
|
|
|
|
if (errno == EINTR)
|
|
return STATUS_OK;
|
|
|
|
perror("PacketReceiveFragment: read() failed");
|
|
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set up a packet write for the postmaster event loop.
|
|
*/
|
|
|
|
void
|
|
PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg)
|
|
{
|
|
pkt->len = (PacketLen) nbytes;
|
|
pkt->nrtodo = nbytes;
|
|
pkt->ptr = (char *) &pkt->pkt;
|
|
pkt->iodone = iodone;
|
|
pkt->arg = arg;
|
|
pkt->state = WritingPacket;
|
|
}
|
|
|
|
|
|
/*
|
|
* Write a packet fragment. Return STATUS_OK if the connection should stay
|
|
* open.
|
|
*/
|
|
|
|
int
|
|
PacketSendFragment(Port *port)
|
|
{
|
|
int done;
|
|
Packet *pkt = &port->pktInfo;
|
|
|
|
#ifdef USE_SSL
|
|
if (port->ssl)
|
|
done = SSL_write(port->ssl, pkt->ptr, pkt->nrtodo);
|
|
else
|
|
#endif
|
|
done = write(port->sock, pkt->ptr, pkt->nrtodo);
|
|
|
|
if (done > 0)
|
|
{
|
|
pkt->nrtodo -= done;
|
|
pkt->ptr += done;
|
|
|
|
/* See if we have written the whole packet. */
|
|
|
|
if (pkt->nrtodo == 0)
|
|
{
|
|
pkt->state = Idle;
|
|
|
|
/* Special case to close the connection. */
|
|
|
|
if (pkt->iodone == NULL)
|
|
return STATUS_ERROR;
|
|
|
|
return (*pkt->iodone) (pkt->arg, pkt->len,
|
|
(void *) &pkt->pkt);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (done == 0)
|
|
return STATUS_ERROR;
|
|
|
|
if (errno == EINTR)
|
|
return STATUS_OK;
|
|
|
|
perror("PacketSendFragment: write() failed");
|
|
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Send an error message from the postmaster to the frontend.
|
|
*/
|
|
|
|
void
|
|
PacketSendError(Packet *pkt, char *errormsg)
|
|
{
|
|
fprintf(stderr, "%s\n", errormsg);
|
|
|
|
pkt->pkt.em.data[0] = 'E';
|
|
StrNCpy(&pkt->pkt.em.data[1], errormsg, sizeof(pkt->pkt.em.data) - 1);
|
|
|
|
/*
|
|
* The NULL i/o callback will cause the connection to be broken when
|
|
* the error message has been sent.
|
|
*/
|
|
|
|
PacketSendSetup(pkt, strlen(pkt->pkt.em.data) + 1, NULL, NULL);
|
|
}
|