nexus: Flesh out VPN support a bit more, cleanup service handling

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index d9ee971..fdf3fed 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 #include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <errno.h>
 
 #define LOG_TAG "CommandListener"
@@ -25,6 +28,7 @@
 #include "Controller.h"
 #include "NetworkManager.h"
 #include "WifiController.h"
+#include "VpnController.h"
 #include "ErrorCode.h"
 
 CommandListener::CommandListener() :
@@ -40,6 +44,8 @@
     registerCmd(new WifiGetVarCmd());
 
     registerCmd(new VpnEnableCmd());
+    registerCmd(new VpnSetVarCmd());
+    registerCmd(new VpnGetVarCmd());
     registerCmd(new VpnDisableCmd());
 }
  
@@ -261,6 +267,79 @@
     return 0;
 }
 
+CommandListener::VpnSetVarCmd::VpnSetVarCmd() :
+                 NexusCommand("vpn_setvar") {
+} 
+
+int CommandListener::VpnSetVarCmd::runCommand(SocketClient *cli, char *data) {
+    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
+
+    char *bword;
+    char *last;
+    char varname[32];
+    char val[250];
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+
+    strncpy(varname, bword, sizeof(varname));
+
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(val, bword, sizeof(val));
+
+    if (!strcasecmp(varname, "vpn_gateway")) {
+        if (vc->setVpnGateway(val))
+            goto out_inval;
+    } else {
+        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
+        return 0;
+    }
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Variable written.", false);
+    return 0;
+
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true);
+    return 0;
+}
+
+CommandListener::VpnGetVarCmd::VpnGetVarCmd() :
+                 NexusCommand("vpn_getvar") {
+} 
+
+int CommandListener::VpnGetVarCmd::runCommand(SocketClient *cli, char *data) {
+    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
+
+    char *bword;
+    char *last;
+    char varname[32];
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+   
+    strncpy(varname, bword, sizeof(varname));
+
+    if (!strcasecmp(varname, "vpn_gateway")) {
+        char buffer[255];
+
+        sprintf(buffer, "%s:%s", varname, inet_ntoa(vc->getVpnGateway()));
+        cli->sendMsg(ErrorCode::VariableRead, buffer, false);
+    } else {
+        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
+        return 0;
+    }
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Variable read.", false);
+    return 0;
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true);
+    return 0;
+}
+
 CommandListener::VpnDisableCmd::VpnDisableCmd() :
                  NexusCommand("vpn_disable") {
 } 
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index 7bc89e3..a44aa29 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -95,6 +95,20 @@
         int runCommand(SocketClient *c, char *data);
     };
 
+    class VpnSetVarCmd : public NexusCommand {
+    public:
+        VpnSetVarCmd();
+        virtual ~VpnSetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class VpnGetVarCmd : public NexusCommand {
+    public:
+        VpnGetVarCmd();
+        virtual ~VpnGetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
     class VpnDisableCmd : public NexusCommand {
     public:
         VpnDisableCmd();
diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h
index 8ca6cae..57c99c2 100644
--- a/nexus/ErrorCode.h
+++ b/nexus/ErrorCode.h
@@ -26,6 +26,9 @@
     static const int WifiScanResult = 125;
     static const int WifiNetworkList = 126;
 
+    static const int VariableRead = 127;
+    static const int VariableWrite = 128;
+
     // 200 series - Requested action has been successfully completed
     static const int CommandOkay = 200;
 
diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
index eff653a..d326ad5 100644
--- a/nexus/OpenVpnController.cpp
+++ b/nexus/OpenVpnController.cpp
@@ -14,17 +14,27 @@
  * limitations under the License.
  */
 #include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #define LOG_TAG "OpenVpnController"
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+#include <sysutils/ServiceManager.h>
+
 #include "OpenVpnController.h"
 
 #define DAEMON_PROP_NAME "vpn.openvpn.status"
+#define DAEMON_CONFIG_FILE "/data/misc/openvpn/openvpn.conf"
 
 OpenVpnController::OpenVpnController() :
                    VpnController() {
+    mServiceManager = new ServiceManager();
+}
+
+OpenVpnController::~OpenVpnController() {
+    delete mServiceManager;
 }
 
 int OpenVpnController::start() {
@@ -37,68 +47,32 @@
 
 int OpenVpnController::enable() {
 
-    // Validate configuration file
-   
-    // Validate key file
-
-    if (startServiceDaemon())
-        return -1;
-
-    errno = -ENOSYS;
-    return -1;
-}
-
-int OpenVpnController::startServiceDaemon() {
-    char status[PROPERTY_VALUE_MAX];
-    int count = 100;
-
-    property_set("ctl.start", "openvpn");
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
-            if (strcmp(status, "ok") == 0)
-                return 0;
-            else if (strcmp(DAEMON_PROP_NAME, "failed") == 0)
-                return -1;
-        }
-        usleep(200000);
-    }
-    property_set(DAEMON_PROP_NAME, "timeout");
-    return -1;
-}
-
-int OpenVpnController::stopServiceDaemon() {
-    char status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 50;
-
-    if (property_get(DAEMON_PROP_NAME, status, NULL) &&
-        !strcmp(status, "stopped")) {
-        LOGD("Service already stopped");
-        return 0;
-    }
-
-    property_set("ctl.stop", "openvpn");
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
-            if (!strcmp(status, "stopped"))
-                break;
-        }
-        usleep(100000);
-    }
-
-    if (!count) {
-        LOGD("Timed out waiting for openvpn to stop");
-        errno = ETIMEDOUT;
+    if (validateConfig()) {
+        LOGE("Error validating configuration file");
         return -1;
     }
 
+    if (mServiceManager->start("openvpn"))
+        return -1;
+
     return 0;
 }
 
 int OpenVpnController::disable() {
-    errno = -ENOSYS;
-    return -1;
+
+    if (mServiceManager->stop("openvpn"))
+        return -1;
+    return 0;
+}
+
+int OpenVpnController::validateConfig() {
+    unlink(DAEMON_CONFIG_FILE);
+
+    FILE *fp = fopen(DAEMON_CONFIG_FILE, "w");
+    if (!fp)
+        return -1;
+
+    fprintf(fp, "remote %s 1194\n", inet_ntoa(getVpnGateway()));
+    fclose(fp);
+    return 0;
 }
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
index 1ecc3fb..7bcc098 100644
--- a/nexus/OpenVpnController.h
+++ b/nexus/OpenVpnController.h
@@ -19,11 +19,15 @@
 
 #include "VpnController.h"
 
+class ServiceManager;
+
 class OpenVpnController : public VpnController {
+private:
+    ServiceManager *mServiceManager;
 
 public:
     OpenVpnController();
-    virtual ~OpenVpnController() {}
+    virtual ~OpenVpnController();
 
     int start();
     int stop();
@@ -33,8 +37,7 @@
 protected:
 
 private:
-    int startServiceDaemon();
-    int stopServiceDaemon();
+    int validateConfig();
 };
 
 #endif
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
index 22964bb..6737d91 100644
--- a/nexus/Supplicant.cpp
+++ b/nexus/Supplicant.cpp
@@ -25,12 +25,7 @@
 
 #include "private/android_filesystem_config.h"
 
-#undef HAVE_LIBC_SYSTEM_PROPERTIES
-
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-#endif
+#include <sysutils/ServiceManager.h>
 
 #include "Supplicant.h"
 #include "SupplicantListener.h"
@@ -44,12 +39,10 @@
 
 #define IFACE_DIR        "/data/system/wpa_supplicant"
 #define DRIVER_PROP_NAME "wlan.driver.status"
-#define SUPPLICANT_NAME  "wpa_supplicant"
-#define SUPP_PROP_NAME   "init.svc.wpa_supplicant"
+#define SUPPLICANT_SERVICE_NAME  "wpa_supplicant"
 #define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
 #define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
 
-
 Supplicant::Supplicant() {
     mCtrl = NULL;
     mMonitor = NULL;
@@ -57,62 +50,25 @@
 
     mState = SupplicantState::UNKNOWN;
 
-    mLatestScanResults = new ScanResultCollection();
+    mServiceManager = new ServiceManager();
 
+    mLatestScanResults = new ScanResultCollection();
     pthread_mutex_init(&mLatestScanResultsLock, NULL);
 }
 
+Supplicant::~Supplicant() {
+    delete mServiceManager;
+}
+
 int Supplicant::start() {
 
     if (setupConfig()) {
         LOGW("Unable to setup supplicant.conf");
     }
-    
-    char status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 200;
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-    const prop_info *pi;
-    unsigned int serial = 0;
-#endif
-
-    if (property_get(SUPP_PROP_NAME, status, NULL) &&
-        !strcmp(status, "running")) {
-    } else {
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-        pi = __system_property_find(SUPP_PROP_NAME);
-        if (pi != NULL)
-            serial = pi->serial;
-#endif
-
-        LOGD("Starting Supplicant");
-        property_set("ctl.start", SUPPLICANT_NAME);
-        sched_yield();
-        while (count--) {
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-            if (!pi)
-                pi = __system_property_find(SUPP_PROP_NAME);
-            if (pi) {
-                __system_property_read(pi, NULL, status);
-                if (strcmp(status, "running") == 0)
-                    break;
-                else if (pi->serial != serial &&
-                        strcmp(status, "stopped") == 0) {
-                    errno = EIO;
-                    return -1;
-                }
-            }
-#else
-            if (property_get(SUPP_PROP_NAME, status, NULL)) {
-                if (!strcmp(status, "running"))
-                    break;
-            }
-#endif
-            usleep(100000);
-        }
-        if (!count) {
-            errno = ETIMEDOUT;
-            return -1;
-        }
+ 
+    if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
+        LOGE("Error starting supplicant (%s)", strerror(errno));
+        return -1;
     }
 
     wpa_ctrl_cleanup();
@@ -125,30 +81,13 @@
 
 int Supplicant::stop() {
 
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 50; 
-
     if (mListener->stopListener()) {
         LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
         return -1;
     }
 
-    if (property_get(SUPP_PROP_NAME, supp_status, NULL)
-        && strcmp(supp_status, "stopped") == 0) {
-        LOGD("Supplicant already stopped");
-        return 0;
-    }
-
-    LOGD("Stopping Supplicant");
-    property_set("ctl.stop", SUPPLICANT_NAME);
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
-            if (strcmp(supp_status, "stopped") == 0)
-                break;
-        }
-        usleep(100000);
+    if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
+        LOGW("Error stopping supplicant (%s)", strerror(errno));
     }
 
     if (mCtrl) {
@@ -160,35 +99,15 @@
         mMonitor = NULL;
     }
 
-    if (!count) {
-        LOGD("Timed out waiting for supplicant to stop");
-        errno = ETIMEDOUT;
-        return -1;
-    }
-
-    LOGD("Supplicant shutdown");
-
     return 0;
 }
 
 bool Supplicant::isStarted() {
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-
-    property_get(SUPP_PROP_NAME, supp_status, NULL);
-
-    if (!strcmp(supp_status, "running"))
-        return true;
-
-    return false;
+    return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
 }
 
 int Supplicant::connectToSupplicant() {
-    char ifname[256];
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-
-    LOGD("connectToSupplicant()");
-    if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
-            || strcmp(supp_status, "running") != 0) {
+    if (!isStarted()) {
         LOGE("Supplicant not running, cannot connect");
         return -1;
     }
@@ -229,7 +148,7 @@
         return -1;
     }
 
-    LOGD("sendCommand(): -> '%s'", cmd);
+//    LOGD("sendCommand(): -> '%s'", cmd);
 
     int rc;
     if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2)  {
@@ -245,7 +164,7 @@
         !strncmp(cmd, "SCAN_RESULTS", 12)) 
         reply[*reply_len] = '\0';
 
-    LOGD("sendCommand(): <- '%s'", reply);
+//    LOGD("sendCommand(): <- '%s'", reply);
     return 0;
 }
 
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
index 4a7ec3a..2ea0892 100644
--- a/nexus/Supplicant.h
+++ b/nexus/Supplicant.h
@@ -19,6 +19,7 @@
 struct wpa_ctrl;
 class SupplicantListener;
 class SupplicantEvent;
+class ServiceManager;
 
 #include <pthread.h>
 
@@ -31,13 +32,14 @@
     struct wpa_ctrl      *mMonitor;
     SupplicantListener   *mListener;
     int                  mState;
+    ServiceManager       *mServiceManager;
 
     ScanResultCollection *mLatestScanResults;
     pthread_mutex_t      mLatestScanResultsLock;
   
 public:
     Supplicant();
-    virtual ~Supplicant() {}
+    virtual ~Supplicant();
 
     int start();
     int stop();
@@ -50,7 +52,6 @@
     int removeNetwork(int networkId);
     WifiNetworkCollection *createNetworkList();
 
-
     int getState() { return mState; }
 
 
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
index 17bfe41..cd24c19 100644
--- a/nexus/VpnController.cpp
+++ b/nexus/VpnController.cpp
@@ -13,7 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <string.h>
 #include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include "VpnController.h"
 
 VpnController::VpnController() :
@@ -21,21 +27,34 @@
 }
 
 int VpnController::start() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::stop() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::enable() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::disable() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
+
+int VpnController::setVpnGateway(const char *vpnGw) {
+    if (!inet_aton(vpnGw, &mVpnGateway)) {
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+int VpnController::setVpnGateway(struct in_addr *vpnGw) {
+    memcpy(&mVpnGateway, vpnGw, sizeof(struct in_addr));
+    return 0;
+}
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
index 049fe6e..4088e6a 100644
--- a/nexus/VpnController.h
+++ b/nexus/VpnController.h
@@ -16,9 +16,15 @@
 #ifndef _VPN_CONTROLLER_H
 #define _VPN_CONTROLLER_H
 
+#include <netinet/in.h>
+
 #include "Controller.h"
 
 class VpnController : public Controller {
+    /*
+     * Gateway of the VPN server to connect to
+     */
+    struct in_addr mVpnGateway;
 
 public:
     VpnController();
@@ -30,6 +36,10 @@
     virtual int enable();
     virtual int disable();
 
+    struct in_addr &getVpnGateway() { return mVpnGateway; }
+    int setVpnGateway(const char *vpnGw);
+    int setVpnGateway(struct in_addr *vpnGw);
+
 protected:
 };