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
33 # can not return normally after fork beacuse no exec was done.
34 # This means that if we don't do a os._exit(0) here the code that
35 # follows the call to "Server.run()" in the "caller code" will be
36 # executed... but by now it has already been executed after the
37 # first process (the one that did the first fork) returned.
46 # we do os.waitpid to avoid leaving a <defunc> (zombie) process
48 # return 0 to inform the caller method that this is not the
52 # Decouple from parent environment.
53 os.chdir(self._root_dir)
60 # see ref: "os._exit(0)"
63 # close all open file descriptors.
64 for fd in range(2, MAX_FD):
70 # Redirect standard file descriptors.
71 self._stderr = stdout = file(STD_ERR, "a", 0)
72 stdin = open('/dev/null', 'r')
73 os.dup2(stdin.fileno(), sys.stdin.fileno())
74 os.dup2(stdout.fileno(), sys.stdout.fileno())
75 os.dup2(self._stderr.fileno(), sys.stderr.fileno())
78 def post_daemonize(self):
82 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
83 self._ctrl_sock.bind(CTRL_SOCK)
84 self._ctrl_sock.listen(0)
86 conn, addr = self._ctrl_sock.accept()
90 msg = self.recv_msg(conn)
91 except socket.timeout, e:
97 reply = self.stop_action()
100 self.send_reply(conn, reply)
104 reply = self.reply_action(msg)
107 self.send_reply(conn, reply)
110 def recv_msg(self, conn):
111 data = conn.recv(1024)
112 decoded = base64.b64decode(data)
113 return decoded.rstrip()
115 def send_reply(self, conn, reply):
116 encoded = base64.b64encode(reply)
117 conn.send("%s\n" % encoded)
121 self._ctrl_sock.close()
126 def stop_action(self):
127 return "Stopping server"
129 def reply_action(self, msg):
130 return "Reply to: %s" % msg
132 def log_error(self, error = None):
135 error = "%s\n" % traceback.format_exc()
136 sys.stderr.write(error)
139 class Forwarder(object):
140 def __init__(self, root_dir = "."):
141 self._ctrl_sock = None
142 self._root_dir = root_dir
147 while not self._stop:
148 data = self.read_data()
149 self.send_to_server(data)
150 data = self.recv_from_server()
151 self.write_data(data)
155 return sys.stdin.readline()
157 def write_data(self, data):
158 sys.stdout.write(data)
161 def send_to_server(self, data):
163 self._ctrl_sock.send(data)
165 if e.errno == errno.EPIPE:
167 self._ctrl_sock.send(data)
170 encoded = data.rstrip()
171 msg = base64.b64decode(encoded)
175 def recv_from_server(self):
176 return self._ctrl_sock.recv(1024)
180 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
181 sock_addr = os.path.join(self._root_dir, CTRL_SOCK)
182 self._ctrl_sock.connect(sock_addr)
184 def disconnect(self):
186 self._ctrl_sock.close()
190 class Client(object):
191 def __init__(self, root_dir = "."):
192 self._process = subprocess.Popen(
194 "from nepi.util import server;c=server.Forwarder('%s');\
195 c.forward()" % root_dir
197 stdin = subprocess.PIPE,
198 stdout = subprocess.PIPE,
201 def send_msg(self, msg):
202 encoded = base64.b64encode(msg)
203 data = "%s\n" % encoded
204 self._process.stdin.write(data)
207 self.send_msg(STOP_MSG)
209 def read_reply(self):
210 data = self._process.stdout.readline()
211 encoded = data.rstrip()
212 return base64.b64decode(encoded)