• 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 
17 /*
18  * Contains helper routines dealing with syncronous access to a non-blocking
19  * sokets.
20  */
21 
22 #include "qemu-common.h"
23 #include "errno.h"
24 #include "iolooper.h"
25 #include "sockets.h"
26 #include "android/utils/debug.h"
27 #include "android/sync-utils.h"
28 #include "android/utils/system.h"
29 
30 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
31 
32 struct SyncSocket {
33     // Helper for performing synchronous I/O on the socket.
34     IoLooper* iolooper;
35 
36     /* Opened socket handle. */
37     int fd;
38 };
39 
40 SyncSocket*
syncsocket_init(int fd)41 syncsocket_init(int fd)
42 {
43     SyncSocket* sync_socket;
44     ANEW0(sync_socket);
45 
46     socket_set_nonblock(fd);
47     sync_socket->iolooper = iolooper_new();
48     sync_socket->fd = fd;
49 
50     return sync_socket;
51 }
52 
53 SyncSocket*
syncsocket_connect(int fd,SockAddress * sockaddr,int timeout)54 syncsocket_connect(int fd, SockAddress* sockaddr, int timeout)
55 {
56     IoLooper* looper;
57     int connect_status;
58     SyncSocket* sync_socket = NULL;
59 
60     socket_set_nonblock(fd);
61 
62     for(;;) {
63         connect_status = socket_connect(fd, sockaddr);
64         if (connect_status >= 0) {
65             // Connected. Create IoLooper for the helper.
66             looper = iolooper_new();
67             break;
68         }
69 
70         if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
71             // Connection is in progress. Wait till it's finished.
72             looper = iolooper_new();
73             iolooper_add_write(looper, fd);
74             connect_status = iolooper_wait(looper, timeout);
75             if (connect_status > 0) {
76                 iolooper_del_write(looper, fd);
77                 break;
78             } else {
79                 iolooper_free(looper);
80                 return NULL;
81             }
82         } else if (errno != EINTR) {
83             return NULL;
84         }
85     }
86 
87     // We're now connected. Lets initialize SyncSocket instance
88     // for this connection.
89     sync_socket = malloc(sizeof(SyncSocket));
90     if (sync_socket == NULL) {
91         derror("PANIC: not enough memory\n");
92         exit(1);
93     }
94 
95     sync_socket->iolooper = looper;
96     sync_socket->fd = fd;
97 
98     return sync_socket;
99 }
100 
101 void
syncsocket_close(SyncSocket * ssocket)102 syncsocket_close(SyncSocket* ssocket)
103 {
104     if (ssocket != NULL && ssocket->fd >= 0) {
105         if (ssocket->iolooper != NULL) {
106             iolooper_reset(ssocket->iolooper);
107         }
108         socket_close(ssocket->fd);
109         ssocket->fd = -1;
110     }
111 }
112 
113 void
syncsocket_free(SyncSocket * ssocket)114 syncsocket_free(SyncSocket* ssocket)
115 {
116     if (ssocket != NULL) {
117         if (ssocket->iolooper != NULL) {
118             iolooper_free(ssocket->iolooper);
119         }
120         free(ssocket);
121     }
122 }
123 
124 int
syncsocket_start_read(SyncSocket * ssocket)125 syncsocket_start_read(SyncSocket* ssocket)
126 {
127     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
128         errno = EINVAL;
129         return -1;
130     }
131     iolooper_add_read(ssocket->iolooper, ssocket->fd);
132     return 0;
133 }
134 
135 int
syncsocket_stop_read(SyncSocket * ssocket)136 syncsocket_stop_read(SyncSocket* ssocket)
137 {
138     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
139         errno = EINVAL;
140         return -1;
141     }
142     iolooper_del_read(ssocket->iolooper, ssocket->fd);
143     return 0;
144 }
145 
146 int
syncsocket_start_write(SyncSocket * ssocket)147 syncsocket_start_write(SyncSocket* ssocket)
148 {
149     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
150         errno = EINVAL;
151         return -1;
152     }
153     iolooper_add_write(ssocket->iolooper, ssocket->fd);
154     return 0;
155 }
156 
157 int
syncsocket_stop_write(SyncSocket * ssocket)158 syncsocket_stop_write(SyncSocket* ssocket)
159 {
160     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
161         errno = EINVAL;
162         return -1;
163     }
164     iolooper_del_write(ssocket->iolooper, ssocket->fd);
165     return 0;
166 }
167 
168 ssize_t
syncsocket_read_absolute(SyncSocket * ssocket,void * buf,size_t size,int64_t deadline)169 syncsocket_read_absolute(SyncSocket* ssocket,
170                          void* buf,
171                          size_t size,
172                          int64_t deadline)
173 {
174     int ret;
175 
176     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
177         errno = EINVAL;
178         return -1;
179     }
180 
181     ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
182     if (ret > 0) {
183         if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) {
184             D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
185             return -1;
186         }
187         do {
188             ret = socket_recv(ssocket->fd, buf, size);
189         } while( ret < 0 && errno == EINTR);
190     } else if (ret == 0) {
191         // Timed out
192         errno = ETIMEDOUT;
193         ret = -1;
194     }
195     return ret;
196 }
197 
198 ssize_t
syncsocket_read(SyncSocket * ssocket,void * buf,size_t size,int timeout)199 syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
200 {
201     return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
202 }
203 
204 ssize_t
syncsocket_write_absolute(SyncSocket * ssocket,const void * buf,size_t size,int64_t deadline)205 syncsocket_write_absolute(SyncSocket* ssocket,
206                           const void* buf,
207                           size_t size,
208                           int64_t deadline)
209 {
210     int ret;
211     size_t written = 0;
212 
213     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
214         errno = EINVAL;
215         return -1;
216     }
217 
218     do {
219         ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
220         if (ret < 0) {
221             return ret;
222         } else if (ret == 0) {
223             // Timeout.
224             errno = ETIMEDOUT;
225             return -1;
226         }
227         if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
228             D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
229             return -1;
230         }
231 
232         do {
233             ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
234         } while( ret < 0 && errno == EINTR);
235 
236         if (ret > 0) {
237             written += ret;
238         } else if (ret < 0) {
239             if (errno != EAGAIN && errno != EWOULDBLOCK) {
240                 return -1;
241             }
242         } else {
243             // Disconnected.
244             errno = ECONNRESET;
245             return -1;
246         }
247     } while (written < size);
248     return (int)written;
249 }
250 
251 ssize_t
syncsocket_write(SyncSocket * ssocket,const void * buf,size_t size,int timeout)252 syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
253 {
254     return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
255 }
256 
257 ssize_t
syncsocket_read_line_absolute(SyncSocket * ssocket,char * buffer,size_t size,int64_t deadline)258 syncsocket_read_line_absolute(SyncSocket* ssocket,
259                               char* buffer,
260                               size_t size,
261                               int64_t deadline)
262 {
263     size_t read_chars = 0;
264 
265     while (read_chars < size) {
266         char ch;
267         int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
268         if (ret <= 0) {
269             return ret;
270         }
271         buffer[read_chars++] = ch;
272         if (ch == '\n') {
273             return read_chars;
274         }
275     }
276 
277     /* Not enough room in the input buffer!*/
278     errno = ENOMEM;
279     return -1;
280 }
281 
282 ssize_t
syncsocket_read_line(SyncSocket * ssocket,char * buffer,size_t size,int timeout)283 syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
284 {
285     return syncsocket_read_line_absolute(ssocket, buffer, size,
286                                          iolooper_now() + timeout);
287 }
288 
289 int
syncsocket_get_socket(SyncSocket * ssocket)290 syncsocket_get_socket(SyncSocket* ssocket)
291 {
292     return (ssocket != NULL) ? ssocket->fd : -1;
293 }
294