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.8 1996/11/15 09:54:28 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.
43 #include <unistd.h> /* for ttyname() */
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
55 #define SOMAXCONN 5 /* from Linux listen(2) man page */
56 #endif /* SOMAXCONN */
61 #include <libpq/pqsignal.h> /* substitute for <signal.h> */
62 #include <libpq/auth.h>
63 #include <libpq/libpq.h> /* where the declarations go */
70 FILE *Pfdebug; /* debugging libpq */
71 int PQAsyncNotifyWaiting; /* for async. notification */
73 /* --------------------------------
74 * pq_init - open portal file descriptors
75 * --------------------------------
83 in = _open_osfhandle(fd, _O_RDONLY);
84 out = _open_osfhandle(fd, _O_APPEND);
85 Pfin = fdopen(in, "rb");
86 Pfout = fdopen(out, "wb");
88 Pfin = fdopen(fd, "r");
89 Pfout = fdopen(dup(fd), "w");
92 elog(FATAL, "pq_init: Couldn't initialize socket connection");
94 if (getenv("LIBPQ_DEBUG")) {
101 /* -------------------------
104 * get a character from the input file,
106 * if Pfdebug is set, also echo the character fetched into Pfdebug
108 * used for debugging libpq
116 if (Pfdebug && c != EOF)
121 /* --------------------------------
122 * pq_gettty - return the name of the tty in the given buffer
123 * --------------------------------
128 (void) strncpy(tp, ttyname(0), 19);
131 /* --------------------------------
132 * pq_getport - return the PGPORT setting
133 * --------------------------------
138 char *envport = getenv("PGPORT");
141 return(atoi(envport));
142 return(atoi(DEF_PGPORT));
145 /* --------------------------------
146 * pq_close - close input / output connections
147 * --------------------------------
160 PQAsyncNotifyWaiting = 0;
165 /* --------------------------------
166 * pq_flush - flush pending output
167 * --------------------------------
176 /* --------------------------------
177 * pq_getstr - get a null terminated string from connection
178 * --------------------------------
181 pq_getstr(char *s, int maxlen)
185 if (Pfin == (FILE *) NULL) {
186 /* elog(DEBUG, "Input descriptor is null"); */
190 while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
195 * If EOF reached let caller know.
196 * (This will only happen if we hit EOF before the string
197 * delimiter is reached.)
206 * USER FUNCTION - gets a newline-terminated string from the backend.
208 * Chiefly here so that applications can use "COPY <rel> to stdout"
209 * and read the output string. Returns a null-terminated string in s.
211 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
212 * the terminating \n (like gets(3)).
215 * EOF if it is detected or invalid arguments are given
216 * 0 if EOL is reached (i.e., \n has been read)
217 * (this is required for backward-compatibility -- this
218 * routine used to always return EOF or 0, assuming that
219 * the line ended within maxlen bytes.)
223 PQgetline(char *s, int maxlen)
227 if (!Pfin || !s || maxlen <= 1)
230 for (; maxlen > 1 && (c = pq_getc(Pfin)) != '\n' && c != EOF; --maxlen) {
236 return(EOF); /* error -- reached EOF before \n */
237 } else if (c == '\n') {
238 return(0); /* done with this line */
240 return(1); /* returning a full buffer */
244 * USER FUNCTION - sends a string to the backend.
246 * Chiefly here so that applications can use "COPY <rel> from stdin".
255 (void) fputs(s, Pfout);
261 /* --------------------------------
262 * pq_getnchar - get n characters from connection
263 * --------------------------------
266 pq_getnchar(char *s, int off, int maxlen)
270 if (Pfin == (FILE *) NULL) {
271 /* elog(DEBUG, "Input descriptor is null"); */
276 while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
280 * If EOF reached let caller know
288 /* --------------------------------
289 * pq_getint - get an integer from connection
290 * we receive an integer a byte at a type and reconstruct it so that
291 * machines with different ENDIAN representations can talk to each
293 * --------------------------------
300 if (Pfin == (FILE *) NULL) {
301 /* elog(DEBUG, "pq_getint: Input descriptor is null"); */
306 while (b-- && (c = pq_getc(Pfin)) != EOF && p < 32) {
307 n |= (c & 0xff) << p;
314 /* --------------------------------
315 * pq_putstr - send a null terminated string to connection
316 * --------------------------------
324 status = fputs(s, Pfout);
326 (void) sprintf(PQerrormsg,
327 "FATAL: pq_putstr: fputs() failed: errno=%d\n",
329 fputs(PQerrormsg, stderr);
330 pqdebug("%s", PQerrormsg);
332 status = fputc('\0', Pfout);
334 (void) sprintf(PQerrormsg,
335 "FATAL: pq_putstr: fputc() failed: errno=%d\n",
337 fputs(PQerrormsg, stderr);
338 pqdebug("%s", PQerrormsg);
343 /* --------------------------------
344 * pq_putnchar - send n characters to connection
345 * --------------------------------
348 pq_putnchar(char *s, int n)
354 status = fputc(*s++, Pfout);
356 (void) sprintf(PQerrormsg,
357 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
359 fputs(PQerrormsg, stderr);
360 pqdebug("%s", PQerrormsg);
366 /* --------------------------------
367 * pq_putint - send an integer to connection
368 * we chop an integer into bytes and send individual bytes
369 * machines with different ENDIAN representations can still talk to each
371 * --------------------------------
374 pq_putint(int i, int b)
383 status = fputc(i & 0xff, Pfout);
386 (void) sprintf(PQerrormsg,
387 "FATAL: pq_putint: fputc() failed: errno=%d\n",
389 fputs(PQerrormsg, stderr);
390 pqdebug("%s", PQerrormsg);
397 * pq_sendoob - send a string over the out-of-band channel
398 * pq_recvoob - receive a string over the oob channel
399 * NB: Fortunately, the out-of-band channel doesn't conflict with
400 * buffered I/O because it is separate from regular com. channel.
404 pq_sendoob(char *msg, int len)
406 int fd = fileno(Pfout);
408 return(send(fd,msg,len,MSG_OOB));
412 pq_recvoob(char *msgPtr, int *lenPtr)
414 int fd = fileno(Pfout);
417 len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
422 /* --------------------------------
423 * pq_getinaddr - initialize address from host and port number
424 * --------------------------------
427 pq_getinaddr(struct sockaddr_in *sin,
433 memset((char *) sin, 0, sizeof(*sin));
436 if (*host >= '0' && *host <= '9')
437 sin->sin_addr.s_addr = inet_addr(host);
439 if (!(hs = gethostbyname(host))) {
443 if (hs->h_addrtype != AF_INET) {
444 (void) sprintf(PQerrormsg,
445 "FATAL: pq_getinaddr: %s not on Internet\n",
447 fputs(PQerrormsg, stderr);
448 pqdebug("%s", PQerrormsg);
451 memmove((char *) &sin->sin_addr,
456 sin->sin_family = AF_INET;
457 sin->sin_port = htons(port);
461 /* --------------------------------
462 * pq_getinserv - initialize address from host and servive name
463 * --------------------------------
466 pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
470 if (*serv >= '0' && *serv <= '9')
471 return(pq_getinaddr(sin, host, atoi(serv)));
472 if (!(ss = getservbyname(serv, NULL))) {
473 (void) sprintf(PQerrormsg,
474 "FATAL: pq_getinserv: unknown service: %s\n",
476 fputs(PQerrormsg, stderr);
477 pqdebug("%s", PQerrormsg);
480 return(pq_getinaddr(sin, host, ntohs(ss->s_port)));
484 * register an out-of-band listener proc--at most one allowed.
485 * This is used for receiving async. notification from the backend.
488 pq_regoob(void (*fptr)())
491 /* Who knows what to do here? */
494 int fd = fileno(Pfout);
496 ioctl(fd, FIOSSAIOOWN, getpid());
498 fcntl(fd, F_SETOWN, getpid());
500 (void) signal(SIGURG,fptr);
508 signal(SIGURG,SIG_DFL);
517 /* int len = sizeof(msg);*/
520 if (pq_recvoob(msg,&len) >= 0) {
522 printf("received notification: %s\n",msg);
523 PQAsyncNotifyWaiting = 1;
524 /* PQappendNotify(msg+1);*/
527 printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
532 * Streams -- wrapper around Unix socket system calls
535 * Stream functions are used for vanilla TCP connection protocol.
539 * StreamServerPort -- open a sock stream "listening" port.
541 * This initializes the Postmaster's connection
544 * ASSUME: that this doesn't need to be non-blocking because
545 * the Postmaster uses select() to tell when the socket
548 * RETURNS: STATUS_OK or STATUS_ERROR
551 StreamServerPort(char *hostName, short portName, int *fdP)
553 struct sockaddr_in sin;
558 /* This is necessary to make it possible for a backend to use
559 ** stdio to read from the socket.
561 int optionvalue = SO_SYNCHRONOUS_NONALERT;
563 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionvalue,
564 sizeof(optionvalue));
568 hostName = "localhost";
570 memset((char *)&sin, 0, sizeof sin);
572 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
573 (void) sprintf(PQerrormsg,
574 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
576 fputs(PQerrormsg, stderr);
577 pqdebug("%s", PQerrormsg);
578 return(STATUS_ERROR);
581 if((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
582 sizeof(one))) == -1) {
583 (void) sprintf(PQerrormsg,
584 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
586 fputs(PQerrormsg, stderr);
587 pqdebug("%s", PQerrormsg);
588 return(STATUS_ERROR);
591 sin.sin_family = AF_INET;
592 sin.sin_port = htons(portName);
594 if (bind(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
595 (void) sprintf(PQerrormsg,
596 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
598 pqdebug("%s", PQerrormsg);
599 (void) strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
600 (void) strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
601 fputs(PQerrormsg, stderr);
602 return(STATUS_ERROR);
605 listen(fd, SOMAXCONN);
607 /* MS: I took this code from Dillon's version. It makes the
608 * listening port non-blocking. That is not necessary (and
609 * may tickle kernel bugs).
611 (void) fcntl(fd, F_SETFD, 1);
612 (void) fcntl(fd, F_SETFL, FNDELAY);
620 * StreamConnection -- create a new connection with client using
623 * This one should be non-blocking.
625 * RETURNS: STATUS_OK or STATUS_ERROR
628 StreamConnection(int server_fd, Port *port)
632 /* accept connection (and fill in the client (remote) address) */
633 addrlen = sizeof(struct sockaddr_in);
634 if ((port->sock = accept(server_fd,
635 (struct sockaddr *) &port->raddr,
637 elog(WARN, "postmaster: StreamConnection: accept: %m");
638 return(STATUS_ERROR);
641 /* fill in the server (local) address */
642 addrlen = sizeof(struct sockaddr_in);
643 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
645 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
646 return(STATUS_ERROR);
649 port->mask = 1 << port->sock;
652 /* reset to non-blocking */
653 fcntl(port->sock, F_SETFL, 1);
660 * StreamClose -- close a client/backend connection
663 StreamClose(int sock)
668 /* ---------------------------
669 * StreamOpen -- From client, initiate a connection with the
670 * server (Postmaster).
672 * RETURNS: STATUS_OK or STATUS_ERROR
674 * NOTE: connection is NOT established just because this
675 * routine exits. Local state is ok, but we haven't
676 * spoken to the postmaster yet.
677 * ---------------------------
680 StreamOpen(char *hostName, short portName, Port *port)
683 int laddrlen = sizeof(struct sockaddr_in);
687 hostName = "localhost";
689 /* set up the server (remote) address */
690 if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET) {
691 (void) sprintf(PQerrormsg,
692 "FATAL: StreamOpen: unknown hostname: %s\n",
694 fputs(PQerrormsg, stderr);
695 pqdebug("%s", PQerrormsg);
696 return(STATUS_ERROR);
698 memset((char *) &port->raddr, 0, sizeof(port->raddr));
699 memmove((char *) &(port->raddr.sin_addr),
702 port->raddr.sin_family = AF_INET;
703 port->raddr.sin_port = htons(portName);
705 /* connect to the server */
706 if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
707 (void) sprintf(PQerrormsg,
708 "FATAL: StreamOpen: socket() failed: errno=%d\n",
710 fputs(PQerrormsg, stderr);
711 pqdebug("%s", PQerrormsg);
712 return(STATUS_ERROR);
714 if (connect(port->sock, (struct sockaddr *)&port->raddr,
715 sizeof(port->raddr)) < 0) {
716 (void) sprintf(PQerrormsg,
717 "FATAL: StreamOpen: connect() failed: errno=%d\n",
719 fputs(PQerrormsg, stderr);
720 pqdebug("%s", PQerrormsg);
721 return(STATUS_ERROR);
724 /* fill in the client address */
725 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
727 (void) sprintf(PQerrormsg,
728 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
730 fputs(PQerrormsg, stderr);
731 pqdebug("%s", PQerrormsg);
732 return(STATUS_ERROR);