This commit is contained in:
j3d1 2016-02-23 21:47:45 +01:00
parent 299490ca5f
commit 0f01d375db
13 changed files with 347 additions and 262 deletions

View file

@ -15,8 +15,7 @@ $(BUILDDIR):
$(TARGET): $(OBJECTS)
$(CC) $^ -o $(BUILDDIR)/$@ -lboost_filesystem -lboost_system -lpthread
$(CC) $^ -o $(BUILDDIR)/$@ -lboost_filesystem -lboost_system -lreadline -lboost_program_options
$(OBJECTS): $(BUILDDIR)/%.o : $(SOURCEDIR)/%.cpp
$(CC) $(CFLAGS) $< -o $@

View file

@ -3,8 +3,10 @@ Command-Line Tool which might in the future be able to configure TP-Link Easy Sm
The usage is loosely based on the swconfig utility.
### dependencys
libboost-filesystem-dev
libboost-system-dev
libboost-filesystem
libboost-system
libboost-program-options
libreadline
### compatible devices
+ TL-SG105E

View file

@ -7,27 +7,40 @@
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include<boost/program_options/parsers.hpp>
#include<readline/readline.h>
#include<readline/history.h>
#include "Program.h"
#include "Interactive.h"
using namespace std;
Interactive::Interactive() {
// TODO Auto-generated constructor stub
}
Interactive::~Interactive() {
// TODO Auto-generated destructor stub
}
int Interactive::run() {
int Interactive::loop() {
string cmd;
while(cmd.compare("quit")){
cout<< "smrtlink>" << flush;
cin >> cmd;
cout << cmd <<endl;;
vector<string> v;
Program p = Program();
p.init();
while (1) {
cmd = readline("smrtlink> ");
if (!cmd.compare("quit") || !cmd.compare("q"))
return 0;
if (!cmd.empty()) {
add_history(cmd.c_str());
v = boost::program_options::split_unix(cmd);
p.run(v);
}
}
return 0;
}
int Interactive::single(vector<string> v) {
Program p = Program();
p.init();
p.run(v);
return 0;
}

View file

@ -10,9 +10,12 @@
class Interactive {
public:
Interactive();
virtual ~Interactive();
int run();
Interactive() {
}
virtual ~Interactive() {
}
int loop();
int single(std::vector<std::string> v);
};
#endif /* INTERACTIVE_H_ */

View file

@ -158,8 +158,8 @@ std::string Packet::opCodeToString() {
return "SET";
case CONFIRM:
return "CONFIRM";
case RETURN:
return "RETURN";
case REPLY:
return "REPLY";
default:
return "NONE";
}

View file

@ -15,10 +15,11 @@
static short sequenceId = 0;
class Packet
{
class Packet {
public:
enum OpCode {DISCOVERY, GET, RETURN, SET, CONFIRM, NONE};
enum OpCode {
DISCOVERY, GET, REPLY, SET, CONFIRM, NONE
};
Packet(OpCode);
static void encode(bytes&);
bytes getBytes();

View file

@ -6,6 +6,9 @@
*/
#include <iostream>
#include <algorithm>
#include <regex>
#include <string>
#include <cstring>
#include "Constant.h"
#include "Program.h"
@ -14,11 +17,110 @@
#include "Socket.h"
#include "Switch.h"
#include "Packet.h"
#include "Filter.h"
#include "Types.h"
#include "lookup.h"
#include "table.h"
using namespace smrtlink;
using namespace std;
int Program::run(vector<string> arg) {
int optind = 0;
std::vector<std::string> vect;
std::map<std::string, std::string> ll;
std::cmatch sm;
std::string cmd = arg[optind++];
io_service->reset();
sock->clear();
switch (caseArg(cmd.c_str())) {
case caseArg("reboot"):
if (reboot())
return 1;
break;
case caseArg("reset"):
if (!reset())
return 0;
break;
case caseArg("save"):
if (save())
return 1;
break;
case caseArg("restore"):
if (restore())
return 1;
break;
case caseArg("flash"):
if (flash())
return 1;
break;
case caseArg("list"):
if (list())
return 1;
break;
case caseArg("sniff"):
if (sniff())
return 1;
break;
case caseArg("encode"):
if (optind < arg.size()) {
std::string s(arg[optind]);
optind++;
if (!encode(s))
return 1;
} else {
fprintf(stderr, "Argument expected after encode\n");
return 1;
}
break;
case caseArg("set"):
while (optind < arg.size()) {
if (regex_match(arg[optind].c_str(), sm,
std::regex("^([a-z]+)=(.*)$"))) {
if (!snd_lookup.exists(sm[1]) && !rcv_lookup.exists(sm[1])) {
cerr << "Unknown argument " << arg[optind] << endl;
return 1;
}
ll.insert(std::pair<std::string, std::string>(sm[1], sm[2]));
} else {
cerr << "Invalid Syntax " << arg[optind] << endl;
return 1;
}
optind++;
}
if (setProperty(ll))
return 1;
break;
case caseArg("get"):
while (optind < arg.size()) {
if (regex_match(arg[optind].c_str(), sm,
std::regex("^([a-z]+)$"))) {
if (!snd_lookup.exists(sm[1]) && !rcv_lookup.exists(sm[1])) {
cerr << "Unknown argument " << arg[optind] << endl;
return 1;
}
vect.push_back(sm[1]);
} else {
cerr << "Invalid argument " << arg[optind] << endl;
return 1;
}
optind++;
}
if (getProperty(vect))
return 1;
break;
default:
printf("Unknown command: %s\n", cmd.c_str());
return 1;
}
io_service->run();
return 0;
}
int printHeader(Packet p) {
if (options.flags.HEADER) {
if (options.flags.HEX) {
@ -93,15 +195,18 @@ int Program::list() {
cout <<"Received Payload:\n"<<a.getBody()<<"\n";
} else {
datasets d =a.getPayload();
Switch sw = Switch();
sw.parse(d);
int b = a.getSwitchMac().hash();
if (devices.empty()||devices.find(b) == devices.end())
devices.insert(pair<int,Switch>(b,Switch()));
devices[a.getSwitchMac().hash()].parse(d);
devices[a.getSwitchMac().hash()].print();
File f;
f.write(sw.toString());
sw.print();
f.write(devices[a.getSwitchMac().hash()].toString());
}
return 0;
});
io_service->run();
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
@ -111,22 +216,15 @@ int Program::list() {
int Program::sniff() {
printf("Listening:\n");
try {
boost::asio::io_service io_service;
Socket s(io_service);
s.setHostIp(host.getIp());
s.init(DST_PORT, SRC_PORT);
s.callback = [](Packet p) {
sock->listen([](Packet p) {
cout << p.opCodeToString() << "\n";
printHeader(p);
printPacket(p);
return 0;
};
s.listen();
io_service.run();
});
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
@ -179,8 +277,6 @@ int Program::setProperty(map<string, string> prop) {
});
return 0;
});
io_service->run();
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
@ -210,7 +306,6 @@ int Program::getProperty(vector<string> prop) {
return 0;
});
io_service->run();
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
@ -240,19 +335,20 @@ int Program::flash() {
int Program::reboot() {
try {
discover([this](Packet a) {
discover(
[this](Packet a) {
datasets d =a.getPayload();
Switch sw = Switch();
sw.parse(d);
cout <<sw.settings.hostname<<"\t";
int b = a.getSwitchMac().hash();
if (devices.empty()||devices.find(b) == devices.end())
devices.insert(pair<int,Switch>(b,Switch()));
devices[a.getSwitchMac().hash()].parse(d);
datasets t = { {SND_PING, 0, {}}};
get(a, t, [this](Packet a) {
datasets d =a.getPayload();
Switch sw = Switch();
sw.parse(d);
cout <<devices[a.getSwitchMac().hash()].settings.hostname<<"\t";
devices[a.getSwitchMac().hash()].parse(d);
datasets t = { {REBOOT, 1, {options.flags.PERMANENT?(byte)1:(byte)0}}};
set(a,t,[this](Packet a) {
if( a.getOpCode()==Packet::CONFIRM)
cout<< "rebooting now.\n";
return 0;
});
@ -260,7 +356,6 @@ int Program::reboot() {
});
return 0;
});
io_service->run();
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
@ -289,33 +384,32 @@ int Program::reset() {
});
return 0;
});
io_service->run();
} catch (exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
int Program::discover(function<int(Packet)> c) {
int Program::discover(Listener c) {
Packet p = Packet(Packet::DISCOVERY);
p.setHostMac(host.getMac());
p.setPayload( { });
sock->callback = c;
sock->listen(c, Filter(Packet::REPLY));
sock->send(p);
return 0;
}
int Program::get(Packet l, datasets t, function<int(Packet)> c) {
int Program::get(Packet l, datasets t, Listener c) {
Packet p = Packet(Packet::GET);
p.setSwitchMac(l.getSwitchMac());
p.setHostMac(host.getMac());
p.setPayload(t);
sock->callback = c;
sock->listen(c, Filter(Packet::REPLY).mac(l.getSwitchMac()));
sock->send(p);
return 0;
}
int Program::set(Packet l, datasets t, function<int(Packet)> c) {
int Program::set(Packet l, datasets t, Listener c) {
Packet p = Packet(Packet::SET);
p.setSwitchMac(l.getSwitchMac());
p.setTokenId(l.getTokenId());
@ -325,12 +419,14 @@ int Program::set(Packet l, datasets t, function<int(Packet)> c) {
datasets ld = { { LOGIN_USER, (short) (n.size()), n }, { LOGIN_PASSWORD,
(short) (w.size()), w } };
p.setPayload(ld + t);
sock->callback = c;
sock->listen(c, Filter(Packet::CONFIRM).mac(l.getSwitchMac()));
sock->send(p);
return 0;
}
void Program::init() {
io_service = std::make_shared<boost::asio::io_service>();
sock = std::make_shared < Socket > (*io_service);
if (options.interface.compare("") == 0)
options.interface = host.getIface();

View file

@ -9,9 +9,11 @@
#define PROGRAM_H_
#include <memory>
#include <vector>
#include "Types.h"
#include "Host.h"
#include "Switch.h"
#include "Socket.h"
class Program {
@ -19,15 +21,19 @@ private:
std::shared_ptr<boost::asio::io_service> io_service;
std::shared_ptr<Socket> sock;
Host host = Host();
std::map<int, Switch> devices;
int get(Packet, datasets, std::function<int(Packet)>);
int set(Packet, datasets, std::function<int(Packet)>);
int discover(std::function<int(Packet)>);
public:
Program() {
io_service = std::make_shared<boost::asio::io_service>();
sock = std::make_shared<Socket>(*io_service);
}
void init();
int run(std::vector<std::string>);
std::function<int()> callback = []() {
return 0;
};
int list();
int sniff();
int encode(std::string);

View file

@ -5,22 +5,26 @@
* Author: jdi
*/
#include <cstdlib>
#include <array>
#include <map>
#include <unistd.h>
#include "Socket.h"
#include "Packet.h"
#include "Constant.h"
#include "Filter.h"
#include "Host.h"
#include "Types.h"
using namespace std;
Socket::Socket(boost::asio::io_service& io_service) :
send_socket_(io_service), receive_socket_(io_service), timer(io_service) {
}
//, resolver( io_service)
void Socket::init(short dst_port, short src_port) {
if (initialized)
return;
Socket::~Socket() {
}
void Socket::init(short dst_port, short src_port) {
if (options.flags.REVERSE) {
short p = dst_port;
dst_port = src_port;
@ -47,26 +51,25 @@ void Socket::init(short dst_port, short src_port) {
receive_socket_.set_option(boost::asio::socket_base::broadcast(true));
receive_socket_.set_option(boost::asio::socket_base::reuse_address(true));
receive_socket_.bind(wildcard_endpoint_);
if (options.timeout != 0) {
timer.expires_from_now(
boost::posix_time::milliseconds(options.timeout));
timer.async_wait([this](const boost::system::error_code& error)
{
if (!error)
{
receive_socket_.close();
}
});
}
initialized = 1;
}
void Socket::setHostIp(ipAddr ip) {
local_ip = ip;
}
void Socket::clear(){
callback.clear();
}
void Socket::listen(Listener l, Filter f) {
if (callback.find(f) == callback.end()) {
callback.insert(ListenerPair(f, l));
} else {
callback[f] = l;
}
receive();
}
void Socket::send(Packet p) {
bytes data = p.getBytes();
p.encode(data);
@ -75,11 +78,12 @@ void Socket::send(Packet p) {
broadcast_endpoint_,
[this](boost::system::error_code ec, std::size_t bytes_sent)
{
listen();
receive();
settimeout();
});
}
void Socket::listen() {
void Socket::receive() {
data.resize(MAX_LENGTH);
receive_socket_.async_receive_from(boost::asio::buffer(data, MAX_LENGTH),
remote_endpoint_,
@ -92,13 +96,37 @@ void Socket::listen() {
data.resize(bytes_recvd);
Packet p = Packet(Packet::NONE);
p.encode(data);
// std::cout << "err" << p.getErrorCode() <<std::endl;
p.parse(data);
//std::cout << "err" << p.getErrorCode() <<std::endl;
if(!callback(p)) {
//TODO do something
for(auto r : callback) {
if(r.first.pass(p)) {
r.second(p);
// std::cout<<"pass"<<std::endl;
break;
} else {
// std::cout<<"no pass"<<std::endl;
}
listen();
}
receive();
settimeout();
}
});
}
void Socket::settimeout() {
if (options.timeout != 0) {
timer.expires_from_now(
boost::posix_time::milliseconds(options.timeout));
timer.async_wait(
[this](const boost::system::error_code& error)
{
if (!error)
{
receive_socket_.close();
receive_socket_.open(boost::asio::ip::udp::v4());
receive_socket_.set_option(boost::asio::socket_base::broadcast(true));
receive_socket_.set_option(boost::asio::socket_base::reuse_address(true));
receive_socket_.bind(wildcard_endpoint_);
}
});
}
}

View file

@ -8,8 +8,10 @@
#ifndef SOCKET_H_
#define SOCKET_H_
#include <map>
#include <boost/asio.hpp>
#include "Packet.h"
#include "Filter.h"
#include "Types.h"
#define SRC_PORT 29809
@ -17,20 +19,22 @@
#define MAX_LENGTH 1024
typedef std::function<int(Packet)> Listener;
typedef std::pair<Filter, Listener> ListenerPair;
class Socket {
public:
Socket(boost::asio::io_service&);
virtual ~Socket() {
}
virtual ~Socket();
void init(short, short);
void clear();
void send(Packet);
void listen();
void setHostIp(ipAddr);
std::function<int(Packet)> callback = [](Packet a) {
return 0;
};
void listen(Listener l, Filter f = Filter());
private:
void receive();
void settimeout();
boost::asio::ip::udp::socket send_socket_;
boost::asio::ip::udp::socket receive_socket_;
boost::asio::ip::udp::endpoint broadcast_endpoint_;
@ -40,7 +44,7 @@ private:
boost::asio::deadline_timer timer;
bytes data = bytes(MAX_LENGTH);
ipAddr local_ip;
int initialized = 0;
std::map<Filter, Listener> callback = { };
};

View file

@ -65,9 +65,13 @@ public:
int parse(datasets);
int parse(dataset);
int parse(std::string);
int print();
int set(std::pair<std::string,std::string>);
std::string get(std::string);
std::string toString();
int print();
struct {
std::string type;
std::string hardware_version;

View file

@ -50,6 +50,28 @@ public:
else break;
}
}
int hash() {
int ret=0;
for (unsigned i = 0; i < 6; i++) {
ret = (ret*33) ^ (*this)[i];
}
return ret;
}
bool operator==(const macAddr &A) {
for (unsigned i = 0; i < 6; i++) {
if(A[i]!=(*this)[i])return false;
}
return true;
}
bool operator!=(const macAddr &A) {
for (unsigned i = 0; i < 6; i++) {
if(A[i]!=(*this)[i])return true;
}
return false;
}
};
/*
@ -95,6 +117,14 @@ public:
}
};
namespace smrtlink {
constexpr unsigned int caseArg(const char* str, int h = 0) {
return !str[h] ? 5381 : (caseArg(str, h + 1) * 33) ^ str[h];
}
}
template<typename T>
std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B) {
std::vector<T> AB;
@ -117,6 +147,7 @@ struct Options {
bool JSON;
bool PLAIN;
bool REVERSE;
bool HEADER;
bool PERMANENT;
bool WAIT;
@ -128,7 +159,7 @@ struct Options {
std::string file;
int debug_level = 0;
int verbosity = 0;
long timeout = 180U;
long timeout = 250U;
};
#endif /* TYPES_H_ */

View file

@ -1,14 +1,13 @@
//============================================================================
// Name : smrtlink.cpp
// Author : jdi
// Version :
// Version : 1.2
// Copyright : GPL v2
// Description : SmrtLink in C++, Ansi-style
//============================================================================
#include <iostream>
#include <string>
#include <regex>
#include <cstring>
#include <sstream>
@ -21,6 +20,7 @@
#include "Interactive.h"
#include "Host.h"
#include "Program.h"
#include "Types.h"
#include "Switch.h"
#include "lookup.h"
@ -32,10 +32,6 @@ using namespace std;
Options options;
constexpr unsigned int caseArg(const char* str, int h = 0) {
return !str[h] ? 5381 : (caseArg(str, h + 1) * 33) ^ str[h];
}
int main(int argc, char *argv[]) {
int index, opt;
@ -56,7 +52,7 @@ int main(int argc, char *argv[]) {
while ((opt = getopt_long(argc, argv, "bhrVsxP:U:i:t::", longopts,
while ((opt = getopt_long(argc, argv, "bhrVXsxP:U:i:t::", longopts,
&index)) != -1) {
switch (opt) {
@ -149,118 +145,20 @@ int main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
Interactive p = Interactive();
if (options.flags.INTERACTIVE) {
if (optind < argc) {
cerr << "Command is ignored in interactive mode\n";
}
Interactive p = Interactive();
if (!p.run())
if (!p.loop())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
}
else if (optind < argc) {
Program p = Program();
p.init();
std::vector<std::string> vect;
std::map<std::string, std::string> list;
std::cmatch sm;
std::string cmd = std::string(argv[optind++]);
switch (caseArg(cmd.c_str())) {
case caseArg("reboot"):
if (!p.reboot())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("reset"):
if (!p.reset())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("save"):
if (!p.save())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("restore"):
if (!p.restore())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("flash"):
if (!p.flash())
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("list"):
if (!p.list())
exit(EXIT_SUCCESS);
break;
case caseArg("sniff"):
if (!p.sniff())
exit(EXIT_SUCCESS);
break;
case caseArg("encode"):
if (optind < argc) {
std::string s(argv[optind]);
optind++;
if (p.encode(s))
exit(EXIT_SUCCESS);
} else {
fprintf(stderr, "Argument expected after encode\n");
exit(EXIT_FAILURE);
}
break;
case caseArg("set"):
while (optind < argc) {
if (regex_match(argv[optind], sm,
std::regex("^([a-z]+)=(.*)$"))) {
if (!snd_lookup.exists(sm[1])&&!rcv_lookup.exists(sm[1])) {
cerr << "Unknown argument " << argv[optind] << endl;
exit(EXIT_FAILURE);
}
list.insert(
std::pair<std::string, std::string>(sm[1], sm[2]));
} else {
cerr << "Invalid Syntax " << argv[optind] << endl;
exit(EXIT_FAILURE);
}
optind++;
}
if (!p.setProperty(list))
exit(EXIT_SUCCESS);
fprintf(stderr, "Not yet implemented.\n");
exit(EXIT_FAILURE);
break;
case caseArg("get"):
while (optind < argc) {
if (regex_match(argv[optind], sm, std::regex("^([a-z]+)$"))) {
if (!snd_lookup.exists(sm[1])&&!rcv_lookup.exists(sm[1])) {
cerr << "Unknown argument " << argv[optind] << endl;
exit(EXIT_FAILURE);
}
vect.push_back(sm[1]);
} else {
cerr << "Invalid argument " << argv[optind] << endl;
exit(EXIT_FAILURE);
}
optind++;
}
if (!p.getProperty(vect))
exit(EXIT_SUCCESS);
break;
default:
printf("Unknown command: %s\n", cmd.c_str());
exit(EXIT_FAILURE);
}
} else if (optind < argc) {
vector<string> v;
while (optind < argc)
v.push_back(argv[optind++]);
p.single(v);
}
exit(EXIT_FAILURE);
}