load.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/env python
  2. '''
  3. WebSocket server-side load test program. Sends and receives traffic
  4. that has a random payload (length and content) that is checksummed and
  5. given a sequence number. Any errors are reported and counted.
  6. '''
  7. import sys, os, select, random, time, optparse, logging
  8. sys.path.insert(0,os.path.join(os.path.dirname(__file__), ".."))
  9. from websockify.websockifyserver import WebSockifyServer, WebSockifyRequestHandler
  10. class WebSocketLoadServer(WebSockifyServer):
  11. recv_cnt = 0
  12. send_cnt = 0
  13. def __init__(self, *args, **kwargs):
  14. self.delay = kwargs.pop('delay')
  15. WebSockifyServer.__init__(self, *args, **kwargs)
  16. class WebSocketLoad(WebSockifyRequestHandler):
  17. max_packet_size = 10000
  18. def new_websocket_client(self):
  19. print "Prepopulating random array"
  20. self.rand_array = []
  21. for i in range(0, self.max_packet_size):
  22. self.rand_array.append(random.randint(0, 9))
  23. self.errors = 0
  24. self.send_cnt = 0
  25. self.recv_cnt = 0
  26. self.responder(self.request)
  27. print "accumulated errors:", self.errors
  28. self.errors = 0
  29. def responder(self, client):
  30. c_pend = 0
  31. cqueue = []
  32. cpartial = ""
  33. socks = [client]
  34. last_send = time.time() * 1000
  35. while True:
  36. ins, outs, excepts = select.select(socks, socks, socks, 1)
  37. if excepts: raise Exception("Socket exception")
  38. if client in ins:
  39. frames, closed = self.recv_frames()
  40. err = self.check(frames)
  41. if err:
  42. self.errors = self.errors + 1
  43. print err
  44. if closed:
  45. break
  46. now = time.time() * 1000
  47. if client in outs:
  48. if c_pend:
  49. last_send = now
  50. c_pend = self.send_frames()
  51. elif now > (last_send + self.server.delay):
  52. last_send = now
  53. c_pend = self.send_frames([self.generate()])
  54. def generate(self):
  55. length = random.randint(10, self.max_packet_size)
  56. numlist = self.rand_array[self.max_packet_size-length:]
  57. # Error in length
  58. #numlist.append(5)
  59. chksum = sum(numlist)
  60. # Error in checksum
  61. #numlist[0] = 5
  62. nums = "".join( [str(n) for n in numlist] )
  63. data = "^%d:%d:%d:%s$" % (self.send_cnt, length, chksum, nums)
  64. self.send_cnt += 1
  65. return data
  66. def check(self, frames):
  67. err = ""
  68. for data in frames:
  69. if data.count('$') > 1:
  70. raise Exception("Multiple parts within single packet")
  71. if len(data) == 0:
  72. self.traffic("_")
  73. continue
  74. if data[0] != "^":
  75. err += "buf did not start with '^'\n"
  76. continue
  77. try:
  78. cnt, length, chksum, nums = data[1:-1].split(':')
  79. cnt = int(cnt)
  80. length = int(length)
  81. chksum = int(chksum)
  82. except ValueError:
  83. print "\n<BOF>" + repr(data) + "<EOF>"
  84. err += "Invalid data format\n"
  85. continue
  86. if self.recv_cnt != cnt:
  87. err += "Expected count %d but got %d\n" % (self.recv_cnt, cnt)
  88. self.recv_cnt = cnt + 1
  89. continue
  90. self.recv_cnt += 1
  91. if len(nums) != length:
  92. err += "Expected length %d but got %d\n" % (length, len(nums))
  93. continue
  94. inv = nums.translate(None, "0123456789")
  95. if inv:
  96. err += "Invalid characters found: %s\n" % inv
  97. continue
  98. real_chksum = 0
  99. for num in nums:
  100. real_chksum += int(num)
  101. if real_chksum != chksum:
  102. err += "Expected checksum %d but real chksum is %d\n" % (chksum, real_chksum)
  103. return err
  104. if __name__ == '__main__':
  105. parser = optparse.OptionParser(usage="%prog [options] listen_port")
  106. parser.add_option("--verbose", "-v", action="store_true",
  107. help="verbose messages and per frame traffic")
  108. parser.add_option("--cert", default="self.pem",
  109. help="SSL certificate file")
  110. parser.add_option("--key", default=None,
  111. help="SSL key file (if separate from cert)")
  112. parser.add_option("--ssl-only", action="store_true",
  113. help="disallow non-encrypted connections")
  114. (opts, args) = parser.parse_args()
  115. try:
  116. if len(args) != 1: raise ValueError
  117. opts.listen_port = int(args[0])
  118. if len(args) not in [1,2]: raise ValueError
  119. opts.listen_port = int(args[0])
  120. if len(args) == 2:
  121. opts.delay = int(args[1])
  122. else:
  123. opts.delay = 10
  124. except ValueError:
  125. parser.error("Invalid arguments")
  126. logging.basicConfig(level=logging.INFO)
  127. opts.web = "."
  128. server = WebSocketLoadServer(WebSocketLoad, **opts.__dict__)
  129. server.start_server()