Пример #1
0
static int32_t
_sock_add_to_mainloop(struct qb_ipcs_connection *c)
{
	int res;

	res = c->service->poll_fns.dispatch_add(c->service->poll_priority,
						c->request.u.us.sock,
						POLLIN | POLLPRI | POLLNVAL,
						c,
						qb_ipcs_dispatch_connection_request);

	if (res < 0) {
		qb_util_log(LOG_ERR,
			    "Error adding socket to mainloop (%s).",
			    c->description);
		return res;
	}
	qb_ipcs_connection_ref(c);

	res = c->service->poll_fns.dispatch_add(c->service->poll_priority,
						c->setup.u.us.sock,
						POLLIN | POLLPRI | POLLNVAL,
						c, _sock_connection_liveliness);
	qb_util_log(LOG_DEBUG, "added %d to poll loop (liveness)",
		    c->setup.u.us.sock);
	if (res < 0) {
		qb_util_perror(LOG_ERR, "Error adding setupfd to mainloop");
		(void)c->service->poll_fns.dispatch_del(c->request.u.us.sock);
		return res;
	}
	qb_ipcs_connection_ref(c);
	return res;
}
Пример #2
0
ssize_t
qb_ipcs_event_sendv(struct qb_ipcs_connection * c,
		    const struct iovec * iov, size_t iov_len)
{
	ssize_t res;
	ssize_t resn;

	if (c == NULL) {
		return -EINVAL;
	}
	qb_ipcs_connection_ref(c);

	res = c->service->funcs.sendv(&c->event, iov, iov_len);
	if (res > 0) {
		c->stats.events++;
		resn = new_event_notification(c);
		if (resn < 0 && resn != -EAGAIN) {
			errno = -resn;
			qb_util_perror(LOG_WARNING, "new_event_notification");
		}
	}

	qb_ipcs_connection_unref(c);
	return res;
}
Пример #3
0
static int32_t
_process_request_(struct qb_ipcs_connection *c, int32_t ms_timeout)
{
	int32_t res = 0;
	ssize_t size;
	struct qb_ipc_request_header *hdr;

	qb_ipcs_connection_ref(c);

	if (c->service->funcs.peek && c->service->funcs.reclaim) {
		size = c->service->funcs.peek(&c->request, (void **)&hdr,
					      ms_timeout);
	} else {
		hdr = c->receive_buf;
		size = c->service->funcs.recv(&c->request,
					      hdr,
					      c->request.max_msg_size,
					      ms_timeout);
	}
	if (size < 0) {
		if (size != -EAGAIN && size != -ETIMEDOUT) {
			qb_util_perror(LOG_ERR,
				       "recv from client connection failed");
		} else {
			c->stats.recv_retries++;
		}
		res = size;
		goto cleanup;
	} else if (size == 0 || hdr->id == QB_IPC_MSG_DISCONNECT) {
		qb_util_log(LOG_DEBUG, "client requesting a disconnect");
		qb_ipcs_disconnect(c);
		res = -ESHUTDOWN;
	} else {
		c->stats.requests++;
		res = c->service->serv_fns.msg_process(c, hdr, hdr->size);
		/* 0 == good, negative == backoff */
		if (res < 0) {
			res = -ENOBUFS;
		} else {
			res = size;
		}
	}

	if (c->service->funcs.peek && c->service->funcs.reclaim) {
		c->service->funcs.reclaim(&c->request);
	}

cleanup:
	qb_ipcs_connection_unref(c);
	return res;
}
Пример #4
0
qb_ipcs_connection_t *
qb_ipcs_connection_first_get(struct qb_ipcs_service * s)
{
	struct qb_ipcs_connection *c;
	struct qb_list_head *iter;

	if (qb_list_empty(&s->connections)) {
		return NULL;
	}
	iter = s->connections.next;

	c = qb_list_entry(iter, struct qb_ipcs_connection, list);
	qb_ipcs_connection_ref(c);

	return c;
}
Пример #5
0
qb_ipcs_connection_t *
qb_ipcs_connection_next_get(struct qb_ipcs_service * s,
			    struct qb_ipcs_connection * current)
{
	struct qb_ipcs_connection *c;
	struct qb_list_head *iter;

	if (current == NULL || current->list.next == &s->connections) {
		return NULL;
	}
	iter = current->list.next;

	c = qb_list_entry(iter, struct qb_ipcs_connection, list);
	qb_ipcs_connection_ref(c);

	return c;
}
Пример #6
0
void
qb_ipcs_request_rate_limit(struct qb_ipcs_service *s,
			   enum qb_ipcs_rate_limit rl)
{
	struct qb_ipcs_connection *c;
	enum qb_loop_priority old_p = s->poll_priority;
	struct qb_list_head *pos;
	struct qb_list_head *n;

	switch (rl) {
	case QB_IPCS_RATE_FAST:
		s->poll_priority = QB_LOOP_HIGH;
		break;
	case QB_IPCS_RATE_SLOW:
	case QB_IPCS_RATE_OFF:
	case QB_IPCS_RATE_OFF_2:
		s->poll_priority = QB_LOOP_LOW;
		break;
	default:
	case QB_IPCS_RATE_NORMAL:
		s->poll_priority = QB_LOOP_MED;
		break;
	}

	for (pos = s->connections.next, n = pos->next;
	     pos != &s->connections; pos = n, n = pos->next) {

		c = qb_list_entry(pos, struct qb_ipcs_connection, list);
		qb_ipcs_connection_ref(c);

		if (rl == QB_IPCS_RATE_OFF) {
			qb_ipcs_flowcontrol_set(c, 1);
		} else if (rl == QB_IPCS_RATE_OFF_2) {
			qb_ipcs_flowcontrol_set(c, 2);
		} else {
			qb_ipcs_flowcontrol_set(c, QB_FALSE);
		}
		if (old_p != s->poll_priority) {
			(void)_modify_dispatch_descriptor_(c);
		}
		qb_ipcs_connection_unref(c);
	}
}
Пример #7
0
ssize_t
qb_ipcs_response_sendv(struct qb_ipcs_connection * c, const struct iovec * iov,
		       size_t iov_len)
{
	ssize_t res;

	if (c == NULL) {
		return -EINVAL;
	}
	qb_ipcs_connection_ref(c);
	res = c->service->funcs.sendv(&c->response, iov, iov_len);
	if (res > 0) {
		c->stats.responses++;
	} else if (res == -EAGAIN || res == -ETIMEDOUT) {
		c->stats.send_retries++;
	}
	qb_ipcs_connection_unref(c);

	return res;
}
Пример #8
0
ssize_t
qb_ipcs_response_send(struct qb_ipcs_connection *c, const void *data,
		      size_t size)
{
	ssize_t res;

	if (c == NULL) {
		return -EINVAL;
	}
	qb_ipcs_connection_ref(c);
	res = c->service->funcs.send(&c->response, data, size);
	if (res == size) {
		c->stats.responses++;
	} else if (res == -EAGAIN || res == -ETIMEDOUT) {
		c->stats.send_retries++;
	}
	qb_ipcs_connection_unref(c);

	return res;
}
Пример #9
0
static int32_t
handle_new_connection(struct qb_ipcs_service *s,
		      int32_t auth_result,
		      int32_t sock,
		      void *msg, size_t len, struct ipc_auth_ugp *ugp)
{
	struct qb_ipcs_connection *c = NULL;
	struct qb_ipc_connection_request *req = msg;
	int32_t res = auth_result;
	int32_t res2 = 0;
	struct qb_ipc_connection_response response;

	c = qb_ipcs_connection_alloc(s);
	if (c == NULL) {
		qb_ipcc_us_sock_close(sock);
		return -ENOMEM;
	}

	c->receive_buf = calloc(1, req->max_msg_size);
	if (c->receive_buf == NULL) {
		free(c);
		qb_ipcc_us_sock_close(sock);
		return -ENOMEM;
	}
	c->setup.u.us.sock = sock;
	c->request.max_msg_size = req->max_msg_size;
	c->response.max_msg_size = req->max_msg_size;
	c->event.max_msg_size = req->max_msg_size;
	c->pid = ugp->pid;
	c->auth.uid = c->euid = ugp->uid;
	c->auth.gid = c->egid = ugp->gid;
	c->auth.mode = 0600;
	c->stats.client_pid = ugp->pid;
	snprintf(c->description, CONNECTION_DESCRIPTION,
		 "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock);

	if (auth_result == 0 && c->service->serv_fns.connection_accept) {
		res = c->service->serv_fns.connection_accept(c,
							     c->euid, c->egid);
	}
	if (res != 0) {
		goto send_response;
	}

	qb_util_log(LOG_DEBUG, "IPC credentials authenticated (%s)",
		    c->description);

	memset(&response, 0, sizeof(response));
	if (s->funcs.connect) {
		res = s->funcs.connect(s, c, &response);
		if (res != 0) {
			goto send_response;
		}
	}
	/*
	 * The connection is good, add it to the active connection list
	 */
	c->state = QB_IPCS_CONNECTION_ACTIVE;
	qb_list_add(&c->list, &s->connections);

send_response:
	response.hdr.id = QB_IPC_MSG_AUTHENTICATE;
	response.hdr.size = sizeof(response);
	response.hdr.error = res;
	if (res == 0) {
		response.connection = (intptr_t) c;
		response.connection_type = s->type;
		response.max_msg_size = c->request.max_msg_size;
		s->stats.active_connections++;
	}

	res2 = qb_ipc_us_send(&c->setup, &response, response.hdr.size);
	if (res == 0 && res2 != response.hdr.size) {
		res = res2;
	}

	if (res == 0) {
		qb_ipcs_connection_ref(c);
		if (s->serv_fns.connection_created) {
			s->serv_fns.connection_created(c);
		}
		if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
			c->state = QB_IPCS_CONNECTION_ESTABLISHED;
		}
		qb_ipcs_connection_unref(c);
	} else {
		if (res == -EACCES) {
			qb_util_log(LOG_ERR, "Invalid IPC credentials (%s).",
				    c->description);
		} else {
			errno = -res;
			qb_util_perror(LOG_ERR,
				       "Error in connection setup (%s)",
				       c->description);
		}
		qb_ipcs_disconnect(c);
	}
	return res;
}