1 /*-------------------------------------------------------------------------
4 * functions related to setting up a connection to the backend
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.9 1996/10/10 08:20:09 bryanh Exp $
12 *-------------------------------------------------------------------------
16 #include <sys/types.h>
17 #include <sys/socket.h>
25 #include <libpq/pqcomm.h> /* for decls of MsgType, PacketBuf, StartupInfo */
29 #if defined(PORTNAME_ultrix4) || defined(PORTNAME_next)
30 /* ultrix is lame and doesn't have strdup in libc for some reason */
31 /* [TRH] So doesn't NEXTSTEP. But whaddaya expect for a non-ANSI
32 standard function? (My, my. Touchy today, are we?) */
35 strdup(const char *string)
39 if ((nstr = malloc(strlen(string)+1)) != NULL)
45 /* use a local version instead of the one found in pqpacket.c */
46 static ConnStatusType connectDB(PGconn *conn);
48 static int packetSend(Port *port, PacketBuf *buf, PacketLen len,
50 static void startup2PacketBuf(StartupInfo* s, PacketBuf* res);
51 static void freePGconn(PGconn *conn);
52 static void closePGconn(PGconn *conn);
54 #define NOTIFYLIST_INITIAL_SIZE 10
55 #define NOTIFYLIST_GROWBY 10
60 * establishes a connection to a postgres backend through the postmaster
61 * at the specified host and port.
63 * returns a PGconn* which is needed for all subsequent libpq calls
64 * if the status field of the connection returned is CONNECTION_BAD,
65 * then some fields may be null'ed out instead of having valid values
67 * Uses these environment variables:
69 * PGHOST identifies host to which to connect if <pghost> argument
70 * is NULL or a null string.
72 * PGPORT identifies TCP port to which to connect if <pgport> argument
73 * is NULL or a null string.
75 * PGTTY identifies tty to which to send messages if <pgtty> argument
76 * is NULL or a null string.
78 * PGOPTIONS identifies connection options if <pgoptions> argument is
79 * NULL or a null string.
81 * PGUSER Postgres username to associate with the connection.
83 * PGDATABASE name of database to which to connect if <pgdatabase>
84 * argument is NULL or a null string
86 * None of the above need be defined. There are defaults for all of them.
91 PQsetdb(const char *pghost, const char* pgport, const char* pgoptions, const char* pgtty, const char* dbName)
95 char errorMessage[ERROR_MSG_LENGTH];
96 /* An error message from some service we call. */
98 /* We encountered an error that prevents successful completion */
100 conn = (PGconn*)malloc(sizeof(PGconn));
104 "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
108 conn->Pfdebug = NULL;
110 conn->notifyList = DLNewList();
112 if (!pghost || pghost[0] == '\0') {
113 if (!(tmp = getenv("PGHOST"))) {
116 conn->pghost = strdup(tmp);
118 conn->pghost = strdup(pghost);
120 if (!pgport || pgport[0] == '\0') {
121 if (!(tmp = getenv("PGPORT"))) {
124 conn->pgport = strdup(tmp);
126 conn->pgport = strdup(pgport);
128 if (!pgtty || pgtty[0] == '\0') {
129 if (!(tmp = getenv("PGTTY"))) {
132 conn->pgtty = strdup(tmp);
134 conn->pgtty = strdup(pgtty);
136 if (!pgoptions || pgoptions[0] == '\0') {
137 if (!(tmp = getenv("PGOPTIONS"))) {
140 conn->pgoptions = strdup(tmp);
142 conn->pgoptions = strdup(pgoptions);
144 if (tmp = getenv("PGUSER")) {
146 conn->pguser = strdup(tmp);
148 tmp = fe_getauthname(errorMessage);
151 sprintf(conn->errorMessage,
152 "FATAL: PQsetdb: Unable to determine a Postgres username!\n");
160 if (((tmp = (char *)dbName) && (dbName[0] != '\0')) ||
161 ((tmp = getenv("PGDATABASE")))) {
162 conn->dbName = strdup(tmp);
163 } else conn->dbName = conn->pguser;
164 } else conn->dbName = NULL;
166 if (error) conn->status = CONNECTION_BAD;
168 conn->status = connectDB(conn);
169 /* Puts message in conn->errorMessage */
170 if (conn->status == CONNECTION_OK) {
172 /* Send a blank query to make sure everything works;
173 in particular, that the database exists.
175 res = PQexec(conn," ");
176 if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) {
177 /* PQexec has put error message in conn->errorMessage */
190 * make a connection to the backend so it is ready to receive queries.
191 * return CONNECTION_OK if successful, CONNECTION_BAD if not.
194 static ConnStatusType
195 connectDB(PGconn *conn)
203 int laddrlen = sizeof(struct sockaddr);
204 Port *port = conn->port;
209 // Initialize the startup packet.
211 // This data structure is used for the seq-packet protocol. It
212 // describes the frontend-backend connection.
216 strncpy(startup.user,conn->pguser,sizeof(startup.user));
217 strncpy(startup.database,conn->dbName,sizeof(startup.database));
218 strncpy(startup.tty,conn->pgtty,sizeof(startup.tty));
219 if (conn->pgoptions) {
220 strncpy(startup.options,conn->pgoptions, sizeof(startup.options));
223 startup.options[0]='\0';
224 startup.execFile[0]='\0'; /* not used */
228 // Open a connection to postmaster/backend.
231 port = (Port *) malloc(sizeof(Port));
232 memset((char *) port, 0, sizeof(Port));
234 if (!(hp = gethostbyname(conn->pghost)) || hp->h_addrtype != AF_INET) {
235 (void) sprintf(conn->errorMessage,
236 "connectDB() -- unknown hostname: %s\n",
238 goto connect_errReturn;
240 memset((char *) &port->raddr, 0, sizeof(port->raddr));
241 memmove((char *) &(port->raddr.sin_addr),
244 port->raddr.sin_family = AF_INET;
245 portno = atoi(conn->pgport);
246 port->raddr.sin_port = htons((unsigned short)(portno));
248 /* connect to the server */
249 if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
250 (void) sprintf(conn->errorMessage,
251 "connectDB() -- socket() failed: errno=%d\n%s\n",
252 errno, strerror(errno));
253 goto connect_errReturn;
255 if (connect(port->sock, (struct sockaddr *)&port->raddr,
256 sizeof(port->raddr)) < 0) {
257 (void) sprintf(conn->errorMessage,
258 "connectDB() failed: Is the postmaster running at '%s' on port '%s'?\n",
259 conn->pghost,conn->pgport);
260 goto connect_errReturn;
264 /* fill in the client address */
265 if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
267 (void) sprintf(conn->errorMessage,
268 "connectDB() -- getsockname() failed: errno=%d\n%s\n",
269 errno, strerror(errno));
270 goto connect_errReturn;
273 /* by this point, connection has been opened */
274 msgtype = fe_getauthsvc(conn->errorMessage);
276 /* pacBuf = startup2PacketBuf(&startup);*/
277 startup2PacketBuf(&startup, &pacBuf);
278 pacBuf.msgtype = (MsgType) htonl(msgtype);
279 status = packetSend(port, &pacBuf, sizeof(PacketBuf), BLOCKING);
281 if (status == STATUS_ERROR)
283 sprintf(conn->errorMessage,
284 "connectDB() -- couldn't send complete packet: errno=%d\n%s\n", errno,strerror(errno));
285 goto connect_errReturn;
288 /* authenticate as required*/
289 if (fe_sendauth(msgtype, port, conn->pghost,
290 conn->errorMessage) != STATUS_OK) {
291 (void) sprintf(conn->errorMessage,
292 "connectDB() -- authentication failed with %s\n",
294 goto connect_errReturn;
297 /* set up the socket file descriptors */
298 conn->Pfout = fdopen(port->sock, "w");
299 conn->Pfin = fdopen(dup(port->sock), "r");
300 if (!conn->Pfout || !conn->Pfin) {
301 (void) sprintf(conn->errorMessage,
302 "connectDB() -- fdopen() failed: errno=%d\n%s\n",
303 errno, strerror(errno));
304 goto connect_errReturn;
309 return CONNECTION_OK;
312 return CONNECTION_BAD;
318 * - free the PGconn data structure
322 freePGconn(PGconn *conn)
324 if (conn->pghost) free(conn->pghost);
325 if (conn->pgtty) free(conn->pgtty);
326 if (conn->pgoptions) free(conn->pgoptions);
327 if (conn->pgport) free(conn->pgport);
328 if (conn->dbName) free(conn->dbName);
329 if (conn->pguser) free(conn->pguser);
330 if (conn->notifyList) DLFreeList(conn->notifyList);
336 - properly close a connection to the backend
339 closePGconn(PGconn *conn)
341 const struct sigaction ignore_action = {SIG_IGN, 0, 0, NULL};
342 struct sigaction oldaction;
344 /* If connection is already gone, that's cool. No reason for kernel
345 to kill us when we try to write to it. So ignore SIGPIPE signals.
347 sigaction(SIGPIPE, (struct sigaction *) &ignore_action, &oldaction);
348 fputs("X\0", conn->Pfout);
350 sigaction(SIGPIPE, &oldaction, NULL);
351 if (conn->Pfout) fclose(conn->Pfout);
352 if (conn->Pfin) fclose(conn->Pfin);
353 if (conn->Pfdebug) fclose(conn->Pfdebug);
354 conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */
359 properly close a connection to the backend
360 also frees the PGconn data structure so it shouldn't be re-used
364 PQfinish(PGconn *conn)
367 fprintf(stderr,"PQfinish() -- pointer to PGconn is null");
369 if (conn->status == CONNECTION_OK)
376 resets the connection to the backend
377 closes the existing connection and makes a new one
380 PQreset(PGconn *conn)
383 fprintf(stderr,"PQreset() -- pointer to PGconn is null");
386 conn->status = connectDB(conn);
393 this is just like PacketSend(), defined in backend/libpq/pqpacket.c
394 but we define it here to avoid linking in all of libpq.a
396 * packetSend -- send a single-packet message.
398 * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
399 * SIDE_EFFECTS: may block.
400 * NOTES: Non-blocking writes would significantly complicate
401 * buffer management. For now, we're not going to do it.
405 packetSend(Port *port,
411 int addrLen = sizeof(struct sockaddr_in);
415 len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
416 (struct sockaddr *)&(port->raddr), addrLen);
418 if (len < totalLen) {
419 return(STATUS_ERROR);
426 * startup2PacketBuf()
428 * this is just like StartupInfo2Packet(), defined in backend/libpq/pqpacket.c
429 * but we repeat it here so we don't have to link in libpq.a
431 * converts a StartupInfo structure to a PacketBuf
434 startup2PacketBuf(StartupInfo* s, PacketBuf* res)
438 /* res = (PacketBuf*)malloc(sizeof(PacketBuf)); */
439 res->len = htonl(sizeof(PacketBuf));
440 /* use \n to delimit the strings */
445 strncpy(tmp, s->database, sizeof(s->database));
446 tmp += sizeof(s->database);
447 strncpy(tmp, s->user, sizeof(s->user));
448 tmp += sizeof(s->user);
449 strncpy(tmp, s->options, sizeof(s->options));
450 tmp += sizeof(s->options);
451 strncpy(tmp, s->execFile, sizeof(s->execFile));
452 tmp += sizeof(s->execFile);
453 strncpy(tmp, s->tty, sizeof(s->execFile));
456 /* =========== accessor functions for PGconn ========= */
461 fprintf(stderr,"PQdb() -- pointer to PGconn is null");
471 fprintf(stderr,"PQhost() -- pointer to PGconn is null");
479 PQoptions(PGconn* conn)
482 fprintf(stderr,"PQoptions() -- pointer to PGconn is null");
485 return conn->pgoptions;
492 fprintf(stderr,"PQtty() -- pointer to PGconn is null");
502 fprintf(stderr,"PQport() -- pointer to PGconn is null");
509 PQstatus(PGconn* conn)
512 fprintf(stderr,"PQstatus() -- pointer to PGconn is null");
513 return CONNECTION_BAD;
519 PQerrorMessage(PGconn* conn)
522 fprintf(stderr,"PQerrorMessage() -- pointer to PGconn is null");
525 return conn->errorMessage;
529 PQtrace(PGconn *conn, FILE* debug_port)
532 conn->status == CONNECTION_BAD) {
536 conn->Pfdebug = debug_port;
540 PQuntrace(PGconn *conn)
543 conn->status == CONNECTION_BAD) {
547 fflush(conn->Pfdebug);
548 fclose(conn->Pfdebug);
549 conn->Pfdebug = NULL;