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