__init__.py 20 KB

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