Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ source/stamp-h1
source/config.h.in~

# OS
/.idea
._*
.DS_Store
Thumbs.db
Expand Down
21 changes: 9 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
FROM alpine:latest
FROM alpine:3.19.0

COPY . /otserv/.
RUN apk add --no-cache \
autoconf build-base pkgconfig boost-dev gmp-dev libxml2-dev \
automake lua lua-dev mariadb-dev crypto++ ccache

RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && \
apk update && \
apk upgrade && \
apk add --no-cache autoconf build-base pkgconfig boost-dev gmp-dev libxml2-dev && \
apk add --no-cache automake lua lua-dev mariadb-dev crypto++ ccache
cd /otserv/source && \
chmod +x autogen.sh && \
./autogen.sh && \
./configure --enable-mysql --enable-server-diag && \
make
COPY source /othire/
WORKDIR /othire/
RUN sh autogen.sh
RUN ./configure --enable-mysql
RUN make -j$(nproc)
3 changes: 3 additions & 0 deletions source/ban.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ bool BanManager::clearTemporaryBans() const

bool BanManager::acceptConnection(uint32_t clientip)
{
if(g_config.getBoolean(ConfigManager::ALLOW_OTC_PROXY) || g_config.getBoolean(ConfigManager::ALLOW_HAPROXY))
return true;

if(clientip == 0) return false;
banLock.lock();

Expand Down
9 changes: 5 additions & 4 deletions source/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,9 +1410,10 @@ void ConditionDamage::endCondition(Creature* creature, ConditionEnd_t reason)
//
}

bool ConditionDamage::updateCondition(const ConditionDamage* addCondition)
bool ConditionDamage::updateCondition(const Condition* addCondition)
{
if(addCondition->doForceUpdate()){
const ConditionDamage* conditionDamage = static_cast<const ConditionDamage*>(addCondition);
if(conditionDamage->doForceUpdate()){
return true;
}

Expand All @@ -1425,13 +1426,13 @@ bool ConditionDamage::updateCondition(const ConditionDamage* addCondition)
}

int32_t oldTotDamage = getTotalDamage();
int32_t newTotDamage = addCondition->getTotalDamage();
int32_t newTotDamage = conditionDamage->getTotalDamage();

if(newTotDamage < oldTotDamage){
return false;
}

if(addCondition->periodDamage < periodDamage){
if(conditionDamage->periodDamage < periodDamage){
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion source/condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class ConditionDamage: public Condition

bool getNextDamage(int32_t& damage);
bool doDamage(Creature* creature, int32_t damage);
bool updateCondition(const ConditionDamage* addCondition);
bool updateCondition(const Condition* addCondition);
};

class ConditionSpeed: public Condition
Expand Down
6 changes: 6 additions & 0 deletions source/config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ logintimeout = 60 * 1000
-- What is the maximum number of packages the client can send per second?
max_packets_per_second = 25

-- OTCv8 proxy support
allow_otc_proxy = false

-- HAProxy support
allow_haproxy = false

-- how deep queryDestination should look for free slots (default -1, infinite)
player_querydestination_deepness = -1

Expand Down
3 changes: 3 additions & 0 deletions source/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ bool ConfigManager::loadFile(const std::string& _filename)
m_confInteger[CAN_ROPE_CREATURES] = getGlobalBoolean(L, "can_rope_creatures", true);
m_confString[DEATH_MSG] = getGlobalString(L, "death_msg", "You are dead.");
m_confInteger[CAN_ATTACK_INVISIBLE] = getGlobalBoolean(L, "can_attack_invisible", false);
m_confString[STATUS_IP] = getGlobalString(L, "status_ip", "");
m_confInteger[MIN_PVP_LEVEL] = getGlobalNumber(L, "min_pvp_level", 0);
#ifdef __MIN_PVP_LEVEL_APPLIES_TO_SUMMONS__
m_confInteger[MIN_PVP_LEVEL_APPLIES_TO_SUMMONS] = getGlobalBoolean(L, "min_pvp_level_applies_to_summons", true);
Expand Down Expand Up @@ -214,6 +215,8 @@ bool ConfigManager::loadFile(const std::string& _filename)
// Cast System
m_confInteger[ENABLE_CAST] = getGlobalBoolean(L, "enableCast", false);
m_confInteger[MAX_CAST_VIEWERS] = getGlobalNumber(L, "max_cast_viewers", 20);
m_confInteger[ALLOW_OTC_PROXY] = getGlobalBoolean(L, "allow_otc_proxy", false);
m_confInteger[ALLOW_HAPROXY] = getGlobalBoolean(L, "allow_haproxy", false);

m_isLoaded = true;
return true;
Expand Down
5 changes: 4 additions & 1 deletion source/configmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class ConfigManager {
SQL_TYPE,
MAP_STORAGE_TYPE,
DEATH_MSG,
STATUS_IP,
LAST_STRING_CONFIG /* this must be the last one */
};

Expand Down Expand Up @@ -167,7 +168,9 @@ class ConfigManager {
GUILD_WAR_FEE,
GUILD_WARS_END_ONLY_ON_STARTUP,
ENABLE_CAST,
MAX_CAST_VIEWERS,
MAX_CAST_VIEWERS,
ALLOW_OTC_PROXY,
ALLOW_HAPROXY,
LAST_INTEGER_CONFIG /* this must be the last one */
};

Expand Down
120 changes: 112 additions & 8 deletions source/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ void Connection::acceptConnection()
{
try{
++m_pendingRead;
m_readTimer.expires_from_now(boost::posix_time::seconds(Connection::read_timeout));
m_readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
m_readTimer.async_wait( boost::bind(&Connection::handleReadTimeout, boost::weak_ptr<Connection>(shared_from_this()), boost::asio::placeholders::error));

// Read size of the first packet
Expand All @@ -269,14 +269,116 @@ void Connection::acceptConnection()
}
}

void Connection::parseOtcProxyPacket(const boost::system::error_code& error)
{
boost::recursive_mutex::scoped_lock lockClass(m_connectionLock);
m_readTimer.cancel();
--m_pendingRead;

if (error) {
closeConnection();
return;
}

const uint8_t* msgBuffer = (const uint8_t*)m_msg.getBuffer();
m_realIP = *reinterpret_cast<const uint32_t*>(msgBuffer);
m_otcProxy = true;
acceptConnection();
}

void Connection::parseHaProxyPacket(const boost::system::error_code& error)
{
boost::recursive_mutex::scoped_lock lockClass(m_connectionLock);
m_readTimer.cancel();
--m_pendingRead;

if (error) {
closeConnection();
return;
}

const uint8_t* msgBuffer = (const uint8_t*)m_msg.getBuffer();
m_realIP = *reinterpret_cast<const uint32_t*>(&msgBuffer[14]);
m_haProxy = true;
acceptConnection();
}

bool Connection::tryParseProxyPacket()
{
// only first packet may contain IP from OTCv8 proxy / haproxy
if (m_receivedFirstHeader) {
return false;
}

m_receivedFirstHeader = true;

uint16_t size = m_msg.decodeHeader();
// OTCv8 proxy, 6 bytes packet
// starts from 2 bytes 0xFFFEu, then 4 bytes with IP uint32_t
if (g_config.getNumber(ConfigManager::ALLOW_OTC_PROXY) && size == 0xFFFEu) {
try {
++m_pendingRead;
m_readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
m_readTimer.async_wait(boost::bind(&Connection::handleReadTimeout, boost::weak_ptr<Connection>(shared_from_this()), boost::asio::placeholders::error));

boost::asio::async_read(getHandle(), boost::asio::buffer(m_msg.getBuffer(), 4),
boost::bind(&Connection::parseOtcProxyPacket, shared_from_this(), boost::asio::placeholders::error));
} catch (boost::system::system_error& e) {
if (m_logError) {
LOG_MESSAGE("NETWORK", LOGTYPE_ERROR, 1, e.what());
m_logError = false;
closeConnection();
}
}
return true;
}

// HAProxy send-proxy-v2, 28 bytes packet
// starts from 2 bytes 0x0A0Du, then 26 bytes, IP uint32_t starts from 17th byte (of 28 bytes)
if (g_config.getNumber(ConfigManager::ALLOW_HAPROXY) && size == 0x0A0Du) {
try {
++m_pendingRead;
m_readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
m_readTimer.async_wait(boost::bind(&Connection::handleReadTimeout, boost::weak_ptr<Connection>(shared_from_this()), boost::asio::placeholders::error));

boost::asio::async_read(getHandle(), boost::asio::buffer(m_msg.getBuffer(), 26),
boost::bind(&Connection::parseHaProxyPacket, shared_from_this(), boost::asio::placeholders::error));
} catch (boost::system::system_error& e) {
if (m_logError) {
LOG_MESSAGE("NETWORK", LOGTYPE_ERROR, 1, e.what());
m_logError = false;
closeConnection();
}
}
return true;
}

return false;
}

void Connection::parseHeader(const boost::system::error_code& error)
{
m_connectionLock.lock();
m_readTimer.cancel();
--m_pendingRead;

int32_t size = m_msg.decodeHeader();
if(error || size <= 0 || size >= NETWORKMESSAGE_MAXSIZE - 16){
if (error) {
handleReadError(error);
closeConnection();
m_connectionLock.unlock();
return;
}

if (tryParseProxyPacket()) {
m_connectionLock.unlock();
return;
}

int32_t size = m_msg.decodeHeader();
if (size <= 0 || size >= NETWORKMESSAGE_MAXSIZE - 16) {
closeConnection();
m_connectionLock.unlock();
return;
}

if(m_connectionState != CONNECTION_STATE_OPEN || m_readError){
Expand All @@ -300,11 +402,9 @@ void Connection::parseHeader(const boost::system::error_code& error)
}
}

--m_pendingRead;

try{
++m_pendingRead;
m_readTimer.expires_from_now(boost::posix_time::seconds(Connection::read_timeout));
m_readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
m_readTimer.async_wait( boost::bind(&Connection::handleReadTimeout, boost::weak_ptr<Connection>(shared_from_this()),
boost::asio::placeholders::error));

Expand Down Expand Up @@ -366,7 +466,7 @@ void Connection::parsePacket(const boost::system::error_code& error)

try{
++m_pendingRead;
m_readTimer.expires_from_now(boost::posix_time::seconds(Connection::read_timeout));
m_readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
m_readTimer.async_wait( boost::bind(&Connection::handleReadTimeout, boost::weak_ptr<Connection>(shared_from_this()),
boost::asio::placeholders::error));

Expand Down Expand Up @@ -429,7 +529,7 @@ void Connection::internalSend(OutputMessage_ptr msg)

try{
++m_pendingWrite;
m_writeTimer.expires_from_now(boost::posix_time::seconds(Connection::write_timeout));
m_writeTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_WRITE_TIMEOUT));
m_writeTimer.async_wait( boost::bind(&Connection::handleWriteTimeout, boost::weak_ptr<Connection>(shared_from_this()),
boost::asio::placeholders::error));

Expand All @@ -447,6 +547,10 @@ void Connection::internalSend(OutputMessage_ptr msg)

uint32_t Connection::getIP() const
{
if (isOtcProxy() || isHaProxy()) {
return m_realIP;
}

//Ip is expressed in network byte order
boost::system::error_code error;
const boost::asio::ip::tcp::endpoint endpoint = m_socket->remote_endpoint(error);
Expand Down
20 changes: 17 additions & 3 deletions source/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include <boost/enable_shared_from_this.hpp>
#include "networkmessage.h"

static constexpr int32_t CONNECTION_WRITE_TIMEOUT = 30;
static constexpr int32_t CONNECTION_READ_TIMEOUT = 30;

class Protocol;
class OutputMessage;
typedef boost::shared_ptr<OutputMessage> OutputMessage_ptr;
Expand Down Expand Up @@ -81,9 +84,6 @@ class Connection : public boost::enable_shared_from_this<Connection>, boost::non
static uint32_t connectionCount;
#endif

enum { write_timeout = 30 };
enum { read_timeout = 30 };

enum ConnectionState_t {
CONNECTION_STATE_OPEN = 0,
CONNECTION_STATE_REQUEST_CLOSE = 1,
Expand All @@ -110,6 +110,10 @@ class Connection : public boost::enable_shared_from_this<Connection>, boost::non
m_writeError = false;
m_readError = false;
m_packetsSent = 0;
m_realIP = 0;
m_otcProxy = false;
m_haProxy = false;
m_receivedFirstHeader = false;
m_timeConnected = time(NULL);

#ifdef __ENABLE_SERVER_DIAGNOSTIC__
Expand All @@ -136,11 +140,16 @@ class Connection : public boost::enable_shared_from_this<Connection>, boost::non
bool send(OutputMessage_ptr msg);

uint32_t getIP() const;
bool isOtcProxy() const { return m_otcProxy; };
bool isHaProxy() const { return m_haProxy; };

int32_t addRef() {return ++m_refCount;}
int32_t unRef() {return --m_refCount;}

private:
void parseOtcProxyPacket(const boost::system::error_code& error);
void parseHaProxyPacket(const boost::system::error_code& error);
bool tryParseProxyPacket();
void parseHeader(const boost::system::error_code& error);
void parsePacket(const boost::system::error_code& error);

Expand Down Expand Up @@ -174,6 +183,11 @@ class Connection : public boost::enable_shared_from_this<Connection>, boost::non
time_t m_timeConnected;
uint32_t m_packetsSent;

uint32_t m_realIP = 0;
bool m_otcProxy = false;
bool m_haProxy = false;
bool m_receivedFirstHeader = false;

int32_t m_pendingWrite;
int32_t m_pendingRead;
ConnectionState_t m_connectionState;
Expand Down
1 change: 1 addition & 0 deletions source/definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum passwordType_t{

// Boost won't complain about non-working function
#define BOOST_ASIO_ENABLE_CANCELIO 1
#define BOOST_BIND_GLOBAL_PLACEHOLDERS

#ifndef __FUNCTION__
#define __FUNCTION__ __func__
Expand Down
2 changes: 2 additions & 0 deletions source/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
destPos.y += 1;
canChangeFloor = false;
break;
case DIRECTION_NONE:
break;
}

if(creature->getPlayer() && canChangeFloor){
Expand Down
2 changes: 1 addition & 1 deletion source/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class AStarNodes{
uint32_t curNode;
};

template<class T> class lessPointer : public std::binary_function<T*, T*, bool>
template<class T> class lessPointer
{
public:
bool operator()(T*& t1, T*& t2) {
Expand Down
8 changes: 4 additions & 4 deletions source/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,10 +685,10 @@ BlockType_t Monster::blockHit(Creature* attacker, CombatType_t combatType, int32

if(elementMod != 0)
damage = (int32_t)std::ceil(damage * ((float)(100 - elementMod) / 100));
if(damage <= 0){
damage = 0;
blockType = BLOCK_DEFENSE;
}
if(damage <= 0){
damage = 0;
blockType = BLOCK_DEFENSE;
}
}

return blockType;
Expand Down
Loading