| /* 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 = malloc (n_bytes); | |
| if (!ret) | |
| exit (errno); | |
| return ret; | |
| } | |
| gpointer | |
| g_malloc0 (gsize n_bytes) | |
| { | |
| gpointer ret = calloc (1, n_bytes); | |
| if (!ret) | |
| exit (errno); | |
| return ret; | |
| } | |
| gpointer | |
| g_realloc (gpointer mem, gsize n_bytes) | |
| { | |
| gpointer ret = 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, 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; | |
| 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); | |
| 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; | |
| } | |
| #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 | |
| 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(_MSC_VER) | |
| struct quehead { | |
| struct quehead *qh_link; | |
| struct quehead *qh_rlink; | |
| }; | |
| void | |
| slirp_insque(void *a, void *b) | |
| { | |
| register struct quehead *element = (struct quehead *) a; | |
| register struct quehead *head = (struct quehead *) b; | |
| element->qh_link = head->qh_link; | |
| head->qh_link = (struct quehead *)element; | |
| element->qh_rlink = (struct quehead *)head; | |
| ((struct quehead *)(element->qh_link))->qh_rlink | |
| = (struct quehead *)element; | |
| } | |
| void | |
| slirp_remque(void *a) | |
| { | |
| register struct quehead *element = (struct quehead *) a; | |
| ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; | |
| ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; | |
| element->qh_rlink = NULL; | |
| } | |
| #endif | |
| #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 = 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 ? g_malloc0 (element_size*(reserved_size + zero_terminated)) : | |
| 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 = 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 = 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 |