📄 fe-connect.c
字号:
* 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 + -