Commit f0506e16 authored by Ming Rui Zhang's avatar Ming Rui Zhang Committed by Adrien Béraud

regex: use std::regex instead of pcre, remove pattern

Sdes_negotiator: Omit pattern.h,unique_ptr Using regex
pluselayer: Remove support for pcre

Change-Id: Iab71f482df0dd89de72e28befa25abc0dadab79f
parent 3df2d8a5
......@@ -815,7 +815,6 @@
<ClCompile Include="..\src\security\memory.cpp" />
<ClCompile Include="..\src\security\tlsvalidator.cpp" />
<ClCompile Include="..\src\security\tls_session.cpp" />
<ClCompile Include="..\src\sip\pattern.cpp" />
<ClCompile Include="..\src\sip\pres_sub_client.cpp" />
<ClCompile Include="..\src\sip\pres_sub_server.cpp" />
<ClCompile Include="..\src\sip\sdes_negotiator.cpp" />
......@@ -978,7 +977,6 @@
<ClInclude Include="..\src\security\memory.h" />
<ClInclude Include="..\src\security\tlsvalidator.h" />
<ClInclude Include="..\src\security\tls_session.h" />
<ClInclude Include="..\src\sip\pattern.h" />
<ClInclude Include="..\src\sip\pres_sub_client.h" />
<ClInclude Include="..\src\sip\pres_sub_server.h" />
<ClInclude Include="..\src\sip\sdes_negotiator.h" />
......
......@@ -211,9 +211,6 @@
<ClCompile Include="..\src\sip\sipvoiplink.cpp">
<Filter>Source Files\sip</Filter>
</ClCompile>
<ClCompile Include="..\src\sip\pattern.cpp">
<Filter>Source Files\sip</Filter>
</ClCompile>
<ClCompile Include="..\src\sip\pres_sub_client.cpp">
<Filter>Source Files\sip</Filter>
</ClCompile>
......@@ -762,9 +759,6 @@
<ClInclude Include="..\src\security\tlsvalidator.h">
<Filter>Source Files\security</Filter>
</ClInclude>
<ClInclude Include="..\src\sip\pattern.h">
<Filter>Source Files\sip</Filter>
</ClInclude>
<ClInclude Include="..\src\sip\pres_sub_client.h">
<Filter>Source Files\sip</Filter>
</ClInclude>
......
......@@ -39,27 +39,14 @@
#include <fstream>
#include <cstring>
// Std-C++11 regex feature implemented only since GCC 4.9
// Using pcre library as replacement
//#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9
#define USE_PCRE_REGEX
#include <pcre.h>
//#else
//#include <regex>
//#endif
#include <regex>
// uncomment to log pulseaudio sink and sources
//#define PA_LOG_SINK_SOURCES
namespace ring {
#ifdef USE_PCRE_REGEX
static const char* ec_pcre_error;
static int ec_pcre_erroffset;
static const std::unique_ptr<pcre, decltype(pcre_free)> PA_EC_SUFFIX {pcre_compile("\\.echo-cancel(?:\\..+)?$", 0, &ec_pcre_error, &ec_pcre_erroffset, nullptr), pcre_free};
#else
static const std::regex PA_EC_SUFFIX {"\\.echo-cancel(?:\\..+)?$"};
#endif
PulseMainLoopLock::PulseMainLoopLock(pa_threaded_mainloop *loop) : loop_(loop)
{
......@@ -497,22 +484,9 @@ void PulseLayer::ringtoneToSpeaker()
std::string stripEchoSufix(std::string deviceName) {
#ifdef USE_PCRE_REGEX
if (PA_EC_SUFFIX) {
static const constexpr int resSize = 3;
int resPos[resSize] {};
int rc = pcre_exec(PA_EC_SUFFIX.get(), nullptr, deviceName.c_str(), deviceName.size(), 0, 0, resPos, resSize);
if (rc > 0) {
int start = resPos[0];
int length = resPos[1];
deviceName.replace(start, length, "");
}
} else
RING_ERR("PCRE compilation failed at offset %d: %s\n", ec_pcre_erroffset, ec_pcre_error);
return deviceName;
#else
return std::regex_replace(deviceName, PA_EC_SUFFIX, "");
#endif
}
void
......
......@@ -28,9 +28,7 @@ libsiplink_la_SOURCES+=sippresence.cpp \
if BUILD_SDES
libsiplink_la_SOURCES+= sdes_negotiator.cpp \
sdes_negotiator.h \
pattern.cpp \
pattern.h
sdes_negotiator.h
libsiplink_la_CXXFLAGS += @PCRE_CFLAGS@
endif
/*
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "pattern.h"
#include <sstream>
#include <cstdio>
namespace ring {
Pattern::Pattern(const std::string& pattern, bool matchGlobally) :
pattern_(pattern),
subject_(),
re_(NULL),
ovector_(),
offset_{0, 0},
count_(0),
matchGlobally_(matchGlobally)
{
// Compile the pattern
int offset;
const char * error;
re_ = pcre_compile(pattern_.c_str(), 0, &error, &offset, NULL);
if (re_ == NULL) {
std::string offsetStr;
std::stringstream ss;
ss << offset;
offsetStr = ss.str();
std::string msg("PCRE compiling failed at offset " + offsetStr);
throw CompileError(msg);
}
// Allocate an appropriate amount
// of memory for the output vector.
int captureCount;
pcre_fullinfo(re_, NULL, PCRE_INFO_CAPTURECOUNT, &captureCount);
ovector_.clear();
ovector_.resize((captureCount + 1) * 3);
}
Pattern::~Pattern()
{
if (re_ != NULL)
pcre_free(re_);
}
std::string Pattern::group(const char *groupName)
{
const char * stringPtr = NULL;
int rc = pcre_get_named_substring(re_, subject_.substr(offset_[0]).c_str(),
&ovector_[0], count_, groupName,
&stringPtr);
if (rc < 0) {
switch (rc) {
case PCRE_ERROR_NOSUBSTRING:
break;
case PCRE_ERROR_NOMEMORY:
throw MatchError("Memory exhausted.");
default:
throw MatchError("Failed to get named substring.");
}
}
std::string matchedStr;
if (stringPtr) {
matchedStr = stringPtr;
pcre_free_substring(stringPtr);
}
return matchedStr;
}
size_t Pattern::start() const
{
return ovector_[0] + offset_[0];
}
size_t Pattern::end() const
{
return (ovector_[1] - 1) + offset_[0];
}
bool Pattern::matches()
{
// Try to find a match for this pattern
int rc = pcre_exec(re_, NULL, subject_.substr(offset_[1]).c_str(),
subject_.length() - offset_[1], 0, 0, &ovector_[0],
ovector_.size());
// Matching failed.
if (rc < 0) {
offset_[0] = offset_[1] = 0;
return false;
}
// Handle the case if matching should be done globally
if (matchGlobally_) {
offset_[0] = offset_[1];
// New offset is old offset + end of relative offset
offset_[1] = ovector_[1] + offset_[0];
}
// Matching succeeded but not enough space.
// @TODO figure out something more clever to do in this case.
if (rc == 0)
throw MatchError("No space to store all substrings.");
// Matching succeeded. Keep the number of substrings for
// subsequent calls to group().
count_ = rc;
return true;
}
std::vector<std::string> Pattern::split()
{
size_t tokenEnd = -1;
size_t tokenStart = 0;
std::vector<std::string> substringSplitted;
while (matches()) {
tokenStart = start();
substringSplitted.push_back(subject_.substr(tokenEnd + 1,
tokenStart - tokenEnd - 1));
tokenEnd = end();
}
substringSplitted.push_back(subject_.substr(tokenEnd + 1,
tokenStart - tokenEnd - 1));
return substringSplitted;
}
} // namespace ring
/*
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __PATTERN_H__
#define __PATTERN_H__
#include <stdexcept>
#include <string>
#include <vector>
#include <pcre.h>
#include "noncopyable.h"
namespace ring {
/**
* Exception object that is thrown when
* an error occurred while compiling the
* regular expression.
*/
class CompileError : public std::invalid_argument {
public:
explicit CompileError(const std::string& error) :
std::invalid_argument(error) {}
};
/**
* Exception object that is thrown when
* an error occurred while mathing a
* pattern to an expression.
*/
class MatchError : public std::invalid_argument {
public:
MatchError(const std::string& error) :
std::invalid_argument(error) {}
};
/**
* This class implements in its way
* some of the libpcre library.
*/
class Pattern {
public:
/**
* Constructor for a regular expression
* pattern evaluator/matcher.
*
* @param pattern
* The regular expression to
* be used for this instance.
*/
Pattern(const std::string& pattern,
bool matchGlobally);
/**
* Destructor. Pcre pattern gets freed
* here.
*/
~Pattern();
/**
* Get the substring matched in a capturing
* group (named or unnamed).
*
* This methods only performs a basic lookup
* inside its internal substring table. Thus,
* matches() should have been called prior to
* this method in order to obtain the desired
* output.
*
* @param groupName The name of the group
*
* @return the substring matched by the
* regular expression designated
* the group name.
*/
std::string group(const char *groupName);
/**
* Try to match the compiled pattern with the implicit
* subject.
*
* @return true If the subject matches the pattern,
* false otherwise.
*
* @pre The regular expression should have been
* compiled prior to the execution of this method.
*
* @post The internal substring table will be updated
* with the new matches. Therefore, subsequent
* calls to group may return different results.
*/
bool matches();
/**
* Split the subject into a list of substrings.
*
* @return A vector of substrings.
*
* @pre The regular expression should have been
* compiled prior to the execution of this method.
*
* @post The internal subject won't be affected by this
* by this operation. In other words: subject_before =
* subject_after.
*/
std::vector<std::string> split();
void updateSubject(const std::string& subject) {
subject_ = subject;
}
private:
/**
* Get the start position of the overall match.
*
* @return the start position of the overall match.
*/
size_t start() const;
/**
* Get the end position of the overall match.
*
* @return the end position of the overall match.
*/
size_t end() const;
NON_COPYABLE(Pattern);
// The regular expression that represents that pattern.
std::string pattern_;
// The optional subject string.
std::string subject_;
/**
* PCRE struct that
* contains the compiled regular
* expression
*/
pcre * re_;
// The internal output vector used by PCRE.
std::vector<int> ovector_;
// Current offset in the ovector_;
int offset_[2];
// The number of substrings matched after calling pcre_exec.
int count_;
bool matchGlobally_;
};
}
#endif // __PATTERN_H__
......@@ -4,6 +4,7 @@
* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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
......@@ -12,65 +13,58 @@
*
* 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
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sdes_negotiator.h"
#include "pattern.h"
#include <memory>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <stdexcept>
#include <regex>
#include <cstdio>
namespace ring {
SdesNegotiator::SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites) :
localCapabilities_(localCapabilites)
SdesNegotiator::SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites) :
localCapabilities_(localCapabilites)
{}
std::vector<CryptoAttribute>
SdesNegotiator::parse(const std::vector<std::string>& attributes)
{
// The patterns below try to follow
// the ABNF grammar rules described in
// RFC4568 section 9.2 with the general
// syntax :
//a=crypto:tag 1*WSP crypto-suite 1*WSP key-params *(1*WSP session-param)
std::unique_ptr<Pattern> generalSyntaxPattern, tagPattern, cryptoSuitePattern,
keyParamsPattern;
// used to match white space (which are used as separator)
try {
// used to match white space (which are used as separator)
generalSyntaxPattern.reset(new Pattern("[\x20\x09]+", true));
tagPattern.reset(new Pattern("^(?P<tag>[0-9]{1,9})", false));
cryptoSuitePattern.reset(new Pattern(
"(?P<cryptoSuite>AES_CM_128_HMAC_SHA1_80|" \
"AES_CM_128_HMAC_SHA1_32|" \
"F8_128_HMAC_SHA1_80|" \
"[A-Za-z0-9_]+)", false)); // srtp-crypto-suite-ext
keyParamsPattern.reset(new Pattern(
"(?P<srtpKeyMethod>inline|[A-Za-z0-9_]+)\\:" \
"(?P<srtpKeyInfo>[A-Za-z0-9\x2B\x2F\x3D]+)" \
"(\\|2\\^(?P<lifetime>[0-9]+)\\|" \
"(?P<mkiValue>[0-9]+)\\:" \
"(?P<mkiLength>[0-9]{1,3})\\;?)?", true));
} catch (const CompileError& exception) {
throw ParseError("A compile exception occurred on a pattern.");
}
static const std::regex generalSyntaxPattern { "[\x20\x09]+" };
static const std::regex tagPattern { "^([0-9]{1,9})" };
static const std::regex cryptoSuitePattern {
"(AES_CM_128_HMAC_SHA1_80|" \
"AES_CM_128_HMAC_SHA1_32|" \
"F8_128_HMAC_SHA1_80|" \
"[A-Za-z0-9_]+)" }; // srtp-crypto-suite-ext
static const std::regex keyParamsPattern {
"(inline|[A-Za-z0-9_]+)\\:" \
"([A-Za-z0-9\x2B\x2F\x3D]+)" \
"((\\|2\\^)([0-9]+)\\|" \
"([0-9]+)\\:" \
"([0-9]{1,3})\\;?)?" };
// Take each line from the vector
// and parse its content
......@@ -79,81 +73,76 @@ SdesNegotiator::parse(const std::vector<std::string>& attributes)
for (const auto &item : attributes) {
// Split the line into its component
// that we will analyze further down.
std::vector<std::string> sdesLine;
// Split the line into its component that we will analyze further down.
// Additional white space is added to better split the content
// Result is stored in the sdsLine
generalSyntaxPattern->updateSubject(item);
std::vector<std::string> sdesLine;
std::smatch sm_generalSyntaxPattern;
try {
sdesLine = generalSyntaxPattern->split();
std::sregex_token_iterator iter(item.begin(), item.end(), generalSyntaxPattern, -1), end;
for ( ; iter != end; ++iter)
sdesLine.push_back(*iter);
if (sdesLine.size() < 3)
throw ParseError("Missing components in SDES line");
} catch (const MatchError& exception) {
throw ParseError("Error while analyzing the SDES line.");
}
if (sdesLine.size() < 3) { throw ParseError("Missing components in SDES line"); }
// Check if the attribute starts with a=crypto
// and get the tag for this line
tagPattern->updateSubject(sdesLine.at(0));
std::string tag;
std::smatch sm_tagPattern;
if ( std::regex_search(sdesLine.at(0), sm_tagPattern, tagPattern) ) {
tag = sm_tagPattern[1];
}
else{ throw ParseError("No Matching Found in Tag Attribute"); }
if (tagPattern->matches()) {
try {
tag = tagPattern->group("tag");
} catch (const MatchError& exception) {
throw ParseError("Error while parsing the tag field");
}
} else
return cryptoAttributeVector;
// Check if the crypto suite is valid and retrieve
// its value.
cryptoSuitePattern->updateSubject(sdesLine.at(1));
std::string cryptoSuite;
std::smatch sm_cryptoSuitePattern;
if (cryptoSuitePattern->matches()) {
try {
cryptoSuite = cryptoSuitePattern->group("cryptoSuite");
} catch (const MatchError& exception) {
throw ParseError("Error while parsing the crypto-suite field");
}
} else
return cryptoAttributeVector;
if ( std::regex_search(sdesLine.at(1), sm_cryptoSuitePattern, cryptoSuitePattern) ) {
cryptoSuite = sm_cryptoSuitePattern[1];
}
else{ throw ParseError("No Matching Found in CryptoSuite Attribute"); }
// Parse one or more key-params field.
keyParamsPattern->updateSubject(sdesLine.at(2));
// Group number is used to locate different paras
std::string srtpKeyInfo;
std::string srtpKeyMethod;
std::string lifetime;
std::string mkiLength;
std::string mkiValue;
std::smatch sm_keyParamsPattern;
if( std::regex_search(sdesLine.at(2), sm_keyParamsPattern,keyParamsPattern) ) {
srtpKeyMethod = sm_keyParamsPattern[1];
srtpKeyInfo = sm_keyParamsPattern[2];
lifetime = sm_keyParamsPattern[5];
mkiValue = sm_keyParamsPattern[6];
mkiLength = sm_keyParamsPattern[7];
try {
while (keyParamsPattern->matches()) {
srtpKeyMethod = keyParamsPattern->group("srtpKeyMethod");
srtpKeyInfo = keyParamsPattern->group("srtpKeyInfo");
lifetime = keyParamsPattern->group("lifetime");
mkiValue = keyParamsPattern->group("mkiValue");
mkiLength = keyParamsPattern->group("mkiLength");
}
} catch (const MatchError& exception) {
throw ParseError("Error while parsing the key-params field");
}
else{ throw ParseError("No Matching Found in Key-params Attribute"); }
// Add the new CryptoAttribute to the vector
cryptoAttributeVector.emplace_back(
tag,
cryptoSuite,
srtpKeyMethod,
srtpKeyInfo,
lifetime,
mkiValue,
mkiLength
std::move(tag),
std::move(cryptoSuite),
std::move(srtpKeyMethod),
std::move(srtpKeyInfo),
std::move(lifetime),
std::move(mkiValue),
std::move(mkiLength)
);
}
return cryptoAttributeVector;
......@@ -167,13 +156,13 @@ SdesNegotiator::negotiate(const std::vector<std::string>& attributes) const
for (const auto& iter_offer : cryptoAttributeVector) {
for (const auto& iter_local : localCapabilities_) {
if (iter_offer.getCryptoSuite() == iter_local.name)
return iter_offer;
return iter_offer;
}
}
}
catch (const ParseError& exception) {}
catch (const MatchError& exception) {}
return {};
}
} // namespace ring
......@@ -328,8 +328,8 @@ void Sdp::setLocalMediaAudioCapabilities(const std::vector<std::shared_ptr<Accou
void
Sdp::printSession(const pjmedia_sdp_session *session, const char* header)
{
sip_utils::register_thread();
static constexpr size_t BUF_SZ = 4095;
sip_utils::register_thread();
std::unique_ptr<pj_pool_t, decltype(pj_pool_release)&> tmpPool_(
pj_pool_create(&getSIPVoIPLink()->getCachingPool()->factory, "printSdp", BUF_SZ, BUF_SZ, nullptr),
pj_pool_release
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment