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