⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fe-connect.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
					 * of this fails.					 */					if (!IS_AF_UNIX(addr_cur->ai_family))					{						if (!connectNoDelay(conn))						{							closesocket(conn->sock);							conn->sock = -1;							conn->addr_cur = addr_cur->ai_next;							continue;						}					}					if (!pg_set_noblock(conn->sock))					{						printfPQExpBuffer(&conn->errorMessage,										  libpq_gettext("could not set socket to non-blocking mode: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));						closesocket(conn->sock);						conn->sock = -1;						conn->addr_cur = addr_cur->ai_next;						continue;					}#ifdef F_SETFD					if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)					{						printfPQExpBuffer(&conn->errorMessage,										  libpq_gettext("could not set socket to close-on-exec mode: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));						closesocket(conn->sock);						conn->sock = -1;						conn->addr_cur = addr_cur->ai_next;						continue;					}#endif   /* F_SETFD */					/*					 * Start/make connection.  This should not block, since we					 * are in nonblock mode.  If it does, well, too bad.					 */					if (connect(conn->sock, addr_cur->ai_addr,								addr_cur->ai_addrlen) < 0)					{						if (SOCK_ERRNO == EINPROGRESS ||							SOCK_ERRNO == EWOULDBLOCK ||							SOCK_ERRNO == EINTR ||							SOCK_ERRNO == 0)						{							/*							 * This is fine - we're in non-blocking mode, and							 * the connection is in progress.  Tell caller to							 * wait for write-ready on socket.							 */							conn->status = CONNECTION_STARTED;							return PGRES_POLLING_WRITING;						}						/* otherwise, trouble */					}					else					{						/*						 * Hm, we're connected already --- seems the "nonblock						 * connection" wasn't.  Advance the state machine and						 * go do the next stuff.						 */						conn->status = CONNECTION_STARTED;						goto keep_going;					}					/*					 * This connection failed --- set up error report, then					 * close socket (do it this way in case close() affects					 * the value of errno...).	We will ignore the connect()					 * failure and keep going if there are more addresses.					 */					connectFailureMessage(conn, SOCK_ERRNO);					if (conn->sock >= 0)					{						closesocket(conn->sock);						conn->sock = -1;					}					/*					 * Try the next address, if any.					 */					conn->addr_cur = addr_cur->ai_next;				}				/* loop over addresses */				/*				 * Ooops, no more addresses.  An appropriate error message is				 * already set up, so just set the right status.				 */				goto error_return;			}		case CONNECTION_STARTED:			{				int			optval;				ACCEPT_TYPE_ARG3 optlen = sizeof(optval);				/*				 * Write ready, since we've made it here, so the connection				 * has been made ... or has failed.				 */				/*				 * Now check (using getsockopt) that there is not an error				 * state waiting for us on the socket.				 */				if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,							   (char *) &optval, &optlen) == -1)				{					printfPQExpBuffer(&conn->errorMessage,					libpq_gettext("could not get socket error status: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));					goto error_return;				}				else if (optval != 0)				{					/*					 * When using a nonblocking connect, we will typically see					 * connect failures at this point, so provide a friendly					 * error message.					 */					connectFailureMessage(conn, optval);					/*					 * If more addresses remain, keep trying, just as in the					 * case where connect() returned failure immediately.					 */					if (conn->addr_cur->ai_next != NULL)					{						if (conn->sock >= 0)						{							closesocket(conn->sock);							conn->sock = -1;						}						conn->addr_cur = conn->addr_cur->ai_next;						conn->status = CONNECTION_NEEDED;						goto keep_going;					}					goto error_return;				}				/* Fill in the client address */				conn->laddr.salen = sizeof(conn->laddr.addr);				if (getsockname(conn->sock,								(struct sockaddr *) & conn->laddr.addr,								&conn->laddr.salen) < 0)				{					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext("could not get client address from socket: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));					goto error_return;				}				/*				 * Make sure we can write before advancing to next step.				 */				conn->status = CONNECTION_MADE;				return PGRES_POLLING_WRITING;			}		case CONNECTION_MADE:			{				char	   *startpacket;				int			packetlen;#ifdef USE_SSL				/*				 * If SSL is enabled and we haven't already got it running,				 * request it instead of sending the startup message.				 */				if (IS_AF_UNIX(conn->raddr.addr.ss_family))				{					/* Don't bother requesting SSL over a Unix socket */					conn->allow_ssl_try = false;				}				if (conn->allow_ssl_try && !conn->wait_ssl_try &&					conn->ssl == NULL)				{					ProtocolVersion pv;					/*					 * Send the SSL request packet.					 *					 * Theoretically, this could block, but it really					 * shouldn't since we only got here if the socket is					 * write-ready.					 */					pv = htonl(NEGOTIATE_SSL_CODE);					if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)					{						printfPQExpBuffer(&conn->errorMessage,										  libpq_gettext("could not send SSL negotiation packet: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));						goto error_return;					}					/* Ok, wait for response */					conn->status = CONNECTION_SSL_STARTUP;					return PGRES_POLLING_READING;				}#endif   /* USE_SSL */				/*				 * Build the startup packet.				 */				if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)					startpacket = pqBuildStartupPacket3(conn, &packetlen,														EnvironmentOptions);				else					startpacket = pqBuildStartupPacket2(conn, &packetlen,														EnvironmentOptions);				if (!startpacket)				{					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext("out of memory\n"));					goto error_return;				}				/*				 * Send the startup packet.				 *				 * Theoretically, this could block, but it really shouldn't				 * since we only got here if the socket is write-ready.				 */				if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)				{					printfPQExpBuffer(&conn->errorMessage,						libpq_gettext("could not send startup packet: %s\n"),							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));					free(startpacket);					goto error_return;				}				free(startpacket);				conn->status = CONNECTION_AWAITING_RESPONSE;				return PGRES_POLLING_READING;			}			/*			 * Handle SSL negotiation: wait for postmaster messages and			 * respond as necessary.			 */		case CONNECTION_SSL_STARTUP:			{#ifdef USE_SSL				PostgresPollingStatusType pollres;				/*				 * On first time through, get the postmaster's response to our				 * SSL negotiation packet.				 */				if (conn->ssl == NULL)				{					/*					 * We use pqReadData here since it has the logic to					 * distinguish no-data-yet from connection closure. Since					 * conn->ssl isn't set, a plain recv() will occur.					 */					char		SSLok;					int			rdresult;					rdresult = pqReadData(conn);					if (rdresult < 0)					{						/* errorMessage is already filled in */						goto error_return;					}					if (rdresult == 0)					{						/* caller failed to wait for data */						return PGRES_POLLING_READING;					}					if (pqGetc(&SSLok, conn) < 0)					{						/* should not happen really */						return PGRES_POLLING_READING;					}					/* mark byte consumed */					conn->inStart = conn->inCursor;					if (SSLok == 'S')					{						/* Do one-time setup; this creates conn->ssl */						if (pqsecure_initialize(conn) == -1)							goto error_return;					}					else if (SSLok == 'N')					{						if (conn->sslmode[0] == 'r')	/* "require" */						{							/* Require SSL, but server does not want it */							printfPQExpBuffer(&conn->errorMessage,											  libpq_gettext("server does not support SSL, but SSL was required\n"));							goto error_return;						}						/* Otherwise, proceed with normal startup */						conn->allow_ssl_try = false;						conn->status = CONNECTION_MADE;						return PGRES_POLLING_WRITING;					}					else if (SSLok == 'E')					{						/* Received error - probably protocol mismatch */						if (conn->Pfdebug)							fprintf(conn->Pfdebug, "received error from server, attempting fallback to pre-7.0\n");						if (conn->sslmode[0] == 'r')	/* "require" */						{							/* Require SSL, but server is too old */							printfPQExpBuffer(&conn->errorMessage,											  libpq_gettext("server does not support SSL, but SSL was required\n"));							goto error_return;						}						/* Otherwise, try again without SSL */						conn->allow_ssl_try = false;						/* Assume it ain't gonna handle protocol 3, either */						conn->pversion = PG_PROTOCOL(2, 0);						/* Must drop the old connection */						closesocket(conn->sock);						conn->sock = -1;						conn->status = CONNECTION_NEEDED;						goto keep_going;					}					else					{						printfPQExpBuffer(&conn->errorMessage,										  libpq_gettext("received invalid response to SSL negotiation: %c\n"),										  SSLok);						goto error_return;					}				}				/*				 * Begin or continue the SSL negotiation process.				 */				pollres = pqsecure_open_client(conn);				if (pollres == PGRES_POLLING_OK)				{					/* SSL handshake done, ready to send startup packet */					conn->status = CONNECTION_MADE;					return PGRES_POLLING_WRITING;				}				return pollres;#else							/* !USE_SSL */				/* can't get here */				goto error_return;#endif   /* USE_SSL */			}			/*			 * Handle authentication exchange: wait for postmaster messages			 * and respond as necessary.			 */		case CONNECTION_AWAITING_RESPONSE:			{				char		beresp;				int			msgLength;				int			avail;				AuthRequest areq;				/*				 * Scan the message from current point (note that if we find				 * the message is incomplete, we will return without advancing				 * inStart, and resume here next time).				 */				conn->inCursor = conn->inStart;				/* Read type byte */				if (pqGetc(&beresp, conn))				{					/* We'll come back when there is more data */					return PGRES_POLLING_READING;				}				/*				 * Validate message type: we expect only an authentication				 * request or an error here.  Anything else probably means				 * it's not Postgres on the other end at all.				 */				if (!(beresp == 'R' || beresp == 'E'))				{					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext(									  "expected authentication request from "												"server, but received %c\n"),									  beresp);					goto error_return;				}				if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)				{					/* Read message length word */					if (pqGetInt(&msgLength, 4, conn))					{						/* We'll come back when there is more data */						return PGRES_POLLING_READING;					}				}				else				{					/* Set phony message length to disable checks below */					msgLength = 8;				}				/*				 * Try to validate message length before using it.				 * Authentication requests can't be very large.  Errors can be				 * a little larger, but not huge.  If we see a large apparent				 * length in an error, it means we're really talking to a				 * pre-3.0-protocol server; cope.				 */				if (beresp == 'R' && (msgLength < 8 || msgLength > 100))				{					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext(									  "expected authentication request from "												"server, but received %c\n"),									  beresp);					goto error_return;				}				if (beresp == 'E' && (msgLength < 8 || msgLength > 30000))				{					/* Handle error from a pre-3.0 server */					conn->inCursor = conn->inStart + 1; /* reread data */					if (pqGets(&conn->errorMessage, conn))					{						/* We'll come back when there is more data */						return PGRES_POLLING_READING;					}					/* OK, we read the message; mark data consumed */					conn->inStart = conn->inCursor;					/*					 * The postmaster typically won't end its message with a					 * newline, so add one to conform to libpq conventions.					 */					appendPQExpBufferChar(&conn->errorMessage, '\n');					/*					 * If we tried to open the connection in 3.0 protocol,					 * fall back to 2.0 protocol.					 */					if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)					{						conn->pversion = PG_PROTOCOL(2, 0);						/* Must drop the old connection */						pqsecure_close(conn);						closesocket(conn->sock);						conn->sock = -1;						conn->status = CONNECTION_NEEDED;						goto keep_going;					}					goto error_return;				}				/*				 * Can't process if message body isn't all here yet.				 *				 * (In protocol 2.0 case, we are assuming messages carry at				 * least 4 bytes of data.)				 */				msgLength -= 4;				avail = conn->inEnd - conn->inCursor;				if (avail < msgLength)				{					/*					 * Before returning, try to enlarge the input buffer if					 * needed to hold the whole message; see notes in					 * pqParseInput3.					 */					if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))						goto error_return;					/* We'll come back when there is more data */					return PGRES_POLLING_READING;				}				/* Handle errors. */				if (beresp == 'E')				{					if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)					{						if (pqGetErrorNotice3(conn, true))						{							/* We'll come back when there is more data */							return PGRES_POLLING_READING;						}					}					else					{						if (pqGets(&conn->errorMessage, conn))						{							/* We'll come back when there is more data */							return PGRES_POLLING_READING;						}					}					/* OK, we read the message; mark data consumed */					conn->inStart = conn->inCursor;#ifdef USE_SSL					/*					 * if sslmode is "allow" and we haven't tried an SSL					 * connection already, then retry with an SSL connection					 */					if (conn->sslmode[0] == 'a' /* "allow" */						&& conn->ssl == NULL						&& conn->allow_ssl_try						&& conn->wait_ssl_try)					{						/* only retry once */						conn->wait_ssl_try = false;						/* Must drop the old connection */						closesocket(conn->sock);						conn->sock = -1;						conn->status = CONNECTION_NEEDED;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -