Closed MarSoft closed 3 weeks ago
Solution of nginx:
#define ngx_socket_errno WSAGetLastError()
u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); // -> FormatMessage(err)
#define ngx_socket_errno errno
u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); // -> strerror(err);
nginx solution looks good, there is more errors with windows socket, than just from send, also recv and select needs check for WSA there is also incosistency in error values, when it comes to socket function in glue, some return -1, and caller needs to resolve errno, while some return -errno (which of course doesn't work properly on windows). that needs to be put in line.
when i think about all that, if we want to propagate errno further (Which seems to be the case, looking at libimobiledevice and libusbmuxd), probly safest aproach will be to wrap every used socket function inside some function in glue, then if return value of said function is SOCKET_ERROR (on WIN32 it's -1), then we can translate WSAGetLastError to errno, and set errno to said value, because on WIN32 errno will be 0 anyways ... then you can let rest of code use errno and strerror.
other option will be to never read either errno or strerror directly, but make wrappers around those two, and handle them accordingly (like nginx does), but seems too much pain to me.
@MarSoft I came up with this fc10c88395f3fefd3b30f3ef9354c45cef7136a6
When building for Win32, socket code from the glue library gets error codes with
WSAGetLastError()
function rather thanerrno
variable, which is correct: e.g. 1 When some error happens, we sometimes seterrno
ourselves: 1 2 3 In other cases, when we detect that error happened we don't toucherrno
and just return-1
to indicate error: 1 But the code inlibusbmuxd
always expects thaterrno
will be set to some non-zero value if error happened: 1 2 3 As a result, on Windows some socket-related errors are not "masked" bylibusbmuxd
becauseerrno
is0
. This results to bugs later on, when the surrounding code thinks that no error have happened.This should be fixed in either of the following approaches:
libusbmuxd
(and probably other users ofsocket_*
code) to not expect non-zeroerrno
in case of error:if (res < 0 && errno != 0) res = -errno;
etcWSAGetLastError()
codes to correspondingerrno
values insocket.c
functions. This may be hard to achieve but would give the best results for the surrounding code which would then be able to properly report errors to the user.errno = WSAGetLastError()
to return WSA error code (which is always > 10000 in case of error), orerrno = EIO
to always return I/O error if any WSA error happened (this is ugly though), or maybe map some WSA errors to correspondingerrno
values and return others as is.I think the last option would be the best one. We can map several known WSA error codes to
errno
values, and for other errors just seterrno
to the raw WSA code just to indicate that an error have happened. This will abstract platform-dependent error handling logic from the outer code, and still allow it to handle some known errors likeEAGAIN
. The only problem with this approach is that the outer code won't be able to properly describe an error to the user, because WSA error codes won't be handled bystrerror
- for example, here. This code is also where partial error mapping would be helpful - if we mapWSAECONNREFUSED
toECONNREFUSED
maybe some WSA code toENODEV
thenidevice_connect
will return the right errors.