📄 fe-connect.c
字号:
/*------------------------------------------------------------------------- * * fe-connect.c * functions related to setting up a connection to the backend * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.323.2.2 2006/05/21 20:19:44 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres_fe.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <ctype.h>#include <time.h>#ifndef WIN32_CLIENT_ONLY#include <unistd.h>#endif#ifndef HAVE_STRDUP#include "strdup.h"#endif#include "libpq-fe.h"#include "libpq-int.h"#include "fe-auth.h"#include "pg_config_paths.h"#ifdef WIN32#include "win32.h"#ifdef _WIN32_IE#undef _WIN32_IE#endif#define _WIN32_IE 0x0500#ifdef near#undef near#endif#define near#include <shlobj.h>#else#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#include <arpa/inet.h>#endif#ifdef ENABLE_THREAD_SAFETY#ifdef WIN32#include "pthread-win32.h"#else#include <pthread.h>#endif#endif#include "libpq/ip.h"#include "mb/pg_wchar.h"#ifndef FD_CLOEXEC#define FD_CLOEXEC 1#endif#ifndef WIN32#define PGPASSFILE ".pgpass"#else#define PGPASSFILE "pgpass.conf"#endif/* fall back options if they are not specified by arguments or defined by environment variables */#define DefaultHost "localhost"#define DefaultTty ""#define DefaultOption ""#define DefaultAuthtype ""#define DefaultPassword ""#ifdef USE_SSL#define DefaultSSLMode "prefer"#else#define DefaultSSLMode "disable"#endif/* ---------- * Definition of the conninfo parameters and their fallback resources. * * If Environment-Var and Compiled-in are specified as NULL, no * fallback is available. If after all no value can be determined * for an option, an error is returned. * * The value for the username is treated specially in conninfo_parse. * If the Compiled-in resource is specified as a NULL value, the * user is determined by pg_fe_getauthname(). * * The Label and Disp-Char entries are provided for applications that * want to use PQconndefaults() to create a generic database connection * dialog. Disp-Char is defined as follows: * "" Normal input field * "*" Password field - hide value * "D" Debug option - don't show by default * * PQconninfoOptions[] is a constant static array that we use to initialize * a dynamically allocated working copy. All the "val" fields in * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val" * fields point to malloc'd strings that should be freed when the working * array is freed (see PQconninfoFree). * ---------- */static const PQconninfoOption PQconninfoOptions[] = { /* * "authtype" is no longer used, so mark it "don't show". We keep it in * the array so as not to reject conninfo strings from old apps that might * still try to set it. */ {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL, "Database-Authtype", "D", 20}, {"service", "PGSERVICE", NULL, NULL, "Database-Service", "", 20}, {"user", "PGUSER", NULL, NULL, "Database-User", "", 20}, {"password", "PGPASSWORD", NULL, NULL, "Database-Password", "*", 20}, {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL, "Connect-timeout", "", 10}, /* strlen(INT32_MAX) == 10 */ {"dbname", "PGDATABASE", NULL, NULL, "Database-Name", "", 20}, {"host", "PGHOST", NULL, NULL, "Database-Host", "", 40}, {"hostaddr", "PGHOSTADDR", NULL, NULL, "Database-Host-IP-Address", "", 45}, {"port", "PGPORT", DEF_PGPORT_STR, NULL, "Database-Port", "", 6}, /* * "tty" is no longer used either, but keep it present for backwards * compatibility. */ {"tty", "PGTTY", DefaultTty, NULL, "Backend-Debug-TTY", "D", 40}, {"options", "PGOPTIONS", DefaultOption, NULL, "Backend-Debug-Options", "D", 40},#ifdef USE_SSL /* * "requiressl" is deprecated, its purpose having been taken over by * "sslmode". It remains for backwards compatibility. */ {"requiressl", "PGREQUIRESSL", "0", NULL, "Require-SSL", "D", 1},#endif /* * "sslmode" option is allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". */ {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL, "SSL-Mode", "", 8}, /* sizeof("disable") == 8 */#ifdef KRB5 /* Kerberos authentication supports specifying the service name */ {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, "Kerberos-service-name", "", 20},#endif /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0}};static const PQEnvironmentOption EnvironmentOptions[] ={ /* common user-interface settings */ { "PGDATESTYLE", "datestyle" }, { "PGTZ", "timezone" }, { "PGCLIENTENCODING", "client_encoding" }, /* internal performance-related settings */ { "PGGEQO", "geqo" }, { NULL, NULL }};static bool connectOptions1(PGconn *conn, const char *conninfo);static bool connectOptions2(PGconn *conn);static int connectDBStart(PGconn *conn);static int connectDBComplete(PGconn *conn);static PGconn *makeEmptyPGconn(void);static void freePGconn(PGconn *conn);static void closePGconn(PGconn *conn);static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage);static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword);static void defaultNoticeReceiver(void *arg, const PGresult *res);static void defaultNoticeProcessor(void *arg, const char *message);static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage);static char *pwdfMatchesString(char *buf, char *token);static char *PasswordFromFile(char *hostname, char *port, char *dbname, char *username);static void default_threadlock(int acquire);/* global variable because fe-auth.c needs to access it */pgthreadlock_t pg_g_threadlock = default_threadlock;/* * Connecting to a Database * * There are now four different ways a user of this API can connect to the * database. Two are not recommended for use in new code, because of their * lack of extensibility with respect to the passing of options to the * backend. These are PQsetdb and PQsetdbLogin (the former now being a macro * to the latter). * * If it is desired to connect in a synchronous (blocking) manner, use the * function PQconnectdb. * * To connect in an asynchronous (non-blocking) manner, use the functions * PQconnectStart, and PQconnectPoll. * * Internally, the static functions connectDBStart, connectDBComplete * are part of the connection procedure. *//* * PQconnectdb * * establishes a connection to a postgres backend through the postmaster * using connection information in a string. * * The conninfo string is a white-separated list of * * option = value * * definitions. Value might be a single value containing no whitespaces or * a single quoted string. If a single quote should appear anywhere in * the value, it must be escaped with a backslash like \' * * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL * if a memory allocation failed. * If the status field of the connection returned is CONNECTION_BAD, * then some fields may be null'ed out instead of having valid values. * * You should call PQfinish (if conn is not NULL) regardless of whether this * call succeeded. */PGconn *PQconnectdb(const char *conninfo){ PGconn *conn = PQconnectStart(conninfo); if (conn && conn->status != CONNECTION_BAD) (void) connectDBComplete(conn); return conn;}/* * PQconnectStart * * Begins the establishment of a connection to a postgres backend through the * postmaster using connection information in a string. * * See comment for PQconnectdb for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status * field of the connection returned is CONNECTION_BAD, an error has * occurred. In this case you should call PQfinish on the result, (perhaps * inspecting the error message first). Other fields of the structure may not * be valid if that occurs. If the status field is not CONNECTION_BAD, then * this stage has succeeded - call PQconnectPoll, using select(2) to see when * this is necessary. * * See PQconnectPoll for more info. */PGconn *PQconnectStart(const char *conninfo){ PGconn *conn; /* * Allocate memory for the conn structure */ conn = makeEmptyPGconn(); if (conn == NULL) return NULL; /* * Parse the conninfo string */ if (!connectOptions1(conn, conninfo)) return conn; /* * Compute derived options */ if (!connectOptions2(conn)) return conn; /* * Connect to the database */ if (!connectDBStart(conn)) { /* Just in case we failed to set it in connectDBStart */ conn->status = CONNECTION_BAD; } return conn;}/* * connectOptions1 * * Internal subroutine to set up connection parameters given an already- * created PGconn and a conninfo string. Derived settings should be * processed by calling connectOptions2 next. (We split them because * PQsetdbLogin overrides defaults in between.) * * Returns true if OK, false if trouble (in which case errorMessage is set * and so is conn->status). */static boolconnectOptions1(PGconn *conn, const char *conninfo){ PQconninfoOption *connOptions; char *tmp; /* * Parse the conninfo string */ connOptions = conninfo_parse(conninfo, &conn->errorMessage); if (connOptions == NULL) { conn->status = CONNECTION_BAD; /* errorMessage is already set */ return false; } /* * Move option values into conn structure * * Don't put anything cute here --- intelligence should be in * connectOptions2 ... * * XXX: probably worth checking strdup() return value here... */ tmp = conninfo_getval(connOptions, "hostaddr"); conn->pghostaddr = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "host"); conn->pghost = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "port"); conn->pgport = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "tty"); conn->pgtty = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "options"); conn->pgoptions = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "dbname"); conn->dbName = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "user"); conn->pguser = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "password"); conn->pgpass = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "connect_timeout"); conn->connect_timeout = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslmode"); conn->sslmode = tmp ? strdup(tmp) : NULL;#ifdef USE_SSL tmp = conninfo_getval(connOptions, "requiressl"); if (tmp && tmp[0] == '1') { /* here warn that the requiressl option is deprecated? */ if (conn->sslmode) free(conn->sslmode); conn->sslmode = strdup("require"); }#endif#ifdef KRB5 tmp = conninfo_getval(connOptions, "krbsrvname"); conn->krbsrvname = tmp ? strdup(tmp) : NULL;#endif /* * Free the option info - all is in conn now */ PQconninfoFree(connOptions); return true;}/* * connectOptions2 * * Compute derived connection options after absorbing all user-supplied info. * * Returns true if OK, false if trouble (in which case errorMessage is set * and so is conn->status). */static boolconnectOptions2(PGconn *conn){ /* * If database name was not given, default it to equal user name */ if ((conn->dbName == NULL || conn->dbName[0] == '\0') && conn->pguser != NULL) { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(conn->pguser); } /* * Supply default password if none given */ if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { if (conn->pgpass) free(conn->pgpass); conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport, conn->dbName, conn->pguser); if (conn->pgpass == NULL) conn->pgpass = strdup(DefaultPassword); } /* * Allow unix socket specification in the host name */ if (conn->pghost && is_absolute_path(conn->pghost)) { if (conn->pgunixsocket) free(conn->pgunixsocket); conn->pgunixsocket = conn->pghost; conn->pghost = NULL; } /* * validate sslmode option */ if (conn->sslmode) { if (strcmp(conn->sslmode, "disable") != 0 && strcmp(conn->sslmode, "allow") != 0 && strcmp(conn->sslmode, "prefer") != 0 && strcmp(conn->sslmode, "require") != 0) { conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid sslmode value: \"%s\"\n"), conn->sslmode); return false; }#ifndef USE_SSL switch (conn->sslmode[0]) { case 'a': /* "allow" */ case 'p': /* "prefer" */ /* * warn user that an SSL connection will never be negotiated * since SSL was not compiled in? */ break; case 'r': /* "require" */ conn->status = CONNECTION_BAD; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), conn->sslmode); return false; }#endif } else conn->sslmode = strdup(DefaultSSLMode); return true;}/* * PQconndefaults * * Parse an empty string like PQconnectdb() would do and return the * working connection options array. * * Using this function, an application may determine all possible options * and their current default values. * * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -