2006-12-03 01:27:18 +00:00
|
|
|
|
2007-05-22 21:01:40 +00:00
|
|
|
import os.path, re
|
|
|
|
|
2007-03-08 22:10:36 +00:00
|
|
|
from twisted.python import log
|
|
|
|
from twisted.application import service
|
|
|
|
from twisted.internet import defer
|
2006-12-03 01:27:18 +00:00
|
|
|
from foolscap import Tub
|
2007-05-21 20:42:51 +00:00
|
|
|
from allmydata.util import idlib, iputil, observer
|
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
|
2007-04-27 20:47:38 +00:00
|
|
|
# Just to get their versions:
|
|
|
|
import allmydata
|
|
|
|
import zfec
|
|
|
|
import foolscap
|
|
|
|
|
2007-05-22 21:01:40 +00:00
|
|
|
# group 1 will be addr (dotted quad string), group 3 if any will be portnum (string)
|
|
|
|
ADDR_RE=re.compile("^([1-9][0-9]*\.[1-9][0-9]*\.[1-9][0-9]*\.[1-9][0-9]*)(:([1-9][0-9]*))?$")
|
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
class Node(service.MultiService):
|
2007-04-30 16:57:52 +00:00
|
|
|
# this implements common functionality of both Client nodes, Introducer
|
|
|
|
# nodes, and Vdrive nodes
|
2006-12-03 01:27:18 +00:00
|
|
|
NODETYPE = "unknown NODETYPE"
|
|
|
|
PORTNUMFILE = None
|
|
|
|
CERTFILE = None
|
2007-05-22 21:01:40 +00:00
|
|
|
LOCAL_IP_FILE = "advertised_ip_addresses"
|
2006-12-05 23:40:48 +00:00
|
|
|
NODEIDFILE = "my_nodeid"
|
2006-12-03 01:27:18 +00:00
|
|
|
|
|
|
|
def __init__(self, basedir="."):
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
self.basedir = os.path.abspath(basedir)
|
2007-03-08 22:10:36 +00:00
|
|
|
self._tub_ready_observerlist = observer.OneShotObserverList()
|
2006-12-03 01:27:18 +00:00
|
|
|
assert self.CERTFILE, "Your node.Node subclass must provide CERTFILE"
|
|
|
|
certfile = os.path.join(self.basedir, self.CERTFILE)
|
2007-05-23 19:41:23 +00:00
|
|
|
self.tub = Tub(certFile=certfile)
|
2007-04-07 03:55:59 +00:00
|
|
|
self.tub.setOption("logLocalFailures", True)
|
|
|
|
self.tub.setOption("logRemoteFailures", True)
|
2006-12-03 01:27:18 +00:00
|
|
|
self.nodeid = idlib.a2b(self.tub.tubID)
|
2006-12-05 23:40:48 +00:00
|
|
|
f = open(os.path.join(self.basedir, self.NODEIDFILE), "w")
|
|
|
|
f.write(idlib.b2a(self.nodeid) + "\n")
|
|
|
|
f.close()
|
2006-12-03 03:27:50 +00:00
|
|
|
self.short_nodeid = self.tub.tubID[:4] # ready for printing
|
2006-12-03 01:27:18 +00:00
|
|
|
assert self.PORTNUMFILE, "Your node.Node subclass must provide PORTNUMFILE"
|
|
|
|
self._portnumfile = os.path.join(self.basedir, self.PORTNUMFILE)
|
2007-05-22 21:06:00 +00:00
|
|
|
try:
|
|
|
|
portnum = int(open(self._portnumfile, "rU").read())
|
|
|
|
except EnvironmentError, ValueError:
|
|
|
|
portnum = 0
|
2006-12-03 01:27:18 +00:00
|
|
|
self.tub.listenOn("tcp:%d" % portnum)
|
|
|
|
# we must wait until our service has started before we can find out
|
|
|
|
# our IP address and thus do tub.setLocation, and we can't register
|
|
|
|
# any services with the Tub until after that point
|
|
|
|
self.tub.setServiceParent(self)
|
|
|
|
|
|
|
|
AUTHKEYSFILEBASE = "authorized_keys."
|
|
|
|
for f in os.listdir(self.basedir):
|
|
|
|
if f.startswith(AUTHKEYSFILEBASE):
|
|
|
|
keyfile = os.path.join(self.basedir, f)
|
|
|
|
portnum = int(f[len(AUTHKEYSFILEBASE):])
|
|
|
|
from allmydata import manhole
|
|
|
|
m = manhole.AuthorizedKeysManhole(portnum, keyfile)
|
|
|
|
m.setServiceParent(self)
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("AuthorizedKeysManhole listening on %d" % portnum)
|
|
|
|
|
2007-04-27 20:47:38 +00:00
|
|
|
self.log("Node constructed. tahoe version: %s, foolscap version: %s, zfec version: %s" % (allmydata.__version__, foolscap.__version__, zfec.__version__,))
|
|
|
|
|
2007-03-08 22:10:36 +00:00
|
|
|
def startService(self):
|
|
|
|
"""Start the node. Returns a Deferred that fires (with self) when it
|
|
|
|
is ready to go.
|
|
|
|
|
|
|
|
Many callers don't pay attention to the return value from
|
|
|
|
startService, since they aren't going to do anything special when it
|
|
|
|
finishes. If they are (for example unit tests which need to wait for
|
|
|
|
the node to fully start up before it gets shut down), they can wait
|
|
|
|
for the Deferred I return to fire. In particular, you should wait for
|
|
|
|
my startService() Deferred to fire before you call my stopService()
|
|
|
|
method.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# note: this class can only be started and stopped once.
|
|
|
|
service.MultiService.startService(self)
|
|
|
|
d = defer.succeed(None)
|
2007-03-08 22:12:52 +00:00
|
|
|
d.addCallback(lambda res: iputil.get_local_addresses_async())
|
2007-03-08 22:10:36 +00:00
|
|
|
d.addCallback(self._setup_tub)
|
|
|
|
d.addCallback(lambda res: self.tub_ready())
|
|
|
|
def _ready(res):
|
|
|
|
self.log("%s running" % self.NODETYPE)
|
|
|
|
self._tub_ready_observerlist.fire(self)
|
|
|
|
return self
|
|
|
|
d.addCallback(_ready)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
"""Shut down the node. Returns a Deferred that fires (with None) when
|
|
|
|
it finally stops kicking."""
|
|
|
|
return self.stopService()
|
|
|
|
|
2006-12-03 03:27:50 +00:00
|
|
|
def log(self, msg):
|
|
|
|
log.msg(self.short_nodeid + ": " + msg)
|
2006-12-03 01:27:18 +00:00
|
|
|
|
2007-03-08 01:43:17 +00:00
|
|
|
def _setup_tub(self, local_addresses):
|
2006-12-03 02:37:31 +00:00
|
|
|
# we can't get a dynamically-assigned portnum until our Tub is
|
|
|
|
# running, which means after startService.
|
2006-12-03 01:27:18 +00:00
|
|
|
l = self.tub.getListeners()[0]
|
|
|
|
portnum = l.getPortnum()
|
2007-05-22 21:01:40 +00:00
|
|
|
# record which port we're listening on, so we can grab the same one next time
|
|
|
|
open(self._portnumfile, "w").write("%d\n" % portnum)
|
|
|
|
|
|
|
|
local_addresses = [ "%s:%d" % (addr, portnum,) for addr in local_addresses ]
|
|
|
|
|
|
|
|
addresses = []
|
|
|
|
try:
|
|
|
|
for addrline in open(os.path.join(self.basedir, self.LOCAL_IP_FILE), "rU"):
|
|
|
|
mo = ADDR_RE.search(addrline)
|
|
|
|
if mo:
|
|
|
|
(addr, dummy, aportnum,) = mo.groups()
|
|
|
|
if aportnum is None:
|
|
|
|
aportnum = portnum
|
|
|
|
addresses.append("%s:%d" % (addr, aportnum,))
|
|
|
|
except EnvironmentError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
addresses.extend(local_addresses)
|
|
|
|
|
|
|
|
location = ",".join(addresses)
|
2007-03-08 01:43:17 +00:00
|
|
|
self.log("Tub location set to %s" % location)
|
|
|
|
self.tub.setLocation(location)
|
2006-12-03 01:27:18 +00:00
|
|
|
return self.tub
|
|
|
|
|
2006-12-03 02:37:31 +00:00
|
|
|
def tub_ready(self):
|
|
|
|
# called when the Tub is available for registerReference
|
2006-12-03 01:27:18 +00:00
|
|
|
pass
|
|
|
|
|
2007-03-08 22:10:36 +00:00
|
|
|
def when_tub_ready(self):
|
|
|
|
return self._tub_ready_observerlist.when_fired()
|
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
def add_service(self, s):
|
|
|
|
s.setServiceParent(self)
|
|
|
|
return s
|
|
|
|
|