Отключите точку доступа WiFi с помощью NetworkManager и Python - PullRequest
3 голосов
/ 20 января 2012

Я создаю приложение Python, которое должно подключаться и отключаться от Wifi на Linux.Я использую слой NetworkManager через замечательную библиотеку networkmanager, найденную в cnetworkmanager (Python CLI для NetworkManager http://vidner.net/martin/software/cnetworkmanager/ спасибо Мартину Виднеру), в демоне (названном stationd).Этот демон запускает gobject.MainLoop.После пробуждения timeout_add_seconds (запускается действием пользователя в графическом интерфейсе), я должен отключить текущий работающий Wifi и подключиться к новому:

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

from networkmanager import NetworkManager
import networkmanager.applet.settings as settings
from networkmanager.applet import USER_SERVICE 
from networkmanager.applet.service import NetworkManagerUserSettings, NetworkManagerSettings
import time
import memcache

import gobject
loop = gobject.MainLoop()

nm = NetworkManager()

dummy_handler = lambda *args: None

cache = memcache.Client(['127.0.0.1:11211',] )


def get_device(dev_spec, hint):
    candidates = []
    devs = NetworkManager().GetDevices()
    for dev in devs:
        if dev._settings_type() == hint:
            candidates.append(dev)
    if len(candidates) == 1:
        return candidates[0]
    for dev in devs:
        if dev["Interface"] == dev_spec:
            return dev
    print "Device '%s' not found" % dev_spec
    return None

def kill_allconnections():
    connections=nm['ActiveConnections']
    for c in connections:
        print c.object_path
        nm.DeactivateConnection(c.object_path)

class Wifi(object):

    def connect(self, ssid, security="open", password=None):
        "Connects to given Wifi network"
        c=None # connection settings
        us = NetworkManagerUserSettings([])
        if security=="open":
            c = settings.WiFi(ssid)
        elif security=="wep":
            c = settings.Wep(ssid, password)
        elif security=="wpa":
            c = settings.WpaPsk(ssid, password)
        else:
            raise AttributeError("invalid security model '%s'"%security)
        svc = USER_SERVICE
        svc_conn = us.addCon(c.conmap)
        hint = svc_conn.settings["connection"]["type"]
        dev = get_device("", hint)
        appath = "/"
        nm.ActivateConnection(svc, svc_conn, dev, appath, reply_handler=dummy_handler, error_handler=dummy_handler)


def change_network_settings():
    key="station:network:change"
    change=cache.get(key)
    if change is not None:
        print "DISCONNECT"
        kill_allconnections()
        print "CHANGE SETTINGS"
        wifi=cache.get(key+':wifi')
        if wifi is not None:
            ssid=cache.get(key+':wifi:ssid')
            security=cache.get(key+':wifi:security')
            password=cache.get(key+':wifi:password')
            print "SWITCHING TO %s"%ssid
            Wifi().connect(ssid, security, password)
        cache.delete(key)
    return True    

def mainloop():
   gobject.timeout_add_seconds(1, change_network_settings)
   try:
      loop.run()
   except KeyboardInterrupt:
      loop.quit()

if __name__=="__main__":
    mainloop()

Это отлично работает для первого соединения (читай: коробкане подключен, демон запущен и коробка безупречно подключается к Wifi).Проблема возникает, когда я пытаюсь подключиться к другому Wifi: kill_allconnections () запускается без вывода сообщений, а метод connect вызывает исключение для nm.ActivateConnection:

Traceback (most recent call last):
  File "stationd.py", line 40, in change_network_settings
    Wifi().connect(ssid, security, password)
  File "/home/biopredictive/station/lib/network.py", line 88, in connect
    us = NetworkManagerUserSettings([])
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 71, in __init__
    super(NetworkManagerUserSettings, self).__init__(conmaps, USER_SERVICE)
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 33, in __init__
    dbus.service.Object.__init__(self, bus, opath, bus_name)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 480, in __init__
    self.add_to_connection(conn, object_path)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 571, in add_to_connection
    self._fallback)
KeyError: "Can't register the object-path handler for '/org/freedesktop/NetworkManagerSettings': there is already a handler"

Похоже, мое прежнее соединение не освободилоРесурсы ?Я очень новичок в программировании gobject / dbus.Не могли бы вы помочь?

1 Ответ

3 голосов
/ 31 января 2012

У меня есть ответ в списке рассылки D-Bus.Цитата здесь для архива:

class Wifi(...):
    def connect(...):
        ...
        us = NetworkManagerUserSettings([]) 

NetworkManagerUserSettings - это сервер, а не клиент.(Это конструктивная особенность NM, которая была исключена в NM 0.9) Вы должны создать только один для демона, а не для каждой попытки соединения.

...