2012-02-14 2 views
0

Мы находимся в процессе преобразования проекта на основе openSl на C++ в python с M2Crypto, и мы столкнулись с несколько необычной проблемой с подпрограммами BIO из M2Crypto. В частности, любой вызов BIO.readlines() вечно ведется в файловом объекте.M2Crypto BIO.readlines висит, python 2.7

Вот краткий пример того, что мы пытались:

f = open('test.txt','w') 
f.write('hello world\n') 
f.close() 

import M2Crypto.BIO 
bio = M2Crypto.BIO.openfile('test.txt','r') 
lines = bio.readlines() 
# the above call hangs forever 

Чтобы гарантировать, что мы не имели что-то ужасно неправильно с нашей установкой OpenSSL, мы создаем небольшую тестовую программу для чтения файла test.txt мы просто создано:

#include <openssl/bio.h> 
#include <openssl/err.h> 
int main() { 
    const int maxrd = 4096; 
    char line[maxrd]; 
    int rd; 
    BIO* bio = BIO_new_file("test.txt","r"); 
    while((rd = BIO_gets(bio, line, maxrd)) > 0) { 
     printf("%s",line); 
     } 
    if (rd == -1) { 
     printf("BIO error %ld\n", ERR_get_error()); 
     } 
    } 

Нет проблем.

Мы изучали файл оболочки M2Crypto-0.21.1/SWIG/_bio.i и думаем, что у нас может возникнуть идея источника проблемы. Строка 109 проверяет значение, возвращаемое из BIO_gets()

if (r < 0) { 
    // return Py_None 
    } 

НО страницу человека для BIO_gets() предполагает, что это может возвращать либо 0 или -1, чтобы указать конец-в-поток.

Я считаю, что это должно быть

if (r < 1) { 
    // return Py_None 
    } 

Но хотел бы видеть, если бы столкнулись друга - или же мы ошиблись в нашем понимании BIO_gets системы().

--- Подробности --- Pythong 2,7 M2Crypto 0.21.1 OpenSSL 0.9.8q-ФИПС 2 дек 2010 FreeBSD 8.2-RELEASE-p4

ответ

0

В других событий наткнуться это в будущем , Я хотел поделиться нашим патчем.

--- M2Crypto-0.21.1.orig/SWIG/_bio.i 2011-01-15 14:10:06.000000000 -0500 
+++ M2Crypto-0.21.1/SWIG/_bio.i 2012-02-14 11:34:15.000000000 -0500 
@@ -106,7 +106,7 @@ 
    Py_BEGIN_ALLOW_THREADS 
    r = BIO_gets(bio, buf, num); 
    Py_END_ALLOW_THREADS 
- if (r < 0) { 
+ if (r < 1) { 
     PyMem_Free(buf); 
     if (ERR_peek_error()) { 
      PyErr_SetString(_bio_err, ERR_reason_error_string(ERR_get_error())); 

ПРИМЕЧАНИЕ: Для тех, кто знаком с внутренностями M2Crypto, были по существу три пути решения этой проблемы. Первый - это исправление, опубликованное выше. Поскольку мы считаем, что это соответствует намерению справочной страницы для BIO_gets(), это решение, на которое мы решили.

Второе решение - исправить M2Crypto/BIO.py. В частности, для исправления кода, который реализует BIO.readlines(), чтобы проверить возвращаемое значение из m2.bio.gets() для None или len (buf) == 0 и рассматривать как конец потока.

Третьим решением было просто избежать вызова BIO.readlines() и ограничить себя вызовом BIO.readline() (note-singluar readline vs readlines) и проверить возвращаемое значение из BIO.readline() для или None или len (buf) == 0.

Третье решение может показаться не таким, как вариант - больше похоже на избегание. Но если вас беспокоит развертывание приложения в среде, где M2Crypto не может быть исправлено, этот подход гарантированно будет наиболее совместимым.

Мы отправили наш патч разработчику записи Heikki, но у него пока не было возможности просмотреть наше предложение. Пока официальный ответ так или иначе не развивается, я хотел поделиться своими мыслями.

+0

BTW - я не знаю, разработчик Хейкки лично ... но его проект M2Crypto абсолютно фантастическим. Это не только исключительная реализация оболочки Python/OpenSSL, но и пример ПРАВОГО способа создания SWIG-кода - чистый, простой, доступный и т. Д. Хорошо, сэр. – user590028

0

Эта проблема относится к bug #717675 в Debian Linux.

Это не воспроизводится в Fedora 21, и я не нашел никаких патчей для Fedora, которые изменяли бы либо BIO.py, либо _bio.i.

Вот патч, который был опубликован для Debian:

--- /usr/lib64/python2.7/site-packages/M2Crypto/BIO.py 2011-01-15 20:10:05.000000000 +0100 
+++ BIO.py 2015-05-20 09:24:46.600582999 +0200 
@@ -73,6 +73,8 @@ 
      buf=m2.bio_gets(self.bio, 4096) 
      if buf is None: 
       break 
+  if len(buf)==0: 
+  break 
      lines.append(buf) 
     return lines 
+0

комментарий или ответ? – null

+0

Ну, я понял, почему в Fedora ошибка не воспроизводится. Существует патч «m2crypto-0.21.1-timeouts.patch», который просто переписывает функцию «makefile» в Connection.py. В этой новой функции вызывается классический класс _fileobject из python socket.py. Это немного странно, потому что это приводит к тому, чтобы избежать всего механика, определенного в BIO.py. Значение возвращаемого объекта open_https больше не является объектом BIO ... Таким образом, часть выгоды от m2crypto теряется, я думаю .... – Jessie

+0

И да, это скорее комментарий, чем ответ. – Jessie

Смежные вопросы