-
Notifications
You must be signed in to change notification settings - Fork 144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Forward transport errors from Secure Session callbacks #375
Conversation
We will need to return TransportErrors from Secure Session methods on failures to extend the ErrorKind enumeration to actually contain the transport error inside its ErrorKind::SessionTransportError variant. This change has a number of implications. First of all, TransportError is not copyable. Therefore we have to let go of the Clone and Copy implementations on the ErrorKind as well as the Clone impl on Error. One should not usually copy errors anyway so this should be okay. Note that Error::kind() now returns a reference to the stored error kind instead of its copy. Another important thing is that TransportError does not implement PartialEq as it is not possible to compare abstract errors in any meaningful way. This implies that we cannot automatically derive implementation of PartialEq for ErrorKind. We have to implement it manually. We need to compare *kinds* of errors here so it is okay to simply ignore the details of transport errors and treat them as equivalent.
Now that we are able to store TransportError inside of a themis::Error we can actually forward the error from the callback to the method call. With this the user can actually see why the transport layer has failed. Use the provided SecureSessionContext to temporarily store the error while the control is still in the C code. Then we extract the error and return it. Such implementation does not support concurrent usage of Secure Session from multiple threads but it's not thread-safe anyway so it is fine to use this approach. We can use negative return values to indicate implementation-specific errors in Secure Session callbacks. The C code returns them as is for us to inspect. While we're here, stop using bare constant "-1" and give it a name. Also, handle the overflow with a different error kind.
} | ||
if length == TRANSPORT_OVERFLOW { | ||
return Err(Error::with_kind(ErrorKind::BufferTooSmall)); | ||
} | ||
if length <= 21 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what mean 21?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A magic number ✨ Actually that's the maximum numerical value of themis_status_t
— THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR.
It is a necessary hack because the current callback API of Secure Session is not able to distinguish between errors and short reads/writes. For example, if secure_session_receive()
returns 15 then it may mean that 15 bytes of data has been received, or it can also mean a THEMIS_DATA_CORRUPT error. There is an outstanding issue for that somewhere...
I guess this constant deserves a name as well.
Ok(received_bytes) => as_isize(received_bytes).unwrap_or(TRANSPORT_OVERFLOW), | ||
Err(error) => { | ||
context.last_error = Some(error); | ||
TRANSPORT_FAILURE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks better with constants usage
} | ||
} | ||
|
||
fn error_kinds_equal(lhs: &ErrorKind, rhs: &ErrorKind) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will be good to add a comment to ErrorKind definition that we should update error_kinds_equal
if some new values will be added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... That's unfortunate but the catch-all branch in this match makes it possible to add a new variant to ErrorKind
without adding a corresponding line to the comparison implementation.
I guess there's no other way around, I'll add a comment and let's hope it will be noticed.
There's another secure_session_receive() call here in this method. It too can return special error codes.
Writing tests for every single method and use case of Secure Session turned out to be useful (surprise-surpise). Then have uncovered that I have missed another place where a special error code may be returned. I guess this should be it. |
And one more usability improvement for Secure Session. Currently it simply ignores and loses any TransportErrors that happen inside the transport callbacks. This was fine when errors were simply
()
but now they can be rich, detailed errors. The users are likely to be interested in the reason why their transport callbacks fail. Let's thread the error through the C call stack and return it the caller.This behavior is currently not tested. I'll add tests in a separate PR which will also improve existing tests for Secure Session. (And note all the breaking changes in the changelog as well.)
Add TransportError to themis::Error
We will need to return TransportErrors from Secure Session methods on failures to extend the ErrorKind enumeration to actually contain the transport error inside its
ErrorKind::SessionTransportError
variant.This change has a number of implications. First of all, TransportError is not copyable. Therefore we have to let go of the
Clone
andCopy
implementations on the ErrorKind as well as the Clone impl on Error. One should not usually copy errors anyway so this should be okay. Note thatError::kind()
now returns a reference to the stored error kind instead of its copy.Another important thing is that TransportError does not implement
PartialEq
as it is not possible to compare abstract errors in any meaningful way. This implies that we cannot automatically derive implementation of PartialEq for ErrorKind. We have to implement it manually. We need to compare kinds of errors here so it is okay to simply ignore the details of transport errors and treat them as equivalent.Forward transport errors from Secure Session callbacks
Now that we are able to store TransportError inside of a
themis::Error
we can actually forward the error from the callback to the method call. With this the user can actually see why the transport layer has failed.Use the provided
SecureSessionContext
to temporarily store the error while the control is still in the C code. Then we extract the error and return it. Such implementation does not support concurrent usage of Secure Session from multiple threads but it's not thread-safe anyway so it is fine to use this approach.We can use negative return values to indicate implementation-specific errors in Secure Session callbacks. The C code returns them as is for us to inspect. While we're here, stop using bare constant
-1
and give it a name. Also, handle the overflow with a different error kind.