source: ogClient-Git/src/ogClient.py @ cc0d987

Last change on this file since cc0d987 was 082079a, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#1056 stop request processing on connection closure

If server closes the connection, close the socket, reconnect and stop
processing. self.connect() already cleans up the internal state, including the
socket state.

  • Property mode set to 100644
File size: 3.9 KB
Line 
1#
2# Copyright (C) 2020-2021 Soleta Networks <info@soleta.eu>
3#
4# This program is free software: you can redistribute it and/or modify it under
5# the terms of the GNU Affero General Public License as published by the
6# Free Software Foundation; either version 3 of the License, or
7# (at your option) any later version.
8
9import errno
10import select
11import socket
12import time
13import email
14import platform
15from io import StringIO
16
17from src.restRequest import *
18from src.ogRest import *
19from enum import Enum
20
21class State(Enum):
22        CONNECTING = 0
23        RECEIVING = 1
24        FORCE_DISCONNECTED = 2
25
26class ogClient:
27        OG_PATH = '/opt/opengnsys/'
28
29        def __init__(self, config):
30                self.CONFIG = config
31
32                self.mode = self.CONFIG['opengnsys']['mode']
33                if self.mode not in {'virtual', 'live'}:
34                        raise ValueError('Mode not supported.')
35
36                if self.CONFIG['samba']['activate']:
37                        assert('user' in self.CONFIG['samba'])
38                        assert('pass' in self.CONFIG['samba'])
39
40                self.ip = self.CONFIG['opengnsys']['ip']
41                self.port = self.CONFIG['opengnsys']['port']
42                self.ogrest = ogRest(self.CONFIG)
43
44        def get_socket(self):
45                return self.sock
46
47        def get_state(self):
48                return self.state
49
50        def cleanup(self):
51                self.data = ""
52                self.content_len = 0
53                self.header_len = 0
54                self.trailer = False
55
56        def connect(self):
57                print('connecting...')
58                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
59                self.sock.setblocking(0)
60                self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
61                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
62                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30)
63                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
64
65                self.state = State.CONNECTING
66                self.cleanup()
67
68                try:
69                        self.sock.connect((self.ip, self.port))
70                except socket.error as err:
71                        if err.errno == errno.EINPROGRESS:
72                                return
73                        elif err.errno == errno.ECONNREFUSED:
74                                return
75
76        def send(self, msg):
77                self.sock.send(bytes(msg, 'utf-8'))
78                return len(msg)
79
80        def connect2(self):
81                try:
82                        self.sock.connect((self.ip, self.port))
83                except socket.error as err:
84                        if err.errno == errno.EISCONN:
85                                print('connected')
86                                self.state = State.RECEIVING
87                        else:
88                                time.sleep(1)
89                                print('connection refused, retrying...')
90                                self.state = State.CONNECTING
91                                self.sock.close()
92                                self.connect()
93
94        def receive(self):
95                try:
96                        data = self.sock.recv(1024).decode('utf-8')
97                except socket.error as err:
98                        data = ''
99                        print('failed to received ' + str(err))
100
101                if len(data) == 0:
102                        self.sock.close()
103                        self.connect()
104                        return
105
106                self.data = self.data + data
107                request = restRequest()
108
109                if not self.trailer:
110                        header_len = self.data.find("\r\n\r\n")
111                        if header_len > 0:
112                                # https://stackoverflow.com/questions/4685217/parse-raw-http-headers
113                                request_line, headers_alone = self.data.split('\n', 1)
114                                headers = email.message_from_file(StringIO(headers_alone))
115
116                                if 'Content-Length' in headers.keys():
117                                        self.content_len = int(headers['Content-Length'])
118
119                                self.trailer = True
120                                # Add 4 because self.data.find("\r\n\r\n") does not count
121                                # "\r\n\r\n" for the length
122                                self.header_len = header_len + 4
123
124                if self.trailer and (len(self.data) >= self.content_len + self.header_len):
125                        request.parser(self.data)
126                        self.ogrest.process_request(request, self)
127                        self.cleanup()
128
129        def disconnect(self):
130                self.state = State.FORCE_DISCONNECTED
131                self.sock.shutdown(socket.SHUT_RDWR)
132                self.sock.close()
133
134        def run(self):
135                while 1:
136                        sock = self.get_socket()
137                        state = self.get_state()
138
139                        if state == State.CONNECTING:
140                                readset = [ sock ]
141                                writeset = [ sock ]
142                        elif state == State.FORCE_DISCONNECTED:
143                                return 0
144                        else:
145                                readset = [ sock ]
146                                writeset = [ ]
147
148                        readable, writable, exception = select.select(readset, writeset, [ ])
149                        if state == State.CONNECTING and sock in writable:
150                                self.connect2()
151                        elif state == State.RECEIVING and sock in readable:
152                                self.receive()
153                        else:
154                                print('wrong state, not ever happen!' + str(state))
Note: See TracBrowser for help on using the repository browser.