[racket] Memory buildup (leak?) when using `copy-port` with SSL connections.

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Dec 18 10:32:52 EST 2014

Is the program reaching the calls to `close-output-port` and
`close-input-port`?

The output port created by `ssl-connect` doesn't send a shutdown
message to the other end of the SSL connection when the port is closed,
because that shutdown action tends to produce errors that have to be
caught. So, my guess is that closing `to-dest` doesn't send a message
that causes the server to close the connection, so `from-dest` never
produces an EOF, and so open ports are accumulated.

If I'm on the right track, you could use plain `tcp-accept` and
`tcp-connect` to create network connections, and then use
`ports->ssl-ports` and specify that closing an output port sends a
shutdown. (Be sure to specify both `#:shutdown-on-close?` and
`#:close-original?`.) You'll need to catch errors raised by
`close-output-port`, though, and use `ssl-abandon-port` if closing an
SSL output port fails.

At Thu, 18 Dec 2014 09:20:46 +0100, Snyder Pearson wrote:
> I build this simple TLS upgrading proxy[2], which sits in front of a TLS
> service and just accepts connections using any SSL/TLS version that Racket
> supports and forwards the data to the service using the default TLS version
> (why would I need this is a long story :)).
> 
> When stress testing this using boom [1], I see significant memory buildup.
> This memory is not released when the test finishes.  It only gets reclaimed
> when I kill the proxy process.  So I suspect there is some kind of memory
> leak going on here.
> 
> In principle, the only values constructed on each iteration of the loop are
> the SSL connection ports, which I'm closing when |pipe| exits.
> 
> Am I using copy-port wrong, or maybe it is itself leaking memory?
> 
> This is using Racket v6.1.1 on Ubuntu 14.10.
> 
> TIA!
> 
> [1] https://github.com/oxtoacart/boom
> 
> [2] Source:
> 
> #lang racket
> 
> (require openssl)
> 
> (define DEBUG #f)
> 
> (define (pipe in out)
>   (thread (λ ()
>              (if DEBUG
>                (copy-port in (current-output-port) out)
>                (copy-port in out))
>              (close-output-port out)
>              (close-input-port in))))
> 
> (define accept (if DEBUG ssl-accept/enable-break ssl-accept))
> (define connect (if DEBUG ssl-connect/enable-break ssl-connect))
> 
> (define listener (ssl-listen 62445))
> (ssl-load-private-key! listener "pk.pem")
> (ssl-load-certificate-chain! listener "cert.pem")
> 
> (let loop ()
>   (let-values (((from-src to-src) (accept listener)))
>     (thread
>       (λ ()
>          (let-values (((from-dest to-dest)
>                             (connect "localhost" 62444 'tls)))
>            (pipe from-src to-dest)
>            (pipe from-dest to-src)))))
>   (loop))
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users


Posted on the users mailing list.