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
32 # can not return normally after fork beacuse no exec was done.
33 # This means that if we don't do a os._exit(0) here the code that
34 # follows the call to "Server.run()" in the "caller code" will be
35 # executed... but by now it has already been executed after the
36 # first process (the one that did the first fork) returned.
42 # we do os.waitpid to avoid leaving a <defunc> (zombie) process
44 # return 0 to inform the caller method that this is not the
48 # Decouple from parent environment.
49 os.chdir(self._root_dir)
56 # see ref: "os._exit(0)"
59 # close all open file descriptors.
60 for fd in range(2, MAX_FD):
66 # Redirect standard file descriptors.
67 self._stderr = stdout = file(STD_ERR, "a", 0)
68 stdin = open('/dev/null', 'r')
69 os.dup2(stdin.fileno(), sys.stdin.fileno())
70 os.dup2(stdout.fileno(), sys.stdout.fileno())
71 os.dup2(self._stderr.fileno(), sys.stderr.fileno())
74 def post_daemonize(self):
78 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
79 self._ctrl_sock.bind(CTRL_SOCK)
80 self._ctrl_sock.listen(0)
82 conn, addr = self._ctrl_sock.accept()
86 msg = self.recv_msg(conn)
87 except socket.timeout, e:
93 reply = self.stop_action()
95 sys.stderr.write("ERROR: %s\n" % sys.exc_info()[0])
96 self.send_reply(conn, reply)
100 reply = self.reply_action(msg)
102 sys.stderr.write("ERROR: %s\n" % sys.exc_info()[0])
103 self.send_reply(conn, reply)
106 def recv_msg(self, conn):
107 data = conn.recv(1024)
108 decoded = base64.b64decode(data)
109 return decoded.rstrip()
111 def send_reply(self, conn, reply):
112 encoded = base64.b64encode(reply)
113 conn.send("%s\n" % encoded)
117 self._ctrl_sock.close()
120 sys.stderr.write("ERROR: %s\n" % sys.exc_info()[0])
122 def stop_action(self):
123 return "Stopping server"
125 def reply_action(self, msg):
126 return "Reply to: %s" % msg
128 class Forwarder(object):
129 def __init__(self, root_dir = "."):
130 self._ctrl_sock = None
131 self._root_dir = root_dir
136 while not self._stop:
137 data = self.read_data()
138 self.send_to_server(data)
139 data = self.recv_from_server()
140 self.write_data(data)
144 return sys.stdin.readline()
146 def write_data(self, data):
147 sys.stdout.write(data)
150 def send_to_server(self, data):
152 self._ctrl_sock.send(data)
154 if e.errno == errno.EPIPE:
156 self._ctrl_sock.send(data)
159 encoded = data.rstrip()
160 msg = base64.b64decode(encoded)
164 def recv_from_server(self):
165 return self._ctrl_sock.recv(1024)
169 self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
170 sock_addr = os.path.join(self._root_dir, CTRL_SOCK)
171 self._ctrl_sock.connect(sock_addr)
173 def disconnect(self):
175 self._ctrl_sock.close()
179 class Client(object):
180 def __init__(self, root_dir = "."):
181 self._process = subprocess.Popen(
183 "from nepi.util import server;c=server.Forwarder('%s');\
184 c.forward()" % root_dir
186 stdin = subprocess.PIPE,
187 stdout = subprocess.PIPE,
190 def send_msg(self, msg):
191 encoded = base64.b64encode(msg)
192 data = "%s\n" % encoded
193 self._process.stdin.write(data)
196 self.send_msg(STOP_MSG)
198 def read_reply(self):
199 data = self._process.stdout.readline()
200 encoded = data.rstrip()
201 return base64.b64decode(encoded)