Plugins for linux samp

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

Плагин для Linux сервера SA-MP 0.3.7-R2, исправляющий потокобезопасность функций RakNet для получения времени

vsergeenko777/samp-plugin-raktimefix

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

Скачать скомпилированную версию. Совместимо только с SA-MP 0.3.7-R2 Linux сервером.

Этот плагин исправляет потокобезопасность функций RakNet::GetTime и RakNet::GetTimeNS, которые используют общую глобальную переменную для хранения результата вызова gettimeofday. Вот код этих функций:

static bool initialized=false; #ifdef _WIN32 static LARGE_INTEGER yo; #else static timeval tp, initialTime; // #endif RakNetTime RakNet::GetTime( void ) < if ( initialized == false ) < #ifdef _WIN32 QueryPerformanceFrequency( &yo ); // The original code shifted right 10 bits //counts = yo.QuadPart >> 10; // It gives the wrong value since 2^10 is not 1000 // counts = yo.QuadPart;// / 1000; #else gettimeofday( &initialTime, 0 ); #endif initialized = true; > #ifdef _WIN32 LARGE_INTEGER PerfVal; QueryPerformanceCounter( &PerfVal ); return (RakNetTime)(PerfVal.QuadPart*1000 / yo.QuadPart); #else gettimeofday( &tp, 0 ); // Seconds to ms and microseconds to ms return ( tp.tv_sec - initialTime.tv_sec ) * 1000 + ( tp.tv_usec - initialTime.tv_usec ) / 1000; #endif > RakNetTimeNS RakNet::GetTimeNS( void ) < if ( initialized == false ) < #ifdef _WIN32 QueryPerformanceFrequency( &yo ); // The original code shifted right 10 bits //counts = yo.QuadPart >> 10; // It gives the wrong value since 2^10 is not 1000 // counts = yo.QuadPart;// / 1000; #else gettimeofday( &initialTime, 0 ); #endif initialized = true; > #ifdef _WIN32 LARGE_INTEGER PerfVal; QueryPerformanceCounter( &PerfVal ); __int64 quotient, remainder; quotient=((PerfVal.QuadPart*1000) / yo.QuadPart); remainder=((PerfVal.QuadPart*1000) % yo.QuadPart); //return (PerfVal.QuadPart*1000 / (yo.QuadPart/1000)); return quotient*1000 + (remainder*1000 / yo.QuadPart); #else gettimeofday( &tp, 0 ); return ( tp.tv_sec - initialTime.tv_sec ) * (RakNetTimeNS) 1000000 + ( tp.tv_usec - initialTime.tv_usec ); #endif >

Изначально эти функции вызывались в основном из сетевого потока RakNet (хотя есть места, где это происходит в потоке пользовательского приложения), но на последних версиях SA-MP использует эти функции из своего главного потока в огромных количествах.

Одновременное выполнение любой из этих функций из разных потоков приводит к повреждению глобальной переменной tp, что в итоге сказывается на возвращаемом результате функции. И чем больше вызовов совершается из разных потоков, тем больше вероятность воспроизведения проблемы.

Примечательно, что Win32 реализация этих функций не имеет такого недостатка, результат вызова QueryPerformanceCounter записывается в локальную переменную PerfVal.

Последствий от этой ошибки может быть множество, но самая заметная проблема заключается в отправке подтверждений полученных пакетов:

unsigned ReliabilityLayer::GenerateDatagram(. ) < // . if (time > nextAckTime) < if (acknowlegements.Size()>0) < output->Write(true); messagesSent++; statistics.acknowlegementBitsSent +=acknowlegements.Serialize(output, (MTUSize-UDP_HEADER_SIZE)*8-1, true); if (acknowlegements.Size()==0) nextAckTime=time+(RakNetTimeNS)(ping*(RakNetTime)(PING_MULTIPLIER_TO_RESEND/4.0f)); else < // printf("Ack full\n"); > writeFalseToHeader=false; > else < writeFalseToHeader=true; nextAckTime=time+(RakNetTimeNS)(ping*(RakNetTime)(PING_MULTIPLIER_TO_RESEND/4.0f)); > > else writeFalseToHeader=true; // . >

RakNet использует полученное функцией RakNet::GetTimeNS время, чтобы запланировать следующую отправку подтверждений клиенту, как это видно на приведенном сверху коде. В ситуациях, когда RakNet::GetTimeNS возвращает некорректный результат (чаще всего он намного больше корректного времени), следующая отправка подтверждений будет запланирована на время в далеком будущем (в рамках секунд). Сервер перестает отправлять подтверждения, что в конечном итоге приводит к решению клиента разорвать соединение.

Плагин перехватывает функции RakNet::GetTime и RakNet::GetTimeNS, чтобы использовать свой вариант реализации, который использует локальную переменную для хранения результата gettimeofday:

RakNetTime HOOK_RakNet_GetTime() < static bool& initialized = *reinterpret_castbool*>(0x81A19C4); static timeval& initialTime = *reinterpret_casttimeval*>(0x81A19BC); if (!initialized) < gettimeofday(&initialTime, NULL); initialized = true; > struct timeval tv; // gettimeofday(&tv, NULL); return 1000 * (tv.tv_sec - initialTime.tv_sec) + (tv.tv_usec - initialTime.tv_usec) / 1000; >

Это исправляет проблему и делает эти функции безопасными для вызова из нескольких потоков.

Очевидно, что разработчики или мейнтейнеры той версии RakNet, которая по сей день используется в SA-MP. Хотя Kalcor тоже внес свой вклад в появление этой проблемы и возможно без него она не была бы такой заметной. Последняя версия RakNet не имеет этой проблемы, как и более стабильный и функциональный форк SLikeNet.

Долгое время эта проблема оставалась незамеченной из-за того, что на актуальных несколько лет назад дистрибутивах Linux реализация gettimeofday каким-то образом избегала проблемы с повреждением глобальной переменной tp. Проблема воспроизводится лишь в современных дистрибутивах (как пример Debian 9, 10 и более поздние версии), что делает невозможным их использование для размещения SA-MP сервера.

Проблема имеет настолько плавающий характер, что может воспроизводиться только несколько раз в сутки, при этом из-за реализации использования RakTime::GetTimeNS (значение времени сохраняется один раз и используется для всех вызовов ReliabilityLayer::Update) одновременно вылетают абсолютно все игроки. Я смог поймать стабильное воспроизведение проблемы с помощью sleep 0 в server.cfg, при котором TPS (кол-во итераций циклов в секунду) было в районе 400 тысяч тиков в секунду, что резко повысило шансы на проявление проблемы (раз в 10-60 секунд) и поэтому стало возможно её исследовать и исправить.

Можно предположить, что до какой-то версии ядра Linux системный вызов gettimeofday имел блокировку, которая обеспечивала защиту от повреждения глобальной переменной tp, но в какой-то момент это было изменено для повышения производительности (хотя я не смог найти подтверждение этому в истории коммитов репозитория Linux).

Дополнительно стоит сказать, что я не смог воспроизвести эту проблему на нескольких виртуальных машинах, только на своих физических серверах. Поэтому, возможно, виртуальные сервера полностью избегают эту проблему, либо она каким-то образом зависит от конфигураций системы или других факторов.

На текущий момент уже завершена долгосрочная поддержка многих дистрибутивов Linux, на которой эта проблема не воспроизводится. Это значит, что эти дистрибутивы постепенно перестают получать обновления программ и утилит, в том числе самые главные — обновления безопасности. Этот плагин позволяет начать использовать новые современные версии дистрибутивов, чтобы размещать на них свои SA-MP сервера.

И хотя я общался с Kalcor насчет этой проблемы, думаю его уже не так сильно будет интересовать её решение и вряд ли у него будет желание выпустить патч сервера с исправлением:

Источник

Добро пожаловать!

Зарегистрировавшись у нас, вы сможете обсуждать, делиться и отправлять личные сообщения другим участникам нашего сообщества.

Если Вы желаете помогать развитию проекта, готовы заполнять раздел(-ы) и подсказывать другим пользователям на портале, есть возможность попасть в команду редакторов. Для этого следует обратиться в техническую поддержку

Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно.
Вам необходимо обновить браузер или попробовать использовать другой.

SAMP VOICE Кастомный порт (Linux)

SAMP VOICE Кастомный порт (Linux) 3.1

SAMPVOICE — это набор разработчика для реализации систем голосового общения на языке Pawn под сервер.

Поддержка версий​

Основные возможности ​

  • Контролируемая передача голосового потока
  • Управление микрофоном игрока
  • Привязка голосового потока к игровым объектам
  • И так далее всё указано в документации

1661245920666.png

3. В server.cfg добавляем параметр sv_port и свой порт.
Например: sv_port 77788.
Автор не я и нет от меня доработок но будет полезно для тех кому лень компилировать код.
Автор плагина: CyberMor
Автор доработки: Bouraoui AL-Moez L.A

Автор ZERODEV Скачивания 41 Просмотры 640 Первый выпуск 23 Авг 2022 Обновление 23 Авг 2022 Оценка 0.00 звёзд 0 оценок

Источник

Читайте также:  Linux невозможно открыть разделяемый объектный файл
Оцените статью
Adblock
detector