Skip to content

Conversation

@jlhawn
Copy link
Contributor

@jlhawn jlhawn commented May 19, 2016

If the reader() goroutine encounters an unexpected error when reading a packet a series of unwinding steps take place:

  • The reader() goroutine shuts down. A deferred function runs which closes the connection.
  • Close() sends a MessageQuit message to the processMessages() goroutine.
  • The processMessages() goroutine shuts down. A deferred function runs which closes the results channels for any pending requests.
  • These pending request handlers receive a nil *PacketResponse because their response channel has been closed. They then return a not-very-helpful error string: "ldap: channel closed".

This patch updates the reader() goroutine to set a closeErr value on the conn when it encounters an unexpected error reading a packet from the server. The processMessages() deferred function checks for closeErr when it is shutting down due to the connection closing and sends this error in the *PacketResponse values to the pending request handlers before closing those results channels. This allows for the error which caused the shutdown to be bubbled up to all pending request calls.

@jlhawn
Copy link
Contributor Author

jlhawn commented May 19, 2016

@flowhamster Could you please take a look? I thought you might have some thoughts on this based on your recent changes in #57.

@jlhawn
Copy link
Contributor Author

jlhawn commented May 19, 2016

As a before/after example, I wrote a simple ldapsearch tool using this library. Here I am attempting to connect on port 636 (the TLS server port) but I try to force StartTLS (which is obviously incompatible):

ldapsearch --host ldap://openldap.dckr.org:636 --start-tls

Before this patch, I get an error which doesn't explain much:

FATA[0000] Unable to connect to LDAP server: unable to perform StartTLS: LDAP Result Code 200 "": ldap: channel closed

But with this patch applied I get much more helpful error message:

FATA[0000] Unable to connect to LDAP server: unable to perform StartTLS: unable to read LDAP response packet: read tcp 172.17.0.2:59256->52.35.216.26:636: read: connection reset by peer

@jlhawn
Copy link
Contributor Author

jlhawn commented Jun 6, 2016

ping @liggitt and @flowhamster

@jamesboswell
Copy link

+1, this looks like a good change to me. ldap: channel closed certainly isn't as helpful as it could be. Is there any concern with adding closeErr to the Conn struct? Backwards breakage?

conn.go Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like this channel could get double-notified with this change... should we do this as well?

close(message.Channel)
delete(l.chanResults, message.MessageID)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or even wait to add it to l.chanResults until we've written successfully

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've added a close(message.Channel) line below and moved the line which adds the channel to l.chanResults from before writing the packet (above) to after (below).

If the reader() goroutine encounters an unexpected error when reading a packet
a series of unwinding takes place:

- The reader() goroutine shuts down. A deferred function runs which closes the
  connection.
- Close() sends a MessageQuit message to the processMessages() goroutine.
- The processMessages() goroutine shuts down. A deferred function runs which
  closes the results channels for any pending requests.
- These pending request handlers receive a nil *PacketResponse because their
  response channel has been closed. They then return a not-very-helpful error
  string: "ldap: channel closed".

This patch updates the reader() goroutine to set a closeErr value on the conn
when it encounters an unexpected error reading a packet from the server. The
processMessages() deferred function checks for this closeErr when it is
shutting down due to the connection closing and sends this error in the
*PacketResponse values to the pending request handlers *before* closing those
results channels. This allows for the error which caused the shutdown to be
bubbled up to all pending request calls.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
@jlhawn jlhawn force-pushed the improve_read_error branch from 0639e91 to fb58c8d Compare June 14, 2016 18:21
@liggitt liggitt merged commit 8a8cb05 into go-ldap:master Jun 14, 2016
@liggitt
Copy link
Contributor

liggitt commented Jun 14, 2016

thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants