static void *secure_unpack_sv_vote_status() { static NETMSG_SV_VOTE_STATUS msg; msg.yes = msg_unpack_int(); msg.no = msg_unpack_int(); msg.pass = msg_unpack_int(); msg.total = msg_unpack_int(); if(msg.yes < 0 || msg.yes > MAX_CLIENTS) { msg_failed_on = "yes"; return 0; } if(msg.no < 0 || msg.no > MAX_CLIENTS) { msg_failed_on = "no"; return 0; } if(msg.pass < 0 || msg.pass > MAX_CLIENTS) { msg_failed_on = "pass"; return 0; } if(msg.total < 0 || msg.total > MAX_CLIENTS) { msg_failed_on = "total"; return 0; } return &msg; }
static void *secure_unpack_sv_emoticon() { static NETMSG_SV_EMOTICON msg; msg.cid = msg_unpack_int(); msg.emoticon = msg_unpack_int(); if(msg.cid < 0 || msg.cid > MAX_CLIENTS-1) { msg_failed_on = "cid"; return 0; } if(msg.emoticon < 0 || msg.emoticon > NUM_EMOTICONS-1) { msg_failed_on = "emoticon"; return 0; } return &msg; }
static void *secure_unpack_sv_chat() { static NETMSG_SV_CHAT msg; msg.team = msg_unpack_int(); msg.cid = msg_unpack_int(); msg.message = msg_unpack_string(); if(msg.team < -1 || msg.team > 1) { msg_failed_on = "team"; return 0; } if(msg.cid < -1 || msg.cid > MAX_CLIENTS-1) { msg_failed_on = "cid"; return 0; } return &msg; }
static void *secure_unpack_cl_changeinfo() { static NETMSG_CL_CHANGEINFO msg; msg.name = msg_unpack_string(); msg.skin = msg_unpack_string(); msg.use_custom_color = msg_unpack_int(); msg.color_body = msg_unpack_int(); msg.color_feet = msg_unpack_int(); if(msg.use_custom_color < 0 || msg.use_custom_color > 1) { msg_failed_on = "use_custom_color"; return 0; } return &msg; }
static void *secure_unpack_sv_killmsg() { static NETMSG_SV_KILLMSG msg; msg.killer = msg_unpack_int(); msg.victim = msg_unpack_int(); msg.weapon = msg_unpack_int(); msg.mode_special = msg_unpack_int(); if(msg.killer < 0 || msg.killer > MAX_CLIENTS-1) { msg_failed_on = "killer"; return 0; } if(msg.victim < 0 || msg.victim > MAX_CLIENTS-1) { msg_failed_on = "victim"; return 0; } if(msg.weapon < -3 || msg.weapon > NUM_WEAPONS-1) { msg_failed_on = "weapon"; return 0; } return &msg; }
static void *secure_unpack_cl_emoticon() { static NETMSG_CL_EMOTICON msg; msg.emoticon = msg_unpack_int(); if(msg.emoticon < 0 || msg.emoticon > NUM_EMOTICONS-1) { msg_failed_on = "emoticon"; return 0; } return &msg; }
static void *secure_unpack_sv_weaponpickup() { static NETMSG_SV_WEAPONPICKUP msg; msg.weapon = msg_unpack_int(); if(msg.weapon < 0 || msg.weapon > NUM_WEAPONS-1) { msg_failed_on = "weapon"; return 0; } return &msg; }
static void *secure_unpack_sv_soundglobal() { static NETMSG_SV_SOUNDGLOBAL msg; msg.soundid = msg_unpack_int(); if(msg.soundid < 0 || msg.soundid > NUM_SOUNDS-1) { msg_failed_on = "soundid"; return 0; } return &msg; }
static void *secure_unpack_cl_say() { static NETMSG_CL_SAY msg; msg.team = msg_unpack_int(); msg.message = msg_unpack_string(); if(msg.team < 0 || msg.team > 1) { msg_failed_on = "team"; return 0; } return &msg; }
int msg_unpack_start(const void *data, int data_size, int *system) { int msg; unpacker_reset(&msg_unpacker, (const unsigned char *)data, data_size); msg = msg_unpack_int(); *system = msg&1; return msg>>1; }
static void *secure_unpack_cl_vote() { static NETMSG_CL_VOTE msg; msg.vote = msg_unpack_int(); if(msg.vote < -1 || msg.vote > 1) { msg_failed_on = "vote"; return 0; } return &msg; }
static void *secure_unpack_cl_setteam() { static NETMSG_CL_SETTEAM msg; msg.team = msg_unpack_int(); if(msg.team < -1 || msg.team > 1) { msg_failed_on = "team"; return 0; } return &msg; }
static void *secure_unpack_sv_vote_set() { static NETMSG_SV_VOTE_SET msg; msg.timeout = msg_unpack_int(); msg.description = msg_unpack_string(); msg.command = msg_unpack_string(); if(msg.timeout < 0 || msg.timeout > 60) { msg_failed_on = "timeout"; return 0; } return &msg; }
static void server_process_client_packet(NETCHUNK *packet) { int cid = packet->client_id; NETADDR addr; int sys; int msg = msg_unpack_start(packet->data, packet->data_size, &sys); if(clients[cid].state == SRVCLIENT_STATE_AUTH) { if(sys && msg == NETMSG_INFO) { char version[64]; const char *password; str_copy(version, msg_unpack_string(), 64); if(strcmp(version, mods_net_version()) != 0) { /* OH F**K! wrong version, drop him */ char reason[256]; str_format(reason, sizeof(reason), "wrong version. server is running '%s' and client '%s'.", mods_net_version(), version); netserver_drop(net, cid, reason); return; } str_copy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH); str_copy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH); password = msg_unpack_string(); if(config.password[0] != 0 && strcmp(config.password, password) != 0) { /* wrong password */ netserver_drop(net, cid, "wrong password"); return; } clients[cid].state = SRVCLIENT_STATE_CONNECTING; server_send_map(cid); } } else { if(sys) { /* system message */ if(msg == NETMSG_REQUEST_MAP_DATA) { int chunk = msg_unpack_int(); int chunk_size = 1024-128; int offset = chunk * chunk_size; int last = 0; /* drop faulty map data requests */ if(chunk < 0 || offset > current_map_size) return; if(offset+chunk_size >= current_map_size) { chunk_size = current_map_size-offset; if(chunk_size < 0) chunk_size = 0; last = 1; } msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH); msg_pack_int(last); msg_pack_int(current_map_size); msg_pack_int(chunk_size); msg_pack_raw(¤t_map_data[offset], chunk_size); msg_pack_end(); server_send_msg(cid); if(config.debug) dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size); } else if(msg == NETMSG_READY) { if(clients[cid].state == SRVCLIENT_STATE_CONNECTING) { netserver_client_addr(net, cid, &addr); dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d", cid, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3] ); clients[cid].state = SRVCLIENT_STATE_READY; mods_connected(cid); } } else if(msg == NETMSG_ENTERGAME) { if(clients[cid].state == SRVCLIENT_STATE_READY) { netserver_client_addr(net, cid, &addr); dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d", cid, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3] ); clients[cid].state = SRVCLIENT_STATE_INGAME; mods_client_enter(cid); } } else if(msg == NETMSG_INPUT) { int tick, size, i; CLIENT_INPUT *input; int64 tagtime; clients[cid].last_acked_snapshot = msg_unpack_int(); tick = msg_unpack_int(); size = msg_unpack_int(); /* check for errors */ if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE) return; if(clients[cid].last_acked_snapshot > 0) clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL; if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0) clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq()); /* add message to report the input timing */ /* skip packets that are old */ if(tick > clients[cid].last_input_tick) { int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq(); msg_pack_start_system(NETMSG_INPUTTIMING, 0); msg_pack_int(tick); msg_pack_int(time_left); msg_pack_end(); server_send_msg(cid); } clients[cid].last_input_tick = tick; input = &clients[cid].inputs[clients[cid].current_input]; if(tick <= server_tick()) tick = server_tick()+1; input->game_tick = tick; for(i = 0; i < size/4; i++) input->data[i] = msg_unpack_int(); mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int)); clients[cid].current_input++; clients[cid].current_input %= 200; /* call the mod with the fresh input data */ if(clients[cid].state == SRVCLIENT_STATE_INGAME) mods_client_direct_input(cid, clients[cid].latestinput.data); } else if(msg == NETMSG_RCON_CMD) { const char *cmd = msg_unpack_string(); if(msg_unpack_error() == 0 && clients[cid].authed) { dbg_msg("server", "cid=%d rcon='%s'", cid, cmd); console_execute_line(cmd); } } else if(msg == NETMSG_RCON_AUTH) { const char *pw; msg_unpack_string(); /* login name, not used */ pw = msg_unpack_string(); if(msg_unpack_error() == 0) { if(config.sv_rcon_password[0] == 0) { server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console."); } else if(strcmp(pw, config.sv_rcon_password) == 0) { msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL); msg_pack_int(1); msg_pack_end(); server_send_msg(cid); clients[cid].authed = 1; server_send_rcon_line(cid, "Authentication successful. Remote console access granted."); dbg_msg("server", "cid=%d authed", cid); } else { server_send_rcon_line(cid, "Wrong password."); } } } else if(msg == NETMSG_PING) { msg_pack_start_system(NETMSG_PING_REPLY, 0); msg_pack_end(); server_send_msg(cid); } else { char hex[] = "0123456789ABCDEF"; char buf[512]; int b; for(b = 0; b < packet->data_size && b < 32; b++) { buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4]; buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf]; buf[b*3+2] = ' '; buf[b*3+3] = 0; } dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size); dbg_msg("server", "%s", buf); } } else { /* game message */ if(clients[cid].state >= SRVCLIENT_STATE_READY) mods_message(msg, cid); } }
void GAMECLIENT::on_message(int msgtype) { // special messages if(msgtype == NETMSGTYPE_SV_EXTRAPROJECTILE) { /* int num = msg_unpack_int(); for(int k = 0; k < num; k++) { NETOBJ_PROJECTILE proj; for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) ((int *)&proj)[i] = msg_unpack_int(); if(msg_unpack_error()) return; if(extraproj_num != MAX_EXTRA_PROJECTILES) { extraproj_projectiles[extraproj_num] = proj; extraproj_num++; } } return;*/ } else if(msgtype == NETMSGTYPE_SV_TUNEPARAMS) { // unpack the new tuning TUNING_PARAMS new_tuning; int *params = (int *)&new_tuning; for(unsigned i = 0; i < sizeof(TUNING_PARAMS)/sizeof(int); i++) params[i] = msg_unpack_int(); // check for unpacking errors if(msg_unpack_error()) return; servermode = SERVERMODE_PURE; // apply new tuning tuning = new_tuning; return; } void *rawmsg = netmsg_secure_unpack(msgtype); if(!rawmsg) { dbg_msg("client", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on()); return; } // TODO: this should be done smarter for(int i = 0; i < all.num; i++) all.components[i]->on_message(msgtype, rawmsg); if(msgtype == NETMSGTYPE_SV_READYTOENTER) { client_entergame(); } else if (msgtype == NETMSGTYPE_SV_EMOTICON) { NETMSG_SV_EMOTICON *msg = (NETMSG_SV_EMOTICON *)rawmsg; // apply clients[msg->cid].emoticon = msg->emoticon; clients[msg->cid].emoticon_start = client_tick(); } else if(msgtype == NETMSGTYPE_SV_SOUNDGLOBAL) { if(suppress_events) return; NETMSG_SV_SOUNDGLOBAL *msg = (NETMSG_SV_SOUNDGLOBAL *)rawmsg; gameclient.sounds->play(SOUNDS::CHN_GLOBAL, msg->soundid, 1.0f, vec2(0,0)); } }