Beispiel #1
0
Datei: ipcc.c Projekt: 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;
}
Beispiel #2
0
static ssize_t
qb_ipc_socket_sendv(struct qb_ipc_one_way *one_way, const struct iovec *iov,
		    size_t iov_len)
{
	int32_t rc;
	struct ipc_us_control *ctl;
	ctl = (struct ipc_us_control *)one_way->u.us.shared_data;

	qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);

	if (one_way->u.us.sock_name) {
		rc = _finish_connecting(one_way);
		if (rc < 0) {
			qb_util_perror(LOG_ERR, "socket connect-on-sendv");
			return rc;
		}
	}

	rc = writev(one_way->u.us.sock, iov, iov_len);

	if (rc == -1) {
		rc = -errno;
		if (errno != EAGAIN) {
			qb_util_perror(LOG_ERR, "socket_sendv:writev %d",
				       one_way->u.us.sock);
		}
	}

	qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);

	if (ctl && rc > 0) {
		qb_atomic_int_inc(&ctl->sent);
	}
	return rc;
}
Beispiel #3
0
static int32_t
posix_mq_create(struct qb_ipcs_connection *c,
		struct qb_ipc_one_way *one_way, const char *name, size_t q_len)
{
	struct mq_attr attr;
	mqd_t q = 0;
	int32_t res = 0;
	mode_t m = 0600;
	size_t max_msg_size = one_way->max_msg_size;

	res = posix_mq_increase_limits(max_msg_size, q_len);
	if (res != 0) {
		return res;
	}
try_smaller:
	if (q != 0) {
		max_msg_size = max_msg_size / 2;
		q_len--;
	}
	attr.mq_flags = O_NONBLOCK;
	attr.mq_maxmsg = q_len;
	attr.mq_msgsize = max_msg_size;

	q = mq_open(name, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, m, &attr);
	if (q == (mqd_t) - 1 && errno == ENOMEM) {
		if (max_msg_size > 9000 && q_len > 3) {
			goto try_smaller;
		}
	}
	if (q == (mqd_t) - 1) {
		res = -errno;
		qb_util_perror(LOG_ERR, "Can't create mq \"%s\"", name);
		return res;
	}
	q_space_used += max_msg_size * q_len;
	one_way->max_msg_size = max_msg_size;
	one_way->u.pmq.q = q;
	(void)strlcpy(one_way->u.pmq.name, name, NAME_MAX);

	res = fchown((int)q, c->euid, c->egid);
	if (res == -1) {
		res = -errno;
		qb_util_perror(LOG_ERR, "fchown:%s", name);
		mq_close(q);
		mq_unlink(name);
	}

	return res;
}
Beispiel #4
0
static int32_t
qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
{
	struct sockaddr_un un_addr;
	int32_t new_fd;
	struct qb_ipcs_service *s = (struct qb_ipcs_service *)data;
	int32_t res;
	socklen_t addrlen = sizeof(struct sockaddr_un);

	if (revent & (POLLNVAL | POLLHUP | POLLERR)) {
		/*
		 * handle shutdown more cleanly.
		 */
		return -1;
	}

retry_accept:
	errno = 0;
	new_fd = accept(fd, (struct sockaddr *)&un_addr, &addrlen);
	if (new_fd == -1 && errno == EINTR) {
		goto retry_accept;
	}

	if (new_fd == -1 && errno == EBADF) {
		qb_util_perror(LOG_ERR,
			       "Could not accept client connection from fd:%d",
			       fd);
		return -1;
	}
	if (new_fd == -1) {
		qb_util_perror(LOG_ERR, "Could not accept client connection");
		/* This is an error, but -1 would indicate disconnect
		 * from the poll loop
		 */
		return 0;
	}

	res = qb_sys_fd_nonblock_cloexec_set(new_fd);
	if (res < 0) {
		close(new_fd);
		/* This is an error, but -1 would indicate disconnect
		 * from the poll loop
		 */
		return 0;
	}

	qb_ipcs_uc_recv_and_auth(new_fd, s);
	return 0;
}
Beispiel #5
0
ssize_t
qb_rb_chunk_peek(struct qb_ringbuffer_s * rb, void **data_out, int32_t timeout)
{
	uint32_t read_pt;
	uint32_t chunk_size;
	uint32_t chunk_magic;
	int32_t res = 0;

	if (rb == NULL) {
		return -EINVAL;
	}
	if (rb->notifier.timedwait_fn) {
		res = rb->notifier.timedwait_fn(rb->notifier.instance, timeout);
	}
	if (res < 0 && res != -EIDRM) {
		if (res == -ETIMEDOUT) {
			return 0;
		} else {
			errno = -res;
			qb_util_perror(LOG_ERR, "sem_timedwait");
		}
		return res;
	}
	read_pt = rb->shared_hdr->read_pt;
	chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);
	if (chunk_magic != QB_RB_CHUNK_MAGIC) {
		if (rb->notifier.post_fn) {
			(void)rb->notifier.post_fn(rb->notifier.instance, res);
		}
		return 0;
	}
	chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
	*data_out = QB_RB_CHUNK_DATA_GET(rb, read_pt);
	return chunk_size;
}
Beispiel #6
0
static int32_t
_finish_connecting(struct qb_ipc_one_way *one_way)
{
	struct sockaddr_un remote_address;
	int res;
	int error;
	int retry = 0;

	set_sock_addr(&remote_address, one_way->u.us.sock_name);

	/* this retry loop is here to help connecting when trying to send
	 * an event right after connection setup.
	 */
	do {
		errno = 0;
		res = connect(one_way->u.us.sock,
			      (struct sockaddr *)&remote_address,
			      QB_SUN_LEN(&remote_address));
		if (res == -1) {
			error = -errno;
			qb_util_perror(LOG_DEBUG, "error calling connect()");
			retry++;
			usleep(100000);
		}
	} while (res == -1 && retry < 10);
	if (res == -1) {
		return error;
	}

	free(one_way->u.us.sock_name);
	one_way->u.us.sock_name = NULL;

	return set_sock_size(one_way->u.us.sock, one_way->max_msg_size);
}
Beispiel #7
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;
}
Beispiel #8
0
int32_t
qb_sys_fd_nonblock_cloexec_set(int32_t fd)
{
	int32_t res = 0;
	int32_t oldflags = fcntl(fd, F_GETFD, 0);

	if (oldflags < 0) {
		oldflags = 0;
	}
	oldflags |= FD_CLOEXEC;
	res = fcntl(fd, F_SETFD, oldflags);
	if (res == -1) {
		res = -errno;
		qb_util_perror(LOG_ERR,
			       "Could not set close-on-exit on fd:%d", fd);
		return res;
	}

	res = fcntl(fd, F_SETFL, O_NONBLOCK);
	if (res == -1) {
		res = -errno;
		qb_util_log(LOG_ERR, "Could not set non-blocking on fd:%d", fd);
	}

	return res;
}
Beispiel #9
0
static ssize_t
qb_ipc_socket_send(struct qb_ipc_one_way *one_way,
		   const void *msg_ptr, size_t msg_len)
{
	ssize_t rc = 0;
	struct ipc_us_control *ctl;
	ctl = (struct ipc_us_control *)one_way->u.us.shared_data;

	if (one_way->u.us.sock_name) {
		rc = _finish_connecting(one_way);
		if (rc < 0) {
			qb_util_log(LOG_ERR, "socket connect-on-send");
			return rc;
		}
	}

	qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);
	rc = send(one_way->u.us.sock, msg_ptr, msg_len, MSG_NOSIGNAL);
	if (rc == -1) {
		rc = -errno;
		if (errno != EAGAIN) {
			qb_util_perror(LOG_ERR, "socket_send:send");
		}
	}
	qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);

	if (ctl && rc == msg_len) {
		qb_atomic_int_inc(&ctl->sent);
	}

	return rc;
}
Beispiel #10
0
ssize_t
qb_rb_chunk_peek(struct qb_ringbuffer_s * rb, void **data_out, int32_t timeout)
{
	uint32_t read_pt;
	uint32_t chunk_size;
	uint32_t chunk_magic;
	int32_t res;

	if (rb == NULL) {
		return -EINVAL;
	}
	res = rb->sem_timedwait_fn(rb, timeout);
	if (res < 0 && res != -EIDRM) {
		if (res != -ETIMEDOUT) {
			qb_util_perror(LOG_ERR, "sem_timedwait");
		}
		return res;
	}
	read_pt = rb->shared_hdr->read_pt;
	chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
	chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);
	*data_out = &rb->shared_data[read_pt + QB_RB_CHUNK_HEADER_WORDS];

	if (chunk_magic != QB_RB_CHUNK_MAGIC) {
		errno = ENOMSG;
		return 0;
	} else {
		return chunk_size;
	}
}
Beispiel #11
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;
}
Beispiel #12
0
Datei: ipcc.c Projekt: krig/libqb
ssize_t
qb_ipcc_sendv_recv(qb_ipcc_connection_t * c,
		   const struct iovec * iov, uint32_t iov_len,
		   void *res_msg, size_t res_len, int32_t ms_timeout)
{
	ssize_t res = 0;
	int32_t timeout_now;
	int32_t timeout_rem = ms_timeout;

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

	if (c->funcs.fc_get) {
		res = c->funcs.fc_get(&c->request);
		if (res < 0) {
			return res;
		} else if (res > 0 && res <= c->fc_enable_max) {
			return -EAGAIN;
		} else {
			/*
			 * we can transmit
			 */
		}
	}

	res = qb_ipcc_sendv(c, iov, iov_len);
	if (res < 0) {
		return res;
	}

	do {
		if (timeout_rem > QB_IPC_MAX_WAIT_MS || ms_timeout == -1) {
			timeout_now = QB_IPC_MAX_WAIT_MS;
		} else {
			timeout_now = timeout_rem;
		}

		res = qb_ipcc_recv(c, res_msg, res_len, timeout_now);
		if (res == -ETIMEDOUT) {
			if (ms_timeout < 0) {
				res = -EAGAIN;
			} else {
				timeout_rem -= timeout_now;
				if (timeout_rem > 0) {
					res = -EAGAIN;
				}
			}
		} else	if (res < 0 && res != -EAGAIN) {
			errno = -res;
			qb_util_perror(LOG_DEBUG,
				       "qb_ipcc_recv %d timeout:(%d/%d)",
				       res, timeout_now, timeout_rem);
		}
	} while (res == -EAGAIN && c->is_connected);

	return res;
}
Beispiel #13
0
ssize_t
qb_rb_chunk_read(struct qb_ringbuffer_s * rb, void *data_out, size_t len,
		 int32_t timeout)
{
	uint32_t read_pt;
	uint32_t chunk_size;
	uint32_t chunk_magic;
	int32_t res = 0;

	if (rb == NULL) {
		return -EINVAL;
	}
	if (rb->notifier.timedwait_fn) {
		res = rb->notifier.timedwait_fn(rb->notifier.instance, timeout);
	}
	if (res < 0 && res != -EIDRM) {
		if (res != -ETIMEDOUT) {
			errno = -res;
			qb_util_perror(LOG_ERR, "sem_timedwait");
		}
		return res;
	}

	read_pt = rb->shared_hdr->read_pt;
	chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);

	if (chunk_magic != QB_RB_CHUNK_MAGIC) {
		if (rb->notifier.timedwait_fn == NULL) {
			return -ETIMEDOUT;
		} else {
			(void)rb->notifier.post_fn(rb->notifier.instance, res);
#ifdef EBADMSG
			return -EBADMSG;
#else
			return -EINVAL;
#endif
		}
	}

	chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
	if (len < chunk_size) {
		qb_util_log(LOG_ERR,
			    "trying to recv chunk of size %d but %d available",
			    len, chunk_size);
		if (rb->notifier.post_fn) {
			(void)rb->notifier.post_fn(rb->notifier.instance, chunk_size);
		}
		return -ENOBUFS;
	}

	memcpy(data_out,
	       QB_RB_CHUNK_DATA_GET(rb, read_pt),
	       chunk_size);

	_rb_chunk_reclaim(rb);

	return chunk_size;
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
0
Datei: ipcc.c Projekt: krig/libqb
static int32_t
_check_connection_state(struct qb_ipcc_connection * c, int32_t res)
{
	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;
	}
	return res;
}
Beispiel #17
0
static int
_rb_chunk_reclaim(struct qb_ringbuffer_s * rb)
{
	uint32_t old_read_pt;
	uint32_t new_read_pt;
	uint32_t old_chunk_size;
	uint32_t chunk_magic;
	int rc = 0;

	old_read_pt = rb->shared_hdr->read_pt;
	chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, old_read_pt);
	if (chunk_magic != QB_RB_CHUNK_MAGIC) {
		return -EINVAL;
	}

	old_chunk_size = QB_RB_CHUNK_SIZE_GET(rb, old_read_pt);
	new_read_pt = qb_rb_chunk_step(rb, old_read_pt);

	/*
	 * clear the header
	 */
	rb->shared_data[old_read_pt] = 0;
	QB_RB_CHUNK_MAGIC_SET(rb, old_read_pt, QB_RB_CHUNK_MAGIC_DEAD);

	/*
	 * set the new read pointer after clearing the header
	 * to prevent a situation where a fast writer will write their
	 * new chunk between setting the new read pointer and clearing the
	 * header.
	 */
	rb->shared_hdr->read_pt = new_read_pt;

	if (rb->notifier.reclaim_fn) {
		rc = rb->notifier.reclaim_fn(rb->notifier.instance,
						 old_chunk_size);
		if (rc < 0) {
			errno = -rc;
			qb_util_perror(LOG_WARNING, "reclaim_fn");
		}
	}

	DEBUG_PRINTF("reclaim [%zd]: read: %u -> %u, write: %u\n",
		     (rb->notifier.q_len_fn ?
		      rb->notifier.q_len_fn(rb->notifier.instance) : 0),
		     old_read_pt,
		     rb->shared_hdr->read_pt,
		     rb->shared_hdr->write_pt);

	return rc;
}
Beispiel #18
0
static ssize_t
qb_ipc_pmq_recv(struct qb_ipc_one_way *one_way,
		void *msg_ptr, size_t msg_len, int32_t ms_timeout)
{
	uint32_t msg_prio;
	struct timespec ts_timeout;
	ssize_t res;

	if (ms_timeout >= 0) {
		qb_util_timespec_from_epoch_get(&ts_timeout);
		qb_timespec_add_ms(&ts_timeout, ms_timeout);
	}

mq_receive_again:
	if (ms_timeout >= 0) {
		res = mq_timedreceive(one_way->u.pmq.q,
				      (char *)msg_ptr,
				      one_way->max_msg_size,
				      &msg_prio, &ts_timeout);
	} else {
		res = mq_receive(one_way->u.pmq.q,
				 (char *)msg_ptr,
				 one_way->max_msg_size, &msg_prio);
	}
	if (res == -1) {
		switch (errno) {
		case EINTR:
			goto mq_receive_again;
			break;
		case EAGAIN:
			res = -ETIMEDOUT;
			break;
		case ETIMEDOUT:
			res = -errno;
			break;
		default:
			res = -errno;
			qb_util_perror(LOG_ERR,
				       "error waiting for mq_timedreceive");
			break;
		}
	}

	return res;
}
Beispiel #19
0
ssize_t
qb_rb_chunk_read(struct qb_ringbuffer_s * rb, void *data_out, size_t len,
		 int32_t timeout)
{
	uint32_t read_pt;
	uint32_t chunk_size;
	int32_t res = 0;

	if (rb == NULL) {
		return -EINVAL;
	}
	if (rb->sem_timedwait_fn) {
		res = rb->sem_timedwait_fn(rb, timeout);
	}
	if (res < 0 && res != -EIDRM) {
		if (res != -ETIMEDOUT) {
			qb_util_perror(LOG_ERR, "sem_timedwait");
		}
		return res;
	}

	if (qb_rb_space_used(rb) == 0) {
		return -ENOMSG;
	}

	read_pt = rb->shared_hdr->read_pt;
	qb_rb_chunk_check(rb, read_pt);
	chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);

	if (len < chunk_size) {
		qb_util_log(LOG_ERR,
			    "trying to recv chunk of size %d but %d available",
			    len, chunk_size);
		return -ENOBUFS;
	}

	memcpy(data_out,
	       &rb->shared_data[read_pt + QB_RB_CHUNK_HEADER_WORDS],
	       chunk_size);

	qb_rb_chunk_reclaim(rb);

	return chunk_size;
}
Beispiel #20
0
static void
_check_connection_state(struct qb_ipcc_connection * c, int32_t res)
{
	if (res >= 0) return;

	if (res != -EAGAIN &&
	    res != -ETIMEDOUT &&
	    res != -EINTR &&
#ifdef EWOULDBLOCK
	    res != -EWOULDBLOCK &&
#endif
	    res != -EINVAL) {
		errno = -res;
		qb_util_perror(LOG_DEBUG,
			    "interpreting result %d as a disconnect",
			    res);
		c->is_connected = QB_FALSE;
	}
}
Beispiel #21
0
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;
}
Beispiel #22
0
int32_t
qb_ipcs_us_publish(struct qb_ipcs_service * s)
{
	struct sockaddr_un un_addr;
	int32_t res;

	/*
	 * Create socket for IPC clients, name socket, listen for connections
	 */
	s->server_sock = socket(PF_UNIX, SOCK_STREAM, 0);
	if (s->server_sock == -1) {
		res = -errno;
		qb_util_perror(LOG_ERR, "Cannot create server socket");
		return res;
	}

	res = qb_sys_fd_nonblock_cloexec_set(s->server_sock);
	if (res < 0) {
		goto error_close;
	}

	memset(&un_addr, 0, sizeof(struct sockaddr_un));
	un_addr.sun_family = AF_UNIX;
#if defined(QB_BSD) || defined(QB_DARWIN)
	un_addr.sun_len = SUN_LEN(&un_addr);
#endif

	qb_util_log(LOG_INFO, "server name: %s", s->name);
#if defined(QB_LINUX) || defined(QB_CYGWIN)
	snprintf(un_addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", s->name);
#else
	{
		struct stat stat_out;
		res = stat(SOCKETDIR, &stat_out);
		if (res == -1 || (res == 0 && !S_ISDIR(stat_out.st_mode))) {
			res = -errno;
			qb_util_log(LOG_CRIT,
				    "Required directory not present %s",
				    SOCKETDIR);
			goto error_close;
		}
		snprintf(un_addr.sun_path, UNIX_PATH_MAX, "%s/%s", SOCKETDIR,
			 s->name);
		unlink(un_addr.sun_path);
	}
#endif

	res = bind(s->server_sock, (struct sockaddr *)&un_addr,
		   QB_SUN_LEN(&un_addr));
	if (res) {
		res = -errno;
		qb_util_perror(LOG_ERR, "Could not bind AF_UNIX (%s)",
			       un_addr.sun_path);
		goto error_close;
	}

	/*
	 * Allow everyone to write to the socket since the IPC layer handles
	 * security automatically
	 */
#if !defined(QB_LINUX) && !defined(QB_CYGWIN)
	res = chmod(un_addr.sun_path, S_IRWXU | S_IRWXG | S_IRWXO);
#endif
	if (listen(s->server_sock, SERVER_BACKLOG) == -1) {
		qb_util_perror(LOG_ERR, "socket listen failed");
	}

	res = s->poll_fns.dispatch_add(s->poll_priority, s->server_sock,
				       POLLIN | POLLPRI | POLLNVAL,
				       s, qb_ipcs_us_connection_acceptor);
	return res;

error_close:
	close(s->server_sock);
	return res;
}
Beispiel #23
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;
}
Beispiel #24
0
int32_t
qb_sys_mmap_file_open(char *path, const char *file, size_t bytes,
		       uint32_t file_flags)
{
	int32_t fd;
	int32_t i;
	int32_t res = 0;
	ssize_t written;
	char *buffer = NULL;
	char *is_absolute = strchr(file, '/');

	if (is_absolute) {
		(void)strlcpy(path, file, PATH_MAX);
	} else {
#if defined(QB_LINUX) || defined(QB_CYGWIN)
		snprintf(path, PATH_MAX, "/dev/shm/%s", file);
#else
		snprintf(path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
		is_absolute = path;
#endif
	}
	fd = open_mmap_file(path, file_flags);
	if (fd < 0 && !is_absolute) {
		qb_util_perror(LOG_ERR, "couldn't open file %s", path);

		snprintf(path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
		fd = open_mmap_file(path, file_flags);
		if (fd < 0) {
			res = -errno;
			qb_util_perror(LOG_ERR, "couldn't open file %s", path);
			return res;
		}
	} else if (fd < 0 && is_absolute) {
		res = -errno;
		qb_util_perror(LOG_ERR, "couldn't open file %s", path);
		return res;
	}

	if (ftruncate(fd, bytes) == -1) {
		res = -errno;
		qb_util_perror(LOG_ERR, "couldn't truncate file %s", path);
		goto unlink_exit;
	}

	if (file_flags & O_CREAT) {
		long page_size = sysconf(_SC_PAGESIZE);
		long write_size = QB_MIN(page_size, bytes);
		if (page_size < 0) {
			res = -errno;
			goto unlink_exit;
		}
		buffer = calloc(1, write_size);
		if (buffer == NULL) {
			res = -ENOMEM;
			goto unlink_exit;
		}
		for (i = 0; i < (bytes / write_size); i++) {
retry_write:
			written = write(fd, buffer, write_size);
			if (written == -1 && errno == EINTR) {
				goto retry_write;
			}
			if (written != write_size) {
				res = -ENOSPC;
				free(buffer);
				goto unlink_exit;
			}
		}
		free(buffer);
	}

	return fd;

unlink_exit:
	unlink(path);
	if (fd > 0) {
		close(fd);
	}
	return res;
}
Beispiel #25
0
void
qb_log_blackbox_print_from_file(const char *bb_filename)
{
	qb_ringbuffer_t *instance;
	ssize_t bytes_read;
	int max_size = 2 * QB_LOG_MAX_LEN;
	char *chunk;
	int fd;
	char time_buf[64];

	fd = open(bb_filename, 0);
	if (fd < 0) {
		qb_util_perror(LOG_ERR, "qb_log_blackbox_print_from_file");
		return;
	}
	instance = qb_rb_create_from_file(fd, 0);
	close(fd);
	if (instance == NULL) {
		return;
	}
	chunk = malloc(max_size);

	do {
		char *ptr;
		uint32_t lineno;
		uint32_t tags;
		uint8_t priority;
		uint32_t fn_size;
		char *function;
		uint32_t len;
		time_t timestamp;
		uint32_t msg_len;
		struct tm *tm;
		char message[QB_LOG_MAX_LEN];

		bytes_read = qb_rb_chunk_read(instance, chunk, max_size, 0);

		if (bytes_read >= 0 && bytes_read < BB_MIN_ENTRY_SIZE) {
			printf("ERROR Corrupt file: blackbox header too small.\n");
			goto cleanup;
		} else if (bytes_read < 0) {
			errno = -bytes_read;
			perror("ERROR: qb_rb_chunk_read failed");
			goto cleanup;
		}
		ptr = chunk;

		/* lineno */
		memcpy(&lineno, ptr, sizeof(uint32_t));
		ptr += sizeof(uint32_t);

		/* tags */
		memcpy(&tags, ptr, sizeof(uint32_t));
		ptr += sizeof(uint32_t);

		/* priority */
		memcpy(&priority, ptr, sizeof(uint8_t));
		ptr += sizeof(uint8_t);

		/* function size & name */
		memcpy(&fn_size, ptr, sizeof(uint32_t));
		if ((fn_size + BB_MIN_ENTRY_SIZE) > bytes_read) {
			printf("ERROR Corrupt file: fn_size way too big %d\n", fn_size);
			goto cleanup;
		}
		if (fn_size <= 0) {
			printf("ERROR Corrupt file: fn_size negative %d\n", fn_size);
			goto cleanup;
		}
		ptr += sizeof(uint32_t);

		function = ptr;
		ptr += fn_size;

		/* timestamp size & content */
		memcpy(&timestamp, ptr, sizeof(time_t));
		ptr += sizeof(time_t);
		tm = localtime(&timestamp);
		if (tm) {
			(void)strftime(time_buf,
				       sizeof(time_buf), "%b %d %T",
				       tm);
		} else {
			snprintf(time_buf, sizeof(time_buf), "%ld",
				 (long int)timestamp);
		}
		/* message length */
		memcpy(&msg_len, ptr, sizeof(uint32_t));
		if (msg_len > QB_LOG_MAX_LEN || msg_len <= 0) {
			printf("ERROR Corrupt file: msg_len out of bounds %d\n", msg_len);
			goto cleanup;
		}

		ptr += sizeof(uint32_t);

		/* message content */
		len = qb_vsnprintf_deserialize(message, QB_LOG_MAX_LEN, ptr);
		assert(len > 0);
		message[len] = '\0';
		len--;
		while (len > 0 && (message[len] == '\n' || message[len] == '\0')) {
			message[len] = '\0';
			len--;
		}

		printf("%-7s %s %s(%u):%u: %s\n",
		       qb_log_priority2str(priority),
		       time_buf, function, lineno, tags, message);

	} while (bytes_read > BB_MIN_ENTRY_SIZE);

cleanup:
	qb_rb_close(instance);
	free(chunk);
}
Beispiel #26
0
/* <u32> file lineno
 * <u32> tags
 * <u8> priority
 * <u32> function name length
 * <string> function name
 * <u32> buffer length
 * <string> buffer
 */
static void
_blackbox_vlogger(int32_t target,
		  struct qb_log_callsite *cs, time_t timestamp, va_list ap)
{
	size_t max_size;
	size_t actual_size;
	uint32_t fn_size;
	char *chunk;
	char *msg_len_pt;
	uint32_t msg_len;
	struct qb_log_target *t = qb_log_target_get(target);

	if (t->instance == NULL) {
		return;
	}

	fn_size = strlen(cs->function) + 1;

	actual_size = 4 * sizeof(uint32_t) + sizeof(uint8_t) + fn_size + sizeof(time_t);
	max_size = actual_size + QB_LOG_MAX_LEN;

	chunk = qb_rb_chunk_alloc(t->instance, max_size);

	if (chunk == NULL) {
		/* something bad has happened. abort blackbox logging */
		qb_util_perror(LOG_ERR, "Blackbox allocation error, aborting blackbox log %s", t->filename);
		qb_rb_close(t->instance);
		t->instance = NULL;
		return;
	}

	/* line number */
	memcpy(chunk, &cs->lineno, sizeof(uint32_t));
	chunk += sizeof(uint32_t);

	/* tags */
	memcpy(chunk, &cs->tags, sizeof(uint32_t));
	chunk += sizeof(uint32_t);

	/* log level/priority */
	memcpy(chunk, &cs->priority, sizeof(uint8_t));
	chunk += sizeof(uint8_t);

	/* function name */
	memcpy(chunk, &fn_size, sizeof(uint32_t));
	chunk += sizeof(uint32_t);
	memcpy(chunk, cs->function, fn_size);
	chunk += fn_size;

	/* timestamp */
	memcpy(chunk, &timestamp, sizeof(time_t));
	chunk += sizeof(time_t);

	/* log message length */
	msg_len_pt = chunk;
	chunk += sizeof(uint32_t);

	/* log message */
	msg_len = qb_vsnprintf_serialize(chunk, QB_LOG_MAX_LEN, cs->format, ap);
	if (msg_len >= QB_LOG_MAX_LEN) {
	    chunk = msg_len_pt + sizeof(uint32_t); /* Reset */

	    msg_len = qb_vsnprintf_serialize(chunk, QB_LOG_MAX_LEN,
		"Log message too long to be stored in the blackbox.  "\
		"Maximum is QB_LOG_MAX_LEN" , ap);
	    actual_size += msg_len;
	}

	actual_size += msg_len;

	/* now that we know the length, write it
	 */
	memcpy(msg_len_pt, &msg_len, sizeof(uint32_t));

	(void)qb_rb_chunk_commit(t->instance, actual_size);
}
Beispiel #27
0
static int32_t
qb_ipcs_us_connect(struct qb_ipcs_service *s,
		   struct qb_ipcs_connection *c,
		   struct qb_ipc_connection_response *r)
{
	char path[PATH_MAX];
	int32_t fd_hdr;
	int32_t res = 0;
	struct ipc_us_control *ctl;
	char *shm_ptr;

	qb_util_log(LOG_DEBUG, "connecting to client (%s)", c->description);

	c->request.u.us.sock = c->setup.u.us.sock;
	c->response.u.us.sock = c->setup.u.us.sock;

	snprintf(r->request, NAME_MAX, "qb-%s-control-%s",
		 s->name, c->description);
	snprintf(r->response, NAME_MAX, "qb-%s-%s", s->name, c->description);

	fd_hdr = qb_sys_mmap_file_open(path, r->request,
				       SHM_CONTROL_SIZE,
				       O_CREAT | O_TRUNC | O_RDWR);
	if (fd_hdr < 0) {
		res = fd_hdr;
		errno = -fd_hdr;
		qb_util_perror(LOG_ERR, "couldn't create file for mmap (%s)",
			       c->description);
		return res;
	}
	(void)strlcpy(r->request, path, PATH_MAX);
	(void)strlcpy(c->request.u.us.shared_file_name, r->request, NAME_MAX);
	res = chown(r->request, c->auth.uid, c->auth.gid);
	if (res != 0) {
		/* ignore res, this is just for the compiler warnings.
		 */
		res = 0;
	}
	res = chmod(r->request, c->auth.mode);
	if (res != 0) {
		/* ignore res, this is just for the compiler warnings.
		 */
		res = 0;
	}

	shm_ptr = mmap(0, SHM_CONTROL_SIZE,
		       PROT_READ | PROT_WRITE, MAP_SHARED, fd_hdr, 0);

	if (shm_ptr == MAP_FAILED) {
		res = -errno;
		qb_util_perror(LOG_ERR, "couldn't create mmap for header (%s)",
			       c->description);
		goto cleanup_hdr;
	}
	c->request.u.us.shared_data = shm_ptr;
	c->response.u.us.shared_data = shm_ptr + sizeof(struct ipc_us_control);
	c->event.u.us.shared_data =  shm_ptr + (2 * sizeof(struct ipc_us_control));

	ctl = (struct ipc_us_control *)c->request.u.us.shared_data;
	ctl->sent = 0;
	ctl->flow_control = 0;
	ctl = (struct ipc_us_control *)c->response.u.us.shared_data;
	ctl->sent = 0;
	ctl->flow_control = 0;
	ctl = (struct ipc_us_control *)c->event.u.us.shared_data;
	ctl->sent = 0;
	ctl->flow_control = 0;

	close(fd_hdr);

	/* request channel */
	res = qb_ipc_dgram_sock_setup(r->response, "request",
				      &c->request.u.us.sock);
	if (res < 0) {
		goto cleanup_hdr;
	}
	c->setup.u.us.sock_name = NULL;
	c->request.u.us.sock_name = NULL;

	/* response channel */
	c->response.u.us.sock = c->request.u.us.sock;
	snprintf(path, PATH_MAX, "%s-%s", r->response, "response");
	c->response.u.us.sock_name = strdup(path);

	/* event channel */
	res = qb_ipc_dgram_sock_setup(r->response, "event-tx",
				      &c->event.u.us.sock);
	if (res < 0) {
		goto cleanup_hdr;
	}
	snprintf(path, PATH_MAX, "%s-%s", r->response, "event");
	c->event.u.us.sock_name = strdup(path);

	res = _sock_add_to_mainloop(c);
	if (res < 0) {
		goto cleanup_hdr;
	}

	return res;

cleanup_hdr:
	free(c->response.u.us.sock_name);
	free(c->event.u.us.sock_name);

	close(fd_hdr);
	unlink(r->request);
	munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE);
	return res;
}
Beispiel #28
0
qb_ringbuffer_t *
qb_rb_create_from_file(int32_t fd, uint32_t flags)
{
	ssize_t n_read;
	size_t n_required;
	size_t total_read = 0;
	uint32_t read_pt;
	uint32_t write_pt;
	struct qb_ringbuffer_s *rb;

	if (fd < 0) {
		return NULL;
	}
	rb = calloc(1, sizeof(struct qb_ringbuffer_s));
	if (rb == NULL) {
		return NULL;
	}
	rb->shared_hdr = calloc(1, sizeof(struct qb_ringbuffer_shared_s));
	if (rb->shared_hdr == NULL) {
		goto cleanup_fail2;
	}

	rb->flags = flags;

	n_required = sizeof(uint32_t);
	n_read = read(fd, &rb->shared_hdr->word_size, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		goto cleanup_fail;
	}
	total_read += n_read;

	n_required = (rb->shared_hdr->word_size * sizeof(uint32_t));

	if ((rb->shared_data = malloc(n_required)) == NULL) {
		qb_util_perror(LOG_ERR, "exhausted virtual memory");
		goto cleanup_fail;
	}
	n_read = read(fd, rb->shared_data, n_required);
	if (n_read < 0) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file data");
		goto cleanup_fail;
	}
	total_read += n_read;

	if (n_read != n_required) {
		qb_util_log(LOG_WARNING, "read %zd bytes, but expected %zu",
			    n_read, n_required);
		goto cleanup_fail;
	}

	n_read = read(fd, &write_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	rb->shared_hdr->write_pt = write_pt;
	total_read += n_read;

	n_read = read(fd, &read_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	rb->shared_hdr->read_pt = read_pt;
	total_read += n_read;

	qb_util_log(LOG_DEBUG, "read total of: %zd", total_read);
	print_header(rb);

	return rb;

cleanup_fail:
	free(rb->shared_hdr);
cleanup_fail2:
	free(rb);
	return NULL;
}
Beispiel #29
0
qb_ringbuffer_t *
qb_rb_open(const char *name, size_t size, uint32_t flags,
	   size_t shared_user_data_size)
{
	struct qb_ringbuffer_s *rb;
	size_t real_size;
	size_t shared_size;
	char path[PATH_MAX];
	int32_t fd_hdr;
	int32_t fd_data;
	uint32_t file_flags = O_RDWR;
	char filename[PATH_MAX];
	int32_t error = 0;
	void *shm_addr;
	long page_size = sysconf(_SC_PAGESIZE);

#ifdef QB_FORCE_SHM_ALIGN
	page_size = QB_MAX(page_size, 16 * 1024);
#endif /* QB_FORCE_SHM_ALIGN */
	real_size = QB_ROUNDUP(size, page_size);
	shared_size =
	    sizeof(struct qb_ringbuffer_shared_s) + shared_user_data_size;

	if (flags & QB_RB_FLAG_CREATE) {
		file_flags |= O_CREAT | O_TRUNC;
	}

	rb = calloc(1, sizeof(struct qb_ringbuffer_s));
	if (rb == NULL) {
		return NULL;
	}

	/*
	 * Create a shared_hdr memory segment for the header.
	 */
	snprintf(filename, PATH_MAX, "qb-%s-header", name);
	fd_hdr = qb_sys_mmap_file_open(path, filename,
				       shared_size, file_flags);
	if (fd_hdr < 0) {
		error = fd_hdr;
		qb_util_log(LOG_ERR, "couldn't create file for mmap");
		goto cleanup_hdr;
	}

	rb->shared_hdr = mmap(0,
			      shared_size,
			      PROT_READ | PROT_WRITE, MAP_SHARED, fd_hdr, 0);

	if (rb->shared_hdr == MAP_FAILED) {
		error = -errno;
		qb_util_log(LOG_ERR, "couldn't create mmap for header");
		goto cleanup_hdr;
	}

	rb->flags = flags;

	/*
	 * create the semaphore
	 */
	if (flags & QB_RB_FLAG_CREATE) {
		rb->shared_data = NULL;
		/* rb->shared_hdr->word_size tracks data by ints and not bytes/chars. */
		rb->shared_hdr->word_size = real_size / sizeof(uint32_t);
		rb->shared_hdr->write_pt = 0;
		rb->shared_hdr->read_pt = 0;
		(void)strlcpy(rb->shared_hdr->hdr_path, path, PATH_MAX);
	}
	error = qb_rb_sem_create(rb, flags);
	if (error < 0) {
		qb_util_perror(LOG_ERR, "couldn't get a semaphore");
		goto cleanup_hdr;
	}

	/* Create the shared_data memory segment for the actual ringbuffer.
	 * They have to be separate.
	 */
	if (flags & QB_RB_FLAG_CREATE) {
		snprintf(filename, PATH_MAX, "qb-%s-data", name);
		fd_data = qb_sys_mmap_file_open(path,
						filename,
						real_size, file_flags);
		(void)strlcpy(rb->shared_hdr->data_path, path, PATH_MAX);
	} else {
		fd_data = qb_sys_mmap_file_open(path,
						rb->shared_hdr->data_path,
						real_size, file_flags);
	}
	if (fd_data < 0) {
		error = fd_data;
		qb_util_log(LOG_ERR, "couldn't create file for mmap");
		goto cleanup_hdr;
	}

	qb_util_log(LOG_DEBUG,
		    "shm size:%zd; real_size:%zd; rb->word_size:%d", size,
		    real_size, rb->shared_hdr->word_size);

	error = qb_sys_circular_mmap(fd_data, &shm_addr, real_size);
	rb->shared_data = shm_addr;
	if (error != 0) {
		qb_util_log(LOG_ERR, "couldn't create circular mmap on %s",
			    rb->shared_hdr->data_path);
		goto cleanup_data;
	}

	if (flags & QB_RB_FLAG_CREATE) {
		memset(rb->shared_data, 0, real_size);
		rb->shared_data[rb->shared_hdr->word_size] = 5;
		rb->shared_hdr->ref_count = 1;
	} else {
		qb_atomic_int_inc(&rb->shared_hdr->ref_count);
	}

	close(fd_hdr);
	close(fd_data);
	return rb;

cleanup_data:
	close(fd_data);
	if (flags & QB_RB_FLAG_CREATE) {
		unlink(rb->shared_hdr->data_path);
	}

cleanup_hdr:
	if (fd_hdr >= 0) {
		close(fd_hdr);
	}
	if (rb && (flags & QB_RB_FLAG_CREATE)) {
		unlink(rb->shared_hdr->hdr_path);
		(void)rb->sem_destroy_fn(rb);
	}
	if (rb && (rb->shared_hdr != MAP_FAILED && rb->shared_hdr != NULL)) {
		munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
	}
	free(rb);
	errno = -error;
	return NULL;
}
Beispiel #30
0
int32_t
qb_ipcc_us_connect(struct qb_ipcc_connection * c,
		   struct qb_ipc_connection_response * r)
{
	int32_t res;
	char path[PATH_MAX];
	int32_t fd_hdr;
	char *shm_ptr;

	qb_atomic_init();

	c->needs_sock_for_poll = QB_FALSE;
	c->funcs.send = qb_ipc_socket_send;
	c->funcs.sendv = qb_ipc_socket_sendv;
	c->funcs.recv = qb_ipc_us_recv_at_most;
	c->funcs.fc_get = qb_ipc_us_fc_get;
	c->funcs.disconnect = qb_ipcc_us_disconnect;

	fd_hdr = qb_sys_mmap_file_open(path, r->request,
				       SHM_CONTROL_SIZE, O_RDWR);
	if (fd_hdr < 0) {
		res = fd_hdr;
		errno = -fd_hdr;
		qb_util_perror(LOG_ERR, "couldn't open file for mmap");
		return res;
	}
	(void)strlcpy(c->request.u.us.shared_file_name, r->request, NAME_MAX);
	shm_ptr = mmap(0, SHM_CONTROL_SIZE,
		       PROT_READ | PROT_WRITE, MAP_SHARED, fd_hdr, 0);

	if (shm_ptr == MAP_FAILED) {
		res = -errno;
		qb_util_perror(LOG_ERR, "couldn't create mmap for header");
		goto cleanup_hdr;
	}
	c->request.u.us.shared_data = shm_ptr;
	c->response.u.us.shared_data = shm_ptr + sizeof(struct ipc_us_control);
	c->event.u.us.shared_data =  shm_ptr + (2 * sizeof(struct ipc_us_control));

	close(fd_hdr);

	res = qb_ipc_dgram_sock_connect(r->response, "response", "request",
					r->max_msg_size, &c->request.u.us.sock);
	if (res != 0) {
		goto cleanup_hdr;
	}
	c->response.u.us.sock = c->request.u.us.sock;

	res = qb_ipc_dgram_sock_connect(r->response, "event", "event-tx",
					r->max_msg_size, &c->event.u.us.sock);
	if (res != 0) {
		goto cleanup_hdr;
	}

	return 0;

cleanup_hdr:
	close(fd_hdr);
	close(c->event.u.us.sock);
	close(c->request.u.us.sock);
	unlink(r->request);
	munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE);
	return res;
}