Ejemplo n.º 1
0
/*
 * Sv_New_f
 *
 * Sends the first message from the server to a connected client.
 * This will be sent on the initial connection and upon each server load.
 */
static void Sv_New_f(void) {
	int player_num;

	Com_Debug("New() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_New_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// demo servers will send the demo file's server info packet
	if (sv.state == SV_ACTIVE_DEMO) {
		return;
	}

	// send the server data
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_SERVER_DATA);
	Msg_WriteLong(&sv_client->netchan.message, PROTOCOL);
	Msg_WriteLong(&sv_client->netchan.message, svs.spawn_count);
	Msg_WriteLong(&sv_client->netchan.message, svs.frame_rate);
	Msg_WriteByte(&sv_client->netchan.message, 0);
	Msg_WriteString(&sv_client->netchan.message, Cvar_GetString("game"));

	player_num = sv_client - svs.clients;
	Msg_WriteShort(&sv_client->netchan.message, player_num);

	// send full level name
	Msg_WriteString(&sv_client->netchan.message, sv.config_strings[CS_NAME]);

	// begin fetching config_strings
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
	Msg_WriteString(&sv_client->netchan.message,
			va("config_strings %i 0\n", svs.spawn_count));
}
Ejemplo n.º 2
0
/*
 * @brief Sends the shutdown message message to all connected clients. The message
 * is sent immediately, because the server could completely terminate after
 * returning from this function.
 */
static void Sv_ShutdownMessage(const char *msg, _Bool reconnect) {
	sv_client_t * cl;
	int32_t i;

	if (!svs.initialized)
		return;

	Sb_Clear(&net_message);

	if (msg) { // send message
		Msg_WriteByte(&net_message, SV_CMD_PRINT);
		Msg_WriteByte(&net_message, PRINT_HIGH);
		Msg_WriteString(&net_message, msg);
	}

	if (reconnect) // send reconnect
		Msg_WriteByte(&net_message, SV_CMD_RECONNECT);
	else
		// or just disconnect
		Msg_WriteByte(&net_message, SV_CMD_DISCONNECT);

	for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++)
		if (cl->state >= SV_CLIENT_CONNECTED)
			Netchan_Transmit(&cl->netchan, net_message.size, net_message.data);
}
Ejemplo n.º 3
0
/*
 * Sv_NextDownload_f
 */
static void Sv_NextDownload_f(void) {
	int r, size, percent;
	byte buf[MAX_MSG_SIZE];
	size_buf_t msg;

	if (!sv_client->download)
		return;

	r = sv_client->download_size - sv_client->download_count;

	if (r > 1024) // cap the download chunk at 1024 bytes
		r = 1024;

	Sb_Init(&msg, buf, MAX_MSG_SIZE);

	Msg_WriteByte(&msg, SV_CMD_DOWNLOAD);
	Msg_WriteShort(&msg, r);

	sv_client->download_count += r;
	size = sv_client->download_size;
	if (!size)
		size = 1;

	percent = sv_client->download_count * 100 / size;
	Msg_WriteByte(&msg, percent);

	Sb_Write(&msg, sv_client->download + sv_client->download_count - r, r);
	Sb_Write(&sv_client->netchan.message, msg.data, msg.size);

	if (sv_client->download_count != sv_client->download_size)
		return;

	Fs_FreeFile(sv_client->download);
	sv_client->download = NULL;
}
Ejemplo n.º 4
0
//==========================================================================
// Msg_WritePackedShort
//  Only 15 bits can be used for the number because the high bit of the 
//  lower byte is used to determine whether the upper byte follows or not.
//==========================================================================
void Msg_WritePackedShort(short w)
{
	if(w < 0x80)				// Can the number be represented with 7 bits?
		Msg_WriteByte(w);
	else
	{
		Msg_WriteByte(0x80 | w);
		Msg_WriteByte(w >> 7);	// Highest bit is lost.
	}
}
Ejemplo n.º 5
0
/*
 * Sv_ConfigStrings_f
 */
static void Sv_ConfigStrings_f(void) {
	unsigned int start;

	Com_Debug("ConfigStrings() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_ConfigStrings_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// handle the case of a level changing while a client was connecting
	if (strtoul(Cmd_Argv(1), NULL, 0) != svs.spawn_count) {
		Com_Debug("Sv_ConfigStrings_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	start = strtoul(Cmd_Argv(2), NULL, 0);

	if (start >= MAX_CONFIG_STRINGS) { // catch bad offsets
		Com_Warn("Sv_ConfigStrings_f: Bad config_string offset from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	// write a packet full of data
	while (sv_client->netchan.message.size < MAX_MSG_SIZE / 2 && start
			< MAX_CONFIG_STRINGS) {
		if (sv.config_strings[start][0]) {
			Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CONFIG_STRING);
			Msg_WriteShort(&sv_client->netchan.message, start);
			Msg_WriteString(&sv_client->netchan.message,
					sv.config_strings[start]);
		}
		start++;
	}

	// send next command
	if (start == MAX_CONFIG_STRINGS) {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("baselines %i 0\n", svs.spawn_count));
	} else {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("config_strings %i %i\n", svs.spawn_count, start));
	}
}
Ejemplo n.º 6
0
/*
 * Sv_Baselines_f
 */
static void Sv_Baselines_f(void) {
	unsigned int start;
	entity_state_t nullstate;
	entity_state_t *base;

	Com_Debug("Baselines() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_Baselines_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// handle the case of a level changing while a client was connecting
	if (strtoul(Cmd_Argv(1), NULL, 0) != svs.spawn_count) {
		Com_Debug("Sv_Baselines_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	start = strtoul(Cmd_Argv(2), NULL, 0);

	memset(&nullstate, 0, sizeof(nullstate));

	// write a packet full of data
	while (sv_client->netchan.message.size < MAX_MSG_SIZE / 2 && start
			< MAX_EDICTS) {
		base = &sv.baselines[start];
		if (base->model1 || base->sound || base->effects) {
			Msg_WriteByte(&sv_client->netchan.message, SV_CMD_ENTITY_BASELINE);
			Msg_WriteDeltaEntity(&nullstate, base, &sv_client->netchan.message,
					true, true);
		}
		start++;
	}

	// send next command
	if (start == MAX_EDICTS) {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("precache %i\n", svs.spawn_count));
	} else {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("baselines %i %i\n", svs.spawn_count, start));
	}
}
Ejemplo n.º 7
0
/*
 * Sv_DropClient
 *
 * Called when the player is totally leaving the server, either willingly
 * or unwillingly.  This is NOT called if the entire server is quitting
 * or crashing.
 */
void Sv_DropClient(sv_client_t *cl) {
	g_edict_t *ent;

	if (cl->state > SV_CLIENT_FREE) { // send the disconnect

		if (cl->state == SV_CLIENT_ACTIVE) { // after informing the game module
			svs.game->ClientDisconnect(cl->edict);
		}

		Msg_WriteByte(&cl->netchan.message, SV_CMD_DISCONNECT);
		Netchan_Transmit(&cl->netchan, cl->netchan.message.size,
				cl->netchan.message.data);
	}

	if (cl->download) {
		Fs_FreeFile(cl->download);
		cl->download = NULL;
	}

	ent = cl->edict;

	memset(cl, 0, sizeof(*cl));

	cl->edict = ent;
	cl->last_frame = -1;
}
Ejemplo n.º 8
0
/*
 * Cl_WriteDemoHeader
 *
 * Writes server_data, config_strings, and baselines once a non-delta
 * compressed frame arrives from the server.
 */
static void Cl_WriteDemoHeader(void) {
	byte buffer[MAX_MSG_SIZE];
	size_buf_t msg;
	int i;
	int len;
	entity_state_t null_state;

	// write out messages to hold the startup information
	Sb_Init(&msg, buffer, sizeof(buffer));

	// write the server data
	Msg_WriteByte(&msg, SV_CMD_SERVER_DATA);
	Msg_WriteLong(&msg, PROTOCOL);
	Msg_WriteLong(&msg, cl.server_count);
	Msg_WriteLong(&msg, cl.server_frame_rate);
	Msg_WriteByte(&msg, 1); // demo_server byte
	Msg_WriteString(&msg, Cvar_GetString("game"));
	Msg_WriteShort(&msg, cl.player_num);
	Msg_WriteString(&msg, cl.config_strings[CS_NAME]);

	// and config_strings
	for (i = 0; i < MAX_CONFIG_STRINGS; i++) {
		if (*cl.config_strings[i] != '\0') {
			if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out
				len = LittleLong(msg.size);
				Fs_Write(&len, 4, 1, cls.demo_file);
				Fs_Write(msg.data, msg.size, 1, cls.demo_file);
				msg.size = 0;
			}

			Msg_WriteByte(&msg, SV_CMD_CONFIG_STRING);
			Msg_WriteShort(&msg, i);
			Msg_WriteString(&msg, cl.config_strings[i]);
		}
	}

	// and baselines
	for (i = 0; i < MAX_EDICTS; i++) {
		entity_state_t *ent = &cl.entities[i].baseline;
		if (!ent->number)
			continue;

		if (msg.size + 64 > msg.max_size) { // write it out
			len = LittleLong(msg.size);
			Fs_Write(&len, 4, 1, cls.demo_file);
			Fs_Write(msg.data, msg.size, 1, cls.demo_file);
			msg.size = 0;
		}

		memset(&null_state, 0, sizeof(null_state));

		Msg_WriteByte(&msg, SV_CMD_ENTITY_BASELINE);
		Msg_WriteDeltaEntity(&null_state, &cl.entities[i].baseline, &msg, true,
				true);
	}

	Msg_WriteByte(&msg, SV_CMD_CBUF_TEXT);
	Msg_WriteString(&msg, "precache 0\n");

	// write it to the demo file

	len = LittleLong(msg.size);
	Fs_Write(&len, 4, 1, cls.demo_file);
	Fs_Write(msg.data, msg.size, 1, cls.demo_file);

	Com_Print("Recording to %s.\n", cls.demo_path);
	// the rest of the demo file will be individual frames
}
Ejemplo n.º 9
0
/*
 * Sv_Download_f
 */
static void Sv_Download_f(void) {
	const char *name;
	void *buf;
	unsigned int i = 0, offset = 0;

	name = Cmd_Argv(1);

	if (Cmd_Argc() > 2)
		offset = strtoul(Cmd_Argv(2), NULL, 0); // downloaded offset

	// catch illegal offset or file_names
	if (*name == '.' || *name == '/' || *name == '\\' || strstr(
			name, "..")) {
		Com_Warn("Sv_Download_f: Malicious download (%s:%d) from %s\n", name,
				offset, Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	while (downloadable[i]) { // ensure download name is allowed
		if (GlobMatch(downloadable[i], name))
			break;
		i++;
	}

	if (!downloadable[i]) { // it wasn't
		Com_Warn("Sv_Download_f: Illegal download (%s) from %s\n", name,
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	if (!sv_udp_download->value) { // lastly, ensure server wishes to allow
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_DOWNLOAD);
		Msg_WriteShort(&sv_client->netchan.message, -1);
		Msg_WriteByte(&sv_client->netchan.message, 0);
		return;
	}

	if (sv_client->download) // free last download
		Fs_FreeFile(sv_client->download);

	sv_client->download_size = Fs_LoadFile(name, &buf);
	sv_client->download = (byte *) buf;
	sv_client->download_count = offset;

	if (offset > sv_client->download_size)
		sv_client->download_count = sv_client->download_size;

	if (!sv_client->download) { // legal file name, but missing file
		Com_Warn("Sv_Download_f: Couldn't download %s to %s\n", name,
				Sv_NetaddrToString(sv_client));
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_DOWNLOAD);
		Msg_WriteShort(&sv_client->netchan.message, -1);
		Msg_WriteByte(&sv_client->netchan.message, 0);
		return;
	}

	Sv_NextDownload_f();
	Com_Debug("Downloading %s to %s\n", name, sv_client->name);
}