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.14 1997/03/20 18:21:35 scrappy 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 <arpa/inet.h>
51 #define SOMAXCONN 5 /* from Linux listen(2) man page */
52 #endif /* SOMAXCONN */
57 #include <libpq/pqsignal.h>
58 #include <libpq/auth.h>
59 #include <libpq/libpq.h> /* where the declarations go */
66 FILE *Pfdebug; /* debugging libpq */
67 int PQAsyncNotifyWaiting; /* for async. notification */
69 /* --------------------------------
70 * pq_init - open portal file descriptors
71 * --------------------------------
76 Pfin = fdopen(fd, "r");
77 Pfout = fdopen(dup(fd), "w");
79 elog(FATAL, "pq_init: Couldn't initialize socket connection");
81 if (getenv("LIBPQ_DEBUG")) {
88 /* -------------------------
91 * get a character from the input file,
93 * if Pfdebug is set, also echo the character fetched into Pfdebug
95 * used for debugging libpq
103 if (Pfdebug && c != EOF)
108 /* --------------------------------
109 * pq_gettty - return the name of the tty in the given buffer
110 * --------------------------------
115 (void) strncpy(tp, ttyname(0), 19);
118 /* --------------------------------
119 * pq_getport - return the PGPORT setting
120 * --------------------------------
125 char *envport = getenv("PGPORT");
128 return(atoi(envport));
129 return(atoi(DEF_PGPORT));
132 /* --------------------------------
133 * pq_close - close input / output connections
134 * --------------------------------
147 PQAsyncNotifyWaiting = 0;
152 /* --------------------------------
153 * pq_flush - flush pending output
154 * --------------------------------
163 /* --------------------------------
164 * pq_getstr - get a null terminated string from connection
165 * --------------------------------
168 pq_getstr(char *s, int maxlen)
172 if (Pfin == (FILE *) NULL) {
173 /* elog(DEBUG, "Input descriptor is null"); */
177 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
182 * If EOF reached let caller know.
183 * (This will only happen if we hit EOF before the string
184 * delimiter is reached.)
193 * USER FUNCTION - gets a newline-terminated string from the backend.
195 * Chiefly here so that applications can use "COPY <rel> to stdout"
196 * and read the output string. Returns a null-terminated string in s.
198 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
199 * the terminating \n (like gets(3)).
202 * EOF if it is detected or invalid arguments are given
203 * 0 if EOL is reached (i.e., \n has been read)
204 * (this is required for backward-compatibility -- this
205 * routine used to always return EOF or 0, assuming that
206 * the line ended within maxlen bytes.)
209 int PQgetline(char *s, int maxlen)
211 if (!Pfin || !s || maxlen <= 1)
214 if(fgets(s, maxlen - 1, Pfin) == NULL)
216 return feof(Pfin) ? EOF : 1;
234 * USER FUNCTION - sends a string to the backend.
236 * Chiefly here so that applications can use "COPY <rel> from stdin".
245 (void) fputs(s, Pfout);
251 /* --------------------------------
252 * pq_getnchar - get n characters from connection
253 * --------------------------------
256 pq_getnchar(char *s, int off, int maxlen)
258 return pqGetNBytes(s + off, maxlen, Pfin);
263 if (Pfin == (FILE *) NULL) {
264 /* elog(DEBUG, "Input descriptor is null"); */
269 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
273 * If EOF reached let caller know
282 /* --------------------------------
283 * pq_getint - get an integer from connection
284 * we receive an integer a byte at a type and reconstruct it so that
285 * machines with different ENDIAN representations can talk to each
287 * --------------------------------
296 /* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
297 EOF is a valid return value for an int! XXX */
302 status = ((n = fgetc(Pfin)) == EOF);
305 pqGetShort(&n, Pfin);
311 fprintf(stderr, "** Unsupported size %d\n", b);
316 (void) sprintf(PQerrormsg,
317 "FATAL: pq_getint failed: errno=%d\n", errno);
318 fputs(PQerrormsg, stderr);
319 pqdebug("%s", PQerrormsg);
326 /* --------------------------------
327 * pq_putstr - send a null terminated string to connection
328 * --------------------------------
333 if(pqPutString(s, Pfout))
335 (void) sprintf(PQerrormsg,
336 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
337 fputs(PQerrormsg, stderr);
338 pqdebug("%s", PQerrormsg);
342 /* --------------------------------
343 * pq_putnchar - send n characters to connection
344 * --------------------------------
347 pq_putnchar(char *s, int n)
349 if(pqPutNBytes(s, n, Pfout))
351 (void) sprintf(PQerrormsg,
352 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
354 fputs(PQerrormsg, stderr);
355 pqdebug("%s", PQerrormsg);
359 /* --------------------------------
360 * pq_putint - send an integer to connection
361 * we chop an integer into bytes and send individual bytes
362 * machines with different ENDIAN representations can still talk to each
364 * --------------------------------
367 pq_putint(int i, int b)
377 status = (fputc(i, Pfout) == EOF);
380 status = pqPutShort(i, Pfout);
383 status = pqPutLong(i, Pfout);
386 fprintf(stderr, "** Unsupported size %d\n", b);
391 (void) sprintf(PQerrormsg,
392 "FATAL: pq_putint failed: errno=%d\n", errno);
393 fputs(PQerrormsg, stderr);
394 pqdebug("%s", PQerrormsg);
399 * pq_sendoob - send a string over the out-of-band channel
400 * pq_recvoob - receive a string over the oob channel
401 * NB: Fortunately, the out-of-band channel doesn't conflict with
402 * buffered I/O because it is separate from regular com. channel.
406 pq_sendoob(char *msg, int len)
408 int fd = fileno(Pfout);
410 return(send(fd,msg,len,MSG_OOB));
414 pq_recvoob(char *msgPtr, int *lenPtr)
416 int fd = fileno(Pfout);
419 len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
424 /* --------------------------------
425 * pq_getinaddr - initialize address from host and port number
426 * --------------------------------
429 pq_getinaddr(struct sockaddr_in *sin,
435 memset((char *) sin, 0, sizeof(*sin));
438 if (*host >= '0' && *host <= '9')
439 sin->sin_addr.s_addr = inet_addr(host);
441 if (!(hs = gethostbyname(host))) {
445 if (hs->h_addrtype != AF_INET) {
446 (void) sprintf(PQerrormsg,
447 "FATAL: pq_getinaddr: %s not on Internet\n",
449 fputs(PQerrormsg, stderr);
450 pqdebug("%s", PQerrormsg);
453 memmove((char *) &sin->sin_addr,
458 sin->sin_family = AF_INET;
459 sin->sin_port = htons(port);
463 /* --------------------------------
464 * pq_getinserv - initialize address from host and servive name
465 * --------------------------------
468 pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
472 if (*serv >= '0' && *serv <= '9')
473 return(pq_getinaddr(sin, host, atoi(serv)));
474 if (!(ss = getservbyname(serv, NULL))) {
475 (void) sprintf(PQerrormsg,
476 "FATAL: pq_getinserv: unknown service: %s\n",
478 fputs(PQerrormsg, stderr);
479 pqdebug("%s", PQerrormsg);
482 return(pq_getinaddr(sin, host, ntohs(ss->s_port)));
486 * register an out-of-band listener proc--at most one allowed.
487 * This is used for receiving async. notification from the backend.
490 pq_regoob(void (*fptr)())
492 int fd = fileno(Pfout);
494 ioctl(fd, FIOSSAIOOWN, getpid());
496 fcntl(fd, F_SETOWN, getpid());
498 (void) pqsignal(SIGURG,fptr);
504 pqsignal(SIGURG,SIG_DFL);
512 /* int len = sizeof(msg);*/
515 if (pq_recvoob(msg,&len) >= 0) {
517 printf("received notification: %s\n",msg);
518 PQAsyncNotifyWaiting = 1;
519 /* PQappendNotify(msg+1);*/
522 printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
527 * Streams -- wrapper around Unix socket system calls
530 * Stream functions are used for vanilla TCP connection protocol.
534 * StreamServerPort -- open a sock stream "listening" port.
536 * This initializes the Postmaster's connection
539 * ASSUME: that this doesn't need to be non-blocking because
540 * the Postmaster uses select() to tell when the socket
543 * RETURNS: STATUS_OK or STATUS_ERROR
546 StreamServerPort(char *hostName, short portName, int *fdP)
548 struct sockaddr_in sin;
554 hostName = "localhost";
556 memset((char *)&sin, 0, sizeof sin);
558 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
559 (void) sprintf(PQerrormsg,
560 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
562 fputs(PQerrormsg, stderr);
563 pqdebug("%s", PQerrormsg);
564 return(STATUS_ERROR);
567 if((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
568 sizeof(one))) == -1) {
569 (void) sprintf(PQerrormsg,
570 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
572 fputs(PQerrormsg, stderr);
573 pqdebug("%s", PQerrormsg);
574 return(STATUS_ERROR);
577 sin.sin_family = AF_INET;
578 sin.sin_port = htons(portName);
580 if (bind(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
581 (void) sprintf(PQerrormsg,
582 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
584 pqdebug("%s", PQerrormsg);
585 (void) strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
586 (void) strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
587 fputs(PQerrormsg, stderr);
588 return(STATUS_ERROR);
591 listen(fd, SOMAXCONN);
593 /* MS: I took this code from Dillon's version. It makes the
594 * listening port non-blocking. That is not necessary (and
595 * may tickle kernel bugs).
597 (void) fcntl(fd, F_SETFD, 1);
598 (void) fcntl(fd, F_SETFL, FNDELAY);
606 * StreamConnection -- create a new connection with client using
609 * This one should be non-blocking.
611 * RETURNS: STATUS_OK or STATUS_ERROR
614 StreamConnection(int server_fd, Port *port)
618 /* accept connection (and fill in the client (remote) address) */
619 addrlen = sizeof(struct sockaddr_in);
620 if ((port->sock = accept(server_fd,
621 (struct sockaddr *) &port->raddr,
623 elog(WARN, "postmaster: StreamConnection: accept: %m");
624 return(STATUS_ERROR);
627 /* fill in the server (local) address */
628 addrlen = sizeof(struct sockaddr_in);
629 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
631 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
632 return(STATUS_ERROR);
635 port->mask = 1 << port->sock;
637 /* reset to non-blocking */
638 fcntl(port->sock, F_SETFL, 1);
644 * StreamClose -- close a client/backend connection
647 StreamClose(int sock)
652 /* ---------------------------
653 * StreamOpen -- From client, initiate a connection with the
654 * server (Postmaster).
656 * RETURNS: STATUS_OK or STATUS_ERROR
658 * NOTE: connection is NOT established just because this
659 * routine exits. Local state is ok, but we haven't
660 * spoken to the postmaster yet.
661 * ---------------------------
664 StreamOpen(char *hostName, short portName, Port *port)
667 int laddrlen = sizeof(struct sockaddr_in);
671 hostName = "localhost";
673 /* set up the server (remote) address */
674 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET) {
675 (void) sprintf(PQerrormsg,
676 "FATAL: StreamOpen: unknown hostname: %s\n",
678 fputs(PQerrormsg, stderr);
679 pqdebug("%s", PQerrormsg);
680 return(STATUS_ERROR);
682 memset((char *) &port->raddr, 0, sizeof(port->raddr));
683 memmove((char *) &(port->raddr.sin_addr),
686 port->raddr.sin_family = AF_INET;
687 port->raddr.sin_port = htons(portName);
689 /* connect to the server */
690 if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
691 (void) sprintf(PQerrormsg,
692 "FATAL: StreamOpen: socket() failed: errno=%d\n",
694 fputs(PQerrormsg, stderr);
695 pqdebug("%s", PQerrormsg);
696 return(STATUS_ERROR);
698 if (connect(port->sock, (struct sockaddr *)&port->raddr,
699 sizeof(port->raddr)) < 0) {
700 (void) sprintf(PQerrormsg,
701 "FATAL: StreamOpen: connect() failed: errno=%d\n",
703 fputs(PQerrormsg, stderr);
704 pqdebug("%s", PQerrormsg);
705 return(STATUS_ERROR);
708 /* fill in the client address */
709 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
711 (void) sprintf(PQerrormsg,
712 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
714 fputs(PQerrormsg, stderr);
715 pqdebug("%s", PQerrormsg);
716 return(STATUS_ERROR);
722 static char *authentication_type_name[] = {
724 "the default authentication type",
728 "host-based authentication",
730 "plaintext password authentication"
733 char *name_of_authentication_type(int type)
737 if(type >= 1 && type <= LAST_AUTHENTICATION_TYPE) {
738 result = authentication_type_name[type];
742 result = "<unknown authentication type>";