1########################################################################### 2# 3# This program is part of Zenoss Core, an open source monitoring platform. 4# Copyright (C) 2008-2010, Zenoss Inc. 5# 6# This program is free software; you can redistribute it and/or modify it 7# under the terms of the GNU General Public License version 2, or (at your 8# option) any later version, as published by the Free Software Foundation. 9# 10# For complete information please visit: http://www.zenoss.com/oss/ 11# 12########################################################################### 13 14__doc__="python classes to integrate the twisted and Samba event loops" 15 16from pysamba.library import * 17from ctypes import * 18 19import os 20import sys 21import errno 22import sys 23import logging 24logging.basicConfig() 25log = logging.getLogger("zen.pysamba") 26 27EVENT_FD_READ = 1 28EVENT_FD_WRITE = 2 29 30class Timer(object): 31 callLater = None 32timer = Timer() 33 34class timeval(Structure): 35 _fields_ = [ 36 ('tv_sec', c_long), 37 ('tv_usec', c_long), 38 ] 39 40#void zenoss_get_next_timeout(struct event_context* event_ctx, struct timeval* timeout) 41library.zenoss_get_next_timeout.restype = None 42library.zenoss_get_next_timeout.argtypes = [c_void_p, POINTER(timeval)] 43#logging will occur within this C function - avoid python logging for verbosity 44#library.zenoss_get_next_timeout = logFuncCall(library.zenoss_get_next_timeout) 45 46library.zenoss_read_ready.restype = None 47library.zenoss_read_ready.argtypes = [c_void_p, c_int] 48library.zenoss_read_ready = logFuncCall(library.zenoss_read_ready) 49 50library.zenoss_write_ready.restype = None 51library.zenoss_write_ready.argtypes = [c_void_p, c_int] 52library.zenoss_write_ready = logFuncCall(library.zenoss_write_ready) 53 54library.lp_do_parameter.restype = None 55library.lp_do_parameter.argtypes = [c_int, c_char_p, c_char_p] 56library.lp_do_parameter = logFuncCall(library.lp_do_parameter) 57 58from twisted.internet.selectreactor import SelectReactor 59from select import select 60 61class WmiReactorMixin: 62 def __init__(self): 63 self.readFdMap = {} 64 self.writeFdMap = {} 65 66 def callTimeouts(self, delay): 67 """ 68 Perform a single iteration of the reactor. Here we make sure that 69 all of our file descriptors that we need to watch are and then delegate 70 the actual watching back to the twisted reactor. 71 """ 72 73 # 74 # determine the next timeout interval based upon any queued events 75 # 76 timeout = timeval() 77 while True: 78 library.zenoss_get_next_timeout(eventContext, byref(timeout)) 79 t = timeout.tv_sec + timeout.tv_usec / 1e6 80 if t > 0.0: break 81 82 if timer.callLater: 83 timer.callLater.cancel() 84 timer.callLater = None 85 timer.callLater = self.callLater(t, self.__checkTimeouts) 86 87 def removeFileDescriptor(self, fd): 88 self.watchFileDescriptor(fd, 0) 89 90 def watchFileDescriptor(self, fd, flags): 91 log.debug("Callback from c: watchFileDescriptor: fd: %s flags: %s" % (fd, flags)) 92 if (flags & EVENT_FD_READ) != 0: 93 if fd not in self.readFdMap: 94 reader = ActivityHook('Reader', fd) 95 self.readFdMap[fd] = reader 96 self.addReader(self.readFdMap[fd]) 97 elif fd in self.readFdMap: 98 self.removeReader(self.readFdMap[fd]) 99 del self.readFdMap[fd] 100 101 if (flags & EVENT_FD_WRITE) != 0: 102 if fd not in self.writeFdMap: 103 writer = ActivityHook('Writer', fd) 104 self.writeFdMap[fd] = writer 105 self.addWriter(self.writeFdMap[fd]) 106 elif fd in self.writeFdMap: 107 self.removeWriter(self.writeFdMap[fd]) 108 del self.writeFdMap[fd] 109 110 return 0 111 112 def __checkTimeouts(self): 113 timer.callLater = None 114 115 def doOnce(self): 116 self.doIteration(0.1) 117 return 0 118 119class WmiReactor(WmiReactorMixin, SelectReactor): 120 def __init__(self): 121 SelectReactor.__init__(self) 122 WmiReactorMixin.__init__(self) 123 124 def _preenDescriptors(self): 125 for fdMap, lst in ( 126 (self.readFdMap, self.readFdMap.keys()), 127 (self.writeFdMap.keys(), self.writeFdMap.keys()) 128 ): 129 for fd in lst: 130 try: 131 select(fd + 1, [fd], [fd], [fd], 0) 132 except: 133 try: 134 fdMap.pop(fd) 135 except IndexError: 136 pass 137 SelectReactor._preenDescriptors(self) 138 139 def doIteration(self, delay): 140 """ 141 Perform a single iteration of the reactor. Here we make sure that 142 all of our file descriptors that we need to watch are and then delegate 143 the actual watching back to the twisted reactor. 144 """ 145 146 self.callTimeouts(delay) 147 return SelectReactor.doIteration(self, delay) 148 149# 150# Install the WmiReactor instead of the default twisted one. See the following 151# ticket for the history of using an epoll vs. select reactor. 152# http://dev.zenoss.org/trac/ticket/4640 153# 154if os.uname()[0] == 'Linux': 155 from twisted.internet.epollreactor import EPollReactor 156 class WmiEPollReactor(WmiReactorMixin, EPollReactor): 157 def __init__(self): 158 EPollReactor.__init__(self) 159 WmiReactorMixin.__init__(self) 160 161 def _remove(self, xer, primary, other, selectables, event, antievent): 162 try: 163 return EPollReactor._remove(self, 164 xer, primary, other, selectables, 165 event, antievent) 166 except IOError, err: 167 # huh, wha? oh, we weren't listening for that fileno anyhow 168 if err.errno != errno.EBADF: 169 raise 170 171 def doPoll(self, delay): 172 self.callTimeouts(delay) 173 return EPollReactor.doPoll(self, delay) 174 175 doIteration = doPoll 176 177 wmiReactor = WmiEPollReactor() 178 179else: 180 wmiReactor = WmiReactor() 181 182callback = reactor_functions() 183callback.fd_callback = library.watch_fd_callback(logFuncCall(wmiReactor.watchFileDescriptor)) 184callback.loop_callback = library.loop_callback(logFuncCall(wmiReactor.doOnce)) 185eventContext = library.async_create_context(byref(callback)) 186 187from twisted.internet.main import installReactor 188try: 189 installReactor(wmiReactor) 190except Exception, e: 191 log.critical("Unable to install the WMI reactor. %s" % e) 192 sys.exit(1) # TODO: pick a better error code? 193 194class ActivityHook: 195 "Notify the Samba event loop of file descriptor activity" 196 197 def __init__(self, prefix, fd): 198 self.prefix = prefix 199 self.fd = fd 200 201 def logPrefix(self): 202 return self.prefix 203 204 def doRead(self): 205 library.zenoss_read_ready(eventContext, self.fd) 206 207 def doWrite(self): 208 library.zenoss_write_ready(eventContext, self.fd) 209 210 def fileno(self): 211 return self.fd 212 213 def connectionLost(self, why): 214 wmiReactor.removeFileDescriptor(self.fd) 215 216# allow users to write: 217# from pysamba.twisted import reactor 218# instead of 219# from twisted.internet import reactor 220from twisted.internet import reactor 221 222def setNTLMv2Authentication(enabled = False): 223 """ 224 Enables or disables the NTLMv2 authentication feature. 225 @param enabled: True if NTLMv2 is supported 226 @type enabled: boolean 227 """ 228 flag = "no" 229 if enabled: 230 flag = "yes" 231 library.lp_do_parameter(-1, "client ntlmv2 auth", flag) 232 log.debug("client ntlmv2 auth is now %s", flag) 233