Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
736 olof 1
###########################################################
2
#
3
# Daemon configuration
4
#
5
###########################################################
6
import logging as log
7
import pickle
8
import hashlib
9
import os
10
import imp
11
import re
12
from ConfigParser import ConfigParser
13
import filters
14
import statespaces
749 olof 15
from CanPktHandlerBase import CanPktHandlerBase
16
from CanPktHandler1 import CanPktHandler1
736 olof 17
 
750 olof 18
from NodeIfSerial import NodeIfSerial
19
from NodeIfTCP import NodeIfTCP
20
from NodeIfUDP import NodeIfUDP
21
from NodeIfTCPTLS import NodeIfTCPTLS
22
from NodeIfCanStim import NodeIfCanStim
23
 
751 olof 24
from TCPServer1 import TCPServer1
25
from TCPTLSServer import TCPTLSServer
26
from CanCtldServer import CanCtldServer
27
 
736 olof 28
class DynamicModuleCfg:
29
    """Dynamic module manager"""
30
 
31
    modSubDir = None
32
    CHECKSUM_FILE = 'checksums'
33
    CHECKSUM_SECTION = 'SHA-1_CHECKSUMS'
34
 
35
    def __init__(self, modSubDir):
36
        self.modSubDir = modSubDir
37
        self.checkSumFile = modSubDir + '/' + self.CHECKSUM_FILE
738 olof 38
        if not os.path.exists(self.checkSumFile):
39
            self.__createCsumsFile()
736 olof 40
 
41
    def loadModule(self, className):
42
        pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
43
        log.debug('Reading from ' + pFileName)
44
        fp = open(pFileName, 'r')
45
        p = pickle.Unpickler(fp)
46
        loadedMod = p.load()
47
        fp.close()
48
        if not self.__verifyCheckSum(className, pFileName):
49
            print 'Invalid checksum'
50
            return None
51
        else:
52
            return loadedMod
53
 
54
 
55
    def loadModules(self, config = None):
56
        subDirFiles = os.listdir(os.getcwd() + '/' + self.modSubDir)
57
        p = re.compile('.p$', re.IGNORECASE)
58
        modFiles = [elem for elem in subDirFiles if p.search(elem) is not None]
59
        modNames = []
60
        for mfName in modFiles:
61
            modNames.append(mfName.split('.')[0])
62
        log.debug('Found modules: ' + str(modNames))
63
        myMods = {}
64
        for mName in modNames:
65
            classObj = self.loadModule(mName)
66
            if classObj is not None:
67
                myMods[mName] = classObj
68
        return myMods
69
 
70
 
71
    def saveModule(self, className, classObj):
72
        pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
73
        log.debug('Writing to ' + pFileName)
74
        fp = open(pFileName, 'w')
75
        p = pickle.Pickler(fp)
76
        p.dump(classObj)
77
        fp.close()
78
        self.__writeCheckSum(className, pFileName)
79
 
80
 
81
    def __doCheckSum(self, filename):
82
        f = open(filename, 'r')
83
        data = f.read()
84
        f.close()
85
        hasher = hashlib.sha1()
86
        hasher.update(data)
87
        digest = hasher.hexdigest()
88
        return digest
89
 
90
 
738 olof 91
    def __createCsumsFile(self):
92
         csumsfile = open(self.checkSumFile, 'w')
93
         csumsfile.write('[' + self.CHECKSUM_SECTION + ']\n')
94
         csumsfile.close()
95
 
96
 
736 olof 97
    def __writeCheckSum(self, entryname, filename):
98
        csumsfile = open(self.checkSumFile, 'r+')
99
        csumcfg = ConfigParser()
100
        csumcfg.readfp(csumsfile)
101
        digest = self.__doCheckSum(filename)
102
        csumcfg.set(self.CHECKSUM_SECTION, entryname, digest)
103
        csumsfile.seek(0)
104
        csumcfg.write(csumsfile)
105
 
106
 
107
    def __verifyCheckSum(self, entryname, filename):
108
        csumsfile = open(self.checkSumFile, 'r')
109
        csumcfg = ConfigParser()
110
        csumcfg.readfp(csumsfile)
111
        digest = csumcfg.get(self.CHECKSUM_SECTION, entryname)
112
        cur_digest = self.__doCheckSum(filename)
113
        log.debug('Old checksum ' + digest + '\nNew checksum: ' + cur_digest)
114
        if cur_digest == digest:
115
            return True
116
        return False
117
 
118
 
119
    def importModule(self, className, requiredAttributes):
120
        """Imports a given class from the module with the same name """
121
 
122
        codeFile = os.getcwd() + '/' + self.modSubDir + '/' + className + '.py'
123
        mod = imp.load_source(self.modSubDir + '.' + className, codeFile)
124
        newClass = eval('mod.' + className)()
125
 
126
        for ra in requiredAttributes:
127
            if not hasattr(newClass, ra):
128
                print className, ': missing required symbol \"' + ra + '\"'
129
                return None
130
 
131
        self.saveModule(className, newClass)
132
        return newClass
133
 
134
 
135
class FilterCfg:
136
    """Filter resource manager"""
137
 
138
    REQUIRED_ATTRIBUTES = ['ASSOCIATED_SPACES', 'DESCRIPTIVE_NAME',
139
                           'attach', 'detach', 'filter']
140
 
141
    dynamicModuleCfg = None
142
    FILTER_SUBDIR = 'filters'
143
    filterModules = {}
144
 
145
    def __init__(self):
146
        self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
147
 
148
    def loadFilter(self, name):
149
        newFilt = self.dynamicModuleCfg.loadModule(name)
150
        if newFilt is not None:
748 olof 151
            self.filterModules[name] = newFilt
736 olof 152
            return True
153
        else:
154
            return False
155
 
156
    def loadFilters(self, config = None):
157
        self.filterModules = self.dynamicModuleCfg.loadModules()
158
        for fM in self.filterModules:
159
            log.debug(fM)
160
 
161
    def __saveFilter(self, className, classObj):
162
        self.dynamicModuleCfg.saveModule(className, classObj)
163
 
164
    def saveFilters(self):
165
        for className in self.filterModules:
166
            self.__saveFilter(className, self.filterModules[className])
167
 
168
    def importFilter(self, className):
169
        """Imports a given filter definition """
170
        classObj = self.dynamicModuleCfg.importModule(className, self.REQUIRED_ATTRIBUTES)
171
        if classObj is not None:
172
            print 'Imported: ' + classObj.DESCRIPTIVE_NAME
173
            return True
174
        else:
175
            return False
176
 
177
 
178
class StateSpaceCfg:
179
    """State space resource manager"""
180
 
748 olof 181
    REQUIRED_ATTRIBUTES = ['DESCRIPTIVE_NAME', 'RELATED_SPACES'
736 olof 182
                           'load', 'reset', 'run', 'unload']
183
 
184
    dynamicModuleCfg = None
185
    FILTER_SUBDIR = 'statespaces'
186
    spaceModules = {}
187
 
188
    def __init__(self):
189
        self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
190
 
191
    def loadSpace(self, name):
192
        newSpace = self.dynamicModuleCfg.loadModule(name)
193
        if newSpace is not None:
748 olof 194
            self.spaceModules[name] = newFilt
736 olof 195
            return True
196
        else:
197
            return False
198
 
199
    def loadSpaces(self, config = None):
200
        self.spaceModules = self.dynamicModuleCfg.loadModules()
201
        for sM in self.spaceModules:
202
            log.debug(sM)
203
 
204
    def __saveSpace(self, className, classObj):
205
        self.dynamicModuleCfg.saveModule(className, classObj)
206
 
207
    def saveSpaces(self):
208
        for className in self.spaceModules:
209
            self.__saveSpace(className, self.spaceModules[className])
210
 
211
    def importSpace(self, name):
212
        """Imports a given state space definition file """
213
        classObj = self.dynamicModuleCfg.importModule(name, self.REQUIRED_ATTRIBUTES)
214
        if classObj is not None:
215
            print 'Imported: ' + classObj.DESCRIPTIVE_NAME
216
            return True
217
        else:
218
            return False
219
 
220
class DaemonConfig:
221
 
222
    stateSpaceCfg = None
223
    filterCfg = None
749 olof 224
    pktHandler = None
225
 
736 olof 226
    filterChain = []
749 olof 227
    nodeInterfaces = []
228
    nodeInterfaceMap = {}
736 olof 229
 
751 olof 230
    serverDaemons = []
231
 
750 olof 232
    INTERFACE_TYPES = {'serial' : NodeIfSerial, 'tcp' : NodeIfTCP,
233
                       'udp' : NodeIfUDP, 'sim' : NodeIfCanStim,
234
                       'tcptls' : NodeIfTCPTLS}
751 olof 235
 
236
    SERVER_TYPES = {'tcpd' : TCPServer1, 'tcptlsd' : TCPTLSServer,
237
                    'canctld' : CanCtldServer}
750 olof 238
 
736 olof 239
    def __init__ (self):
240
        self.filterCfg = FilterCfg()
241
        self.stateSpaceCfg = StateSpaceCfg()
750 olof 242
        self.pktHandler = CanPktHandler1(self)
736 olof 243
 
749 olof 244
    def load(self):
245
        self.stateSpaceCfg.loadSpaces()
750 olof 246
        self.filterCfg.loadFilters()
247
        self.__setupFilterBindings()
248
        self.__setupStateSpaceRelations()
249
        self.__setupFilterChain()
250
 
749 olof 251
    def save(self):
252
        self.stateSpaceCfg.saveSpaces()
253
        self.filterCfg.saveFilters()
254
 
750 olof 255
    def addInterface(self, type, cfg = None):
256
        """ addInterface
257
        type - a valid interface type name
258
        cfg - interface configuration
259
        returns: True on success, False otherwise """
260
 
261
        if not self.INTERFACE_TYPES.has_key(type):
262
            log.debug('addInterface called with invalid interface type')
263
            return False
264
 
752 olof 265
        if cfg is None:
266
            cfg = self.INTERFACE_TYPES[type].DEFAULT_CONFIG
267
 
750 olof 268
        nodeIf = self.INTERFACE_TYPES[type](self.pktHandler, cfg)
269
        self.nodeInterfaces.append(nodeIf)
751 olof 270
        return True
750 olof 271
 
272
    def remInterface(self, name):
273
        pass
751 olof 274
 
275
    def addServerDaemon(self, type, cfg = None):
750 olof 276
 
751 olof 277
        if not self.SERVER_TYPES.has_key(type):
278
            log.debug('addServerDaemon called with invalid daemon type')
279
            return False
280
 
752 olof 281
        if cfg is None:
282
            cfg = self.SERVER_TYPES[type].DEFAULT_CONFIG
283
 
284
        serverd = self.SERVER_TYPES[type](self.pktHandler, cfg) # actung!
285
        self.serverDaemons.append(serverd)
286
        return True
751 olof 287
 
288
    def remServerDaemon(self, name):
289
        pass
290
 
749 olof 291
    def __setupFilterChain(self):
736 olof 292
        self.filterChain = ['DefaultFilter']
293
 
749 olof 294
    def __setupFilterBindings(self):
736 olof 295
        for f in self.filterCfg.filterModules.values():
296
            assocSpaces = []
297
            for s in f.ASSOCIATED_SPACES:
298
                if self.stateSpaceCfg.spaceModules.has_key(s):
299
                    assocSpaces.append(self.stateSpaceCfg.spaceModules[s])
300
                else:
301
                    print 'WARNING: Reference to undefined state space: ' + s
302
            setattr(f, '__ASSOCIATED_SPACES__', assocSpaces)
748 olof 303
 
750 olof 304
    def __setupStateSpaceRelations(self):
748 olof 305
        for sm in self.stateSpaceCfg.spaceModules:
306
            relatedSpaceNames = self.stateSpaceCfg.spaceModules[sm].RELATED_SPACES
307
            relatedSpaces = {}
308
            for rsname in relatedSpaceNames:
309
                relatedSpaces[rsname] = self.stateSpaceCfg.spaceModules[rsname]
750 olof 310
            setattr(self.stateSpaceCfg.spaceModules[sm], '__RELATED_SPACES__', relatedSpaces)
311