*
* 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 "qemu/osdep.h"
+#include "qemu-common.h"
#include "qapi/error.h"
+#include "qapi/qapi-visit-sockets.h"
+#include "qemu/module.h"
#include "io/channel-socket.h"
#include "io/channel-watch.h"
#include "trace.h"
+#include "qapi/clone-visitor.h"
#define SOCKET_MAX_FDS 16
sioc->fd = -1;
ioc = QIO_CHANNEL(sioc);
- ioc->features |= (1 << QIO_CHANNEL_FEATURE_SHUTDOWN);
+ qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
#ifdef WIN32
ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL);
int fd,
Error **errp)
{
- int val;
- socklen_t len = sizeof(val);
-
if (sioc->fd != -1) {
error_setg(errp, "Socket is already open");
return -1;
#ifndef WIN32
if (sioc->localAddr.ss_family == AF_UNIX) {
QIOChannel *ioc = QIO_CHANNEL(sioc);
- ioc->features |= (1 << QIO_CHANNEL_FEATURE_FD_PASS);
+ qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS);
}
#endif /* WIN32 */
- if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &val, &len) == 0 && val) {
- QIOChannel *ioc = QIO_CHANNEL(sioc);
- ioc->features |= (1 << QIO_CHANNEL_FEATURE_LISTEN);
- }
return 0;
int fd;
trace_qio_channel_socket_connect_sync(ioc, addr);
- fd = socket_connect(addr, errp, NULL, NULL);
+ fd = socket_connect(addr, errp);
if (fd < 0) {
trace_qio_channel_socket_connect_fail(ioc);
return -1;
}
-static int qio_channel_socket_connect_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_connect_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
SocketAddress *addr = opaque;
- int ret;
+ Error *err = NULL;
- ret = qio_channel_socket_connect_sync(ioc,
- addr,
- errp);
+ qio_channel_socket_connect_sync(ioc, addr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
SocketAddress *addr,
QIOTaskFunc callback,
gpointer opaque,
- GDestroyNotify destroy)
+ GDestroyNotify destroy,
+ GMainContext *context)
{
QIOTask *task = qio_task_new(
OBJECT(ioc), callback, opaque, destroy);
SocketAddress *addrCopy;
- qapi_copy_SocketAddress(&addrCopy, addr);
+ addrCopy = QAPI_CLONE(SocketAddress, addr);
/* socket_connect() does a non-blocking connect(), but it
* still blocks in DNS lookups, so we must use a thread */
qio_task_run_in_thread(task,
qio_channel_socket_connect_worker,
addrCopy,
- (GDestroyNotify)qapi_free_SocketAddress);
+ (GDestroyNotify)qapi_free_SocketAddress,
+ context);
}
close(fd);
return -1;
}
+ qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_LISTEN);
return 0;
}
-static int qio_channel_socket_listen_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_listen_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
SocketAddress *addr = opaque;
- int ret;
+ Error *err = NULL;
- ret = qio_channel_socket_listen_sync(ioc,
- addr,
- errp);
+ qio_channel_socket_listen_sync(ioc, addr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
SocketAddress *addr,
QIOTaskFunc callback,
gpointer opaque,
- GDestroyNotify destroy)
+ GDestroyNotify destroy,
+ GMainContext *context)
{
QIOTask *task = qio_task_new(
OBJECT(ioc), callback, opaque, destroy);
SocketAddress *addrCopy;
- qapi_copy_SocketAddress(&addrCopy, addr);
+ addrCopy = QAPI_CLONE(SocketAddress, addr);
/* socket_listen() blocks in DNS lookups, so we must use a thread */
trace_qio_channel_socket_listen_async(ioc, addr);
qio_task_run_in_thread(task,
qio_channel_socket_listen_worker,
addrCopy,
- (GDestroyNotify)qapi_free_SocketAddress);
+ (GDestroyNotify)qapi_free_SocketAddress,
+ context);
}
g_free(data);
}
-static int qio_channel_socket_dgram_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_dgram_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
struct QIOChannelSocketDGramWorkerData *data = opaque;
- int ret;
+ Error *err = NULL;
/* socket_dgram() blocks in DNS lookups, so we must use a thread */
- ret = qio_channel_socket_dgram_sync(ioc,
- data->localAddr,
- data->remoteAddr,
- errp);
+ qio_channel_socket_dgram_sync(ioc, data->localAddr,
+ data->remoteAddr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
SocketAddress *remoteAddr,
QIOTaskFunc callback,
gpointer opaque,
- GDestroyNotify destroy)
+ GDestroyNotify destroy,
+ GMainContext *context)
{
QIOTask *task = qio_task_new(
OBJECT(ioc), callback, opaque, destroy);
struct QIOChannelSocketDGramWorkerData *data = g_new0(
struct QIOChannelSocketDGramWorkerData, 1);
- qapi_copy_SocketAddress(&data->localAddr, localAddr);
- qapi_copy_SocketAddress(&data->remoteAddr, remoteAddr);
+ data->localAddr = QAPI_CLONE(SocketAddress, localAddr);
+ data->remoteAddr = QAPI_CLONE(SocketAddress, remoteAddr);
trace_qio_channel_socket_dgram_async(ioc, localAddr, remoteAddr);
qio_task_run_in_thread(task,
qio_channel_socket_dgram_worker,
data,
- qio_channel_socket_dgram_worker_free);
+ qio_channel_socket_dgram_worker_free,
+ context);
}
{
QIOChannelSocket *cioc;
- cioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET));
- cioc->fd = -1;
+ cioc = qio_channel_socket_new();
cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
cioc->localAddrLen = sizeof(ioc->localAddr);
-#ifdef WIN32
- QIO_CHANNEL(cioc)->event = CreateEvent(NULL, FALSE, FALSE, NULL);
-#endif
-
-
retry:
trace_qio_channel_socket_accept(ioc);
cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
&cioc->remoteAddrLen);
if (cioc->fd < 0) {
- trace_qio_channel_socket_accept_fail(ioc);
if (errno == EINTR) {
goto retry;
}
+ error_setg_errno(errp, errno, "Unable to accept connection");
+ trace_qio_channel_socket_accept_fail(ioc);
goto error;
}
#ifndef WIN32
if (cioc->localAddr.ss_family == AF_UNIX) {
- QIO_CHANNEL(cioc)->features |= (1 << QIO_CHANNEL_FEATURE_FD_PASS);
+ QIOChannel *ioc_local = QIO_CHANNEL(cioc);
+ qio_channel_set_feature(ioc_local, QIO_CHANNEL_FEATURE_FD_PASS);
}
#endif /* WIN32 */
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj);
if (ioc->fd != -1) {
- if (QIO_CHANNEL(ioc)->features & QIO_CHANNEL_FEATURE_LISTEN) {
+ QIOChannel *ioc_local = QIO_CHANNEL(ioc);
+ if (qio_channel_has_feature(ioc_local, QIO_CHANNEL_FEATURE_LISTEN)) {
Error *err = NULL;
socket_listen_cleanup(ioc->fd, &err);
qemu_set_block(sioc->fd);
} else {
qemu_set_nonblock(sioc->fd);
-#ifdef WIN32
- WSAEventSelect(sioc->fd, ioc->event,
- FD_READ | FD_ACCEPT | FD_CLOSE |
- FD_CONNECT | FD_WRITE | FD_OOB);
-#endif
}
return 0;
}
Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+ int rc = 0;
if (sioc->fd != -1) {
#ifdef WIN32
WSAEventSelect(sioc->fd, NULL, 0);
#endif
+ if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) {
+ socket_listen_cleanup(sioc->fd, errp);
+ }
+
if (closesocket(sioc->fd) < 0) {
sioc->fd = -1;
error_setg_errno(errp, errno,
}
sioc->fd = -1;
}
- return 0;
+ return rc;
}
static int
return 0;
}
+static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc,
+ AioContext *ctx,
+ IOHandler *io_read,
+ IOHandler *io_write,
+ void *opaque)
+{
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+ aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque);
+}
+
static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
GIOCondition condition)
{
ioc_klass->io_set_cork = qio_channel_socket_set_cork;
ioc_klass->io_set_delay = qio_channel_socket_set_delay;
ioc_klass->io_create_watch = qio_channel_socket_create_watch;
+ ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler;
}
static const TypeInfo qio_channel_socket_info = {