summaryrefslogtreecommitdiff
path: root/src/libosmo-mgcp/mgcp_conn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libosmo-mgcp/mgcp_conn.c')
-rw-r--r--src/libosmo-mgcp/mgcp_conn.c141
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,