]> granicus.if.org Git - postgresql/blob - src/backend/libpq/pqcomm.c
Inline memset() as MemSet().
[postgresql] / src / backend / libpq / pqcomm.c
1  /*-------------------------------------------------------------------------
2  *
3  * pqcomm.c--
4  *        Communication functions between the Frontend and the Backend
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.23 1997/09/18 20:20:39 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * INTERFACE ROUTINES
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.
31  *
32  * NOTES
33  *              These functions are used by both frontend applications and
34  *              the postgres backend.
35  *
36  */
37 #include <stdio.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <unistd.h>                             /* for ttyname() */
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <arpa/inet.h>
49
50 #if defined(linux)
51 #ifndef SOMAXCONN
52 #define SOMAXCONN 5                             /* from Linux listen(2) man page */
53 #endif                                                  /* SOMAXCONN */
54 #endif                                                  /* linux */
55
56 #include <postgres.h>
57
58 #include <libpq/pqsignal.h>
59 #include <libpq/auth.h>
60 #include <libpq/libpq.h>                /* where the declarations go */
61
62 /* ----------------
63  *              declarations
64  * ----------------
65  */
66 FILE       *Pfout,
67                    *Pfin;
68 FILE       *Pfdebug;                    /* debugging libpq */
69 int                     PQAsyncNotifyWaiting;           /* for async. notification */
70
71 /* --------------------------------
72  *              pq_init - open portal file descriptors
73  * --------------------------------
74  */
75 void
76 pq_init(int fd)
77 {
78         Pfin = fdopen(fd, "r");
79         Pfout = fdopen(dup(fd), "w");
80         if (!Pfin || !Pfout)
81                 elog(FATAL, "pq_init: Couldn't initialize socket connection");
82         PQnotifies_init();
83         if (getenv("LIBPQ_DEBUG"))
84         {
85                 Pfdebug = stderr;
86         }
87         else
88         {
89                 Pfdebug = NULL;
90         }
91 }
92
93 /* -------------------------
94  *       pq_getc(File* fin)
95  *
96  *       get a character from the input file,
97  *
98  *       if Pfdebug is set, also echo the character fetched into Pfdebug
99  *
100  *       used for debugging libpq
101  */
102 static int
103 pq_getc(FILE *fin)
104 {
105         int                     c;
106
107         c = getc(fin);
108         if (Pfdebug && c != EOF)
109                 putc(c, Pfdebug);
110         return c;
111 }
112
113 /* --------------------------------
114  *              pq_gettty - return the name of the tty in the given buffer
115  * --------------------------------
116  */
117 void
118 pq_gettty(char *tp)
119 {
120         strncpy(tp, ttyname(0), 19);
121 }
122
123 /* --------------------------------
124  *              pq_getport - return the PGPORT setting
125  * --------------------------------
126  */
127 int
128 pq_getport()
129 {
130         char       *envport = getenv("PGPORT");
131
132         if (envport)
133                 return (atoi(envport));
134         return (atoi(DEF_PGPORT));
135 }
136
137 /* --------------------------------
138  *              pq_close - close input / output connections
139  * --------------------------------
140  */
141 void
142 pq_close()
143 {
144         if (Pfin)
145         {
146                 fclose(Pfin);
147                 Pfin = NULL;
148         }
149         if (Pfout)
150         {
151                 fclose(Pfout);
152                 Pfout = NULL;
153         }
154         PQAsyncNotifyWaiting = 0;
155         PQnotifies_init();
156         pq_unregoob();
157 }
158
159 /* --------------------------------
160  *              pq_flush - flush pending output
161  * --------------------------------
162  */
163 void
164 pq_flush()
165 {
166         if (Pfout)
167                 fflush(Pfout);
168 }
169
170 /* --------------------------------
171  *              pq_getstr - get a null terminated string from connection
172  * --------------------------------
173  */
174 int
175 pq_getstr(char *s, int maxlen)
176 {
177         int                     c = '\0';
178
179         if (Pfin == (FILE *) NULL)
180         {
181 /*              elog(DEBUG, "Input descriptor is null"); */
182                 return (EOF);
183         }
184
185         while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
186                 *s++ = c;
187         *s = '\0';
188
189         /* -----------------
190          *         If EOF reached let caller know.
191          *         (This will only happen if we hit EOF before the string
192          *         delimiter is reached.)
193          * -----------------
194          */
195         if (c == EOF)
196                 return (EOF);
197         return (!EOF);
198 }
199
200 /*
201  * USER FUNCTION - gets a newline-terminated string from the backend.
202  *
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.
205  *
206  * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
207  * the terminating \n (like gets(3)).
208  *
209  * RETURNS:
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.)
215  *              1 in other cases
216  */
217 int
218 PQgetline(char *s, int maxlen)
219 {
220         if (!Pfin || !s || maxlen <= 1)
221                 return (EOF);
222
223         if (fgets(s, maxlen - 1, Pfin) == NULL)
224         {
225                 return feof(Pfin) ? EOF : 1;
226         }
227         else
228         {
229                 for (; *s; s++)
230                 {
231                         if (*s == '\n')
232                         {
233                                 *s = '\0';
234                                 break;
235                         }
236                 }
237         }
238
239         return 0;
240 }
241
242 /*
243  * USER FUNCTION - sends a string to the backend.
244  *
245  * Chiefly here so that applications can use "COPY <rel> from stdin".
246  *
247  * RETURNS:
248  *              0 in all cases.
249  */
250 int
251 PQputline(char *s)
252 {
253         if (Pfout)
254         {
255                 fputs(s, Pfout);
256                 fflush(Pfout);
257         }
258         return (0);
259 }
260
261 /* --------------------------------
262  *              pq_getnchar - get n characters from connection
263  * --------------------------------
264  */
265 int
266 pq_getnchar(char *s, int off, int maxlen)
267 {
268         return pqGetNBytes(s + off, maxlen, Pfin);
269
270 #if 0
271         int                     c = '\0';
272
273         if (Pfin == (FILE *) NULL)
274         {
275 /*              elog(DEBUG, "Input descriptor is null"); */
276                 return (EOF);
277         }
278
279         s += off;
280         while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
281                 *s++ = c;
282
283         /* -----------------
284          *         If EOF reached let caller know
285          * -----------------
286          */
287         if (c == EOF)
288                 return (EOF);
289         return (!EOF);
290 #endif
291 }
292
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
297  *       other
298  * --------------------------------
299  */
300 int
301 pq_getint(int b)
302 {
303         int                     n,
304                                 status = 1;
305
306         if (!Pfin)
307                 return EOF;
308
309         /*
310          * mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
311          * EOF is a valid return value for an int! XXX
312          */
313
314         switch (b)
315         {
316                 case 1:
317                         status = ((n = fgetc(Pfin)) == EOF);
318                         break;
319                 case 2:
320                         status = pqGetShort(&n, Pfin);
321                         break;
322                 case 4:
323                         status = pqGetLong(&n, Pfin);
324                         break;
325                 default:
326                         fprintf(stderr, "** Unsupported size %d\n", b);
327         }
328
329         if (status)
330         {
331                 sprintf(PQerrormsg,
332                                 "FATAL: pq_getint failed: errno=%d\n", errno);
333                 fputs(PQerrormsg, stderr);
334                 pqdebug("%s", PQerrormsg);
335                 n = 0;
336         }
337
338         return n;
339 }
340
341 /* --------------------------------
342  *              pq_putstr - send a null terminated string to connection
343  * --------------------------------
344  */
345 void
346 pq_putstr(char *s)
347 {
348         if (pqPutString(s, Pfout))
349         {
350                 sprintf(PQerrormsg,
351                                 "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
352                 fputs(PQerrormsg, stderr);
353                 pqdebug("%s", PQerrormsg);
354         }
355 }
356
357 /* --------------------------------
358  *              pq_putnchar - send n characters to connection
359  * --------------------------------
360  */
361 void
362 pq_putnchar(char *s, int n)
363 {
364         if (pqPutNBytes(s, n, Pfout))
365         {
366                 sprintf(PQerrormsg,
367                                 "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
368                                 errno);
369                 fputs(PQerrormsg, stderr);
370                 pqdebug("%s", PQerrormsg);
371         }
372 }
373
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
378  *       other
379  * --------------------------------
380  */
381 void
382 pq_putint(int i, int b)
383 {
384         int                     status;
385
386         if (!Pfout)
387                 return;
388
389         status = 1;
390         switch (b)
391         {
392                 case 1:
393                         status = (fputc(i, Pfout) == EOF);
394                         break;
395                 case 2:
396                         status = pqPutShort(i, Pfout);
397                         break;
398                 case 4:
399                         status = pqPutLong(i, Pfout);
400                         break;
401                 default:
402                         fprintf(stderr, "** Unsupported size %d\n", b);
403         }
404
405         if (status)
406         {
407                 sprintf(PQerrormsg,
408                                 "FATAL: pq_putint failed: errno=%d\n", errno);
409                 fputs(PQerrormsg, stderr);
410                 pqdebug("%s", PQerrormsg);
411         }
412 }
413
414 /* ---
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.
419  * ---
420  */
421 int
422 pq_sendoob(char *msg, int len)
423 {
424         int                     fd = fileno(Pfout);
425
426         return (send(fd, msg, len, MSG_OOB));
427 }
428
429 int
430 pq_recvoob(char *msgPtr, int *lenPtr)
431 {
432         int                     fd = fileno(Pfout);
433         int                     len = 0;
434
435         len = recv(fd, msgPtr + len, *lenPtr, MSG_OOB);
436         *lenPtr = len;
437         return (len);
438 }
439
440 /* --------------------------------
441  *              pq_getinaddr - initialize address from host and port number
442  * --------------------------------
443  */
444 int
445 pq_getinaddr(struct sockaddr_in * sin,
446                          char *host,
447                          int port)
448 {
449         struct hostent *hs;
450
451         MemSet((char *) sin, 0, sizeof(*sin));
452
453         if (host)
454         {
455                 if (*host >= '0' && *host <= '9')
456                         sin->sin_addr.s_addr = inet_addr(host);
457                 else
458                 {
459                         if (!(hs = gethostbyname(host)))
460                         {
461                                 perror(host);
462                                 return (1);
463                         }
464                         if (hs->h_addrtype != AF_INET)
465                         {
466                                 sprintf(PQerrormsg,
467                                                 "FATAL: pq_getinaddr: %s not on Internet\n",
468                                                 host);
469                                 fputs(PQerrormsg, stderr);
470                                 pqdebug("%s", PQerrormsg);
471                                 return (1);
472                         }
473                         memmove((char *) &sin->sin_addr,
474                                         hs->h_addr,
475                                         hs->h_length);
476                 }
477         }
478         sin->sin_family = AF_INET;
479         sin->sin_port = htons(port);
480         return (0);
481 }
482
483 /* --------------------------------
484  *              pq_getinserv - initialize address from host and servive name
485  * --------------------------------
486  */
487 int
488 pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
489 {
490         struct servent *ss;
491
492         if (*serv >= '0' && *serv <= '9')
493                 return (pq_getinaddr(sin, host, atoi(serv)));
494         if (!(ss = getservbyname(serv, NULL)))
495         {
496                 sprintf(PQerrormsg,
497                                 "FATAL: pq_getinserv: unknown service: %s\n",
498                                 serv);
499                 fputs(PQerrormsg, stderr);
500                 pqdebug("%s", PQerrormsg);
501                 return (1);
502         }
503         return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
504 }
505
506 /*
507  * register an out-of-band listener proc--at most one allowed.
508  * This is used for receiving async. notification from the backend.
509  */
510 void
511 pq_regoob(void (*fptr) ())
512 {
513         int                     fd = fileno(Pfout);
514
515 #if defined(hpux)
516         ioctl(fd, FIOSSAIOOWN, getpid());
517 #elif defined(sco)
518         ioctl(fd, SIOCSPGRP, getpid());
519 #else
520         fcntl(fd, F_SETOWN, getpid());
521 #endif                                                  /* hpux */
522         pqsignal(SIGURG, fptr);
523 }
524
525 void
526 pq_unregoob()
527 {
528         pqsignal(SIGURG, SIG_DFL);
529 }
530
531
532 void
533 pq_async_notify()
534 {
535         char            msg[20];
536
537         /* int len = sizeof(msg); */
538         int                     len = 20;
539
540         if (pq_recvoob(msg, &len) >= 0)
541         {
542                 /* debugging */
543                 printf("received notification: %s\n", msg);
544                 PQAsyncNotifyWaiting = 1;
545                 /* PQappendNotify(msg+1); */
546         }
547         else
548         {
549                 extern int      errno;
550
551                 printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
552         }
553 }
554
555 /*
556  * Streams -- wrapper around Unix socket system calls
557  *
558  *
559  *              Stream functions are used for vanilla TCP connection protocol.
560  */
561
562 /*
563  * StreamServerPort -- open a sock stream "listening" port.
564  *
565  * This initializes the Postmaster's connection
566  *              accepting port.
567  *
568  * ASSUME: that this doesn't need to be non-blocking because
569  *              the Postmaster uses select() to tell when the socket
570  *              is ready.
571  *
572  * RETURNS: STATUS_OK or STATUS_ERROR
573  */
574 int
575 StreamServerPort(char *hostName, short portName, int *fdP)
576 {
577         struct sockaddr_in sin;
578         int                     fd;
579         int                     one = 1;
580
581
582         if (!hostName)
583                 hostName = "localhost";
584
585         MemSet((char *) &sin, 0, sizeof sin);
586
587         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
588         {
589                 sprintf(PQerrormsg,
590                                 "FATAL: StreamServerPort: socket() failed: errno=%d\n",
591                                 errno);
592                 fputs(PQerrormsg, stderr);
593                 pqdebug("%s", PQerrormsg);
594                 return (STATUS_ERROR);
595         }
596
597         if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
598                                         sizeof(one))) == -1)
599         {
600                 sprintf(PQerrormsg,
601                                 "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
602                                 errno);
603                 fputs(PQerrormsg, stderr);
604                 pqdebug("%s", PQerrormsg);
605                 return (STATUS_ERROR);
606         }
607
608         sin.sin_family = AF_INET;
609         sin.sin_port = htons(portName);
610
611         if (bind(fd, (struct sockaddr *) & sin, sizeof sin) < 0)
612         {
613                 sprintf(PQerrormsg,
614                                 "FATAL: StreamServerPort: bind() failed: errno=%d\n",
615                                 errno);
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);
621         }
622
623         listen(fd, SOMAXCONN);
624
625         /*
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
628          * bugs).
629          *
630          * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
631          */
632
633         *fdP = fd;
634         return (STATUS_OK);
635 }
636
637 /*
638  * StreamConnection -- create a new connection with client using
639  *              server port.
640  *
641  * This one should be non-blocking.
642  *
643  * RETURNS: STATUS_OK or STATUS_ERROR
644  */
645 int
646 StreamConnection(int server_fd, Port *port)
647 {
648         int                     addrlen;
649
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,
654                                                          &addrlen)) < 0)
655         {
656                 elog(WARN, "postmaster: StreamConnection: accept: %m");
657                 return (STATUS_ERROR);
658         }
659
660         /* fill in the server (local) address */
661         addrlen = sizeof(struct sockaddr_in);
662         if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
663                                         &addrlen) < 0)
664         {
665                 elog(WARN, "postmaster: StreamConnection: getsockname: %m");
666                 return (STATUS_ERROR);
667         }
668         {
669                 struct protoent *pe;
670                 int                     on = 1;
671
672                 pe = getprotobyname("TCP");
673                 if (pe == NULL)
674                 {
675                         elog(WARN, "postmaster: getprotobyname failed");
676                         return (STATUS_ERROR);
677                 }
678                 if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
679                                            &on, sizeof(on)) < 0)
680                 {
681                         elog(WARN, "postmaster: setsockopt failed");
682                         return (STATUS_ERROR);
683                 }
684         }
685
686         port->mask = 1 << port->sock;
687
688         /* reset to non-blocking */
689         fcntl(port->sock, F_SETFL, 1);
690
691         return (STATUS_OK);
692 }
693
694 /*
695  * StreamClose -- close a client/backend connection
696  */
697 void
698 StreamClose(int sock)
699 {
700         close(sock);
701 }
702
703 /* ---------------------------
704  * StreamOpen -- From client, initiate a connection with the
705  *              server (Postmaster).
706  *
707  * RETURNS: STATUS_OK or STATUS_ERROR
708  *
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  * ---------------------------
713  */
714 int
715 StreamOpen(char *hostName, short portName, Port *port)
716 {
717         struct hostent *hp;
718         int                     laddrlen = sizeof(struct sockaddr_in);
719         extern int      errno;
720
721         if (!hostName)
722                 hostName = "localhost";
723
724         /* set up the server (remote) address */
725         if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
726         {
727                 sprintf(PQerrormsg,
728                                 "FATAL: StreamOpen: unknown hostname: %s\n",
729                                 hostName);
730                 fputs(PQerrormsg, stderr);
731                 pqdebug("%s", PQerrormsg);
732                 return (STATUS_ERROR);
733         }
734         MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
735         memmove((char *) &(port->raddr.sin_addr),
736                         (char *) hp->h_addr,
737                         hp->h_length);
738         port->raddr.sin_family = AF_INET;
739         port->raddr.sin_port = htons(portName);
740
741         /* connect to the server */
742         if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
743         {
744                 sprintf(PQerrormsg,
745                                 "FATAL: StreamOpen: socket() failed: errno=%d\n",
746                                 errno);
747                 fputs(PQerrormsg, stderr);
748                 pqdebug("%s", PQerrormsg);
749                 return (STATUS_ERROR);
750         }
751         if (connect(port->sock, (struct sockaddr *) & port->raddr,
752                                 sizeof(port->raddr)) < 0)
753         {
754                 sprintf(PQerrormsg,
755                                 "FATAL: StreamOpen: connect() failed: errno=%d\n",
756                                 errno);
757                 fputs(PQerrormsg, stderr);
758                 pqdebug("%s", PQerrormsg);
759                 return (STATUS_ERROR);
760         }
761
762         /* fill in the client address */
763         if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
764                                         &laddrlen) < 0)
765         {
766                 sprintf(PQerrormsg,
767                                 "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
768                                 errno);
769                 fputs(PQerrormsg, stderr);
770                 pqdebug("%s", PQerrormsg);
771                 return (STATUS_ERROR);
772         }
773
774         return (STATUS_OK);
775 }
776
777 static char *authentication_type_name[] = {
778         0, 0, 0, 0, 0, 0, 0,
779         "the default authentication type",
780         0, 0,
781         "Kerberos v4",
782         "Kerberos v5",
783         "host-based authentication",
784         "unauthenication",
785         "plaintext password authentication"
786 };
787
788 char       *
789 name_of_authentication_type(int type)
790 {
791         char       *result = 0;
792
793         if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
794         {
795                 result = authentication_type_name[type];
796         }
797
798         if (result == 0)
799         {
800                 result = "<unknown authentication type>";
801         }
802
803         return result;
804 }