/* * Copyright (C) 2015 by Multi-Tech Systems * * This file is part of lora-query. * * lora-query 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. * * lora-query 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 lora-query. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Version.h" #define INET_ADDR "127.0.0.1" #define INET_PORT 6677 #define MAX_RECEIVED_BYTES 2000 #define TIMEOUT 100 /* By default 100 msec */ int opt_get_stats = 0; int opt_get_nodelist = 0; int opt_get_json = 0; int opt_stats_reset = 0; int opt_get_nodeconfig = 0; int opt_add_node = 0; int opt_delete_node = 0; int opt_update_node = 0; int opt_command = 0; int opt_timeout = 0; char* command_command; char* node_get_addr; char* node_delete_addr; char* node_config_addr; char* node_update_addr; char* node_update_field; char* node_update_value; int node_add_count = 0; char* node_add_args[6]; int command_count = 0; char* command_args[20]; int timeout = TIMEOUT; const char* cmd_stats = "stats json_api"; const char* cmd_stats_reset = "stats reset"; const char* cmd_node_list = "node stats"; const char* cmd_node_list_json = "node stats json"; const char* cmd_node_update = "node update"; const char* cmd_node_delete = "node delete"; const char* cmd_nodeadd = "node add"; const std::string lora_command_output("/var/tmp/lora_command_output"); const std::string lora_network_stats_json("/var/tmp/lora_network_stats.json"); const std::string lora_network_nodelist("/var/tmp/lora_network_nodelist"); const std::string lora_network_nodelist_json("/var/tmp/lora_network_nodelist.json"); std::stringstream receiveStream; const int nodeSize = 16; const int configSize = 7; void runCmd(const char *command); void printStats(void); void printNodeList(void); void saveToFile(const std::string& fileName, const std::string& buffer); void parseOptions(int argc, char** argv); void printHelp(const std::string& sApp); std::string trim(std::string& str); int main(int argc, char**argv) { parseOptions(argc, argv); if (opt_stats_reset) { runCmd(cmd_stats_reset); } if (opt_command) { std::stringstream cmd; for (int i = 0; i < command_count; i++) { cmd << " " << command_args[i]; } runCmd(cmd.str().c_str()); if (receiveStream.str().empty()) { return 0; } saveToFile(lora_command_output, receiveStream.str()); std::cout << receiveStream.str(); } if (opt_get_stats) { runCmd(cmd_stats); printStats(); } if (opt_get_nodelist) { if (opt_get_json) { runCmd(cmd_node_list_json); if (receiveStream.str().empty()) { return 0; } saveToFile(lora_network_nodelist_json, receiveStream.str()); std::cout << receiveStream.str(); } else { runCmd(cmd_node_list); if (receiveStream.str().empty()) { return 0; } saveToFile(lora_network_nodelist, receiveStream.str()); std::cout << receiveStream.str(); } } if (opt_add_node) { if (node_add_count < 4) { std::cout << "usage: --node-add [CLASS] ([APP-KEY] | [NET-SKEY] [APP-SKEY])\n"; return 0; } std::stringstream cmd; cmd << cmd_nodeadd; for (int i = 0; i < node_add_count; i++) { cmd << " " << node_add_args[i]; } runCmd(cmd.str().c_str()); if (!receiveStream.str().empty()) { std::cout << receiveStream.str(); } } if (opt_delete_node) { char buff[256]; snprintf(buff, 256, "%s %s", cmd_node_delete, node_delete_addr); runCmd(buff); if (!receiveStream.str().empty()) { std::cout << receiveStream.str(); } } if (opt_update_node) { std::stringstream cmd; cmd << cmd_node_update; cmd << " " << node_update_addr; cmd << " " << node_update_field; cmd << " " << node_update_value; runCmd(cmd.str().c_str()); if (!receiveStream.str().empty()) { std::cout << receiveStream.str(); } } return 0; } void runCmd(const char *command) { int sockfd; struct sockaddr_in servaddr; int receiveBytes = 0; char receiveMessage[MAX_RECEIVED_BYTES]; struct timeval tv; if (opt_timeout) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } else { // set initial timeout to 5 seconds tv.tv_sec = 5; tv.tv_usec = 0; } receiveStream.str(""); receiveStream.clear(); if (system("netstat -lanu | grep 6677 &> /dev/null")) { return; } if (NULL == command) { printError("Command is null\n"); return; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(INET_ADDR); servaddr.sin_port = htons(INET_PORT); memset(receiveMessage, 0, MAX_RECEIVED_BYTES); if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { printError("setsockopt error\n"); return; } // Lower timeout for subsequent reads tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; sendto(sockfd, command, strlen(command), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); while (1) { receiveBytes = recvfrom(sockfd, receiveMessage, MAX_RECEIVED_BYTES, 0, NULL, NULL); if (receiveBytes < 0) { /*printf("timeout\n");*/ break; } // Lower timeout for subsequent reads if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { printError("setsockopt error\n"); return; } receiveStream << std::string(receiveMessage, receiveBytes); } } void printStats() { if (receiveStream.str().empty()) { return; } saveToFile(lora_network_stats_json, receiveStream.str()); std::cout << receiveStream.str(); } void saveToFile(const std::string& fileName, const std::string& buffer) { std::ofstream outFile; outFile.open(fileName); outFile << buffer; outFile.close(); } void parseOptions(int argc, char** argv) { if (argc == 1) { printHelp(argv[0]); exit(0); } const char* short_options = "hvsrnc:a:u:d:jt:x:"; const struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { "stats", no_argument, 0, 's' }, { "stats-reset", no_argument, 0, 'r' }, { "node-list", no_argument, 0, 'n' }, { "command", required_argument, 0, 'x' }, { "json", no_argument, 0, 'j' }, { "timeout", required_argument, 0, 't' }, { 0, 0, 0, 0 } }; int rez; int option_index; while ((rez = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) { switch (rez) { case 'x': { ++opt_command; command_args[command_count++] = optarg; for (int i = optind; i < argc; i++) { command_args[command_count++] = argv[i]; } break; } case 's': { ++opt_get_stats; break; } case 'r': { ++opt_stats_reset; break; } case 'n': { ++opt_get_nodelist; break; } case 'j': { ++opt_get_json; break; } case 't': { opt_timeout = 1; timeout = atoi(optarg); break; } case 'v': printf("Version: %s\n", Version::version.c_str()); exit(0); break; case 'h': case '?': default: { printHelp(argv[0]); exit(0); break; } }; }; } void printHelp(const std::string& sApp) { printf("Usage: %s [-t timeout] [-s] [-n]\n", sApp.c_str()); printf("\tSimple UDP client utility to pull info from LoRa Network server\n"); printf("\t--timeout (t) : UDP recv timeout, default: 100 (msecs)\n"); printf("\t--stats (s) : get LoRa Network server statistics\n"); printf("\t--stats-reset (r) : reset LoRa Network server statistics\n"); printf("\t--node-list (n) : get Node List\n"); printf("\t--command (x) : send command string to network server\n"); printf("\t\tusage: --command ...\n"); printf("\t\tex: --command device list json\n"); printf("\t\tex: -x help\n"); printf("\t--json (j) : data in json format\n"); printf("\t--help (?) : returns this message\n"); printf("\t--version (v) : print version\n"); } std::string trim(std::string& str) { str.erase(std::unique(str.begin(), str.end(), [](char a, char b) {return a == ' ' && b == ' ';}), str.end()); return str; }