aboutsummaryrefslogtreecommitdiff
path: root/src/backend/libpq/pqpacket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libpq/pqpacket.c')
-rw-r--r--src/backend/libpq/pqpacket.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/src/backend/libpq/pqpacket.c b/src/backend/libpq/pqpacket.c
new file mode 100644
index 00000000000..edf373d1afb
--- /dev/null
+++ b/src/backend/libpq/pqpacket.c
@@ -0,0 +1,283 @@
+/*-------------------------------------------------------------------------
+ *
+ * pqpacket.c--
+ * routines for reading and writing data packets sent/received by
+ * POSTGRES clients and servers
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/* NOTES
+ * This is the module that understands the lowest-level part
+ * of the communication protocol. All of the trickiness in
+ * this module is for making sure that non-blocking I/O in
+ * the Postmaster works correctly. Check the notes in PacketRecv
+ * on non-blocking I/O.
+ *
+ * Data Structures:
+ * Port has two important functions. (1) It records the
+ * sock/addr used in communication. (2) It holds partially
+ * read in messages. This is especially important when
+ * we haven't seen enough to construct a complete packet
+ * header.
+ *
+ * PacketBuf -- None of the clients of this module should know
+ * what goes into a packet hdr (although they know how big
+ * it is). This routine is in charge of host to net order
+ * conversion for headers. Data conversion is someone elses
+ * responsibility.
+ *
+ * IMPORTANT: these routines are called by backends, clients, and
+ * the Postmaster.
+ *
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#else
+#include <winsock.h>
+#endif /*WIN32 */
+#include <fcntl.h>
+#include <errno.h>
+
+#include "postgres.h"
+#include "miscadmin.h"
+#include "utils/elog.h"
+#include "storage/ipc.h"
+#include "libpq/pqcomm.h" /* where the declarations go */
+#include "libpq/libpq.h"
+
+/*
+ * PacketReceive -- receive a packet on a port.
+ *
+ * RETURNS: connection id of the packet sender, if one
+ * is available.
+ *
+ */
+int
+PacketReceive(Port *port, /* receive port */
+ PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
+ bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
+{
+ PacketLen max_size = sizeof(PacketBuf);
+ PacketLen cc; /* character count -- bytes recvd */
+ PacketLen packetLen; /* remaining packet chars to read */
+ Addr tmp; /* curr recv buf pointer */
+ int addrLen = sizeof(struct sockaddr_in);
+ int hdrLen;
+ int flag;
+ int decr;
+
+ hdrLen = sizeof(buf->len);
+
+ if (nonBlocking == NON_BLOCKING) {
+ flag = MSG_PEEK;
+ decr = 0;
+ } else {
+ flag = 0;
+ decr = hdrLen;
+ }
+ /*
+ * Assume port->nBytes is zero unless we were interrupted during
+ * non-blocking I/O. This first recvfrom() is to get the hdr
+ * information so we know how many bytes to read. Life would
+ * be very complicated if we read too much data (buffering).
+ */
+ tmp = ((Addr)buf) + port->nBytes;
+
+ if (port->nBytes >= hdrLen) {
+ packetLen = ntohl(buf->len) - port->nBytes;
+ }
+ else {
+ /* peeking into the incoming message */
+ cc = recvfrom(port->sock, (char *)&(buf->len), hdrLen, flag,
+ (struct sockaddr*) &(port->raddr), &addrLen);
+ if (cc < hdrLen) {
+ /* if cc is negative, the system call failed */
+ if (cc < 0) {
+ return(STATUS_ERROR);
+ }
+ /*
+ * cc == 0 means the connection was broken at the
+ * other end.
+ */
+ else if (! cc) {
+ return(STATUS_INVALID);
+
+ } else {
+ /*
+ * Worst case. We didn't even read in enough data to
+ * get the header length.
+ * since we are using a data stream,
+ * this happens only if the client is mallicious.
+ *
+ * Don't save the number of bytes we've read so far.
+ * Since we only peeked at the incoming message, the
+ * kernel is going to keep it for us.
+ */
+ return(STATUS_NOT_DONE);
+ }
+ } else {
+ /*
+ * great. got the header. now get the true length (including
+ * header size).
+ */
+ packetLen = ntohl(buf->len);
+ /*
+ * if someone is sending us junk, close the connection
+ */
+ if (packetLen > max_size) {
+ port->nBytes = packetLen;
+ return(STATUS_BAD_PACKET);
+ }
+ packetLen -= decr;
+ tmp += decr - port->nBytes;
+ }
+ }
+
+ /*
+ * Now that we know how big it is, read the packet. We read
+ * the entire packet, since the last call was just a peek.
+ */
+ while (packetLen) {
+ cc = recvfrom(port->sock, tmp, packetLen, 0,
+ (struct sockaddr*) &(port->raddr), &addrLen);
+ if (cc < 0)
+ return(STATUS_ERROR);
+ /*
+ * cc == 0 means the connection was broken at the
+ * other end.
+ */
+ else if (! cc)
+ return(STATUS_INVALID);
+
+/*
+ fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
+ packetLen, cc);
+*/
+ tmp += cc;
+ packetLen -= cc;
+
+ /* if non-blocking, we're done. */
+ if (nonBlocking && packetLen) {
+ port->nBytes += cc;
+ return(STATUS_NOT_DONE);
+ }
+ }
+
+ port->nBytes = 0;
+ return(STATUS_OK);
+}
+
+/*
+ * PacketSend -- send a single-packet message.
+ *
+ * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
+ * SIDE_EFFECTS: may block.
+ * NOTES: Non-blocking writes would significantly complicate
+ * buffer management. For now, we're not going to do it.
+ *
+ */
+int
+PacketSend(Port *port,
+ PacketBuf *buf,
+ PacketLen len,
+ bool nonBlocking)
+{
+ PacketLen totalLen;
+ int addrLen = sizeof(struct sockaddr_in);
+
+ Assert(!nonBlocking);
+ Assert(buf);
+
+ totalLen = len;
+
+ len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
+ (struct sockaddr *)&(port->raddr), addrLen);
+
+ if (len < totalLen) {
+ (void) sprintf(PQerrormsg,
+ "FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ return(STATUS_ERROR);
+ }
+
+ return(STATUS_OK);
+}
+
+/*
+ * StartupInfo2PacketBuf -
+ * convert the fields of the StartupInfo to a PacketBuf
+ *
+ */
+/* moved to src/libpq/fe-connect.c */
+/*
+PacketBuf*
+StartupInfo2PacketBuf(StartupInfo* s)
+{
+ PacketBuf* res;
+ char* tmp;
+
+ res = (PacketBuf*)malloc(sizeof(PacketBuf));
+ res->len = htonl(sizeof(PacketBuf));
+ res->data[0] = '\0';
+
+ tmp= res->data;
+
+ strncpy(tmp, s->database, sizeof(s->database));
+ tmp += sizeof(s->database);
+ strncpy(tmp, s->user, sizeof(s->user));
+ tmp += sizeof(s->user);
+ strncpy(tmp, s->options, sizeof(s->options));
+ tmp += sizeof(s->options);
+ strncpy(tmp, s->execFile, sizeof(s->execFile));
+ tmp += sizeof(s->execFile);
+ strncpy(tmp, s->tty, sizeof(s->execFile));
+
+ return res;
+}
+*/
+
+/*
+ * PacketBuf2StartupInfo -
+ * convert the fields of the StartupInfo to a PacketBuf
+ *
+ */
+/* moved to postmaster.c
+StartupInfo*
+PacketBuf2StartupInfo(PacketBuf* p)
+{
+ StartupInfo* res;
+ char* tmp;
+
+ res = (StartupInfo*)malloc(sizeof(StartupInfo));
+
+ res->database[0]='\0';
+ res->user[0]='\0';
+ res->options[0]='\0';
+ res->execFile[0]='\0';
+ res->tty[0]='\0';
+
+ tmp= p->data;
+ strncpy(res->database,tmp,sizeof(res->database));
+ tmp += sizeof(res->database);
+ strncpy(res->user,tmp, sizeof(res->user));
+ tmp += sizeof(res->user);
+ strncpy(res->options,tmp, sizeof(res->options));
+ tmp += sizeof(res->options);
+ strncpy(res->execFile,tmp, sizeof(res->execFile));
+ tmp += sizeof(res->execFile);
+ strncpy(res->tty,tmp, sizeof(res->tty));
+
+ return res;
+}
+*/