#include "iobox_api.h" #include "cJSON.h" namespace ANSCENTER { iobox_api::iobox_api(std::string ip_mcast, int port_mcast) { this->ip_mcast = ip_mcast; this->port_mcast = port_mcast; WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "WSAStartup failed with error: " << WSAGetLastError() << std::endl; return; } } iobox_api::~iobox_api() { WSACleanup(); } bool isStringExistInVectorString(const std::vector& vec, const std::string& str) { try { for (const auto& item : vec) { if (item.find(str) != std::string::npos) { std::cout << "Found partial match: " << str << " in " << item << std::endl; return true; } } // for (const auto& item : vec) { // if (item == str) { // std::cout << "Found duplicate: " << str << std::endl; // return true; // } // } return false; // return std::find(vec.begin(), vec.end(), str) != vec.end(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } void printBufferAsHex(const char* buffer, size_t length) { try { for (size_t i = 0; i < length; ++i) { printf("%02X ", static_cast(buffer[i])); if ((i + 1) % 16 == 0) { printf("\n"); } } printf("\n"); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void printStringAsHex(const std::string& str) { try { for (size_t i = 0; i < str.size(); ++i) { printf("%02X ", static_cast(str[i])); if ((i + 1) % 16 == 0) { printf("\n"); } } printf("\n"); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } bool isValidIp(const std::string& ip) { struct sockaddr_in sa; return inet_pton(AF_INET, ip.c_str(), &(sa.sin_addr)) != 0; } std::string hostNameToIp(std::string hostName) { struct hostent* host; struct in_addr addr; if ((host = gethostbyname(hostName.c_str())) == NULL) { std::cerr << "Failed to get host by name: " << hostName << std::endl; return ""; } addr.s_addr = *(u_long*)host->h_addr_list[0]; return inet_ntoa(addr); } std::string checkIpFromRemote(const std::string& remote) { std::string ip; if (!isValidIp(remote)) { std::cout << "Host name address: " << remote << std::endl; ip = hostNameToIp(remote); if (ip == "") { std::cerr << "Failed to get ip from host name: " << remote << std::endl; return ""; } return ip; } else return remote; } iobox_info_t parseIoboxResponseObj(cJSON* responseObj) { try { iobox_info_t info; cJSON* model = cJSON_GetObjectItem(responseObj, "Model"); if (model != nullptr) { info.model = model->valuestring; } cJSON* serial = cJSON_GetObjectItem(responseObj, "Serial"); if (serial != nullptr) { //info.serial_number = serial->valuestring; } cJSON* hwVer = cJSON_GetObjectItem(responseObj, "HwVer"); if (hwVer != nullptr) { info.hardware_version = hwVer->valuestring; } cJSON* fwVer = cJSON_GetObjectItem(responseObj, "FwVer"); if (fwVer != nullptr) { info.firmware_version = fwVer->valuestring; } cJSON* macAddr = cJSON_GetObjectItem(responseObj, "macAddr"); if (macAddr != nullptr) { info.mac_address = macAddr->valuestring; info.serial_number = macAddr->valuestring; } cJSON* localIp = cJSON_GetObjectItem(responseObj, "localIp"); if (localIp != nullptr) { info.ip_address = localIp->valuestring; } return info; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return iobox_info_t(); } } iobox_info_t parseIoboxResponse(const std::string& response) { try{ //exp: {"response": { "Model":"ANS IOBOX","Serial":"IO123","HwVer":"11", "FwVer":"22","macAddr":"a2c3d4e5f6","localIp":"192.168.110.121"}} iobox_info_t info; cJSON* root = cJSON_Parse(response.c_str()); if (root == nullptr) { std::cerr << "Failed to parse JSON" << std::endl; return info; } cJSON* responseObj = cJSON_GetObjectItem(root, "response"); if (responseObj == nullptr) { std::cerr << "Failed to get response object" << std::endl; cJSON_Delete(root); return info; } info = parseIoboxResponseObj(responseObj); cJSON_Delete(root); std::cout << "Parsed IOBox Info:" << std::endl; std::cout << " Model: " << info.model << std::endl; std::cout << " Serial Number: " << info.serial_number << std::endl; std::cout << " Hardware Version: " << info.hardware_version << std::endl; std::cout << " Firmware Version: " << info.firmware_version << std::endl; std::cout << " MAC Address: " << info.mac_address << std::endl; std::cout << " IP Address: " << info.ip_address << std::endl; std::cout << " Public IP Address: " << info.ip_public_address << std::endl; return info; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return iobox_info_t(); } } void show_info_iobox(iobox_info_t iobox_info) { std::cout << " IP Address: " << iobox_info.ip_address << std::endl; } void iobox_api::show_profile_iobox(std::string remote) { try { std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return; } iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; return; } show_profile_iobox(*profile); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void iobox_api::show_profile_iobox(iobox_profile_t profile) { try { // std::cout << "Profile ioboxs: " << this->iobox_profiles.size() << std::endl; // for (const iobox_profile_t& profile : this->iobox_profiles) { // std::cout << "* Index: " << &profile - &this->iobox_profiles[0] << std::endl; show_info_iobox(profile.iobox_info); std::cout << " Is connected: " << profile.is_connected << std::endl; std::cout << " Is anthenticated: " << profile.is_anthenticated << std::endl; std::cout << " TCP Socket: " << profile.sock_tcp << std::endl; std::cout << " Counting get: " << profile.counting_get << std::endl; std::cout << " Model: " << profile.iobox_info.model << std::endl; std::cout << " Serial Number: " << profile.iobox_info.serial_number << std::endl; std::cout << " Hardware Version: " << profile.iobox_info.hardware_version << std::endl; std::cout << " Firmware Version: " << profile.iobox_info.firmware_version << std::endl; std::cout << " MAC Address: " << profile.iobox_info.mac_address << std::endl; std::cout << " IP Address: " << profile.iobox_info.ip_address << std::endl; std::cout << " Public IP Address: " << profile.iobox_info.ip_public_address << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void iobox_api::show_profile_ioboxs() { try { if (this->iobox_profiles.size() == 0) { std::cout << "No iobox profiles" << std::endl; return; } for (const auto& profile : this->iobox_profiles) { std::cout << "* Index: " << &profile - &this->iobox_profiles[0] << std::endl; show_profile_iobox(profile); } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void iobox_api::save_info_iobox(iobox_info_t iobox_info) { try { iobox_profile_t profile; profile.counting_get = 0; profile.is_connected = false; profile.is_anthenticated = false; profile.sock_tcp = INVALID_SOCKET; profile.iobox_info = iobox_info; this->iobox_profiles.push_back(profile); std::cout << "Save iobox, num device current: " << this->iobox_profiles.size() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void iobox_api::remove_last_info_iobox() { try { if (this->iobox_profiles.size() == 0) { std::cout << "No iobox profiles" << std::endl; return; } this->iobox_profiles.pop_back(); std::cout << "Remove last iobox, num device current: " << this->iobox_profiles.size() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } bool iobox_api::sendTcpMessage(const std::string& ip, const char* buffer, size_t length, bool needCheckAuthen) { try { for (auto& profile : this->iobox_profiles) { if ((profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) && profile.is_connected && profile.sock_tcp != INVALID_SOCKET) { if (needCheckAuthen && !profile.is_anthenticated) { std::cerr << "Please anthenticate before send message" << std::endl; return false; } int result = send(profile.sock_tcp, buffer, length, 0); if (result == SOCKET_ERROR) { std::cerr << "send failed with error: " << WSAGetLastError() << std::endl; return false; } std::cout << "Sent " << length << " bytes message to " << ip << std::endl; std::cout << "Message: " << buffer << std::endl; // printBufferAsHex(buffer, length); return true; } } std::cerr << "IP address not found or not connected: " << ip << std::endl; return false; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } bool iobox_api::receiveTcpMessage(const std::string& ip, char* buffer, size_t& length) { try { for (auto& profile : this->iobox_profiles) { if ((profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) && profile.is_connected && profile.sock_tcp != INVALID_SOCKET) { setSocketTimeout(profile.sock_tcp, 3000); int recvLen = recv(profile.sock_tcp, buffer, length, 0); if (recvLen > 0) { length = recvLen; buffer[length] = '\0'; std::cout << "Received message: " << length << " bytes" << std::endl; std::cout << "Message: " << buffer << std::endl; // printBufferAsHex(buffer, recvLen); return true; } else { std::cerr << "recv failed with error: " << WSAGetLastError() << std::endl; return false; } } } std::cerr << "IP address not found or not connected: " << ip << std::endl; return false; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } void iobox_api::sendMulticastMessage(const std::string& message) { try { SOCKET sock = INVALID_SOCKET; struct sockaddr_in multicastAddr; sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl; WSACleanup(); return; } memset(&multicastAddr, 0, sizeof(multicastAddr)); multicastAddr.sin_family = AF_INET; multicastAddr.sin_addr.s_addr = inet_addr(this->ip_mcast.c_str()); multicastAddr.sin_port = htons(this->port_mcast); if (sendto(sock, message.c_str(), message.length(), 0, (struct sockaddr*)&multicastAddr, sizeof(multicastAddr)) == SOCKET_ERROR) { std::cerr << "sendto failed with error: " << WSAGetLastError() << std::endl; } else { std::cout << "Sent message: " << message << std::endl; } closesocket(sock); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } void iobox_api::setSocketTimeout(SOCKET sock, int timeout) { try { struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) < 0) { std::cerr << "setsockopt failed with error: " << WSAGetLastError() << std::endl; } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } std::string createAliasName(const std::string& serial, const std::string& hwVer, const std::string& fwVer, uint16_t index) { return "SN" + serial + "H" + hwVer + "F" + fwVer + "I" + std::to_string(index); } std::string createMulticastAlias(const std::string& aliasName, const std::string& model, const std::string& serial, const std::string& ip) { //exp: Alias-Model-SN-IP return aliasName + "-" + model + "-" + serial + "-" + ip; } uint16_t iobox_api::getIndexIoboxFromIp(const std::string& ip) { try { for (const auto& profile : this->iobox_profiles) { if (profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) { return &profile - &this->iobox_profiles[0] + 1; } } return -1; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return -1; } } std::vector iobox_api::scanNetworkDevicesMulticast(int timeout) { std::lock_guard lock(_mutex); try { std::vector devices; for (const auto& item : this->iobox_profiles) { if (item.is_connected || item.sock_tcp != INVALID_SOCKET) { std::cout << "Please close connection to " << item.iobox_info.ip_address << "(public: " << item.iobox_info.ip_public_address << ") " << "befor new scan" << std::endl; if (!item.iobox_info.ip_public_address.empty()) { disconnectToIobox(item.iobox_info.ip_public_address); } else { disconnectToIobox(item.iobox_info.ip_address); } } } //remove all elements from iobox_profiles before and we start with new scan this->iobox_profiles.clear(); // WSADATA wsaData; SOCKET sock = INVALID_SOCKET; struct sockaddr_in multicastAddr; struct ip_mreq multicastRequest; char recvBuf[1024]; struct sockaddr_in recvAddr; int recvAddrLen = sizeof(recvAddr); std::string message = "{\"request\":\"Discovery\"}"; // if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { // std::cerr << "WSAStartup failed with error: " << WSAGetLastError() << std::endl; // return devices; // } sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl; // WSACleanup(); return devices; } memset(&multicastAddr, 0, sizeof(multicastAddr)); multicastAddr.sin_family = AF_INET; multicastAddr.sin_addr.s_addr = htonl(INADDR_ANY); multicastAddr.sin_port = htons(this->port_mcast); if (bind(sock, (struct sockaddr*)&multicastAddr, sizeof(multicastAddr)) == SOCKET_ERROR) { std::cerr << "bind failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); // WSACleanup(); return devices; } multicastRequest.imr_multiaddr.s_addr = inet_addr(this->ip_mcast.c_str()); multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY); #ifndef TEST_FIX_IP // if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest)) < 0) { // std::cerr << "setsockopt failed with error: " << WSAGetLastError() << std::endl; // closesocket(sock); // // WSACleanup(); // return devices; // } #endif setSocketTimeout(sock, 3000); auto start = std::chrono::steady_clock::now(); sendMulticastMessage(message); while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout)) { int recvLen = recvfrom(sock, recvBuf, sizeof(recvBuf) - 1, 0, (struct sockaddr*)&recvAddr, &recvAddrLen); if (recvLen > 0) { recvBuf[recvLen] = '\0'; std::string message_rsp(recvBuf); std::string senderIp = inet_ntoa(recvAddr.sin_addr); std::cout << "Received message: \"" << message_rsp << "\" from " << senderIp << std::endl; iobox_info_t info = parseIoboxResponse(message_rsp); if (info.ip_address == senderIp && info.ip_address != "" && !isStringExistInVectorString(devices, senderIp)) { std::string aliasName = createAliasName(info.serial_number, info.hardware_version, info.firmware_version, devices.size() + 1); std::string multicastAlias = createMulticastAlias(aliasName, info.model, info.serial_number, info.ip_address); std::cout << "multicast alias: " << multicastAlias << std::endl; devices.push_back(multicastAlias); save_info_iobox(info); } } else { // std::cerr << "recvfrom failed with error: " << WSAGetLastError() << std::endl; // sendMulticastMessage(message); } } #ifndef TEST_FIX_IP // setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest)); #endif closesocket(sock); // WSACleanup(); return devices; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return std::vector(); } } bool parseResponeCommon(const std::string& response, const std::string& action, std::string& getResult, std::string& getReason, iobox_info_t& iobox_info) { try { cJSON* root = cJSON_Parse(response.c_str()); if (root == nullptr) { std::cerr << "Failed to parse JSON" << std::endl; return false; } cJSON* responseObj = cJSON_GetObjectItem(root, "response"); if (responseObj == nullptr) { std::cerr << "Failed to get response object" << std::endl; cJSON_Delete(root); return false; } cJSON* actionResponse = cJSON_GetObjectItem(responseObj, "action"); if (actionResponse == nullptr || strcmp(actionResponse->valuestring, action.c_str()) != 0) { std::cerr << "Action mismatch or not found" << std::endl; cJSON_Delete(root); return false; } cJSON* resultResponse = cJSON_GetObjectItem(responseObj, "result"); if (resultResponse == nullptr) { std::cerr << "Failed to get result" << std::endl; cJSON_Delete(root); return false; } if (resultResponse->type == cJSON_Array) { char* result = cJSON_PrintUnformatted(resultResponse); std::cout << "Result: " << result << std::endl; std::string resultStr(result); cJSON_free(result); getResult = resultStr; } else if (resultResponse->type == cJSON_String) { getResult = resultResponse->valuestring; } if (cJSON_HasObjectItem(responseObj, "info")) { cJSON* infoResponse = cJSON_GetObjectItem(responseObj, "info"); if (infoResponse == nullptr) { std::cerr << "Failed to get info" << std::endl; cJSON_Delete(root); return false; } iobox_info = parseIoboxResponseObj(infoResponse); } cJSON* reasonResponse = cJSON_GetObjectItem(responseObj, "reason"); if (reasonResponse == nullptr) { // std::cerr << "Failed to get reason" << std::endl; cJSON_Delete(root); return true; } getReason = reasonResponse->valuestring; cJSON_Delete(root); return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } std::string iobox_api::connectToIobox(const std::string& remote, int port, const std::string& username, const std::string& password) { // check ip is already in iobox_profiles bool is_exist = false; iobox_profile_t* item = nullptr; std::string aliasConnect = ""; bool is_onlyAuthen = false; std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return aliasConnect; } std::cout << "IP address: " << ip << std::endl; try { for (auto& profile : this->iobox_profiles) { if (profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) { is_exist = true; item = &profile; if (item->is_connected && item->is_anthenticated) { std::cout << "Ip is already connected and anthenticated: " << ip << std::endl; uint16_t idx = getIndexIoboxFromIp(ip); std::string aliasName = createAliasName(item->iobox_info.serial_number, item->iobox_info.hardware_version, item->iobox_info.firmware_version, idx); aliasConnect = createMulticastAlias(aliasName, item->iobox_info.model, item->iobox_info.serial_number, item->iobox_info.ip_public_address == "" ? item->iobox_info.ip_address : item->iobox_info.ip_public_address); return aliasConnect; } else if (item->is_connected && !item->is_anthenticated) { std::cout << "Ip is already connected but not anthenticated: " << ip << std::endl; // std::cout << "Please disconnect before reconnect" << std::endl; // return aliasConnect; is_onlyAuthen = true; } break; } } if (is_exist == false) { std::cout << "Ip is not exist in list scan, now retry connect to this ip and append it to profile: " << ip << std::endl; // return false; } // WSADATA wsaData; SOCKET sock = INVALID_SOCKET; struct sockaddr_in serverAddr; char recvBuf[1024]; int recvLen = 0; struct timeval tv; tv.tv_sec = 3000; tv.tv_usec = 0; // Initialize Winsock // int result = WSAStartup(MAKEWORD(2, 2), &wsaData); // if (result != 0) { // std::cerr << "WSAStartup failed: " << result << std::endl; // return false; // } if (is_onlyAuthen == false) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl; // WSACleanup(); return aliasConnect; } serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr(ip.c_str()); serverAddr.sin_port = htons(port); if (connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { std::cerr << "connect failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); // WSACleanup(); return aliasConnect; } } else { sock = item->sock_tcp; } setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); std::string action = "auth"; //{"request":{"action":"auth","username":"","password":""}} std::string authMessage = "{\"request\":{\"action\":\"" + action + "\",\"username\":\"" + username + "\",\"password\":\"" + password + "\"}}"; int sendLen = send(sock, authMessage.c_str(), authMessage.length(), 0); if (sendLen == SOCKET_ERROR) { std::cerr << "send failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); // WSACleanup(); return aliasConnect; } //{"response":{"action":"auth","result":"","reason":""}} iobox_info_t info; recvLen = recv(sock, recvBuf, sizeof(recvBuf) - 1, 0); if (recvLen > 0) { recvBuf[recvLen] = '\0'; std::cout << "Received message: " << recvBuf << std::endl; std::string response(recvBuf); std::string result; std::string reason; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; if (result == "success") { std::cout << "Authentication success" << std::endl; } else { std::cerr << "Authentication failed" << std::endl; std::cerr << "Reason: " << reason << std::endl; closesocket(sock); // WSACleanup(); return aliasConnect; } } else { std::cerr << "Parse response failed" << std::endl; closesocket(sock); // WSACleanup(); return aliasConnect; } } else { std::cerr << "recv failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); // WSACleanup(); return aliasConnect; } // closesocket(sock); // WSACleanup(); if (item == nullptr) { if (info.ip_address == "") { std::cerr << "Failed to get info from response" << std::endl; closesocket(sock); return aliasConnect; } if (info.ip_address != ip) { info.ip_public_address = ip; } save_info_iobox(info); for (auto& profile : this->iobox_profiles) { if (profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) { item = &profile; break; } } } if (item == nullptr) return aliasConnect; uint16_t idx = getIndexIoboxFromIp(ip); std::string aliasName = createAliasName(item->iobox_info.serial_number, item->iobox_info.hardware_version, item->iobox_info.firmware_version, idx); aliasConnect = createMulticastAlias(aliasName, item->iobox_info.model, item->iobox_info.serial_number, item->iobox_info.ip_public_address == "" ? item->iobox_info.ip_address : item->iobox_info.ip_public_address); std::cout << "alias: " << aliasConnect << std::endl; item->sock_tcp = sock; item->is_connected = true; item->is_anthenticated = true; return aliasConnect; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return aliasConnect; } } bool iobox_api::connectToIoboxWithoutAuthen(const std::string& remote, int port) { // check ip is already in iobox_profiles bool is_exist = false; iobox_profile_t* item = nullptr; std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { for (auto& profile : this->iobox_profiles) { if (profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) { is_exist = true; item = &profile; if (item->is_connected) { std::cout << "Ip is already connected: " << ip << std::endl; return true; } break; } } if (is_exist == false) { std::cout << "Ip is not exist in list scan" << ip << std::endl; return false; } // WSADATA wsaData; SOCKET sock = INVALID_SOCKET; struct sockaddr_in serverAddr; char recvBuf[1024]; int recvLen = 0; struct timeval tv; tv.tv_sec = 3000; tv.tv_usec = 0; // Initialize Winsock // int result = WSAStartup(MAKEWORD(2, 2), &wsaData); // if (result != 0) { // std::cerr << "WSAStartup failed: " << result << std::endl; // return false; // } sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl; // WSACleanup(); return false; } serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr(ip.c_str()); serverAddr.sin_port = htons(port); if (connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { std::cerr << "connect failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); // WSACleanup(); return false; } // closesocket(sock); // WSACleanup(); item->sock_tcp = sock; item->is_connected = true; item->is_anthenticated = false; return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } bool iobox_api::disconnectToIobox(const std::string& remote) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { // check ip is already in iobox_profiles bool is_exist = false; iobox_profile_t* item = nullptr; for (auto& profile : this->iobox_profiles) { if (profile.iobox_info.ip_address == ip || profile.iobox_info.ip_public_address == ip) { item = &profile; is_exist = true; if (item->is_connected) { std::cout << "Ip is already connected: " << ip << std::endl; } break; } } if (is_exist == false) { std::cout << "Ip is not exist in list scan" << ip << std::endl; return false; } item->counting_get = 0; item->is_connected = false; item->is_anthenticated = false; closesocket(item->sock_tcp); item->sock_tcp = INVALID_SOCKET; // WSACleanup(); std::cout << "Disconnected" << std::endl; return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } bool iobox_api::setAuthenticationIobox(const std::string& remote, const std::string& username, const std::string& password) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; return false; } std::string action = "change_auth"; //{"request": {"action":"change_auth","username":"","password":""}} std::string authMessage = "{\"request\":{\"action\":\"" + action + "\",\"username\":\"" + username + "\",\"password\":\"" + password + "\"}}"; if (!sendTcpMessage(ip, authMessage.c_str(), authMessage.length(), true)) { return false; } //{"response":{"action":"change_auth","result":"","reason":""}} char revBuf[256]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { return false; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; if (result == "success") { std::cout << "Change auth success" << std::endl; } else { std::cerr << "Change auth failed" << std::endl; std::cerr << "Reason: " << reason << std::endl; return false; } } else { std::cerr << "Parse response failed" << std::endl; return false; } return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } std::string iobox_api::generateToken(const std::string& remote) { std::lock_guard lock(_mutex); try { std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return ""; } iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; return ""; } //may be change this later return profile->iobox_info.serial_number + profile->iobox_info.model; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return ""; } } bool iobox_api::resetAuthenticationIobox(const std::string& remote, const std::string& token) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { bool needRemove = false; iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; // return false; // need temporary save iobox_info iobox_info_t info; info.ip_address = ip; save_info_iobox(info); profile = findProfileByIp(ip); needRemove = true; } if (connectToIoboxWithoutAuthen(ip, DEVICE_TCP_PORT) == false) { if (needRemove) remove_last_info_iobox(); return false; } //{"request": {"action":"factory_reset","token":""}} std::string action = "factory_reset"; std::string resetMessage = "{\"request\":{\"action\":\"" + action + "\",\"token\":\"" + token + "\"}}"; if (!sendTcpMessage(ip, resetMessage.c_str(), resetMessage.length(), false)) { if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } char revBuf[256]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; if (result == "success") { std::cout << "Factory reset success" << std::endl; if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return true; } else { std::cerr << "Factory reset failed" << std::endl; std::cerr << "Reason: " << reason << std::endl; if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } } else { std::cerr << "Parse response failed" << std::endl; if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } bool iobox_api::resetIobox(const std::string& remote, const std::string& token) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { bool needRemove = false; iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; // return false; // need temporary save iobox_info iobox_info_t info; info.ip_address = ip; save_info_iobox(info); profile = findProfileByIp(ip); needRemove = true; } if (connectToIoboxWithoutAuthen(ip, DEVICE_TCP_PORT) == false) { if (needRemove) remove_last_info_iobox(); return false; } //{"request": {"action":"restart","token":""}} std::string action = "restart"; std::string resetMessage = "{\"request\":{\"action\":\"" + action + "\",\"token\":\"" + token + "\"}}"; if (!sendTcpMessage(ip, resetMessage.c_str(), resetMessage.length(), false)) { if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } char revBuf[256]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; if (result == "success") { std::cout << "Restart success" << std::endl; } else { std::cerr << "Restart failed" << std::endl; std::cerr << "Reason: " << reason << std::endl; if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } } else { std::cerr << "Parse response failed" << std::endl; if (profile->is_anthenticated == false) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); } return false; } disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } iobox_profile_t* iobox_api::findProfileByIp(const std::string& ip) { std::lock_guard lock(_mutex); try { iobox_profile_t* profile = nullptr; for (auto& item : this->iobox_profiles) { if (item.iobox_info.ip_address == ip || item.iobox_info.ip_public_address == ip) { profile = &item; } } return profile; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return nullptr; } } std::string iobox_api::getValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return ""; } try { iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; return ""; } //{"request": {"action":"getValue","channel":""}} std::string action = "getValue"; std::string getValueMessage = "{\"request\":{\"action\":\"" + action + "\",\"channel\":\"" + channelName + "\"}}"; if (!sendTcpMessage(ip, getValueMessage.c_str(), getValueMessage.length(), true)) { return ""; } char revBuf[256]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { return ""; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; return result; } else { std::cerr << "Parse response failed" << std::endl; return ""; } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return ""; } } bool iobox_api::setValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName, const std::string& value) { std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return false; } try { iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; return false; } //not check valid channel name here //{"request": {"action":"setValue", "channel":"","value":""}} std::string action = "setValue"; std::string setValueMessage = "{\"request\":{\"action\":\"" + action + "\",\"channel\":\"" + channelName + "\",\"value\":\"" + value + "\"}}"; if (!sendTcpMessage(ip, setValueMessage.c_str(), setValueMessage.length(), true)) { return false; } char revBuf[256]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { return false; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; if (result == "success") { std::cout << "Set value success" << std::endl; } else { std::cerr << "Set value failed" << std::endl; std::cerr << "Reason: " << reason << std::endl; return false; } } else { std::cerr << "Parse response failed" << std::endl; return false; } return true; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return false; } } std::vector iobox_api::getDeviceChannelNames(const std::string& remote) { bool needRemove = false; std::vector channelNames; std::lock_guard lock(this->_mutex); std::string ip = checkIpFromRemote(remote); if (ip == "") { std::cerr << "Failed to get ip from remote: " << remote << std::endl; return channelNames; } try { iobox_profile_t* profile = findProfileByIp(ip); if (profile == nullptr) { std::cerr << "IP address not found: " << ip << std::endl; // return channelNames; // need temporary save iobox_info iobox_info_t info; info.ip_address = ip; save_info_iobox(info); profile = findProfileByIp(ip); needRemove = true; } if (connectToIoboxWithoutAuthen(ip, DEVICE_TCP_PORT) == false) { if (needRemove) remove_last_info_iobox(); return channelNames; } //{"request": {"action":"channelList"}} std::string action = "channelList"; std::string channelListMessage = "{\"request\":{\"action\":\"" + action + "\"}}"; if (!sendTcpMessage(ip, channelListMessage.c_str(), channelListMessage.length(), false)) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return channelNames; } char revBuf[1024]; size_t responseLength = sizeof(revBuf); if (!receiveTcpMessage(ip, revBuf, responseLength)) { disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return channelNames; } revBuf[responseLength] = '\0'; std::string response(revBuf); std::string result; std::string reason; iobox_info_t info; if (parseResponeCommon(response, action, result, reason, info)) { std::cout << "Parse response success" << std::endl; cJSON* root = cJSON_Parse(result.c_str()); if (root == nullptr) { std::cerr << "Failed to parse JSON" << std::endl; disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return channelNames; } if (root->type != cJSON_Array) { std::cerr << "Failed to get array" << std::endl; cJSON_Delete(root); disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return channelNames; } cJSON* channelList = root; if (info.ip_address != ip) { info.ip_public_address = ip; } profile->iobox_info = info; int arraySize = cJSON_GetArraySize(channelList); for (int i = 0; i < arraySize; ++i) { cJSON* channel = cJSON_GetArrayItem(channelList, i); if (channel != nullptr && channel->type == cJSON_String) { uint16_t idx = getIndexIoboxFromIp(ip); std::string aliasName = createAliasName(info.serial_number, info.hardware_version, info.firmware_version, idx); std::string multicastAlias = createMulticastAlias(aliasName, info.model, info.serial_number, info.ip_public_address == "" ? info.ip_address : info.ip_public_address); std::string channelName = multicastAlias + "-" + channel->valuestring; channelNames.push_back(channelName); } } cJSON_Delete(root); // disconnectToIobox(ip); //not need remove return channelNames; } else { std::cerr << "Parse response failed" << std::endl; disconnectToIobox(ip); if (needRemove) remove_last_info_iobox(); return channelNames; } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return channelNames; } } bool iobox_api::openRS232(const std::string& ip, const std::string& port, int baudrate, int databits, int stopbits, int parity) { return false; } bool iobox_api::closeRS232(const std::string& ip) { return false; } bool iobox_api::writeRS232(const std::string& ip, std::string dataToSend, int timeout) { return false; } bool iobox_api::readRS232(const std::string& ip, std::string& receivedData, const std::string& terminateString, int timeout) { return false; } bool iobox_api::readRS232Bytes(const std::string& ip, std::string& receivedData, int numBytes, int timeout) { return false; } }