diff --git a/cmd/P4wnP1_service/P4wnP1_service.go b/cmd/P4wnP1_service/P4wnP1_service.go index c79be49..ebd9745 100644 --- a/cmd/P4wnP1_service/P4wnP1_service.go +++ b/cmd/P4wnP1_service/P4wnP1_service.go @@ -46,7 +46,7 @@ func main() { state.Led.SetLed(&pb.LEDSettings{1}) //service.StartEventManager(20) - log.SetOutput(state.EvMgr) +// log.SetOutput(state.EvMgr) log.Println("TESTMESSAGE") go func() { err := common.RunBashScript("/usr/local/P4wnP1/scripts/servicestart.sh") diff --git a/service/state.go b/service/state.go index 254b46e..0b27525 100644 --- a/service/state.go +++ b/service/state.go @@ -40,9 +40,7 @@ func InitGlobalServiceState() (err error) { IpAddress4: "172.24.0.1", Netmask4: "255.255.255.0", } - state.Wifi = &WifiState{ - Settings: GetDefaultWiFiSettings(), - } + state.Wifi = NewWifiState(GetDefaultWiFiSettings(), wifi_if_name) state.HidDevPath = make(map[string]string) //should be initialized BEFORE UsbGadgetManager uses it state.EvMgr = NewEventManager(20) diff --git a/service/wifi.go b/service/wifi.go index 786062c..230281e 100644 --- a/service/wifi.go +++ b/service/wifi.go @@ -17,6 +17,7 @@ import ( "bufio" "io" "regexp" + "sync" ) const ( @@ -41,8 +42,132 @@ const ( type WifiState struct { Settings *pb.WiFiSettings + CmdWpaSupplicant *exec.Cmd + mutexWpaSupplicant *sync.Mutex + IfaceName string + PathWpaSupplicantConf string } +func NewWifiState(startupSettings *pb.WiFiSettings, ifName string) (res *WifiState) { + if !wifiWpaSupplicantAvailable() { + panic("wpa_supplicant seems to be missing, please install it") + } + + res = &WifiState{ + IfaceName: ifName, + Settings: startupSettings, + CmdWpaSupplicant: nil, + mutexWpaSupplicant: &sync.Mutex{}, + PathWpaSupplicantConf: confFileWpaSupplicant(ifName), + } + return +} + + +func (wifiState *WifiState) StopWpaSupplicant() (err error) { + eSuccess := fmt.Sprintf("... wpa_supplicant for interface '%s' stopped", wifiState.IfaceName) + eCantStop := fmt.Sprintf("... couldn't terminate wpa_supplicant for interface '%s'", wifiState.IfaceName) + + log.Printf("... stop running wpa_supplicant processes for interface '%s'\n", wifiState.IfaceName) + + wifiState.mutexWpaSupplicant.Lock() + defer wifiState.mutexWpaSupplicant.Unlock() + + if wifiState.CmdWpaSupplicant == nil { + log.Printf("... wpa_supplicant for interface '%s' wasn't running, no need to stop it\n", wifiState.IfaceName) + return nil + } + + wifiState.CmdWpaSupplicant.Process.Signal(syscall.SIGTERM) + wifiState.CmdWpaSupplicant.Wait() + if !wifiState.CmdWpaSupplicant.ProcessState.Exited() { + log.Printf("... wpa_supplicant didn't react on SIGTERM for interface '%s', trying SIGKILL\n", wifiState.IfaceName) + wifiState.CmdWpaSupplicant.Process.Kill() + + time.Sleep(500*time.Millisecond) + if wifiState.CmdWpaSupplicant.ProcessState.Exited() { + wifiState.CmdWpaSupplicant = nil + log.Println(eSuccess) + return nil + } else { + log.Println(eCantStop) + return errors.New(eCantStop) + } + } + + wifiState.CmdWpaSupplicant = nil + log.Println(eSuccess) + return nil +} + + +func (wifiState *WifiState) StartWpaSupplicant(timeout time.Duration) (err error) { + log.Printf("Starting wpa_supplicant for interface '%s'...\n", wifiState.IfaceName) + + wifiState.mutexWpaSupplicant.Lock() + defer wifiState.mutexWpaSupplicant.Unlock() + + //check if interface is valid + if_exists,_ := CheckInterfaceExistence(wifiState.IfaceName) + if !if_exists { + return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", wifiState.IfaceName)) + } + + + + //stop wpa_supplicant if already running + if wifiState.CmdWpaSupplicant != nil { + wifiState.StopWpaSupplicant() + } + + //we monitor output of wpa_supplicant till we are connected, fail due to wrong PSK or timeout is reached + //Note: PID file creation doesn't work when not started as daemon, so we do it manually, later on + wifiState.CmdWpaSupplicant = exec.Command("/sbin/wpa_supplicant", "-c", wifiState.PathWpaSupplicantConf, "-i", wifiState.IfaceName) + + wpa_stdout, err := wifiState.CmdWpaSupplicant.StdoutPipe() + if err != nil { return err} + + err = wifiState.CmdWpaSupplicant.Start() + if err != nil { return err} + + //result channel + wpa_res := make(chan string, 1) + defer close(wpa_res) + + //start output parser + wpa_stdout_reader := bufio.NewReader(wpa_stdout) + + go wifiWpaSupplicantOutParser(wpa_res, wpa_stdout_reader) + + //analyse output + select { + case res := <-wpa_res: + if strings.Contains(res, "CONNECTED") { + //We could return success and keep wpa_supplicant running + log.Println("... connected to given WiFi network, wpa_supplicant running") + return nil + } + if strings.Contains(res, "WRONG_KEY") { + //we stop wpa_supplicant and return err + log.Println("... seems the wrong PSK wwas provided for the given WiFi network, stopping wpa_supplicant ...") + //wifiStopWpaSupplicant(nameIface) + log.Println("... killing wpa_supplicant") + wifiState.StopWpaSupplicant() + return errors.New("Wrong PSK") + } + case <- time.After(timeout): + //we stop wpa_supplicant and return err + log.Printf("... wpa_supplicant reached timeout of '%v' without beeing able to connect to given network\n", timeout) + log.Println("... killing wpa_supplicant") + wifiState.StopWpaSupplicant() + return errors.New("TIMEOUT REACHED") + } + + + return nil +} + + type BSS struct { SSID string BSSID net.HardwareAddr @@ -99,7 +224,7 @@ func (state *WifiState) DeployWifiSettings(ws *pb.WiFiSettings) (err error) { } //stop wpa_supplicant if needed - wifiStopWpaSupplicant(wifi_if_name) + state.StopWpaSupplicant() //kill hostapd in case it is still running err = wifiStopHostapd(ifName) if err != nil { return err } // ToDo: returning at this point is a bit harsh @@ -141,7 +266,7 @@ func (state *WifiState) DeployWifiSettings(ws *pb.WiFiSettings) (err error) { err = WifiCreateWpaSupplicantConfigFile(ws.BssCfgClient.SSID, ws.BssCfgClient.PSK, confFileWpaSupplicant(wifi_if_name)) if err != nil { return err } //ToDo: proper error handling, in case connection not possible - err = wifiStartWpaSupplicant(wifi_if_name, WPA_SUPPLICANT_CONNECT_TIMEOUT) + err = state.StartWpaSupplicant(WPA_SUPPLICANT_CONNECT_TIMEOUT) if err != nil { return err } } @@ -400,103 +525,7 @@ func wifiWpaSupplicantOutParser(chanResult chan string, reader *bufio.Reader) { log.Println("... stopped monitoring wpa_supplicant output") } -func wifiStartWpaSupplicant(nameIface string, timeout time.Duration) (err error) { - log.Printf("Starting wpa_supplicant for interface '%s'...\n", nameIface) - //check if interface is valid - if_exists,_ := CheckInterfaceExistence(nameIface) - if !if_exists { - return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface)) - } - - if !wifiWpaSupplicantAvailable() { - return errors.New("wpa_supplicant seems to be missing, please install it") - } - - confpath := confFileWpaSupplicant(nameIface) - - //stop wpa_supplicant if already running - wifiStopWpaSupplicant(nameIface) - - - //we monitor output of wpa_supplicant till we are connected, fail due to wrong PSK or timeout is reached - //Note: PID file creation doesn't work when not started as daemon, so we do it manually, later on - proc := exec.Command("/sbin/wpa_supplicant", "-P", pidFileWpaSupplicant(nameIface), "-c", confpath, "-i", nameIface) - - wpa_stdout, err := proc.StdoutPipe() - if err != nil { return err} - - err = proc.Start() - if err != nil { return err} - - //Create PID file by hand, as we're not running wpa_supplicant in daemon mode - err = ioutil.WriteFile(pidFileWpaSupplicant(nameIface), []byte(fmt.Sprintf("%d", proc.Process.Pid)), os.ModePerm) - - //result channel - wpa_res := make(chan string, 1) - //start output parser - wpa_stdout_reader := bufio.NewReader(wpa_stdout) - - go wifiWpaSupplicantOutParser(wpa_res, wpa_stdout_reader) - - //analyse output - select { - case res := <-wpa_res: - if strings.Contains(res, "CONNECTED") { - //We could return success and keep wpa_supplicant running - log.Println("... connected to given WiFi network, wpa_supplicant running") - return nil - } - if strings.Contains(res, "WRONG_KEY") { - //we stop wpa_supplicant and return err - log.Println("... seems the wrong PSK wwas provided for the given WiFi network, stopping wpa_supplicant ...") - //wifiStopWpaSupplicant(nameIface) - log.Println("... killing wpa_supplicant") - proc.Process.Kill() - return errors.New("Wrong PSK") - } - case <- time.After(timeout): - //we stop wpa_supplicant and return err - log.Printf("... wpa_supplicant reached timeout of '%v' without beeing able to connect to given network\n", timeout) - log.Println("... killing wpa_supplicant") - //wifiStopWpaSupplicant(nameIface) - proc.Process.Kill() - return errors.New("TIMEOUT REACHED") - } - - - return nil -} - - -func wifiStopWpaSupplicant(nameIface string) (err error) { - log.Printf("... stop running wpa_supplicant processes for interface '%s'\n", nameIface) - running,pid,err := wifiIsWpaSupplicantRunning(wifi_if_name) - if err != nil { return err } - if !running { - log.Printf("... wpa_supplicant for interface '%s' isn't running, no need to stop it\n", nameIface) - return nil - } - //kill the pid - err = syscall.Kill(pid, syscall.SIGTERM) - if err != nil { return } - - time.Sleep(500*time.Millisecond) - - //check if stopped - running,pid,err = wifiIsHostapdRunning(nameIface) - if err != nil { return } - if (running) { - log.Printf("... couldn't terminate wpa_supplicant for interface '%s'\n", nameIface) - } else { - log.Printf("... wpa_supplicant for interface '%s' stopped\n", nameIface) - } - - //Delete PID file - os.Remove(pidFileHostapd(nameIface)) - - return nil -} func pidFileHostapd(nameIface string) string { return fmt.Sprintf("/var/run/hostapd_%s.pid", nameIface)