1 /*-------------------------------------------------------------------------
4 * Communication functions between the Frontend and the Backend
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.34 1998/01/25 05:13:18 momjian Exp $
12 *-------------------------------------------------------------------------
16 * pq_gettty - return the name of the tty in the given buffer
17 * pq_getport - return the PGPORT setting
18 * pq_close - close input / output connections
19 * pq_flush - flush pending output
20 * pq_getstr - get a null terminated string from connection
21 * pq_getnchar - get n characters from connection
22 * pq_getint - get an integer from connection
23 * pq_putstr - send a null terminated string to connection
24 * pq_putnchar - send n characters to connection
25 * pq_putint - send an integer to connection
26 * pq_getinaddr - initialize address from host and port number
27 * pq_getinserv - initialize address from host and service name
28 * pq_connect - create remote input / output connection
29 * pq_accept - accept remote input / output connection
30 * pq_async_notify - receive notification from backend.
33 * These functions are used by both frontend applications and
34 * the postgres backend.
42 #include <unistd.h> /* for ttyname() */
43 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <netinet/tcp.h>
49 #include <arpa/inet.h>
53 #define SOMAXCONN 5 /* from Linux listen(2) man page */
54 #endif /* SOMAXCONN */
59 #include <miscadmin.h>
60 #include <libpq/pqsignal.h>
61 #include <libpq/auth.h>
62 #include <libpq/libpq.h> /* where the declarations go */
63 #include <storage/ipc.h>
71 FILE *Pfdebug; /* debugging libpq */
72 int PQAsyncNotifyWaiting; /* for async. notification */
74 /* --------------------------------
75 * pq_init - open portal file descriptors
76 * --------------------------------
81 Pfin = fdopen(fd, "r");
82 Pfout = fdopen(dup(fd), "w");
84 elog(FATAL, "pq_init: Couldn't initialize socket connection");
86 if (getenv("LIBPQ_DEBUG"))
96 /* -------------------------
99 * get a character from the input file,
101 * if Pfdebug is set, also echo the character fetched into Pfdebug
103 * used for debugging libpq
111 if (Pfdebug && c != EOF)
116 /* --------------------------------
117 * pq_gettty - return the name of the tty in the given buffer
118 * --------------------------------
123 strncpy(tp, ttyname(0), 19);
126 /* --------------------------------
127 * pq_getport - return the PGPORT setting
128 * --------------------------------
133 char *envport = getenv("PGPORT");
136 return (atoi(envport));
137 return (atoi(DEF_PGPORT));
140 /* --------------------------------
141 * pq_close - close input / output connections
142 * --------------------------------
157 PQAsyncNotifyWaiting = 0;
162 /* --------------------------------
163 * pq_flush - flush pending output
164 * --------------------------------
173 /* --------------------------------
174 * pq_getstr - get a null terminated string from connection
175 * --------------------------------
178 pq_getstr(char *s, int maxlen)
182 if (Pfin == (FILE *) NULL)
184 /* elog(DEBUG, "Input descriptor is null"); */
188 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
193 * If EOF reached let caller know.
194 * (This will only happen if we hit EOF before the string
195 * delimiter is reached.)
204 * USER FUNCTION - gets a newline-terminated string from the backend.
206 * Chiefly here so that applications can use "COPY <rel> to stdout"
207 * and read the output string. Returns a null-terminated string in s.
209 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
210 * the terminating \n (like gets(3)).
213 * EOF if it is detected or invalid arguments are given
214 * 0 if EOL is reached (i.e., \n has been read)
215 * (this is required for backward-compatibility -- this
216 * routine used to always return EOF or 0, assuming that
217 * the line ended within maxlen bytes.)
221 PQgetline(char *s, int maxlen)
223 if (!Pfin || !s || maxlen <= 1)
226 if (fgets(s, maxlen - 1, Pfin) == NULL)
228 return feof(Pfin) ? EOF : 1;
246 * USER FUNCTION - sends a string to the backend.
248 * Chiefly here so that applications can use "COPY <rel> from stdin".
264 /* --------------------------------
265 * pq_getnchar - get n characters from connection
266 * --------------------------------
269 pq_getnchar(char *s, int off, int maxlen)
271 return pqGetNBytes(s + off, maxlen, Pfin);
276 if (Pfin == (FILE *) NULL)
278 /* elog(DEBUG, "Input descriptor is null"); */
283 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
287 * If EOF reached let caller know
296 /* --------------------------------
297 * pq_getint - get an integer from connection
298 * we receive an integer a byte at a type and reconstruct it so that
299 * machines with different ENDIAN representations can talk to each
301 * --------------------------------
313 * mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
314 * EOF is a valid return value for an int! XXX
320 status = ((n = fgetc(Pfin)) == EOF);
323 status = pqGetShort(&n, Pfin);
326 status = pqGetLong(&n, Pfin);
329 fprintf(stderr, "** Unsupported size %d\n", b);
335 "FATAL: pq_getint failed: errno=%d\n", errno);
336 fputs(PQerrormsg, stderr);
337 pqdebug("%s", PQerrormsg);
344 /* --------------------------------
345 * pq_putstr - send a null terminated string to connection
346 * --------------------------------
351 if (pqPutString(s, Pfout))
354 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
355 fputs(PQerrormsg, stderr);
356 pqdebug("%s", PQerrormsg);
360 /* --------------------------------
361 * pq_putnchar - send n characters to connection
362 * --------------------------------
365 pq_putnchar(char *s, int n)
367 if (pqPutNBytes(s, n, Pfout))
370 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
372 fputs(PQerrormsg, stderr);
373 pqdebug("%s", PQerrormsg);
377 /* --------------------------------
378 * pq_putint - send an integer to connection
379 * we chop an integer into bytes and send individual bytes
380 * machines with different ENDIAN representations can still talk to each
382 * --------------------------------
385 pq_putint(int i, int b)
396 status = (fputc(i, Pfout) == EOF);
399 status = pqPutShort(i, Pfout);
402 status = pqPutLong(i, Pfout);
405 fprintf(stderr, "** Unsupported size %d\n", b);
411 "FATAL: pq_putint failed: errno=%d\n", errno);
412 fputs(PQerrormsg, stderr);
413 pqdebug("%s", PQerrormsg);
418 * pq_sendoob - send a string over the out-of-band channel
419 * pq_recvoob - receive a string over the oob channel
420 * NB: Fortunately, the out-of-band channel doesn't conflict with
421 * buffered I/O because it is separate from regular com. channel.
425 pq_sendoob(char *msg, int len)
427 int fd = fileno(Pfout);
429 return (send(fd, msg, len, MSG_OOB));
433 pq_recvoob(char *msgPtr, int *lenPtr)
435 int fd = fileno(Pfout);
438 len = recv(fd, msgPtr + len, *lenPtr, MSG_OOB);
443 /* --------------------------------
444 * pq_getinaddr - initialize address from host and port number
445 * --------------------------------
448 pq_getinaddr(struct sockaddr_in * sin,
454 MemSet((char *) sin, 0, sizeof(*sin));
458 if (*host >= '0' && *host <= '9')
459 sin->sin_addr.s_addr = inet_addr(host);
462 if (!(hs = gethostbyname(host)))
467 if (hs->h_addrtype != AF_INET)
470 "FATAL: pq_getinaddr: %s not on Internet\n",
472 fputs(PQerrormsg, stderr);
473 pqdebug("%s", PQerrormsg);
476 memmove((char *) &sin->sin_addr,
481 sin->sin_family = AF_INET;
482 sin->sin_port = htons(port);
486 /* --------------------------------
487 * pq_getinserv - initialize address from host and servive name
488 * --------------------------------
491 pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
495 if (*serv >= '0' && *serv <= '9')
496 return (pq_getinaddr(sin, host, atoi(serv)));
497 if (!(ss = getservbyname(serv, NULL)))
500 "FATAL: pq_getinserv: unknown service: %s\n",
502 fputs(PQerrormsg, stderr);
503 pqdebug("%s", PQerrormsg);
506 return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
510 * register an out-of-band listener proc--at most one allowed.
511 * This is used for receiving async. notification from the backend.
514 pq_regoob(void (*fptr) ())
516 int fd = fileno(Pfout);
519 ioctl(fd, FIOSSAIOOWN, MyProcPid);
521 ioctl(fd, SIOCSPGRP, MyProcPid);
523 fcntl(fd, F_SETOWN, MyProcPid);
525 pqsignal(SIGURG, fptr);
531 pqsignal(SIGURG, SIG_DFL);
540 /* int len = sizeof(msg); */
543 if (pq_recvoob(msg, &len) >= 0)
546 printf("received notification: %s\n", msg);
547 PQAsyncNotifyWaiting = 1;
548 /* PQappendNotify(msg+1); */
554 printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
559 * Streams -- wrapper around Unix socket system calls
562 * Stream functions are used for vanilla TCP connection protocol.
566 * StreamServerPort -- open a sock stream "listening" port.
568 * This initializes the Postmaster's connection
571 * ASSUME: that this doesn't need to be non-blocking because
572 * the Postmaster uses select() to tell when the socket
575 * RETURNS: STATUS_OK or STATUS_ERROR
578 static char sock_path[MAXPGPATH+1] = "";
581 * Shutdown routine for backend connection
582 * If a Unix socket is used for communication, explicitly close it.
592 StreamServerPort(char *hostName, short portName, int *fdP)
596 struct sockaddr_in in;
597 struct sockaddr_un un;
605 family = ((hostName != NULL) ? AF_INET : AF_UNIX);
607 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
610 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
612 fputs(PQerrormsg, stderr);
613 pqdebug("%s", PQerrormsg);
614 return (STATUS_ERROR);
616 if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
620 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
622 fputs(PQerrormsg, stderr);
623 pqdebug("%s", PQerrormsg);
624 return (STATUS_ERROR);
626 bzero(&saddr, sizeof(saddr));
627 if (family == AF_UNIX)
629 saddr.un.sun_family = family;
630 len = UNIXSOCK_PATH(saddr.un, portName);
631 strcpy(sock_path, saddr.un.sun_path);
635 saddr.in.sin_family = family;
636 saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
637 saddr.in.sin_port = htons(portName);
638 len = sizeof saddr.in;
640 err = bind(fd, (struct sockaddr *) & saddr, len);
644 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
646 pqdebug("%s", PQerrormsg);
647 strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
648 if (family == AF_UNIX)
649 strcat(PQerrormsg, "\tIf not, remove socket node (/tmp/.s.PGSQL.<portnr>)and retry.\n");
651 strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
652 fputs(PQerrormsg, stderr);
653 return (STATUS_ERROR);
656 listen(fd, SOMAXCONN);
659 * MS: I took this code from Dillon's version. It makes the listening
660 * port non-blocking. That is not necessary (and may tickle kernel
663 * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
667 if (family == AF_UNIX)
669 chmod(sock_path, 0777);
676 * StreamConnection -- create a new connection with client using
679 * This one should be non-blocking.
681 * RETURNS: STATUS_OK or STATUS_ERROR
684 StreamConnection(int server_fd, Port *port)
688 int family = port->raddr.in.sin_family;
690 /* accept connection (and fill in the client (remote) address) */
691 len = family == AF_INET ?
692 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_un);
694 if ((port->sock = accept(server_fd,
695 (struct sockaddr *) & port->raddr,
698 elog(ERROR, "postmaster: StreamConnection: accept: %m");
699 return (STATUS_ERROR);
702 /* fill in the server (local) address */
704 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
707 elog(ERROR, "postmaster: StreamConnection: getsockname: %m");
708 return (STATUS_ERROR);
710 if (family == AF_INET)
715 pe = getprotobyname("TCP");
718 elog(ERROR, "postmaster: getprotobyname failed");
719 return (STATUS_ERROR);
721 if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
722 &on, sizeof(on)) < 0)
724 elog(ERROR, "postmaster: setsockopt failed");
725 return (STATUS_ERROR);
729 port->mask = 1 << port->sock;
731 /* reset to non-blocking */
732 fcntl(port->sock, F_SETFL, 1);
738 * StreamClose -- close a client/backend connection
741 StreamClose(int sock)
746 /* ---------------------------
747 * StreamOpen -- From client, initiate a connection with the
748 * server (Postmaster).
750 * RETURNS: STATUS_OK or STATUS_ERROR
752 * NOTE: connection is NOT established just because this
753 * routine exits. Local state is ok, but we haven't
754 * spoken to the postmaster yet.
755 * ---------------------------
758 StreamOpen(char *hostName, short portName, Port *port)
765 /* set up the server (remote) address */
766 MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
769 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
772 "FATAL: StreamOpen: unknown hostname: %s\n",
774 fputs(PQerrormsg, stderr);
775 pqdebug("%s", PQerrormsg);
776 return (STATUS_ERROR);
778 memmove((char *) &(port->raddr.in.sin_addr),
781 port->raddr.in.sin_family = AF_INET;
782 port->raddr.in.sin_port = htons(portName);
783 len = sizeof(struct sockaddr_in);
787 port->raddr.un.sun_family = AF_UNIX;
788 len = UNIXSOCK_PATH(port->raddr.un, portName);
790 /* connect to the server */
791 if ((port->sock = socket(port->raddr.in.sin_family, SOCK_STREAM, 0)) < 0)
794 "FATAL: StreamOpen: socket() failed: errno=%d\n",
796 fputs(PQerrormsg, stderr);
797 pqdebug("%s", PQerrormsg);
798 return (STATUS_ERROR);
800 err = connect(port->sock, (struct sockaddr *) & port->raddr, len);
804 "FATAL: StreamOpen: connect() failed: errno=%d\n",
806 fputs(PQerrormsg, stderr);
807 pqdebug("%s", PQerrormsg);
808 return (STATUS_ERROR);
811 /* fill in the client address */
812 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
816 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
818 fputs(PQerrormsg, stderr);
819 pqdebug("%s", PQerrormsg);
820 return (STATUS_ERROR);
826 static char *authentication_type_name[] = {
828 "the default authentication type",
832 "host-based authentication",
834 "plaintext password authentication"
838 name_of_authentication_type(int type)
842 if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
844 result = authentication_type_name[type];
849 result = "<unknown authentication type>";