Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F7159119
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
84 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/deps/pjsip/pjmedia/build/Makefile b/deps/pjsip/pjmedia/build/Makefile
index f9d7cddd..ee621f7f 100644
--- a/deps/pjsip/pjmedia/build/Makefile
+++ b/deps/pjsip/pjmedia/build/Makefile
@@ -1,231 +1,231 @@
include ../../build.mak
include ../../version.mak
THIRD_PARTY:=$(PJDIR)/third_party
SRTP_INC=$(CC_INC)$(THIRD_PARTY)/build/srtp \
$(CC_INC)$(THIRD_PARTY)/srtp/crypto/include \
$(CC_INC)$(THIRD_PARTY)/srtp/include
include $(PJDIR)/build/common.mak
RULES_MAK := $(PJDIR)/build/rules.mak
PJLIB_LIB:=$(PJDIR)/pjlib/lib/libpj-$(TARGET_NAME)$(LIBEXT)
PJLIB_UTIL_LIB:=$(PJDIR)/pjlib-util/lib/libpjlib-util-$(TARGET_NAME)$(LIBEXT)
PJNATH_LIB:=$(PJDIR)/pjnath/lib/libpjnath-$(TARGET_NAME)$(LIBEXT)
export PJMEDIA_LIB:=../lib/libpjmedia-$(TARGET_NAME)$(LIBEXT)
export PJMEDIA_CODEC_LIB:=../lib/libpjmedia-codec-$(TARGET_NAME)$(LIBEXT)
export PJSDP_LIB:=../lib/libpjsdp-$(TARGET_NAME)$(LIBEXT)
export PJMEDIA_AUDIODEV_LIB:=../lib/libpjmedia-audiodev-$(TARGET_NAME)$(LIBEXT)
export PJMEDIA_VIDEODEV_LIB:=../lib/libpjmedia-videodev-$(TARGET_NAME)$(LIBEXT)
###############################################################################
# Gather all flags.
#
export _CFLAGS := $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \
$(CFLAGS) $(CC_INC)../include \
$(CC_INC)../../pjlib/include \
$(CC_INC)../../pjlib-util/include \
$(CC_INC)../../pjmedia/include \
$(CC_INC)../../pjnath/include \
$(CC_INC)../.. \
$(SRTP_INC)
export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \
$(HOST_CXXFLAGS) $(CXXFLAGS)
export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJMEDIA_VIDEODEV_LIB)) \
$(subst /,$(HOST_PSEP),$(PJMEDIA_CODEC_LIB)) \
$(subst /,$(HOST_PSEP),$(PJMEDIA_LIB)) \
$(subst /,$(HOST_PSEP),$(PJMEDIA_AUDIODEV_LIB)) \
$(subst /,$(HOST_PSEP),$(PJLIB_LIB)) \
$(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \
$(subst /,$(HOST_PSEP),$(PJNATH_LIB)) \
-L$(PJDIR)/third_party/lib \
$(APP_THIRD_PARTY_LIBS) \
$(APP_THIRD_PARTY_EXT) \
$(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \
$(LDFLAGS)
###############################################################################
# Defines for building PJMEDIA library
#
export PJMEDIA_SRCDIR = ../src/pjmedia
export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
alaw_ulaw.o alaw_ulaw_table.o avi_player.o \
bidirectional.o clock_thread.o codec.o conference.o \
conf_switch.o converter.o converter_libswscale.o converter_libyuv.o \
delaybuf.o echo_common.o \
echo_port.o echo_suppress.o endpoint.o errno.o \
event.o format.o ffmpeg_util.o \
g711.o jbuf.o master_port.o mem_capture.o mem_player.o \
mixer_port.o null_port.o plc_common.o port.o splitcomb.o \
resample_resample.o resample_libsamplerate.o \
resample_port.o rtcp.o rtcp_xr.o rtp.o \
sdp.o sdp_cmp.o sdp_neg.o session.o silencedet.o \
sound_legacy.o sound_port.o stereo_port.o stream_common.o \
stream.o stream_info.o tonegen.o transport_adapter_sample.o \
- transport_ice.o transport_loop.o transport_srtp.o transport_udp.o \
+ transport_ice.o transport_loop.o transport_srtp.o transport_zrtp.o transport_udp.o \
types.o vid_codec.o vid_codec_util.o \
vid_port.o vid_stream.o vid_stream_info.o vid_tee.o \
wav_player.o wav_playlist.o wav_writer.o wave.o \
wsola.o
export PJMEDIA_CFLAGS += $(_CFLAGS)
###############################################################################
# Defines for building PJMEDIA-AUDIODEV library
#
export PJMEDIA_AUDIODEV_SRCDIR = ../src/pjmedia-audiodev
export PJMEDIA_AUDIODEV_OBJS += audiodev.o audiotest.o errno.o \
legacy_dev.o null_dev.o wmme_dev.o \
alsa_dev.o bb10_dev.o bdimad_dev.o \
android_jni_dev.o opensl_dev.o
export PJMEDIA_AUDIODEV_CFLAGS += $(_CFLAGS)
###############################################################################
# Defines for building PJMEDIA-VIDEODEV library
#
export PJMEDIA_VIDEODEV_SRCDIR = ../src/pjmedia-videodev
export PJMEDIA_VIDEODEV_OBJS += errno.o videodev.o avi_dev.o ffmpeg_dev.o \
colorbar_dev.o v4l2_dev.o opengl_dev.o fb_dev.o null_dev.o
export PJMEDIA_VIDEODEV_CFLAGS += $(_CFLAGS)
export PJMEDIA_VIDEODEV_CXXFLAGS += $(_CXXFLAGS)
###############################################################################
# Defines for building PJSDP library
# Note that SDP functionality is already INCLUDED in PJMEDIA.
# The PJSDP library should only be used for applications that want SDP
# but don't want to use the rest of the media framework.
#
export PJSDP_SRCDIR = ../src/pjmedia
export PJSDP_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
errno.o sdp.o sdp_cmp.o sdp_neg.o
export PJSDP_CFLAGS += $(_CFLAGS)
###############################################################################
# Defines for building PJMEDIA-Codec library
#
export PJMEDIA_CODEC_SRCDIR = ../src/pjmedia-codec
export PJMEDIA_CODEC_OBJS += audio_codecs.o ffmpeg_vid_codecs.o openh264.o \
h263_packetizer.o h264_packetizer.o \
$(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
ipp_codecs.o silk.o $(CODEC_OBJS) \
g7221_sdp_match.o amr_sdp_match.o
export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
$(ILBC_CFLAGS) $(IPP_CFLAGS) $(G7221_CFLAGS)
export PJMEDIA_CODEC_CXXFLAGS += $(_CXXFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
$(ILBC_CFLAGS) $(IPP_CFLAGS) $(G7221_CFLAGS)
###############################################################################
# Defines for building test application
#
export PJMEDIA_TEST_SRCDIR = ../src/test
export PJMEDIA_TEST_OBJS += codec_vectors.o jbuf_test.o main.o mips_test.o \
vid_codec_test.o vid_dev_test.o vid_port_test.o \
rtp_test.o test.o
export PJMEDIA_TEST_OBJS += sdp_neg_test.o
export PJMEDIA_TEST_CFLAGS += $(_CFLAGS)
export PJMEDIA_TEST_LDFLAGS += $(_LDFLAGS)
export PJMEDIA_TEST_EXE:=../bin/pjmedia-test-$(TARGET_NAME)$(HOST_EXE)
export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
###############################################################################
# Main entry
#
# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory.
#
TARGETS := pjmedia pjmedia-videodev pjmedia-audiodev pjmedia-codec pjsdp
all: $(TARGETS)
doc:
cd .. && rm -rf docs/$(PJ_VERSION) && doxygen docs/doxygen.cfg
@if [ -n "$(WWWDIR)" ] && ! [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html" ] ; then \
echo "Creating docs/$(PJ_VERSION)/pjmedia/docs/html" ; \
mkdir -p $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html ; \
fi
@if [ -n "$(WWWDIR)" ] && [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html" ] ; then \
echo "Copying docs/$(PJ_VERSION) to $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html.." ; \
cp -v -a ../docs/$(PJ_VERSION)/html/* $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html/ ; \
fi
dep: depend
distclean: realclean
.PHONY: dep depend pjmedia pjmedia-codec pjmedia-videodev pjmedia-audiodev pjmedia-test clean realclean distclean
pjmedia:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $(PJMEDIA_LIB)
pjmedia-codec:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_CODEC app=pjmedia-codec $(PJMEDIA_CODEC_LIB)
pjmedia-videodev:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $(PJMEDIA_VIDEODEV_LIB)
pjmedia-audiodev:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $(PJMEDIA_AUDIODEV_LIB)
pjsdp:
$(MAKE) -f $(RULES_MAK) APP=PJSDP app=pjsdp $(PJSDP_LIB)
$(PJMEDIA_LIB): pjmedia
pjmedia-test: $(PJMEDIA_LIB) pjmedia
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $(PJMEDIA_TEST_EXE)
.PHONY: ../lib/pjmedia.ko
../lib/pjmedia.ko:
echo Making $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $@
.PHONY: ../lib/pjmedia-codec.ko
../lib/pjmedia-codec.ko:
echo Making $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_CODEC app=pjmedia-codec $@
.PHONY: ../lib/pjmedia-test.ko
../lib/pjmedia-test.ko:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $@
clean:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_CODEC app=pjmedia-codec $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $@
$(MAKE) -f $(RULES_MAK) APP=PJSDP app=pjsdp $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $@
realclean:
$(subst @@,$(subst /,$(HOST_PSEP),.pjmedia-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjmedia-videodev-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjmedia-audiodev-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjmedia-codec-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjmedia-test-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),.pjsdp-$(TARGET_NAME).depend),$(HOST_RMR))
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_CODEC app=pjmedia-codec $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $@
$(MAKE) -f $(RULES_MAK) APP=PJSDP app=pjsdp $@
depend:
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_CODEC app=pjmedia-codec $@
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $@
$(MAKE) -f $(RULES_MAK) APP=PJSDP app=pjsdp $@
echo '$(PJMEDIA_TEST_EXE): $(PJMEDIA_LIB) $(PJMEDIA_CODEC_LIB) $(PJNATH_LIB) $(PJLIB_UTIL_LIB) $(PJLIB_LIB)' >> .pjmedia-test-$(TARGET_NAME).depend
diff --git a/deps/pjsip/pjmedia/include/pjmedia.h b/deps/pjsip/pjmedia/include/pjmedia.h
index fa8a23e8..4c019dc4 100644
--- a/deps/pjsip/pjmedia/include/pjmedia.h
+++ b/deps/pjsip/pjmedia/include/pjmedia.h
@@ -1,82 +1,83 @@
/* $Id: pjmedia.h 3664 2011-07-19 03:42:28Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PJMEDIA_H__
#define __PJMEDIA_H__
/**
* @file pjmedia.h
* @brief PJMEDIA main header file.
*/
#include <pjmedia/alaw_ulaw.h>
#include <pjmedia/avi_stream.h>
#include <pjmedia/bidirectional.h>
#include <pjmedia/circbuf.h>
#include <pjmedia/clock.h>
#include <pjmedia/codec.h>
#include <pjmedia/conference.h>
#include <pjmedia/converter.h>
#include <pjmedia/delaybuf.h>
#include <pjmedia/echo.h>
#include <pjmedia/echo_port.h>
#include <pjmedia/endpoint.h>
#include <pjmedia/errno.h>
#include <pjmedia/event.h>
#include <pjmedia/frame.h>
#include <pjmedia/format.h>
#include <pjmedia/g711.h>
#include <pjmedia/jbuf.h>
#include <pjmedia/master_port.h>
#include <pjmedia/mem_port.h>
#include <pjmedia/mixer_port.h>
#include <pjmedia/null_port.h>
#include <pjmedia/plc.h>
#include <pjmedia/port.h>
#include <pjmedia/resample.h>
#include <pjmedia/rtcp.h>
#include <pjmedia/rtcp_xr.h>
#include <pjmedia/rtp.h>
#include <pjmedia/sdp.h>
#include <pjmedia/sdp_neg.h>
//#include <pjmedia/session.h>
#include <pjmedia/silencedet.h>
#include <pjmedia/sound.h>
#include <pjmedia/sound_port.h>
#include <pjmedia/splitcomb.h>
#include <pjmedia/stereo.h>
#include <pjmedia/stream.h>
#include <pjmedia/stream_common.h>
#include <pjmedia/tonegen.h>
#include <pjmedia/transport.h>
#include <pjmedia/transport_adapter_sample.h>
#include <pjmedia/transport_ice.h>
#include <pjmedia/transport_loop.h>
#include <pjmedia/transport_srtp.h>
+#include <pjmedia/transport_zrtp.h>
#include <pjmedia/transport_udp.h>
#include <pjmedia/vid_port.h>
#include <pjmedia/vid_codec.h>
#include <pjmedia/vid_stream.h>
#include <pjmedia/vid_tee.h>
#include <pjmedia/wav_playlist.h>
#include <pjmedia/wav_port.h>
#include <pjmedia/wave.h>
#include <pjmedia/wsola.h>
#endif /* __PJMEDIA_H__ */
diff --git a/deps/pjsip/pjmedia/include/pjmedia/transport_zrtp.h b/deps/pjsip/pjmedia/include/pjmedia/transport_zrtp.h
new file mode 100644
index 00000000..4a32bd4d
--- /dev/null
+++ b/deps/pjsip/pjmedia/include/pjmedia/transport_zrtp.h
@@ -0,0 +1,647 @@
+/* $Id$ */
+/*
+ Copyright (C) 2010 Werner Dittmann
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PJMEDIA_TRANSPORT_ZRTP_H__
+#define __PJMEDIA_TRANSPORT_ZRTP_H__
+
+/**
+ * @file transport_zrtp.h
+ * @brief ZRTP Media Transport Adapter
+ */
+
+/* transport.h includes types.h -> config.h -> config_auto.h */
+#include <pjmedia/transport.h>
+
+#include "../../third_party/zsrtp/zrtp/zrtp/libzrtpcpp/ZrtpCWrapper.h"
+
+/**
+ * @defgroup PJMEDIA_TRANSPORT_ZRTP ZRTP Transport Adapter
+ * @brief This the ZRTP transport adapter.
+ * @{
+ *
+ * PJMEDIA extension to support GNU ZRTP.
+ *
+ * ZRTP was developed by Phil Zimmermann and provides functions to
+ * negotiate keys and other necessary data (crypto data) to set-up
+ * the Secure RTP (SRTP) crypto context. Refer to Phil's ZRTP
+ * specification at his <a href="http://zfoneproject.com/">Zfone
+ * project</a> site to get more detailed information about the
+ * capabilities of ZRTP.
+ *
+ * <b>Short overview of the ZRTP implementation</b>
+ *
+ * ZRTP is a specific protocol to negotiate encryption algorithms
+ * and the required key material. ZRTP uses a RTP session to
+ * exchange its protocol messages. Thus ZRTP is independent of any
+ * signaling protocol like SIP, XMPP and alike.
+ *
+ * A complete GNU ZRTP implementation consists of two parts, the
+ * GNU ZRTP core and some specific code that binds the GNU ZRTP core to
+ * the underlying RTP/SRTP stack and the operating system:
+ * <ul>
+ * <li>
+ * The GNU ZRTP core is independent of a specific RTP/SRTP
+ * stack and the operationg system and consists of the ZRTP
+ * protocol state engine, the ZRTP protocol messages, and the
+ * GNU ZRTP engine. The GNU ZRTP engine provides methods to
+ * setup ZRTP message and to analyze received ZRTP messages,
+ * to compute the crypto data required for SRTP, and to
+ * maintain the required hashes and HMAC.
+ * </li>
+ * <li>
+ * The second part of an implementation is specific
+ * <em>glue</em> code the binds the GNU ZRTP core to the
+ * actual RTP/SRTP implementation and other operating system
+ * specific services such as timers, mutexes.
+ * </li>
+ * </ul>
+ *
+ * The GNU ZRTP core uses callback methods (refer to
+ * zrtp_Callback) to access RTP/SRTP or operating specific methods,
+ * for example to send data via the RTP stack, to access
+ * timers, provide mutex handling, and to report events to the
+ * application.
+ *
+ * <b>The PJMEDIA ZRTP transport</b>
+ *
+ * ZRTP transport implements code that is specific to the pjmedia
+ * implementation. ZRTP transport also implements the specific code to
+ * provide the mutex and timeout handling to the GNU ZRTP
+ * core. Both, the mutex and the timeout handling, use the pjlib
+ * library to stay independent of the operating
+ * seystem.
+ *
+ * To perform its tasks ZRTP transport
+ * <ul>
+ * <li> implements the pjmedia transport functions and callbacks.
+ * </li>
+ * <li> implements the zrtp_Callbacks methods to provide
+ * access and other specific services (timer, mutex) to GNU
+ * ZRTP
+ * </li>
+ * <li> provides ZRTP specific methods that applications may use
+ * to control and setup GNU ZRTP
+ * </li>
+ * <li> can register and use an application specific callback
+ * class (refer to zrtp_UserCallbacks)
+ * </li>
+ * </ul>
+ *
+ * After instantiating a GNU ZRTP session (see below for a short
+ * example) applications may use the methods of
+ * ZRTP transport and the ZRTP engine to control and setup GNU ZRTP,
+ * for example enable or disable ZRTP processing or getting ZRTP status
+ * information.
+ *
+ * GNU ZRTP defines zrtp_UserCallback methods structure that an application
+ * may use and register with ZRTP transport. GNU ZRTP and ZRTP transport
+ * use the zrtp_UserCallback methods to report ZRTP events to the
+ * application. The application may display this information to
+ * the user or act otherwise.
+ *
+ * The following figure depicts the relationships between
+ * ZRTP transport, pjmedia RTP implementation, the GNU ZRTP core,
+ * SRTP and an application that provides zrtp_UserCallback methods.
+ *
+ @verbatim
+ +-----------+
+ | |
+ | SRTP-ZRTP |
+ | |
+ +-----------+
+ |C Wrapper |
+ +-----+-----+
+ |
+ | uses
+ |
+ +-----------------+ +-------+--------+ +-+-----------------+
+ | App (pjsua) | | | |C| |
+ | creates a | uses | transport_zrtp | uses | | GNU ZRTP |
+ | ZRTP transport +------+ implements +------+W| core |
+ | and implements | | zrtp_Callback | |r| implementation |
+ |zrtp_UserCallback| | | |a| (ZRtp et al) |
+ +-----------------+ +----------------+ |p| |
+ +-+-----------------+
+
+@endverbatim
+ *
+ * The following short code snippet shows how to use ZRTP transport
+ *
+ * @code
+ *
+ * #include <pjmedia/transport_zrtp.h>
+ * ...
+ * // Create media transport
+ * status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
+ * 0, &transport);
+ * if (status != PJ_SUCCESS)
+ * return status;
+ *
+ * status = pjmedia_transport_zrtp_create(med_endpt, NULL, transport,
+ * &zrtp_tp);
+ * app_perror(THIS_FILE, "Error creating zrtp", status);
+ * transport = zrtp_tp;
+ * if (dir == PJMEDIA_DIR_ENCODING)
+ * pjmedia_transport_zrtp_initialize(transport, "testenc.zid", 1, NULL);
+ * else
+ * pjmedia_transport_zrtp_initialize(transport, "testdec.zid", 1, NULL);
+ * ...
+ * @endcode
+ *
+ */
+
+#define PJMEDIA_TRANSPORT_TYPE_ZRTP PJMEDIA_TRANSPORT_TYPE_USER+2
+
+PJ_BEGIN_DECL
+
+/**
+ * ZRTP option.
+ */
+typedef enum pjmedia_zrtp_use
+{
+ /** When this flag is specified, ZRTP will be disabled. */
+ PJMEDIA_NO_ZRTP = 1,
+
+ /** When this flag is specified, PJSUA-LIB creates a ZRTP transport
+ * call calls back the applicaion for further process if callback is
+ * set.
+ */
+ PJMEDIA_CREATE_ZRTP = 2
+
+} pjmedia_zrtp_use;
+
+/**
+ * This structure specifies ZRTP transport specific info. This will fit
+ * into \a buffer field of pjmedia_transport_specific_info.
+ */
+typedef struct pjmedia_zrtp_info
+{
+ /**
+ * Specify whether the ZRTP transport is active for this session.
+ */
+ pj_bool_t active;
+
+ /**
+ * Specify the cipher being used.
+ */
+ char cipher[128];
+
+} pjmedia_zrtp_info;
+
+/**
+ * Application callback methods.
+ *
+ * The RTP stack specific part of GNU ZRTP uses these callback methods
+ * to report ZRTP events to the application. Thus the application that
+ * instantiates the RTP stack shall implement these methods and show these
+ * inforemation to the user.
+ *
+ * <b>CAVEAT</b><br/>
+ * All user callback methods run in the context of the RTP thread. Thus
+ * it is of paramount importance to keep the execution time of the methods
+ * as short as possible.
+ *
+ * @author Werner Dittmann <Werner.Dittmann@t-online.de>
+ */
+typedef struct pjmedia_zrtp_cb
+{
+ /**
+ * Inform user interface that security is active now.
+ *
+ * ZRTP calls this method if the sender and the receiver are
+ * in secure mode now.
+ *
+ * @param cipher
+ * Name and mode of cipher used to encrypt the SRTP stream
+ */
+ void (*secure_on)(pjmedia_transport *tp, char* cipher);
+
+ /**
+ * Inform user interface that security is not active any more.
+ *
+ * ZRTP calls this method if either the sender or the receiver
+ * left secure mode.
+ *
+ */
+ void (*secure_off)(pjmedia_transport *tp);
+
+ /**
+ * Show the Short Authentication String (SAS) on user interface.
+ *
+ * ZRTP calls this method to display the SAS and inform about the SAS
+ * verification status. The user interface shall enable a SAS verfication
+ * button (or similar UI element). The user shall click on this UI
+ * element after he/she confirmed the SAS code with the partner.
+ *
+ * @param sas
+ * The string containing the SAS.
+ * @param verified
+ * If <code>verified</code> is true then SAS was verified by both
+ * parties during a previous call, otherwise it is set to false.
+ */
+ void (*show_sas)(pjmedia_transport *tp, char* sas, int32_t verified);
+
+ /**
+ * Inform the user that ZRTP received "go clear" message from its peer.
+ *
+ * On receipt of a go clear message the user is requested to confirm
+ * a switch to unsecure (clear) modus. Until the user confirms ZRTP
+ * (and the underlying RTP) does not send any data.
+ *
+ */
+ void (*confirm_go_clear)(pjmedia_transport *tp);
+
+ /**
+ * Show some information to user.
+ *
+ * ZRTP calls this method to display some information to the user.
+ * Along with the message ZRTP provides a severity indicator that
+ * defines: Info, Warning, Error, and Alert. Refer to the <code>
+ * MessageSeverity</code> enum in <code>ZrtpCodes.h</code>. The
+ * UI may use this indicator to highlight messages or alike.
+ *
+ * @param sev
+ * Severity of the message.
+ * @param subCode
+ * The subcode identifying the reason.
+ */
+ void (*show_message)(pjmedia_transport *tp, int32_t sev, int32_t subCode);
+
+ /**
+ * ZRTP transport calls this if the negotiation failed.
+ *
+ * ZRTPQueue calls this method in case ZRTP negotiation failed. The
+ * parameters show the severity as well as some explanatory text.
+ * Refer to the <code>MessageSeverity</code> enum above.
+ *
+ * @param severity
+ * This defines the message's severity
+ * @param subCode
+ * The subcode identifying the reason.
+ */
+ void (*negotiation_failed)(pjmedia_transport *tp, int32_t severity, int32_t subCode);
+
+ /**
+ * ZRTP transport calls this method if the other side does not support ZRTP.
+ *
+ * If the other side does not answer the ZRTP <em>Hello</em> packets then
+ * ZRTP calls this method.
+ *
+ */
+ void (*not_supported_by_other)(pjmedia_transport *tp);
+
+ /**
+ * ZRTP transport calls this method to inform about a PBX enrollment request.
+ *
+ * Please refer to chapter 8.3 ff to get more details about PBX enrollment
+ * and SAS relay.
+ *
+ * @param info
+ * Give some information to the user about the PBX requesting an
+ * enrollment.
+ */
+ void (*ask_enrollment)(pjmedia_transport *tp, int32_t info);
+
+ /**
+ * ZRTP transport calls this method to inform about PBX enrollment result.
+ *
+ * Informs the use about the acceptance or denial of an PBX enrollment
+ * request
+ *
+ * @param info
+ * Give some information to the user about the result of an
+ * enrollment.
+ */
+ void (*inform_enrollment)(pjmedia_transport *tp, int32_t info);
+
+ /**
+ * ZRTP transport calls this method to request a SAS signature.
+ *
+ * After ZRTP core was able to compute the Short Authentication String
+ * (SAS) it calls this method. The client may now use an approriate
+ * method to sign the SAS. The client may use
+ * setSignatureData() of ZrtpQueue to store the signature
+ * data an enable signature transmission to the other peer. Refer
+ * to chapter 8.2 of ZRTP specification.
+ *
+ * @param sas
+ * The SAS string to sign.
+ * @see ZrtpQueue#setSignatureData
+ *
+ */
+ void (*sign_sas)(pjmedia_transport *tp, uint8_t* sas);
+
+ /**
+ * ZRTP transport calls this method to request a SAS signature check.
+ *
+ * After ZRTP received a SAS signature in one of the Confirm packets it
+ * call this method. The client may use <code>getSignatureLength()</code>
+ * and <code>getSignatureData()</code>of ZrtpQueue to get the signature
+ * data and perform the signature check. Refer to chapter 8.2 of ZRTP
+ * specification.
+ *
+ * If the signature check fails the client may return false to ZRTP. In
+ * this case ZRTP signals an error to the other peer and terminates
+ * the ZRTP handshake.
+ *
+ * @param sas
+ * The SAS string that was signed by the other peer.
+ * @return
+ * true if the signature was ok, false otherwise.
+ *
+ */
+ int32_t (*check_sas_signature)(pjmedia_transport *tp, uint8_t* sas);
+} pjmedia_zrtp_cb;
+
+
+/**
+ * Create the transport adapter, specifying the underlying transport to be
+ * used to send and receive RTP/RTCP packets.
+ *
+ * @param endpt The media endpoint.
+ * @param timer_heap The heap where timers will be scheduled.
+ * @param transport The underlying media transport to send and receive
+ * RTP/RTCP packets.
+ * @param p_tp Pointer to receive the media transport instance.
+ *
+ * @param close_slave
+ * Close the slave transport on transport_destroy. PJSUA-LIB
+ * sets this to PJ_FALSE because it takes care of this.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_zrtp_create( pjmedia_endpt *endpt,
+ pj_timer_heap_t *timer_heap,
+ pjmedia_transport *transport,
+ pjmedia_transport **p_tp,
+ pj_bool_t close_slave);
+
+/*
+ * Implement the specific ZRTP transport functions
+ */
+
+/**
+ * Initialize the ZRTP transport.
+ *
+ * Before an application can use ZRTP it has to initialize the
+ * ZRTP implementation. This method opens a file that contains ZRTP specific
+ * information such as the applications ZID (ZRTP id) and its
+ * retained shared secrets.
+ *
+ * Before an application initializes the ZRTP it may use ZRTP functions
+ * to set specific configuration data. See the relevant documentation
+ * in @c ZrtpCWrapper.h . The application can peform this after
+ * it created transport_zrtp.
+ *
+ * If one application requires several ZRTP sessions all
+ * sessions use the same timeout thread and use the same ZID
+ * file. Therefore an application does not need to do any
+ * synchronisation regading ZID files or timeouts. This is
+ * managed by the ZRTP implementation.
+ *
+ * The current implementation of ZRTP transport does not support
+ * different ZID files for one application instance. This
+ * restriction may be removed in later versions.
+ *
+ * The application may specify its own ZID file name. If no
+ * ZID file name is specified it defaults to
+ * <code>$HOME/.GNUccRTP.zid</code> if the <code>HOME</code>
+ * environment variable is set. If it is not set the current
+ * directory is used.
+ *
+ * If the method could set up the timeout thread and open the ZID
+ * file then it enables ZRTP processing and returns.
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ * @param zidFilename
+ * The name of the ZID file, can be a relative or absolut
+ * filename.
+ *
+ * @param autoEnable
+ * if set to true the method automatically sets enableZrtp to
+ * true. This enables the ZRTP auto-sense mode.
+ *
+ * @param zrtp_cb
+ * Pointer the application's ZRTP callbacks structure. Setting
+ * a NULL switches off the user callbacks
+ * @return
+ * PJ_SUCCESS on success, ZRTP processing enabled, other codes
+ * leave ZRTP processing disabled.
+ *
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_zrtp_initialize(pjmedia_transport *tp,
+ const char *zidFilename,
+ pj_bool_t autoEnable,
+ pjmedia_zrtp_cb *zrtp_cb);
+/**
+ * Enable or disable ZRTP processing.
+ *
+ * Call this method to enable or disable ZRTP processing after
+ * calling <code>pjmedia_transport_zrtp_initialize</code> with the
+ * parameter @c autoEnable set to false. This can be done before
+ * using a RTP session or at any time during a RTP session.
+ *
+ * Existing SRTP sessions or currently active ZRTP processing will
+ * not be stopped or disconnected.
+ *
+ * If the application enables ZRTP then:
+ * <ul>
+ * <li>ZRTP transport starts to send ZRTP Hello packets after at least
+ * one RTP packet was sent and received on the associated RTP
+ * session. Thus if an application enables ZRTP and ZRTP transport
+ * detects traffic on the RTP session then ZRTP transport automatically
+ * starts the ZRTP protocol. This automatic start is convenient
+ * for applications that negotiate RTP parameters and set up RTP
+ * sessions but the actual RTP traffic starts some time later.
+ * </li>
+ * <li>ZRTP transport analyses incoming packets to detect ZRTP
+ * messages. If ZRTP was started, either via automatic start (see
+ * above) or explicitly via @c zrtp_startZrtp, then ZrtpQueue
+ * forwards ZRTP packets to the GNU ZRTP core.
+ * </ul>
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ * @param onOff
+ * @c 1 to enable ZRTP, @c 0 to disable ZRTP
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_setEnableZrtp(pjmedia_transport *tp, pj_bool_t onOff);
+
+/**
+ * Return the state of ZRTP enable state.
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ * @return @c true if ZRTP processing is enabled, @c false
+ * otherwise.
+ */
+PJ_DECL(pj_bool_t) pjmedia_transport_zrtp_isEnableZrtp(pjmedia_transport *tp);
+
+/**
+ * Starts the ZRTP protocol engine.
+ *
+ * Applications may call this method to immediatly start the ZRTP protocol
+ * engine any time after initializing ZRTP and setting optinal parameters,
+ * for example client id or multi-stream parameters.
+ *
+ * If the application does not call this method but sucessfully initialized
+ * the ZRTP engine using @c pjmedia_transport_zrtp_initialize then ZRTP may
+ * also start, depending on the autoEnable parameter.
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ * @see pjmedia_transport_zrtp_initialize
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_startZrtp(pjmedia_transport *tp);
+
+/**
+ * Stops the ZRTP protocol engine.
+ *
+ * Applications call this method to stop the ZRTP protocol
+ * engine. The ZRTP transport can not start or process any ZRTP
+ * negotiations.
+ *
+ * This call does not deactivate SRTP processing of ZRTP transport, thus
+ * the ZRTP transport still encrypts/decrypts data via SRTP.
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_stopZrtp(pjmedia_transport *tp);
+
+/**
+ * Set the local SSRC in case of receive-only sessions.
+ *
+ * Receiver-only RTP sessions never send RTP packets, thus ZRTP cannot learn
+ * the local (sender) SSRC. ZRTP requires the SSRC to bind the RTP session
+ * to the SRTP and its handshake. In this case the application shall generate
+ * a SSRC value and set it.
+ *
+ * Usually an application knows if a specific RTP session is receive-only, for
+ * example by inspecting and parsing the SDP data.
+ *
+ * If the application later decides to switch this RTP session to full-duplex
+ * mode (send and receive) it shall use the generated SSRC to intialize the
+ * RTP session. Then the outgoing packets are encrypted by SRTP.
+ *
+ * @param tp
+ * Pointer to the ZRTP transport data as returned by
+ * @c pjmedia_transport_zrtp_create.
+ *
+ * @param ssrc
+ * The local ssrc value in host order.
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_setLocalSSRC(pjmedia_transport *tp, uint32_t ssrc);
+
+/**
+ * Check the state of the MitM mode flag.
+ *
+ * If true then this ZRTP session acts as MitM, usually enabled by a PBX
+ * client (user agent)
+ *
+ * @return state of mitmMode
+ */
+PJ_DECL(pj_bool_t) pjmedia_transport_zrtp_isMitmMode(pjmedia_transport *tp);
+
+/**
+ * Set the state of the MitM mode flag.
+ *
+ * If MitM mode is set to true this ZRTP session acts as MitM, usually
+ * enabled by a PBX client (user agent).
+ *
+ * @param mitmMode defines the new state of the mitmMode flag
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_setMitmMode(pjmedia_transport *tp, pj_bool_t mitmMode);
+
+/**
+ * Set / reset the SAS verification flag.
+ *
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_setSASVerified(pjmedia_transport *tp, pj_bool_t verified);
+
+/**
+ * Get the peer's ZID.
+ *
+ */
+PJ_DECL(int) pjmedia_transport_zrtp_getPeerZid(pjmedia_transport *tp, unsigned char* data);
+
+/**
+ * Get the peer's name.
+ *
+ */
+PJ_DECL(char*) pjmedia_transport_zrtp_getPeerName(pjmedia_transport *tp);
+
+/**
+ * Set the peer's name.
+ *
+ */
+PJ_DECL(void) pjmedia_transport_zrtp_putPeerName(pjmedia_transport *tp, const char *name);
+
+
+PJ_DECL(char*) pjmedia_transport_zrtp_getMultiStreamParameters(pjmedia_transport *tp, pj_int32_t *length);
+
+PJ_DECL(void) pjmedia_transport_zrtp_setMultiStreamParameters(pjmedia_transport *tp, const char *parameters, pj_int32_t length, pjmedia_transport *master_tp);
+
+/**
+ * Get the ZRTP context pointer.
+ *
+ * Appplications need the ZRTP context pointer if they call ZRTP specific
+ * methods. The ZRTP specific include file @c ZrtpCWrapper contains the
+ * descriptions of the ZRTP methods.
+ *
+ * @return Pointer to ZRTP context
+ *
+ * @see zrtp_setAuxSecret()
+ * @see zrtp_setPbxSecret()
+ * @see zrtp_inState()
+ * @see zrtp_SASVerified()
+ * @see zrtp_resetSASVerified()
+ * @see zrtp_getHelloHash()
+ * @see zrtp_getMultiStrParams()
+ * @see zrtp_setMultiStrParams()
+ * @see zrtp_isMultiStream()
+ * @see zrtp_isMultiStreamAvailable()
+ * @see zrtp_acceptEnrollment()
+ * @see zrtp_setSignatureData()
+ * @see zrtp_getSignatureData()
+ * @see zrtp_getSignatureLength()
+ * @see zrtp_getZid();
+ */
+PJ_DECL(ZrtpContext*) pjmedia_transport_zrtp_getZrtpContext(pjmedia_transport *tp);
+
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
+#endif /* __PJMEDIA_TRANSPORT_ADAPTER_SAMPLE_H__ */
+
+
diff --git a/deps/pjsip/pjmedia/src/pjmedia/transport_zrtp.c b/deps/pjsip/pjmedia/src/pjmedia/transport_zrtp.c
new file mode 100644
index 00000000..4c2f40fc
--- /dev/null
+++ b/deps/pjsip/pjmedia/src/pjmedia/transport_zrtp.c
@@ -0,0 +1,1258 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2010 Werner Dittmann
+ * This is the pjmedia ZRTP transport module.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <pjmedia/transport_zrtp.h>
+#include <pjmedia/endpoint.h>
+#include <pjlib.h>
+#include <pjlib-util.h>
+
+#include "../../third_party/zsrtp/include/ZsrtpCWrapper.h"
+
+#define THIS_FILE "transport_zrtp.c"
+
+#define MAX_RTP_BUFFER_LEN PJMEDIA_MAX_MTU
+#define MAX_RTCP_BUFFER_LEN PJMEDIA_MAX_MTU
+
+
+/* Transport functions prototypes */
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+ pjmedia_transport_info *info);
+static pj_status_t transport_attach(pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ void*,
+ pj_ssize_t));
+static void transport_detach(pjmedia_transport *tp,
+ void *strm);
+static pj_status_t transport_send_rtp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_media_stop(pjmedia_transport *tp);
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+ pjmedia_dir dir,
+ unsigned pct_lost);
+static pj_status_t transport_destroy(pjmedia_transport *tp);
+
+
+/* The transport operations */
+static struct pjmedia_transport_op tp_zrtp_op =
+{
+ &transport_get_info,
+ &transport_attach,
+ &transport_detach,
+ &transport_send_rtp,
+ &transport_send_rtcp,
+ &transport_send_rtcp2,
+ &transport_media_create,
+ &transport_encode_sdp,
+ &transport_media_start,
+ &transport_media_stop,
+ &transport_simulate_lost,
+ &transport_destroy
+};
+
+/* The transport zrtp instance */
+struct tp_zrtp
+{
+ pjmedia_transport base;
+ pj_pool_t *pool;
+
+ /* Stream information. */
+ void *stream_user_data;
+ void (*stream_rtp_cb)(void *user_data,
+ void *pkt,
+ pj_ssize_t);
+ void (*stream_rtcp_cb)(void *user_data,
+ void *pkt,
+ pj_ssize_t);
+
+ /* Add your own member here.. */
+ uint64_t protect;
+ uint64_t unprotect;
+ int32_t unprotect_err;
+ int32_t refcount;
+ pj_timer_heap_t* timer_heap;
+ pj_timer_entry timeoutEntry;
+ pj_mutex_t* zrtpMutex;
+ ZsrtpContext* srtpReceive;
+ ZsrtpContext* srtpSend;
+ ZsrtpContextCtrl* srtcpReceive;
+ ZsrtpContextCtrl* srtcpSend;
+ void* sendBuffer;
+ void* sendBufferCtrl;
+ pj_uint8_t* zrtpBuffer;
+// pj_int32_t sendBufferLen;
+ pj_uint32_t peerSSRC; /* stored in host order */
+ pj_uint32_t localSSRC; /* stored in host order */
+ char* clientIdString;
+ pjmedia_transport *slave_tp;
+ pjmedia_zrtp_cb cb;
+ ZrtpContext* zrtpCtx;
+ pj_uint16_t zrtpSeq;
+ pj_bool_t enableZrtp;
+ pj_bool_t started;
+ pj_bool_t close_slave;
+ pj_bool_t mitmMode;
+ char cipher[128];
+};
+
+/* Forward declaration of thethe ZRTP specific callback functions that this
+ adapter must implement */
+static int32_t zrtp_sendDataZRTP(ZrtpContext* ctx, const uint8_t* data, int32_t length) ;
+static int32_t zrtp_activateTimer(ZrtpContext* ctx, int32_t time) ;
+static int32_t zrtp_cancelTimer(ZrtpContext* ctx) ;
+static void zrtp_sendInfo(ZrtpContext* ctx, int32_t severity, int32_t subCode) ;
+static int32_t zrtp_srtpSecretsReady(ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part) ;
+static void zrtp_srtpSecretsOff(ZrtpContext* ctx, int32_t part) ;
+static void zrtp_srtpSecretsOn(ZrtpContext* ctx, char* c, char* s, int32_t verified) ;
+static void zrtp_handleGoClear(ZrtpContext* ctx) ;
+static void zrtp_zrtpNegotiationFailed(ZrtpContext* ctx, int32_t severity, int32_t subCode) ;
+static void zrtp_zrtpNotSuppOther(ZrtpContext* ctx) ;
+static void zrtp_synchEnter(ZrtpContext* ctx) ;
+static void zrtp_synchLeave(ZrtpContext* ctx) ;
+static void zrtp_zrtpAskEnrollment(ZrtpContext* ctx, int32_t info) ;
+static void zrtp_zrtpInformEnrollment(ZrtpContext* ctx, int32_t info) ;
+static void zrtp_signSAS(ZrtpContext* ctx, uint8_t* sasHash) ;
+static int32_t zrtp_checkSASSignature(ZrtpContext* ctx, uint8_t* sasHash) ;
+
+/* The callback function structure for ZRTP */
+static zrtp_Callbacks c_callbacks =
+{
+ &zrtp_sendDataZRTP,
+ &zrtp_activateTimer,
+ &zrtp_cancelTimer,
+ &zrtp_sendInfo,
+ &zrtp_srtpSecretsReady,
+ &zrtp_srtpSecretsOff,
+ &zrtp_srtpSecretsOn,
+ &zrtp_handleGoClear,
+ &zrtp_zrtpNegotiationFailed,
+ &zrtp_zrtpNotSuppOther,
+ &zrtp_synchEnter,
+ &zrtp_synchLeave,
+ &zrtp_zrtpAskEnrollment,
+ &zrtp_zrtpInformEnrollment,
+ &zrtp_signSAS,
+ &zrtp_checkSASSignature
+};
+
+static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e);
+
+static char clientId[] = "SIP SIMPLE Client SDK";
+
+/*
+ * Create the ZRTP transport.
+ */
+PJ_DEF(pj_status_t) pjmedia_transport_zrtp_create(pjmedia_endpt *endpt,
+ pj_timer_heap_t *timer_heap,
+ pjmedia_transport *tp,
+ pjmedia_transport **p_tp,
+ pj_bool_t close_slave)
+{
+ pj_pool_t *pool;
+ struct tp_zrtp *zrtp;
+
+ PJ_ASSERT_RETURN(endpt && tp && p_tp, PJ_EINVAL);
+
+ /* Create the pool and initialize the adapter structure */
+ pool = pjmedia_endpt_create_pool(endpt, "zrtp%p", 5*1024, 512);
+ zrtp = PJ_POOL_ZALLOC_T(pool, struct tp_zrtp);
+ zrtp->pool = pool;
+
+ /* Initialize base pjmedia_transport */
+ pj_memcpy(zrtp->base.name, pool->obj_name, PJ_MAX_OBJ_NAME);
+ zrtp->base.type = tp->type;
+ zrtp->base.op = &tp_zrtp_op;
+
+ /* Set the timer heap to be used for timers */
+ zrtp->timer_heap = timer_heap;
+
+ /* Create the empty wrapper */
+ zrtp->zrtpCtx = zrtp_CreateWrapper();
+
+ /* Initialize standard values */
+ zrtp->clientIdString = clientId; /* Set standard name */
+ zrtp->zrtpSeq = 1; /* TODO: randomize */
+ pj_mutex_create_simple(zrtp->pool, "zrtp", &zrtp->zrtpMutex);
+ zrtp->zrtpBuffer = pj_pool_zalloc(pool, MAX_ZRTP_SIZE);
+ zrtp->sendBuffer = pj_pool_zalloc(pool, MAX_RTP_BUFFER_LEN);
+ zrtp->sendBufferCtrl = pj_pool_zalloc(pool, MAX_RTCP_BUFFER_LEN);
+
+ zrtp->slave_tp = tp;
+ zrtp->close_slave = close_slave;
+ zrtp->mitmMode = PJ_FALSE;
+
+ /* Done */
+ zrtp->refcount++;
+ *p_tp = &zrtp->base;
+ return PJ_SUCCESS;
+}
+
+PJ_DECL(pj_status_t) pjmedia_transport_zrtp_initialize(pjmedia_transport *tp,
+ const char *zidFilename,
+ pj_bool_t autoEnable,
+ pjmedia_zrtp_cb *cb)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ zrtp_initializeZrtpEngine(zrtp->zrtpCtx, &c_callbacks, zrtp->clientIdString,
+ zidFilename, zrtp, zrtp->mitmMode);
+ zrtp->enableZrtp = autoEnable;
+ if (cb)
+ pj_memcpy(&zrtp->cb, cb, sizeof(pjmedia_zrtp_cb));
+ return PJ_SUCCESS;
+}
+
+static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)e->user_data;
+
+ zrtp_processTimeout(zrtp->zrtpCtx);
+ PJ_UNUSED_ARG(ht);
+}
+
+/*
+ * Here start with callback functions that support the ZRTP core
+ */
+static int32_t zrtp_sendDataZRTP(ZrtpContext* ctx, const uint8_t* data, int32_t length)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+ pj_uint16_t totalLen = length + 12; /* Fixed number of bytes of ZRTP header */
+ pj_uint32_t crc;
+ pj_uint8_t* buffer = zrtp->zrtpBuffer;
+ pj_uint16_t* pus;
+ pj_uint32_t* pui;
+
+ if ((totalLen) > MAX_ZRTP_SIZE)
+ return 0;
+
+ /* Get some handy pointers */
+ pus = (pj_uint16_t*)buffer;
+ pui = (pj_uint32_t*)buffer;
+
+ /* set up fixed ZRTP header */
+ *buffer = 0x10; /* invalid RTP version - refer to ZRTP spec chap 5 */
+ *(buffer + 1) = 0;
+ pus[1] = pj_htons(zrtp->zrtpSeq++);
+ pui[1] = pj_htonl(ZRTP_MAGIC);
+ pui[2] = pj_htonl(zrtp->localSSRC); /* stored in host order */
+
+ /* Copy ZRTP message data behind the header data */
+ pj_memcpy(buffer+12, data, length);
+
+ /* Setup and compute ZRTP CRC */
+ crc = zrtp_GenerateCksum(buffer, totalLen-CRC_SIZE);
+
+ /* convert and store CRC in ZRTP packet.*/
+ crc = zrtp_EndCksum(crc);
+ *(uint32_t*)(buffer+totalLen-CRC_SIZE) = pj_htonl(crc);
+
+ /* Send the ZRTP packet using the slave transport */
+ return (pjmedia_transport_send_rtp(zrtp->slave_tp, buffer, totalLen) == PJ_SUCCESS) ? 1 : 0;
+}
+
+static int32_t zrtp_activateTimer(ZrtpContext* ctx, int32_t time)
+{
+ pj_time_val timeout;
+ pj_status_t status;
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ timeout.sec = time / 1000;
+ timeout.msec = time % 1000;
+
+ pj_timer_entry_init(&zrtp->timeoutEntry, 0, zrtp, &timer_callback);
+ status = pj_timer_heap_schedule(zrtp->timer_heap, &zrtp->timeoutEntry, &timeout);
+ if (status == PJ_SUCCESS)
+ return 1;
+ else
+ return 0;
+}
+
+static int32_t zrtp_cancelTimer(ZrtpContext* ctx)
+{
+ pj_status_t status;
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ status = pj_timer_heap_cancel(zrtp->timer_heap, &zrtp->timeoutEntry);
+ if (status == PJ_SUCCESS)
+ return 1;
+ else
+ return 0;
+}
+
+static void zrtp_sendInfo(ZrtpContext* ctx, int32_t severity, int32_t subCode)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.show_message)
+ zrtp->cb.show_message(&zrtp->base, severity, subCode);
+
+}
+
+static int32_t zrtp_srtpSecretsReady(ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ ZsrtpContext* recvCrypto;
+ ZsrtpContext* senderCrypto;
+ ZsrtpContextCtrl* recvCryptoCtrl;
+ ZsrtpContextCtrl* senderCryptoCtrl;
+ int cipher;
+ int authn;
+ int authKeyLen;
+ // int srtcpAuthTagLen;
+
+ if (secrets->authAlgorithm == zrtp_Sha1) {
+ authn = SrtpAuthenticationSha1Hmac;
+ authKeyLen = 20;
+ // srtcpAuthTagLen = 80; // Always 80 bit for SRTCP / SHA1
+ }
+
+ if (secrets->authAlgorithm == zrtp_Skein) {
+ authn = SrtpAuthenticationSkeinHmac;
+ authKeyLen = 32;
+ // srtcpAuthTagLen = 64; // Always 64 bit for SRTCP / Skein
+ }
+
+ if (secrets->symEncAlgorithm == zrtp_Aes)
+ cipher = SrtpEncryptionAESCM;
+
+ if (secrets->symEncAlgorithm == zrtp_TwoFish)
+ cipher = SrtpEncryptionTWOCM;
+
+ if (part == ForSender) {
+ // To encrypt packets: intiator uses initiator keys,
+ // responder uses responder keys
+ // Create a "half baked" crypto context first and store it. This is
+ // the main crypto context for the sending part of the connection.
+ if (secrets->role == Initiator) {
+ senderCrypto = zsrtp_CreateWrapper(zrtp->localSSRC,
+ 0,
+ 0L, // keyderivation << 48,
+ cipher, // encryption algo
+ authn, // authtentication algo
+ (unsigned char*)secrets->keyInitiator, // Master Key
+ secrets->initKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltInitiator, // Master Salt
+ secrets->initSaltLen / 8, // Master Salt length
+ secrets->initKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->initSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag lenA
+
+ senderCryptoCtrl = zsrtp_CreateWrapperCtrl(zrtp->localSSRC,
+ cipher, // encryption algo
+ authn, // authtication algo
+ (unsigned char*)secrets->keyInitiator, // Master Key
+ secrets->initKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltInitiator, // Master Salt
+ secrets->initSaltLen / 8, // Master Salt length
+ secrets->initKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->initSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+ // srtcpAuthTagLen / 8); // authentication tag len
+ }
+ else {
+ senderCrypto = zsrtp_CreateWrapper(zrtp->localSSRC,
+ 0,
+ 0L, // keyderivation << 48,
+ cipher, // encryption algo
+ authn, // authtentication algo
+ (unsigned char*)secrets->keyResponder, // Master Key
+ secrets->respKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltResponder, // Master Salt
+ secrets->respSaltLen / 8, // Master Salt length
+ secrets->respKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->respSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+
+ senderCryptoCtrl = zsrtp_CreateWrapperCtrl(zrtp->localSSRC,
+ cipher, // encryption algo
+ authn, // authtication algo
+ (unsigned char*)secrets->keyResponder, // Master Key
+ secrets->respKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltResponder, // Master Salt
+ secrets->respSaltLen / 8, // Master Salt length
+ secrets->respKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->respSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+ // srtcpAuthTagLen / 8); // authentication tag len
+ }
+ if (senderCrypto == NULL) {
+ return 0;
+ }
+ // Create a SRTP crypto context for real SSRC sender stream.
+ // Note: key derivation can be done at this time only if the
+ // key derivation rate is 0 (disabled). For ZRTP this is the
+ // case: the key derivation is defined as 2^48
+ // which is effectively 0.
+ zsrtp_deriveSrtpKeys(senderCrypto, 0L);
+ zrtp->srtpSend = senderCrypto;
+
+ zsrtp_deriveSrtpKeysCtrl(senderCryptoCtrl);
+ zrtp->srtcpSend = senderCryptoCtrl;
+ }
+ if (part == ForReceiver) {
+ // To decrypt packets: intiator uses responder keys,
+ // responder initiator keys
+ // See comment above.
+ if (secrets->role == Initiator) {
+ recvCrypto = zsrtp_CreateWrapper(zrtp->peerSSRC,
+ 0,
+ 0L, // keyderivation << 48,
+ cipher, // encryption algo
+ authn, // authtentication algo
+ (unsigned char*)secrets->keyResponder, // Master Key
+ secrets->respKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltResponder, // Master Salt
+ secrets->respSaltLen / 8, // Master Salt length
+ secrets->respKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->respSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+
+ recvCryptoCtrl = zsrtp_CreateWrapperCtrl(zrtp->peerSSRC,
+ cipher, // encryption algo
+ authn, // authtication algo
+ (unsigned char*)secrets->keyResponder, // Master Key
+ secrets->respKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltResponder, // Master Salt
+ secrets->respSaltLen / 8, // Master Salt length
+ secrets->respKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->respSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+ // srtcpAuthTagLen / 8); // authentication tag len
+ }
+ else {
+ recvCrypto = zsrtp_CreateWrapper(zrtp->peerSSRC,
+ 0,
+ 0L, // keyderivation << 48,
+ cipher, // encryption algo
+ authn, // authtentication algo
+ (unsigned char*)secrets->keyInitiator, // Master Key
+ secrets->initKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltInitiator, // Master Salt
+ secrets->initSaltLen / 8, // Master Salt length
+ secrets->initKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->initSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+
+ recvCryptoCtrl = zsrtp_CreateWrapperCtrl(zrtp->peerSSRC,
+ cipher, // encryption algo
+ authn, // authtication algo
+ (unsigned char*)secrets->keyInitiator, // Master Key
+ secrets->initKeyLen / 8, // Master Key length
+ (unsigned char*)secrets->saltInitiator, // Master Salt
+ secrets->initSaltLen / 8, // Master Salt length
+ secrets->initKeyLen / 8, // encryption keyl
+ authKeyLen, // authentication key len
+ secrets->initSaltLen / 8, // session salt len
+ secrets->srtpAuthTagLen / 8); // authentication tag len
+ // srtcpAuthTagLen / 8); // authentication tag len
+ }
+ if (recvCrypto == NULL) {
+ return 0;
+ }
+ // Create a SRTP crypto context for real SSRC input stream.
+ // If the sender didn't provide a SSRC just insert the template
+ // into the queue. After we received the first packet the real
+ // crypto context will be created.
+ //
+ // Note: key derivation can be done at this time only if the
+ // key derivation rate is 0 (disabled). For ZRTP this is the
+ // case: the key derivation is defined as 2^48
+ // which is effectively 0.
+ zsrtp_deriveSrtpKeys(recvCrypto, 0L);
+ zrtp->srtpReceive = recvCrypto;
+
+ zsrtp_deriveSrtpKeysCtrl(recvCryptoCtrl);
+ zrtp->srtcpReceive = recvCryptoCtrl;
+ }
+ return 1;
+}
+
+static void zrtp_srtpSecretsOff(ZrtpContext* ctx, int32_t part)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (part == ForSender)
+ {
+ zsrtp_DestroyWrapper(zrtp->srtpSend);
+ zsrtp_DestroyWrapperCtrl(zrtp->srtcpSend);
+ zrtp->srtpSend = NULL;
+ zrtp->srtcpSend = NULL;
+ }
+ if (part == ForReceiver)
+ {
+ zsrtp_DestroyWrapper(zrtp->srtpReceive);
+ zsrtp_DestroyWrapperCtrl(zrtp->srtcpReceive);
+ zrtp->srtpReceive = NULL;
+ zrtp->srtcpReceive = NULL;
+ }
+
+ if (zrtp->cb.secure_off)
+ zrtp->cb.secure_off(&zrtp->base);
+}
+
+static void zrtp_srtpSecretsOn(ZrtpContext* ctx, char* c, char* s, int32_t verified)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+ int len;
+
+ len = strlen(c);
+ if (len > sizeof(zrtp->cipher) - 1)
+ len = sizeof(zrtp->cipher) - 1;
+ memcpy(zrtp->cipher, c, len);
+ zrtp->cipher[len] = '\0';
+
+ if (zrtp->cb.secure_on)
+ zrtp->cb.secure_on(&zrtp->base, c);
+
+ if (s && strlen(s) > 0 && zrtp->cb.show_sas)
+ zrtp->cb.show_sas(&zrtp->base, s, verified);
+}
+
+static void zrtp_handleGoClear(ZrtpContext* ctx)
+{
+ /* TODO: implement */
+}
+
+static void zrtp_zrtpNegotiationFailed(ZrtpContext* ctx, int32_t severity, int32_t subCode)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.negotiation_failed)
+ zrtp->cb.negotiation_failed(&zrtp->base, severity, subCode);
+}
+
+static void zrtp_zrtpNotSuppOther(ZrtpContext* ctx)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.not_supported_by_other)
+ zrtp->cb.not_supported_by_other(&zrtp->base);
+}
+
+static void zrtp_synchEnter(ZrtpContext* ctx)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+ pj_mutex_lock(zrtp->zrtpMutex);
+}
+
+static void zrtp_synchLeave(ZrtpContext* ctx)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+ pj_mutex_unlock(zrtp->zrtpMutex);
+}
+
+static void zrtp_zrtpAskEnrollment(ZrtpContext* ctx, int32_t info)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.ask_enrollment)
+ zrtp->cb.ask_enrollment(&zrtp->base, info);
+}
+
+static void zrtp_zrtpInformEnrollment(ZrtpContext* ctx, int32_t info)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.inform_enrollment)
+ zrtp->cb.inform_enrollment(&zrtp->base, info);
+}
+
+static void zrtp_signSAS(ZrtpContext* ctx, uint8_t* sasHash)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.sign_sas)
+ zrtp->cb.sign_sas(&zrtp->base, sasHash);
+}
+
+static int32_t zrtp_checkSASSignature(ZrtpContext* ctx, uint8_t* sasHash)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;
+
+ if (zrtp->cb.check_sas_signature)
+ return zrtp->cb.check_sas_signature(&zrtp->base, sasHash);
+ return 0;
+}
+
+/*
+ * Implement the specific ZRTP transport functions
+ */
+PJ_DEF(void) pjmedia_transport_zrtp_setEnableZrtp(pjmedia_transport *tp, pj_bool_t onOff)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ zrtp->enableZrtp = onOff;
+}
+
+PJ_DEF(pj_bool_t) pjmedia_transport_zrtp_isEnableZrtp(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_FALSE);
+
+ return zrtp->enableZrtp;
+
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_startZrtp(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp && zrtp->zrtpCtx);
+
+ zrtp_startZrtpEngine(zrtp->zrtpCtx);
+ zrtp->started = 1;
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_stopZrtp(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp && zrtp->zrtpCtx);
+
+ zrtp_stopZrtpEngine(zrtp->zrtpCtx);
+ zrtp->started = 0;
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_setLocalSSRC(pjmedia_transport *tp, uint32_t ssrc)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ zrtp->localSSRC = ssrc;
+}
+
+PJ_DEF(pj_bool_t) pjmedia_transport_zrtp_isMitmMode(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ return zrtp->mitmMode;
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_setMitmMode(pjmedia_transport *tp, pj_bool_t mitmMode)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ zrtp->mitmMode = mitmMode;
+}
+
+PJ_DEF(ZrtpContext*) pjmedia_transport_zrtp_getZrtpContext(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, NULL);
+
+ return zrtp->zrtpCtx;
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_setSASVerified(pjmedia_transport *tp, pj_bool_t verified)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ if (verified)
+ zrtp_SASVerified(zrtp->zrtpCtx);
+ else
+ zrtp_resetSASVerified(zrtp->zrtpCtx);
+}
+
+PJ_DEF(int) pjmedia_transport_zrtp_getPeerZid(pjmedia_transport *tp, unsigned char* data)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ return zrtp_getPeerZid(zrtp->zrtpCtx, data);
+}
+
+PJ_DEF(char*) pjmedia_transport_zrtp_getPeerName(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ return zrtp_getPeerName(zrtp->zrtpCtx);
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_putPeerName(pjmedia_transport *tp, const char *name)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ zrtp_putPeerName(zrtp->zrtpCtx, name);
+}
+
+PJ_DEF(char*) pjmedia_transport_zrtp_getMultiStreamParameters(pjmedia_transport *tp, pj_int32_t *length)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_assert(tp);
+
+ return zrtp_getMultiStrParams(zrtp->zrtpCtx, length);
+}
+
+PJ_DEF(void) pjmedia_transport_zrtp_setMultiStreamParameters(pjmedia_transport *tp, const char *parameters, pj_int32_t length, pjmedia_transport *master_tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ struct tp_zrtp *master_zrtp = (struct tp_zrtp*)master_tp;
+ pj_assert(tp);
+ pj_assert(master_tp);
+
+ zrtp_setMultiStrParams(zrtp->zrtpCtx, parameters, length, master_zrtp->zrtpCtx);
+}
+
+/*
+ * get_info() is called to get the transport addresses to be put
+ * in SDP c= line and a=rtcp line.
+ */
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+ pjmedia_transport_info *info)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pjmedia_zrtp_info zrtp_info;
+ int spc_info_idx;
+
+ PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);
+ PJ_ASSERT_RETURN(info->specific_info_cnt <
+ PJMEDIA_TRANSPORT_SPECIFIC_INFO_MAXCNT, PJ_ETOOMANY);
+
+ zrtp_info.active = zrtp_inState(zrtp->zrtpCtx, SecureState) ? PJ_TRUE : PJ_FALSE;
+ if (zrtp_info.active)
+ memcpy(zrtp_info.cipher, zrtp->cipher, sizeof(zrtp->cipher));
+ else
+ zrtp_info.cipher[0] = '\0';
+
+ spc_info_idx = info->specific_info_cnt++;
+ info->spc_info[spc_info_idx].type = PJMEDIA_TRANSPORT_TYPE_ZRTP;
+
+ pj_memcpy(&info->spc_info[spc_info_idx].buffer, &zrtp_info,
+ sizeof(zrtp_info));
+
+ return pjmedia_transport_get_info(zrtp->slave_tp, info);
+}
+
+/* This is our RTP callback, that is called by the slave transport when it
+ * receives RTP packet.
+ */
+static void transport_rtp_cb(void *user_data, void *pkt, pj_ssize_t size)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)user_data;
+
+ pj_uint8_t* buffer = (pj_uint8_t*)pkt;
+ int32_t newLen = 0;
+ pj_status_t rc = PJ_SUCCESS;
+
+ pj_assert(zrtp && zrtp->stream_rtcp_cb && pkt);
+
+ // check if this could be a real RTP/SRTP packet.
+ if ((*buffer & 0xf0) != 0x10)
+ {
+ // Could be real RTP, check if we are in secure mode
+ if (zrtp->srtpReceive == NULL || size < 0)
+ {
+ zrtp->stream_rtp_cb(zrtp->stream_user_data, pkt, size);
+ }
+ else
+ {
+ rc = zsrtp_unprotect(zrtp->srtpReceive, pkt, size, &newLen);
+ if (rc == 1)
+ {
+ zrtp->unprotect++;
+ zrtp->stream_rtp_cb(zrtp->stream_user_data, pkt,
+ newLen);
+ zrtp->unprotect_err = 0;
+ }
+ else
+ {
+ if (zrtp->cb.show_message)
+ {
+ if (rc == -1)
+ zrtp->cb.show_message(&zrtp->base, zrtp_Warning, zrtp_WarningSRTPauthError);
+ else
+ zrtp->cb.show_message(&zrtp->base, zrtp_Warning, zrtp_WarningSRTPreplayError);
+ }
+ zrtp->unprotect_err = rc;
+ }
+ }
+ if (!zrtp->started && zrtp->enableZrtp)
+ pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp);
+
+ return;
+ }
+
+ // We assume all other packets are ZRTP packets here. Process
+ // if ZRTP processing is enabled. Because valid RTP packets are
+ // already handled we delete any packets here after processing.
+ if (zrtp->enableZrtp && zrtp->zrtpCtx != NULL)
+ {
+ // Get CRC value into crc (see above how to compute the offset)
+ pj_uint16_t temp = size - CRC_SIZE;
+ pj_uint32_t crc = *(uint32_t*)(buffer + temp);
+ crc = pj_ntohl(crc);
+
+ if (!zrtp_CheckCksum(buffer, temp, crc))
+ {
+ if (zrtp->cb.show_message)
+ zrtp->cb.show_message(&zrtp->base, zrtp_Warning, zrtp_WarningCRCmismatch);
+ return;
+ }
+
+ pj_uint32_t magic = *(pj_uint32_t*)(buffer + 4);
+ magic = pj_ntohl(magic);
+
+ // Check if it is really a ZRTP packet, return, no further processing
+ if (magic != ZRTP_MAGIC)
+ return;
+
+ // cover the case if the other party sends _only_ ZRTP packets at the
+ // beginning of a session. Start ZRTP in this case as well.
+ if (!zrtp->started)
+ {
+ pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp);
+ }
+ // this now points beyond the undefined and length field.
+ // We need them, thus adjust
+ unsigned char* zrtpMsg = (buffer + 12);
+
+ // store peer's SSRC in host order, used when creating the CryptoContext
+ zrtp->peerSSRC = *(pj_uint32_t*)(buffer + 8);
+ zrtp->peerSSRC = pj_ntohl(zrtp->peerSSRC);
+ zrtp_processZrtpMessage(zrtp->zrtpCtx, zrtpMsg, zrtp->peerSSRC, size);
+ }
+}
+
+
+/* This is our RTCP callback, that is called by the slave transport when it
+ * receives RTCP packet.
+ */
+static void transport_rtcp_cb(void *user_data, void *pkt, pj_ssize_t size)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)user_data;
+ int32_t newLen = 0;
+ pj_status_t rc = PJ_SUCCESS;
+
+ pj_assert(zrtp && zrtp->stream_rtcp_cb);
+
+ if (zrtp->srtcpReceive == NULL || size < 0)
+ {
+ zrtp->stream_rtcp_cb(zrtp->stream_user_data, pkt, size);
+ }
+ else
+ {
+ rc = zsrtp_unprotectCtrl(zrtp->srtcpReceive, pkt, size, &newLen);
+
+ if (rc == 1)
+ {
+ /* Call stream's callback */
+ zrtp->stream_rtcp_cb(zrtp->stream_user_data, pkt, newLen);
+ }
+ else
+ {
+ // Testing: print some error output
+ }
+ }
+}
+
+
+/*
+ * attach() is called by stream to register callbacks that we should
+ * call on receipt of RTP and RTCP packets.
+ */
+static pj_status_t transport_attach(pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ void*,
+ pj_ssize_t))
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
+
+ /* In this example, we will save the stream information and callbacks
+ * to our structure, and we will register different RTP/RTCP callbacks
+ * instead.
+ */
+ pj_assert(zrtp->stream_user_data == NULL);
+ zrtp->stream_user_data = user_data;
+ zrtp->stream_rtp_cb = rtp_cb;
+ zrtp->stream_rtcp_cb = rtcp_cb;
+
+ status = pjmedia_transport_attach(zrtp->slave_tp, zrtp, rem_addr,
+ rem_rtcp, addr_len, &transport_rtp_cb,
+ &transport_rtcp_cb);
+ if (status != PJ_SUCCESS)
+ {
+ zrtp->stream_user_data = NULL;
+ zrtp->stream_rtp_cb = NULL;
+ zrtp->stream_rtcp_cb = NULL;
+ return status;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * detach() is called when the media is terminated, and the stream is
+ * to be disconnected from us.
+ */
+static void transport_detach(pjmedia_transport *tp, void *strm)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+
+ PJ_UNUSED_ARG(strm);
+ PJ_ASSERT_ON_FAIL(tp, return);
+
+ if (zrtp->stream_user_data != NULL)
+ {
+ pjmedia_transport_detach(zrtp->slave_tp, zrtp);
+ zrtp->stream_user_data = NULL;
+ zrtp->stream_rtp_cb = NULL;
+ zrtp->stream_rtcp_cb = NULL;
+ }
+}
+
+
+/*
+ * send_rtp() is called to send RTP packet. The "pkt" and "size" argument
+ * contain both the RTP header and the payload.
+ */
+static pj_status_t transport_send_rtp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_uint32_t* pui = (pj_uint32_t*)pkt;
+ int32_t newLen = 0;
+ pj_status_t rc = PJ_SUCCESS;
+
+ PJ_ASSERT_RETURN(tp && pkt, PJ_EINVAL);
+
+
+ if (!zrtp->started && zrtp->enableZrtp)
+ {
+ if (zrtp->localSSRC == 0)
+ zrtp->localSSRC = pj_ntohl(pui[2]); /* Learn own SSRC before starting ZRTP */
+
+ pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp);
+ }
+
+ if (zrtp->srtpSend == NULL)
+ {
+ return pjmedia_transport_send_rtp(zrtp->slave_tp, pkt, size);
+ }
+ else
+ {
+ if (size+80 > MAX_RTP_BUFFER_LEN)
+ return PJ_ETOOBIG;
+
+ pj_memcpy(zrtp->sendBuffer, pkt, size);
+ rc = zsrtp_protect(zrtp->srtpSend, zrtp->sendBuffer, size, &newLen);
+ zrtp->protect++;
+
+ if (rc == 1)
+ return pjmedia_transport_send_rtp(zrtp->slave_tp, zrtp->sendBuffer, newLen);
+ else
+ return PJ_EIGNORED;
+ }
+}
+
+
+/*
+ * send_rtcp() is called to send RTCP packet. The "pkt" and "size" argument
+ * contain the RTCP packet.
+ */
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ pj_status_t rc = PJ_SUCCESS;
+ int32_t newLen = 0;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ /* You may do some processing to the RTCP packet here if you want. */
+ if (zrtp->srtcpSend == NULL)
+ {
+ return pjmedia_transport_send_rtcp(zrtp->slave_tp, pkt, size);
+ }
+ else
+ {
+ if (size+80 > MAX_RTCP_BUFFER_LEN)
+ return PJ_ETOOBIG;
+
+ pj_memcpy(zrtp->sendBufferCtrl, pkt, size);
+ rc = zsrtp_protectCtrl(zrtp->srtcpSend, zrtp->sendBufferCtrl, size, &newLen);
+
+ if (rc == 1)
+ return pjmedia_transport_send_rtcp(zrtp->slave_tp, zrtp->sendBufferCtrl, newLen);
+ else
+ return PJ_EIGNORED;
+ }
+
+ /* Send the packet using the slave transport */
+// return pjmedia_transport_send_rtcp(zrtp->slave_tp, pkt, size);
+}
+
+
+/*
+ * This is another variant of send_rtcp(), with the alternate destination
+ * address in the argument.
+ */
+static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ return pjmedia_transport_send_rtcp2(zrtp->slave_tp, addr, addr_len,
+ pkt, size);
+}
+
+/*
+ * The media_create() is called when the transport is about to be used for
+ * a new call.
+ */
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ /* if "rem_sdp" is not NULL, it means we are UAS. You may do some
+ * inspections on the incoming SDP to verify that the SDP is acceptable
+ * for us. If the SDP is not acceptable, we can reject the SDP by
+ * returning non-PJ_SUCCESS.
+ */
+ if (rem_sdp)
+ {
+ /* Do your stuff.. */
+ }
+
+ /* Once we're done with our initialization, pass the call to the
+ * slave transports to let it do it's own initialization too.
+ */
+ return pjmedia_transport_media_create(zrtp->slave_tp, sdp_pool, options,
+ rem_sdp, media_index);
+}
+
+/*
+ * The encode_sdp() is called when we're about to send SDP to remote party,
+ * either as SDP offer or as SDP answer.
+ */
+static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ int32_t numVersions, i;
+
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ /* If "rem_sdp" is not NULL, it means we're encoding SDP answer. You may
+ * do some more checking on the SDP's once again to make sure that
+ * everything is okay before we send SDP.
+ */
+ if (rem_sdp)
+ {
+ /* Do checking stuffs here.. */
+ }
+
+ /* Add zrtp-hash attributes to both INVITE and 200 OK. */
+ numVersions = zrtp_getNumberSupportedVersions(zrtp->zrtpCtx);
+ for (i = 0; i < numVersions; i++) {
+ char *zrtp_hello_hash = zrtp_getHelloHash(zrtp->zrtpCtx, i);
+ if (zrtp_hello_hash && *zrtp_hello_hash) {
+ int zrtp_hello_hash_len = strlen(zrtp_hello_hash);
+ pj_str_t *zrtp_hash_str = PJ_POOL_ALLOC_T(sdp_pool, pj_str_t);
+ pjmedia_sdp_attr *zrtp_hash = NULL;
+
+ zrtp_hash_str->ptr = zrtp_hello_hash;
+ zrtp_hash_str->slen = zrtp_hello_hash_len;
+
+ zrtp_hash = pjmedia_sdp_attr_create(sdp_pool, "zrtp-hash", zrtp_hash_str);
+ if (zrtp_hash &&
+ pjmedia_sdp_attr_add(&local_sdp->media[media_index]->attr_count, local_sdp->media[media_index]->attr, zrtp_hash) == PJ_SUCCESS) {
+ PJ_LOG(4, (THIS_FILE, "attribute added: a=zrtp-hash:%s", zrtp_hello_hash));
+ }
+ else {
+ PJ_LOG(4, (THIS_FILE, "error adding attribute: a=zrtp-hash:%s", zrtp_hello_hash));
+ }
+ }
+ }
+
+ /* You may do anything to the local_sdp, e.g. adding new attributes, or
+ * even modifying the SDP if you want.
+ */
+ if (0)
+ {
+ /* Say we add a proprietary attribute here.. */
+ pjmedia_sdp_attr *my_attr;
+
+ my_attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr);
+ pj_strdup2(sdp_pool, &my_attr->name, "X-zrtp");
+ pj_strdup2(sdp_pool, &my_attr->value, "some value");
+
+ pjmedia_sdp_attr_add(&local_sdp->media[media_index]->attr_count,
+ local_sdp->media[media_index]->attr,
+ my_attr);
+ }
+
+ /* And then pass the call to slave transport to let it encode its
+ * information in the SDP. You may choose to call encode_sdp() to slave
+ * first before adding your custom attributes if you want.
+ */
+ return pjmedia_transport_encode_sdp(zrtp->slave_tp, sdp_pool, local_sdp, rem_sdp, media_index);
+}
+
+/*
+ * The media_start() is called once both local and remote SDP have been
+ * negotiated successfully, and the media is ready to start. Here we can start
+ * committing our processing.
+ */
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ /* Do something.. */
+
+ /* And pass the call to the slave transport */
+ return pjmedia_transport_media_start(zrtp->slave_tp, pool, local_sdp,
+ rem_sdp, media_index);
+}
+
+/*
+ * The media_stop() is called when media has been stopped.
+ */
+static pj_status_t transport_media_stop(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ /* Do something.. */
+ PJ_LOG(4, (THIS_FILE, "Media stop - encrypted packets: %ld, decrypted packets: %ld",
+ zrtp->protect, zrtp->unprotect));
+
+ /* And pass the call to the slave transport */
+ return pjmedia_transport_media_stop(zrtp->slave_tp);
+}
+
+/*
+ * simulate_lost() is called to simulate packet lost
+ */
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+ pjmedia_dir dir,
+ unsigned pct_lost)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ return pjmedia_transport_simulate_lost(zrtp->slave_tp, dir, pct_lost);
+}
+
+/*
+ * destroy() is called when the transport is no longer needed.
+ */
+static pj_status_t transport_destroy(pjmedia_transport *tp)
+{
+ struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
+
+ PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+ PJ_LOG(4, (THIS_FILE, "Destroy - encrypted packets: %ld, decrypted packets: %ld",
+ zrtp->protect, zrtp->unprotect));
+
+ /* close the slave transport in case */
+ if (zrtp->close_slave && zrtp->slave_tp)
+ pjmedia_transport_close(zrtp->slave_tp);
+
+ /* Self destruct.. */
+ zrtp_stopZrtpEngine(zrtp->zrtpCtx);
+ zrtp_DestroyWrapper(zrtp->zrtpCtx);
+ zrtp->zrtpCtx = NULL;
+
+ /* In case mutex is being acquired by other thread */
+ pj_mutex_lock(zrtp->zrtpMutex);
+ pj_mutex_unlock(zrtp->zrtpMutex);
+ pj_mutex_destroy(zrtp->zrtpMutex);
+
+ pj_pool_release(zrtp->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+
+
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 2:29 AM (13 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3408607
Default Alt Text
(84 KB)
Attached To
Mode
rPYNSIPSIMPLE python3-sipsimple
Attached
Detach File
Event Timeline
Log In to Comment