blob: 4f2fd81c4f8616c4faa5fffb32977f3bd2cb2796 [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 }
82 } else if (errno != EINTR) {
83 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 }
187 do {
Vladimir Chtchetkine17ecca62011-02-07 14:14:14 -0800188 ret = socket_recv(ssocket->fd, buf, size);
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800189 } while( ret < 0 && errno == EINTR);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800190 } else if (ret == 0) {
191 // Timed out
192 errno = ETIMEDOUT;
193 ret = -1;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800194 }
195 return ret;
196}
197
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800198ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800199syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800200{
201 return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
202}
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800203
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800204ssize_t
205syncsocket_write_absolute(SyncSocket* ssocket,
206 const void* buf,
207 size_t size,
208 int64_t deadline)
209{
210 int ret;
211 size_t written = 0;
212
213 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
214 errno = EINVAL;
215 return -1;
216 }
217
218 do {
219 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
220 if (ret < 0) {
221 return ret;
222 } else if (ret == 0) {
223 // Timeout.
224 errno = ETIMEDOUT;
225 return -1;
226 }
227 if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
228 D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
229 return -1;
230 }
231
232 do {
Vladimir Chtchetkine17ecca62011-02-07 14:14:14 -0800233 ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800234 } while( ret < 0 && errno == EINTR);
235
236 if (ret > 0) {
237 written += ret;
238 } else if (ret < 0) {
239 if (errno != EAGAIN && errno != EWOULDBLOCK) {
240 return -1;
241 }
242 } else {
243 // Disconnected.
244 errno = ECONNRESET;
245 return -1;
246 }
247 } while (written < size);
248 return (int)written;
249}
250
251ssize_t
252syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
253{
254 return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
255}
256
257ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800258syncsocket_read_line_absolute(SyncSocket* ssocket,
259 char* buffer,
260 size_t size,
261 int64_t deadline)
262{
263 size_t read_chars = 0;
264
265 while (read_chars < size) {
266 char ch;
267 int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
268 if (ret <= 0) {
269 return ret;
270 }
271 buffer[read_chars++] = ch;
272 if (ch == '\n') {
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800273 return read_chars;
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800274 }
275 }
276
277 /* Not enough room in the input buffer!*/
278 errno = ENOMEM;
279 return -1;
280}
281
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800282ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800283syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
284{
285 return syncsocket_read_line_absolute(ssocket, buffer, size,
286 iolooper_now() + timeout);
287}
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800288
289int
290syncsocket_get_socket(SyncSocket* ssocket)
291{
292 return (ssocket != NULL) ? ssocket->fd : -1;
293}