__init__.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. lserver.debug("conn: '{}', addr: '{}'".format(
  190. conn,
  191. addr,
  192. ))
  193. handler = self.make_handler(conn, addr)
  194. self.register_conn(conn, addr)
  195. self.register_handler(handler, conn)
  196. lserver.debug("peername: '{}', sockname: '{}'".format(
  197. conn.getpeername(),
  198. conn.getsockname(),
  199. ))
  200. elif ( socket_handler
  201. and (socket_handler in self.connection_handler) ):
  202. lserver.debug("handling client connection")
  203. try:
  204. data = socket_handler.recv()
  205. if not data:
  206. lserver.info("connection {} closed".format(self.socket))
  207. self.unregister_handler(socket_handler, s)
  208. self.unregister_conn(conn)
  209. socket_handler.close()
  210. else:
  211. lschat.info("Client:"+data.strip())
  212. socket_handler.handle(data)
  213. except Exception as e:
  214. lserver.error(e, exc_info=True)
  215. else:
  216. lserver.debug("else!")
  217. lserver.debug(socket_handler)
  218. time.sleep(1)
  219. def cleanup(self):
  220. pass
  221. class Client(threading.Thread):
  222. """docstring for Client"""
  223. is_connecting = False
  224. is_connected = False
  225. status = "uninitialized"
  226. def __init__(self,
  227. host,
  228. port=None,
  229. af_family="AF_INET",
  230. handle_data_func=None,
  231. error_handler=None,
  232. block_size=1024,
  233. ):
  234. self.super_class = super(Client, self)
  235. self.super_class.__init__()
  236. self.name = "Client"
  237. self.exit_event = False
  238. self.host = host
  239. self.port = port
  240. self.af_family = af_family
  241. self.block_size = block_size
  242. self.handle_data_func = handle_data_func
  243. self.is_connected = False
  244. self.error_handler = error_handler
  245. # self.socket = self.make_socket()
  246. self.socket = None
  247. self.status = "disconnected"
  248. def connect(self):
  249. self.status = "connecting"
  250. self.socket = self.make_socket()
  251. lclient.info(
  252. "connecting to socket '{}' of type {}".format(
  253. self.host,
  254. self.af_family
  255. )
  256. )
  257. try:
  258. if self.af_family == "AF_INET":
  259. self.socket.connect((self.host, self.port))
  260. elif self.af_family == "AF_UNIX":
  261. if os.path.exists(self.host):
  262. self.socket.connect(self.host)
  263. else:
  264. lclient.warn("File not found. Aborting.")
  265. return
  266. self.is_connected = True
  267. self.status = "connected"
  268. lclient.info("connected")
  269. return True
  270. except Exception as e:
  271. lclient.debug(e, exc_info=True)
  272. if type(e) is ConnectionRefusedError:
  273. lclient.info("failed to connect to socket '{}'".format(self.host))
  274. self.disconnect()
  275. return False
  276. def disconnect(self):
  277. lclient.info("disconnecting from socket '{}'".format(self.host))
  278. self.is_connected = False
  279. self.status = "disconnected"
  280. if self.socket:
  281. try:
  282. self.socket.shutdown(socket.SHUT_RDWR)
  283. except Exception as e:
  284. lclient.error(e)
  285. try:
  286. self.socket.close()
  287. except Exception as e:
  288. lclient.error("error occured while closing the socket, " +
  289. "maybe it is already closed",exc_info=e)
  290. del self.socket
  291. self.socket = None
  292. def handle_data(self, data_received):
  293. data_decoded = data_received.decode("utf-8")
  294. lcchat.info("Server: "+data_decoded)
  295. if self.handle_data_func:
  296. try:
  297. self.handle_data_func(data_decoded)
  298. except Exception as e:
  299. lclient.error(e, exc_info=True)
  300. def is_running(self):
  301. return (self in threading.enumerate())
  302. def make_socket(self):
  303. lclient.info("creating a {} socket".format(self.af_family))
  304. if self.af_family == "AF_INET":
  305. s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  306. elif self.af_family == "AF_UNIX":
  307. s = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
  308. else:
  309. raise ValueError(
  310. "AF_FAMILY '{}' not supported!".format(
  311. self.af_family
  312. )
  313. )
  314. return s
  315. def main_loop(self):
  316. lclient.debug("starting main loop")
  317. while ( not self.exit_event ):
  318. if not self.status in ["connected"]:
  319. time.sleep(0.1)
  320. continue
  321. # print(0)
  322. read_confirmed, write_confirmed, exc_confirmed \
  323. = select.select(
  324. [self.socket],
  325. [],
  326. [self.socket],
  327. 1
  328. )
  329. if self.socket in exc_confirmed:
  330. self.is_connected = False
  331. lclient.warning("socket is expected to corrupt, exiting")
  332. self.disconnect()
  333. # self.stop()
  334. break
  335. elif self.socket in read_confirmed:
  336. try:
  337. data_received = self.read_from_socket()
  338. if data_received == b'':
  339. lclient.info("connection is broken, closing socket exiting")
  340. self.disconnect()
  341. # self.stop()
  342. # break
  343. else:
  344. try:
  345. self.handle_data(data_received)
  346. except Exception as e:
  347. lserver.error(
  348. "Error while handling data",
  349. exc_info=e
  350. )
  351. except Exception as e:
  352. lclient.error(e, exc_info=True)
  353. if type(e) is OSError:
  354. self.is_connected = False
  355. lclient.warn("connection broken, exiting")
  356. self.disconnect()
  357. # self.stop()
  358. # break
  359. else:
  360. raise
  361. else:
  362. time.sleep(0.1)
  363. def read_from_socket(self):
  364. data_received = self.socket.recv(self.block_size)
  365. return data_received
  366. def run(self):
  367. # self.connect()
  368. if self.error_handler:
  369. self.error_handler(self.main_loop)
  370. else:
  371. self.main_loop()
  372. def send(self, msg):
  373. msg = msg.rstrip()
  374. msg_encoded = bytes(msg+"\r\n", "utf-8")
  375. try:
  376. lcchat.info("Client: "+msg)
  377. self.socket.send(msg_encoded)
  378. except Exception as e:
  379. self.is_connected = False
  380. lclient.error(e, exc_info=True)
  381. self.status = "shutdown"
  382. def setup(self):
  383. pass
  384. def stop(self,reason=None):
  385. self.disconnect()
  386. self.exit_event = True
  387. if reason:
  388. print(reason)
  389. class AsyncClient(object):
  390. """docstring for Client"""
  391. is_connecting = False
  392. is_connected = False
  393. status = "uninitialized"
  394. def __init__(self,
  395. host,
  396. port=None,
  397. af_family="AF_INET",
  398. handle_data_func=None,
  399. error_handler=None,
  400. block_size=1024,
  401. ):
  402. self.super_class = super(AsyncClient, self)
  403. self.super_class.__init__()
  404. self.name = "Client"
  405. self.exit_event = False
  406. self.host = host
  407. self.port = port
  408. self.af_family = af_family
  409. self.block_size = block_size
  410. self.handle_data_func = handle_data_func
  411. self.is_connected = False
  412. self.error_handler = error_handler
  413. self.socket = None
  414. self.status = "disconnected"
  415. def connect(self):
  416. self.status = "connecting"
  417. self.socket = self.make_socket()
  418. lclient.info("connecting to socket '{}' of type {}".format(
  419. self.host,self.af_family))
  420. try:
  421. if self.af_family == "AF_INET":
  422. self.socket.connect((self.host, self.port))
  423. elif self.af_family == "AF_UNIX":
  424. self.socket.connect(self.host)
  425. # if os.path.exists(self.host):
  426. # pass
  427. # else:
  428. # lclient.warn("File not found. Aborting.")
  429. # return
  430. self.is_connected = True
  431. self.status = "connected"
  432. lclient.info("connected")
  433. return True
  434. except Exception as e:
  435. lclient.debug(e, exc_info=True)
  436. if type(e) is ConnectionRefusedError:
  437. lclient.info("failed to connect to socket '{}'".format(self.host))
  438. self.disconnect()
  439. return False
  440. def disconnect(self):
  441. lclient.info("disconnecting from socket '{}'".format(self.host))
  442. self.is_connected = False
  443. self.status = "disconnected"
  444. if self.socket:
  445. try:
  446. self.socket.shutdown(socket.SHUT_RDWR)
  447. except Exception as e:
  448. lclient.error(e)
  449. try:
  450. self.socket.close()
  451. except Exception as e:
  452. lclient.error("error occured while closing the socket, " +
  453. "maybe it is already closed",exc_info=e)
  454. del self.socket
  455. self.socket = None
  456. def handle_data(self, data_received):
  457. data_decoded = data_received.decode("utf-8")
  458. lcchat.info("Server: "+data_decoded)
  459. if self.handle_data_func:
  460. try:
  461. self.handle_data_func(data_decoded)
  462. except Exception as e:
  463. lclient.error(e, exc_info=True)
  464. def is_running(self):
  465. return (self in threading.enumerate())
  466. def make_socket(self):
  467. lclient.info("creating a {} socket".format(self.af_family))
  468. if self.af_family == "AF_INET":
  469. s = trio.socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  470. elif self.af_family == "AF_UNIX":
  471. s = trio.socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
  472. else:
  473. raise ValueError(
  474. "AF_FAMILY '{}' not supported!".format(
  475. self.af_family
  476. )
  477. )
  478. return s
  479. def main_loop(self):
  480. lclient.debug("starting main loop")
  481. while ( not self.exit_event ):
  482. if not self.status in ["connected"]:
  483. time.sleep(0.1)
  484. continue
  485. # print(0)
  486. read_confirmed, write_confirmed, exc_confirmed \
  487. = select.select(
  488. [self.socket],
  489. [],
  490. [self.socket],
  491. 1
  492. )
  493. if self.socket in exc_confirmed:
  494. self.is_connected = False
  495. lclient.warning("socket is expected to corrupt, exiting")
  496. self.disconnect()
  497. # self.stop()
  498. break
  499. elif self.socket in read_confirmed:
  500. try:
  501. data_received = self.read_from_socket()
  502. if data_received == b'':
  503. lclient.info("connection is broken, closing socket exiting")
  504. self.disconnect()
  505. # self.stop()
  506. # break
  507. else:
  508. self.handle_data(data_received)
  509. except Exception as e:
  510. lclient.error(e, exc_info=True)
  511. if type(e) is OSError:
  512. self.is_connected = False
  513. lclient.warn("connection broken, exiting")
  514. self.disconnect()
  515. # self.stop()
  516. # break
  517. else:
  518. raise
  519. else:
  520. time.sleep(0.1)
  521. def read_from_socket(self):
  522. data_received = self.socket.recv(self.block_size)
  523. return data_received
  524. def run(self,connect=False):
  525. if connect:
  526. self.connect()
  527. if self.error_handler:
  528. self.error_handler(self.main_loop)
  529. else:
  530. self.main_loop()
  531. def send(self, msg):
  532. msg = msg.rstrip()
  533. msg_encoded = bytes(msg+"\r\n", "utf-8")
  534. try:
  535. lcchat.info("Client: "+msg)
  536. self.socket.send(msg_encoded)
  537. except Exception as e:
  538. self.is_connected = False
  539. lclient.error(e, exc_info=True)
  540. self.status = "shutdown"
  541. def setup(self):
  542. pass
  543. def stop(self,reason=None):
  544. self.disconnect()
  545. self.exit_event = True
  546. if reason:
  547. print(reason)
  548. #