summaryrefslogtreecommitdiff
path: root/day4/task4/client.py
blob: 33ea0848efdf8c023c3d3ae9d26372517f83cf10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import socket
from time import sleep
import struct
import json
import shelve


def pack_data(data):
    encoded = data.encode()
    return struct.pack('I', len(encoded)) + encoded


def prepare_data(data):
    cmd, args = data.split(' ', maxsplit=1)

    if cmd == 'get':
        return json.dumps({'method': 'get', 'path': args})

    elif cmd == 'cp':
        paths = args.split()
        if len(paths) != 2:
            raise ValueError('Неверное количество путей в параметрах.')
        src, dest = args.split()
        if src not in db:
            return json.dumps({'method': 'get_cp', 'path': src})
        with open(dest, 'wb') as f:
            f.write(db[src])

    else:
        raise ValueError('Команда не распознана')


def parse_response(data):
    return json.loads(data.decode())


def get_response(connection):
    buffer = b''
    while len(buffer) < DATATYPE_SIZE:
        data = connection.recv(DATATYPE_SIZE - len(buffer))
        if not data:
            raise ConnectionError('Connection was closed')

        buffer += data

    size_packed, buffer = buffer[:DATATYPE_SIZE], buffer[DATATYPE_SIZE:]
    if not size_packed:
        raise ConnectionError('Connection was closed')

    (size,) = struct.unpack('I', size_packed)
    data = connection.recv(size - len(buffer))
    return parse_response(buffer + data)


def download_file(filesize, connection):
    data = b''
    count = 0
    while count < filesize:
        (size,) = struct.unpack('I', connection.recv(DATATYPE_SIZE))
        data += connection.recv(size)
        count += size

    return data


def handle_response(data, connection):
    if data['status'] == 0:
        print(f'Загружаем файл размером {data["size"]} байт...')
        file_data = download_file(data['size'], connection)
        db[data['path']] = file_data
        print('Загрузка завершена')

    elif data['status'] == 1:
        print(data['reason'])

    elif data['status'] == 2:
        print('Неизвестная ошибка:')
        print(data['reason'])


def try_connect():
    cnt = 0
    sock = socket.socket()
    while cnt < 10:
        try:
            cnt += 1
            sock.connect(ADDR)

        except ConnectionRefusedError:
            print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...')
            sleep(3)

        else:
            return sock

    else:
        print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...')
        sock.close()
        return


HOST, PORT = ADDR = 'localhost', 6000
DATATYPE_SIZE = 4  # int

sock = try_connect()
if sock is None:
    quit()


db = shelve.open('backdoor.db')

while True:
    try:
        data = input('Введите команду:\n')
        data = prepare_data(data)
        if data is None:
            continue

    except KeyboardInterrupt:
        break

    except ValueError as err:
        print(err)

    else:
        packet = pack_data(data)
        sock.sendall(packet)
        response = get_response(sock)
        handle_response(response, sock)

sock.close()