2 # -*- coding: utf-8 -*-
13 CTRL_SOCK = "ctrl.sock"
14 STD_ERR = "stderr.log"
20 def __init__(self, root_dir = "."):
21 self._root_dir = root_dir
23 self._ctrl_sock = None
31 # can not return normally after fork beacuse no exec was done.
32 # This means that if we don't do a os._exit(0) here the code that
33 # follows the call to "Server.run()" in the "caller code" will be
34 # executed... but by now it has already been executed after the
35 # first process (the one that did the first fork) returned.
41 # we do os.waitpid to avoid leaving a <defunc> (zombie) process
43 # return 0 to inform the caller method that this is not the
47 # Decouple from parent environment.
48 os.chdir(self._root_dir)
55 # see ref: "os._exit(0)"
58 # close all open file descriptors.
59 for fd in range(2, MAX_FD):
65 # Redirect standard file descriptors.
66 self._stderr = stdout = file(STD_ERR, "a", 0)
67 stdin = open('/dev/null', 'r')
68 os.dup2(stdin.fileno(), sys.stdin.fileno())
69 os.dup2(stdout.fileno(), sys.stdout.fileno())
70 os.dup2(self._stderr.fileno(), sys.stderr.fileno())
74 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
75 self._ctrl_sock.bind(CTRL_SOCK)
76 self._ctrl_sock.listen(0)
78 conn, addr = self._ctrl_sock.accept()
82 msg = self.recv_msg(conn)
83 except socket.timeout, e:
88 reply = "Stopping server"
89 self.send_reply(conn, reply)
92 reply = "Replying to %s" % msg
93 self.send_reply(conn, reply)
96 def recv_msg(self, conn):
97 data = conn.recv(1024)
98 decoded = base64.b64decode(data)
99 return decoded.rstrip()
101 def send_reply(self, conn, reply):
102 encoded = base64.b64encode(reply)
103 conn.send("%s\n" % encoded)
107 self._ctrl_sock.close()
110 sys.stderr.write("ERROR: %s\n" % str(e))
112 class Forwarder(object):
113 def __init__(self, root_dir = "."):
114 self._ctrl_sock = None
115 self._root_dir = root_dir
120 while not self._stop:
121 data = self.read_data()
122 self.send_to_server(data)
123 reply = self.recv_from_server()
124 self.write_reply(reply)
128 return sys.stdin.readline()
130 def write_reply(self, reply):
131 sys.stdout.write("%s\n" % reply)
133 def send_to_server(self, data):
135 self._ctrl_sock.send(data)
137 if e.errno == errno.EPIPE:
139 self._ctrl_sock.send(data)
142 encoded = data.rstrip()
143 msg = base64.b64decode(encoded)
147 def recv_from_server(self):
148 data = self._ctrl_sock.recv(1024)
149 encoded = data.rstrip()
150 reply = base64.b64decode(encoded)
155 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
156 sock_addr = os.path.join(self._root_dir, CTRL_SOCK)
157 self._ctrl_sock.connect(sock_addr)
159 def disconnect(self):
161 self._ctrl_sock.close()
165 class Client(object):
166 def __init__(self, root_dir = "."):
167 self._process = subprocess.Popen(
169 "from nepi.util import server;c=server.Forwarder('%s');\
170 c.forward()" % root_dir
172 stdin = subprocess.PIPE,
175 def send_msg(self, msg):
176 encoded = base64.b64encode(msg)
177 self._process.stdin.write("%s\n" % encoded)
180 self.send_msg(STOP_MSG)