Commit ae32fe2a authored by Avery Pennarun's avatar Avery Pennarun

Merge branch 'python23' - python 2.3 compatibility

* python23:
  Oops, missed another << operator to replace with _shl().
  socket.SHUT_RD and socket.SHUT_WR don't exist in python 2.3.
  compat/ssubprocess.py: some python versions don't have os.closerange().
  _nb_clean: don't catch EPIPE after all.
  Fix busy-waiting in two situations:
  Factor out common mainloop code between client and server.
  Implement our own left-shift operator to shut up python 2.3 warnings.
  Don't use set() since it's not in python 2.3.
  import and use subprocess.py from python 2.6.
  Remove list comprehensions for python 2.3 compatibility.
parents 518df410 5070f2ff
import struct, socket, select, subprocess, errno, re import struct, socket, select, errno, re
import compat.ssubprocess as ssubprocess
import helpers, ssnet, ssh import helpers, ssnet, ssh
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
from helpers import * from helpers import *
def original_dst(sock): def original_dst(sock):
try: try:
SO_ORIGINAL_DST = 80 SO_ORIGINAL_DST = 80
...@@ -45,7 +47,7 @@ class FirewallClient: ...@@ -45,7 +47,7 @@ class FirewallClient:
e = None e = None
for argv in argv_tries: for argv in argv_tries:
try: try:
self.p = subprocess.Popen(argv, stdout=s1, preexec_fn=setup) self.p = ssubprocess.Popen(argv, stdout=s1, preexec_fn=setup)
e = None e = None
break break
except OSError, e: except OSError, e:
...@@ -175,20 +177,7 @@ def _main(listener, fw, use_server, remotename, python, seed_hosts, auto_nets): ...@@ -175,20 +177,7 @@ def _main(listener, fw, use_server, remotename, python, seed_hosts, auto_nets):
if rv: if rv:
raise Fatal('server died with error code %d' % rv) raise Fatal('server died with error code %d' % rv)
r = set() ssnet.runonce(handlers, mux)
w = set()
x = set()
handlers = filter(lambda s: s.ok, handlers)
for s in handlers:
s.pre_select(r,w,x)
debug2('Waiting: %d[%d,%d,%d]...\n'
% (len(handlers), len(r), len(w), len(x)))
(r,w,x) = select.select(r,w,x)
#log('r=%r w=%r x=%r\n' % (r,w,x))
ready = set(r) | set(w) | set(x)
for s in handlers:
if s.socks & ready:
s.callback()
if use_server: if use_server:
mux.callback() mux.callback()
mux.check_fullness() mux.check_fullness()
......
This diff is collapsed.
import subprocess, re, errno import re, errno
import compat.ssubprocess as ssubprocess
import helpers import helpers
from helpers import * from helpers import *
def ipt_chain_exists(name): def ipt_chain_exists(name):
argv = ['iptables', '-t', 'nat', '-nL'] argv = ['iptables', '-t', 'nat', '-nL']
p = subprocess.Popen(argv, stdout = subprocess.PIPE) p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
for line in p.stdout: for line in p.stdout:
if line.startswith('Chain %s ' % name): if line.startswith('Chain %s ' % name):
return True return True
...@@ -17,7 +18,7 @@ def ipt_chain_exists(name): ...@@ -17,7 +18,7 @@ def ipt_chain_exists(name):
def ipt(*args): def ipt(*args):
argv = ['iptables', '-t', 'nat'] + list(args) argv = ['iptables', '-t', 'nat'] + list(args)
debug1('>> %s\n' % ' '.join(argv)) debug1('>> %s\n' % ' '.join(argv))
rv = subprocess.call(argv) rv = ssubprocess.call(argv)
if rv: if rv:
raise Fatal('%r returned %d' % (argv, rv)) raise Fatal('%r returned %d' % (argv, rv))
...@@ -64,7 +65,7 @@ def do_iptables(port, subnets): ...@@ -64,7 +65,7 @@ def do_iptables(port, subnets):
def ipfw_rule_exists(n): def ipfw_rule_exists(n):
argv = ['ipfw', 'list'] argv = ['ipfw', 'list']
p = subprocess.Popen(argv, stdout = subprocess.PIPE) p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
found = False found = False
for line in p.stdout: for line in p.stdout:
if line.startswith('%05d ' % n): if line.startswith('%05d ' % n):
...@@ -82,7 +83,7 @@ def ipfw_rule_exists(n): ...@@ -82,7 +83,7 @@ def ipfw_rule_exists(n):
def sysctl_get(name): def sysctl_get(name):
argv = ['sysctl', '-n', name] argv = ['sysctl', '-n', name]
p = subprocess.Popen(argv, stdout = subprocess.PIPE) p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
line = p.stdout.readline() line = p.stdout.readline()
rv = p.wait() rv = p.wait()
if rv: if rv:
...@@ -96,7 +97,7 @@ def sysctl_get(name): ...@@ -96,7 +97,7 @@ def sysctl_get(name):
def _sysctl_set(name, val): def _sysctl_set(name, val):
argv = ['sysctl', '-w', '%s=%s' % (name, val)] argv = ['sysctl', '-w', '%s=%s' % (name, val)]
debug1('>> %s\n' % ' '.join(argv)) debug1('>> %s\n' % ' '.join(argv))
rv = subprocess.call(argv, stdout = open('/dev/null', 'w')) rv = ssubprocess.call(argv, stdout = open('/dev/null', 'w'))
_oldctls = [] _oldctls = []
...@@ -110,7 +111,7 @@ def sysctl_set(name, val): ...@@ -110,7 +111,7 @@ def sysctl_set(name, val):
def ipfw(*args): def ipfw(*args):
argv = ['ipfw', '-q'] + list(args) argv = ['ipfw', '-q'] + list(args)
debug1('>> %s\n' % ' '.join(argv)) debug1('>> %s\n' % ' '.join(argv))
rv = subprocess.call(argv) rv = ssubprocess.call(argv)
if rv: if rv:
raise Fatal('%r returned %d' % (argv, rv)) raise Fatal('%r returned %d' % (argv, rv))
......
...@@ -28,3 +28,10 @@ def debug3(s): ...@@ -28,3 +28,10 @@ def debug3(s):
class Fatal(Exception): class Fatal(Exception):
pass pass
def list_contains_any(l, sub):
for i in sub:
if i in l:
return True
return False
import subprocess, time, socket, re, select, errno import time, socket, re, select, errno
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
import compat.ssubprocess as ssubprocess
import helpers import helpers
from helpers import * from helpers import *
...@@ -108,7 +109,7 @@ def _check_netstat(): ...@@ -108,7 +109,7 @@ def _check_netstat():
debug2(' > netstat\n') debug2(' > netstat\n')
argv = ['netstat', '-n'] argv = ['netstat', '-n']
try: try:
p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=null) p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
content = p.stdout.read() content = p.stdout.read()
p.wait() p.wait()
except OSError, e: except OSError, e:
...@@ -128,7 +129,7 @@ def _check_smb(hostname): ...@@ -128,7 +129,7 @@ def _check_smb(hostname):
argv = ['smbclient', '-U', '%', '-L', hostname] argv = ['smbclient', '-U', '%', '-L', hostname]
debug2(' > smb: %s\n' % hostname) debug2(' > smb: %s\n' % hostname)
try: try:
p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=null) p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
lines = p.stdout.readlines() lines = p.stdout.readlines()
p.wait() p.wait()
except OSError, e: except OSError, e:
...@@ -185,7 +186,7 @@ def _check_nmb(hostname, is_workgroup, is_master): ...@@ -185,7 +186,7 @@ def _check_nmb(hostname, is_workgroup, is_master):
argv = ['nmblookup'] + ['-M']*is_master + ['--', hostname] argv = ['nmblookup'] + ['-M']*is_master + ['--', hostname]
debug2(' > n%d%d: %s\n' % (is_workgroup, is_master, hostname)) debug2(' > n%d%d: %s\n' % (is_workgroup, is_master, hostname))
try: try:
p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=null) p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
lines = p.stdout.readlines() lines = p.stdout.readlines()
rv = p.wait() rv = p.wait()
except OSError, e: except OSError, e:
......
import re, struct, socket, select, subprocess, traceback import re, struct, socket, select, traceback
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
import ssnet, helpers, hostwatch import ssnet, helpers, hostwatch
import compat.ssubprocess as ssubprocess
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
from helpers import * from helpers import *
...@@ -36,14 +37,18 @@ def _maskbits(netmask): ...@@ -36,14 +37,18 @@ def _maskbits(netmask):
if not netmask: if not netmask:
return 32 return 32
for i in range(32): for i in range(32):
if netmask[0] & (1<<i): if netmask[0] & _shl(1, i):
return 32-i return 32-i
return 0 return 0
def _shl(n, bits):
return n * int(2**bits)
def _list_routes(): def _list_routes():
argv = ['netstat', '-rn'] argv = ['netstat', '-rn']
p = subprocess.Popen(argv, stdout=subprocess.PIPE) p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
routes = [] routes = []
for line in p.stdout: for line in p.stdout:
cols = re.split(r'\s+', line) cols = re.split(r'\s+', line)
...@@ -53,7 +58,7 @@ def _list_routes(): ...@@ -53,7 +58,7 @@ def _list_routes():
maskw = _ipmatch(cols[2]) # linux only maskw = _ipmatch(cols[2]) # linux only
mask = _maskbits(maskw) # returns 32 if maskw is null mask = _maskbits(maskw) # returns 32 if maskw is null
width = min(ipw[1], mask) width = min(ipw[1], mask)
ip = ipw[0] & (((1<<width)-1) << (32-width)) ip = ipw[0] & _shl(_shl(1, width) - 1, 32-width)
routes.append((socket.inet_ntoa(struct.pack('!I', ip)), width)) routes.append((socket.inet_ntoa(struct.pack('!I', ip)), width))
rv = p.wait() rv = p.wait()
if rv != 0: if rv != 0:
...@@ -122,8 +127,9 @@ def main(): ...@@ -122,8 +127,9 @@ def main():
socket.fromfd(sys.stdout.fileno(), socket.fromfd(sys.stdout.fileno(),
socket.AF_INET, socket.SOCK_STREAM)) socket.AF_INET, socket.SOCK_STREAM))
handlers.append(mux) handlers.append(mux)
routepkt = ''.join('%s,%d\n' % r routepkt = ''
for r in routes) for r in routes:
routepkt += '%s,%d\n' % r
mux.send(0, ssnet.CMD_ROUTES, routepkt) mux.send(0, ssnet.CMD_ROUTES, routepkt)
hw = Hostwatch() hw = Hostwatch()
...@@ -156,21 +162,6 @@ def main(): ...@@ -156,21 +162,6 @@ def main():
if rpid: if rpid:
raise Fatal('hostwatch exited unexpectedly: code 0x%04x\n' % rv) raise Fatal('hostwatch exited unexpectedly: code 0x%04x\n' % rv)
r = set() ssnet.runonce(handlers, mux)
w = set()
x = set()
handlers = filter(lambda s: s.ok, handlers)
for s in handlers:
s.pre_select(r,w,x)
debug2('Waiting: %d[%d,%d,%d] (fullness=%d/%d)...\n'
% (len(handlers), len(r), len(w), len(x),
mux.fullness, mux.too_full))
(r,w,x) = select.select(r,w,x)
#log('r=%r w=%r x=%r\n' % (r,w,x))
ready = set(r) | set(w) | set(x)
for s in handlers:
#debug2('check: %r: %r\n' % (s, s.socks & ready))
if s.socks & ready:
s.callback()
mux.check_fullness() mux.check_fullness()
mux.callback() mux.callback()
import sys, os, re, subprocess, socket, zlib import sys, os, re, socket, zlib
import compat.ssubprocess as ssubprocess
import helpers import helpers
from helpers import * from helpers import *
...@@ -14,9 +15,10 @@ def readfile(name): ...@@ -14,9 +15,10 @@ def readfile(name):
def empackage(z, filename): def empackage(z, filename):
(path,basename) = os.path.split(filename)
content = z.compress(readfile(filename)) content = z.compress(readfile(filename))
content += z.flush(zlib.Z_SYNC_FLUSH) content += z.flush(zlib.Z_SYNC_FLUSH)
return '%s\n%d\n%s' % (filename,len(content), content) return '%s\n%d\n%s' % (basename,len(content), content)
def connect(rhostport, python): def connect(rhostport, python):
...@@ -33,6 +35,7 @@ def connect(rhostport, python): ...@@ -33,6 +35,7 @@ def connect(rhostport, python):
z = zlib.compressobj(1) z = zlib.compressobj(1)
content = readfile('assembler.py') content = readfile('assembler.py')
content2 = (empackage(z, 'helpers.py') + content2 = (empackage(z, 'helpers.py') +
empackage(z, 'compat/ssubprocess.py') +
empackage(z, 'ssnet.py') + empackage(z, 'ssnet.py') +
empackage(z, 'hostwatch.py') + empackage(z, 'hostwatch.py') +
empackage(z, 'server.py') + empackage(z, 'server.py') +
...@@ -58,7 +61,7 @@ def connect(rhostport, python): ...@@ -58,7 +61,7 @@ def connect(rhostport, python):
s1a,s1b = os.dup(s1.fileno()), os.dup(s1.fileno()) s1a,s1b = os.dup(s1.fileno()), os.dup(s1.fileno())
s1.close() s1.close()
debug2('executing: %r\n' % argv) debug2('executing: %r\n' % argv)
p = subprocess.Popen(argv, stdin=s1a, stdout=s1b, preexec_fn=setup, p = ssubprocess.Popen(argv, stdin=s1a, stdout=s1b, preexec_fn=setup,
close_fds=True) close_fds=True)
os.close(s1a) os.close(s1a)
os.close(s1b) os.close(s1b)
......
...@@ -2,6 +2,12 @@ import struct, socket, errno, select ...@@ -2,6 +2,12 @@ import struct, socket, errno, select
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
from helpers import * from helpers import *
# these don't exist in the socket module in python 2.3!
SHUT_RD = 0
SHUT_WR = 1
SHUT_RDWR = 2
HDR_LEN = 8 HDR_LEN = 8
...@@ -31,13 +37,30 @@ cmd_to_name = { ...@@ -31,13 +37,30 @@ cmd_to_name = {
def _add(l, elem):
if not elem in l:
l.append(elem)
def _fds(l):
out = []
for i in l:
try:
out.append(i.fileno())
except AttributeError:
out.append(i)
out.sort()
return out
def _nb_clean(func, *args): def _nb_clean(func, *args):
try: try:
return func(*args) return func(*args)
except OSError, e: except OSError, e:
if e.errno not in (errno.EWOULDBLOCK, errno.EAGAIN, errno.EPIPE): if e.errno not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise raise
else: else:
debug3('%s: err was: %s\n' % (func.__name__, e))
return None return None
...@@ -69,21 +92,30 @@ class SockWrapper: ...@@ -69,21 +92,30 @@ class SockWrapper:
debug1('%r: error was: %r\n' % (self, self.exc)) debug1('%r: error was: %r\n' % (self, self.exc))
def __repr__(self): def __repr__(self):
return 'SW:%s' % (self.peername,) if self.rsock == self.wsock:
fds = '#%d' % self.rsock.fileno()
else:
fds = '#%d,%d' % (self.rsock.fileno(), self.wsock.fileno())
return 'SW%s:%s' % (fds, self.peername)
def seterr(self, e): def seterr(self, e):
if not self.exc: if not self.exc:
self.exc = e self.exc = e
def try_connect(self): def try_connect(self):
if self.connect_to and self.shut_write:
self.noread()
self.connect_to = None
if not self.connect_to: if not self.connect_to:
return # already connected return # already connected
self.rsock.setblocking(False) self.rsock.setblocking(False)
debug3('%r: trying connect to %r\n' % (self, self.connect_to))
try: try:
self.rsock.connect(self.connect_to) self.rsock.connect(self.connect_to)
# connected successfully (Linux) # connected successfully (Linux)
self.connect_to = None self.connect_to = None
except socket.error, e: except socket.error, e:
debug3('%r: connect result: %r\n' % (self, e))
if e.args[0] in [errno.EINPROGRESS, errno.EALREADY]: if e.args[0] in [errno.EINPROGRESS, errno.EALREADY]:
pass # not connected yet pass # not connected yet
elif e.args[0] == errno.EISCONN: elif e.args[0] == errno.EISCONN:
...@@ -102,14 +134,14 @@ class SockWrapper: ...@@ -102,14 +134,14 @@ class SockWrapper:
if not self.shut_read: if not self.shut_read:
debug2('%r: done reading\n' % self) debug2('%r: done reading\n' % self)
self.shut_read = True self.shut_read = True
#self.rsock.shutdown(socket.SHUT_RD) # doesn't do anything anyway #self.rsock.shutdown(SHUT_RD) # doesn't do anything anyway
def nowrite(self): def nowrite(self):
if not self.shut_write: if not self.shut_write:
debug2('%r: done writing\n' % self) debug2('%r: done writing\n' % self)
self.shut_write = True self.shut_write = True
try: try:
self.wsock.shutdown(socket.SHUT_WR) self.wsock.shutdown(SHUT_WR)
except socket.error, e: except socket.error, e:
self.seterr(e) self.seterr(e)
...@@ -159,7 +191,7 @@ class SockWrapper: ...@@ -159,7 +191,7 @@ class SockWrapper:
wrote = outwrap.write(self.buf[0]) wrote = outwrap.write(self.buf[0])
self.buf[0] = self.buf[0][wrote:] self.buf[0] = self.buf[0][wrote:]
while self.buf and not self.buf[0]: while self.buf and not self.buf[0]:
self.buf[0:1] = [] self.buf.pop(0)
if not self.buf and self.shut_read: if not self.buf and self.shut_read:
outwrap.nowrite() outwrap.nowrite()
...@@ -167,12 +199,13 @@ class SockWrapper: ...@@ -167,12 +199,13 @@ class SockWrapper:
class Handler: class Handler:
def __init__(self, socks = None, callback = None): def __init__(self, socks = None, callback = None):
self.ok = True self.ok = True
self.socks = set(socks or []) self.socks = socks or []
if callback: if callback:
self.callback = callback self.callback = callback
def pre_select(self, r, w, x): def pre_select(self, r, w, x):
r |= self.socks for i in self.socks:
_add(r, i)
def callback(self): def callback(self):
log('--no callback defined-- %r\n' % self) log('--no callback defined-- %r\n' % self)
...@@ -181,7 +214,7 @@ class Handler: ...@@ -181,7 +214,7 @@ class Handler:
v = s.recv(4096) v = s.recv(4096)
if not v: if not v:
log('--closed-- %r\n' % self) log('--closed-- %r\n' % self)
self.socks = set() self.socks = []
self.ok = False self.ok = False
...@@ -194,20 +227,20 @@ class Proxy(Handler): ...@@ -194,20 +227,20 @@ class Proxy(Handler):
def pre_select(self, r, w, x): def pre_select(self, r, w, x):
if self.wrap1.connect_to: if self.wrap1.connect_to:
w.add(self.wrap1.rsock) _add(w, self.wrap1.rsock)
elif self.wrap1.buf: elif self.wrap1.buf:
if not self.wrap2.too_full(): if not self.wrap2.too_full():
w.add(self.wrap2.wsock) _add(w, self.wrap2.wsock)
elif not self.wrap1.shut_read: elif not self.wrap1.shut_read:
r.add(self.wrap1.rsock) _add(r, self.wrap1.rsock)
if self.wrap2.connect_to: if self.wrap2.connect_to:
w.add(self.wrap2.rsock) _add(w, self.wrap2.rsock)
elif self.wrap2.buf: elif self.wrap2.buf:
if not self.wrap1.too_full(): if not self.wrap1.too_full():
w.add(self.wrap1.wsock) _add(w, self.wrap1.wsock)
elif not self.wrap2.shut_read: elif not self.wrap2.shut_read:
r.add(self.wrap2.rsock) _add(r, self.wrap2.rsock)
def callback(self): def callback(self):
self.wrap1.try_connect() self.wrap1.try_connect()
...@@ -216,6 +249,12 @@ class Proxy(Handler): ...@@ -216,6 +249,12 @@ class Proxy(Handler):
self.wrap2.fill() self.wrap2.fill()
self.wrap1.copy_to(self.wrap2) self.wrap1.copy_to(self.wrap2)
self.wrap2.copy_to(self.wrap1) self.wrap2.copy_to(self.wrap1)
if self.wrap1.buf and self.wrap2.shut_write:
self.wrap1.buf = []
self.wrap1.noread()
if self.wrap2.buf and self.wrap1.shut_write:
self.wrap2.buf = []
self.wrap2.noread()
if (self.wrap1.shut_read and self.wrap2.shut_read and if (self.wrap1.shut_read and self.wrap2.shut_read and
not self.wrap1.buf and not self.wrap2.buf): not self.wrap1.buf and not self.wrap2.buf):
self.ok = False self.ok = False
...@@ -247,7 +286,10 @@ class Mux(Handler): ...@@ -247,7 +286,10 @@ class Mux(Handler):
return self.chani return self.chani
def amount_queued(self): def amount_queued(self):
return sum(len(b) for b in self.outbuf) total = 0
for b in self.outbuf:
total += len(b)
return total
def check_fullness(self): def check_fullness(self):
if self.fullness > 32768: if self.fullness > 32768:
...@@ -346,9 +388,9 @@ class Mux(Handler): ...@@ -346,9 +388,9 @@ class Mux(Handler):
break break
def pre_select(self, r, w, x): def pre_select(self, r, w, x):
r.add(self.rsock) _add(r, self.rsock)
if self.outbuf: if self.outbuf:
w.add(self.wsock) _add(w, self.wsock)
def callback(self): def callback(self):
(r,w,x) = select.select([self.rsock], [self.wsock], [], 0) (r,w,x) = select.select([self.rsock], [self.wsock], [], 0)
...@@ -420,3 +462,28 @@ def connect_dst(ip, port): ...@@ -420,3 +462,28 @@ def connect_dst(ip, port):
return SockWrapper(outsock, outsock, return SockWrapper(outsock, outsock,
connect_to = (ip,port), connect_to = (ip,port),
peername = '%s:%d' % (ip,port)) peername = '%s:%d' % (ip,port))
def runonce(handlers, mux):
r = []
w = []
x = []
handlers = filter(lambda s: s.ok, handlers)
for s in handlers:
s.pre_select(r,w,x)
debug2('Waiting: %d r=%r w=%r x=%r (fullness=%d/%d)\n'
% (len(handlers), _fds(r), _fds(w), _fds(x),
mux.fullness, mux.too_full))
(r,w,x) = select.select(r,w,x)
debug2(' Ready: %d r=%r w=%r x=%r\n'
% (len(handlers), _fds(r), _fds(w), _fds(x)))
ready = r+w+x
did = {}
for h in handlers:
for s in h.socks:
if s in ready:
h.callback()
did[s] = 1
for s in ready:
if not s in did:
raise Fatal('socket %r was not used by any handler' % s)
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