Exemplo n.º 1
0
void server_wait(server *s)
{
	int maxfd = s->socket;
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(s->socket, &rfds);

	GList *i;
	for (i = s->connections; i != NULL; i = i->next)
	{
		connection *c = (connection *)i->data;
		int fd = connection_socket(c);
		if (fd > maxfd) maxfd = fd;
		FD_SET(fd, &rfds);
	}

	struct timeval tv;
	tv.tv_sec = TIMEOUT_SEC;
	tv.tv_usec = TIMEOUT_USEC;
	int status = select(maxfd + 1, &rfds, NULL, NULL, &tv);

	if (status > 0)
	{
		if (FD_ISSET(s->socket, &rfds))
		{
			if (!g_queue_is_empty(s->free_connections))
			{
				connection *c = (connection *)g_queue_pop_head(s->free_connections);
				s->connections = g_list_append(s->connections, c);

				connection_accept(c, s->socket);
				if (connection_socket(c) == 0) halt_error("Socket accept really shouldn't fail");
			}
		}

		GList *j = s->connections;
		while (j != NULL)
		{
			GList *next = j->next;

			connection *c = (connection *)j->data;
			if (FD_ISSET(connection_socket(c), &rfds))
			{
				if (connection_receive(c))
				{
					j->data = NULL;
					s->connections = g_list_delete_link(s->connections, j);
					g_queue_push_tail(s->free_connections, c);
				}
			}

			j = next;
		}
	}
	else if (status == 0)
	{
		// connection timeout
		GList *j = s->connections;
		while (j != NULL)
		{
			GList *next = j->next;

			connection *c = (connection *)j->data;
			connection_timeout_increment(c, TIMEOUT_SEC + (((float)TIMEOUT_USEC) / 1000000.0f));

			if (connection_timedout(c))
			{
				j->data = NULL;
				s->connections = g_list_delete_link(s->connections, j);
				g_queue_push_tail(s->free_connections, c);
			}

			j = next;
		}
	}
	else
	{
		// TODO: Don't know if this is ever a fatal error
		//halt_error("Error in socket select");
		return;
	}
}
Exemplo n.º 2
0
int server(unsigned short port, int demarcaciones, int taxPorDemarcacion, int iters, int timeout_millis, int txdelay_millis, bool debug) {
	connection_t conn;
	packet_t outgoing;
	packet_t * incoming;

	if (!connection_server(&conn, port)) {
		fprintf(stderr, "Unable to spawn server on port %u: ", port);
		connection_error(&conn, stderr);
		fprintf(stderr, "\n");
		return 1;
	}

	if (debug) {
		connection_debug(&conn, stderr);
	}

	gestion_taxi_t * taxis = calloc(demarcaciones * taxPorDemarcacion, sizeof(gestion_taxi_t));
	if (taxis == NULL) {
		fprintf(stderr, "Failed to allocate memory for taxi stats structure: %s\n", strerror(errno));
		return 1;
	}

	fprintf(stderr, "Waiting for clientes at port: [%d]\n", port);
	int connected = 0;
	int pendingAccAck = demarcaciones * taxPorDemarcacion;
	while (pendingAccAck > 0) {
		if (!connection_receive(&conn, &incoming, NULL)) { /* TODO: check how to safely implement a timeout here */
			fprintf(stderr, "Error receiving login packet: ");
			connection_error(&conn, stderr);
			fprintf(stderr, "\n");

			if (connection_dead(&conn)) {
				connection_close(&conn);
				free(taxis);
				return 1;
			}

			continue;
		}

		bool duplicate = false;
		int pos;
		switch (incoming->type) {
			case PACKET_TYPE_LOGIN:
				if (incoming->login.version != PACKET_VERSION) {
					fprintf(stderr, "Got LOGIN with version %08X but server version is %08X\n", incoming->login.version, PACKET_VERSION);
					connection_discard(&conn);
					continue;
				}
				connection_accept(&conn);

				for (pos = 0; pos < connected; pos++) {
					if (connection_cmp(&taxis[pos].conexionConTaxi, &conn)) {
						duplicate = true;
						fprintf(stderr, "Got duplicated login packet from taxi %d-%d. Re-sending acknowledgement\n", pos / taxPorDemarcacion, pos % taxPorDemarcacion);
						break;
					}
				}

				if (!duplicate) {
					if (connected == taxPorDemarcacion * demarcaciones) {
						fprintf(stderr, "Received new LOGIN but all taxis have been already registered\n");
						continue;
					}

					fprintf(stderr, "Registered new taxi %d-%d\n", connected / taxPorDemarcacion, connected % taxPorDemarcacion);
					memcpy(&taxis[connected].conexionConTaxi, &conn, sizeof(conn));
					connected++;
				}

				outgoing.type = PACKET_TYPE_ACCEPT;
				outgoing.accept.zone = pos / taxPorDemarcacion;
				outgoing.accept.id = pos % taxPorDemarcacion;
				outgoing.accept.neighbors = taxPorDemarcacion - 1;
				outgoing.accept.ticks = iters;
				outgoing.accept.timeout = timeout_millis;
				outgoing.accept.txdelay = txdelay_millis;
				if (!connection_send(&conn, &outgoing)) {
					fprintf(stderr, "Error replying to login packet: ");
					connection_error(&conn, stderr);
					fprintf(stderr, "\n");
					connection_close(&conn);
					free(taxis);
					return 1;
				}

				break;

			case PACKET_TYPE_ACCACK:
				if (incoming->accack.zone >= demarcaciones || incoming->accack.id >= taxPorDemarcacion) {
					fprintf(stderr, "Received illegal accept acknowledgement from taxi %u-%u\n", incoming->accack.zone, incoming->accack.id);
					connection_discard(&conn);
					continue;
				}
				connection_accept(&conn);

				gestion_taxi_t * taxi = &taxis[incoming->accack.zone * taxPorDemarcacion + incoming->accack.id];
				if (!taxi->hasAckdAccept) {
					taxi->hasAckdAccept = true;
					pendingAccAck--;
				}
				break;

			default:
				connection_discard(&conn);
				fprintf(stderr, "Unexpected packet %s during login phase. Discarding.\n", packet_name(incoming));
				continue;
		}
	}

	outgoing.type = PACKET_TYPE_START;
	for (int pos = 0; pos < demarcaciones * taxPorDemarcacion; pos++) {
		if (!connection_send(&taxis[pos].conexionConTaxi, &outgoing)) {
			fprintf(stderr, "Error sending start packet: ");
			connection_error(&conn, stderr);
			fprintf(stderr, "\n");
			connection_close(&conn);
			free(taxis);
			return 1;
		}
	}

	int statsRcv = 0;
	struct timeval defaulttimeout = { (timeout_millis * 2) / 1000, ((timeout_millis * 2) % 1000) * 1000 };
	struct timeval timeout = defaulttimeout;
	while (statsRcv < demarcaciones * taxPorDemarcacion) {
		if (!connection_receive(&conn, &incoming, NULL)) {
			fprintf(stderr, "Error receiving packet in main loop: ");
			connection_error(&conn, stderr);
			fprintf(stderr, "\n");

			if (conn.err == CONNERR_TIMEOUT) {
				break;
			}

			if (connection_dead(&conn)) {
				connection_close(&conn);
				free(taxis);
				return 1;
			}

			continue;
		}

		gestion_taxi_t * taxi;
		switch (incoming->type) {
			case PACKET_TYPE_ACCACK:
				outgoing.type = PACKET_TYPE_START;
				if (!connection_send(&conn, &outgoing)) {
					fprintf(stderr, "Failed to send start packet in main loop: ");
					connection_error(&conn, stderr);
					fprintf(stderr, "\n");
					connection_close(&conn);
					return 1;
				}
				timeout = defaulttimeout;
				break;

			case PACKET_TYPE_POSITION:
				if (incoming->position.zone > demarcaciones || incoming->position.id > taxPorDemarcacion) {
					fprintf(stderr, "Received position from illegal taxi %u-%u\n", outgoing.position.zone, outgoing.position.id);
					connection_discard(&conn);
					continue;
				}

				for (int neighbor = 0; neighbor < taxPorDemarcacion; neighbor++) {
					if (neighbor == incoming->position.id) {
						continue;
					}

					if (!connection_send(&taxis[incoming->position.zone * taxPorDemarcacion + neighbor].conexionConTaxi, incoming)) {
						fprintf(stderr, "Error forwarding position packet: ");
						connection_error(&taxis[incoming->position.zone * taxPorDemarcacion + neighbor].conexionConTaxi, stderr);
						fprintf(stderr, "\n");
						connection_close(&conn);
						free(taxis);
						return 1;
					}
				}
				timeout = defaulttimeout;
				connection_accept(&conn);
				break;

			case PACKET_TYPE_POSACK:
				if (incoming->posack.zone > demarcaciones || incoming->posack.id > taxPorDemarcacion) {
					fprintf(stderr, "Received acknowledgement from illegal taxi %u-%u\n", incoming->posack.zone, incoming->posack.id);
					break;
				}

				if (incoming->posack.neighbor > taxPorDemarcacion) {
					fprintf(stderr, "Received acknowledgement from %u-%u targeting out-of-bounds taxi %u-%u\n", incoming->posack.zone, incoming->posack.id, incoming->posack.zone, incoming->posack.neighbor);
					break;
				}

				taxi = &taxis[incoming->posack.zone * taxPorDemarcacion + incoming->posack.neighbor];
				if (!connection_send(&taxi->conexionConTaxi, incoming)) {
					fprintf(stderr, "Error forwarding acknowledgement packet: ");
					connection_error(&taxi->conexionConTaxi, stderr);
					fprintf(stderr, "\n");
					connection_close(&conn);
					free(taxis);
					return 1;
				}
				timeout = defaulttimeout;
				connection_accept(&conn);
				break;

			case PACKET_TYPE_STATS:
				taxi = &taxis[incoming->stats.zone * taxPorDemarcacion + incoming->stats.id];
				if (!taxi->hasSentStats) {
					printf("%u, %u, %u, %u, %u, %u, %u, %u\n",
						incoming->stats.zone,
						incoming->stats.id,
						incoming->stats.ticks,
						incoming->stats.posrcv,
						incoming->stats.ackrcv,
						incoming->stats.itmin,
						incoming->stats.itavg,
						incoming->stats.itmax
					);
					taxi->hasSentStats = true;
					statsRcv++;
				}

				outgoing.type = PACKET_TYPE_STATACK;
				if (!connection_send(&taxi->conexionConTaxi, &outgoing)) {
					fprintf(stderr, "Error sending stats acknowledgement packet: ");
					connection_error(&taxi->conexionConTaxi, stderr);
					fprintf(stderr, "\n");
					connection_close(&conn);
					free(taxis);
					return 1;
				}

				timeout = defaulttimeout;
				connection_accept(&conn);
				break;

			default:
				fprintf(stderr, "Unexpected packet %s during main loop\n", packet_name(incoming));
				connection_discard(&conn);
				continue;
		}
	}

	// TODO: Interpretar estadísticas
	return 0;
}