PageRenderTime 80ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 1ms

/gnsocket/gn_socket.py

https://gitlab.com/pineiden/gus
Python | 969 lines | 921 code | 15 blank | 33 comment | 5 complexity | 6dbfc588e4cb878f9455cf130a96cfcc MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. # Echo server program
  3. import os
  4. import socket
  5. import asyncio
  6. import errno
  7. import math
  8. import re
  9. import ssl
  10. from pathlib import Path
  11. from basic_logtools.filelog import LogFile
  12. from asyncio import shield, wait_for, Task
  13. # These values are constant
  14. try:
  15. from conf.socket_conf import AF_TYPE, SOCK_TYPE
  16. from conf.socket_conf import HEADER
  17. from conf.socket_conf import ENDER
  18. from conf.socket_conf import sock
  19. from conf.socket_conf import gnc_path
  20. from conf.socket_conf import t_out
  21. from conf.socket_conf import buffsize
  22. from conf.socket_conf import uin
  23. from conf.socket_conf import char_code
  24. from conf.socket_conf import n_listen
  25. from conf.socket_conf import address
  26. except Exception:
  27. from .conf.socket_conf import AF_TYPE, SOCK_TYPE
  28. from .conf.socket_conf import HEADER
  29. from .conf.socket_conf import ENDER
  30. from .conf.socket_conf import sock
  31. from .conf.socket_conf import gnc_path
  32. from .conf.socket_conf import t_out
  33. from .conf.socket_conf import buffsize
  34. from .conf.socket_conf import uin
  35. from .conf.socket_conf import char_code
  36. from .conf.socket_conf import n_listen
  37. from .conf.socket_conf import address
  38. from networktools.library import (pattern_value,
  39. fill_pattern,
  40. context_split,
  41. gns_loads,
  42. gns_dumps,
  43. my_random_string,
  44. complete_nro,
  45. hextring,
  46. hextring2int)
  47. from networktools.colorprint import gprint, bprint, rprint
  48. from networktools.time import now, timestamp
  49. from networktools.path import home_path
  50. from rich import print
  51. # Asyncio guide:
  52. # http://www.snarky.ca/how-the-heck-does-async-await-work-in-python-3-5
  53. # More ref about socket:
  54. # http://stackoverflow.com/questions/27014955/socket-connect-vs-bind
  55. # example:
  56. # Best example: https://gist.github.com/jamilatta/7603968
  57. # from scheduler import ReadWait, WriteWait
  58. import uuid
  59. import chardet
  60. from datetime import datetime, timedelta
  61. from dataclasses import field, dataclass
  62. from typing import Callable, Dict, List
  63. MSG_STRUCT = b"IDX hex(PAGE)/hex(TOT_PAGES) MSG hex(LEN) MSG END"
  64. MSG_TEMPLATE = "{idx} {page}/{tot_pages} MSG {length} MSG END"
  65. MSG_SPACES = [x.start() for x in re.finditer(b' ', MSG_STRUCT)]
  66. @dataclass
  67. class GNCSocket:
  68. gnc_path: Path = gnc_path
  69. mode: str = "server"
  70. buffsize: int = 1024
  71. timeout: int = 5
  72. raise_timeout: bool = True
  73. backlog: int = 100
  74. ssl: bool = False
  75. host: str = 'localhost'
  76. port: int = 6666
  77. uin: int = 6
  78. header: str = HEADER
  79. ender: str = ENDER
  80. msg_struct: str = MSG_STRUCT
  81. msg_template: str = MSG_TEMPLATE
  82. msg_spaces: str= field(default_factory=lambda:MSG_SPACES)
  83. AF_TYPE: socket = AF_TYPE
  84. report:Callable = field(default_factory=lambda:print)
  85. log_path:Path = Path.home()/'log/socket_log'
  86. log_level:str = 'ERROR'
  87. """
  88. This class allows you to enable a socket to communicate among different process or terminals.
  89. Define a protocol that take a string of bytes and slice in an amount of parts related to the
  90. *buffsize* parameter.
  91. You can select the *mode* to use this class: like a server to *listen* connections or like a client to *connect* to some source.
  92. Also, if you need security, set the ssl parameter to True.
  93. The *backlog* parameter aludes to the queued connections to the server.
  94. Socket class for GNC
  95. Create or connect to an UNIX/TCP socket
  96. Methods:
  97. * connect
  98. * send_msg
  99. * recv_msg
  100. * server
  101. * client
  102. """
  103. def __post_init__(self):
  104. if self.ssl:
  105. self.set_ssl(**kwargs)
  106. else:
  107. self.context = None
  108. # self.set_logger()
  109. self.status = False
  110. self.idx = []
  111. self.conns = []
  112. self.addrs = []
  113. self.msg_r = ''
  114. # asyncio coroutines
  115. self.alert = ""
  116. self.loop = ''
  117. self.mq = {}
  118. # message queues
  119. self.clients = {}
  120. self.idc = []
  121. self.server = object
  122. # a fn to print or show on some other screen
  123. #
  124. # new client queue: if a new client is created, then give
  125. # the idc value to heart_beat assigned to this client
  126. self.new_client_queue = asyncio.Queue()
  127. #
  128. self.logger = LogFile(self.class_name,
  129. self.mode,
  130. "_".join(map(str,self.address)),
  131. path=self.log_path,
  132. base_level=self.log_level)
  133. self.queue_socket_status = None
  134. self.active_conn = {}
  135. self.relation = {}
  136. self.closing = {}
  137. @property
  138. def address(self):
  139. if AF_TYPE == socket.AF_UNIX:
  140. if self.gnc_path.exists(self.gnc_path):
  141. self.gnc_path.remove()
  142. return self.gnc_path
  143. return (self.host, self.port)
  144. def off_new_client(self, key):
  145. if key in self.active_conn.keys():
  146. self.active_conn[key]=False
  147. def on_new_client(self, key):
  148. if key in self.active_conn.keys():
  149. self.active_conn[key]=True
  150. def new_client(self, key):
  151. return self.active_conn.get(key)
  152. def set_new_client(self, key):
  153. self.active_conn[key]=True
  154. @property
  155. def class_name(self):
  156. return self.__class__.__name__
  157. def set_queue_socket_status(self, queue):
  158. self.queue_socket_status = queue
  159. def set_ssl(self, **kwargs):
  160. purpose_key = kwargs.get('ssl_protocol', 'tls')
  161. self.protocols = {
  162. 'tls': ssl.PROTOCOL_SSLv23,
  163. }
  164. self.protocol = self.protocols.get(purpose_key, ssl.PROTOCOL_SSLv23)
  165. self.set_certs = kwargs.get('set_certificates',
  166. {'cafile': None,
  167. 'capath': None,
  168. 'cadata': None,
  169. 'crtkey': None})
  170. data_ssl = {}
  171. data_ssl.update(self.set_certs)
  172. self.ssl_context(self.protocol, data_ssl)
  173. def ssl_context(self, protocol, data_ssl):
  174. self.context = ssl.SSLContext(protocol)
  175. crt = data_ssl.get('cafile')
  176. key = data_ssl.get('crtkey')
  177. if self.mode == 'server':
  178. self.context.load_cert_chain(crt, key)
  179. elif self.mode == 'client':
  180. path = data_ssl.get('cadata')
  181. data = data_ssl.get('capath')
  182. self.context.load_verify_locations(crt, path, data)
  183. print("SSL Settings end")
  184. def send_msg_sock_status(self, value):
  185. msg = {'command': 'socket_bar',
  186. 'status': value}
  187. if self.queue_socket_status:
  188. self.queue_socket_status.put(msg)
  189. self.queue_socket_status.join()
  190. def set_status(self, value):
  191. if value in [True, False]:
  192. self.status = value
  193. else:
  194. print("Status don't change")
  195. # self.logger.info("Se crea modifica status a %s" %value)
  196. def switch_status(self):
  197. self.status = not self.status
  198. # self.logger.info("Se crea modifica status a %s" %self.status)
  199. def get_status(self):
  200. return self.status
  201. def set_loop(self, loop):
  202. print(format(loop))
  203. self.loop = loop
  204. def get_writer(self, idc):
  205. return self.clients[idc]['writer']
  206. def get_reader(self, idc):
  207. return self.clients[idc]['reader']
  208. def generate_msg(self, msg: str):
  209. # self.msg_struct = b"IDX hex(PAGE)/hex(TOT_PAGES) MSG hex(LEN) MSG END"
  210. # self.msg_tempalte = b"{header} {page}/{tot_pages} MSG {length} MSG END"
  211. b_msg = msg.encode(char_code)
  212. T_LEN = len(b_msg)
  213. # Cantidad de caracteres en hexadecimal
  214. hex_T_LEN = hextring(T_LEN)
  215. # Se obtiene el largo de caracteres como
  216. # cota superior de largo de mensaje
  217. # A utilizar en paginacion
  218. # largo del valor
  219. # n_char es lo mismo
  220. new_n = len(hex_T_LEN)
  221. self.n_char = new_n
  222. # obtener el largo base del mensaje
  223. self.base_len = len(self.header) + len(self.ender) + \
  224. len(self.msg_spaces) + self.uin + 3 * self.n_char + 1
  225. # n_char is the amount of chars for numbers
  226. # tha last +1 is for the space after IDX
  227. # Largo de pedazo de mensaje a enviar por partes
  228. self.len_msg = self.buffsize - self.base_len
  229. assert self.len_msg >= 1, "Debes definir un buffsize de mayor tamaño"
  230. assert new_n + 1 < self.len_msg, "No es posible enviar mensaje"
  231. # Cantidad maxima de mensajes a enviar
  232. n_msgs = math.ceil(T_LEN / self.len_msg)
  233. # transformar a hex y sacar string
  234. hex_n_msgs = hextring(n_msgs)
  235. # Cantidad de paginas
  236. self.N_n_msgs = len(str(hex_n_msgs))
  237. # hex_nmsgs = str(hex(n_msgs)).split('x')[1]
  238. ender = self.ender.encode(char_code)
  239. # Se construye: hex(PAGE)/hex(TOT_PAGES) MSG hex(LEN) MSG END
  240. NON = "".encode(char_code)
  241. head_template = "{header} {page}/{tot_pages} {length} "
  242. msg_ender = " END"
  243. if n_msgs > 1:
  244. for i in range(n_msgs):
  245. # Construir header:
  246. # Conocer parte de msg a enviar
  247. # Conocer largo de msg_i
  248. # Cantidad carácteres largo
  249. step = i * self.len_msg
  250. this_page = hextring(i + 1)
  251. msg_i = b_msg[step:step + self.len_msg]
  252. msg_l = len(msg_i)
  253. # +2 erased because quoted don't go
  254. msg_len = msg_l + len(ender)
  255. # print("MSG to send -> Encoded by" , the_encoding)
  256. componentes = {
  257. 'header': self.header,
  258. 'page': complete_nro(this_page, n=new_n),
  259. 'tot_pages': complete_nro(hex_n_msgs, n=new_n),
  260. 'length': complete_nro(hextring(msg_len), n=new_n)
  261. }
  262. msg_header = head_template.format(**componentes)
  263. this_msg = NON.join([msg_header.encode(char_code),
  264. msg_i,
  265. msg_ender.encode(char_code)])
  266. #bprint("Generated msg Encoded by")
  267. # rprint(this_msg)
  268. yield this_msg
  269. elif n_msgs == 1:
  270. this_page = hextring(1)
  271. msg_len = (T_LEN + len(ender))
  272. hex_msg_len = complete_nro(hextring(msg_len), n=new_n)
  273. componentes = {
  274. 'header': self.header,
  275. 'page': complete_nro(this_page, n=new_n),
  276. 'tot_pages': complete_nro(hextring(1), n=new_n),
  277. 'length': complete_nro(hextring(msg_len), n=new_n)
  278. }
  279. msg_header = head_template.format(**componentes)
  280. this_msg = NON.join([msg_header.encode(char_code),
  281. b_msg,
  282. msg_ender.encode(char_code)])
  283. #print("Generated msg Encoded by" , the_encoding)
  284. yield this_msg
  285. def gen_idx(self):
  286. IDX = my_random_string(self.uin)
  287. t = True
  288. while t:
  289. if IDX not in self.idx:
  290. self.idx.append(IDX)
  291. t = False
  292. else:
  293. IDX = my_random_string(self.uin)
  294. return IDX
  295. async def send_msg(self, msg, id_client):
  296. writer = self.clients.get(id_client).get('writer')
  297. # tot = self.N_n_msgs
  298. try:
  299. if writer.transport.is_closing():
  300. # self.logger.error("La conexión se cerró %s" % self.status)
  301. raise Exception("Conexión perdida")
  302. # assert tot == len(msg), "Hay un cruce de mensajes"
  303. pre = datetime.now()
  304. await shield(self.send_text(msg, writer))
  305. delta= datetime.now()-pre
  306. bprint("Sended msg %sin %s" %(msg,delta.total_seconds()))
  307. await shield(self.send_text('<END>', writer))
  308. except asyncio.CancelledError as ex:
  309. bprint("Cancelled error en send_msg")
  310. self.logger.exception("Hubo una excepción, error de cancelación con modulo asyncio %s" % self.status)
  311. raise ex
  312. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  313. rprint("Error de conexion")
  314. self.logger.exception("Excepción por desconexión %s, mode %s"%(
  315. conn_error,self.mode))
  316. await asyncio.sleep(10)
  317. raise conn_error
  318. except socket.error as ex:
  319. bprint("Socket error en send msg")
  320. self.logger.exception("Hubo una excepción, error en socket %s" % self.status)
  321. await asyncio.sleep(10)
  322. raise ex
  323. except Exception as ex:
  324. bprint("Excpecion desconocida send_msg")
  325. self.set_status(False)
  326. await asyncio.sleep(10)
  327. self.logger.exception("Hubo una excepción %s" % self.status)
  328. raise ex
  329. except asyncio.TimeoutError as te:
  330. bprint("Send-msg timeouterror")
  331. self.logger.exception(
  332. "Hubo una excepción, error de timeout con modulo asyncio %s" %te)
  333. raise te
  334. async def send_text(self, msg, writer):
  335. IDX = self.gen_idx().encode(char_code)
  336. for b_msg in self.generate_msg(msg):
  337. to_send = b"".join([IDX, b" ", b_msg])
  338. if writer.get_extra_info('peername'):
  339. writer.write(to_send)
  340. await writer.drain()
  341. else:
  342. writer.write_eof()
  343. await writer.close()
  344. def get_extra_info(self, idc):
  345. writer = self.clients.get(idc).get('writer')
  346. return writer.get_extra_info('peername')
  347. def send_eof(self, id_client):
  348. writer = self.clients.get(id_client).get('writer')
  349. writer.write_eof()
  350. def abort(self, id_client):
  351. writer = self.clients.get(id_client).get('writer')
  352. writer.abort()
  353. def at_eof(self, id_client):
  354. reader = self.clients.get(id_client).get('reader')
  355. return reader.at_eof()
  356. def feed_eof(self, id_client):
  357. reader = self.clients.get(id_client).get('reader')
  358. reader.feed_eof()
  359. async def heart_beat(self, idc, *args, **kwargs):
  360. sleep = kwargs.get('sleep', 2)
  361. await asyncio.sleep(sleep)
  362. client_name = kwargs.get('client_name')
  363. tnow = now()
  364. idc = self.relation.get(client_name)
  365. reader = self.clients.get(idc,{}).get('reader')
  366. writer = self.clients.get(idc,{}).get('writer')
  367. if idc in self.clients.keys() and reader and writer:
  368. await asyncio.sleep(.5)
  369. closing = writer.is_closing()
  370. extra_info = writer.get_extra_info('peername')
  371. at_eof = reader.at_eof()
  372. self.report("test hb",not closing and extra_info and not at_eof)
  373. if not closing and extra_info and not at_eof:
  374. kwargs.update({"result":True, "msg":"idc exists ok"})
  375. return [idc, *args], kwargs
  376. else:
  377. msg_error = "Closing %s, extra_info %s, at_eof %s" %(closing, extra_info,at_eof)
  378. self.report("heartbeat", "msgerror "+msg_error)
  379. self.logger.error(msg_error)
  380. self.logger.error("no heart_beat, at %s" %tnow)
  381. print("IDC To close", idc)
  382. try:
  383. await self.close(idc)
  384. self.on_new_client(client_name)
  385. print("Conexiones activas", self.active_conn)
  386. except BrokenPipeError as be:
  387. self.report("heart_beat","Close->Broken Pipe Error al cerrar %s bytes" %(be))
  388. self.logger.exception("Socket error %s, mode %s"%(e, self.mode))
  389. await asyncio.sleep(1)
  390. self.on_new_client(client_name)
  391. await asyncio.sleep(2)
  392. except socket.error as e:
  393. self.report("heart_beat","Socket error, <%s>, client"%(e, client_name))
  394. self.logger.exception("Socket error %s, mode %s"%(e, self.mode))
  395. await asyncio.sleep(1)
  396. self.on_new_client(client_name)
  397. await asyncio.sleep(2)
  398. except asyncio.TimeoutError as te:
  399. self.logger.exception("Tiempo fuera en intento de cerrar conexión %s, mode %s" %(te, self.mode))
  400. self.on_new_client(client_name)
  401. await asyncio.sleep(2)
  402. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  403. self.logger.exception("Excepción por desconexión %s, mode %s"%(conn_error, self.mode))
  404. self.on_new_client(client_name)
  405. await asyncio.sleep(2)
  406. except Exception as e:
  407. self.report("heart_beat","Excepción no considerada, <%s>"%e)
  408. self.logger.exception("Excepción no considerada %s, mode %s"%(e, self.mode))
  409. await asyncio.sleep(1)
  410. self.on_new_client(client_name)
  411. await asyncio.sleep(2)
  412. self.logger.exception("Cerrando correctamente la conexión, por no heartbeat")
  413. self.status = False
  414. kwargs.update({"result":True, "msg":"idc exists ok"})
  415. return [idc, *args], kwargs
  416. else:
  417. self.logger.error("no heart_beat, idc %s not client, mode %s" % (idc, self.mode))
  418. return [idc, *args], kwargs
  419. async def readbytes(self, reader, n, idc, origin="none"):
  420. future = reader.readexactly(n)
  421. try:
  422. if not self.closing.get(idc):
  423. result = await future
  424. return result
  425. except BrokenPipeError as be:
  426. self.report("readbytes","Close->Broken Pipe Error al cerrar %s bytes" %(be))
  427. await asyncio.sleep(5)
  428. return b''
  429. except socket.error as se:
  430. self.report("readbytes","Close->Socket Error al leer %s bytes" %(se))
  431. await asyncio.sleep(5)
  432. return b''
  433. except asyncio.TimeoutError as te:
  434. self.report("readbytes","Error Timeout al leer %d bytes en %s, origen: %s" %(n, self.mode, origin))
  435. self.logger.exception("Mode %s, Tiempo fuera al leer en readbytes, %s, origen %s"%(self.mode,te,
  436. origin))
  437. await asyncio.sleep(5)
  438. return b''
  439. except asyncio.IncompleteReadError as ir:
  440. self.report("readbytes","Incomplete read, mode %s" %self.mode, reader, n)
  441. self.logger.exception("Mode %s, Tiempo fuera al no poder leer en readbytes %s bytes, %s"%(n, self.mode,ir))
  442. await asyncio.sleep(5)
  443. return b''
  444. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  445. self.logger.exception("Excepción por desconexión al intentar leer %s"%conn_error)
  446. await asyncio.sleep(5)
  447. return b''
  448. except Exception as e:
  449. self.report("readbytes","Excepción no considerada", e)
  450. self.logger.exception("Excepción no considerada al intentar leer%s"%e)
  451. await asyncio.sleep(5)
  452. return b''
  453. async def recv_msg(self, id_client):
  454. if id_client in self.clients:
  455. reader = self.clients[id_client]['reader']
  456. writer = self.clients[id_client]['writer']
  457. #heartbeat = await self.heart_beat(id_client)
  458. # addr = self.addr
  459. bs_0 = 1
  460. count = 0
  461. b_header = b''
  462. idx_recv = ''
  463. t = True
  464. msg_tot = b''
  465. mlist = []
  466. n_msgs_idx = 0
  467. try:
  468. # moment 1 -> get hueader
  469. if writer.transport.is_closing():
  470. # self.logger.error("La conexión se cerró %s" % writer)
  471. raise Exception("Conexión perdida")
  472. idx_recv = ''
  473. page = [0, 0]
  474. while t:
  475. while count < 4:
  476. if not reader.at_eof():
  477. char_recv = None
  478. # moment 2 -> get content message, check if there are more
  479. try:
  480. char_recv = await shield(self.readbytes(reader, bs_0,
  481. id_client,origin="recv_msg_header"))
  482. except asyncio.TimeoutError as te:
  483. self.logger.exception("Tiempo fuera en intento de cerrar conexión %s, mode %s" %(
  484. te, self.mode))
  485. await asyncio.sleep(10)
  486. continue
  487. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  488. self.logger.exception("Excepción por desconexión %s, mode %s"%(
  489. conn_error, self.mode))
  490. await asyncio.sleep(10)
  491. continue
  492. except Exception as ex:
  493. self.report("recv_msg","Error al leer data -> %s" % ex, char_recv)
  494. continue
  495. else:
  496. ex = reader.exception()
  497. await asyncio.sleep(1)
  498. print("Excepcion de lectura -> EOF")
  499. b_header += char_recv
  500. # cuando ocurre un espacio, sumar count
  501. # de otra manera continuar iteración
  502. if char_recv == b" ":
  503. count += 1
  504. header = b_header.decode(char_code)
  505. b_header = b''
  506. spaces = [x.start() for x in re.finditer(' ', header)]
  507. sp_1 = spaces[0]
  508. sp_2 = spaces[1]
  509. sp_3 = spaces[2]
  510. # obtener número de página
  511. s_page = header[sp_2 + 1:sp_3].split("/")
  512. a = page[0]
  513. b = page[1]
  514. page = list(map(hextring2int, s_page))
  515. sp_4 = spaces[3]
  516. check_header = header[sp_1 + 1:sp_2]
  517. assert self.header == header[sp_1 + 1:
  518. sp_2], "No es un encabezado correcto"
  519. this_idx_recv = header[:sp_1]
  520. if idx_recv == '':
  521. idx_recv = this_idx_recv
  522. n_msgs_idx = 1
  523. else:
  524. n_msgs_idx += 1
  525. assert n_msgs_idx == page[
  526. 0], "Error en mensaje, no coincide #idx con pagina " + str(
  527. page[0])
  528. lmsg = header[sp_3 + 1:sp_4]
  529. bs_1 = hextring2int(lmsg)+1
  530. b_MSG = b''
  531. n = 0
  532. while n < bs_1:
  533. bm = None
  534. # moment 2 -> get content message, check if there are more
  535. try:
  536. bm = await shield(self.readbytes(reader, 1, id_client, origin="recv_msg_body"))
  537. except asyncio.TimeoutError as te:
  538. self.logger.exception("Tiempo fuera en intento de cerrar conexión %s, mode %s" %(
  539. te, self.mode))
  540. await asyncio.sleep(10)
  541. continue
  542. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  543. self.logger.exception("Excepción por desconexión %s, mode %s"%(
  544. conn_error, self.mode))
  545. await asyncio.sleep(10)
  546. continue
  547. except Exception as ex:
  548. self.logger.exception("Error al leer datos %s, con %s" %(ex, b_MSG))
  549. print("Error en conexión excepction:<%s>" % ex)
  550. print("Mensaje....", bm)
  551. continue
  552. if bm:
  553. b_MSG += bm
  554. n += 1
  555. l_ender = len(self.ender.encode(char_code))
  556. nlast = b_MSG.rfind(b" ")
  557. pre_msg = b_MSG[:nlast]
  558. count = 0
  559. if pre_msg == b"<END>" or page[0] == page[1]:
  560. t = False
  561. mlist.append(pre_msg)
  562. n_msgs_idx = 0
  563. break
  564. else:
  565. mlist.append(pre_msg)
  566. except asyncio.CancelledError as ex:
  567. self.logger.exception("Error de conexión cancelada %s" %ex)
  568. self.report("recv_msg","Asyncio cancelación de conexión <%s>"%ex)
  569. except socket.error as ex:
  570. self.logger.exception("Error de conexión de socket %s" %ex)
  571. self.report("recv_msg","Error de socket")
  572. await asyncio.sleep(3)
  573. self.report("recv_msg","Falla en la conexión al recibir mensaje, %s"%ex)
  574. except Exception as ex:
  575. await asyncio.sleep(3)
  576. self.logger.exception("Error de conexión %s" %ex)
  577. self.report("recv_msg","Falla en la conexión al recibir mensaje, %s"%ex)
  578. self.report("recv_msg","Lista msgs", mlist)
  579. #print("Procesando final")
  580. msg_tot = b"".join(mlist)
  581. MSG_TOT = msg_tot.decode(char_code)
  582. MT = MSG_TOT.strip()
  583. MT = MSG_TOT.rstrip()
  584. self.msg_r = MSG_TOT
  585. return MSG_TOT
  586. else:
  587. return None
  588. def get_path(self):
  589. return self.gnc_path
  590. def get_address(self):
  591. return self.address
  592. def set_address(self, address):
  593. self.address = address
  594. def set_path(self, new_gnc_path):
  595. if os.path.exists(new_gnc_path):
  596. os.remove(new_gnc_path)
  597. self.gnc_path = new_gnc_path
  598. # callback for create server:
  599. def set_idc(self):
  600. """
  601. Defines a new id for relation process-collect_task, check if exists
  602. """
  603. uin = 4
  604. idc = my_random_string(uin)
  605. while True:
  606. if idc not in self.idc:
  607. self.idc.append(idc)
  608. break
  609. else:
  610. idc = my_random_string(uin)
  611. return idc
  612. async def set_reader_writer(self, reader, writer):
  613. idc = self.set_idc()
  614. # self.log_info_client(writer)
  615. new_client = {
  616. 'reader': reader,
  617. 'writer': writer
  618. }
  619. self.clients[idc]=new_client
  620. return idc
  621. def log_info_client(self, writer):
  622. names = ['peername', 'socket', 'sockname']
  623. for name in names:
  624. info = writer.get_extra_info(name)
  625. # self.loggger.info("La info correspondiente a %s es %s" %(name, info))
  626. def off_blocking(self):
  627. if self.mode == 'server':
  628. [sock.setblocking(False) for sock in self.server.sockets]
  629. elif self.mode == 'client':
  630. pass
  631. def on_blocking(self):
  632. if self.mode == 'server':
  633. [sock.setblocking(True) for sock in self.server.sockets]
  634. elif self.mode == 'client':
  635. pass
  636. def settimeout(self, timeout=5):
  637. [sock.settimeout(timeout) for sock in self.server.sockets]
  638. async def connect(self):
  639. """
  640. Connect client to socket
  641. """
  642. while not self.status:
  643. try:
  644. result = await self.loop.sock_connect(
  645. self.sock, self.address)
  646. self.alert = "Conectado a socket-base"
  647. self.status = True
  648. self.report("async connect","Resultado de conectar socket")
  649. print(result)
  650. # self.logger.info("Conexión a %s realizada" % self.address)
  651. break
  652. except socket.timeout as timeout:
  653. # self.on_blocking()
  654. # self.logger.error(
  655. # "Error en conexión con %s, error: %s" % (self.address, timeout))
  656. self.report("async connect","Error de socket a GSOF \
  657. en conexión %s, %s" % (self.address, timeout))
  658. self.status = False
  659. await asyncio.sleep(.5)
  660. await self.connect() # go to begin -|^
  661. except socket.error as e:
  662. self.status = False
  663. # self.on_blocking()
  664. if e.errno == errno.ECONNREFUSED:
  665. pass
  666. # self.logger.error(e)
  667. else:
  668. pass
  669. # self.logger.error(e)
  670. def clean_socket(self, host, port):
  671. comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  672. self.report("clean socket", "ex socket->ComSocket:::", comSocket)
  673. self.report("clean socket", socket.SOL_SOCKET, socket.SO_REUSEADDR)
  674. self.report("clean socket", socket.SOL_SOCKET, socket.SO_REUSEPORT)
  675. self.report("clean socket", "Cleaning address", (host, port))
  676. comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  677. comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  678. # comSocket.shutdown(socket.SHUT_RDWR)
  679. async def close(self, idc):
  680. self.closing[idc]=True
  681. self.report("close", "La conexión se cerró en cliente %s" % idc)
  682. self.logger.error("La conexión se cerró en cliente %s" % idc)
  683. self.status = False
  684. print(idc, self.clients)
  685. if idc in self.clients:
  686. reader = self.clients.get(idc,{}).get('reader')
  687. writer = self.clients.get(idc,{}).get('writer')
  688. try:
  689. if writer:
  690. if writer.can_write_eof():
  691. print("Closing idc client,,,,")
  692. writer.close()
  693. del self.clients[idc]
  694. print("Deleted idc de clients", idc, self.clients)
  695. except BrokenPipeError as be:
  696. self.report("close","Close->Broken Pipe Error al cerrar %s bytes" %(be))
  697. raise be
  698. except socket.error as se:
  699. self.report("close","Close->Socket Error al leer %s bytes" %(se))
  700. raise se
  701. except asyncio.TimeoutError as te:
  702. self.report("close","Close->Error Timeout al leer %d bytes" %(te))
  703. self.logger.exception("Tiempo fuera al leer en close, %s"%(te))
  704. except asyncio.IncompleteReadError as ir:
  705. self.report("close", "Close_>Incomplete read, reader %s" %reader)
  706. self.logger.exception("Station %s, Tiempo fuera al no poder leer en readbytes %s bytes, %s"%(n, self.station,ir))
  707. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  708. self.logger.exception("Close->Excepción por desconexión al intentar leer %s"%conn_error)
  709. raise conn_error
  710. except Exception as e:
  711. self.report("close", "Excepción no considerada", e)
  712. self.logger.exception("Close->Excepción no considerada al intentar leer%s"%e)
  713. raise e
  714. else:
  715. raise Exception("No existe %s"%idc)
  716. async def create_server(self, callback_io, loop):
  717. # SI ES UNIX SOCKET
  718. # includes bind
  719. # https://github.com/python/asyncio/blob/fff05d480760703adbc3e2d4cb3dbcfbff803c29/asyncio/unix_events.py
  720. bprint("loop runing before create server")
  721. self.report("create server",loop.is_running())
  722. mode = self.mode
  723. context = self.context
  724. self.report("create server", "Creando server---_>")
  725. self.report("create server", loop, mode, context, AF_TYPE)
  726. self.server = None
  727. try:
  728. if mode == 'server':
  729. if AF_TYPE == socket.AF_UNIX:
  730. self.report("create server", "Se crea Socket Server Unix")
  731. # ref https://docs.python.org/3/library/asyncio-eventloop.html
  732. future_server = asyncio.start_unix_server(callback_io,
  733. loop=loop,
  734. path=self.get_path(),
  735. limit=self.backlog,
  736. ssl=context)
  737. self.server = await asyncio.wait_for(future_server, timeout=self.timeout)
  738. elif AF_TYPE in {socket.AF_INET, socket.AF_INET6}:
  739. host = self.address[0]
  740. port = self.address[1]
  741. self.report("create server","Se crea Socket Server TCPx")
  742. self.report("create server","Cleaning address")
  743. self.clean_socket(host, port)
  744. self.report("create server","Closing cleaning address")
  745. self.report("create server","New server listening......")
  746. rprint(host)
  747. rprint(port)
  748. future_server = asyncio.start_server(
  749. callback_io,
  750. loop=loop,
  751. host=host,
  752. port=port,
  753. family=AF_TYPE,
  754. backlog=self.backlog,
  755. ssl=context)
  756. self.report("create server","Future coro to run server:::")
  757. rprint(future_server)
  758. self.server = await asyncio.wait_for(future_server, timeout=self.timeout)
  759. self.report("create server","(create_server works!)El server es")
  760. self.report("create server",loop)
  761. print(self.server, type(self.server))
  762. else:
  763. self.report("create server", "Asigna primero mode=server")
  764. except asyncio.TimeoutError as te:
  765. self.logger.exception("Tiempo fuera en intento de cerrar conexión %s, mode %s" %(
  766. te, self.mode))
  767. await asyncio.sleep(10)
  768. raise te
  769. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  770. self.logger.exception("Excepción por desconexión %s, mode %s"%(
  771. conn_error, self.mode))
  772. self.report("create server", "Excepcion error de conexión", conn_error)
  773. await asyncio.sleep(10)
  774. except Exception as ex:
  775. self.report("create server","Excepcion en create_server <::::", ex, "::::>")
  776. except asyncio.TimeoutError as te:
  777. self.report("create server","Timeout error", te)
  778. raise te
  779. self.status = 'OFF'
  780. return self.server
  781. async def create_client(self):
  782. mode = self.mode
  783. loop = self.loop
  784. self.send_msg_sock_status(20)
  785. reader,writer =(None,None)
  786. idc = ""
  787. while self.status!='ON':
  788. try:
  789. if mode == 'client':
  790. if AF_TYPE == socket.AF_UNIX:
  791. # ref https://docs.python.org/3/library/asyncio-eventloop.html
  792. future_unix_client = asyncio.open_unix_connection(
  793. loop=loop, path=self.get_path(), ssl=self.context)
  794. (reader, writer) = await asyncio.wait_for(future_unix_client, timeout=self.timeout)
  795. self.send_msg_sock_status(40)
  796. elif AF_TYPE == socket.AF_INET or AF_TYPE == socket.AF_INET6:
  797. host = self.address[0]
  798. port = self.address[1]
  799. print("La direccion es %s con tipo: %s " % (self.address,
  800. AF_TYPE))
  801. future_client = asyncio.open_connection(
  802. loop=loop,
  803. host=host,
  804. port=port,
  805. ssl=self.context)
  806. (reader, writer) = await asyncio.wait_for(future_client, timeout=self.timeout)
  807. self.send_msg_sock_status(40)
  808. idc = await self.set_reader_writer(reader, writer)
  809. self.report("create server","Cliente creado--->", idc)
  810. self.report("create server","Clientes", self.clients)
  811. self.send_msg_sock_status(50)
  812. self.alert = "Conectado a socket-base"
  813. self.status = 'ON'
  814. self.report("create server",self.alert)
  815. self.report("create server","Creando nuevo client")
  816. except asyncio.TimeoutError as te:
  817. self.logger.exception("Tiempo fuera en intento de cerrar conexión %s, mode %s" %(
  818. te, self.mode))
  819. self.report("create server", "Excepcion error de timeout", te)
  820. self.status = 'OFF'
  821. await asyncio.sleep(10)
  822. except (ConnectionResetError, ConnectionAbortedError) as conn_error:
  823. self.logger.exception("Excepción por desconexión %s, mode %s"%(
  824. conn_error, self.mode))
  825. await asyncio.sleep(10)
  826. self.status = 'OFF'
  827. except Exception as ex:
  828. self.report("create client","Excepcion en", ex)
  829. print("Creating new client?", self.new_client)
  830. self.send_msg_sock_status(-1)
  831. self.status = 'OFF'
  832. await asyncio.sleep(10)
  833. return idc
  834. def set_backlog(self, new_backlog):
  835. # ?
  836. assert isinstance(new_backlog,
  837. int), "El nuevo backlog no es un valor válido"
  838. self.backlog = new_backlog
  839. async def accept(self):
  840. conn, addr = await self.loop.sock_accept(self.server.sockets[0])
  841. self.conns.append(conn)
  842. self.addrs.append(addr)
  843. self.conn = conn
  844. self.addr = addr
  845. self.status = 'ON'
  846. return conn, addr
  847. def list_clients(self):
  848. for i in range(len(self.conss)):
  849. print(str(self.addrs[i]) + ":" + str(self.conns[i]))
  850. def clean_client(self, idc):
  851. self.report("clean_client","Limpiando cliente", idc)
  852. if idc in self.clients:
  853. client = self.clients.get(idc)
  854. client.get('writer').close()
  855. del self.clients[idc]
  856. async def wait_closed(self):
  857. for ids, client in self.clients.items():
  858. await client.get('writer').wait_closed()
  859. if self.mode == 'server' and self.server:
  860. await self.server.wait_closed()
  861. async def server(self):
  862. await self.create_server()
  863. async def client(self):
  864. return await self.create_client()
  865. # Connect to path
  866. def get_name(self):
  867. return self.gnc_path
  868. def __enter__(self):
  869. self.report("enter socket","Starting GNC Socket (enter)")
  870. return self
  871. def __exit__(self, exception_type, exception_value, traceback):
  872. bprint("="*20)
  873. self.report("enter socket","Enviando EOF al otro lado")
  874. self.report("enter socket","Clossing succesful, Socket exit->",
  875. exception_type, exception_value, traceback)
  876. self.report("enter socket","Socket exit -> traceback", traceback)
  877. self.report("enter socket","Closing GNC Socket")
  878. # self.close()
  879. self.report("enter socket","Socket closed")
  880. self.report("enter socket",self.loop)
  881. self.report("enter socket","Loop status |^")
  882. # self.loop.run_until_complete(self.wait_closed())
  883. self.report("enter socket", "="*20)