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