We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Raise AttributeError when closing a socket
I want pwnlib to listen on a port, but when I close the socket it raise AssertionError.

Here's my code:
```python
from pwnlib import tubes
import os

p = tubes.listen.listen(1337, "127.0.0.1")

os.system("nohup curl 127.0.0.1:1337/start123end >/dev/null 2>/dev/null &")

print(p.recvregex(b"start([\s\S]+)end"))

p.close()
```

And here's the error message: 
```
Exception in thread Thread-1 (accepter):
Traceback (most recent call last):
  File "/usr/lib64/python3.10/threading.py", line 1016, in _bootstrap_inner
    self.run()
  File "/usr/lib64/python3.10/threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py", line 129, in accepter
    self.settimeout(self.timeout)
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py", line 1186, in settimeout
    self.timeout = timeout
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/timeout.py", line 146, in timeout
    assert not self._stop
AssertionError
b'GET /start123end'
Traceback (most recent call last):
  File "THE PYTHON SCRIPT ABOVE", line 10, in <module>
    p.close()
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py", line 177, in close
    super(listen, self).close()
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/sock.py", line 173, in close
    self._close_msg()
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/sock.py", line 176, in _close_msg
    self.info('Closed connection to %s port %d', self.rhost, self.rport)
  File "MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py", line 170, in __getattr__
    return getattr(super(listen, self), key)
AttributeError: 'super' object has no attribute 'rhost'. Did you mean: 'lhost'?

```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwnlib/tubes/listen.py`
Content:
```
1 from __future__ import absolute_import
2 from __future__ import division
3 
4 import errno
5 import socket
6 
7 from pwnlib.context import context
8 from pwnlib.log import getLogger
9 from pwnlib.timeout import Timeout
10 from pwnlib.tubes.sock import sock
11 
12 log = getLogger(__name__)
13 
14 class listen(sock):
15     r"""Creates an TCP or UDP-socket to receive data on. It supports
16     both IPv4 and IPv6.
17 
18     The returned object supports all the methods from
19     :class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.
20 
21     Arguments:
22         port(int): The port to connect to.
23             Defaults to a port auto-selected by the operating system.
24         bindaddr(str): The address to bind to.
25             Defaults to ``0.0.0.0`` / `::`.
26         fam: The string "any", "ipv4" or "ipv6" or an integer to pass to :func:`socket.getaddrinfo`.
27         typ: The string "tcp" or "udp" or an integer to pass to :func:`socket.getaddrinfo`.
28 
29     Examples:
30 
31         >>> l = listen(1234)
32         >>> r = remote('localhost', l.lport)
33         >>> _ = l.wait_for_connection()
34         >>> l.sendline(b'Hello')
35         >>> r.recvline()
36         b'Hello\n'
37 
38         >>> # It works with ipv4 by default
39         >>> l = listen()
40         >>> l.spawn_process('/bin/sh')
41         >>> r = remote('127.0.0.1', l.lport)
42         >>> r.sendline(b'echo Goodbye')
43         >>> r.recvline()
44         b'Goodbye\n'
45 
46         >>> # and it works with ipv6 by defaut, too!
47         >>> l = listen()
48         >>> r = remote('::1', l.lport)
49         >>> r.sendline(b'Bye-bye')
50         >>> l.recvline()
51         b'Bye-bye\n'
52     """
53 
54     #: Local port
55     lport = 0
56 
57     #: Local host
58     lhost = None
59 
60     #: Socket type (e.g. socket.SOCK_STREAM)
61     type = None
62 
63     #: Socket family
64     family = None
65 
66     #: Socket protocol
67     protocol = None
68 
69     #: Canonical name of the listening interface
70     canonname = None
71 
72     #: Sockaddr structure that is being listened on
73     sockaddr = None
74 
75     _accepter = None
76 
77     def __init__(self, port=0, bindaddr='::',
78                  fam='any', typ='tcp', *args, **kwargs):
79         super(listen, self).__init__(*args, **kwargs)
80 
81         fam = self._get_family(fam)
82         typ = self._get_type(typ)
83 
84         if fam == socket.AF_INET and bindaddr == '::':
85             bindaddr = '0.0.0.0'
86 
87         h = self.waitfor('Trying to bind to %s on port %s' % (bindaddr, port))
88 
89         for res in socket.getaddrinfo(bindaddr, port, fam, typ, 0, socket.AI_PASSIVE):
90             self.family, self.type, self.proto, self.canonname, self.sockaddr = res
91 
92             if self.type not in [socket.SOCK_STREAM, socket.SOCK_DGRAM]:
93                 continue
94 
95             h.status("Trying %s" % self.sockaddr[0])
96             listen_sock = socket.socket(self.family, self.type, self.proto)
97             listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
98             if self.family == socket.AF_INET6:
99                 try:
100                     listen_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, fam == socket.AF_INET6)
101                 except (socket.error, AttributeError):
102                     self.warn("could not set socket to accept also IPV4")
103             listen_sock.bind(self.sockaddr)
104             self.lhost, self.lport = listen_sock.getsockname()[:2]
105             if self.type == socket.SOCK_STREAM:
106                 listen_sock.listen(1)
107             break
108         else:
109             h.failure()
110             self.error("Could not bind to %s on port %s" % (bindaddr, port))
111 
112         h.success()
113 
114         h = self.waitfor('Waiting for connections on %s:%s' % (self.lhost, self.lport))
115 
116         def accepter():
117             while True:
118                 try:
119                     if self.type == socket.SOCK_STREAM:
120                         self.sock, rhost = listen_sock.accept()
121                         listen_sock.close()
122                     else:
123                         data, rhost = listen_sock.recvfrom(4096)
124                         listen_sock.connect(rhost)
125                         self.sock = listen_sock
126                         self.unrecv(data)
127                     self.settimeout(self.timeout)
128                     break
129                 except socket.error as e:
130                     if e.errno == errno.EINTR:
131                         continue
132                     h.failure()
133                     self.exception("Socket failure while waiting for connection")
134                     self.sock = None
135                     return
136 
137             self.rhost, self.rport = rhost[:2]
138             h.success('Got connection from %s on port %d' % (self.rhost, self.rport))
139 
140         self._accepter = context.Thread(target = accepter)
141         self._accepter.daemon = True
142         self._accepter.start()
143 
144     def spawn_process(self, *args, **kwargs):
145         def accepter():
146             self.wait_for_connection()
147             self.sock.setblocking(1)
148             p = super(listen, self).spawn_process(*args, **kwargs)
149             p.wait()
150             self.close()
151         t = context.Thread(target = accepter)
152         t.daemon = True
153         t.start()
154 
155     def wait_for_connection(self):
156         """Blocks until a connection has been established."""
157         self.sock
158         return self
159 
160     @property
161     def sock(self):
162         try:
163             return self.__dict__['sock']
164         except KeyError:
165             pass
166         self._accepter.join(timeout=self.timeout)
167         return self.__dict__.get('sock')
168 
169     @sock.setter
170     def sock(self, s):
171         self.__dict__['sock'] = s
172 
173     def close(self):
174         # since `close` is scheduled to run on exit we must check that we got
175         # a connection or the program will hang in the `join` call above
176         if self._accepter and self._accepter.is_alive():
177             return
178         super(listen, self).close()
179
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwnlib/tubes/listen.py b/pwnlib/tubes/listen.py
--- a/pwnlib/tubes/listen.py
+++ b/pwnlib/tubes/listen.py
@@ -13,7 +13,8 @@
 
 class listen(sock):
     r"""Creates an TCP or UDP-socket to receive data on. It supports
-    both IPv4 and IPv6.
+    both IPv4 and IPv6. You need to call :meth:`wait_for_connection`
+    before using the listen socket.
 
     The returned object supports all the methods from
     :class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.
@@ -46,6 +47,7 @@
         >>> # and it works with ipv6 by defaut, too!
         >>> l = listen()
         >>> r = remote('::1', l.lport)
+        >>> _ = l.wait_for_connection()
         >>> r.sendline(b'Bye-bye')
         >>> l.recvline()
         b'Bye-bye\n'

{"golden_diff": "diff --git a/pwnlib/tubes/listen.py b/pwnlib/tubes/listen.py\n--- a/pwnlib/tubes/listen.py\n+++ b/pwnlib/tubes/listen.py\n@@ -13,7 +13,8 @@\n \n class listen(sock):\n     r\"\"\"Creates an TCP or UDP-socket to receive data on. It supports\n-    both IPv4 and IPv6.\n+    both IPv4 and IPv6. You need to call :meth:`wait_for_connection`\n+    before using the listen socket.\n \n     The returned object supports all the methods from\n     :class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.\n@@ -46,6 +47,7 @@\n         >>> # and it works with ipv6 by defaut, too!\n         >>> l = listen()\n         >>> r = remote('::1', l.lport)\n+        >>> _ = l.wait_for_connection()\n         >>> r.sendline(b'Bye-bye')\n         >>> l.recvline()\n         b'Bye-bye\\n'\n", "issue": "Raise AttributeError when closing a socket\nI want pwnlib to listen on a port, but when I close the socket it raise AssertionError.\r\n\r\nHere's my code:\r\n```python\r\nfrom pwnlib import tubes\r\nimport os\r\n\r\np = tubes.listen.listen(1337, \"127.0.0.1\")\r\n\r\nos.system(\"nohup curl 127.0.0.1:1337/start123end >/dev/null 2>/dev/null &\")\r\n\r\nprint(p.recvregex(b\"start([\\s\\S]+)end\"))\r\n\r\np.close()\r\n```\r\n\r\nAnd here's the error message: \r\n```\r\nException in thread Thread-1 (accepter):\r\nTraceback (most recent call last):\r\n  File \"/usr/lib64/python3.10/threading.py\", line 1016, in _bootstrap_inner\r\n    self.run()\r\n  File \"/usr/lib64/python3.10/threading.py\", line 953, in run\r\n    self._target(*self._args, **self._kwargs)\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py\", line 129, in accepter\r\n    self.settimeout(self.timeout)\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py\", line 1186, in settimeout\r\n    self.timeout = timeout\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/timeout.py\", line 146, in timeout\r\n    assert not self._stop\r\nAssertionError\r\nb'GET /start123end'\r\nTraceback (most recent call last):\r\n  File \"THE PYTHON SCRIPT ABOVE\", line 10, in <module>\r\n    p.close()\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py\", line 177, in close\r\n    super(listen, self).close()\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/sock.py\", line 173, in close\r\n    self._close_msg()\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/sock.py\", line 176, in _close_msg\r\n    self.info('Closed connection to %s port %d', self.rhost, self.rport)\r\n  File \"MYHOME/.local/lib/python3.10/site-packages/pwnlib/tubes/listen.py\", line 170, in __getattr__\r\n    return getattr(super(listen, self), key)\r\nAttributeError: 'super' object has no attribute 'rhost'. Did you mean: 'lhost'?\r\n\r\n```\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\n\nimport errno\nimport socket\n\nfrom pwnlib.context import context\nfrom pwnlib.log import getLogger\nfrom pwnlib.timeout import Timeout\nfrom pwnlib.tubes.sock import sock\n\nlog = getLogger(__name__)\n\nclass listen(sock):\n    r\"\"\"Creates an TCP or UDP-socket to receive data on. It supports\n    both IPv4 and IPv6.\n\n    The returned object supports all the methods from\n    :class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.\n\n    Arguments:\n        port(int): The port to connect to.\n            Defaults to a port auto-selected by the operating system.\n        bindaddr(str): The address to bind to.\n            Defaults to ``0.0.0.0`` / `::`.\n        fam: The string \"any\", \"ipv4\" or \"ipv6\" or an integer to pass to :func:`socket.getaddrinfo`.\n        typ: The string \"tcp\" or \"udp\" or an integer to pass to :func:`socket.getaddrinfo`.\n\n    Examples:\n\n        >>> l = listen(1234)\n        >>> r = remote('localhost', l.lport)\n        >>> _ = l.wait_for_connection()\n        >>> l.sendline(b'Hello')\n        >>> r.recvline()\n        b'Hello\\n'\n\n        >>> # It works with ipv4 by default\n        >>> l = listen()\n        >>> l.spawn_process('/bin/sh')\n        >>> r = remote('127.0.0.1', l.lport)\n        >>> r.sendline(b'echo Goodbye')\n        >>> r.recvline()\n        b'Goodbye\\n'\n\n        >>> # and it works with ipv6 by defaut, too!\n        >>> l = listen()\n        >>> r = remote('::1', l.lport)\n        >>> r.sendline(b'Bye-bye')\n        >>> l.recvline()\n        b'Bye-bye\\n'\n    \"\"\"\n\n    #: Local port\n    lport = 0\n\n    #: Local host\n    lhost = None\n\n    #: Socket type (e.g. socket.SOCK_STREAM)\n    type = None\n\n    #: Socket family\n    family = None\n\n    #: Socket protocol\n    protocol = None\n\n    #: Canonical name of the listening interface\n    canonname = None\n\n    #: Sockaddr structure that is being listened on\n    sockaddr = None\n\n    _accepter = None\n\n    def __init__(self, port=0, bindaddr='::',\n                 fam='any', typ='tcp', *args, **kwargs):\n        super(listen, self).__init__(*args, **kwargs)\n\n        fam = self._get_family(fam)\n        typ = self._get_type(typ)\n\n        if fam == socket.AF_INET and bindaddr == '::':\n            bindaddr = '0.0.0.0'\n\n        h = self.waitfor('Trying to bind to %s on port %s' % (bindaddr, port))\n\n        for res in socket.getaddrinfo(bindaddr, port, fam, typ, 0, socket.AI_PASSIVE):\n            self.family, self.type, self.proto, self.canonname, self.sockaddr = res\n\n            if self.type not in [socket.SOCK_STREAM, socket.SOCK_DGRAM]:\n                continue\n\n            h.status(\"Trying %s\" % self.sockaddr[0])\n            listen_sock = socket.socket(self.family, self.type, self.proto)\n            listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n            if self.family == socket.AF_INET6:\n                try:\n                    listen_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, fam == socket.AF_INET6)\n                except (socket.error, AttributeError):\n                    self.warn(\"could not set socket to accept also IPV4\")\n            listen_sock.bind(self.sockaddr)\n            self.lhost, self.lport = listen_sock.getsockname()[:2]\n            if self.type == socket.SOCK_STREAM:\n                listen_sock.listen(1)\n            break\n        else:\n            h.failure()\n            self.error(\"Could not bind to %s on port %s\" % (bindaddr, port))\n\n        h.success()\n\n        h = self.waitfor('Waiting for connections on %s:%s' % (self.lhost, self.lport))\n\n        def accepter():\n            while True:\n                try:\n                    if self.type == socket.SOCK_STREAM:\n                        self.sock, rhost = listen_sock.accept()\n                        listen_sock.close()\n                    else:\n                        data, rhost = listen_sock.recvfrom(4096)\n                        listen_sock.connect(rhost)\n                        self.sock = listen_sock\n                        self.unrecv(data)\n                    self.settimeout(self.timeout)\n                    break\n                except socket.error as e:\n                    if e.errno == errno.EINTR:\n                        continue\n                    h.failure()\n                    self.exception(\"Socket failure while waiting for connection\")\n                    self.sock = None\n                    return\n\n            self.rhost, self.rport = rhost[:2]\n            h.success('Got connection from %s on port %d' % (self.rhost, self.rport))\n\n        self._accepter = context.Thread(target = accepter)\n        self._accepter.daemon = True\n        self._accepter.start()\n\n    def spawn_process(self, *args, **kwargs):\n        def accepter():\n            self.wait_for_connection()\n            self.sock.setblocking(1)\n            p = super(listen, self).spawn_process(*args, **kwargs)\n            p.wait()\n            self.close()\n        t = context.Thread(target = accepter)\n        t.daemon = True\n        t.start()\n\n    def wait_for_connection(self):\n        \"\"\"Blocks until a connection has been established.\"\"\"\n        self.sock\n        return self\n\n    @property\n    def sock(self):\n        try:\n            return self.__dict__['sock']\n        except KeyError:\n            pass\n        self._accepter.join(timeout=self.timeout)\n        return self.__dict__.get('sock')\n\n    @sock.setter\n    def sock(self, s):\n        self.__dict__['sock'] = s\n\n    def close(self):\n        # since `close` is scheduled to run on exit we must check that we got\n        # a connection or the program will hang in the `join` call above\n        if self._accepter and self._accepter.is_alive():\n            return\n        super(listen, self).close()\n", "path": "pwnlib/tubes/listen.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\n\nimport errno\nimport socket\n\nfrom pwnlib.context import context\nfrom pwnlib.log import getLogger\nfrom pwnlib.timeout import Timeout\nfrom pwnlib.tubes.sock import sock\n\nlog = getLogger(__name__)\n\nclass listen(sock):\n    r\"\"\"Creates an TCP or UDP-socket to receive data on. It supports\n    both IPv4 and IPv6. You need to call :meth:`wait_for_connection`\n    before using the listen socket.\n\n    The returned object supports all the methods from\n    :class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.\n\n    Arguments:\n        port(int): The port to connect to.\n            Defaults to a port auto-selected by the operating system.\n        bindaddr(str): The address to bind to.\n            Defaults to ``0.0.0.0`` / `::`.\n        fam: The string \"any\", \"ipv4\" or \"ipv6\" or an integer to pass to :func:`socket.getaddrinfo`.\n        typ: The string \"tcp\" or \"udp\" or an integer to pass to :func:`socket.getaddrinfo`.\n\n    Examples:\n\n        >>> l = listen(1234)\n        >>> r = remote('localhost', l.lport)\n        >>> _ = l.wait_for_connection()\n        >>> l.sendline(b'Hello')\n        >>> r.recvline()\n        b'Hello\\n'\n\n        >>> # It works with ipv4 by default\n        >>> l = listen()\n        >>> l.spawn_process('/bin/sh')\n        >>> r = remote('127.0.0.1', l.lport)\n        >>> r.sendline(b'echo Goodbye')\n        >>> r.recvline()\n        b'Goodbye\\n'\n\n        >>> # and it works with ipv6 by defaut, too!\n        >>> l = listen()\n        >>> r = remote('::1', l.lport)\n        >>> _ = l.wait_for_connection()\n        >>> r.sendline(b'Bye-bye')\n        >>> l.recvline()\n        b'Bye-bye\\n'\n    \"\"\"\n\n    #: Local port\n    lport = 0\n\n    #: Local host\n    lhost = None\n\n    #: Socket type (e.g. socket.SOCK_STREAM)\n    type = None\n\n    #: Socket family\n    family = None\n\n    #: Socket protocol\n    protocol = None\n\n    #: Canonical name of the listening interface\n    canonname = None\n\n    #: Sockaddr structure that is being listened on\n    sockaddr = None\n\n    _accepter = None\n\n    def __init__(self, port=0, bindaddr='::',\n                 fam='any', typ='tcp', *args, **kwargs):\n        super(listen, self).__init__(*args, **kwargs)\n\n        fam = self._get_family(fam)\n        typ = self._get_type(typ)\n\n        if fam == socket.AF_INET and bindaddr == '::':\n            bindaddr = '0.0.0.0'\n\n        h = self.waitfor('Trying to bind to %s on port %s' % (bindaddr, port))\n\n        for res in socket.getaddrinfo(bindaddr, port, fam, typ, 0, socket.AI_PASSIVE):\n            self.family, self.type, self.proto, self.canonname, self.sockaddr = res\n\n            if self.type not in [socket.SOCK_STREAM, socket.SOCK_DGRAM]:\n                continue\n\n            h.status(\"Trying %s\" % self.sockaddr[0])\n            listen_sock = socket.socket(self.family, self.type, self.proto)\n            listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n            if self.family == socket.AF_INET6:\n                try:\n                    listen_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, fam == socket.AF_INET6)\n                except (socket.error, AttributeError):\n                    self.warn(\"could not set socket to accept also IPV4\")\n            listen_sock.bind(self.sockaddr)\n            self.lhost, self.lport = listen_sock.getsockname()[:2]\n            if self.type == socket.SOCK_STREAM:\n                listen_sock.listen(1)\n            break\n        else:\n            h.failure()\n            self.error(\"Could not bind to %s on port %s\" % (bindaddr, port))\n\n        h.success()\n\n        h = self.waitfor('Waiting for connections on %s:%s' % (self.lhost, self.lport))\n\n        def accepter():\n            while True:\n                try:\n                    if self.type == socket.SOCK_STREAM:\n                        self.sock, rhost = listen_sock.accept()\n                        listen_sock.close()\n                    else:\n                        data, rhost = listen_sock.recvfrom(4096)\n                        listen_sock.connect(rhost)\n                        self.sock = listen_sock\n                        self.unrecv(data)\n                    self.settimeout(self.timeout)\n                    break\n                except socket.error as e:\n                    if e.errno == errno.EINTR:\n                        continue\n                    h.failure()\n                    self.exception(\"Socket failure while waiting for connection\")\n                    self.sock = None\n                    return\n\n            self.rhost, self.rport = rhost[:2]\n            h.success('Got connection from %s on port %d' % (self.rhost, self.rport))\n\n        self._accepter = context.Thread(target = accepter)\n        self._accepter.daemon = True\n        self._accepter.start()\n\n    def spawn_process(self, *args, **kwargs):\n        def accepter():\n            self.wait_for_connection()\n            self.sock.setblocking(1)\n            p = super(listen, self).spawn_process(*args, **kwargs)\n            p.wait()\n            self.close()\n        t = context.Thread(target = accepter)\n        t.daemon = True\n        t.start()\n\n    def wait_for_connection(self):\n        \"\"\"Blocks until a connection has been established.\"\"\"\n        self.sock\n        return self\n\n    @property\n    def sock(self):\n        try:\n            return self.__dict__['sock']\n        except KeyError:\n            pass\n        self._accepter.join(timeout=self.timeout)\n        return self.__dict__.get('sock')\n\n    @sock.setter\n    def sock(self, s):\n        self.__dict__['sock'] = s\n\n    def close(self):\n        # since `close` is scheduled to run on exit we must check that we got\n        # a connection or the program will hang in the `join` call above\n        if self._accepter and self._accepter.is_alive():\n            return\n        super(listen, self).close()\n", "path": "pwnlib/tubes/listen.py"}]}