respondd_client.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/env python3
  2. import socket
  3. import select
  4. import struct
  5. import json
  6. import time
  7. import re
  8. import lib.helper
  9. from lib.ratelimit import rateLimit
  10. from lib.nodeinfo import Nodeinfo
  11. from lib.neighbours import Neighbours
  12. from lib.statistics import Statistics
  13. class ResponddClient:
  14. def __init__(self, config):
  15. self._config = config
  16. if 'rate_limit' in self._config:
  17. if 'rate_limit_burst' not in self._config:
  18. self._config['rate_limit_burst'] = 10
  19. self.__RateLimit = rateLimit(self._config['rate_limit'], self._config['rate_limit_burst'])
  20. else:
  21. self.__RateLimit = None
  22. self._nodeinfo = Nodeinfo(self._config)
  23. self._neighbours = Neighbours(self._config)
  24. self._statistics = Statistics(self._config)
  25. self._sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
  26. @staticmethod
  27. def joinMCAST(sock, addr, ifname):
  28. group = socket.inet_pton(socket.AF_INET6, addr)
  29. if_idx = socket.if_nametoindex(ifname)
  30. sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group + struct.pack('I', if_idx))
  31. def start(self):
  32. self._sock.bind(('::', self._config['port']))
  33. lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'if'])
  34. for line in lines:
  35. lineMatch = re.match(r'^([^:]*)', line)
  36. self.joinMCAST(self._sock, self._config['addr'], lineMatch.group(1))
  37. self.joinMCAST(self._sock, self._config['addr'], self._config['bridge'])
  38. while True:
  39. msg, sourceAddress = self._sock.recvfrom(2048)
  40. msgSplit = str(msg, 'UTF-8').split(' ')
  41. if msgSplit[0] == 'GET': # multi_request
  42. for request in msgSplit[1:]:
  43. self.sendResponse(sourceAddress, request, True)
  44. else: # single_request
  45. self.sendResponse(sourceAddress, msgSplit[0], False)
  46. def sendResponse(self, destAddress, responseType, withCompression):
  47. if self.__RateLimit is not None and not self.__RateLimit.limit():
  48. print('rate limit reached!')
  49. return
  50. tStart = time.time()
  51. responseClass = None
  52. if responseType == 'statistics':
  53. responseClass = self._statistics
  54. elif responseType == 'nodeinfo':
  55. responseClass = self._nodeinfo
  56. elif responseType == 'neighbours':
  57. responseClass = self._neighbours
  58. else:
  59. print('unknown command: ' + responseType)
  60. return
  61. if not self._config['dry_run']:
  62. if withCompression:
  63. self._sock.sendto(responseClass.getJSONCompressed(responseType), destAddress)
  64. else:
  65. self._sock.sendto(responseClass.getJSON(), destAddress)
  66. if self._config['verbose'] or self._config['dry_run']:
  67. print('%14.3f %35s %5d %13s %5.3f: ' % (tStart, destAddress[0], destAddress[1], responseType, time.time() - tStart), end='')
  68. print(json.dumps(responseClass.getStruct(responseType), sort_keys=True, indent=4))