Fix "adb sync" (and "adb push") error reporting.

This patch ensures that we read any error response from the server if the
server closes the connection. Unfortunately, that's not sufficient to ensure
that we always see the server's error message --- sometimes the data just
gets thrown away because we keep writing without reading. Setting SO_LINGER
avoids this.

Bug: http://b/25230872
Change-Id: I96c019cc72bd139198de79bf29e6536cc462c20f
This commit is contained in:
Elliott Hughes 2015-11-20 22:01:06 -08:00
parent ddf41f1ad0
commit cc65c3b9f8
4 changed files with 65 additions and 62 deletions

View File

@ -33,21 +33,17 @@ static alistener listener_list = {
};
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
asocket *s;
if(ev & FDE_READ) {
if (ev & FDE_READ) {
struct sockaddr addr;
socklen_t alen;
int fd;
socklen_t alen = sizeof(addr);
int fd = adb_socket_accept(_fd, &addr, &alen);
if (fd < 0) return;
alen = sizeof(addr);
fd = adb_socket_accept(_fd, &addr, &alen);
if(fd < 0) return;
int rcv_buf_size = CHUNK_SIZE;
adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
adb_socket_setbufsize(fd, CHUNK_SIZE);
s = create_local_socket(fd);
if(s) {
asocket* s = create_local_socket(fd);
if (s) {
connect_to_smartsocket(s);
return;
}

View File

@ -103,7 +103,7 @@ class SyncConnection {
// Sending header, payload, and footer in a single write makes a huge
// difference to "adb sync" performance.
bool SendSmallFile(const char* path_and_mode,
const char* rpath,
const char* lpath, const char* rpath,
unsigned mtime,
const char* data, size_t data_length) {
Print(rpath);
@ -139,8 +139,7 @@ class SyncConnection {
req_done->path_length = mtime;
p += sizeof(SyncRequest);
if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
total_bytes += data_length;
return true;
}
@ -164,31 +163,27 @@ class SyncConnection {
int lfd = adb_open(lpath, O_RDONLY);
if (lfd < 0) {
Error("cannot open '%s': %s", lpath, strerror(errno));
Error("opening '%s' locally failed: %s", lpath, strerror(errno));
return false;
}
syncsendbuf sbuf;
sbuf.id = ID_DATA;
while (true) {
int ret = adb_read(lfd, sbuf.data, max);
if (ret <= 0) {
if (ret < 0) {
Error("cannot read '%s': %s", lpath, strerror(errno));
adb_close(lfd);
return false;
}
int bytes_read = adb_read(lfd, sbuf.data, max);
if (bytes_read == -1) {
Error("reading '%s' locally failed: %s", lpath, strerror(errno));
adb_close(lfd);
return false;
} else if (bytes_read == 0) {
break;
}
sbuf.size = ret;
if (!WriteFdExactly(fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
adb_close(lfd);
return false;
}
total_bytes += ret;
sbuf.size = bytes_read;
WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
bytes_copied += ret;
total_bytes += bytes_read;
bytes_copied += bytes_read;
int percentage = static_cast<int>(bytes_copied * 100 / total_size);
Printf("%s: %d%%", rpath, percentage);
@ -199,12 +194,7 @@ class SyncConnection {
syncmsg msg;
msg.data.id = ID_DONE;
msg.data.size = mtime;
if (!WriteFdExactly(fd, &msg.data, sizeof(msg.data))) {
Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
return false;
}
return true;
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
}
bool CopyDone(const char* from, const char* to) {
@ -297,6 +287,27 @@ class SyncConnection {
return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
}
bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
if (!WriteFdExactly(fd, data, data_length)) {
if (errno == ECONNRESET) {
// Assume adbd told us why it was closing the connection, and
// try to read failure reason from adbd.
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
} else if (msg.status.id != ID_FAIL) {
Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
} else {
ReportCopyFailure(from, to, msg);
}
} else {
Error("%zu-byte write failed: %s", data_length, strerror(errno));
}
_exit(1);
}
return true;
}
static uint64_t CurrentTimeMs() {
struct timeval tv;
gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
@ -362,7 +373,9 @@ static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
}
buf[data_length++] = '\0';
if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, mtime, buf, data_length)) return false;
if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
return false;
}
return sc.CopyDone(lpath, rpath);
#endif
}
@ -383,7 +396,8 @@ static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
return false;
}
if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, mtime, data.data(), data.size())) {
if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
data.data(), data.size())) {
return false;
}
} else {

View File

@ -394,6 +394,18 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) {
void file_sync_service(int fd, void* cookie) {
std::vector<char> buffer(SYNC_DATA_MAX);
// If there's a problem on the device, we'll send an ID_FAIL message and
// close the socket. Unfortunately the kernel will sometimes throw that
// data away if the other end keeps writing without reading (which is
// the normal case with our protocol --- they won't read until the end).
// So set SO_LINGER to give the client 20s to get around to reading our
// failure response. Without this, the other side's ability to report
// useful errors is reduced.
struct linger l;
l.l_onoff = 1;
l.l_linger = 20;
adb_setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
while (handle_sync_command(fd, buffer)) {
}

View File

@ -242,18 +242,6 @@ extern int adb_setsockopt(int fd, int level, int optname, const void* optva
#undef setsockopt
#define setsockopt ___xxx_setsockopt
static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
{
int opt = bufsize;
return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt));
}
static __inline__ void disable_tcp_nagle( int fd )
{
int on = 1;
adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on));
}
extern int adb_socketpair( int sv[2] );
static __inline__ int adb_is_absolute_host_path(const char* path) {
@ -670,18 +658,6 @@ static __inline__ int adb_thread_setname(const std::string& name) {
#endif
}
static __inline__ int adb_socket_setbufsize(int fd, int bufsize )
{
int opt = bufsize;
return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
}
static __inline__ void disable_tcp_nagle(int fd)
{
int on = 1;
setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
}
static __inline__ int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen )
{
return setsockopt( fd, level, optname, optval, optlen );
@ -739,4 +715,9 @@ static __inline__ unsigned long adb_thread_id()
#endif /* !_WIN32 */
static inline void disable_tcp_nagle(int fd) {
int off = 1;
adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
}
#endif /* _ADB_SYSDEPS_H */