• 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 "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