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.23 1997/09/18 20:20:39 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>
44 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <arpa/inet.h>
52 #define SOMAXCONN 5 /* from Linux listen(2) man page */
53 #endif /* SOMAXCONN */
58 #include <libpq/pqsignal.h>
59 #include <libpq/auth.h>
60 #include <libpq/libpq.h> /* where the declarations go */
68 FILE *Pfdebug; /* debugging libpq */
69 int PQAsyncNotifyWaiting; /* for async. notification */
71 /* --------------------------------
72 * pq_init - open portal file descriptors
73 * --------------------------------
78 Pfin = fdopen(fd, "r");
79 Pfout = fdopen(dup(fd), "w");
81 elog(FATAL, "pq_init: Couldn't initialize socket connection");
83 if (getenv("LIBPQ_DEBUG"))
93 /* -------------------------
96 * get a character from the input file,
98 * if Pfdebug is set, also echo the character fetched into Pfdebug
100 * used for debugging libpq
108 if (Pfdebug && c != EOF)
113 /* --------------------------------
114 * pq_gettty - return the name of the tty in the given buffer
115 * --------------------------------
120 strncpy(tp, ttyname(0), 19);
123 /* --------------------------------
124 * pq_getport - return the PGPORT setting
125 * --------------------------------
130 char *envport = getenv("PGPORT");
133 return (atoi(envport));
134 return (atoi(DEF_PGPORT));
137 /* --------------------------------
138 * pq_close - close input / output connections
139 * --------------------------------
154 PQAsyncNotifyWaiting = 0;
159 /* --------------------------------
160 * pq_flush - flush pending output
161 * --------------------------------
170 /* --------------------------------
171 * pq_getstr - get a null terminated string from connection
172 * --------------------------------
175 pq_getstr(char *s, int maxlen)
179 if (Pfin == (FILE *) NULL)
181 /* elog(DEBUG, "Input descriptor is null"); */
185 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
190 * If EOF reached let caller know.
191 * (This will only happen if we hit EOF before the string
192 * delimiter is reached.)
201 * USER FUNCTION - gets a newline-terminated string from the backend.
203 * Chiefly here so that applications can use "COPY <rel> to stdout"
204 * and read the output string. Returns a null-terminated string in s.
206 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
207 * the terminating \n (like gets(3)).
210 * EOF if it is detected or invalid arguments are given
211 * 0 if EOL is reached (i.e., \n has been read)
212 * (this is required for backward-compatibility -- this
213 * routine used to always return EOF or 0, assuming that
214 * the line ended within maxlen bytes.)
218 PQgetline(char *s, int maxlen)
220 if (!Pfin || !s || maxlen <= 1)
223 if (fgets(s, maxlen - 1, Pfin) == NULL)
225 return feof(Pfin) ? EOF : 1;
243 * USER FUNCTION - sends a string to the backend.
245 * Chiefly here so that applications can use "COPY <rel> from stdin".
261 /* --------------------------------
262 * pq_getnchar - get n characters from connection
263 * --------------------------------
266 pq_getnchar(char *s, int off, int maxlen)
268 return pqGetNBytes(s + off, maxlen, Pfin);
273 if (Pfin == (FILE *) NULL)
275 /* elog(DEBUG, "Input descriptor is null"); */
280 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
284 * If EOF reached let caller know
293 /* --------------------------------
294 * pq_getint - get an integer from connection
295 * we receive an integer a byte at a type and reconstruct it so that
296 * machines with different ENDIAN representations can talk to each
298 * --------------------------------
310 * mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
311 * EOF is a valid return value for an int! XXX
317 status = ((n = fgetc(Pfin)) == EOF);
320 status = pqGetShort(&n, Pfin);
323 status = pqGetLong(&n, Pfin);
326 fprintf(stderr, "** Unsupported size %d\n", b);
332 "FATAL: pq_getint failed: errno=%d\n", errno);
333 fputs(PQerrormsg, stderr);
334 pqdebug("%s", PQerrormsg);
341 /* --------------------------------
342 * pq_putstr - send a null terminated string to connection
343 * --------------------------------
348 if (pqPutString(s, Pfout))
351 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
352 fputs(PQerrormsg, stderr);
353 pqdebug("%s", PQerrormsg);
357 /* --------------------------------
358 * pq_putnchar - send n characters to connection
359 * --------------------------------
362 pq_putnchar(char *s, int n)
364 if (pqPutNBytes(s, n, Pfout))
367 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
369 fputs(PQerrormsg, stderr);
370 pqdebug("%s", PQerrormsg);
374 /* --------------------------------
375 * pq_putint - send an integer to connection
376 * we chop an integer into bytes and send individual bytes
377 * machines with different ENDIAN representations can still talk to each
379 * --------------------------------
382 pq_putint(int i, int b)
393 status = (fputc(i, Pfout) == EOF);
396 status = pqPutShort(i, Pfout);
399 status = pqPutLong(i, Pfout);
402 fprintf(stderr, "** Unsupported size %d\n", b);
408 "FATAL: pq_putint failed: errno=%d\n", errno);
409 fputs(PQerrormsg, stderr);
410 pqdebug("%s", PQerrormsg);
415 * pq_sendoob - send a string over the out-of-band channel
416 * pq_recvoob - receive a string over the oob channel
417 * NB: Fortunately, the out-of-band channel doesn't conflict with
418 * buffered I/O because it is separate from regular com. channel.
422 pq_sendoob(char *msg, int len)
424 int fd = fileno(Pfout);
426 return (send(fd, msg, len, MSG_OOB));
430 pq_recvoob(char *msgPtr, int *lenPtr)
432 int fd = fileno(Pfout);
435 len = recv(fd, msgPtr + len, *lenPtr, MSG_OOB);
440 /* --------------------------------
441 * pq_getinaddr - initialize address from host and port number
442 * --------------------------------
445 pq_getinaddr(struct sockaddr_in * sin,
451 MemSet((char *) sin, 0, sizeof(*sin));
455 if (*host >= '0' && *host <= '9')
456 sin->sin_addr.s_addr = inet_addr(host);
459 if (!(hs = gethostbyname(host)))
464 if (hs->h_addrtype != AF_INET)
467 "FATAL: pq_getinaddr: %s not on Internet\n",
469 fputs(PQerrormsg, stderr);
470 pqdebug("%s", PQerrormsg);
473 memmove((char *) &sin->sin_addr,
478 sin->sin_family = AF_INET;
479 sin->sin_port = htons(port);
483 /* --------------------------------
484 * pq_getinserv - initialize address from host and servive name
485 * --------------------------------
488 pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
492 if (*serv >= '0' && *serv <= '9')
493 return (pq_getinaddr(sin, host, atoi(serv)));
494 if (!(ss = getservbyname(serv, NULL)))
497 "FATAL: pq_getinserv: unknown service: %s\n",
499 fputs(PQerrormsg, stderr);
500 pqdebug("%s", PQerrormsg);
503 return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
507 * register an out-of-band listener proc--at most one allowed.
508 * This is used for receiving async. notification from the backend.
511 pq_regoob(void (*fptr) ())
513 int fd = fileno(Pfout);
516 ioctl(fd, FIOSSAIOOWN, getpid());
518 ioctl(fd, SIOCSPGRP, getpid());
520 fcntl(fd, F_SETOWN, getpid());
522 pqsignal(SIGURG, fptr);
528 pqsignal(SIGURG, SIG_DFL);
537 /* int len = sizeof(msg); */
540 if (pq_recvoob(msg, &len) >= 0)
543 printf("received notification: %s\n", msg);
544 PQAsyncNotifyWaiting = 1;
545 /* PQappendNotify(msg+1); */
551 printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
556 * Streams -- wrapper around Unix socket system calls
559 * Stream functions are used for vanilla TCP connection protocol.
563 * StreamServerPort -- open a sock stream "listening" port.
565 * This initializes the Postmaster's connection
568 * ASSUME: that this doesn't need to be non-blocking because
569 * the Postmaster uses select() to tell when the socket
572 * RETURNS: STATUS_OK or STATUS_ERROR
575 StreamServerPort(char *hostName, short portName, int *fdP)
577 struct sockaddr_in sin;
583 hostName = "localhost";
585 MemSet((char *) &sin, 0, sizeof sin);
587 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
590 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
592 fputs(PQerrormsg, stderr);
593 pqdebug("%s", PQerrormsg);
594 return (STATUS_ERROR);
597 if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
601 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
603 fputs(PQerrormsg, stderr);
604 pqdebug("%s", PQerrormsg);
605 return (STATUS_ERROR);
608 sin.sin_family = AF_INET;
609 sin.sin_port = htons(portName);
611 if (bind(fd, (struct sockaddr *) & sin, sizeof sin) < 0)
614 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
616 pqdebug("%s", PQerrormsg);
617 strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
618 strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
619 fputs(PQerrormsg, stderr);
620 return (STATUS_ERROR);
623 listen(fd, SOMAXCONN);
626 * MS: I took this code from Dillon's version. It makes the listening
627 * port non-blocking. That is not necessary (and may tickle kernel
630 * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
638 * StreamConnection -- create a new connection with client using
641 * This one should be non-blocking.
643 * RETURNS: STATUS_OK or STATUS_ERROR
646 StreamConnection(int server_fd, Port *port)
650 /* accept connection (and fill in the client (remote) address) */
651 addrlen = sizeof(struct sockaddr_in);
652 if ((port->sock = accept(server_fd,
653 (struct sockaddr *) & port->raddr,
656 elog(WARN, "postmaster: StreamConnection: accept: %m");
657 return (STATUS_ERROR);
660 /* fill in the server (local) address */
661 addrlen = sizeof(struct sockaddr_in);
662 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
665 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
666 return (STATUS_ERROR);
672 pe = getprotobyname("TCP");
675 elog(WARN, "postmaster: getprotobyname failed");
676 return (STATUS_ERROR);
678 if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
679 &on, sizeof(on)) < 0)
681 elog(WARN, "postmaster: setsockopt failed");
682 return (STATUS_ERROR);
686 port->mask = 1 << port->sock;
688 /* reset to non-blocking */
689 fcntl(port->sock, F_SETFL, 1);
695 * StreamClose -- close a client/backend connection
698 StreamClose(int sock)
703 /* ---------------------------
704 * StreamOpen -- From client, initiate a connection with the
705 * server (Postmaster).
707 * RETURNS: STATUS_OK or STATUS_ERROR
709 * NOTE: connection is NOT established just because this
710 * routine exits. Local state is ok, but we haven't
711 * spoken to the postmaster yet.
712 * ---------------------------
715 StreamOpen(char *hostName, short portName, Port *port)
718 int laddrlen = sizeof(struct sockaddr_in);
722 hostName = "localhost";
724 /* set up the server (remote) address */
725 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
728 "FATAL: StreamOpen: unknown hostname: %s\n",
730 fputs(PQerrormsg, stderr);
731 pqdebug("%s", PQerrormsg);
732 return (STATUS_ERROR);
734 MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
735 memmove((char *) &(port->raddr.sin_addr),
738 port->raddr.sin_family = AF_INET;
739 port->raddr.sin_port = htons(portName);
741 /* connect to the server */
742 if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
745 "FATAL: StreamOpen: socket() failed: errno=%d\n",
747 fputs(PQerrormsg, stderr);
748 pqdebug("%s", PQerrormsg);
749 return (STATUS_ERROR);
751 if (connect(port->sock, (struct sockaddr *) & port->raddr,
752 sizeof(port->raddr)) < 0)
755 "FATAL: StreamOpen: connect() failed: errno=%d\n",
757 fputs(PQerrormsg, stderr);
758 pqdebug("%s", PQerrormsg);
759 return (STATUS_ERROR);
762 /* fill in the client address */
763 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
767 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
769 fputs(PQerrormsg, stderr);
770 pqdebug("%s", PQerrormsg);
771 return (STATUS_ERROR);
777 static char *authentication_type_name[] = {
779 "the default authentication type",
783 "host-based authentication",
785 "plaintext password authentication"
789 name_of_authentication_type(int type)
793 if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
795 result = authentication_type_name[type];
800 result = "<unknown authentication type>";