Exemplo n.º 1
0
Arquivo: ipcc.c Projeto: krig/libqb
static int32_t
_check_connection_state_with(struct qb_ipcc_connection * c, int32_t res,
			     struct qb_ipc_one_way * one_way,
			     int32_t ms_timeout, int32_t events)
{
	if (res >= 0) return res;

	if (qb_ipc_us_sock_error_is_disconnected(res)) {
		errno = -res;
		qb_util_perror(LOG_DEBUG,
			       "interpreting result %d as a disconnect",
			       res);
		c->is_connected = QB_FALSE;
	}

	if (res == -EAGAIN || res == -ETIMEDOUT) {
		int32_t res2;
		int32_t poll_ms = ms_timeout;
		if (res == -ETIMEDOUT) {
			poll_ms = 0;
		}
		res2 = qb_ipc_us_ready(one_way, &c->setup, poll_ms, events);
		if (qb_ipc_us_sock_error_is_disconnected(res2)) {
			errno = -res2;
			qb_util_perror(LOG_DEBUG,
				       "%s %d %s",
				       "interpreting result",
				       res2,
				       "(from socket) as a disconnect");
			c->is_connected = QB_FALSE;
		}
		res = res2;
	}
	return res;
}
Exemplo n.º 2
0
int32_t
qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
			 struct qb_ipc_connection_response *r)
{
	int32_t res;
	struct qb_ipc_connection_request request;
	struct ipc_auth_data *data;
#ifdef QB_LINUX
	int off = 0;
	int on = 1;
#endif

	res = qb_ipcc_stream_sock_connect(c->name, &c->setup.u.us.sock);
	if (res != 0) {
		return res;
	}
#ifdef QB_LINUX
	setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &on,
		   sizeof(on));
#endif

	memset(&request, 0, sizeof(request));
	request.hdr.id = QB_IPC_MSG_AUTHENTICATE;
	request.hdr.size = sizeof(request);
	request.max_msg_size = c->setup.max_msg_size;
	res = qb_ipc_us_send(&c->setup, &request, request.hdr.size);
	if (res < 0) {
		qb_ipcc_us_sock_close(c->setup.u.us.sock);
		return res;
	}

	data = init_ipc_auth_data(c->setup.u.us.sock, sizeof(struct qb_ipc_connection_response));
	if (data == NULL) {
		qb_ipcc_us_sock_close(c->setup.u.us.sock);
		return -ENOMEM;
	}

	qb_ipc_us_ready(&c->setup, NULL, -1, POLLIN);
	res = qb_ipc_us_recv_msghdr(data);

#ifdef QB_LINUX
	setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &off,
		   sizeof(off));
#endif

	if (res != data->len) {
		destroy_ipc_auth_data(data);
		return res;
	}

	memcpy(r, &data->msg.res, sizeof(struct qb_ipc_connection_response));

	qb_ipc_auth_creds(data);
	c->egid = data->ugp.gid;
	c->server_pid = data->ugp.pid;

	destroy_ipc_auth_data(data);
	return r->hdr.error;
}
Exemplo n.º 3
0
/*
 * recv an entire message - and try hard to get all of it.
 */
ssize_t
qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
	       void *msg, size_t len, int32_t timeout)
{
	int32_t result;
	int32_t final_rc = 0;
	int32_t processed = 0;
	int32_t to_recv = len;
	char *data = msg;

	qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);

retry_recv:
	result = recv(one_way->u.us.sock, &data[processed], to_recv,
		      MSG_NOSIGNAL | MSG_WAITALL);

	if (result == -1) {
		if (errno == EAGAIN && (processed > 0 || timeout == -1)) {
			result = qb_ipc_us_ready(one_way, NULL, timeout, POLLIN);
			if (result == 0 || result == -EAGAIN) {
				goto retry_recv;
			}
			final_rc = result;
			goto cleanup_sigpipe;
		} else if (errno == ECONNRESET || errno == EPIPE) {
			final_rc = -ENOTCONN;
			goto cleanup_sigpipe;
		} else {
			final_rc = -errno;
			goto cleanup_sigpipe;
		}
	}

	if (result == 0) {
		final_rc = -ENOTCONN;
		goto cleanup_sigpipe;
	}
	processed += result;
	to_recv -= result;
	if (processed != len) {
		goto retry_recv;
	}
	final_rc = processed;

cleanup_sigpipe:
	qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
	return final_rc;
}
Exemplo n.º 4
0
static int32_t
_check_connection_state_with(struct qb_ipcc_connection * c, int32_t res,
			     struct qb_ipc_one_way * one_way,
			     int32_t ms_timeout, int32_t events)
{
	if (res >= 0) return res;

	if (qb_ipc_us_sock_error_is_disconnected(res)) {
		errno = -res;
		qb_util_perror(LOG_DEBUG,
			       "interpreting result %d as a disconnect",
			       res);
		c->is_connected = QB_FALSE;
	}

	if (res == -EAGAIN || res == -ETIMEDOUT) {
		int32_t res2;
		int32_t poll_ms = ms_timeout;
		if (res == -ETIMEDOUT) {
			poll_ms = 0;
		}
		res2 = qb_ipc_us_ready(one_way, &c->setup, poll_ms, events);
		if (qb_ipc_us_sock_error_is_disconnected(res2)) {
			errno = -res2;
			qb_util_perror(LOG_DEBUG,
				       "%s %d %s",
				       "interpreting result",
				       res2,
				       "(from socket) as a disconnect");
			c->is_connected = QB_FALSE;
			res = res2;
		} else if (res != -ETIMEDOUT) {
			/* if the result we're checking against is a TIMEOUT error.
			 * don't override that result with another error that does
			 * not imply a disconnect */
			res = res2;
		}
	}
	return res;
}
Exemplo n.º 5
0
/*
 * recv a message of unknown size.
 */
static ssize_t
qb_ipc_us_recv_at_most(struct qb_ipc_one_way *one_way,
		       void *msg, size_t len, int32_t timeout)
{
	int32_t result;
	int32_t final_rc = 0;
	int32_t to_recv = 0;
	char *data = msg;
	struct ipc_us_control *ctl = NULL;
	int32_t time_waited = 0;
	int32_t time_to_wait = timeout;

	if (timeout == -1) {
		time_to_wait = 1000;
	}

	qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);

retry_peek:
	result = recv(one_way->u.us.sock, data,
		      sizeof(struct qb_ipc_request_header),
		      MSG_NOSIGNAL | MSG_PEEK);

	if (result == -1) {
		if (errno == EAGAIN && (time_waited < timeout || timeout == -1)) {
			result = qb_ipc_us_ready(one_way, NULL,
						 time_to_wait, POLLIN);
			time_waited += time_to_wait;
			goto retry_peek;
		} else {
			return -errno;
		}
	}
	if (result >= sizeof(struct qb_ipc_request_header)) {
		struct qb_ipc_request_header *hdr = NULL;
		hdr = (struct qb_ipc_request_header *)msg;
		to_recv = hdr->size;
	}

	result = recv(one_way->u.us.sock, data, to_recv,
		      MSG_NOSIGNAL | MSG_WAITALL);
	if (result == -1) {
		final_rc = -errno;
		goto cleanup_sigpipe;
	} else if (result == 0) {
		qb_util_log(LOG_DEBUG, "recv == 0 -> ENOTCONN");

		final_rc = -ENOTCONN;
		goto cleanup_sigpipe;
	}

	final_rc = result;

	ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
	if (ctl) {
		(void)qb_atomic_int_dec_and_test(&ctl->sent);
	}

cleanup_sigpipe:
	qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
	return final_rc;
}
Exemplo n.º 6
0
/*
 * recv a message of unknown size.
 */
static ssize_t
qb_ipc_us_recv_at_most(struct qb_ipc_one_way *one_way,
		       void *msg, size_t len, int32_t timeout)
{
	int32_t result;
	int32_t final_rc = 0;
	int32_t to_recv = 0;
	char *data = msg;
	struct ipc_us_control *ctl = NULL;
	int32_t time_waited = 0;
	int32_t time_to_wait = timeout;

	if (timeout == -1) {
		time_to_wait = 1000;
	}

	qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);

retry_peek:
	result = recv(one_way->u.us.sock, data,
		      sizeof(struct qb_ipc_request_header),
		      MSG_NOSIGNAL | MSG_PEEK);

	if (result == -1) {

		if (errno != EAGAIN) {
			final_rc = -errno;
#if !(defined(QB_LINUX) || defined(QB_CYGWIN))
			if (errno == ECONNRESET || errno == EPIPE) {
				final_rc = -ENOTCONN;
			}
#endif
			goto cleanup_sigpipe;
		}

		/* check to see if we have enough time left to try again */
		if (time_waited < timeout || timeout == -1) {
			result = qb_ipc_us_ready(one_way, NULL, time_to_wait, POLLIN);
			if (qb_ipc_us_sock_error_is_disconnected(result)) {
				final_rc = result;
				goto cleanup_sigpipe;
			}
			time_waited += time_to_wait;
			goto retry_peek;
		} else if (time_waited >= timeout) {
			final_rc = -ETIMEDOUT;
			goto cleanup_sigpipe;
		}
	}
	if (result >= sizeof(struct qb_ipc_request_header)) {
		struct qb_ipc_request_header *hdr = NULL;
		hdr = (struct qb_ipc_request_header *)msg;
		to_recv = hdr->size;
	}

	result = recv(one_way->u.us.sock, data, to_recv,
		      MSG_NOSIGNAL | MSG_WAITALL);
	if (result == -1) {
		final_rc = -errno;
		goto cleanup_sigpipe;
	} else if (result == 0) {
		qb_util_log(LOG_DEBUG, "recv == 0 -> ENOTCONN");

		final_rc = -ENOTCONN;
		goto cleanup_sigpipe;
	}

	final_rc = result;

	ctl = (struct ipc_us_control *)one_way->u.us.shared_data;
	if (ctl) {
		(void)qb_atomic_int_dec_and_test(&ctl->sent);
	}

cleanup_sigpipe:
	qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
	return final_rc;
}