cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

channel-socket.c (23136B)


      1/*
      2 * QEMU I/O channels sockets driver
      3 *
      4 * Copyright (c) 2015 Red Hat, Inc.
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "qemu-common.h"
     22#include "qapi/error.h"
     23#include "qapi/qapi-visit-sockets.h"
     24#include "qemu/module.h"
     25#include "io/channel-socket.h"
     26#include "io/channel-watch.h"
     27#include "trace.h"
     28#include "qapi/clone-visitor.h"
     29
     30#define SOCKET_MAX_FDS 16
     31
     32SocketAddress *
     33qio_channel_socket_get_local_address(QIOChannelSocket *ioc,
     34                                     Error **errp)
     35{
     36    return socket_sockaddr_to_address(&ioc->localAddr,
     37                                      ioc->localAddrLen,
     38                                      errp);
     39}
     40
     41SocketAddress *
     42qio_channel_socket_get_remote_address(QIOChannelSocket *ioc,
     43                                      Error **errp)
     44{
     45    return socket_sockaddr_to_address(&ioc->remoteAddr,
     46                                      ioc->remoteAddrLen,
     47                                      errp);
     48}
     49
     50QIOChannelSocket *
     51qio_channel_socket_new(void)
     52{
     53    QIOChannelSocket *sioc;
     54    QIOChannel *ioc;
     55
     56    sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET));
     57    sioc->fd = -1;
     58
     59    ioc = QIO_CHANNEL(sioc);
     60    qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
     61
     62#ifdef WIN32
     63    ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL);
     64#endif
     65
     66    trace_qio_channel_socket_new(sioc);
     67
     68    return sioc;
     69}
     70
     71
     72static int
     73qio_channel_socket_set_fd(QIOChannelSocket *sioc,
     74                          int fd,
     75                          Error **errp)
     76{
     77    if (sioc->fd != -1) {
     78        error_setg(errp, "Socket is already open");
     79        return -1;
     80    }
     81
     82    sioc->fd = fd;
     83    sioc->remoteAddrLen = sizeof(sioc->remoteAddr);
     84    sioc->localAddrLen = sizeof(sioc->localAddr);
     85
     86
     87    if (getpeername(fd, (struct sockaddr *)&sioc->remoteAddr,
     88                    &sioc->remoteAddrLen) < 0) {
     89        if (errno == ENOTCONN) {
     90            memset(&sioc->remoteAddr, 0, sizeof(sioc->remoteAddr));
     91            sioc->remoteAddrLen = sizeof(sioc->remoteAddr);
     92        } else {
     93            error_setg_errno(errp, errno,
     94                             "Unable to query remote socket address");
     95            goto error;
     96        }
     97    }
     98
     99    if (getsockname(fd, (struct sockaddr *)&sioc->localAddr,
    100                    &sioc->localAddrLen) < 0) {
    101        error_setg_errno(errp, errno,
    102                         "Unable to query local socket address");
    103        goto error;
    104    }
    105
    106#ifndef WIN32
    107    if (sioc->localAddr.ss_family == AF_UNIX) {
    108        QIOChannel *ioc = QIO_CHANNEL(sioc);
    109        qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS);
    110    }
    111#endif /* WIN32 */
    112
    113    return 0;
    114
    115 error:
    116    sioc->fd = -1; /* Let the caller close FD on failure */
    117    return -1;
    118}
    119
    120QIOChannelSocket *
    121qio_channel_socket_new_fd(int fd,
    122                          Error **errp)
    123{
    124    QIOChannelSocket *ioc;
    125
    126    ioc = qio_channel_socket_new();
    127    if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) {
    128        object_unref(OBJECT(ioc));
    129        return NULL;
    130    }
    131
    132    trace_qio_channel_socket_new_fd(ioc, fd);
    133
    134    return ioc;
    135}
    136
    137
    138int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
    139                                    SocketAddress *addr,
    140                                    Error **errp)
    141{
    142    int fd;
    143
    144    trace_qio_channel_socket_connect_sync(ioc, addr);
    145    fd = socket_connect(addr, errp);
    146    if (fd < 0) {
    147        trace_qio_channel_socket_connect_fail(ioc);
    148        return -1;
    149    }
    150
    151    trace_qio_channel_socket_connect_complete(ioc, fd);
    152    if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) {
    153        close(fd);
    154        return -1;
    155    }
    156
    157    return 0;
    158}
    159
    160
    161static void qio_channel_socket_connect_worker(QIOTask *task,
    162                                              gpointer opaque)
    163{
    164    QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
    165    SocketAddress *addr = opaque;
    166    Error *err = NULL;
    167
    168    qio_channel_socket_connect_sync(ioc, addr, &err);
    169
    170    qio_task_set_error(task, err);
    171}
    172
    173
    174void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
    175                                      SocketAddress *addr,
    176                                      QIOTaskFunc callback,
    177                                      gpointer opaque,
    178                                      GDestroyNotify destroy,
    179                                      GMainContext *context)
    180{
    181    QIOTask *task = qio_task_new(
    182        OBJECT(ioc), callback, opaque, destroy);
    183    SocketAddress *addrCopy;
    184
    185    addrCopy = QAPI_CLONE(SocketAddress, addr);
    186
    187    /* socket_connect() does a non-blocking connect(), but it
    188     * still blocks in DNS lookups, so we must use a thread */
    189    trace_qio_channel_socket_connect_async(ioc, addr);
    190    qio_task_run_in_thread(task,
    191                           qio_channel_socket_connect_worker,
    192                           addrCopy,
    193                           (GDestroyNotify)qapi_free_SocketAddress,
    194                           context);
    195}
    196
    197
    198int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
    199                                   SocketAddress *addr,
    200                                   int num,
    201                                   Error **errp)
    202{
    203    int fd;
    204
    205    trace_qio_channel_socket_listen_sync(ioc, addr, num);
    206    fd = socket_listen(addr, num, errp);
    207    if (fd < 0) {
    208        trace_qio_channel_socket_listen_fail(ioc);
    209        return -1;
    210    }
    211
    212    trace_qio_channel_socket_listen_complete(ioc, fd);
    213    if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) {
    214        close(fd);
    215        return -1;
    216    }
    217    qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_LISTEN);
    218
    219    return 0;
    220}
    221
    222
    223struct QIOChannelListenWorkerData {
    224    SocketAddress *addr;
    225    int num; /* amount of expected connections */
    226};
    227
    228static void qio_channel_listen_worker_free(gpointer opaque)
    229{
    230    struct QIOChannelListenWorkerData *data = opaque;
    231
    232    qapi_free_SocketAddress(data->addr);
    233    g_free(data);
    234}
    235
    236static void qio_channel_socket_listen_worker(QIOTask *task,
    237                                             gpointer opaque)
    238{
    239    QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
    240    struct QIOChannelListenWorkerData *data = opaque;
    241    Error *err = NULL;
    242
    243    qio_channel_socket_listen_sync(ioc, data->addr, data->num, &err);
    244
    245    qio_task_set_error(task, err);
    246}
    247
    248
    249void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
    250                                     SocketAddress *addr,
    251                                     int num,
    252                                     QIOTaskFunc callback,
    253                                     gpointer opaque,
    254                                     GDestroyNotify destroy,
    255                                     GMainContext *context)
    256{
    257    QIOTask *task = qio_task_new(
    258        OBJECT(ioc), callback, opaque, destroy);
    259    struct QIOChannelListenWorkerData *data;
    260
    261    data = g_new0(struct QIOChannelListenWorkerData, 1);
    262    data->addr = QAPI_CLONE(SocketAddress, addr);
    263    data->num = num;
    264
    265    /* socket_listen() blocks in DNS lookups, so we must use a thread */
    266    trace_qio_channel_socket_listen_async(ioc, addr, num);
    267    qio_task_run_in_thread(task,
    268                           qio_channel_socket_listen_worker,
    269                           data,
    270                           qio_channel_listen_worker_free,
    271                           context);
    272}
    273
    274
    275int qio_channel_socket_dgram_sync(QIOChannelSocket *ioc,
    276                                  SocketAddress *localAddr,
    277                                  SocketAddress *remoteAddr,
    278                                  Error **errp)
    279{
    280    int fd;
    281
    282    trace_qio_channel_socket_dgram_sync(ioc, localAddr, remoteAddr);
    283    fd = socket_dgram(remoteAddr, localAddr, errp);
    284    if (fd < 0) {
    285        trace_qio_channel_socket_dgram_fail(ioc);
    286        return -1;
    287    }
    288
    289    trace_qio_channel_socket_dgram_complete(ioc, fd);
    290    if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) {
    291        close(fd);
    292        return -1;
    293    }
    294
    295    return 0;
    296}
    297
    298
    299struct QIOChannelSocketDGramWorkerData {
    300    SocketAddress *localAddr;
    301    SocketAddress *remoteAddr;
    302};
    303
    304
    305static void qio_channel_socket_dgram_worker_free(gpointer opaque)
    306{
    307    struct QIOChannelSocketDGramWorkerData *data = opaque;
    308    qapi_free_SocketAddress(data->localAddr);
    309    qapi_free_SocketAddress(data->remoteAddr);
    310    g_free(data);
    311}
    312
    313static void qio_channel_socket_dgram_worker(QIOTask *task,
    314                                            gpointer opaque)
    315{
    316    QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
    317    struct QIOChannelSocketDGramWorkerData *data = opaque;
    318    Error *err = NULL;
    319
    320    /* socket_dgram() blocks in DNS lookups, so we must use a thread */
    321    qio_channel_socket_dgram_sync(ioc, data->localAddr,
    322                                  data->remoteAddr, &err);
    323
    324    qio_task_set_error(task, err);
    325}
    326
    327
    328void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,
    329                                    SocketAddress *localAddr,
    330                                    SocketAddress *remoteAddr,
    331                                    QIOTaskFunc callback,
    332                                    gpointer opaque,
    333                                    GDestroyNotify destroy,
    334                                    GMainContext *context)
    335{
    336    QIOTask *task = qio_task_new(
    337        OBJECT(ioc), callback, opaque, destroy);
    338    struct QIOChannelSocketDGramWorkerData *data = g_new0(
    339        struct QIOChannelSocketDGramWorkerData, 1);
    340
    341    data->localAddr = QAPI_CLONE(SocketAddress, localAddr);
    342    data->remoteAddr = QAPI_CLONE(SocketAddress, remoteAddr);
    343
    344    trace_qio_channel_socket_dgram_async(ioc, localAddr, remoteAddr);
    345    qio_task_run_in_thread(task,
    346                           qio_channel_socket_dgram_worker,
    347                           data,
    348                           qio_channel_socket_dgram_worker_free,
    349                           context);
    350}
    351
    352
    353QIOChannelSocket *
    354qio_channel_socket_accept(QIOChannelSocket *ioc,
    355                          Error **errp)
    356{
    357    QIOChannelSocket *cioc;
    358
    359    cioc = qio_channel_socket_new();
    360    cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
    361    cioc->localAddrLen = sizeof(ioc->localAddr);
    362
    363 retry:
    364    trace_qio_channel_socket_accept(ioc);
    365    cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
    366                           &cioc->remoteAddrLen);
    367    if (cioc->fd < 0) {
    368        if (errno == EINTR) {
    369            goto retry;
    370        }
    371        error_setg_errno(errp, errno, "Unable to accept connection");
    372        trace_qio_channel_socket_accept_fail(ioc);
    373        goto error;
    374    }
    375
    376    if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr,
    377                    &cioc->localAddrLen) < 0) {
    378        error_setg_errno(errp, errno,
    379                         "Unable to query local socket address");
    380        goto error;
    381    }
    382
    383#ifndef WIN32
    384    if (cioc->localAddr.ss_family == AF_UNIX) {
    385        QIOChannel *ioc_local = QIO_CHANNEL(cioc);
    386        qio_channel_set_feature(ioc_local, QIO_CHANNEL_FEATURE_FD_PASS);
    387    }
    388#endif /* WIN32 */
    389
    390    trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd);
    391    return cioc;
    392
    393 error:
    394    object_unref(OBJECT(cioc));
    395    return NULL;
    396}
    397
    398static void qio_channel_socket_init(Object *obj)
    399{
    400    QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj);
    401    ioc->fd = -1;
    402}
    403
    404static void qio_channel_socket_finalize(Object *obj)
    405{
    406    QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj);
    407
    408    if (ioc->fd != -1) {
    409        QIOChannel *ioc_local = QIO_CHANNEL(ioc);
    410        if (qio_channel_has_feature(ioc_local, QIO_CHANNEL_FEATURE_LISTEN)) {
    411            Error *err = NULL;
    412
    413            socket_listen_cleanup(ioc->fd, &err);
    414            if (err) {
    415                error_report_err(err);
    416                err = NULL;
    417            }
    418        }
    419#ifdef WIN32
    420        WSAEventSelect(ioc->fd, NULL, 0);
    421#endif
    422        closesocket(ioc->fd);
    423        ioc->fd = -1;
    424    }
    425}
    426
    427
    428#ifndef WIN32
    429static void qio_channel_socket_copy_fds(struct msghdr *msg,
    430                                        int **fds, size_t *nfds)
    431{
    432    struct cmsghdr *cmsg;
    433
    434    *nfds = 0;
    435    *fds = NULL;
    436
    437    for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
    438        int fd_size, i;
    439        int gotfds;
    440
    441        if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
    442            cmsg->cmsg_level != SOL_SOCKET ||
    443            cmsg->cmsg_type != SCM_RIGHTS) {
    444            continue;
    445        }
    446
    447        fd_size = cmsg->cmsg_len - CMSG_LEN(0);
    448
    449        if (!fd_size) {
    450            continue;
    451        }
    452
    453        gotfds = fd_size / sizeof(int);
    454        *fds = g_renew(int, *fds, *nfds + gotfds);
    455        memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size);
    456
    457        for (i = 0; i < gotfds; i++) {
    458            int fd = (*fds)[*nfds + i];
    459            if (fd < 0) {
    460                continue;
    461            }
    462
    463            /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
    464            qemu_set_block(fd);
    465
    466#ifndef MSG_CMSG_CLOEXEC
    467            qemu_set_cloexec(fd);
    468#endif
    469        }
    470        *nfds += gotfds;
    471    }
    472}
    473
    474
    475static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
    476                                        const struct iovec *iov,
    477                                        size_t niov,
    478                                        int **fds,
    479                                        size_t *nfds,
    480                                        Error **errp)
    481{
    482    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    483    ssize_t ret;
    484    struct msghdr msg = { NULL, };
    485    char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)];
    486    int sflags = 0;
    487
    488    memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
    489
    490    msg.msg_iov = (struct iovec *)iov;
    491    msg.msg_iovlen = niov;
    492    if (fds && nfds) {
    493        msg.msg_control = control;
    494        msg.msg_controllen = sizeof(control);
    495#ifdef MSG_CMSG_CLOEXEC
    496        sflags |= MSG_CMSG_CLOEXEC;
    497#endif
    498
    499    }
    500
    501 retry:
    502    ret = recvmsg(sioc->fd, &msg, sflags);
    503    if (ret < 0) {
    504        if (errno == EAGAIN) {
    505            return QIO_CHANNEL_ERR_BLOCK;
    506        }
    507        if (errno == EINTR) {
    508            goto retry;
    509        }
    510
    511        error_setg_errno(errp, errno,
    512                         "Unable to read from socket");
    513        return -1;
    514    }
    515
    516    if (fds && nfds) {
    517        qio_channel_socket_copy_fds(&msg, fds, nfds);
    518    }
    519
    520    return ret;
    521}
    522
    523static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
    524                                         const struct iovec *iov,
    525                                         size_t niov,
    526                                         int *fds,
    527                                         size_t nfds,
    528                                         Error **errp)
    529{
    530    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    531    ssize_t ret;
    532    struct msghdr msg = { NULL, };
    533    char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)];
    534    size_t fdsize = sizeof(int) * nfds;
    535    struct cmsghdr *cmsg;
    536
    537    memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
    538
    539    msg.msg_iov = (struct iovec *)iov;
    540    msg.msg_iovlen = niov;
    541
    542    if (nfds) {
    543        if (nfds > SOCKET_MAX_FDS) {
    544            error_setg_errno(errp, EINVAL,
    545                             "Only %d FDs can be sent, got %zu",
    546                             SOCKET_MAX_FDS, nfds);
    547            return -1;
    548        }
    549
    550        msg.msg_control = control;
    551        msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfds);
    552
    553        cmsg = CMSG_FIRSTHDR(&msg);
    554        cmsg->cmsg_len = CMSG_LEN(fdsize);
    555        cmsg->cmsg_level = SOL_SOCKET;
    556        cmsg->cmsg_type = SCM_RIGHTS;
    557        memcpy(CMSG_DATA(cmsg), fds, fdsize);
    558    }
    559
    560 retry:
    561    ret = sendmsg(sioc->fd, &msg, 0);
    562    if (ret <= 0) {
    563        if (errno == EAGAIN) {
    564            return QIO_CHANNEL_ERR_BLOCK;
    565        }
    566        if (errno == EINTR) {
    567            goto retry;
    568        }
    569        error_setg_errno(errp, errno,
    570                         "Unable to write to socket");
    571        return -1;
    572    }
    573    return ret;
    574}
    575#else /* WIN32 */
    576static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
    577                                        const struct iovec *iov,
    578                                        size_t niov,
    579                                        int **fds,
    580                                        size_t *nfds,
    581                                        Error **errp)
    582{
    583    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    584    ssize_t done = 0;
    585    ssize_t i;
    586
    587    for (i = 0; i < niov; i++) {
    588        ssize_t ret;
    589    retry:
    590        ret = recv(sioc->fd,
    591                   iov[i].iov_base,
    592                   iov[i].iov_len,
    593                   0);
    594        if (ret < 0) {
    595            if (errno == EAGAIN) {
    596                if (done) {
    597                    return done;
    598                } else {
    599                    return QIO_CHANNEL_ERR_BLOCK;
    600                }
    601            } else if (errno == EINTR) {
    602                goto retry;
    603            } else {
    604                error_setg_errno(errp, errno,
    605                                 "Unable to read from socket");
    606                return -1;
    607            }
    608        }
    609        done += ret;
    610        if (ret < iov[i].iov_len) {
    611            return done;
    612        }
    613    }
    614
    615    return done;
    616}
    617
    618static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
    619                                         const struct iovec *iov,
    620                                         size_t niov,
    621                                         int *fds,
    622                                         size_t nfds,
    623                                         Error **errp)
    624{
    625    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    626    ssize_t done = 0;
    627    ssize_t i;
    628
    629    for (i = 0; i < niov; i++) {
    630        ssize_t ret;
    631    retry:
    632        ret = send(sioc->fd,
    633                   iov[i].iov_base,
    634                   iov[i].iov_len,
    635                   0);
    636        if (ret < 0) {
    637            if (errno == EAGAIN) {
    638                if (done) {
    639                    return done;
    640                } else {
    641                    return QIO_CHANNEL_ERR_BLOCK;
    642                }
    643            } else if (errno == EINTR) {
    644                goto retry;
    645            } else {
    646                error_setg_errno(errp, errno,
    647                                 "Unable to write to socket");
    648                return -1;
    649            }
    650        }
    651        done += ret;
    652        if (ret < iov[i].iov_len) {
    653            return done;
    654        }
    655    }
    656
    657    return done;
    658}
    659#endif /* WIN32 */
    660
    661static int
    662qio_channel_socket_set_blocking(QIOChannel *ioc,
    663                                bool enabled,
    664                                Error **errp)
    665{
    666    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    667
    668    if (enabled) {
    669        qemu_set_block(sioc->fd);
    670    } else {
    671        qemu_set_nonblock(sioc->fd);
    672    }
    673    return 0;
    674}
    675
    676
    677static void
    678qio_channel_socket_set_delay(QIOChannel *ioc,
    679                             bool enabled)
    680{
    681    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    682    int v = enabled ? 0 : 1;
    683
    684    qemu_setsockopt(sioc->fd,
    685                    IPPROTO_TCP, TCP_NODELAY,
    686                    &v, sizeof(v));
    687}
    688
    689
    690static void
    691qio_channel_socket_set_cork(QIOChannel *ioc,
    692                            bool enabled)
    693{
    694    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    695    int v = enabled ? 1 : 0;
    696
    697    socket_set_cork(sioc->fd, v);
    698}
    699
    700
    701static int
    702qio_channel_socket_close(QIOChannel *ioc,
    703                         Error **errp)
    704{
    705    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    706    int rc = 0;
    707    Error *err = NULL;
    708
    709    if (sioc->fd != -1) {
    710#ifdef WIN32
    711        WSAEventSelect(sioc->fd, NULL, 0);
    712#endif
    713        if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) {
    714            socket_listen_cleanup(sioc->fd, errp);
    715        }
    716
    717        if (closesocket(sioc->fd) < 0) {
    718            sioc->fd = -1;
    719            error_setg_errno(&err, errno, "Unable to close socket");
    720            error_propagate(errp, err);
    721            return -1;
    722        }
    723        sioc->fd = -1;
    724    }
    725    return rc;
    726}
    727
    728static int
    729qio_channel_socket_shutdown(QIOChannel *ioc,
    730                            QIOChannelShutdown how,
    731                            Error **errp)
    732{
    733    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    734    int sockhow;
    735
    736    switch (how) {
    737    case QIO_CHANNEL_SHUTDOWN_READ:
    738        sockhow = SHUT_RD;
    739        break;
    740    case QIO_CHANNEL_SHUTDOWN_WRITE:
    741        sockhow = SHUT_WR;
    742        break;
    743    case QIO_CHANNEL_SHUTDOWN_BOTH:
    744    default:
    745        sockhow = SHUT_RDWR;
    746        break;
    747    }
    748
    749    if (shutdown(sioc->fd, sockhow) < 0) {
    750        error_setg_errno(errp, errno,
    751                         "Unable to shutdown socket");
    752        return -1;
    753    }
    754    return 0;
    755}
    756
    757static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc,
    758                                                  AioContext *ctx,
    759                                                  IOHandler *io_read,
    760                                                  IOHandler *io_write,
    761                                                  void *opaque)
    762{
    763    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    764    aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque);
    765}
    766
    767static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
    768                                                GIOCondition condition)
    769{
    770    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
    771    return qio_channel_create_socket_watch(ioc,
    772                                           sioc->fd,
    773                                           condition);
    774}
    775
    776static void qio_channel_socket_class_init(ObjectClass *klass,
    777                                          void *class_data G_GNUC_UNUSED)
    778{
    779    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
    780
    781    ioc_klass->io_writev = qio_channel_socket_writev;
    782    ioc_klass->io_readv = qio_channel_socket_readv;
    783    ioc_klass->io_set_blocking = qio_channel_socket_set_blocking;
    784    ioc_klass->io_close = qio_channel_socket_close;
    785    ioc_klass->io_shutdown = qio_channel_socket_shutdown;
    786    ioc_klass->io_set_cork = qio_channel_socket_set_cork;
    787    ioc_klass->io_set_delay = qio_channel_socket_set_delay;
    788    ioc_klass->io_create_watch = qio_channel_socket_create_watch;
    789    ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler;
    790}
    791
    792static const TypeInfo qio_channel_socket_info = {
    793    .parent = TYPE_QIO_CHANNEL,
    794    .name = TYPE_QIO_CHANNEL_SOCKET,
    795    .instance_size = sizeof(QIOChannelSocket),
    796    .instance_init = qio_channel_socket_init,
    797    .instance_finalize = qio_channel_socket_finalize,
    798    .class_init = qio_channel_socket_class_init,
    799};
    800
    801static void qio_channel_socket_register_types(void)
    802{
    803    type_register_static(&qio_channel_socket_info);
    804}
    805
    806type_init(qio_channel_socket_register_types);