Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/access/rtp/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 11 kB image not shown  

Quelle  sdp.c   Sprache: C

 

/**
 * @file sdp.c
 * @brief Real-Time Protocol (RTP) demux module for VLC media player
 */

/*****************************************************************************
 * Copyright © 2020 Rémi Denis-Courmont
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 ****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "sdp.h"
#include <vlc_common.h>

static bool istokenchar(unsigned char c)
{   /* RFC4566 §9 */
    if (c < 0x21 || c > 0x7E)
        return false;
    if (memchr("\x22\x28\x29\x2C\x2F\x5B\x5C\x5D", c, 8) != NULL)
        return false;
    if (c > 0x39 && c < 0x41)
        return false;
    return true;
}

static size_t vlc_sdp_token_length(const char *str)
{
    const char *p = str;

    while (istokenchar(*p))
        p++;
    return p - str;
}

static bool vlc_sdp_is_token(const char *str)
{
    return str[vlc_sdp_token_length(str)] == '\0';
}

static void vlc_sdp_conn_free(struct vlc_sdp_conn **conn)
{
    struct vlc_sdp_conn *c = *conn;

    *conn = c->next;
    free(c);
}

static struct vlc_sdp_conn *vlc_sdp_conn_parse(const char *str, size_t len)
{
    const char *end = str + len;
    const char *net_type = str;
    const char *addr_type = memchr(str, ' ', len);

    if (addr_type == NULL) {
bad:
        errno = EINVAL;
        return NULL;
    }

    addr_type++; /* skip white space */
    const char *addr = memchr(addr_type, ' ', end - addr_type);

    if (addr == NULL)
        goto bad;

    addr++; /* skip white space */

    if (memchr(addr, ' ', end - addr) != NULL)
        goto bad;

    size_t addrlen = end - addr;
    struct vlc_sdp_conn *c = malloc(sizeof (*c) + addrlen + 1);
    if (unlikely(c == NULL))
        return NULL;

    c->next = NULL;
    c->family = 0;
    c->ttl = 255;
    c->addr_count = 1;
    memcpy(c->addr, addr, addrlen);
    c->addr[addrlen] = '\0';

    if (len >= 7 && memcmp(net_type, "IN ", 3) == 0) {
        int offset = 0, val = -1;

        if (memcmp(addr_type, "IP4 ", 4) == 0) {
            /* IPv4 */
            c->family = 4;
            val = sscanf(c->addr, "%*[^/]%n/%hhu/%hu", &offset, &c->ttl,
                         &c->addr_count);

        } else if (memcmp(addr_type, "IP6 ", 4) == 0) {
            /* IPv6 */
            c->family = 6;
            val = sscanf(c->addr, "%*[^/]%n/%hu", &offset, &c->addr_count);
        }

        if (val >= 0)
            c->addr[offset] = '\0';
    }

    return c;
}

static struct vlc_sdp_attr *vlc_sdp_attr_parse(const char *str, size_t len)
{
    size_t namelen = vlc_sdp_token_length(str);
    if (namelen < len && str[namelen] != ':') {
        errno = EINVAL;
        return NULL;
    }

    struct vlc_sdp_attr *a = malloc(sizeof (*a) + len + 1);
    if (unlikely(a == NULL))
        return NULL;

    memcpy(a->name, str, len);
    a->name[namelen] = '\0';
    if (namelen < len) {
        a->name[len] = '\0';
        a->value = a->name + namelen + 1;
    } else
        a->value = NULL;
    a->next = NULL;
    return a;
}

static void vlc_sdp_attr_free(struct vlc_sdp_attr **attr)
{
    struct vlc_sdp_attr *a = *attr;

    *attr = a->next;
    free(a);
}

static void vlc_sdp_media_free(struct vlc_sdp_media **media)
{
    struct vlc_sdp_media *m = *media;

    while (m->conns != NULL)
        vlc_sdp_conn_free(&m->conns);
    while (m->attrs != NULL)
        vlc_sdp_attr_free(&m->attrs);

    *media = m->next;
    free(m->format);
    free(m->proto);
    free(m->type);
    free(m);
}

static struct vlc_sdp_media *vlc_sdp_media_parse(struct vlc_sdp *sdp,
                                                 const char *str, size_t len)
{
    const char *end = str + len;
    const char *media = str;
    const char *media_end = memchr(str, ' ', end - str);

    if (media_end == NULL) {
bad:
        errno = EINVAL;
        return NULL;
    }

    const char *port = media_end + 1;
    const char *port_end = memchr(port, ' ', end - port);

    if (port_end == NULL)
        goto bad;

    const char *proto = port_end + 1;
    char *port_cur;
    unsigned long port_start = strtoul(port, &port_cur, 10);
    unsigned long port_count = 1;

    if (*port_cur == '/')
        port_count = strtoul(port_cur + 1, &port_cur, 10);
    if (port_cur != port_end)
        goto bad;

    const char *proto_end = memchr(proto, ' ', end - proto);

    if (proto_end == NULL)
        goto bad;

    const char *format = proto_end + 1;

    if (format >= end)
        goto bad;

    struct vlc_sdp_media *m = malloc(sizeof (*m));
    if (unlikely(m == NULL))
        return NULL;

    m->next = NULL;
    m->session = sdp;
    m->conns = NULL;
    m->attrs = NULL;
    m->type = strndup(media, media_end - media);
    m->port = port_start;
    m->port_count = port_count;
    m->proto = strndup(proto, proto_end - proto);
    m->format = strndup(format, end - format);

    if (unlikely(m->type == NULL || m->proto == NULL || m->format == NULL))
        vlc_sdp_media_free(&m);
    if (!vlc_sdp_is_token(m->type)) {
        vlc_sdp_media_free(&m);
        errno = EINVAL;
    }

    return m;
}

struct vlc_sdp_input
{
    const char *cursor;
    const char *end;
};

static int vlc_sdp_getline(struct vlc_sdp_input *restrict in,
                           const char **restrict pp, size_t *restrict lenp)
{
    assert(in->end >= in->cursor);
    *lenp = 0;

    if (in->end == in->cursor)
        return 0; /* end */

    const char *lf = memchr(in->cursor, '\n', in->end - in->cursor);

    if (lf == NULL)
        goto error; /* cannot locate end of line */

    const char *end = memchr(in->cursor, '\r', lf - in->cursor);
    if (end != NULL) {
        /* CR should be present. If so, it must be right before LF. */
        if (end != lf - 1)
            goto error; /* CR within a line is not permitted. */
    } else
        end = lf;

    if ((end - in->cursor) < 2 || in->cursor[1] != '=')
        goto error;

    int c = (unsigned char)in->cursor[0];

    *pp = in->cursor + 2;
    *lenp = end - *pp;
    in->cursor = lf + 1;

    return c;

error:
    errno = EINVAL;
    return -1;
}

const struct vlc_sdp_attr *vlc_sdp_attr_first_by_name(
    struct vlc_sdp_attr *const *ap, const char *name)
{
    for (const struct vlc_sdp_attr *a = *ap; a != NULL; a = a->next)
        if (!strcmp(a->name, name))
            return a;

    return NULL;
}

void vlc_sdp_free(struct vlc_sdp *sdp)
{
    while (sdp->media != NULL)
        vlc_sdp_media_free(&sdp->media);

    while (sdp->attrs != NULL)
        vlc_sdp_attr_free(&sdp->attrs);

    if (sdp->conn != NULL)
        vlc_sdp_conn_free(&sdp->conn);

    free(sdp->info);
    free(sdp->name);
    free(sdp);
}

struct vlc_sdp *vlc_sdp_parse(const char *str, size_t length)
{
    if (memchr(str, 0, length) != NULL) {
        /* Nul byte inside the SDP is not permitted. */
        errno = EINVAL;
        return NULL;
    }

    struct vlc_sdp_input in = { str, str + length };
    const char *line;
    size_t linelen;
    int c;

    /* Version line, must be "0" */
    if (vlc_sdp_getline(&in, &line, &linelen) != 'v'
     || linelen != 1 || memcmp(line, "0", 1)) {
        errno = EINVAL;
        return NULL;
    }

    /* Origin line (ignored for now) */
    if (vlc_sdp_getline(&in, &line, &linelen) != 'o') {
        errno = EINVAL;
        return NULL;
    }

    struct vlc_sdp *sdp = malloc(sizeof (*sdp));
    if (unlikely(sdp == NULL))
        return NULL;

    sdp->name = NULL;
    sdp->info = NULL;
    sdp->conn = NULL;
    sdp->attrs = NULL;
    sdp->media = NULL;

    /* Session name line */
    if (vlc_sdp_getline(&in, &line, &linelen) != 's')
        goto bad;

    sdp->name = strndup(line, linelen);
    if (unlikely(sdp->name == NULL))
        goto error;

    c = vlc_sdp_getline(&in, &line, &linelen);

    /* Session information line (optional) */
    if (c == 'i') {
        sdp->info = strndup(line, linelen);
        if (unlikely(sdp->info == NULL))
            goto error;

        c = vlc_sdp_getline(&in, &line, &linelen);
    }

    /* URL line (optional) */
    if (c == 'u')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Email lines */
    while (c == 'e')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Phone number lines */
    while (c == 'p')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Session connection line (optional) */
    if (c == 'c') {
        sdp->conn = vlc_sdp_conn_parse(line, linelen);
        if (sdp->conn == NULL)
            goto error;

        c = vlc_sdp_getline(&in, &line, &linelen);
    }

    /* Session bandwidth lines */
    while (c == 'b')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Time descriptions / Session time lines */
    while (c == 't') {
        c = vlc_sdp_getline(&in, &line, &linelen);

        /* Repeat lines */
        while (c == 'r')
            c = vlc_sdp_getline(&in, &line, &linelen);
    }

    /* Time adjustment lines */
    while (c == 'z')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Session encryption key line (unused in real life) */
    if (c == 'k')
        c = vlc_sdp_getline(&in, &line, &linelen);

    /* Session attribute lines */
    for (struct vlc_sdp_attr **ap = &sdp->attrs; c == 'a';) {
        struct vlc_sdp_attr *a = vlc_sdp_attr_parse(line, linelen);
        if (a == NULL)
            goto error;

        *ap = a;
        ap = &a->next;
        c = vlc_sdp_getline(&in, &line, &linelen);
    }

    /* Media descriptions / Media lines */
    for (struct vlc_sdp_media **mp = &sdp->media; c == 'm';) {
        struct vlc_sdp_media *m = vlc_sdp_media_parse(sdp, line, linelen);
        if (m == NULL)
            goto error;

        *mp = m;
        mp = &m->next;
        c = vlc_sdp_getline(&in, &line, &linelen);

        /* Media title line */
        if (c == 'i')
            c = vlc_sdp_getline(&in, &line, &linelen);

        /* Media connection lines */
        for (struct vlc_sdp_conn **cp = &m->conns; c == 'c';) {
             struct vlc_sdp_conn *conn = vlc_sdp_conn_parse(line, linelen);
             if (conn == NULL)
                 goto error;

             *cp = conn;
             cp = &conn->next;
             c = vlc_sdp_getline(&in, &line, &linelen);
        }

        /* Media bandwidth lines */
        while (c == 'b')
            c = vlc_sdp_getline(&in, &line, &linelen);

        /* Media encryption key line (unused in real life) */
        if (c == 'k')
            c = vlc_sdp_getline(&in, &line, &linelen);

        /* Session attribute lines */
        for (struct vlc_sdp_attr **ap = &m->attrs; c == 'a';) {
            struct vlc_sdp_attr *a = vlc_sdp_attr_parse(line, linelen);
            if (a == NULL)
                goto error;

            *ap = a;
            ap = &a->next;
            c = vlc_sdp_getline(&in, &line, &linelen);
        }
    }

    if (c == 0)
        return sdp;

bad:
    errno = EINVAL;
error:
    vlc_sdp_free(sdp);
    return NULL;
}

Messung
CHZG
85959892

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


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.