6
6
# This program is partly derived from an example program for an Avahi
7
7
# service publisher, downloaded from
8
8
# <http://avahi.org/wiki/PythonPublishExample>. This includes the
9
# methods "add", "remove", "server_state_changed",
10
# "entry_group_state_changed", "cleanup", and "activate" in the
11
# "AvahiService" class, and some lines in "main".
9
# methods "add" and "remove" in the "AvahiService" class, the
10
# "server_state_changed" and "entry_group_state_changed" functions,
11
# and some lines in "main".
13
13
# Everything else is
14
14
# Copyright © 2008,2009 Teddy Hogeborn
125
125
max_renames: integer; maximum number of renames
126
126
rename_count: integer; counter so we only rename after collisions
127
127
a sensible number of times
128
group: D-Bus Entry Group
131
129
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
132
130
servicetype = None, port = None, TXT = None,
133
131
domain = u"", host = u"", max_renames = 32768,
134
protocol = avahi.PROTO_UNSPEC, bus = None):
132
protocol = avahi.PROTO_UNSPEC):
135
133
self.interface = interface
137
135
self.type = servicetype
152
147
u" after %i retries, exiting.",
153
148
self.rename_count)
154
149
raise AvahiServiceError(u"Too many renames")
155
self.name = self.server.GetAlternativeServiceName(self.name)
150
self.name = server.GetAlternativeServiceName(self.name)
156
151
logger.info(u"Changing Zeroconf service name to %r ...",
158
153
syslogger.setFormatter(logging.Formatter
159
154
(u'Mandos (%s) [%%(process)d]:'
160
155
u' %%(levelname)s: %%(message)s'
164
159
self.rename_count += 1
165
160
def remove(self):
166
161
"""Derived from the Avahi example code"""
167
if self.group is not None:
162
if group is not None:
170
165
"""Derived from the Avahi example code"""
171
if self.group is None:
172
self.group = dbus.Interface(
173
self.bus.get_object(avahi.DBUS_NAME,
174
self.server.EntryGroupNew()),
175
avahi.DBUS_INTERFACE_ENTRY_GROUP)
176
self.group.connect_to_signal('StateChanged',
177
self.entry_group_state_changed)
168
group = dbus.Interface(bus.get_object
170
server.EntryGroupNew()),
171
avahi.DBUS_INTERFACE_ENTRY_GROUP)
172
group.connect_to_signal('StateChanged',
173
entry_group_state_changed)
178
174
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
179
self.name, self.type)
180
self.group.AddService(
183
dbus.UInt32(0), # flags
184
self.name, self.type,
185
self.domain, self.host,
186
dbus.UInt16(self.port),
187
avahi.string_array_to_txt_array(self.TXT))
189
def entry_group_state_changed(self, state, error):
190
"""Derived from the Avahi example code"""
191
logger.debug(u"Avahi state change: %i", state)
193
if state == avahi.ENTRY_GROUP_ESTABLISHED:
194
logger.debug(u"Zeroconf service established.")
195
elif state == avahi.ENTRY_GROUP_COLLISION:
196
logger.warning(u"Zeroconf service name collision.")
198
elif state == avahi.ENTRY_GROUP_FAILURE:
199
logger.critical(u"Avahi: Error in group state changed %s",
201
raise AvahiGroupError(u"State changed: %s"
204
"""Derived from the Avahi example code"""
205
if self.group is not None:
208
def server_state_changed(self, state):
209
"""Derived from the Avahi example code"""
210
if state == avahi.SERVER_COLLISION:
211
logger.error(u"Zeroconf server name collision")
213
elif state == avahi.SERVER_RUNNING:
216
"""Derived from the Avahi example code"""
217
if self.server is None:
218
self.server = dbus.Interface(
219
self.bus.get_object(avahi.DBUS_NAME,
220
avahi.DBUS_PATH_SERVER),
221
avahi.DBUS_INTERFACE_SERVER)
222
self.server.connect_to_signal(u"StateChanged",
223
self.server_state_changed)
224
self.server_state_changed(self.server.GetState())
175
service.name, service.type)
177
self.interface, # interface
178
self.protocol, # protocol
179
dbus.UInt32(0), # flags
180
self.name, self.type,
181
self.domain, self.host,
182
dbus.UInt16(self.port),
183
avahi.string_array_to_txt_array(self.TXT))
186
# From the Avahi example code:
187
group = None # our entry group
188
# End of Avahi example code
191
def _datetime_to_dbus(dt, variant_level=0):
192
"""Convert a UTC datetime.datetime() to a D-Bus type."""
193
return dbus.String(dt.isoformat(), variant_level=variant_level)
227
196
class Client(object):
483
452
# dbus.service.Object doesn't use super(), so we can't either.
485
def __init__(self, bus = None, *args, **kwargs):
454
def __init__(self, *args, **kwargs):
487
455
Client.__init__(self, *args, **kwargs)
488
456
# Only now, when this client is initialized, can it show up on
490
458
self.dbus_object_path = (dbus.ObjectPath
492
460
+ self.name.replace(u".", u"_")))
493
dbus.service.Object.__init__(self, self.bus,
461
dbus.service.Object.__init__(self, bus,
494
462
self.dbus_object_path)
497
def _datetime_to_dbus(dt, variant_level=0):
498
"""Convert a UTC datetime.datetime() to a D-Bus type."""
499
return dbus.String(dt.isoformat(),
500
variant_level=variant_level)
502
463
def enable(self):
503
464
oldstate = getattr(self, u"enabled", False)
504
465
r = Client.enable(self)
506
467
# Emit D-Bus signals
507
468
self.PropertyChanged(dbus.String(u"enabled"),
508
469
dbus.Boolean(True, variant_level=1))
509
self.PropertyChanged(
510
dbus.String(u"last_enabled"),
511
self._datetime_to_dbus(self.last_enabled,
470
self.PropertyChanged(dbus.String(u"last_enabled"),
471
(_datetime_to_dbus(self.last_enabled,
515
475
def disable(self, signal = True):
619
579
dbus.String(u"host"):
620
580
dbus.String(self.host, variant_level=1),
621
581
dbus.String(u"created"):
622
self._datetime_to_dbus(self.created,
582
_datetime_to_dbus(self.created, variant_level=1),
624
583
dbus.String(u"last_enabled"):
625
(self._datetime_to_dbus(self.last_enabled,
584
(_datetime_to_dbus(self.last_enabled,
627
586
if self.last_enabled is not None
628
587
else dbus.Boolean(False, variant_level=1)),
629
588
dbus.String(u"enabled"):
630
589
dbus.Boolean(self.enabled, variant_level=1),
631
590
dbus.String(u"last_checked_ok"):
632
(self._datetime_to_dbus(self.last_checked_ok,
591
(_datetime_to_dbus(self.last_checked_ok,
634
593
if self.last_checked_ok is not None
635
594
else dbus.Boolean (False, variant_level=1)),
636
595
dbus.String(u"timeout"):
1091
1050
return timevalue
1053
def server_state_changed(state):
1054
"""Derived from the Avahi example code"""
1055
if state == avahi.SERVER_COLLISION:
1056
logger.error(u"Zeroconf server name collision")
1058
elif state == avahi.SERVER_RUNNING:
1062
def entry_group_state_changed(state, error):
1063
"""Derived from the Avahi example code"""
1064
logger.debug(u"Avahi state change: %i", state)
1066
if state == avahi.ENTRY_GROUP_ESTABLISHED:
1067
logger.debug(u"Zeroconf service established.")
1068
elif state == avahi.ENTRY_GROUP_COLLISION:
1069
logger.warning(u"Zeroconf service name collision.")
1071
elif state == avahi.ENTRY_GROUP_FAILURE:
1072
logger.critical(u"Avahi: Error in group state changed %s",
1074
raise AvahiGroupError(u"State changed: %s" % unicode(error))
1094
1076
def if_nametoindex(interface):
1095
1077
"""Call the C function if_nametoindex(), or equivalent
1242
1224
u"checker": u"fping -q -- %%(host)s",
1245
client_config = configparser.SafeConfigParser(client_defaults)
1227
client_config = ConfigParser.SafeConfigParser(client_defaults)
1246
1228
client_config.read(os.path.join(server_settings[u"configdir"],
1247
1229
u"clients.conf"))
1249
1231
global mandos_dbus_service
1250
1232
mandos_dbus_service = None
1253
1235
tcp_server = IPv6_TCPServer((server_settings[u"address"],
1254
1236
server_settings[u"port"]),
1300
1282
(gnutls.library.functions
1301
1283
.gnutls_global_set_log_function(debug_gnutls))
1286
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1287
service = AvahiService(name = server_settings[u"servicename"],
1288
servicetype = u"_mandos._tcp",
1289
protocol = protocol)
1290
if server_settings["interface"]:
1291
service.interface = (if_nametoindex
1292
(str(server_settings[u"interface"])))
1303
1294
global main_loop
1304
1297
# From the Avahi example code
1305
1298
DBusGMainLoop(set_as_default=True )
1306
1299
main_loop = gobject.MainLoop()
1307
1300
bus = dbus.SystemBus()
1301
server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
1302
avahi.DBUS_PATH_SERVER),
1303
avahi.DBUS_INTERFACE_SERVER)
1308
1304
# End of Avahi example code
1310
1306
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1311
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1312
service = AvahiService(name = server_settings[u"servicename"],
1313
servicetype = u"_mandos._tcp",
1314
protocol = protocol, bus = bus)
1315
if server_settings["interface"]:
1316
service.interface = (if_nametoindex
1317
(str(server_settings[u"interface"])))
1319
1308
client_class = Client
1321
client_class = functools.partial(ClientDBus, bus = bus)
1310
client_class = ClientDBus
1323
1312
client_class(name = section,
1324
1313
config= dict(client_config.items(section)))
1325
1314
for section in client_config.sections()))