<commit_before>/*
 * Copyright (c) 2015 <NAME>, Inc., http://www.sippysoft.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#if defined(HAVE_CONFIG_H)
#include "config_pp.h"
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "rtpp_types.h"
#include "rtpp_network.h"
#include "rtpp_tnotify_set.h"
#include "rtpp_tnotify_tgt.h"

#define RTPP_TNOTIFY_TARGETS_MAX 64
#define RTPP_TNOTIFY_WILDCARDS_MAX 2

#define CC_SELF_STR	"%%CC_SELF%%"

struct rtpp_tnotify_wildcard {
    char *socket_name;
    int socket_type;
    int port;
};

union rtpp_tnotify_entry {
    struct rtpp_tnotify_target rtt;
    struct rtpp_tnotify_wildcard rtw;
};

struct rtpp_tnotify_set {
    struct rtpp_tnotify_set_obj pub;
    struct rtpp_tnotify_target *tp[RTPP_TNOTIFY_TARGETS_MAX];
    int tp_len;
    struct rtpp_tnotify_wildcard *wp[RTPP_TNOTIFY_WILDCARDS_MAX];
    int wp_len;
};

#define PUB2PVT(pubp)      ((struct rtpp_tnotify_set *)((char *)(pubp) - offsetof(struct rtpp_tnotify_set, pub)))

static void rtpp_tnotify_set_dtor(struct rtpp_tnotify_set_obj *);
static int rtpp_tnotify_set_append(struct rtpp_tnotify_set_obj *, const char *, const char **);
static struct rtpp_tnotify_target *rtpp_tnotify_set_lookup(struct rtpp_tnotify_set_obj *,
  const char *, struct sockaddr *);
static int rtpp_tnotify_set_isenabled(struct rtpp_tnotify_set_obj *);

struct rtpp_tnotify_set_obj *
rtpp_tnotify_set_ctor(void)
{
    struct rtpp_tnotify_set *pvt;

    pvt = malloc(sizeof(struct rtpp_tnotify_set));
    if (pvt == NULL) {
        return (NULL);
    }
    memset(pvt, '\0', sizeof(struct rtpp_tnotify_set));
    pvt->pub.dtor = &rtpp_tnotify_set_dtor;
    pvt->pub.append = &rtpp_tnotify_set_append;
    pvt->pub.lookup = &rtpp_tnotify_set_lookup;
    pvt->pub.isenabled = &rtpp_tnotify_set_isenabled;

    return (&pvt->pub);
}

static void
rtpp_tnotify_set_dtor(struct rtpp_tnotify_set_obj *pub)
{
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_target *tp;
    int i;

    pvt = PUB2PVT(pub);
    for (i = 0; i < pvt->tp_len; i++) {
        tp = pvt->tp[i];
        if (tp->socket_name != NULL)
            free(tp->socket_name);
        if (tp->connected) {
            assert(tp->fd >= 0);
            close(tp->fd);
        }
        free(tp);
    }
    for (i = 0; i < pvt->wp_len; i++) {
        free(pvt->wp[i]->socket_name);
        free(pvt->wp[i]);
    }
    free(pvt);
}

static int
parse_hostport(const char *hostport, char *host, int hsize, char *port, int psize,
  int testonly, const char **e)
{
    const char *cp;
    int myport;

    cp = strrchr(hostport, ':');
    if (cp == NULL || cp[1] == '\0' || cp == hostport) {
        *e = "Can't parse host:port: invalid address";
        return (-1);
    }
    myport = atoi(cp + 1);
    if (myport <= 0 || myport > 65535) {
        *e = "Can't parse host:port: invalid port";
        return (-1);
    }

    if (testonly != 0)
        return (0);

    if (cp - hostport + 1 > hsize || psize < 6) {
        *e = "Can't parse host:port: supplied buffers are too small";
        return (-1);
    }

    memcpy(host, hostport, cp - hostport);
    host[cp - hostport] = '\0';
    snprintf(port, psize, "%d", myport);
    return (0);
}

/* Returns 0 for a specific target, 1 for wildcard, -1 for an error */
static int
parse_timeout_sock(const char *sock_name, union rtpp_tnotify_entry *rtep,
  const char **e)
{
    char host[512], port[10];
    char *new_sn, **snp;
    int n, rval;
    const char *sprefix, *usock_name;

    snp = &rtep->rtt.socket_name;
    rval = 0;
    sprefix = NULL;
    if (strncmp("unix:", sock_name, 5) == 0) {
        usock_name = sock_name + 5;
        rtep->rtt.socket_type = PF_LOCAL;
    } else if (strncmp("tcp:", sock_name, 4) == 0) {
        if (parse_hostport(sock_name + 4, host, sizeof(host), port, sizeof(port), 0, e) != 0) {
            return (-1);
        }
        rtep->rtt.socket_type = PF_INET;
    } else {
        sprefix = "unix:";
        usock_name = sock_name;
        rtep->rtt.socket_type = PF_LOCAL;
    }
    if (rtep->rtt.socket_type == PF_UNIX) {
        if (strlen(usock_name) == 0) {
            *e = "Timeout notification socket name too short";
            return (-1);
        }
        rtep->rtt.remote.u.sun_family = AF_LOCAL;
        strncpy(rtep->rtt.remote.u.sun_path, usock_name, sizeof(rtep->rtt.remote.u.sun_path) - 1);
#if defined(HAVE_SOCKADDR_SUN_LEN)
        rtep->rtt.remote.u.sun_len = strlen(rtep->rtt.remote.u.sun_path);
#endif
        rtep->rtt.remote_len = sizeof(rtep->rtt.remote.u);
    } else if (rtep->rtt.socket_type == PF_INET && strcmp(host, CC_SELF_STR) == 0) {
        rtep->rtw.socket_type = PF_INET;
        rtep->rtw.port = atoi(port);
        snp = &rtep->rtt.socket_name;
        rval = 1;
    } else {
        n = resolve(sstosa(&(rtep->rtt.remote.i)), AF_INET, host, port, AI_PASSIVE);
        if (n != 0) {
            *e = gai_strerror(n);
            return (-1);
        }
        rtep->rtt.remote_len = SA_LEN(sstosa(&(rtep->rtt.remote.i)));
    }
    if (sprefix == NULL) {
        new_sn = strdup(sock_name);
    } else {
        asprintf(&new_sn, "%s%s", sprefix, usock_name);
    }
    if (new_sn == NULL) {
        *e = strerror(errno);
        return (-1);
    }
    *snp = new_sn;

    return (rval);
}

static int
rtpp_tnotify_set_append(struct rtpp_tnotify_set_obj *pub,
  const char *socket_name, const char **e)
{
    int rval;
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_target *tntp;
    struct rtpp_tnotify_wildcard *tnwp;
    union rtpp_tnotify_entry rte;

    pvt = PUB2PVT(pub);
    memset(&rte, '\0', sizeof(union rtpp_tnotify_entry));
    rval = parse_timeout_sock(socket_name, &rte, e);
    if (rval < 0) {
        goto e0;
    }
    tntp = NULL;
    tnwp = NULL;
    if (rval == 0) {
        if (pvt->tp_len == RTPP_TNOTIFY_TARGETS_MAX) {
            *e = "Number of notify targets exceeds RTPP_TNOTIFY_TARGETS_MAX";
            goto e0;
        }
        tntp = malloc(sizeof(struct rtpp_tnotify_target));
        if (tntp == NULL) {
             *e = strerror(errno);
             goto e1;
        }
        memcpy(tntp, &rte.rtt, sizeof(struct rtpp_tnotify_target));
        tntp->connected = 0;
        tntp->fd = -1;
        pvt->tp[pvt->tp_len] = tntp;
        pvt->tp_len += 1;
    } else {
        if (pvt->wp_len == RTPP_TNOTIFY_WILDCARDS_MAX) {
            *e = "Number of notify wildcards exceeds RTPP_TNOTIFY_WILDCARDS_MAX";
            goto e0;
        }
        tnwp = malloc(sizeof(struct rtpp_tnotify_wildcard));
        if (tnwp == NULL) {
             *e = strerror(errno);
             goto e1;
        }
        memcpy(tnwp, &rte.rtw, sizeof(struct rtpp_tnotify_wildcard));
        pvt->wp[pvt->wp_len] = tnwp;
        pvt->wp_len += 1;
    }

    return (0);

e1:
    if (tntp != NULL)
        free(tntp);
    if (tnwp != NULL)
        free(tnwp);
e0:
    return (-1);
}

static struct rtpp_tnotify_target *
get_tp4wp(struct rtpp_tnotify_set *pvt, struct rtpp_tnotify_wildcard *wp,
  struct sockaddr *ccaddr)
{
    int i;
    struct rtpp_tnotify_target *tp;
    struct sockaddr_in localhost;

    if (ccaddr == NULL) {
        /* Request on the unix domain socket, assume it's 127.0.0.1 */
        memset(&localhost, '\0', sizeof(struct sockaddr_in));
        inet_aton("127.0.0.1", &localhost.sin_addr);
        ccaddr = sstosa(&localhost);
        ccaddr->sa_family = AF_INET;
    }
    for (i = 0; i < pvt->tp_len; i++) {
        /* First check against existing targets */
        tp = pvt->tp[i];
        if (tp->socket_type != wp->socket_type)
            continue;
        if (!ishostseq(ccaddr, sstosa(&tp->remote.i)))
            continue;
        if (getport(sstosa(&tp->remote.i)) != wp->port)
            continue;
        return (tp);
    }
    /* Nothing found, crank up a new entry */
    tp = malloc(sizeof(struct rtpp_tnotify_target));
    if (tp == NULL) {
        return (NULL);
    }
    memset(tp, '\0', sizeof(struct rtpp_tnotify_target));
    tp->remote_len = SA_LEN(ccaddr);
    memcpy(&tp->remote.i, ccaddr, tp->remote_len);
    setport(sstosa(&tp->remote.i), wp->port);
    tp->socket_type = wp->socket_type;
    tp->connected = 0;
    tp->fd = -1;
    pvt->tp[pvt->tp_len] = tp;
    pvt->tp_len += 1;
    return (tp);
}

static struct rtpp_tnotify_target *
rtpp_tnotify_set_lookup(struct rtpp_tnotify_set_obj *pub, const char *socket_name,
  struct sockaddr *ccaddr)
{
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_wildcard *wp;
    int i;
    char *sep;

    pvt = PUB2PVT(pub);
    for (i = 0; i < pvt->tp_len; i++) {
        if (pvt->tp[i]->socket_name == NULL)<commit_msg>Don't overflow RTPP_TNOTIFY_TARGETS_MAX.<commit_after>/*
 * Copyright (c) 2015 Sippy Software, Inc., http://www.sippysoft.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#if defined(HAVE_CONFIG_H)
#include "config_pp.h"
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "rtpp_types.h"
#include "rtpp_network.h"
#include "rtpp_tnotify_set.h"
#include "rtpp_tnotify_tgt.h"

#define RTPP_TNOTIFY_TARGETS_MAX 64
#define RTPP_TNOTIFY_WILDCARDS_MAX 2

#define CC_SELF_STR	"%%CC_SELF%%"

struct rtpp_tnotify_wildcard {
    char *socket_name;
    int socket_type;
    int port;
};

union rtpp_tnotify_entry {
    struct rtpp_tnotify_target rtt;
    struct rtpp_tnotify_wildcard rtw;
};

struct rtpp_tnotify_set {
    struct rtpp_tnotify_set_obj pub;
    struct rtpp_tnotify_target *tp[RTPP_TNOTIFY_TARGETS_MAX];
    int tp_len;
    struct rtpp_tnotify_wildcard *wp[RTPP_TNOTIFY_WILDCARDS_MAX];
    int wp_len;
};

#define PUB2PVT(pubp)      ((struct rtpp_tnotify_set *)((char *)(pubp) - offsetof(struct rtpp_tnotify_set, pub)))

static void rtpp_tnotify_set_dtor(struct rtpp_tnotify_set_obj *);
static int rtpp_tnotify_set_append(struct rtpp_tnotify_set_obj *, const char *, const char **);
static struct rtpp_tnotify_target *rtpp_tnotify_set_lookup(struct rtpp_tnotify_set_obj *,
  const char *, struct sockaddr *);
static int rtpp_tnotify_set_isenabled(struct rtpp_tnotify_set_obj *);

struct rtpp_tnotify_set_obj *
rtpp_tnotify_set_ctor(void)
{
    struct rtpp_tnotify_set *pvt;

    pvt = malloc(sizeof(struct rtpp_tnotify_set));
    if (pvt == NULL) {
        return (NULL);
    }
    memset(pvt, '\0', sizeof(struct rtpp_tnotify_set));
    pvt->pub.dtor = &rtpp_tnotify_set_dtor;
    pvt->pub.append = &rtpp_tnotify_set_append;
    pvt->pub.lookup = &rtpp_tnotify_set_lookup;
    pvt->pub.isenabled = &rtpp_tnotify_set_isenabled;

    return (&pvt->pub);
}

static void
rtpp_tnotify_set_dtor(struct rtpp_tnotify_set_obj *pub)
{
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_target *tp;
    int i;

    pvt = PUB2PVT(pub);
    for (i = 0; i < pvt->tp_len; i++) {
        tp = pvt->tp[i];
        if (tp->socket_name != NULL)
            free(tp->socket_name);
        if (tp->connected) {
            assert(tp->fd >= 0);
            close(tp->fd);
        }
        free(tp);
    }
    for (i = 0; i < pvt->wp_len; i++) {
        free(pvt->wp[i]->socket_name);
        free(pvt->wp[i]);
    }
    free(pvt);
}

static int
parse_hostport(const char *hostport, char *host, int hsize, char *port, int psize,
  int testonly, const char **e)
{
    const char *cp;
    int myport;

    cp = strrchr(hostport, ':');
    if (cp == NULL || cp[1] == '\0' || cp == hostport) {
        *e = "Can't parse host:port: invalid address";
        return (-1);
    }
    myport = atoi(cp + 1);
    if (myport <= 0 || myport > 65535) {
        *e = "Can't parse host:port: invalid port";
        return (-1);
    }

    if (testonly != 0)
        return (0);

    if (cp - hostport + 1 > hsize || psize < 6) {
        *e = "Can't parse host:port: supplied buffers are too small";
        return (-1);
    }

    memcpy(host, hostport, cp - hostport);
    host[cp - hostport] = '\0';
    snprintf(port, psize, "%d", myport);
    return (0);
}

/* Returns 0 for a specific target, 1 for wildcard, -1 for an error */
static int
parse_timeout_sock(const char *sock_name, union rtpp_tnotify_entry *rtep,
  const char **e)
{
    char host[512], port[10];
    char *new_sn, **snp;
    int n, rval;
    const char *sprefix, *usock_name;

    snp = &rtep->rtt.socket_name;
    rval = 0;
    sprefix = NULL;
    if (strncmp("unix:", sock_name, 5) == 0) {
        usock_name = sock_name + 5;
        rtep->rtt.socket_type = PF_LOCAL;
    } else if (strncmp("tcp:", sock_name, 4) == 0) {
        if (parse_hostport(sock_name + 4, host, sizeof(host), port, sizeof(port), 0, e) != 0) {
            return (-1);
        }
        rtep->rtt.socket_type = PF_INET;
    } else {
        sprefix = "unix:";
        usock_name = sock_name;
        rtep->rtt.socket_type = PF_LOCAL;
    }
    if (rtep->rtt.socket_type == PF_UNIX) {
        if (strlen(usock_name) == 0) {
            *e = "Timeout notification socket name too short";
            return (-1);
        }
        rtep->rtt.remote.u.sun_family = AF_LOCAL;
        strncpy(rtep->rtt.remote.u.sun_path, usock_name, sizeof(rtep->rtt.remote.u.sun_path) - 1);
#if defined(HAVE_SOCKADDR_SUN_LEN)
        rtep->rtt.remote.u.sun_len = strlen(rtep->rtt.remote.u.sun_path);
#endif
        rtep->rtt.remote_len = sizeof(rtep->rtt.remote.u);
    } else if (rtep->rtt.socket_type == PF_INET && strcmp(host, CC_SELF_STR) == 0) {
        rtep->rtw.socket_type = PF_INET;
        rtep->rtw.port = atoi(port);
        snp = &rtep->rtt.socket_name;
        rval = 1;
    } else {
        n = resolve(sstosa(&(rtep->rtt.remote.i)), AF_INET, host, port, AI_PASSIVE);
        if (n != 0) {
            *e = gai_strerror(n);
            return (-1);
        }
        rtep->rtt.remote_len = SA_LEN(sstosa(&(rtep->rtt.remote.i)));
    }
    if (sprefix == NULL) {
        new_sn = strdup(sock_name);
    } else {
        asprintf(&new_sn, "%s%s", sprefix, usock_name);
    }
    if (new_sn == NULL) {
        *e = strerror(errno);
        return (-1);
    }
    *snp = new_sn;

    return (rval);
}

static int
rtpp_tnotify_set_append(struct rtpp_tnotify_set_obj *pub,
  const char *socket_name, const char **e)
{
    int rval;
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_target *tntp;
    struct rtpp_tnotify_wildcard *tnwp;
    union rtpp_tnotify_entry rte;

    pvt = PUB2PVT(pub);
    memset(&rte, '\0', sizeof(union rtpp_tnotify_entry));
    rval = parse_timeout_sock(socket_name, &rte, e);
    if (rval < 0) {
        goto e0;
    }
    tntp = NULL;
    tnwp = NULL;
    if (rval == 0) {
        if (pvt->tp_len == RTPP_TNOTIFY_TARGETS_MAX) {
            *e = "Number of notify targets exceeds RTPP_TNOTIFY_TARGETS_MAX";
            goto e0;
        }
        tntp = malloc(sizeof(struct rtpp_tnotify_target));
        if (tntp == NULL) {
             *e = strerror(errno);
             goto e1;
        }
        memcpy(tntp, &rte.rtt, sizeof(struct rtpp_tnotify_target));
        tntp->connected = 0;
        tntp->fd = -1;
        pvt->tp[pvt->tp_len] = tntp;
        pvt->tp_len += 1;
    } else {
        if (pvt->wp_len == RTPP_TNOTIFY_WILDCARDS_MAX) {
            *e = "Number of notify wildcards exceeds RTPP_TNOTIFY_WILDCARDS_MAX";
            goto e0;
        }
        tnwp = malloc(sizeof(struct rtpp_tnotify_wildcard));
        if (tnwp == NULL) {
             *e = strerror(errno);
             goto e1;
        }
        memcpy(tnwp, &rte.rtw, sizeof(struct rtpp_tnotify_wildcard));
        pvt->wp[pvt->wp_len] = tnwp;
        pvt->wp_len += 1;
    }

    return (0);

e1:
    if (tntp != NULL)
        free(tntp);
    if (tnwp != NULL)
        free(tnwp);
e0:
    return (-1);
}

static struct rtpp_tnotify_target *
get_tp4wp(struct rtpp_tnotify_set *pvt, struct rtpp_tnotify_wildcard *wp,
  struct sockaddr *ccaddr)
{
    int i;
    struct rtpp_tnotify_target *tp;
    struct sockaddr_in localhost;

    if (ccaddr == NULL) {
        /* Request on the unix domain socket, assume it's 127.0.0.1 */
        memset(&localhost, '\0', sizeof(struct sockaddr_in));
        inet_aton("127.0.0.1", &localhost.sin_addr);
        ccaddr = sstosa(&localhost);
        ccaddr->sa_family = AF_INET;
    }
    for (i = 0; i < pvt->tp_len; i++) {
        /* First check against existing targets */
        tp = pvt->tp[i];
        if (tp->socket_type != wp->socket_type)
            continue;
        if (!ishostseq(ccaddr, sstosa(&tp->remote.i)))
            continue;
        if (getport(sstosa(&tp->remote.i)) != wp->port)
            continue;
        return (tp);
    }
    /* Nothing found, crank up a new entry */
    if (pvt->tp_len == RTPP_TNOTIFY_TARGETS_MAX) {
        return (NULL);
    }
    tp = malloc(sizeof(struct rtpp_tnotify_target));
    if (tp == NULL) {
        return (NULL);
    }
    memset(tp, '\0', sizeof(struct rtpp_tnotify_target));
    tp->remote_len = SA_LEN(ccaddr);
    memcpy(&tp->remote.i, ccaddr, tp->remote_len);
    setport(sstosa(&tp->remote.i), wp->port);
    tp->socket_type = wp->socket_type;
    tp->connected = 0;
    tp->fd = -1;
    pvt->tp[pvt->tp_len] = tp;
    pvt->tp_len += 1;
    return (tp);
}

static struct rtpp_tnotify_target *
rtpp_tnotify_set_lookup(struct rtpp_tnotify_set_obj *pub, const char *socket_name,
  struct sockaddr *ccaddr)
{
    struct rtpp_tnotify_set *pvt;
    struct rtpp_tnotify_wildcard *wp;
    int i;
    char *sep;

    pvt = PUB2PVT(pub);
    for (i = 0; i < pvt->tp_len; i++) {
        if (pvt->tp[i]->socket_name == NULL)
{'fraction_non_alphanumeric': 0.1299357433658704, 'fraction_numerical': 0.009515867955069406, 'mean_word_length': 2.7783543365455894, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 173, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5734737', 'n_tokens_mistral': 7764, 'n_tokens_neox': 7454, 'n_words': 1795}