SSL_shutdown is messy and often unneeded; disable it by default

svn: r2766
This commit is contained in:
Matthew Flatt 2006-04-24 19:05:56 +00:00
parent 812f9b0257
commit 1d50d7b176

View File

@ -19,7 +19,8 @@
(module mzssl2 mzscheme
(require (lib "foreign.ss")
(lib "port.ss")
(lib "etc.ss"))
(lib "etc.ss")
(lib "kw.ss"))
(provide ssl-available?
@ -100,6 +101,9 @@
(define-ssl SSL_CTX_new (_SSL_METHOD* -> _SSL_CTX*))
(define-ssl SSL_CTX_free (_SSL_CTX* -> _void))
(define-ssl SSL_CTX_ctrl (_SSL_CTX* _int _long _pointer -> _long))
(define (SSL_CTX_set_mode ctx m)
(SSL_CTX_ctrl ctx SSL_CTRL_MODE m #f))
(define-ssl SSL_CTX_set_verify (_SSL_CTX* _int _pointer -> _void))
(define-ssl SSL_CTX_use_certificate_chain_file (_SSL_CTX* _bytes -> _int))
@ -140,6 +144,9 @@
(define SSL_VERIFY_PEER #x01)
(define SSL_VERIFY_FAIL_IF_NO_PEER_CERT #x02)
(define SSL_MODE_ENABLE_PARTIAL_WRITE #x01)
(define SSL_CTRL_MODE 33)
(define-mzscheme scheme_start_atomic (-> _void))
(define-mzscheme scheme_end_atomic (-> _void))
(define-mzscheme scheme_make_custodian (_pointer -> _scheme))
@ -219,7 +226,9 @@
(define-struct mzssl (ssl i o r-bio w-bio pipe-r pipe-w
buffer lock
flushing? must-write must-read
refcount close? finalizer-cancel))
refcount
close-original? shutdown-on-close?
finalizer-cancel))
(define (make-immobile-bytes n)
(if (regexp-match #rx#"3m" (path->bytes (system-library-subpath)))
@ -264,6 +273,7 @@
(atomically ; so we reliably register the finalizer
(let ([ctx (SSL_CTX_new meth)])
(check-valid ctx who "context creation")
(SSL_CTX_set_mode ctx SSL_MODE_ENABLE_PARTIAL_WRITE)
(register-finalizer ctx (lambda (v) (SSL_CTX_free v)))
((if client? make-ssl-client-context make-ssl-server-context) ctx))))))
@ -278,7 +288,9 @@
(define (get-context who context-or-encrypt-method client?)
(if (ssl-context? context-or-encrypt-method)
(ssl-context-ctx context-or-encrypt-method)
(SSL_CTX_new (encrypt->method who "context" context-or-encrypt-method client?))))
(let ([ctx (SSL_CTX_new (encrypt->method who "context" context-or-encrypt-method client?))])
(SSL_CTX_set_mode ctx SSL_MODE_ENABLE_PARTIAL_WRITE)
ctx)))
(define (get-context/listener who ssl-context-or-listener)
(cond
@ -361,7 +373,7 @@
(atomically
(set-box! (mzssl-finalizer-cancel mzssl) #f)
(SSL_free (mzssl-ssl mzssl)))
(when (mzssl-close? mzssl)
(when (mzssl-close-original? mzssl)
(close-input-port (mzssl-i mzssl))
(close-output-port (mzssl-o mzssl)))))
@ -692,29 +704,28 @@
(semaphore-peek-evt (mzssl-flushing? mzssl))
;; issue shutdown (i.e., EOF on read end)
(begin
(let loop ([cnt 0])
(let ([out-blocked? (pump-output mzssl)])
(let ([n (SSL_shutdown (mzssl-ssl mzssl))])
(unless (= n 1)
(let ([err (SSL_get_error (mzssl-ssl mzssl) n)])
(cond
[(= err SSL_ERROR_WANT_READ)
(pump-input-once mzssl (if out-blocked? (mzssl-o mzssl) #t))
(loop cnt)]
[(= err SSL_ERROR_WANT_WRITE)
(pump-output-once mzssl #t #f)
(loop cnt)]
[else
(if (= n 0)
;; When 0 is returned, the SSL object no longer correctly
;; reports what it wants (e.g., a write). If pumping blocked
;; or if this is our first time around, then wait on the
;; underlying output and try again.
(when (or (zero? cnt) out-blocked?)
(flush-ssl mzssl #f)
(loop (add1 cnt)))
(error 'read-bytes "SSL shutdown failed ~a"
(get-error-message (ERR_get_error))))]))))))
(when (mzssl-shutdown-on-close? mzssl)
(let loop ([cnt 0])
(let ([out-blocked? (flush-ssl mzssl #f)])
(let ([n (SSL_shutdown (mzssl-ssl mzssl))])
(unless (= n 1)
(let ([err (SSL_get_error (mzssl-ssl mzssl) n)])
(cond
[(= err SSL_ERROR_WANT_READ)
(pump-input-once mzssl (if out-blocked? (mzssl-o mzssl) #t))
(loop cnt)]
[(= err SSL_ERROR_WANT_WRITE)
(pump-output-once mzssl #t #f)
(loop cnt)]
[else
(if (= n 0)
;; When 0 is returned, the SSL object doesn't correctly
;; report what it wants (e.g., a write). Send everything
;; out that we have and try again, up to 10 times.
(unless (cnt . >= . 10)
(loop (add1 cnt)))
(error 'read-bytes "SSL shutdown failed ~a"
(get-error-message (ERR_get_error))))])))))))
(mzssl-release mzssl)
#f)))]
[close-loop
@ -738,8 +749,14 @@
[() buffer-mode]
[(mode) (set! buffer-mode mode)]))))
(define (ports->ssl-ports i o context-or-encrypt-method connect/accept close?)
(wrap-ports 'port->ssl-ports i o context-or-encrypt-method connect/accept close?))
(define/kw (ports->ssl-ports i o
#:key
[context #f]
[encrypt default-encrypt]
[mode 'connect]
[close-original? #f]
[shutdown-on-close? #f])
(wrap-ports 'port->ssl-ports i o (or context encrypt) mode close-original? shutdown-on-close?))
(define (create-ssl who context-or-encrypt-method connect/accept)
(atomically ; so we register the finalizer (and it's ok since everything is non-blocking)
@ -796,7 +813,7 @@
;; Return SSL and the cancel boxL:
(values ssl cancel r-bio w-bio connect?)))))))))
(define (wrap-ports who i o context-or-encrypt-method connect/accept close?)
(define (wrap-ports who i o context-or-encrypt-method connect/accept close? shutdown-on-close?)
(unless (input-port? i)
(raise-type-error who "input port" i))
(unless (output-port? o)
@ -808,7 +825,10 @@
(let-values ([(buffer) (make-bytes 4096)]
[(pipe-r pipe-w) (make-pipe)]
[(cancel) (box #t)])
(let ([mzssl (make-mzssl ssl i o r-bio w-bio pipe-r pipe-w buffer (make-semaphore 1) #f #f #f 2 close? cancel)])
(let ([mzssl (make-mzssl ssl i o r-bio w-bio pipe-r pipe-w
buffer (make-semaphore 1) #f #f #f 2
close? shutdown-on-close?
cancel)])
(let loop ()
(let ([status (if connect?
(SSL_connect ssl)
@ -865,7 +885,7 @@
(close-input-port i)
(close-output-port o)
(raise exn))])
(wrap-ports who i o (ssl-listener-mzctx ssl-listener) 'accept #t))))
(wrap-ports who i o (ssl-listener-mzctx ssl-listener) 'accept #t #f))))
(define (ssl-accept ssl-listener)
(do-ssl-accept 'ssl-accept tcp-accept ssl-listener))
@ -883,7 +903,7 @@
(close-input-port i)
(close-output-port o)
(raise exn))])
(wrap-ports who i o client-context-or-protocol-symbol 'connect #t))))
(wrap-ports who i o client-context-or-protocol-symbol 'connect #t #f))))
(define ssl-connect
(opt-lambda (hostname port-k [client-context-or-protocol-symbol default-encrypt])