void CMapLayers::BackgroundMapUpdate() { if(m_Type == TYPE_BACKGROUND && m_pMenuMap) { // unload map m_pMenuMap->Unload(); int HourOfTheDay = (time_timestamp()/3600)%24; char aBuf[128]; str_format(aBuf, sizeof(aBuf), "ui/%s_%s.map", g_Config.m_ClMenuMap, (HourOfTheDay >= 6 && HourOfTheDay < 18) ? "day" : "night"); if(!m_pMenuMap->Load(aBuf, m_pClient->Storage())) { str_format(aBuf, sizeof(aBuf), "map '%s' not found", g_Config.m_ClMenuMap); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf); return; } str_format(aBuf, sizeof(aBuf), "loaded map '%s'", g_Config.m_ClMenuMap); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf); m_pMenuLayers->Init(Kernel(), m_pMenuMap); RenderTools()->RenderTilemapGenerateSkip(m_pMenuLayers); m_pClient->m_pMapimages->OnMenuMapLoad(m_pMenuMap); LoadEnvPoints(m_pMenuLayers, m_lEnvPointsMenu); } }
int CNetServer::Update() { int Now = time_timestamp(); for(int i = 0; i < MaxClients(); i++) { m_aSlots[i].m_Connection.Update(); if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) Drop(i, m_aSlots[i].m_Connection.ErrorString()); } // remove expired bans while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now) { CBan *pBan = m_BanPool_FirstUsed; BanRemoveByObject(pBan); } return 0; }
void CNetBan::Update() { int Now = time_timestamp(); // remove expired bans char aBuf[256], aNetStr[256]; while(m_BanAddrPool.First() && m_BanAddrPool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanAddrPool.First()->m_Info.m_Expires < Now) { str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanAddrPool.First()->m_Data, aNetStr, sizeof(aNetStr))); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); m_BanAddrPool.Remove(m_BanAddrPool.First()); } while(m_BanRangePool.First() && m_BanRangePool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanRangePool.First()->m_Info.m_Expires < Now) { str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanRangePool.First()->m_Data, aNetStr, sizeof(aNetStr))); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); m_BanRangePool.Remove(m_BanRangePool.First()); } }
int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason) { // do not ban localhost if(NetMatch(pData, &m_LocalhostIPV4) || NetMatch(pData, &m_LocalhostIPV6)) { Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (localhost)"); return -1; } int Stamp = Seconds > 0 ? time_timestamp()+Seconds : CBanInfo::EXPIRES_NEVER; // set up info CBanInfo Info = {0}; Info.m_Expires = Stamp; str_copy(Info.m_aReason, pReason, sizeof(Info.m_aReason)); // check if it already exists CNetHash NetHash(pData); CBan<typename T::CDataType> *pBan = pBanPool->Find(pData, &NetHash); if(pBan) { // adjust the ban pBanPool->Update(pBan, &Info); char aBuf[128]; MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); return 1; } // add ban and print result pBan = pBanPool->Add(pData, &Info, &NetHash); if(pBan) { char aBuf[128]; MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANADD); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); return 0; } else Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (full banlist)"); return -1; }
void CNetBan::MakeBanInfo(const CBan<T> *pBan, char *pBuf, unsigned BuffSize, int Type) const { if(pBan == 0 || pBuf == 0) { if(BuffSize > 0) pBuf[0] = 0; return; } // build type based part char aBuf[256]; if(Type == MSGTYPE_PLAYER) str_copy(aBuf, "You have been banned", sizeof(aBuf)); else { char aTemp[256]; switch(Type) { case MSGTYPE_LIST: str_format(aBuf, sizeof(aBuf), "%s banned", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; case MSGTYPE_BANADD: str_format(aBuf, sizeof(aBuf), "banned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; case MSGTYPE_BANREM: str_format(aBuf, sizeof(aBuf), "unbanned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; default: aBuf[0] = 0; } } // add info part if(pBan->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER) { int Mins = ((pBan->m_Info.m_Expires-time_timestamp()) + 59) / 60; if(Mins <= 1) str_format(pBuf, BuffSize, "%s for 1 minute (%s)", aBuf, pBan->m_Info.m_aReason); else str_format(pBuf, BuffSize, "%s for %d minutes (%s)", aBuf, Mins, pBan->m_Info.m_aReason); } else str_format(pBuf, BuffSize, "%s for life (%s)", aBuf, pBan->m_Info.m_aReason); }
int netserver_update(NETSERVER *s) { unsigned now = time_timestamp(); int i; for(i = 0; i < s->max_clients; i++) { conn_update(&s->slots[i].conn); if(s->slots[i].conn.state == NET_CONNSTATE_ERROR) netserver_drop(s, i, conn_error(&s->slots[i].conn)); } /* remove expired bans */ while(s->banpool_firstused && s->banpool_firstused->info.expires < now) { NETBAN *ban = s->banpool_firstused; netserver_ban_remove_by_object(s, ban); } (void)now; return 0; }
void CNetBan::ConBansSave(IConsole::IResult *pResult, void *pUser) { CNetBan *pThis = static_cast<CNetBan *>(pUser); char aBuf[256]; IOHANDLE File = pThis->Storage()->OpenFile(pResult->GetString(0), IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!File) { str_format(aBuf, sizeof(aBuf), "failed to save banlist to '%s'", pResult->GetString(0)); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); return; } int Now = time_timestamp(); char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE]; for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext) { int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1; net_addr_str(&pBan->m_Data, aAddrStr1, sizeof(aAddrStr1), false); str_format(aBuf, sizeof(aBuf), "ban %s %i %s", aAddrStr1, Min, pBan->m_Info.m_aReason); io_write(File, aBuf, str_length(aBuf)); io_write_newline(File); } for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext) { int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1; net_addr_str(&pBan->m_Data.m_LB, aAddrStr1, sizeof(aAddrStr1), false); net_addr_str(&pBan->m_Data.m_UB, aAddrStr2, sizeof(aAddrStr2), false); str_format(aBuf, sizeof(aBuf), "ban_range %s %s %i %s", aAddrStr1, aAddrStr2, Min, pBan->m_Info.m_aReason); io_write(File, aBuf, str_length(aBuf)); io_write_newline(File); } io_close(File); str_format(aBuf, sizeof(aBuf), "saved banlist to '%s'", pResult->GetString(0)); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); }
/* TODO: chopp up this function into smaller working parts */ int netserver_recv(NETSERVER *s, NETCHUNK *chunk) { unsigned now = time_timestamp(); while(1) { NETADDR addr; int i, bytes, found; /* check for a chunk */ if(recvinfo_fetch_chunk(&s->recv, chunk)) return 1; /* TODO: empty the recvinfo */ bytes = net_udp_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE); /* no more packets for now */ if(bytes <= 0) break; if(unpack_packet(s->recv.buffer, bytes, &s->recv.data) == 0) { NETBAN *ban = 0; NETADDR banaddr = addr; int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff; found = 0; banaddr.port = 0; /* search a ban */ for(ban = s->bans[iphash]; ban; ban = ban->hashnext) { if(net_addr_comp(&ban->info.addr, &banaddr) == 0) break; } /* check if we just should drop the packet */ if(ban) { // banned, reply with a message char banstr[128]; if(ban->info.expires) { int mins = ((ban->info.expires - now)+59)/60; if(mins == 1) str_format(banstr, sizeof(banstr), "banned for %d minute", mins); else str_format(banstr, sizeof(banstr), "banned for %d minutes", mins); } else str_format(banstr, sizeof(banstr), "banned for life"); send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, banstr, str_length(banstr)+1); continue; } if(s->recv.data.flags&NET_PACKETFLAG_CONNLESS) { chunk->flags = NETSENDFLAG_CONNLESS; chunk->client_id = -1; chunk->address = addr; chunk->data_size = s->recv.data.data_size; chunk->data = s->recv.data.chunk_data; return 1; } else { /* TODO: check size here */ if(s->recv.data.flags&NET_PACKETFLAG_CONTROL && s->recv.data.chunk_data[0] == NET_CTRLMSG_CONNECT) { found = 0; /* check if we already got this client */ for(i = 0; i < s->max_clients; i++) { if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE && net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0) { found = 1; /* silent ignore.. we got this client already */ break; } } /* client that wants to connect */ if(!found) { for(i = 0; i < s->max_clients; i++) { if(s->slots[i].conn.state == NET_CONNSTATE_OFFLINE) { found = 1; conn_feed(&s->slots[i].conn, &s->recv.data, &addr); if(s->new_client) s->new_client(i, s->user_ptr); break; } } if(!found) { const char fullmsg[] = "server is full"; send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, fullmsg, sizeof(fullmsg)); } } } else { /* normal packet, find matching slot */ for(i = 0; i < s->max_clients; i++) { if(net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0) { if(conn_feed(&s->slots[i].conn, &s->recv.data, &addr)) { if(s->recv.data.data_size) recvinfo_start(&s->recv, &addr, &s->slots[i].conn, i); } } } } } } } return 0; }
int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds) { int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff; unsigned stamp = 0xffffffff; NETBAN *ban; /* remove the port */ addr.port = 0; if(seconds) stamp = time_timestamp() + seconds; /* search to see if it already exists */ ban = s->bans[iphash]; MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0); if(ban) { /* adjust the ban */ ban->info.expires = stamp; return 0; } if(!s->banpool_firstfree) return -1; /* fetch and clear the new ban */ ban = s->banpool_firstfree; MACRO_LIST_UNLINK(ban, s->banpool_firstfree, prev, next); /* setup the ban info */ ban->info.expires = stamp; ban->info.addr = addr; /* add it to the ban hash */ MACRO_LIST_LINK_FIRST(ban, s->bans[iphash], hashprev, hashnext); /* insert it into the used list */ { if(s->banpool_firstused) { NETBAN *insert_after = s->banpool_firstused; MACRO_LIST_FIND(insert_after, next, stamp < insert_after->info.expires); if(insert_after) insert_after = insert_after->prev; else { /* add to last */ insert_after = s->banpool_firstused; while(insert_after->next) insert_after = insert_after->next; } if(insert_after) { MACRO_LIST_LINK_AFTER(ban, insert_after, prev, next); } else { MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next); } } else { MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next); } } /* drop banned clients */ { char buf[128]; int i; NETADDR banaddr; if(seconds) str_format(buf, sizeof(buf), "you have been banned for %d minutes", seconds/60); else str_format(buf, sizeof(buf), "you have been banned for life"); for(i = 0; i < s->max_clients; i++) { banaddr = s->slots[i].conn.peeraddr; banaddr.port = 0; if(net_addr_comp(&addr, &banaddr) == 0) netserver_drop(s, i, buf); } } return 0; }
/* TODO: chopp up this function into smaller working parts */ int CNetServer::Recv(CNetChunk *pChunk) { unsigned Now = time_timestamp(); while(1) { NETADDR Addr; // check for a chunk if(m_RecvUnpacker.FetchChunk(pChunk)) return 1; // TODO: empty the recvinfo int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE); // no more packets for now if(Bytes <= 0) break; if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0) { CBan *pBan = 0; NETADDR BanAddr = Addr; int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3]+BanAddr.ip[4]+BanAddr.ip[5]+BanAddr.ip[6]+BanAddr.ip[7]+ BanAddr.ip[8]+BanAddr.ip[9]+BanAddr.ip[10]+BanAddr.ip[11]+BanAddr.ip[12]+BanAddr.ip[13]+BanAddr.ip[14]+BanAddr.ip[15])&0xff; int Found = 0; BanAddr.port = 0; // search a ban for(pBan = m_aBans[IpHash]; pBan; pBan = pBan->m_pHashNext) { if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0) break; } // check if we just should drop the packet if(pBan) { // banned, reply with a message char BanStr[128]; if(pBan->m_Info.m_Expires > -1) { int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60; if(Mins <= 1) str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason); else str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason); } else str_format(BanStr, sizeof(BanStr), "Banned for life (%s)", pBan->m_Info.m_Reason); CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1); continue; } if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS) { pChunk->m_Flags = NETSENDFLAG_CONNLESS; pChunk->m_ClientID = -1; pChunk->m_Address = Addr; pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize; pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData; return 1; } else { // TODO: check size here if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT) { Found = 0; // check if we already got this client for(int i = 0; i < MaxClients(); i++) { NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE && net_addr_comp(&PeerAddr, &Addr) == 0) { Found = 1; // silent ignore.. we got this client already break; } } // client that wants to connect if(!Found) { // only allow a specific number of players with the same ip NETADDR ThisAddr = Addr, OtherAddr; int FoundAddr = 1; ThisAddr.port = 0; for(int i = 0; i < MaxClients(); ++i) { if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) continue; OtherAddr = m_aSlots[i].m_Connection.PeerAddress(); OtherAddr.port = 0; if(!net_addr_comp(&ThisAddr, &OtherAddr)) { if(FoundAddr++ >= m_MaxClientsPerIP) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP); CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf)); return 0; } } } for(int i = 0; i < MaxClients(); i++) { if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) { Found = 1; m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr); if(m_pfnNewClient) m_pfnNewClient(i, m_UserPtr); break; } } if(!Found) { const char FullMsg[] = "This server is full"; CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg)); } } } else { // normal packet, find matching slot for(int i = 0; i < MaxClients(); i++) { NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); if(net_addr_comp(&PeerAddr, &Addr) == 0) { if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr)) { if(m_RecvUnpacker.m_Data.m_DataSize) m_RecvUnpacker.Start(&Addr, &m_aSlots[i].m_Connection, i); } } } } } } } return 0; }
int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason) { int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+ Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff; int Stamp = -1; CBan *pBan; // remove the port Addr.port = 0; if(Seconds) Stamp = time_timestamp() + Seconds; // search to see if it already exists pBan = m_aBans[IpHash]; MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0); if(pBan) { // adjust the ban pBan->m_Info.m_Expires = Stamp; return 0; } if(!m_BanPool_FirstFree) return -1; // fetch and clear the new ban pBan = m_BanPool_FirstFree; MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext); // setup the ban info pBan->m_Info.m_Expires = Stamp; pBan->m_Info.m_Addr = Addr; str_copy(pBan->m_Info.m_Reason, pReason, sizeof(pBan->m_Info.m_Reason)); // add it to the ban hash MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext); // insert it into the used list { if(m_BanPool_FirstUsed) { CBan *pInsertAfter = m_BanPool_FirstUsed; MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires); if(pInsertAfter) pInsertAfter = pInsertAfter->m_pPrev; else { // add to last pInsertAfter = m_BanPool_FirstUsed; while(pInsertAfter->m_pNext) pInsertAfter = pInsertAfter->m_pNext; } if(pInsertAfter) { MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext); } else { MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); } } else { MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); } } // drop banned clients { char Buf[128]; NETADDR BanAddr; if(Stamp > -1) { int Mins = (Seconds + 59) / 60; if(Mins <= 1) str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason); else str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason); } else str_format(Buf, sizeof(Buf), "You have been banned for life (%s)", pReason); for(int i = 0; i < MaxClients(); i++) { BanAddr = m_aSlots[i].m_Connection.PeerAddress(); BanAddr.port = 0; if(net_addr_comp(&Addr, &BanAddr) == 0) Drop(i, Buf); } } return 0; }