fe-connect.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,647 行 · 第 1/5 页
C
2,647 行
/*------------------------------------------------------------------------- * * fe-connect.c * functions related to setting up a connection to the backend * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.263.2.1 2003/12/19 23:32:36 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres_fe.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <ctype.h>#include <time.h>#ifndef HAVE_STRDUP#include "strdup.h"#endif#include "libpq-fe.h"#include "libpq-int.h"#include "fe-auth.h"#ifdef WIN32#include "win32.h"#else#include <sys/socket.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#include <arpa/inet.h>#endif#include "libpq/ip.h"#include "mb/pg_wchar.h"/* For FNCTL_NONBLOCK */#if defined(WIN32) || defined(__BEOS__)long ioctlsocket_ret=1;#endif#define PGPASSFILE ".pgpass"/* 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 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 */ /* 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);/* * 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 (PGconn *) 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 ... */ 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 /* * 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; }#ifdef NOT_USED /* * parse dbName to get all additional info in it, if any */ if (update_db_info(conn) != 0) { conn->status = CONNECTION_BAD; /* errorMessage is already set */ return false; }#endif /* * 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 * and should be freed when no longer needed via PQconninfoFree(). (In prior * versions, the returned array was static, but that's not thread-safe.) * Pre-7.0 applications that use this function will see a small memory leak * until they are updated to call PQconninfoFree. */PQconninfoOption *PQconndefaults(void){ PQExpBufferData errorBuf; PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); connOptions = conninfo_parse("", &errorBuf); termPQExpBuffer(&errorBuf); return connOptions;}/* ---------------- * PQsetdbLogin * * establishes a connection to a postgres backend through the postmaster * at the specified host and port. * * returns a PGconn* which is needed for all subsequent libpq calls * * if the status field of the connection returned is CONNECTION_BAD, * then only the errorMessage is likely to be useful. * ---------------- */PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd){ PGconn *conn; /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?