blob: 8d5582378b229685e66b82adbeacd4b36ffb48ac [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"
28
29#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
30
31struct SyncSocket {
32 // Helper for performing synchronous I/O on the socket.
33 IoLooper* iolooper;
34
35 /* Opened socket handle. */
36 int fd;
37};
38
39SyncSocket*
40syncsocket_connect(int fd, SockAddress* sockaddr, int timeout)
41{
42 IoLooper* looper = NULL;
43 int connect_status;
44 SyncSocket* sync_socket;
45
46 socket_set_nonblock(fd);
47
48 for(;;) {
49 connect_status = socket_connect(fd, sockaddr);
50 if (connect_status >= 0) {
51 // Connected. Create IoLooper for the helper.
52 looper = iolooper_new();
53 break;
54 }
55
56 if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
57 // Connection is in progress. Wait till it's finished.
58 looper = iolooper_new();
59 iolooper_add_write(looper, fd);
60 connect_status = iolooper_wait(looper, timeout);
61 if (connect_status > 0) {
62 iolooper_del_write(looper, fd);
63 } else {
64 iolooper_free(looper);
65 return NULL;
66 }
67 } else if (errno != EINTR) {
68 return NULL;
69 }
70 }
71
72 // We're now connected. Lets initialize SyncSocket instance
73 // for this connection.
74 sync_socket = malloc(sizeof(SyncSocket));
75 if (sync_socket == NULL) {
76 derror("PANIC: not enough memory\n");
77 exit(1);
78 }
79
80 sync_socket->iolooper = looper;
81 sync_socket->fd = fd;
82
83 return sync_socket;
84}
85
86void
87syncsocket_close(SyncSocket* ssocket)
88{
89 if (ssocket != NULL && ssocket->fd >= 0) {
90 if (ssocket->iolooper != NULL) {
91 iolooper_reset(ssocket->iolooper);
92 }
93 socket_close(ssocket->fd);
94 ssocket->fd = -1;
95 }
96}
97
98void
99syncsocket_free(SyncSocket* ssocket)
100{
101 if (ssocket != NULL) {
102 syncsocket_close(ssocket);
103 if (ssocket->iolooper != NULL) {
104 iolooper_free(ssocket->iolooper);
105 }
106 free(ssocket);
107 }
108}
109
110int
111syncsocket_start_read(SyncSocket* ssocket)
112{
113 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
114 errno = EINVAL;
115 return -1;
116 }
117 iolooper_add_read(ssocket->iolooper, ssocket->fd);
118 return 0;
119}
120
121int
122syncsocket_stop_read(SyncSocket* ssocket)
123{
124 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
125 errno = EINVAL;
126 return -1;
127 }
128 iolooper_del_read(ssocket->iolooper, ssocket->fd);
129 return 0;
130}
131
132int
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800133syncsocket_start_write(SyncSocket* ssocket)
134{
135 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
136 errno = EINVAL;
137 return -1;
138 }
139 iolooper_add_write(ssocket->iolooper, ssocket->fd);
140 return 0;
141}
142
143int
144syncsocket_stop_write(SyncSocket* ssocket)
145{
146 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
147 errno = EINVAL;
148 return -1;
149 }
150 iolooper_del_write(ssocket->iolooper, ssocket->fd);
151 return 0;
152}
153
154ssize_t
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800155syncsocket_read_absolute(SyncSocket* ssocket,
156 void* buf,
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800157 size_t size,
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800158 int64_t deadline)
159{
160 int ret;
161
162 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
163 errno = EINVAL;
164 return -1;
165 }
166
167 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
168 if (ret > 0) {
169 if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) {
170 D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
171 return -1;
172 }
173 do {
174 ret = read(ssocket->fd, buf, size);
175 } while( ret < 0 && errno == EINTR);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800176 } else if (ret == 0) {
177 // Timed out
178 errno = ETIMEDOUT;
179 ret = -1;
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800180 }
181 return ret;
182}
183
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800184ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800185syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
Vladimir Chtchetkinea8fc4912010-11-30 09:32:55 -0800186{
187 return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
188}
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800189
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800190ssize_t
191syncsocket_write_absolute(SyncSocket* ssocket,
192 const void* buf,
193 size_t size,
194 int64_t deadline)
195{
196 int ret;
197 size_t written = 0;
198
199 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
200 errno = EINVAL;
201 return -1;
202 }
203
204 do {
205 ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
206 if (ret < 0) {
207 return ret;
208 } else if (ret == 0) {
209 // Timeout.
210 errno = ETIMEDOUT;
211 return -1;
212 }
213 if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
214 D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
215 return -1;
216 }
217
218 do {
219 ret = write(ssocket->fd, (const char*)buf + written, size - written);
220 } while( ret < 0 && errno == EINTR);
221
222 if (ret > 0) {
223 written += ret;
224 } else if (ret < 0) {
225 if (errno != EAGAIN && errno != EWOULDBLOCK) {
226 return -1;
227 }
228 } else {
229 // Disconnected.
230 errno = ECONNRESET;
231 return -1;
232 }
233 } while (written < size);
234 return (int)written;
235}
236
237ssize_t
238syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
239{
240 return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
241}
242
243ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800244syncsocket_read_line_absolute(SyncSocket* ssocket,
245 char* buffer,
246 size_t size,
247 int64_t deadline)
248{
249 size_t read_chars = 0;
250
251 while (read_chars < size) {
252 char ch;
253 int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
254 if (ret <= 0) {
255 return ret;
256 }
257 buffer[read_chars++] = ch;
258 if (ch == '\n') {
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800259 return read_chars;
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800260 }
261 }
262
263 /* Not enough room in the input buffer!*/
264 errno = ENOMEM;
265 return -1;
266}
267
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800268ssize_t
Vladimir Chtchetkine0d4c8822010-12-01 17:29:09 -0800269syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
270{
271 return syncsocket_read_line_absolute(ssocket, buffer, size,
272 iolooper_now() + timeout);
273}