• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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