コード例 #1
0
ファイル: sv_client.c プロジェクト: darkshade9/aq2w
/*
 * 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;
}
コード例 #2
0
ファイル: sv_main.c プロジェクト: darkshade9/aq2w
/*
 * Sv_Shutdown
 *
 * Called when server is shutting down due to error or an explicit `quit`.
 */
void Sv_Shutdown(const char *msg) {

	Sv_ShutdownServer(msg);

	Sv_ShutdownMasters();

	Net_Config(NS_SERVER, false);

	Sb_Init(&net_message, net_message_buffer, sizeof(net_message_buffer));

	memset(&svs, 0, sizeof(svs));
}
コード例 #3
0
ファイル: sv_init.c プロジェクト: devilx4/quake2world
/*
 * @brief Entry point for spawning a new server or changing maps / demos. Brings any
 * connected clients along for the ride by broadcasting a reconnect before
 * clearing state. Special effort is made to ensure that a locally connected
 * client sees the reconnect message immediately.
 */
void Sv_InitServer(const char *server, sv_state_t state) {
#ifdef BUILD_CLIENT
	extern void Cl_Disconnect(void);
#endif
	char path[MAX_QPATH];

	Com_Debug("Sv_InitServer: %s (%d)\n", server, state);

	Cbuf_CopyToDefer();

	// ensure that the requested map or demo exists
	if (state == SV_ACTIVE_DEMO)
		g_snprintf(path, sizeof(path), "demos/%s.dem", server);
	else
		g_snprintf(path, sizeof(path), "maps/%s.bsp", server);

	if (!Fs_Exists(path)) {
		Com_Print("Couldn't open %s\n", path);
		return;
	}

	// inform any connected clients to reconnect to us
	Sv_ShutdownMessage("Server restarting...\n", true);

#ifdef BUILD_CLIENT
	// disconnect any local client, they'll immediately reconnect
	Cl_Disconnect();
#endif

	// clear the sv_server_t structure
	Sv_ClearState();

	Com_Print("Server initialization...\n");

	// initialize the clients, loading the game module if we need it
	Sv_InitClients();

	// load the map or demo and related media
	Sv_LoadMedia(server, state);
	sv.state = state;

	Sb_Init(&sv.multicast, sv.multicast_buffer, sizeof(sv.multicast_buffer));

	Com_Print("Server initialized\n");
	Com_InitSubsystem(Q2W_SERVER);

	svs.initialized = true;
}
コード例 #4
0
ファイル: sv_main.c プロジェクト: darkshade9/aq2w
/*
 * Sv_Init
 *
 * Only called at Quake2World startup, not for each game.
 */
void Sv_Init(void) {

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

	sv_rcon_password = Cvar_Get("rcon_password", "", 0, NULL);

	sv_download_url = Cvar_Get("sv_download_url", "", CVAR_SERVER_INFO, NULL);
	sv_enforce_time = Cvar_Get("sv_enforce_time",
			va("%d", CMD_MSEC_MAX_DRIFT_ERRORS), 0, NULL);

	sv_hostname = Cvar_Get("sv_hostname", "Quake2World",
			CVAR_SERVER_INFO | CVAR_ARCHIVE, NULL);
	sv_public = Cvar_Get("sv_public", "0", 0, NULL);

	if (dedicated->value)
		sv_max_clients = Cvar_Get("sv_max_clients", "8",
				CVAR_SERVER_INFO | CVAR_LATCH, NULL);
	else
		sv_max_clients = Cvar_Get("sv_max_clients", "1",
				CVAR_SERVER_INFO | CVAR_LATCH, NULL);

	sv_framerate = Cvar_Get("sv_framerate", va("%d", SERVER_FRAME_RATE),
			CVAR_SERVER_INFO | CVAR_LATCH, NULL);
	sv_timeout = Cvar_Get("sv_timeout", va("%d", SERVER_TIMEOUT), 0, NULL);
	sv_udp_download = Cvar_Get("sv_udp_download", "1", CVAR_ARCHIVE, NULL);

	// set this so clients and server browsers can see it
	Cvar_Get("sv_protocol", va("%i", PROTOCOL), CVAR_SERVER_INFO | CVAR_NO_SET,
			NULL);

	Sv_InitCommands();

	Sv_InitMasters();

	Sb_Init(&net_message, net_message_buffer, sizeof(net_message_buffer));

	Net_Config(NS_SERVER, true);
}
コード例 #5
0
ファイル: cl_demo.c プロジェクト: darkshade9/aq2w
/*
 * 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
}
コード例 #6
0
ファイル: sv_main.c プロジェクト: darkshade9/aq2w
/*
 * Svc_Connect
 *
 * A connection request that did not come from the master.
 */
static void Svc_Connect(void) {
	char user_info[MAX_USER_INFO_STRING];
	sv_client_t *cl, *client;
	net_addr_t addr;
	int version;
	byte qport;
	unsigned int challenge;
	int i;

	Com_Debug("Svc_Connect()\n");

	addr = net_from;

	version = atoi(Cmd_Argv(1));

	// resolve protocol
	if (version != PROTOCOL) {
		Netchan_OutOfBandPrint(NS_SERVER, addr,
				"print\nServer is version %d.\n", PROTOCOL);
		return;
	}

	qport = strtoul(Cmd_Argv(2), NULL, 0) & 0xff;

	challenge = strtoul(Cmd_Argv(3), NULL, 0);

	//copy user_info, leave room for ip stuffing
	strncpy(user_info, Cmd_Argv(4), sizeof(user_info) - 1 - 25);
	user_info[sizeof(user_info) - 1] = 0;

	if (*user_info == '\0') { // catch empty user_info
		Com_Print("Empty user_info from %s\n", Net_NetaddrToString(addr));
		Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nConnection refused.\n");
		return;
	}

	if (strchr(user_info, '\xFF')) { // catch end of message in string exploit
		Com_Print("Illegal user_info contained xFF from %s\n",
				Net_NetaddrToString(addr));
		Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nConnection refused.\n");
		return;
	}

	if (strlen(GetUserInfo(user_info, "ip"))) { // catch spoofed ips
		Com_Print("Illegal user_info contained ip from %s\n",
				Net_NetaddrToString(addr));
		Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nConnection refused.\n");
		return;
	}

	if (!ValidateUserInfo(user_info)) { // catch otherwise invalid user_info
		Com_Print("Invalid user_info from %s\n", Net_NetaddrToString(addr));
		Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nConnection refused.\n");
		return;
	}

	// force the ip so the game can filter on it
	SetUserInfo(user_info, "ip", Net_NetaddrToString(addr));

	// enforce a valid challenge to avoid denial of service attack
	for (i = 0; i < MAX_CHALLENGES; i++) {
		if (Net_CompareClientNetaddr(addr, svs.challenges[i].addr)) {
			if (challenge == svs.challenges[i].challenge) {
				svs.challenges[i].challenge = 0;
				break; // good
			}
			Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nBad challenge.\n");
			return;
		}
	}
	if (i == MAX_CHALLENGES) {
		Netchan_OutOfBandPrint(NS_SERVER, addr,
				"print\nNo challenge for address.\n");
		return;
	}

	// resolve the client slot
	client = NULL;

	// first check for an ungraceful reconnect (client crashed, perhaps)
	for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++) {

		const net_chan_t *ch = &cl->netchan;

		if (cl->state == SV_CLIENT_FREE) // not in use, not interested
			continue;

		// the base address and either the qport or real port must match
		if (Net_CompareClientNetaddr(addr, ch->remote_address) &&
				(qport == ch->qport || ch->remote_address.port == addr.port)) {
			client = cl;
			break;
		}
	}

	// otherwise, treat as a fresh connect to a new slot
	if (!client) {
		for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++) {
			if (cl->state == SV_CLIENT_FREE) { // we have a free one
				client = cl;
				break;
			}
		}
	}

	// no soup for you, next!!
	if (!client) {
		Netchan_OutOfBandPrint(NS_SERVER, addr, "print\nServer is full.\n");
		Com_Debug("Rejected a connection.\n");
		return;
	}

	// give the game a chance to reject this connection or modify the user_info
	if (!(svs.game->ClientConnect(client->edict, user_info))) {

		if (*GetUserInfo(user_info, "rejmsg")) {
			Netchan_OutOfBandPrint(NS_SERVER, addr,
					"print\n%s\nConnection refused.\n",
					GetUserInfo(user_info, "rejmsg"));
		} else {
			Netchan_OutOfBandPrint(NS_SERVER, addr,
					"print\nConnection refused.\n");
		}

		Com_Debug("Game rejected a connection.\n");
		return;
	}

	// parse some info from the info strings
	strncpy(client->user_info, user_info, sizeof(client->user_info) - 1);
	Sv_UserInfoChanged(client);

	// send the connect packet to the client
	Netchan_OutOfBandPrint(NS_SERVER, addr, "client_connect %s",
			sv_download_url->string);

	Netchan_Setup(NS_SERVER, &client->netchan, addr, qport);

	Sb_Init(&client->datagram, client->datagram_buf,
			sizeof(client->datagram_buf));
	client->datagram.allow_overflow = true;

	client->last_message = svs.real_time; // don't timeout

	client->state = SV_CLIENT_CONNECTED;
}