client: Implement support for queueing Agent messages
[platform/upstream/connman.git] / client / agent.c
index 01182e6..ce7e194 100644 (file)
@@ -39,6 +39,7 @@
 #include "agent.h"
 
 #define AGENT_INTERFACE      "net.connman.Agent"
+#define VPN_AGENT_INTERFACE  "net.connman.vpn.Agent"
 
 struct agent_data {
        char *interface;
@@ -47,11 +48,17 @@ struct agent_data {
        DBusMessage *reply;
        DBusMessageIter iter;
        DBusMessageIter dict;
+       GDBusMethodFunction pending_function;
 };
 
+static DBusConnection *agent_connection;
+
 static struct agent_data agent_request = {
        AGENT_INTERFACE,
 };
+static struct agent_data vpn_agent_request = {
+       VPN_AGENT_INTERFACE,
+};
 
 static void request_input_ssid_return(char *input, void *user_data);
 static void request_input_passphrase_return(char *input, void *user_data);
@@ -115,6 +122,10 @@ static void pending_message_remove(struct agent_data *request)
 
 static void pending_command_complete(char *message)
 {
+       struct agent_data *next_request = NULL;
+       DBusMessage *pending_message;
+       GDBusMethodFunction pending_function;
+
        __connmanctl_save_rl();
 
        fprintf(stdout, "%s", message);
@@ -125,6 +136,36 @@ static void pending_command_complete(char *message)
                __connmanctl_command_mode();
        else
                __connmanctl_agent_mode("", NULL, NULL);
+
+       if (agent_request.message != NULL)
+               next_request = &agent_request;
+       else if (vpn_agent_request.message != NULL)
+               next_request = &vpn_agent_request;
+
+       if (next_request == NULL)
+               return;
+
+       pending_message = next_request->message;
+       pending_function = next_request->pending_function;
+       next_request->pending_function = NULL;
+
+       pending_function(agent_connection, next_request->message,
+                       next_request);
+
+       dbus_message_unref(pending_message);
+}
+
+static bool handle_message(DBusMessage *message, struct agent_data *request,
+               GDBusMethodFunction function)
+{
+       if (agent_request.pending_function == NULL &&
+                       vpn_agent_request.pending_function == NULL)
+               return true;
+
+       request->message = dbus_message_ref(message);
+       request->pending_function = function;
+
+       return false;
 }
 
 static DBusMessage *agent_release(DBusConnection *connection,
@@ -132,6 +173,9 @@ static DBusMessage *agent_release(DBusConnection *connection,
 {
        struct agent_data *request = user_data;
 
+       if (handle_message(message, request, agent_release) == false)
+               return NULL;
+
        g_dbus_unregister_interface(connection, agent_path(),
                        request->interface);
        request->registered = false;
@@ -140,6 +184,9 @@ static DBusMessage *agent_release(DBusConnection *connection,
 
        if (strcmp(request->interface, AGENT_INTERFACE) == 0)
                pending_command_complete("Agent unregistered by ConnMan\n");
+       else
+               pending_command_complete("VPN Agent unregistered by ConnMan "
+                               "VPNd\n");
 
        if (__connmanctl_is_interactive() == false)
                __connmanctl_quit();
@@ -152,17 +199,21 @@ static DBusMessage *agent_cancel(DBusConnection *connection,
 {
        struct agent_data *request = user_data;
 
+       if (handle_message(message, request, agent_cancel) == false)
+               return NULL;
+
        pending_message_remove(request);
 
        if (strcmp(request->interface, AGENT_INTERFACE) == 0)
                pending_command_complete("Agent request cancelled by "
                                "ConnMan\n");
+       else
+               pending_command_complete("VPN Agent request cancelled by "
+                               "ConnMan VPNd\n");
 
        return dbus_message_new_method_return(message);
 }
 
-static DBusConnection *agent_connection = NULL;
-
 static void request_browser_return(char *input, void *user_data)
 {
        struct agent_data *request = user_data;
@@ -191,6 +242,9 @@ static DBusMessage *agent_request_browser(DBusConnection *connection,
        DBusMessageIter iter;
        char *service, *url;
 
+       if (handle_message(message, request, agent_request_browser) == false)
+               return NULL;
+
        dbus_message_iter_init(message, &iter);
 
        dbus_message_iter_get_basic(&iter, &service);
@@ -202,7 +256,6 @@ static DBusMessage *agent_request_browser(DBusConnection *connection,
        fprintf(stdout, "  %s\n", url);
        __connmanctl_redraw_rl();
 
-       agent_connection = connection;
        request->message = dbus_message_ref(message);
        __connmanctl_agent_mode("Connected (yes/no)? ",
                        request_browser_return, request);
@@ -219,6 +272,10 @@ static void report_error_return(char *input, void *user_data)
                if (strcmp(request->interface, AGENT_INTERFACE) == 0)
                        g_dbus_send_error(agent_connection, request->message,
                                        "net.connman.Agent.Error.Retry", NULL);
+               else
+                       g_dbus_send_error(agent_connection, request->message,
+                                       "net.connman.vpn.Agent.Error.Retry",
+                                       NULL);
                break;
        case 0:
                g_dbus_send_reply(agent_connection, request->message,
@@ -239,6 +296,9 @@ static DBusMessage *agent_report_error(DBusConnection *connection,
        DBusMessageIter iter;
        char *path, *service, *error;
 
+       if (handle_message(message, request, agent_report_error) == false)
+               return NULL;
+
        dbus_message_iter_init(message, &iter);
 
        dbus_message_iter_get_basic(&iter, &path);
@@ -250,10 +310,11 @@ static DBusMessage *agent_report_error(DBusConnection *connection,
        __connmanctl_save_rl();
        if (strcmp(request->interface, AGENT_INTERFACE) == 0)
                fprintf(stdout, "Agent ReportError %s\n", service);
+       else
+               fprintf(stdout, "VPN Agent ReportError %s\n", service);
        fprintf(stdout, "  %s\n", error);
        __connmanctl_redraw_rl();
 
-       agent_connection = connection;
        request->message = dbus_message_ref(message);
        __connmanctl_agent_mode("Retry (yes/no)? ", report_error_return,
                        request);
@@ -384,6 +445,9 @@ static DBusMessage *agent_request_input(DBusConnection *connection,
 
        int i;
 
+       if (handle_message(message, request, agent_request_input) == false)
+               return NULL;
+
        dbus_message_iter_init(message, &iter);
 
        dbus_message_iter_get_basic(&iter, &str);
@@ -442,7 +506,6 @@ static DBusMessage *agent_request_input(DBusConnection *connection,
                dbus_message_iter_next(&dict);
        }
 
-       agent_connection = connection;
        request->reply = dbus_message_new_method_return(message);
        dbus_message_iter_init_append(request->reply, &request->iter);
 
@@ -458,8 +521,8 @@ static DBusMessage *agent_request_input(DBusConnection *connection,
 }
 
 static const GDBusMethodTable agent_methods[] = {
-       { GDBUS_METHOD("Release", NULL, NULL, agent_release) },
-       { GDBUS_METHOD("Cancel", NULL, NULL, agent_cancel) },
+       { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
+       { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
        { GDBUS_ASYNC_METHOD("RequestBrowser",
                                GDBUS_ARGS({ "service", "o" },
                                        { "url", "s" }),
@@ -504,6 +567,8 @@ int __connmanctl_agent_register(DBusConnection *connection)
                return -EALREADY;
        }
 
+       agent_connection = connection;
+
        if (g_dbus_register_interface(connection, path,
                                        AGENT_INTERFACE, agent_methods,
                                        NULL, NULL, &agent_request,
@@ -563,3 +628,105 @@ int __connmanctl_agent_unregister(DBusConnection *connection)
 
        return result;
 }
+
+static const GDBusMethodTable vpn_agent_methods[] = {
+       { GDBUS_ASYNC_METHOD("Release", NULL, NULL, agent_release) },
+       { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, agent_cancel) },
+       { GDBUS_ASYNC_METHOD("ReportError",
+                               GDBUS_ARGS({ "service", "o" },
+                                       { "error", "s" }),
+                               NULL, agent_report_error) },
+       { },
+};
+
+static int vpn_agent_register_return(DBusMessageIter *iter, const char *error,
+               void *user_data)
+{
+       DBusConnection *connection = user_data;
+
+       if (error != NULL) {
+               g_dbus_unregister_interface(connection, agent_path(),
+                               VPN_AGENT_INTERFACE);
+               fprintf(stderr, "Error registering VPN Agent: %s\n", error);
+               return 0;
+       }
+
+       vpn_agent_request.registered = true;
+       fprintf(stdout, "VPN Agent registered\n");
+
+       return -EINPROGRESS;
+}
+
+int __connmanctl_vpn_agent_register(DBusConnection *connection)
+{
+       char *path = agent_path();
+       int result;
+
+       if (vpn_agent_request.registered == true) {
+               fprintf(stderr, "VPN Agent already registered\n");
+               return -EALREADY;
+       }
+
+       agent_connection = connection;
+
+       if (g_dbus_register_interface(connection, path,
+                                       VPN_AGENT_INTERFACE, vpn_agent_methods,
+                                       NULL, NULL, &vpn_agent_request,
+                                       NULL) == FALSE) {
+               fprintf(stderr, "Error: Failed to register VPN Agent "
+                               "callbacks\n");
+               return 0;
+       }
+
+       result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
+                       VPN_PATH, "net.connman.vpn.Manager", "RegisterAgent",
+                       vpn_agent_register_return, connection,
+                       DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
+
+       if (result != -EINPROGRESS) {
+               g_dbus_unregister_interface(connection, agent_path(),
+                               VPN_AGENT_INTERFACE);
+
+               fprintf(stderr, "Error: Failed to register VPN Agent\n");
+       }
+
+       return result;
+}
+
+static int vpn_agent_unregister_return(DBusMessageIter *iter,
+               const char *error, void *user_data)
+{
+       if (error != NULL) {
+               fprintf(stderr, "Error unregistering VPN Agent: %s\n", error);
+               return 0;
+       }
+
+       vpn_agent_request.registered = false;
+       fprintf(stdout, "VPN Agent unregistered\n");
+
+       return 0;
+}
+
+int __connmanctl_vpn_agent_unregister(DBusConnection *connection)
+{
+       char *path = agent_path();
+       int result;
+
+       if (vpn_agent_request.registered == false) {
+               fprintf(stderr, "VPN Agent not registered\n");
+               return -EALREADY;
+       }
+
+       g_dbus_unregister_interface(connection, agent_path(),
+                       VPN_AGENT_INTERFACE);
+
+       result = __connmanctl_dbus_method_call(connection, VPN_SERVICE,
+                       VPN_PATH, "net.connman.vpn.Manager", "UnregisterAgent",
+                       vpn_agent_unregister_return, NULL,
+                       DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
+
+       if (result != -EINPROGRESS)
+               fprintf(stderr, "Error: Failed to unregister VPN Agent\n");
+
+       return result;
+}