Hello!

We are seeing connection failures when using "sslmode=require" on forked
connections.  Attached is example code that makes 2 passes. The first pass
uses "sslmode=disable" and the second uses "sslmode=require".  The first
pass completes successfully, but the second pass fails.  I'm looking for
insight as to why this might be happening.

Note: we are very aware of the dev notes about forking, however know that
we are not sharing the forked connection, we simply open the connection in
the parent thread and then pass that to the child thread to use.

Thank you for any insight,

-Jim P.
/*
 gcc -I/usr/include/postgresql -L/usr/lib/postgresql/12/lib -o pq-test 
pq-test.c -lpq
*/

#include <libpq-fe.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>

/* Sample output:
** pottmi@ubuntu ~/src
** % ./pq-test
** [37095] with sslmode=require:
** [37095] Calling New()
** [37097] Calling Exec()
** [37098] Calling Exec()
** [37098] Error in results: PGRES_FATAL_ERROR
** 
** [37095] with sslmode=disable:
** [37095] Calling New()
** [37100] Calling Exec()
** [37101] Calling Exec()
** pottmi@ubuntu ~/src
** 
** pottmi@ubuntu ~/src
** % uname -a
** Linux ubuntu 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 
2022 x86_64 x86_64 x86_64 GNU/Linux
** pottmi@ubuntu ~/src
** % cat /etc/debian_version
** bullseye/sid
** pottmi@ubuntu ~/src
*/


char *connectwillfail = 
"postgresql://kicktest:changeme@localhost:5432/kicktest?sslmode=require";
char *connectwillsucceed = 
"postgresql://kicktest:changeme@localhost:5432/kicktest?sslmode=disable";
char *sql = "select count(*) from information_schema.tables where table_schema 
= 'public'";

PGconn *New(const char *connectstr)
{
   PGconn *con;
   printf("[%d] Calling New()\n", getpid());
   con = PQconnectdb(connectstr);
   if (PQstatus(con) != CONNECTION_OK)
   {
      printf("[%d] could not connect to %s because %s\n", getpid(),
                     connectstr, PQerrorMessage(con));
   }

   return(con);
}

void Exec(PGconn *con, char *sql)
{
   printf("[%d] Calling Exec()\n", getpid());
   PGresult *result;
   ExecStatusType status;

   result = PQexec(con, sql);
   status = PQresultStatus(result);

   if (status != PGRES_TUPLES_OK)
   {
      printf("[%d] Error in results: %s\n", getpid(), PQresStatus(status));
   }
   PQclear(result);
}

void runit(const char *connectstring)
{

   int status;
   // Allocate connection in parent, but we will not use it in the parent 
process.
   PGconn *con = New(connectstring);

   int pid = fork();

   if (pid == 0) // Child process
   {
      // use connection in first child.
      Exec(con, sql);
      exit(0);
   }
   else if (pid > 0) // Parent process
   {
      int pidrtn = wait(&status);
   }
   else // if (pid < 0)  // Error
   {
         printf("[%d] Failed to fork! (errno=%d)\n", pid, errno);
         exit(1);
   }

   pid = fork();
   if (pid == 0) // Child process
   {
      // use connection in a second child.
      Exec(con, sql);
      exit(0);
   }
   else if (pid > 0) // Parent process
   {
      int pidrtn = wait(&status);
   }
   else // if (pid < 0)  // Error
   {
         printf("[%d] Failed to fork! (errno=%d)\n", pid, errno);
         exit(1);
   }

   PQfinish(con);
}

void main(void)
{
   printf("[%d] with sslmode=require:\n", getpid());
   runit(connectwillfail);
   printf("\n[%d] with sslmode=disable:\n", getpid());
   runit(connectwillsucceed);
}

Reply via email to