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