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

net-listener.c (9285B)


      1/*
      2 * QEMU network listener
      3 *
      4 * Copyright (c) 2016-2017 Red Hat, Inc.
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program 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
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with this program; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "io/net-listener.h"
     23#include "io/dns-resolver.h"
     24#include "qapi/error.h"
     25#include "qemu/module.h"
     26
     27QIONetListener *qio_net_listener_new(void)
     28{
     29    return QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER));
     30}
     31
     32void qio_net_listener_set_name(QIONetListener *listener,
     33                               const char *name)
     34{
     35    g_free(listener->name);
     36    listener->name = g_strdup(name);
     37}
     38
     39
     40static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
     41                                              GIOCondition condition,
     42                                              gpointer opaque)
     43{
     44    QIONetListener *listener = QIO_NET_LISTENER(opaque);
     45    QIOChannelSocket *sioc;
     46
     47    sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
     48                                     NULL);
     49    if (!sioc) {
     50        return TRUE;
     51    }
     52
     53    if (listener->io_func) {
     54        listener->io_func(listener, sioc, listener->io_data);
     55    }
     56
     57    object_unref(OBJECT(sioc));
     58
     59    return TRUE;
     60}
     61
     62
     63int qio_net_listener_open_sync(QIONetListener *listener,
     64                               SocketAddress *addr,
     65                               int num,
     66                               Error **errp)
     67{
     68    QIODNSResolver *resolver = qio_dns_resolver_get_instance();
     69    SocketAddress **resaddrs;
     70    size_t nresaddrs;
     71    size_t i;
     72    Error *err = NULL;
     73    bool success = false;
     74
     75    if (qio_dns_resolver_lookup_sync(resolver,
     76                                     addr,
     77                                     &nresaddrs,
     78                                     &resaddrs,
     79                                     errp) < 0) {
     80        return -1;
     81    }
     82
     83    for (i = 0; i < nresaddrs; i++) {
     84        QIOChannelSocket *sioc = qio_channel_socket_new();
     85
     86        if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num,
     87                                           err ? NULL : &err) == 0) {
     88            success = true;
     89
     90            qio_net_listener_add(listener, sioc);
     91        }
     92
     93        qapi_free_SocketAddress(resaddrs[i]);
     94        object_unref(OBJECT(sioc));
     95    }
     96    g_free(resaddrs);
     97
     98    if (success) {
     99        error_free(err);
    100        return 0;
    101    } else {
    102        error_propagate(errp, err);
    103        return -1;
    104    }
    105}
    106
    107
    108void qio_net_listener_add(QIONetListener *listener,
    109                          QIOChannelSocket *sioc)
    110{
    111    if (listener->name) {
    112        char *name = g_strdup_printf("%s-listen", listener->name);
    113        qio_channel_set_name(QIO_CHANNEL(sioc), name);
    114        g_free(name);
    115    }
    116
    117    listener->sioc = g_renew(QIOChannelSocket *, listener->sioc,
    118                             listener->nsioc + 1);
    119    listener->io_source = g_renew(typeof(listener->io_source[0]),
    120                                  listener->io_source,
    121                                  listener->nsioc + 1);
    122    listener->sioc[listener->nsioc] = sioc;
    123    listener->io_source[listener->nsioc] = NULL;
    124
    125    object_ref(OBJECT(sioc));
    126    listener->connected = true;
    127
    128    if (listener->io_func != NULL) {
    129        object_ref(OBJECT(listener));
    130        listener->io_source[listener->nsioc] = qio_channel_add_watch_source(
    131            QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN,
    132            qio_net_listener_channel_func,
    133            listener, (GDestroyNotify)object_unref, NULL);
    134    }
    135
    136    listener->nsioc++;
    137}
    138
    139
    140void qio_net_listener_set_client_func_full(QIONetListener *listener,
    141                                           QIONetListenerClientFunc func,
    142                                           gpointer data,
    143                                           GDestroyNotify notify,
    144                                           GMainContext *context)
    145{
    146    size_t i;
    147
    148    if (listener->io_notify) {
    149        listener->io_notify(listener->io_data);
    150    }
    151    listener->io_func = func;
    152    listener->io_data = data;
    153    listener->io_notify = notify;
    154
    155    for (i = 0; i < listener->nsioc; i++) {
    156        if (listener->io_source[i]) {
    157            g_source_destroy(listener->io_source[i]);
    158            g_source_unref(listener->io_source[i]);
    159            listener->io_source[i] = NULL;
    160        }
    161    }
    162
    163    if (listener->io_func != NULL) {
    164        for (i = 0; i < listener->nsioc; i++) {
    165            object_ref(OBJECT(listener));
    166            listener->io_source[i] = qio_channel_add_watch_source(
    167                QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
    168                qio_net_listener_channel_func,
    169                listener, (GDestroyNotify)object_unref, context);
    170        }
    171    }
    172}
    173
    174void qio_net_listener_set_client_func(QIONetListener *listener,
    175                                      QIONetListenerClientFunc func,
    176                                      gpointer data,
    177                                      GDestroyNotify notify)
    178{
    179    qio_net_listener_set_client_func_full(listener, func, data,
    180                                          notify, NULL);
    181}
    182
    183struct QIONetListenerClientWaitData {
    184    QIOChannelSocket *sioc;
    185    GMainLoop *loop;
    186};
    187
    188
    189static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc,
    190                                                  GIOCondition condition,
    191                                                  gpointer opaque)
    192{
    193    struct QIONetListenerClientWaitData *data = opaque;
    194    QIOChannelSocket *sioc;
    195
    196    sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
    197                                     NULL);
    198    if (!sioc) {
    199        return TRUE;
    200    }
    201
    202    if (data->sioc) {
    203        object_unref(OBJECT(sioc));
    204    } else {
    205        data->sioc = sioc;
    206        g_main_loop_quit(data->loop);
    207    }
    208
    209    return TRUE;
    210}
    211
    212QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)
    213{
    214    GMainContext *ctxt = g_main_context_new();
    215    GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
    216    GSource **sources;
    217    struct QIONetListenerClientWaitData data = {
    218        .sioc = NULL,
    219        .loop = loop
    220    };
    221    size_t i;
    222
    223    for (i = 0; i < listener->nsioc; i++) {
    224        if (listener->io_source[i]) {
    225            g_source_destroy(listener->io_source[i]);
    226            g_source_unref(listener->io_source[i]);
    227            listener->io_source[i] = NULL;
    228        }
    229    }
    230
    231    sources = g_new0(GSource *, listener->nsioc);
    232    for (i = 0; i < listener->nsioc; i++) {
    233        sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]),
    234                                              G_IO_IN);
    235
    236        g_source_set_callback(sources[i],
    237                              (GSourceFunc)qio_net_listener_wait_client_func,
    238                              &data,
    239                              NULL);
    240        g_source_attach(sources[i], ctxt);
    241    }
    242
    243    g_main_loop_run(loop);
    244
    245    for (i = 0; i < listener->nsioc; i++) {
    246        g_source_unref(sources[i]);
    247    }
    248    g_free(sources);
    249    g_main_loop_unref(loop);
    250    g_main_context_unref(ctxt);
    251
    252    if (listener->io_func != NULL) {
    253        for (i = 0; i < listener->nsioc; i++) {
    254            object_ref(OBJECT(listener));
    255            listener->io_source[i] = qio_channel_add_watch_source(
    256                QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
    257                qio_net_listener_channel_func,
    258                listener, (GDestroyNotify)object_unref, NULL);
    259        }
    260    }
    261
    262    return data.sioc;
    263}
    264
    265void qio_net_listener_disconnect(QIONetListener *listener)
    266{
    267    size_t i;
    268
    269    if (!listener->connected) {
    270        return;
    271    }
    272
    273    for (i = 0; i < listener->nsioc; i++) {
    274        if (listener->io_source[i]) {
    275            g_source_destroy(listener->io_source[i]);
    276            g_source_unref(listener->io_source[i]);
    277            listener->io_source[i] = NULL;
    278        }
    279        qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL);
    280    }
    281    listener->connected = false;
    282}
    283
    284
    285bool qio_net_listener_is_connected(QIONetListener *listener)
    286{
    287    return listener->connected;
    288}
    289
    290static void qio_net_listener_finalize(Object *obj)
    291{
    292    QIONetListener *listener = QIO_NET_LISTENER(obj);
    293    size_t i;
    294
    295    if (listener->io_notify) {
    296        listener->io_notify(listener->io_data);
    297    }
    298    qio_net_listener_disconnect(listener);
    299
    300    for (i = 0; i < listener->nsioc; i++) {
    301        object_unref(OBJECT(listener->sioc[i]));
    302    }
    303    g_free(listener->io_source);
    304    g_free(listener->sioc);
    305    g_free(listener->name);
    306}
    307
    308static const TypeInfo qio_net_listener_info = {
    309    .parent = TYPE_OBJECT,
    310    .name = TYPE_QIO_NET_LISTENER,
    311    .instance_size = sizeof(QIONetListener),
    312    .instance_finalize = qio_net_listener_finalize,
    313};
    314
    315
    316static void qio_net_listener_register_types(void)
    317{
    318    type_register_static(&qio_net_listener_info);
    319}
    320
    321
    322type_init(qio_net_listener_register_types);