Files
wmic/pysamba/twisted/reactor.py
T

233 lines
7.4 KiB
Python
Raw Normal View History

2019-02-16 00:16:52 +01:00
###########################################################################
#
# This program is part of Zenoss Core, an open source monitoring platform.
# Copyright (C) 2008-2010, Zenoss Inc.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# For complete information please visit: http://www.zenoss.com/oss/
#
###########################################################################
__doc__="python classes to integrate the twisted and Samba event loops"
from pysamba.library import *
from ctypes import *
import os
import sys
import errno
import sys
import logging
logging.basicConfig()
log = logging.getLogger("zen.pysamba")
EVENT_FD_READ = 1
EVENT_FD_WRITE = 2
class Timer(object):
callLater = None
timer = Timer()
class timeval(Structure):
_fields_ = [
('tv_sec', c_long),
('tv_usec', c_long),
]
#void zenoss_get_next_timeout(struct event_context* event_ctx, struct timeval* timeout)
library.zenoss_get_next_timeout.restype = None
library.zenoss_get_next_timeout.argtypes = [c_void_p, POINTER(timeval)]
#logging will occur within this C function - avoid python logging for verbosity
#library.zenoss_get_next_timeout = logFuncCall(library.zenoss_get_next_timeout)
library.zenoss_read_ready.restype = None
library.zenoss_read_ready.argtypes = [c_void_p, c_int]
library.zenoss_read_ready = logFuncCall(library.zenoss_read_ready)
library.zenoss_write_ready.restype = None
library.zenoss_write_ready.argtypes = [c_void_p, c_int]
library.zenoss_write_ready = logFuncCall(library.zenoss_write_ready)
library.lp_do_parameter.restype = None
library.lp_do_parameter.argtypes = [c_int, c_char_p, c_char_p]
library.lp_do_parameter = logFuncCall(library.lp_do_parameter)
from twisted.internet.selectreactor import SelectReactor
from select import select
class WmiReactorMixin:
def __init__(self):
self.readFdMap = {}
self.writeFdMap = {}
def callTimeouts(self, delay):
"""
Perform a single iteration of the reactor. Here we make sure that
all of our file descriptors that we need to watch are and then delegate
the actual watching back to the twisted reactor.
"""
#
# determine the next timeout interval based upon any queued events
#
timeout = timeval()
while True:
library.zenoss_get_next_timeout(eventContext, byref(timeout))
t = timeout.tv_sec + timeout.tv_usec / 1e6
if t > 0.0: break
if timer.callLater:
timer.callLater.cancel()
timer.callLater = None
timer.callLater = self.callLater(t, self.__checkTimeouts)
def removeFileDescriptor(self, fd):
self.watchFileDescriptor(fd, 0)
def watchFileDescriptor(self, fd, flags):
log.debug("Callback from c: watchFileDescriptor: fd: %s flags: %s" % (fd, flags))
if (flags & EVENT_FD_READ) != 0:
if fd not in self.readFdMap:
reader = ActivityHook('Reader', fd)
self.readFdMap[fd] = reader
self.addReader(self.readFdMap[fd])
elif fd in self.readFdMap:
self.removeReader(self.readFdMap[fd])
del self.readFdMap[fd]
if (flags & EVENT_FD_WRITE) != 0:
if fd not in self.writeFdMap:
writer = ActivityHook('Writer', fd)
self.writeFdMap[fd] = writer
self.addWriter(self.writeFdMap[fd])
elif fd in self.writeFdMap:
self.removeWriter(self.writeFdMap[fd])
del self.writeFdMap[fd]
return 0
def __checkTimeouts(self):
timer.callLater = None
def doOnce(self):
self.doIteration(0.1)
return 0
class WmiReactor(WmiReactorMixin, SelectReactor):
def __init__(self):
SelectReactor.__init__(self)
WmiReactorMixin.__init__(self)
def _preenDescriptors(self):
for fdMap, lst in (
(self.readFdMap, self.readFdMap.keys()),
(self.writeFdMap.keys(), self.writeFdMap.keys())
):
for fd in lst:
try:
select(fd + 1, [fd], [fd], [fd], 0)
except:
try:
fdMap.pop(fd)
except IndexError:
pass
SelectReactor._preenDescriptors(self)
def doIteration(self, delay):
"""
Perform a single iteration of the reactor. Here we make sure that
all of our file descriptors that we need to watch are and then delegate
the actual watching back to the twisted reactor.
"""
self.callTimeouts(delay)
return SelectReactor.doIteration(self, delay)
#
# Install the WmiReactor instead of the default twisted one. See the following
# ticket for the history of using an epoll vs. select reactor.
# http://dev.zenoss.org/trac/ticket/4640
#
if os.uname()[0] == 'Linux':
from twisted.internet.epollreactor import EPollReactor
class WmiEPollReactor(WmiReactorMixin, EPollReactor):
def __init__(self):
EPollReactor.__init__(self)
WmiReactorMixin.__init__(self)
def _remove(self, xer, primary, other, selectables, event, antievent):
try:
return EPollReactor._remove(self,
xer, primary, other, selectables,
event, antievent)
except IOError, err:
# huh, wha? oh, we weren't listening for that fileno anyhow
if err.errno != errno.EBADF:
raise
def doPoll(self, delay):
self.callTimeouts(delay)
return EPollReactor.doPoll(self, delay)
doIteration = doPoll
wmiReactor = WmiEPollReactor()
else:
wmiReactor = WmiReactor()
callback = reactor_functions()
callback.fd_callback = library.watch_fd_callback(logFuncCall(wmiReactor.watchFileDescriptor))
callback.loop_callback = library.loop_callback(logFuncCall(wmiReactor.doOnce))
eventContext = library.async_create_context(byref(callback))
from twisted.internet.main import installReactor
try:
installReactor(wmiReactor)
except Exception, e:
log.critical("Unable to install the WMI reactor. %s" % e)
sys.exit(1) # TODO: pick a better error code?
class ActivityHook:
"Notify the Samba event loop of file descriptor activity"
def __init__(self, prefix, fd):
self.prefix = prefix
self.fd = fd
def logPrefix(self):
return self.prefix
def doRead(self):
library.zenoss_read_ready(eventContext, self.fd)
def doWrite(self):
library.zenoss_write_ready(eventContext, self.fd)
def fileno(self):
return self.fd
def connectionLost(self, why):
wmiReactor.removeFileDescriptor(self.fd)
# allow users to write:
# from pysamba.twisted import reactor
# instead of
# from twisted.internet import reactor
from twisted.internet import reactor
def setNTLMv2Authentication(enabled = False):
"""
Enables or disables the NTLMv2 authentication feature.
@param enabled: True if NTLMv2 is supported
@type enabled: boolean
"""
flag = "no"
if enabled:
flag = "yes"
library.lp_do_parameter(-1, "client ntlmv2 auth", flag)
log.debug("client ntlmv2 auth is now %s", flag)