source: ogClient-Git/src/ogClient.py @ 1ab981a

Last change on this file since 1ab981a was fa0e48a, checked in by Jose M. Guisado <jguisado@…>, 3 years ago

#1065 Init event socket according to mode

Commit 700aa89ea99 introduced the use of getattr when getting event
socket to avoid errors in case it was not initialized.

Prefer to initialize accordingly inside the ogClient class constructor.

  • Property mode set to 100644
File size: 5.1 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
14from io import StringIO
15
16from src.restRequest import *
17from src.ogRest import *
18from enum import Enum
19
20class State(Enum):
21        CONNECTING = 0
22        RECEIVING = 1
23        FORCE_DISCONNECTED = 2
24
25class ogClient:
26        OG_PATH = '/opt/opengnsys/'
27
28        def __init__(self, config):
29                self.CONFIG = config
30
31                self.mode = self.CONFIG['opengnsys']['mode']
32                if self.mode not in {'virtual', 'live', 'linux', 'windows'}:
33                        raise ValueError('Mode not supported.')
34                if self.mode in {'linux', 'windows'}:
35                        self.event_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
36                        self.event_sock.setblocking(0)
37                        self.event_sock.bind(('127.0.0.1', 55885))
38                else:
39                        self.event_sock = None
40
41                if self.CONFIG['samba']['activate']:
42                        assert('user' in self.CONFIG['samba'])
43                        assert('pass' in self.CONFIG['samba'])
44
45                self.ip = self.CONFIG['opengnsys']['ip']
46                self.port = self.CONFIG['opengnsys']['port']
47                self.ogrest = ogRest(self.CONFIG)
48
49        def get_socket(self):
50                return self.sock
51
52        def get_event_socket(self):
53                return self.event_sock
54
55        def get_state(self):
56                return self.state
57
58        def send_event_hint(self, message):
59                try:
60                        event, action, user = message.split(" ")
61                        logging.warning("%s, %s, %s", event, action, user)
62                except:
63                        logging.warning("Error parsing session datagram")
64                        return
65
66                if (event != "session" or
67                    action not in ['start', 'stop'] or
68                    not user):
69                        logging.warning("Invalid value in session datagram: %s", message)
70
71                payload = jsonBody({'event': event, 'action': action, 'user': user})
72                response = restResponse(ogResponses.EARLY_HINTS, payload)
73                self.send(response.get())
74
75        def cleanup(self):
76                self.data = ""
77                self.content_len = 0
78                self.header_len = 0
79                self.trailer = False
80
81        def connect(self):
82                print('connecting...')
83                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
84                self.sock.setblocking(0)
85                self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
86                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
87                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30)
88                self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
89
90                self.state = State.CONNECTING
91                self.cleanup()
92
93                try:
94                        self.sock.connect((self.ip, self.port))
95                except socket.error as err:
96                        if err.errno == errno.EINPROGRESS:
97                                return
98                        elif err.errno == errno.ECONNREFUSED:
99                                return
100
101        def send(self, msg):
102                self.sock.send(bytes(msg, 'utf-8'))
103                return len(msg)
104
105        def connect2(self):
106                try:
107                        self.sock.connect((self.ip, self.port))
108                except socket.error as err:
109                        if err.errno == errno.EISCONN:
110                                print('connected')
111                                self.state = State.RECEIVING
112                        else:
113                                time.sleep(1)
114                                print('connection refused, retrying...')
115                                self.state = State.CONNECTING
116                                self.sock.close()
117                                self.connect()
118
119        def receive(self):
120                try:
121                        data = self.sock.recv(1024).decode('utf-8')
122                except socket.error as err:
123                        data = ''
124                        print('failed to received ' + str(err))
125
126                if len(data) == 0:
127                        self.sock.close()
128                        self.ogrest.kill_process()
129                        self.connect()
130                        return
131
132                self.data = self.data + data
133                request = restRequest()
134
135                if not self.trailer:
136                        header_len = self.data.find("\r\n\r\n")
137                        if header_len > 0:
138                                # https://stackoverflow.com/questions/4685217/parse-raw-http-headers
139                                request_line, headers_alone = self.data.split('\n', 1)
140                                headers = email.message_from_file(StringIO(headers_alone))
141
142                                if 'Content-Length' in headers.keys():
143                                        self.content_len = int(headers['Content-Length'])
144
145                                self.trailer = True
146                                # Add 4 because self.data.find("\r\n\r\n") does not count
147                                # "\r\n\r\n" for the length
148                                self.header_len = header_len + 4
149
150                if self.trailer and (len(self.data) >= self.content_len + self.header_len):
151                        request.parser(self.data)
152                        self.ogrest.process_request(request, self)
153                        self.cleanup()
154
155        def disconnect(self):
156                self.state = State.FORCE_DISCONNECTED
157                self.sock.shutdown(socket.SHUT_RDWR)
158                self.sock.close()
159
160        def run(self):
161                while 1:
162                        sock = self.get_socket()
163                        event_sock = self.get_event_socket()
164                        state = self.get_state()
165
166                        if state == State.CONNECTING:
167                                readset = [ sock ]
168                                writeset = [ sock ]
169                                exceptset = [ sock ]
170                        elif state == State.FORCE_DISCONNECTED:
171                                return 0
172                        else:
173                                readset = [ sock, event_sock ] if event_sock else [ sock ]
174                                writeset = [ ]
175                                exceptset = [ ]
176
177                        readable, writable, exception = select.select(readset, writeset, exceptset)
178                        if state == State.CONNECTING and sock in writable:
179                                self.connect2()
180                        elif state == State.RECEIVING and sock in readable:
181                                self.receive()
182                        elif state == State.CONNECTING and sock in exception:
183                                self.connect2()
184                        elif state == State.RECEIVING and event_sock in readable:
185                                message = event_sock.recv(4096).decode('utf-8').rstrip()
186                                self.send_event_hint(message)
187                        else:
188                                print('wrong state, not ever happen!' + str(state))
Note: See TracBrowser for help on using the repository browser.