iproxy contains a loop which forwards data between host and device. All it does is reading data from one socket and writing into another. Writing is implemented like this:
int sent = 0;
while (sent < r) {
int s = socket_send(cdata->sfd, buffer+sent, r-sent);
if (s <= 0) {
break;
}
sent += s;
}
Where socket_send is defined like this in libimobiledevice-glue:
int socket_send(int fd, void *data, size_t length)
{
int flags = 0;
int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT);
if (res <= 0) {
return res;
}
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
#endif
int s = (int)send(fd, data, length, flags);
if (s < 0) {
#ifdef _WIN32
errno = WSAError_to_errno(WSAGetLastError());
#endif
return -errno;
}
return s;
}
Where socket_check_fd does poll or select on fd waiting for it to become writable.
The code is reasonable: it expects that socket_check_fd completing successfully implies that send will either complete successfully or fail with some non-transient error. It turns out that this expectation does not always hold: send might still occasionally return EAGAIN even if socket_check_fd returns successfully.
This happens on Mac OS X when socket_check_fd is using select (rather than poll): select might return that fd is writable but send will fail with EAGAIN. This leads to a very confusing data loss: socket_send fails to forward a chunk of data but the socket is still perfectly fine and subsequent writes and reads from this socket succeed just fine.
poll+send does not seem to have such a bug, at least I could not reproduce it in my testing - however it might still be a good idea to guard against EAGAIN somewhere, e.g. by retrying the whole socket_check_fd and send dance.
iproxycontains a loop which forwards data between host and device. All it does is reading data from one socket and writing into another. Writing is implemented like this:Where
socket_sendis defined like this inlibimobiledevice-glue:Where
socket_check_fddoespollorselectonfdwaiting for it to become writable.The code is reasonable: it expects that
socket_check_fdcompleting successfully implies thatsendwill either complete successfully or fail with some non-transient error. It turns out that this expectation does not always hold:sendmight still occasionally returnEAGAINeven ifsocket_check_fdreturns successfully.This happens on Mac OS X when
socket_check_fdis usingselect(rather thanpoll):selectmight return thatfdis writable butsendwill fail withEAGAIN. This leads to a very confusing data loss:socket_sendfails to forward a chunk of data but the socket is still perfectly fine and subsequent writes and reads from this socket succeed just fine.poll+senddoes not seem to have such a bug, at least I could not reproduce it in my testing - however it might still be a good idea to guard againstEAGAINsomewhere, e.g. by retrying the wholesocket_check_fdandsenddance.