fe-connect.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,647 行 · 第 1/5 页
C
2,647 行
* Allocate memory for the conn structure */ conn = makeEmptyPGconn(); if (conn == NULL) return (PGconn *) NULL; /* * Parse an empty conninfo string in order to set up the same defaults * that PQconnectdb() would use. */ if (!connectOptions1(conn, "")) return conn; /* * Absorb specified options into conn structure, overriding defaults */ if (pghost && pghost[0] != '\0') { if (conn->pghost) free(conn->pghost); conn->pghost = strdup(pghost); } if (pgport && pgport[0] != '\0') { if (conn->pgport) free(conn->pgport); conn->pgport = strdup(pgport); } if (pgoptions && pgoptions[0] != '\0') { if (conn->pgoptions) free(conn->pgoptions); conn->pgoptions = strdup(pgoptions); } if (pgtty && pgtty[0] != '\0') { if (conn->pgtty) free(conn->pgtty); conn->pgtty = strdup(pgtty); } if (dbName && dbName[0] != '\0') { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(dbName); } if (login && login[0] != '\0') { if (conn->pguser) free(conn->pguser); conn->pguser = strdup(login); } if (pwd && pwd[0] != '\0') { if (conn->pgpass) free(conn->pgpass); conn->pgpass = strdup(pwd); } /* * Compute derived options */ if (!connectOptions2(conn)) return conn; /* * Connect to the database */ if (connectDBStart(conn)) (void) connectDBComplete(conn); return conn;}#ifdef NOT_USED /* because it's broken *//* * update_db_info - * get all additional info out of dbName */static intupdate_db_info(PGconn *conn){ char *tmp, *tmp2, *old = conn->dbName; if (strchr(conn->dbName, '@') != NULL) { /* old style: dbname[@server][:port] */ tmp = strrchr(conn->dbName, ':'); if (tmp != NULL) /* port number given */ { if (conn->pgport) free(conn->pgport); conn->pgport = strdup(tmp + 1); *tmp = '\0'; } tmp = strrchr(conn->dbName, '@'); if (tmp != NULL) /* host name given */ { if (conn->pghost) free(conn->pghost); conn->pghost = strdup(tmp + 1); *tmp = '\0'; } conn->dbName = strdup(old); free(old); } else { int offset; /* * only allow protocols tcp and unix */ if (strncmp(conn->dbName, "tcp:", 4) == 0) offset = 4; else if (strncmp(conn->dbName, "unix:", 5) == 0) offset = 5; else return 0; if (strncmp(conn->dbName + offset, "postgresql://", strlen("postgresql://")) == 0) { /*------- * new style: * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:] * [/db name][?options] *------- */ offset += strlen("postgresql://"); tmp = strrchr(conn->dbName + offset, '?'); if (tmp != NULL) /* options given */ { if (conn->pgoptions) free(conn->pgoptions); conn->pgoptions = strdup(tmp + 1); *tmp = '\0'; } tmp = last_path_separator(conn->dbName + offset); if (tmp != NULL) /* database name given */ { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(tmp + 1); *tmp = '\0'; } else { /* * Why do we default only this value from the environment * again? */ if ((tmp = getenv("PGDATABASE")) != NULL) { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(tmp); } else if (conn->pguser) { if (conn->dbName) free(conn->dbName); conn->dbName = strdup(conn->pguser); } } tmp = strrchr(old + offset, ':'); if (tmp != NULL) /* port number or Unix socket path given */ { *tmp = '\0'; if ((tmp2 = strchr(tmp + 1, ':')) != NULL) { if (strncmp(old, "unix:", 5) != 0) { printfPQExpBuffer(&conn->errorMessage, "connectDBStart() -- " "socket name can only be specified with " "non-TCP\n"); return 1; } *tmp2 = '\0'; if (conn->pgunixsocket) free(conn->pgunixsocket); conn->pgunixsocket = strdup(tmp + 1); } else { if (conn->pgport) free(conn->pgport); conn->pgport = strdup(tmp + 1); if (conn->pgunixsocket) free(conn->pgunixsocket); conn->pgunixsocket = NULL; } } if (strncmp(old, "unix:", 5) == 0) { if (conn->pghost) free(conn->pghost); conn->pghost = NULL; if (strcmp(old + offset, "localhost") != 0) { printfPQExpBuffer(&conn->errorMessage, "connectDBStart() -- " "non-TCP access only possible on " "localhost\n"); return 1; } } else { if (conn->pghost) free(conn->pghost); conn->pghost = strdup(old + offset); } free(old); } } return 0;}#endif /* NOT_USED *//* ---------- * connectMakeNonblocking - * Make a connection non-blocking. * Returns 1 if successful, 0 if not. * ---------- */static intconnectMakeNonblocking(PGconn *conn){ if (FCNTL_NONBLOCK(conn->sock) < 0) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to non-blocking mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } return 1;}/* ---------- * connectNoDelay - * Sets the TCP_NODELAY socket option. * Returns 1 if successful, 0 if not. * ---------- */static intconnectNoDelay(PGconn *conn){#ifdef TCP_NODELAY int on = 1; if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to TCP no delay mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; }#endif return 1;}/* ---------- * connectFailureMessage - * create a friendly error message on connection failure. * ---------- */static voidconnectFailureMessage(PGconn *conn, int errorno){ char sebuf[256];#ifdef HAVE_UNIX_SOCKETS if (IS_AF_UNIX(conn->raddr.addr.ss_family)) { char service[NI_MAXHOST]; getnameinfo_all(&conn->raddr.addr, conn->raddr.salen, NULL, 0, service, sizeof(service), NI_NUMERICSERV); printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "could not connect to server: %s\n" "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n" ), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), service); } else#endif /* HAVE_UNIX_SOCKETS */ { printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "could not connect to server: %s\n" "\tIs the server running on host \"%s\" and accepting\n" "\tTCP/IP connections on port %s?\n" ), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), conn->pghostaddr ? conn->pghostaddr : (conn->pghost ? conn->pghost : "???"), conn->pgport); }}/* ---------- * connectDBStart - * Begin the process of making a connection to the backend. * * Returns 1 if successful, 0 if not. * ---------- */static intconnectDBStart(PGconn *conn){ int portnum; char portstr[128]; struct addrinfo *addrs = NULL; struct addrinfo hint; const char *node = NULL; int ret; if (!conn) return 0; /* Ensure our buffers are empty */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; /* * Determine the parameters to pass to getaddrinfo_all. */ /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; hint.ai_family = AF_UNSPEC; /* Set up port number as a string */ if (conn->pgport != NULL && conn->pgport[0] != '\0') portnum = atoi(conn->pgport); else portnum = DEF_PGPORT; snprintf(portstr, sizeof(portstr), "%d", portnum); if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') { /* Using pghostaddr avoids a hostname lookup */ node = conn->pghostaddr; hint.ai_family = AF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; } else if (conn->pghost != NULL && conn->pghost[0] != '\0') { /* Using pghost, so we have to look-up the hostname */ node = conn->pghost; hint.ai_family = AF_UNSPEC; }#ifdef HAVE_UNIX_SOCKETS else { /* pghostaddr and pghost are NULL, so use Unix domain socket */ node = NULL; hint.ai_family = AF_UNIX; UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); }#endif /* HAVE_UNIX_SOCKETS */ /* Use getaddrinfo_all() to resolve the address */ ret = getaddrinfo_all(node, portstr, &hint, &addrs); if (ret || !addrs) { if (node) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not translate host name \"%s\" to address: %s\n"), node, gai_strerror(ret)); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), portstr, gai_strerror(ret)); freeaddrinfo_all(hint.ai_family, addrs); goto connect_errReturn; }#ifdef USE_SSL /* setup values based on SSL mode */ if (conn->sslmode[0] == 'd') /* "disable" */ conn->allow_ssl_try = false; else if (conn->sslmode[0] == 'a') /* "allow" */ conn->wait_ssl_try = true;#endif /* * Set up to try to connect, with protocol 3.0 as the first attempt. */ conn->addrlist = addrs; conn->addr_cur = addrs; conn->addrlist_family = hint.ai_family; conn->pversion = PG_PROTOCOL(3, 0); conn->status = CONNECTION_NEEDED; /* * The code for processing CONNECTION_NEEDED state is in * PQconnectPoll(), so that it can easily be re-executed if needed * again during the asynchronous startup process. However, we must * run it once here, because callers expect a success return from this * routine to mean that we are in PGRES_POLLING_WRITING connection * state. */ if (PQconnectPoll(conn) == PGRES_POLLING_WRITING) return 1;connect_errReturn: if (conn->sock >= 0) { pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; } conn->status = CONNECTION_BAD; return 0;}/* * connectDBComplete * * Block and complete a connection. * * Returns 1 on success, 0 on failure. */static intconnectDBComplete(PGconn *conn){ PostgresPollingStatusType flag = PGRES_POLLING_WRITING; time_t finish_time = ((time_t) -1); if (conn == NULL || conn->status == CONNECTION_BAD) return 0; /* * Set up a time limit, if connect_timeout isn't zero. */ if (conn->connect_timeout != NULL) { int timeout = atoi(conn->connect_timeout); if (timeout > 0) { /* * Rounding could cause connection to fail; need at least 2 * secs */ if (timeout < 2) timeout = 2; /* calculate the finish time based on start + timeout */ finish_time = time(NULL) + timeout; } } for (;;) { /* * Wait, if necessary. Note that the initial state (just after * PQconnectStart) is to wait for the socket to select for * writing. */ switch (flag) { case PGRES_POLLING_OK: return 1; /* success! */ case PGRES_POLLING_READING: if (pqWaitTimed(1, 0, conn, finish_time)) { conn->status = CONNECTION_BAD; return 0; } break; case PGRES_POLLING_WRITING: if (pqWaitTimed(0, 1, conn, finish_time)) { conn->status = CONNECTION_BAD; return 0; } break; default: /* Just in case we failed to set it in PQconnectPoll */ conn->status = CONNECTION_BAD; return 0; } /* * Now try to advance the state machine. */ flag = PQconnectPoll(conn);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?