Ejemplo n.º 1
0
void WatchDirectory(void *thread_data) {
  // Copy thread inputs to local variables
  MediaScan *s = ((thread_data_type *)thread_data)->s;
  LPTSTR lpDir = ((thread_data_type *)thread_data)->lpDir;

  // Data variables for the windows directory change notification
  OVERLAPPED oOverlap;
  FILE_NOTIFY_INFORMATION Buffer[FILE_BUFFER_SZ];
  char buf[256];
  char full_path[MAX_PATH_STR_LEN];
  DWORD BytesReturned;

  // Overlapped I/O variables
  WSAOVERLAPPED RecvOverlapped;
  HANDLE hDir;
  DWORD dwWaitStatus;
  DWORD dwBytesRead;
  BOOL bResult;
  WSABUF DataBuf;
  DWORD RecvBytes, Flags;
  char buffer[DATA_BUFSIZE];
  int rc = 0;
  int err = 0;
  char *pBase = 0;

  // Thread state variables
  int ThreadRunning = TRUE;

  // Initialize the cache database
  if (!init_bdb(s)) {
    MediaScanError *e = error_create("", MS_ERROR_CACHE, "Unable to initialize libmediascan cache");
    send_error(s, e);
  }

  SecureZeroMemory(buffer, DATA_BUFSIZE);

  // Make sure the RecvOverlapped struct is zeroed out
  SecureZeroMemory((PVOID) & oOverlap, sizeof(OVERLAPPED));

  // Create the event that will get fired when a directory changes
  oOverlap.hEvent = CreateEvent(NULL, // default security attributes
                                TRUE, // manual-reset event
                                FALSE,  // initial state is nonsignaled
                                TEXT("MyFileChangeEvent")); // "FileChangeEvent" name

  // Make sure the RecvOverlapped struct is zeroed out
  SecureZeroMemory((PVOID) & RecvOverlapped, sizeof(WSAOVERLAPPED));

  // Create an event handle and setup an overlapped structure.
  RecvOverlapped.hEvent = WSACreateEvent();
  if (RecvOverlapped.hEvent == NULL) {
    LOG_ERROR("WSACreateEvent failed: %d\n", WSAGetLastError());
    return;
  }

  DataBuf.len = DATA_BUFSIZE;
  DataBuf.buf = buffer;

  // Open the directory that we are going to have windows monitor, note the share modes
  hDir = CreateFile(lpDir,      // pointer to the file name
                    FILE_LIST_DIRECTORY,  // access (read/write) mode
                    FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, // share mode
                    NULL,       // security descriptor
                    OPEN_EXISTING,  // how to create
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,  // file attributes
                    NULL);      // file with attributes to copy

  // Tell windows to monitor the folder asyncroniously using overlapped I/O
  ReadDirectoryChangesW(hDir,   // handle to directory
                        &Buffer,  // read results buffer
                        FILE_BUFFER_SZ * sizeof(FILE_NOTIFY_INFORMATION), // length of buffer
                        TRUE,   // Monitor sub-directories = TRUE
                        DETECTION_FILTER, // filter conditions
                        &BytesReturned, // bytes returned
                        &oOverlap,  // We are using overlapped I/O
                        NULL);  // Not using completion routine

  Flags = 0;
/* XXX FIXME, reqpipe is gone
  rc = WSARecv(s->thread->reqpipe[0], &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
  if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
    LOG_ERROR("WSARecv failed with error: %d\n", err);
    return;
  }
*/

  // Run until we are told to stop. It is important to let the thread clean up after itself so
  // there is shutdown code at the bottom of this function.
  while (ThreadRunning) {

    // Set up the events are going to wait for
    HANDLE event_list[2] = { oOverlap.hEvent, RecvOverlapped.hEvent };
    FILE_NOTIFY_INFORMATION *fni;
    LOG_LEVEL(1, "\nWaiting for notification...\n");

    // Wait forever for notification.
    dwWaitStatus = WaitForMultipleObjects(2,  // number of objects in array
                                          event_list, // array of objects
                                          FALSE,  // wait for any object
                                          INFINITE);  // infinite wait

    switch (dwWaitStatus) {
        // This is for the event oOverlap.hEvent
      case WAIT_OBJECT_0:
        bResult = GetOverlappedResult(hDir, &oOverlap, &dwBytesRead, TRUE);

        pBase = (char *)Buffer;
        do {

          fni = (FILE_NOTIFY_INFORMATION *) pBase;

          // Note pRecord->FileName is in UTF-16, have to convert it to 8 bits
          WideCharToMultiByte(CP_UTF8, 0, fni->FileName,  // the string you have
                              fni->FileNameLength / 2,  // length of the string
                              buf,  // output
                              _countof(buf),  // size of the buffer in bytes - if you leave it zero the return value is the length required for the output buffer
                              NULL, NULL);
          buf[fni->FileNameLength / 2] = 0;


          // Set up a full path to the file to be scanned and call ms_scan_fileCall scan here with the file changed
          strcpy(full_path, lpDir);
          strcat(full_path, "\\");
          strcat(full_path, buf);
          LOG_INFO("Found File Changed: %s", full_path);

          switch (fni->Action) {

            case FILE_ACTION_ADDED:
              LOG_INFO("  file was added\n");

              // We get notifications even while a file is being copied. This will wait 60 seconds for the file to finish.
              if (WaitForFile(full_path, 10)) {
                ms_scan_file(s, full_path, TYPE_UNKNOWN);
              }
              else {
                LOG_ERROR("A file found by the background scanner never finished copying");
              }

              break;
            case FILE_ACTION_REMOVED:
              LOG_INFO("  file was removed\n");
              HandleRemovedFile(s, full_path);
              break;

            case FILE_ACTION_MODIFIED:
              LOG_INFO("	file was modified\n");  // This can be a change in the time stamp or attributes.";
              // We get notifications even while a file is being copied. This will wait 60 seconds for the file to finish.
              if (WaitForFile(full_path, 10)) {
                ms_scan_file(s, full_path, TYPE_UNKNOWN);
              }
              else {
                LOG_ERROR("A file found by the background scanner never finished copying");
              }

              break;
/*            case FILE_ACTION_RENAMED_OLD_NAME:
								LOG_INFO("	file was renamed and this is the old name\n");
              break;
            case FILE_ACTION_RENAMED_NEW_NAME:
								LOG_INFO("	file was renamed and this is the new name\n");
              break;
*/ }

          if (!fni->NextEntryOffset)
            break;
          pBase += fni->NextEntryOffset;
        } while (TRUE);

        SecureZeroMemory((PVOID) Buffer, sizeof(Buffer));
        ReadDirectoryChangesW(hDir, // handle to directory
                              &Buffer,  // read results buffer
                              sizeof(Buffer), // length of buffer
                              TRUE, // Monitor sub-directories = TRUE
                              DETECTION_FILTER, // filter conditions
                              &BytesReturned, // bytes returned
                              &oOverlap,  // We are using overlapped I/O
                              NULL);  // Not using completion routine

        break;                  /* WAIT_OBJECT_0: */

        // This is for the event s->ghSignalEvent
      case WAIT_OBJECT_0 + 1:

        ThreadRunning = FALSE;

        break;                  /* WAIT_OBJECT_0 + 1: */

      case WAIT_TIMEOUT:

        // A timeout occurred, this would happen if some value other
        // than INFINITE is used in the Wait call and no changes occur.
        // In a single-threaded environment you might not want an
        // INFINITE wait.

        LOG_INFO("\nNo changes in the timeout period.\n");
        break;

      default:
        LOG_ERROR("\n ERROR: Unhandled dwWaitStatus.\n");
        ExitThread(GetLastError());
        break;
    }
  }

  // Free the data that was passed to this thread on the heap
  if (thread_data != NULL) {
    free(thread_data);
    thread_data = NULL;         // Ensure address is not reused.
  }

  CancelIo(hDir);

  if (!HasOverlappedIoCompleted(&oOverlap)) {
    SleepEx(5, TRUE);
  }

  WSACloseEvent(RecvOverlapped.hEvent);
  CloseHandle(oOverlap.hEvent);


  ExitThread(GetLastError());

}                               /* WatchDirectory() */
Ejemplo n.º 2
0
u8 rtw_set_802_11_connect(_adapter* padapter, const u8 *bssid, NDIS_802_11_SSID *ssid)
{
	_irqL irqL;
	u8 status = _SUCCESS;
	u32 cur_time = 0;
	bool bssid_valid = _TRUE;
	bool ssid_valid = _TRUE;
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;

_func_enter_;

	if (!ssid || rtw_validate_ssid(ssid) == _FALSE)
		ssid_valid = _FALSE;

	if (!bssid || rtw_validate_bssid(bssid) == _FALSE)
		bssid_valid = _FALSE;

	if (ssid_valid == _FALSE && bssid_valid == _FALSE) {
		DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n",
			FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid);
		status = _FAIL;
		goto exit;
	}

	if(padapter->hw_init_completed==_FALSE){
		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
			 ("set_ssid: hw_init_completed==_FALSE=>exit!!!\n"));
		status = _FAIL;
		goto exit;
	}

	_enter_critical_bh(&pmlmepriv->lock, &irqL);

	LOG_LEVEL(_drv_info_, FUNC_ADPT_FMT"  fw_state=0x%08x\n",
		FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));

	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) {
		goto handle_tkip_countermeasure;
	} else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) {
		goto release_mlme_lock;
	}

handle_tkip_countermeasure:
	if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) {
		status = _FAIL;
		goto release_mlme_lock;
	}

	if (ssid && ssid_valid)
		_rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(NDIS_802_11_SSID));

	if (bssid && bssid_valid) {
		_rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
		pmlmepriv->assoc_by_bssid = _TRUE;
	}

	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) {
		pmlmepriv->to_join = _TRUE;	
	}
	else {
		status = rtw_do_join(padapter);
	}

release_mlme_lock:
	_exit_critical_bh(&pmlmepriv->lock, &irqL);

exit:
	
_func_exit_;

	return status;
}
Ejemplo n.º 3
0
int APIENTRY WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str, int nWinMode){	

	LOG_PREFIX("logs\\clientLog");
	LOG_LEVEL(logger::Debug); // уровень лога в рантайме (например, берём из командной строки)

	LOG_DEBUG << "WinMain starting..";
	Scene=0; hDC=0;
	int full=0; int WindowX=0; int WindowY=0; int Width=800; int Height=600;
	
	full	= GetPrivateProfileIntA("Options", "FullScreenEnable", 0, "Data/graph.ini");
	WindowX = GetPrivateProfileIntA("Options", "WindowX", 0, "Data/graph.ini");
	WindowY = GetPrivateProfileIntA("Options", "WindowY", 0, "Data/graph.ini");
	Width	= GetPrivateProfileIntA("Options", "Width", 800, "Data/graph.ini");
	Height	= GetPrivateProfileIntA("Options", "Height", 600, "Data/graph.ini");

Scene = new TScene();

	if ( full == 0 ){ 
		WNDCLASSA wcl;
			
		wcl.hInstance = hThisInst;
		wcl.lpszClassName = "OpenGLWinClass";
		wcl.lpfnWndProc = WindowFunc;
		wcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
		
		wcl.hIcon = NULL;
		wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
		wcl.lpszMenuName = NULL;
		
		wcl.cbClsExtra = 0;
		wcl.cbWndExtra = 0;
		
		wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
//		RegisterClassA(&wcl);
		if ( !RegisterClassA(&wcl) ) return -1;//throw "RegisterClass";

		hWnd = CreateWindowA("OpenGLWinClass", "Elt",WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WindowX, WindowY, Width, Height, NULL, NULL, hThisInst, NULL);
		ShowWindow(hWnd, SW_SHOWNORMAL);
		UpdateWindow(hWnd);
	}	


	if ( full == 1 ){
		DEVMODE   ss;
		WNDCLASSA  wcl;

		memset(&ss, 0, sizeof(ss) );
		ss.dmSize    = sizeof(ss);
		ss.dmPelsWidth  = Width;
		ss.dmPelsHeight  = Height;
		ss.dmBitsPerPel  = 32;
		ss.dmFields    = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		if (ChangeDisplaySettings(&ss, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) MessageBoxA(NULL, "Ошибка в ChangeDisplaySettings", "Error", MB_OK | MB_ICONSTOP);

		memset(&wcl, 0, sizeof(wcl) );
		wcl.lpfnWndProc		= (WNDPROC)WindowFunc;
		wcl.hInstance		= hThisInst;
		wcl.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
		wcl.hCursor			= LoadCursor(NULL, IDC_ARROW);
		wcl.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
		wcl.lpszClassName	= "OpenGLWinClass";

		if ( !RegisterClassA(&wcl) ) return -1;//throw "RegisterClass";
		hWnd = CreateWindowA("OpenGLWinClass", "Elt", WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, Width, Height, NULL, NULL, hThisInst, NULL);
		if ( !hWnd ) return -1;//throw "CreateWindow";
		SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, 1 ); 
		ShowWindow(hWnd, SW_SHOWMAXIMIZED);
	}

	MSG msg;
	LOG_DEBUG << "WinMain started end";
	LOG_DEBUG << "World Init...";
	World->Init();
	LOG_DEBUG << "...End World Init";

//---network init
	LOG_DEBUG << "netClient.Init()";
	netClient.Init(World);
	//World->SetNetStatData(&netClient.mNetStat);
	netClient.SetTimeBetweenPacketsSend(500);
	LOG_DEBUG << "netClient.Run()";
	netClient.Run();
//---------------
	tTick gTick;
	gTick.Init(20);//50 раз в сек
	LOG_DEBUG << "Start Main loop";
	do{
		if(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
		{
			if( msg.message == WM_QUIT ) break;
			TranslateMessage( &msg );
			DispatchMessage ( &msg );
		}
		World->CDM(); // Center of Decision Making (Graphics + Logic)
		gTick.Wait();//Зачем ждать? Перести в World->CDM() и если рано - не ждать а выходить
	}while(!bGameOver);
	LOG_DEBUG << "End Main loop";
	LOG_DEBUG << "World->Destroy()";
	World->Destroy();
//---network release
	LOG_DEBUG << "netClient.Stop()";
	netClient.Stop();
	LOG_DEBUG << "netClient.Release()";
	netClient.Release();
//----------
	if (Scene) delete Scene;
	LOG_DEBUG << "Scene deleted";

	LOG_DEBUG << "World destroy";
	DestroyWindow(hWnd);
	LOG_DEBUG << "Windows destroy";

	if ( full == 1 ) ChangeDisplaySettings(NULL, 0);
	LOG_DEBUG << "EXIT";
	return 0;
}
Ejemplo n.º 4
0
int main( int argc, char *argv[] )  {
    tf::options o;
    o.register_option(tf::option("help", "Displays help", false, false, "help", 'h'));
    o.register_option(tf::option("config", "Configuration file to load", true, false, "config", 'c'));
    o.register_option(tf::option("loglevel", "Logging level (DEBUG, INFO, WARNING, ERROR)", false, true, "loglevel", 'l'));
    o.register_option(tf::option("interface", "Interface to bind to", false, true, "interface", 'i'));
    o.register_option(tf::option("service", "Service to process", true, true, "service", 's'));

    o.register_option(tf::option("nobanner", "Don't display startup banner", false, false, "nobanner", 'x'));
    o.register_option(tf::option("daemon", "Run in daemon mode", false, false, "daemon", 'd'));

    try {
        o.parse(argc, argv);
    } catch (const tf::option_exception &e) {
        ERROR_LOG(e.what());
        o.printUsage();
        return 1;
    }

    std::string loglevel;
    if (o.get("loglevel", loglevel)) {
        if (loglevel == "DEBUG") {
            LOG_LEVEL(tf::logger::debug);
        } else if (loglevel == "INFO") {
            LOG_LEVEL(tf::logger::info);
        } else if (loglevel == "WARNING") {
            LOG_LEVEL(tf::logger::warning);
        } else if (loglevel == "ERROR") {
            LOG_LEVEL(tf::logger::error);
        } else {
            ERROR_LOG("Invalid log level");
            return 1;
        }
    } else {
        LOG_LEVEL(tf::logger::warning);
    }
    LOG_THREADS(true);

    if (!o.get("nobanner", false)) {
        char output[1024];
        sprintf(output, banner, PROJECT_VERSION, 2016);
        tf::logger::instance().log(tf::logger::info, output);
    }

    std::string configFile;
    o.get("config", configFile);
    DEBUG_LOG("Using config file '" << configFile << "'");

    if (o.get("daemon", false)) {
        tf::run_as_daemon();
    }

    try {
        const std::string interface = o.getWithDefault("interface", "0.0.0.0");
        const std::string service = o.getWithDefault("service", "7900");
        fp::bootstrap engine(interface, service);
        engine.run();
	} catch (const std::exception &stde) {
		ERROR_LOG("Internal error: " << stde.what());
		return 1;
	}
}
Ejemplo n.º 5
0
int main( int argc, char *argv[] )  {
    tf::options o;
    o.register_option(tf::option("help", "Displays help", false, false, "help", 'h'));
    o.register_option(tf::option("loglevel", "Logging level (DEBUG, INFO, WARNING, ERROR)", false, true, "loglevel", 'l'));
    o.register_option(tf::option("url", "URL to connect to", true, true, "url", 'u'));
    o.register_option(tf::option("subject", "Subject to user", true, true, "subject", 's'));

    try {
        o.parse(argc, argv);
    } catch (const tf::option_exception &e) {
        ERROR_LOG(e.what());
        o.printUsage();
        return 1;
    }

    std::string loglevel;
    if (o.get("loglevel", loglevel)) {
        if (loglevel == "DEBUG") {
            LOG_LEVEL(tf::logger::debug);
        } else if (loglevel == "INFO") {
            LOG_LEVEL(tf::logger::info);
        } else if (loglevel == "WARNING") {
            LOG_LEVEL(tf::logger::warning);
        } else if (loglevel == "ERROR") {
            LOG_LEVEL(tf::logger::error);
        } else {
            ERROR_LOG("Invalid log level");
            return 1;
        }
    } else {
        LOG_LEVEL(tf::logger::warning);
    }

    try {
        fp::Session::initialise();

        const std::string url = o.getWithDefault("url", "");
        std::string subject;
        if (!o.get("subject", subject)) {
            ERROR_LOG("You must specify a subject");
        }

        fp::BlockingQueue queue;
        auto transport = fp::make_realm_connection(url.c_str(), "");

        const fp::Subscriber subscriber(transport, subject.c_str(), [&](const fp::Subscriber *event, const fp::Message *msg) noexcept {
            INFO_LOG(*msg);
        });

        queue.addSubscriber(subscriber);

        bool shutdown = false;
        auto terminate = [&](const fp::SignalEvent *event, const int signal) noexcept {
            INFO_LOG("Shutdown signal caught...");
            shutdown = true;
        };
        auto sigint_handler = queue.registerEvent(SIGINT, terminate);
        auto sigterm_handler = queue.registerEvent(SIGTERM, terminate);

        while (!shutdown) {
            queue.dispatch();
        }

        queue.unregisterEvent(sigint_handler);
        queue.unregisterEvent(sigterm_handler);
        queue.removeSubscriber(subscriber);
        fp::Session::destroy();
    } catch (const std::exception &stde) {
        ERROR_LOG("Internal error: " << stde.what());
        return 1;
    }
}
Ejemplo n.º 6
0
shared_ptr<OGRSpatialReference> MapReprojector::createPlanarProjection(const OGREnvelope& env,
  Radians maxAngleError, Meters maxDistanceError, Meters testDistance, bool warnOnFail)
{
  vector< shared_ptr<OGRSpatialReference> > projs = createAllPlanarProjections(env);

  QString deg = QChar(0x00B0);

  if (projs.size() == 0)
  {
    throw HootException("No candidate planar projections are available.");
  }

  vector<PlanarTestResult> testResults;
  vector<PlanarTestResult> passingResults;

  // if the envelope has zero size then return an orthographic projection.
  if (env.MaxX == env.MinX || env.MaxY == env.MinY)
  {
    return createOrthographic(env);
  }

  for (size_t i = 0; i < projs.size(); ++i)
  {
    PlanarTestResult tr;
    tr.i = i;
    if (_evaluateProjection(env, projs[i], testDistance, tr.distanceError, tr.angleError))
    {
      // create a score that is weighted by the user's threshold values.
      tr.score = tr.distanceError / maxDistanceError + tr.angleError / maxAngleError;
      testResults.push_back(tr);
      if (tr.distanceError <= maxDistanceError && tr.angleError <= maxAngleError)
      {
        passingResults.push_back(tr);
      }
    }
    else
    {
      tr.distanceError = numeric_limits<double>::max();
      tr.angleError = numeric_limits<double>::max();
      tr.score = numeric_limits<double>::max();
      testResults.push_back(tr);
    }
    //LOG_INFO("dis: " << tr.distanceError << "m angle: " << toDegrees(tr.angleError) << deg);
  }

  //  |<---                       80 cols                                         -->|
  QString errorMessage =
      "A projection within the specified error bounds could not be found. This is "
      "likely due to a very large bounds on the data. Please read "
      "'Hootenanny - Distance and Angle Errors Due to Reprojection' for more "
      "information. You may experience poor conflation performance as a result.";
  int bestIndex = -1;
  Log::WarningLevel level = Log::Debug;
  if (passingResults.size() > 0)
  {
    bestIndex = _findBestScore(passingResults);

    char* wkt = 0;
    projs[bestIndex]->exportToWkt(&wkt);
    LOG_DEBUG("Projection: " << wkt)
    OGRFree(wkt);
  }
  else if (warnOnFail == false)
  {
    level = Log::Warn;
  }
  else if (testResults.size() > 0)
  {
    LOG_WARN(errorMessage);
    bestIndex = _findBestScore(testResults);
    level = Log::Info;
  }

  LOG_LEVEL(level, "Planar projection has max distance error " << fixed << setprecision(2)
            << testResults[bestIndex].distanceError << "m "
            << "(" << testResults[bestIndex].distanceError / testDistance * 100.0 << "%) "
            << "and max angular error: " << toDegrees(testResults[bestIndex].angleError) << deg
            << " test distance: " << testDistance << "m");
  LOG_LEVEL(level, "Projection: " << toWkt(projs[bestIndex]));

  if (bestIndex == -1)
  {
    throw HootException(errorMessage);
  }

  return projs[bestIndex];
}
Ejemplo n.º 7
0
int main( int argc, char *argv[] )  {
    tf::options o;
    o.register_option(tf::option("help", "Displays help", false, false, "help", 'h'));
    o.register_option(tf::option("loglevel", "Logging level (DEBUG, INFO, WARNING, ERROR)", false, true, "loglevel", 'l'));
    o.register_option(tf::option("url", "URL to connect to", true, true, "url", 'u'));
    o.register_option(tf::option("rate", "Sending message rate", false, true, "rate", 'r'));
    o.register_option(tf::option("count", "Number of messages to send", false, true, "count", 'c'));

    try {
        o.parse(argc, argv);
    } catch (const tf::option_exception &e) {
        ERROR_LOG(e.what());
        o.printUsage();
        return 1;
    }

    std::string loglevel;
    if (o.get("loglevel", loglevel)) {
        if (loglevel == "DEBUG") {
            LOG_LEVEL(tf::logger::debug);
        } else if (loglevel == "INFO") {
            LOG_LEVEL(tf::logger::info);
        } else if (loglevel == "WARNING") {
            LOG_LEVEL(tf::logger::warning);
        } else if (loglevel == "ERROR") {
            LOG_LEVEL(tf::logger::error);
        } else {
            ERROR_LOG("Invalid log level");
            return 1;
        }
    } else {
        LOG_LEVEL(tf::logger::warning);
    }

    const size_t count = o.get("count", 1000ul);
    const size_t rate = o.get("rate", 100ul);

    try {
        using TimeType = std::chrono::high_resolution_clock::time_point;
        using ResultsType = std::pair<TimeType, TimeType>;
        std::vector<ResultsType> m_times(count);

        fp::Session::initialise();
        if (std::thread::hardware_concurrency() >= 4) {
            fp::Session::assign_to_cpu({2, 3});
        } else if (std::thread::hardware_concurrency() >= 2) {
            fp::Session::assign_to_cpu({0, 1});
        }

        const std::string url = o.getWithDefault("url", "");

        fp::BlockingQueue queue;
        auto transport = fp::make_realm_connection(url.c_str(), "");

        if (!transport->valid()) {
            ERROR_LOG("Failed to create transport");
            return 1;
        }

        uint32_t id = 0;
        bool shutdown = false;

        fp::MutableMessage sendMsg;
        sendMsg.setSubject("TEST.PERF.SOURCE");
        sendMsg.addScalarField("id", id);

        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::microseconds(1000000) / rate);
        INFO_LOG("Sending a message every " << duration.count() << " us");

        queue.registerEvent(duration, [&](fp::TimerEvent *event) noexcept {
            if (id < count) {
                sendMsg.clear();
                sendMsg.setSubject("TEST.PERF.SOURCE");
                sendMsg.addScalarField("id", id);
                m_times[id].first = std::chrono::high_resolution_clock::now();
                if (transport->sendMessage(sendMsg) == fp::OK) {
                    DEBUG_LOG("Message send successfully: " << sendMsg);
                } else {
                    ERROR_LOG("Failed to send message");
                    exit(1);
                }
                id++;
            }
        });

        fp::Subscriber subscriber(transport, "TEST.PERF.SINK", [&](const fp::Subscriber *event, const fp::Message *recvMsg) noexcept {
            DEBUG_LOG("Received message from sink: " << *recvMsg);
//            std::chrono::high_resolution_clock::time_point t = std::chrono::high_resolution_clock::now();
            uint32_t recv_id = 0;
            if (recvMsg->getScalarField("id", recv_id)) {
                DEBUG_LOG("Processing message: " << recv_id);
                uint64_t ts = 0;
                if (recvMsg->getScalarField("timestamp", ts)) {
                    std::chrono::microseconds dur(ts);
                    std::chrono::time_point<std::chrono::high_resolution_clock> t(dur);
                    m_times[recv_id].second = t;
                }
            }
            if (recv_id >= count - 1) {
                shutdown = true;
            }
        });
        queue.addSubscriber(subscriber);

        while (!shutdown) {
            queue.dispatch();
        }

        fp::Session::destroy();

        std::vector<std::chrono::microseconds> latencies;
        latencies.reserve(count);
        std::transform(m_times.begin(), m_times.end(), std::back_inserter(latencies), [&](auto &result) {
            return std::chrono::duration_cast<std::chrono::microseconds>(result.second - result.first);
        });

        std::future<double> avg = std::async(std::launch::async, [&latencies]() {
            uint64_t total = 0;
            std::for_each(latencies.begin(), latencies.end(), [&total](auto &v) {
                total += v.count();
            });
            return static_cast<double>(total) / latencies.size();
        });

        std::future<std::chrono::microseconds> min = std::async(std::launch::async, [&latencies]() {
            return *std::min_element(latencies.begin(), latencies.end());
        });

        std::future<std::chrono::microseconds> max = std::async(std::launch::async, [&latencies]() {
            return *std::max_element(latencies.begin(), latencies.end());
        });

        auto find_p = [&](size_t p) {
            size_t index = std::floor((static_cast<double>(100 - p) / 100.0) * latencies.size());
            std::nth_element(latencies.begin(), latencies.begin() + index, latencies.end(), std::greater<std::chrono::microseconds>());
            return latencies[index];
        };

        std::future<std::chrono::microseconds> p99 = std::async(std::launch::async, std::bind(find_p, 95));
        std::future<std::chrono::microseconds> p90 = std::async(std::launch::async, std::bind(find_p, 90));
        std::future<std::chrono::microseconds> p50 = std::async(std::launch::async, std::bind(find_p, 50));

        INFO_LOG("Avg round trip: " << avg.get() << " us");
        INFO_LOG("Min round trip: " << min.get().count() << " us");
        INFO_LOG("Max round trip: " << max.get().count() << " us");
        INFO_LOG("P99 round trip: " << p99.get().count() << " us");
        INFO_LOG("P90 round trip: " << p90.get().count() << " us");
        INFO_LOG("P50 round trip: " << p50.get().count() << " us");

    } catch (const std::exception &stde) {
        ERROR_LOG("Internal error: " << stde.what());
        return 1;
    }
}