Esempio n. 1
0
/*
 * @brief
 */
static void Sv_ReadPackets(void) {
	int32_t i;
	sv_client_t * cl;
	byte qport;

	while (Net_ReceiveDatagram(NS_UDP_SERVER, &net_from, &net_message)) {

		// check for connectionless packet (0xffffffff) first
		if (*(uint32_t *) net_message.data == 0xffffffff) {
			Sv_ConnectionlessPacket();
			continue;
		}

		// read the qport out of the message so we can fix up
		// stupid address translating routers
		Net_BeginReading(&net_message);

		Net_ReadLong(&net_message); // sequence number
		Net_ReadLong(&net_message); // sequence number

		qport = Net_ReadByte(&net_message) & 0xff;

		// check for packets from connected clients
		for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++) {

			if (cl->state == SV_CLIENT_FREE)
				continue;

			if (!Net_CompareClientNetaddr(&net_from, &cl->net_chan.remote_address))
				continue;

			if (cl->net_chan.qport != qport)
				continue;

			if (cl->net_chan.remote_address.port != net_from.port) {
				Com_Warn("Fixing up a translated port\n");
				cl->net_chan.remote_address.port = net_from.port;
			}

			// this is a valid, sequenced packet, so process it
			if (Netchan_Process(&cl->net_chan, &net_message)) {
				cl->last_message = svs.real_time; // nudge timeout
				Sv_ParseClientMessage(cl);
			}

			// we've processed the packet for the correct client, so break
			break;
		}
	}
}
Esempio n. 2
0
/*
 * @brief A connection-less packet has four leading 0xff bytes to distinguish
 * it from a game channel. Clients that are in the game can still send these,
 * and they will be handled here.
 */
static void Sv_ConnectionlessPacket(void) {

	Net_BeginReading(&net_message);
	Net_ReadLong(&net_message); // skip the -1 marker

	const char *s = Net_ReadStringLine(&net_message);

	Cmd_TokenizeString(s);

	const char *c = Cmd_Argv(0);
	const char *a = Net_NetaddrToString(&net_from);

	Com_Debug("Packet from %s: %s\n", a, c);

	if (!g_strcmp0(c, "ping"))
		Svc_Ping();
	else if (!g_strcmp0(c, "ack"))
		Svc_Ack();
	else if (!g_strcmp0(c, "status"))
		Svc_Status();
	else if (!g_strcmp0(c, "info"))
		Svc_Info();
	else if (!g_strcmp0(c, "get_challenge"))
		Svc_GetChallenge();
	else if (!g_strcmp0(c, "connect"))
		Svc_Connect();
	else if (!g_strcmp0(c, "rcon"))
		Svc_RemoteCommand();
	else
		Com_Print("Bad connectionless packet from %s:\n%s\n", a, s);
}
Esempio n. 3
0
/*
 * @brief
 */
static void Cl_ParseServerData(void) {
	char *str;
	int32_t i;

	// wipe the cl_client_t struct
	Cl_ClearState();

	cls.state = CL_CONNECTED;
	cls.key_state.dest = KEY_CONSOLE;

	// parse protocol version number
	i = Net_ReadLong(&net_message);

	// ensure protocol matches
	if (i != PROTOCOL) {
		Com_Error(ERR_DROP, "Server is using unknown protocol %d\n", i);
	}

	// retrieve spawn count and packet rate
	cl.server_count = Net_ReadLong(&net_message);
	cl.server_hz = Net_ReadLong(&net_message);

	// determine if we're viewing a demo
	cl.demo_server = Net_ReadByte(&net_message);

	// game directory
	str = Net_ReadString(&net_message);
	if (g_strcmp0(Cvar_GetString("game"), str)) {

		Fs_SetGame(str);

		// reload the client game
		Cl_InitCgame();
	}

	// parse player entity number
	cl.entity_num = Net_ReadShort(&net_message);

	// get the full level name
	str = Net_ReadString(&net_message);
	Com_Print("\n");
	Com_Print("%c%s\n", 2, str);
}
Esempio n. 4
0
/**
 * @brief Receive data from the specified TCP stream.
 */
_Bool Net_ReceiveStream(int32_t sock, mem_buf_t *buf) {

	buf->size = buf->read = 0;

	const ssize_t received = recv(sock, (void *) buf->data, buf->max_size, 0);
	if (received == -1) {

		if (Net_GetError() == EWOULDBLOCK) {
			return false;    // no data, don't crap our pants
		}

		Com_Warn("%s\n", Net_GetErrorString());
		return false;
	}

	buf->size = received;

	// check the packet length
	return Net_ReadLong(buf) > -1;
}
Esempio n. 5
0
/*
 * @brief Called when the current net_message is from remote_address
 * modifies net_message so that it points to the packet payload
 */
_Bool Netchan_Process(net_chan_t *chan, mem_buf_t *msg) {
	uint32_t sequence, sequence_ack;
	uint32_t reliable_ack, reliable_message;

	// get sequence numbers
	Net_BeginReading(msg);

	sequence = Net_ReadLong(msg);
	sequence_ack = Net_ReadLong(msg);

	// read the qport if we are a server
	if (chan->source == NS_UDP_SERVER)
		Net_ReadByte(msg);

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;

	sequence &= ~(1 << 31);
	sequence_ack &= ~(1 << 31);

	if (net_showpackets->value) {
		if (reliable_message)
			Com_Print("Recv %u bytes: s=%i reliable=%i ack=%i rack=%i\n", (uint32_t) msg->size,
					sequence, chan->incoming_reliable_sequence ^ 1, sequence_ack, reliable_ack);
		else
			Com_Print("Recv %u bytes : s=%i ack=%i rack=%i\n", (uint32_t) msg->size, sequence,
					sequence_ack, reliable_ack);
	}

	// discard stale or duplicated packets
	if (sequence <= chan->incoming_sequence) {
		if (net_showdrop->value)
			Com_Print("%s:Out of order packet %i at %i\n",
					Net_NetaddrToString(&chan->remote_address), sequence, chan->incoming_sequence);
		return false;
	}

	// dropped packets don't keep the message from being used
	chan->dropped = sequence - (chan->incoming_sequence + 1);
	if (chan->dropped > 0) {
		if (net_showdrop->value)
			Com_Print("%s:Dropped %i packets at %i\n", Net_NetaddrToString(&chan->remote_address),
					chan->dropped, sequence);
	}

	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	if (reliable_ack == chan->reliable_sequence)
		chan->reliable_size = 0; // it has been received

	// if this message contains a reliable message, bump incoming_reliable_sequence
	chan->incoming_sequence = sequence;
	chan->incoming_acknowledged = sequence_ack;
	chan->incoming_reliable_acknowledged = reliable_ack;
	if (reliable_message) {
		chan->incoming_reliable_sequence ^= 1;
	}

	// the message can now be read from the current message pointer
	chan->last_received = quake2world.time;

	return true;
}