blob: 365d475b1ef08336afd0a3ba94ad381e32ffc76c [file] [log] [blame]
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Contains helper routines dealing with syncronous access to a non-blocking
19 * sokets.
20 */
21
22#include "qemu-common.h"
23#include "errno.h"
David 'Digit' Turnerd413fa52013-12-14 23:35:20 +010024#include "android/iolooper.h"
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010025#include "android/sockets.h"
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080026#include "android/utils/debug.h"
27#include "android/sync-utils.h"
Vladimir Chtchetkine9411a562011-01-19 18:29:27 -080028#include "android/utils/system.h"
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080029
30#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
31
32struct SyncSocket {
33 // Helper for performing synchronous I/O on the socket.
34 IoLooper* iolooper;
35
36 /* Opened socket handle. */
37 int fd;
38};
39
40SyncSocket*
Vladimir Chtchetkine9411a562011-01-19 18:29:27 -080041syncsocket_init(int fd)
42{
43 SyncSocket* sync_socket;
44 ANEW0(sync_socket);
45
46 socket_set_nonblock(fd);
47 sync_socket->iolooper = iolooper_new();
48 sync_socket->fd = fd;
49
50 return sync_socket;
51}
52
53SyncSocket*
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080054syncsocket_connect(int fd, SockAddress* sockaddr, int timeout)
55{
Vladimir Chtchetkine9411a562011-01-19 18:29:27 -080056 IoLooper* looper;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080057 int connect_status;
Vladimir Chtchetkine9411a562011-01-19 18:29:27 -080058 SyncSocket* sync_socket = NULL;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080059
60 socket_set_nonblock(fd);
61
62 for(;;) {
63 connect_status = socket_connect(fd, sockaddr);
64 if (connect_status >= 0) {
65 // Connected. Create IoLooper for the helper.
66 looper = iolooper_new();
67 break;
68 }
69
70 if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
71 // Connection is in progress. Wait till it's finished.
72 looper = iolooper_new();
73 iolooper_add_write(looper, fd);
74 connect_status = iolooper_wait(looper, timeout);
75 if (connect_status > 0) {
76 iolooper_del_write(looper, fd);
Vladimir Chtchetkine17ecca62011-02-07 14:14:14 -080077 break;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080078 } else {
79 iolooper_free(looper);
80 return NULL;
81 }
David 'Digit' Turneraf81d742014-02-03 17:11:18 +010082 } else {
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -080083 return NULL;
84 }
85 }
86
87 // We're now connected. Lets initialize SyncSocket instance
88 // for this connection.
89 sync_socket = malloc(sizeof(SyncSocket));
90 if (sync_socket == NULL) {
91 derror("PANIC: not enough memory\n");
92 exit(1);
93 }
94
95 sync_socket->iolooper = looper;
96 sync_socket->fd = fd;
97
98 return sync_socket;
99}
100
101void
102syncsocket_close(SyncSocket* ssocket)
103{
104 if (ssocket != NULL && ssocket->fd >= 0) {
105 if (ssocket->iolooper != NULL) {
106 iolooper_reset(ssocket->iolooper);
107 }
108 socket_close(ssocket->fd);
109 ssocket->fd = -1;
110 }
111}
112
113void
114syncsocket_free(SyncSocket* ssocket)
115{
116 if (ssocket != NULL) {
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800117 if (ssocket->iolooper != NULL) {
118 iolooper_free(ssocket->iolooper);
119 }
120 free(ssocket);
121 }
122}
123
124int
125syncsocket_start_read(SyncSocket* ssocket)
126{
127 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
128 errno = EINVAL;
129 return -1;
130 }
131 iolooper_add_read(ssocket->iolooper, ssocket->fd);
132 return 0;
133}
134
135int
136syncsocket_stop_read(SyncSocket* ssocket)
137{
138 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
139 errno = EINVAL;
140 return -1;
141 }
142 iolooper_del_read(ssocket->iolooper, ssocket->fd);
143 return 0;
144}
145
146int
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800147syncsocket_start_write(SyncSocket* ssocket)
148{
149 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
150 errno = EINVAL;
151 return -1;
152 }
153 iolooper_add_write(ssocket->iolooper, ssocket->fd);
154 return 0;
155}
156
157int
158syncsocket_stop_write(SyncSocket* ssocket)
159{
160 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
161 errno = EINVAL;
162 return -1;
163 }
164 iolooper_del_write(ssocket->iolooper, ssocket->fd);
165 return 0;
166}
167
168ssize_t
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800169syncsocket_read_absolute(SyncSocket* ssocket,
170 void* buf,
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800171 size_t size,
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800172 int64_t deadline)
173{
174 int ret;
175
176 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
177 errno = EINVAL;
178 return -1;
179 }
180
181 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
182 if (ret > 0) {
183 if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) {
184 D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
185 return -1;
186 }
David 'Digit' Turneraf81d742014-02-03 17:11:18 +0100187 ret = socket_recv(ssocket->fd, buf, size);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800188 } else if (ret == 0) {
189 // Timed out
190 errno = ETIMEDOUT;
191 ret = -1;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800192 }
193 return ret;
194}
195
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800196ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800197syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800198{
199 return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
200}
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800201
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800202ssize_t
203syncsocket_write_absolute(SyncSocket* ssocket,
204 const void* buf,
205 size_t size,
206 int64_t deadline)
207{
208 int ret;
209 size_t written = 0;
210
211 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
212 errno = EINVAL;
213 return -1;
214 }
215
216 do {
217 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
218 if (ret < 0) {
219 return ret;
220 } else if (ret == 0) {
221 // Timeout.
222 errno = ETIMEDOUT;
223 return -1;
224 }
225 if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
226 D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
227 return -1;
228 }
229
David 'Digit' Turneraf81d742014-02-03 17:11:18 +0100230 ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800231 if (ret > 0) {
232 written += ret;
233 } else if (ret < 0) {
234 if (errno != EAGAIN && errno != EWOULDBLOCK) {
235 return -1;
236 }
237 } else {
238 // Disconnected.
239 errno = ECONNRESET;
240 return -1;
241 }
242 } while (written < size);
243 return (int)written;
244}
245
246ssize_t
247syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
248{
249 return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
250}
251
252ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800253syncsocket_read_line_absolute(SyncSocket* ssocket,
254 char* buffer,
255 size_t size,
256 int64_t deadline)
257{
258 size_t read_chars = 0;
259
260 while (read_chars < size) {
261 char ch;
262 int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
263 if (ret <= 0) {
264 return ret;
265 }
266 buffer[read_chars++] = ch;
267 if (ch == '\n') {
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800268 return read_chars;
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800269 }
270 }
271
272 /* Not enough room in the input buffer!*/
273 errno = ENOMEM;
274 return -1;
275}
276
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800277ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800278syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
279{
280 return syncsocket_read_line_absolute(ssocket, buffer, size,
281 iolooper_now() + timeout);
282}
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800283
284int
285syncsocket_get_socket(SyncSocket* ssocket)
286{
287 return (ssocket != NULL) ? ssocket->fd : -1;
288}