blob: 6d3cea6c719668494280a1c34951638167929b58 [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"
24#include "iolooper.h"
25#include "sockets.h"
26#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);
77 } else {
78 iolooper_free(looper);
79 return NULL;
80 }
81 } else if (errno != EINTR) {
82 return NULL;
83 }
84 }
85
86 // We're now connected. Lets initialize SyncSocket instance
87 // for this connection.
88 sync_socket = malloc(sizeof(SyncSocket));
89 if (sync_socket == NULL) {
90 derror("PANIC: not enough memory\n");
91 exit(1);
92 }
93
94 sync_socket->iolooper = looper;
95 sync_socket->fd = fd;
96
97 return sync_socket;
98}
99
100void
101syncsocket_close(SyncSocket* ssocket)
102{
103 if (ssocket != NULL && ssocket->fd >= 0) {
104 if (ssocket->iolooper != NULL) {
105 iolooper_reset(ssocket->iolooper);
106 }
107 socket_close(ssocket->fd);
108 ssocket->fd = -1;
109 }
110}
111
112void
113syncsocket_free(SyncSocket* ssocket)
114{
115 if (ssocket != NULL) {
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800116 if (ssocket->iolooper != NULL) {
117 iolooper_free(ssocket->iolooper);
118 }
119 free(ssocket);
120 }
121}
122
123int
124syncsocket_start_read(SyncSocket* ssocket)
125{
126 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
127 errno = EINVAL;
128 return -1;
129 }
130 iolooper_add_read(ssocket->iolooper, ssocket->fd);
131 return 0;
132}
133
134int
135syncsocket_stop_read(SyncSocket* ssocket)
136{
137 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
138 errno = EINVAL;
139 return -1;
140 }
141 iolooper_del_read(ssocket->iolooper, ssocket->fd);
142 return 0;
143}
144
145int
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800146syncsocket_start_write(SyncSocket* ssocket)
147{
148 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
149 errno = EINVAL;
150 return -1;
151 }
152 iolooper_add_write(ssocket->iolooper, ssocket->fd);
153 return 0;
154}
155
156int
157syncsocket_stop_write(SyncSocket* ssocket)
158{
159 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
160 errno = EINVAL;
161 return -1;
162 }
163 iolooper_del_write(ssocket->iolooper, ssocket->fd);
164 return 0;
165}
166
167ssize_t
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800168syncsocket_read_absolute(SyncSocket* ssocket,
169 void* buf,
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800170 size_t size,
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800171 int64_t deadline)
172{
173 int ret;
174
175 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
176 errno = EINVAL;
177 return -1;
178 }
179
180 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
181 if (ret > 0) {
182 if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) {
183 D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
184 return -1;
185 }
186 do {
187 ret = read(ssocket->fd, buf, size);
188 } while( ret < 0 && errno == EINTR);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800189 } else if (ret == 0) {
190 // Timed out
191 errno = ETIMEDOUT;
192 ret = -1;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800193 }
194 return ret;
195}
196
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800197ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800198syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800199{
200 return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
201}
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800202
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800203ssize_t
204syncsocket_write_absolute(SyncSocket* ssocket,
205 const void* buf,
206 size_t size,
207 int64_t deadline)
208{
209 int ret;
210 size_t written = 0;
211
212 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
213 errno = EINVAL;
214 return -1;
215 }
216
217 do {
218 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
219 if (ret < 0) {
220 return ret;
221 } else if (ret == 0) {
222 // Timeout.
223 errno = ETIMEDOUT;
224 return -1;
225 }
226 if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
227 D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
228 return -1;
229 }
230
231 do {
232 ret = write(ssocket->fd, (const char*)buf + written, size - written);
233 } while( ret < 0 && errno == EINTR);
234
235 if (ret > 0) {
236 written += ret;
237 } else if (ret < 0) {
238 if (errno != EAGAIN && errno != EWOULDBLOCK) {
239 return -1;
240 }
241 } else {
242 // Disconnected.
243 errno = ECONNRESET;
244 return -1;
245 }
246 } while (written < size);
247 return (int)written;
248}
249
250ssize_t
251syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
252{
253 return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
254}
255
256ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800257syncsocket_read_line_absolute(SyncSocket* ssocket,
258 char* buffer,
259 size_t size,
260 int64_t deadline)
261{
262 size_t read_chars = 0;
263
264 while (read_chars < size) {
265 char ch;
266 int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
267 if (ret <= 0) {
268 return ret;
269 }
270 buffer[read_chars++] = ch;
271 if (ch == '\n') {
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800272 return read_chars;
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800273 }
274 }
275
276 /* Not enough room in the input buffer!*/
277 errno = ENOMEM;
278 return -1;
279}
280
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800281ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800282syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
283{
284 return syncsocket_read_line_absolute(ssocket, buffer, size,
285 iolooper_now() + timeout);
286}
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800287
288int
289syncsocket_get_socket(SyncSocket* ssocket)
290{
291 return (ssocket != NULL) ? ssocket->fd : -1;
292}