baresip/modules/gzrtp/session.cpp

228 lines
4.7 KiB
C++

/**
* @file session.cpp GNU ZRTP: Session class implementation
*
* Copyright (C) 2010 - 2017 Alfred E. Heggestad
*/
#include <stdint.h>
#include <re.h>
#include <baresip.h>
#include "session.h"
std::vector<Session *> Session::s_sessl;
Session::Session(const ZRTPConfig& config)
: m_start_parallel(config.start_parallel)
, m_master(NULL)
, m_encrypted(0)
{
int newid = 1;
for (std::vector<Session *>::iterator it = s_sessl.begin();
it != s_sessl.end(); ++it) {
if ((*it)->id() >= newid)
newid = (*it)->id() + 1;
}
m_id = newid;
s_sessl.push_back(this);
debug("zrtp: New session <%d>\n", id());
}
Session::~Session()
{
for (std::vector<Session *>::iterator it = s_sessl.begin();
it != s_sessl.end(); ++it) {
if (*it == this) {
s_sessl.erase(it);
break;
}
}
debug("zrtp: Session <%d> is destroyed\n", id());
}
Stream *Session::create_stream(const ZRTPConfig& config,
udp_sock *rtpsock,
udp_sock *rtcpsock,
uint32_t local_ssrc,
StreamMediaType media_type)
{
int err = 0;
Stream *st = new Stream (err, config, this, rtpsock, rtcpsock,
local_ssrc, media_type);
if (!st || err) {
delete st;
return NULL;
}
return st;
}
int Session::start_stream(Stream *stream)
{
if (stream->started())
return 0;
m_streams.push_back(stream);
// Start all streams in parallel using DH mode. This is a kind of
// probing. The first stream to receive HelloACK will be the master
// stream. If disabled, only the first stream starts in DH (master)
// mode.
if (m_start_parallel) {
if (m_master && m_encrypted)
// If we already have a master in secure state,
// start in multistream mode
return stream->start(m_master);
else
// Start a new stream in DH mode
return stream->start(NULL);
}
else {
if (!m_master) {
// Start the first stream in DH mode
m_master = stream;
return stream->start(NULL);
}
else if (m_encrypted) {
// Master is in secure state; multistream
return stream->start(m_master);
}
}
return 0;
}
bool Session::request_master(Stream *stream)
{
if (!m_start_parallel)
return true;
if (m_master)
return false;
// This is the first stream to receive HelloACK. It will be
// used as the master for the other streams in the session.
m_master = stream;
// Stop other DH-mode streams. They will be started in the
// multistream mode after the master enters secure state.
for (std::vector<Stream *>::iterator it = m_streams.begin();
it != m_streams.end(); ++it) {
if (*it != m_master) {
(*it)->stop();
}
}
return true;
}
void Session::on_secure(Stream *stream)
{
char buf[128] = "";
++m_encrypted;
if (m_encrypted == m_streams.size() && m_master) {
info("zrtp: All streams are encrypted (%s), "
"SAS is [%s] (%s)\n",
m_master->get_ciphers(),
m_master->get_sas(),
(m_master->sas_verified())? "verified" : "NOT VERIFIED");
if (m_master->sas_verified() && m_master->session()->eventh) {
if (re_snprintf(buf, sizeof(buf), "%d",
m_master->session()->id()))
(m_master->session()->eventh)
(MENC_EVENT_PEER_VERIFIED,
buf,
NULL,
m_master->session()->arg);
else
warning("zrtp: failed to print"
" verified argument\n");
}
return;
}
if (stream != m_master)
return;
// Master stream has just entered secure state. Start other
// streams in the multistream mode.
debug("zrtp: Starting other streams (%d)\n", m_streams.size() - 1);
for (std::vector<Stream *>::iterator it = m_streams.begin();
it != m_streams.end(); ++it) {
if (*it != m_master) {
(*it)->start(m_master);
}
}
}
int Session::cmd_verify_sas(struct re_printf *pf, void *arg)
{
return cmd_sas(true, pf, arg);
}
int Session::cmd_unverify_sas(struct re_printf *pf, void *arg)
{
return cmd_sas(false, pf, arg);
}
int Session::cmd_sas(bool verify, struct re_printf *pf, void *arg)
{
const struct cmd_arg *carg = (struct cmd_arg *)arg;
(void)pf;
int id = -1;
Session *sess = NULL;
if (str_isset(carg->prm))
id = atoi(carg->prm);
for (std::vector<Session *>::iterator it = s_sessl.begin();
it != s_sessl.end(); ++it) {
if ((*it)->id() == id) {
sess = *it;
break;
}
}
if (!sess) {
warning("zrtp: No session with id %d\n", id);
return EINVAL;
}
if (!sess->m_master) {
warning("zrtp: No master stream for the session with id %d\n",
sess->id());
return EFAULT;
}
sess->m_master->verify_sas(verify);
info("zrtp: Session <%d>: SAS [%s] is %s\n", sess->id(),
sess->m_master->get_sas(),
(sess->m_master->sas_verified())? "verified" : "NOT VERIFIED");
return 0;
}