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