1 """Given a pair of pipes with a python process at each end, this module
2 allows one end to make calls on the other. This is used by the su module
3 to allow control of a subprocess running as another user, but it may also
4 be useful in other situations. The caller end should use the master_proxy
10 from __future__
import generators
11 # Note: do not import rox or gtk. Needs to work without DISPLAY.
13 from select
import select
14 import cPickle
as pickle
18 def __init__(self
, to_peer
, from_peer
, slave_object
= None):
19 if not hasattr(to_peer
, 'fileno'):
20 to_peer
= os
.fdopen(to_peer
, 'w')
21 if not hasattr(from_peer
, 'fileno'):
22 from_peer
= os
.fdopen(from_peer
, 'r')
23 self
.to_peer
= to_peer
24 self
.from_peer
= from_peer
28 self
.enable_read_watch()
30 def enable_read_watch(self
):
31 gobject
.io_add_watch(self
.from_peer
, gobject
.IO_IN
,
32 lambda src
, cond
: self
.read_ready())
34 def enable_write_watch(self
):
35 gobject
.io_add_watch(self
.to_peer
.fileno(), gobject
.IO_OUT
,
36 lambda src
, cond
: self
.write_ready())
38 def write_object(self
, object):
39 if self
.to_peer
is None:
40 raise Exception('Peer is defunct')
41 if not self
.out_buffer
:
42 self
.enable_write_watch()
44 s
= pickle
.dumps(object)
45 s
= str(len(s
)) + ":" + s
48 def write_ready(self
):
49 """Returns True if the buffer is not empty on exit."""
50 while self
.out_buffer
:
51 w
= select([], [self
.to_peer
], [], 0)[1]
53 print "Not ready for writing"
55 n
= os
.write(self
.to_peer
.fileno(), self
.out_buffer
)
56 self
.out_buffer
= self
.out_buffer
[n
:]
60 new
= os
.read(self
.from_peer
.fileno(), 1000)
63 self
.lost_connection()
66 while ':' in self
.in_buffer
:
67 l
, rest
= self
.in_buffer
.split(':', 1)
70 return True # Haven't got everything yet
72 self
.in_buffer
= rest
[l
:]
73 value
= pickle
.loads(s
)
78 self
.to_slave
= self
.from_slave
= None
80 def lost_connection(self
):
81 raise Exception("Lost connection to peer!")
83 class SlaveProxy(Proxy
):
84 """Methods invoked on MasterProxy.root will be invoked on
85 slave_object. The result is a master_proxy.RequestBlocker."""
86 def __init__(self
, to_master
, from_master
, slave_object
):
87 Proxy
.__init
__(self
, to_master
, from_master
)
88 self
.slave_object
= slave_object
90 def _dispatch(self
, value
):
91 serial
, method
, args
= value
93 result
= getattr(self
.slave_object
, method
)(*args
)
96 self
.write_object((serial
, result
))
98 def lost_connection(self
):