diff options
Diffstat (limited to 'src/backend/libpq/pqpacket.c')
-rw-r--r-- | src/backend/libpq/pqpacket.c | 283 |
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; +} +*/ |