1# encoding: utf-8
2
3__all__ = ['Pipe', 'pipe']
4
5
6class Pipe(object):
7    """An OS independent asynchronous pipe."""
8
9    def __init__(self):
10        # Based on Zope async.py: http://svn.zope.org/zc.ngi/trunk/src/zc/ngi/async.py
11
12        self.writer = socket.socket()
13        self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
14
15        count = 0
16        while 1:
17            count += 1
18            a = socket.socket()
19            a.bind(("127.0.0.1", 0))
20            connect_address = a.getsockname()
21            a.listen(1)
22
23            try:
24                self.writer.connect(connect_address)
25                break
26
27            except socket.error:
28                detail = exception().exception
29
30                if detail[0] != errno.WSAEADDRINUSE:
31                    raise
32
33                if count >= 10:
34                    a.close()
35                    self.writer.close()
36                    raise socket.error("Cannot bind trigger!")
37
38                a.close()
39
40        self.reader, addr = a.accept()
41        self.reader.setblocking(0)
42        self.writer.setblocking(0)
43        a.close()
44
45        self.writer_fd = self.writer.fileno()
46        self.reader_fd = self.reader.fileno()
47
48    def read(self):
49        """Emulate a file descriptors read method"""
50        try:
51            return self.reader.recv(1)
52        except socket.error:
53            ex = exception().exception
54            if ex.args[0] == errno.EWOULDBLOCK:
55                raise IOError
56            raise
57
58    def write(self, data):
59        """Emulate a file descriptors write method"""
60        return self.writer.send(data)
61
62
63def pipe():
64    """Return the optimum pipe implementation for the capabilities of the active system."""
65
66    try:
67        from os import pipe
68        return pipe()
69
70    except:
71        pipe = Pipe()
72        return pipe.reader_fd, pipe.writer_fd
73