static int parseServiceInfo()

in src/pgclient/src/interfaces/libpq/fe-connect.c [364:569]


static int parseServiceInfo(PQconninfoOption *options,
				 PQExpBuffer errorMessage);
static int parseServiceFile(const char *serviceFile,
				 const char *service,
				 PQconninfoOption *options,
				 PQExpBuffer errorMessage,
				 bool *group_found);
static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
				 char *username);
static bool getPgPassFilename(char *pgpassfile);
static void dot_pg_pass_warning(PGconn *conn);
static void default_threadlock(int acquire);

// Defined in ClientSideCursorExecutor.h
struct _ClientSideCursorExecutor *createCscExecutor(PGconn *pConn);
struct _ClientSideCursorExecutor *releaseCscExecutor(struct _ClientSideCursorExecutor *pCscExecutor);

static int connect_using_proxy(int sock, PGconn* conn);


/* global variable because fe-auth.c needs to access it */
pgthreadlock_t pg_g_threadlock = default_threadlock;


/*
*
* Connects to a socket by proxy. Completes the SOCKS5 protocol.
*/
static
int connect_using_proxy(int sock, PGconn* conn)
{
	RS_LOG_TRACE("FECNN", "%s", __func__);
	char buffer[4096];
	char *ptr = buffer;
	int res;
	int responseLen;
	time_t now;
    time_t finish_time;
	/* Deprecated. 
	   Generic connection/login timeout used in connectDBComplete and
	   PQconnectPoll should not be used for proxy timeout.
	int timeout = conn->connect_timeout ? atoi(conn->connect_timeout) : -1;
	*/
	static const int PROXY_LOGIN_TIMEOUT_SECONDS = 5;
	int timeout = PROXY_LOGIN_TIMEOUT_SECONDS;

	// HTTP CONNECT method
	const char* HTTP_CONNECT_REQUEST = "CONNECT ";
	const size_t CONNECT_REQUEST_LEN = 8;

	// Request header which contains the credentials to authenticate a user agent to a proxy server
	const char* HTTP_PROXY_AUTH = "Proxy-Authorization: ";
	const size_t HTTP_PROXY_AUTH_LEN = 21;

	// Host: note that hostname and IP are different keys. Refer to class PGOClient.
	// PGOUtils::IsIpAddress(m_settings.m_host) ? "hostaddr" : "host"
	const char* destname = (conn->pghostaddr ? conn->pghostaddr :
		(conn->pghost ? conn->pghost : "localhost"));
	size_t destnamelen = strlen(destname);

	// Port
	const char* port = conn->pgport ? conn->pgport : "5439";
	
	size_t portlen = strlen(port);

	// Proxy authentication type
	const char* authtype = conn->proxy_auth_type ? conn->proxy_auth_type : "Basic";
	size_t authtypelen = strlen(authtype);

	// Proxy credentials (base64 encoded string)
	const char* credentials = conn->proxy_credentials ? conn->proxy_credentials : "";
	size_t credentialslen = strlen(credentials);

    if (!conn->proxy_host || !*conn->proxy_host)
    {
        return connect(sock, (struct sockaddr *) &conn->raddr.addr, conn->raddr.salen);
    }
    res = connect(sock, (struct sockaddr *) &conn->paddr.addr, conn->paddr.salen);
	if (res < 0)
	{
		if (SOCK_ERRNO == EINPROGRESS ||
#ifdef WIN32
			SOCK_ERRNO == EWOULDBLOCK ||
#endif
			SOCK_ERRNO == EINTR)
		{
			/*
			* This is fine - we're in non-blocking mode, and
			* the connection is in progress.
			* Poll until we can write.
			*/
			if (pqWaitTimed(0, 1, conn, -1) < 0)
			{
				return res;
			}
		}
		else
		{
			conn->status = CONNECTION_BAD;
			return res;
		}
	}

	/*
	* Send the HTTP connect request. Formatted:
	* CONNECT <destination>:<port> HTTP/1.1\r\n
	*/
	memcpy(ptr, HTTP_CONNECT_REQUEST, CONNECT_REQUEST_LEN);
	ptr += CONNECT_REQUEST_LEN;
	memcpy(ptr, destname, destnamelen);
	ptr += destnamelen;
	*ptr++ = ':';
	memcpy(ptr, port, portlen);
	ptr += portlen;
	*ptr++ = ' ';
	memcpy(ptr, "HTTP/1.1", 8);
	ptr += 8;
	*ptr++ = '\r';
	*ptr++ = '\n';

	/*
	* Add Proxy-Authorization request header if credentials is required. Formatted:
	* Proxy-Authorization: <authtype> <credentials>\r\n
	*/
	if (credentialslen > 0)
	{
		memcpy(ptr, HTTP_PROXY_AUTH, HTTP_PROXY_AUTH_LEN);
		ptr += HTTP_PROXY_AUTH_LEN;
		memcpy(ptr, authtype, authtypelen);
		ptr += authtypelen;
		*ptr++ = ' ';
		memcpy(ptr, credentials, credentialslen);
		ptr += credentialslen;
		*ptr++ = '\r';
		*ptr++ = '\n';
	}

	/* Add CRLF to end the HTTP message */
	*ptr++ = '\r';
	*ptr++ = '\n';

	/* Send these bytes to the server */
retry1:
	if (send(sock, buffer, ptr - buffer, 0) < 0)
	{
		if (SOCK_ERRNO == EINTR)
			/* Interrupted system call - we'll just try again */
			goto retry1;
		else
		{
			appendPQExpBuffer(&conn->errorMessage,
				libpq_gettext("could not send data to proxy server."));
			conn->status = CONNECTION_BAD;
			return -1;
		}
	}

	/* 2. Get the response from the server.
	Should be "HTTP/1.1 200 Connection established\r\n" */
retry2:
    // Get the current time
    time(&now);
    // Add 5 seconds to the current time
    finish_time = now + timeout;
	if (pqWaitTimed(1, 0, conn, finish_time) < 0)
	{
		RS_LOG_WARN("FECNN", "could not receive data from proxy server. SOCK_ERRNO:%d", SOCK_ERRNO);
		appendPQExpBuffer(&conn->errorMessage,
			libpq_gettext("could not receive data from proxy server."));
		conn->status = CONNECTION_BAD;
		return -1;
	}

	if ((responseLen = recv(sock, buffer, sizeof(buffer), 0)) < 0)
	{
		if (SOCK_ERRNO == EINTR)
			/* Interrupted system call - we'll just try again */
			goto retry2;
		else
		{
			appendPQExpBuffer(&conn->errorMessage,
				libpq_gettext("could not receive data from proxy server."));
			conn->status = CONNECTION_BAD;
			RS_LOG_WARN("FECNN", "could not receive data from proxy server.2");
			return -1;
		}
	}
	buffer[responseLen] = '\0';

	/* Check that we got HTTP code 200. (HTTP OK). */
	/* We skip over the start of the header ("HTTP/1.1") (9 characters). */
	/* Note that this also accepts "HTTP/1.0" */
	/* We accept all 2xx HTTP codes (indicates success). */
	if (responseLen < 9 + 3 ||
		buffer[9] != '2')
	{
		appendPQExpBuffer(&conn->errorMessage,
			libpq_gettext("Proxy returned error: %s"), buffer);
			RS_LOG_ERROR("FECNN", "Proxy returned error: %s", buffer);
		conn->status = CONNECTION_BAD;
		return -1;
	}

	return 0;
}