Skip to content

Commit ba6fe37

Browse files
jflydsommers
authored andcommitted
python: Fix StatusChangeCallback() so it works without a LogCallback
SessionManager.StatusChangeCallback() requires that LogForward be enabled, which previously only happened in `LogCallback`. Now both of them do it, which requires a bit of bookkeeping. This fixes #197 Message-Id: <20230906171758.344862-1-jeremyfleischman@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg26990.html Signed-off-by: Jeremy Fleischman <jeremyfleischman@gmail.com> Signed-off-by: David Sommerseth <davids@openvpn.net>
1 parent e939785 commit ba6fe37

File tree

1 file changed

+63
-11
lines changed

1 file changed

+63
-11
lines changed

src/python/openvpn3/SessionManager.py

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#
55
# Copyright (C) 2018 - 2023 OpenVPN Inc <sales@openvpn.net>
66
# Copyright (C) 2018 - 2023 David Sommerseth <davids@openvpn.net>
7+
# Copyright (C) 2023 Jeremy Fleischman <jeremyfleischman@gmail.com>
78
#
89

910
##
@@ -114,6 +115,7 @@ def __init__(self, dbuscon, objpath):
114115
self.__log_callback = None
115116
self.__status_callback = None
116117
self.__deleted = False
118+
self.__log_forward_enabled = False
117119

118120

119121
def __del__(self):
@@ -284,23 +286,33 @@ def GetFormattedStatistics(self, prefix='Connection statistics:\n', format_str='
284286
#
285287
#
286288
def LogCallback(self, cbfnc):
289+
if cbfnc is not None and self.__log_callback is not None:
290+
# In this case, the program must first disable the
291+
# current LogCallback() before setting a new one.
292+
raise RuntimeError('LogCallback() is already enabled')
293+
294+
if cbfnc is None and self.__log_callback is None:
295+
# This is fine: disabling a callback when there is no
296+
# callback is a simple no-op.
297+
return
298+
287299
if cbfnc is not None:
300+
# Subscribe to Log signals, which will be processed
301+
# by the callback function
288302
self.__log_callback = cbfnc
289303
self.__dbuscon.add_signal_receiver(cbfnc,
290304
signal_name='Log',
291305
dbus_interface='net.openvpn.v3.backends',
292306
bus_name='net.openvpn.v3.log',
293307
path=self.__session_path)
294-
self.__session_intf.LogForward(True)
295308
else:
296-
try:
297-
self.__session_intf.LogForward(False)
298-
except dbus.exceptions.DBusException:
299-
# If this fails, the session is typically already removed
300-
pass
301-
self.__dbuscon.remove_signal_receiver(self.__log_callback, 'Log')
302-
self.__log_callback = None
309+
# Only remove the callback if there actually *is* a callback
310+
# currently.
311+
if self.__log_callback is not None:
312+
self.__dbuscon.remove_signal_receiver(self.__log_callback, 'Log')
313+
self.__log_callback = None
303314

315+
self.__set_log_forward()
304316

305317
##
306318
# Subscribes to the StatusChange signals for this session and register
@@ -310,18 +322,34 @@ def LogCallback(self, cbfnc):
310322
# (integer) StatusMajor, (integer) StatusMinor, (string) message
311323
#
312324
def StatusChangeCallback(self, cbfnc):
325+
if cbfnc is not None and self.__status_callback is not None:
326+
# In this case, the program must first disable the
327+
# current StatusChangeCallback() before setting a new one.
328+
raise RuntimeError('StatusChangeCallback() is already enabled')
329+
330+
if cbfnc is None and self.__status_callback is None:
331+
# This is fine: disabling a callback when there is no
332+
# callback is a simple no-op.
333+
return
334+
313335
if cbfnc is not None:
336+
# Subscribe to StatusChange signals, which will be processed
337+
# by the callback function
314338
self.__status_callback = cbfnc
315339
self.__dbuscon.add_signal_receiver(cbfnc,
316340
signal_name='StatusChange',
317341
dbus_interface='net.openvpn.v3.backends',
318342
bus_name='net.openvpn.v3.log',
319343
path=self.__session_path)
320344
else:
321-
self.__dbuscon.remove_signal_receiver(self.__status_callback,
322-
'StatusChange')
323-
self.__status_callback = None
345+
# Only remove the callback if there actually *is* a callback
346+
# currently.
347+
if self.__status_callback is not None:
348+
self.__dbuscon.remove_signal_receiver(self.__status_callback,
349+
'StatusChange')
350+
self.__status_callback = None
324351

352+
self.__set_log_forward()
325353

326354

327355
##
@@ -417,6 +445,30 @@ def GetDCO(self):
417445
def SetDCO(self, dco):
418446
self.__prop_intf.Set('net.openvpn.v3.sessions', 'dco', dco)
419447

448+
##
449+
# Internal method to enable/disable LogForward as needed.
450+
# Must be called whenever a callback that needs LogForward enabled is
451+
# added or removed.
452+
#
453+
def __set_log_forward(self):
454+
# The LogCallback and the StatusChangeCallback both need LogForward
455+
# enabled. In other words, LogForward should be enabled if one or both
456+
# of those callbacks are registered.
457+
should_log_forward_be_enabled = (
458+
self.__log_callback is not None or self.__status_callback is not None
459+
)
460+
461+
if should_log_forward_be_enabled and not self.__log_forward_enabled:
462+
self.__session_intf.LogForward(True)
463+
self.__log_forward_enabled = True
464+
elif not should_log_forward_be_enabled and self.__log_forward_enabled:
465+
try:
466+
self.__session_intf.LogForward(False)
467+
except dbus.exceptions.DBusException:
468+
# If this fails, the session is typically already removed
469+
pass
470+
471+
self.__log_forward_enabled = False
420472

421473

422474
##

0 commit comments

Comments
 (0)