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.15 1997/04/16 06:25:13 vadim 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 */
67 FILE *Pfdebug; /* debugging libpq */
68 int PQAsyncNotifyWaiting; /* for async. notification */
70 /* --------------------------------
71 * pq_init - open portal file descriptors
72 * --------------------------------
77 Pfin = fdopen(fd, "r");
78 Pfout = fdopen(dup(fd), "w");
80 elog(FATAL, "pq_init: Couldn't initialize socket connection");
82 if (getenv("LIBPQ_DEBUG")) {
89 /* -------------------------
92 * get a character from the input file,
94 * if Pfdebug is set, also echo the character fetched into Pfdebug
96 * used for debugging libpq
104 if (Pfdebug && c != EOF)
109 /* --------------------------------
110 * pq_gettty - return the name of the tty in the given buffer
111 * --------------------------------
116 (void) strncpy(tp, ttyname(0), 19);
119 /* --------------------------------
120 * pq_getport - return the PGPORT setting
121 * --------------------------------
126 char *envport = getenv("PGPORT");
129 return(atoi(envport));
130 return(atoi(DEF_PGPORT));
133 /* --------------------------------
134 * pq_close - close input / output connections
135 * --------------------------------
148 PQAsyncNotifyWaiting = 0;
153 /* --------------------------------
154 * pq_flush - flush pending output
155 * --------------------------------
164 /* --------------------------------
165 * pq_getstr - get a null terminated string from connection
166 * --------------------------------
169 pq_getstr(char *s, int maxlen)
173 if (Pfin == (FILE *) NULL) {
174 /* elog(DEBUG, "Input descriptor is null"); */
178 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
183 * If EOF reached let caller know.
184 * (This will only happen if we hit EOF before the string
185 * delimiter is reached.)
194 * USER FUNCTION - gets a newline-terminated string from the backend.
196 * Chiefly here so that applications can use "COPY <rel> to stdout"
197 * and read the output string. Returns a null-terminated string in s.
199 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
200 * the terminating \n (like gets(3)).
203 * EOF if it is detected or invalid arguments are given
204 * 0 if EOL is reached (i.e., \n has been read)
205 * (this is required for backward-compatibility -- this
206 * routine used to always return EOF or 0, assuming that
207 * the line ended within maxlen bytes.)
210 int PQgetline(char *s, int maxlen)
212 if (!Pfin || !s || maxlen <= 1)
215 if(fgets(s, maxlen - 1, Pfin) == NULL)
217 return feof(Pfin) ? EOF : 1;
235 * USER FUNCTION - sends a string to the backend.
237 * Chiefly here so that applications can use "COPY <rel> from stdin".
246 (void) fputs(s, Pfout);
252 /* --------------------------------
253 * pq_getnchar - get n characters from connection
254 * --------------------------------
257 pq_getnchar(char *s, int off, int maxlen)
259 return pqGetNBytes(s + off, maxlen, Pfin);
264 if (Pfin == (FILE *) NULL) {
265 /* elog(DEBUG, "Input descriptor is null"); */
270 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
274 * If EOF reached let caller know
283 /* --------------------------------
284 * pq_getint - get an integer from connection
285 * we receive an integer a byte at a type and reconstruct it so that
286 * machines with different ENDIAN representations can talk to each
288 * --------------------------------
297 /* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
298 EOF is a valid return value for an int! XXX */
303 status = ((n = fgetc(Pfin)) == EOF);
306 pqGetShort(&n, Pfin);
312 fprintf(stderr, "** Unsupported size %d\n", b);
317 (void) sprintf(PQerrormsg,
318 "FATAL: pq_getint failed: errno=%d\n", errno);
319 fputs(PQerrormsg, stderr);
320 pqdebug("%s", PQerrormsg);
327 /* --------------------------------
328 * pq_putstr - send a null terminated string to connection
329 * --------------------------------
334 if(pqPutString(s, Pfout))
336 (void) sprintf(PQerrormsg,
337 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
338 fputs(PQerrormsg, stderr);
339 pqdebug("%s", PQerrormsg);
343 /* --------------------------------
344 * pq_putnchar - send n characters to connection
345 * --------------------------------
348 pq_putnchar(char *s, int n)
350 if(pqPutNBytes(s, n, Pfout))
352 (void) sprintf(PQerrormsg,
353 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
355 fputs(PQerrormsg, stderr);
356 pqdebug("%s", PQerrormsg);
360 /* --------------------------------
361 * pq_putint - send an integer to connection
362 * we chop an integer into bytes and send individual bytes
363 * machines with different ENDIAN representations can still talk to each
365 * --------------------------------
368 pq_putint(int i, int b)
378 status = (fputc(i, Pfout) == EOF);
381 status = pqPutShort(i, Pfout);
384 status = pqPutLong(i, Pfout);
387 fprintf(stderr, "** Unsupported size %d\n", b);
392 (void) sprintf(PQerrormsg,
393 "FATAL: pq_putint failed: errno=%d\n", errno);
394 fputs(PQerrormsg, stderr);
395 pqdebug("%s", PQerrormsg);
400 * pq_sendoob - send a string over the out-of-band channel
401 * pq_recvoob - receive a string over the oob channel
402 * NB: Fortunately, the out-of-band channel doesn't conflict with
403 * buffered I/O because it is separate from regular com. channel.
407 pq_sendoob(char *msg, int len)
409 int fd = fileno(Pfout);
411 return(send(fd,msg,len,MSG_OOB));
415 pq_recvoob(char *msgPtr, int *lenPtr)
417 int fd = fileno(Pfout);
420 len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
425 /* --------------------------------
426 * pq_getinaddr - initialize address from host and port number
427 * --------------------------------
430 pq_getinaddr(struct sockaddr_in *sin,
436 memset((char *) sin, 0, sizeof(*sin));
439 if (*host >= '0' && *host <= '9')
440 sin->sin_addr.s_addr = inet_addr(host);
442 if (!(hs = gethostbyname(host))) {
446 if (hs->h_addrtype != AF_INET) {
447 (void) sprintf(PQerrormsg,
448 "FATAL: pq_getinaddr: %s not on Internet\n",
450 fputs(PQerrormsg, stderr);
451 pqdebug("%s", PQerrormsg);
454 memmove((char *) &sin->sin_addr,
459 sin->sin_family = AF_INET;
460 sin->sin_port = htons(port);
464 /* --------------------------------
465 * pq_getinserv - initialize address from host and servive name
466 * --------------------------------
469 pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
473 if (*serv >= '0' && *serv <= '9')
474 return(pq_getinaddr(sin, host, atoi(serv)));
475 if (!(ss = getservbyname(serv, NULL))) {
476 (void) sprintf(PQerrormsg,
477 "FATAL: pq_getinserv: unknown service: %s\n",
479 fputs(PQerrormsg, stderr);
480 pqdebug("%s", PQerrormsg);
483 return(pq_getinaddr(sin, host, ntohs(ss->s_port)));
487 * register an out-of-band listener proc--at most one allowed.
488 * This is used for receiving async. notification from the backend.
491 pq_regoob(void (*fptr)())
493 int fd = fileno(Pfout);
495 ioctl(fd, FIOSSAIOOWN, getpid());
497 fcntl(fd, F_SETOWN, getpid());
499 (void) pqsignal(SIGURG,fptr);
505 pqsignal(SIGURG,SIG_DFL);
513 /* int len = sizeof(msg);*/
516 if (pq_recvoob(msg,&len) >= 0) {
518 printf("received notification: %s\n",msg);
519 PQAsyncNotifyWaiting = 1;
520 /* PQappendNotify(msg+1);*/
523 printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
528 * Streams -- wrapper around Unix socket system calls
531 * Stream functions are used for vanilla TCP connection protocol.
535 * StreamServerPort -- open a sock stream "listening" port.
537 * This initializes the Postmaster's connection
540 * ASSUME: that this doesn't need to be non-blocking because
541 * the Postmaster uses select() to tell when the socket
544 * RETURNS: STATUS_OK or STATUS_ERROR
547 StreamServerPort(char *hostName, short portName, int *fdP)
549 struct sockaddr_in sin;
555 hostName = "localhost";
557 memset((char *)&sin, 0, sizeof sin);
559 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
560 (void) sprintf(PQerrormsg,
561 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
563 fputs(PQerrormsg, stderr);
564 pqdebug("%s", PQerrormsg);
565 return(STATUS_ERROR);
568 if((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
569 sizeof(one))) == -1) {
570 (void) sprintf(PQerrormsg,
571 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
573 fputs(PQerrormsg, stderr);
574 pqdebug("%s", PQerrormsg);
575 return(STATUS_ERROR);
578 sin.sin_family = AF_INET;
579 sin.sin_port = htons(portName);
581 if (bind(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
582 (void) sprintf(PQerrormsg,
583 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
585 pqdebug("%s", PQerrormsg);
586 (void) strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
587 (void) strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
588 fputs(PQerrormsg, stderr);
589 return(STATUS_ERROR);
592 listen(fd, SOMAXCONN);
594 /* MS: I took this code from Dillon's version. It makes the
595 * listening port non-blocking. That is not necessary (and
596 * may tickle kernel bugs).
598 (void) fcntl(fd, F_SETFD, 1);
599 (void) fcntl(fd, F_SETFL, FNDELAY);
607 * StreamConnection -- create a new connection with client using
610 * This one should be non-blocking.
612 * RETURNS: STATUS_OK or STATUS_ERROR
615 StreamConnection(int server_fd, Port *port)
619 /* accept connection (and fill in the client (remote) address) */
620 addrlen = sizeof(struct sockaddr_in);
621 if ((port->sock = accept(server_fd,
622 (struct sockaddr *) &port->raddr,
624 elog(WARN, "postmaster: StreamConnection: accept: %m");
625 return(STATUS_ERROR);
628 /* fill in the server (local) address */
629 addrlen = sizeof(struct sockaddr_in);
630 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
632 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
633 return(STATUS_ERROR);
639 pe = getprotobyname ("TCP");
642 elog(WARN, "postmaster: getprotobyname failed");
643 return(STATUS_ERROR);
645 if ( setsockopt (port->sock, pe->p_proto, TCP_NODELAY,
646 &on, sizeof (on)) < 0 )
648 elog(WARN, "postmaster: setsockopt failed");
649 return(STATUS_ERROR);
653 port->mask = 1 << port->sock;
655 /* reset to non-blocking */
656 fcntl(port->sock, F_SETFL, 1);
662 * StreamClose -- close a client/backend connection
665 StreamClose(int sock)
670 /* ---------------------------
671 * StreamOpen -- From client, initiate a connection with the
672 * server (Postmaster).
674 * RETURNS: STATUS_OK or STATUS_ERROR
676 * NOTE: connection is NOT established just because this
677 * routine exits. Local state is ok, but we haven't
678 * spoken to the postmaster yet.
679 * ---------------------------
682 StreamOpen(char *hostName, short portName, Port *port)
685 int laddrlen = sizeof(struct sockaddr_in);
689 hostName = "localhost";
691 /* set up the server (remote) address */
692 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET) {
693 (void) sprintf(PQerrormsg,
694 "FATAL: StreamOpen: unknown hostname: %s\n",
696 fputs(PQerrormsg, stderr);
697 pqdebug("%s", PQerrormsg);
698 return(STATUS_ERROR);
700 memset((char *) &port->raddr, 0, sizeof(port->raddr));
701 memmove((char *) &(port->raddr.sin_addr),
704 port->raddr.sin_family = AF_INET;
705 port->raddr.sin_port = htons(portName);
707 /* connect to the server */
708 if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
709 (void) sprintf(PQerrormsg,
710 "FATAL: StreamOpen: socket() failed: errno=%d\n",
712 fputs(PQerrormsg, stderr);
713 pqdebug("%s", PQerrormsg);
714 return(STATUS_ERROR);
716 if (connect(port->sock, (struct sockaddr *)&port->raddr,
717 sizeof(port->raddr)) < 0) {
718 (void) sprintf(PQerrormsg,
719 "FATAL: StreamOpen: connect() failed: errno=%d\n",
721 fputs(PQerrormsg, stderr);
722 pqdebug("%s", PQerrormsg);
723 return(STATUS_ERROR);
726 /* fill in the client address */
727 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
729 (void) sprintf(PQerrormsg,
730 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
732 fputs(PQerrormsg, stderr);
733 pqdebug("%s", PQerrormsg);
734 return(STATUS_ERROR);
740 static char *authentication_type_name[] = {
742 "the default authentication type",
746 "host-based authentication",
748 "plaintext password authentication"
751 char *name_of_authentication_type(int type)
755 if(type >= 1 && type <= LAST_AUTHENTICATION_TYPE) {
756 result = authentication_type_name[type];
760 result = "<unknown authentication type>";