gnuradionetwork/frn/protocol/manager.py

227 lines
7.4 KiB
Python
Raw Permalink Normal View History

2010-08-18 15:46:58 +00:00
# -*- coding: utf-8 -*-
#
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
# See LICENSE.txt for copyright info
from twisted.internet.defer import Deferred, succeed
from twisted.internet.protocol import ReconnectingClientFactory, ServerFactory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.protocols.policies import TimeoutMixin
2010-08-18 15:46:58 +00:00
from twisted.internet.task import LoopingCall
from twisted.python import log
from frn.user import FRNUser
from frn.protocol import versions
from frn.utility import *
class FRNManagerClient(LineOnlyReceiver):
PING_PERIOD = 3.0 # Seconds between ping requests
2010-08-18 15:46:58 +00:00
def connectionMade(self):
log.msg("Connected to manager [%s]" % self.transport.getPeer().host)
self.notifications = []
self.factory.managerConnected(self)
2010-08-18 15:46:58 +00:00
def connectionLost(self, reason):
log.msg("Manager disconnected")
try:
self.pingtimer.stop()
except: pass
for d in self.notifications:
d.errback(reason)
self.factory.managerDisconnected(self)
2010-08-18 15:46:58 +00:00
def notifyFinish(self):
self.notifications.append(Deferred())
return self.notifications[-1]
def finish(self, result):
d = self.notifications[0]
del self.notifications[0]
d.callback(result)
def lineReceived(self, line):
#log.msg("notifications: %s" % str(self.notifications))
2010-08-18 15:46:58 +00:00
if hasattr(self, 'serverlist'):
# TODO
pass
else:
self.finish(line.strip())
def sendServerLogin(self, user):
def loginDone(result):
self.managerdata = parseSimpleXML(result)
log.msg("Server login results: %s" % str(self.managerdata))
if int(self.managerdata['MC']) > 2009004:
2010-08-18 15:46:58 +00:00
self.sendLine(responseToChallange(
self.managerdata['KP']))
if self.managerdata['AL'] != '0':
self.transport.loseConnection()
else:
self.pingtimer = LoopingCall(self.sendPing)
self.pingtimer.start(self.PING_PERIOD, False)
self.factory.resetDelay()
2010-08-18 15:46:58 +00:00
return self.managerdata
log.msg("Sending server login")
user.VX = versions.server
self.sendLine("SC:"+user.asXML(
'VX','SN','PT','OW','PW'))
return self.notifyFinish().addCallback(loginDone)
def sendServerLogout(self, user):
self.transport.loseConnection()
return succeed(None)
def sendPing(self):
self.sendLine("P")
return self.notifyFinish()
def sendClientLogin(self, client):
self.sendLine("CC:"+client.asXML(
'EA','PW','ON','BC','NN','CT','NT','DS','IP'))
return self.notifyFinish()
def sendClientLogout(self, client):
self.sendLine("CD:"+client.asXML('ID'))
return self.notifyFinish()
def getClientList(self):
#self.sendLine('SM')
raise NotImplementedError # TODO
def sendRegisterUser(self, user):
self.sendLine("IG:"+user.asXML(
'ON','EA','BC','DS','NN','CT'))
return self.notifyFinish()
class FRNManagerClientFactory(ReconnectingClientFactory):
protocol = FRNManagerClient
def managerConnected(self, connection):
pass
def managerDisconnected(self, connection):
pass
2010-08-18 15:46:58 +00:00
class FRNManagerServer(LineOnlyReceiver, TimeoutMixin):
2010-08-18 15:46:58 +00:00
def connectionMade(self):
log.msg("Manager client connected from %s" % self.transport.getPeer().host)
self._phase = "CONNECTED"
self.serverInfo = None
2010-08-18 15:46:58 +00:00
self.kp = makeRandomChallange()
self.setTimeout(30.0)
2010-08-18 15:46:58 +00:00
def connectionLost(self, reason):
log.msg("Manager client disconnected from %s: %s" %
(self.transport.getPeer().host, reason))
if self.serverInfo:
self.manager.serverLogout(self.serverInfo)
self.serverInfo = None
self._phase = "DISCONNECTED"
2010-08-18 15:46:58 +00:00
def _authOnly(self):
if self._phase != "AUTHENTICATED":
log.msg("Unauthorized action!")
self.transport.loseConnection()
def lineReceived(self, line):
self.resetTimeout()
2010-08-18 15:46:58 +00:00
sline = line.strip()
if self._phase == "CHALLANGE":
if sline == responseToChallange(self.kp):
self._phase = "AUTHENTICATED"
self.serverInfo = self.tmpServerInfo
log.msg("Auth success: %s" % repr(self.serverInfo))
2010-08-18 15:46:58 +00:00
else:
self.transport.loseConnection()
else:
if sline == 'P': # Ping
self.sendLine('F')
elif sline == 'SM': # Client list
self.sendClientList()
else:
cmd, body = sline.split(':', 1)
xbody = parseSimpleXML(body)
handler = getattr(self, 'decode'+cmd, None)
if handler is None:
self.unimplemented(cmd, xbody)
else:
handler(xbody)
def sendClientList(self):
def gotClientList(cl):
self.sendLine(str(len(cl)))
for sn, sp in cl:
self.sendLine("%s - Port: %d" % (sn, sp))
self.sendLine(str(len(cl[(sn,sp)])))
for nt in cl[(sn,sp)]:
self.sendLine(nt)
self.sendLine(str(len(cl[(sn,sp)][nt])))
for u in cl[(sn,sp)][nt]:
self.sendLine(u.asXML('EA','ON','BC','DS','NN','CT'))
2010-08-18 15:46:58 +00:00
log.msg("SM")
return self.manager.getClientList().addCallback(gotClientList)
2010-08-18 15:46:58 +00:00
def unimplemented(self, cmd, body):
log.err("Unimplemented command %s: %s" % (cmd, str(body)))
def decodeSC(self, body): # Server login
def sendManagerInfo(res):
if versions.manager > 2009004:
self._phase = "CHALLANGE"
self.tmpServerInfo = FRNUser(**body)
2010-08-18 15:46:58 +00:00
else:
self._phase = "AUTHENTICATED"
self.serverInfo = FRNUser(**body)
log.msg("Auth success: %s" % repr(self.serverInfo))
2010-08-18 15:46:58 +00:00
self.sendLine(formatSimpleXML([
('SV', versions.server),
('CV', versions.client),
('MC', versions.manager),
('AL', res),
2010-08-18 15:46:58 +00:00
('KP', self.kp)
]))
log.msg("SC: %s" % str(body))
self.manager.serverLogin(FRNUser(**body)).addCallback(
sendManagerInfo) # TODO: second authentication phase
def decodeCC(self, body): # Client login
log.msg("CC: %s" % str(body))
self._authOnly()
self.manager.clientLogin(self.serverInfo, FRNUser(**body)).addCallback(
2010-08-18 15:46:58 +00:00
self.sendLine)
def decodeCD(self, body): # Client logout
log.msg("CD: %s" % str(body))
self._authOnly()
self.manager.clientLogout(self.serverInfo, FRNUser(**body)).addCallback(
2010-08-18 15:46:58 +00:00
self.sendLine)
def decodeIG(self, body): # Account creation
log.msg("IG: %s" % str(body))
self.manager.registerUser(FRNUser(**body)).addCallback(
self.sendLine)
class FRNManagerServerFactory(ServerFactory):
protocol = FRNManagerServer
def __init__(self, managerFactory):
self.managerFactory = managerFactory
def buildProtocol(self, addr):
p = ServerFactory.buildProtocol(self, addr)
p.manager = self.managerFactory()
return p
# vim: set et ai sw=4 ts=4 sts=4: