Files
i2p.itoopie/apps/sam/python/src/i2p/router.py
2004-08-02 14:47:44 +00:00

186 lines
5.5 KiB
Python

# -------------------------------------------------------------
# router.py: Router control module
# -------------------------------------------------------------
"""
Router control module
"""
import i2p
import i2p.socket
import i2p.eep
from i2p.pylib import socket as pysocket # Import Python socket
import os, sys
import os.path
import time
import threading
import urllib2
check_addrlist = [i2p.socket.samaddr, i2p.eep.eepaddr]
router_config = 'router.config' # Router config filename
# True if our Python program started the router
our_router = False
our_router_lock = threading.Lock()
def find(dir=None):
"""Find the absolute path to a locally installed I2P router.
An I2P installation is located by looking in the
the dir argument given to the function, then in the
environment I2P, then in PATH. It looks for startRouter.sh
or startRouter.bat. Raises ValueError if an I2P installation
could not be located.
"""
sep = os.pathsep # Path separator
L = []
if dir != None and dir != '': L += dir.split(sep)
if 'I2P' in os.environ: L += os.environ['I2P'].split(sep)
if 'PATH' in os.environ: L += os.environ['PATH'].split(sep)
for dirname in L:
filename = os.path.join(dirname, 'startRouter.bat')
if os.path.exists(filename):
return dirname
filename = os.path.join(dirname, 'startRouter.sh')
if os.path.exists(filename):
return dirname
raise ValueError('I2P installation not found')
def check(dir=None):
"""Checks whether a locally installed router is running. Does
nothing if successful, otherwise raises i2p.RouterError.
An I2P installation is located by using find(dir).
The router.config file is parsed for 'router.adminPort'.
This port is queried to determine whether the router is
running.
"""
config = _parse_config(os.path.join(find(dir), router_config))
port = config.get('router.adminPort', '')
try:
port = int(port)
except:
raise ValueError('router.adminPort missing or bad in ' +
router_config)
try:
s = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_STREAM)
s.connect(('127.0.0.1', port))
s.close()
except pysocket.error:
raise i2p.RouterError('could not contact 127.0.0.1:' + str(port))
def _run_program(filename):
"""Runs the given program in a new process and new terminal."""
if sys.platform[:3] == 'win':
os.startfile(filename)
global our_router
our_router = True
else:
# Linux possibilities:
# sh -c command
# xterm -e command
# bash -c command
# Try os.spawnl() with the above.
raise ValueError('unimplemented')
def start(dir=None, hidden=False):
"""Start a locally installed I2P router. Does nothing if
the router has already been started.
An I2P installation is located by using find(dir).
If hidden is True, do not show a terminal for the router.
"""
routerdir = find(dir)
router = os.path.join(routerdir, 'startRouter.bat')
try:
check(dir)
return # Already running
except:
pass # Not yet running
olddir = os.getcwd()
if hidden:
raise ValueError('unimplemented')
our_router_lock.acquire()
try:
os.chdir(routerdir)
try:
_run_program(router)
finally:
os.chdir(olddir)
finally:
our_router_lock.release()
# Ideas for hidden=True:
# Parse startRouter.bat, and run same command with javaw
# on Windows to hide command box.
# Perhaps use javaw (?) or javaws (j2sdk1.4.2/jre/javaws/javaws)
# Perhaps /path-to/program 2>/dev/null 1>/dev/null&
def _parse_config(filename):
"""Return a dict with (name, value) items for the given I2P configuration file."""
f = open(filename, 'r')
s = f.read()
f.close()
ans = {}
for line in s.split('\n'):
line = line.strip()
if '#' in line: line = line[:line.find('#')]
pair = line.split('=')
if len(pair) == 2:
ans[pair[0].strip()] = pair[1].strip()
return ans
def stop(dir=None, force=False):
"""Stop a locally installed I2P router, if it was started by
the current Python program. If force is True, stop the
router even if it was started by another process. Do nothing
if force is False and the router was started by another program.
The file 'router.config' is located using the same search
process used for find(dir). It is parsed for
'router.shutdownPassword' and 'router.adminPort'. The
router is shut down through the admin port.
Raises i2p.RouterError if the I2P router is running but cannot
be stopped. You must uncomment the
'router.shutdownPassword' line for this command to work.
"""
if force == False and our_router == False:
return
config = _parse_config(os.path.join(find(dir), router_config))
password = config.get('router.shutdownPassword', '')
if password == '':
raise ValueError('router.shutdownPassword not found in ' +
router_config)
admin_port = config.get('router.adminPort', '')
if admin_port == '':
raise ValueError('router.adminPort not found in ' + router_config)
try:
admin_port = int(admin_port)
except:
raise ValueError('invalid router.adminPort in ' + router_config)
try:
sock = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_STREAM)
sock.connect(('127.0.0.1', admin_port))
sock.send('GET /shutdown?password=' + password + ' HTTP/1.0\r\n\r\n')
time.sleep(0.01)
sock.close()
except:
raise i2p.RouterError('router shutdown failed')
# Assume shutdown succeeded (it will take 30 seconds).