pyOpenSSL SSL3_WRITE_PENDING:bad write retry, retu

2019-08-01 11:20发布

问题:

I'm now developing a chatting server in Python. I am in the middle of applying pyOpenSSL to the chatting server and dummy clients which I made for testing. But whenever sending text messages and photo file from dummy clients to the server, pyOpenSSL returns significant error which drives me to stop using pyOpenSSL like below.

send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
send_text_message() : exception : [Errno 1] _ssl.c:1309: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry

Could you let me know how to solve the error? there's one more error which causes dummy client to die.

[client1|chatting1A] socket closed : device_id : client1, client_chatting_id : chatting1A, error : [Errno 10053] 
Exception in thread Thread-8:
Traceback (most recent call last):
  File "C:\Python27\lib\threading.py", line 810, in __bootstrap_inner
    self.run()
  File "C:\Python27\lib\threading.py", line 1082, in run
    self.function(*self.args, **self.kwargs)
  File "D:\temp\uTok1\uTokSocketServer\com\rurusoft\utok\DummyClient.py", line 97, in send_photo_message
    sock.write(message)
  File "C:\Python27\lib\ssl.py", line 172, in write
    return self._sslobj.write(data)
error: [Errno 10054]

Without pyOpenSSL, dummy clients and the server work well. Applying pyOpenSSL causes unexpected problems :(. If you have encountered the problems or have solutions to the problems, please let me know. .... If there's no solutions to the error, I'd rather find out other alternatives not using OpenSSL.. Or do you know any alterntives which can encrypt/decrypt chatting messages and personal files transfered between machines?

Though I already stored data to be sent in a local variable before writing(sending) the data, the error happens everytime.


  json_encoded = json.dumps(data)
          while True:
              try:
                  sock.write(json_encoded)
                  break
              except Exception, e:
                  Log.print_log(self.LOG_TAG, 'send_text_message() : exception : %s' % (e))
                  time.sleep(0.05)

Solved : As @David Schwartz commented, the following codes solved the upper issues.

    import StringIO
    ...
    io = StringIO.StringIO()
    io.write(json.dumps(data))
    buffer = io.getvalue()
    while True:
        try:
            sock.write(buffer)
            break
    ...
    

回答1:

OpenSSL has very strict requirements about how writes can be retried -- specifically the buffer's address and contents must not be changed. When you retry a write, you must retry with the exact same buffer (the same contents are not sufficient and, of course, different contents is absolutely prohibited).

For example, this is broken:

ssl_socket.send(send_buffer.getvalue())

Since you didn't store the value you passed to send, if you need to retry the send, how can you pass it the same value? There's no guarantee a subsequent call to getvalue will return the same result. Repeating this operation can generate a bad write retry if the buffer moves, which it can at any time.

Update: Your code does nothing to prevent the buffer from changing. There is no object that does not change that reflects the buffer. Try:

io = StringIO()
json.dumps(data, io)
buffer = io.getvalue()

      while True:
          try:
              sock.write(buffer)
              break

Here, io is the buffer, and getvalue is called on it only once.