diff options
Diffstat (limited to 'src/libosmo-mgcp/mgcp_conn.c')
-rw-r--r-- | src/libosmo-mgcp/mgcp_conn.c | 141 |
1 files changed, 87 insertions, 54 deletions
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c index e0eec63..998dbc5 100644 --- a/src/libosmo-mgcp/mgcp_conn.c +++ b/src/libosmo-mgcp/mgcp_conn.c @@ -24,10 +24,51 @@ #include <osmocom/mgcp/mgcp_conn.h> #include <osmocom/mgcp/mgcp_internal.h> #include <osmocom/mgcp/mgcp_common.h> -#include <osmocom/mgcp/mgcp_ep.h> +#include <osmocom/mgcp/mgcp_endp.h> +#include <osmocom/gsm/gsm_utils.h> +#include <ctype.h> + +/* Allocate a new connection identifier. According to RFC3435, they must + * be unique only within the scope of the endpoint. (Caller must provide + * memory for id) */ +static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id) +{ + int i; + int k; + int rc; + uint8_t id_bin[16]; + char *id_hex; + + /* Generate a connection id that is unique for the current endpoint. + * Technically a counter would be sufficient, but in order to + * be able to find a specific connection in large logfiles and to + * prevent unintentional connections we assign the connection + * identifiers randomly from a reasonable large number space */ + for (i = 0; i < 32; i++) { + rc = osmo_get_rand_id(id_bin, sizeof(id_bin)); + if (rc < 0) + return rc; + + id_hex = osmo_hexdump_nospc(id_bin, sizeof(id_bin)); + for (k = 0; k < strlen(id_hex); k++) + id_hex[k] = toupper(id_hex[k]); + + /* ensure that the generated conn_id is unique + * for this endpoint */ + if (!mgcp_conn_get_rtp(endp, id_hex)) { + osmo_strlcpy(id, id_hex, MGCP_CONN_ID_LENGTH); + return 0; + } + } + + LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x, unable to generate a unique connectionIdentifier\n", + ENDPOINT_NUMBER(endp)); + + return -1; +} /* Reset codec state and free memory */ -static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec) +static void mgcp_rtp_codec_init(struct mgcp_rtp_codec *codec) { codec->payload_type = -1; codec->subtype_name = NULL; @@ -42,22 +83,20 @@ static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec) talloc_free(codec->audio_name); } -/* Reset states, free memory, set defaults and reset codec state */ -static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn) +/* Initialize rtp connection struct with default values */ +static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn) { - struct mgcp_rtp_end *end = &conn->end; + struct mgcp_rtp_end *end = &conn_rtp->end; - conn->type = MGCP_RTP_DEFAULT; - conn->osmux.allocated_cid = -1; + conn_rtp->type = MGCP_RTP_DEFAULT; + conn_rtp->osmux.allocated_cid = -1; + + /* backpointer to the generic part of the connection */ + conn->u.rtp.conn = conn; end->rtp.fd = -1; end->rtcp.fd = -1; - end->local_port = 0; - end->packets_rx = 0; - end->octets_rx = 0; - end->packets_tx = 0; - end->octets_tx = 0; - end->dropped_packets = 0; + memset(&end->stats, 0, sizeof(end->stats)); end->rtp_port = end->rtcp_port = 0; talloc_free(end->fmtp_extra); end->fmtp_extra = NULL; @@ -67,8 +106,16 @@ static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn) end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; end->output_enabled = 0; - mgcp_rtp_codec_reset(&end->codec); - mgcp_rtp_codec_reset(&end->alt_codec); + mgcp_rtp_codec_init(&end->codec); + mgcp_rtp_codec_init(&end->alt_codec); +} + +/* Cleanup rtp connection struct */ +static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp) +{ + osmux_disable_conn(conn_rtp); + osmux_release_cid(conn_rtp); + mgcp_free_rtp_port(&conn_rtp->end); } /*! allocate a new connection list entry. @@ -78,22 +125,15 @@ static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn) * \param[in] type connection type (e.g. MGCP_CONN_TYPE_RTP) * \returns pointer to allocated connection, NULL on error */ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, - uint32_t id, enum mgcp_conn_type type, - char *name) + enum mgcp_conn_type type, char *name) { struct mgcp_conn *conn; - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - OSMO_ASSERT(strlen(name) < sizeof(conn->name)); + int rc; /* Do not allow more then two connections */ if (llist_count(&endp->conns) >= endp->type->max_conns) return NULL; - /* Prevent duplicate connection IDs */ - if (mgcp_conn_get(endp, id)) - return NULL; - /* Create new connection and add it to the list */ conn = talloc_zero(ctx, struct mgcp_conn); if (!conn) @@ -102,13 +142,16 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, conn->type = type; conn->mode = MGCP_CONN_NONE; conn->mode_orig = MGCP_CONN_NONE; - conn->id = id; - conn->u.rtp.conn = conn; - strcpy(conn->name, name); + osmo_strlcpy(conn->name, name, sizeof(conn->name)); + rc = mgcp_alloc_id(endp, conn->id); + if (rc < 0) { + talloc_free(conn); + return NULL; + } switch (type) { case MGCP_CONN_TYPE_RTP: - mgcp_rtp_conn_reset(&conn->u.rtp); + mgcp_rtp_conn_init(&conn->u.rtp, conn); break; default: /* NOTE: This should never be called with an @@ -126,15 +169,12 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, * \param[in] endp associated endpoint * \param[in] id identification number of the connection * \returns pointer to allocated connection, NULL if not found */ -struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, uint32_t id) +struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id) { - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - struct mgcp_conn *conn; llist_for_each_entry(conn, &endp->conns, entry) { - if (conn->id == id) + if (strncmp(conn->id, id, sizeof(conn->id)) == 0) return conn; } @@ -145,11 +185,9 @@ struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, uint32_t id) * \param[in] endp associated endpoint * \param[in] id identification number of the connection * \returns pointer to allocated connection, NULL if not found */ -struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, uint32_t id) +struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, + const char *id) { - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - struct mgcp_conn *conn; conn = mgcp_conn_get(endp, id); @@ -165,22 +203,23 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, uint32_t id) /*! free a connection by its ID. * \param[in] endp associated endpoint * \param[in] id identification number of the connection */ -void mgcp_conn_free(struct mgcp_endpoint *endp, uint32_t id) +void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id) { - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - struct mgcp_conn *conn; conn = mgcp_conn_get(endp, id); if (!conn) return; + /* Run endpoint cleanup action. By this we inform the endpoint about + * the removal of the connection and allow it to clean up its inner + * state accordingly */ + if (endp->type->cleanup_cb) + endp->type->cleanup_cb(endp, conn); + switch (conn->type) { case MGCP_CONN_TYPE_RTP: - osmux_disable_conn(&conn->u.rtp); - osmux_release_cid(&conn->u.rtp); - mgcp_free_rtp_port(&conn->u.rtp.end); + mgcp_rtp_conn_cleanup(&conn->u.rtp); break; default: /* NOTE: This should never be called with an @@ -197,9 +236,6 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, uint32_t id) * \param[in] endp associated endpoint */ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp) { - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - struct mgcp_conn *conn; if (llist_empty(&endp->conns)) @@ -216,9 +252,6 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp) * \param[in] endp associated endpoint */ void mgcp_conn_free_all(struct mgcp_endpoint *endp) { - OSMO_ASSERT(endp); - OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL); - struct mgcp_conn *conn; struct mgcp_conn *conn_tmp; @@ -230,12 +263,12 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp) return; } -/*! dump basic connection information to human readble string. +/*! dump basic connection information to human readable string. * \param[in] conn to dump - * \returns human readble string */ + * \returns human readable string */ char *mgcp_conn_dump(struct mgcp_conn *conn) { - static char str[256]; + static char str[sizeof(conn->name)+sizeof(conn->id)+256]; if (!conn) { snprintf(str, sizeof(str), "(null connection)"); @@ -245,7 +278,7 @@ char *mgcp_conn_dump(struct mgcp_conn *conn) switch (conn->type) { case MGCP_CONN_TYPE_RTP: /* Dump RTP connection */ - snprintf(str, sizeof(str), "(%s/rtp, id:%u, ip:%s, " + snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, " "rtp:%u rtcp:%u)", conn->name, conn->id, |