* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
/* Needed early for CONFIG_BSD etc. */
-#include "config-host.h"
-
-#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
-#include <sys/mman.h>
-#endif
#ifdef CONFIG_SOLARIS
-#include <sys/types.h>
#include <sys/statvfs.h>
/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
discussion about Solaris header problems */
#endif
#include "qemu-common.h"
-#include "trace.h"
+#include "qemu/cutils.h"
#include "qemu/sockets.h"
+#include "qemu/error-report.h"
#include "monitor/monitor.h"
static bool fips_enabled = false;
-static const char *qemu_version = QEMU_VERSION;
+static const char *hw_version = QEMU_HW_VERSION;
int socket_set_cork(int fd, int v)
{
#if defined(SOL_TCP) && defined(TCP_CORK)
- return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
+ return qemu_setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
#else
return 0;
#endif
}
+int socket_set_nodelay(int fd)
+{
+ int v = 1;
+ return qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
+}
+
int qemu_madvise(void *addr, size_t len, int advice)
{
if (advice == QEMU_MADV_INVALID) {
int serrno;
int dup_flags;
-#ifdef F_DUPFD_CLOEXEC
- ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
-#else
- ret = dup(fd);
- if (ret != -1) {
- qemu_set_cloexec(ret);
- }
-#endif
+ ret = qemu_dup(fd);
if (ret == -1) {
goto fail;
}
return -1;
}
+int qemu_dup(int fd)
+{
+ int ret;
+#ifdef F_DUPFD_CLOEXEC
+ ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
+ ret = dup(fd);
+ if (ret != -1) {
+ qemu_set_cloexec(ret);
+ }
+#endif
+ return ret;
+}
+
static int qemu_parse_fdset(const char *param)
{
return qemu_parse_fd(param);
}
#endif
+#ifdef O_DIRECT
+ if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) {
+ error_report("file system may not support O_DIRECT");
+ errno = EINVAL; /* in case it was clobbered */
+ }
+#endif /* O_DIRECT */
+
return ret;
}
return ret;
}
-/*
- * A variant of send(2) which handles partial write.
- *
- * Return the number of bytes transferred, which is only
- * smaller than `count' if there is an error.
- *
- * This function won't work with non-blocking fd's.
- * Any of the possibilities with non-bloking fd's is bad:
- * - return a short write (then name is wrong)
- * - busy wait adding (errno == EAGAIN) to the loop
- */
-ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
-{
- ssize_t ret = 0;
- ssize_t total = 0;
-
- while (count) {
- ret = send(fd, buf, count, flags);
- if (ret < 0) {
- if (errno == EINTR) {
- continue;
- }
- break;
- }
-
- count -= ret;
- buf += ret;
- total += ret;
- }
-
- return total;
-}
-
-/*
- * A variant of recv(2) which handles partial write.
- *
- * Return the number of bytes transferred, which is only
- * smaller than `count' if there is an error.
- *
- * This function won't work with non-blocking fd's.
- * Any of the possibilities with non-bloking fd's is bad:
- * - return a short write (then name is wrong)
- * - busy wait adding (errno == EAGAIN) to the loop
- */
-ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
-{
- ssize_t ret = 0;
- ssize_t total = 0;
-
- while (count) {
- ret = qemu_recv(fd, buf, count, flags);
- if (ret <= 0) {
- if (ret < 0 && errno == EINTR) {
- continue;
- }
- break;
- }
-
- count -= ret;
- buf += ret;
- total += ret;
- }
-
- return total;
-}
-
-void qemu_set_version(const char *version)
+void qemu_set_hw_version(const char *version)
{
- qemu_version = version;
+ hw_version = version;
}
-const char *qemu_get_version(void)
+const char *qemu_hw_version(void)
{
- return qemu_version;
+ return hw_version;
}
void fips_set_state(bool requested)
return fips_enabled;
}
+#ifdef _WIN32
+static void socket_cleanup(void)
+{
+ WSACleanup();
+}
+#endif
+
+int socket_init(void)
+{
+#ifdef _WIN32
+ WSADATA Data;
+ int ret, err;
+
+ ret = WSAStartup(MAKEWORD(2, 2), &Data);
+ if (ret != 0) {
+ err = WSAGetLastError();
+ fprintf(stderr, "WSAStartup: %d\n", err);
+ return -1;
+ }
+ atexit(socket_cleanup);
+#endif
+ return 0;
+}
+
+#if !GLIB_CHECK_VERSION(2, 31, 0)
+/* Ensure that glib is running in multi-threaded mode
+ * Old versions of glib require explicit initialization. Failure to do
+ * this results in the single-threaded code paths being taken inside
+ * glib. For example, the g_slice allocator will not be thread-safe
+ * and cause crashes.
+ */
+static void __attribute__((constructor)) thread_init(void)
+{
+ if (!g_thread_supported()) {
+ g_thread_init(NULL);
+ }
+}
+#endif
+
+#ifndef CONFIG_IOVEC
+/* helper function for iov_send_recv() */
+static ssize_t
+readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
+{
+ unsigned i = 0;
+ ssize_t ret = 0;
+ while (i < iov_cnt) {
+ ssize_t r = do_write
+ ? write(fd, iov[i].iov_base, iov[i].iov_len)
+ : read(fd, iov[i].iov_base, iov[i].iov_len);
+ if (r > 0) {
+ ret += r;
+ } else if (!r) {
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ } else {
+ /* else it is some "other" error,
+ * only return if there was no data processed. */
+ if (ret == 0) {
+ ret = -1;
+ }
+ break;
+ }
+ i++;
+ }
+ return ret;
+}
+
+ssize_t
+readv(int fd, const struct iovec *iov, int iov_cnt)
+{
+ return readv_writev(fd, iov, iov_cnt, false);
+}
+
+ssize_t
+writev(int fd, const struct iovec *iov, int iov_cnt)
+{
+ return readv_writev(fd, iov, iov_cnt, true);
+}
+#endif