Add base files for ikap protocol

parent abc27238
*.py[cod]
# C extensions
*.so
# Installer logs
pip-log.txt
*.log
conf/*.conf
ssl/*.key
logs/*
run/*
#!/bin/bash
###########################################################################
# Copyright (c) 2018- Franco (nextime) Lanza <franco@unixmedia.it>
#
# Penguidom System Controller Daemon "penguidomd"
#
# This file is part of penguidomd.
#
# penguidomd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
rm -f `find . -name '*.pyc'`
rm -f `find . -name '*~'`
rm -f log/*.log
rm -f run/*.pid
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Copyright (c) 2011-2014 Unixmedia S.r.l. <info@unixmedia.it>
; Copyright (c) 2011-2014 Franco (nextime) Lanza <franco@unixmedia.it>
;
; Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
;
; This file is part of domotikad.
;
; domotikad is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[general]
loglevel: info
timeserver: yes
timeinterval: 480
action_status_timer: 2
remove_old_status: 1800
autodetect: no
boards_syspwd: domotika
devices_admpwd: domotika
notify_expiretime: 604800
language: it
[geo]
latitude: 45.5967710 ; milan-> 45.4636889
longitude: 8.7547400 ; milan-> 9.1881408
elevation: 205.000000 ; milan-> 122.246513
location: Lonate Pozzolo,it
openweathermap_appid: 7c9892bf8419193b5ea234f5cf6ad87d
[ikapserver]
enable = yes
interface: 0.0.0.0
ethdev: eth0
port: 6654
notifyport: 6654
tcpenable: yes
tcpport: 6654
tcpinterface: 127.0.0.1
loglevel: error
timeupdates: 1
rollingupdates: yes
rollinnum: 5
timeoffline:15
timecheckoffline:5
[proxy]
loglevel: info
localproxypaths: phpmyadmin,domotika,admin,daemons,plugins
localproxyhosts: none
localproxypathsnologin: none
localproxyhostsnologin: none
localproxyport: 80
[protocol]
loglevel: info
timecheck: yes
tollerance: 10
netpwd:
[web]
enable: yes
enableusergui: yes
enablesqlgui: yes
enablemysqlgui: yes
enableajaxgui: yes
enablerestgui: yes
enablemediagui: yes
logintheme: theme_dmblack
interface: 0.0.0.0
sslport: 443
port: 81
defaultpath: /lowp/home
nologinpaths: resources/js
privkey: ssl/privkey.key
cacert: ssl/cacert.crt
loglevel: info
nologindefaultuser: guest
nologindefaultpass: guest
nologinips: none
cookie_aeskey: CHANGE_ME_PLEASE
[media]
loglevel: info
localtranscode: 15
local_only: yes
transcode: ffmpeg,vlc
transcode_h264: vlc
transcode_webm: ffmpeg
transcode_raw: ffmpeg
[upnp]
enable: yes
ethdev: eth0
loglevel: info
[database]
loglevel: info
dbtype: mysql
dbhost: localhost
dmdbname: domotika
dbuser: domotika
dbpass: dmdbpwdmsql
[smtp]
enable: yes
interface: 127.0.0.1
port: 27
loglevel: info
[asterisk]
loglevel: info
manager_enable: yes
manager_ip: 127.0.0.1
manager_port: 5038
manager_user: domotika
manager_pass: dmastpwd
fagi_enable: yes
fagi_timeout: 50
fagi_iface: 127.0.0.1
fagi_port: 4573
sip_localnet: 192.168.0.0/16
sip_externaddr:
sip_externhost:
[voiceui]
loglevel: debug
triggerword: domotica
stopword: basta cosi domotica grazie
stopcommand: silenzio domotica
useoutput: no
[dns]
ns1: 8.8.8.8
ns2: 8.8.9.9
host: q.unixmedia.net
ip: auto
[messenger]
app_secret:
verify_token:
page_token:
auth_host: https://[YOURHOST]/botauth/messenger/
auth_img: https://[YOURHOST]/img/logo_login.png
auth_title: Nexlab's domotika
#!/bin/bash
###########################################################################
# Copyright (c) 2011-2014 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2014 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
### BEGIN INIT INFO
# Provides: domotikad
# Required-Start: $syslog $remote_fs mysql
# Required-Stop: $syslog $remote_fs
# X-Interactive: yes
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start and stop Domotika
# Description: Domotika is an home automation system
### END INIT INFO
#if [ -f /usr/lib/bindhack.so ] ; then
# export LD_PRELOAD=/usr/lib/bindhack.so
# export BIND_SRC=192.168.181.1
#fi
cd /home/domotika
./domotikad $@
if [ x"$1" = x"stop" ] ; then
chk=$(pgrep "domotikad")
if [ x"$chk" != x"" ] ; then
kill -9 $chk >/dev/null 2>&1
fi
fi
exit 0
###########################################################################
# Copyright (c) 2018- Franco (nextime) Lanza <franco@unixmedia.it>
#
# Penguidom System Controller Daemon "penguidomd"
#
# This file is part of penguidomd.
#
# penguidomd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from twisted.internet.protocol import DatagramProtocol, ServerFactory
from twisted.protocols.basic import Int8StringReceiver
import time
from twisted.internet import reactor
import sys
from socket import SOL_SOCKET, SO_BROADCAST, AF_INET, SOCK_DGRAM, socket
import IN
import struct
from nexlibs.nexcrypt import AES256
from nexlibs import nexcrypt as dmcrypt
import logging
from dmlib import constants as C
from dmlib import ikaprotocol as proto
from nexlibs.utils.genutils import revlist, isTrue
import copy
from nexlibs.utils import pwgen
from singleton import Singleton
log = logging.getLogger( 'IKAP' )
if not 'SO_BINDTODEVICE' in dir(IN):
IN.SO_BINDTODEVICE = 25
class TCPClientRegistry(Singleton):
clients={}
def __init__(self, *args, **kwargs):
Singleton.__init__( self )
def add_client(self, key, client, port):
if key in self.clients.keys():
self.clients[key].append({'port': port, 'session': client, 'ip': key})
else:
self.clients[key]=[{'port': port, 'session': client, 'ip': key}]
def del_client(self, key, port):
if key in self.clients.keys():
for c in self.clients[key]:
if c['port']==port:
self.clients[key].remove(c)
if len(self.clients[key])==0:
del self.clients[key]
def get_clients(self, key=False):
if key and key in self.clients.keys():
return self.clients[key]
elif not key:
return [c for b in self.clients.values() for c in b]
return []
TCPCLIENTREG=TCPClientRegistry.getInstance()
class DomIkaBaseProtocol(object):
debugmode = False
lastsettime=0
def __init__(self, core, *args, **kwargs):
self.core = core
self.initializated = False
def retriveMemKey(self):
if len(self.core.configGet('protocol', 'netpwd'))>4:
memkey=dmcrypt.DMHash256(self.core.configGet('protocol', 'netpwd'))
log.info("Protocol password is configured")
else:
log.info("Protocol password is DEFAULT")
memkey=copy.deepcopy(proto.DEFKEY)
return memkey
def checkTimeLimits(self, epoch):
# check if we are out of time limits
now=int(time.time())
if isTrue(self.core.configGet('protocol','timecheck')):
tollerance=int(self.core.configGet('protocol','tollerance'))
if(int(epoch)<now-tollerance or int(epoch)>now+tollerance):
return False
return True
def initializeProtocol(self):
self.memiv=copy.deepcopy(proto.DEFIV)
self.memkey=self.retriveMemKey()
if(self.memkey!=proto.DEFKEY):
self.memiv=pwgen.generateIV128(self.memkey)
self.aes=AES256(struct.unpack('<8L', self.memkey), struct.unpack('<4L', self.memiv))
self.aesdata=AES256(struct.unpack('<8L', self.memkey), struct.unpack('<4L', self.memiv))
self.debugmode=False
if self.core.configGet('protocol','loglevel').lower()=='debug':
self.debugmode=True
self.ikahdr=proto.IkaPacketHeader()
def invalidPacket(self):
pass
def createIkapPacket(self, command, ctx=False, act=False, arg=False, msgtype=False, src="Q.SERVER"):
p=proto.IkaPacket(memkey=self.memkey, memiv=self.memiv)
p.setSrc(src)
p.setDst(str(command))
if(ctx):
p.setCtx(ctx)
if(act):
p.setAct(act)
if(arg):
try:
if type(arg).__name__=='dict':
if 'ip' in arg.keys():
arg=proto.dictToIkapArg(arg)
else:
arg=proto.dictToIkapArg(arg, "0.0.0.0")
except:
import traceback
traceback.print_exc(file=sys.stdout)
pass
p.setArg(arg)
else:
p.setArg(C.IKAP_BROADCAST)
if(msgtype):
p.setMsgType(msgtype)
return p
def ikapPacketReceived(self, data, (host, port), ptype='UDP4'):
#log.info( "%r -> %s:%d, aes received %r" % (time.time(), host, port, data))
log.info("%r -> %s:%d, received packet" % (time.time(), host, port))
log.debug("raw data: %r" % data)
#print struct.unpack('B', data[0])
now=int(time.time())
#NEXTIME
if(struct.unpack('B', data[0])[0]==C.IKAP_STARTBYTE):
self.aes.setEncryptData(data[1:33])
try:
self.ikahdr.formatHeader(self.aes.cleandata)
log.debug( 'HEADER %s' % self.ikahdr)
log.debug( 'CHECKSUM %s' % hex(self.ikahdr.chksum))
log.debug('CALCULATED CHECKSUM: %s' % hex(self.ikahdr.calculateCheckSum()))
log.debug('HEADER TIME: %d' % int(self.ikahdr.epoch))
totlen=self.ikahdr.srclen+self.ikahdr.dstlen+self.ikahdr.arglen
datalendiff=len(data[33:])-totlen
offset=0
self.aesdata.key=struct.unpack('<8L', self.memkey)
self.aesdata.iv=self.ikahdr.key
self.aesdata.setEncryptData(data[33:])
if(self.ikahdr.srclen>0):
log.info('SRC: %s' % self.aesdata.cleandata[offset:self.ikahdr.srclen])
offset=self.ikahdr.srclen
dstend=offset+self.ikahdr.dstlen
src=""
if(self.ikahdr.srclen>0):
src=self.aesdata.cleandata[:self.ikahdr.srclen].rstrip()
dst=""
if(self.ikahdr.dstlen>0):
dst=self.aesdata.cleandata[offset:dstend]
log.info('DST: %s' % dst)
if src=='Q.RELAYPROTO':
return
offset=dstend
argend=offset+self.ikahdr.arglen
epoch=struct.unpack('<L', self.aesdata.cleandata[argend:argend+4])[0]
except:
log.error("INVALID PACKET RECEIVED (CRYPTO) FROM "+str(host))
return
log.debug("EPOCH: %s" %str(epoch))
if(epoch!=self.ikahdr.epoch):
log.error("INVALID PACKET RECEIVED (CRYPTO) FROM "+str(host)+" (epoch doesn't match!)")
return
arg=False
if(self.ikahdr.arglen>0):
arg=self.aesdata.cleandata[offset:argend]
if self.ikahdr.msgtype==C.IKAP_MSG_DEBUG:
if dst.startswith("DEBUG.INPUT.CHANGED.TO") or dst.startswith("DEBUG.RELAY.CHANGED.TO"):
arg=struct.unpack('B', arg[0])[0]
elif self.ikahdr.msgtype==C.IKAP_MSG_NOTIFY and dst.startswith("BOOTED."):
self.core.broadcastTime(host)
#self.sendCommand("SETTIME", arg=struct.pack("<L", int(time.time())), act=C.IKAP_ACT_BOARD, ctx=C.IKAP_CTX_SYSTEM, msgtype=C.IKAP_MSG_ACTION, ipdst=host)
elif self.ikahdr.msgtype==C.IKAP_MSG_NOTIFY and self.ikahdr.ctx==C.IKAP_CTX_SYSTEM and dst=='RELAY.AMPERE.LIMIT':
try:
log.info("Relay "+str(struct.unpack("<B", arg[1])[0])+" has gone in overrun at "+str(float(struct.unpack("<B", arg[0])[0])/10.0)+" Ampere")
except:
pass
elif self.ikahdr.ctx==C.IKAP_CTX_SYSTEM and self.ikahdr.msgtype==C.IKAP_MSG_NOTIFYCONF:
if dst.startswith("NETWORK."):
astr=struct.unpack('<26B', arg[:26])
webport=80
if len(arg)>26:
webport=struct.unpack('<H', arg[26:28])[0]
self.core.updateWebPort(src, host, webport, port, ptype)
arg="\n\tIP: "+".".join([str(x) for x in astr[0:4]])
arg+="\n\tNETMASK: "+".".join([str(x) for x in astr[4:8]])
arg+="\n\tGW: "+".".join([str(x) for x in astr[8:12]])
arg+="\n\tDNS1: "+".".join([str(x) for x in astr[12:16]])
arg+="\n\tDNS2: "+".".join([str(x) for x in astr[16:20]])
arg+="\n\tMAC: "+":".join([hex(x)[2:].zfill(2) for x in astr[20:26]])
arg+="\n\tWEBPORT: "+str(webport)
elif dst.startswith("IOSTATUS.DEF"):
astr=struct.unpack('<'+str(len(arg))+'B', arg)
elif dst.startswith("IOSTATUS.NOW") and self.checkTimeLimits(self.ikahdr.epoch):
def manageIOSTATUS(self, arg):
astr=struct.unpack('<'+str(len(arg))+'B', arg)
baseboard_type=struct.unpack('<H', arg[2:4])[0]
msg_fwtype=struct.unpack('<B', arg[0])[0]
try:
log.debug('ARG: %s' % str(arg))
log.debug('RAWARG: %r' % self.aesdata.cleandata[offset:argend])
except:
log.debug('CANNOT WRITE ARGS')
try:
log.info('ARGDICT: '+str(proto.ikapArgtoDict(self.aesdata.cleandata[offset:argend])))
except:
log.info("NO ARGDICT IS FEASIBLE")
argdict=proto.getDefaultDict()
argdict['ip']=host
argdict['raw']=arg
try:
#if self.ikahdr.msgtype==C.IKAP_MSG_ACTION:
if self.ikahdr.ctx!=C.IKAP_CTX_SYSTEM:
argdict=proto.ikapArgtoDict(self.aesdata.cleandata[offset:argend])
except:
pass
offset=argend
end=offset+4
checkdate=struct.unpack("<L", self.aesdata.cleandata[offset:end])[0]
log.debug('CHECKDATE: %s' % str(checkdate))
# XXX CONTROLLARE!
packet_isvalid=True
#if self.ikahdr.msgtype!=C.IKAP_MSG_ACTION:
# argdict=False
if packet_isvalid:
if self.checkTimeLimits(self.ikahdr.epoch):
self.core.manageIncomingPacket(self.ikahdr, src, dst, arg, host, port, ptype, argdict, data)
else:
log.error("INVALID PACKET TIME FROM "+str(host)+" - packet time: "+str(self.ikahdr.epoch)+" now: "+str(time.time()))
now=int(time.time())
if now-self.lastsettime>10:
self.core.broadcastTime()
else:
self.core.broadcastTime(host)
self.invalidPacket()
else:
log.error("INVALID PACKET (second check) FROM "+str(host))
self.invalidPacket()
else:
log.error("INVALID PACKET (start) FROM "+str(host))
self.invalidPacket()
log.debug('-----------------------------')
class DomIkaUDP(DatagramProtocol, DomIkaBaseProtocol):
def retrivePort(self, msgtype):
if msgtype in [C.IKAP_BROADCAST, C.IKAP_MSG_REQUEST, C.IKAP_MSG_REQUESTCONF,
C.IKAP_MSG_SETCONF, C.IKAP_MSG_ACK]:
return int(self.core.configGet('ikapserver', 'port'))
return int(self.core.configGet('ikapserver', 'notifyport'))
def startProtocol(self):
self.initializeProtocol()
self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
try:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE,
self.core.configGet('ikapserver', 'ethdev'))
except:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE, "eth0")
def sendRawData(self, data, msgtype, ipdst='255.255.255.255'):
if not self.initializated:
self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
try:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE,
self.core.configGet('ikapserver', 'ethdev'))
except:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE, "eth0")
self.initializated = True
self.transport.write(data, (ipdst, self.retrivePort(msgtype)))
def sendCommand(self, command, ctx=False, act=False, arg=False, msgtype=False,
src="Q.SERVER", ipdst="255.255.255.255" ):
if not self.initializated:
self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
try:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE,
self.core.configGet('ikapserver', 'ethdev'))
except:
self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE, "eth0")
self.initializated = True
p=self.createIkapPacket(command, ctx, act, arg, msgtype, src)
self.sendRawData(p.toSend(), msgtype, ipdst)
log.debug('SEND UDP PACKET: %r' % p.cleanpacket())
def datagramReceived(self, data, (host, port)):
return self.ikapPacketReceived(data, (host, int(self.core.configGet('ikapserver', 'port'))), 'UDP4')
class DomIkaTCP(Int8StringReceiver, DomIkaBaseProtocol):
disconnected=True
def sendRawData(self, data, *a, **kw ):
self.sendString(data)
def sendCommand(self, command, ctx=False, act=False, arg=False, msgtype=False,
src="Q.SERVER", ipdst="255.255.255.255" ):
p=self.createIkapPacket(command, ctx, act, arg, msgtype, src)
self.sendRawData(p.toSend())
log.debug('SEND TCP PACKET: %r' % p.cleanpacket())
def stringReceived(self, data):
addr = self.transport.getPeer()
host, port = addr.host, addr.port
return self.ikapPacketReceived(data, (host, port), 'TCP4')
def connectionLost(self, *a):
self.disconnected=True
addr = self.transport.getPeer()
host, port = addr.host, addr.port
TCPCLIENTREG.del_client(host, port)
def connectionMade(self):
#self.transport.setTcpNoDelay()
#self.transport.setTcpKeepAlive()
self.disconnected=False
self.sendCommand("IOSTATUS.NOW", arg=C.IKAP_BROADCAST, act=C.IKAP_ACT_BOARD,
ctx=C.IKAP_CTX_SYSTEM, msgtype=C.IKAP_MSG_REQUESTCONF)
self.sendCommand("SETTIME", arg=struct.pack("<L", int(time.time())), act=C.IKAP_ACT_BOARD, ctx=C.IKAP_CTX_SYSTEM, msgtype=C.IKAP_MSG_ACTION)
#self.core.broadcastTime()
def invalidPacket(self):
try:
self.transport.write("GO AWAY!")
except:
pass
reactor.callLater(0.2, self.transport.abortConnection)
class DomIkaServerFactory(ServerFactory):
protocol=DomIkaTCP
def __init__(self, core, *a, **kw):
self.core = core
def buildProtocol(self, addr):
p = self.protocol(self.core)
p.factory = self
TCPCLIENTREG.add_client(addr.host, p, addr.port)
return p
def sendRawData(self, data, msgtype, ipdst='255.255.255.255'):
if ipdst in ['255.255.255.255','0.0.0.0']:
cs=TCPCLIENTREG.get_clients()
else:
cs=TCPCLIENTREG.get_clients(str(ipdst))
for c in cs:
try:
c['session'].sendRawData(data, msgtype, ipdst)
except:
TCPCLIENTREG.del_client(cs['ip'], cs['port'])
def sendCommand(self, command, ctx=False, act=False, arg=False, msgtype=False,
src="Q.SERVER", ipdst="255.255.255.255" ):
if ipdst in ['255.255.255.255','0.0.0.0']:
cs=TCPCLIENTREG.get_clients()
else:
cs=TCPCLIENTREG.get_clients(str(ipdst))
for c in cs:
try:
c['session'].sendCommand(command,ctx,act,arg,msgtype,src)
except:
TCPCLIENTREG.del_client(cs['ip'], cs['port'])
if __name__ == '__main__':
from twisted.internet import reactor
reactor.listenUDP(6654, DomIkaUDP(), self.core.configGet('ikapserver', 'interface'))
reactor.run()
###########################################################################
# Copyright (c) 2018- Franco (nextime) Lanza <franco@unixmedia.it>
#
# Penguidom System Controller Daemon "penguidomd"
#
# This file is part of penguidomd.
#
# penguidomd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from twisted.application import service
from twisted.internet import defer, reactor, task, protocol, threads
from nexlibs.utils.genutils import configFile, FakeObject, ConvenienceCaller
from nexlibs.utils import genutils
import logging, sys, os
import subprocess
import time, copy
from twisted.web import microdom as xml
from nexlibs.utils import webutils as wu
from dmlib import constants as C
import time
from txscheduling import task as txcron
from txscheduling.cron import CronSchedule, parseCronLine
from txscheduling.interfaces import ISchedule
from netifaces import interfaces, ifaddresses, AF_INET
import struct
from dmlib import dmdomain
from singleton import Singleton
import ikap
try:
import hashlib
md5 = hashlib
md5.new = hashlib.md5
sha1 = hashlib.sha1
except:
import md5
import sha1
ALLIP=C.IKAP_BROADCAST
ACTION_STATUS={}
log = logging.getLogger( 'Core' )
class penguidomService(service.Service):
initialized=False
udp=False
tcp=False
def __init__(self, *args, **kwargs):
log.info('Initializing Core')
self.curdir=kwargs['curdir']
self.config=kwargs['config']
sys.path.append(self.curdir+"/penguidom")
log.debug('Current dir: '+self.curdir)
if self.parent:
self.parent.__new__(self.parent, self, *args)
def _callback(self, who, cmd, *args, **kwargs):
"""
The callback that try to find an appropriate method exported
to a higher level object by the ConvenienceCaller metaclass.
This isn't intended to be called by the user directly, instead pass it
to the instance of the higher level object initialization or by
setting it using the abstraction of the ConvenienceCaller metaclass
"""
try:
f=getattr(self, who+'_on_'+cmd)
if f and callable(f):
return f
except:
raise AttributeError(" ".join([cmd, 'doesn\'t exists']))
def isStarted(self):
log.debug("isStarted() called")
self.isConfigured()
def isConfigured(self):
self.initialized=True
log.debug("isConfigured() called")
def getIkapUDP(self):
caller = ConvenienceCaller(lambda c: self._callback('ikap', c))
self.udp = ikap.DomIkaUDP(caller)
return self.udp
def getIkapTCP(self):
caller = ConvenienceCaller(lambda c: self._callback('ikap', c))
self.tcp = ikap.DomIkaServerFactory(caller)
return self.tcp
###########################################################################
# Copyright (c) 2018- Franco (nextime) Lanza <franco@unixmedia.it>
#
# Penguidom System Controller Daemon "penguidomd"
#
# This file is part of penguidomd.
#
# penguidomd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from nexlibs.singleton import *
#!/usr/bin/env python
###########################################################################
# Copyright (c) 2018- Franco (nextime) Lanza <franco@unixmedia.it>
#
# Penguidom System Controller Daemon "penguidomd"
#
# This file is part of penguidomd.
#
# penguidomd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from twisted.internet import epollreactor
epollreactor.install()
from twisted.internet import reactor, ssl, protocol, endpoints
from twisted.application import service, internet, app, reactors
from twisted.web import server
import logging, time, sys, os
from nexlibs.daemonizer import Daemonizer
from penguidom import penguidom
from nexlibs.utils.genutils import configFile
from logging import handlers as loghandlers
try:
import setproctitle
setproctitle.setproctitle('penguidomd')
print 'Setting process title to', sys.argv[0]
except:
pass
loglevels = {
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL,
'debug': logging.DEBUG
}
#LOGLEN=104857600 # 100 mega
#LOGLEN=10485760 # 10 mega
LOGLEN=26214400 # 25 mega
class penguidomDaemon(Daemonizer):
def __init__(self):
self.curdir = os.path.abspath(os.path.dirname(sys.argv[0]))
log.debug("Reading daemon Config file")
self.daemoncfg = configFile(self.curdir+'/conf/penguidomd.conf')
self.daemoncfg.readConfig()
log.debug("Daemonizing process")
Daemonizer.__init__(self, self.curdir+'/run/penguidom.pid')
def main_loop(self):
log.debug("Main loop called")
application = service.Application("penguidomd")
PENGUIDOMServerService = penguidom.penguidomService('penguidomd', curdir=self.curdir, config=self.daemoncfg)
serviceCollection = service.IServiceCollection(application)
PENGUIDOMServerService.setServiceParent(serviceCollection)
IkapServerUDP = PENGUIDOMServerService.getIkapUDP()
IkapServerTCP = PENGUIDOMServerService.getIkapTCP()
if str(self.daemoncfg.get('ikap', 'enable')).lower() in ['yes', '1', 'y','true']:
reactor.listenUDP(int(self.daemoncfg.get('ikap', 'port')), IkapServerUDP,
interface=str(self.daemoncfg.get('ikap', 'interface')))
if self.daemoncfg.get('ikap', 'port') != self.daemoncfg.get('ikap', 'notifyport'):
reactor.listenUDP(int(self.daemoncfg.get('ikap', 'notifyport')), IkapServerUDP,
interface=str(self.daemoncfg.get('ikap', 'interface')))
if str(self.daemoncfg.get('ikap', 'tcpenable')).lower() in ['yes', '1', 'y','true']:
reactor.listenTCP(int(self.daemoncfg.get('ikap', 'tcpport')), IkapServerTCP,
interface=str(self.daemoncfg.get('ikap', 'tcpinterface')))
log.debug("Running reactor")
reactor.callWhenRunning(PENGUIDOMServerService.isStarted)
reactor.run()
if __name__ == "__main__":
# Starting all loggers
# file di log da 100 mega, per 5 rotazioni
formatter = logging.Formatter('%(asctime)s => %(name)-12s: %(levelname)-8s %(message)s')
logdict={"corelog":
{"file":"penguidom.log","name":[("Core","general")]},
"protocollog":
{"file":"ikap.log","name":
[("IKAProtocol","ikap"),("IKAPServer","ikap"),("DMDomain","ikap")]},
}
for l in logdict.keys():
logdict[l]["handler"] = loghandlers.RotatingFileHandler(
os.path.abspath(os.path.dirname(sys.argv[0]))+'/logs/'+logdict[l]["file"], 'a', LOGLEN, 5)
logdict[l]["handler"].setLevel(logging.DEBUG)
logdict[l]["handler"].setFormatter(formatter)
logging.basicConfig()
log = logging.getLogger( 'DaemonStarter' )
log.addHandler(logdict["corelog"]["handler"])
log.setLevel( logging.INFO )
curdir = os.path.abspath(os.path.dirname(sys.argv[0]))
daemoncfg = configFile(curdir+'/conf/penguidomd.conf')
daemoncfg.readConfig()
for l in logdict.keys():
for n in logdict[l]["name"]:
lh = logging.getLogger(n[0])
lh.setLevel( loglevels[daemoncfg.get(n[1], 'loglevel')] )
lh.addHandler( logdict[l]["handler"] )
logging.basicConfig()
# staring the application
if len(sys.argv) > 1:
log.debug("Starting daemon with option "+sys.argv[1])
penguidomDaemon().process_command_line(sys.argv)
else:
print 'Please specify start, stop or debug option'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment