RetroShare/libretroshare/src/rsserver/p3face-server.cc
Gioacchino Mazzurco 9b8d0afacb
Fix sporadic crash in JSON API async calls
In Restbed one is not supposed to call session->yield outside the
  threads controlled by Restbed. RetroShare JSON API async call were
  calling session->yield from threads controlled by RetroShare all the
  times, this caused crashes in some cases, like when the JSON API
  socket timed out concurrently with the session->yield call .
  To solve this problem session->yield from async
  calls are now wrapped insto mService->schedule to ensure they are
  executed on the right thread (aka one of the threads controlled by
  Restbed).
While solving this issue I realized also that passing RsEvents as const
  references around was quite limiting in cases where the event need to
  be finally handled in another thread, in that case passing by const
  reference the RsEvent needed to be copied by value into the thread
  that process it, in this copy by value process the information of
  which was the original specific type is lost, and then only the data
  and methods from general RsEvents are available, unless the handler
  does tricky stuff with type coercion etc. To solve this limitation
  pass the events as std::shared_ptr<const RsEvent> seems the safer and
  more elegant solution.
2019-08-27 11:59:38 +02:00

274 lines
7.4 KiB
C++

/*******************************************************************************
* libretroshare/src/rsserver: p3face-server.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2015 by Robert Fernie <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "util/rstime.h"
#include "rsserver/p3face.h"
#include "retroshare/rsplugin.h"
#include "tcponudp/tou.h"
#include <unistd.h>
#include "pqi/authssl.h"
#include <sys/time.h>
#include "util/rstime.h"
#include "pqi/p3peermgr.h"
#include "pqi/p3linkmgr.h"
#include "pqi/p3netmgr.h"
#include "util/rsdebug.h"
#include "retroshare/rsevents.h"
#include "services/rseventsservice.h"
/****
#define DEBUG_TICK 1
****/
#define WARN_BIG_CYCLE_TIME (0.2)
#ifdef WINDOWS_SYS
#include "util/rstime.h"
#include <sys/timeb.h>
#endif
/*extern*/ RsControl* rsControl = nullptr;
static double getCurrentTS()
{
#ifndef WINDOWS_SYS
struct timeval cts_tmp;
gettimeofday(&cts_tmp, NULL);
double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0;
#else
struct _timeb timebuf;
_ftime( &timebuf);
double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0;
#endif
return cts;
}
// These values should be tunable from the GUI, to offer a compromise between speed and CPU use.
// In some cases (VOIP) it's likely that we will need to set them temporarily to a very low
// value, in order to favor a fast feedback
const double RsServer::minTimeDelta = 0.05; // 25;
const double RsServer::maxTimeDelta = 0.2;
const double RsServer::kickLimit = 0.15;
RsServer::RsServer() :
coreMutex("RsServer"), mShutdownCallback([](int){}),
coreReady(false)
{
{
RsEventsService* tmpRsEvtPtr = new RsEventsService();
rsEvents = tmpRsEvtPtr;
startServiceThread(tmpRsEvtPtr, "RsEventsService");
}
// This is needed asap.
//
mNotify = new p3Notify() ;
rsNotify = mNotify ;
mPeerMgr = NULL;
mLinkMgr = NULL;
mNetMgr = NULL;
mHistoryMgr = NULL;
pqih = NULL;
mPluginsManager = NULL;
/* services */
mHeart = NULL;
mDisc = NULL;
msgSrv = NULL;
chatSrv = NULL;
mStatusSrv = NULL;
mGxsTunnels = NULL;
mMin = 0;
mLoop = 0;
mLastts = getCurrentTS();
mLastSec = 0; /* for the slower ticked stuff */
mTimeDelta = 0.25 ;
mAvgTickRate = mTimeDelta;
/* caches (that need ticking) */
/* Config */
mConfigMgr = NULL;
mGeneralConfig = NULL;
}
RsServer::~RsServer()
{
delete mGxsTrans;
}
/* General Internal Helper Functions
----> MUST BE LOCKED!
*/
/* Thread Fn: Run the Core */
void RsServer::data_tick()
{
rstime::rs_usleep(mTimeDelta * 1000000);
double ts = getCurrentTS();
double delta = ts - mLastts;
/* for the fast ticked stuff */
if (delta > mTimeDelta)
{
#ifdef DEBUG_TICK
std::cerr << "Delta: " << delta << std::endl;
std::cerr << "Time Delta: " << mTimeDelta << std::endl;
std::cerr << "Avg Tick Rate: " << mAvgTickRate << std::endl;
#endif
mLastts = ts;
/******************************** RUN SERVER *****************/
lockRsCore();
int moreToTick = pqih->tick();
#ifdef DEBUG_TICK
std::cerr << "RsServer::run() ftserver->tick(): moreToTick: " << moreToTick << std::endl;
#endif
unlockRsCore();
/* tick the Managers */
mPeerMgr->tick();
mLinkMgr->tick();
mNetMgr->tick();
/******************************** RUN SERVER *****************/
/* adjust tick rate depending on whether there is more.
*/
mAvgTickRate = 0.2 * mTimeDelta + 0.8 * mAvgTickRate;
if (1 == moreToTick)
{
mTimeDelta = 0.9 * mAvgTickRate;
if (mTimeDelta > kickLimit)
{
/* force next tick in one sec
* if we are reading data.
*/
mTimeDelta = kickLimit;
mAvgTickRate = kickLimit;
}
}
else
{
mTimeDelta = 1.1 * mAvgTickRate;
}
/* limiter */
if (mTimeDelta < minTimeDelta)
{
mTimeDelta = minTimeDelta;
}
else if (mTimeDelta > maxTimeDelta)
{
mTimeDelta = maxTimeDelta;
}
/* Fast Updates */
/* now we have the slow ticking stuff */
/* stuff ticked once a second (but can be slowed down) */
if ((int) ts > mLastSec)
{
mLastSec = (int) ts;
// Every second! (UDP keepalive).
//tou_tick_stunkeepalive();
// every five loops (> 5 secs)
if (mLoop % 5 == 0)
{
// update_quick_stats();
// Update All Every 5 Seconds.
// These Update Functions do the locking themselves.
#ifdef DEBUG_TICK
std::cerr << "RsServer::run() Updates()" << std::endl;
#endif
mConfigMgr->tick(); /* saves stuff */
}
// every 60 loops (> 1 min)
if (++mLoop >= 60)
{
mLoop = 0;
/* force saving FileTransferStatus TODO */
//ftserver->saveFileTransferStatus();
/* see if we need to resave certs */
//AuthSSL::getAuthSSL()->CheckSaveCertificates();
/* hour loop */
if (++mMin >= 60)
{
mMin = 0;
}
}
/* Tick slow services */
if(rsPlugins)
rsPlugins->slowTickPlugins((rstime_t)ts);
// slow update tick as well.
// update();
} // end of slow tick.
} // end of only once a second.
#ifdef DEBUG_TICK
double endCycleTs = getCurrentTS();
double cycleTime = endCycleTs - ts;
if (cycleTime > WARN_BIG_CYCLE_TIME)
{
std::string out;
rs_sprintf(out, "RsServer::run() WARNING Excessively Long Cycle Time: %g secs => Please DEBUG", cycleTime);
std::cerr << out << std::endl;
}
#endif
}