core ZRTP support (see zfoneproject.com)

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@950 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Stefan Sayer 18 years ago
parent a5d8e78aa4
commit 6f44a030bb

@ -11,7 +11,7 @@ RELEASE=$(REL_VERSION)$(EXTRAVERSION)
CPPFLAGS += -D_DEBUG \
-D_THREAD_SAFE -D_REENTRANT \
-DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"'\
-DSEMS_VERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"'\
-DOS='"$(OS)"' \
# -DMAX_RTP_SESSIONS=8192 \
# -DOpenSER \
@ -34,6 +34,10 @@ CPPFLAGS += -D_DEBUG \
#
#USE_LIBSAMPLERATE = yes
#
# ZRTP support? (see zfoneproject.com)
#WITH_ZRTP = yes
#
# exclude some modules from compilation?
# e.g. python modules:

@ -51,6 +51,10 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#endif
#include <set>
using std::set;
@ -203,6 +207,36 @@ int AmRtpStream::send( unsigned int ts, unsigned char* buffer, unsigned int size
rp.compile((unsigned char*)buffer,size);
rp.setAddr(&r_saddr);
#ifdef WITH_ZRTP
if (session->zrtp_audio) {
zrtp_status_t status = zrtp_status_fail;
unsigned int size = rp.getBufferSize();
status = zrtp_process_rtp(session->zrtp_audio, (char*)rp.getBuffer(), &size);
switch (status) {
case zrtp_status_drop: {
DBG("ZRTP says: drop packet! %u - %u\n", size, rp.getBufferSize());
return 0;
}
case zrtp_status_ok: {
// DBG("ZRTP says: ok!\n");
if (rp.getBufferSize() != size)
// DBG("SEND packet size before: %d, after %d\n",
// rp.getBufferSize(), size);
rp.setBufferSize(size);
} break;
default:
case zrtp_status_fail: {
DBG("ZRTP says: fail!\n");
// DBG("(f)");
return 0;
}
}
}
#endif
if(rp.send(l_sd) < 0){
ERROR("while sending RTP packet.\n");
return -1;
@ -211,6 +245,24 @@ int AmRtpStream::send( unsigned int ts, unsigned char* buffer, unsigned int size
return size;
}
int AmRtpStream::send_raw( char* packet, unsigned int length )
{
if ((mute) || (hold))
return 0;
AmRtpPacket rp;
rp.compile_raw((unsigned char*)packet, length);
rp.setAddr(&r_saddr);
if(rp.send(l_sd) < 0){
ERROR("while sending raw RTP packet.\n");
return -1;
}
return length;
}
// returns
// @param ts [out] timestamp of the received packet,
// in audio buffer relative time
@ -404,6 +456,13 @@ void AmRtpStream::init(const vector<SdpPayload*>& sdp_payloads)
payload = sdp_payload->payload_type;
last_payload = payload;
resume();
#ifdef WITH_ZRTP
if( session->zrtp_audio ) {
DBG("now starting zrtp stream...\n");
zrtp_start_stream( session->zrtp_audio );
}
#endif
}
void AmRtpStream::pause()
@ -455,7 +514,50 @@ void AmRtpStream::bufferPacket(AmRtpPacket* p)
if (receive_buf.find(p->timestamp) != receive_buf.end())
mem.freePacket(receive_buf[p->timestamp]);
receive_buf[p->timestamp] = p;
#ifdef WITH_ZRTP
if (session->zrtp_audio) {
zrtp_status_t status = zrtp_status_fail;
unsigned int size = p->getBufferSize();
status = zrtp_process_srtp(session->zrtp_audio, (char*)p->getBuffer(), &size);
switch (status)
{
case zrtp_status_forward:
case zrtp_status_ok: {
p->setBufferSize(size);
if (p->parse() < 0) {
ERROR("parsing decoded packet!\n");
mem.freePacket(p);
} else {
receive_buf[p->timestamp] = p;
}
} break;
case zrtp_status_drop: {
//
// This is a protocol ZRTP packet or masked RTP media.
// In either case the packet must be dropped to protect your
// media codec
mem.freePacket(p);
} break;
case zrtp_status_fail:
default: {
ERROR("zrtp_status_fail!\n");
//
// This is some kind of error - see logs for more information
//
mem.freePacket(p);
} break;
}
} else {
#endif // WITH_ZRTP
receive_buf[p->timestamp] = p;
#ifdef WITH_ZRTP
}
#endif
receive_mut.unlock();
}

@ -165,6 +165,7 @@ public:
unsigned char* buffer,
unsigned int size );
int send_raw( char* packet, unsigned int length );
int receive( unsigned char* buffer, unsigned int size,
unsigned int& ts, int& payload);
@ -211,6 +212,8 @@ public:
void setPassiveMode(bool p) { passive = p; }
bool getPassiveMode() { return passive; }
unsigned int get_ssrc() { return l_ssrc; }
/**
* Set remote telephone event
* payload type

@ -37,6 +37,10 @@
#include "AmDtmfDetector.h"
#include "AmPlayoutBuffer.h"
#ifdef WITH_ZRTP
#include "AmZRTP.h"
#endif
#include "log.h"
#include <algorithm>
@ -46,7 +50,6 @@
#include <sys/time.h>
// AmSessionEventHandler methods
bool AmSessionEventHandler::process(AmEvent*)
{
return false;
@ -128,6 +131,9 @@ AmSession::AmSession()
m_dtmfDetector(this), m_dtmfEventQueue(&m_dtmfDetector),
m_dtmfDetectionEnabled(true),
accept_early_session(false)
#ifdef WITH_ZRTP
, zrtp_session(NULL), zrtp_audio(NULL), enable_zrtp(true)
#endif
{
use_local_audio[AM_AUDIO_IN] = false;
use_local_audio[AM_AUDIO_OUT] = false;
@ -139,6 +145,10 @@ AmSession::~AmSession()
evh != ev_handlers.end(); evh++)
if((*evh)->destroy)
delete *evh;
#ifdef WITH_ZRTP
AmZRTP::freeSession(zrtp_session);
#endif
}
void AmSession::setCallgroup(const string& cg) {
@ -344,6 +354,39 @@ void AmSession::negotiate(const string& sdp_body,
void AmSession::run()
{
#ifdef WITH_ZRTP
if (enable_zrtp) {
zrtp_session = (zrtp_conn_ctx_t*)malloc(sizeof(zrtp_conn_ctx_t));
if (NULL == zrtp_session) {
ERROR("allocating ZRTP session context mem.\n");
} else {
zrtp_profile_t profile;
zrtp_profile_autoload(&profile, &AmZRTP::zrtp_global);
profile.active = false;
profile.allowclear = true;
profile.autosecure = true; // automatically go into secure mode at the beginning
if (zrtp_status_ok != zrtp_init_session_ctx( zrtp_session,
&AmZRTP::zrtp_global,
&profile,
AmZRTP::zrtp_instance_zid) ) {
ERROR("initializing ZRTP session context\n");
return;
}
zrtp_audio = zrtp_attach_stream(zrtp_session, rtp_str.get_ssrc());
zrtp_audio->stream_usr_data = this;
if (NULL == zrtp_audio) {
ERROR("attaching zrtp stream.\n");
return;
}
DBG("initialized ZRTP session context OK\n");
}
}
#endif
try {
try {
@ -524,6 +567,14 @@ void AmSession::process(AmEvent* ev)
onRtpTimeout();
return;
}
#ifdef WITH_ZRTP
AmZRTPEvent* zrtp_ev = dynamic_cast<AmZRTPEvent*>(ev);
if(zrtp_ev){
onZRTPEvent((zrtp_event_t)zrtp_ev->event_id, zrtp_ev->stream_ctx);
return;
}
#endif
}
@ -827,3 +878,92 @@ string AmSession::advertisedIP()
return AmConfig::LocalIP; // "listen" parameter.
return set_ip;
}
#ifdef WITH_ZRTP
void AmSession::onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx) {
DBG("AmSession::onZRTPEvent \n");
switch (event)
{
case ZRTP_EVENT_IS_SECURE: {
INFO("ZRTP_EVENT_IS_SECURE \n");
// info->is_verified = ctx->_session_ctx->secrets.verifieds & ZRTP_BIT_RS0;
zrtp_conn_ctx_t *session = stream_ctx->_session_ctx;
if (ZRTP_SAS_BASE32 == session->sas_values.rendering) {
DBG("Got SAS value <<<%.4s>>>\n", session->sas_values.str1.buffer);
} else {
DBG("Got SAS values SAS1 '%s' and SAS2 '%s'\n",
session->sas_values.str1.buffer,
session->sas_values.str2.buffer);
}
} break;
case ZRTP_EVENT_IS_PENDINGCLEAR:
INFO("ZRTP_EVENT_IS_PENDINGCLEAR\n");
INFO("other side requested goClear. Going clear.\n\n");
zrtp_clear_stream(zrtp_audio);
break;
case ZRTP_EVENT_IS_CLEAR:
INFO("ZRTP_EVENT_IS_CLEAR\n");
break;
case ZRTP_EVENT_UNSUPPORTED:
INFO("ZRTP_EVENT_UNSUPPORTED\n");
break;
case ZRTP_EVENT_IS_INITIATINGSECURE:
INFO("ZRTP_EVENT_IS_INITIATINGSECURE\n");
break;
case ZRTP_EVENT_IS_PENDINGSECURE:
INFO("ZRTP_EVENT_PENDINGSECURE\n");
break;
case ZRTP_EVENT_IS_SECURE_DONE:
INFO("ZRTP_EVENT_IS_SECURE_DONE\n");
break;
case ZRTP_EVENT_ERROR:
INFO("ZRTP_EVENT_ERROR\n");
break;
case ZRTP_EVENT_NO_ZRTP:
INFO("ZRTP_EVENT_NO_ZRTP\n");
break;
case ZRTP_EVENT_NO_ZRTP_QUICK:
INFO("ZRTP_EVENT_NO_ZRTP_QUICK\n");
break;
// pbx functions
case ZRTP_EVENT_IS_CLIENT_ENROLLMENT:
INFO("ZRTP_EVENT_IS_CLIENT_ENROLLMENT\n");
break;
case ZRTP_EVENT_NEW_USER_ENROLLED:
INFO("ZRTP_EVENT_NEW_USER_ENROLLED\n");
break;
case ZRTP_EVENT_USER_ALREADY_ENROLLED:
INFO("ZRTP_EVENT_USER_ALREADY_ENROLLED\n");
break;
case ZRTP_EVENT_USER_UNENROLLED:
INFO("ZRTP_EVENT_USER_UNENROLLED\n");
break;
case ZRTP_EVENT_LOCAL_SAS_UPDATED:
INFO("ZRTP_EVENT_LOCAL_SAS_UPDATED\n");
break;
case ZRTP_EVENT_REMOTE_SAS_UPDATED:
INFO("ZRTP_EVENT_REMOTE_SAS_UPDATED\n");
break;
// errors
case ZRTP_EVENT_WRONG_SIGNALING_HASH:
INFO("ZRTP_EVENT_WRONG_SIGNALING_HASH\n");
break;
case ZRTP_EVENT_WRONG_MESSAGE_HMAC:
INFO("ZRTP_EVENT_WRONG_MESSAGE_HMAC\n");
break;
default:
INFO("unknown ZRTP_EVENT\n");
break;
} // end events case
}
#endif

@ -38,6 +38,10 @@
#include "AmSipEvent.h"
#include "AmApi.h"
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#endif
#include <string>
#include <vector>
#include <queue>
@ -145,7 +149,6 @@ private:
protected:
AmSdp sdp;
AmRtpAudio rtp_str;
/** this is the group the media is processed with
- by default local tag */
@ -155,6 +158,17 @@ protected:
bool accept_early_session;
public:
AmRtpAudio rtp_str;
#ifdef WITH_ZRTP
zrtp_conn_ctx_t* zrtp_session; // ZRTP session
zrtp_stream_ctx_t* zrtp_audio; // ZRTP stream for audio
/** must be set before session is started! i.e. in constructor */
bool enable_zrtp;
#endif
AmSipDialog dlg;
/**
@ -439,6 +453,14 @@ public:
virtual void onSipReply(const AmSipReply& reply);
#ifdef WITH_ZRTP
/**
* ZRTP events @see ZRTP
*/
virtual void onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx);
#endif
/** This callback is called if RTP timeout encountered */
virtual void onRtpTimeout();
@ -457,7 +479,7 @@ public:
const string& body,
string& hdrs,
int flags);
// The IP address to put as c= in SDP bodies and to use for Contact:.
string advertisedIP();
};

@ -0,0 +1,162 @@
/*
* $Id: AmZRTP.cpp 934 2008-05-06 09:25:34Z sayer $
*
* Copyright (C) 2008 iptego GmbH
*
* This file is part of sems, a free SIP media server.
*
* sems 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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
*/
#ifdef WITH_ZRTP
#include "AmZRTP.h"
#include "AmSession.h"
#include "log.h"
#include "AmConfigReader.h"
#include "AmUtils.h"
#define ZRTP_CACHE_SAVE_INTERVAL 1
string AmZRTP::cache_path = "zrtp_cache.dat";
int AmZRTP::zrtp_cache_save_cntr = 0;
AmMutex AmZRTP::zrtp_cache_mut;
zrtp_global_ctx_t AmZRTP::zrtp_global; // persistent storage for libzrtp data
zrtp_zid_t AmZRTP::zrtp_instance_zid = {"defaultsems"}; // todo: generate one
int AmZRTP::init() {
AmConfigReader cfg;
string cfgname=add2path(AmConfig::ModConfigPath, 1, "zrtp.conf");
if(cfg.loadFile(cfgname)) {
ERROR("No %s config file present.\n",
cfgname.c_str());
return -1;
}
cache_path = cfg.getParameter("cache_path");
string zid = cfg.getParameter("zid");
if (zid.length() != sizeof(zrtp_zid_t)) {
ERROR("ZID of this instance MUST be set for ZRTP.\n");
ERROR("ZID needs to be %u characters long.\n",
sizeof(zrtp_zid_t));
return -1;
}
for (int i=0;i<12;i++)
zrtp_instance_zid[i]=zid[i];
DBG("initializing ZRTP library with ZID '%s', cache path '%s'.\n",
zid.c_str(), cache_path.c_str());
if ( zrtp_status_ok != zrtp_init(&zrtp_global, "zrtp_sems") ) {
ERROR("Some error during zrtp initialization\n");
return -1;
}
zrtp_add_entropy(&zrtp_global, NULL, 0);
DBG("ZRTP initialized ok.\n");
return 0;
}
void AmZRTP::freeSession(zrtp_conn_ctx_t* zrtp_session) {
zrtp_done_session_ctx(zrtp_session);
free(zrtp_session);
// save zrtp cache
zrtp_cache_mut.lock();
if (!((++zrtp_cache_save_cntr) % ZRTP_CACHE_SAVE_INTERVAL)) {
if (zrtp_cache_user_down() != zrtp_status_ok) {
ERROR("while writing ZRTP cache.\n");
}
}
zrtp_cache_mut.unlock();
}
void zrtp_get_cache_path(char *path, uint32_t length) {
sprintf(path, "%s", AmZRTP::cache_path.c_str());
}
// void zrtp_get_cache_path(char *path, uint32_t length) {
// }
void zrtp_event_callback(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx)
{
if (NULL==stream_ctx) {
ERROR("event received without stream context.\n");
return;
}
AmSession* sess = reinterpret_cast<AmSession*>(stream_ctx->stream_usr_data);
if (NULL==sess) {
ERROR("event received without session set up.\n");
return;
}
sess->postEvent(new AmZRTPEvent(event, stream_ctx));
}
void zrtp_play_alert(zrtp_stream_ctx_t* ctx) {
INFO("zrtp_play_alert: ALERT!\n");
ctx->need_play_alert = zrtp_play_no;
}
int zrtp_send_rtp( const zrtp_stream_ctx_t* stream_ctx,
char* packet, unsigned int length) {
if (NULL==stream_ctx) {
ERROR("trying to send packet without stream context.\n");
return -1;
}
AmSession* sess = reinterpret_cast<AmSession*>(stream_ctx->stream_usr_data);
if (NULL==sess) {
ERROR("trying to send packet without session set up.\n");
return -1;
}
return sess->rtp_str.send_raw(packet, length);
}
#define BUFFER_LOG_SIZE 256
void zrtp_print_log(log_level_t level, const char* format, ...)
{
char buffer[BUFFER_LOG_SIZE];
va_list arg;
va_start(arg, format);
vsnprintf(buffer, BUFFER_LOG_SIZE, format, arg);
va_end( arg );
int sems_lvl = L_ERR;
switch(level) {
case ZRTP_LOG_DEBUG: sems_lvl = L_DBG; break;
case ZRTP_LOG_INFO: sems_lvl = L_INFO; break;
case ZRTP_LOG_WARNING: sems_lvl = L_WARN; break;
case ZRTP_LOG_ERROR: sems_lvl = L_ERR; break;
case ZRTP_LOG_FATAL: sems_lvl = L_ERR; break;
case ZRTP_LOG_ALL: sems_lvl = L_ERR; break;
}
_LOG(sems_lvl, "*** %s", buffer);
}
#endif

@ -0,0 +1,73 @@
/*
* $Id: AmZRTP.h 934 2008-05-06 09:25:34Z sayer $
*
* Copyright (C) 2008 iptego GmbH
*
* This file is part of sems, a free SIP media server.
*
* sems 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems 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 _AM_ZRTP_H
#define _AM_ZRTP_H
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#include "AmThread.h"
#include "AmEvent.h"
#include <string>
#include "zrtp/zrtp.h"
extern zrtp_global_ctx_t zrtp_global; // persistent storage for libzrtp data
extern zrtp_zid_t zrtp_instance_zid;
struct AmZRTPEvent : public AmEvent {
zrtp_stream_ctx_t* stream_ctx;
AmZRTPEvent(int event_id, zrtp_stream_ctx_t* stream_ctx)
: AmEvent(event_id), stream_ctx(stream_ctx) { }
~AmZRTPEvent() { }
};
struct AmZRTP {
static int zrtp_cache_save_cntr;
static std::string cache_path;
static AmMutex zrtp_cache_mut;
static int init();
static zrtp_global_ctx_t zrtp_global;
static zrtp_zid_t zrtp_instance_zid;
static void freeSession(zrtp_conn_ctx_t* zrtp_session);
};
#if defined(__cplusplus)
extern "C" {
#endif
void zrtp_get_cache_path(char *path, uint32_t length);
zrtp_status_t zrtp_cache_user_down();
#if defined(__cplusplus)
}
#endif
#endif // WITH_ZRTP
#endif //_AM_ZRTP_H

@ -4,7 +4,7 @@ LIBNAME=sems.so
PLUGIN_DIR=plug-in
SRCS=$(filter-out $(NAME).cpp, $(wildcard *.cpp))
HDRS=$(SRCS:.cpp=.h)
OBJS=$(SRCS:.cpp=.o)
OBJS=$(SRCS:.cpp=.o)
DEPS=$(SRCS:.cpp=.d) $(NAME).d
AUDIO_FILES=$(notdir $(wildcard wav/*.wav))
@ -65,6 +65,14 @@ CPPFLAGS += -DUSE_LIBSAMPLERATE
LDFLAGS +=-lsamplerate
endif
ifdef WITH_ZRTP
CPPFLAGS += -DWITH_ZRTP \
-DBUILD_ZRTP_MUTEXES \
-DBUILD_DEFAULT_CACHE -DBUILD_DEFAULT_TIMER -DUNIX -DBUILD_ZRTP_MUTEXES \
-I/usr/local/include/zrtp
LDFLAGS +=-lzrtp -lbn
endif
# implicit rules
%.o : %.cpp %.d ../Makefile.defs
$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)

@ -0,0 +1,9 @@
#
# Path to secrets cache file. Must be writable.
#
cache_path=zrtp_cache.dat
#
# ZID - must be set to a unique identifier on installation.
#
#zid=012345678901

@ -35,6 +35,8 @@
#include "AmIcmpWatcher.h"
#include "AmRtpReceiver.h"
#include "AmZRTP.h"
#include "log.h"
#include <unistd.h>
@ -70,7 +72,6 @@ int main_pid=0;
int child_pid=0;
int is_main=1;
static int parse_args(int argc, char* argv[], const string& flags,
const string& options, std::map<char,string>& args);
@ -375,6 +376,13 @@ int main(int argc, char* argv[])
init_random();
#ifdef WITH_ZRTP
if (AmZRTP::init()) {
ERROR("Some error during zrtp initialization\n");
return -1;
}
#endif
DBG("Starting session container\n");
AmSessionContainer::instance()->start();
@ -576,3 +584,4 @@ static int parse_args(int argc, char* argv[],
}
return 0;
}

@ -45,7 +45,7 @@
#define MAX_FORWARDS "70"
#define DEFAULT_SIGNATURE "Sip Express Media Server " \
"(" VERSION " (" ARCH "/" OS"))"
"(" SEMS_VERSION " (" ARCH "/" OS"))"
// session considered dead after 5 minutes no RTP
#define DEAD_RTP_TIME 5*60

Loading…
Cancel
Save