* 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.
- *
- * The implementation of g_poll (functions poll_rest, g_poll) at the end of
- * this file are based on code from GNOME glib-2 and use a different license,
- * see the license comment there.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include <malloc.h>
-/* this must come after including "trace.h" */
-#include <shlobj.h>
-
static int get_allocation_granularity(void)
{
SYSTEM_INFO system_info;
}
}
-void qemu_set_block(int fd)
+void qemu_socket_set_block(int fd)
{
unsigned long opt = 0;
- WSAEventSelect(fd, NULL, 0);
+ qemu_socket_unselect(fd, NULL);
ioctlsocket(fd, FIONBIO, &opt);
}
-int qemu_try_set_nonblock(int fd)
+int qemu_socket_try_set_nonblock(int fd)
{
unsigned long opt = 1;
if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) {
return 0;
}
-void qemu_set_nonblock(int fd)
+void qemu_socket_set_nonblock(int fd)
{
- (void)qemu_try_set_nonblock(fd);
+ (void)qemu_socket_try_set_nonblock(fd);
}
int socket_set_fast_reuse(int fd)
char *
qemu_get_local_state_dir(void)
{
- HRESULT result;
- char base_path[MAX_PATH+1] = "";
+ const char * const *data_dirs = g_get_system_data_dirs();
- result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
- /* SHGFP_TYPE_CURRENT */ 0, base_path);
- if (result != S_OK) {
- /* misconfigured environment */
- g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result);
- abort();
- }
- return g_strdup(base_path);
+ g_assert(data_dirs && data_dirs[0]);
+
+ return g_strdup(data_dirs[0]);
}
void qemu_set_tty_echo(int fd, bool echo)
}
}
-static const char *exec_dir;
-
-void qemu_init_exec_dir(const char *argv0)
-{
-
- char *p;
- char buf[MAX_PATH];
- DWORD len;
-
- if (exec_dir) {
- return;
- }
-
- len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
- if (len == 0) {
- return;
- }
-
- buf[len] = 0;
- p = buf + len - 1;
- while (p != buf && *p != '\\') {
- p--;
- }
- *p = 0;
- if (access(buf, R_OK) == 0) {
- exec_dir = g_strdup(buf);
- } else {
- exec_dir = CONFIG_BINDIR;
- }
-}
-
-const char *qemu_get_exec_dir(void)
-{
- return exec_dir;
-}
-
int getpagesize(void)
{
SYSTEM_INFO system_info;
return system_info.dwPageSize;
}
-void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
- Error **errp)
+void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
+ ThreadContext *tc, Error **errp)
{
int i;
size_t pagesize = qemu_real_host_page_size();
- memory = (memory + pagesize - 1) & -pagesize;
- for (i = 0; i < memory / pagesize; i++) {
+ sz = (sz + pagesize - 1) & -pagesize;
+ for (i = 0; i < sz / pagesize; i++) {
memset(area + pagesize * i, 0, 1);
}
}
}
-pid_t qemu_fork(Error **errp)
+bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
+ long lNetworkEvents, Error **errp)
{
- errno = ENOSYS;
- error_setg_errno(errp, errno,
- "cannot fork child process");
- return -1;
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (errp == NULL) {
+ errp = &error_warn;
+ }
+
+ if (s == INVALID_SOCKET) {
+ error_setg(errp, "invalid socket fd=%d", sockfd);
+ return false;
+ }
+
+ if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) {
+ error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()");
+ return false;
+ }
+
+ return true;
}
+bool qemu_socket_unselect(int sockfd, Error **errp)
+{
+ return qemu_socket_select(sockfd, NULL, 0, errp);
+}
#undef connect
int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
{
int ret;
- ret = connect(sockfd, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = connect(s, addr, addrlen);
if (ret < 0) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
errno = EINPROGRESS;
int qemu_listen_wrap(int sockfd, int backlog)
{
int ret;
- ret = listen(sockfd, backlog);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = listen(s, backlog);
if (ret < 0) {
errno = socket_error();
}
socklen_t addrlen)
{
int ret;
- ret = bind(sockfd, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = bind(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
}
+#undef close
+int qemu_close_wrap(int fd)
+{
+ int ret;
+ DWORD flags = 0;
+ SOCKET s = INVALID_SOCKET;
+
+ if (fd_is_socket(fd)) {
+ s = _get_osfhandle(fd);
+
+ /*
+ * If we were to just call _close on the descriptor, it would close the
+ * HANDLE, but it wouldn't free any of the resources associated to the
+ * SOCKET, and we can't call _close after calling closesocket, because
+ * closesocket has already closed the HANDLE, and _close would attempt to
+ * close the HANDLE again, resulting in a double free. We can however
+ * protect the HANDLE from actually being closed long enough to close the
+ * file descriptor, then close the socket itself.
+ */
+ if (!GetHandleInformation((HANDLE)s, &flags)) {
+ errno = EACCES;
+ return -1;
+ }
+
+ if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
+ errno = EACCES;
+ return -1;
+ }
+ }
+
+ ret = close(fd);
+
+ if (s != INVALID_SOCKET && !SetHandleInformation((HANDLE)s, flags, flags)) {
+ errno = EACCES;
+ return -1;
+ }
+
+ /*
+ * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle,
+ * but the FD is actually freed
+ */
+ if (ret < 0 && (s == INVALID_SOCKET || errno != EBADF)) {
+ return ret;
+ }
+
+ if (s != INVALID_SOCKET) {
+ ret = closesocket(s);
+ if (ret < 0) {
+ errno = socket_error();
+ }
+ }
+
+ return ret;
+}
+
+
#undef socket
int qemu_socket_wrap(int domain, int type, int protocol)
{
- int ret;
- ret = socket(domain, type, protocol);
- if (ret < 0) {
+ SOCKET s;
+ int fd;
+
+ s = socket(domain, type, protocol);
+ if (s == -1) {
errno = socket_error();
+ return -1;
}
- return ret;
+
+ fd = _open_osfhandle(s, _O_BINARY);
+ if (fd < 0) {
+ closesocket(s);
+ /* _open_osfhandle may not set errno, and closesocket() may override it */
+ errno = ENOMEM;
+ }
+
+ return fd;
}
int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
socklen_t *addrlen)
{
- int ret;
- ret = accept(sockfd, addr, addrlen);
- if (ret < 0) {
+ int fd;
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ s = accept(s, addr, addrlen);
+ if (s == -1) {
errno = socket_error();
+ return -1;
}
- return ret;
+
+ fd = _open_osfhandle(s, _O_BINARY);
+ if (fd < 0) {
+ closesocket(s);
+ /* _open_osfhandle may not set errno, and closesocket() may override it */
+ errno = ENOMEM;
+ }
+
+ return fd;
}
int qemu_shutdown_wrap(int sockfd, int how)
{
int ret;
- ret = shutdown(sockfd, how);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = shutdown(s, how);
if (ret < 0) {
errno = socket_error();
}
int qemu_ioctlsocket_wrap(int fd, int req, void *val)
{
int ret;
- ret = ioctlsocket(fd, req, val);
- if (ret < 0) {
- errno = socket_error();
- }
- return ret;
-}
+ SOCKET s = _get_osfhandle(fd);
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
-#undef closesocket
-int qemu_closesocket_wrap(int fd)
-{
- int ret;
- ret = closesocket(fd);
+ ret = ioctlsocket(s, req, val);
if (ret < 0) {
errno = socket_error();
}
void *optval, socklen_t *optlen)
{
int ret;
- ret = getsockopt(sockfd, level, optname, optval, optlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = getsockopt(s, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
const void *optval, socklen_t optlen)
{
int ret;
- ret = setsockopt(sockfd, level, optname, optval, optlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = setsockopt(s, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
socklen_t *addrlen)
{
int ret;
- ret = getpeername(sockfd, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = getpeername(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
socklen_t *addrlen)
{
int ret;
- ret = getsockname(sockfd, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = getsockname(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
{
int ret;
- ret = send(sockfd, buf, len, flags);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = send(s, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
const struct sockaddr *addr, socklen_t addrlen)
{
int ret;
- ret = sendto(sockfd, buf, len, flags, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = sendto(s, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
{
int ret;
- ret = recv(sockfd, buf, len, flags);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = recv(s, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
struct sockaddr *addr, socklen_t *addrlen)
{
int ret;
- ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
+ SOCKET s = _get_osfhandle(sockfd);
+
+ if (s == INVALID_SOCKET) {
+ return -1;
+ }
+
+ ret = recvfrom(s, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}