Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  ktipc.c

  Sprache: C
 

/*
 * Copyright (c) 2020, Google Inc. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER 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.
 */

#include <lib/ktipc/ktipc.h>

#include <assert.h>
#include <err.h>
#include <inttypes.h>
#include <kernel/thread.h>
#include <lib/trusty/handle_set.h>
#include <lib/trusty/ipc.h>
#include <lib/trusty/ipc_msg.h>
#include <lk/init.h>
#include <lk/list.h>
#include <string.h>
#include <trace.h>

#define LOCAL_TRACE 0

struct ksrv_event_handler {
    void (*handler)(struct ktipc_server* ksrv,
                    struct ksrv_event_handler* evth,
                    uint32_t event);
};

struct ksrv_port {
    struct handle_ref href;
    struct ksrv_event_handler evth;
    const struct ktipc_srv_ops* ops;
    const struct ktipc_port* port;
};

struct ksrv_chan {
    struct handle_ref href;
    struct ksrv_event_handler evth;
    const struct ktipc_srv_ops* ops;
    const struct ktipc_port* port;
    void* user_ctx;
};

/*
 * Helper to close channel
 */

static void ktipc_chan_close(struct ksrv_chan* kchan) {
    void* user_ctx = kchan->user_ctx;
    const struct ktipc_srv_ops* ops = kchan->ops;

    /* detach handle_ref */
    handle_set_detach_ref(&kchan->href);

    /* close channel */
    handle_decref(kchan->href.handle);

    /* free memory */
    free(kchan);

    /*  cleanup user allocated state if any */
    if (user_ctx) {
        ops->on_channel_cleanup(user_ctx);
    }
}

static void chan_event_handler(struct ktipc_server* ksrv,
                               struct ksrv_event_handler* evth,
                               uint32_t event) {
    int rc;

    struct ksrv_chan* kchan = containerof(evth, struct ksrv_chan, evth);

    if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_READY)) {
        /* should never happen for channel handles */
        TRACEF("error event (0x%" PRIx32 ")\n", event);
        ktipc_chan_close(kchan);
        return;
    }

    if (event & IPC_HANDLE_POLL_MSG) {
        LTRACEF("got message\n");

        rc = kchan->ops->on_message(kchan->port, kchan->href.handle,
                                    kchan->user_ctx);
        if (rc < 0) {
            /* report an error and close channel */
            TRACEF("failed (%d) to handle event on channel %p\n", rc,
                   kchan->href.handle);
            ktipc_chan_close(kchan);
            return;
        }
    }

    if (event & IPC_HANDLE_POLL_HUP) {
        LTRACEF("connection closed by peer\n");

        /* closed by peer. */
        if (kchan->ops->on_disconnect) {
            kchan->ops->on_disconnect(kchan->port, kchan->href.handle,
                                      kchan->user_ctx);
        }
        ktipc_chan_close(kchan);
        return;
    }

    if (event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
        LTRACEF("unblocked for sending\n");

        if (kchan->ops->on_send_unblocked) {
            rc = kchan->ops->on_send_unblocked(kchan->port, kchan->href.handle,
                                               kchan->user_ctx);
            if (rc < 0) {
                /* report an error and close channel */
                TRACEF("failed (%d) to handle event on channel %p\n", rc,
                       kchan->href.handle);
                ktipc_chan_close(kchan);
                return;
            }
        } else {
            LTRACEF("send-unblocking not handled for channel %p\n",
                    kchan->href.handle);
            ktipc_chan_close(kchan);
            return;
        }
    }
}

/*
 *  Check if client is allowed to connect on specified port
 */

static bool client_is_allowed(const struct ktipc_port_acl* acl,
                              const struct uuid* peer) {
    uint32_t i;

    if (!acl->uuid_num)
        return true;

    for (i = 0; i < acl->uuid_num; i++) {
        if (memcmp(peer, acl->uuids[i], sizeof(*peer)) == 0) {
            /* match */
            return true;
        }
    }

    return false;
}

/*
 *  Handle incoming connection
 */

static void handle_connect(struct ktipc_server* ksrv, struct ksrv_port* kport) {
    int rc;
    struct handle* hchan;
    const struct uuid* peer;
    void* user_ctx = NULL;
    struct ksrv_chan* kchan;

    /* incoming connection: accept it */
    rc = ipc_port_accept(kport->href.handle, &hchan, &peer);
    if (rc < 0) {
        TRACEF("failed (%d) to accept on port %s\n", rc, kport->port->name);
        return;
    }

    /* do access control */
    if (!client_is_allowed(kport->port->acl, peer)) {
        TRACEF("access denied on port %s\n", kport->port->name);
        goto err_access;
    }

    kchan = calloc(1sizeof(*kchan));
    if (!kchan) {
        TRACEF("oom handling connect on port %s\n", kport->port->name);
        goto err_oom;
    }

    /* setup channel structure */
    kchan->evth.handler = chan_event_handler;
    kchan->port = kport->port;
    kchan->ops = kport->ops;

    /* add new channel to handle set */
    kchan->href.emask = ~0U;
    kchan->href.cookie = &kchan->evth;
    kchan->href.handle = hchan;

    rc = handle_set_attach(ksrv->hset, &kchan->href);
    if (rc != NO_ERROR) {
        TRACEF("failed (%d) to add chan to hset\n", rc);
        goto err_hset_add;
    }

    /* invoke on_connect handler if any */
    if (kport->ops->on_connect) {
        rc = kport->ops->on_connect(kport->port, hchan, peer, &user_ctx);
        if (rc < 0) {
            TRACEF("on_connect failed (%d) on port %s\n", rc,
                   kport->port->name);
            goto err_on_connect;
        }
    }

    /* attach context provided by caller */
    kchan->user_ctx = user_ctx;

    return;

err_on_connect:
    handle_set_detach_ref(&kchan->href);
err_hset_add:
    free(kchan);
err_oom:
err_access:
    handle_decref(hchan);
}

static void port_event_handler(struct ktipc_server* ksrv,
                               struct ksrv_event_handler* evth,
                               uint32_t event) {
    struct ksrv_port* kport = containerof(evth, struct ksrv_port, evth);

    if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_HUP) ||
        (event & IPC_HANDLE_POLL_MSG) ||
        (event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
        /* should never happen with port handles */
        LTRACEF("error event (0x%" PRIx32 ") for port\n", event);
        return;
    }

    if (event & IPC_HANDLE_POLL_READY) {
        handle_connect(ksrv, kport);
    }
}

int ktipc_server_add_port(struct ktipc_server* ksrv,
                          const struct ktipc_port* port,
                          const struct ktipc_srv_ops* ops) {
    int rc;
    struct ksrv_port* kport;

    if (!ksrv) {
        rc = ERR_INVALID_ARGS;
        goto err_null_ksrv;
    }

    /* validate ops structure */
    if (!ops) {
        TRACEF("ktipc_srv_ops structure is NULL\n");
        rc = ERR_INVALID_ARGS;
        goto err_null_ops;
    }
    if (!ops->on_message) {
        TRACEF("on_message handler is NULL\n");
        rc = ERR_INVALID_ARGS;
        goto err_null_on_message;
    }
    /* on_channel_cleanup is required if on_connect is present */
    if (ops->on_connect && !ops->on_channel_cleanup) {
        TRACEF("on_connect handler without on_channel_cleanup\n");
        rc = ERR_INVALID_ARGS;
        goto err_null_on_channel_cleanup;
    }

    /* allocate port tracking structure */
    kport = calloc(1sizeof(*kport));
    if (!kport) {
        TRACEF("failed to allocate port\n");
        rc = ERR_NO_MEMORY;
        goto err_oom;
    }

    /* create port */
    rc = ipc_port_create(port->uuid, port->name, port->msg_queue_len,
                         port->msg_max_size, port->acl->flags,
                         &kport->href.handle);
    if (rc) {
        TRACEF("failed (%d) to create port %s\n", rc, port->name);
        goto err_port_create;
    }

    /* and publish it */
    rc = ipc_port_publish(kport->href.handle);
    if (rc) {
        TRACEF("failed (%d) to publish port %s\n", rc, port->name);
        goto err_port_publish;
    }

    /* configure port event handler */
    kport->evth.handler = port_event_handler;
    kport->port = port;
    kport->ops = ops;

    /* attach it to handle set */
    kport->href.emask = ~0U;
    kport->href.cookie = &kport->evth;

    rc = handle_set_attach(ksrv->hset, &kport->href);
    if (rc < 0) {
        TRACEF("failed (%d) to attach handle for port %s\n", rc, port->name);
        goto err_hset_add_port;
    }

    /* kick have handles event */
    event_signal(&ksrv->have_handles_evt, false);

    return 0;

err_hset_add_port:
err_port_publish:
    handle_decref(kport->href.handle);
err_port_create:
    free(kport);
err_oom:
err_null_on_channel_cleanup:
err_null_on_message:
err_null_ops:
err_null_ksrv:
    return rc;
}

static void ksrv_event_loop(struct ktipc_server* ksrv) {
    int rc;
    struct handle_ref evt_ref;

    while (true) {
        /* wait here until we have handles */
        event_wait(&ksrv->have_handles_evt);
        while (true) {
            rc = handle_set_wait(ksrv->hset, &evt_ref, INFINITE_TIME);
            if (rc != NO_ERROR) {
                panic("handle_set_wait failed: %d\n", rc);
            }

            /* get handler and invoke it */
            struct ksrv_event_handler* evth = evt_ref.cookie;
            DEBUG_ASSERT(evth && evth->handler);
            evth->handler(ksrv, evth, evt_ref.emask);

            /* decrement ref obtained by handle_set_wait */
            handle_decref(evt_ref.handle);
        }
    }
}

static int ksrv_thread(void* args) {
    struct ktipc_server* ksrv = args;

    LTRACEF("starting ktipc service: %s\n", ksrv->name);

    ksrv->hset = handle_set_create();
    if (!ksrv->hset) {
        TRACEF("failed to create handle set\n");
        return ERR_NO_MEMORY;
    }

    /* enter event loop */
    ksrv_event_loop(ksrv);
    LTRACEF("event loop returned\n");

    /* kill handle set */
    handle_decref(ksrv->hset);
    return 0;
}

int ktipc_server_start(struct ktipc_server* ksrv) {
    DEBUG_ASSERT(ksrv);
    DEBUG_ASSERT(!ksrv->thread);

    ksrv->thread = thread_create(ksrv->name, ksrv_thread, ksrv,
                                 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
    if (!ksrv->thread) {
        TRACEF("failed to create %s thread\n", ksrv->name);
        return ERR_NO_MEMORY;
    }
    thread_resume(ksrv->thread);
    return 0;
}

int ktipc_recv_iov(struct handle* chan,
                   size_t min_sz,
                   struct iovec_kern* iov,
                   uint32_t num_iov,
                   struct handle** handles,
                   uint32_t num_handles) {
    int rc;
    struct ipc_msg_info msg_inf;
    size_t max_sz = 0;

    rc = ipc_get_msg(chan, &msg_inf);
    if (rc) {
        return rc;
    }

    for (uint32_t i = 0; i < num_iov; i++) {
        max_sz += iov[i].iov_len;
    }

    if (msg_inf.len < min_sz || msg_inf.len > max_sz) {
        /* unexpected msg size: buffer too small or too big */
        rc = ERR_BAD_LEN;
    } else {
        struct ipc_msg_kern msg = {
                .iov = iov,
                .num_iov = num_iov,
                .handles = handles,
                .num_handles = num_handles,
        };
        rc = ipc_read_msg(chan, msg_inf.id, 0, &msg);
    }

    ipc_put_msg(chan, msg_inf.id);
    return rc;
}

void ktipc_server_init(struct ktipc_server* ksrv, const char* name) {
    ksrv->name = name;
    ksrv->hset = NULL;
    ksrv->thread = NULL;
    event_init(&ksrv->have_handles_evt, false0);
}

Messung V0.5 in Prozent
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik