diff --git a/include/mzrtp/receiver.hh b/include/mzrtp/receiver.hh index 8816a9c..49e6a04 100644 --- a/include/mzrtp/receiver.hh +++ b/include/mzrtp/receiver.hh @@ -22,6 +22,16 @@ namespace uvg_rtp { /* TODO: */ ssize_t get_msg(void *ptr, size_t len); + /* ZRTP packet handler is used after ZRTP state initialization has finished + * and media exchange has started. RTP packet dispatcher gives the packet + * to "zrtp_handler" which then checks whether the packet is a ZRTP packet + * or not and processes it accordingly. + * + * Return RTP_OK on success + * Return RTP_PKT_NOT_HANDLED if "buffer" does not contain a ZRTP message + * Return RTP_GENERIC_ERROR if "buffer" contains an invalid ZRTP message */ + rtp_error_t zrtp_handler(ssize_t size, void *buffer); + private: uint8_t *mem_; size_t len_; diff --git a/include/util.hh b/include/util.hh index 564c11e..19c9441 100644 --- a/include/util.hh +++ b/include/util.hh @@ -36,6 +36,8 @@ const int MAX_PACKET = 65536; const int MAX_PAYLOAD = 1443; typedef enum RTP_ERROR { + RTP_PKT_MODIFIED = 4, /* packet was modified by the layer (see src/pkt_dispatch.cc) */ + RTP_PKT_NOT_HANDLED = 3, /* packet does not belong to this layer */ RTP_INTERRUPTED = 2, RTP_NOT_READY = 1, RTP_OK = 0, diff --git a/src/mzrtp/receiver.cc b/src/mzrtp/receiver.cc index 3943d91..84dfa6d 100644 --- a/src/mzrtp/receiver.cc +++ b/src/mzrtp/receiver.cc @@ -216,4 +216,47 @@ ssize_t uvg_rtp::zrtp_msg::receiver::get_msg(void *ptr, size_t len) memcpy(ptr, mem_, cpy_len); return rlen_; } + +rtp_error_t uvg_rtp::zrtp_msg::receiver::zrtp_handler(ssize_t size, void *buffer) +{ + zrtp_msg *msg = (zrtp_msg *)buffer; + + /* not a ZRTP packet */ + if (msg->header.version || msg->header.magic != ZRTP_HEADER_MAGIC || msg->magic != ZRTP_MSG_MAGIC) + return RTP_PKT_NOT_HANDLED; + + switch (msg->msgblock) { + /* None of these messages should be received by this stream + * during this stage so return RTP_GENERIC_ERROR to indicate that the packet + * is invalid and that it should not be dispatched to other packet handlers */ + case ZRTP_MSG_HELLO: + case ZRTP_MSG_HELLO_ACK: + case ZRTP_MSG_COMMIT: + case ZRTP_MSG_DH_PART1: + case ZRTP_MSG_DH_PART2: + case ZRTP_MSG_CONFIRM1: + case ZRTP_MSG_CONFIRM2: + case ZRTP_MSG_CONF2_ACK: + return RTP_GENERIC_ERROR; + + case ZRTP_MSG_ERROR: + /* TODO: */ + return RTP_OK; + + case ZRTP_MSG_ERROR_ACK: + /* TODO: */ + return RTP_OK; + + case ZRTP_MSG_SAS_RELAY: + return RTP_OK; + + case ZRTP_MSG_RELAY_ACK: + return RTP_OK; + + case ZRTP_MSG_PING_ACK: + return RTP_OK; + + /* TODO: goclear & co-opeartion with srtp */ + } +} #endif diff --git a/src/pkt_dispatch.cc b/src/pkt_dispatch.cc index a47ada4..49a8d02 100644 --- a/src/pkt_dispatch.cc +++ b/src/pkt_dispatch.cc @@ -52,7 +52,14 @@ std::vector& uvg_rtp::pkt_dispatcher::get_handlers() * For example, if runner detects an incoming ZRTP packet, that packet is immediately dispatched to the * installed ZRTP handler if ZRTP has been enabled. * Likewise, if RTP packet authentication has been enabled, runner validates the packet before passing - * it onto any other layer so all future work on the packet is not done in vain due to invalid data */ + * it onto any other layer so all future work on the packet is not done in vain due to invalid data + * + * One piece of design choice that complicates the design of packet dispatcher a little is that the order + * of handlers is important. First handler must be ZRTP and then follows SRTP, RTP and finally media handlers. + * This requirement gives packet handler a clean and generic interface while giving a possibility to modify + * the packet in each of the called handlers if needed. For example SRTP handler verifies RTP authentication + * tag and decrypts the packet and RTP handler verifies the fields of the RTP packet and processes it into + * a more easily modifiable format for the media handler. */ static void runner(uvg_rtp::pkt_dispatcher *dispatcher, uvg_rtp::socket& socket) { int nread; @@ -90,13 +97,18 @@ static void runner(uvg_rtp::pkt_dispatcher *dispatcher, uvg_rtp::socket& socket) switch ((ret = (*handler)(nread, recv_buffer))) { /* packet was handled successfully or the packet was in some way corrupted */ case RTP_OK: - case RTP_GENERIC_ERROR: break; - /* the received packet is not handled by the called handler */ + /* the received packet is not handled at all or only partially by the called handler + * proceed to the next handler */ case RTP_PKT_NOT_HANDLED: + case RTP_PKT_MODIFIED: continue; + case RTP_GENERIC_ERROR: + LOG_DEBUG("Received a corrputed packet!"); + break; + default: LOG_ERROR("Unknown error code from packet handler: %d", ret); break;