Esempio n. 1
0
int tcp_master(dthread_t *thread)
{
	if (!thread || !thread->data) {
		return KNOT_EINVAL;
	}

	iohandler_t *handler = (iohandler_t *)thread->data;
	unsigned *iostate = &handler->thread_state[dt_get_id(thread)];

	int ret = KNOT_EOK;
	ref_t *ref = NULL;
	tcp_context_t tcp;
	memset(&tcp, 0, sizeof(tcp_context_t));

	/* Create big enough memory cushion. */
	knot_mm_t mm;
	mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);

	/* Create TCP answering context. */
	tcp.server = handler->server;
	tcp.thread_id = handler->thread_id[dt_get_id(thread)];
	tcp.overlay.mm = &mm;

	/* Prepare structures for bound sockets. */
	conf_val_t val = conf_get(conf(), C_SRV, C_LISTEN);
	fdset_init(&tcp.set, conf_val_count(&val) + CONF_XFERS);

	/* Create iovec abstraction. */
	for (unsigned i = 0; i < 2; ++i) {
		tcp.iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE;
		tcp.iov[i].iov_base = malloc(tcp.iov[i].iov_len);
		if (tcp.iov[i].iov_base == NULL) {
			ret = KNOT_ENOMEM;
			goto finish;
		}
	}

	/* Initialize sweep interval. */
	timev_t next_sweep = {0};
	time_now(&next_sweep);
	next_sweep.tv_sec += TCP_SWEEP_INTERVAL;

	for(;;) {

		/* Check handler state. */
		if (unlikely(*iostate & ServerReload)) {
			*iostate &= ~ServerReload;

			/* Cancel client connections. */
			for (unsigned i = tcp.client_threshold; i < tcp.set.n; ++i) {
				close(tcp.set.pfd[i].fd);
			}

			ref_release(ref);
			ref = server_set_ifaces(handler->server, &tcp.set, IO_TCP, tcp.thread_id);
			if (tcp.set.n == 0) {
				break; /* Terminate on zero interfaces. */
			}

			tcp.client_threshold = tcp.set.n;
		}

		/* Check for cancellation. */
		if (dt_is_cancelled(thread)) {
			break;
		}

		/* Serve client requests. */
		tcp_wait_for_events(&tcp);

		/* Sweep inactive clients. */
		if (tcp.last_poll_time.tv_sec >= next_sweep.tv_sec) {
			fdset_sweep(&tcp.set, &tcp_sweep, NULL);
			time_now(&next_sweep);
			next_sweep.tv_sec += TCP_SWEEP_INTERVAL;
		}
	}

finish:
	free(tcp.iov[0].iov_base);
	free(tcp.iov[1].iov_base);
	mp_delete(mm.ctx);
	fdset_clear(&tcp.set);
	ref_release(ref);

	return ret;
}
Esempio n. 2
0
int main(int argc, char *argv[])
{
	plan(12);

	/* 1. Create fdset. */
	fdset_t set;
	int ret = fdset_init(&set, 32);
	is_int(0, ret, "fdset: init");

	/* 2. Create pipe. */
	int fds[2], tmpfds[2];
	ret = pipe(fds);
	ok(ret >= 0, "fdset: pipe() works");
	ret = pipe(tmpfds);
	ok(ret >= 0, "fdset: 2nd pipe() works");

	/* 3. Add fd to set. */
	ret = fdset_add(&set, fds[0], POLLIN, NULL);
	is_int(0, ret, "fdset: add to set works");
	fdset_add(&set, tmpfds[0], POLLIN, NULL);

	/* Schedule write. */
	struct timeval ts, te;
	gettimeofday(&ts, 0);
	pthread_t t;
	pthread_create(&t, 0, thr_action, &fds[1]);

	/* 4. Watch fdset. */
	int nfds = poll(set.pfd, set.n, 60 * 1000);
	gettimeofday(&te, 0);
	size_t diff = timeval_diff(&ts, &te);

	ok(nfds > 0, "fdset: poll returned %d events in %zu ms", nfds, diff);

	/* 5. Prepare event set. */
	ok(set.pfd[0].revents & POLLIN, "fdset: pipe is active");

	/* 6. Receive data. */
	char buf = 0x00;
	ret = read(set.pfd[0].fd, &buf, WRITE_PATTERN_LEN);
	ok(ret >= 0 && buf == WRITE_PATTERN, "fdset: contains valid data");

	/* 7-9. Remove from event set. */
	ret = fdset_remove(&set, 0);
	is_int(0, ret, "fdset: remove from fdset works");
	close(fds[0]);
	close(fds[1]);
	ret = fdset_remove(&set, 0);
	close(tmpfds[1]);
	close(tmpfds[1]);
	is_int(0, ret, "fdset: remove from fdset works (2)");
	ret = fdset_remove(&set, 0);
	ok(ret != 0, "fdset: removing nonexistent item");

	/* 10. Crash test. */
	fdset_init(0, 0);
	fdset_add(0, 1, 1, 0);
	fdset_add(0, 0, 1, 0);
	fdset_remove(0, 1);
	fdset_remove(0, 0);
	ok(1, "fdset: crash test successful");

	/* 11. Destroy fdset. */
	ret = fdset_clear(&set);
	is_int(0, ret, "fdset: destroyed");

	/* Cleanup. */
	pthread_join(t, 0);

	return 0;
}