wpaspy.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/python
  2. #
  3. # wpa_supplicant/hostapd control interface using Python
  4. # Copyright (c) 2013, Jouni Malinen <j@w1.fi>
  5. #
  6. # This software may be distributed under the terms of the BSD license.
  7. # See README for more details.
  8. from __future__ import print_function
  9. import os
  10. import stat
  11. import socket
  12. import select
  13. counter = 0
  14. class Ctrl:
  15. def __init__(self, path, port=9877):
  16. global counter
  17. self.started = False
  18. self.attached = False
  19. self.path = path
  20. self.port = port
  21. try:
  22. mode = os.stat(path).st_mode
  23. if stat.S_ISSOCK(mode):
  24. self.udp = False
  25. else:
  26. self.udp = True
  27. except:
  28. self.udp = True
  29. if not self.udp:
  30. self.s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
  31. self.dest = path
  32. self.local = "/tmp/wpa_ctrl_" + str(os.getpid()) + '-' + str(counter)
  33. counter += 1
  34. self.s.bind(self.local)
  35. try:
  36. self.s.connect(self.dest)
  37. except Exception as e:
  38. self.s.close()
  39. os.unlink(self.local)
  40. raise
  41. else:
  42. try:
  43. self.s = None
  44. ai_list = socket.getaddrinfo(path, port, socket.AF_INET,
  45. socket.SOCK_DGRAM)
  46. for af, socktype, proto, cn, sockaddr in ai_list:
  47. self.sockaddr = sockaddr
  48. break
  49. self.s = socket.socket(af, socktype)
  50. self.s.settimeout(5)
  51. self.s.sendto(b"GET_COOKIE", sockaddr)
  52. reply, server = self.s.recvfrom(4096)
  53. self.cookie = reply
  54. self.port = port
  55. except:
  56. print("connect exception ", path, str(port))
  57. if self.s != None:
  58. self.s.close()
  59. raise
  60. self.started = True
  61. def __del__(self):
  62. self.close()
  63. def close(self):
  64. if self.attached:
  65. try:
  66. self.detach()
  67. except Exception as e:
  68. # Need to ignore this allow the socket to be closed
  69. self.attached = False
  70. pass
  71. if self.started:
  72. self.s.close()
  73. if not self.udp:
  74. os.unlink(self.local)
  75. self.started = False
  76. def request(self, cmd, timeout=10):
  77. if type(cmd) == str:
  78. try:
  79. cmd2 = cmd.encode()
  80. cmd = cmd2
  81. except UnicodeDecodeError as e:
  82. pass
  83. if self.udp:
  84. self.s.sendto(self.cookie + cmd, self.sockaddr)
  85. else:
  86. self.s.send(cmd)
  87. [r, w, e] = select.select([self.s], [], [], timeout)
  88. if r:
  89. res = self.s.recv(4096).decode()
  90. try:
  91. r = str(res)
  92. except UnicodeDecodeError as e:
  93. r = res
  94. return r
  95. raise Exception("Timeout on waiting response")
  96. def attach(self):
  97. if self.attached:
  98. return None
  99. res = self.request("ATTACH")
  100. if "OK" in res:
  101. self.attached = True
  102. return None
  103. raise Exception("ATTACH failed")
  104. def detach(self):
  105. if not self.attached:
  106. return None
  107. if self.s.fileno() == -1:
  108. self.attached = False
  109. return None
  110. while self.pending():
  111. ev = self.recv()
  112. res = self.request("DETACH")
  113. if "FAIL" not in res:
  114. self.attached = False
  115. return None
  116. raise Exception("DETACH failed")
  117. def terminate(self):
  118. if self.attached:
  119. try:
  120. self.detach()
  121. except Exception as e:
  122. # Need to ignore this to allow the socket to be closed
  123. self.attached = False
  124. self.request("TERMINATE")
  125. self.close()
  126. def pending(self, timeout=0):
  127. [r, w, e] = select.select([self.s], [], [], timeout)
  128. if r:
  129. return True
  130. return False
  131. def recv(self):
  132. res = self.s.recv(4096).decode()
  133. try:
  134. r = str(res)
  135. except UnicodeDecodeError as e:
  136. r = res
  137. return r