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.27 1997/11/17 16:17:14 thomas 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 */
61 #include <storage/ipc.h>
69 FILE *Pfdebug; /* debugging libpq */
70 int PQAsyncNotifyWaiting; /* for async. notification */
72 /* --------------------------------
73 * pq_init - open portal file descriptors
74 * --------------------------------
79 Pfin = fdopen(fd, "r");
80 Pfout = fdopen(dup(fd), "w");
82 elog(FATAL, "pq_init: Couldn't initialize socket connection");
84 if (getenv("LIBPQ_DEBUG"))
94 /* -------------------------
97 * get a character from the input file,
99 * if Pfdebug is set, also echo the character fetched into Pfdebug
101 * used for debugging libpq
109 if (Pfdebug && c != EOF)
114 /* --------------------------------
115 * pq_gettty - return the name of the tty in the given buffer
116 * --------------------------------
121 strncpy(tp, ttyname(0), 19);
124 /* --------------------------------
125 * pq_getport - return the PGPORT setting
126 * --------------------------------
131 char *envport = getenv("PGPORT");
134 return (atoi(envport));
135 return (atoi(DEF_PGPORT));
138 /* --------------------------------
139 * pq_close - close input / output connections
140 * --------------------------------
155 PQAsyncNotifyWaiting = 0;
160 /* --------------------------------
161 * pq_flush - flush pending output
162 * --------------------------------
171 /* --------------------------------
172 * pq_getstr - get a null terminated string from connection
173 * --------------------------------
176 pq_getstr(char *s, int maxlen)
180 if (Pfin == (FILE *) NULL)
182 /* elog(DEBUG, "Input descriptor is null"); */
186 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
191 * If EOF reached let caller know.
192 * (This will only happen if we hit EOF before the string
193 * delimiter is reached.)
202 * USER FUNCTION - gets a newline-terminated string from the backend.
204 * Chiefly here so that applications can use "COPY <rel> to stdout"
205 * and read the output string. Returns a null-terminated string in s.
207 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
208 * the terminating \n (like gets(3)).
211 * EOF if it is detected or invalid arguments are given
212 * 0 if EOL is reached (i.e., \n has been read)
213 * (this is required for backward-compatibility -- this
214 * routine used to always return EOF or 0, assuming that
215 * the line ended within maxlen bytes.)
219 PQgetline(char *s, int maxlen)
221 if (!Pfin || !s || maxlen <= 1)
224 if (fgets(s, maxlen - 1, Pfin) == NULL)
226 return feof(Pfin) ? EOF : 1;
244 * USER FUNCTION - sends a string to the backend.
246 * Chiefly here so that applications can use "COPY <rel> from stdin".
262 /* --------------------------------
263 * pq_getnchar - get n characters from connection
264 * --------------------------------
267 pq_getnchar(char *s, int off, int maxlen)
269 return pqGetNBytes(s + off, maxlen, Pfin);
274 if (Pfin == (FILE *) NULL)
276 /* elog(DEBUG, "Input descriptor is null"); */
281 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
285 * If EOF reached let caller know
294 /* --------------------------------
295 * pq_getint - get an integer from connection
296 * we receive an integer a byte at a type and reconstruct it so that
297 * machines with different ENDIAN representations can talk to each
299 * --------------------------------
311 * mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
312 * EOF is a valid return value for an int! XXX
318 status = ((n = fgetc(Pfin)) == EOF);
321 status = pqGetShort(&n, Pfin);
324 status = pqGetLong(&n, Pfin);
327 fprintf(stderr, "** Unsupported size %d\n", b);
333 "FATAL: pq_getint failed: errno=%d\n", errno);
334 fputs(PQerrormsg, stderr);
335 pqdebug("%s", PQerrormsg);
342 /* --------------------------------
343 * pq_putstr - send a null terminated string to connection
344 * --------------------------------
349 if (pqPutString(s, Pfout))
352 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
353 fputs(PQerrormsg, stderr);
354 pqdebug("%s", PQerrormsg);
358 /* --------------------------------
359 * pq_putnchar - send n characters to connection
360 * --------------------------------
363 pq_putnchar(char *s, int n)
365 if (pqPutNBytes(s, n, Pfout))
368 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
370 fputs(PQerrormsg, stderr);
371 pqdebug("%s", PQerrormsg);
375 /* --------------------------------
376 * pq_putint - send an integer to connection
377 * we chop an integer into bytes and send individual bytes
378 * machines with different ENDIAN representations can still talk to each
380 * --------------------------------
383 pq_putint(int i, int b)
394 status = (fputc(i, Pfout) == EOF);
397 status = pqPutShort(i, Pfout);
400 status = pqPutLong(i, Pfout);
403 fprintf(stderr, "** Unsupported size %d\n", b);
409 "FATAL: pq_putint failed: errno=%d\n", errno);
410 fputs(PQerrormsg, stderr);
411 pqdebug("%s", PQerrormsg);
416 * pq_sendoob - send a string over the out-of-band channel
417 * pq_recvoob - receive a string over the oob channel
418 * NB: Fortunately, the out-of-band channel doesn't conflict with
419 * buffered I/O because it is separate from regular com. channel.
423 pq_sendoob(char *msg, int len)
425 int fd = fileno(Pfout);
427 return (send(fd, msg, len, MSG_OOB));
431 pq_recvoob(char *msgPtr, int *lenPtr)
433 int fd = fileno(Pfout);
436 len = recv(fd, msgPtr + len, *lenPtr, MSG_OOB);
441 /* --------------------------------
442 * pq_getinaddr - initialize address from host and port number
443 * --------------------------------
446 pq_getinaddr(struct sockaddr_in * sin,
452 MemSet((char *) sin, 0, sizeof(*sin));
456 if (*host >= '0' && *host <= '9')
457 sin->sin_addr.s_addr = inet_addr(host);
460 if (!(hs = gethostbyname(host)))
465 if (hs->h_addrtype != AF_INET)
468 "FATAL: pq_getinaddr: %s not on Internet\n",
470 fputs(PQerrormsg, stderr);
471 pqdebug("%s", PQerrormsg);
474 memmove((char *) &sin->sin_addr,
479 sin->sin_family = AF_INET;
480 sin->sin_port = htons(port);
484 /* --------------------------------
485 * pq_getinserv - initialize address from host and servive name
486 * --------------------------------
489 pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
493 if (*serv >= '0' && *serv <= '9')
494 return (pq_getinaddr(sin, host, atoi(serv)));
495 if (!(ss = getservbyname(serv, NULL)))
498 "FATAL: pq_getinserv: unknown service: %s\n",
500 fputs(PQerrormsg, stderr);
501 pqdebug("%s", PQerrormsg);
504 return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
508 * register an out-of-band listener proc--at most one allowed.
509 * This is used for receiving async. notification from the backend.
512 pq_regoob(void (*fptr) ())
514 int fd = fileno(Pfout);
517 ioctl(fd, FIOSSAIOOWN, getpid());
519 ioctl(fd, SIOCSPGRP, getpid());
521 fcntl(fd, F_SETOWN, getpid());
523 pqsignal(SIGURG, fptr);
529 pqsignal(SIGURG, SIG_DFL);
538 /* int len = sizeof(msg); */
541 if (pq_recvoob(msg, &len) >= 0)
544 printf("received notification: %s\n", msg);
545 PQAsyncNotifyWaiting = 1;
546 /* PQappendNotify(msg+1); */
552 printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
557 * Streams -- wrapper around Unix socket system calls
560 * Stream functions are used for vanilla TCP connection protocol.
564 * StreamServerPort -- open a sock stream "listening" port.
566 * This initializes the Postmaster's connection
569 * ASSUME: that this doesn't need to be non-blocking because
570 * the Postmaster uses select() to tell when the socket
573 * RETURNS: STATUS_OK or STATUS_ERROR
576 static char sock_path[100] = "";
586 StreamServerPort(char *hostName, short portName, int *fdP)
590 struct sockaddr_in in;
591 struct sockaddr_un un;
599 family = ((hostName != NULL) ? AF_INET : AF_UNIX);
601 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
604 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
606 fputs(PQerrormsg, stderr);
607 pqdebug("%s", PQerrormsg);
608 return (STATUS_ERROR);
610 if (family == AF_UNIX)
611 on_exitpg(do_unlink, (caddr_t) 0);
612 if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
616 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
618 fputs(PQerrormsg, stderr);
619 pqdebug("%s", PQerrormsg);
620 return (STATUS_ERROR);
622 bzero(&saddr, sizeof(saddr));
623 if (family == AF_UNIX)
625 saddr.un.sun_family = family;
626 len = UNIXSOCK_PATH(saddr.un, portName);
627 strcpy(sock_path, saddr.un.sun_path);
631 saddr.in.sin_family = family;
632 saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
633 saddr.in.sin_port = htons(portName);
634 len = sizeof saddr.in;
636 err = bind(fd, (struct sockaddr *) & saddr, len);
640 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
642 pqdebug("%s", PQerrormsg);
643 strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
644 strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
645 fputs(PQerrormsg, stderr);
646 return (STATUS_ERROR);
649 listen(fd, SOMAXCONN);
652 * MS: I took this code from Dillon's version. It makes the listening
653 * port non-blocking. That is not necessary (and may tickle kernel
656 * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
664 * StreamConnection -- create a new connection with client using
667 * This one should be non-blocking.
669 * RETURNS: STATUS_OK or STATUS_ERROR
672 StreamConnection(int server_fd, Port *port)
676 int family = port->raddr.in.sin_family;
678 /* accept connection (and fill in the client (remote) address) */
679 len = family == AF_INET ?
680 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_un);
682 if ((port->sock = accept(server_fd,
683 (struct sockaddr *) & port->raddr,
686 elog(WARN, "postmaster: StreamConnection: accept: %m");
687 return (STATUS_ERROR);
690 /* fill in the server (local) address */
692 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
695 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
696 return (STATUS_ERROR);
698 if (family == AF_INET)
703 pe = getprotobyname("TCP");
706 elog(WARN, "postmaster: getprotobyname failed");
707 return (STATUS_ERROR);
709 if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
710 &on, sizeof(on)) < 0)
712 elog(WARN, "postmaster: setsockopt failed");
713 return (STATUS_ERROR);
717 port->mask = 1 << port->sock;
719 /* reset to non-blocking */
720 fcntl(port->sock, F_SETFL, 1);
726 * StreamClose -- close a client/backend connection
729 StreamClose(int sock)
734 /* ---------------------------
735 * StreamOpen -- From client, initiate a connection with the
736 * server (Postmaster).
738 * RETURNS: STATUS_OK or STATUS_ERROR
740 * NOTE: connection is NOT established just because this
741 * routine exits. Local state is ok, but we haven't
742 * spoken to the postmaster yet.
743 * ---------------------------
746 StreamOpen(char *hostName, short portName, Port *port)
753 /* set up the server (remote) address */
754 MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
757 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
760 "FATAL: StreamOpen: unknown hostname: %s\n",
762 fputs(PQerrormsg, stderr);
763 pqdebug("%s", PQerrormsg);
764 return (STATUS_ERROR);
766 memmove((char *) &(port->raddr.in.sin_addr),
769 port->raddr.in.sin_family = AF_INET;
770 port->raddr.in.sin_port = htons(portName);
771 len = sizeof(struct sockaddr_in);
775 port->raddr.un.sun_family = AF_UNIX;
776 len = UNIXSOCK_PATH(port->raddr.un, portName);
778 /* connect to the server */
779 if ((port->sock = socket(port->raddr.in.sin_family, SOCK_STREAM, 0)) < 0)
782 "FATAL: StreamOpen: socket() failed: errno=%d\n",
784 fputs(PQerrormsg, stderr);
785 pqdebug("%s", PQerrormsg);
786 return (STATUS_ERROR);
788 err = connect(port->sock, (struct sockaddr *) & port->raddr, len);
792 "FATAL: StreamOpen: connect() failed: errno=%d\n",
794 fputs(PQerrormsg, stderr);
795 pqdebug("%s", PQerrormsg);
796 return (STATUS_ERROR);
799 /* fill in the client address */
800 if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
804 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
806 fputs(PQerrormsg, stderr);
807 pqdebug("%s", PQerrormsg);
808 return (STATUS_ERROR);
814 static char *authentication_type_name[] = {
816 "the default authentication type",
820 "host-based authentication",
822 "plaintext password authentication"
826 name_of_authentication_type(int type)
830 if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
832 result = authentication_type_name[type];
837 result = "<unknown authentication type>";