Page MenuHomePhabricator

No OneTemporary

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

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)

Event Timeline