Compare commits

..

1 Commits

Author SHA1 Message Date
Brendan LE GLAUNEC c21bf07fe4 Initial commit 2016-05-20 14:00:37 +02:00
67 changed files with 192 additions and 2511 deletions
+5 -91
View File
@@ -13,21 +13,7 @@
## limitations under the License.
cmake_minimum_required (VERSION 2.8.1)
cmake_policy(SET CMP0048 OLD)
set (PROJECT_NAME cameradar)
project (${PROJECT_NAME})
message ("Here")
set (${PROJECT_NAME}_VERSION_MAJOR 1)
set (${PROJECT_NAME}_VERSION_MINOR 0)
set (${PROJECT_NAME}_VERSION_PATCH 4)
set (${PROJECT_NAME}_SUFFIX "-beta")
set (${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}${${PROJECT_NAME}_SUFFIX}")
find_package(Git REQUIRED)
cmake_policy(SET CMP0042 NEW)
# compiler flags
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") #enable C++14
@@ -46,89 +32,17 @@ set(CMAKE_MACOSX_RPATH 1)
# list of all cache managers
set (CAMERADAR_CACHE_MANAGERS "")
# dependencies directory
set(DEPS_DIR ${CMAKE_SOURCE_DIR}/deps)
# output path for cache managers
set (CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER cache_managers)
set (CAMERADAR_CACHE_MANAGER_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER})
set (CCTV_CACHE_MANAGER_OUTPUT_FOLDER cache_managers)
set (CCTV_CACHE_MANAGER_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CCTV_CACHE_MANAGER_OUTPUT_FOLDER})
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# the place where the version.h file is generated, used from the main.cpp of cameradar
set (VERSION_INCLUDE_DIR ${PROJECT_BINARY_DIR})
# get the git revision
message (STATUS "retrieve current git revision SHA1 of cameradar")
execute_process(
COMMAND "git" "rev-parse" "HEAD"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE CAMERADAR_GIT_SHA1
)
# remove last character of the git output (\n)
string(LENGTH ${CAMERADAR_GIT_SHA1} CAMERADAR_GIT_SHA1_LEN)
math(EXPR CAMERADAR_GIT_SHA1_LEN "${CAMERADAR_GIT_SHA1_LEN} - 1")
string(SUBSTRING ${CAMERADAR_GIT_SHA1} 0 ${CAMERADAR_GIT_SHA1_LEN} CAMERADAR_GIT_SHA1)
# print the SHA1
message (STATUS "current cameradar git revision SHA1 is ${CAMERADAR_GIT_SHA1}")
# generate build number from the current timestamp
string(TIMESTAMP CAMERADAR_VERSION_BUILD "%Y%m%d%H%M%S" "UTC")
# print version
message (STATUS "current cameradar build version will be ${CAMERADAR_VERSION_BUILD}")
configure_file (
"${PROJECT_SOURCE_DIR}/version.h.in"
"${PROJECT_BINARY_DIR}/version.h"
)
# add all deps libraries to the link directories path
link_directories (
# third party libraries
"deps/jsoncpp/src/deps.jsoncpp/src/lib_json"
"deps/boost/src/deps.boost/libs"
"deps/mysql-connector/lib"
)
include_directories (
"cameradar_standalone/include"
"deps/jsoncpp/src/deps.jsoncpp/include"
"deps/boost/src/deps.boost/include"
"deps/mysql-connector/include"
"cameradar_standalone/include"
"../cctv_server2/deps/jsoncpp/src/deps.jsoncpp/include"
)
set (${CAMERADAR_BINARIES} "")
set (${CAMERADAR_LIBRARIES} "")
#build cache managers
add_subdirectory (deps)
message ("Debug")
add_subdirectory (cameradar_standalone)
add_subdirectory (cache_managers)
list (APPEND CAMERADAR_LIBRARIES ${CAMERADAR_INSTALL_DEPENDENCIES} ${CAMERADAR_LIBRARIES})
install (PROGRAMS ${CAMERADAR_BINARIES} DESTINATION bin)
install (FILES ${CAMERADAR_CACHE_MANAGERS} DESTINATION cache_managers)
install (FILES ${CAMERADAR_LIBRARIES} DESTINATION libraries)
install (DIRECTORY ${CMAKE_SOURCE_DIR}/deps/licenses DESTINATION libraries)
# cpack configuration
include (InstallRequiredSystemLibraries)
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "cameradar")
set (CPACK_PACKAGE_VENDOR "Etix Labs")
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "cameradar tool")
set (CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}_${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}")
set (CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set (CPACK_PACKAGE_VERSION_MAJOR "0")
set (CPACK_PACKAGE_VERSION_MINOR "2")
set (CPACK_PACKAGE_VERSION_PATCH "2")
set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}")
set (CPACK_GENERATOR "TGZ")
set (CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)
+9 -77
View File
@@ -1,10 +1,6 @@
# Cameradar
## An RTSP surveillance camera access multitool
[![cameradar License](https://img.shields.io/badge/license-Apache-blue.svg)](#license)
[![Latest release](https://img.shields.io/badge/release-1.0.4-green.svg)](https://github.com/EtixLabs/cameradar/releases/latest)
## An RTSP surveillance camera access multitool.
#### Cameradar allows you to:
@@ -22,15 +18,7 @@ Of course, you can also call for individual tasks if you plug in a Database to C
## Table of content
- [Quick install](#quick-install)
- [Dependencies](#quick-install###dependencies)
- [Five steps guide](#quick-install###five-steps-guide)
- [Manual installation](#manual-installation)
- [Dependencies](#manual-installation###dependencies)
- [Steps](#manual-installation###Steps)
- [Advanced docker deployment](#advanced-docker-deployment)
- [Dependencies](#advanced-docker-deployment###dependencies)
- [Deploy a custom version of Cameradar](#advanced-docker-deployment###deploy-a-custom-version-of-cameradar)
- [Installation](#installation)
- [Configuration](#configuration)
- [Output](#output)
- [Check camera access](#check-camera-access)
@@ -40,79 +28,23 @@ Of course, you can also call for individual tasks if you plug in a Database to C
- [Next improvements](#next-improvements)
- [License](#license)
## Quick install
The quick install uses docker to build Cameradar without polluting your machine with dependencies and makes it easy to deploy Cameradar in a few commands. **However, it may require networking knowledge, as your docker containers will need access to the cameras subnetwork.**
### Dependencies
The only dependencies are `docker`, `docker-tools`, `git` and `make`.
### Five steps guide
1. `git clone https://github.com/EtixLabs/cameradar.git`
2. Go into the Cameradar repository, then to the `deployment` directory
3. Tweak the `conf/cameradar.conf.json` as you need (see [the onfiguration guide here](#configuration) for more information)
4. Run `docker-compose build cameradar` to build the cameradar container
5. Run `docker-compose up cameradar` to launch Cameradar
If you want to deploy your custom version of Cameradar using the same method, you should check the [advanced docker deployment](#advanced-docker-deployment) tutorial here.
## Manual installation
The manual installation is recommended if you want to tweak Cameradar and quickly test them using CMake and running Cameradar in command-line. If you just want to use Cameradar, it is recommended to use the [quick install](#quick-install) instead.
### Dependencies
To install Cameradar you will need these packages
* cmake (`cmake`)
* git (`git`)
* gstreamer1.x (`libgstreamer1.0-dev`)
* ffmpeg (`ffmpeg`)
* boost (`libboost-all-dev`)
* libcurl (`libcurl4-openssl-dev`)
### Steps
## Installation
The simplest way would be to follow these steps :
1. `git clone https://github.com/EtixLabs/cameradar.git`
2. Go into the Cameradar repository, create a directory named `build` and go in it
1. `git clone git@github.com:EtixLabs/cameradar.git`
2. Go into the Cameradar repository, create a directory named `build`
3. In the build directory, run `cmake ..` This will generate the Makefiles you need to build Cameradar
4. Run the command `make`
5. This should compile Cameradar. Go into the `cameradar_standalone` directory
6. You can now customize the `conf/cameradar.conf.json` file to set the subnetworks and specific ports you want to scan, as well as the thumbnail generation path. More information will be given about the configuration file in another part of this document.
7. You are now ready to launch Cameradar by launching `./cameradar` in the cameradar_standalone directory.
## Advanced Docker deployment
### Dependencies
The only dependencies are `docker` and `docker-compose`.
### Deploy a custom version of Cameradar
2. Go into the Cameradar repository, create a directory named `build` and go in it
3. In the build directory, run `cmake .. -DCMAKE_BUILD_TYPE=Release` This will generate the Makefiles you need to build Cameradar
4. Run the command `make package` to compile it into a package
5. Copy your package into the `deployment` directory
6. Run `docker-compose build cameradar` to build the cameradar container using your custom package
5. Run `docker-compose up cameradar` to launch Cameradar
### Configuration
Here is the basic content of the configuration file with simple placeholders :
```json
{
"mysql_db" : {
"host" : "MYSQL_SERVER_IP_ADDRESS",
"port" : MYSQL_SERVER_PORT,
"user": "root",
"password": "root",
"db_name": "cmrdr"
},
"subnets" : "SUBNET1,SUBNET2,SUBNET3,[...]",
"ports" : "PORT1,PORT2,[...]",
"rtsp_url_file" : "conf/url.json",
@@ -128,8 +60,7 @@ The subnetworks should be passed separated by commas only, and their subnet form
"subnets" : "172.100.16.0/24,172.100.17.0/24,localhost,192.168.1.13"
```
The **RTSP ports for most cameras are 554**, so you should probably specify 554 as one of the ports you scan. Not giving any ports in the configuration will scan every port of every host found on the subnetworks.
The **RTSP ports for most cameras are 554**, so you should probably specify 554 as one of the ports you scan. Not giving any ports in the configuration will scan every port of every host found on the subnetworks..How is formatted Cameradar's result
You **can use your own files for the ids and routes dictionaries** used to bruteforce the cameras, but the Cameradar repo already gives you a good base that works with most cameras.
The thumbnail storage path should be a **valid and accessible directory** in which the thumbnails will be stored.
@@ -138,6 +69,8 @@ The cache manager path and name variables are used to change the cache manager y
## Output
Here you go :
```json
{
"address" : "173.16.100.45",
@@ -219,8 +152,7 @@ If you have other cool ideas, feel free to share them with me at brendan.leglaun
## Next improvements
- [x] Add a docker deployment to avoid the current deps hell
- [x] Development of a MySQL cache manager
- [ ] Development of a MySQL cache manager
- [ ] Development of a JSON file cache manager
- [ ] Development of an XML file cache manager
+2 -3
View File
@@ -16,9 +16,8 @@ cmake_minimum_required (VERSION 2.8.1)
cmake_policy(SET CMP0042 NEW)
# set temporarly the ouput path for all server plugins
set (LIBRARY_OUTPUT_PATH ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH})
set (LIBRARY_OUTPUT_PATH ${CCTV_CAMERA_MANAGER_OUTPUT_PATH})
add_subdirectory(dumb_cache_manager)
add_subdirectory(mysql_cache_manager)
set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
set (CCTV_CACHE_MANAGERS ${CCTV_CACHE_MANAGERS} PARENT_SCOPE)
@@ -20,6 +20,7 @@ project(dumb_cache_manager CXX)
find_package(PkgConfig)
include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES})
message("${CAMERADAR_INCLUDES}")
include (find_sources)
find_sources ("src" "include")
@@ -28,6 +29,6 @@ add_library (dumb_cache_manager SHARED ${SOURCES})
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
target_link_libraries (dumb_cache_manager)
set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}dumb_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX})
set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}dumb_cache_manager{CMAKE_SHARED_LIBRARY_SUFFIX})
list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME})
set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
@@ -14,11 +14,11 @@
#pragma once
#include <vector>
#include <cachemanager.h>
#include <stream_model.h>
#include <configuration.h>
#include <logger.h>
#include <stream_model.h>
#include <vector>
namespace etix {
namespace cameradar {
@@ -42,9 +42,9 @@ public:
void update_stream(const etix::cameradar::stream_model& newmodel);
std::vector<etix::cameradar::stream_model> get_streams();
std::vector<etix::cameradar::stream_model> get_streams() const;
std::vector<etix::cameradar::stream_model> get_valid_streams();
std::vector<etix::cameradar::stream_model> get_valid_streams() const;
};
}
}
@@ -53,32 +53,29 @@ dumb_cache_manager::set_streams(std::vector<etix::cameradar::stream_model> model
//! Inserts a single stream to the cache
void
dumb_cache_manager::update_stream(const etix::cameradar::stream_model& newmodel) {
for (auto& stream : this->streams) {
if (stream.address == newmodel.address && stream.port == newmodel.port) {
stream = newmodel;
}
for (auto& it : this->streams) {
if (it.address == newmodel.address && it.port == newmodel.port) { it = newmodel; }
}
}
//! Gets all cached streams
std::vector<etix::cameradar::stream_model>
dumb_cache_manager::get_streams() {
dumb_cache_manager::get_streams() const {
std::vector<stream_model> ret;
for (const auto& stream : this->streams) {
if (not stream.service_name.compare("rtsp") && not stream.state.compare("open"))
ret.push_back(stream);
for (const auto& it : this->streams) {
if (not it.service_name.compare("rtsp") && not it.state.compare("open")) ret.push_back(it);
}
return ret;
}
//! Gets all valid streams
std::vector<etix::cameradar::stream_model>
dumb_cache_manager::get_valid_streams() {
dumb_cache_manager::get_valid_streams() const {
std::vector<stream_model> ret;
for (const auto& stream : this->streams) {
if ((not stream.service_name.compare("rtsp") && not stream.state.compare("open")) &&
stream.ids_found && stream.path_found)
ret.push_back(stream);
for (const auto& it : this->streams) {
if ((not it.service_name.compare("rtsp") && not it.state.compare("open")) && it.ids_found &&
it.path_found)
ret.push_back(it);
}
return ret;
}
@@ -1,33 +0,0 @@
## Copyright 2016 Etix Labs
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
cmake_minimum_required (VERSION 2.8.1)
cmake_policy(SET CMP0042 NEW)
project(mysql_cache_manager CXX)
find_package(PkgConfig)
include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES})
include (find_sources)
find_sources ("src" "include")
add_library (mysql_cache_manager SHARED ${SOURCES})
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
target_link_libraries (mysql_cache_manager jsoncpp mysqlcppconn pthread)
set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}mysql_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX})
list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME})
set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
@@ -1,85 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cppconn/resultset.h> // for ResultSet
#include <mutex> // for mutex
#include <stdbool.h> // for bool, false
#include <string> // for string
#include <utility> // for pair, make_pair
#include "query_result.h"
namespace sql {
class Connection;
class Driver;
class ResultSet;
}
namespace etix {
namespace cameradar {
namespace mysql {
//! MySQL Database connection handling
//! Abstracts all connection to the database
class db_connection {
private:
static const std::string create_database_query;
//! SQL driver
sql::Driver* driver = nullptr;
//! SQL connection
sql::Connection* connection = nullptr;
std::mutex access_mtx;
bool connected = false;
std::string db_name;
//! Create the database if it doesn't exist at connector launch
empty_result create_database(void);
public:
db_connection(void);
~db_connection(void);
//! Try to connect to the database
std::pair<bool, std::string> connect(const std::string& host,
const std::string& user,
const std::string& pass,
const std::string& db_name,
bool create_db_if_not_exist = true);
//! Execute a MySQL command
empty_result execute(const std::string& request);
//! Execute a query
query_result<sql::ResultSet*> query(const std::string& query);
bool is_connected();
//! Return db_name
const std::string&
get_db_name(void) const {
return this->db_name;
}
};
} // mysql
} // cameradar
} // etix
@@ -1,81 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cachemanager.h>
#include <configuration.h>
#include <db_conn.h>
#include <fmt.h>
#include <logger.h>
#include <stream_model.h>
#include <vector>
namespace etix {
namespace cameradar {
struct mysql_configuration {
unsigned int port;
std::string host;
std::string db_name;
std::string user;
std::string password;
mysql_configuration() = default;
mysql_configuration(unsigned int port,
const std::string& host,
const std::string& db_name,
const std::string& user = "",
const std::string& password = "")
: port(port), host(host), db_name(db_name), user(user), password(password) {}
};
class mysql_cache_manager : public cache_manager_base {
private:
static const std::string name;
std::vector<etix::cameradar::stream_model> streams;
std::shared_ptr<etix::cameradar::configuration> configuration;
etix::cameradar::mysql_configuration db_conf;
etix::cameradar::mysql::db_connection connection;
static const std::string create_table_query;
static const std::string insert_with_id_query;
static const std::string exist_query;
static const std::string get_results_query;
static const std::string update_result_query;
public:
using cache_manager_base::cache_manager_base;
~mysql_cache_manager();
// Specific to MySQL
bool execute_query(const std::string& query);
const std::string& get_name() const override;
static const std::string& static_get_name();
bool load_mysql_conf(std::shared_ptr<etix::cameradar::configuration> configuration);
bool configure(std::shared_ptr<etix::cameradar::configuration> configuration) override;
void set_streams(std::vector<etix::cameradar::stream_model> model);
void update_stream(const etix::cameradar::stream_model& newmodel);
std::vector<etix::cameradar::stream_model> get_streams();
std::vector<etix::cameradar::stream_model> get_valid_streams();
};
}
}
@@ -1,65 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
namespace etix {
namespace cameradar {
namespace mysql {
enum class execute_result { success, not_found, no_row_updated, sql_error, error };
//! Wrapper of a DB query result
//! Templated on the data type we want to return (list<model>, bool, whatever)
template <typename DataType>
struct query_result {
DataType data;
execute_result state;
std::string error_msg;
inline bool
success(void) const {
return state == execute_result::success;
}
inline bool
error(void) const {
return not success();
}
};
//! Empty query result for when we just want to return the status
//! of the request with no associated data
template <>
struct query_result<void> {
execute_result state;
std::string error_msg;
inline bool
success(void) const {
return state == execute_result::success;
}
inline bool
error(void) const {
return not success();
}
};
typedef query_result<void> empty_result;
} //! mysql
} //! cameradar
} //! etix
@@ -1,139 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "db_conn.h" // for db_connection
#include "cppconn/connection.h" // for Connection
#include "query_result.h" // for queries
#include <cppconn/driver.h> // for get_driver_instance, etc
#include <cppconn/exception.h> // for SQLException
#include <cppconn/statement.h> // for Statement
#include <fmt.h> // for fmt
#include <logger.h> // for LOG_
namespace etix {
namespace cameradar {
namespace mysql {
const std::string db_connection::create_database_query = "CREATE DATABASE IF NOT EXISTS %s";
db_connection::db_connection() : connected(false) {}
db_connection::~db_connection() { delete this->connection; }
std::pair<bool, std::string>
db_connection::connect(const std::string& host,
const std::string& user,
const std::string& pass,
const std::string& db_name,
bool create_db_if_not_exist) {
this->db_name = db_name;
try {
this->driver = get_driver_instance();
if (this->driver == nullptr) {
return std::make_pair(false, "Cannot instantiate sql_driver");
}
this->connection = driver->connect(host, user, pass);
if (this->connection == nullptr) return std::make_pair(false, "Cannot connect to mysql");
this->connected = true;
if (create_db_if_not_exist) {
auto cdb = this->create_database();
if (cdb.state == mysql::execute_result::sql_error) { return { false, cdb.error_msg }; }
this->connection->setSchema(db_name);
}
} catch (sql::SQLException& e) {
this->connected = false;
return { false, e.what() };
}
return std::make_pair(true, "");
}
empty_result
db_connection::execute(const std::string& request) {
std::lock_guard<std::mutex> lock(this->access_mtx);
sql::Statement* stmt = nullptr;
empty_result return_value = { execute_result::success, "" };
if (!this->is_connected()) {
return { execute_result::sql_error, "Error, not connected to MySQL database" };
}
try {
stmt = this->connection->createStatement();
stmt->execute(request);
if (stmt->getUpdateCount() == 0) {
return_value = { execute_result::no_row_updated, "No row updated" };
}
} catch (sql::SQLException& e) { return_value = { execute_result::sql_error, e.what() }; }
if (stmt) { delete stmt; }
return return_value;
}
query_result<sql::ResultSet*>
db_connection::query(const std::string& query) {
std::lock_guard<std::mutex> lock(this->access_mtx);
sql::Statement* stmt = nullptr;
query_result<sql::ResultSet*> return_value = { nullptr, execute_result::success, "" };
if (!this->is_connected()) {
return { nullptr, execute_result::sql_error, "Error, not connected to MySQL database" };
}
try {
stmt = this->connection->createStatement();
return_value = { stmt->executeQuery(query), execute_result::success, "" };
} catch (sql::SQLException& e) {
return_value = { nullptr, execute_result::sql_error, e.what() };
}
if (stmt) { delete stmt; }
return return_value;
}
bool
db_connection::is_connected() {
if (this->connection == nullptr) return false;
// check if our connection is always valid
if (this->connection->isClosed() || not this->connection->isValid()) {
LOG_INFO_("MySQL database connection is either closed or invalid, try to reconnect.",
"db_connection");
this->connection->reconnect();
if (this->connection->isClosed() || not this->connection->isValid()) {
this->connected = false;
LOG_ERR_("Unable to reconnect to MySQL.", "db_connection");
}
}
return this->connected;
}
empty_result
db_connection::create_database() {
auto query = tool::fmt(this->create_database_query, this->db_name.c_str());
return this->execute(query);
}
} // mysql
} // cameradar
} // etix
@@ -1,274 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <mysql_cache_manager.h>
/* DATA FORMAT
**
** Example :
**
** "address" : "173.16.100.45",
** "ids_found" : true,
** "password" : "123456",
** "path_found" : true,
** "port" : 554,
** "product" : "Vivotek FD9381-HTV",
** "protocol" : "tcp",
** "route" : "/live.sdp",
** "service_name" : "rtsp",
** "state" : "open",
** "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg",
** "username" : "admin"
**
*/
namespace etix {
namespace cameradar {
const std::string mysql_cache_manager::create_table_query =
"CREATE TABLE IF NOT EXISTS `results` ("
"`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, "
"`address` tinytext NOT NULL, "
"`password` tinytext NOT NULL, "
"`product` tinytext NOT NULL, "
"`protocol` tinytext NOT NULL, "
"`route` tinytext NOT NULL, "
"`service_name` tinytext NOT NULL, "
"`state` tinytext NOT NULL, "
"`thumbnail_path` tinytext NOT NULL, "
"`username` tinytext NOT NULL, "
"`port` int(11) UNSIGNED NOT NULL, "
"`ids_found` tinytext NOT NULL, "
"`path_found` tinytext NOT NULL, "
"PRIMARY KEY (`id`));";
const std::string mysql_cache_manager::insert_with_id_query =
"INSERT INTO `%s`.`results`"
" (`address`, `password`, `product`, `protocol`, `route`, `service_name`, `state`, "
"`thumbnail_path`, `username`, `port`, `ids_found`, `path_found`)"
" VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')";
const std::string mysql_cache_manager::update_result_query =
"UPDATE `%s`.`results` SET"
" `results`.`address` = '%s',"
" `results`.`password` = '%s',"
" `results`.`product` = '%s',"
" `results`.`protocol` = '%s',"
" `results`.`route` = '%s',"
" `results`.`service_name` = '%s',"
" `results`.`state` = '%s',"
" `results`.`thumbnail_path` = '%s',"
" `results`.`username` = '%s',"
" `results`.`port` = '%s',"
" `results`.`ids_found` = '%s',"
" `results`.`path_found` = '%s'"
" WHERE `results`.`address` LIKE '%s'";
const std::string mysql_cache_manager::exist_query =
"SELECT * FROM `%s`.`results` WHERE `results`.`address` = '%s'";
const std::string mysql_cache_manager::get_results_query = "SELECT * FROM `%s`.`results`";
const std::string mysql_cache_manager::name = "mysql-cache-manager";
mysql_cache_manager::~mysql_cache_manager() {}
const std::string&
mysql_cache_manager::get_name() const {
return mysql_cache_manager::static_get_name();
}
const std::string&
mysql_cache_manager::static_get_name() {
return mysql_cache_manager::name;
}
bool
mysql_cache_manager::configure(std::shared_ptr<etix::cameradar::configuration> configuration) {
return this->load_mysql_conf(configuration);
}
bool
mysql_cache_manager::execute_query(const std::string& query) {
auto check_err = [](const auto& res) {
if (res.state == mysql::execute_result::sql_error) {
LOG_WARN_(res.error_msg, "mysql_cache_manager");
return false;
}
return true;
};
return check_err(this->connection.execute(query));
}
bool
mysql_cache_manager::load_mysql_conf(
std::shared_ptr<etix::cameradar::configuration> configuration) {
this->configuration = configuration;
try {
this->db_conf.host = configuration->raw_conf["mysql_db"]["host"].asString();
this->db_conf.port = configuration->raw_conf["mysql_db"]["port"].asUInt();
this->db_conf.user = configuration->raw_conf["mysql_db"]["user"].asString();
this->db_conf.password = configuration->raw_conf["mysql_db"]["password"].asString();
this->db_conf.db_name = configuration->raw_conf["mysql_db"]["db_name"].asString();
} catch (std::exception& e) {
LOG_ERR_("Configuration of the MySQL db failed : " + std::string(e.what()),
"mysql_cache_manager");
return false;
}
if (not this->connection
.connect(db_conf.host + ":" + std::to_string(db_conf.port),
db_conf.user,
db_conf.password,
db_conf.db_name)
.first) {
LOG_ERR_("Configuration of the MySQL DB failed", "mysql_cache_manager");
return false;
}
// Tries to create the Result table in the DB and returns the success state
return (execute_query(create_table_query));
}
//! Replaces all cached streams by the content of the vector given as
//! parameter
void
mysql_cache_manager::set_streams(std::vector<etix::cameradar::stream_model> models) {
LOG_DEBUG_("Beginning stream list DB insertion", "mysql_cache_manager");
for (const auto& model : models) {
if (!model.service_name.compare("rtsp") && !model.state.compare("open")) {
auto query = tool::fmt(
this->exist_query, this->connection.get_db_name().c_str(), model.address.c_str());
auto result = this->connection.query(query);
// If an entry already exists for this address in the database,
// no need to insert it.
// TODO : Update an entry if it already exists.
if (result.data->next()) return;
query = tool::fmt(this->insert_with_id_query,
this->connection.get_db_name().c_str(),
model.address.c_str(),
model.password.c_str(),
model.product.c_str(),
model.protocol.c_str(),
model.route.c_str(),
model.service_name.c_str(),
model.state.c_str(),
model.thumbnail_path.c_str(),
model.username.c_str(),
std::to_string(model.port).c_str(),
std::to_string(model.ids_found).c_str(),
std::to_string(model.path_found).c_str());
execute_query(query);
}
}
}
//! Inserts a single stream to the cache
void
mysql_cache_manager::update_stream(const etix::cameradar::stream_model& model) {
auto query = tool::fmt(this->update_result_query,
this->connection.get_db_name().c_str(),
model.address.c_str(),
model.password.c_str(),
model.product.c_str(),
model.protocol.c_str(),
model.route.c_str(),
model.service_name.c_str(),
model.state.c_str(),
model.thumbnail_path.c_str(),
model.username.c_str(),
std::to_string(model.port).c_str(),
std::to_string(model.ids_found).c_str(),
std::to_string(model.path_found).c_str(),
model.address.c_str());
execute_query(query);
}
//! Gets all cached streams
std::vector<etix::cameradar::stream_model>
mysql_cache_manager::get_streams() {
auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str());
auto result = this->connection.query(query);
if (not result.data) {
delete result.data;
return {};
}
std::vector<stream_model> lst;
while (result.data->next()) {
// If it's an open RTSP stream
if (not result.data->getString("state").compare("open") &&
not result.data->getString("service_name").compare("rtsp")) {
stream_model s{
result.data->getString("address"), result.data->getUInt("port"),
result.data->getString("username"), result.data->getString("password"),
result.data->getString("route"), result.data->getString("service_name"),
result.data->getString("product"), result.data->getString("protocol"),
result.data->getString("state"), result.data->getBoolean("ids_found"),
result.data->getBoolean("path_found"), result.data->getString("thumbnail_path")
};
lst.push_back(s);
}
}
delete result.data;
return lst;
}
//! Gets all valid streams
std::vector<etix::cameradar::stream_model>
mysql_cache_manager::get_valid_streams() {
auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str());
auto result = this->connection.query(query);
if (not result.data) {
delete result.data;
return {};
}
std::vector<stream_model> lst;
while (result.data->next()) {
// If the ID and the Path were found add this stream
if (not result.data->getString("ids_found").compare("1") &&
not result.data->getString("path_found").compare("1")) {
stream_model s{
result.data->getString("address"), result.data->getUInt("port"),
result.data->getString("username"), result.data->getString("password"),
result.data->getString("route"), result.data->getString("service_name"),
result.data->getString("product"), result.data->getString("protocol"),
result.data->getString("state"), result.data->getBoolean("ids_found"),
result.data->getBoolean("path_found"), result.data->getString("thumbnail_path")
};
lst.push_back(s);
}
}
delete result.data;
return lst;
}
extern "C" {
cache_manager_iface*
cache_manager_instance_new() {
return new mysql_cache_manager();
}
}
}
}
+4 -9
View File
@@ -13,7 +13,7 @@
## limitations under the License.
cmake_minimum_required (VERSION 2.8.1)
cmake_policy(SET CMP0048 OLD)
cmake_policy(SET CMP0042 NEW)
project(cameradar CXX)
@@ -23,15 +23,11 @@ include(FindPkgConfig)
pkg_search_module(GSTREAMER REQUIRED gstreamer-1.0)
find_library(LIB_GSTREAMER NAMES ${GSTREAMER_LIBRARIES} HINTS ${GSTREAMER_LIBRARY_DIRS})
include_directories (
${GSTREAMER_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/include
${VERSION_INCLUDE_DIR}
)
include_directories (${GSTREAMER_INCLUDE_DIRS})
link_directories (
${GSTREAMER_LIBRARY_DIRS}
"../deps/jsoncpp/src/deps.jsoncpp/src/lib_json"
"../../cctv_server2/deps/jsoncpp/src/deps.jsoncpp/src/lib_json"
)
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
@@ -56,5 +52,4 @@ add_custom_command(TARGET cameradar PRE_BUILD
${CMAKE_SOURCE_DIR}/cameradar_standalone/conf $<TARGET_FILE_DIR:cameradar>/conf/)
set (BINARIES_NAME ${PROJECT_BINARY_DIR}/cameradar)
list (APPEND CAMERADAR_BINARIES ${BINARIES_NAME})
set (CAMERADAR_BINARIES ${CAMERADAR_BINARIES} PARENT_SCOPE)
list (APPEND CCTV_BINARIES ${BINARIES_NAME})
+2 -13
View File
@@ -1,13 +1,5 @@
{
"mysql_db" : {
"host" : "0.0.0.0",
"port" : 3306,
"user": "root",
"password": "root",
"db_name": "cctv_dev"
},
"subnets" : "172.16.100.11",
"subnets" : "172.16.100.13,localhost",
// If not specified, will scan all ports (1-65535)
"ports" : "554,8554",
@@ -17,9 +9,6 @@
// You must give an accessible path to an already existing directory
"thumbnail_storage_path" : "/tmp",
// This is the path that will be used in the Docker container
// if you're not familiar with Docker, only change the
// cache_manager_name value
"cache_manager_path" : "../cache_managers",
"cache_manager_path" : "../cache_managers/dumb_cache_manager",
"cache_manager_name" : "dumb"
}
+6 -6
View File
@@ -14,10 +14,10 @@
#pragma once
#include <configuration.h>
#include <vector>
#include <memory>
#include <stream_model.h>
#include <vector>
#include <configuration.h>
namespace etix {
namespace cameradar {
@@ -42,10 +42,10 @@ public:
virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0;
//! Gets all cached streams
virtual std::vector<etix::cameradar::stream_model> get_streams() = 0;
virtual std::vector<etix::cameradar::stream_model> get_streams() const = 0;
//! Gets all valid streams which have been accessed
virtual std::vector<etix::cameradar::stream_model> get_valid_streams() = 0;
virtual std::vector<etix::cameradar::stream_model> get_valid_streams() const = 0;
};
class cache_manager_base : public cache_manager_iface {
@@ -68,10 +68,10 @@ public:
virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0;
//! Gets all cached streams
virtual std::vector<etix::cameradar::stream_model> get_streams() = 0;
virtual std::vector<etix::cameradar::stream_model> get_streams() const = 0;
//! Gets all valid streams which have been accessed
virtual std::vector<etix::cameradar::stream_model> get_valid_streams() = 0;
virtual std::vector<etix::cameradar::stream_model> get_valid_streams() const = 0;
//! Get the manager's instance
cache_manager_base& get_instance();
+1 -1
View File
@@ -64,7 +64,7 @@ public:
const std::pair<bool, etix::tool::opt_parse>& opts)
: busy(false)
, current(task::init)
, nmap_output("/tmp/scans/scan" + std::to_string(std::chrono::system_clock::to_time_t(
, nmap_output("scans/scan" + std::to_string(std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now())) +
".xml")
, conf(conf)
@@ -14,15 +14,11 @@
#pragma once
#include <assert.h> // assert
#include <csignal> // sigint
#include <iostream> // stc::cout
// To avoid an unused warning for the asserted in handle_signal
#define _unused(x) ((void)(x))
#include <assert.h> // assert
namespace etix {
namespace cameradar {
enum class stop_priority { running, stop, force_stop };
@@ -34,7 +30,6 @@ public:
virtual int
handle_signal(int signum) {
assert(signum == SIGINT);
_unused(signum);
std::cout << "\b\b\b\033[K";
if (this->ss == stop_priority::running)
this->ss = stop_priority::stop;
+2 -2
View File
@@ -14,8 +14,8 @@
#pragma once
#include <json/value.h>
#include <string>
#include <json/value.h>
namespace etix {
namespace cameradar {
@@ -24,7 +24,7 @@ struct stream_model {
// Ex : "172.16.100.113"
std::string address;
// Ex : 8554
unsigned int port;
unsigned short port;
// Ex : "admin"
std::string username = "";
// Ex : "123456"
+6 -5
View File
@@ -14,11 +14,12 @@
#pragma once
#include <cachemanager.h> // cacheManager
#include <cameradar_task.h> // task interface
#include <fstream> // std::ofstream
#include <iostream> // std::ofstream
#include <stream_model.h> // data model
#include <cameradar_task.h> // task interface
#include <boost/algorithm/string/find.hpp> // boost::find
#include <iostream> // std::ofstream
#include <fstream> // std::ofstream
#include <stream_model.h> // data model
#include <cachemanager.h> // cacheManager
namespace etix {
namespace cameradar {
+13 -4
View File
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <configuration.h> // configuration
#include <fstream> // std::ifstream
#include <unistd.h> // access, F_OK
#include <configuration.h> // configuration
namespace etix {
@@ -22,9 +22,9 @@ namespace cameradar {
const std::string configuration::name_ = "configuration";
// Read a file at the path "path"
// If the file is available we return the whole content as
// an std::string inside a pair
// read a file at the path "path"
// if the file is available we return the whole content as an std::string inside
// a pair
// otherwise return false and an empty string inside a pair
std::pair<bool, std::string>
read_file(const std::string& path) {
@@ -107,6 +107,14 @@ configuration::load_url() {
auto root = Json::Value();
auto reader = Json::Reader();
reader.parse(content, root);
// auto result = tool::json::check_fields(
// {{"urls", Json::arrayValue, root["urls"]}}, "general
// configuration");
// if (not result.first) {
// LOG_ERR_(result.second, "general configuration");
// return false;
// }
for (unsigned int i = 0; i < root["urls"].size(); i++) {
if (not root["urls"][i].isString()) {
@@ -186,6 +194,7 @@ load(const std::string& path) {
}
// Deserialize the json to a configuration struct
// and return
// REPLACE THIS WITH JSONCPP
std::pair<bool, configuration> conf = serialize(root);
conf.second.raw_conf = root;
conf.first &= conf.second.load_url();
+3 -6
View File
@@ -71,15 +71,12 @@ curl_describe(const std::string& path, bool logs) {
curl_easy_cleanup(csession);
fclose(protofile);
curl_global_cleanup();
LOG_DEBUG_("Response code : " + std::to_string(rc), "describe");
if (logs) {
// Some cameras return 400 instead of 401, don't know why.
// Some cameras timeout and then curl considers the status as 0
if (rc != 401 && rc != 400 && rc && pos == std::string::npos)
if (rc != 401 && pos == std::string::npos)
LOG_INFO_("Unprotected camera discovered.", "brutelogs");
return ((res == CURLE_OK) && rc != 401 && rc != 400 && rc);
return ((res == CURLE_OK) && rc != 401);
}
return ((res == CURLE_OK) && rc != 404 && rc != 400 && rc);
return ((res == CURLE_OK) && rc != 404);
}
}
}
+4 -13
View File
@@ -20,20 +20,12 @@ namespace cameradar {
// The main loop of the binary
void
dispatcher::run() {
if (not(*cache)->configure(std::make_shared<configuration>(conf))) {
LOG_ERR_(
"There was a problem with the cache manager, Cameradar can't work properly without "
"cache management",
"dispatcher");
return;
}
std::thread worker(&dispatcher::do_stuff, this);
using namespace std::chrono_literals;
// Catch CTRL+C signal
// catch CTRL+C signal
signal_handler::instance();
// Wait for event or end
// wait for event or end
while (signal_handler::instance().should_stop() not_eq stop_priority::stop &&
current != task::finished) {
std::this_thread::sleep_for(30ms);
@@ -44,7 +36,7 @@ dispatcher::run() {
LOG_INFO_("Press CTRL+C again to force stop", "dispatcher");
}
// Waiting for task to cleanup / force stop command
// waiting for task to cleanup / force stop command
while ((signal_handler::instance().should_stop() not_eq stop_priority::force_stop) and
doing_stuff()) {
std::this_thread::sleep_for(std::chrono::milliseconds(30));
@@ -84,8 +76,7 @@ dispatcher::do_stuff() {
if (queue.front()->run())
queue.pop_front();
else {
LOG_ERR_("An error occured in one of the tasks, Cameradar will now stop.",
"dispatcher");
LOG_ERR_("An error occured in one of the tasks, Cameradar will now stop.", "dispatcher");
break;
}
}
+2 -12
View File
@@ -12,21 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "version.h" // versionning
#include <dispatcher.h> // program loop
#include <fs.h> // fs::home
#include <iostream> // iostream
#include <opt_parse.h> // parsing opt
#include <dispatcher.h> // program loop
namespace cmrdr = etix::cameradar;
void
print_version() {
std::cout << "Cameradar version " << CAMERADAR_VERSION << std::endl;
std::cout << "Build " << CAMERADAR_VERSION_BUILD << std::endl;
std::cout << "Git commit " << CAMERADAR_VERSION_GIT_SHA1 << std::endl;
}
// Command line parsing
std::pair<bool, etix::tool::opt_parse>
parse_cmdline(int argc, char* argv[]) {
@@ -46,7 +37,7 @@ parse_cmdline(int argc, char* argv[]) {
opt_parse.print_help();
return std::make_pair(false, opt_parse);
} else if (opt_parse.exist("-v")) {
print_version();
std::cout << "Cameradar 0.1" << std::endl;
return std::make_pair(false, opt_parse);
} else if (opt_parse.has_error()) {
std::cout << "Usage: ./cameradar [option]\n\toptions:\n" << std::endl;
@@ -85,7 +76,6 @@ main(int argc, char* argv[]) {
auto args = parse_cmdline(argc, argv);
if (not args.first) return EXIT_FAILURE;
print_version();
// configure file configuration path
auto conf_path = std::string{};
if (not args.second.exist("-c")) {
+15 -16
View File
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cachemanager.h>
#include <tasks/brutelogs.h>
#include <cachemanager.h>
namespace etix {
namespace cameradar {
@@ -36,26 +36,26 @@ brutelogs::test_ids(const etix::cameradar::stream_model& stream,
std::string path = stream.service_name + "://";
if (username != "" || password != "") { path += username + ":" + password + "@"; }
path += stream.address + ":" + std::to_string(stream.port);
LOG_DEBUG_("Testing ids : " + path, "brutelogs");
LOG_DEBUG_("Testing ids : " + path, "bruteforce");
try {
if (curl_describe(path, true)) {
LOG_DEBUG_("[FOUND IDS] : " + path, "brutelogs");
LOG_DEBUG_("[FOUND IDS] : " + path, "bruteforce");
found = true;
stream_model newstream{
stream.address, stream.port, username, password,
stream.route, stream.service_name, stream.product, stream.protocol,
stream.state, true, stream.path_found, stream.thumbnail_path
stream.address, stream.port, username, password,
stream.route, stream.service_name, stream.product, stream.protocol,
stream.state, stream.path_found, true, stream.thumbnail_path
};
(*cache)->update_stream(newstream);
} else {
stream_model newstream{ stream.address, stream.port, username,
password, stream.route, stream.service_name,
stream.product, stream.protocol, stream.state,
false, stream.path_found, stream.thumbnail_path };
stream_model newstream{ stream.address, stream.port, username,
password, stream.route, stream.service_name,
stream.product, stream.protocol, stream.state,
stream.path_found, false, stream.thumbnail_path };
(*cache)->update_stream(newstream);
}
} catch (const std::runtime_error& e) {
LOG_DEBUG_("Ids already tested : " + std::string(e.what()), "brutelogs");
LOG_DEBUG_("Ids already tested : " + std::string(e.what()), "bruteforce");
}
return found;
}
@@ -75,9 +75,8 @@ brutelogs::run() const {
LOG_INFO_(
"Beginning bruteforce of the usernames and passwords task, it may "
"take a while.",
"brutelogs");
"bruteforce");
std::vector<etix::cameradar::stream_model> streams = (*cache)->get_streams();
LOG_DEBUG_("Found " + std::to_string(streams.size()) + " streams in the cache", "brutelogs");
bool doubleskip;
size_t found = 0;
for (const auto& stream : streams) {
@@ -89,7 +88,7 @@ brutelogs::run() const {
" : This camera's ids were already discovered in "
"the database. Skipping to "
"the next camera.",
"brutelogs");
"bruteforce");
++found;
} else {
for (const auto& username : conf.usernames) {
@@ -111,12 +110,12 @@ brutelogs::run() const {
}
}
if (!found) {
LOG_WARN_(no_ids_warning_, "brutelogs");
LOG_WARN_(no_ids_warning_, "bruteforce");
return false;
} else
LOG_INFO_("Found " + std::to_string(found) + " ids for " + std::to_string(streams.size()) +
" cameras",
"brutelogs");
"bruteforce");
return true;
}
}
+3 -4
View File
@@ -28,9 +28,9 @@ namespace cameradar {
//! problem.
bool
nmap_is_ok() {
return (
(system("dpkg -l | cut -c 5-9 | grep nmap") == 0)
&& launch_command("mkdir -p /tmp/scans")); // Creates the directory in which the scans will be stored
return (launch_command("test `dpkg -l | cut -c 5-9 | grep nmap` = nmap")
// && launch_command("test `nmap --version | cut -c 14-18 | head -n2 | tail -n1` = 6.47")
&& launch_command("mkdir -p scans")); // Creates the directory in which the scans will be stored
}
//! Launches and checks the return of the nmap command
@@ -44,7 +44,6 @@ mapping::run() const {
LOG_INFO_("Beginning mapping task. This may take a while.", "mapping");
std::string cmd =
"nmap -T4 -A " + subnets + " -p " + this->conf.ports + " -oX " + nmap_output;
LOG_DEBUG_("Launching nmap : " + cmd, "mapping");
bool ret = launch_command(cmd);
if (ret)
LOG_INFO_("Nmap XML output successfully generated in file: " + nmap_output, "mapping");
+4 -4
View File
@@ -27,9 +27,9 @@ static const std::string no_hosts_found_ =
//! Avoids segfaults on unknown xml structure
std::string
xml_safe_get(const TiXmlElement* elem, const std::string& attr) {
if (elem == nullptr) return "closed";
if (elem == nullptr) return "Closed";
if (elem->Attribute(attr.c_str()) != nullptr) return std::string(elem->Attribute(attr.c_str()));
return "closed";
return "Closed";
}
//! Parse a single host node (generally containing only one camera)
@@ -51,8 +51,8 @@ parsing::parse_camera(TiXmlElement* xml_host, std::vector<stream_model>& data) c
stream.service_name = xml_safe_get(service, "name");
stream.product = xml_safe_get(service, "product");
} else {
stream.service_name = "closed";
stream.product = "closed";
stream.service_name = "Closed";
stream.product = "Closed";
}
data.push_back(stream);
}
@@ -29,25 +29,18 @@ stream_check::run() const {
std::vector<stream_model> streams = (*cache)->get_valid_streams();
if (not streams.size()) {
LOG_WARN_("There were no valid streams to check. Cameradar will stop.", "stream_check");
return false;
}
for (const auto& stream : streams) {
GError* error = NULL;
pipeline =
gst_parse_launch("rtspsrc name=source ! rtph264depay ! h264parse ! fakesink", &error);
std::string location = "rtsp://";
location += stream.username + ":" + stream.password + "@" + stream.address + ":" + std::to_string(stream.port);
if (pipeline == NULL) {
LOG_ERR_("[" + stream.address + "] Can't configure pipeline", "stream_check");
return false;
} else {
elem = gst_bin_get_by_name(GST_BIN(pipeline), "source");
LOG_DEBUG_("Launching gstreamer check on rtsp://" + stream.username + ":" + stream.password + "@" + stream.address + ":" + std::to_string(stream.port), "gstreamer check");
g_object_set(G_OBJECT(elem), "location", location.c_str(), "latency", 20, NULL);
g_object_set(G_OBJECT(elem), "location", stream.address, "latency", 20, NULL);
if (gst_element_set_state(pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
LOG_ERR_(
@@ -48,12 +48,7 @@ bool
thumbnail::run() const {
std::vector<stream_model> streams = (*cache)->get_valid_streams();
LOG_INFO_("Started thumbnail generation, it may take a while", "thumbnail");
if (not streams.size()) {
LOG_WARN_("There were no valid streams to generate thumbnails from. Cameradar will stop.", "thumbnail_generation");
return false;
}
for (const auto& stream : streams) {
LOG_DEBUG_("Generating thumbnail for " + stream.address, "thumbnail_generation");
if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running)
break;
std::string ffmpeg_cmd =
+91
View File
@@ -0,0 +1,91 @@
## Copyright 2016 Etix Labs
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
message(STATUS "Configuring deps.boost")
set(BOOST_VERSION 1.60.0)
# set(BoostSHA1 2fc96c1651ac6fe9859b678b165bd78dc211e881)
# Set up general b2 (bjam) command line arguments
set(b2Args <SOURCE_DIR>/b2
# link=static
threading=multi
runtime-link=shared
--layout=tagged
--build-dir=build
--without-wave
--without-python
stage
-d+2
)
if(TARGET_ARCH STREQUAL "x86_64")
list(APPEND b2Args address-model=64)
endif()
string(REPLACE "." "_" BOOST_VERSION_UNDERSCORE ${BOOST_VERSION})
set(BOOST_DIR boost)
set(BOOST_PATH ${DEPS_DIR}/${BOOST_DIR})
# Set up build steps
include(ExternalProject)
ExternalProject_Add(
deps.boost
PREFIX ${BOOST_PATH}
URL http://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION_UNDERSCORE}.tar.bz2/download
TIMEOUT 600
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory <SOURCE_DIR>/build
BUILD_COMMAND "${b2Args}"
# BUILD_COMMAND "<SOURCE_DIR>/b2 address-model=64 threading=multi runtime-link=shared --layout=tagged --build-dir=<SOURCE_DIR>/build"
BUILD_IN_SOURCE ON
INSTALL_COMMAND ""
# INSTALL_COMMAND <SOURCE_DIR>/b2 install --prefix=${BOOST_PATH}
LOG_DOWNLOAD ON
LOG_UPDATE ON
LOG_CONFIGURE ON
LOG_BUILD ON
LOG_TEST ON
LOG_INSTALL ON
)
# Set extra step to build b2 (bjam)
set(b2Bootstrap "./bootstrap.sh")
ExternalProject_Add_Step(
deps.boost
make_b2
COMMAND ${b2Bootstrap}
COMMENT "Building b2..."
DEPENDEES download
DEPENDERS configure
WORKING_DIRECTORY <SOURCE_DIR>
LOG ON
)
ExternalProject_Get_Property(deps.boost SOURCE_DIR)
set(BOOST_INCLUDE_DIR ${SOURCE_DIR} PARENT_SCOPE)
set(BOOST_LIBRARY_DIR "${SOURCE_DIR}/stage/lib")
set(BOOST_LIBRARY_DIR ${BOOST_LIBRARY_DIR} PARENT_SCOPE)
# list all the boost libraries .dylib/.so
file(GLOB BOOST_INSTALL_DEPENDENCIES "${BOOST_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}boost_*${CMAKE_SHARED_LIBRARY_SUFFIX}")
list (APPEND CCTV_INSTALL_DEPENDENCIES ${BOOST_INSTALL_DEPENDENCIES})
# on linux
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
file(GLOB BOOST_INSTALL_DEPENDENCIES "${BOOST_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}boost_*${CMAKE_SHARED_LIBRARY_SUFFIX}.${BOOST_VERSION}")
list (APPEND CCTV_INSTALL_DEPENDENCIES ${BOOST_INSTALL_DEPENDENCIES})
endif()
set(CCTV_INSTALL_DEPENDENCIES ${CCTV_INSTALL_DEPENDENCIES} PARENT_SCOPE)
+2 -2
View File
@@ -43,6 +43,6 @@ set (JSONCPP_LIBRARY_DIR "${SOURCE_DIR}/src/lib_json")
set (JSONCPP_LIBRARY_DIR ${JSONCPP_LIBRARY_DIR} PARENT_SCOPE)
file(GLOB JSONCPP_INSTALL_DEPENDENCIES "${JSONCPP_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}jsoncpp*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
list (APPEND CAMERADAR_INSTALL_DEPENDENCIES ${JSONCPP_INSTALL_DEPENDENCIES})
list (APPEND CCTV_INSTALL_DEPENDENCIES ${JSONCPP_INSTALL_DEPENDENCIES})
set(CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE)
set(CCTV_INSTALL_DEPENDENCIES ${CCTV_INSTALL_DEPENDENCIES} PARENT_SCOPE)
-43
View File
@@ -1,43 +0,0 @@
# Copyright (C) 2015 Etix Labs - All Rights Reserved.
# All information contained herein is, and remains the property of Etix Labs and its suppliers,
# if any. The intellectual and technical concepts contained herein are proprietary to Etix Labs
# Dissemination of this information or reproduction of this material is strictly forbidden unless
# prior written permission is obtained from Etix Labs.
# MySQL Connector dependency
message(STATUS "Configuring deps.mysqlconnector")
set (MYSQL_CONNECTOR_VERSION 1.1.6)
set (MD5 9e49dcfc1408b18b3d3ca02781ff7efb)
set (MYSQL_CONNECTOR_DIR mysql-connector)
set (MYSQL_CONNECTOR_PATH ${DEPS_DIR}/${MYSQL_CONNECTOR_DIR})
set (BOOST_ROOT_DIR ${DEPS_DIR}/boost/src/deps.boost)
# include(ExternalProject)
ExternalProject_Add(
deps.mysql_connector
PREFIX ${MYSQL_CONNECTOR_PATH}
URL http://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-${MYSQL_CONNECTOR_VERSION}.tar.gz
URL_HASH MD5=${MD5}
CONFIGURE_COMMAND ${CMAKE_COMMAND} -DBOOST_ROOT=${BOOST_ROOT_DIR} "-DCMAKE_INSTALL_PREFIX=${MYSQL_CONNECTOR_PATH}" -DBUILD_TYPE=Release -DMYSQL_CXXFLAGS=-fexceptions <SOURCE_DIR>
BUILD_IN_SOURCE ON
UPDATE_COMMAND ""
BUILD_COMMAND ${CMAKE_MAKE_PROGRAM}
INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install
LOG_DOWNLOAD ON
LOG_UPDATE ON
LOG_CONFIGURE ON
LOG_BUILD ON
)
set (MYSQL_CONNECTOR_INCLUDE_DIR "${MYSQL_CONNECTOR_PATH}/include" PARENT_SCOPE)
set (MYSQL_CONNECTOR_LIBRARY_DIR "${MYSQL_CONNECTOR_PATH}/lib")
set (MYSQL_CONNECTOR_LIBRARY_DIR ${MYSQL_CONNECTOR_LIBRARY_DIR} PARENT_SCOPE)
# list all the hiredis libraries
file(GLOB MYSQL_CONNECTOR_INSTALL_DEPENDENCIES "${MYSQL_CONNECTOR_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}mysqlcppconn*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
list (APPEND CAMERADAR_INSTALL_DEPENDENCIES ${MYSQL_CONNECTOR_INSTALL_DEPENDENCIES})
set(CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE)
-24
View File
@@ -1,24 +0,0 @@
FROM ubuntu:16.04
MAINTAINER brendan.leglaunec@etixgroup.com
ENV LD_LIBRARY_PATH="/cameradar/libraries"
RUN apt-get update && apt-get install -y \
nmap \
ffmpeg \
libboost-all-dev \
libgstreamer1.0-dev \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
libcurl4-openssl-dev \
libmysqlclient20 \
mysql-client
ADD cameradar_*_Release_Linux.tar.gz /
RUN mv cameradar_*_Release_Linux cameradar
RUN mkdir /conf
ADD run.sh /run.sh
CMD ["/run.sh"]
Binary file not shown.
-25
View File
@@ -1,25 +0,0 @@
{
"mysql_db" : {
"host" : "__MYSQL_ADDR__",
"port" : __MYSQL_PORT__,
"user": "root",
"password": "root",
"db_name": "cmrdr"
},
"subnets" : "localhost",
// If not specified, will scan all ports (1-65535)
"ports" : "554,8554",
"rtsp_url_file" : "conf/url.json",
"rtsp_ids_file" : "conf/ids.json",
// You must give an accessible path to an already existing directory
"thumbnail_storage_path" : "/tmp",
// This is the path that will be used in the Docker container
// if you're not familiar with Docker, only change the
// cache_manager_name value
"cache_manager_path" : "/cameradar/cache_managers",
"cache_manager_name" : "mysql"
}
-31
View File
@@ -1,31 +0,0 @@
{
"username": [
"",
"admin",
"Admin",
"root",
"supervisor",
"ubnt"
],
"password" : [
"",
"admin",
"9999",
"123456",
"pass",
"camera",
"1234",
"12345",
"fliradmin",
"system",
"jvc",
"meinsm",
"root",
"4321",
"1111111",
"password",
"ikwd",
"supervisor",
"ubnt"
]
}
-77
View File
@@ -1,77 +0,0 @@
{
"urls" : [
"/",
"/1.AMP",
"/1/stream1",
"/CAM_ID.password.mp2",
"/GetData.cgi",
"/MediaInput/h264",
"/MediaInput/mpeg4",
"/VideoInput/1/h264/1",
"/access_code",
"/access_name_for_stream_1_to_5",
"/av0_0",
"/av2",
"/avn=2",
"/axis-media/media.amp",
"/cam",
"/cam0_0",
"/cam0_1",
"/cam1/h264",
"/cam1/h264/multicast",
"/cam1/mjpeg",
"/cam1/mpeg4",
"/camera.stm",
"/ch0",
"/ch001.sdp",
"/ch0_unicast_firststream",
"/ch0_unicast_secondstream",
"/channel1",
"/h264",
"/h264/media.amp",
"/image.mpg",
"/img/media.sav",
"/img/video.asf",
"/img/video.sav",
"/ioImage/1",
"/ipcam.sdp",
"/ipcam_h264.sdp",
"/live.sdp",
"/live/h264",
"/live/mpeg4",
"/live_mpeg4.sdp",
"/livestream",
"/livestream/",
"/media/media.amp",
"/media/video1",
"/mjpeg/media.smp",
"/mp4",
"/mpeg4",
"/mpeg4/1/media.amp",
"/mpeg4/media.amp",
"/mpeg4/media.smp",
"/mpeg4unicast",
"/mpg4/rtsp.amp",
"/multicaststream",
"/now.mp4",
"/nph-h264.cgi",
"/nphMpeg4/g726-640x",
"/nphMpeg4/g726-640x480",
"/nphMpeg4/nil-320x240",
"/play1.sdp",
"/play2.sdp",
"/rtpvideo1.sdp",
"/rtsp_tunnel",
"/rtsph264",
"/stream1",
"/user.pin.mp2",
"/user_defined",
"/video",
"/video.3gp",
"/video.mp4",
"/video1",
"/video1+audio1",
"/vis",
"/wfov"
]
}
-16
View File
@@ -1,16 +0,0 @@
cameradar:
build: .
dockerfile: Dockerfile
env_file: env_file
volumes:
- "./conf:/tmp/conf:ro"
- "./cameradar_thumbnails:/tmp/cameradar_thumbnails"
links:
- mysql
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: cmrdr
ports:
- "3306:3306"
-2
View File
@@ -1,2 +0,0 @@
CAMERAS_SUBNETWORKS=172.16.100.0/24,192.168.178.47
CAMERAS_PORTS=554,8554
-46
View File
@@ -1,46 +0,0 @@
#!/usr/bin/env bash
ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"
COL_YELLOW=$ESC_SEQ"33;01m"
COL_BLUE=$ESC_SEQ"34;01m"
COL_MAGENTA=$ESC_SEQ"35;01m"
COL_CYAN=$ESC_SEQ"36;01m"
# declare usefuls vars
CONF=/conf/cameradar.conf.json
# copy configuration
cp /tmp/conf/* /conf/
echo -n "replacing cameras subnetworks in configuration "
sed -i s#__CAMERAS_SUBNETWORKS__#$CAMERAS_SUBNETWORKS#g $CONF
echo -e $COL_GREEN"ok"$COL_RESET
echo -n "replacing cameras ports in configuration "
sed -i s#__PORTS_TO_CHECK__#$CAMERAS_PORTS#g $CONF
echo -e $COL_GREEN"ok"$COL_RESET
# Replace ext_cctv_mysql with the IP address of your DB or the name of its Docker
# container. The container has to be linked in docker-compose.yml for cameradar
# to be able to interact with it.
echo -n "replacing mysql host and port in configuration "
sed -i s#__MYSQL_ADDR__#mysql#g $CONF
# Reaplce 3306 with the port of your DB
sed -i s#__MYSQL_PORT__#3306#g $CONF
echo -e $COL_GREEN"ok"$COL_RESET
echo -n "waiting for mysql to be ready "
while ! mysqladmin ping -h"mysql" -P3306 --silent; do
sleep 1
done
echo -e $COL_GREEN"ok"$COL_RESET
/cameradar/bin/cameradar -l 1 -c /conf/cameradar.conf.json &
cameradar_pid=$!
trap 'kill -2 $cameradar_pid; wait $cameradar_pid; exit $?' SIGTERM SIGINT
wait $cameradar_pid
-23
View File
@@ -1,23 +0,0 @@
## Copyright 2016 Etix Labs
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
cmake_minimum_required (VERSION 2.8.1)
# Lib subdirectory
include (jsoncpp)
include (mysql_connector)
set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM ON)
set (CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE)
-23
View File
@@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-55
View File
@@ -1,55 +0,0 @@
The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...
The author (Baptiste Lepilleur) explicitly disclaims copyright in all
jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
released under the terms of the MIT License (see below).
In jurisdictions which recognize Public Domain property, the user of this
software may choose to accept it either as 1) Public Domain, 2) under the
conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.
The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:
http://en.wikipedia.org/wiki/MIT_License
The full text of the MIT License follows:
========================================================================
Copyright (c) 2007-2010 Baptiste Lepilleur
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
========================================================================
(END LICENSE TEXT)
The MIT license is compatible with both the GPL and commercial
software, affording one all of the rights of Public Domain with the
minor nuisance of being required to keep the above copyright notice
and license text in the source code. Note also that by accepting the
Public Domain "license" you can re-license your copy using whatever
license you like.
-43
View File
@@ -1,43 +0,0 @@
FROM ubuntu:15.10
MAINTAINER brendan.leglaunec@etixgroup.com
ENV LD_LIBRARY_PATH="/cctv/libraries"
# install go
RUN apt-get update && apt-get install -y make git wget curl
RUN wget https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz
RUN tar -C /usr/local -xzf go1.6.linux-amd64.tar.gz
# set variable env
ENV GOPATH=/go
ENV PATH=$PATH:/go/bin
ENV PATH=$PATH:/usr/local/go/bin
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
# needed for cameradar
RUN apt-get update && apt-get install -y \
nmap \
libmysqlclient18 \
ffmpeg \
mysql-client \
libgstreamer1.0-dev \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
libcurl4-openssl-dev
RUN apt-get install -y psmisc
ADD cctv_*_Debug_Linux.tar.gz /
RUN mv cctv_*_Debug_Linux cctv
# create cameradaratest folder in go src path
RUN mkdir -p /go/src/cameradartest
ADD ./conf /conf
ADD ./docker/run_cameradartest.sh /run.sh
# get go deps
RUN go get github.com/go-sql-driver/mysql
RUN mkdir /thumbnails
WORKDIR /go/src/cameradartest
CMD ["/run.sh"]
-14
View File
@@ -1,14 +0,0 @@
FROM ubuntu:15.10
MAINTAINER brendan.leglaunec@etixgroup.com
RUN useradd -m vlc; \
apt-get update; \
apt-get install -y vlc-nox
RUN sed -i s/geteuid/getppid/g /usr/bin/vlc
ADD ./docker/screen.png /vlc/screen.png
COPY ./docker/run_vlc.sh /start.sh
COPY ./etix_rtsp_server /etix_rtsp_server
EXPOSE 8554
-14
View File
@@ -1,14 +0,0 @@
{
"mysql_db" : {
"host" : "0.0.0.0",
"port" : 3306,
"user": "root",
"password": "root",
"db_name": "cctv"
},
"subnets" : "172.16.100.13 localhost",
"ports" : "554,8554", // if not specified, default will be 1-65535
"rtsp_url_file" : "conf/url.json",
"rtsp_ids_file" : "conf/ids.json",
"thumbnail_storage_path" : "/ce/que/tu/veux"
}
-44
View File
@@ -1,44 +0,0 @@
{
"Output": "cameratest.log.xml",
"Cameradar" : {
"Path": "/home/ullaakut/Work/cctv_server2/cameradar/test/cameradar",
"Args": "-l 1 -c tmp_config",
"Ports": "554,5554,8554",
"IdsPath": "conf/ids.json",
"RoutesPath": "conf/url.json",
"ThumbPath": "/home/ullaakut/.cctv",
"dbHost": "0.0.0.0",
"dbPort": 3306,
"dbUser": "root",
"dbPassword": "root",
"dbName": "cctv",
"Console": false
},
"Tests" : [
{
"address" : "127.0.0.1",
"password" : "",
"port" : "8554",
"route" : "live.sdp",
"username" : "",
"valid" : true
},
{
"address" : "172.16.100.11",
"password" : "",
"port" : "553",
"route" : "live.sdp",
"username" : "admin",
"valid" : false
},
{
"address" : "172.16.100.13",
"password" : "",
"port" : "554",
"route" : "live.sdp",
"username" : "admin",
"valid" : true
}
]
}
-31
View File
@@ -1,31 +0,0 @@
{
"username": [
"",
"admin",
"Admin",
"root",
"supervisor",
"ubnt"
],
"password" : [
"",
"admin",
"9999",
"123456",
"pass",
"camera",
"1234",
"12345",
"fliradmin",
"system",
"jvc",
"meinsm",
"root",
"4321",
"1111111",
"password",
"ikwd",
"supervisor",
"ubnt"
]
}
-77
View File
@@ -1,77 +0,0 @@
{
"urls" : [
"/",
"/1.AMP",
"/1/stream1",
"/CAM_ID.password.mp2",
"/GetData.cgi",
"/MediaInput/h264",
"/MediaInput/mpeg4",
"/VideoInput/1/h264/1",
"/access_code",
"/access_name_for_stream_1_to_5",
"/av0_0",
"/av2",
"/avn=2",
"/axis-media/media.amp",
"/cam",
"/cam0_0",
"/cam0_1",
"/cam1/h264",
"/cam1/h264/multicast",
"/cam1/mjpeg",
"/cam1/mpeg4",
"/camera.stm",
"/ch0",
"/ch001.sdp",
"/ch0_unicast_firststream",
"/ch0_unicast_secondstream",
"/channel1",
"/h264",
"/h264/media.amp",
"/image.mpg",
"/img/media.sav",
"/img/video.asf",
"/img/video.sav",
"/ioImage/1",
"/ipcam.sdp",
"/ipcam_h264.sdp",
"/live.sdp",
"/live/h264",
"/live/mpeg4",
"/live_mpeg4.sdp",
"/livestream",
"/livestream/",
"/media/media.amp",
"/media/video1",
"/mjpeg/media.smp",
"/mp4",
"/mpeg4",
"/mpeg4/1/media.amp",
"/mpeg4/media.amp",
"/mpeg4/media.smp",
"/mpeg4unicast",
"/mpg4/rtsp.amp",
"/multicaststream",
"/now.mp4",
"/nph-h264.cgi",
"/nphMpeg4/g726-640x",
"/nphMpeg4/g726-640x480",
"/nphMpeg4/nil-320x240",
"/play1.sdp",
"/play2.sdp",
"/rtpvideo1.sdp",
"/rtsp_tunnel",
"/rtsph264",
"/stream1",
"/user.pin.mp2",
"/user_defined",
"/video",
"/video.3gp",
"/video.mp4",
"/video1",
"/video1+audio1",
"/vis",
"/wfov"
]
}
-18
View File
@@ -1,18 +0,0 @@
{
"Output": "cameratest.log.xml",
"Cameradar" : {
"Path": "/cctv/bin/cameradar",
"Args": "-l 1 -c tmp_config",
"Ports": "554,5554,8554,5548",
"IdsPath": "/conf/ids.json",
"RoutesPath": "/conf/url.json",
"ThumbPath": "/thumbnails",
"dbHost": "mysql_cameradar",
"dbPort": 3306,
"dbUser": "root",
"dbPassword": "root",
"dbName": "cctv",
"Console": false
},
"Tests" : __CAMERAS__
}
-31
View File
@@ -1,31 +0,0 @@
{
"username": [
"",
"admin",
"Admin",
"root",
"supervisor",
"ubnt"
],
"password" : [
"",
"admin",
"9999",
"123456",
"pass",
"camera",
"1234",
"12345",
"fliradmin",
"system",
"jvc",
"meinsm",
"root",
"4321",
"1111111",
"password",
"ikwd",
"supervisor",
"ubnt"
]
}
-77
View File
@@ -1,77 +0,0 @@
{
"urls" : [
"/",
"/1.AMP",
"/1/stream1",
"/CAM_ID.password.mp2",
"/GetData.cgi",
"/MediaInput/h264",
"/MediaInput/mpeg4",
"/VideoInput/1/h264/1",
"/access_code",
"/access_name_for_stream_1_to_5",
"/av0_0",
"/av2",
"/avn=2",
"/axis-media/media.amp",
"/cam",
"/cam0_0",
"/cam0_1",
"/cam1/h264",
"/cam1/h264/multicast",
"/cam1/mjpeg",
"/cam1/mpeg4",
"/camera.stm",
"/ch0",
"/ch001.sdp",
"/ch0_unicast_firststream",
"/ch0_unicast_secondstream",
"/channel1",
"/h264",
"/h264/media.amp",
"/image.mpg",
"/img/media.sav",
"/img/video.asf",
"/img/video.sav",
"/ioImage/1",
"/ipcam.sdp",
"/ipcam_h264.sdp",
"/live.sdp",
"/live/h264",
"/live/mpeg4",
"/live_mpeg4.sdp",
"/livestream",
"/livestream/",
"/media/media.amp",
"/media/video1",
"/mjpeg/media.smp",
"/mp4",
"/mpeg4",
"/mpeg4/1/media.amp",
"/mpeg4/media.amp",
"/mpeg4/media.smp",
"/mpeg4unicast",
"/mpg4/rtsp.amp",
"/multicaststream",
"/now.mp4",
"/nph-h264.cgi",
"/nphMpeg4/g726-640x",
"/nphMpeg4/g726-640x480",
"/nphMpeg4/nil-320x240",
"/play1.sdp",
"/play2.sdp",
"/rtpvideo1.sdp",
"/rtsp_tunnel",
"/rtsph264",
"/stream1",
"/user.pin.mp2",
"/user_defined",
"/video",
"/video.3gp",
"/video.mp4",
"/video1",
"/video1+audio1",
"/vis",
"/wfov"
]
}
-107
View File
@@ -1,107 +0,0 @@
#!/bin/bash
ports=('8554' '8554' '8554' '8554' '8554' '8554')
users=('admin' 'root' 'ubnt' 'Admin' 'supervisor' '')
passwords=('admin' 'root' '12345' 'ubnt' 'password' '')
routes=('live.sdp' 'live.sdp' 'ch001.sdp' '' 'invalid' 'live_mpeg4.sdp')
cams_name_pattern="fake_camera_"
# json generation variable only
json="[\n"
first=true
# $1 = adress, $2 = port, $3 = path, $4 = usernam $5 = password, $6 = valid
function make_json {
if [ "$first" = true ] ; then first=false
else json="$json,\n"; fi
json="$json{"
json="$json\"address\":\"$1\","
json="$json\"port\":\"$2\","
json="$json\"route\":\"$3\","
json="$json\"username\":\"$4\","
json="$json\"password\":\"$5\","
json="$json\"valid\":$6"
json="$json}"
}
# $1 = configuration template path
function generate_conf {
echo "generate configuration"
sed s#__CAMERAS__#$json#g $1 > cameradartest.conf.json
}
# $1 = numbers of cameras to generate
function start {
# Seed random generator
RANDOM=$(date +%s)
# start cameras
for (( i=1; i<=$1; i++ )); do
name="$cams_name_pattern$i"
# random conf
conf_idx=$(($RANDOM % ${#ports[@]}))
# get conf variables
port=${ports[$conf_idx]}
user=${users[$conf_idx]}
passw=${passwords[$conf_idx]}
route=${routes[$conf_idx]}
is_valid=true
# if conf_idx = 4 -> invalid conf
if [ "$conf_idx" == "4" ] ; then is_valid=false; fi
docker run -d --name "$name" fake-camera /start.sh "$port" "$user" "$passw" "$route"
make_json "$name" "$port" "$route" "$user" "$passw" $is_valid
done
# finalize json
json="$json]"
echo "$json"
}
function stop {
# if no cameras containers are started just exit
camera_count="`docker ps -a -q --filter="name=$cams_name_pattern" | wc -l`"
if [ "$camera_count" == "0" ]; then
echo "error: no cameras started"; exit 1
fi
echo "stopping and removing $camera_count containers"
# docker stop $(docker ps -a -q --filter="name=$cams_name_pattern")
docker rm -f $(docker ps -a -q --filter="name=$cams_name_pattern") > /dev/null
}
# need first argument at least
if [ "$1" == "" ]; then
echo "error: invalid number of argument"
exit 1
fi
case $1 in
"start")
# check if the argument is a number.
re='^[0-9]+$'
if ! [[ $2 =~ $re ]] ; then
echo "error: argument is not a number"; exit 1
fi
if [[ "$3" == "" ]] ; then
echo "error: missing path to the configuration file template"; exit 1
fi
echo "starting $2 cameras"
start $2
generate_conf $3
;;
"stop")
echo "stopping all cameras tests"
stop
;;
"help")
echo "./gen_cameras.sh start CAMS_NB - start CAMS_NB cameras"
echo " stop - stop all started cameras"
echo " help - display this help"
exit 0
;;
*)
echo "invalid test name"
exit 1
;;
esac
-15
View File
@@ -1,15 +0,0 @@
#!/bin/bash
while ! mysqladmin ping -h"mysql_cameradar" -P3306 --silent; do
sleep 1
done
ls -alhR /conf
cat /etc/hosts
# build
go build
# run test
./cameradartest /tmp/tests/cameradartest.conf.json
cp cameratest.log.xml /tmp/tests/
-16
View File
@@ -1,16 +0,0 @@
#!/bin/bash
port=$1
user=$2
passw=$3
route=$4
url=""
# need first argument at least
if [ "$2" == "" ]; then
url="rtsp://:$port/$route"
else
url="rtsp://$user:$passw@:$port/$route"
fi
./etix_rtsp_server -u $s -p $3 -r $4
# cvlc /vlc/screen.png -I dummy --sout-keep --no-drop-late-frames --no-skip-frames --image-duration 9999 --sout="#transcode{vcodec=h264,fps=15,venc=x264{preset=ultrafast,tune=zerolatency,keyint=30,bframes=0,ref=1,level=30,profile=baseline,hrd=cbr,crf=20,ratetol=1.0,vbv-maxrate=1200,vbv-bufsize=1200,lookahead=0}}:rtp{sdp=$url}" --sout-all
Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.
-58
View File
@@ -1,58 +0,0 @@
#!/bin/bash
# check if a debug package exist in the current folder
if ! ls ./cctv_*_Debug_Linux.tar.gz 1> /dev/null 2>&1; then
(echo "no debug package in the current folder"; exit 137)
exit 137
fi
cams_name_pattern="fake_camera_"
cmd=""
function make_docker_command {
cmd="docker run --rm"
# start cameras
for (( i=1; i<=$1; i++ )); do
name="$cams_name_pattern$i"
cmd="$cmd --link=\"$name\""
done
# add mysql libk
cmd="$cmd --link=\"mysql_cameradar\""
# add cameradar srcs
cmd="$cmd -v \"`pwd`/src:/go/src/cameradartest\""
# add cmaeradar conf
cmd="$cmd -v \"`pwd`/:/tmp/tests\""
# add container name
cmd="$cmd cameradartest"
}
function start_test {
make_docker_command $1
./docker/gen_cameras.sh start $1 ./docker/cameratest.conf.tmpl.json
eval $cmd
./docker/gen_cameras.sh stop
}
# build images
echo "building docker images"
# building fake-camera container
docker build -f Dockerfile-camera -t fake-camera .
# building cameradartest image
docker build -t cameradartest .
# getting mysql
echo "starting mysql"
docker pull mysql:5.7
docker run --name mysql_cameradar -e MYSQL_DATABASE=cctv -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
start_test 1
start_test 5
# start_test 10
# start_test 20
# stop mysql
echo "stopping mysql"
docker rm -f mysql_cameradar
-32
View File
@@ -1,32 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"os"
)
func (m *manager) parseConfig() bool {
// Get config file path
confPath := "conf/cameratest.conf.json"
av := len(os.Args)
if av == 2 {
confPath = os.Args[1]
}
// Load config
fmt.Printf("Loading config file: %s ... ", confPath)
configFile, err := os.Open(confPath)
if err != nil {
fmt.Printf("\nCan't open config file: %s\n", err)
return false
}
dec := json.NewDecoder(configFile)
if err = dec.Decode(&m); err != nil {
fmt.Printf("\nUnable to deserialize config file: %s\n", err)
return false
}
fmt.Println("Configuration file successfully loaded\n")
return true
}
-24
View File
@@ -1,24 +0,0 @@
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
"strconv"
)
func (m *manager) dropDB() bool {
dsn := m.DB.User + ":" + m.DB.Password + "@" + "tcp(" + m.DB.Host + ":" + strconv.Itoa(m.DB.Port) + ")/" + m.DB.Db_name + "?charset=utf8"
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Println(err)
}
defer db.Close()
q := "DROP DATABASE cctv;"
_, err = db.Exec(q)
if err != nil {
fmt.Println(err)
}
fmt.Println("------ Dropped CCTV Database -------")
return true
}
-24
View File
@@ -1,24 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"os"
)
// Launch it via goroutine
// Start read log of service
func getResult(test *[]Result, resultPath string) bool {
// Load config
resultFile, err := os.Open(resultPath)
if err != nil {
fmt.Printf("\nCan't open result file: %s\n", err)
return false
}
dec := json.NewDecoder(resultFile)
if err = dec.Decode(&test); err != nil {
fmt.Printf("\nUnable to deserialize result file: %s\n", err)
return false
}
return true
}
-28
View File
@@ -1,28 +0,0 @@
package main
import (
"bufio"
"fmt"
"io"
)
// Launch it via goroutine
// Start read log of service
func readLog(service *Service, reader io.ReadCloser) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
str := scanner.Text()
if service.Console {
fmt.Printf("[%s] %s\n", service.Path, str)
}
fmt.Printf("%s\n", str)
service.Mutex.Lock()
service.Logs = append(service.Logs, str)
service.Mutex.Unlock()
}
if err := scanner.Err(); err != nil {
fmt.Printf("[%s] Service failed: %s\n", service.Path, err)
}
fmt.Printf("Logger of service: [%s] stopped\n", service.Path)
service.Active = false
}
-30
View File
@@ -1,30 +0,0 @@
package main
import (
"fmt"
)
func main() {
manager := new(manager)
defer manager.Stop()
// Parse conf (streams should already be launched by Jenkins)
fmt.Println("--- Initializing Cameradar Test Tool ... ---")
if !manager.Init() {
fmt.Println("-> Cameradar Test Tool initialization FAILED")
return
}
// Run tests
if !manager.Run() {
fmt.Println("-> Cameradar Test Tool FAILED")
}
// Write results
fmt.Println("--- Writing results... ---")
if !manager.WriteResults(*(manager.Result), manager.Config.Output) {
fmt.Println("-> Write results FAILED")
return
}
fmt.Println("--- Writing results done ---")
}
-54
View File
@@ -1,54 +0,0 @@
package main
import (
"fmt"
"sync"
)
type manager struct {
Config
Tests []Result
Result *TestCase
DB mysql_db
}
type Config struct {
Cameradar Service `json:"Cameradar"`
Output string
}
func (m *manager) Init() bool {
fmt.Println("- Parsing")
if !m.parseConfig() {
return false
}
fmt.Println("- Cleaning content")
killService(&m.Config.Cameradar)
return true
}
func (m *manager) Run() bool {
var wg sync.WaitGroup
fmt.Println("\n- Launching all tests")
var newTest = new(TestCase)
newTest.expected = m.Tests
if (m.generateConfig(m.Tests, &m.DB)) {
m.dropDB()
wg.Add(1)
go m.invokeTestCase(newTest, &wg)
m.Result = newTest
}
wg.Wait()
fmt.Printf("All tests completed\n")
return true
}
func (m *manager) Stop() bool {
killService(&m.Config.Cameradar)
return true
}
-87
View File
@@ -1,87 +0,0 @@
package main
import (
"fmt"
"os/exec"
"strings"
"sync"
)
type Service struct {
Path string `json:"Path"`
Args string `json:"Args"`
Ports string `json:"Ports"`
IdsPath string `json:"IdsPath"`
RoutesPath string `json:"RoutesPath"`
DbHost string `json:"dbHost"`
DbPort int `json:"dbPort"`
DbUser string `json:"dbUser"`
DbPassword string `json:"dbPassword"`
DbName string `json:"dbName"`
ThumbPath string `json:"ThumbPath"`
Console bool `json:"Console"`
Logs []string
Active bool // Based on io.ReadCloser status
Mutex sync.Mutex
cmd *exec.Cmd // Go handler of the service
}
func startService(service *Service) bool {
// Launch service
args := strings.Fields(service.Args)
service.cmd = exec.Command(service.Path, args...)
handler, err := service.cmd.StdoutPipe()
if err != nil {
fmt.Println(err)
return false
}
errHandler, err := service.cmd.StderrPipe()
if err != nil {
fmt.Println(err)
return false
}
// Launch
err = service.cmd.Start()
if err != nil {
fmt.Println(err)
return false
}
fmt.Printf("Service: [%s] started\n", service.Path)
service.Active = true
// Read service logs and update service status
// Set pipes
go readLog(service, handler)
go readLog(service, errHandler)
return true
}
// Stop only specified service instance
func stopService(service *Service) {
service.cmd.Process.Kill()
}
// Kill all instances of specified service
func killService(service *Service) {
// Sending SIGTERM
fmt.Printf("Executing: killall %s\n", service.Path)
cmd := exec.Command("killall", service.Path)
err := cmd.Run()
if err != nil {
fmt.Println(err)
}
// Sending SIGABORT, more reliable for VLC
sigAbort := []string{service.Path, "-s", "SIGABRT"}
fmt.Printf("Executing: killall %s -s SIGABRT\n", service.Path)
cmd = exec.Command("killall", sigAbort...)
err = cmd.Run()
if err != nil {
fmt.Println(err)
}
}
-168
View File
@@ -1,168 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sync"
"time"
"net"
)
type mysql_db struct {
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Db_name string `json:"db_name"`
}
type CameradarConfig struct {
Mysql_db mysql_db `json:"mysql_db"`
Subnets string `json:"subnets"`
Ports string `json:"ports"`
Rtsp_url_file string `json:"rtsp_url_file"`
Rtsp_ids_file string `json:"rtsp_ids_file"`
Thumbnail_storage_path string `json:"thumbnail_storage_path"`
}
type Result struct {
Address string `json:"address"`
Password string `json:"password"`
Port string `json:"port"`
Route string `json:"route"`
Username string `json:"username"`
Valid bool `json:"valid,omitempty"`
Thumb string `json:"thumbnail_path,omitempty"`
}
type TestCase struct {
expected []Result
result []Result
time time.Duration
ok bool
}
// Invoke the test
// Wrap results in a TestResult object
func (m *manager) invokeTestCase(testCase *TestCase, wg *sync.WaitGroup) {
startTime := time.Now()
if m.runTestCase(testCase) {
testCase.time = time.Since(startTime)
testCase.ok = true
fmt.Printf("Test OK in %.6fs\n", testCase.time.Seconds())
} else {
testCase.time = time.Since(startTime)
testCase.ok = false
fmt.Printf("Test failed in %.6fs\n", testCase.time.Seconds())
}
wg.Done()
}
func (m *manager) runTestCase(test *TestCase) bool {
fmt.Printf("Test triggered\n")
Cameradar := m.Config.Cameradar
startService(&Cameradar)
for Cameradar.Active {
time.Sleep(5 * time.Millisecond)
}
found := 0
toFind := len(test.expected)
var validResults []Result
if getResult(&test.result, "result.json") {
// Check all valid resutls that are supposed to match
// Add them to the valid results and leave the failed
// ones in the expected slice
for _, r := range test.result {
index := 0
r.Valid = true
for _, e := range test.expected {
e.Thumb = r.Thumb
var err error
var addr[] string
addr, err = net.LookupHost(e.Address)
e.Address = addr[0]
if e == r {
_, err = os.Stat(r.Thumb)
if err == nil {
fmt.Println("The result of ", r.Address, " is valid and the thumbnails were generated by Cameradar.")
found++
validResults = Extend(validResults, r)
test.expected = append(test.expected[:index], test.expected[index+1:]...)
break
} else {
fmt.Println("The result of ", r.Address, " seemed valid, but the thumbnails could not be generated by Cameradar.")
}
}
index++
}
}
index := 0
// If the result did not match the expected but it was supposed to fail
// Add it to the valid results and remove it from the expected slice
for _, e := range test.expected {
if !e.Valid {
found++
validResults = Extend(validResults, e)
test.expected = append(test.expected[:index], test.expected[index+1:]...)
break
}
index++
}
// If we found all the expected results, return true
if found == toFind {
return true
}
test.result = validResults
}
return false
}
func (m *manager) generateConfig(test []Result, DataBase *mysql_db) bool {
var config CameradarConfig
var db mysql_db
db.Host = m.Config.Cameradar.DbHost
db.Port = m.Config.Cameradar.DbPort
db.User = m.Config.Cameradar.DbUser
db.Password = m.Config.Cameradar.DbPassword
db.Db_name = m.Config.Cameradar.DbName
for _, t := range test {
if len(config.Subnets) > 0 {
config.Subnets += ","
}
config.Subnets += t.Address
}
config.Mysql_db = db
config.Ports = m.Config.Cameradar.Ports
config.Rtsp_url_file = m.Config.Cameradar.RoutesPath
config.Rtsp_ids_file = m.Config.Cameradar.IdsPath
config.Thumbnail_storage_path = m.Config.Cameradar.ThumbPath
b, _ := json.Marshal(config)
fmt.Println(string(b))
err := ioutil.WriteFile("tmp_config", b, 0644)
if err != nil {
fmt.Println(err)
return false
}
*DataBase = db
return true
}
func Extend(slice []Result, element Result) []Result {
n := len(slice)
if n == cap(slice) {
// Slice is full; must grow.
// We double its size and add 1, so if the size is zero we still grow.
newSlice := make([]Result, len(slice), 2*len(slice)+1)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0 : n+1]
slice[n] = element
return slice
}
-146
View File
@@ -1,146 +0,0 @@
package main
import (
"encoding/xml"
"fmt"
"io"
"os"
"time"
)
////////////////////////////////////////////////
// Data declarations
// JUnitTestSuites is a collection of JUnit test suites.
type JUnitTestSuites struct {
XMLName xml.Name `xml:"testsuites"`
Suites []JUnitTestSuite
}
// JUnitTestSuite is a single JUnit test suite which may contain many
// testcases.
type JUnitTestSuite struct {
Tests int `xml:"tests,attr"`
Failures int `xml:"failures,attr"`
Time string `xml:"time,attr"`
TestCases []JUnitTestCase
}
// JUnitTestCase is a single test case with its result.
type JUnitTestCase struct {
Message string `xml:"message,attr"`
Time string `xml:"time,attr"`
Failure *JUnitFailure `xml:"failure,omitempty"`
}
// JUnitFailure contains data related to a failed test.
type JUnitFailure struct {
Message string `xml:"message,attr"`
Type string `xml:"type,attr"`
Contents string `xml:",chardata"`
}
func (m *manager) WriteResults(result TestCase, output string) bool {
fmt.Printf("Displaying results...\n")
// Write Console report
m.writeConsoleReport(result)
// Write XML report
// Open xml
file, err := os.OpenFile(output, os.O_RDONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Printf("Error opening XML: %s\n", err)
return false
}
defer file.Close()
err = m.writeJUnitReportXML(result, file, output)
if err != nil {
fmt.Printf("Error writing XML: %s\n", err)
return false
}
fmt.Printf("-> JUnit XML report written: %s\n", output)
return true
}
// Write tests results under JUnit format on w
func (m *manager) writeJUnitReportXML(result TestCase, r io.ReadWriter, output string) error {
suites := JUnitTestSuites{}
dec := xml.NewDecoder(r)
if err := dec.Decode(&suites); err != nil {
fmt.Printf("\nUnable to deserialize XML log file: %s\n", err)
}
ts := JUnitTestSuite{
Tests: len(result.result) + len(result.expected),
Failures: 0,
Time: fmt.Sprintf("%.6f", result.time.Seconds()),
TestCases: []JUnitTestCase{},
}
// Run throught all iterations
testCase := JUnitTestCase{
Time: fmt.Sprintf("%.6f", result.time.Seconds()),
Failure: nil,
}
if len(result.result) > 0 {
testCase.Message = "These streams matched what we expected:"
}
for _, success := range result.result {
testCase.Message += " " + success.Address
}
if !result.ok {
testCase.Failure = &JUnitFailure{
Message: "These streams did not match what we expected:",
Type: "",
}
}
for _, fail := range result.expected {
ts.Failures++
testCase.Failure.Message += " " + fail.Address
}
ts.TestCases = append(ts.TestCases, testCase)
suites.Suites = append(suites.Suites, ts)
// Fix indent
bytes, err := xml.MarshalIndent(suites, "", "\t")
if err != nil {
return err
}
// Write in param stream
w, err := os.OpenFile(output, os.O_WRONLY|os.O_TRUNC, 0644)
writer := io.Writer(w)
writer.Write(bytes)
return nil
}
func (m *manager) writeConsoleReport(result TestCase) bool {
min := 50 * time.Hour
max := 0 * time.Second
total := 0 * time.Second
successCount := 0
failureCount := 0
if result.ok {
successCount++
total += result.time
if result.time < min {
min = result.time
}
if result.time > max {
max = result.time
}
} else {
failureCount++
}
fmt.Println("--- Test summary ---\n")
if successCount > 0 {
fmt.Printf("Results: %d/%d (%d%%)\n", successCount, successCount+failureCount, successCount*100/(successCount+failureCount))
fmt.Printf("Total time: %.6fs\n", total.Seconds())
fmt.Printf("Average time: %.6fs\n", total.Seconds()/float64(successCount))
fmt.Printf("Min time: %.6fs\n", min.Seconds())
fmt.Printf("Max time: %.6fs\n", max.Seconds())
} else {
fmt.Printf("No test in success\n")
}
return true
}
-26
View File
@@ -1,26 +0,0 @@
// Copyright 2016 Etix Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CAMERADAR_H__201605202152__
#define __CAMERADAR_H__201605202152__
// the configured options and settings for Tutorial
#define CAMERADAR_VERSION "@cameradar_VERSION@"
#define CAMERADAR_VERSION_MAJOR @cameradar_VERSION_MAJOR@
#define CAMERADAR_VERSION_MINOR @cameradar_VERSION_MINOR@
#define CAMERADAR_VERSION_PATCH @cameradar_VERSION_PATCH@
#define CAMERADAR_VERSION_GIT_SHA1 "@CAMERADAR_VERSION_SHA1@"
#define CAMERADAR_VERSION_BUILD "@CAMERADAR_VERSION_BUILD@"
#endif // __CAMERADAR_H__201605202152__