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