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