1 /*
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 #include "android/async-utils.h"
17 #include "unistd.h"
18
19 void
asyncReader_init(AsyncReader * ar,void * buffer,size_t buffsize,LoopIo * io)20 asyncReader_init(AsyncReader* ar,
21 void* buffer,
22 size_t buffsize,
23 LoopIo* io)
24 {
25 ar->buffer = buffer;
26 ar->buffsize = buffsize;
27 ar->pos = 0;
28 ar->io = io;
29 if (buffsize > 0)
30 loopIo_wantRead(io);
31 }
32
33 AsyncStatus
asyncReader_read(AsyncReader * ar)34 asyncReader_read(AsyncReader* ar)
35 {
36 int ret;
37
38 if (ar->pos >= ar->buffsize) {
39 return ASYNC_COMPLETE;
40 }
41
42 do {
43 ret = socket_recv(ar->io->fd, ar->buffer + ar->pos, ar->buffsize - ar->pos);
44 if (ret == 0) {
45 /* disconnection ! */
46 errno = ECONNRESET;
47 return ASYNC_ERROR;
48 }
49 if (ret < 0) {
50 if (errno == EINTR) /* loop on EINTR */
51 continue;
52 if (errno == EWOULDBLOCK || errno == EAGAIN) {
53 loopIo_wantRead(ar->io);
54 return ASYNC_NEED_MORE;
55 }
56 return ASYNC_ERROR;
57 }
58 ar->pos += ret;
59
60 } while (ar->pos < ar->buffsize);
61
62 loopIo_dontWantRead(ar->io);
63 return ASYNC_COMPLETE;
64 }
65
66 void
asyncWriter_init(AsyncWriter * aw,const void * buffer,size_t buffsize,LoopIo * io)67 asyncWriter_init(AsyncWriter* aw,
68 const void* buffer,
69 size_t buffsize,
70 LoopIo* io)
71 {
72 aw->buffer = buffer;
73 aw->buffsize = buffsize;
74 aw->pos = 0;
75 aw->io = io;
76 if (buffsize > 0)
77 loopIo_wantWrite(io);
78 }
79
80 AsyncStatus
asyncWriter_write(AsyncWriter * aw)81 asyncWriter_write(AsyncWriter* aw)
82 {
83 int ret;
84
85 if (aw->pos >= aw->buffsize) {
86 return ASYNC_COMPLETE;
87 }
88
89 do {
90 ret = socket_send(aw->io->fd, aw->buffer + aw->pos, aw->buffsize - aw->pos);
91 if (ret == 0) {
92 /* disconnection ! */
93 errno = ECONNRESET;
94 return ASYNC_ERROR;
95 }
96 if (ret < 0) {
97 if (errno == EINTR) /* loop on EINTR */
98 continue;
99 if (errno == EWOULDBLOCK || errno == EAGAIN) {
100 return ASYNC_NEED_MORE;
101 }
102 return ASYNC_ERROR;
103 }
104 aw->pos += ret;
105
106 } while (aw->pos < aw->buffsize);
107
108 loopIo_dontWantWrite(aw->io);
109 return ASYNC_COMPLETE;
110 }
111
112
113 void
asyncLineReader_init(AsyncLineReader * alr,void * buffer,size_t buffsize,LoopIo * io)114 asyncLineReader_init(AsyncLineReader* alr,
115 void* buffer,
116 size_t buffsize,
117 LoopIo* io)
118 {
119 alr->buffer = buffer;
120 alr->buffsize = buffsize;
121 alr->pos = 0;
122 alr->io = io;
123 alr->eol = '\n';
124 if (buffsize > 0)
125 loopIo_wantRead(io);
126 }
127
128 AsyncStatus
asyncLineReader_read(AsyncLineReader * alr)129 asyncLineReader_read(AsyncLineReader* alr)
130 {
131 int ret;
132
133 if (alr->pos >= alr->buffsize) {
134 errno = ENOMEM;
135 return ASYNC_ERROR;
136 }
137
138 do {
139 char ch;
140 ret = socket_recv(alr->io->fd, &ch, 1);
141 if (ret == 0) {
142 /* disconnection ! */
143 errno = ECONNRESET;
144 return ASYNC_ERROR;
145 }
146 if (ret < 0) {
147 if (errno == EINTR) /* loop on EINTR */
148 continue;
149 if (errno == EWOULDBLOCK || errno == EAGAIN) {
150 loopIo_wantRead(alr->io);
151 return ASYNC_NEED_MORE;
152 }
153 return ASYNC_ERROR;
154 }
155 alr->buffer[alr->pos++] = (uint8_t)ch;
156 if (ch == alr->eol) {
157 loopIo_dontWantRead(alr->io);
158 return ASYNC_COMPLETE;
159 }
160 } while (alr->pos < alr->buffsize);
161
162 /* Not enough room in the input buffer!*/
163 loopIo_dontWantRead(alr->io);
164 errno = ENOMEM;
165 return ASYNC_ERROR;
166 }
167
168 const char*
asyncLineReader_getLineRaw(AsyncLineReader * alr,int * pLength)169 asyncLineReader_getLineRaw(AsyncLineReader* alr, int *pLength)
170 {
171 if (alr->pos == 0 || alr->pos > alr->buffsize)
172 return NULL;
173
174 if (pLength != 0)
175 *pLength = alr->pos;
176
177 return (const char*) alr->buffer;
178 }
179
180 const char*
asyncLineReader_getLine(AsyncLineReader * alr)181 asyncLineReader_getLine(AsyncLineReader* alr)
182 {
183 /* Strip trailing \n if any */
184 size_t pos = alr->pos;
185 char* buffer = (char*) alr->buffer;
186
187 if (pos == 0 || pos > alr->buffsize)
188 return NULL;
189
190 pos--;
191
192 /* Check that we have a proper terminator, and replace it with 0 */
193 if (alr->eol == '\n') {
194 if (buffer[pos] != '\n')
195 return NULL;
196
197 buffer[pos] = '\0';
198
199 /* Also strip \r\n */
200 if (pos > 0 && buffer[--pos] == '\r') {
201 buffer[pos] = '\0';
202 }
203 }
204
205 return (const char*) buffer;
206 }
207
208
209 enum {
210 CONNECT_ERROR = 0,
211 CONNECT_CONNECTING,
212 CONNECT_COMPLETED
213 };
214
215 AsyncStatus
asyncConnector_init(AsyncConnector * ac,const SockAddress * address,LoopIo * io)216 asyncConnector_init(AsyncConnector* ac,
217 const SockAddress* address,
218 LoopIo* io)
219 {
220 int ret;
221 ac->error = 0;
222 ac->io = io;
223 ret = socket_connect(io->fd, address);
224 if (ret == 0) {
225 ac->state = CONNECT_COMPLETED;
226 return ASYNC_COMPLETE;
227 }
228 if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) {
229 ac->state = CONNECT_CONNECTING;
230 /* The socket will be marked writable for select() when the
231 * connection is established, or when it is definitely
232 * refused / timed-out, for any reason. */
233 loopIo_wantWrite(io);
234 return ASYNC_NEED_MORE;
235 }
236 ac->error = errno;
237 ac->state = CONNECT_ERROR;
238 return ASYNC_ERROR;
239 }
240
241 AsyncStatus
asyncConnector_run(AsyncConnector * ac)242 asyncConnector_run(AsyncConnector* ac)
243 {
244 switch (ac->state) {
245 case CONNECT_ERROR:
246 errno = ac->error;
247 return ASYNC_ERROR;
248
249 case CONNECT_CONNECTING:
250 loopIo_dontWantWrite(ac->io);
251 /* We need to read the socket error to determine if
252 * the connection was really succesful or not. This
253 * is optional, because in case of error a future
254 * socket_recv() or socket_send() will fail anyway, but this
255 * allows us to get a better error value as soon as
256 * possible.
257 */
258 ac->error = socket_get_error(ac->io->fd);
259 if (ac->error == 0) {
260 ac->state = CONNECT_COMPLETED;
261 return ASYNC_COMPLETE;
262 }
263 ac->state = CONNECT_ERROR;
264 errno = ac->error;
265 return ASYNC_ERROR;
266
267 default:
268 return ASYNC_COMPLETE;
269 }
270 }
271
272 int
asyncConnector_stop(AsyncConnector * ac)273 asyncConnector_stop(AsyncConnector* ac)
274 {
275 if (ac->state == CONNECT_CONNECTING) {
276 loopIo_dontWantWrite(ac->io);
277 ac->state = CONNECT_COMPLETED;
278 return 0;
279 }
280 return -1;
281 }
282