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 + -
显示快捷键?