diff --git a/Makefile b/Makefile index 2404b58..a031fb5 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,7 @@ $(BUILDDIR): $(TARGET): $(OBJECTS) - $(CC) $^ -o $(BUILDDIR)/$@ -lboost_filesystem -lboost_system - + $(CC) $^ -o $(BUILDDIR)/$@ -lboost_filesystem -lboost_system -lreadline -lboost_program_options $(OBJECTS): $(BUILDDIR)/%.o : $(SOURCEDIR)/%.cpp $(CC) $(CFLAGS) $< -o $@ diff --git a/README.md b/README.md index 36f6447..cd00218 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/Constant.h b/src/Constant.h index 31e73fc..ecc44a4 100644 --- a/src/Constant.h +++ b/src/Constant.h @@ -11,41 +11,31 @@ #include "Types.h" #define VERSION "smrtlink (v1.1 Linux)\n" -#define USAGE "usage: %s [-bdhjrvswx] [-i interface] [-u [password:]username]\n\ - [-p password] \n\n" +#define USAGE "usage: %s [-bhrVstx] [-i interface] [-U [password:]username]\n\ + [-P password] \n\n" #define HELP "\ - Option Summary:\n\ - -h --help This help text\n\ - -v --version Display version of this tool\n\ - -d --debug [n] Show debugging messages\n\ - -r switch ports to emulate switch while sniffing\n\ - -b --header Show header\n\ - -x --hex Display Packets as Hex String\n\ - -j --json Display Packets as JSON\n\ - -i --interface only use one Interface\n\ - -u --user <[password:]username>\n\ - -p --password \n\ - Login with Username and Password\n\ - -f --file choose a settings file\n\n\ - -t --timeout Timeout in milliseconds. Default: 180\n\ - -I --interactive Not yet implemented\n\ - -O --stdout Not yet implemented\n\ - -w --wait Not yet implemented: blocking until operation is completed\n\ - -s --permanent Not yet implemented: make changes immediately permanent\n\n\ - Command Summary:\n\ - help This help text\n\ - list list all connected switches\n\ - sniff [type:] []\n\ - capture and display all incoming or outgoing packets\n\ - depending on the --reverse option\n\ - encode use encoding algorithm on hex data separated by colon\n\ - get Not yet implemented\n\ - set Not yet implemented\n\ - get|save Not yet implemented: save config to file\n\ - set|restore Not yet implemented: restore onfig from file\n\ - flash Not yet implemented: replace firmware\n\ - reboot Not yet implemented\n\ - reset Not yet implemented\n\n\ + Option Summary:\n\ + -h --help This help text\n\ + -V --version Display version of this tool\n\ +\ + -r --reverse switch ports to emulate switch while sniffing\n\ + -i --interface only use one Interface\n\ + -t --timeout Timeout in milliseconds. Default: 180\n\ + -s --permanent make changes immediately permanent\n\ +\ + -b --header Show header\n\ + -x --hex Display Packets as Hex String\n\ +\ + -U --user <[password:]username>\n\ + -P --password \n\ + Login with Username and Password\n\n\ + Command Summary:\n\ + list list all connected switches\n\ + sniff capture and display all incoming or outgoing packets\n\ + depending on the --reverse option\n\ + encode use encoding algorithm on hex data separated by colon\n\ + reboot Not yet implemented\n\ + reset Not yet implemented\n\n\ ### for questions please contact ###\n\n" //TODO /* @@ -54,13 +44,6 @@ * */ -#define FLAG_HEX 1 -#define FLAG_REVERSE 2 -#define FLAG_HEADER 4 -#define FLAG_PERMANENT 8 -#define FLAG_WAIT 16 -#define FLAG_DEBUG 32 - extern Options options; #endif /* OPTIONS_H_ */ diff --git a/src/Filter.cpp b/src/Filter.cpp new file mode 100644 index 0000000..cb5f87d --- /dev/null +++ b/src/Filter.cpp @@ -0,0 +1,53 @@ +/* + * Filter.cpp + * + * Created on: 23.02.2016 + * Author: jedi + */ + +#include "Filter.h" + +Filter::Filter() { +} +Filter::Filter(macAddr a) { + switchMac = a; +} +Filter::Filter(Packet::OpCode o) { + oc = o; +} + +Filter Filter::opcode(Packet::OpCode o) { + oc = o; + return *this; +} +Filter Filter::mac(macAddr a) { + switchMac = a; + return *this; +} +Filter Filter::tokenid(short i) { + tokenId = i; + return *this; +} + +bool Filter::pass(const Packet p) const { + macAddr none { 0, 0, 0, 0, 0, 0 }; + if (this->oc != Packet::NONE && this->oc != p.getOpCode()) + return false; + if (this->switchMac != none && this->switchMac != p.getSwitchMac()) + return false; + if (this->tokenId != -1 && this->tokenId != p.getTokenId()) + return false; + /* if (fragmentOffset != p.getF && fragmentOffset != -1) + return false;*/ + return true; +} + +bool Filter::operator<(const Filter f) const { + if (this->oc != f.oc) + return this->oc > f.oc; + if (this->switchMac != f.switchMac) + return this->switchMac > f.switchMac; + if (this->tokenId != f.tokenId) + return this->tokenId > f.tokenId; + return false; +} diff --git a/src/Filter.h b/src/Filter.h new file mode 100644 index 0000000..a9d9213 --- /dev/null +++ b/src/Filter.h @@ -0,0 +1,30 @@ +/* + * Filter.h + * + * Created on: 23.02.2016 + * Author: jedi + */ + +#ifndef FILTER_H_ +#define FILTER_H_ + +#include "Packet.h" + +class Filter { +public: + Filter(); + Filter(Packet::OpCode); + Filter(macAddr); + Filter opcode(Packet::OpCode); + Filter mac(macAddr); + Filter tokenid(short); + bool pass(const Packet) const; + bool operator<(const Filter) const; +private: + Packet::OpCode oc = Packet::NONE; + macAddr switchMac = { 0, 0, 0, 0, 0, 0 }; + short tokenId = -1; + short fragmentOffset = -1; +}; + +#endif /* FILTER_H_ */ diff --git a/src/Interactive.cpp b/src/Interactive.cpp new file mode 100644 index 0000000..19ab930 --- /dev/null +++ b/src/Interactive.cpp @@ -0,0 +1,46 @@ +/* + * Interactive.cpp + * + * Created on: 27.01.2016 + * Author: jedi + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "Program.h" +#include "Interactive.h" + +using namespace std; + +int Interactive::loop() { + string cmd; + vector 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 v) { + Program p = Program(); + p.init(); + p.run(v); + return 0; +} + diff --git a/src/Interactive.h b/src/Interactive.h new file mode 100644 index 0000000..d1d974a --- /dev/null +++ b/src/Interactive.h @@ -0,0 +1,21 @@ +/* + * Interactive.h + * + * Created on: 27.01.2016 + * Author: jedi + */ + +#ifndef INTERACTIVE_H_ +#define INTERACTIVE_H_ + +class Interactive { +public: + Interactive() { + } + virtual ~Interactive() { + } + int loop(); + int single(std::vector v); +}; + +#endif /* INTERACTIVE_H_ */ diff --git a/src/Options.h b/src/Options.h deleted file mode 100644 index 034ee3f..0000000 --- a/src/Options.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Options.h - * - * Created on: 11.09.2015 - * Author: jdi - */ - -#ifndef OPTIONS_H_ -#define OPTIONS_H_ - -#include "Types.h" - -#define VERSION "smrtlink (v1 Linux)\n" -#define USAGE "usage: %s [-bdhjrvswx] [-i interface] [-u [password:]username]\n\ - [-p password] \n\n" -#define HELP "\ - Option Summary:\n\ - -h --help This help text\n\ - -v --version Display version of this tool\n\ - -d --debug [n] Show debugging messages\n\ - -r switch ports to emulate switch while sniffing\n\ - -b --header Show header\n\ - -x --hex Display Packets as Hex String\n\ - -j --json Display Packets as JSON\n\ - -i --interface only use one Interface\n\ - -u --user <[password:]username>\n\ - -p --password \n\ - Login with Username and Password\n\ - -f --file choose a settings file\n\n\ - -t --timeout Timeout in milliseconds. Default: 180\n\ - -I --interactive Not yet implemented\n\ - -O --stdout Not yet implemented\n\ - -w --wait Not yet implemented: blocking until operation is completed\n\ - -s --permanent Not yet implemented: make changes immediately permanent\n\n\ - Command Summary:\n\ - help This help text\n\ - list list all connected switches\n\ - sniff [type:] []\n\ - capture and display all incoming or outgoing packets\n\ - depending on the --reverse option\n\ - encode use encoding algorithm on hex data separated by colon\n\ - get Not yet implemented\n\ - set Not yet implemented\n\ - get|save Not yet implemented: save config to file\n\ - set|restore Not yet implemented: restore onfig from file\n\ - flash Not yet implemented: replace firmware\n\ - reboot Not yet implemented\n\ - reset Not yet implemented\n\n\ - ### for questions please contact ###\n\n" -//TODO -/* - * Stdin - * socketmode - * - */ - -#define FLAG_HEX 1 -#define FLAG_REVERSE 2 -#define FLAG_HEADER 4 -#define FLAG_PERMANENT 8 -#define FLAG_WAIT 16 -#define FLAG_DEBUG 32 - -extern Options options; - -#endif /* OPTIONS_H_ */ diff --git a/src/Packet.cpp b/src/Packet.cpp index ce3ad13..9bcf06c 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -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"; } @@ -277,6 +277,14 @@ void Packet::pull(bytes &arr, int &index, int &ret) { ret |= arr[index++] & 0xFF; } +byte Packet::getOpCode() const { + return opCode; +} + +void Packet::setOpCode(byte opCode) { + this->opCode = opCode; +} + void Packet::pull(bytes &arr, int &index, dataset &ret) { pull(arr, index, ret.type); pull(arr, index, ret.len); diff --git a/src/Packet.h b/src/Packet.h index 327e713..a34e1c9 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -13,14 +13,15 @@ #include "Types.h" -static short sequenceId=0; +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); - void encode(bytes&); + static void encode(bytes&); bytes getBytes(); void parse(bytes); void printHeader(); @@ -37,10 +38,12 @@ public: void setHostMac(macAddr); void setSwitchMac(macAddr); void setCheckSum(int); - void setSequenceId(short ); + void setSequenceId(short); void setPayload(datasets payload); short getTokenId() const; void setTokenId(short tokenId = 0); + byte getOpCode() const; + void setOpCode(byte opCode); private: bytes head = bytes(32); @@ -48,9 +51,9 @@ private: datasets payload; byte version = 1; byte opCode; - macAddr switchMac { {0, 0, 0, 0, 0, 0}}; - macAddr hostMac { {0, 0, 0, 0, 0, 0}}; - macAddr broadcastMac { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; + macAddr switchMac { { 0, 0, 0, 0, 0, 0 } }; + macAddr hostMac { { 0, 0, 0, 0, 0, 0 } }; + macAddr broadcastMac { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; short tokenId = 0; short fragmentOffset = 0; int errorCode = 0; @@ -58,7 +61,7 @@ private: short flag = 0; void buildHead(); void buildBody(); - void push(bytes&, int&, short ); + void push(bytes&, int&, short); void push(bytes&, int&, int); void push(bytes&, int&, byte); void push(bytes&, int&, bytes); @@ -68,7 +71,7 @@ private: void pull(bytes&, int&, short &); void pull(bytes&, int&, int&); void pull(bytes&, int&, byte&); - void pull(bytes&, int&, bytes&, unsigned ); + void pull(bytes&, int&, bytes&, unsigned); void pull(bytes&, int&, ipAddr&); void pull(bytes&, int&, macAddr&); void pull(bytes&, int&, dataset&); diff --git a/src/Program.cpp b/src/Program.cpp index 636ed70..d14c7d1 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -6,6 +6,9 @@ */ #include #include +#include +#include +#include #include "Constant.h" #include "Program.h" @@ -14,13 +17,114 @@ #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 arg) { + int optind = 0; + std::vector vect; + std::map 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(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 & FLAG_HEADER) { - if (options.flags & FLAG_HEX) { - std::cout << "Received Header:\n\t" << p.getHead() << "\n"; + if (options.flags.HEADER) { + if (options.flags.HEX) { + cout << "Received Header:\n\t" << p.getHead() << "\n"; } else { p.printHeader(); printf("\n"); @@ -30,56 +134,51 @@ int printHeader(Packet p) { } int printPacket(Packet p) { - if (options.flags & FLAG_HEX) { - std::cout << "Received Payload:\n\t" << p.getBody() << "\n"; + if (options.flags.HEX) { + cout << "Received Payload:\n\t" << p.getBody() << "\n"; } else { for (dataset d : p.getPayload()) { - auto lookup = - (options.flags & FLAG_REVERSE) ? snd_lookup : rcv_lookup; + auto lookup = (options.flags.REVERSE) ? snd_lookup : rcv_lookup; if (lookup.exists(d.type)) { table::set s = lookup[d.type]; if (d.len > 0) { switch (s.format) { case table::STRING: - std::cout << "+\t" << s.name << " = " << &d.value[0] - << "\n"; + cout << "+\t" << s.name << " = " << &d.value[0] << "\n"; break; case table::BOOL: - std::cout << "+\t" << s.name << " = " + cout << "+\t" << s.name << " = " << (d.value[0] ? "YES" : "NO") << "\n"; break; case table::HEX: - std::cout << "+\t" << s.name << " = " << d.value - << "\n"; + cout << "+\t" << s.name << " = " << d.value << "\n"; break; case table::DEC: - std::cout << "+\t" << s.name << " = "; + cout << "+\t" << s.name << " = "; if (d.value.size() > 0) - std::cout << std::dec << (unsigned) d.value[0]; + cout << dec << (unsigned) d.value[0]; for (unsigned i = 1; i < d.value.size(); i++) - std::cout << std::dec << "." - << (unsigned) d.value[i]; - std::cout << "\n"; + cout << dec << "." << (unsigned) d.value[i]; + cout << "\n"; break; case table::ACTION: - std::cout << "Error:" << s.name + cout << "Error:" << s.name << " is marked as 'action' but carries payload." << d.value << "\n"; break; default: - std::cout << "+\t" << s.name << " = " << d.value - << "\n"; + cout << "+\t" << s.name << " = " << d.value << "\n"; break; } } else { //empty - std::cout << std::dec << ">\t" << s.name << "\n"; + cout << dec << ">\t" << s.name << "\n"; } } else { //unknown id if (d.len > 0) { - std::cout << "##\t" << d.type << ":\n\t"; - std::cout << std::hex << d.value << std::dec << "\n"; + cout << "##\t" << d.type << ":\n\t"; + cout << hex << d.value << dec << "\n"; } else { //empty - std::cout << "#>\t" << d.type << "\n"; + cout << "#>\t" << d.type << "\n"; } } } @@ -88,144 +187,129 @@ int printPacket(Packet p) { } int Program::list() { - - std::cout << "List:\n"; - Packet p = Packet(Packet::DISCOVERY); - p.setHostMac(host.getMac()); - p.setPayload( { }); - bytes b = p.getBytes(); - p.encode(b); - try { - sock->setHostIp(host.getIp()); - sock->init(DST_PORT, SRC_PORT); - sock->callback = - [this](Packet a) { - printHeader(a); - if (options.flags & FLAG_HEX) { - std::cout <<"Received Payload:\n"<send(b); - io_service->run(); - } catch (std::exception& e) { - std::cerr << "Exception: " << e.what() << "\n"; + cout << "List:\n"; + discover([this](Packet a) { + printHeader(a); + if (options.flags.HEX) { + cout <<"Received Payload:\n"<(b,Switch())); + devices[a.getSwitchMac().hash()].parse(d); + devices[a.getSwitchMac().hash()].print(); + + File f; + f.write(devices[a.getSwitchMac().hash()].toString()); + } + return 0; + }); + } catch (exception& e) { + cerr << "Exception: " << e.what() << "\n"; } - return 1; + return 0; } 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) { - std::cout << p.opCodeToString() << "\n"; + sock->listen([](Packet p) { + cout << p.opCodeToString() << "\n"; printHeader(p); printPacket(p); return 0; - }; - s.listen(); - io_service.run(); - } catch (std::exception& e) { - std::cerr << "Exception: " << e.what() << "\n"; + }); + } catch (exception& e) { + cerr << "Exception: " << e.what() << "\n"; } - - return 1; + return 0; } -int Program::encode(std::string s) { - bytes d(s); - Packet p = Packet(Packet::DISCOVERY); +int Program::encode(string s) { + bytes d; + d = d.readHex(s); + Packet p = Packet(Packet::NONE); p.encode(d); - std::cout << d << std::endl; + cout << d << endl; return 0; } -int Program::setProperty() { - return 0; -} - -int Program::getProperty() { - std::cout << "List:\n"; - Packet p = Packet(Packet::DISCOVERY); - p.setHostMac(host.getMac()); - p.setPayload( { }); - bytes b = p.getBytes(); - p.encode(b); - auto s = sock; +int Program::setProperty(map prop) { try { - sock->setHostIp(host.getIp()); - sock->init(DST_PORT, SRC_PORT); - sock->callback = - [this](Packet a) { - auto s = sock; - datasets d =a.getPayload(); - Switch sw = Switch(); - sw.parse(d); - std::cout <<"\t"<callback = - [this](Packet a) { - auto s = sock; + datasets t = { {SND_PING, 0, {}}}; + get(a, t, [this,data](Packet a) { datasets d =a.getPayload(); Switch sw = Switch(); sw.parse(d); - Packet p = Packet(Packet::SET); - p.setSwitchMac(a.getSwitchMac()); - p.setTokenId(a.getTokenId()); - p.setHostMac(host.getMac()); - bytes n = options.user; - bytes w = options.password; - n.push_back('\0'); - w.push_back('\0'); - datasets t = { - { LOGIN_USER, (short)(n.size()), n}, - { LOGIN_PASSWORD, (short)(w.size()), w}, - { REBOOT, 1, {0}} - }; - p.setPayload(t); - bytes c = p.getBytes(); - p.encode(c); + set(a,data, - sock->callback = - [this](Packet a) { - std::cout << a.opCodeToString() << "\n"; - printHeader(a); - printPacket(a); - return 0; - }; - sock->send(c); + [this](Packet a) { + cout << a.opCodeToString() << "\n"; + printHeader(a); + printPacket(a); + return 0; + }); return 0; - }; - - sock->send(c); - return 0; - }; - sock->send(b); - io_service->run(); - } catch (std::exception& e) { - std::cerr << "Exception: " << e.what() << "\n"; + }); + return 0; + }); + } catch (exception& e) { + cerr << "Exception: " << e.what() << "\n"; } - return 1; + return 0; +} + +int Program::getProperty(vector prop) { + try { + datasets data = { }; + for (string s : prop) { + dataset d; + d.type = snd_lookup.type(s); + data.push_back(d); + } + cout << "List:\n"; + discover([this,data](Packet a) { + datasets d =a.getPayload(); + Switch sw = Switch(); + sw.parse(d); + sw.print(); + get(a, data, [this](Packet a) { + cout << a.opCodeToString() << "\n"; + printHeader(a); + printPacket(a); + return 0; + }); + return 0; + }); + + } catch (exception& e) { + cerr << "Exception: " << e.what() << "\n"; + } + return 0; } int Program::save() { @@ -233,40 +317,119 @@ int Program::save() { sw.settings.hostname = "testname.lan"; File f; f.write(sw.toString()); - return 1; + return 0; } int Program::restore() { File f; Switch sw; sw.parse(f.read()); - std::cout << "Devices:\n\t" << sw.settings.hostname << " (" - << sw.device.type << ")\tMAC: " << sw.device.mac << "\tIP: " - << sw.settings.ip_addr << "\n"; - return 1; + sw.print(); + return 0; } int Program::flash() { - return 0; + return 1; } int Program::reboot() { - + try { + discover( + [this](Packet a) { + datasets d =a.getPayload(); + int b = a.getSwitchMac().hash(); + if (devices.empty()||devices.find(b) == devices.end()) + devices.insert(pair(b,Switch())); + devices[a.getSwitchMac().hash()].parse(d); + datasets t = { {SND_PING, 0, {}}}; + get(a, t, [this](Packet a) { + datasets d =a.getPayload(); + cout <) { +int Program::discover(Listener c) { + Packet p = Packet(Packet::DISCOVERY); + p.setHostMac(host.getMac()); + p.setPayload( { }); + sock->listen(c, Filter(Packet::REPLY)); + sock->send(p); + return 0; +} +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->listen(c, Filter(Packet::REPLY).mac(l.getSwitchMac())); + sock->send(p); + return 0; +} + +int Program::set(Packet l, datasets t, Listener c) { + Packet p = Packet(Packet::SET); + p.setSwitchMac(l.getSwitchMac()); + p.setTokenId(l.getTokenId()); + p.setHostMac(host.getMac()); + bytes n = options.user; + bytes w = options.password; + datasets ld = { { LOGIN_USER, (short) (n.size()), n }, { LOGIN_PASSWORD, + (short) (w.size()), w } }; + p.setPayload(ld + t); + sock->listen(c, Filter(Packet::CONFIRM).mac(l.getSwitchMac())); + sock->send(p); return 0; } void Program::init() { + io_service = std::make_shared(); + sock = std::make_shared < Socket > (*io_service); if (options.interface.compare("") == 0) options.interface = host.getIface(); + + sock->setHostIp(host.getIp()); + sock->init(DST_PORT, SRC_PORT); } diff --git a/src/Program.h b/src/Program.h index 1bd97da..b039623 100644 --- a/src/Program.h +++ b/src/Program.h @@ -9,34 +9,42 @@ #define PROGRAM_H_ #include +#include #include "Types.h" #include "Host.h" +#include "Switch.h" #include "Socket.h" class Program { private: - std::shared_ptr io_service; - std::shared_ptr sock; - Host host = Host(); - int ping(std::function); + std::shared_ptr io_service; + std::shared_ptr sock; + Host host = Host(); + std::map devices; + int get(Packet, datasets, std::function); + int set(Packet, datasets, std::function); + int discover(std::function); public: - Program() { - io_service = std::make_shared(); - sock = std::make_shared(*io_service); - } - void init(); - int list(); - int sniff(); - int encode(std::string); - int setProperty(); - int getProperty(); - int save(); - int restore(); - int flash(); - int reboot(); - int reset(); - std::string input; + Program() { + } + void init(); + int run(std::vector); + std::function callback = []() { + return 0; + }; + + int list(); + int sniff(); + int encode(std::string); + int getProperty(std::vector); + int setProperty(std::map); + int save(); + int restore(); + int flash(); + int reboot(); + int reset(); + std::string input; }; #endif /* PROGRAM_H_ */ diff --git a/src/Socket.cpp b/src/Socket.cpp index 191971e..f6d6282 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -5,29 +5,33 @@ * Author: jdi */ #include -#include +#include #include #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; - if (options.flags & FLAG_REVERSE) { +Socket::~Socket() { +} + +void Socket::init(short dst_port, short src_port) { + if (options.flags.REVERSE) { short p = dst_port; dst_port = src_port; src_port = p; } - if (options.flags & FLAG_DEBUG) + if (options.debug_level >= 1) std::cout << "Local IP:\t" << local_ip << "\n"; wildcard_endpoint_ = boost::asio::ip::udp::endpoint( @@ -47,37 +51,39 @@ 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::send(bytes data) { +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); unsigned char * a = &data[0]; send_socket_.async_send_to(boost::asio::buffer(a, data.size()), 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_, @@ -90,13 +96,37 @@ void Socket::listen() { data.resize(bytes_recvd); Packet p = Packet(Packet::NONE); p.encode(data); - // std::cout << "err" << p.getErrorCode() < #include #include "Packet.h" +#include "Filter.h" #include "Types.h" #define SRC_PORT 29809 @@ -17,30 +19,32 @@ #define MAX_LENGTH 1024 +typedef std::function Listener; +typedef std::pair ListenerPair; + class Socket { public: - Socket(boost::asio::io_service&); - virtual ~Socket() { - } - void init(short, short); - void send(bytes); - void listen(); - void setHostIp(ipAddr); - std::function callback = [](Packet a) { - return 0; - }; + Socket(boost::asio::io_service&); + virtual ~Socket(); + void init(short, short); + void clear(); + void send(Packet); + void setHostIp(ipAddr); + void listen(Listener l, Filter f = Filter()); private: - boost::asio::ip::udp::socket send_socket_; - boost::asio::ip::udp::socket receive_socket_; - boost::asio::ip::udp::endpoint broadcast_endpoint_; - boost::asio::ip::udp::endpoint remote_endpoint_; - boost::asio::ip::udp::endpoint wildcard_endpoint_; - boost::asio::ip::udp::endpoint local_endpoint_; - boost::asio::deadline_timer timer; - bytes data = bytes(MAX_LENGTH); - ipAddr local_ip; - int initialized = 0; + 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_; + boost::asio::ip::udp::endpoint remote_endpoint_; + boost::asio::ip::udp::endpoint wildcard_endpoint_; + boost::asio::ip::udp::endpoint local_endpoint_; + boost::asio::deadline_timer timer; + bytes data = bytes(MAX_LENGTH); + ipAddr local_ip; + std::map callback = { }; }; diff --git a/src/Switch-Cmd.cpp b/src/Switch-Cmd.cpp new file mode 100644 index 0000000..916b69e --- /dev/null +++ b/src/Switch-Cmd.cpp @@ -0,0 +1,31 @@ +/* + * Switch.cpp + * + * Created on: 29.09.2015 + * Author: jdi + */ + +#include +#include "Types.h" +#include "Switch.h" +#include "Constant.h" +#include "table.h" + +using namespace smrtlink; +using namespace std; + +int Switch::set(pair str) { + + return 0; +} + +std::string Switch::get(std::string str) { + std::string ret; + switch (caseArg(str.c_str())) { + case caseArg("ip"): + ret = "0.0.0.0"; + break; + } + return ret; +} + diff --git a/src/Switch-Json.cpp b/src/Switch-Json.cpp index 21f1477..c94961c 100644 --- a/src/Switch-Json.cpp +++ b/src/Switch-Json.cpp @@ -16,7 +16,7 @@ int Switch::parse(std::string str) { if (json.Parse(str.c_str()).HasParseError()) return 1; - if (options.flags & FLAG_DEBUG) + if (options.debug_level>=1) std::cout << "\nParsing to document succeeded.\n"; if (json.IsObject()) { diff --git a/src/Switch.cpp b/src/Switch.cpp index 89419a8..0d6966e 100644 --- a/src/Switch.cpp +++ b/src/Switch.cpp @@ -19,6 +19,12 @@ int Switch::parse(datasets arr) { return 0; } +int Switch::print() { + std::cout << "\t" << settings.hostname << " (" << device.type << ")\tMAC: " + << device.mac << "\tIP: " << settings.ip_addr << "\n"; + return 0; +} + int Switch::parse(dataset d) { switch (d.type) { case RCV_TYPE: @@ -63,4 +69,3 @@ int Switch::parse(dataset d) { } return 0; } - diff --git a/src/Switch.h b/src/Switch.h index 88a3351..cb962ab 100644 --- a/src/Switch.h +++ b/src/Switch.h @@ -65,8 +65,13 @@ public: int parse(datasets); int parse(dataset); int parse(std::string); + int set(std::pair); + + std::string get(std::string); std::string toString(); + int print(); + struct { std::string type; std::string hardware_version; diff --git a/src/Types.h b/src/Types.h index 019c07f..b27657d 100644 --- a/src/Types.h +++ b/src/Types.h @@ -21,105 +21,145 @@ class macAddr: public std::array { public: - friend std::ostream& operator<<(std::ostream& out, const macAddr& arr) { - out << std::hex << std::setw(2) << std::setfill('0') - << (unsigned) arr[0]; - for (unsigned i = 1; i < 6; i++) { - out << ":" << std::setw(2) << std::setfill('0') - << (unsigned) arr[i]; - } - return out; - } + friend std::ostream& operator<<(std::ostream& out, const macAddr& arr) { + out << std::hex << std::setw(2) << std::setfill('0') + << (unsigned) arr[0]; + for (unsigned i = 1; i < 6; i++) { + out << ":" << std::setw(2) << std::setfill('0') + << (unsigned) arr[i]; + } + return out; + } - macAddr() { - *this= {0,0,0,0,0,0}; - } + macAddr() { + *this= {0,0,0,0,0,0}; + } - macAddr(std::initializer_list s) { - int i = 0; + macAddr(std::initializer_list s) { + int i = 0; for (byte b : s) { - if(i<6) (*this)[i++]=b; - else break; + if(i<6) (*this)[i++]=b; + else break; } - } + } - macAddr(bytes bts) { - int i = 0; + macAddr(bytes bts) { + int i = 0; for (byte b : bts) { - if(i<6) (*this)[i++]=b; - else break; + if(i<6) (*this)[i++]=b; + 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; + } }; /* -class mac_addr : public std::array { -public: - typedef std::array super; + class mac_addr : public std::array { + public: + typedef std::array super; - using super::super; - - mac_addr{00, 00, 00, 000}; -}; -*/ + using super::super; + mac_addr{00, 00, 00, 000}; + }; + */ class ipAddr: public std::array { public: - ipAddr() { - *this= {0,0,0,0,0,0}; - } + ipAddr() { + *this= {0,0,0,0,0,0}; + } - ipAddr(std::initializer_list s) { - int i = 0; - for (byte b : s) { - if(i<4) (*this)[i++]=b; - else break; + ipAddr(std::initializer_list s) { + int i = 0; + for (byte b : s) { + if(i<4) (*this)[i++]=b; + else break; } - } + } - ipAddr(bytes bts) { - int i = 0; + ipAddr(bytes bts) { + int i = 0; for (byte b : bts) { - if(i<4) (*this)[i++]=b; - else break; + if(i<4) (*this)[i++]=b; + else break; } - } + } - friend std::ostream& operator<<(std::ostream& out, ipAddr& arr) { - out << std::dec << (unsigned) arr[0]; - for (unsigned i = 1; i < 4; i++) { - out << "." << (unsigned) arr[i]; - } - return out; - } + friend std::ostream& operator<<(std::ostream& out, ipAddr& arr) { + out << std::dec << (unsigned) arr[0]; + for (unsigned i = 1; i < 4; i++) { + out << "." << (unsigned) arr[i]; + } + return out; + } }; +namespace smrtlink { + +constexpr unsigned int caseArg(const char* str, int h = 0) { + return !str[h] ? 5381 : (caseArg(str, h + 1) * 33) ^ str[h]; +} + +} + template std::vector operator+(const std::vector &A, const std::vector &B) { - std::vector AB; - AB.reserve(A.size() + B.size()); // preallocate memory - AB.insert(AB.end(), A.begin(), A.end()); // add A; - AB.insert(AB.end(), B.begin(), B.end()); // add B; - return AB; + std::vector AB; + AB.reserve(A.size() + B.size()); // preallocate memory + AB.insert(AB.end(), A.begin(), A.end()); // add A; + AB.insert(AB.end(), B.begin(), B.end()); // add B; + return AB; } template std::vector &operator+=(std::vector &A, const std::vector &B) { - A.reserve(A.size() + B.size()); - A.insert(A.end(), B.begin(), B.end()); - return A; + A.reserve(A.size() + B.size()); + A.insert(A.end(), B.begin(), B.end()); + return A; } struct Options { - unsigned flags = 0x00; - std::string user; - std::string password; - std::string interface; - std::string file; - int debug_level=0; - long timeout = 180U; + struct { + bool HEX; + bool JSON; + bool PLAIN; + bool REVERSE; + + bool HEADER; + bool PERMANENT; + bool WAIT; + bool INTERACTIVE; + } flags; + std::string user; + std::string password; + std::string interface; + std::string file; + int debug_level = 0; + int verbosity = 0; + long timeout = 250U; }; #endif /* TYPES_H_ */ diff --git a/src/bytes.h b/src/bytes.h index eb129d6..01f597d 100644 --- a/src/bytes.h +++ b/src/bytes.h @@ -28,6 +28,7 @@ public: } bytes(std::string d) : vector(d.begin(), d.end()){ + this->push_back('\0'); } bytes(std::initializer_list s) diff --git a/src/datasets.h b/src/datasets.h index bc9ac83..7b08f4f 100644 --- a/src/datasets.h +++ b/src/datasets.h @@ -27,6 +27,14 @@ public: push_back(b); } } + + datasets operator+(const datasets &B) { + datasets AB; + AB.reserve(this->size() + B.size()); + AB.insert(AB.end(), this->begin(), this->end()); + AB.insert(AB.end(), B.begin(), B.end()); + return AB; + } }; #endif /* DATASETS_H_ */ diff --git a/src/lookup.h b/src/lookup.h index a51f9bf..179c638 100644 --- a/src/lookup.h +++ b/src/lookup.h @@ -15,14 +15,14 @@ enum { }; static table rcv_lookup { -#define LOOKUP_SET(id, num, type) { RCV_ ## id, table::type, #id }, +#define LOOKUP_SET(id, num, type) { RCV_ ## id, table::type,#id, #id }, #include "lookup/rcv.lst" #include "lookup/general.lst" #undef LOOKUP_SET }; static table snd_lookup { -#define LOOKUP_SET(id, num, type) { SND_ ## id, table::type, #id }, +#define LOOKUP_SET(id, num, type) { SND_ ## id, table::type,#id, #id }, #include "lookup/snd.lst" #include "lookup/general.lst" #undef LOOKUP_SET diff --git a/src/lookup/input.lst b/src/lookup/input.lst new file mode 100644 index 0000000..5c48cff --- /dev/null +++ b/src/lookup/input.lst @@ -0,0 +1,38 @@ +LOOKUP_SET(type, TYPE, STRING) //+string +LOOKUP_SET(mac, MAC, HEX) //+byte[6] +LOOKUP_SET(firmware,FIRMWARE_VERSION, STRING) +LOOKUP_SET(hardware,HARDWARE_VERSION, STRING) + + +LOOKUP_SET(HOSTNAME,host, 2, STRING) //+string +LOOKUP_SET(IP_ADDR,ip, 4, DEC) //+byte[4] +LOOKUP_SET(IP_MASK,mask, 5, DEC) //+byte[4] +LOOKUP_SET(GATEWAY,gateway, 6, DEC) //+byte[4] +LOOKUP_SET(DHCP_ENABLED,dhcp, 9, BOOL) //+bool byte + +LOOKUP_SET(PORT_VLAN_FOOOOO, 2101,2101, HEX) + +LOOKUP_SET(PORTS, ports, 10, DEC) //+byte, maybe number of ports + +LOOKUP_SET(IGMP_SNOOPING, igmp, 4352, HEX) //??? +LOOKUP_SET(PORTS_SETTINGS, psetings, 4096, HEX) //+per port +LOOKUP_SET(PORT_TRUNK, trunk, 4608, HEX) //byte[5] last byte bitmask?? + +LOOKUP_SET(MTU_VLAN, 8192,8192, HEX) //byte[2] first byte bool,second byte port id +LOOKUP_SET(PORT_VLAN_ENABLED, 8448,8448, BOOL) //open page +LOOKUP_SET(PORT_VLAN, 8449,8449, HEX) +LOOKUP_SET(PORT_VLAN_MAX, 8450,8450, DEC) +LOOKUP_SET(VLAN_ENABLED, 8704, 8704, BOOL) //+bool byte +LOOKUP_SET(VLAN, 8705,8705, HEX) //+one set per vlan +LOOKUP_SET(VLAN_PVID, 8706,8706, HEX) //+per port +LOOKUP_SET(VLAN_FOOOO, 8707,8707, DEC) //???? + +LOOKUP_SET(QOS_BASIC_ENABLED, 12288,12288, BOOL) //+bool = QoS Mod +LOOKUP_SET(QOS_BASIC, 12289,12289, HEX) //+per port ??? +LOOKUP_SET(BW_CONTROL_INGRESS, 12544,12544, HEX) //+per port ??? +LOOKUP_SET(BW_CONTROL_EGRESS, 12545,12545, HEX) //+per port ??? +LOOKUP_SET(STORM_CONTROL, 12800,12800, HEX) //+per port ??? +LOOKUP_SET(PORT_MIRROR, 16640,16640, HEX) //byte[10] second byte port id??? +LOOKUP_SET(PORT_STATISTICS, 16384,16384, HEX) //+per port ??? +LOOKUP_SET(CABLE_TEST, 16896,16896, HEX) //+per port ??? +LOOKUP_SET(LOOP_PREVENTION, 17152,17152, BOOL) //+bool byte \ No newline at end of file diff --git a/src/smrtlink.cpp b/src/smrtlink.cpp index 8a821ee..735587c 100644 --- a/src/smrtlink.cpp +++ b/src/smrtlink.cpp @@ -1,221 +1,165 @@ //============================================================================ // Name : smrtlink.cpp // Author : jdi -// Version : +// Version : 1.2 // Copyright : GPL v2 // Description : SmrtLink in C++, Ansi-style //============================================================================ -#include #include -#include #include + +#include +#include #include -#include #include #include #include "Constant.h" +#include "Interactive.h" #include "Host.h" #include "Program.h" +#include "Types.h" #include "Switch.h" +#include "lookup.h" #define no_argument 0 #define required_argument 1 #define optional_argument 2 +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 opt, index; + int index, opt; - options.user = DEFAULT_USER; - options.password = DEFAULT_PASS; + options.user = DEFAULT_USER; + options.password = DEFAULT_PASS; - const struct option longopts[] = { { "version", no_argument, 0, 'v' }, { - "help", no_argument, 0, 'h' }, { "reverse", no_argument, 0, 'r' }, { - "permanent", no_argument, 0, 's' }, { "debug", optional_argument, 0, - 'd' }, { "password", required_argument, 0, 'p' }, { "user", - required_argument, 0, 'u' }, { "interface", required_argument, 0, 'i' }, { - "header", required_argument, 0, 'b' }, { "hex", required_argument, - 0, 'x' }, { "file", required_argument, 0, 'f' }, { "timeout", - required_argument, 0, 't' }, { "wait", - required_argument, 0, 'w' }, { 0, 0, 0, 0 }, }; + const struct option longopts[] = { { "version", no_argument, 0, 'V' }, { + "verbose", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, { + "reverse", no_argument, 0, 'r' }, + { "permanent", no_argument, 0, 's' }, { "debug", optional_argument, + 0, 'd' }, { "password", required_argument, 0, 'P' }, { + "user", required_argument, 0, 'U' }, { "interface", + required_argument, 0, 'i' }, { "header", required_argument, + 0, 'b' }, { "hex", required_argument, 0, 'x' }, { "file", + required_argument, 0, 'f' }, { "timeout", required_argument, + 0, 't' }, { "wait", required_argument, 0, 'w' }, { 0, 0, 0, + 0 }, }; - Program p = Program(); - while ((opt = getopt_long(argc, argv, "bhrvswxp:u:i:f:t:d::", longopts, - &index)) != -1) { - switch (opt) { - case 'h': - fprintf(stderr, VERSION); - fprintf(stderr, USAGE, argv[0]); - fprintf(stderr, HELP); - exit(EXIT_SUCCESS); - break; + while ((opt = getopt_long(argc, argv, "bhrVXsxP:U:i:t::", longopts, + &index)) != -1) { + switch (opt) { - case 'v': - fprintf(stderr, VERSION); - exit(EXIT_SUCCESS); - break; + case 'h': + fprintf(stderr, VERSION); + fprintf(stderr, USAGE, argv[0]); + fprintf(stderr, HELP); + exit(EXIT_SUCCESS); + break; - case 'r': - options.flags |= FLAG_REVERSE; - break; + case 'V': + fprintf(stderr, VERSION); + exit(EXIT_SUCCESS); + break; - case 'b': - options.flags |= FLAG_HEADER; - break; + case 'r': + options.flags.REVERSE = true; + break; - case 'x': - options.flags |= FLAG_HEX; - break; + case 'b': + options.flags.HEADER = true; + break; - case 's': - options.flags |= FLAG_PERMANENT; - break; + case 'x': + options.flags.HEX = true; + break; - case 'w': - options.flags |= FLAG_WAIT; - break; + case 's': + options.flags.PERMANENT = true; + break; - case 'd': - options.flags |= FLAG_DEBUG; - if (optarg != NULL) - options.debug_level = atoi(optarg); - break; + case 'w': + options.flags.WAIT = true; + break; - case 't': - options.timeout = atol(optarg); - break; + case 'X': + options.flags.INTERACTIVE = true; + break; - case 'f': - options.file = std::string(optarg); - break; + case 'v': + if (optarg != NULL) + options.verbosity = atoi(optarg); + else + options.verbosity++; + break; - case 'p': - options.password = std::string(optarg); - break; + case 'd': + if (optarg != NULL) + options.debug_level = atoi(optarg); + else + options.debug_level++; + break; - case 'u': - options.user = std::string(optarg); - break; + case 't': + options.timeout = atol(optarg); + break; - case 'i': - options.interface = std::string(optarg); - break; + case 'f': + options.file = std::string(optarg); + break; - default: /* '?' */ - fprintf(stderr, "Unknown option\n"); - fprintf(stderr, USAGE, argv[0]); - exit(EXIT_FAILURE); - } - } + case 'P': + options.password = std::string(optarg); + break; - /*//TODO stdin - std::ostringstream bucket; - bucket << std::cin.rdbuf(); - p.input = bucket.str(); - */ + case 'U': + options.user = std::string(optarg); + break; - if (optind >= argc) { - fprintf(stderr, "Command expected\n"); - fprintf(stderr, USAGE, argv[0]); - exit(EXIT_FAILURE); - } + case 'i': + options.interface = std::string(optarg); + break; - p.init(); + default: /* '?' */ + fprintf(stderr, "Unknown option\n"); + fprintf(stderr, USAGE, argv[0]); + exit(EXIT_FAILURE); + } + } - if (optind < argc) { - std::string cmd = std::string(argv[optind++]); + /*//TODO stdin + std::ostringstream bucket; + bucket << std::cin.rdbuf(); + p.input = bucket.str(); + */ - switch (caseArg(cmd.c_str())) { - case caseArg("set"): - if (p.setProperty()) - exit(EXIT_SUCCESS); - fprintf(stderr, "Not yet implemented.\n"); - exit(EXIT_FAILURE); - break; - 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; + if (optind >= argc && !options.flags.INTERACTIVE) { + cerr << "Command expected\n"; + cerr << USAGE; + exit(EXIT_FAILURE); + } - case caseArg("get"): - if (p.getProperty()) - exit(EXIT_SUCCESS); - 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("help"): - fprintf(stderr, VERSION); - fprintf(stderr, USAGE, argv[0]); - fprintf(stderr, HELP); - exit(EXIT_SUCCESS); - break; - - default: - printf("Unknown command: %s\n", cmd.c_str()); - while (optind < argc) { - printf("->%s\n", argv[optind]); - optind++; - } - exit(EXIT_FAILURE); - } - } - exit(EXIT_FAILURE); + Interactive p = Interactive(); + if (options.flags.INTERACTIVE) { + if (optind < argc) { + cerr << "Command is ignored in interactive mode\n"; + } + if (!p.loop()) + exit(EXIT_SUCCESS); + fprintf(stderr, "Not yet implemented.\n"); + exit(EXIT_FAILURE); + } else if (optind < argc) { + vector v; + while (optind < argc) + v.push_back(argv[optind++]); + p.single(v); + } + exit(EXIT_FAILURE); } diff --git a/src/table.cpp b/src/table.cpp index e207490..f159ced 100644 --- a/src/table.cpp +++ b/src/table.cpp @@ -8,18 +8,35 @@ #include #include "table.h" + table::table(std::initializer_list l) { - int i = 0; - for (set s : l) { - this->left[s.type] = s; - } + int i = 0; + this->data.resize(l.size()); + for (set s : l) { + this->data[i] = s; + this->left[s.type] = &this->data[i]; + this->right[s.name] = &this->data[i]; + i++; + } } -table::set table::operator[](short n){ - return this->left[n]; +const table::set table::operator[](std::string s){ + return *this->right[s]; +} +const table::set table::operator[](short n){ + return *this->left[n]; +} +bool table::exists(std::string s){ + return !(right.find(s) == right.end()); } bool table::exists(short n){ - return !(left.find(n) == left.end()); + return !(left.find(n) == left.end()); +} +short table::type(std::string s){ + return this->right[s]->type; +} +std::string table::id(short n){ + return this->left[n]->id; } std::string table::name(short n){ - return this->left[n].name; + return this->left[n]->name; } diff --git a/src/table.h b/src/table.h index 377c768..128d26e 100644 --- a/src/table.h +++ b/src/table.h @@ -17,14 +17,21 @@ public: struct set { short type; F format; - std::string name; + std::string name; + std::string id; }; - table(std::initializer_list l); - set operator[](short); - bool exists(short); - std::string name(short); + table(std::initializer_list l); + const table::set operator[](std::string); + const table::set operator[](short); + bool exists(std::string); + bool exists(short); + short type(std::string); + std::string id(short); + std::string name(short); private: - std::map left; + std::vector data; + std::map left; + std::map right; }; #endif /* LOOKUPTABLE_H_ */