2013-10-10 5 views
5

मैं अपने सर्वर प्रोग्राम में ओपनएसएसएल समर्थन जोड़ने पर काम कर रहा हूं, और आम तौर पर यह बहुत अच्छी तरह से काम कर रहा है, लेकिन मुझे एक समस्या आई है।ओपनएसएसएल मुझे "एक फ़ंक्शन कहलाता है जिसे आपको कॉल नहीं करना चाहिए" त्रुटि क्यों देता है?

सबसे पहले, कुछ पृष्ठभूमि: सर्वर एकल-थ्रेडेड है और एक साथ कई क्लाइंट को संभालने के लिए गैर-अवरुद्ध I/O और एक चुनिंदा() लूप का उपयोग करता है। सर्वर libssl.0.9.8.dylib और lib crypto.0.9.8.dylib से जुड़ा हुआ है (यानी मैकोज़/एक्स 10.8.5 द्वारा/usr/lib में प्रदान की गई लाइब्रेरी)। ग्राहक < -> सर्वर प्रोटोकॉल एक मालिकाना पूर्ण-डुप्लेक्स संदेश प्रोटोकॉल है; यानी, क्लाइंट और सर्वर को किसी भी समय डेटा भेजने और प्राप्त करने की अनुमति है, और ग्राहक < -> सर्वर टीसीपी कनेक्शन अनिश्चित काल तक जुड़े रहते हैं (यानी जब तक ग्राहक या सर्वर डिस्कनेक्ट करने का निर्णय नहीं लेता)।

समस्या यह है: मेरे क्लाइंट सर्वर से कनेक्ट हो सकते हैं, और डेटा भेजना और प्राप्त करना ठीक है (अब मुझे SSL_ERROR_WANT_WRITE और SSL_ERROR_WANT_READ तर्क सॉर्ट किया गया है) ... लेकिन यदि कोई सर्वर स्वीकार करता है() 'नया क्लाइंट कनेक्शन जबकि अन्य ग्राहक डेटा भेजने या प्राप्त करने के बीच में हैं, एसएसएल परत तोड़ने लगती है। विशेष रूप से, सर्वर के तुरंत बाद सेट-एसएसएल() दिनचर्या (नीचे दिखाया गया) नया स्वीकार्य सॉकेट सेट करने के लिए चलाता है, SSL_read() एक या अधिक (पूर्व-मौजूदा) क्लाइंट के सॉकेट पर वापस आ जाएगा -1, और

SSL_read() ERROR: 5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248: 

इस त्रुटि पहले प्रकट होता है के बाद, सर्वर मोटे तौर पर कार्य करना बंद कर: ERR_print_errors_fp (stderr) इस उत्पादन देता है। डाटा आंदोलन बंद हो जाता है, और अगर मैं किसी अन्य क्लाइंट कनेक्ट करने का प्रयास मैं अक्सर इस त्रुटि मिलती है:

SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578: 

यह मेरा परीक्षण परिदृश्य में समय का लगभग 25% होता है। यदि मैं सुनिश्चित करता हूं कि नया क्लाइंट कनेक्ट होने पर मेरे पूर्व-मौजूदा क्लाइंट कनेक्शन निष्क्रिय हैं (कोई डेटा भेजा या प्राप्त नहीं किया गया है), यह कभी नहीं होता है। क्या किसी को पता है कि यहां क्या गलत हो रहा है? क्या मुझे ओपनएसएसएल बग मिला है, या क्या कुछ विवरण है जो मैं देख रहा हूं? यदि यह उपयोगी है, तो मेरे प्रोग्राम से कुछ प्रासंगिक कोड नीचे चिपकाया गया है। openssl-उपयोगकर्ताओं की मेलिंग सूची पर

// Socket setup routine, called when the server accepts a new TCP socket 
int SSLSession :: SetupSSL(int sockfd) 
{ 
    _ctx = SSL_CTX_new(SSLv23_method()); 
    if (_ctx) 
    { 
    SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); 

    _ssl = SSL_new(_ctx); 
    if (_ssl) 
    { 
     _sbio = BIO_new_socket(sockfd, BIO_NOCLOSE); 
     if (_sbio) 
     { 
      SSL_set_bio(_ssl, _sbio, _sbio); 
      SSL_set_accept_state(_ssl); 

      BIO_set_nbio(_sbio, !blocking); 
      ERR_print_errors_fp(stderr); 

      return RESULT_SUCCESS; 
     } 
     else fprintf(stderr, "SSLSession: BIO_new_socket() failed!\n"); 
    } 
    else fprintf(stderr, "SSLSession: SSL_new() failed!\n"); 
    } 
    else fprintf(stderr, "SSLSession: SSL_CTX_new() failed!\n"); 

    return RESULT_FAILURE; 
} 

// Socket read routine -- returns number of bytes read from SSL-land 
int32 SSLSession :: Read(void *buffer, uint32 size) 
{ 
    if (_ssl == NULL) return -1; 

    int32 bytes = SSL_read(_ssl, buffer, size); 
    if (bytes > 0) 
    { 
    _sslState &= ~(SSL_STATE_READ_WANTS_READABLE_SOCKET | SSL_STATE_READ_WANTS_WRITEABLE_SOCKET); 
    } 
    else if (bytes == 0) return -1; // connection was terminated 
    else 
    { 
    int err = SSL_get_error(_ssl, bytes); 
    if (err == SSL_ERROR_WANT_WRITE) 
    { 
     // We have to wait until our socket is writeable, and then repeat our SSL_read() call. 
     _sslState &= ~SSL_STATE_READ_WANTS_READABLE_SOCKET; 
     _sslState |= SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else if (err == SSL_ERROR_WANT_READ) 
    { 
     // We have to wait until our socket is readable, and then repeat our SSL_read() call. 
     _sslState |= SSL_STATE_READ_WANTS_READABLE_SOCKET; 
     _sslState &= ~SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else 
    { 
     fprintf(stderr, "SSL_read() ERROR: "); 
     ERR_print_errors_fp(stderr); 
    } 
    } 
    return bytes; 
} 

// Socket write routine -- returns number of bytes written to SSL-land 
int32 SSLSession :: Write(const void *buffer, uint32 size) 
{ 
    if (_ssl == NULL) return -1; 

    int32 bytes = SSL_write(_ssl, buffer, size); 
    if (bytes > 0) 
    { 
    _sslState &= ~(SSL_STATE_WRITE_WANTS_READABLE_SOCKET | SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET); 
    } 
    else if (bytes == 0) return -1; // connection was terminated 
    else 
    { 
    int err = SSL_get_error(_ssl, bytes); 
    if (err == SSL_ERROR_WANT_READ) 
    { 
     // We have to wait until our socket is readable, and then repeat our SSL_write() call. 
     _sslState |= SSL_STATE_WRITE_WANTS_READABLE_SOCKET; 
     _sslState &= ~SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else if (err == SSL_ERROR_WANT_WRITE) 
    { 
     // We have to wait until our socket is writeable, and then repeat our SSL_write() call. 
     _sslState &= ~SSL_STATE_WRITE_WANTS_READABLE_SOCKET; 
     _sslState |= SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else 
    { 
     fprintf(stderr,"SSL_write() ERROR!"); 
     ERR_print_errors_fp(stderr); 
    } 
    } 
    return bytes; 
} 

उत्तर

7

मुझे किसी ने इसके यह पता लगाने में मदद मिली; समस्या यह थी कि मैं SSLS23_method() के साथ अपना एसएसएल सत्र स्थापित कर रहा था, और SSLv23_method() का उपयोग करते समय, आपको एसएसएल_पेंडिंग() को कॉल नहीं करना चाहिए जब तक कि एसएसएल हैंडशेक ने प्रोटोकॉल (एसएसएलवी 2, एसएसएलवी 3, टीएलएसवी 1, आदि) पर बातचीत समाप्त नहीं की है। यह वास्तव में उपयोग करने जा रहा है।

चूंकि मेरे एप्लिकेशन को एसएसएल के पुराने संस्करणों के साथ संगतता की आवश्यकता नहीं है, इसलिए मेरे लिए त्वरित कार्य-आसपास SSLv23_method() को SSLv23_method() के बजाय सेटअप के दौरान कॉल करना है। यदि पिछली संगतता की आवश्यकता होती है, तो मुझे प्रोटोकॉल वार्ता पूर्ण होने पर पता लगाने का कुछ तरीका पता लगाना होगा और तब तक SSL_pending() को कॉल करने से बचें; लेकिन अब मैं इस मुद्दे को अनदेखा कर रहा हूं क्योंकि मुझे उस कार्यक्षमता की आवश्यकता नहीं है।

संबंधित मुद्दे

 संबंधित मुद्दे