2020-01-24 13:44:29 +00:00
|
|
|
/*
|
|
|
|
* vireventglibwatch.c: GSource impl for sockets
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015-2020 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "vireventglibwatch.h"
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
typedef struct virEventGLibFDSource virEventGLibFDSource;
|
|
|
|
struct virEventGLibFDSource {
|
|
|
|
GSource parent;
|
|
|
|
GPollFD pollfd;
|
|
|
|
int fd;
|
|
|
|
GIOCondition condition;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virEventGLibFDSourcePrepare(GSource *source G_GNUC_UNUSED,
|
|
|
|
gint *timeout)
|
|
|
|
{
|
|
|
|
*timeout = -1;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virEventGLibFDSourceCheck(GSource *source)
|
|
|
|
{
|
|
|
|
virEventGLibFDSource *ssource = (virEventGLibFDSource *)source;
|
|
|
|
|
|
|
|
return ssource->pollfd.revents & ssource->condition;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virEventGLibFDSourceDispatch(GSource *source,
|
|
|
|
GSourceFunc callback,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
virEventGLibSocketFunc func = (virEventGLibSocketFunc)callback;
|
|
|
|
virEventGLibFDSource *ssource = (virEventGLibFDSource *)source;
|
|
|
|
|
|
|
|
return (*func)(ssource->fd,
|
|
|
|
ssource->pollfd.revents & ssource->condition,
|
|
|
|
user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
virEventGLibFDSourceFinalize(GSource *source G_GNUC_UNUSED)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GSourceFuncs virEventGLibFDSourceFuncs = {
|
|
|
|
.prepare = virEventGLibFDSourcePrepare,
|
|
|
|
.check = virEventGLibFDSourceCheck,
|
|
|
|
.dispatch = virEventGLibFDSourceDispatch,
|
|
|
|
.finalize = virEventGLibFDSourceFinalize
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GSource *virEventGLibCreateSocketWatch(int fd,
|
|
|
|
GIOCondition condition)
|
|
|
|
{
|
|
|
|
GSource *source;
|
|
|
|
virEventGLibFDSource *ssource;
|
|
|
|
|
|
|
|
source = g_source_new(&virEventGLibFDSourceFuncs,
|
|
|
|
sizeof(virEventGLibFDSource));
|
|
|
|
ssource = (virEventGLibFDSource *)source;
|
|
|
|
|
2020-02-19 00:00:49 +00:00
|
|
|
ssource->condition = condition | G_IO_HUP | G_IO_ERR;
|
2020-01-24 13:44:29 +00:00
|
|
|
ssource->fd = fd;
|
|
|
|
|
|
|
|
ssource->pollfd.fd = fd;
|
2020-02-19 00:00:49 +00:00
|
|
|
ssource->pollfd.events = condition | G_IO_HUP | G_IO_ERR;
|
2020-01-24 13:44:29 +00:00
|
|
|
|
|
|
|
g_source_add_poll(source, &ssource->pollfd);
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* WIN32 */
|
|
|
|
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
# include <winsock2.h>
|
|
|
|
|
|
|
|
typedef struct virEventGLibSocketSource virEventGLibSocketSource;
|
|
|
|
struct virEventGLibSocketSource {
|
|
|
|
GSource parent;
|
|
|
|
GPollFD pollfd;
|
|
|
|
int fd;
|
|
|
|
SOCKET socket;
|
|
|
|
HANDLE event;
|
|
|
|
int revents;
|
|
|
|
GIOCondition condition;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virEventGLibSocketSourcePrepare(GSource *source G_GNUC_UNUSED,
|
|
|
|
gint *timeout)
|
|
|
|
{
|
|
|
|
*timeout = -1;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NB, this impl only works when the socket is in non-blocking
|
|
|
|
* mode on Win32
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
virEventGLibSocketSourceCheck(GSource *source)
|
|
|
|
{
|
|
|
|
static struct timeval tv0;
|
|
|
|
|
|
|
|
virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
|
|
|
|
WSANETWORKEVENTS ev;
|
|
|
|
fd_set rfds, wfds, xfds;
|
|
|
|
|
|
|
|
if (!ssource->condition)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
WSAEnumNetworkEvents(ssource->socket, ssource->event, &ev);
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_ZERO(&wfds);
|
|
|
|
FD_ZERO(&xfds);
|
|
|
|
if (ssource->condition & G_IO_IN)
|
|
|
|
FD_SET(ssource->socket, &rfds);
|
|
|
|
if (ssource->condition & G_IO_OUT)
|
|
|
|
FD_SET(ssource->socket, &wfds);
|
|
|
|
if (ssource->condition & G_IO_PRI)
|
|
|
|
FD_SET(ssource->socket, &xfds);
|
|
|
|
|
|
|
|
ssource->revents = 0;
|
|
|
|
if (select(0, &rfds, &wfds, &xfds, &tv0) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (FD_ISSET(ssource->socket, &rfds))
|
|
|
|
ssource->revents |= G_IO_IN;
|
|
|
|
|
|
|
|
if (FD_ISSET(ssource->socket, &wfds))
|
|
|
|
ssource->revents |= G_IO_OUT;
|
|
|
|
|
|
|
|
if (FD_ISSET(ssource->socket, &xfds))
|
|
|
|
ssource->revents |= G_IO_PRI;
|
|
|
|
|
|
|
|
return ssource->revents;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virEventGLibSocketSourceDispatch(GSource *source,
|
|
|
|
GSourceFunc callback,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
virEventGLibSocketFunc func = (virEventGLibSocketFunc)callback;
|
|
|
|
virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
|
|
|
|
|
|
|
|
return (*func)(ssource->fd, ssource->revents, user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
virEventGLibSocketSourceFinalize(GSource *source)
|
|
|
|
{
|
|
|
|
virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
|
|
|
|
|
|
|
|
WSAEventSelect(ssource->socket, NULL, 0);
|
|
|
|
CloseHandle(ssource->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GSourceFuncs virEventGLibSocketSourceFuncs = {
|
|
|
|
.prepare = virEventGLibSocketSourcePrepare,
|
|
|
|
.check = virEventGLibSocketSourceCheck,
|
|
|
|
.dispatch = virEventGLibSocketSourceDispatch,
|
|
|
|
.finalize = virEventGLibSocketSourceFinalize
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GSource *virEventGLibCreateSocketWatch(int fd,
|
|
|
|
GIOCondition condition)
|
|
|
|
{
|
|
|
|
GSource *source;
|
|
|
|
virEventGLibSocketSource *ssource;
|
|
|
|
|
|
|
|
source = g_source_new(&virEventGLibSocketSourceFuncs,
|
|
|
|
sizeof(virEventGLibSocketSource));
|
|
|
|
ssource = (virEventGLibSocketSource *)source;
|
|
|
|
|
|
|
|
ssource->condition = condition;
|
|
|
|
ssource->fd = fd;
|
|
|
|
ssource->socket = _get_osfhandle(fd);
|
|
|
|
ssource->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
ssource->revents = 0;
|
|
|
|
|
|
|
|
ssource->pollfd.fd = (gintptr)ssource->event;
|
|
|
|
ssource->pollfd.events = G_IO_IN;
|
|
|
|
|
|
|
|
WSAEventSelect(ssource->socket, ssource->event,
|
|
|
|
FD_READ | FD_ACCEPT | FD_CLOSE |
|
|
|
|
FD_CONNECT | FD_WRITE | FD_OOB);
|
|
|
|
|
|
|
|
g_source_add_poll(source, &ssource->pollfd);
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
|
|
|
2020-07-28 14:54:13 +00:00
|
|
|
GSource *
|
|
|
|
virEventGLibAddSocketWatch(int fd,
|
|
|
|
GIOCondition condition,
|
|
|
|
GMainContext *context,
|
|
|
|
virEventGLibSocketFunc func,
|
|
|
|
gpointer opaque,
|
|
|
|
GDestroyNotify notify)
|
2020-01-24 13:44:29 +00:00
|
|
|
{
|
2020-07-28 14:54:13 +00:00
|
|
|
GSource *source = NULL;
|
2020-01-24 13:44:29 +00:00
|
|
|
|
|
|
|
source = virEventGLibCreateSocketWatch(fd, condition);
|
|
|
|
g_source_set_callback(source, (GSourceFunc)func, opaque, notify);
|
|
|
|
|
2020-07-28 14:54:13 +00:00
|
|
|
g_source_attach(source, context);
|
|
|
|
|
|
|
|
return source;
|
2020-01-24 13:44:29 +00:00
|
|
|
}
|