NEW: ebus-daemon merged into ebusd.
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "appl.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
|
||||
Appl& Appl::Instance()
|
||||
{
|
||||
static Appl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Appl::~Appl()
|
||||
{
|
||||
m_args.clear();
|
||||
m_params.clear();
|
||||
}
|
||||
|
||||
void Appl::addItem(const char* name, Param param, const char* shortname,
|
||||
const char* longname, const char* description,
|
||||
Datatype datatype, Optiontype optiontype)
|
||||
{
|
||||
if (strlen(name) != 0)
|
||||
m_params[name] = param;
|
||||
|
||||
if (strlen(longname) != 0) {
|
||||
Arg arg;
|
||||
arg.name = name;
|
||||
arg.shortname = shortname;
|
||||
arg.longname = longname;
|
||||
arg.description = description;
|
||||
arg.datatype = datatype;
|
||||
arg.optiontype = optiontype;
|
||||
m_args.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
void Appl::printArgs()
|
||||
{
|
||||
std::cerr << std::endl << "Usage:" << std::endl << " "
|
||||
<< m_argv[0].substr(2) << " [Options]" << std::endl
|
||||
<< std::endl << "Options:" << std::endl;
|
||||
|
||||
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
|
||||
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " ";
|
||||
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
|
||||
<< " | --" << a_it->longname
|
||||
<< "\t" << a_it->description
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
bool Appl::parseArgs(int argc, char* argv[])
|
||||
{
|
||||
std::vector<std::string> _argv(argv, argv + argc);
|
||||
m_argc = argc;
|
||||
m_argv = _argv;
|
||||
|
||||
for (int i = 1; i < m_argc; i++) {
|
||||
|
||||
// find option with long format '--'
|
||||
if (m_argv[i].rfind("--") == 0 && m_argv[i].size() > 2) {
|
||||
// is next item an added argument?
|
||||
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos) {
|
||||
if (checkArg(m_argv[i].substr(2), m_argv[i+1]) == false)
|
||||
return false;
|
||||
} else {
|
||||
if (checkArg(m_argv[i].substr(2), "") == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
// find option with short format '-'
|
||||
} else if (m_argv[i].rfind("-") == 0 && m_argv[i].size() > 1) {
|
||||
|
||||
// walk through all characters
|
||||
for (size_t j = 1; j < m_argv[i].size(); j++) {
|
||||
|
||||
// only last charater could have an argument
|
||||
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos
|
||||
&& j+1 == m_argv[i].size()) {
|
||||
if (checkArg(m_argv[i].substr(j,1), m_argv[i+1]) == false)
|
||||
return false;
|
||||
} else {
|
||||
if (checkArg(m_argv[i].substr(j,1), "") == false)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Appl::printSettings()
|
||||
{
|
||||
std::cerr << std::endl << "Settings:" << std::endl;
|
||||
|
||||
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
|
||||
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " ";
|
||||
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
|
||||
<< " | --" << a_it->longname
|
||||
<< " = ";
|
||||
if (a_it->datatype == type_bool) {
|
||||
if (getParam<bool>(a_it->name) == true)
|
||||
std::cerr << "yes" << std::endl;
|
||||
else
|
||||
std::cerr << "no" << std::endl;
|
||||
}
|
||||
else if (a_it->datatype == type_int) {
|
||||
std::cerr << getParam<int>(a_it->name) << std::endl;
|
||||
}
|
||||
else if (a_it->datatype == type_long) {
|
||||
std::cerr << getParam<long>(a_it->name) << std::endl;
|
||||
}
|
||||
else if (a_it->datatype == type_float) {
|
||||
std::cerr << getParam<float>(a_it->name) << std::endl;
|
||||
}
|
||||
else if (a_it->datatype == type_string) {
|
||||
std::cerr << getParam<const char*>(a_it->name) << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
bool Appl::checkArg(const std::string& name, const std::string& arg)
|
||||
{
|
||||
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
|
||||
if (a_it->shortname == name || a_it->longname == name) {
|
||||
if (a_it->optiontype == opt_mandatory && arg.size() == 0) {
|
||||
std::cerr << std::endl << "option requires an argument '"
|
||||
<< name << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a_it->optiontype == opt_optional && arg.size() != 0)
|
||||
|| a_it->optiontype != opt_optional)
|
||||
addParam(a_it->name, arg, a_it->datatype);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << m_argv[0].substr(2) << ": Unknown Option -- " << name << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Appl::addParam(const char* name, const std::string arg, Datatype datatype)
|
||||
{
|
||||
switch (datatype) {
|
||||
case type_bool:
|
||||
m_params[name] = true;
|
||||
break;
|
||||
case type_int:
|
||||
m_params[name] = strtol(arg.c_str(), NULL, 10);
|
||||
break;
|
||||
case type_long:
|
||||
m_params[name] = strtol(arg.c_str(), NULL, 10);
|
||||
break;
|
||||
case type_float:
|
||||
m_params[name] = static_cast<float>(strtod(arg.c_str(), NULL));
|
||||
break;
|
||||
case type_string:
|
||||
m_params[name] = arg.c_str();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef APPL_H_
|
||||
#define APPL_H_
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class Appl
|
||||
{
|
||||
|
||||
private:
|
||||
struct Option;
|
||||
|
||||
public:
|
||||
enum Datatype { type_none, type_bool, type_int, type_long, type_float, type_string };
|
||||
enum Optiontype { opt_none, opt_optional, opt_mandatory };
|
||||
|
||||
union Param {
|
||||
bool b;
|
||||
int i;
|
||||
long l;
|
||||
float f;
|
||||
const char* c;
|
||||
|
||||
Param() { memset(this, 0, sizeof(Param)); }
|
||||
Param(bool _b) : b(_b) {}
|
||||
Param(int _i) : i(_i) {}
|
||||
Param(long _l) : l(_l) {}
|
||||
Param(float _f) : f(_f) {}
|
||||
Param(const char* _c) : c(_c) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T getParam(const char* name)
|
||||
{
|
||||
p_it = m_params.find(name);
|
||||
return (reinterpret_cast<T&>(p_it->second));
|
||||
}
|
||||
|
||||
static Appl& Instance();
|
||||
|
||||
~Appl();
|
||||
|
||||
void addItem(const char* name, Param param, const char* shortname,
|
||||
const char* longname, const char* description,
|
||||
Datatype datatype, Optiontype optiontype);
|
||||
|
||||
void printArgs();
|
||||
|
||||
bool parseArgs(int argc, char* argv[]);
|
||||
void printSettings();
|
||||
|
||||
private:
|
||||
Appl() {}
|
||||
Appl(const Appl&);
|
||||
Appl& operator= (const Appl&);
|
||||
|
||||
struct Arg {
|
||||
const char* name;
|
||||
const char* shortname;
|
||||
const char* longname;
|
||||
const char* description;
|
||||
Datatype datatype;
|
||||
Optiontype optiontype;
|
||||
};
|
||||
|
||||
int m_argc;
|
||||
std::vector<std::string> m_argv;
|
||||
|
||||
std::vector<Arg> m_args;
|
||||
std::vector<Arg>::const_iterator a_it;
|
||||
|
||||
std::map<const char*, Param> m_params;
|
||||
std::map<const char*, Param>::iterator p_it;
|
||||
|
||||
bool checkArg(const std::string& name, const std::string& arg);
|
||||
|
||||
void addParam(const char* name, Param param) { m_params[name] = param; }
|
||||
|
||||
void addParam(const char* name, const std::string arg, Datatype datatype);
|
||||
};
|
||||
|
||||
#endif // APPL_H_
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "daemon.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
Daemon& Daemon::Instance()
|
||||
{
|
||||
static Daemon instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Daemon::run(const char* file)
|
||||
{
|
||||
m_status = false;
|
||||
m_pidfile = file;
|
||||
m_pidfd = 0;
|
||||
|
||||
pid_t pid;
|
||||
|
||||
// fork off the parent process
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
std::cerr << "daemon fork() failed." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// If we got a good PID, then we can exit the parent process
|
||||
if (pid > 0) {
|
||||
// printf("Child process created: %d\n", pid);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// At this point we are executing as the child process
|
||||
|
||||
// Set file permissions 750
|
||||
umask(027);
|
||||
|
||||
// Create a new SID for the child process and
|
||||
// detach the process from the parent (normally a shell)
|
||||
if (setsid() < 0) {
|
||||
std::cerr << "daemon setsid() failed." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Change the current working directory. This prevents the current
|
||||
// directory from being locked; hence not being able to remove it.
|
||||
if (chdir("/tmp") < 0) { //DAEMON_WORKDIR
|
||||
std::cerr << "daemon chdir() failed." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Close stdin, stdout and stderr
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
// write pidfile and try to lock it
|
||||
if (pidfile_open() == false) {
|
||||
std::cerr << "can't open pidfile: %s" << m_pidfile << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
m_status = true;
|
||||
}
|
||||
|
||||
bool Daemon::pidfile_open()
|
||||
{
|
||||
char pid[10];
|
||||
|
||||
m_pidfd = open(m_pidfile, O_RDWR|O_CREAT, 0600);
|
||||
if (m_pidfd < 0)
|
||||
return false;
|
||||
|
||||
if (lockf(m_pidfd, F_TLOCK, 0) < 0)
|
||||
return false;
|
||||
|
||||
sprintf(pid, "%d\n", getpid());
|
||||
if (write(m_pidfd, pid, strlen(pid)) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon::pidfile_close()
|
||||
{
|
||||
if (close(m_pidfd) < 0)
|
||||
return false;
|
||||
|
||||
if (remove(m_pidfile) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_H_
|
||||
#define DAEMON_H_
|
||||
|
||||
class Daemon
|
||||
{
|
||||
|
||||
public:
|
||||
static Daemon& Instance();
|
||||
~Daemon() {}
|
||||
|
||||
void run(const char* file);
|
||||
void stop() { pidfile_close(); }
|
||||
bool status() { return m_status; }
|
||||
|
||||
private:
|
||||
bool m_status;
|
||||
const char* m_pidfile;
|
||||
int m_pidfd;
|
||||
|
||||
Daemon() {}
|
||||
Daemon(const Daemon&);
|
||||
Daemon& operator= (const Daemon&);
|
||||
|
||||
bool pidfile_open();
|
||||
bool pidfile_close();
|
||||
|
||||
};
|
||||
|
||||
#endif // DAEMON_H_
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char* AreaNames[Size_of_Area] = { "bas", "net", "bus", "cyc" };
|
||||
static const char* LevelNames[Size_of_Level] = { "error", "event", "trace", "debug" };
|
||||
|
||||
int calcArea(const std::string area)
|
||||
{
|
||||
int m_area = 0;
|
||||
|
||||
// prepare data
|
||||
std::string token;
|
||||
std::istringstream stream(area);
|
||||
std::vector<std::string> cmd;
|
||||
|
||||
while (std::getline(stream, token, ',') != 0)
|
||||
cmd.push_back(token);
|
||||
|
||||
for (std::vector<std::string>::iterator it = cmd.begin() ; it != cmd.end(); ++it)
|
||||
for (int i = 0; i < Size_of_Area; i++) {
|
||||
if (strcasecmp("all", it->c_str()) == 0)
|
||||
return (pow(2, (int)Size_of_Area) - 1);
|
||||
|
||||
if (strcasecmp(AreaNames[i], it->c_str()) == 0)
|
||||
m_area += pow(2, i);
|
||||
}
|
||||
|
||||
return m_area;
|
||||
}
|
||||
|
||||
int calcLevel(const std::string level)
|
||||
{
|
||||
int m_level = event;
|
||||
for (int i = 0; i < Size_of_Level; i++)
|
||||
if (strcasecmp(LevelNames[i], level.c_str()) == 0)
|
||||
return i;
|
||||
|
||||
return m_level;
|
||||
}
|
||||
|
||||
|
||||
LogMessage::LogMessage(const int area, const int level, const std::string text, const Status status)
|
||||
: m_area(area), m_level(level), m_text(text), m_status(status)
|
||||
{
|
||||
char time[24];
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
struct tm* tm;
|
||||
|
||||
gettimeofday(&tv, &tz);
|
||||
tm = localtime(&tv.tv_sec);
|
||||
|
||||
sprintf(&time[0], "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
|
||||
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec/1000);
|
||||
|
||||
m_time = std::string(time);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogSink::addMessage(const LogMessage& message)
|
||||
{
|
||||
LogMessage* tmp = new LogMessage(LogMessage(message));
|
||||
m_queue.add((tmp));
|
||||
}
|
||||
|
||||
void* LogSink::run()
|
||||
{
|
||||
while (1) {
|
||||
LogMessage* message = m_queue.remove();
|
||||
if (message->getStatus() == LogMessage::End) {
|
||||
delete message;
|
||||
while (m_queue.size() == true) {
|
||||
LogMessage* message = m_queue.remove();
|
||||
write(*message);
|
||||
delete message;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
write(*message);
|
||||
delete message;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int LogConsole::m_numInstance = 0;
|
||||
|
||||
void LogConsole::write(const LogMessage& message) const
|
||||
{
|
||||
std::cout << message.getTime() << " ["
|
||||
<< AreaNames[(int)log2(message.getArea())] << " "
|
||||
<< LevelNames[message.getLevel()] << "] "
|
||||
<< message.getText() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int LogFile::m_numInstance = 0;
|
||||
|
||||
void LogFile::write(const LogMessage& message) const
|
||||
{
|
||||
std::fstream file(m_filename.c_str(), std::ios::out | std::ios::app);
|
||||
|
||||
if (file.is_open() == true) {
|
||||
file << message.getTime() << " ["
|
||||
<< AreaNames[(int)log2(message.getArea())] << " "
|
||||
<< LevelNames[message.getLevel()] << "] "
|
||||
<< message.getText() << std::endl;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogInstance& LogInstance::Instance()
|
||||
{
|
||||
static LogInstance instance;
|
||||
return (instance);
|
||||
}
|
||||
|
||||
LogInstance::~LogInstance()
|
||||
{
|
||||
while (m_sinks.empty() == false)
|
||||
*this -= *(m_sinks.begin());
|
||||
}
|
||||
|
||||
LogInstance& LogInstance::operator+= (LogSink* sink)
|
||||
{
|
||||
sinkCI_t itEnd = m_sinks.end();
|
||||
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
|
||||
|
||||
if (it == itEnd)
|
||||
m_sinks.push_back(sink);
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
LogInstance& LogInstance::operator-= (const LogSink* sink)
|
||||
{
|
||||
sinkCI_t itEnd = m_sinks.end();
|
||||
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
|
||||
|
||||
if (it == itEnd)
|
||||
return (*this);
|
||||
|
||||
m_sinks.erase(it);
|
||||
|
||||
delete (sink);
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void LogInstance::log(const int area, const int level, const std::string& data, ...)
|
||||
{
|
||||
if (m_running == true) {
|
||||
char* tmp;
|
||||
va_list ap;
|
||||
va_start(ap, data);
|
||||
|
||||
if (vasprintf(&tmp, data.c_str(), ap) != -1) {
|
||||
std::string buffer(tmp);
|
||||
m_messages.add(new LogMessage(LogMessage(area, level, buffer, LogMessage::Run)));
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void* LogInstance::run()
|
||||
{
|
||||
m_running = true;
|
||||
|
||||
while (m_running == true) {
|
||||
LogMessage* message = m_messages.remove();
|
||||
|
||||
sinkCI_t iter = m_sinks.begin();
|
||||
|
||||
for (; iter != m_sinks.end(); ++iter) {
|
||||
if (*iter != 0) {
|
||||
|
||||
if (((*iter)->getAreas() & message->getArea()
|
||||
&& (*iter)->getLevel() >= message->getLevel())
|
||||
&& message->getStatus() == LogMessage::Run) {
|
||||
(*iter)->addMessage(*message);
|
||||
} else if (message->getStatus() == LogMessage::End) {
|
||||
(*iter)->addMessage(*message);
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
delete message;
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LogInstance::stop()
|
||||
{
|
||||
m_messages.add(new LogMessage(LogMessage(bas, error, "", LogMessage::End)));
|
||||
// TODO: Improve this method
|
||||
usleep(100000);
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_H_
|
||||
#define LOGGER_H_
|
||||
|
||||
#include "wqueue.h"
|
||||
#include "thread.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
|
||||
enum Area { bas=1, net=2, bus=4, cyc=8, all=15, Size_of_Area=4 };
|
||||
enum Level { error=0, event, trace, debug, Size_of_Level };
|
||||
|
||||
int calcArea(const std::string area);
|
||||
int calcLevel(const std::string level);
|
||||
|
||||
|
||||
class LogMessage
|
||||
{
|
||||
|
||||
public:
|
||||
enum Status { Run, End };
|
||||
|
||||
LogMessage(const int area, const int level, const std::string text, const Status status);
|
||||
|
||||
~LogMessage() {}
|
||||
|
||||
LogMessage(const LogMessage& src)
|
||||
: m_area(src.m_area), m_level(src.m_level), m_text(src.m_text),
|
||||
m_status(src.m_status), m_time(src.m_time) {}
|
||||
|
||||
void operator= (const LogMessage& src)
|
||||
{ m_area = src.m_area; m_level = src.m_level; m_text = src.m_text;
|
||||
m_status = src.m_status; m_time = src.m_time; }
|
||||
|
||||
int getArea() const { return (m_area); }
|
||||
int getLevel() const { return(m_level); }
|
||||
std::string getText() const { return (m_text.c_str()); }
|
||||
Status getStatus() const { return (m_status); }
|
||||
std::string getTime() const { return (m_time.c_str()); }
|
||||
|
||||
private:
|
||||
int m_area;
|
||||
int m_level;
|
||||
std::string m_text;
|
||||
Status m_status;
|
||||
std::string m_time;
|
||||
|
||||
};
|
||||
|
||||
enum Type { Console, Logfile };
|
||||
|
||||
class LogSink : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
LogSink(const int areas, const int level, const Type type, const char* name)
|
||||
: m_areas(areas), m_level(level), m_type(type), m_name(name) {}
|
||||
|
||||
virtual ~LogSink() {}
|
||||
|
||||
void addMessage(const LogMessage& message);
|
||||
|
||||
void* run();
|
||||
|
||||
int getAreas() const { return (m_areas); }
|
||||
void setAreas(const int& areas) { m_areas = areas; }
|
||||
|
||||
int getLevel() const { return (m_level); }
|
||||
void setLevel(const int& level) { m_level = level; }
|
||||
|
||||
Type getType() const { return (m_type); }
|
||||
const char* getName() const { return (m_name.c_str()); }
|
||||
|
||||
protected:
|
||||
WQueue<LogMessage*> m_queue;
|
||||
|
||||
private:
|
||||
int m_areas;
|
||||
int m_level;
|
||||
Type m_type;
|
||||
std::string m_name;
|
||||
|
||||
virtual void write(const LogMessage& message) const = 0;
|
||||
|
||||
};
|
||||
|
||||
class LogConsole : public LogSink
|
||||
{
|
||||
|
||||
public:
|
||||
LogConsole(const int areas, const int level, const char* name)
|
||||
: LogSink(areas, level, Console, name), m_instance(++m_numInstance)
|
||||
{ this->start(name); }
|
||||
|
||||
~LogConsole() {}
|
||||
|
||||
private:
|
||||
const int m_instance;
|
||||
static int m_numInstance;
|
||||
|
||||
void write(const LogMessage& message) const;
|
||||
|
||||
};
|
||||
|
||||
class LogFile : public LogSink
|
||||
{
|
||||
|
||||
public:
|
||||
LogFile(const int areas, const int level, const char* name, const char* filename)
|
||||
: LogSink(areas, level, Logfile, name), m_filename(filename), m_instance(++m_numInstance)
|
||||
{ this->start(name); }
|
||||
|
||||
~LogFile() {}
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
const int m_instance;
|
||||
static int m_numInstance;
|
||||
|
||||
void write(const LogMessage& message) const;
|
||||
|
||||
};
|
||||
|
||||
class LogInstance : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
static LogInstance& Instance();
|
||||
|
||||
~LogInstance();
|
||||
|
||||
LogInstance& operator+= (LogSink* sink);
|
||||
LogInstance& operator-= (const LogSink* sink);
|
||||
|
||||
void log(const int area, const int level, const std::string& text, ...);
|
||||
|
||||
int getNumberOfSinks() const { return(m_sinks.size()); }
|
||||
LogSink* getSink(const int Index) const { return(m_sinks[Index]); }
|
||||
|
||||
void* run();
|
||||
|
||||
void stop();
|
||||
|
||||
private:
|
||||
LogInstance() {}
|
||||
LogInstance(const LogInstance&);
|
||||
LogInstance& operator= (const LogInstance&);
|
||||
|
||||
typedef std::vector<LogSink*> sink_t;
|
||||
typedef std::vector<LogSink*>::iterator sinkCI_t;
|
||||
|
||||
sink_t m_sinks;
|
||||
|
||||
WQueue<LogMessage*> m_messages;
|
||||
|
||||
bool m_running;
|
||||
|
||||
};
|
||||
|
||||
#endif // LOGGER_H_
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef NOTIFY_H_
|
||||
#define NOTIFY_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
class Notify
|
||||
{
|
||||
|
||||
public:
|
||||
Notify()
|
||||
{
|
||||
int pipefd[2];
|
||||
int ret = pipe(pipefd);
|
||||
|
||||
if (ret == 0) {
|
||||
m_recvfd = pipefd[0];
|
||||
m_sendfd = pipefd[1];
|
||||
|
||||
fcntl(m_sendfd, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
}
|
||||
virtual ~Notify() { close(m_sendfd); close(m_recvfd); }
|
||||
|
||||
int notifyFD() const { return m_recvfd; }
|
||||
int notify() const { return write(m_sendfd,"1",1); }
|
||||
|
||||
private:
|
||||
int m_recvfd;
|
||||
int m_sendfd;
|
||||
|
||||
};
|
||||
|
||||
#endif // NOTIFY_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "tcpsocket.h"
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
TCPSocket::TCPSocket(int sfd, struct sockaddr_in* address) : m_sfd(sfd)
|
||||
{
|
||||
char ip[17];
|
||||
inet_ntop(AF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip)-1);
|
||||
m_ip = ip;
|
||||
m_port = ntohs(address->sin_port);
|
||||
}
|
||||
|
||||
bool TCPSocket::isValid()
|
||||
{
|
||||
if (fcntl(m_sfd, F_GETFL) == -1)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int TCPListener::start()
|
||||
{
|
||||
if (m_listening == true)
|
||||
return 0;
|
||||
|
||||
m_lfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
struct sockaddr_in address;
|
||||
|
||||
memset(&address, 0, sizeof(address));
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(m_port);
|
||||
|
||||
if (m_address.size() > 0)
|
||||
inet_pton(AF_INET, m_address.c_str(), &(address.sin_addr));
|
||||
else
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
int optval = 1;
|
||||
setsockopt(m_lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
|
||||
int result = bind(m_lfd, (struct sockaddr*) &address, sizeof(address));
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = listen(m_lfd, 5);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
m_listening = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
TCPSocket* TCPListener::newSocket()
|
||||
{
|
||||
if (m_listening == false)
|
||||
return NULL;
|
||||
|
||||
struct sockaddr_in address;
|
||||
socklen_t len = sizeof(address);
|
||||
|
||||
memset(&address, 0, sizeof(address));
|
||||
|
||||
int sfd = accept(m_lfd, (struct sockaddr*) &address, &len);
|
||||
|
||||
if (sfd < 0)
|
||||
return NULL;
|
||||
|
||||
return new TCPSocket(sfd, &address);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef TCPSOCKET_H_
|
||||
#define TCPSOCKET_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
class TCPSocket
|
||||
{
|
||||
|
||||
public:
|
||||
friend class TCPListener;
|
||||
|
||||
~TCPSocket() { close(m_sfd); }
|
||||
|
||||
ssize_t recv(char* buffer, size_t len) { return read(m_sfd, buffer, len); }
|
||||
ssize_t send(const char* buffer, size_t len) { return write(m_sfd, buffer, len); }
|
||||
|
||||
int getPort() const { return m_port; }
|
||||
std::string getIP() const { return m_ip; }
|
||||
|
||||
int getFD() const { return m_sfd; }
|
||||
bool isValid();
|
||||
|
||||
private:
|
||||
int m_sfd;
|
||||
int m_port;
|
||||
std::string m_ip;
|
||||
|
||||
TCPSocket(int sd, struct sockaddr_in* address);
|
||||
|
||||
};
|
||||
|
||||
class TCPListener
|
||||
{
|
||||
|
||||
public:
|
||||
TCPListener(int port, std::string address)
|
||||
: m_lfd(0), m_port(port), m_address(address), m_listening(false) {}
|
||||
|
||||
~TCPListener() { if (m_lfd > 0) {close(m_lfd);} }
|
||||
|
||||
int start();
|
||||
TCPSocket* newSocket();
|
||||
|
||||
int getFD() const { return m_lfd; }
|
||||
|
||||
private:
|
||||
int m_lfd;
|
||||
int m_port;
|
||||
std::string m_address;
|
||||
bool m_listening;
|
||||
|
||||
};
|
||||
|
||||
#endif // TCPSOCKET_H_
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
static void* runThread(void* arg)
|
||||
{
|
||||
return ((Thread *)arg)->run();
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
if (m_running == true && m_detached == false)
|
||||
pthread_detach(m_threadid);
|
||||
|
||||
if (m_running == true)
|
||||
pthread_cancel(m_threadid);
|
||||
}
|
||||
|
||||
int Thread::start(const char* name)
|
||||
{
|
||||
|
||||
int result = pthread_create(&m_threadid, NULL, runThread, this);
|
||||
|
||||
if (result == 0) {
|
||||
pthread_setname_np(m_threadid, name);
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Thread::join()
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (m_running == true) {
|
||||
result = pthread_join(m_threadid, NULL);
|
||||
|
||||
if (result == 0)
|
||||
m_detached = false;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Thread::detach()
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (m_running == true && m_detached == false) {
|
||||
result = pthread_detach(m_threadid);
|
||||
|
||||
if (result == 0)
|
||||
m_detached = true;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef THREAD_H_
|
||||
#define THREAD_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
class Thread
|
||||
{
|
||||
|
||||
public:
|
||||
Thread() : m_threadid(0), m_running(false), m_detached(false) {}
|
||||
virtual ~Thread();
|
||||
|
||||
int start(const char* name);
|
||||
int join();
|
||||
int detach();
|
||||
pthread_t self() {return m_threadid; }
|
||||
|
||||
virtual void* run() = 0;
|
||||
|
||||
private:
|
||||
pthread_t m_threadid;
|
||||
bool m_running;
|
||||
bool m_detached;
|
||||
|
||||
};
|
||||
|
||||
#endif // THREAD_H_
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <roland.jax@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef WQUEUE_H_
|
||||
#define WQUEUE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <list>
|
||||
|
||||
template <typename T> class WQueue
|
||||
{
|
||||
|
||||
public:
|
||||
WQueue()
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_condv, NULL);
|
||||
}
|
||||
|
||||
~WQueue()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_condv);
|
||||
}
|
||||
|
||||
void add(T item)
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
m_queue.push_back(item);
|
||||
|
||||
pthread_cond_signal(&m_condv);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
T remove()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
while (m_queue.size() == 0)
|
||||
pthread_cond_wait(&m_condv, &m_mutex);
|
||||
|
||||
T item = m_queue.front();
|
||||
m_queue.pop_front();
|
||||
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
int size = m_queue.size();
|
||||
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<T> m_queue;
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_condv;
|
||||
|
||||
};
|
||||
|
||||
#endif // WQUEUE_H_
|
||||
Reference in New Issue
Block a user