Review at  https://gerrit.osmocom.org/4146

client: add unified function to generate MGCP messages

currently the only way to generate MGCP messages is to use
mgcp_msg_crcx(), mgcp_msg_mdcx() and mgcp_msg_dlcx(). All
three function take a fixed set of parameters via their
parameter list. There is no way to add or leave away optional
parameters.

add function mgcp_msg_gen(), this function takes a unified
message struct. The struct features a presence bitmask which
allows to enable and disable parameters as needed. It is also
possible to add new parameters in the future without breaking
the API.

Change-Id: I29c5e2fb972896faeb771ba040f015592487fcbe
---
M include/osmocom/mgcp_client/mgcp_client.h
M src/libosmo-mgcp-client/mgcp_client.c
M tests/mgcp_client/mgcp_client_test.c
M tests/mgcp_client/mgcp_client_test.ok
4 files changed, 237 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/46/4146/1

diff --git a/include/osmocom/mgcp_client/mgcp_client.h 
b/include/osmocom/mgcp_client/mgcp_client.h
index efc1f76..9368a76 100644
--- a/include/osmocom/mgcp_client/mgcp_client.h
+++ b/include/osmocom/mgcp_client/mgcp_client.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <stdint.h>
+#include <sys/socket.h>
 
 #include <osmocom/mgcp_client/mgcp_common.h>
 
@@ -37,6 +38,33 @@
        uint16_t audio_port;
 };
 
+enum mgcp_verb {
+       MGCP_VERB_CRCX,
+       MGCP_VERB_MDCX,
+       MGCP_VERB_DLCX,
+       MGCP_VERB_AUEP,
+       MGCP_VERB_RSIP,
+};
+
+#define MGCP_MSG_T_ENDPOINT    0x0001
+#define MGCP_MSG_T_CALL_ID     0x0002
+#define MGCP_MSG_T_CONN_ID     0x0004
+#define MGCP_MSG_T_RTP_ADDR    0x0008
+#define MGCP_MSG_T_CONN_MODE   0x0010
+
+/* See also RFC3435 section 3.2.1.3 */
+#define MGCP_EINDPOINT_MAXLEN (255*2+1+1)
+
+struct mgcp_msg {
+       enum mgcp_verb verb;
+       uint32_t presence;
+       char endpoint[MGCP_EINDPOINT_MAXLEN];
+       unsigned int call_id;
+       uint32_t conn_id;
+       struct sockaddr_storage rtp_addr;
+       enum mgcp_connection_mode conn_mode;
+};
+
 void mgcp_client_conf_init(struct mgcp_client_conf *conf);
 void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf 
*conf);
 int mgcp_client_config_write(struct vty *vty, const char *indent);
@@ -63,17 +91,22 @@
 
 enum mgcp_connection_mode;
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
                           uint16_t rtp_endpoint, unsigned int call_id,
                           enum mgcp_connection_mode mode);
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
                           uint16_t rtp_endpoint, const char *rtp_conn_addr,
                           uint16_t rtp_port, enum mgcp_connection_mode mode);
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
                           unsigned int call_id);
 
+struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
+
 extern const struct value_string mgcp_client_connection_mode_strs[];
 static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode 
mode)
 {
diff --git a/src/libosmo-mgcp-client/mgcp_client.c 
b/src/libosmo-mgcp-client/mgcp_client.c
index 1cd37be..175f81a 100644
--- a/src/libosmo-mgcp-client/mgcp_client.c
+++ b/src/libosmo-mgcp-client/mgcp_client.c
@@ -23,6 +23,7 @@
 #include <osmocom/core/write_queue.h>
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/byteswap.h>
 
 #include <osmocom/mgcp_client/mgcp_client.h>
 #include <osmocom/mgcp_client/mgcp_client_internal.h>
@@ -568,6 +569,7 @@
        return mgcp->next_trans_id ++;
 }
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
                           uint16_t rtp_endpoint, unsigned int call_id,
                           enum mgcp_connection_mode mode)
@@ -585,6 +587,7 @@
                 mgcp_client_cmode_name(mode));
 }
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
                           uint16_t rtp_endpoint, const char *rtp_conn_addr,
                           uint16_t rtp_port, enum mgcp_connection_mode mode)
@@ -605,6 +608,7 @@
                 rtp_port);
 }
 
+/* Deprecated, please use mgcp_msg_gen() instead */
 struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
                           unsigned int call_id)
 {
@@ -614,6 +618,113 @@
                                 "C: %x\r\n", trans_id, rtp_endpoint, call_id);
 }
 
+#define MGCP_CRCX_MANDATORY (MGCP_MSG_T_ENDPOINT | MGCP_MSG_T_CALL_ID | 
MGCP_MSG_T_CONN_ID | MGCP_MSG_T_CONN_MODE)
+#define MGCP_MDCX_MANDATORY (MGCP_MSG_T_ENDPOINT | MGCP_MSG_T_CONN_ID)
+#define MGCP_DLCX_MANDATORY (MGCP_MSG_T_ENDPOINT)
+#define MGCP_AUEP_MANDATORY (MGCP_MSG_T_ENDPOINT)
+#define MGCP_RSIP_MANDATORY 0  /* none */
+
+struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
+{
+       mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
+       uint32_t mandatory_mask;
+       static char compose[4096 - 128];
+       struct sockaddr_in *sin;
+       struct sockaddr_in6 *sin6;
+       struct sockaddr_storage *ss;
+       uint16_t port = 0;
+       char addr[INET6_ADDRSTRLEN];
+
+       /* Add command verb */
+       switch (mgcp_msg->verb) {
+       case MGCP_VERB_CRCX:
+               mandatory_mask = MGCP_CRCX_MANDATORY;
+               sprintf(compose, "CRCX %u", trans_id);
+               break;
+       case MGCP_VERB_MDCX:
+               mandatory_mask = MGCP_MDCX_MANDATORY;
+               sprintf(compose, "MDCX %u", trans_id);
+               break;
+       case MGCP_VERB_DLCX:
+               mandatory_mask = MGCP_DLCX_MANDATORY;
+               sprintf(compose, "DLCX %u", trans_id);
+               break;
+       case MGCP_VERB_AUEP:
+               mandatory_mask = MGCP_AUEP_MANDATORY;
+               sprintf(compose, "AUEP %u", trans_id);
+               break;
+       case MGCP_VERB_RSIP:
+               mandatory_mask = MGCP_RSIP_MANDATORY;
+               sprintf(compose, "RSIP %u", trans_id);
+               break;
+       default:
+               /* Invalid command verb -- abort */
+               return NULL;
+       }
+
+       /* Check if mandatory fiels are missing */
+       if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask))
+               return NULL;
+
+       /* Add endpoint name */
+       if (mgcp_msg->presence & MGCP_MSG_T_ENDPOINT)
+               sprintf(compose + strlen(compose), " %s", mgcp_msg->endpoint);
+
+       /* Add protocol version */
+       sprintf(compose + strlen(compose), " MGCP 1.0\r\n");
+
+       /* Add call id */
+       if (mgcp_msg->presence & MGCP_MSG_T_CALL_ID)
+               sprintf(compose + strlen(compose), "C: %x\r\n",
+                       mgcp_msg->call_id);
+
+       /* Add connection id */
+       if (mgcp_msg->presence & MGCP_MSG_T_CONN_ID)
+               sprintf(compose + strlen(compose), "I: %u\r\n",
+                       mgcp_msg->conn_id);
+
+       /* Add local connection options */
+       if (mgcp_msg->presence & MGCP_MSG_T_CONN_ID
+           && mgcp_msg->verb == MGCP_VERB_CRCX)
+               sprintf(compose + strlen(compose), "L: p:20, a:AMR, nt:IN\r\n");
+
+       /* Add mode */
+       if (mgcp_msg->presence & MGCP_MSG_T_CONN_MODE)
+               sprintf(compose + strlen(compose), "M: %s\r\n",
+                       mgcp_client_cmode_name(mgcp_msg->conn_mode));
+
+       /* Add RTP address and port (SDP) */
+       if (mgcp_msg->presence & MGCP_MSG_T_RTP_ADDR) {
+               sprintf(compose + strlen(compose), "\r\n");
+
+               ss = &mgcp_msg->rtp_addr;
+               switch (ss->ss_family) {
+               case AF_INET:
+                       sin = (struct sockaddr_in *)ss;
+                       port = osmo_ntohs(sin->sin_port);
+                       inet_ntop(AF_INET, &sin->sin_addr, addr,
+                                 INET_ADDRSTRLEN);
+                       sprintf(compose + strlen(compose), "c=IN IP4 %s\r\n",
+                               addr);
+
+                       break;
+               case AF_INET6:
+                       sin6 = (struct sockaddr_in6 *)ss;
+                       port = osmo_ntohs(sin6->sin6_port);
+                       inet_ntop(AF_INET6, &sin6->sin6_addr, addr,
+                                 INET6_ADDRSTRLEN);
+                       sprintf(compose + strlen(compose), "c=IN IP6 %s\r\n",
+                               addr);
+                       break;
+               }
+
+               sprintf(compose + strlen(compose), "m=audio %u RTP/AVP 255\r\n",
+                       port);
+       }
+
+       return mgcp_msg_from_str(trans_id, compose);
+}
+
 struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
 {
        return &mgcp->actual;
diff --git a/tests/mgcp_client/mgcp_client_test.c 
b/tests/mgcp_client/mgcp_client_test.c
index f2f0e0f..1ed6a9a 100644
--- a/tests/mgcp_client/mgcp_client_test.c
+++ b/tests/mgcp_client/mgcp_client_test.c
@@ -19,6 +19,9 @@
  */
 
 #include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/application.h>
@@ -149,6 +152,67 @@
                "a=ptime:20\r\n");
 }
 
+void test_mgcp_msg(void)
+{
+       struct msgb *msg;
+
+       struct mgcp_msg mgcp_msg;
+       struct sockaddr_in *sin;
+
+       if (mgcp)
+               talloc_free(mgcp);
+       mgcp = mgcp_client_init(ctx, &conf);
+
+       /* Pre-fill the message struct with some arbitary values */
+       sin = (struct sockaddr_in *)&mgcp_msg.rtp_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_port = htons(1234);
+       inet_aton("192.168.100.23", &sin->sin_addr);
+       strcpy(mgcp_msg.endpoint, "23@mgw");
+       mgcp_msg.call_id = 47;
+       mgcp_msg.conn_id = 11;
+       mgcp_msg.conn_mode = MGCP_CONN_RECV_SEND;
+
+       printf("\n");
+
+       printf("Generated CRCX message:\n");
+       mgcp_msg.verb = MGCP_VERB_CRCX;
+       mgcp_msg.presence =
+           (MGCP_MSG_T_ENDPOINT | MGCP_MSG_T_CALL_ID | MGCP_MSG_T_CONN_ID |
+            MGCP_MSG_T_CONN_MODE);
+       msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+       printf("%s\n", msg->data);
+
+       printf("Generated MDCX message:\n");
+       mgcp_msg.verb = MGCP_VERB_MDCX;
+       mgcp_msg.presence =
+           (MGCP_MSG_T_ENDPOINT | MGCP_MSG_T_CALL_ID | MGCP_MSG_T_CONN_ID |
+            MGCP_MSG_T_CONN_MODE | MGCP_MSG_T_RTP_ADDR);
+       msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+       printf("%s\n", msg->data);
+
+       printf("Generated DLCX message:\n");
+       mgcp_msg.verb = MGCP_VERB_DLCX;
+       mgcp_msg.presence =
+           (MGCP_MSG_T_ENDPOINT | MGCP_MSG_T_CALL_ID | MGCP_MSG_T_CONN_ID);
+       msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+       printf("%s\n", msg->data);
+
+       printf("Generated AUEP message:\n");
+       mgcp_msg.verb = MGCP_VERB_AUEP;
+       mgcp_msg.presence = (MGCP_MSG_T_ENDPOINT);
+       msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+       printf("%s\n", msg->data);
+
+       printf("Generated RSIP message:\n");
+       mgcp_msg.verb = MGCP_VERB_RSIP;
+       mgcp_msg.presence = (MGCP_MSG_T_ENDPOINT);
+       msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+       printf("%s\n", msg->data);
+
+       msgb_free(msg);
+}
+
 static const struct log_info_cat log_categories[] = {
 };
 
@@ -167,6 +231,7 @@
        mgcp_client_conf_init(&conf);
 
        test_crcx();
+       test_mgcp_msg();
 
        printf("Done\n");
        fprintf(stderr, "Done\n");
diff --git a/tests/mgcp_client/mgcp_client_test.ok 
b/tests/mgcp_client/mgcp_client_test.ok
index d35f2d6..7c4819d 100644
--- a/tests/mgcp_client/mgcp_client_test.ok
+++ b/tests/mgcp_client/mgcp_client_test.ok
@@ -28,4 +28,32 @@
   head.trans_id = 1
   head.comment = OK
   audio_port = 16002
+
+Generated CRCX message:
+CRCX 1 23@mgw MGCP 1.0
+C: 2f
+I: 11
+L: p:20, a:AMR, nt:IN
+M: sendrecv
+
+Generated MDCX message:
+MDCX 2 23@mgw MGCP 1.0
+C: 2f
+I: 11
+M: sendrecv
+
+c=IN IP4 192.168.100.23
+m=audio 1234 RTP/AVP 255
+
+Generated DLCX message:
+DLCX 3 23@mgw MGCP 1.0
+C: 2f
+I: 11
+
+Generated AUEP message:
+AUEP 4 23@mgw MGCP 1.0
+
+Generated RSIP message:
+RSIP 5 23@mgw MGCP 1.0
+
 Done

-- 
To view, visit https://gerrit.osmocom.org/4146
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I29c5e2fb972896faeb771ba040f015592487fcbe
Gerrit-PatchSet: 1
Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-Owner: dexter <[email protected]>

Reply via email to