Skip to content

iproxy (or socket_send) should better guard against EAGAIN #151

@mraleph

Description

@mraleph

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions