コード例 #1
0
ファイル: tcpr-chat.c プロジェクト: tl268/tcpr
static void *read_updates(void *arg)
{
	struct update update;
	ssize_t size;

	(void)arg;

	size = read(update_socket, &update, sizeof(update));
	clock_gettime(CLOCK_REALTIME, &timestamp);
	if (size < 0) {
		perror("Receiving update");
		exit(EXIT_FAILURE);
	}
	if (recovering) {
		message("Recovered.");
		state->tcpr.delta = update.tcpr.delta;
		fprintf(stderr, "Peer has acknowledged %" PRIu32 " bytes.\n",
				ntohl(update.tcpr.peer_ack)
					- ntohl(state->tcpr.peer_ack));
		fprintf(stderr, "Delta is now %" PRIu32 ".\n",
				state->tcpr.delta);
	} else {
		message("Connected.");
		pthread_mutex_lock(&flags_lock);
		memcpy(state, &update, sizeof(update));
		pthread_cond_broadcast(&state_ready);
		pthread_mutex_unlock(&flags_lock);
	}

	while ((size = read(update_socket, &update, sizeof(update))) > 0) {
		clock_gettime(CLOCK_REALTIME, &timestamp);
		if (!update.tcpr.flags) {
			message("Filter needs recovery.");
			if (write(update_socket, state, sizeof(*state)) < 0) {
				perror("Sending state");
				exit(EXIT_FAILURE);
			}
			message_now("Sent state to filter.");
		} else if (update.tcpr.flags & TCPR_TIME_WAIT) {
			message("Entering TIME_WAIT.");
			pthread_mutex_lock(&flags_lock);
			state->tcpr.flags |= TCPR_TIME_WAIT;
			pthread_mutex_unlock(&flags_lock);
			/*  FIXME: should TIME_WAIT for safety */
			if (write(update_socket, state, sizeof(*state)) < 0) {
				perror("Removing filter state");
				exit(EXIT_FAILURE);
			}
			message_now("Removed filter state.");
			return NULL;
		} else {
			message("Unexpected update.");
		}
	}
	if (size < 0) {
		perror("Receiving update");
		exit(EXIT_FAILURE);
	}
	return NULL;
}
コード例 #2
0
ファイル: tcpr-chat.c プロジェクト: tl268/tcpr
static void recover_connection(void)
{
	struct sockaddr_in addr;

	message_now("Recovering connection.");

	data_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (data_socket < 0) {
		perror("Creating socket");
		exit(EXIT_FAILURE);
	}
	setup_socket(data_socket);

	addr.sin_family = AF_INET;
	addr.sin_port = state->tcpr.port;
	addr.sin_addr.s_addr = state->address;
	if (bind(data_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("Binding");
		exit(EXIT_FAILURE);
	}

	addr.sin_family = AF_INET;
	addr.sin_port = state->tcpr.peer_port;
	addr.sin_addr.s_addr = state->peer_address;
	if (connect(data_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("Connecting");
		exit(EXIT_FAILURE);
	}

	message_now("Connected.");
	pthread_create(&read_thread, NULL, read_from_peer, NULL);
	pthread_create(&send_thread, NULL, send_to_peer, NULL);
}
コード例 #3
0
ファイル: tcpr-chat.c プロジェクト: psp26/tcpr
static void *read_from_peer(void *arg)
{
	char buf[1024];
	ssize_t bytes;
	ssize_t sent;
	ssize_t size;

	(void)arg;

	if (filtering) {
		pthread_mutex_lock(&flags_lock);
		while (!state->tcpr.flags)
			pthread_cond_wait(&state_ready, &flags_lock);
		pthread_mutex_unlock(&flags_lock);
	}

	message_now("Starting receive loop.");
	while ((size = read(data_socket, buf, sizeof(buf))) > 0) {
		message_now("Received data.");
		for (sent = 0; sent < size; sent += bytes) {
			bytes = write(1, &buf[sent], size - sent);
			if (bytes < 0) {
				perror("Printing");
				exit(EXIT_FAILURE);
			}
			if (filtering) {
				state->tcpr.ack = htonl(ntohl(state->tcpr.ack)
								+ bytes);
				if (sendto(update_socket, state,
						sizeof(*state), 0,
						(struct sockaddr *)
						&filter_address,
						sizeof(filter_address)) < 0) {
					perror("Sending acknowledgment");
					exit(EXIT_FAILURE);
				}
			}
		}
	}
	if (size < 0) {
		perror("Receiving");
		exit(EXIT_FAILURE);
	}

	message_now("Done receiving.");
	if (filtering) {
		pthread_mutex_lock(&flags_lock);
		state->tcpr.flags |= TCPR_DONE_READING;
		pthread_mutex_unlock(&flags_lock);
		if (sendto(update_socket, state, sizeof(*state), 0,
				(struct sockaddr *)&filter_address,
				sizeof(filter_address)) < 0) {
			perror("Sending input shutdown");
			exit(EXIT_FAILURE);
		}
	}
	return NULL;
}
コード例 #4
0
ファイル: tcpr-chat.c プロジェクト: psp26/tcpr
static void *send_to_peer(void *arg)
{
	char buf[1024];
	ssize_t bytes;
	ssize_t sent;
	ssize_t size;

	(void)arg;

	if (filtering) {
		pthread_mutex_lock(&flags_lock);
		while (!state->tcpr.flags)
			pthread_cond_wait(&state_ready, &flags_lock);
		pthread_mutex_unlock(&flags_lock);
	}

	message_now("Starting send loop.");
	while ((size = read(0, buf, sizeof(buf))) > 0)
		for (sent = 0; sent < size; sent += bytes) {
			clock_gettime(CLOCK_REALTIME, &timestamp);
			bytes = write(data_socket, &buf[sent], size - sent);
			message("Sending data.");
			message_now("Sent.");
			if (bytes < 0) {
				perror("Sending");
				exit(EXIT_FAILURE);
			}
		}
	if (size < 0) {
		perror("Reading");
		exit(EXIT_FAILURE);
	}

	message_now("Done sending.");
	if (filtering) {
		pthread_mutex_lock(&flags_lock);
		state->tcpr.flags |= TCPR_DONE_WRITING;
		pthread_mutex_unlock(&flags_lock);
		if (sendto(update_socket, state, sizeof(*state), 0,
				(struct sockaddr *)&filter_address,
				sizeof(filter_address)) < 0) {
			perror("Sending input shutdown");
			exit(EXIT_FAILURE);
		}
	}
	if (shutdown(data_socket, SHUT_WR) < 0) {
		perror("Shutting down output");
		exit(EXIT_FAILURE);
	}
	return NULL;
}
コード例 #5
0
ファイル: tcpr-chat.c プロジェクト: tl268/tcpr
static void setup_state(void)
{
	message_now("Initializing persistent state.");

	state_fd = open(state_file, O_RDWR | O_CREAT, 0600);
	if (state_fd < 0) {
		perror("Opening persistent state");
		exit(EXIT_FAILURE);
	}
	if (ftruncate(state_fd, sizeof(*state)) < 0) {
		perror("Resizing persistent state");
		exit(EXIT_FAILURE);
	}
	state = mmap(NULL, sizeof(*state), PROT_READ | PROT_WRITE,
			MAP_SHARED, state_fd, 0);
	if (state == MAP_FAILED) {
		perror("Mapping persistent state");
		exit(EXIT_FAILURE);
	}

	if (state->tcpr.flags && !(state->tcpr.flags & TCPR_TIME_WAIT))
		recovering = 1;

	pthread_mutex_init(&flags_lock, NULL);
	pthread_cond_init(&state_ready, NULL);
}
コード例 #6
0
ファイル: tcpr-chat.c プロジェクト: psp26/tcpr
static void setup_update_connection(void)
{
	struct sockaddr_un addr;

	message_now("Establishing update connection.");

	update_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (update_socket < 0) {
		perror("Creating update socket");
		exit(EXIT_FAILURE);
	}

	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, application_path, sizeof(addr.sun_path) - 1);
	unlink(application_path);
	if (bind(update_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("Binding update socket");
		exit(EXIT_FAILURE);
	}

	memset(&filter_address, 0, sizeof(filter_address));
	filter_address.sun_family = AF_UNIX;
	strncpy(filter_address.sun_path, filter_path,
		sizeof(filter_address.sun_path) - 1);

	pthread_create(&update_thread, NULL, read_updates, NULL);
}
コード例 #7
0
ファイル: tcpr-chat.c プロジェクト: psp26/tcpr
static void finish(void)
{
	pthread_join(read_thread, NULL);
	pthread_join(send_thread, NULL);

	message_now("Closing connection.");
	if (close(data_socket) < 0) {
		perror("Closing connection");
		exit(EXIT_FAILURE);
	}

	if (update_socket) {
		message_now("Closing update connection.");
		pthread_join(update_thread, NULL);
		if (close(update_socket) < 0) {
			perror("Closing update connection");
			exit(EXIT_FAILURE);
		}
		unlink(application_path);

		message_now("Removing persistent state.");
		if (munmap(state, sizeof(*state)) < 0) {
			perror("Unmapping persistent state");
			exit(EXIT_FAILURE);
		}
		if (close(state_fd) < 0) {
			perror("Closing persistent state");
			exit(EXIT_FAILURE);
		}
		if (unlink(state_file) < 0) {
			perror("Destroying persistent state");
			exit(EXIT_FAILURE);
		}

		pthread_mutex_destroy(&flags_lock);
		pthread_cond_destroy(&state_ready);
	}
}
コード例 #8
0
ファイル: tcpr-chat.c プロジェクト: tl268/tcpr
static void setup_update_connection(void)
{
	int ret;
	struct addrinfo *ai;
	struct addrinfo hints;

	message_now("Establishing update connection.");

	update_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (update_socket < 0) {
		perror("Creating update socket");
		exit(EXIT_FAILURE);
	}

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;

	ret = getaddrinfo(application_host, application_port, &hints, &ai);
	if (ret) {
		fprintf(stderr, "Resolving application address: %s\n",
				gai_strerror(ret));
		exit(EXIT_FAILURE);
	}
	if (bind(update_socket, ai->ai_addr, ai->ai_addrlen) < 0) {
		perror("Binding update socket");
		exit(EXIT_FAILURE);
	}
	freeaddrinfo(ai);

	ret = getaddrinfo(filter_host, filter_port, &hints, &ai);
	if (ret) {
		fprintf(stderr, "Resolving filter address: %s\n",
				gai_strerror(ret));
		exit(EXIT_FAILURE);
	}
	if (connect(update_socket, ai->ai_addr, ai->ai_addrlen) < 0) {
		perror("Connecting update socket");
		exit(EXIT_FAILURE);
	}
	freeaddrinfo(ai);

	pthread_create(&update_thread, NULL, read_updates, NULL);
}
コード例 #9
0
ファイル: tcpr-chat.c プロジェクト: tl268/tcpr
static void setup_connection(void)
{
	int ret;
	int s;
	struct addrinfo *ai;
	struct addrinfo hints;

	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0) {
		perror("Creating socket");
		exit(EXIT_FAILURE);
	}
	setup_socket(s);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	if (bind_host || bind_port) {
		hints.ai_flags = (connect_port ? 0 : AI_PASSIVE);
		ret = getaddrinfo(bind_host, bind_port, &hints, &ai);
		if (ret) {
			fprintf(stderr, "Resolving bind address: %s\n",
					gai_strerror(ret));
			exit(EXIT_FAILURE);
		}
		if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
			perror("Binding");
			exit(EXIT_FAILURE);
		}
		freeaddrinfo(ai);
	}

	if (connect_port) {
		message_now("Connecting to peer.");
		hints.ai_flags = 0;
		ret = getaddrinfo(connect_host, connect_port, &hints, &ai);
		if (ret) {
			fprintf(stderr, "Resolving peer address: %s\n",
					gai_strerror(ret));
			exit(EXIT_FAILURE);
		}
		if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
			perror("Connecting");
			exit(EXIT_FAILURE);
		}
		clock_gettime(CLOCK_REALTIME, &timestamp);
		freeaddrinfo(ai);
		data_socket = s;
	} else {
		message_now("Waiting for peer to connect.");
		if (listen(s, 1) < 0) {
			perror("Listening");
			exit(EXIT_FAILURE);
		}
		data_socket = accept(s, NULL, NULL);
		clock_gettime(CLOCK_REALTIME, &timestamp);
		if (data_socket < 0) {
			perror("Accepting");
			exit(EXIT_FAILURE);
		}
		close(s);
	}

	message("Connected.");
	pthread_create(&read_thread, NULL, read_from_peer, NULL);
	pthread_create(&send_thread, NULL, send_to_peer, NULL);
}