aboutsummaryrefslogtreecommitdiffstats
path: root/telephony/sysdeps_qemu.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch)
tree550ce922ea0e125ac6a9738210ce2939bf2fe901 /telephony/sysdeps_qemu.c
parent413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff)
downloadexternal_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2
Initial Contribution
Diffstat (limited to 'telephony/sysdeps_qemu.c')
-rw-r--r--telephony/sysdeps_qemu.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/telephony/sysdeps_qemu.c b/telephony/sysdeps_qemu.c
new file mode 100644
index 0000000..e1107aa
--- /dev/null
+++ b/telephony/sysdeps_qemu.c
@@ -0,0 +1,376 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "sockets.h"
+#include "sysdeps.h"
+#include "vl.h"
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#endif
+
+#define DEBUG 1
+
+#define D_ACTIVE DEBUG
+
+#if DEBUG
+#define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+#define D(...) ((void)0)
+#endif
+
+/** TIME
+ **/
+
+SysTime
+sys_time_ms( void )
+{
+ return qemu_get_clock( rt_clock );
+}
+
+/** TIMERS
+ **/
+
+typedef struct SysTimerRec_ {
+ QEMUTimer* timer;
+ QEMUTimerCB* callback;
+ void* opaque;
+ SysTimer next;
+} SysTimerRec;
+
+#define MAX_TIMERS 32
+
+static SysTimerRec _s_timers0[ MAX_TIMERS ];
+static SysTimer _s_free_timers;
+
+static void
+sys_init_timers( void )
+{
+ int nn;
+ for (nn = 0; nn < MAX_TIMERS-1; nn++)
+ _s_timers0[nn].next = _s_timers0 + (nn+1);
+
+ _s_free_timers = _s_timers0;
+}
+
+static SysTimer
+sys_timer_alloc( void )
+{
+ SysTimer timer = _s_free_timers;
+
+ if (timer != NULL) {
+ _s_free_timers = timer->next;
+ timer->next = NULL;
+ timer->timer = NULL;
+ }
+ return timer;
+}
+
+
+static void
+sys_timer_free( SysTimer timer )
+{
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ qemu_free_timer( timer->timer );
+ timer->timer = NULL;
+ }
+ timer->next = _s_free_timers;
+ _s_free_timers = timer;
+}
+
+
+SysTimer sys_timer_create( void )
+{
+ SysTimer timer = sys_timer_alloc();
+ return timer;
+}
+
+void
+sys_timer_set( SysTimer timer, SysTime when, SysCallback _callback, void* opaque )
+{
+ QEMUTimerCB* callback = (QEMUTimerCB*)_callback;
+
+ if (callback == NULL) { /* unsetting the timer */
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ qemu_free_timer( timer->timer );
+ timer->timer = NULL;
+ }
+ timer->callback = callback;
+ timer->opaque = NULL;
+ return;
+ }
+
+ if ( timer->timer ) {
+ if ( timer->callback == callback && timer->opaque == opaque )
+ goto ReuseTimer;
+
+ /* need to replace the timer */
+ qemu_free_timer( timer->timer );
+ }
+
+ timer->timer = qemu_new_timer( rt_clock, callback, opaque );
+ timer->callback = callback;
+ timer->opaque = opaque;
+
+ReuseTimer:
+ qemu_mod_timer( timer->timer, when );
+}
+
+void
+sys_timer_unset( SysTimer timer )
+{
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ }
+}
+
+void
+sys_timer_destroy( SysTimer timer )
+{
+ sys_timer_free( timer );
+}
+
+
+/** CHANNELS
+ **/
+
+typedef struct SysChannelRec_ {
+ int fd;
+ SysChannelCallback callback;
+ void* opaque;
+ SysChannel next;
+} SysChannelRec;
+
+#define MAX_CHANNELS 16
+
+static SysChannelRec _s_channels0[ MAX_CHANNELS ];
+static SysChannel _s_free_channels;
+
+static void
+sys_init_channels( void )
+{
+ int nn;
+
+ for ( nn = 0; nn < MAX_CHANNELS-1; nn++ ) {
+ _s_channels0[nn].next = _s_channels0 + (nn+1);
+ }
+ _s_free_channels = _s_channels0;
+}
+
+static SysChannel
+sys_channel_alloc( )
+{
+ SysChannel channel = _s_free_channels;
+ if (channel != NULL) {
+ _s_free_channels = channel->next;
+ channel->next = NULL;
+ channel->fd = -1;
+ channel->callback = NULL;
+ channel->opaque = NULL;
+ }
+ return channel;
+}
+
+static void
+sys_channel_free( SysChannel channel )
+{
+ if (channel->fd >= 0) {
+ socket_close( channel->fd );
+ channel->fd = -1;
+ }
+ channel->next = _s_free_channels;
+ _s_free_channels = channel;
+}
+
+
+static void
+sys_channel_read_handler( void* _channel )
+{
+ SysChannel channel = _channel;
+ D( "%s: read event for channel %p:%d\n", __FUNCTION__,
+ channel, channel->fd );
+ channel->callback( channel->opaque, SYS_EVENT_READ );
+}
+
+static void
+sys_channel_write_handler( void* _channel )
+{
+ SysChannel channel = _channel;
+ D( "%s: write event for channel %p:%d\n", __FUNCTION__, channel, channel->fd );
+ channel->callback( channel->opaque, SYS_EVENT_WRITE );
+}
+
+void
+sys_channel_on( SysChannel channel,
+ int events,
+ SysChannelCallback event_callback,
+ void* event_opaque )
+{
+ IOHandler* read_handler = NULL;
+ IOHandler* write_handler = NULL;
+
+ if (events & SYS_EVENT_READ) {
+ read_handler = sys_channel_read_handler;
+ }
+ if (events & SYS_EVENT_WRITE) {
+ write_handler = sys_channel_write_handler;
+ }
+ channel->callback = event_callback;
+ channel->opaque = event_opaque;
+ qemu_set_fd_handler( channel->fd, read_handler, write_handler, channel );
+}
+
+int
+sys_channel_read( SysChannel channel, void* buffer, int size )
+{
+ int len = size;
+ char* buf = (char*) buffer;
+
+ while (len > 0) {
+ int ret = recv(channel->fd, buf, len, 0);
+ if (ret < 0) {
+ if (socket_errno == EINTR)
+ continue;
+ if (socket_errno == EWOULDBLOCK)
+ break;
+ D( "%s: after reading %d bytes, recv() returned error %d: %s\n",
+ __FUNCTION__, size - len, socket_errno, socket_errstr());
+ return -1;
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
+ return size - len;
+}
+
+
+int
+sys_channel_write( SysChannel channel, const void* buffer, int size )
+{
+ int len = size;
+ const char* buf = (const char*) buffer;
+
+ while (len > 0) {
+ int ret = send(channel->fd, buf, len, 0);
+ if (ret < 0) {
+ if (socket_errno == EINTR)
+ continue;
+ if (socket_errno == EWOULDBLOCK)
+ break;
+ D( "%s: send() returned error %d: %s\n",
+ __FUNCTION__, socket_errno, socket_errstr());
+ return -1;
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
+ return size - len;
+}
+
+void sys_channel_close( SysChannel channel )
+{
+ qemu_set_fd_handler( channel->fd, NULL, NULL, NULL );
+ sys_channel_free( channel );
+}
+
+void sys_main_init( void )
+{
+ sys_init_channels();
+ sys_init_timers();
+}
+
+
+int sys_main_loop( void )
+{
+ /* no looping, qemu has its own event loop */
+ return 0;
+}
+
+
+
+
+SysChannel
+sys_channel_create_tcp_server( int port )
+{
+ SysChannel channel = sys_channel_alloc();
+ const int BACKLOG = 4;
+
+ channel->fd = socket_anyaddr_server( port, SOCK_STREAM );
+ if (channel->fd < 0) {
+ D( "%s: failed to created network socket on TCP:%d\n", port );
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ D( "%s: server channel %p:%d now listening on port %d\n",
+ __FUNCTION__, channel, channel->fd, port );
+
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_handler( SysChannel server_channel )
+{
+ SysChannel channel = sys_channel_alloc();
+
+ D( "%s: creating handler from server channel %p:%d\n", __FUNCTION__,
+ server_channel, server_channel->fd );
+
+ channel->fd = socket_accept_any( server_channel->fd );
+ if (channel->fd < 0) {
+ perror( "accept" );
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ /* disable Nagle algorithm */
+ socket_set_lowlatency( channel->fd );
+
+ D( "%s: handler %p:%d created from server %p:%d\n", __FUNCTION__,
+ server_channel, server_channel->fd, channel, channel->fd );
+
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_client( const char* hostname, int port )
+{
+ SysChannel channel = sys_channel_alloc();
+
+ channel->fd = socket_network_client( hostname, port, SOCK_STREAM );
+ if (channel->fd < 0) {
+ sys_channel_free(channel);
+ return NULL;
+ };
+
+ /* set to non-blocking and disable Nagle algorithm */
+ socket_set_nonblock( channel->fd );
+ socket_set_lowlatency( channel->fd );
+
+ return channel;
+}
+