346 lines
8.4 KiB
C
346 lines
8.4 KiB
C
/* glib_qemu_stubs.c:
|
|
------------------------------------------------------------------------------
|
|
Copyright (c) 2015, Mark Pizzolato
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of the author shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from the author.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
This module provides the minimal aspects of glib and qemu which are referenced
|
|
by the current qemu SLiRP code and are needed to get SLiRP functionality for
|
|
the simh network code.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#ifdef _WIN32
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#endif
|
|
#include "qemu/compiler.h"
|
|
#include "qemu/typedefs.h"
|
|
#include <sockets.h>
|
|
#include <stdarg.h>
|
|
#include "glib.h"
|
|
|
|
gpointer
|
|
g_malloc (gsize n_bytes)
|
|
{
|
|
gpointer ret = (gpointer)malloc (n_bytes);
|
|
|
|
if (!ret)
|
|
exit (errno);
|
|
return ret;
|
|
}
|
|
|
|
gpointer
|
|
g_malloc0 (gsize n_bytes)
|
|
{
|
|
gpointer ret = (gpointer)calloc (1, n_bytes);
|
|
|
|
if (!ret)
|
|
exit (errno);
|
|
return ret;
|
|
}
|
|
|
|
gpointer
|
|
g_realloc (gpointer mem, gsize n_bytes)
|
|
{
|
|
gpointer ret = (gpointer)realloc (mem, n_bytes);
|
|
|
|
if (!ret)
|
|
exit (errno);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
g_free (gpointer mem)
|
|
{
|
|
free (mem);
|
|
}
|
|
|
|
gchar *
|
|
g_strdup (const gchar *str)
|
|
{
|
|
gchar *nstr = NULL;
|
|
|
|
if (str) {
|
|
nstr = (gchar *)malloc (strlen(str)+1);
|
|
if (!nstr)
|
|
exit (errno);
|
|
strcpy (nstr, str);
|
|
}
|
|
return nstr;
|
|
}
|
|
|
|
void pstrcpy(char *buf, int buf_size, const char *str)
|
|
{
|
|
int c;
|
|
char *q = buf;
|
|
|
|
if (buf_size <= 0)
|
|
return;
|
|
|
|
for(;;) {
|
|
c = *str++;
|
|
if (c == 0 || q >= buf + buf_size - 1)
|
|
break;
|
|
*q++ = c;
|
|
}
|
|
*q = '\0';
|
|
}
|
|
|
|
int qemu_socket(int domain, int type, int protocol)
|
|
{
|
|
return socket (domain, type, protocol);
|
|
}
|
|
|
|
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
|
{
|
|
return accept (s, addr, addrlen);
|
|
}
|
|
|
|
int qemu_setsockopt (int s, int level, int optname, void *optval, int optlen)
|
|
{
|
|
return setsockopt ((SOCKET)s, level, optname, (char *)optval, optlen);
|
|
}
|
|
|
|
int qemu_recv (int s, void *buf, size_t len, int flags)
|
|
{
|
|
return recv ((SOCKET)s, (char *)buf, len, flags);
|
|
}
|
|
|
|
int socket_set_nodelay(int fd)
|
|
{
|
|
int v = 1;
|
|
return setsockopt((SOCKET)fd, IPPROTO_TCP, TCP_NODELAY, (char *)&v, sizeof(v));
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
void qemu_set_nonblock(int fd)
|
|
{
|
|
unsigned long non_block = 1;
|
|
|
|
(void)ioctlsocket ((SOCKET)fd, FIONBIO, &non_block); /* set nonblocking */
|
|
}
|
|
#else
|
|
#include <fcntl.h>
|
|
void qemu_set_nonblock(int fd)
|
|
{
|
|
int f;
|
|
|
|
f = fcntl(fd, F_GETFL);
|
|
if (f != -1)
|
|
(void)fcntl(fd, F_SETFL, f | O_NONBLOCK);
|
|
}
|
|
#endif
|
|
|
|
int socket_set_fast_reuse(int fd)
|
|
{
|
|
int val = 1, ret;
|
|
|
|
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
|
(const char *)&val, sizeof(val));
|
|
return ret;
|
|
}
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
#include <time.h>
|
|
#ifdef _WIN32
|
|
int64_t qemu_clock_get_ns(int type)
|
|
{
|
|
uint64_t now, unixbase;
|
|
|
|
unixbase = 116444736;
|
|
unixbase *= 1000000000;
|
|
GetSystemTimeAsFileTime((FILETIME*)&now);
|
|
now -= unixbase;
|
|
return now*100;
|
|
}
|
|
|
|
#else
|
|
|
|
#if !defined(CLOCK_REALTIME) && !defined(__hpux)
|
|
#define CLOCK_REALTIME 1
|
|
int clock_gettime(int clk_id, struct timespec *tp);
|
|
#endif
|
|
|
|
int64_t qemu_clock_get_ns(int type)
|
|
{
|
|
struct timespec tv;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &tv);
|
|
return tv.tv_sec * 1000000000LL + tv.tv_nsec;
|
|
}
|
|
#endif
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
void monitor_printf(Monitor *mon, const char *fmt, ...)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start (arglist, fmt);
|
|
vfprintf ((FILE *)mon, fmt, arglist);
|
|
va_end (arglist);
|
|
}
|
|
|
|
void g_log (const gchar *log_domain,
|
|
GLogLevelFlags log_level,
|
|
const gchar *format,
|
|
...)
|
|
{
|
|
va_list arglist;
|
|
|
|
fprintf (stderr, "%s(%X): ", log_domain ? log_domain : "", log_level);
|
|
va_start (arglist, format);
|
|
vfprintf (stderr, format, arglist);
|
|
va_end (arglist);
|
|
}
|
|
|
|
int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
|
|
{
|
|
fprintf (stderr, "qemu_chr_fe_write() called\n");
|
|
return 0;
|
|
}
|
|
|
|
void qemu_notify_event(void)
|
|
{
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
int
|
|
inet_aton(const char *arg, struct in_addr *addr)
|
|
{
|
|
(*addr).s_addr = inet_addr (arg);
|
|
return (*addr).s_addr != INADDR_BROADCAST;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* glib GArray functionality is needed */
|
|
|
|
typedef struct {
|
|
gchar *data;
|
|
guint len;
|
|
guint _element_size; /* element size */
|
|
guint _size; /* allocated element count size */
|
|
gboolean _zero_terminated;
|
|
gboolean _clear;
|
|
} GArrayInternal;
|
|
|
|
GArray *
|
|
g_array_sized_new (gboolean zero_terminated,
|
|
gboolean clear,
|
|
guint element_size,
|
|
guint reserved_size)
|
|
{
|
|
GArrayInternal *ar = (GArrayInternal *)g_malloc (sizeof (*ar));
|
|
|
|
ar->_zero_terminated = zero_terminated ? 1 : 0;
|
|
ar->_clear = clear ? 1 : 0;
|
|
ar->_element_size = element_size;
|
|
ar->_size = reserved_size;
|
|
ar->len = 0;
|
|
ar->data = clear ? (gchar *)g_malloc0 (element_size*(reserved_size + zero_terminated)) :
|
|
(gchar *)g_malloc (element_size*(reserved_size + zero_terminated));
|
|
if (ar->_zero_terminated && !ar->_clear)
|
|
memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size);
|
|
return (GArray *)ar;
|
|
}
|
|
|
|
gchar *
|
|
g_array_free (GArray *array,
|
|
gboolean free_segment)
|
|
{
|
|
gchar *result = ((array == NULL) || free_segment) ? NULL : array->data;
|
|
|
|
if (array != NULL) {
|
|
if (free_segment)
|
|
free (array->data);
|
|
free (array);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
GArray *
|
|
g_array_set_size (GArray *array,
|
|
guint length)
|
|
{
|
|
GArrayInternal *ar = (GArrayInternal *)array;
|
|
|
|
if (length > ar->_size) {
|
|
ar->data = (gchar *)g_realloc (ar->data, (length + ar->_zero_terminated) * ar->_element_size);
|
|
if (ar->_clear)
|
|
memset (ar->data + (ar->len * ar->_element_size), 0, (length + ar->_zero_terminated - ar->len) * ar->_element_size);
|
|
ar->_size = length;
|
|
}
|
|
ar->len = length;
|
|
if (ar->_zero_terminated)
|
|
memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size);
|
|
return array;
|
|
}
|
|
|
|
GArray *
|
|
g_array_append_vals (GArray *array,
|
|
gconstpointer data,
|
|
guint len)
|
|
{
|
|
GArrayInternal *ar = (GArrayInternal *)array;
|
|
|
|
if ((ar->len + len) > ar->_size) {
|
|
ar->data = (gchar *)g_realloc (ar->data, (ar->len + len + ar->_zero_terminated) * ar->_element_size);
|
|
ar->_size = ar->len + len;
|
|
}
|
|
memcpy (ar->data + (ar->len * ar->_element_size), data, len * ar->_element_size);
|
|
ar->len += len;
|
|
if (ar->_zero_terminated)
|
|
memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size);
|
|
return array;
|
|
}
|
|
|
|
guint
|
|
g_array_get_element_size (GArray *array)
|
|
{
|
|
GArrayInternal *ar = (GArrayInternal *)array;
|
|
|
|
return ar->_element_size;
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
char *socket_strerror(int errnum)
|
|
{
|
|
static char buf[512];
|
|
|
|
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buf, sizeof(buf), NULL))
|
|
sprintf(buf, "Error Code: %d", errno);
|
|
return buf;
|
|
}
|
|
#endif
|