XS-CBT-backup / xs-cbt-backup

Proof of concept backup program using the Changed Block Tracking APIs of XenServer
7 stars 1 forks source link

Use a timeout for read/write operations #3

Closed gaborigloi closed 6 years ago

gaborigloi commented 6 years ago

This does work for sending data: Using netcat to simulate an unresponsive server:

$ nc -l localhost 10809

On the client side:

>>> c = new_nbd_client("localhost","jk",use_tls=False)
Connecting to export 'jk' on host 'localhost' and port '10809'

NBD_CMD_DISC
NBD request offset=0 length=0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/cbt-tests/new_nbd_client.py", line 141, in __init__
    exportname=exportname, use_tls=use_tls)
  File "/tmp/cbt-tests/new_nbd_client.py", line 215, in _fixed_new_style_handshake
    nbd_magic = self._recvall(len("NBDMAGIC"))
  File "/tmp/cbt-tests/new_nbd_client.py", line 158, in _recvall
    b = self._s.recv(length - len(data))
socket.timeout: timed out
>>>
gaborigloi commented 6 years ago

Verified with netcat and this test program test.py:

from new_nbd_client import new_nbd_client

c = new_nbd_client("localhost",use_tls=False)

that the program indeed has a 30-second timeout for reading:

$ time python3 test.py 
Connecting to export '' on host 'localhost' and port '10809'
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    c = new_nbd_client("localhost",use_tls=False)
  File "/tmp/cbt-tests/new_nbd_client.py", line 141, in __init__
    exportname=exportname, use_tls=use_tls)
  File "/tmp/cbt-tests/new_nbd_client.py", line 215, in _fixed_new_style_handshake
    nbd_magic = self._recvall(len("NBDMAGIC"))
  File "/tmp/cbt-tests/new_nbd_client.py", line 158, in _recvall
    b = self._s.recv(length - len(data))
socket.timeout: timed out
NBD_CMD_DISC
NBD request offset=0 length=0
Command exited with non-zero status 1
0.08user 0.00system 0:30.12elapsed 0%CPU (0avgtext+0avgdata 22188maxresident)k
0inputs+0outputs (0major+3219minor)pagefaults 0swaps
gaborigloi commented 6 years ago

I have verified with the following Python 3.6 server program (modified version of the server example here: https://docs.python.org/3/library/socketserver.html#socketserver-tcpserver-example):

import socketserver
import time

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.request.sendall(b'NBDMAGIC')
        self.request.sendall(b'IHAVEOPT')
        time.sleep(31)
        self.request.sendall(b'\x00\x01')
        self.data = self.request.recv(1).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)

if __name__ == "__main__":
    HOST, PORT = "localhost", 10809

    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        server.serve_forever()

that the NBD client indeed obeys the 30-second timeout for sending too:

$ time python3 test.py 
Connecting to export '' on host 'localhost' and port '10809'
NBDMAGIC
IHAVEOPT
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    c = new_nbd_client("localhost",use_tls=False)
  File "/tmp/cbt-tests/new_nbd_client.py", line 141, in __init__
    exportname=exportname, use_tls=use_tls)
  File "/tmp/cbt-tests/new_nbd_client.py", line 221, in _fixed_new_style_handshake
    buf = self._recvall(2)
  File "/tmp/cbt-tests/new_nbd_client.py", line 158, in _recvall
    b = self._s.recv(length - len(data))
socket.timeout: timed out
NBD_CMD_DISC
NBD request offset=0 length=0
Command exited with non-zero status 1
0.08user 0.00system 0:30.11elapsed 0%CPU (0avgtext+0avgdata 22108maxresident)k
0inputs+0outputs (0major+3227minor)pagefaults 0swaps

When I changed the server sleep time to 29 in the server program, I got a different error (probably because the server finished handling the client):

$ time python3 test.py 
Connecting to export '' on host 'localhost' and port '10809'
NBDMAGIC
IHAVEOPT
buf
sending client flags
sent client flags
NBD sending option header
option='1' data_length='0'
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    c = new_nbd_client("localhost",use_tls=False)
  File "/tmp/cbt-tests/new_nbd_client.py", line 141, in __init__
    exportname=exportname, use_tls=use_tls)
  File "/tmp/cbt-tests/new_nbd_client.py", line 242, in _fixed_new_style_handshake
    buf = self._recvall(8)
  File "/tmp/cbt-tests/new_nbd_client.py", line 160, in _recvall
    raise NBDEOFError
new_nbd_client.NBDEOFError
NBD_CMD_DISC
NBD request offset=0 length=0
Exception ignored in: <bound method new_nbd_client.__del__ of <new_nbd_client.new_nbd_client object at 0x7f349f2b89e8>>
Traceback (most recent call last):
  File "/tmp/cbt-tests/new_nbd_client.py", line 146, in __del__
    self.close()
  File "/tmp/cbt-tests/new_nbd_client.py", line 152, in close
    self._disconnect()
  File "/tmp/cbt-tests/new_nbd_client.py", line 328, in _disconnect
    self._s.sendall(header)
BrokenPipeError: [Errno 32] Broken pipe
Command exited with non-zero status 1
0.09user 0.01system 0:29.13elapsed 0%CPU (0avgtext+0avgdata 22288maxresident)k
0inputs+0outputs (0major+3225minor)pagefaults 0swaps