Beispiel #1
0
/* --------------------------------
 * ForwardCacheToFrontend - simply forwards cached data to the frontend
 *
 * since the cached data passed from the caller is in escaped binary string
 * format, unescape it and send it to the frontend appending 'Z' at the end.
 * returns 0 on success, -1 otherwise.
 * --------------------------------
 */
static int ForwardCacheToFrontend(POOL_CONNECTION *frontend, char *cache, char tstate)
{
	int sendlen;
	size_t sz;
	char *binary_cache = NULL;

	binary_cache = (char *)PQunescapeBytea((unsigned char *)cache, &sz);
	sendlen = (int) sz;
	if (malloc_failed(binary_cache))
		return -1;

	pool_debug("ForwardCacheToFrontend: query cache found (%d bytes)", sendlen);

	/* forward cache to the frontend */
	pool_write(frontend, binary_cache, sendlen);

	/* send ReadyForQuery to the frontend*/
	pool_write(frontend, "Z", 1);
	sendlen = htonl(5);
	pool_write(frontend, &sendlen, sizeof(int));
	if (pool_write_and_flush(frontend, &tstate, 1) < 0)
	{
		pool_error("pool_query_cache_lookup: error while writing data to the frontend");
		PQfreemem(binary_cache);
		return -1;
	}

	PQfreemem(binary_cache);
	return 0;
}
Beispiel #2
0
/* attempt to negotiate a secure connection */
void pool_ssl_negotiate_serverclient(POOL_CONNECTION *cp) {

	cp->ssl_active = -1;

	if ( (!pool_config->ssl) || init_ssl_ctx(cp, ssl_conn_serverclient)) {
		/* write back an "SSL reject" response before returning */
		pool_write_and_flush(cp, "N", 1);
	} else {
		/* write back an "SSL accept" response */
		pool_write_and_flush(cp, "S", 1);

		SSL_set_fd(cp->ssl, cp->fd);
		SSL_RETURN_VOID_IF( (SSL_accept(cp->ssl) < 0), "SSL_accept");
		cp->ssl_active = 1;
	}
}
Beispiel #3
0
POOL_STATUS NotificationResponse(POOL_CONNECTION *frontend,
								 POOL_CONNECTION_POOL *backend)
{
	int pid, pid1;
	char *condition, *condition1 = NULL;
	int len, len1 = 0;
	int i;
	POOL_STATUS status;

	pool_write(frontend, "A", 1);

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
		{
			if (pool_read(CONNECTION(backend, i), &pid, sizeof(pid)) < 0)
				return POOL_ERROR;
			condition = pool_read_string(CONNECTION(backend, i), &len, 0);
			if (condition == NULL)
				return POOL_END;

			if (IS_MASTER_NODE_ID(i))
			{
				pid1 = pid;
				len1 = len;
				condition1 = strdup(condition);
			}
		}
	}

	pool_write(frontend, &pid1, sizeof(pid1));
	status = pool_write_and_flush(frontend, condition1, len1);
	free(condition1);
	return status;
}
Beispiel #4
0
POOL_STATUS NoticeResponse(POOL_CONNECTION *frontend,
						   POOL_CONNECTION_POOL *backend)
{
	char *string = NULL;
	int len;
	int i;

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
		{
			/* read notice message */
			string = pool_read_string(CONNECTION(backend, i), &len, 0);
			if (string == NULL)
				return POOL_END;
		}
	}

	/* forward to the frontend */
	pool_write(frontend, "N", 1);
	if (pool_write_and_flush(frontend, string, len) < 0)
	{
		return POOL_END;
	}
	return POOL_CONTINUE;
}
Beispiel #5
0
/*
* send startup packet
*/
int send_startup_packet(POOL_CONNECTION_POOL_SLOT *cp)
{
	int len;

	len = htonl(cp->sp->len + sizeof(len));
	pool_write(cp->con, &len, sizeof(len));
	return pool_write_and_flush(cp->con, cp->sp->startup_packet, cp->sp->len);
}
void version_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
{
	static short num_fields = 1;
	static char *field_names[] = {"pool_version"};
	short s;
	int len;
	int size;
	int hsize;

	static unsigned char nullmap[2] = {0xff, 0xff};
	int nbytes = (num_fields + 7)/8;

	POOL_REPORT_VERSION *version = get_version();

	send_row_description(frontend, backend, num_fields, field_names);

	if (MAJOR(backend) == PROTO_MAJOR_V2)
	{
		/* ascii row */
			pool_write(frontend, "D", 1);
			pool_write_and_flush(frontend, nullmap, nbytes);

		size = strlen(version[0].version);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
		pool_write(frontend, version[0].version, size);
	}
	else
	{
		/* data row */
			pool_write(frontend, "D", 1);
		len = 6; /* int32 + int16; */
		len += 4 + strlen(version[0].version); /* int32 + data */
			len = htonl(len);
			pool_write(frontend, &len, sizeof(len));
			s = htons(num_fields);
			pool_write(frontend, &s, sizeof(s));

		len = htonl(strlen(version[0].version));
			pool_write(frontend, &len, sizeof(len));
		pool_write(frontend, version[0].version, strlen(version[0].version));
	}

	send_complete_and_ready(frontend, backend, 1);

	free(version);
	}
Beispiel #7
0
/* attempt to negotiate a secure connection */
void pool_ssl_negotiate_clientserver(POOL_CONNECTION *cp) {
	int ssl_packet[2] = { htonl(sizeof(int)*2), htonl(NEGOTIATE_SSL_CODE) };
	char server_response;

	cp->ssl_active = -1;

	if ( (!pool_config->ssl) || init_ssl_ctx(cp, ssl_conn_clientserver))
		return;

	ereport(DEBUG1,
		(errmsg("attempting to negotiate a secure connection"),
			 errdetail("sending client->server SSL request")));
	pool_write_and_flush(cp, ssl_packet, sizeof(int)*2);

	if (pool_read(cp, &server_response, 1) < 0)
	{
		ereport(WARNING,
				(errmsg("error while attempting to negotiate a secure connection, pool_read failed")));
 		return;
	}

	ereport(DEBUG1,
		(errmsg("attempting to negotiate a secure connection"),
			 errdetail("client->server SSL response: %c", server_response)));

	switch (server_response) {
		case 'S':
			SSL_set_fd(cp->ssl, cp->fd);
			SSL_RETURN_VOID_IF( (SSL_connect(cp->ssl) < 0),
			                    "SSL_connect");
			cp->ssl_active = 1;
			break;
		case 'N':
			/*
			 * If backend does not support SSL but pgpool does, we get this.
			 * i.e. This is normal.
			 */
			ereport(DEBUG1,
				(errmsg("attempting to negotiate a secure connection"),
					 errdetail("server doesn't want to talk SSL")));
			break;
		default:
			ereport(WARNING,
					(errmsg("error while attempting to negotiate a secure connection, unhandled response: %c", server_response)));
			break;
	}
}
Beispiel #8
0
POOL_STATUS EmptyQueryResponse(POOL_CONNECTION *frontend,
							   POOL_CONNECTION_POOL *backend)
{
	char c;
	int i;

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
		{
			if (pool_read(CONNECTION(backend, i), &c, sizeof(c)) < 0)
				return POOL_END;
		}
	}

	pool_write(frontend, "I", 1);
	return pool_write_and_flush(frontend, "", 1);
}
Beispiel #9
0
POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend,
						  POOL_CONNECTION_POOL *backend)
{
	char *string = NULL;
	int len;
	int i;
	POOL_STATUS ret = POOL_CONTINUE;

	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
		{
			/* read error message */
			string = pool_read_string(CONNECTION(backend, i), &len, 0);
			if (string == NULL)
				return POOL_END;
		}
	}

	/* forward to the frontend */
	pool_write(frontend, "E", 1);
	if (pool_write_and_flush(frontend, string, len) < 0)
		return POOL_END;

	/* 
	 * check session context, because this function is called 
	 * by pool_do_auth too.
	 */
	if (pool_get_session_context())
		ret = raise_intentional_error_if_need(backend);

	/* change transaction state */
	for (i=0;i<NUM_BACKENDS;i++)
	{
		if (VALID_BACKEND(i))
		{
			if (TSTATE(backend, i) == 'T')
				TSTATE(backend, i) = 'E';
		}
	}

	return ret;
}
void pools_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
{
	static short num_fields = 12;
	static char *field_names[] = {"pool_pid", "start_time", "pool_id", "backend_id", "database", "username", "create_time",
                                  "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
	short s;
	int len;
	int i;
	static unsigned char nullmap[2] = {0xff, 0xff};
	int nbytes = (num_fields + 7)/8;
	int nrows;
	int size;
	int hsize;
	char proc_pid[16];
	char pool_id[16];
	char proc_start_time[20];
	char proc_create_time[20];
	char majorversion[5];
	char minorversion[5];
	char pool_counter[16];
	char backend_id[16];
	char backend_pid[16];
	char connected[2];

    POOL_REPORT_POOLS *pools = get_pools(&nrows);

	send_row_description(frontend, backend, num_fields, field_names);

	if (MAJOR(backend) == PROTO_MAJOR_V2) hsize = 4;
	else hsize = 0;

		/* ascii row */
		for (i=0;i<nrows;i++)
		{
			snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
			snprintf(pool_id, sizeof(pool_id), "%d", pools[i].pool_id);
			if (pools[i].start_time)
				strftime(proc_start_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pools[i].start_time));
			else
				*proc_start_time = '\0';
			if (pools[i].create_time)
				strftime(proc_create_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pools[i].create_time));
			else
				*proc_create_time = '\0';
			snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
			snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
			snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
			snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
			snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
			snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);

			if (MAJOR(backend) == PROTO_MAJOR_V2)
			{
				pool_write(frontend, "D", 1);
				pool_write_and_flush(frontend, nullmap, nbytes);
			}
			else
			{
				pool_write(frontend, "D", 1);
				len = 6; /* int32 + int16; */
				len += 4 + strlen(proc_pid);          /* int32 + data */
				len += 4 + strlen(proc_start_time);        /* int32 + data */
				len += 4 + strlen(pool_id);           /* int32 + data */
				len += 4 + strlen(backend_id);        /* int32 + data */
				len += 4 + strlen(pools[i].database);          /* int32 + data */
				len += 4 + strlen(pools[i].username);          /* int32 + data */
				len += 4 + strlen(proc_create_time);       /* int32 + data */
				len += 4 + strlen(majorversion); /* int32 + data */
				len += 4 + strlen(minorversion); /* int32 + data */
				len += 4 + strlen(pool_counter);      /* int32 + data */
				len += 4 + strlen(backend_pid);   /* int32 + data */
				len += 4 + strlen(connected);    /* int32 + data */
			
				len = htonl(len);
				pool_write(frontend, &len, sizeof(len));
				s = htons(num_fields);
				pool_write(frontend, &s, sizeof(s));
			}

			len = strlen(proc_pid);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, proc_pid, len);

			len = strlen(proc_start_time);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, proc_start_time, len);

			len = strlen(pool_id);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, pool_id, len);

			len = strlen(backend_id);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, backend_id, len);

			len = strlen(pools[i].database);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, pools[i].database, len);

			len = strlen(pools[i].username);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, pools[i].username, len);

			len = strlen(proc_create_time);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, proc_create_time, len);

			len = strlen(majorversion);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, majorversion, len);

			len = strlen(minorversion);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, minorversion, len);

			len = strlen(pool_counter);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, pool_counter, len);

			len = strlen(backend_pid);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, backend_pid, len);

			len = strlen(connected);
			size = htonl(len+hsize);
			pool_write(frontend, &size, sizeof(size));
			pool_write(frontend, connected, len);
		}

	send_complete_and_ready(frontend, backend, nrows);

	free(pools);
}
void nodes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
		{
	static short num_fields = 5;
	static char *field_names[] = {"node_id","hostname", "port", "status", "lb_weight"};
	int i;
	short s;
	int len;
	int nrows;
	int size;
	int hsize;
	static unsigned char nullmap[2] = {0xff, 0xff};
	int nbytes = (num_fields + 7)/8;

	POOL_REPORT_NODES* nodes = get_nodes(&nrows);

	send_row_description(frontend, backend, num_fields, field_names);

	if (MAJOR(backend) == PROTO_MAJOR_V2)
	{
		/* ascii row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			pool_write_and_flush(frontend, nullmap, nbytes);

			size = strlen(nodes[i].node_id);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, nodes[i].node_id, size);

			size = strlen(nodes[i].hostname);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, nodes[i].hostname, size);

			size = strlen(nodes[i].port);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, nodes[i].port, size);

			size = strlen(nodes[i].status);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, nodes[i].status, size);

			size = strlen(nodes[i].lb_weight);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, nodes[i].lb_weight, size);
		}
	}
	else
	{
		/* data row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			len = 6; /* int32 + int16; */
			len += 4 + strlen(nodes[i].node_id);   /* int32 + data; */
			len += 4 + strlen(nodes[i].hostname);  /* int32 + data; */
			len += 4 + strlen(nodes[i].port);      /* int32 + data; */
			len += 4 + strlen(nodes[i].status);    /* int32 + data; */
			len += 4 + strlen(nodes[i].lb_weight); /* int32 + data; */
			len = htonl(len);
			pool_write(frontend, &len, sizeof(len));
			s = htons(num_fields);
			pool_write(frontend, &s, sizeof(s));

			len = htonl(strlen(nodes[i].node_id));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, nodes[i].node_id, strlen(nodes[i].node_id));

			len = htonl(strlen(nodes[i].hostname));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, nodes[i].hostname, strlen(nodes[i].hostname));

			len = htonl(strlen(nodes[i].port));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, nodes[i].port, strlen(nodes[i].port));

			len = htonl(strlen(nodes[i].status));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, nodes[i].status, strlen(nodes[i].status));

			len = htonl(strlen(nodes[i].lb_weight));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, nodes[i].lb_weight, strlen(nodes[i].lb_weight));
		}
	}

	send_complete_and_ready(frontend, backend, nrows);

	free(nodes);
	}
void config_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
		{
	static char *field_names[] = {"item", "value", "description"};
	static unsigned char nullmap[2] = {0xff, 0xff};
	static short num_fields = 3;
	short s;
	int nbytes = (num_fields + 7)/8;
	int len;
	int nrows;
	int size;
	int hsize;
	int i;

	POOL_REPORT_CONFIG *status = get_config(&nrows);

	send_row_description(frontend, backend, num_fields, field_names);

	if (MAJOR(backend) == PROTO_MAJOR_V2)
	{
		/* ascii row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			pool_write_and_flush(frontend, nullmap, nbytes);

			size = strlen(status[i].name);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, status[i].name, size);

			size = strlen(status[i].value);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, status[i].value, size);

			size = strlen(status[i].desc);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, status[i].desc, size);
		}
	}
	else
	{
		/* data row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			len = 6; /* int32 + int16; */
			len += 4 + strlen(status[i].name);  /* int32 + data; */
			len += 4 + strlen(status[i].value); /* int32 + data; */
			len += 4 + strlen(status[i].desc);  /* int32 + data; */
			len = htonl(len);
			pool_write(frontend, &len, sizeof(len));
			s = htons(num_fields);
			pool_write(frontend, &s, sizeof(s));

			len = htonl(strlen(status[i].name));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, status[i].name, strlen(status[i].name));

			len = htonl(strlen(status[i].value));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, status[i].value, strlen(status[i].value));

			len = htonl(strlen(status[i].desc));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, status[i].desc, strlen(status[i].desc));
		}
	}

	send_complete_and_ready(frontend, backend, nrows);

	free(status);
}
void processes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
		{
	static short num_fields = 6;
	static char *field_names[] = {"pool_pid", "start_time", "database", "username", "create_time", "pool_counter"};
	short s;
	int len;
	int nrows;
	int size;
	int hsize;
    int i;
    static unsigned char nullmap[2] = {0xff, 0xff};
	int nbytes = (num_fields + 7)/8;

    POOL_REPORT_PROCESSES *processes = get_processes(&nrows);

	send_row_description(frontend, backend, num_fields, field_names);

	if (MAJOR(backend) == PROTO_MAJOR_V2)
	{
		/* ascii row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			pool_write_and_flush(frontend, nullmap, nbytes);

			size = strlen(processes[i].pool_pid);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].pool_pid, size);

			size = strlen(processes[i].start_time);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].start_time, size);

			size = strlen(processes[i].database);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].database, size);

			size = strlen(processes[i].username);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].username, size);

			size = strlen(processes[i].create_time);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].create_time, size);

			size = strlen(processes[i].pool_counter);
			hsize = htonl(size+4);
			pool_write(frontend, &hsize, sizeof(hsize));
			pool_write(frontend, processes[i].pool_counter, size);
		}
	}
	else
	{
		/* data row */
		for (i=0;i<nrows;i++)
		{
			pool_write(frontend, "D", 1);
			len = 6; /* int32 + int16; */
			len += 4 + strlen(processes[i].pool_pid);     /* int32 + data */
			len += 4 + strlen(processes[i].start_time);   /* int32 + data */
			len += 4 + strlen(processes[i].database);     /* int32 + data */
			len += 4 + strlen(processes[i].username);     /* int32 + data */
			len += 4 + strlen(processes[i].create_time);  /* int32 + data */
			len += 4 + strlen(processes[i].pool_counter); /* int32 + data */
			len = htonl(len);
			pool_write(frontend, &len, sizeof(len));
			s = htons(num_fields);
			pool_write(frontend, &s, sizeof(s));

			len = htonl(strlen(processes[i].pool_pid));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].pool_pid, strlen(processes[i].pool_pid));

			len = htonl(strlen(processes[i].start_time));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].start_time, strlen(processes[i].start_time));

			len = htonl(strlen(processes[i].database));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].database, strlen(processes[i].database));

			len = htonl(strlen(processes[i].username));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].username, strlen(processes[i].username));

			len = htonl(strlen(processes[i].create_time));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].create_time, strlen(processes[i].create_time));

			len = htonl(strlen(processes[i].pool_counter));
			pool_write(frontend, &len, sizeof(len));
			pool_write(frontend, processes[i].pool_counter, strlen(processes[i].pool_counter));
		}
	}

	send_complete_and_ready(frontend, backend, nrows);

	free(processes);
	}
Beispiel #14
0
/*
 * Do authentication. Assuming the only caller is
 * *make_persistent_db_connection().
 */
static int s_do_auth(POOL_CONNECTION_POOL_SLOT *cp, char *password)
{
	char kind;
	int status;
	int length;
	int auth_kind;
	char state;
	char *p;
	int pid, key;
	bool keydata_done;

	/*
	 * read kind expecting 'R' packet (authentication response)
	 */
	status = pool_read(cp->con, &kind, sizeof(kind));
	if (status < 0)
	{
		pool_error("s_do_auth: error while reading message kind");
		return -1;
	}

	if (kind != 'R')
	{
		pool_error("s_do_auth: expecting R got %c", kind);
		return -1;
	}

	/* read message length */
	status = pool_read(cp->con, &length, sizeof(length));
	if (status < 0)
	{
		pool_error("s_do_auth: error while reading message length");
		return -1;
	}
	length = ntohl(length);

	/* read auth kind */
	status = pool_read(cp->con, &auth_kind, sizeof(auth_kind));
	if (status < 0)
	{
		pool_error("s_do_auth: error while reading auth kind");
		return -1;
	}
	auth_kind = ntohl(auth_kind);
	pool_debug("s_do_auth: auth kind: %d", auth_kind);

	if (auth_kind == 0)	/* trust authentication? */
	{
		cp->con->auth_kind = 0;
	}
	else if (auth_kind == 3) /* clear text password? */
	{
		int size = htonl(strlen(password) + 5);

		pool_write(cp->con, "p", 1);
		pool_write(cp->con, &size, sizeof(size));
		pool_write_and_flush(cp->con, password, strlen(password) + 1);
		status = pool_flush(cp->con);
		if (status > 0)
		{
			pool_error("s_do_auth: error while sending clear text password");
			return -1;
		}
		return s_do_auth(cp, password);
	}
	else if (auth_kind == 4) /* crypt password? */
	{
		int size;
		char salt[3];
		char *crypt_password;

		status = pool_read(cp->con, &salt, 2);
		if (status > 0)
		{
			pool_error("s_do_auth: error while reading crypt salt");
			return -1;
		}
		salt[2] = '\0';

		crypt_password = crypt(password, salt);
		size = htonl(strlen(crypt_password) + 5);
		pool_write(cp->con, "p", 1);
		pool_write(cp->con, &size, sizeof(size));
		pool_write_and_flush(cp->con, crypt_password, strlen(crypt_password) + 1);
		status = pool_flush(cp->con);
		if (status > 0)
		{
			pool_error("s_do_auth: error while sending crypt password");
			return -1;
		}
		return s_do_auth(cp, password);
	}
	else if (auth_kind == 5) /* md5 password? */
	{
		char salt[4];
		char *buf, *buf1;
		int size;

		status = pool_read(cp->con, &salt, 4);
		if (status > 0)
		{
			pool_error("s_do_auth: error while reading md5 salt");
			return -1;
		}

		buf = malloc(2 * (MD5_PASSWD_LEN + 4)); /* hash + "md5" + '\0' */
		if (buf == NULL)
		{
			pool_error("s_do_auth(): malloc failed: %s", strerror(errno));
			return -1;
		}
		memset(buf, 0, 2 * (MD5_PASSWD_LEN + 4));

		/* build md5 password */
		buf1 = buf + MD5_PASSWD_LEN + 4;
		pool_md5_encrypt(password, cp->sp->user, strlen(cp->sp->user), buf1);
		pool_md5_encrypt(buf1, salt, 4, buf + 3);
		memcpy(buf, "md5", 3);

		size = htonl(strlen(buf) + 5);
		pool_write(cp->con, "p", 1);
		pool_write(cp->con, &size, sizeof(size));
		pool_write_and_flush(cp->con, buf, strlen(buf) + 1);
		status = pool_flush(cp->con);
		if (status > 0)
		{
			pool_error("s_do_auth: error while sending md5 password");
			return -1;
		}

		status = s_do_auth(cp, password);
		free(buf);
		return status;
	}
	else
	{
		pool_error("s_do_auth: auth kind %d not supported yet", auth_kind);
		return -1;
	}

	/*
	 * Read backend key data and wait until Ready for query arriving or
	 * error happens.
	 */

	keydata_done = false;

	for (;;)
	{
		status = pool_read(cp->con, &kind, sizeof(kind));
		if (status < 0)
		{
			pool_error("s_do_auth: error while reading message kind");
			return -1;
		}

		switch (kind)
		{
			case 'K':	/* backend key data */
				keydata_done = true;
				pool_debug("s_do_auth: backend key data received");

				/* read message length */
				status = pool_read(cp->con, &length, sizeof(length));
				if (status < 0)
				{
					pool_error("s_do_auth: error while reading message length");
					return -1;
				}
				if (ntohl(length) != 12)
				{
					pool_error("s_do_auth: backend key data length is not 12 (%d)", ntohl(length));
				}

				/* read pid */
				if (pool_read(cp->con, &pid, sizeof(pid)) < 0)
				{
					pool_error("s_do_auth: failed to read pid");
					return -1;
				}
				cp->pid = pid;

				/* read key */
				if (pool_read(cp->con, &key, sizeof(key)) < 0)
				{
					pool_error("s_do_auth: failed to read key");
					return -1;
				}
				cp->key = key;
				break;

			case 'Z':	/* Ready for query */
				/* read message length */
				status = pool_read(cp->con, &length, sizeof(length));
				if (status < 0)
				{
					pool_error("s_do_auth: error while reading message length");
					return -1;
				}
				length = ntohl(length);

				/* read transaction state */
				status = pool_read(cp->con, &state, sizeof(state));
				if (status < 0)
				{
					pool_error("s_do_auth: error while reading transaction state");
					return -1;
				}

				pool_debug("s_do_auth: transaction state: %c", state);
				cp->con->tstate = state;

				if (!keydata_done)
				{
					pool_error("s_do_auth: ready for query arrived before receiving keydata");
				}
				return 0;
				break;

			case 'S':	/* parameter status */
			case 'N':	/* notice response */
			case 'E':	/* error response */
				/* Just throw away data */
				status = pool_read(cp->con, &length, sizeof(length));
				if (status < 0)
				{
					pool_error("s_do_auth: error while reading message length. kind:%c", kind);
					return -1;
				}

				length = ntohl(length);
				length -= 4;

				p = pool_read2(cp->con, length);
				if (p == NULL)
					return -1;
				break;

			default:
				pool_error("s_do_auth: unknown response \"%c\" while processing BackendKeyData",
						   kind);
				break;
		}
	}
	return -1;
}
Beispiel #15
0
/*
 * process cancel request
 */
void cancel_request(CancelPacket *sp)
{
	int	len;
	int fd;
	POOL_CONNECTION *con;
	int i,j,k;
	ConnectionInfo *c = NULL;
	CancelPacket cp;
	bool found = false;

	pool_debug("Cancel request received");

	/* look for cancel key from shmem info */
	for (i=0;i<pool_config->num_init_children;i++)
	{
		for (j=0;j<pool_config->max_pool;j++)
		{
			for (k=0;k<NUM_BACKENDS;k++)
			{
				c = pool_coninfo(i, j, k);
				pool_debug("con_info: address:%p database:%s user:%s pid:%d key:%d i:%d",
						   c, c->database, c->user, ntohl(c->pid), ntohl(c->key),i);

				if (c->pid == sp->pid && c->key == sp->key)
				{
					pool_debug("found pid:%d key:%d i:%d",ntohl(c->pid), ntohl(c->key),i);
					c = pool_coninfo(i, j, 0);
					found = true;
					goto found;
				}
			}
		}
	}

 found:
	if (!found)
	{
		pool_error("cancel_request: invalid cancel key: pid:%d key:%d",ntohl(sp->pid), ntohl(sp->key));
		return;	/* invalid key */
	}

	for (i=0;i<NUM_BACKENDS;i++,c++)
	{
		if (!VALID_BACKEND(i))
			continue;

		if (*(BACKEND_INFO(i).backend_hostname) == '/')
			fd = connect_unix_domain_socket(i, TRUE);
		else
			fd = connect_inet_domain_socket(i, TRUE);

		if (fd < 0)
		{
			pool_error("Could not create socket for sending cancel request for backend %d", i);
			return;
		}

		con = pool_open(fd);
		if (con == NULL)
			return;

		len = htonl(sizeof(len) + sizeof(CancelPacket));
		pool_write(con, &len, sizeof(len));

		cp.protoVersion = sp->protoVersion;
		cp.pid = c->pid;
		cp.key = c->key;

		pool_log("cancel_request: canceling backend pid:%d key: %d", ntohl(cp.pid),ntohl(cp.key));

		if (pool_write_and_flush(con, &cp, sizeof(CancelPacket)) < 0)
			pool_error("Could not send cancel request packet for backend %d", i);

		pool_close(con);

		/*
		 * this is needed to ensure that the next DB node executes the
		 * query supposed to be canceled.
		 */
		sleep(1);
	}
}
Beispiel #16
0
void pool_ssl_negotiate_serverclient(POOL_CONNECTION *cp) {
	ereport(DEBUG1,
			(errmsg("SSL is requested but SSL support is not available")));
	pool_write_and_flush(cp, "N", 1);
	cp->ssl_active = -1;
}
Beispiel #17
0
/* --------------------------------
 * search_system_db_for_cache - search for query cache in libpq protocol level
 *
 * sends a cache searching query string using libpq protocol to the SystemDB.
 * if the SystemDB returns cache, forward the data to the frontend, and return
 * CACHE_FOUND. if cache was not found, silently discards the remaining data
 * returned by the SystemDB, and return CACHE_NOT_FOUND. returns CACHE_ERROR
 * if an error was encountered.
 * --------------------------------
 */
static CACHE_STATUS
search_system_db_for_cache(POOL_CONNECTION *frontend, char *sql, int sql_len, struct timeval *t, char tstate)
{
	fd_set readmask;
	int fds;
	int num_fds;
	struct timeval *timeout = NULL;
	char kind;
	int readlen;
	char *data = NULL;
	CACHE_STATUS return_value = CACHE_ERROR;
	int cache_found = 0;

	pool_debug("pool_query_cache_lookup: executing query: \"%s\"", sql);

	pool_write(SYSDB_CON, "Q", 1);
	if (SYSDB_MAJOR == PROTO_MAJOR_V3)
	{
		int sendlen = htonl(sql_len + 4);
		pool_write(SYSDB_CON, &sendlen, sizeof(sendlen));
	}
	if (pool_write_and_flush(SYSDB_CON, sql, sql_len) < 0)
	{
		pool_error("pool_query_cache_lookup: error while sending data to the SystemDB");
		return CACHE_ERROR;
	}

	if ((t->tv_sec + t->tv_usec) == 0)
		timeout = NULL;
	else
		timeout = t;

	/* don't really need select() or for(;;) here, but we may need it someday... or not */
	for (;;)
	{
		FD_ZERO(&readmask);
		num_fds = 0;

		num_fds = SYSDB_CON->fd + 1;
		FD_SET(SYSDB_CON->fd, &readmask);
		fds = select(num_fds, &readmask, NULL, NULL, timeout);
		if (fds == -1)
		{
			if (errno == EINTR)
				continue;

			pool_error("pool_query_cache_lookup: select() failed. reason: %s", strerror(errno));
			return CACHE_ERROR;
		}

		/* select() timeout */
		if (fds == 0)
			return CACHE_ERROR;

		for (;;)
		{
			if (! FD_ISSET(SYSDB_CON->fd, &readmask))
			{
				pool_error("pool_query_cache_lookup: select() failed");
				return CACHE_ERROR;
			}

			/* read kind */
			if (pool_read(SYSDB_CON, &kind, sizeof(kind)) < 0)
			{
				pool_error("pool_query_cache_lookup: error while reading message kind");
				return CACHE_ERROR;
			}
			pool_debug("pool_query_cache_lookup: received %c from systemdb", kind);

			/* just do the routine work of reading data in. data won't be used */
			if (kind == 'T')
			{
				if (SYSDB_MAJOR == PROTO_MAJOR_V3)
				{
					if (pool_read(SYSDB_CON, &readlen, sizeof(int)) < 0)
					{
						pool_error("pool_query_cache_lookup: error while reading message length");
						return CACHE_ERROR;
					}
					readlen = ntohl(readlen) - sizeof(int);
					data = pool_read2(SYSDB_CON, readlen);
				}
				else
				{
					data = pool_read_string(SYSDB_CON, &readlen, 0);
				}
			}
			else if (kind == 'D') /* cache found! forward it to the frontend */
			{
				char *cache;
				int status;

				cache_found = 1;

				if (SYSDB_MAJOR == PROTO_MAJOR_V3)
				{
					if (pool_read(SYSDB_CON, &readlen, sizeof(readlen)) < 0)
					{
						pool_error("pool_query_cache_lookup: error while reading message length");
						return CACHE_ERROR;
					}
					readlen = ntohl(readlen) - sizeof(int);
					cache = pool_read2(SYSDB_CON, readlen);
				}
				else
				{
					cache = pool_read_string(SYSDB_CON, &readlen, 0);
				}

				if (cache == NULL)
				{
					pool_error("pool_query_cache_lookup: error while reading message body");
					return CACHE_ERROR;
				}

				cache[readlen] = '\0';

				cache += sizeof(short);	/* number of columns in 'D' (we know it's always going to be 1, so skip) */
				cache += sizeof(int); /* length of escaped bytea cache in string format. don't need the length */

				status = ForwardCacheToFrontend(frontend, cache, tstate);
				if (status < 0)
				{
					/* fatal error has occured while forwarding cache */
					pool_error("pool_query_cache_lookup: query cache forwarding failed");
					return_value = CACHE_ERROR;
				}
			}
			else if (kind == 'C') /* see if 'D' was received */
			{
				if (cache_found)
					return_value = CACHE_FOUND;
				else
					return_value = CACHE_NOT_FOUND;

				/* must discard the remaining data */
				if (SYSDB_MAJOR == PROTO_MAJOR_V3)
				{
					if (pool_read(SYSDB_CON, &readlen, sizeof(int)) < 0)
					{
						pool_error("pool_query_cache_lookup: error while reading message length");
						return CACHE_ERROR;
					}
					readlen = ntohl(readlen) - sizeof(int);
					data = pool_read2(SYSDB_CON, readlen);
				}
				else
				{
					data = pool_read_string(SYSDB_CON, &readlen, 0);
				}
			}
			else if (kind == 'Z')
			{
				/* must discard the remaining data */
				if (SYSDB_MAJOR == PROTO_MAJOR_V3)
				{
					if (pool_read(SYSDB_CON, &readlen, sizeof(int)) < 0)
					{
						pool_error("pool_query_cache_lookup: error while reading message length");
						return CACHE_ERROR;
					}
					readlen = ntohl(readlen) - sizeof(int);
					data = pool_read2(SYSDB_CON, readlen);
				}
				else
				{
					data = pool_read_string(SYSDB_CON, &readlen, 0);
				}

				break;
			}
			else if (kind == 'E')
			{
				/* must discard the remaining data */
				if (SYSDB_MAJOR == PROTO_MAJOR_V3)
				{
					if (pool_read(SYSDB_CON, &readlen, sizeof(int)) < 0)
					{
						pool_error("pool_query_cache_lookup: error while reading message length");
						return CACHE_ERROR;
					}
					readlen = ntohl(readlen) - sizeof(int);
					data = pool_read2(SYSDB_CON, readlen);
				}
				else
				{
					data = pool_read_string(SYSDB_CON, &readlen, 0);
				}

				return_value = CACHE_ERROR;
			}
			else
			{
				/* shouldn't get here, but just in case */
				return CACHE_ERROR;
			}
		}

		break;
	}

	return return_value;
}