nut/clients/nutclient.cpp

1732 lines
31 KiB
C++
Raw Permalink Normal View History

2013-11-24 15:00:12 +00:00
/* nutclient.cpp - nutclient C++ library implementation
Copyright (C) 2012 Emilien Kia <emilien.kia@gmail.com>
This program 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 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "nutclient.h"
#include <sstream>
#include <errno.h>
#include <string.h>
#include <stdio.h>
/* Windows/Linux Socket compatibility layer: */
/* Thanks to Benjamin Roux (http://broux.developpez.com/articles/c/sockets/) */
#ifdef WIN32
# include <winsock2.h>
#else
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <unistd.h> /* close */
# include <netdb.h> /* gethostbyname */
# include <fcntl.h>
# define INVALID_SOCKET -1
# define SOCKET_ERROR -1
# define closesocket(s) close(s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR;
#endif /* WIN32 */
/* End of Windows/Linux Socket compatibility layer: */
/* Include nut common utility functions or define simple ones if not */
#ifdef HAVE_NUTCOMMON
#include "common.h"
#else /* HAVE_NUTCOMMON */
#include <stdlib.h>
#include <string.h>
static inline void *xmalloc(size_t size){return malloc(size);}
static inline void *xcalloc(size_t number, size_t size){return calloc(number, size);}
static inline void *xrealloc(void *ptr, size_t size){return realloc(ptr, size);}
static inline char *xstrdup(const char *string){return strdup(string);}
#endif /* HAVE_NUTCOMMON */
namespace nut
{
SystemException::SystemException():
NutException(err())
{
}
std::string SystemException::err()
{
if(errno==0)
return "Undefined system error";
else
{
std::stringstream str;
str << "System error " << errno << ": " << strerror(errno);
return str.str();
}
}
namespace internal
{
/**
* Internal socket wrapper.
* Provides only client socket functions.
*
* Implemented as separate internal class to easily hide plateform specificities.
*/
class Socket
{
public:
Socket();
void connect(const std::string& host, int port)throw(nut::IOException);
void disconnect();
bool isConnected()const;
void setTimeout(long timeout);
bool hasTimeout()const{return _tv.tv_sec>=0;}
size_t read(void* buf, size_t sz)throw(nut::IOException);
size_t write(const void* buf, size_t sz)throw(nut::IOException);
std::string read()throw(nut::IOException);
void write(const std::string& str)throw(nut::IOException);
private:
SOCKET _sock;
struct timeval _tv;
std::string _buffer; /* Received buffer, string because data should be text only. */
};
Socket::Socket():
_sock(INVALID_SOCKET),
_tv()
{
_tv.tv_sec = -1;
_tv.tv_usec = 0;
}
void Socket::setTimeout(long timeout)
{
_tv.tv_sec = timeout;
}
void Socket::connect(const std::string& host, int port)throw(nut::IOException)
{
int sock_fd;
struct addrinfo hints, *res, *ai;
char sport[NI_MAXSERV];
int v;
fd_set wfds;
int error;
socklen_t error_size;
long fd_flags;
_sock = -1;
if (host.empty()) {
throw nut::UnknownHostException();
}
snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
while ((v = getaddrinfo(host.c_str(), sport, &hints, &res)) != 0) {
switch (v)
{
case EAI_AGAIN:
continue;
case EAI_NONAME:
throw nut::UnknownHostException();
case EAI_SYSTEM:
throw nut::SystemException();
case EAI_MEMORY:
throw nut::NutException("Out of memory");
default:
throw nut::NutException("Unknown error");
}
}
for (ai = res; ai != NULL; ai = ai->ai_next) {
sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock_fd < 0) {
switch (errno)
{
case EAFNOSUPPORT:
case EINVAL:
break;
default:
throw nut::SystemException();
}
continue;
}
/* non blocking connect */
if(hasTimeout()) {
fd_flags = fcntl(sock_fd, F_GETFL);
fd_flags |= O_NONBLOCK;
fcntl(sock_fd, F_SETFL, fd_flags);
}
while ((v = ::connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) {
if(errno == EINPROGRESS) {
FD_ZERO(&wfds);
FD_SET(sock_fd, &wfds);
select(sock_fd+1,NULL,&wfds,NULL, hasTimeout()?&_tv:NULL);
if (FD_ISSET(sock_fd, &wfds)) {
error_size = sizeof(error);
getsockopt(sock_fd,SOL_SOCKET,SO_ERROR,
&error,&error_size);
if( error == 0) {
/* connect successful */
v = 0;
break;
}
errno = error;
}
else {
/* Timeout */
v = -1;
break;
}
}
switch (errno)
{
case EAFNOSUPPORT:
break;
case EINTR:
case EAGAIN:
continue;
default:
// ups->upserror = UPSCLI_ERR_CONNFAILURE;
// ups->syserrno = errno;
break;
}
break;
}
if (v < 0) {
close(sock_fd);
continue;
}
/* switch back to blocking operation */
if(hasTimeout()) {
fd_flags = fcntl(sock_fd, F_GETFL);
fd_flags &= ~O_NONBLOCK;
fcntl(sock_fd, F_SETFL, fd_flags);
}
_sock = sock_fd;
// ups->upserror = 0;
// ups->syserrno = 0;
break;
}
freeaddrinfo(res);
if (_sock < 0) {
throw nut::IOException("Cannot connect to host");
}
#ifdef OLD
struct hostent *hostinfo = NULL;
SOCKADDR_IN sin = { 0 };
hostinfo = ::gethostbyname(host.c_str());
if(hostinfo == NULL) /* Host doesnt exist */
{
throw nut::UnknownHostException();
}
// Create socket
_sock = ::socket(PF_INET, SOCK_STREAM, 0);
if(_sock == INVALID_SOCKET)
{
throw nut::IOException("Cannot create socket");
}
// Connect
sin.sin_addr = *(IN_ADDR *) hostinfo->h_addr;
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
if(::connect(_sock,(SOCKADDR *) &sin, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
_sock = INVALID_SOCKET;
throw nut::IOException("Cannot connect to host");
}
#endif // OLD
}
void Socket::disconnect()
{
if(_sock != INVALID_SOCKET)
{
::closesocket(_sock);
_sock = INVALID_SOCKET;
}
_buffer.clear();
}
bool Socket::isConnected()const
{
return _sock!=INVALID_SOCKET;
}
size_t Socket::read(void* buf, size_t sz)throw(nut::IOException)
{
if(!isConnected())
{
throw nut::NotConnectedException();
}
if(_tv.tv_sec>=0)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(_sock, &fds);
int ret = select(_sock+1, &fds, NULL, NULL, &_tv);
if (ret < 1) {
throw nut::TimeoutException();
}
}
ssize_t res = ::read(_sock, buf, sz);
if(res==-1)
{
disconnect();
throw nut::IOException("Error while reading on socket");
}
return (size_t) res;
}
size_t Socket::write(const void* buf, size_t sz)throw(nut::IOException)
{
if(!isConnected())
{
throw nut::NotConnectedException();
}
if(_tv.tv_sec>=0)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(_sock, &fds);
int ret = select(_sock+1, NULL, &fds, NULL, &_tv);
if (ret < 1) {
throw nut::TimeoutException();
}
}
ssize_t res = ::write(_sock, buf, sz);
if(res==-1)
{
disconnect();
throw nut::IOException("Error while writing on socket");
}
return (size_t) res;
}
std::string Socket::read()throw(nut::IOException)
{
std::string res;
char buff[256];
while(true)
{
// Look at already read data in _buffer
if(!_buffer.empty())
{
size_t idx = _buffer.find('\n');
if(idx!=std::string::npos)
{
res += _buffer.substr(0, idx);
_buffer.erase(0, idx+1);
return res;
}
res += _buffer;
}
// Read new buffer
size_t sz = read(&buff, 256);
2016-07-18 00:11:41 +00:00
if(sz==0)
{
disconnect();
throw nut::IOException("Server closed connection unexpectedly");
}
2013-11-24 15:00:12 +00:00
_buffer.assign(buff, sz);
}
}
void Socket::write(const std::string& str)throw(nut::IOException)
{
// write(str.c_str(), str.size());
// write("\n", 1);
std::string buff = str + "\n";
write(buff.c_str(), buff.size());
}
}/* namespace internal */
/*
*
* Client implementation
*
*/
Client::Client()
{
}
Client::~Client()
{
}
bool Client::hasDevice(const std::string& dev)throw(NutException)
{
std::set<std::string> devs = getDeviceNames();
return devs.find(dev) != devs.end();
}
Device Client::getDevice(const std::string& name)throw(NutException)
{
if(hasDevice(name))
return Device(this, name);
else
return Device(NULL, "");
}
std::set<Device> Client::getDevices()throw(NutException)
{
std::set<Device> res;
std::set<std::string> devs = getDeviceNames();
for(std::set<std::string>::iterator it=devs.begin(); it!=devs.end(); ++it)
{
res.insert(Device(this, *it));
}
return res;
}
bool Client::hasDeviceVariable(const std::string& dev, const std::string& name)throw(NutException)
{
std::set<std::string> names = getDeviceVariableNames(dev);
return names.find(name) != names.end();
}
std::map<std::string,std::vector<std::string> > Client::getDeviceVariableValues(const std::string& dev)throw(NutException)
{
std::map<std::string,std::vector<std::string> > res;
std::set<std::string> names = getDeviceVariableNames(dev);
for(std::set<std::string>::iterator it=names.begin(); it!=names.end(); ++it)
{
const std::string& name = *it;
res[name] = getDeviceVariableValue(dev, name);
}
return res;
}
bool Client::hasDeviceCommand(const std::string& dev, const std::string& name)throw(NutException)
{
std::set<std::string> names = getDeviceCommandNames(dev);
return names.find(name) != names.end();
}
/*
*
* TCP Client implementation
*
*/
TcpClient::TcpClient():
Client(),
_host("localhost"),
_port(3493),
_socket(new internal::Socket)
{
// Do not connect now
}
TcpClient::TcpClient(const std::string& host, int port)throw(IOException):
Client(),
_socket(new internal::Socket)
{
connect(host, port);
}
TcpClient::~TcpClient()
{
delete _socket;
}
void TcpClient::connect(const std::string& host, int port)throw(IOException)
{
_host = host;
_port = port;
connect();
}
void TcpClient::connect()throw(nut::IOException)
{
_socket->connect(_host, _port);
}
std::string TcpClient::getHost()const
{
return _host;
}
int TcpClient::getPort()const
{
return _port;
}
bool TcpClient::isConnected()const
{
return _socket->isConnected();
}
void TcpClient::disconnect()
{
_socket->disconnect();
}
void TcpClient::setTimeout(long timeout)
{
_timeout = timeout;
}
long TcpClient::getTimeout()const
{
return _timeout;
}
void TcpClient::authenticate(const std::string& user, const std::string& passwd)
throw(NutException)
{
detectError(sendQuery("USERNAME " + user));
detectError(sendQuery("PASSWORD " + passwd));
}
void TcpClient::logout()throw(NutException)
{
detectError(sendQuery("LOGOUT"));
_socket->disconnect();
}
Device TcpClient::getDevice(const std::string& name)throw(NutException)
{
try
{
get("UPSDESC", name);
}
catch(NutException& ex)
{
if(ex.str()=="UNKNOWN-UPS")
return Device(NULL, "");
else
throw;
}
return Device(this, name);
}
std::set<std::string> TcpClient::getDeviceNames()throw(NutException)
{
std::set<std::string> res;
std::vector<std::vector<std::string> > devs = list("UPS");
for(std::vector<std::vector<std::string> >::iterator it=devs.begin();
it!=devs.end(); ++it)
{
std::string id = (*it)[0];
if(!id.empty())
res.insert(id);
}
return res;
}
std::string TcpClient::getDeviceDescription(const std::string& name)throw(NutException)
{
return get("UPSDESC", name)[0];
}
std::set<std::string> TcpClient::getDeviceVariableNames(const std::string& dev)throw(NutException)
{
std::set<std::string> set;
std::vector<std::vector<std::string> > res = list("VAR", dev);
for(size_t n=0; n<res.size(); ++n)
{
set.insert(res[n][0]);
}
return set;
}
std::set<std::string> TcpClient::getDeviceRWVariableNames(const std::string& dev)throw(NutException)
{
std::set<std::string> set;
std::vector<std::vector<std::string> > res = list("RW", dev);
for(size_t n=0; n<res.size(); ++n)
{
set.insert(res[n][0]);
}
return set;
}
std::string TcpClient::getDeviceVariableDescription(const std::string& dev, const std::string& name)throw(NutException)
{
return get("DESC", dev + " " + name)[0];
}
std::vector<std::string> TcpClient::getDeviceVariableValue(const std::string& dev, const std::string& name)throw(NutException)
{
return get("VAR", dev + " " + name);
}
std::map<std::string,std::vector<std::string> > TcpClient::getDeviceVariableValues(const std::string& dev)throw(NutException)
{
std::map<std::string,std::vector<std::string> > map;
std::vector<std::vector<std::string> > res = list("VAR", dev);
for(size_t n=0; n<res.size(); ++n)
{
std::vector<std::string>& vals = res[n];
std::string var = vals[0];
vals.erase(vals.begin());
map[var] = vals;
}
return map;
}
void TcpClient::setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value)throw(NutException)
{
std::string query = "SET VAR " + dev + " " + name + " " + escape(value);
detectError(sendQuery(query));
}
void TcpClient::setDeviceVariable(const std::string& dev, const std::string& name, const std::vector<std::string>& values)throw(NutException)
{
std::string query = "SET VAR " + dev + " " + name;
for(size_t n=0; n<values.size(); ++n)
{
query += " " + escape(values[n]);
}
detectError(sendQuery(query));
}
std::set<std::string> TcpClient::getDeviceCommandNames(const std::string& dev)throw(NutException)
{
std::set<std::string> cmds;
std::vector<std::vector<std::string> > res = list("CMD", dev);
for(size_t n=0; n<res.size(); ++n)
{
cmds.insert(res[n][0]);
}
return cmds;
}
std::string TcpClient::getDeviceCommandDescription(const std::string& dev, const std::string& name)throw(NutException)
{
return get("CMDDESC", dev + " " + name)[0];
}
void TcpClient::executeDeviceCommand(const std::string& dev, const std::string& name)throw(NutException)
{
detectError(sendQuery("INSTCMD " + dev + " " + name));
}
void TcpClient::deviceLogin(const std::string& dev)throw(NutException)
{
detectError(sendQuery("LOGIN " + dev));
}
void TcpClient::deviceMaster(const std::string& dev)throw(NutException)
{
detectError(sendQuery("MASTER " + dev));
}
void TcpClient::deviceForcedShutdown(const std::string& dev)throw(NutException)
{
detectError(sendQuery("FSD " + dev));
}
int TcpClient::deviceGetNumLogins(const std::string& dev)throw(NutException)
{
std::string num = get("NUMLOGINS", dev)[0];
return atoi(num.c_str());
}
std::vector<std::string> TcpClient::get
(const std::string& subcmd, const std::string& params) throw(NutException)
{
std::string req = subcmd;
if(!params.empty())
{
req += " " + params;
}
std::string res = sendQuery("GET " + req);
detectError(res);
if(res.substr(0, req.size()) != req)
{
throw NutException("Invalid response");
}
return explode(res, req.size());
}
std::vector<std::vector<std::string> > TcpClient::list
(const std::string& subcmd, const std::string& params) throw(NutException)
{
std::string req = subcmd;
if(!params.empty())
{
req += " " + params;
}
std::string res = sendQuery("LIST " + req);
detectError(res);
if(res != ("BEGIN LIST " + req))
{
throw NutException("Invalid response");
}
std::vector<std::vector<std::string> > arr;
while(true)
{
res = _socket->read();
detectError(res);
if(res == ("END LIST " + req))
{
return arr;
}
if(res.substr(0, req.size()) == req)
{
arr.push_back(explode(res, req.size()));
}
else
{
throw NutException("Invalid response");
}
}
}
std::string TcpClient::sendQuery(const std::string& req)throw(IOException)
{
_socket->write(req);
return _socket->read();
}
void TcpClient::detectError(const std::string& req)throw(NutException)
{
if(req.substr(0,3)=="ERR")
{
throw NutException(req.substr(4));
}
}
std::vector<std::string> TcpClient::explode(const std::string& str, size_t begin)
{
std::vector<std::string> res;
std::string temp;
enum STATE {
INIT,
SIMPLE_STRING,
QUOTED_STRING,
SIMPLE_ESCAPE,
QUOTED_ESCAPE
} state = INIT;
for(size_t idx=begin; idx<str.size(); ++idx)
{
char c = str[idx];
switch(state)
{
case INIT:
if(c==' ' /* || c=='\t' */)
{ /* Do nothing */ }
else if(c=='"')
{
state = QUOTED_STRING;
}
else if(c=='\\')
{
state = SIMPLE_ESCAPE;
}
/* What about bad characters ? */
else
{
temp += c;
state = SIMPLE_STRING;
}
break;
case SIMPLE_STRING:
if(c==' ' /* || c=='\t' */)
{
/* if(!temp.empty()) : Must not occur */
res.push_back(temp);
temp.clear();
state = INIT;
}
else if(c=='\\')
{
state = SIMPLE_ESCAPE;
}
else if(c=='"')
{
/* if(!temp.empty()) : Must not occur */
res.push_back(temp);
temp.clear();
state = QUOTED_STRING;
}
/* What about bad characters ? */
else
{
temp += c;
}
break;
case QUOTED_STRING:
if(c=='\\')
{
state = QUOTED_ESCAPE;
}
else if(c=='"')
{
res.push_back(temp);
temp.clear();
state = INIT;
}
/* What about bad characters ? */
else
{
temp += c;
}
break;
case SIMPLE_ESCAPE:
if(c=='\\' || c=='"' || c==' ' /* || c=='\t'*/)
{
temp += c;
}
else
{
temp += '\\' + c; // Really do this ?
}
state = SIMPLE_STRING;
break;
case QUOTED_ESCAPE:
if(c=='\\' || c=='"')
{
temp += c;
}
else
{
temp += '\\' + c; // Really do this ?
}
state = QUOTED_STRING;
break;
}
}
if(!temp.empty())
{
res.push_back(temp);
}
return res;
}
std::string TcpClient::escape(const std::string& str)
{
std::string res = "\"";
for(size_t n=0; n<str.size(); n++)
{
char c = str[n];
if(c=='"')
res += "\\\"";
else if(c=='\\')
res += "\\\\";
else
res += c;
}
res += '"';
return res;
}
/*
*
* Device implementation
*
*/
Device::Device(Client* client, const std::string& name):
_client(client),
_name(name)
{
}
Device::Device(const Device& dev):
_client(dev._client),
_name(dev._name)
{
}
Device::~Device()
{
}
std::string Device::getName()const
{
return _name;
}
const Client* Device::getClient()const
{
return _client;
}
Client* Device::getClient()
{
return _client;
}
bool Device::isOk()const
{
return _client!=NULL && !_name.empty();
}
Device::operator bool()const
{
return isOk();
}
bool Device::operator!()const
{
return !isOk();
}
bool Device::operator==(const Device& dev)const
{
return dev._client==_client && dev._name==_name;
}
bool Device::operator<(const Device& dev)const
{
return getName()<dev.getName();
}
std::string Device::getDescription()throw(NutException)
{
return getClient()->getDeviceDescription(getName());
}
std::vector<std::string> Device::getVariableValue(const std::string& name)
throw(NutException)
{
return getClient()->getDeviceVariableValue(getName(), name);
}
std::map<std::string,std::vector<std::string> > Device::getVariableValues()
throw(NutException)
{
return getClient()->getDeviceVariableValues(getName());
}
std::set<std::string> Device::getVariableNames()throw(NutException)
{
return getClient()->getDeviceVariableNames(getName());
}
std::set<std::string> Device::getRWVariableNames()throw(NutException)
{
return getClient()->getDeviceRWVariableNames(getName());
}
void Device::setVariable(const std::string& name, const std::string& value)throw(NutException)
{
getClient()->setDeviceVariable(getName(), name, value);
}
void Device::setVariable(const std::string& name, const std::vector<std::string>& values)
throw(NutException)
{
getClient()->setDeviceVariable(getName(), name, values);
}
Variable Device::getVariable(const std::string& name)throw(NutException)
{
if(getClient()->hasDeviceVariable(getName(), name))
return Variable(this, name);
else
return Variable(NULL, "");
}
std::set<Variable> Device::getVariables()throw(NutException)
{
std::set<Variable> set;
std::set<std::string> names = getClient()->getDeviceVariableNames(getName());
for(std::set<std::string>::iterator it=names.begin(); it!=names.end(); ++it)
{
set.insert(Variable(this, *it));
}
return set;
}
std::set<Variable> Device::getRWVariables()throw(NutException)
{
std::set<Variable> set;
std::set<std::string> names = getClient()->getDeviceRWVariableNames(getName());
for(std::set<std::string>::iterator it=names.begin(); it!=names.end(); ++it)
{
set.insert(Variable(this, *it));
}
return set;
}
std::set<std::string> Device::getCommandNames()throw(NutException)
{
return getClient()->getDeviceCommandNames(getName());
}
std::set<Command> Device::getCommands()throw(NutException)
{
std::set<Command> cmds;
std::set<std::string> res = getCommandNames();
for(std::set<std::string>::iterator it=res.begin(); it!=res.end(); ++it)
{
cmds.insert(Command(this, *it));
}
return cmds;
}
Command Device::getCommand(const std::string& name)throw(NutException)
{
if(getClient()->hasDeviceCommand(getName(), name))
return Command(this, name);
else
return Command(NULL, "");
}
void Device::executeCommand(const std::string& name)throw(NutException)
{
getClient()->executeDeviceCommand(getName(), name);
}
void Device::login()throw(NutException)
{
getClient()->deviceLogin(getName());
}
void Device::master()throw(NutException)
{
getClient()->deviceMaster(getName());
}
void Device::forcedShutdown()throw(NutException)
{
}
int Device::getNumLogins()throw(NutException)
{
return getClient()->deviceGetNumLogins(getName());
}
/*
*
* Variable implementation
*
*/
Variable::Variable(Device* dev, const std::string& name):
_device(dev),
_name(name)
{
}
Variable::Variable(const Variable& var):
_device(var._device),
_name(var._name)
{
}
Variable::~Variable()
{
}
std::string Variable::getName()const
{
return _name;
}
const Device* Variable::getDevice()const
{
return _device;
}
Device* Variable::getDevice()
{
return _device;
}
bool Variable::isOk()const
{
return _device!=NULL && !_name.empty();
}
Variable::operator bool()const
{
return isOk();
}
bool Variable::operator!()const
{
return !isOk();
}
bool Variable::operator==(const Variable& var)const
{
return var._device==_device && var._name==_name;
}
bool Variable::operator<(const Variable& var)const
{
return getName()<var.getName();
}
std::vector<std::string> Variable::getValue()throw(NutException)
{
return getDevice()->getClient()->getDeviceVariableValue(getDevice()->getName(), getName());
}
std::string Variable::getDescription()throw(NutException)
{
return getDevice()->getClient()->getDeviceVariableDescription(getDevice()->getName(), getName());
}
void Variable::setValue(const std::string& value)throw(NutException)
{
getDevice()->setVariable(getName(), value);
}
void Variable::setValues(const std::vector<std::string>& values)throw(NutException)
{
getDevice()->setVariable(getName(), values);
}
/*
*
* Command implementation
*
*/
Command::Command(Device* dev, const std::string& name):
_device(dev),
_name(name)
{
}
Command::Command(const Command& cmd):
_device(cmd._device),
_name(cmd._name)
{
}
Command::~Command()
{
}
std::string Command::getName()const
{
return _name;
}
const Device* Command::getDevice()const
{
return _device;
}
Device* Command::getDevice()
{
return _device;
}
bool Command::isOk()const
{
return _device!=NULL && !_name.empty();
}
Command::operator bool()const
{
return isOk();
}
bool Command::operator!()const
{
return !isOk();
}
bool Command::operator==(const Command& cmd)const
{
return cmd._device==_device && cmd._name==_name;
}
bool Command::operator<(const Command& cmd)const
{
return getName()<cmd.getName();
}
std::string Command::getDescription()throw(NutException)
{
return getDevice()->getClient()->getDeviceCommandDescription(getDevice()->getName(), getName());
}
void Command::execute()throw(NutException)
{
getDevice()->executeCommand(getName());
}
} /* namespace nut */
/**
* C nutclient API.
*/
extern "C" {
strarr strarr_alloc(unsigned short count)
{
strarr arr = (strarr)xcalloc(count+1, sizeof(char*));
arr[count] = NULL;
return arr;
}
void strarr_free(strarr arr)
{
char** pstr = arr;
while(*pstr!=NULL)
{
free(*pstr);
++pstr;
}
free(arr);
}
static strarr stringset_to_strarr(const std::set<std::string>& strset)
{
strarr arr = strarr_alloc(strset.size());
strarr pstr = arr;
for(std::set<std::string>::const_iterator it=strset.begin(); it!=strset.end(); ++it)
{
*pstr = xstrdup(it->c_str());
}
return arr;
}
static strarr stringvector_to_strarr(const std::vector<std::string>& strset)
{
strarr arr = strarr_alloc(strset.size());
strarr pstr = arr;
for(std::vector<std::string>::const_iterator it=strset.begin(); it!=strset.end(); ++it)
{
*pstr = xstrdup(it->c_str());
}
return arr;
}
NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short port)
{
nut::TcpClient* client = new nut::TcpClient;
try
{
client->connect(host, port);
return (NUTCLIENT_TCP_t)client;
}
catch(nut::NutException& ex)
{
// TODO really catch it
delete client;
return NULL;
}
}
void nutclient_destroy(NUTCLIENT_t client)
{
if(client)
{
delete (nut::Client*)client;
}
}
int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client)
{
if(client)
{
nut::TcpClient* cl = dynamic_cast<nut::TcpClient*>((nut::Client*)client);
if(cl)
{
return cl->isConnected() ? 1 : 0;
}
}
return 0;
}
void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client)
{
if(client)
{
nut::TcpClient* cl = dynamic_cast<nut::TcpClient*>((nut::Client*)client);
if(cl)
{
cl->disconnect();
}
}
}
int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client)
{
if(client)
{
nut::TcpClient* cl = dynamic_cast<nut::TcpClient*>((nut::Client*)client);
if(cl)
{
try
{
cl->connect();
return 0;
}
catch(...){}
}
}
return -1;
}
void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, long timeout)
{
if(client)
{
nut::TcpClient* cl = dynamic_cast<nut::TcpClient*>((nut::Client*)client);
if(cl)
{
cl->setTimeout(timeout);
}
}
}
long nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client)
{
if(client)
{
nut::TcpClient* cl = dynamic_cast<nut::TcpClient*>((nut::Client*)client);
if(cl)
{
return cl->getTimeout();
}
}
return -1;
}
void nutclient_authenticate(NUTCLIENT_t client, const char* login, const char* passwd)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->authenticate(login, passwd);
}
catch(...){}
}
}
}
void nutclient_logout(NUTCLIENT_t client)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->logout();
}
catch(...){}
}
}
}
void nutclient_device_login(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->deviceLogin(dev);
}
catch(...){}
}
}
}
int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return cl->deviceGetNumLogins(dev);
}
catch(...){}
}
}
return -1;
}
void nutclient_device_master(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->deviceMaster(dev);
}
catch(...){}
}
}
}
void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->deviceForcedShutdown(dev);
}
catch(...){}
}
}
}
strarr nutclient_get_devices(NUTCLIENT_t client)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return stringset_to_strarr(cl->getDeviceNames());
}
catch(...){}
}
}
return NULL;
}
int nutclient_has_device(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return cl->hasDevice(dev)?1:0;
}
catch(...){}
}
}
return 0;
}
char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return xstrdup(cl->getDeviceDescription(dev).c_str());
}
catch(...){}
}
}
return NULL;
}
strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return stringset_to_strarr(cl->getDeviceVariableNames(dev));
}
catch(...){}
}
}
return NULL;
}
strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return stringset_to_strarr(cl->getDeviceRWVariableNames(dev));
}
catch(...){}
}
}
return NULL;
}
int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return cl->hasDeviceVariable(dev, var)?1:0;
}
catch(...){}
}
}
return 0;
}
char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* dev, const char* var)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return xstrdup(cl->getDeviceVariableDescription(dev, var).c_str());
}
catch(...){}
}
}
return NULL;
}
strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return stringvector_to_strarr(cl->getDeviceVariableValue(dev, var));
}
catch(...){}
}
}
return NULL;
}
void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->setDeviceVariable(dev, var, value);
}
catch(...){}
}
}
}
void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var, const strarr values)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
std::vector<std::string> vals;
strarr pstr = (strarr)values;
while(*pstr)
{
vals.push_back(std::string(*pstr));
++pstr;
}
cl->setDeviceVariable(dev, var, vals);
}
catch(...){}
}
}
}
strarr nutclient_get_device_commands(NUTCLIENT_t client, const char* dev)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return stringset_to_strarr(cl->getDeviceCommandNames(dev));
}
catch(...){}
}
}
return NULL;
}
int nutclient_has_device_command(NUTCLIENT_t client, const char* dev, const char* cmd)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return cl->hasDeviceCommand(dev, cmd)?1:0;
}
catch(...){}
}
}
return 0;
}
char* nutclient_get_device_command_description(NUTCLIENT_t client, const char* dev, const char* cmd)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
return xstrdup(cl->getDeviceCommandDescription(dev, cmd).c_str());
}
catch(...){}
}
}
return NULL;
}
void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const char* cmd)
{
if(client)
{
nut::Client* cl = (nut::Client*)client;
if(cl)
{
try
{
cl->executeDeviceCommand(dev, cmd);
}
catch(...){}
}
}
}
} /* extern "C" */