blob: ec0b3f57524353dcce08e18ebdc797f293fbeaec [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12#include "sockets.h"
13#include "sysdeps.h"
14#include "qemu-timer.h"
15#ifdef _WIN32
16#include <winsock2.h>
17#else
18#include <sys/socket.h>
19#include <sys/select.h>
20#include <sys/types.h>
21#include <netinet/in.h>
22#include <netinet/tcp.h>
23#include <netdb.h>
24#endif
25
26#define DEBUG 1
27
28#define D_ACTIVE DEBUG
29
30#if DEBUG
31#define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
32#else
33#define D(...) ((void)0)
34#endif
35
36/** TIME
37 **/
38
39SysTime
40sys_time_ms( void )
41{
42 return qemu_get_clock( rt_clock );
43}
44
45/** TIMERS
46 **/
47
48typedef struct SysTimerRec_ {
49 QEMUTimer* timer;
50 QEMUTimerCB* callback;
51 void* opaque;
52 SysTimer next;
53} SysTimerRec;
54
55#define MAX_TIMERS 32
56
57static SysTimerRec _s_timers0[ MAX_TIMERS ];
58static SysTimer _s_free_timers;
59
60static void
61sys_init_timers( void )
62{
63 int nn;
64 for (nn = 0; nn < MAX_TIMERS-1; nn++)
65 _s_timers0[nn].next = _s_timers0 + (nn+1);
66
67 _s_free_timers = _s_timers0;
68}
69
70static SysTimer
71sys_timer_alloc( void )
72{
73 SysTimer timer = _s_free_timers;
74
75 if (timer != NULL) {
76 _s_free_timers = timer->next;
77 timer->next = NULL;
78 timer->timer = NULL;
79 }
80 return timer;
81}
82
83
84static void
85sys_timer_free( SysTimer timer )
86{
87 if (timer->timer) {
88 qemu_del_timer( timer->timer );
89 qemu_free_timer( timer->timer );
90 timer->timer = NULL;
91 }
92 timer->next = _s_free_timers;
93 _s_free_timers = timer;
94}
95
96
97SysTimer sys_timer_create( void )
98{
99 SysTimer timer = sys_timer_alloc();
100 return timer;
101}
102
103void
104sys_timer_set( SysTimer timer, SysTime when, SysCallback _callback, void* opaque )
105{
106 QEMUTimerCB* callback = (QEMUTimerCB*)_callback;
107
108 if (callback == NULL) { /* unsetting the timer */
109 if (timer->timer) {
110 qemu_del_timer( timer->timer );
111 qemu_free_timer( timer->timer );
112 timer->timer = NULL;
113 }
114 timer->callback = callback;
115 timer->opaque = NULL;
116 return;
117 }
118
119 if ( timer->timer ) {
120 if ( timer->callback == callback && timer->opaque == opaque )
121 goto ReuseTimer;
122
123 /* need to replace the timer */
124 qemu_free_timer( timer->timer );
125 }
126
127 timer->timer = qemu_new_timer( rt_clock, callback, opaque );
128 timer->callback = callback;
129 timer->opaque = opaque;
130
131ReuseTimer:
132 qemu_mod_timer( timer->timer, when );
133}
134
135void
136sys_timer_unset( SysTimer timer )
137{
138 if (timer->timer) {
139 qemu_del_timer( timer->timer );
140 }
141}
142
143void
144sys_timer_destroy( SysTimer timer )
145{
146 sys_timer_free( timer );
147}
148
149
150/** CHANNELS
151 **/
152
153typedef struct SysChannelRec_ {
154 int fd;
155 SysChannelCallback callback;
156 void* opaque;
157 SysChannel next;
158} SysChannelRec;
159
160#define MAX_CHANNELS 16
161
162static SysChannelRec _s_channels0[ MAX_CHANNELS ];
163static SysChannel _s_free_channels;
164
165static void
166sys_init_channels( void )
167{
168 int nn;
169
170 for ( nn = 0; nn < MAX_CHANNELS-1; nn++ ) {
171 _s_channels0[nn].next = _s_channels0 + (nn+1);
172 }
173 _s_free_channels = _s_channels0;
174}
175
176static SysChannel
177sys_channel_alloc( )
178{
179 SysChannel channel = _s_free_channels;
180 if (channel != NULL) {
181 _s_free_channels = channel->next;
182 channel->next = NULL;
183 channel->fd = -1;
184 channel->callback = NULL;
185 channel->opaque = NULL;
186 }
187 return channel;
188}
189
190static void
191sys_channel_free( SysChannel channel )
192{
193 if (channel->fd >= 0) {
194 socket_close( channel->fd );
195 channel->fd = -1;
196 }
197 channel->next = _s_free_channels;
198 _s_free_channels = channel;
199}
200
201
202static void
203sys_channel_read_handler( void* _channel )
204{
205 SysChannel channel = _channel;
206 D( "%s: read event for channel %p:%d\n", __FUNCTION__,
207 channel, channel->fd );
208 channel->callback( channel->opaque, SYS_EVENT_READ );
209}
210
211static void
212sys_channel_write_handler( void* _channel )
213{
214 SysChannel channel = _channel;
215 D( "%s: write event for channel %p:%d\n", __FUNCTION__, channel, channel->fd );
216 channel->callback( channel->opaque, SYS_EVENT_WRITE );
217}
218
219void
220sys_channel_on( SysChannel channel,
221 int events,
222 SysChannelCallback event_callback,
223 void* event_opaque )
224{
225 IOHandler* read_handler = NULL;
226 IOHandler* write_handler = NULL;
227
228 if (events & SYS_EVENT_READ) {
229 read_handler = sys_channel_read_handler;
230 }
231 if (events & SYS_EVENT_WRITE) {
232 write_handler = sys_channel_write_handler;
233 }
234 channel->callback = event_callback;
235 channel->opaque = event_opaque;
236 qemu_set_fd_handler( channel->fd, read_handler, write_handler, channel );
237}
238
239int
240sys_channel_read( SysChannel channel, void* buffer, int size )
241{
242 int len = size;
243 char* buf = (char*) buffer;
244
245 while (len > 0) {
246 int ret = socket_recv(channel->fd, buf, len);
247 if (ret < 0) {
248 if (errno == EINTR)
249 continue;
250 if (errno == EWOULDBLOCK)
251 break;
252 D( "%s: after reading %d bytes, recv() returned error %d: %s\n",
253 __FUNCTION__, size - len, errno, errno_str);
254 return -1;
255 } else if (ret == 0) {
256 break;
257 } else {
258 buf += ret;
259 len -= ret;
260 }
261 }
262 return size - len;
263}
264
265
266int
267sys_channel_write( SysChannel channel, const void* buffer, int size )
268{
269 int len = size;
270 const char* buf = (const char*) buffer;
271
272 while (len > 0) {
273 int ret = socket_send(channel->fd, buf, len);
274 if (ret < 0) {
275 if (errno == EINTR)
276 continue;
277 if (errno == EWOULDBLOCK)
278 break;
279 D( "%s: send() returned error %d: %s\n",
280 __FUNCTION__, errno, errno_str);
281 return -1;
282 } else if (ret == 0) {
283 break;
284 } else {
285 buf += ret;
286 len -= ret;
287 }
288 }
289 return size - len;
290}
291
292void sys_channel_close( SysChannel channel )
293{
294 qemu_set_fd_handler( channel->fd, NULL, NULL, NULL );
295 sys_channel_free( channel );
296}
297
298void sys_main_init( void )
299{
300 sys_init_channels();
301 sys_init_timers();
302}
303
304
305int sys_main_loop( void )
306{
307 /* no looping, qemu has its own event loop */
308 return 0;
309}
310
311
312
313
314SysChannel
315sys_channel_create_tcp_server( int port )
316{
317 SysChannel channel = sys_channel_alloc();
318
319 channel->fd = socket_anyaddr_server( port, SOCKET_STREAM );
320 if (channel->fd < 0) {
321 D( "%s: failed to created network socket on TCP:%d\n",
322 __FUNCTION__, port );
323 sys_channel_free( channel );
324 return NULL;
325 }
326
327 D( "%s: server channel %p:%d now listening on port %d\n",
328 __FUNCTION__, channel, channel->fd, port );
329
330 return channel;
331}
332
333
334SysChannel
335sys_channel_create_tcp_handler( SysChannel server_channel )
336{
337 SysChannel channel = sys_channel_alloc();
338
339 D( "%s: creating handler from server channel %p:%d\n", __FUNCTION__,
340 server_channel, server_channel->fd );
341
342 channel->fd = socket_accept_any( server_channel->fd );
343 if (channel->fd < 0) {
344 perror( "accept" );
345 sys_channel_free( channel );
346 return NULL;
347 }
348
349 /* disable Nagle algorithm */
350 socket_set_nodelay( channel->fd );
351
352 D( "%s: handler %p:%d created from server %p:%d\n", __FUNCTION__,
353 server_channel, server_channel->fd, channel, channel->fd );
354
355 return channel;
356}
357
358
359SysChannel
360sys_channel_create_tcp_client( const char* hostname, int port )
361{
362 SysChannel channel = sys_channel_alloc();
363
364 channel->fd = socket_network_client( hostname, port, SOCKET_STREAM );
365 if (channel->fd < 0) {
366 sys_channel_free(channel);
367 return NULL;
368 };
369
370 /* set to non-blocking and disable Nagle algorithm */
371 socket_set_nonblock( channel->fd );
372 socket_set_nodelay( channel->fd );
373
374 return channel;
375}
376