diff --git a/src/SetWifiConfig.cpp b/src/SetWifiConfig.cpp index 3bfcfa9..157f10d 100644 --- a/src/SetWifiConfig.cpp +++ b/src/SetWifiConfig.cpp @@ -26,31 +26,46 @@ using namespace pipedal; +#define IP_RANGE "172.22.0" +#define PIPEDAL_IP IP_RANGE ".1" +#define PIPEDAL_NETWORK PIPEDAL_IP "/24" + +#define SYSTEMCTL_BIN "/usr/bin/systemctl" void pipedal::SetWifiConfig(const WifiConfigSettings&settings) { char band; if (!settings.enable_) { - SysExec("/usr/bin/systemctl stop hostapd"); - SysExec("/usr/bin/systemctl disable hostapd"); + SysExec(SYSTEMCTL_BIN " stop hostapd"); + SysExec(SYSTEMCTL_BIN " disable hostapd"); - SysExec("/usr/bin/systemctl enable wpa_supplicant"); - SysExec("/usr/bin/systemctl start wpa_supplicant"); + SysExec(SYSTEMCTL_BIN " enable wpa_supplicant"); + SysExec(SYSTEMCTL_BIN " start wpa_supplicant"); } else { - boost::filesystem::path path("/etc/hostapd/hostapd.conf"); - SystemConfigFile apdConfig(path); - apdConfig.Set("ieee80211n","1",false); - apdConfig.Set("ieee80211d","1",false); - apdConfig.Set("ieee80211ac","1",false); - apdConfig.Set("ieee80211d","1",false); - apdConfig.Set("ht_capab","[HT40][SHORT-GI-20][DSSS_CCK-40]",false); - apdConfig.Set("rsn_pairwise","CCMP",false); + std::filesystem::path path("/etc/hostapd/hostapd.conf"); + SystemConfigFile apdConfig; + if (std::filesystem::exists(path)) + { + apdConfig.Load(path); + } + apdConfig.Set("interface","wlan0"); + apdConfig.Set("driver","nl80211"); + apdConfig.Set("country_code",settings.countryCode_); - apdConfig.Set("wmm_enabled","1"); + apdConfig.Set("ieee80211n","1","Wi-Fi features"); + apdConfig.SetDefault("ieee80211d","1"); + apdConfig.SetDefault("ieee80211ac","1"); + apdConfig.SetDefault("ieee80211d","1"); + apdConfig.Set("ht_capab","[HT40][SHORT-GI-20][DSSS_CCK-40]"); + + + apdConfig.Set("wmm_enabled","1","Authentication options"); apdConfig.Set("auth_algs","1"); apdConfig.Set("wpa","2"); - + apdConfig.SetDefault("wpa_pairwise","TKIP CCMP"); + apdConfig.SetDefault("wpa_ptk_rekey","600"); + apdConfig.SetDefault("rsn_pairwise","CCMP"); std::string hwMode = "g"; if (settings.channel_.length() > 0 && settings.channel_[0] == 'a') { @@ -72,22 +87,94 @@ void pipedal::SetWifiConfig(const WifiConfigSettings&settings) } } + apdConfig.Set("ssid",settings.hotspotName_,"Access point configuration"); if (settings.password_.length() != 0) { apdConfig.Set("wpa_passphrase",settings.password_); } - apdConfig.Set("ssid",settings.hotspotName_); - apdConfig.Set("country_code",settings.countryCode_); apdConfig.Set("hw_mode",hwMode); apdConfig.Set("channel",channel); - apdConfig.Save(); - SysExec("/usr/bin/systemctl daemon-reload"); + // ******************** dsnmasq ****** + std::filesystem::path dnsMasqPath("/etc/dnsmasq.conf"); + SystemConfigFile dnsMasq; + + try { + dnsMasq.Load(dnsMasqPath); + } catch (const std::exception &) + { + // ignore. + } - SysExec("/usr/bin/systemctl mask wpa_supplicant"); - SysExec("/usr/bin/systemctl stop wpa_supplicant"); + + dnsMasq.Set("interface","wlan0","Name of the Wi-Fi interface"); + dnsMasq.Set("listen-address",PIPEDAL_IP); - if (SysExec("/usr/bin/systemctl restart hostapd") != 0) + dnsMasq.SetDefault("dhcp-range", IP_RANGE ".3," IP_RANGE ".127,12h","dhcp configuration"); + dnsMasq.SetDefault("domain","local"); + std::stringstream sAddress; + sAddress << "/" << settings.mdnsName_ << ".local/" IP_RANGE << ".1"; + dnsMasq.Set("address",sAddress.str()); + + // ****** dhcpd.conf ***/ + std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); + if (std::filesystem::exists(dhcpcdConfig)) + { + SystemConfigFile dhcpcd(dhcpcdConfig); + + int line = dhcpcd.GetLineThatStartsWith("hostname"); + std::string hostNameLine; + if (settings.mdnsName_ != "") + { + hostNameLine = "hostname " + settings.mdnsName_; + } else { + hostNameLine = "hostname"; // the default value. + } + if (line != -1) { + dhcpcd.SetLineValue(line,hostNameLine); + } else { + dhcpcd.AppendLine(hostNameLine); + } + line = dhcpcd.GetLineNumber("interface wlan0"); + if (line != -1) { + dhcpcd.EraseLine(line); + while (line < dhcpcd.GetLineCount()) + { + const std::string &lineValue = dhcpcd.GetLineValue(line); + if (lineValue.length() > 0 && (lineValue[0] == ' ' || lineValue[0] == '\t')) + { + dhcpcd.EraseLine(line); + } else { + break; + } + } + } + if (line == -1) { + dhcpcd.AppendLine(""); + line = dhcpcd.GetLineCount(); + } + dhcpcd.InsertLine(line++,"interface wlan0"); + dhcpcd.InsertLine(line++," static ip_address=" PIPEDAL_NETWORK); + dhcpcd.InsertLine(line++," nohook wpa_supplicant"); + dhcpcd.Save(dhcpcdConfig); + } + + // ***** save the config files *** + + apdConfig.Save(path); + dnsMasq.Save(dnsMasqPath); + + + + // **************** start services ************ + SysExec("rfkill unblock wlan"); + SysExec(SYSTEMCTL_BIN " daemon-reload"); + + SysExec(SYSTEMCTL_BIN " mask wpa_supplicant"); + SysExec(SYSTEMCTL_BIN " stop wpa_supplicant"); + + SysExec(SYSTEMCTL_BIN " unmask hostapd"); + if (SysExec(SYSTEMCTL_BIN " restart hostapd") != 0) { throw PiPedalException("Unable to start the access point."); @@ -96,8 +183,15 @@ void pipedal::SetWifiConfig(const WifiConfigSettings&settings) { throw PiPedalException("Unable to start the access point."); } - SysExec("/usr/bin/systemctl enable hostapd"); + SysExec(SYSTEMCTL_BIN " enable hostapd"); + + SysExec(SYSTEMCTL_BIN " stop wpa_supplicant"); + SysExec(SYSTEMCTL_BIN " mask wpa_supplicant"); + + SysExec(SYSTEMCTL_BIN " restart dnsmasq"); + SysExec(SYSTEMCTL_BIN " enable dnsmasq"); } } + diff --git a/src/SystemConfigFile.cpp b/src/SystemConfigFile.cpp index a3a76c8..324a968 100644 --- a/src/SystemConfigFile.cpp +++ b/src/SystemConfigFile.cpp @@ -27,7 +27,22 @@ using namespace pipedal; using namespace std; -void SystemConfigFile::Load(const boost::filesystem::path&path) + +static std::string makeLine(const std::string &key, const std::string &value) +{ + stringstream s; + if (value.length() == 0) + { + s << key; + } + else + { + s << key << "=" << value; + } + return s.str(); +} + +void SystemConfigFile::Load(const std::filesystem::path &path) { this->lines.clear(); @@ -42,7 +57,7 @@ void SystemConfigFile::Load(const boost::filesystem::path&path) while (true) { std::string line; - std::getline(f,line); + std::getline(f, line); if (f.fail()) { break; @@ -50,107 +65,130 @@ void SystemConfigFile::Load(const boost::filesystem::path&path) lines.push_back(line); } this->currentPath = path; - - } int64_t SystemConfigFile::GetLine(const std::string &key) const { for (size_t i = 0; i < lines.size(); ++i) { - if (LineMatches(lines[i],key)) + if (LineMatches(lines[i], key)) { return i; } } + std::string commentedKey = "#" + key; + for (size_t i = 0; i < lines.size(); ++i) + { + if (LineMatches(lines[i], commentedKey)) + { + return i; + } + } + return -1; } -bool SystemConfigFile::HasValue(const std::string&key) const +bool SystemConfigFile::HasValue(const std::string &key) const { - return GetLine(key) != -1; + int line = GetLine(key); + if (line == -1) + return false; + return lines[line][0] != '#'; } static inline std::string ValuePart(const std::string &line) { auto pos = line.find('='); - if (pos == std::string::npos) throw PiPedalException("Value not found."); - return line.substr(pos+1); - + if (pos == std::string::npos) + throw PiPedalException("Value not found."); + return line.substr(pos + 1); } -std::string SystemConfigFile::Get(const std::string&key) const +std::string SystemConfigFile::Get(const std::string &key) const { int64_t lineIndex = GetLine(key); - if (lineIndex == -1) throw PiPedalArgumentException("Not found."); + if (lineIndex == -1) + throw PiPedalArgumentException("Not found."); return ValuePart(lines[lineIndex]); - } -bool SystemConfigFile::Get(const std::string&key,std::string*pResult) const +bool SystemConfigFile::Get(const std::string &key, std::string *pResult) const { int64_t lineIndex = GetLine(key); - if (lineIndex == -1) return false; + if (lineIndex == -1) + return false; *pResult = ValuePart(lines[lineIndex]); return true; } -void SystemConfigFile::Set(const std::string&key,const std::string &value) +void SystemConfigFile::Set(const std::string &key, const std::string &value) { - stringstream s; - s << key << "=" << value; - std::string line = s.str(); + std::string line = makeLine(key, value); + int lineIndex = GetLine(key); - if (lineIndex != -1) { + if (lineIndex != -1) + { lines[lineIndex] = line; - } else { + } + else + { lines.push_back(line); } } +void SystemConfigFile::SetDefault(const std::string &key, const std::string &value) +{ + int lineIndex = GetLine(key); + if (lineIndex == -1) + { + lines.push_back(makeLine(key, value)); + } else if (lines[lineIndex][0] != '#') { + lines[lineIndex] = makeLine(key,value); + } +} -bool SystemConfigFile::Erase(const std::string&key) + + +bool SystemConfigFile::Erase(const std::string &key) { bool matched = false; for (size_t i = 0; i < lines.size(); ++i) { - if (LineMatches(lines[i],key)) + if (LineMatches(lines[i], key)) { matched = true; - lines.erase(lines.begin()+i); + lines.erase(lines.begin() + i); --i; } } return matched; - } -static std::string makeLine(const std::string&key, const std::string&value) { - stringstream s; - s << key << "=" << value; - return s.str(); -} -int64_t SystemConfigFile::Insert(int64_t position, const std::string&key, const std::string&value) +int64_t SystemConfigFile::Insert(int64_t position, const std::string &key, const std::string &value) { if (position < 0 || position >= lines.size()) { - lines.push_back(makeLine(key,value)); + lines.push_back(makeLine(key, value)); return (int64_t)lines.size(); - } else { - lines.insert(lines.begin()+position,makeLine(key,value)); - return position+1; + } + else + { + lines.insert(lines.begin() + position, makeLine(key, value)); + return position + 1; } } -int64_t SystemConfigFile::Insert(int64_t position, const std::string&line) +int64_t SystemConfigFile::Insert(int64_t position, const std::string &line) { if (position < 0 || position >= lines.size()) { lines.push_back(line); return (int64_t)lines.size(); - } else { - lines.insert(lines.begin()+position,line); - return position+1; + } + else + { + lines.insert(lines.begin() + position, line); + return position + 1; } } -bool SystemConfigFile::LineMatches(const std::string &line, const std::string&key) const +inline bool SystemConfigFile::LineMatches(const std::string &line, const std::string &key) const { // (very permissive interpretation) int pos = 0; @@ -158,46 +196,61 @@ bool SystemConfigFile::LineMatches(const std::string &line, const std::string&ke { ++pos; } - if (line.compare(pos,pos+key.length(),key) != 0) return false; - pos += key.length();\ + if (line.compare(pos, pos + key.length(), key) != 0) + return false; + pos += key.length(); while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t')) { ++pos; } + if (pos == line.length()) + return true; return pos < line.length() && line[pos] == '='; } -void SystemConfigFile::SetLine(int64_t lineIndex,const std::string&key,const std::string &value ) +void SystemConfigFile::SetLine(int64_t lineIndex, const std::string &key, const std::string &value) { - stringstream s; - s << key << "=" << value; + std::string line = makeLine(key, value); if (lineIndex >= 0 && lineIndex < this->lines.size()) { - this->lines[lineIndex] = s.str(); - } else { - this->lines.push_back(s.str()); + this->lines[lineIndex] = line; + } + else + { + this->lines.push_back(line); } } -void SystemConfigFile::Set(const std::string&key,const std::string &value, bool overwrite) -{ - if (!overwrite) - { - if (HasValue(key)) return; - } - Set(key,value); -} -void SystemConfigFile::Set(const std::string&key,const std::string &value, const std::string&comment) +void SystemConfigFile::SetDefault(const std::string &key, const std::string &value, const std::string &comment) { - uint64_t lineIndex = GetLine(key); - if (lineIndex != -1) + int lineIndex = GetLine(key); + if (lineIndex == -1) { - SetLine(lineIndex, key, value); - } else { lines.push_back(""); lines.push_back("# " + comment); - SetLine(-1,key,value); + + lines.push_back(makeLine(key, value)); + } else { + if (lines[lineIndex][0] == '#') + { + lines[lineIndex] = makeLine(key,value); + } + } +} + +void SystemConfigFile::Set(const std::string &key, const std::string &value, const std::string &comment) +{ + auto lineIndex = GetLine(key); + if (lineIndex != -1) + { + SetLine(lineIndex, key, value); + } + else + { + lines.push_back(""); + lines.push_back("# " + comment); + SetLine(-1, key, value); } } @@ -207,13 +260,13 @@ void SystemConfigFile::Save(std::ostream &os) { os << lines[i] << std::endl; } - } -void SystemConfigFile::Save(const boost::filesystem::path&path) +void SystemConfigFile::Save(const std::filesystem::path &path) { ofstream f(path); - if (!f.is_open()) { + if (!f.is_open()) + { stringstream s; s << "Unable to write to " << path; throw PiPedalException(s.str()); @@ -230,3 +283,50 @@ void SystemConfigFile::Save() { Save(this->currentPath); } + +int SystemConfigFile::GetLineNumber(const std::string &line) const { + for (int i = 0; i < lines.size(); ++i) + { + if (lines[i] == line) + { + return i; + } + } + return -1; + +} +void SystemConfigFile::EraseLine(int i) +{ + if (i < 0 || i >= lines.size()) throw PiPedalArgumentException("Range error."); + lines.erase(lines.begin()+i); +} + +bool SystemConfigFile::EraseLine(const std::string &line) +{ + int lineNumber = GetLineNumber(line); + if (lineNumber == -1) return false; + lines.erase(lines.begin() + lineNumber); + return true; +} + +void SystemConfigFile::InsertLine(int position, const std::string&line) +{ + this->lines.insert(lines.begin()+position,line); +} + +int SystemConfigFile::GetLineThatStartsWith(const std::string&text) const +{ + for (size_t i = 0; i < lines.size(); ++i) + { + if (lines[i].rfind(text,0) != std::string::npos) { + return (int)i; + } + } + return -1; +} + +void SystemConfigFile::AppendLine(const std::string &line) +{ + lines.push_back(line); +} + diff --git a/src/SystemConfigFile.hpp b/src/SystemConfigFile.hpp index 163b882..5b1b8e8 100644 --- a/src/SystemConfigFile.hpp +++ b/src/SystemConfigFile.hpp @@ -18,12 +18,12 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #pragma once -#include +#include namespace pipedal { class SystemConfigFile { - boost::filesystem::path currentPath; + std::filesystem::path currentPath; std::vector lines; void SetLine(int64_t lineIndex,const std::string&key,const std::string &value ); bool LineMatches(const std::string &line, const std::string&key) const; @@ -31,15 +31,15 @@ public: SystemConfigFile() { } - SystemConfigFile(const boost::filesystem::path& path) + SystemConfigFile(const std::filesystem::path& path) { Load(path); } - void Load(const boost::filesystem::path&path); + void Load(const std::filesystem::path&path); void Save(std::ostream &os); - void Save(const boost::filesystem::path&path); + void Save(const std::filesystem::path&path); void Save(); int64_t GetLine(const std::string &key) const; @@ -47,12 +47,23 @@ public: bool Get(const std::string&key,std::string*pResult) const; std::string Get(const std::string&key) const; void Set(const std::string&key,const std::string &value); - void Set(const std::string&key,const std::string &value, bool overwrite); void Set(const std::string&key,const std::string &value, const std::string&comment); + void SetDefault(const std::string&key, const std::string &value); + void SetDefault(const std::string&key,const std::string &value, const std::string &comment); + bool Erase(const std::string&key); int64_t Insert(int64_t position, const std::string&key, const std::string&value); int64_t Insert(int64_t position, const std::string&line); - + int GetLineNumber(const std::string&line) const; + bool HasLine(const std::string&line) const { return GetLineNumber(line) != -1; } + void EraseLine(int i); + int GetLineThatStartsWith(const std::string&text) const; + int GetLineCount() const { return (int)lines.size();} + const std::string & GetLineValue(int line) const { return lines[line]; } + bool EraseLine(const std::string&line); + void InsertLine(int position, const std::string&line); + void AppendLine(const std::string&line); + void SetLineValue(int index, const std::string&line) { lines[index] = line; } }; }; \ No newline at end of file diff --git a/src/SystemConfigFileTest.cpp b/src/SystemConfigFileTest.cpp index aac5bdf..354d1b1 100644 --- a/src/SystemConfigFileTest.cpp +++ b/src/SystemConfigFileTest.cpp @@ -33,7 +33,7 @@ using namespace pipedal; TEST_CASE( "SystemConfigFile Test", "[system_config_file_test]" ) { - boost::filesystem::path path("/etc/hostapd/hostapd.conf"); + std::filesystem::path path("/etc/hostapd/hostapd.conf"); SystemConfigFile file(path); std::string driverName; diff --git a/src/WifiConfigSettings.cpp b/src/WifiConfigSettings.cpp index 352f7ac..6341081 100644 --- a/src/WifiConfigSettings.cpp +++ b/src/WifiConfigSettings.cpp @@ -28,6 +28,7 @@ JSON_MAP_BEGIN(WifiConfigSettings) JSON_MAP_REFERENCE(WifiConfigSettings,rebootRequired) JSON_MAP_REFERENCE(WifiConfigSettings,enable) JSON_MAP_REFERENCE(WifiConfigSettings,hotspotName) + JSON_MAP_REFERENCE(WifiConfigSettings,mdnsName) JSON_MAP_REFERENCE(WifiConfigSettings,hasPassword) JSON_MAP_REFERENCE(WifiConfigSettings,password) JSON_MAP_REFERENCE(WifiConfigSettings,countryCode) diff --git a/src/WifiConfigSettings.hpp b/src/WifiConfigSettings.hpp index a875c4a..c39f4f8 100644 --- a/src/WifiConfigSettings.hpp +++ b/src/WifiConfigSettings.hpp @@ -31,6 +31,7 @@ namespace pipedal { bool enable_ = false; std::string countryCode_ = "US"; // iso 3661 std::string hotspotName_ = "pipedal"; + std::string mdnsName_ = "pipedal"; bool hasPassword_ = false; std::string password_; std::string channel_ = "g6";