Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  libipm_recv.c

  Sprache: C
 

/**
 * Copyright (C) 2022 Matt Burt, all xrdp contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/**
 * @file    libipm/libipm.c
 * @brief   Inter-Process Messaging building and parsing definitions
 */


#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif

#include <stdio.h>
#include <stdarg.h>

#include "libipm.h"
#include "libipm_private.h"
#include "libipm_facilities.h"
#include "trans.h"
#include "log.h"
#include "os_calls.h"
#include "string_calls.h"

/**************************************************************************//**
 * Checks the message header in the input stream, and gets the size
 */
static enum libipm_status
validate_msg_header(struct trans *trans, int *size)
{
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
    enum libipm_status rv = E_LI_BAD_HEADER;

    int version;
    int facility;
    int reserved;

    in_uint16_le(trans->in_s, version);
    in_uint16_le(trans->in_s, *size);
    in_uint16_le(trans->in_s, facility);
    in_uint16_le(trans->in_s, priv->in_msgno);
    in_uint32_le(trans->in_s, reserved);

    if (version != LIBIPM_VERSION)
    {
        LOG(LOG_LEVEL_ERROR,
            "Unexpected version number %d from IPM", version);
    }
    else if (*size < HEADER_SIZE || *size > LIBIPM_MAX_MSG_SIZE)
    {
        LOG(LOG_LEVEL_ERROR,
            "Invalid message length %d from IPM", *size);
    }
    else if (facility != priv->facility)
    {
        LOG(LOG_LEVEL_ERROR,
            "Invalid facility %d from IPM - expected %d",
            facility, priv->facility);
    }
    else if (reserved != 0)
    {
        LOG(LOG_LEVEL_ERROR,
            "Invalid reserved field %d from IPM", reserved);
    }
    else
    {
        rv = E_LI_SUCCESS;
    }

    return rv;
}

/*****************************************************************************/

enum libipm_status
libipm_msg_in_check_available(struct trans *trans, int *available)
{
    enum libipm_status rv = E_LI_SUCCESS;

    *available = 0;

    if (trans == NULL || trans->extra_data == NULL)
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "Failed devel check");
        rv = E_LI_PROGRAM_ERROR;
    }
    else if (trans->status != TRANS_STATUS_UP)
    {
        rv = E_LI_PROGRAM_ERROR; /* Caller should have checked this */
    }
    else
    {
        unsigned int len = trans->in_s->end - trans->in_s->data; /* Data read so far */

        if (len == trans->header_size)
        {
            if (trans->extra_flags == 0)
            {
                /* We've read the header so far - validate it */
                int size;
                rv = validate_msg_header(trans, &size);
                if (rv == 0)
                {
                    /* Header is OK */
                    trans->extra_flags = 1;
                    trans->header_size = size;

                    *available = (size == HEADER_SIZE);
                }
            }
            else
            {
                *available = 1;
            }
        }
    }

    return rv;
}

/*****************************************************************************/

enum libipm_status
libipm_msg_in_wait_available(struct trans *trans)
{
    tbus wobj[2]; // trans_get_wait_objs() can return at most 2 elements
    int ocnt = 0;
    enum libipm_status rv = E_LI_SUCCESS;

    if (trans == NULL || trans->extra_data == NULL ||
            trans->status != TRANS_STATUS_UP)
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "Failed devel check");
        rv = E_LI_PROGRAM_ERROR;
    }
    else if (trans_get_wait_objs(trans, wobj, &ocnt) != 0)
    {
        LOG(LOG_LEVEL_ERROR, "Can't get wait object for libipm transport");
        rv = E_LI_TRANSPORT_ERROR;
    }
    else
    {
        int gotmsg = 0;
        /* Prevent trans_check_wait_objs() actioning any callcacks
         * when the message is complete */

        ttrans_data_in saved_trans_data_in = trans->trans_data_in;
        trans->trans_data_in = NULL;

        while (rv == E_LI_SUCCESS && !gotmsg)
        {
            if (g_obj_wait(wobj, ocnt, NULL, 0, -1) != 0)
            {
                LOG(LOG_LEVEL_ERROR, "Error waiting on libipm transport");
                rv = E_LI_TRANSPORT_ERROR;
            }
            else if (trans_check_wait_objs(trans) != 0)
            {
                LOG(LOG_LEVEL_ERROR, "Error reading libipm transport");
                rv = E_LI_TRANSPORT_ERROR;
            }
            else
            {
                /* This call logs errors already */
                rv = libipm_msg_in_check_available(trans, &gotmsg);
            }
        }

        /* Restore transport callback operation */
        trans->trans_data_in = saved_trans_data_in;
    }

    return rv;
}

/*****************************************************************************/

unsigned short
libipm_msg_in_get_msgno(const struct trans *trans)
{
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;

    return (priv == NULL) ? 0 : priv->in_msgno;
}

/*****************************************************************************/

char
libipm_msg_in_peek_type(struct trans *trans)
{
    int result;

    if (s_check_rem(trans->in_s, 1))
    {
        char c;
        in_uint8_peek(trans->in_s, c);
        if (g_strchr(libipm_valid_type_chars, c) != NULL)
        {
            result = c; /* Only return valid characters */
        }
        else
        {
            result = '?';
        }
    }
    else
    {
        result = '\0';
    }

    return result;
}

/**************************************************************************//**
 * Log an input parsing error
 *
 * @param trans libipm transport
 * @param format printf-like format descriptor
 */
printflike(23static void
log_parse_error(struct trans *trans, const char *format, ...)
{
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
    const char *msgno_str = NULL;
    char msgno_str_buff[32];

    char buff[256];
    unsigned int len;

    /* Find a string for the message number */
    if (priv->msgno_to_str != NULL)
    {
        msgno_str = priv->msgno_to_str(priv->in_msgno);
    }
    if (msgno_str == NULL)
    {
        g_snprintf(msgno_str_buff, sizeof(msgno_str_buff),
                   "[code #%d]", priv->in_msgno);
        msgno_str = msgno_str_buff;
    }

    len = g_snprintf(buff, sizeof(buff),
                     "Error parsing ipm message for %s, parameter %d :",
                     msgno_str, priv->in_param_count);
    if (len < sizeof(buff))
    {
        va_list ap;

        va_start(ap, format);
        vsnprintf(&buff[len], sizeof(buff) - len, format, ap);
        va_end(ap);
    }
    LOG(LOG_LEVEL_ERROR, "%s", buff);
}

/* Common format string for overflow reporting */
static const char *
not_enough_input_msg = "Input buffer overflow for '%c'";

/**************************************************************************//**
 * Extract a bool from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr Pointer to pointer to receive the value
 * @return != 0 for error
 *
 * The value must be a 0 or 1 on-the-wire, or an error is returned.
 */
static enum libipm_status
extract_bool_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;
    int b;

    if (!s_check_rem(s, 1))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        in_uint8(s, b);
        if (b < 0 || b > 1)
        {
            log_parse_error(trans, "Boolean has value other than 0/1");
            rv = E_LI_BAD_VALUE;
        }
        else
        {
            int *tmp = va_arg(*argptr, int *);
            *tmp = b;
        }
    }
    return rv;
}

/**************************************************************************//**
 * Extract an octet from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_int8_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;

    if (!s_check_rem(s, 1))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        unsigned char *tmp = va_arg(*argptr, unsigned char *);
        in_uint8(s, *tmp);
    }
    return rv;
}


/**************************************************************************//**
 * Extract a 16-bit integer from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_int16_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;

    if (!s_check_rem(s, 2))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        uint16_t *tmp = va_arg(*argptr, uint16_t *);
        /*
         * C99 7.18.1.1 requires int16_t (if present) to be a two's
         * complement representation, so this line is valid for both
         * int16_t and uint16_t */

        in_uint16_le(s, *tmp);
    }
    return rv;
}

/**************************************************************************//**
 * Extract a 32-bit integer from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_int32_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;

    if (!s_check_rem(s, 4))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        uint32_t *tmp = va_arg(*argptr, uint32_t *);
        /*
         * C99 7.18.1.1 requires int32_t (if present) to be a two's
         * complement representation, so this line is valid for both
         * int32_t and uint32_t */

        in_uint32_le(s, *tmp);
    }
    return rv;
}

/**************************************************************************//**
 * Extract a 64-bit integer from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_int64_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;

    if (!s_check_rem(s, 8))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        uint64_t *tmp = va_arg(*argptr, uint64_t *);
        /*
         * C99 7.18.1.1 requires int64_t (if present) to be a two's
         * complement representation, so this line is valid for both
         * int64_t and uint64_t */

        in_uint64_le(s, *tmp);
    }
    return rv;
}

/**************************************************************************//**
 * Extract a char * pointer from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_char_ptr_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;

    /* Look for a string terminator in the rest of the input stream */
    char *termptr = g_strnchr(s->p,  '\0', s->end - s->p);

    if (termptr == NULL)
    {
        log_parse_error(trans, "Unterminated string value");
        rv = E_LI_BAD_VALUE;
    }
    else
    {
        char **tmp = va_arg(*argptr, char **);

        *tmp = s->p;
        s->p = termptr + 1;
    }
    return rv;
}


/**************************************************************************//**
 * Extract a file descriptor from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to receive the value
 * @return != 0 for error
 */
static enum libipm_status
extract_fd_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;

    /* File descriptor available? */
    if (priv->in_fd_index >= priv->in_fd_count)
    {
        log_parse_error(trans, "No file descriptors available");
        rv = E_LI_TOO_MANY_FDS;
    }
    else
    {
        int *tmp = va_arg(*argptr, int *);

        *tmp = priv->in_fds[priv->in_fd_index++];
    }
    return rv;
}

/**************************************************************************//**
 * Extract a fixed size block from the input stream
 *
 * @param c Type letter which triggered the call
 * @param trans libipm transport
 * @param argptr argptr to pointer to block descriptor
 * @return != 0 for error
 */
static enum libipm_status
extract_fsb_type(char c, struct trans *trans, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;
    const struct libipm_fsb *fsb = va_arg(*argptr, const struct libipm_fsb *);

    if (fsb == NULL || fsb->data == NULL)
    {
        log_parse_error(trans, "Malformed descriptor for '%c'", c);
        rv = E_LI_PROGRAM_ERROR;
    }
    else if (!s_check_rem(s, 2))
    {
        log_parse_error(trans, not_enough_input_msg, c);
        rv = E_LI_BUFFER_OVERFLOW;
    }
    else
    {
        unsigned int len;
        in_uint16_le(s, len);

        if (len != fsb->datalen)
        {
            log_parse_error(trans, "Type '%c'. Expected %u bytes, but got %u",
                            c, fsb->datalen, len);
            rv = E_LI_BAD_VALUE;
        }
        else if (!s_check_rem(s, len))
        {
            log_parse_error(trans, not_enough_input_msg, c);
            rv = E_LI_BUFFER_OVERFLOW;
        }
        else
        {
            in_uint8a(s, fsb->data, len);
            rv = E_LI_SUCCESS;
        }
    }
    return rv;
}

/**************************************************************************//**
 * Local function to pull data from the input stream
 *
 * @param trans libipm transport
 * @param format type-system compatible string
 * @param argptr Pointers to variables to receive extracted data
 * @pre - trans->priv has been checked to be non-NULL
 * @return != 0 for error
 */
static enum libipm_status
libipm_msg_in_parsev(struct trans *trans, const char *format, va_list *argptr)
{
    enum libipm_status rv = E_LI_SUCCESS;
    struct stream *s = trans->in_s;
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
    const char *cp;

    if (format != NULL)
    {
        for (cp = format; rv == 0 && *cp != '\0' ; ++cp)
        {
            char c = *cp;
            char actual_c;
            ++priv->in_param_count; /* Count the parameter */

            /* Check the type of the input is supported */
            if (g_strchr(libipm_valid_type_chars, c) == NULL)
            {
                log_parse_error(trans,
                                "Type code '%c' is not supported", c);
                rv = E_LI_UNSUPPORTED_TYPE;
                break;
            }

            /* Check the type of the input matches the stream */
            if (!s_check_rem(s, 1))
            {
                log_parse_error(trans, not_enough_input_msg, c);
                rv = E_LI_BUFFER_OVERFLOW;
                break;
            }
            in_uint8(s, actual_c);
            if (c != actual_c)
            {
                log_parse_error(trans, "Expected '%c', got '%c'", c, actual_c);
                rv = E_LI_UNEXPECTED_TYPE;
                break;
            }

            switch (c)
            {
                case 'y':
                    rv = extract_int8_type(c, trans, argptr);
                    break;

                case 'b':
                    rv = extract_bool_type(c, trans, argptr);
                    break;

                case 'n':
                case 'q':
                    rv = extract_int16_type(c, trans, argptr);
                    break;

                case 'i':
                case 'u':
                    rv = extract_int32_type(c, trans, argptr);
                    break;

                case 'x':
                case 't':
                    rv = extract_int64_type(c, trans, argptr);
                    break;

                case 's':
                    rv = extract_char_ptr_type(c, trans, argptr);
                    break;

                case 'h':
                    rv = extract_fd_type(c, trans, argptr);
                    break;

                case 'B':
                    rv = extract_fsb_type(c, trans, argptr);
                    break;

                default:
                    log_parse_error(trans,
                                    "Reserved type code '%c' "
                                    "is unimplemented", c);
                    rv = E_LI_UNIMPLEMENTED_TYPE;
                    break;
            }
        }
    }

    return rv;
}

/*****************************************************************************/

enum libipm_status
libipm_msg_in_parse(struct trans *trans, const char *format, ...)
{
    enum libipm_status rv;
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
    if (priv == NULL)
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "uninitialised transport");
        rv = E_LI_PROGRAM_ERROR;
    }
    else
    {
        va_list argptr;

        va_start(argptr, format);
        rv = libipm_msg_in_parsev(trans, format, &argptr);
        va_end(argptr);
    }

    return rv;
}

/*****************************************************************************/

void
libipm_msg_in_reset(struct trans *trans)
{
    struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;

    if (priv == NULL)
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "uninitialised transport");
    }
    else
    {
        if ((priv->flags & LIBIPM_E_MSG_IN_ERASE_AFTER_USE) != 0)
        {
            struct stream *s = trans->in_s;
            g_memset(s->data, '\0', s->end - s->data);
            priv->flags &= ~LIBIPM_E_MSG_IN_ERASE_AFTER_USE;
        }
        priv->in_msgno = 0;
        priv->in_param_count = 0;
        libipm_msg_in_close_file_descriptors(trans);
    }

    trans->extra_flags = 0;
    trans->header_size = HEADER_SIZE;
    trans->no_stream_init_on_data_in = 1;
    init_stream(trans->in_s, LIBIPM_MAX_MSG_SIZE);
}

Messung V0.5 in Prozent
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© 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