From ca9169123c475f461ce7d1912260d7ce65f7b61e Mon Sep 17 00:00:00 2001
From: phil <me@filou.se>
Date: Fri, 23 Apr 2021 13:51:45 +0200
Subject: [PATCH] basic rtsp srv integration w/o management

---
 src/include/aes67/utils/sapd.h |   7 +-
 src/utils/rtsp-srv.c           |   2 +-
 src/utils/sapd/CMakeLists.txt  |   2 +
 src/utils/sapd/sapd.c          | 149 +++++++++++++++++++++++++++------
 4 files changed, 132 insertions(+), 28 deletions(-)

diff --git a/src/include/aes67/utils/sapd.h b/src/include/aes67/utils/sapd.h
index c3b73c1..8febe3c 100644
--- a/src/include/aes67/utils/sapd.h
+++ b/src/include/aes67/utils/sapd.h
@@ -46,8 +46,8 @@ extern "C" {
 #define AES67_SAPD_SYSLOG_OPTION    0
 #define AES67_SAPD_SYSLOG_FACILITY  LOG_DAEMON
 
-#define AES67_SAPD_LOCAL_SOCK     "/var/run/sapd.sock"
-//#define AES67_SAPD_LOCAL_SOCK      "sapd.sock"
+//#define AES67_SAPD_LOCAL_SOCK     "/var/run/sapd.sock"
+#define AES67_SAPD_LOCAL_SOCK      "sapd.sock"
 #define AES67_SAPD_LOCAL_LISTEN_BACKLOG    3
 #define AES67_SAPD_LOCAL_MAX_CONNECTIONS   10
 
@@ -206,6 +206,9 @@ extern "C" {
 #define AES67_SAPD_CMD_RAV_UNPUBLISH    "ravunpub"
 #define AES67_SAPD_CMD_RAV_UNPUBLISH_FMT "ravunpub %s"
 
+#define AES67_SAPD_CMD_RAV_ANNOUNCE     "ravan"
+#define AES67_SAPD_CMD_RAV_UNANNOUNCE     "ravunan"
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/utils/rtsp-srv.c b/src/utils/rtsp-srv.c
index 291778c..353fe0c 100644
--- a/src/utils/rtsp-srv.c
+++ b/src/utils/rtsp-srv.c
@@ -90,7 +90,7 @@ void aes67_rtsp_srv_deinit(struct aes67_rtsp_srv * srv)
 int aes67_rtsp_srv_start(struct aes67_rtsp_srv * srv, const enum aes67_net_ipver ipver, const u8_t *ip, u16_t port)
 {
     assert(srv);
-    assert(ipver != aes67_net_ipver_4);
+    assert(ipver == aes67_net_ipver_4);
 //    assert(ip);
     assert(port);
 
diff --git a/src/utils/sapd/CMakeLists.txt b/src/utils/sapd/CMakeLists.txt
index 327e3d5..f8129a3 100644
--- a/src/utils/sapd/CMakeLists.txt
+++ b/src/utils/sapd/CMakeLists.txt
@@ -19,6 +19,8 @@ if (${SAPD_WITH_RAV})
             ${AES67_MDNS_SOURCE_FILES}
             ${AES67_DIR}/src/include/aes67/utils/rtsp-dsc.h
             ${AES67_DIR}/src/utils/rtsp-dsc.c
+            ${AES67_DIR}/src/include/aes67/utils/rtsp-srv.h
+            ${AES67_DIR}/src/utils/rtsp-srv.c
             ${AES67_DIR}/src/third_party/dnmfarrell/URI-Encode-C/src/uri_encode.h
             ${AES67_DIR}/src/third_party/dnmfarrell/URI-Encode-C/src/uri_encode.c
     )
diff --git a/src/utils/sapd/sapd.c b/src/utils/sapd/sapd.c
index 0e776d8..39f7a7f 100644
--- a/src/utils/sapd/sapd.c
+++ b/src/utils/sapd/sapd.c
@@ -25,6 +25,7 @@
 #if AES67_SAPD_WITH_RAV == 1
 #include "aes67/utils/mdns.h"
 #include "aes67/utils/rtsp-dsc.h"
+#include "aes67/utils/rtsp-srv.h"
 #include "aes67/rav.h"
 #include "dnmfarrell/URI-Encode-C/src/uri_encode.h"
 #endif
@@ -183,6 +184,9 @@ static void write_rav_unpublish_by(struct rav_session_st * session, struct conne
 static void cmd_rav_list(struct connection_st * con, u8_t * cmdline, size_t len);
 static void cmd_rav_publish(struct connection_st * con, u8_t * cmdline, size_t len);
 static void cmd_rav_unpublish(struct connection_st * con, u8_t * cmdline, size_t len);
+
+static void cmd_rav_announce(struct connection_st * con, u8_t * cmdline, size_t len);
+static void cmd_rav_unannounce(struct connection_st * con, u8_t * cmdline, size_t len);
 #endif
 
 
@@ -203,6 +207,9 @@ static struct {
     uint16_t rav_publish_delay;
     uint16_t rav_update_interval;
     bool rav_handover;
+    bool rav_server_enabled;
+    uint16_t rav_server_port;
+    bool rav_auto_announce;
 #endif// AES67_SAPD_WITH_RAV == 1
 
 } opts = {
@@ -218,7 +225,10 @@ static struct {
         .rav_auto_publish = true,
         .rav_publish_delay = RAV_PUBLISH_DELAY_DEFAULT,
         .rav_update_interval = RAV_UPDATE_INTERVAL_DEFAULT,
-        .rav_handover = true
+        .rav_handover = true,
+        .rav_server_enabled = true,
+        .rav_server_port = 9191,
+        .rav_auto_announce = true
 #endif // AES67_SAPD_WITH_RAV == 1
 };
 
@@ -231,11 +241,13 @@ static struct {
     aes67_mdns_context_t mdns_context;
     aes67_mdns_resource_t mdns_browse_res;
     struct rav_session_st * first_session;
-    struct aes67_rtsp_dsc_res_st rtsp;
+    struct aes67_rtsp_dsc_res_st rtsp_dsc;
     struct rav_session_st * rtsp_session;
     struct aes67_timer retry_timer;
     struct aes67_timer publish_timer;
     struct aes67_timer update_timer;
+
+    struct aes67_rtsp_srv rtsp_srv;
 } rav = {
     .mdns_context = NULL,
     .mdns_browse_res = NULL,
@@ -268,7 +280,9 @@ static const struct cmd_st commands[] = {
 #if AES67_SAPD_WITH_RAV == 1
         CMD_INIT(AES67_SAPD_CMD_RAV_LIST, cmd_rav_list),
         CMD_INIT(AES67_SAPD_CMD_RAV_PUBLISH, cmd_rav_publish),
-        CMD_INIT(AES67_SAPD_CMD_RAV_UNPUBLISH, cmd_rav_unpublish)
+        CMD_INIT(AES67_SAPD_CMD_RAV_UNPUBLISH, cmd_rav_unpublish),
+        CMD_INIT(AES67_SAPD_CMD_RAV_ANNOUNCE, cmd_rav_announce),
+        CMD_INIT(AES67_SAPD_CMD_RAV_UNANNOUNCE, cmd_rav_unannounce)
 #endif
 };
 
@@ -327,6 +341,13 @@ static void help(FILE * fd)
              "\t --rav-no-handover\n"
              "\t\t\t Discovered ravenna session that are also found through SAP will NOT give\n"
              "\t\t\t up local management (ie will NOT continue to announce sessions)."
+             "\t --rav-disable-server\n"
+             "\t\t\t Generally disables Ravenna service announcements and RTSP server (default enabled).\n"
+             "\t --rav-server-port <port>\n"
+             "\t\t\t Port on which to start RTSP server to server SDP files (default 9191).\n"
+             "\t --rav-no-autoannounce\n"
+             "\t\t\t Local services will not be automatically announced as ravenna services and\n"
+             "\t\t\t made available through the built in RTSP server (default enabled).\n"
  #endif
             "\nCompile time options:\n"
             "\t AES67_SAP_MIN_INTERVAL_SEC \t %d \t // +- announce time, depends on SAP traffic\n"
@@ -411,11 +432,26 @@ static void block_until_event()
             }
         }
 
-        if (rav.rtsp.state == aes67_rtsp_dsc_state_awaiting_response && rav.rtsp.sockfd != -1){
-            FD_SET(rav.rtsp.sockfd, &rfds);
-            FD_SET(rav.rtsp.sockfd, &xfds);
-            if (rav.rtsp.sockfd > nfds){
-                nfds = rav.rtsp.sockfd;
+        if (rav.rtsp_dsc.state == aes67_rtsp_dsc_state_awaiting_response && rav.rtsp_dsc.sockfd != -1){
+            FD_SET(rav.rtsp_dsc.sockfd, &rfds);
+            FD_SET(rav.rtsp_dsc.sockfd, &xfds);
+            if (rav.rtsp_dsc.sockfd > nfds){
+                nfds = rav.rtsp_dsc.sockfd;
+            }
+        }
+
+        if (opts.rav_server_enabled){
+            FD_SET(rav.rtsp_srv.listen_sockfd, &rfds);
+            FD_SET(rav.rtsp_srv.listen_sockfd, &xfds);
+            if (rav.rtsp_srv.listen_sockfd > nfds){
+                nfds = rav.rtsp_srv.listen_sockfd;
+            }
+            if (rav.rtsp_srv.client_sockfd != -1){
+                FD_SET(rav.rtsp_srv.client_sockfd, &rfds);
+                FD_SET(rav.rtsp_srv.client_sockfd, &xfds);
+                if (rav.rtsp_srv.client_sockfd > nfds){
+                    nfds = rav.rtsp_srv.client_sockfd;
+                }
             }
         }
     }
@@ -661,7 +697,7 @@ static void rav_session_delete(struct rav_session_st * session)
 
     // if currently SDP lookup is in process with given session, abort
     if (rav.rtsp_session == session){
-        aes67_rtsp_dsc_stop(&rav.rtsp);
+        aes67_rtsp_dsc_stop(&rav.rtsp_dsc);
         rav.rtsp_session = NULL;
     }
 
@@ -700,7 +736,7 @@ static int rav_setup()
         return EXIT_FAILURE;
     }
 
-    aes67_rtsp_dsc_init(&rav.rtsp, false);
+    aes67_rtsp_dsc_init(&rav.rtsp_dsc, false);
 
     aes67_timer_init(&rav.retry_timer);
     aes67_timer_init(&rav.publish_timer);
@@ -708,16 +744,33 @@ static int rav_setup()
 
     syslog(LOG_INFO, "Browsing for Ravenna sessions");
 
+    if (opts.rav_server_enabled){
+        aes67_rtsp_srv_init(&rav.rtsp_srv, false, NULL);
+
+        aes67_rtsp_srv_blocking(&rav.rtsp_srv, false);
+
+        if (aes67_rtsp_srv_start(&rav.rtsp_srv, aes67_net_ipver_4, NULL, opts.rav_server_port)){
+            syslog(LOG_ERR, "Failed to start RTSP server on port %hu", opts.rav_server_port);
+            return EXIT_FAILURE;
+        }
+
+        syslog(LOG_INFO, "Started RTSP server on port %hu", opts.rav_server_port);
+    }
+
     return EXIT_SUCCESS;
 }
 
 static void rav_teardown()
 {
+    if (opts.rav_server_enabled){
+        aes67_rtsp_srv_deinit(&rav.rtsp_srv);
+    }
+
     aes67_timer_deinit(&rav.publish_timer);
     aes67_timer_deinit(&rav.update_timer);
     aes67_timer_deinit(&rav.retry_timer);
 
-    aes67_rtsp_dsc_deinit(&rav.rtsp);
+    aes67_rtsp_dsc_deinit(&rav.rtsp_dsc);
 
     if (rav.mdns_context == NULL){
         return;
@@ -734,33 +787,33 @@ static void rav_process()
 
     //// check if rtsp sdp lookup has anything to do
     // first process pending
-    if (rav.rtsp.state == aes67_rtsp_dsc_state_awaiting_response){
+    if (rav.rtsp_dsc.state == aes67_rtsp_dsc_state_awaiting_response){
 
-        aes67_rtsp_dsc_process(&rav.rtsp);
+        aes67_rtsp_dsc_process(&rav.rtsp_dsc);
     }
     // if done
-    if (rav.rtsp.state == aes67_rtsp_dsc_state_done){
+    if (rav.rtsp_dsc.state == aes67_rtsp_dsc_state_done){
 
         // update last activity?
         rav.rtsp_session->last_activity = time(NULL);
 
         // checking for some meaningful min-length
-        if (rav.rtsp.statuscode == AES67_RTSP_STATUS_OK && rav.rtsp.contentlen > 32){
+        if (rav.rtsp_dsc.statuscode == AES67_RTSP_STATUS_OK && rav.rtsp_dsc.contentlen > 32){
 
-            u8_t *sdp = (u8_t*)aes67_rtsp_dsc_content(&rav.rtsp);
+            u8_t *sdp = (u8_t*)aes67_rtsp_dsc_content(&rav.rtsp_dsc);
             assert(sdp != NULL); // should not occur
 
             // get origin (o=..) offset v=0\r\n
             u8_t * o = sdp[4] == '\n' ? &sdp[5] : &sdp[4];
 
-            sdp[rav.rtsp.contentlen] = '\0';
+            sdp[rav.rtsp_dsc.contentlen] = '\0';
 
 //            printf("%s\n", o);
 //            printf("origin %c%c%c %d\n", o[0], o[1] ,o[2], rav.rtsp.contentlen - (o - sdp));
 
             struct aes67_sdp_originator origin;
 
-            if (aes67_sdp_origin_fromstr(&origin, o, rav.rtsp.contentlen - (o - sdp)) == AES67_SDP_ERROR){
+            if (aes67_sdp_origin_fromstr(&origin, o, rav.rtsp_dsc.contentlen - (o - sdp)) == AES67_SDP_ERROR){
                 if (rav.rtsp_session->state == rav_state_sdp_available || rav.rtsp_session->state == rav_state_sdp_published){
                     // if prior sdp retrieved, ignore error, assume a temporary fail
                     //TODO anything to consider? if device went offline, the rtsp start operation will fail
@@ -793,13 +846,13 @@ static void rav_process()
                 // update SDP info
                 memcpy(&rav.rtsp_session->origin, &origin, sizeof(struct aes67_sdp_originator));
 
-                rav.rtsp_session->sdp = malloc(rav.rtsp.contentlen + 1);
+                rav.rtsp_session->sdp = malloc(rav.rtsp_dsc.contentlen + 1);
 
                 assert(rav.rtsp_session->sdp != NULL);
 
-                memcpy(rav.rtsp_session->sdp, sdp, rav.rtsp.contentlen);
-                rav.rtsp_session->sdp[rav.rtsp.contentlen] = '\0'; // not needed, but in case dumping
-                rav.rtsp_session->sdplen = rav.rtsp.contentlen;
+                memcpy(rav.rtsp_session->sdp, sdp, rav.rtsp_dsc.contentlen);
+                rav.rtsp_session->sdp[rav.rtsp_dsc.contentlen] = '\0'; // not needed, but in case dumping
+                rav.rtsp_session->sdplen = rav.rtsp_dsc.contentlen;
 
 
                 if (rav.rtsp_session->state == rav_state_discovered || (!opts.rav_auto_publish && rav.rtsp_session->state == rav_state_sdp_available)){
@@ -820,10 +873,10 @@ static void rav_process()
 
         // make available for next describe operation
         rav.rtsp_session = NULL;
-        rav.rtsp.state = aes67_rtsp_dsc_state_bored;
+        rav.rtsp_dsc.state = aes67_rtsp_dsc_state_bored;
     }
     // if actually nothing to do
-    if (rav.rtsp.state == aes67_rtsp_dsc_state_bored){
+    if (rav.rtsp_dsc.state == aes67_rtsp_dsc_state_bored){
 
         struct rav_session_st * session = rav.first_session;
         struct rav_session_st * oldest = NULL;
@@ -867,7 +920,7 @@ static void rav_process()
             char uri[256];
             snprintf(uri, sizeof(uri), "/by-name/%s", name);
 
-            if (aes67_rtsp_dsc_start(&rav.rtsp, session->addr.ipver, session->addr.ip, session->addr.port, uri)){
+            if (aes67_rtsp_dsc_start(&rav.rtsp_dsc, session->addr.ipver, session->addr.ip, session->addr.port, uri)){
 
                 //TODO what can a start fail signify?
                 // - a device gone offline without telling anyone
@@ -953,7 +1006,13 @@ static void rav_process()
         u32_t wait_sec = opts.rav_publish_delay - (time(NULL) - oldest->last_activity);
         aes67_timer_set(&rav.publish_timer, 1000 * wait_sec);
     }
+
+
+    if (opts.rav_server_enabled){
+        aes67_rtsp_srv_process(&rav.rtsp_srv);
+    }
 }
+
 static void rav_publish_by(struct rav_session_st * session, struct connection_st * con)
 {
     syslog(LOG_INFO, "Publishing through SAP: %s", session->name);
@@ -2118,6 +2177,27 @@ static void cmd_rav_unpublish(struct connection_st * con, u8_t * cmdline, size_t
     }
 
 }
+
+static void cmd_rav_announce(struct connection_st * con, u8_t * cmdline, size_t len)
+{
+    if (!opts.rav_enabled || !opts.rav_server_enabled){
+        write_error(con, AES67_SAPD_ERR_NOTENABLED, NULL);
+        return;
+    }
+
+    //TODO
+}
+
+static void cmd_rav_unannounce(struct connection_st * con, u8_t * cmdline, size_t len)
+{
+    if (!opts.rav_enabled || !opts.rav_server_enabled){
+        write_error(con, AES67_SAPD_ERR_NOTENABLED, NULL);
+        return;
+    }
+
+    //TODO
+}
+
 #endif
 
 int main(int argc, char * argv[]){
@@ -2153,6 +2233,9 @@ int main(int argc, char * argv[]){
                 {"rav-no-autopub", no_argument, 0, 18},
 #endif
                 {"sdp-dir", required_argument, 0, 19},
+                {"rav-disable-server", no_argument, 0, 20},
+                {"rav-no-autoannounce", no_argument, 0, 21},
+                {"rav-server-port", required_argument, 0, 22},
                 {0,         0,                 0,  0 }
         };
 
@@ -2249,6 +2332,22 @@ int main(int argc, char * argv[]){
                 opts.rav_auto_publish = false;
                 break;
             }
+
+            case 20: // -- rav-disable-server
+                opts.rav_server_enabled = false;
+                break;
+
+            case 21: // --rav-no-autoannounce
+                opts.rav_auto_announce = false;
+                break;
+
+            case 22:
+                opts.rav_server_port = atoi(optarg);
+                if (!opts.rav_server_port){
+                    fprintf(stderr, "invalid port for RTSP service: %s\n", optarg);
+                    return EXIT_FAILURE;
+                }
+                break;
 #endif
 
             case 19: // --sdp-dir
-- 
GitLab