curl_easy_perform () en panne sur le serveur Ubuntu 14

Voici ma fonction de téléchargement.

Le but est de: télécharger uniquement un morceau de fichier en fonction du décalage et de la taille du bloc

Dans cette fonction, si p_offset n’est pas nul, j’appelle fseek() par moi-même et ensuite je laisse libcurl lire le contenu du fichier en utilisant fread() .

L’appelant de la fonction est chargé de donner une taille de bloc correcte et valide, en s’assurant que p_offset + p_sizeOfChunk <= ACTUAL_SIZE_OF_FILE

La réponse du serveur est supposée être une chaîne. Je l’obtiens via mon callback writeToSsortingng()

Le code fonctionne bien sous Windows et OS X. Mais curl_easy_perform() bloque parfois sur Ubuntu 14.

Y a-t-il quelque chose dans mon code qui me manque qui pourrait causer ce crash?

 void uploadFile( const ssortingng & p_filename, const ssortingng & p_url, size_t p_offset, size_t p_sizeOfChunk ) { FILE * file( fopen( p_filename.c_str(), "rb" ) ); if ( !file ) { throw Exception( __FILE__, __LINE__ ) << "Could not open file " << p_filename << " when posting to " << p_url; } if ( p_offset ) { if ( fseek( file, (long)p_offset, SEEK_SET ) ) { throw Exception( __FILE__, __LINE__ ) << "Could not seek in file " << p_filename << " when posting to " << p_url; } } CURL * curl( curl_easy_init() ); if ( !curl ) { throw Exception( __FILE__, __LINE__ ) << "Could not initialize cURL when posting " << p_filename << " to " << p_url; } // URL curl_easy_setopt( curl, CURLOPT_URL, p_url.c_str() ); // PUT HTTP method string answer; curl_easy_setopt( curl, CURLOPT_UPLOAD, 1L ); curl_easy_setopt( curl, CURLOPT_READFUNCTION, fread ); curl_easy_setopt( curl, CURLOPT_READDATA, file ); curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeToString ); curl_easy_setopt( curl, CURLOPT_WRITEDATA, &answer ); curl_easy_setopt( curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)p_sizeOfChunk ); char errorBuffer[ CURL_ERROR_SIZE + 1 ]; curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, errorBuffer ); // No signal handlers... curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 ); curl_easy_setopt( curl, CURLOPT_TIMEOUT_MS, 120000 ); // HEADER char contentLength[ 512 ]; snprintf( contentLength, sizeof( contentLength ), "Content-Length: %zu", p_sizeOfChunk ); struct curl_slist * headers( nullptr ); headers = curl_slist_append( headers, contentLength ); curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ); // SSL curl_easy_setopt( curl, CURLOPT_CAINFO, "path/to/cacert.pem" ); CURLcode res( curl_easy_perform( curl ) ); fclose( file ); if ( res != CURLE_OK && res != CURLE_SEND_ERROR ) { curl_easy_cleanup( curl ); throw Exception( __FILE__, __LINE__ ) << "cURL error when posting " << p_filename << " to " << p_url << ": " << errorBuffer; } long httpResponseCode( 0 ); curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &httpResponseCode ); curl_easy_cleanup( curl ); if ( ( httpResponseCode / 100 ) != 2 ) { cout << answer << endl; throw Exception( __FILE__, __LINE__ ) << "HTTP error " << httpResponseCode << " when posting " << p_filename; } } 

Je reçois la réponse et l’enregistre sur une std::ssortingng avec writeToSsortingng() . Ce n’est sûrement pas la raison de l’accident. Je l’ai testé juste en retournant la size * count et le crash se produit toujours.

 static size_t writeToSsortingng( const void * ptr, size_t size, size_t count, FILE * stream ) { ssortingng & retContent( *( reinterpret_cast( stream ) ) ); if ( !retContent.length() ) { int skipBOM( ( reinterpret_cast( ptr )[ 0 ] == 0xEF && reinterpret_cast( ptr )[ 1 ] == 0xBB && reinterpret_cast( ptr )[ 2 ] == 0xBF ) ? 3 : 0 ); retContent += ssortingng( static_cast( ptr ) + skipBOM, static_cast( size * count ) - skipBOM ); } else { retContent += ssortingng( static_cast( ptr ), size * count ); } return size * count; } 

Voici la stack au moment de l’accident! Il semble être lié à OpenSSL.

 #0 0x00007ffff65ad35d in write () at ../sysdeps/unix/syscall-template.S:81 #1 0x00007ffff73187a6 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #2 0x00007ffff731684b in BIO_write () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #3 0x00007ffff6ffcb72 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0 #4 0x00007ffff6ffd273 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0 #5 0x00007ffff76873e1 in ossl_send (conn=0x7ffef8013b28, sockindex=0, mem=0x7ffef8005379, len=16384, curlcode=0x7fff127fa5c0) at vtls/openssl.c:2720 #6 0x00007ffff762fe0f in Curl_write (conn=0x7ffef8013b28, sockfd=64, mem=0x7ffef8005379, len=16384, written=0x7fff127fa608) at sendf.c:233 #7 0x00007ffff764fb01 in readwrite_upload (data=0x7ffef8000a78, conn=0x7ffef8013b28, k=0x7ffef8000af0, didwhat=0x7fff127fa664) at transfer.c:954 #8 0x00007ffff764fdd9 in Curl_readwrite (conn=0x7ffef8013b28, done=0x7fff127fa6dc) at transfer.c:1059 #9 0x00007ffff765ced7 in multi_runsingle (multi=0x7ffef800a668, now=..., data=0x7ffef8000a78) at multi.c:1484 #10 0x00007ffff765d60c in curl_multi_perform (multi_handle=0x7ffef800a668, running_handles=0x7fff127fa870) at multi.c:1759 #11 0x00007ffff7652103 in easy_transfer (multi=0x7ffef800a668) at easy.c:705 #12 0x00007ffff7652311 in easy_perform (data=0x7ffef8000a78, events=false) at easy.c:793 #13 0x00007ffff7652364 in curl_easy_perform (easy=0x7ffef8000a78) at easy.c:812 #14 ... 

Première chose: lancez-le avec le débogueur (ou obtenez un fichier core dump) pour savoir où il échoue réellement.

Je ne suis pas sûr que cela puisse être le problème … mais en regardant la documentation , la fonction que vous passez dans CURLOPT_WRITEFUNCTION doit avoir la signature suivante.

 size_t function( char *ptr, size_t size, size_t nmemb, void *userdata); 

Cependant dans votre cas:

 size_t writeToSsortingng(const void * ptr, size_t size, size_t count, FILE * stream); 

Apparemment, l’implémentation par défaut de CURLOPT_WRITEFUNCTION attend un fichier FILE *, mais sous la forme * vide

Le problème était dans les détails que j’ai complètement mal compris.

 curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 ); 

L’effet de CURLOPT_NOSIGNAL empêche libcurl de gérer les signaux! Mon interprétation originale était complètement inverse. L’erreur s’est produite parce que sur OS X, cela fonctionne [et la gestion des tuyaux existe également], donc j’ai supposé que la “gestion des signaux” était correcte. Je ne sais pas pourquoi sur OS X le même bug ne s’est pas présenté. En tout cas, j’ai supprimé cette ligne et cela fonctionne parfaitement.

Et, bien sûr, une autre solution possible consiste à définir explicitement ir à zéro:

 curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 0 );