__init__.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. #!/usr/bin/python3.5
  2. # Copyright 2017 Digital
  3. #
  4. # This file is part of DigiLib.
  5. #
  6. # DigiLib is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # DigiLib is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with DigiLib. If not, see <http://www.gnu.org/licenses/>.
  18. import logging
  19. import logging.handlers
  20. import os
  21. import queue
  22. import select
  23. import socket
  24. import sys
  25. import threading
  26. import time
  27. import traceback
  28. import trio
  29. lclient = logging.getLogger(__name__+".client")
  30. lserver = logging.getLogger(__name__+".server")
  31. lchat = logging.getLogger(__name__+".chat")
  32. class ConnHandlerBase(object):
  33. def __init__(self, socket, addr, server):
  34. self.status = "init"
  35. super(ConnHandlerBase, self).__init__()
  36. self.socket = socket
  37. self.addr = addr
  38. self.server = server
  39. self.block_size = 1024
  40. self.welcome_client()
  41. self.status="connected"
  42. def welcome_client(self):
  43. pass
  44. def handle(self, data_decoded):
  45. return
  46. def recv(self):
  47. try:
  48. data_received = self.socket.recv(self.block_size)
  49. data_decoded = data_received.decode("utf-8")
  50. if data_decoded:
  51. lchat.info(data_decoded.strip())
  52. self.handle(data_decoded)
  53. return True
  54. else:
  55. lserver.debug("connection corrupted")
  56. return False
  57. except Exception as e:
  58. lserver.error(e, exc_info=True)
  59. return False
  60. def send(self, msg):
  61. msg_encoded = bytes(msg, "utf-8")
  62. lchat.info("Server:"+msg)
  63. try:
  64. self.socket.send(msg_encoded)
  65. return True
  66. except Exception as e:
  67. lserver.error(e, exc_info=True)
  68. return False
  69. def close(self):
  70. self.status = "closed"
  71. try:
  72. self.socket.shutdown(0)
  73. except:
  74. lserver.error("error during socket shutdown, ignoring")
  75. try:
  76. self.socket.close()
  77. except:
  78. lserver.error("error closing socket, maybe already closed")
  79. class ConnHandlerEcho(ConnHandlerBase):
  80. def __init__(self, socket, addr, server):
  81. self.status = "init"
  82. self.super_class = super(ConnHandlerEcho, self)
  83. self.super_class.__init__(socket, addr, server)
  84. self.server = server
  85. def welcome_client(self):
  86. self.send("welcome to the client")
  87. def handle(self, data_decoded):
  88. lchat.info("Client:"+data_decoded)
  89. for h in list(set(self.server.connection_handler)-{self}):
  90. h.send(data_decoded)
  91. class Server(object):
  92. """docstring for SocketHandler"""
  93. def __init__(self,
  94. host,
  95. port=None,
  96. af_family="AF_INET",
  97. max_allowed_clients=5,
  98. handler=None,
  99. handler_kwargs={},
  100. ):
  101. super(Server, self).__init__()
  102. self.exit_event = False
  103. self.host=host
  104. self.port=port
  105. self.af_family = af_family
  106. self.handler_kwargs = handler_kwargs
  107. self.handler = handler
  108. self.max_allowed_clients = max_allowed_clients
  109. self.socket = self.make_socket()
  110. self.connection_handler = []
  111. self.conn_to_addr = {}
  112. self.addr_to_conn = {}
  113. self.conn_to_handler ={}
  114. self.handler_to_conn = {}
  115. self.read_sockets_expected = [self.socket]
  116. self.write_sockets_expected = []
  117. self.exc_sockets_expected = []
  118. def make_socket(self):
  119. lserver.debug("making a {} socket".format(self.af_family))
  120. if self.af_family == "AF_INET":
  121. return socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  122. elif self.af_family == "AF_UNIX":
  123. return socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
  124. else:
  125. raise ValueError(
  126. "AF_FAMILY '{}' not supported!".format(
  127. self.af_family
  128. )
  129. )
  130. def make_handler(self, conn, addr):
  131. return self.handler(conn, addr, self, **self.handler_kwargs)
  132. def register_conn(self, conn, addr):
  133. lserver.info(
  134. "New Connection, addr: '{}', socket: '{}'".format(addr,conn)
  135. )
  136. self.read_sockets_expected.append(conn)
  137. if addr:
  138. self.conn_to_addr[conn] = addr
  139. self.addr_to_conn[addr] = conn
  140. def unregister_conn(self, conn):
  141. self.read_sockets_expected.remove(conn)
  142. addr = self.conn_to_addr.get(conn, False)
  143. if addr:
  144. del self.addr_to_conn[addr]
  145. del self.conn_to_addr[conn]
  146. def register_handler(self, handler, conn):
  147. self.connection_handler.append(handler)
  148. self.conn_to_handler[conn] = handler
  149. self.handler_to_conn[handler] = conn
  150. def unregister_handler(self, handler, conn):
  151. self.connection_handler.remove(handler)
  152. del self.conn_to_handler[conn]
  153. del self.handler_to_conn[handler]
  154. def setup(self):
  155. lserver.info("setting up socket")
  156. if self.af_family == "AF_INET":
  157. self.socket.bind((self.host, self.port))
  158. elif self.af_family == "AF_UNIX":
  159. if os.path.exists(self.host):
  160. lserver.debug("file already exists")
  161. lserver.debug("attempting to remove it")
  162. os.remove(self.host)
  163. self.socket.bind(self.host)
  164. self.socket.listen(self.max_allowed_clients)
  165. # self.socket.settimeout(1)
  166. def run(self):
  167. self.setup()
  168. lserver.debug("entering main loop")
  169. while ( not self.exit_event ):
  170. # lserver.debug(self.read_sockets_expected)
  171. # lserver.debug(self.write_sockets_expected)
  172. # lserver.debug(self.exc_sockets_expected)
  173. read_sockets_confirmed, \
  174. write_sockets_confirmed, \
  175. exc_sockets_confirmed \
  176. = select.select(self.read_sockets_expected,
  177. self.write_sockets_expected,
  178. self.exc_sockets_expected,
  179. )
  180. for s in read_sockets_confirmed:
  181. socket_handler = self.conn_to_handler.get(s, None)
  182. if ( s == self.socket ):
  183. lserver.debug("handling new client")
  184. conn, addr = self.socket.accept()
  185. handler = self.make_handler(conn, addr)
  186. self.register_conn(conn, addr)
  187. self.register_handler(handler, conn)
  188. elif ( socket_handler
  189. and (socket_handler in self.connection_handler) ):
  190. lserver.debug("handling client connection")
  191. try:
  192. if not socket_handler.recv():
  193. lserver.info("connection is broken, closing socket and removing it")
  194. self.unregister_handler(socket_handler, s)
  195. self.unregister_conn(conn)
  196. socket_handler.close()
  197. except Exception as e:
  198. lserver.error(e, exc_info=True)
  199. else:
  200. lserver.debug("else!")
  201. lserver.debug(socket_handler)
  202. time.sleep(1)
  203. def cleanup(self):
  204. pass
  205. class Client(threading.Thread):
  206. """docstring for Client"""
  207. is_connecting = False
  208. is_connected = False
  209. status = "uninitialized"
  210. def __init__(self,
  211. host,
  212. port=None,
  213. af_family="AF_INET",
  214. handle_data_func=None,
  215. error_handler=None,
  216. block_size=1024,
  217. ):
  218. self.super_class = super(Client, self)
  219. self.super_class.__init__()
  220. self.name = "Client"
  221. self.exit_event = False
  222. self.host = host
  223. self.port = port
  224. self.af_family = af_family
  225. self.block_size = block_size
  226. self.handle_data_func = handle_data_func
  227. self.is_connected = False
  228. self.error_handler = error_handler
  229. # self.socket = self.make_socket()
  230. self.socket = None
  231. self.status = "disconnected"
  232. def connect(self):
  233. self.status = "connecting"
  234. self.socket = self.make_socket()
  235. lclient.info(
  236. "connecting to socket '{}' of type {}".format(
  237. self.host,
  238. self.af_family
  239. )
  240. )
  241. try:
  242. if self.af_family == "AF_INET":
  243. self.socket.connect((self.host, self.port))
  244. elif self.af_family == "AF_UNIX":
  245. if os.path.exists(self.host):
  246. self.socket.connect(self.host)
  247. else:
  248. lclient.warn("File not found. Aborting.")
  249. return
  250. self.is_connected = True
  251. self.status = "connected"
  252. lclient.info("connected")
  253. return True
  254. except Exception as e:
  255. lclient.debug(e, exc_info=True)
  256. if type(e) is ConnectionRefusedError:
  257. lclient.info("failed to connect to socket '{}'".format(self.host))
  258. self.disconnect()
  259. return False
  260. def disconnect(self):
  261. lclient.info("disconnecting from socket '{}'".format(self.host))
  262. self.is_connected = False
  263. self.status = "disconnected"
  264. if self.socket:
  265. try:
  266. self.socket.shutdown(socket.SHUT_RDWR)
  267. except Exception as e:
  268. lclient.error(e)
  269. try:
  270. self.socket.close()
  271. except Exception as e:
  272. lclient.error("error occured while closing the socket, " +
  273. "maybe it is already closed",exc_info=e)
  274. del self.socket
  275. self.socket = None
  276. def handle_data(self, data_received):
  277. data_decoded = data_received.decode("utf-8")
  278. lchat.info("Server: "+data_decoded)
  279. if self.handle_data_func:
  280. try:
  281. self.handle_data_func(data_decoded)
  282. except Exception as e:
  283. lclient.error(e, exc_info=True)
  284. def is_running(self):
  285. return (self in threading.enumerate())
  286. def make_socket(self):
  287. lclient.info("creating a {} socket".format(self.af_family))
  288. if self.af_family == "AF_INET":
  289. s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  290. elif self.af_family == "AF_UNIX":
  291. s = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
  292. else:
  293. raise ValueError(
  294. "AF_FAMILY '{}' not supported!".format(
  295. self.af_family
  296. )
  297. )
  298. return s
  299. def main_loop(self):
  300. lclient.debug("starting main loop")
  301. while ( not self.exit_event ):
  302. if not self.status in ["connected"]:
  303. time.sleep(0.1)
  304. continue
  305. # print(0)
  306. read_confirmed, write_confirmed, exc_confirmed \
  307. = select.select(
  308. [self.socket],
  309. [],
  310. [self.socket],
  311. 1
  312. )
  313. if self.socket in exc_confirmed:
  314. self.is_connected = False
  315. lclient.warning("socket is expected to corrupt, exiting")
  316. self.disconnect()
  317. # self.stop()
  318. break
  319. elif self.socket in read_confirmed:
  320. try:
  321. data_received = self.read_from_socket()
  322. if data_received == b'':
  323. lclient.info("connection is broken, closing socket exiting")
  324. self.disconnect()
  325. # self.stop()
  326. # break
  327. else:
  328. self.handle_data(data_received)
  329. except Exception as e:
  330. lclient.error(e, exc_info=True)
  331. if type(e) is OSError:
  332. self.is_connected = False
  333. lclient.warn("connection broken, exiting")
  334. self.disconnect()
  335. # self.stop()
  336. # break
  337. else:
  338. raise
  339. else:
  340. time.sleep(0.1)
  341. def read_from_socket(self):
  342. data_received = self.socket.recv(self.block_size)
  343. return data_received
  344. def run(self):
  345. # self.connect()
  346. if self.error_handler:
  347. self.error_handler(self.main_loop)
  348. else:
  349. self.main_loop()
  350. def send(self, msg):
  351. msg = msg.rstrip()
  352. msg_encoded = bytes(msg+"\r\n", "utf-8")
  353. try:
  354. lchat.info("Client: "+msg)
  355. self.socket.send(msg_encoded)
  356. except Exception as e:
  357. self.is_connected = False
  358. lclient.error(e, exc_info=True)
  359. self.status = "shutdown"
  360. def setup(self):
  361. pass
  362. def stop(self,reason=None):
  363. self.disconnect()
  364. self.exit_event = True
  365. if reason:
  366. print(reason)
  367. class AsyncClient(object):
  368. """docstring for Client"""
  369. is_connecting = False
  370. is_connected = False
  371. status = "uninitialized"
  372. def __init__(self,
  373. host,
  374. port=None,
  375. af_family="AF_INET",
  376. handle_data_func=None,
  377. error_handler=None,
  378. block_size=1024,
  379. ):
  380. self.super_class = super(AsyncClient, self)
  381. self.super_class.__init__()
  382. self.name = "Client"
  383. self.exit_event = False
  384. self.host = host
  385. self.port = port
  386. self.af_family = af_family
  387. self.block_size = block_size
  388. self.handle_data_func = handle_data_func
  389. self.is_connected = False
  390. self.error_handler = error_handler
  391. self.socket = None
  392. self.status = "disconnected"
  393. def connect(self):
  394. self.status = "connecting"
  395. self.socket = self.make_socket()
  396. lclient.info("connecting to socket '{}' of type {}".format(
  397. self.host,self.af_family))
  398. try:
  399. if self.af_family == "AF_INET":
  400. self.socket.connect((self.host, self.port))
  401. elif self.af_family == "AF_UNIX":
  402. self.socket.connect(self.host)
  403. # if os.path.exists(self.host):
  404. # pass
  405. # else:
  406. # lclient.warn("File not found. Aborting.")
  407. # return
  408. self.is_connected = True
  409. self.status = "connected"
  410. lclient.info("connected")
  411. return True
  412. except Exception as e:
  413. lclient.debug(e, exc_info=True)
  414. if type(e) is ConnectionRefusedError:
  415. lclient.info("failed to connect to socket '{}'".format(self.host))
  416. self.disconnect()
  417. return False
  418. def disconnect(self):
  419. lclient.info("disconnecting from socket '{}'".format(self.host))
  420. self.is_connected = False
  421. self.status = "disconnected"
  422. if self.socket:
  423. try:
  424. self.socket.shutdown(socket.SHUT_RDWR)
  425. except Exception as e:
  426. lclient.error(e)
  427. try:
  428. self.socket.close()
  429. except Exception as e:
  430. lclient.error("error occured while closing the socket, " +
  431. "maybe it is already closed",exc_info=e)
  432. del self.socket
  433. self.socket = None
  434. def handle_data(self, data_received):
  435. data_decoded = data_received.decode("utf-8")
  436. lchat.info("Server: "+data_decoded)
  437. if self.handle_data_func:
  438. try:
  439. self.handle_data_func(data_decoded)
  440. except Exception as e:
  441. lclient.error(e, exc_info=True)
  442. def is_running(self):
  443. return (self in threading.enumerate())
  444. def make_socket(self):
  445. lclient.info("creating a {} socket".format(self.af_family))
  446. if self.af_family == "AF_INET":
  447. s = trio.socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  448. elif self.af_family == "AF_UNIX":
  449. s = trio.socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
  450. else:
  451. raise ValueError(
  452. "AF_FAMILY '{}' not supported!".format(
  453. self.af_family
  454. )
  455. )
  456. return s
  457. def main_loop(self):
  458. lclient.debug("starting main loop")
  459. while ( not self.exit_event ):
  460. if not self.status in ["connected"]:
  461. time.sleep(0.1)
  462. continue
  463. # print(0)
  464. read_confirmed, write_confirmed, exc_confirmed \
  465. = select.select(
  466. [self.socket],
  467. [],
  468. [self.socket],
  469. 1
  470. )
  471. if self.socket in exc_confirmed:
  472. self.is_connected = False
  473. lclient.warning("socket is expected to corrupt, exiting")
  474. self.disconnect()
  475. # self.stop()
  476. break
  477. elif self.socket in read_confirmed:
  478. try:
  479. data_received = self.read_from_socket()
  480. if data_received == b'':
  481. lclient.info("connection is broken, closing socket exiting")
  482. self.disconnect()
  483. # self.stop()
  484. # break
  485. else:
  486. self.handle_data(data_received)
  487. except Exception as e:
  488. lclient.error(e, exc_info=True)
  489. if type(e) is OSError:
  490. self.is_connected = False
  491. lclient.warn("connection broken, exiting")
  492. self.disconnect()
  493. # self.stop()
  494. # break
  495. else:
  496. raise
  497. else:
  498. time.sleep(0.1)
  499. def read_from_socket(self):
  500. data_received = self.socket.recv(self.block_size)
  501. return data_received
  502. def run(self,connect=False):
  503. if connect:
  504. self.connect()
  505. if self.error_handler:
  506. self.error_handler(self.main_loop)
  507. else:
  508. self.main_loop()
  509. def send(self, msg):
  510. msg = msg.rstrip()
  511. msg_encoded = bytes(msg+"\r\n", "utf-8")
  512. try:
  513. lchat.info("Client: "+msg)
  514. self.socket.send(msg_encoded)
  515. except Exception as e:
  516. self.is_connected = False
  517. lclient.error(e, exc_info=True)
  518. self.status = "shutdown"
  519. def setup(self):
  520. pass
  521. def stop(self,reason=None):
  522. self.disconnect()
  523. self.exit_event = True
  524. if reason:
  525. print(reason)
  526. #