def __init__(self, fifo_number):
        entropysource.EntropySource.__init__(self)
        self.buff = WesBuffer(QRNGSource.BUFFER_SIZE)

        self.fifo_number = fifo_number

        self.thread_spawned = None
        self.thread = None
        self.lock = threading.Lock()
        self.stop_event = threading.Event()
        self.init_event = threading.Event()

        self.start_fifo_client()
    def __init__(self, uri, client_id, hmac_key):
        entropysource.EntropySource.__init__(self)
        self.uri = uri
        self.buff = WesBuffer(NetworkEntropySource.BUFFER_SIZE)
        self.client_id = client_id
        try:
            self.hmac_key = hmac_key.decode('base64')
        except TypeError:
            logging.critical("Invalid HMAC key: '%s'", hmac_key)
            sys.exit(1)

        self.last_rekey = 0
        self.aes_key = None
        self.rekey()

        self.state = ClientState.pre_init
        self.io_loop = None
        self.lock = threading.Lock()
        self.stop_event = threading.Event()
        self.thread = threading.Thread(target=self._start_networking)
        self.thread.start()
class QRNGSource(entropysource.EntropySource):
    '''Entropy source based on QRNG Fifo workaround.'''

    BUFFER_SIZE = 8193
    READ_SIZE  = 64

    def __init__(self, fifo_number):
        entropysource.EntropySource.__init__(self)
        self.buff = WesBuffer(QRNGSource.BUFFER_SIZE)

        self.fifo_number = fifo_number

        self.thread_spawned = None
        self.thread = None
        self.lock = threading.Lock()
        self.stop_event = threading.Event()
        self.init_event = threading.Event()

        self.start_fifo_client()

    def start_fifo_client(self):
        '''Start the fifo client'''
        logging.debug("Thread spawned: %s", self.thread_spawned)
        if not self.thread_spawned:
            self.thread_spawned = True
            self.init_event.clear()
            self.stop_event.clear()
            self.thread = threading.Thread(target=self._start_fifo)
            self.thread.start()

    def get_entropy_input(self, security_strength,
                          min_bits, max_bits,
                          prediction_resistance):
        '''Return entropy from network source.'''

        if max_bits < min_bits:
            raise ValueError('max_length must be greater than or ' +
                             'equal to min_length')

        min_bytes = (min_bits + 7) / 8

        random_bytes = ''
        backoff = 0.01

        if not self.init_event.is_set():
            while not self.init_event.is_set():
                time.sleep(.1)

            # TODO: Make less hacky (still timing based)
            time.sleep(1)

        # Only try to get data when buffer isn't empty to prevent
        #  a two second decay when qrng goes down and drbg is running
        #  off old seed (qrng as seed case).
        if self.buff.bytes_ready() > 0:
            while len(random_bytes) < min_bytes:
                with self.lock:
                    new_bytes = self.buff.get_random_data(
                        min_bytes)

                if len(new_bytes) == 0:
                    logging.debug("Sleep %f", backoff)
                    if backoff > 2.0:
                        break
                    time.sleep(backoff)
                    backoff = backoff * 2
                else:
                    backoff = 0.01
                    random_bytes += str(new_bytes)

            self.total_bytes += len(random_bytes)

            random_bytes = utilities.binstr_leftmost(random_bytes, max_bits)

        if len(random_bytes) >= min_bytes:
            return 'SUCCESS', random_bytes
        else:
            self.restart_fifo_client()
            return 'ERROR', (("Internal pool doesn't contain "
                              "enough entropy. Only got %i bytes.") %
                             len(random_bytes))

    def restart_fifo_client(self):
        '''Close qrng fifo source.'''
        logging.debug("Stopping qrng fifo client")
        if self.stop_event:
            self.stop_event.set()

        # Wait for the thread to exit before spawning it again
        while self.stop_event.is_set():
            time.sleep(.1)

        self.thread_spawned = False

        self.start_fifo_client()

    def _start_fifo(self):
        '''Start fifo client'''
        logging.debug("Starting qrng fifo client.")
        #pylint: disable=E1121
        self.FifoClient(self.fifo_number, self.buff, self.lock,
                        self.stop_event, self.init_event)
        #pylint: enable=E1121
        logging.debug("QRNG Fifo client closed.")

    def close_entropy_source(self):
        '''Close entropy source'''
        if self.stop_event:
            self.stop_event.set()

        self.thread_spawned = False

    def get_name(self):
        '''Get name'''
        return '/tmp/wesqrng' + str(self.fifo_number)


    #pylint: disable=E1101,R0913
    class FifoClient(object):
        '''QRNG Fifo client'''

        def __init__(self, fifo_number, buff,
                     lock, stop_event, init_event):
            self.fifo_path = '/tmp/wesqrng' + str(fifo_number)
            self.fifo_number = fifo_number
            self.stop_event = stop_event
            self.init_event = init_event
            self.lock = lock
            self.buff = buff
            self.bytes_req = 0

            self.c_client = None

            self.spawn_c_client()
            self.run()
            self.c_client.kill()
            self.stop_event.clear()

        def spawn_c_client(self):
            '''Spawn C client to create QRNG Fifo'''
            c_client_path = os.path.join(
                os.path.dirname(
                    os.path.dirname(
                        os.path.dirname(
                            os.path.dirname(
                                os.path.realpath(__file__))))),
                'src-c', 'wesqrngd', 'wesqrngd')

            logging.debug('Spawing fifo_c_client: %s', c_client_path)

            if os.path.exists(self.fifo_path):
                os.remove(self.fifo_path)

            devnull = open('/dev/null', 'w')
            self.c_client = Popen([c_client_path, str(self.fifo_number)],
                                  stdout=devnull, stderr=devnull)

        def run(self):
            '''Create connection'''
            logging.debug("Looking for file: %s", self.fifo_path)
            while not os.path.exists(self.fifo_path):
                time.sleep(.1)

            logging.debug("Found file: %s", self.fifo_path)

            self.init_event.set()

            try:
                with open(self.fifo_path, 'rb') as fifo:
                    while not self.stop_event.is_set():
                        if (self.buff.bytes_needed() >
                                QRNGSource.READ_SIZE):
                            new_data = fifo.read(QRNGSource.READ_SIZE)
                            with self.lock:
                                self.buff.add_random_data(
                                    new_data)
                        time.sleep(0)
            except IOError as error:
                logging.warning("Error reading from FIFO, resetting: %s",
                                error)
class NetworkEntropySource(entropysource.EntropySource):
    '''
    An entropy source based on the WES EaaS system.
    '''

    REKEY_PERIOD = 1000000 # bytes
    BUFFER_SIZE = 8193

    def __init__(self, uri, client_id, hmac_key):
        entropysource.EntropySource.__init__(self)
        self.uri = uri
        self.buff = WesBuffer(NetworkEntropySource.BUFFER_SIZE)
        self.client_id = client_id
        try:
            self.hmac_key = hmac_key.decode('base64')
        except TypeError:
            logging.critical("Invalid HMAC key: '%s'", hmac_key)
            sys.exit(1)

        self.last_rekey = 0
        self.aes_key = None
        self.rekey()

        self.state = ClientState.pre_init
        self.io_loop = None
        self.lock = threading.Lock()
        self.stop_event = threading.Event()
        self.thread = threading.Thread(target=self._start_networking)
        self.thread.start()

    def get_name(self):
        '''Get name of entropy source for use in statistics'''
        return 'Network: %s' % self.uri

    def rekey(self):
        '''Generate new key for encryption'''
        valid_source = entropysource.get_valid_source()
        self.last_rekey = self.total_bytes

        status, aes_key = valid_source.get_entropy_input(128, 256, 256, False)
        if status != 'SUCCESS':
            raise WesEntropyException('Cannot create AES key')
        #pylint: disable=C0103
        status, iv =  valid_source.get_entropy_input(128, 128, 128, False)
        #pylint: enable=C0103
        if status != 'SUCCESS':
            raise WesEntropyException('Cannot create AES IV')
        self.aes_key = AES.new(aes_key, AES.MODE_CBC, iv)
        # raise WesEntropyException('Cannot create AES IV')

    def get_entropy_input(self, security_strength,
                          min_bits, max_bits,
                          prediction_resistance):
        '''Return entropy from network source.'''

        # If initializing, wait up to 30 seconds to allow network to connect.
        if self.state < 2:
            timeout_start = time.time()
            timeout = 30

            while self.state < 2 and time.time() < timeout_start + timeout:
                time.sleep(.1)

        if max_bits < min_bits:
            raise ValueError('max_length must be greater than or ' +
                             'equal to min_length')

        min_bytes = (min_bits + 7) / 8

        # To encrypt with AES, must have blocks of 16 bytes
        aes_bytes = ((min_bytes + 15) / 16) * 16

        random_bytes = ''
        backoff = 0.01

        # Only try to get data when buffer isn't empty to prevent
        #  a two second decay when network goes down and drbg is running
        #  off old seed (network as seed case).
        if self.buff.bytes_ready() > 0:
            while len(random_bytes) < aes_bytes:
                with self.lock:
                    new_bytes = self.buff.get_random_data(aes_bytes -
                                                          len(random_bytes))

                if len(new_bytes) == 0:
                    logging.warning("Sleep %f", backoff)
                    if backoff > 2.0:
                        break
                    time.sleep(backoff)
                    backoff = backoff * 2
                else:
                    backoff = 0.01
                    random_bytes += str(new_bytes)

            # If we haven't hit a timeout
            if len(random_bytes) == aes_bytes:
                random_bytes = self.aes_key.encrypt(random_bytes)

                if len(random_bytes) > min_bytes:
                    random_bytes = random_bytes[0:min_bytes]

                self.total_bytes += len(random_bytes)

                if (self.total_bytes >
                        self.last_rekey + NetworkEntropySource.REKEY_PERIOD):
                    self.rekey()

                random_bytes = utilities.binstr_leftmost(random_bytes, max_bits)

                if len(random_bytes) >= min_bytes:
                    return 'SUCCESS', random_bytes

        return 'ERROR', (("Internal pool doesn't contain "
                          "enough entropy. Only got %i bytes.") %
                         len(random_bytes))

    def close_entropy_source(self):
        '''Close network entropy source.'''
        logging.debug("Stopping entropy client")
        if self.stop_event:
            self.stop_event.set()
        try:
            if self.io_loop:
                self.io_loop.add_callback(lambda x: x.stop(), self.io_loop)
        except RuntimeError:
            # No-op if the IOLoop is already closing.
            pass

    def _start_networking(self):
        '''Start networking client'''
        logging.debug("Starting entropy client.")
        self.io_loop = IOLoop()
        self.EaaSClient(self, self.uri, self.buff, self.client_id,
                        self.hmac_key, self.lock, self.stop_event)
        self.io_loop.start()
        logging.debug("Closing entropy client.")
        self.io_loop.close()

    def get_state(self):
        '''Get network connection state'''
        return self.state

    def set_state(self, state):
        '''Set network connection state'''
        self.state = state


    #pylint: disable=E1101,R0913
    class EaaSClient(object):
        '''Entropy as a Service client'''

        def __init__(self, entropy_source, uri, buff, client_id, hmac_key,
                     lock, stop_event):
            self.uri = uri
            self.buff = buff
            self.client_id = client_id
            self.hmac_key = hmac_key

            self.stop_event = stop_event
            self.lock = lock
            self.bytes_req = 0
            self.hbt = 15


            self.poll_buffer = None
            self.heartbeat = None
            self.conn = None

            self.entropy_source = entropy_source
            self.client_msg_number = 0
            self.server_msg_number = -1
            self.conn_failures = 0

            self.do_connect()

        def do_connect(self):
            '''Create connection'''
            logging.debug('Connecting to %s.', self.uri)
            websock = websocket_connect(
                self.uri, on_message_callback=self.received_message_callback)
            websock.add_done_callback(self.connect_callback)
            self.entropy_source.set_state(ClientState.init)

        def connect_callback(self, conn):
            '''Connection callback'''
            logging.debug('Connected to %s.', self.uri)

            try:
                assert self.entropy_source.get_state() == ClientState.init

                self.conn = conn.result()
                self.conn_failures = 0
            except socket.error as error:
                logging.warning(
                    "Error connecting to server, trying again. %s", str(error))
                time.sleep(1)
                self.reset_connection()
                return

            self.heartbeat = IOLoop.current().add_timeout(
                timedelta(seconds=self.hbt), self.do_heartbeat)
            self.poll_buffer = IOLoop.current().add_callback(
                self.do_poll_buffer)

            self.send_hello()
            self.entropy_source.set_state(ClientState.expect_hello)

        def hmac_and_send(self, message):
            '''Calculate HMAC, insert into message, and send'''
            message.header.hmac = calc_hmac(self.hmac_key, message).digest()

            self.conn.write_message(
                message.SerializeToString(), binary=True)

        def send_hello(self):
            '''Initial server comm, do hello, setup shared secret'''
            # Setup hello
            logging.debug("Sending hello message to server.")
            message = WesMessage()
            message.header.magic = 'WES1'
            message.header.msg_type = message.header.CLIENT_HELLO
            message.header.msg_number = self.client_msg_number
            self.client_msg_number += 1

            message.client_hello.client_id = self.client_id
            #TODO: Add nonce to messages G^X mod p
            message.client_hello.nonce = ''

            self.hmac_and_send(message)

        def do_poll_buffer(self):
            '''Poll buffer'''
            # Wait until the handshake is finished
            if self.entropy_source.get_state() == ClientState.expect_data:
                bytes_needed = self.buff.bytes_needed() - self.bytes_req
                # logging.debug('Bytes needed: %s',
                #              self.buff.bytes_needed())
                # logging.debug('Bytes requested: %s', self.bytes_req)

                if bytes_needed >= (self.buff.buff_size / 8):

                    self.send_data_request(bytes_needed)

                    self.bytes_req += bytes_needed

            if IOLoop:
                self.poll_buffer = IOLoop.current().add_callback(
                    self.do_poll_buffer)

        def send_data_request(self, bytes_needed):
            '''Send data request to server'''
            logging.debug('Asking for %s bytes.',
                          str(bytes_needed))

            message = WesMessage()
            message.header.magic = 'WES1'
            message.header.msg_type = message.header.DATA_REQUEST
            message.header.msg_number = self.client_msg_number
            self.client_msg_number += 1
            message.header.hmac = ''

            message.data_request.num_bytes = bytes_needed

            self.hmac_and_send(message)

        def do_heartbeat(self):
            '''Heartbeat'''
            stream = self.conn.protocol.stream
            if stream.closed():
                self.heartbeat = None
            else:
                self.heartbeat = stream.io_loop.add_timeout(
                    timedelta(seconds=self.hbt), self.do_heartbeat)
                self.conn.protocol.write_ping('ping')

        def handle_hello(self, message):
            '''Handle server_hello'''
            # Handle hello
            #TODO: Use nonce to compute shared secret G^Y mod p
            #TODO: Use shared secret as key for hmac going forward
            #TODO: Verify signature
            logging.debug(
                "Got hello message from server. msg: %s", message)
            self.entropy_source.set_state(ClientState.expect_data)

        def handle_data_delivery(self, message):
            '''Handle data_delivery'''
            if message.header.msg_type != message.header.DATA_DELIVERY:
                logging.warning('Invalid msg_type: %i',
                                message.header.msg_type)
                return

            logging.debug(
                'Got delivery, num_bytes = %i, current bytes req: %i',
                len(message.data_delivery.data), self.bytes_req)

            self.bytes_req -= len(message.data_delivery.data)
            self.bytes_req = max(0, self.bytes_req)

            with self.lock:
                self.buff.add_random_data(message.data_delivery.data)

            self.entropy_source.set_state(ClientState.expect_data)

        @staticmethod
        def handle_error(message):
            '''Handle error message from server'''
            logging.error(
                "Closing connection: error from WES Entropy Server: '%s'",
                message.error.error_msg)
            IOLoop.current().stop()

        def received_message_callback(self, buff):
            '''Receive message'''
            if buff is None:
                self.reset_connection()
                return

            message = WesMessage()
            message.ParseFromString(buff)

            if message.header.magic != 'WES1':
                logging.warning('Invalid magic: %s', message.header.magic)
                return

            if message.header.msg_type == message.header.ERROR:
                self.handle_error(message)
                return

            if message.header.msg_number != self.server_msg_number + 1:
                logging.warning (
                    'Invalid delivery_msg_number %i '
                    '!=  server_msg_number %i',
                    message.header.msg_number, self.server_msg_number + 1)
                return
            self.server_msg_number = message.header.msg_number

            if not self.check_hmac(message):
                logging.warning("Hmac failed, dropping message")
                return

            if self.entropy_source.get_state() == ClientState.expect_hello:
                logging.debug("Got message in expect_hello state.")
                self.handle_hello(message)

            elif self.entropy_source.get_state() == ClientState.expect_data:
                logging.debug("Got message in expect_data state.")
                self.handle_data_delivery(message)

            else:
                logging.warning("Invalid client state %s",
                                self.entropy_source.get_state())


        def check_hmac(self, message):
            '''Check message's hmac for validity'''
            return (calc_hmac(self.hmac_key, message).digest() ==
                    message.header.hmac)

        def reset_connection(self):
            '''Reset connection to server'''
            self.conn_failures += 1
            if self.conn_failures >= 10:
                self.stop_event.set()

            if self.heartbeat is not None:
                heartbeat = self.heartbeat
                self.heartbeat = None
                IOLoop.current().remove_timeout(heartbeat)

            if not self.stop_event.is_set():
                self.client_msg_number = 0
                self.server_msg_number = -1
                self.entropy_source.set_state(ClientState.init)
                self.do_connect()