diff options
author | Thomas Haller <thaller@redhat.com> | 2014-11-12 15:44:26 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-11-13 15:05:26 +0100 |
commit | f5b83d8af34094cf7b5d706a1394d735c10e6606 (patch) | |
tree | 643e0a808c67e0fa672d7e8a370bfd3136363c52 | |
parent | b7ca1c84ee6f1871dd965a025e21852a8fdadd76 (diff) | |
download | NetworkManager-f5b83d8af34094cf7b5d706a1394d735c10e6606.tar.gz |
firewall: always complete callbacks asynchronously
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | src/nm-firewall-manager.c | 129 |
1 files changed, 98 insertions, 31 deletions
diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index ccd30cbca9..afef42e989 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -45,6 +45,8 @@ typedef struct { guint name_owner_id; DBusGProxy * proxy; gboolean running; + + GSList *pending_calls; } NMFirewallManagerPrivate; enum { @@ -57,17 +59,27 @@ static guint signals[LAST_SIGNAL] = { 0 }; /********************************************************************/ +#define PENDING_CALL_DUMMY ((NMFirewallPendingCall) ((void *) nm_firewall_manager_init) ) +#define PENDING_CALL_FROM_INFO(info) ((NMFirewallPendingCall) info) + typedef struct { + NMFirewallManager *self; char *iface; FwAddToZoneFunc callback; gpointer user_data; guint id; gboolean completed; + + gboolean cancelled; + gboolean is_idly_scheduled; + DBusGProxyCall *dbus_call; } CBInfo; static void -cb_info_free (CBInfo *info) +_cb_info_free (CBInfo *info) { + NMFirewallManagerPrivate *priv; + g_return_if_fail (info != NULL); if (!info->completed) { @@ -82,27 +94,54 @@ cb_info_free (CBInfo *info) } } g_free (info->iface); - g_free (info); + + priv = NM_FIREWALL_MANAGER_GET_PRIVATE (info->self); + priv->pending_calls = g_slist_remove (priv->pending_calls, info); + g_object_unref (info->self); + + g_slice_free (CBInfo, info); } static CBInfo * -_cb_info_create (const char *iface, FwAddToZoneFunc callback, gpointer user_data) +_cb_info_create (NMFirewallManager *self, const char *iface, FwAddToZoneFunc callback, gpointer user_data) { + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); static guint id; CBInfo *info; - info = g_malloc (sizeof (CBInfo)); + info = g_slice_new0 (CBInfo); if (++id == 0) ++id; + info->self = g_object_ref (self); info->id = id; info->iface = g_strdup (iface); info->completed = FALSE; info->callback = callback; info->user_data = user_data; + priv->pending_calls = g_slist_prepend (priv->pending_calls, info); return info; } +static gboolean +add_or_change_idle_cb (gpointer user_data) +{ + CBInfo *info = user_data; + + if (info->cancelled) { + /* operation was cancelled. _cb_info_free will invoke callback. */ + } else { + nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone call pretends success [%u]", + info->iface, info->id); + if (info->callback) + info->callback (NULL, info->user_data); + info->completed = TRUE; + } + + _cb_info_free (info); + return G_SOURCE_REMOVE; +} + static void add_or_change_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) { @@ -146,25 +185,33 @@ nm_firewall_manager_add_or_change_zone (NMFirewallManager *self, CBInfo *info; if (priv->running == FALSE) { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change skipped (not running)", iface); - if (callback) - callback (NULL, user_data); - return NULL; + if (callback) { + info = _cb_info_create (self, iface, callback, user_data); + info->is_idly_scheduled= TRUE; + g_idle_add (add_or_change_idle_cb, info); + nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u] (not running, simulate success)", iface, add ? "add" : "change", + zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id); + return PENDING_CALL_FROM_INFO (info); + } else { + nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change skipped (not running)", iface); + return PENDING_CALL_DUMMY; + } } - info = _cb_info_create (iface, callback, user_data); + info = _cb_info_create (self, iface, callback, user_data); nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u]", iface, add ? "add" : "change", zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id); - return (NMFirewallPendingCall) dbus_g_proxy_begin_call_with_timeout (priv->proxy, - add ? "addInterface" : "changeZone", - add_or_change_cb, - info, - (GDestroyNotify) cb_info_free, - 10000, /* timeout */ - G_TYPE_STRING, zone ? zone : "", - G_TYPE_STRING, iface, - G_TYPE_INVALID); + info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + add ? "addInterface" : "changeZone", + add_or_change_cb, + info, + (GDestroyNotify) _cb_info_free, + 10000, /* timeout */ + G_TYPE_STRING, zone ? zone : "", + G_TYPE_STRING, iface, + G_TYPE_INVALID); + return PENDING_CALL_FROM_INFO (info); } static void @@ -206,29 +253,49 @@ nm_firewall_manager_remove_from_zone (NMFirewallManager *self, if (priv->running == FALSE) { nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove skipped (not running)", iface); - return NULL; + return PENDING_CALL_DUMMY; } - info = _cb_info_create (iface, NULL, NULL); + info = _cb_info_create (self, iface, NULL, NULL); nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove -> %s%s%s [%u]", iface, zone?"\"":"", zone ? zone : "*", zone?"\"":"", info->id); - return (NMFirewallPendingCall) dbus_g_proxy_begin_call_with_timeout (priv->proxy, - "removeInterface", - remove_cb, - info, - (GDestroyNotify) cb_info_free, - 10000, /* timeout */ - G_TYPE_STRING, zone ? zone : "", - G_TYPE_STRING, iface, - G_TYPE_INVALID); + info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + "removeInterface", + remove_cb, + info, + (GDestroyNotify) _cb_info_free, + 10000, /* timeout */ + G_TYPE_STRING, zone ? zone : "", + G_TYPE_STRING, iface, + G_TYPE_INVALID); + return PENDING_CALL_FROM_INFO (info); } void nm_firewall_manager_cancel_call (NMFirewallManager *self, NMFirewallPendingCall call) { + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + GSList *pending; + CBInfo *info; + g_return_if_fail (NM_IS_FIREWALL_MANAGER (self)); - dbus_g_proxy_cancel_call (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy, - (DBusGProxyCall *) call); + + if (call == PENDING_CALL_DUMMY) + return; + + pending = g_slist_find (priv->pending_calls, call); + + if (!pending) + return; + priv->pending_calls = g_slist_remove_link (priv->pending_calls, pending); + + info = (CBInfo *) call; + if (info->is_idly_scheduled) + info->cancelled = TRUE; + else { + dbus_g_proxy_cancel_call (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy, + info->dbus_call); + } } static void |