diff options
-rw-r--r-- | qemu_pipe/include/qemu_pipe.h | 6 | ||||
-rw-r--r-- | qemu_pipe/qemu_pipe.cpp | 72 |
2 files changed, 28 insertions, 50 deletions
diff --git a/qemu_pipe/include/qemu_pipe.h b/qemu_pipe/include/qemu_pipe.h index 16486c087..098749899 100644 --- a/qemu_pipe/include/qemu_pipe.h +++ b/qemu_pipe/include/qemu_pipe.h | |||
@@ -28,8 +28,10 @@ extern "C" { | |||
28 | // This file descriptor can be used as a standard pipe/socket descriptor. | 28 | // This file descriptor can be used as a standard pipe/socket descriptor. |
29 | // | 29 | // |
30 | // 'pipeName' is the name of the emulator service you want to connect to, | 30 | // 'pipeName' is the name of the emulator service you want to connect to, |
31 | // and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles'). | 31 | // and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles'). |
32 | // | 32 | // For backward compatibility, the 'pipe:' prefix can be omitted, and in |
33 | // that case, qemu_pipe_open will add it for you. | ||
34 | |||
33 | // On success, return a valid file descriptor, or -1/errno on failure. E.g.: | 35 | // On success, return a valid file descriptor, or -1/errno on failure. E.g.: |
34 | // | 36 | // |
35 | // EINVAL -> unknown/unsupported pipeName | 37 | // EINVAL -> unknown/unsupported pipeName |
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp index a4529deb8..beeccb07f 100644 --- a/qemu_pipe/qemu_pipe.cpp +++ b/qemu_pipe/qemu_pipe.cpp | |||
@@ -22,6 +22,10 @@ | |||
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <stdio.h> | 23 | #include <stdio.h> |
24 | 24 | ||
25 | #include <android-base/file.h> | ||
26 | |||
27 | using android::base::ReadFully; | ||
28 | using android::base::WriteFully; | ||
25 | 29 | ||
26 | // Define QEMU_PIPE_DEBUG if you want to print error messages when an error | 30 | // Define QEMU_PIPE_DEBUG if you want to print error messages when an error |
27 | // occurs during pipe operations. The macro should simply take a printf-style | 31 | // occurs during pipe operations. The macro should simply take a printf-style |
@@ -30,29 +34,9 @@ | |||
30 | # define QEMU_PIPE_DEBUG(...) (void)0 | 34 | # define QEMU_PIPE_DEBUG(...) (void)0 |
31 | #endif | 35 | #endif |
32 | 36 | ||
33 | // Try to open a new Qemu fast-pipe. This function returns a file descriptor | ||
34 | // that can be used to communicate with a named service managed by the | ||
35 | // emulator. | ||
36 | // | ||
37 | // This file descriptor can be used as a standard pipe/socket descriptor. | ||
38 | // | ||
39 | // 'pipeName' is the name of the emulator service you want to connect to, | ||
40 | // and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles'). | ||
41 | // | ||
42 | // On success, return a valid file descriptor, or -1/errno on failure. E.g.: | ||
43 | // | ||
44 | // EINVAL -> unknown/unsupported pipeName | ||
45 | // ENOSYS -> fast pipes not available in this system. | ||
46 | // | ||
47 | // ENOSYS should never happen, except if you're trying to run within a | ||
48 | // misconfigured emulator. | ||
49 | // | ||
50 | // You should be able to open several pipes to the same pipe service, | ||
51 | // except for a few special cases (e.g. GSM modem), where EBUSY will be | ||
52 | // returned if more than one client tries to connect to it. | ||
53 | int qemu_pipe_open(const char* pipeName) { | 37 | int qemu_pipe_open(const char* pipeName) { |
54 | // Sanity check. | 38 | // Sanity check. |
55 | if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) { | 39 | if (!pipeName) { |
56 | errno = EINVAL; | 40 | errno = EINVAL; |
57 | return -1; | 41 | return -1; |
58 | } | 42 | } |
@@ -66,48 +50,41 @@ int qemu_pipe_open(const char* pipeName) { | |||
66 | 50 | ||
67 | // Write the pipe name, *including* the trailing zero which is necessary. | 51 | // Write the pipe name, *including* the trailing zero which is necessary. |
68 | size_t pipeNameLen = strlen(pipeName); | 52 | size_t pipeNameLen = strlen(pipeName); |
69 | ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U)); | 53 | if (WriteFully(fd, pipeName, pipeNameLen + 1U)) { |
70 | if (ret != (ssize_t)pipeNameLen + 1) { | 54 | return fd; |
71 | QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s", | 55 | } |
72 | __FUNCTION__, pipeName, strerror(errno)); | 56 | |
73 | if (ret == 0) { | 57 | // now, add 'pipe:' prefix and try again |
74 | errno = ECONNRESET; | 58 | // Note: host side will wait for the trailing '\0' to start |
75 | } else if (ret > 0) { | 59 | // service lookup. |
76 | errno = EINVAL; | 60 | const char pipe_prefix[] = "pipe:"; |
77 | } | 61 | if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) && |
78 | return -1; | 62 | WriteFully(fd, pipeName, pipeNameLen + 1U)) { |
63 | return fd; | ||
79 | } | 64 | } |
80 | return fd; | 65 | QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s", |
66 | __FUNCTION__, pipeName, strerror(errno)); | ||
67 | close(fd); | ||
68 | return -1; | ||
81 | } | 69 | } |
82 | 70 | ||
83 | // Send a framed message |buff| of |len| bytes through the |fd| descriptor. | ||
84 | // This really adds a 4-hexchar prefix describing the payload size. | ||
85 | // Returns 0 on success, and -1 on error. | ||
86 | int qemu_pipe_frame_send(int fd, const void* buff, size_t len) { | 71 | int qemu_pipe_frame_send(int fd, const void* buff, size_t len) { |
87 | char header[5]; | 72 | char header[5]; |
88 | snprintf(header, sizeof(header), "%04zx", len); | 73 | snprintf(header, sizeof(header), "%04zx", len); |
89 | ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4)); | 74 | if (!WriteFully(fd, header, 4)) { |
90 | if (ret != 4) { | ||
91 | QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno)); | 75 | QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno)); |
92 | return -1; | 76 | return -1; |
93 | } | 77 | } |
94 | ret = TEMP_FAILURE_RETRY(write(fd, buff, len)); | 78 | if (!WriteFully(fd, buff, len)) { |
95 | if (ret != (ssize_t)len) { | ||
96 | QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno)); | 79 | QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno)); |
97 | return -1; | 80 | return -1; |
98 | } | 81 | } |
99 | return 0; | 82 | return 0; |
100 | } | 83 | } |
101 | 84 | ||
102 | // Read a frame message from |fd|, and store it into |buff| of |len| bytes. | ||
103 | // If the framed message is larger than |len|, then this returns -1 and the | ||
104 | // content is lost. Otherwise, this returns the size of the message. NOTE: | ||
105 | // empty messages are possible in a framed wire protocol and do not mean | ||
106 | // end-of-stream. | ||
107 | int qemu_pipe_frame_recv(int fd, void* buff, size_t len) { | 85 | int qemu_pipe_frame_recv(int fd, void* buff, size_t len) { |
108 | char header[5]; | 86 | char header[5]; |
109 | ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4)); | 87 | if (!ReadFully(fd, header, 4)) { |
110 | if (ret != 4) { | ||
111 | QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno)); | 88 | QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno)); |
112 | return -1; | 89 | return -1; |
113 | } | 90 | } |
@@ -122,8 +99,7 @@ int qemu_pipe_frame_recv(int fd, void* buff, size_t len) { | |||
122 | len); | 99 | len); |
123 | return -1; | 100 | return -1; |
124 | } | 101 | } |
125 | ret = TEMP_FAILURE_RETRY(read(fd, buff, size)); | 102 | if (!ReadFully(fd, buff, size)) { |
126 | if (ret != (ssize_t)size) { | ||
127 | QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s", | 103 | QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s", |
128 | strerror(errno)); | 104 | strerror(errno)); |
129 | return -1; | 105 | return -1; |