コード例 #1
0
ファイル: ipc_socket.c プロジェクト: fjrti/libqb
static void
_sock_rm_from_mainloop(struct qb_ipcs_connection *c)
{
	(void)c->service->poll_fns.dispatch_del(c->request.u.us.sock);
	qb_ipcs_connection_unref(c);

	(void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock);
	qb_ipcs_connection_unref(c);
}
コード例 #2
0
ファイル: ipcs.c プロジェクト: ip1981/libqb
void
qb_ipcs_disconnect(struct qb_ipcs_connection *c)
{
	int32_t res = 0;
	qb_loop_job_dispatch_fn rerun_job;

	if (c == NULL) {
		return;
	}
	qb_util_log(LOG_DEBUG, "%s() state:%d", __func__, c->state);

	if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
		c->state = QB_IPCS_CONNECTION_INACTIVE;
		c->service->stats.closed_connections++;

		qb_ipcs_sockets_disconnect(c);
		/* return early as it's an incomplete connection.
		 */
		return;
	}
	if (c->state == QB_IPCS_CONNECTION_ESTABLISHED) {
		c->state = QB_IPCS_CONNECTION_SHUTTING_DOWN;
		c->service->stats.active_connections--;
		c->service->stats.closed_connections++;

		qb_ipcs_sockets_disconnect(c);
	}
	if (c->state == QB_IPCS_CONNECTION_SHUTTING_DOWN) {
		res = 0;
		if (c->service->serv_fns.connection_closed) {
			res = c->service->serv_fns.connection_closed(c);
		}
		if (res == 0) {
			qb_ipcs_connection_unref(c);
		} else {
			/* OK, so they want the connection_closed
			 * function re-run */
			rerun_job =
			    (qb_loop_job_dispatch_fn) qb_ipcs_disconnect;
			res = c->service->poll_fns.job_add(QB_LOOP_LOW,
							   c,
							   rerun_job);
			if (res != 0) {
				/* last ditch attempt to cleanup */
				qb_ipcs_connection_unref(c);
			}
		}
	}
}
コード例 #3
0
ファイル: ipcs.c プロジェクト: ip1981/libqb
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;
}
コード例 #4
0
ファイル: ipcs.c プロジェクト: ip1981/libqb
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;
}
コード例 #5
0
ファイル: ipc.c プロジェクト: credativ/pacemaker
void
crm_client_disconnect_all(qb_ipcs_service_t *service)
{
    qb_ipcs_connection_t *c = qb_ipcs_connection_first_get(service);

    while (c != NULL) {
        qb_ipcs_connection_t *last = c;

        c = qb_ipcs_connection_next_get(service, last);

        /* There really shouldn't be anyone connected at this point */
        crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
        qb_ipcs_disconnect(last);
        qb_ipcs_connection_unref(last);
    }
}
コード例 #6
0
ファイル: ipcs.c プロジェクト: ip1981/libqb
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
ファイル: ipcs.c プロジェクト: ip1981/libqb
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
ファイル: ipcs.c プロジェクト: ip1981/libqb
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
ファイル: ipc_setup.c プロジェクト: nozawat/libqb
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;
}
コード例 #10
0
ファイル: ipcs.c プロジェクト: ip1981/libqb
int32_t
qb_ipcs_dispatch_connection_request(int32_t fd, int32_t revents, void *data)
{
	struct qb_ipcs_connection *c = (struct qb_ipcs_connection *)data;
	char bytes[MAX_RECV_MSGS];
	int32_t res;
	int32_t res2;
	int32_t recvd = 0;
	ssize_t avail;

	if (revents & POLLNVAL) {
		qb_util_log(LOG_DEBUG, "NVAL conn:%p fd:%d", c, fd);
		return -EINVAL;
	}
	if (revents & POLLHUP) {
		qb_util_log(LOG_DEBUG, "HUP conn:%p fd:%d", c, fd);
		qb_ipcs_disconnect(c);
		return -ESHUTDOWN;
	}

	if (revents & POLLOUT) {
		res = resend_event_notifications(c);
		if (res < 0 && res != -EAGAIN) {
			errno = -res;
			qb_util_perror(LOG_WARNING, "resend_event_notifications");
		}
		if ((revents & POLLIN) == 0) {
			return 0;
		}
	}
	if (c->fc_enabled) {
		return 0;
	}
	avail = _request_q_len_get(c);

	if (c->service->needs_sock_for_poll && avail == 0) {
		res2 = qb_ipc_us_recv(&c->setup, bytes, 1, 0);
		qb_util_log(LOG_WARNING,
			    "conn:%p Nothing in q but got POLLIN on fd:%d (res2:%d)",
			    c, fd, res2);
		return 0;
	}

	do {
		res = _process_request_(c, IPC_REQUEST_TIMEOUT);
		if (res > 0 || res == -ENOBUFS || res == -EINVAL) {
			recvd++;
		}
		if (res > 0) {
			avail--;
		}
	} while (avail > 0 && res > 0 && !c->fc_enabled);

	if (c->service->needs_sock_for_poll && recvd > 0) {
		res2 = qb_ipc_us_recv(&c->setup, bytes, recvd, -1);
		if (res2 < 0) {
			errno = -res2;
			qb_util_perror(LOG_ERR, "error receiving from setup sock");
		}
	}

	res = QB_MIN(0, res);
	if (res == -EAGAIN || res == -ETIMEDOUT || res == -ENOBUFS) {
		res = 0;
	}
	if (res != 0) {
		errno = -res;
		qb_util_perror(LOG_ERR, "request returned error");
		qb_ipcs_connection_unref(c);
	}

	return res;
}