Merge branch 'master' into mr3.4

mr3.4.2
Andrew Pogrebennyk 12 years ago
commit 2f9a6aa33f

@ -52,6 +52,7 @@ DEF_ACTION_1P(DLGGetOtherIdAction);
DEF_ACTION_1P(DLGGetRtpRelayModeAction);
DEF_ACTION_2P(DLGReferAction);
DEF_ACTION_2P(DLGInfoAction);
DEF_ACTION_2P(DLGB2BRelayErrorAction);
DEF_ACTION_2P(DLGAddReplyBodyPartAction);

@ -74,7 +74,7 @@ int MOD_CLS_NAME::preload() {
}
int MOD_CLS_NAME::add_regex(const string& r_name, const string& r_reg) {
if (regexes[r_name].regcomp(r_reg.c_str(), REG_NOSUB | REG_EXTENDED)) {
if (regexes[r_name].regcomp(r_reg.c_str(), /* REG_NOSUB | */ REG_EXTENDED)) {
ERROR("compiling '%s' for regex '%s'\n", r_reg.c_str(), r_name.c_str());
regexes.erase(r_name);
return -1;
@ -97,8 +97,18 @@ MATCH_CONDITION_START(SCExecRegexCondition) {
return false;
}
int res = it->second.regexec(val.c_str(), 1, NULL, 0);
regmatch_t matches[it->second.get_nsub()+1];
int res = it->second.regexec(val.c_str(), it->second.get_nsub(), matches, 0);
// res==0 -> match
if (!res) {
for (size_t i=1;i<it->second.get_nsub()+1;i++) {
if (matches[i].rm_so < 0) continue;
sc_sess->var["regex.match["+int2str((unsigned int)i)+"]"] =
val.substr(matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so);
}
}
DBG("regex did %smatch\n", res==0?"":"not ");
if (inv) {
return res != 0;
@ -131,7 +141,17 @@ EXEC_ACTION_START(SCExecRegexAction) {
EXEC_ACTION_STOP;
}
int res = it->second.regexec(val.c_str(), 1, NULL, 0);
regmatch_t matches[it->second.get_nsub()+1];
int res = it->second.regexec(val.c_str(), it->second.get_nsub()+1, matches, 0);
if (!res) {
for (size_t i=1;i<it->second.get_nsub()+1;i++) {
if (matches[i].rm_so < 0) continue;
sc_sess->var["regex.match["+int2str((unsigned int)i)+"]"] =
val.substr(matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so);
}
}
if (!res) {
// yeah side effects
sc_sess->var["regex.match"] = "1";
@ -179,3 +199,7 @@ int TsRegex::regexec(const char *_string, size_t nmatch,
m.unlock();
return res;
}
size_t TsRegex::get_nsub() {
return i ? reg.re_nsub : 0;
}

@ -46,7 +46,7 @@ class TsRegex {
~TsRegex();
int regcomp(const char *regex, int cflags);
int regexec(const char *_string, size_t nmatch, regmatch_t pmatch[], int eflags);
size_t get_nsub();
};
DECLARE_MODULE_BEGIN(MOD_CLS_NAME);

@ -210,6 +210,7 @@ CONST_ACTION_2P(MODSBCActionProfileSet, ',', false);
EXEC_ACTION_START(MODSBCActionProfileSet) {
string profile_param = resolveVars(par1, sess, sc_sess, event_params);
string value = resolveVars(par2, sess, sc_sess, event_params);
FilterEntry mf;
ACTION_GET_PROFILE;
@ -268,7 +269,6 @@ EXEC_ACTION_START(MODSBCActionProfileSet) {
SET_TO_CALL_PROFILE("aleg_next_hop", aleg_next_hop);
// TODO: message_filter
// TODO: header_filter
// TODO: sdp_filter
@ -312,6 +312,22 @@ EXEC_ACTION_START(MODSBCActionProfileSet) {
EXEC_ACTION_STOP;
}
if (profile_param == "message_filter") {
mf.filter_type = String2FilterType(value.c_str());
DBG("message_filter set to '%s'\n", value.c_str());
EXEC_ACTION_STOP;
}
if (profile_param == "message_list") {
vector<string> elems = explode(value, ",");
for (vector<string>::iterator it=elems.begin(); it != elems.end(); it++)
mf.filter_list.insert(*it);
profile->messagefilter.push_back(mf);
mf.filter_type = Undefined;
DBG("message_list set to '%s'\n", value.c_str());
EXEC_ACTION_STOP;
}
}
// TODO: Transcoder Settings

@ -173,14 +173,14 @@ int JsonRpcServer::processMessage(char* msgbuf, unsigned int* msg_size,
}
string id;
bool id_is_int = false;
if (rpc_params.hasMember("id")) {
if (isArgCStr(rpc_params["id"]))
if (isArgCStr(rpc_params["id"])) {
id = rpc_params["id"].asCStr();
else if (isArgInt(rpc_params["id"]))
} else if (isArgInt(rpc_params["id"])) {
id = int2str(rpc_params["id"].asInt());
else if (isArgBool(rpc_params["id"]))
id = rpc_params["id"].asBool() ? "True":"False";
else {
id_is_int = true;
} else {
ERROR("incorrect type for jsonrpc id <%s>\n",
AmArg::print(rpc_params["id"]).c_str());
}
@ -237,11 +237,18 @@ int JsonRpcServer::processMessage(char* msgbuf, unsigned int* msg_size,
}
AmArg rpc_res;
int int_id;
execRpc(rpc_params, rpc_res);
// rpc_res["error"] = AmArg(); // Undef/null
// rpc_res["id"] = rpc_params["id"];
if (!id.empty()) {
if (id_is_int) {
str2int(id, int_id);
rpc_res["id"] = int_id;
} else {
rpc_res["id"] = id;
}
}
string res_s = arg2json(rpc_res);
if (res_s.length() > MAX_RPC_MSG_SIZE) {
@ -287,7 +294,6 @@ void JsonRpcServer::execRpc(const string& method, const string& id, const AmArg&
if (factory == "core") {
runCoreMethod(fact_meth, params, rpc_res["result"]);
rpc_res["id"] = id;
rpc_res["error"] = AmArg(); // Undef/null
rpc_res["jsonrpc"] = "2.0";
return;
}
@ -344,10 +350,9 @@ void JsonRpcServer::execRpc(const string& method, const string& id, const AmArg&
// todo: notification!
rpc_res["id"] = id;
rpc_res["jsonrpc"] = "2.0";
rpc_res.erase("result");
return;
}
rpc_res["error"] = AmArg(); // Undef/null
}
void JsonRpcServer::runCoreMethod(const string& method, const AmArg& params, AmArg& res) {

@ -25,7 +25,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "AmEventDispatcher.h"
#include "AmSessionContainer.h"
#include "AmAppTimer.h"
#include "log.h"
@ -88,8 +88,8 @@ void _AmAppTimer::app_timer_cb(app_timer* at)
user_timers[at->get_q_id()][at->get_id()] = at_local;
} else {
DBG("timer fired: %d for '%s'\n", at->get_id(), at->get_q_id().c_str());
AmEventDispatcher::instance()->post(at->get_q_id(),
new AmTimeoutEvent(at->get_id()));
AmSessionContainer::instance()->postEvent(at->get_q_id(),
new AmTimeoutEvent(at->get_id()));
delete at;
}

@ -585,12 +585,13 @@ void AmB2BMedia::changeSessionUnsafe(bool a_leg, AmB2BSession *new_session)
for (RelayStreamIterator j = relay_streams.begin(); j != relay_streams.end(); ++j) {
AmRtpStream &a = (*j)->a;
AmRtpStream &b = (*j)->a;
AmRtpStream &b = (*j)->b;
// FIXME: is stop & resume receiving needed here?
a.changeSession(new_session);
b.changeSession(new_session);
if (a_leg)
a.changeSession(new_session);
else
b.changeSession(new_session);
}
if (needs_processing) {

@ -99,9 +99,15 @@ const char* AmBasicSipDialog::getStatusStr()
return getStatusStr(status);
}
string AmBasicSipDialog::getContactHdr()
string AmBasicSipDialog::getContactHdr() {
return
SIP_HDR_COLSP(SIP_HDR_CONTACT) "<"+ getContactUri() += ">" CRLF;
}
string AmBasicSipDialog::getContactUri()
{
string contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) "<sip:";
string contact_uri = "sip:";
if(!ext_local_tag.empty()) {
contact_uri += local_tag + "@";
@ -118,8 +124,6 @@ string AmBasicSipDialog::getContactHdr()
contact_uri += ";" + contact_params;
}
contact_uri += ">" CRLF;
return contact_uri;
}

@ -310,6 +310,11 @@ public:
*/
string getContactHdr();
/**
* Compute the Contact URI for the next request
*/
string getContactUri();
/**
* Compute the Route-HF for the next request
*/

@ -52,6 +52,7 @@ int AmAudioRtpFormat::setCurrentPayload(Payload pl)
this->advertized_rate = pl.advertised_clock_rate;
DBG("fmt.advertized_rate = %d", this->advertized_rate);
this->frame_size = 20*this->rate/1000;
DBG("fmt.sdp_format_parameters = %s", this->sdp_format_parameters.c_str());
if (this->codec != NULL) {
destroyCodec();
}
@ -333,6 +334,8 @@ int AmRtpAudio::init(const AmSdp& local,
}
fmt_p->setCurrentPayload(payloads[pl_it->second.index]);
fmt.reset(fmt_p);
amci_codec_t* codec = fmt->getCodec();
use_default_plc = ((codec==NULL) || (codec->plc == NULL));
fec.reset(new LowcFE(getSampleRate()));
@ -371,7 +374,13 @@ int AmRtpAudio::setCurrentPayload(int payload)
}
this->payload = payload;
return ((AmAudioRtpFormat*)fmt.get())->setCurrentPayload(payloads[index]);
int res = ((AmAudioRtpFormat*)fmt.get())->setCurrentPayload(payloads[index]);
amci_codec_t* codec = fmt->getCodec();
use_default_plc = ((codec==NULL) || (codec->plc == NULL));
return res;
}
else {
return 0;

@ -33,14 +33,19 @@ using std::map;
#include "strings.h"
#endif
#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"
static void parse_session_attr(AmSdp* sdp_msg, char* s, char** next);
static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s);
static void parse_sdp_connection(AmSdp* sdp_msg, char* s, char t);
static char* parse_sdp_connection(AmSdp* sdp_msg, char* s, char t);
static void parse_sdp_media(AmSdp* sdp_msg, char* s);
static void parse_sdp_attr(AmSdp* sdp_msg, char* s);
static char* parse_sdp_attr(AmSdp* sdp_msg, char* s);
static void parse_sdp_origin(AmSdp* sdp_masg, char* s);
inline char* get_next_line(char* s);
inline char* skip_till_next_line(char* s, size_t& line_len);
static char* is_eql_next(char* s);
static char* parse_until(char* s, char end);
static char* parse_until(char* s, char* end, char c);
@ -555,7 +560,7 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
{
if (!s) return true; // SDP can't be empty, return error (true really used for failure?)
char* next=0;
char* next=0; size_t line_len = 0;
register parse_st state;
//default state
state=SDP_DESCR;
@ -568,11 +573,13 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
case 'v':
{
s = is_eql_next(s);
next = get_next_line(s);
if (int(next-s)-2 >= 0) {
string version(s, int(next-s)-2);
next = skip_till_next_line(s, line_len);
if (line_len) {
string version(s, line_len);
str2i(version, sdp_msg->version);
//DBG("parse_sdp_line_ex: found version\n");
// DBG("parse_sdp_line_ex: found version '%s'\n", version.c_str());
} else {
sdp_msg->version = 0;
}
s = next;
state = SDP_DESCR;
@ -588,23 +595,24 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
break;
case 's':
{
//DBG("parse_sdp_line_ex: found session\n");
s = is_eql_next(s);
next = get_next_line(s);
if (int(next-s)-2 >= 0) {
string sessionName(s, int(next-s)-2);
sdp_msg->sessionName = sessionName;
next = skip_till_next_line(s, line_len);
if (line_len) {
sdp_msg->sessionName = string(s, line_len);
} else {
sdp_msg->sessionName.clear();
}
s = next;
break;
}
case 'u': {
//DBG("parse_sdp_line_ex: found uri\n");
s = is_eql_next(s);
next = get_next_line(s);
if (int(next-s)-2 >= 0) {
sdp_msg->uri = string(s, int(next-s)-2);
next = skip_till_next_line(s, line_len);
if (line_len) {
sdp_msg->uri = string(s, line_len);
} else {
sdp_msg->uri.clear();
}
s = next;
} break;
@ -615,14 +623,11 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
case 'b':
case 't':
case 'k':
//DBG("parse_sdp_line_ex: found unknown line '%c'\n", *s);
s = is_eql_next(s);
next = get_next_line(s);
s = next;
s = skip_till_next_line(s, line_len);
state = SDP_DESCR;
break;
case 'a':
//DBG("parse_sdp_line_ex: found attributes\n");
s = is_eql_next(s);
parse_session_attr(sdp_msg, s, &next);
// next = get_next_line(s);
@ -631,11 +636,9 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
state = SDP_DESCR;
break;
case 'c':
//DBG("parse_sdp_line_ex: found connection\n");
s = is_eql_next(s);
parse_sdp_connection(sdp_msg, s, 'd');
s = get_next_line(s);
state = SDP_DESCR;
s = parse_sdp_connection(sdp_msg, s, 'd');
state = SDP_DESCR;
break;
case 'm':
//DBG("parse_sdp_line_ex: found media\n");
@ -644,11 +647,17 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
default:
{
next = get_next_line(s);
if (int(next-s)-2 >= 0) {
string line(s, int(next-s)-2);
next = skip_till_next_line(s, line_len);
if (line_len) {
sdp_msg->uri = string(s, line_len);
} else {
sdp_msg->uri.clear();
}
next = skip_till_next_line(s, line_len);
if (line_len) {
DBG("parse_sdp_line: skipping unknown Session description %s=\n",
(char*)line.c_str());
string(s, line_len).c_str());
}
s = next;
break;
@ -661,45 +670,42 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
case 'm':
s = is_eql_next(s);
parse_sdp_media(sdp_msg, s);
s = get_next_line(s);
s = skip_till_next_line(s, line_len);
state = SDP_MEDIA;
break;
case 'i':
s = is_eql_next(s);
s = get_next_line(s);
s = skip_till_next_line(s, line_len);
state = SDP_MEDIA;
break;
case 'c':
s = is_eql_next(s);
//DBG("parse_sdp_line: found media connection\n");
parse_sdp_connection(sdp_msg, s, 'm');
s = get_next_line(s);
s = parse_sdp_connection(sdp_msg, s, 'm');
state = SDP_MEDIA;
break;
case 'b':
s = is_eql_next(s);
s = get_next_line(s);
s = skip_till_next_line(s, line_len);
state = SDP_MEDIA;
break;
case 'k':
s = is_eql_next(s);
s = get_next_line(s);
s = skip_till_next_line(s, line_len);
state = SDP_MEDIA;
break;
case 'a':
s = is_eql_next(s);
parse_sdp_attr(sdp_msg, s);
s = get_next_line(s);
s = parse_sdp_attr(sdp_msg, s);
state = SDP_MEDIA;
break;
default :
{
next = get_next_line(s);
if (int(next-s)-2 >= 0) {
string line(s, int(next-s)-2);
DBG("parse_sdp_line: skipping unknown Media description '%s'\n",
(char*)line.c_str());
next = skip_till_next_line(s, line_len);
if (line_len) {
DBG("parse_sdp_line: skipping unknown Media description '%.*s'\n",
(int)line_len, s);
}
s = next;
break;
@ -713,17 +719,23 @@ static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
}
static void parse_sdp_connection(AmSdp* sdp_msg, char* s, char t)
static char* parse_sdp_connection(AmSdp* sdp_msg, char* s, char t)
{
char* connection_line=s;
char* next=0;
char* line_end=0;
char* next_line=0;
size_t line_len = 0;
int parsing=1;
SdpConnection c;
line_end = get_next_line(s);
next_line = skip_till_next_line(s, line_len);
if (line_len <= 7) { // should be at least c=IN IP4 ...
DBG("short connection line '%.*s'\n", (int)line_len, s);
return next_line;
}
register sdp_connection_st state;
state = NET_TYPE;
@ -732,34 +744,35 @@ static void parse_sdp_connection(AmSdp* sdp_msg, char* s, char t)
while(parsing){
switch(state){
case NET_TYPE:
//Ignore NET_TYPE since it is always IN
connection_line +=3;
//Ignore NET_TYPE since it is always IN, fixme
c.network = NT_IN; // fixme
connection_line +=3; // fixme
state = ADDR_TYPE;
break;
case ADDR_TYPE:
{
string addr_type(connection_line,3);
connection_line +=4;
connection_line +=4; // fixme
if(addr_type == "IP4"){
c.addrType = 1;
c.addrType = AT_V4;
state = IP4;
}else if(addr_type == "IP6"){
c.addrType = 2;
c.addrType = AT_V6;
state = IP6;
}else{
ERROR("parse_sdp_connection: Unknown addr_type in c=\n");
c.addrType = 0;
parsing = 0;
DBG("parse_sdp_connection: Unknown addr_type in c-line: '%s'\n", addr_type.c_str());
c.addrType = AT_NONE;
parsing = 0; // ???
}
break;
}
case IP4:
{
if(contains(connection_line, line_end, '/')){
if(contains(connection_line, next_line, '/')){
next = parse_until(s, '/');
c.address = string(connection_line,int(next-connection_line)-2);
}else{
c.address = string(connection_line, int(line_end-connection_line)-2);
c.address = string(connection_line, line_len-7);
}
parsing = 0;
break;
@ -767,11 +780,11 @@ static void parse_sdp_connection(AmSdp* sdp_msg, char* s, char t)
case IP6:
{
if(contains(connection_line, line_end, '/')){
if(contains(connection_line, next_line, '/')){
next = parse_until(s, '/');
c.address = string(connection_line, int(next-connection_line)-2);
}else{
c.address = string(connection_line, int(line_end-connection_line)-2);
c.address = string(connection_line, line_len-7);
}
parsing = 0;
break;
@ -788,7 +801,7 @@ static void parse_sdp_connection(AmSdp* sdp_msg, char* s, char t)
}
//DBG("parse_sdp_line_ex: parse_sdp_connection: done parsing sdp connection\n");
return;
return next_line;
}
@ -930,7 +943,8 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
// session level attribute
static void parse_session_attr(AmSdp* sdp_msg, char* s, char** next) {
*next = get_next_line(s);
size_t line_len = 0;
*next = skip_till_next_line(s, line_len);
if (*next == s) {
WARN("premature end of SDP in session attr\n");
while (**next != '\0') (*next)++;
@ -938,7 +952,7 @@ static void parse_session_attr(AmSdp* sdp_msg, char* s, char** next) {
}
char* attr_end = *next-1;
while (attr_end >= s &&
((*attr_end == 10) || (*attr_end == 13)))
((*attr_end == LF) || (*attr_end == CR)))
attr_end--;
if (*attr_end == ':') {
@ -959,15 +973,14 @@ static void parse_session_attr(AmSdp* sdp_msg, char* s, char** next) {
string(col, attr_end-col+1)));
// DBG("got session attribute '%.*s:%.*s'\n", (int)(col-s-1), s, (int)(attr_end-col+1), col);
}
}
// media level attribute
static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
static char* parse_sdp_attr(AmSdp* sdp_msg, char* s)
{
if(sdp_msg->media.empty()){
ERROR("While parsing media options: no actual media !\n");
return;
return s;
}
SdpMedia& media = sdp_msg->media.back();
@ -981,20 +994,16 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
char* attr_line=s;
char* next=0;
char* line_end=0;
size_t line_len = 0;
int parsing = 1;
line_end = get_next_line(attr_line);
line_end = skip_till_next_line(attr_line, line_len);
unsigned int payload_type, clock_rate, encoding_param = 0;
string encoding_name, params;
string attr;
if (!contains(attr_line, line_end, ':')) {
next = parse_until(attr_line, '\r');
if (next >= line_end) {
DBG("found attribute line '%s', which is not followed by cr\n", attr_line);
next = line_end;
}
attr = string(attr_line, int(next-attr_line)-1);
attr = string(attr_line, line_len);
attr_check(attr);
parsing = 0;
} else {
@ -1089,10 +1098,10 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
} else if(attr == "fmtp"){
while(parsing){
switch(fmtp_st){
switch(fmtp_st){ // fixme
case FORMAT:
{
next = parse_until(attr_line, ' ');
next = parse_until(attr_line, line_end, ' ');
string fmtp_format(attr_line, int(next-attr_line)-1);
str2i(fmtp_format, payload_type);
attr_line = next;
@ -1100,12 +1109,12 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
break;
}
case FORMAT_PARAM:
{
line_end--;
while (is_wsp(*line_end))
line_end--;
{
char* param_end = line_end-1;
while (is_wsp(*param_end))
param_end--;
params = string(attr_line, line_end-attr_line+1);
params = string(attr_line, param_end-attr_line+1);
parsing = 0;
}
break;
@ -1127,21 +1136,20 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
} else if (attr == "direction") {
if (parsing) {
next = parse_until(attr_line, '\r');
if(next < line_end){
string value(attr_line, int(next-attr_line)-1);
if (value == "active") {
media.dir=SdpMedia::DirActive;
// DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
} else if (value == "passive") {
media.dir=SdpMedia::DirPassive;
//DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
} else if (attr == "both") {
media.dir=SdpMedia::DirBoth;
//DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
}
size_t dir_len = 0;
next = skip_till_next_line(attr_line, dir_len);
string value(attr_line, dir_len);
if (value == "active") {
media.dir=SdpMedia::DirActive;
// DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
} else if (value == "passive") {
media.dir=SdpMedia::DirPassive;
//DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
} else if (attr == "both") {
media.dir=SdpMedia::DirBoth;
//DBG("found media attr 'direction' value '%s'\n", (char*)value.c_str());
} else {
DBG("found media attribute 'direction', but value is not followed by cr\n");
DBG("found unknown value for media attribute 'direction'\n");
}
} else {
DBG("ignoring direction attribute without value\n");
@ -1162,12 +1170,9 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
attr_check(attr);
string value;
if (parsing) {
next = parse_until(attr_line, '\r');
if(next >= line_end){
DBG("found media attribute '%s', but value is not followed by cr\n",
(char *)attr.c_str());
}
value = string (attr_line, int(next-attr_line)-1);
size_t attr_len = 0;
next = skip_till_next_line(attr_line, attr_len);
value = string (attr_line, attr_len);
}
// if (value.empty()) {
@ -1177,6 +1182,7 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
// }
media.attributes.push_back(SdpAttribute(attr, value));
}
return line_end;
}
static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
@ -1184,7 +1190,8 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
char* origin_line = s;
char* next=0;
char* line_end=0;
line_end = get_next_line(s);
size_t line_len=0;
line_end = skip_till_next_line(s, line_len);
register sdp_origin_st origin_st;
origin_st = USER;
@ -1248,6 +1255,7 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
break;
}
string net_type(origin_line, int(next-origin_line)-1);
origin.conn.network = NT_IN; // fixme
origin_line = next;
origin_st = ADDR;
break;
@ -1260,7 +1268,17 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
origin_st = UNICAST_ADDR;
break;
}
string addr_type(origin_line, int(next-origin_line)-1);
if(addr_type == "IP4"){
origin.conn.addrType = AT_V4;
}else if(addr_type == "IP6"){
origin.conn.addrType = AT_V6;
}else{
DBG("parse_sdp_connection: Unknown addr_type in o line: '%s'\n", addr_type.c_str());
origin.conn.addrType = AT_NONE;
}
origin_line = next;
origin_st = UNICAST_ADDR;
break;
@ -1268,12 +1286,18 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
case UNICAST_ADDR:
{
next = parse_until(origin_line, ' ');
//check if line contains more values than allowed
if(next > line_end){
origin.conn.address = string(origin_line, int(line_end-origin_line)-2);
}else{
DBG("parse_sdp_origin: 'o=' contains more values than allowed; these values will be ignored\n");
origin.conn.address = string(origin_line, int(next-origin_line)-1);
if (next != origin_line) {
//check if line contains more values than allowed
if(next > line_end){
size_t addr_len = 0;
skip_till_next_line(origin_line, addr_len);
origin.conn.address = string(origin_line, addr_len);
}else{
DBG("parse_sdp_origin: 'o=' contains more values than allowed; these values will be ignored\n");
origin.conn.address = string(origin_line, int(next-origin_line)-1);
}
} else {
origin.conn.address = "";
}
parsing = 0;
break;
@ -1328,6 +1352,28 @@ static char* parse_until(char* s, char* end, char c)
return line;
}
static size_t len_till_eol(char* s, char* end)
{
size_t res=0;
char* line=s;
while(line<end && *line && *line != '\r' && *line != '\n'){
line++;
res++;
}
return res;
}
static size_t len_till_char_or_eol(char* s, char* end, char c)
{
size_t res=0;
char* line=s;
while(line<end && *line && *line != c && *line != '\r' && *line != '\n'){
line++;
res++;
}
return res;
}
static char* is_eql_next(char* s)
{
char* current_line=s;
@ -1343,20 +1389,53 @@ inline char* get_next_line(char* s)
char* next_line=s;
//search for next line
while( *next_line != '\0') {
if(*next_line == 13){
next_line +=2;
if(*next_line == CR){
next_line++;
if (*next_line == LF) {
next_line++;
break;
} else {
continue;
}
} else if (*next_line == LF){
next_line++;
break;
}
else if(*next_line == 10){
next_line +=1;
break;
}
next_line++;
}
return next_line;
}
/* skip to 0, CRLF or LF;
@return line_len length of current line
@return start of next line
*/
inline char* skip_till_next_line(char* s, size_t& line_len)
{
char* next_line=s;
line_len = 0;
//search for next line
while( *next_line != '\0') {
if (*next_line == CR) {
next_line++;
if (*next_line == LF) {
next_line++;
break;
} else {
continue;
}
} else if (*next_line == LF){
next_line++;
break;
}
line_len++;
next_line++;
}
return next_line;
}
/*
*Check if known media type is used

@ -66,10 +66,10 @@ class AmSipTimeoutEvent: public AmSipEvent
AmSipReply rpl;
AmSipTimeoutEvent(EvType t, unsigned int cseq_num)
: AmSipEvent(), type(t)
: AmSipEvent(), type(t), cseq(cseq_num)
{}
AmSipTimeoutEvent(EvType t, AmSipRequest &_req, AmSipReply &_rpl)
: AmSipEvent(), type(t), req(_req), rpl(_rpl)
: AmSipEvent(), type(t), req(_req), rpl(_rpl), cseq(_req.cseq)
{}
virtual void operator() (AmBasicSipDialog* dlg);

@ -287,7 +287,8 @@ void AmSIPRegistration::onSipReply(const AmSipRequest& req,
DBG("positive reply to REGISTER!\n");
size_t end = 0;
string local_contact_hdr = dlg.getContactHdr();
string local_contact_hdr = info.contact.empty() ?
dlg.getContactUri() : info.contact;
local_contact.parse_contact(local_contact_hdr, (size_t)0, end);
local_contact.dump();

@ -29,7 +29,7 @@
#define _amci_h_
/** AUDIO_BUFFER_SIZE must be a power of 2 */
#define AUDIO_BUFFER_SIZE (1<<12) /* 2 KB */
#define AUDIO_BUFFER_SIZE (1<<13) /* 4 KB samples */
#ifdef __cplusplus
extern "C" {

@ -85,4 +85,6 @@
#define CODEC_iSAC_WB 40
#define CODEC_OPUS 50
#endif

@ -215,7 +215,7 @@ void log_stacktrace(int ll)
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; ++i) {
_LOG(ll,"stack-trace(%i): %s", i, strs[i]);
_LOG(ll,"stack-trace(%i/[%p]): %s", i, callstack[i], strs[i]);
}
free(strs);
}

@ -0,0 +1,8 @@
COREPATH =../..
plug_in_name = opus
#module_cflags = -I /opt/include
module_ldflags = -lm -fPIC -lopus
include ../Makefile.audio_module

@ -0,0 +1,246 @@
/*
* Copyright (C) 2002-2003 Fhg Fokus
*
* 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. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS 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
*/
#include "amci.h"
#include "codecs.h"
#include "../../log.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/**
* @file plug-in/opus/opus.c
* OPUS support
* This plug-in imports the OPUS Codec.
*
* See http://www.opus-codec.org/ .
* Features: <ul>
* <li>OPUS codec/payload/subtype
* <li>OPUS file format
* </ul>
*
*/
#include <opus/opus.h>
#define _OPUS_APPLICATION_ OPUS_APPLICATION_VOIP
/* Allowed values:
OPUS_APPLICATION_VOIP Process signal for improved speech intelligibility.
OPUS_APPLICATION_AUDIO Favor faithfulness to the original input.
OPUS_APPLICATION_RESTRICTED_LOWDELAY Configure the minimum possible coding delay by disabling certain modes of operation.*/
#define _OPUS_MAX_BANDWIDTH_ OPUS_BANDWIDTH_FULLBAND
/* Allowed values:
OPUS_BANDWIDTH_NARROWBAND - 4 kHz passband
OPUS_BANDWIDTH_MEDIUMBAND - 6 kHz passband
OPUS_BANDWIDTH_WIDEBAND - 8 kHz passband
OPUS_BANDWIDTH_SUPERWIDEBAND - 12 kHz passband
OPUS_BANDWIDTH_FULLBAND - 20 kHz passband */
#define _OPUS_PKT_LOSS_PCT_ 5
/* Allowed values: 0 - 100 */
#define _OPUS_COMPLEXITY_ 10
/* Allowed values: 0 - 10, where 10 is highest computational complexity */
#define _OPUS_INBAND_FEC_ 1
/* Forward error correction.
Allowed values: 0 - 1 */
#define _OPUS_DTX_ 0
/* Discontinued transmission
Allowed values: 0 - 1 */
static int opus_2_pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec );
static int opus_plc( unsigned char* out_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec );
static int pcm16_2_opus( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec );
static long opus_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
static void opus_destroy(long h_inst);
#if SYSTEM_SAMPLECLOCK_RATE >= 48000
#define _OPUS_RATE 48000
#elif SYSTEM_SAMPLECLOCK_RATE >= 24000
#define _OPUS_RATE 24000
#elif SYSTEM_SAMPLECLOCK_RATE >= 12000
#define _OPUS_RATE 12000
#elif SYSTEM_SAMPLECLOCK_RATE >= 8000
#define _OPUS_RATE 8000
#else
#error Minimal sample rate for OPUS codec is 8000.
#endif
BEGIN_EXPORTS( "opus" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC( CODEC_OPUS, pcm16_2_opus, opus_2_pcm16, opus_plc,
opus_create,
opus_destroy,
NULL, NULL )
END_CODECS
BEGIN_PAYLOADS
PAYLOAD( -1, "opus", _OPUS_RATE, 48000, 1, CODEC_OPUS, AMCI_PT_AUDIO_FRAME )
END_PAYLOADS
BEGIN_FILE_FORMATS
END_FILE_FORMATS
END_EXPORTS
typedef struct {
OpusEncoder* opus_enc;
OpusDecoder* opus_dec;
} opus_state_t;
long opus_create(const char* format_parameters, amci_codec_fmt_info_t* format_description) {
opus_state_t* codec_inst;
int error;
if (format_parameters) {
DBG("OPUS params: >>%s<<.\n", format_parameters);
}
format_description[0].id = AMCI_FMT_FRAME_LENGTH ;
format_description[0].value = 20;
format_description[1].id = AMCI_FMT_FRAME_SIZE;
format_description[1].value = 20 * _OPUS_RATE / 1000;
format_description[2].id = 0;
codec_inst = (opus_state_t*)malloc(sizeof(opus_state_t));
if (!codec_inst)
return -1;
codec_inst->opus_enc = opus_encoder_create(_OPUS_RATE,1,_OPUS_APPLICATION_,&error);
if (error) {
DBG("OPUS: error %d while creating encoder state.\n", error);
return -1;
}
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_FORCE_CHANNELS(1));
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_MAX_BANDWIDTH(_OPUS_MAX_BANDWIDTH_));
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_PACKET_LOSS_PERC(_OPUS_PKT_LOSS_PCT_));
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_COMPLEXITY(_OPUS_COMPLEXITY_));
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_INBAND_FEC(_OPUS_INBAND_FEC_));
opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_DTX(_OPUS_DTX_));
codec_inst->opus_dec = opus_decoder_create(_OPUS_RATE,1,&error);
if (error) {
DBG("OPUS: error %d while creating decoder state.\n", error);
opus_encoder_destroy(codec_inst->opus_enc);
return -1;
}
return (long)codec_inst;
}
void opus_destroy(long h_inst) {
opus_state_t* codec_inst;
if (h_inst) {
codec_inst = (opus_state_t*)h_inst;
opus_encoder_destroy(codec_inst->opus_enc);
opus_decoder_destroy(codec_inst->opus_dec);
free(codec_inst);
}
}
int pcm16_2_opus( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec )
{
opus_state_t* codec_inst;
int res;
if (!h_codec){
ERROR("opus codec not initialized.\n");
return 0;
}
codec_inst = (opus_state_t*)h_codec;
res = opus_encode(codec_inst->opus_enc, (opus_int16*)in_buf, size/2/channels, out_buf, AUDIO_BUFFER_SIZE);
/* returns bytes in encoded frame */
/* DBG ("OPUS encode: size: %d, chan: %d, rate: %d, result %d.\n", size, channels, rate, res); */
return res;
}
static int opus_2_pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec )
{
opus_state_t* codec_inst;
int res;
if (!h_codec){
ERROR("opus codec not initialized.\n");
return 0;
}
codec_inst = (opus_state_t*)h_codec;
if (0<(res = opus_decode(codec_inst->opus_dec, in_buf, size, (opus_int16*)out_buf, AUDIO_BUFFER_SIZE/2, 0))) {
/* returns samples in encoded frame */
res*=2;
}
/* DBG ("OPUS decode: size: %d, chan: %d, rate: %d, result %d.\n", size, channels, rate, res); */
return res;
}
static int opus_plc( unsigned char* out_buf, unsigned int size,
unsigned int channels, unsigned int rate, long h_codec )
{
opus_state_t* codec_inst;
int res;
if (!h_codec){
ERROR("opus codec not initialized.\n");
return 0;
}
codec_inst = (opus_state_t*)h_codec;
if (size/channels > AUDIO_BUFFER_SIZE) {
/* DBG("OPUS plc: size %d, chan %d exceeds buffer size %d.\n", size, channels, AUDIO_BUFFER_SIZE); */
return 0;
}
if (0<(res = opus_decode(codec_inst->opus_dec, NULL, 0, (opus_int16*)out_buf, size/2/channels, 0))) {
/* returns samples in encoded frame */
res*=2;
}
/* DBG ("OPUS plc: size: %d, chan: %d, rate: %d, result %d.\n", size, channels, rate, res); */
return res;
}

@ -58,6 +58,11 @@ SessionTimer::SessionTimer(AmSession* s)
{
}
SessionTimer::~SessionTimer(){
if (NULL != s)
removeTimers(s);
}
bool SessionTimer::process(AmEvent* ev)
{
assert(ev);

@ -156,7 +156,7 @@ protected:
public:
SessionTimer(AmSession*);
virtual ~SessionTimer(){}
virtual ~SessionTimer();
/* @see AmSessionEventHandler */
virtual int configure(AmConfigReader& conf);

@ -36,6 +36,8 @@
#include "AmPlugIn.h"
#include "AmApi.h"
#include "sip/trans_table.h"
#include <string>
using std::string;
@ -289,6 +291,7 @@ int StatsUDPServer::execute(char* msg_buf, string& reply,
reply =
"calls - number of active calls (Session Container size)\n"
"which - print available commands\n"
"version - return SEMS version\n"
"set_loglevel <loglevel> - set log level\n"
"get_loglevel - get log level\n"
"set_cpslimit <limit> - set maximum allowed CPS\n"
@ -300,12 +303,21 @@ int StatsUDPServer::execute(char* msg_buf, string& reply,
"get_cpsavg - get calls per second (5 sec average)\n"
"get_cpsmax - get maximum of CPS since the last query\n"
"dump_transactions - dump transaction table to log (loglevel debug)\n"
"DI <factory> <function> (<args>)* - invoke DI command\n"
"\n"
"When in shutdown mode, SEMS will answer with the configured 5xx errorcode to\n"
"new INVITE and OPTIONS requests.\n"
;
}
else if (cmd_str == "version") {
reply = SEMS_VERSION;
}
else if (cmd_str == "dump_transactions") {
dumps_transactions();
reply = "200 OK";
}
else if (cmd_str.length() > 4 && cmd_str.substr(0, 4) == "set_") {
// setters
if (cmd_str.substr(4, 8) == "loglevel") {

@ -226,10 +226,16 @@ bool UACAuth::onSipReply(const AmSipRequest& req, const AmSipReply& reply,
}
int flags = SIP_FLAGS_VERBATIM | SIP_FLAGS_NOAUTH;
size_t skip = 0, pos1, pos2, hdr_start;
if (findHeader(hdrs, SIP_HDR_CONTACT, skip, pos1, pos2, hdr_start) ||
findHeader(hdrs, "m", skip, pos1, pos2, hdr_start))
flags |= SIP_FLAGS_NOCONTACT;
// resend request
if (dlg->sendRequest(ri->second.method,
&(ri->second.body),
hdrs, SIP_FLAGS_VERBATIM | SIP_FLAGS_NOAUTH) == 0) {
hdrs, flags) == 0) {
processed = true;
DBG("authenticated request successfully sent.\n");
// undo SIP dialog status change

@ -280,9 +280,12 @@ const char* sip_trans::state_str() const
void sip_trans::dump() const
{
DBG("type=%s (0x%x); msg=%p; to_tag=%.*s;"
" reply_status=%i; state=%s (%i); retr_buf=%p\n",
" reply_status=%i; state=%s (%i); retr_buf=%p; timers [%s,%s,%s]\n",
type_str(),type,msg,to_tag.len,to_tag.s,
reply_status,state_str(),state,retr_buf);
reply_status,state_str(),state,retr_buf,
timers[0]==NULL?"none":timer_name(timers[0]->type),
timers[1]==NULL?"none":timer_name(timers[1]->type),
timers[2]==NULL?"none":timer_name(timers[2]->type));
}
/** EMACS **

@ -1406,8 +1406,8 @@ int _trans_layer::cancel(trans_ticket* tt, const cstring& dialog_id,
}
if(!t){
DBG("No transaction to cancel: wrong key or finally replied\n");
bucket->unlock();
DBG("No transaction to cancel: wrong key or finally replied\n");
return 0;
}
@ -1416,8 +1416,10 @@ int _trans_layer::cancel(trans_ticket* tt, const cstring& dialog_id,
// RFC 3261 says: SHOULD NOT be sent for other request
// than INVITE.
if(req->u.request->method != sip_request::INVITE){
t->dump();
bucket->unlock();
ERROR("Trying to cancel a non-INVITE request (we SHOULD NOT do that)\n");
ERROR("Trying to cancel a non-INVITE request (we SHOULD NOT do that); inv_cseq: %u, i:%.*s\n",
inv_cseq, dialog_id.len,dialog_id.s);
return -1;
}
@ -1439,8 +1441,10 @@ int _trans_layer::cancel(trans_ticket* tt, const cstring& dialog_id,
}
case TS_COMPLETED:
ERROR("Trying to cancel a request while in TS_COMPLETED state; inv_cseq: %u, i:%.*s\n",
inv_cseq, dialog_id.len,dialog_id.s);
t->dump();
bucket->unlock();
ERROR("Trying to cancel a request while in TS_COMPLETED state\n");
return -1;
case TS_PROCEEDING:
@ -1449,8 +1453,10 @@ int _trans_layer::cancel(trans_ticket* tt, const cstring& dialog_id,
break;
default:
ERROR("Trying to cancel a request while in %s state; inv_cseq: %u, i:%.*s\n",
t->state_str(), inv_cseq, dialog_id.len,dialog_id.s);
t->dump();
bucket->unlock();
ERROR("Trying to cancel a request while in unknown state\n");
return -1;
}
@ -1836,13 +1842,24 @@ int _trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg*
if(reply_code >= 300){
if(reply_code == 503) {
if(default_bl_ttl) {
bool forget_reply = false;
if(reply_code == 503 &&
(t->state == TS_CALLING ||
t->state == TS_PROCEEDING)) {
if(!(t->flags & TR_FLAG_DISABLE_BL)) {
tr_blacklist::instance()->insert(&t->msg->remote_ip,
default_bl_ttl,"503");
}
if(!try_next_ip(bucket,t,false))
goto end;
if(msg->local_socket) { // remote reply
if(!try_next_ip(bucket,t,true))
forget_reply = true;
}
else { // local reply
if(!try_next_ip(bucket,t,false))
goto end;
}
}
// Final error reply
@ -1860,6 +1877,9 @@ int _trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg*
send_non_200_ack(msg,t);
t->reset_timer(STIMER_D, D_TIMER, bucket->get_id());
if(forget_reply)
goto end;
goto pass_reply;
case TS_ABANDONED:
@ -2488,7 +2508,11 @@ void _trans_layer::timer_expired(trans_timer* t, trans_bucket* bucket,
} break;
case STIMER_M: {
try_next_ip(bucket,tr,true);
if(!try_next_ip(bucket,tr,true)) {
// Abandon old transaction
tr->clear_timer(STIMER_A);
tr->state = TS_ABANDONED;
}
} break;
case STIMER_BL:
@ -2654,10 +2678,6 @@ int _trans_layer::try_next_ip(trans_bucket* bucket, sip_trans* tr,
tmp_msg.release();
n_tr->msg = p_msg;
// Abandon old transaction
tr->clear_timer(STIMER_A);
tr->state = TS_ABANDONED;
// take over target set
n_tr->targets = tr->targets;
tr->targets = NULL;

@ -22,6 +22,7 @@ FCT_BGN() {
log_stderr=true;
log_level=3;
FCTMF_SUITE_CALL(test_sdp);
FCTMF_SUITE_CALL(test_auth);
FCTMF_SUITE_CALL(test_headers);
FCTMF_SUITE_CALL(test_uriparser);

@ -0,0 +1,90 @@
#include "fct.h"
#include "log.h"
#include "AmSdp.h"
#define CRLF "\r\n"
#define LF "\n"
FCTMF_SUITE_BGN(test_sdp) {
FCT_TEST_BGN(normal_sdp_ok) {
AmSdp s;
string sdp =
"v=0" CRLF
"o=- 3615077380 3615077398 IN IP4 178.66.14.5" CRLF
"s=-" CRLF
"c=IN IP4 178.66.14.5" CRLF
"t=0 0" CRLF
"m=audio 21964 RTP/AVP 0 101" CRLF
"a=sendrecv" CRLF
"a=ptime:20" CRLF
"a=rtpmap:0 PCMU/8000" CRLF
"a=rtpmap:101 telephone-event/8000" CRLF
"a=fmtp:101 0-15" CRLF ;
fct_chk(!s.parse(sdp.c_str()));
fct_chk(s.version==0);
fct_chk(s.origin.user == "-");
fct_chk(s.origin.sessId == 3615077380);
fct_chk(s.origin.sessV == 3615077398);
fct_chk(s.origin.conn.address == "178.66.14.5");
fct_chk(s.origin.conn.network == NT_IN);
fct_chk(s.origin.conn.addrType == AT_V4);
fct_chk(s.conn.address == "178.66.14.5");
fct_chk(s.conn.network == NT_IN);
fct_chk(s.conn.addrType == AT_V4);
fct_chk(s.media.size() == 1);
fct_chk(s.media[0].type == MT_AUDIO);
fct_chk(s.media[0].port == 21964);
fct_chk(s.media[0].transport == TP_RTPAVP);
fct_chk(s.media[0].payloads.size()==2);
fct_chk(s.media[0].payloads[0].payload_type==0);
fct_chk(s.media[0].payloads[1].payload_type==101);
fct_chk(s.media[0].payloads[0].encoding_name=="PCMU");
fct_chk(s.media[0].payloads[1].encoding_name=="telephone-event");
} FCT_TEST_END();
FCT_TEST_BGN(sdp_LF_no_CRLF) {
AmSdp s;
string sdp =
"v=0" LF
"o=- 3615077380 3615077398 IN IP4 178.66.14.5" LF
"s=-" LF
"c=IN IP4 178.66.14.5" LF
"t=0 0" LF
"m=audio 21964 RTP/AVP 0 101" LF
"a=sendrecv" LF
"a=ptime:20" LF
"a=rtpmap:0 PCMU/8000" LF
"a=rtpmap:101 telephone-event/8000" LF
"a=fmtp:101 0-15" LF ;
fct_chk(!s.parse(sdp.c_str()));
fct_chk(s.version==0);
fct_chk(s.origin.user == "-");
fct_chk(s.origin.sessId == 3615077380);
fct_chk(s.origin.sessV == 3615077398);
fct_chk(s.origin.conn.address == "178.66.14.5");
fct_chk(s.origin.conn.network == NT_IN);
fct_chk(s.origin.conn.addrType == AT_V4);
fct_chk(s.conn.address == "178.66.14.5");
fct_chk(s.conn.network == NT_IN);
fct_chk(s.conn.addrType == AT_V4);
fct_chk(s.media.size() == 1);
fct_chk(s.media[0].type == MT_AUDIO);
fct_chk(s.media[0].port == 21964);
fct_chk(s.media[0].transport == TP_RTPAVP);
fct_chk(s.media[0].payloads.size()==2);
fct_chk(s.media[0].payloads[0].payload_type==0);
fct_chk(s.media[0].payloads[1].payload_type==101);
fct_chk(s.media[0].payloads[0].encoding_name=="PCMU");
fct_chk(s.media[0].payloads[1].encoding_name=="telephone-event");
} FCT_TEST_END();
} FCTMF_SUITE_END();

@ -5,9 +5,11 @@ set -e
dpkg-maintscript-helper rm_conffile /etc/default/sems -- "$@"
dpkg-maintscript-helper rm_conffile /etc/init.d/sems -- "$@"
# don't do anything when called with other argument than configure
case "$1" in
configure)
# add sems user
adduser --quiet --system --group --disabled-password --shell /bin/false \
--gecos "SIP Express Media Server" --home /var/run/ngcp-sems sems || true
;;
abort-upgrade|abort-remove|abort-deconfigure)
exit 0
@ -18,54 +20,6 @@ case "$1" in
;;
esac
restart_handler() {
if [ -x "/etc/init.d/ngcp-sems" ]; then
if [ -x "$(which invoke-rc.d 2>/dev/null)" ]; then
invoke-rc.d ngcp-sems restart || exit $?
else
/etc/init.d/ngcp-sems restart || exit $?
fi
fi
}
initscript_handler() {
if [ -x "/etc/init.d/ngcp-sems" ]; then
update-rc.d ngcp-sems defaults >/dev/null
invoke-rc.d ngcp-sems start || exit $?
fi
}
init_handler() {
# just invoke init script wrappers on ce systems since
# they do not provide ngcp-check_active and we don't
# have to handle inactive nodes
if ! [ -x "$(which ngcp-check_active 2>/dev/null)" ]; then
restart_handler
initscript_handler
else # do not restart daemon on inactive node in pro systems
if ngcp-check_active ; then
echo "Active node detected, restarting ngcp-sems"
restart_handler
else
echo "Inactive node detected, ignoring request to restart ngcp-sems"
fi
fi
}
# add sems user
adduser --quiet --system --group --disabled-password --shell /bin/false \
--gecos "SIP Express Media Server" --home /var/run/ngcp-sems sems || true
init_handler
echo ""
echo "***"
echo "Configuration of ngcp-sems has finished."
echo ""
echo "To restart it when configuration has changed use '/etc/init.d/ngcp-sems restart'"
echo ""
echo "To change it's configuration use 'dpkg-reconfigure ngcp-sems'"
echo "***"
echo ""
#DEBHELPER#
exit 0

@ -1,18 +0,0 @@
#!/bin/sh
# postrm script for ngcp-sems
set -e
removal_wrapper() {
# remove the init script only on ce systems, as the
# the pro system handle it inside the monitoring/HA setup
if ! [ -x "$(which ngcp-check_active 2>/dev/null)" ]; then
update-rc.d ngcp-sems remove >/dev/null
fi
}
if [ "$1" = "purge" ] ; then
removal_wrapper
fi
exit 0

@ -1,4 +1,3 @@
sipwise/sw_vcs.patch
upstream/0001-dsm-mod_dlg-q-f-make-compilable.patch
no_config.patch
py_sems_path.patch

@ -1,24 +0,0 @@
From c008d587acc92faa62afb622ce15e85a72d54c38 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=A1clav=20Kubart?= <vaclav.kubart@frafos.com>
Date: Fri, 16 May 2014 16:19:55 +0200
Subject: [PATCH] dsm mod_dlg q/f: make compilable
---
apps/dsm/mods/mod_dlg/ModDlg.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/dsm/mods/mod_dlg/ModDlg.h b/apps/dsm/mods/mod_dlg/ModDlg.h
index 23cb104..098f772 100644
--- a/apps/dsm/mods/mod_dlg/ModDlg.h
+++ b/apps/dsm/mods/mod_dlg/ModDlg.h
@@ -52,6 +52,7 @@ DEF_ACTION_1P(DLGGetOtherIdAction);
DEF_ACTION_1P(DLGGetRtpRelayModeAction);
DEF_ACTION_2P(DLGReferAction);
+DEF_ACTION_2P(DLGInfoAction);
DEF_ACTION_2P(DLGB2BRelayErrorAction);
DEF_ACTION_2P(DLGAddReplyBodyPartAction);
--
2.0.0.rc0

@ -0,0 +1,2 @@
core/compat/getarch
core/compat/getos

@ -0,0 +1,7 @@
This plugin implements JSON-RPC protocol version 2.0
(http://www.jsonrpc.org/specification) operating over TCP/Netstrings.
Each request and response is of form <size>:<request or response> where
<size> tells the number of bytes in <request or response>.
Configuration file jsonrpc.conf can contain parameters jsonrpc_port
(default 7080) and server_threads (default 5).

@ -154,19 +154,20 @@ sbc.isDisconnected() / sbc.isNoReply() / sbc.isRinging() / sbc.isConnected() / s
Actions
-------
sbc.profileSet(profile_variable, value) - set SBC profile options
*** only meaningful in 'start' event (later, most profile options are not used any more) ***
profile_variables: To, RURI, FROM, Call-ID, next_hop, RURI_host, refuse_with,
outbound_proxy, force_outbound_proxy = "yes" | "no,
*** only meaningful in 'start' event (later, most profile options
are not used any more) ***
profile_variables: To, RURI, FROM, Call-ID, next_hop, RURI_host,
refuse_with, outbound_proxy, force_outbound_proxy = "yes" | "no,
aleg_outbound_proxy, aleg_force_outbound_proxy = "yes" | "no,
next_hop_1st_req = "yes" | "no, patch_ruri_next_hop = "yes" | "no,
aleg_next_hop,
append_headers, append_headers_req,
rtprelay_enabled = "yes" | "no,
force_symmetric_rtp = "yes" | "no, aleg_force_symmetric_rtp = "yes" | "no,
msgflags_symmetric_rtp = "yes" | "no,
rtprelay_transparent_seqno = "yes" | "no, rtprelay_transparent_ssrc = "yes" | "no,
rtprelay_interface, aleg_rtprelay_interface,
rtprelay_dtmf_detection = "yes" | "no, rtprelay_dtmf_filtering = "yes" | "no
next_hop_1st_req = "yes" | "no, patch_ruri_next_hop = "yes" | "no,
aleg_next_hop, append_headers, append_headers_req,
rtprelay_enabled = "yes" | "no, force_symmetric_rtp = "yes" | "no,
aleg_force_symmetric_rtp = "yes" | "no, msgflags_symmetric_rtp =
"yes" | "no, rtprelay_transparent_seqno = "yes" | "no,
rtprelay_transparent_ssrc = "yes" | "no,
rtprelay_interface, aleg_rtprelay_interface,
rtprelay_dtmf_detection = "yes" | "no, rtprelay_dtmf_filtering =
"yes" | "no, message_filter, message_list
sbc.stopCall(string cause) - stop both call legs

@ -15,6 +15,8 @@ regex.compile(name, reg_ex)
regex.match(name, match_string)
Match match_string on regex referenced by name.
$regex.match is set to 1 if matched, 0 if not matched.
$regex.match[n] is set to nth substring match, starting with 1
($regex.match[1] is set to first substring match...)
regex.clear(name)
Clear the regex referenced by name.
@ -22,9 +24,8 @@ regex.clear(name)
Conditions:
regex.match(name, match_string)
Match match_string on regex referenced by name.
$regex.match[n] is set to nth substring match, starting with 1
($regex.match[1] is set to first substring match...)
TODO:
- implement substring adressing
- find a better way for $regex.match side-effect

@ -40,3 +40,10 @@ override_dh_auto_install:
override_dh_strip:
dh_strip --dbg-package=sems-dbg
# those binaries aren't automatically stripped
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos

@ -40,3 +40,10 @@ override_dh_auto_install:
override_dh_strip:
dh_strip --dbg-package=sems-dbg
# those binaries aren't automatically stripped
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos

@ -40,3 +40,10 @@ override_dh_auto_install:
override_dh_strip:
dh_strip --dbg-package=sems-dbg
# those binaries aren't automatically stripped
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos

@ -0,0 +1,112 @@
sems (1.6.0~dev) unstable; urgency=medium
* Devel version
-- Victor Seva <linuxmaniac@torreviejawireless.org> Thu, 03 Apr 2014 17:52:53 +0200
sems (1.5.0) maverick; urgency=low
* Core
- configurable SIP timers (global)
- timer C support (mainly for SBC)
- SUBSCRIBE/NOTIFY support
- multi-mime bodies
- wideband / multiple sample frequency support
- multiple destinations (faked SRV record)
- DNS SRV: support for 503 replies
- multi-threaded RTP receiver
- complete rework of offer/answer mechanisms
* Codecs:
- iSAC
- SILK
- SPEEX 16kHz, 32kHz
- G722
- L16
* SBC
- audio & dtmf transcoder
- call-control modules
- lots of small improvements
* Monitoring
- munin plugin
* DSM
- mod_xml: XML handling
- mod_curl: HTTP requests
- mod_subscription: SUBSCRIBE/NOTIFY
- mod_regex: regular expressions
- lots of small improvements
* App Plug-ins
- db_reg_agent: register SIP accounts from a DB
- rtmp: RTMP gateway
-- Raphael Coeffic <rco@iptel.org> Tue, 03 Jul 2012 15:06:08 +0200
sems (1.4.0) maverick; urgency=low
* SEMS 1.4.0 release
-- Stefan Sayer <stefan.sayer@frafos.com> Tue, 15 Mar 2011 11:13:05 +0100
sems (1.3.0) unstable; urgency=low
* 100rel (PRACK) support
* DNS cache, lb on SRV records
* B2B with Session Timer
* json-rpc v2 module
* SIP stack moved into core
* optimizations, especially for signaling
* many DSM improvements
-- Stefan Sayer <stefan.sayer@frafos.com> Sun, 26 Sep 2010 17:35:22 -0400
sems (1.2.0) unstable; urgency=low
* SEMS 1.2.0 release
-- Stefan Sayer <stefan.sayer@frafos.com> Tue, 30 Mar 2010 21:46:39 +0200
sems (1.1.1) unstable; urgency=low
* SEMS 1.1.1 bugfix release - fixed Via HF missing the port number
in ACK to 200 reply - do not try to scale too short RTP packets -
fixed initialization of SSL - caused random crashing of xmlrpc
server - fix size() for AmArg struct type - authenticate on both
401 and 407 reply in click2dial - fixed ssl build dependency for
DIAMETER client in deb
-- Stefan Sayer <stefan.sayer@frafos.com> Tue, 07 Jul 2009 15:13:24 +0200
sems (1.1.0-1) unstable; urgency=low
* DSM state machine scripting (it's cool!)
* an (experimental) ISDN gateway module
* binrpc: MT (SER->) and connection pool (->SER)
* MT xmlrpc server
* controlled server shutdown
* improved logging
* g722 in 8khz compat mode
* out of dialog request handling for modules & dialogs without
sessions
* audio file autorewind, AmAudio mixing
* SIP and media IP separately configurable
* UID/DID support for voicemail/-box/annrecorder
* and quite some bugs and mem leaks fixed, documentation, etc.
-- Stefan Sayer <sayer@iptel.org> Tue, 20 Jan 2009 18:11:25 +0100
sems (1.1.0-0rc1) unstable; urgency=low
* Debian Release Candidate 1 for 1.1.
-- Stefan Sayer <sayer@iptel.org> Mon, 8 Dec 2008 23:01:40 +0200
sems (1.0.0-0pre1-r856M) unstable; urgency=low
* Debian Release Candidate 1 for 1.0.
-- Stefan Sayer <sayer@iptel.org> Sun, 2 Mar 2002 23:41:31 +0200

@ -0,0 +1,54 @@
Source: sems
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Uploaders: Victor Seva <linuxmaniac@torreviejawireless.org>
Build-Depends: debhelper (>= 9~),
flite-dev,
libcurl4-openssl-dev | libcurl4-gnutls-dev,
libev-dev,
libevent-dev (>= 2.0.0),
libhiredis-dev,
libmysql++-dev,
libspandsp-dev,
libspeex-dev,
libssl-dev,
libxml2-dev,
openssl,
python-dev,
python-sip-dev
Standards-Version: 3.9.5
Package: sems
Architecture: any
Depends: adduser, python, ${misc:Depends}, ${shlibs:Depends}
Description: SIP Express Media Server, very fast and flexible SIP media server
SEMS, the SIP Express Media Server, is a free, high performance,
extensible media server and SBC for SIP (RFC3261) based VoIP services. It
features voicemail, conferencing, announcements, pre-call announcements,
prepaid service, calling card service etc.
Package: sems-dbg
Architecture: any
Section: debug
Priority: extra
Depends: sems (= ${binary:Version}), ${misc:Depends}
Description: Debugging symbols for Sems SIP Express Media Server
SEMS, the SIP Express Media Server, is a free, high performance,
extensible media server and SBC for SIP (RFC3261) based VoIP services. It
features voicemail, conferencing, announcements, pre-call announcements,
prepaid service, calling card service etc.
.
This package contains the debugging sysmbols.
Package: libsems1-dev
Architecture: any
Section: libdevel
Depends: ${misc:Depends}
Description: development files for SIP Express Media Server
SEMS, the SIP Express Media Server, is a free, high performance,
extensible media server and SBC for SIP (RFC3261) based VoIP services. It
features voicemail, conferencing, announcements, pre-call announcements,
prepaid service, calling card service etc.
.
This package contains the files needed to compile sems applications.

@ -0,0 +1,34 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: SEMS
Upstream-Contact: semsdev@lists.iptel.org
Source: http://www.iptel.org/sems
Files: *
Copyright:
2005-2014 Raphael Coeffic <rco@iptel.org>
2010-2014 FRAFOS GmbH
2005-2014 Stefan Sayer <stefan.sayer@frafos.com>
2002-2005 FhG Fokus
2006-2010 iptelorg GmbH
2007-2009 IPTEGO GmbH
2007-2013 Juha Heinanen <jh@tutpro.com>
2007 Andreas Granig <agranig@sipwise.com>
2009-2010 TelTech Systems Inc.
2006-2007 Maxim Sobolev <sobomax@sippysoft.com>
2010 Anton Zagorskiy amberovsky@gmail.com
2011-2012 Peter Lemenkov <lemenkov@gmail.com>
Various others (see README file)
License: GPL-2.0+ OpenSSL exception
On Debian systems, the full text of the GNU General Public
License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'.
* Exception: permission to copy, modify, propagate, and distribute a work
* formed by combining OpenSSL toolkit software and the code in this file,
* such as linking with software components and libraries released under
* OpenSSL project license.
Files: debian/*
Copyright: 2014 Victor Seva <linuxmaniac@torreviejawireless.org>
2008-2014, Stefan Sayer <stefan.sayer@frafos.com>
License: GPL-2+
On Debian systems, the full text of the GNU General Public
License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'.

@ -0,0 +1,13 @@
Makefile.defs usr/include/sems/
core/*.h usr/include/sems/
core/SampleArray.cc usr/include/sems/
core/amci usr/include/sems/
core/ampi usr/include/sems/
core/compat/*.c usr/include/sems/compat/
core/compat/*.h usr/include/sems/compat/
core/compat/getarch usr/include/sems/compat/
core/compat/getos usr/include/sems/compat/
core/plug-in/Makefile.app_module usr/include/sems/plug-in/
core/plug-in/Makefile.audio_module usr/include/sems/plug-in/
core/rtp usr/include/sems/
core/sip/*.h usr/include/sems/sip/

@ -0,0 +1,49 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
PYTHON_MODULES=ivr conf_auth mailbox pin_collect
EXCLUDED_MODULES=gateway examples mp3 twit
EXCLUDED_DSM_MODULES=mod_aws
EXCLUDED_DSM_PY_MODULES=mod_aws mod_py
CPPFLAGS += -DHAVE_XMLRPCPP_SSL
export USE_SPANDSP=yes LONG_DEBUG_MESSAGE=yes CPPFLAGS="$(CPPFLAGS)"
%:
dh $@
override_dh_auto_build:
$(MAKE) \
cfg-target=/etc/sems/ prefix=/usr \
exclude_app_modules="$(EXCLUDED_MODULES)" \
exclude_dsm_modules="$(EXCLUDED_DSM_MODULES)" \
DESTDIR=$(CURDIR)/debian/sems
override_dh_auto_install:
$(MAKE) -C core/ install \
DESTDIR=$(CURDIR)/debian/sems \
prefix=/usr \
cfg-target=/etc/sems/
$(MAKE) -C apps/ install \
exclude_app_modules="$(EXCLUDED_MODULES) $(PYTHON_MODULES)" \
exclude_dsm_modules="$(EXCLUDED_DSM_PY_MODULES)" \
DESTDIR=$(CURDIR)/debian/sems \
prefix=/usr \
cfg-target=/etc/sems/
override_dh_strip:
dh_strip --dbg-package=sems-dbg
# those binaries aren't automatically stripped
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos

@ -0,0 +1,25 @@
# configuration for SEMS - SIP Express Media Server
#
# this file is sourced by SEMS init script /etc/init.d/sems
# Don't start with default config as we need to deploy the ngcp-templates first
SEMS_RUN="no"
# ser configuration file
SEMS_CFG_FILE="/etc/sems/sems.conf"
# user to run SEMS as
SEMS_USER="sems"
# group to run SEMS as
SEMS_GROUP="sems"
SEMS_RUNDIR="/var/run/sems"
# sems pidfile
SEMS_PIDFILE="$SEMS_RUNDIR/sems.pid"
# set if you want to create core files
SEMS_CREATE_CORE="yes"
SEMS_COREDIR="/var/cores"

@ -0,0 +1,108 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: sems
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/stop SEMS Application Server
### END INIT INFO
. /lib/lsb/init-functions
# read configuration from /etc/default/sems file
if test -f /etc/default/sems ; then
. /etc/default/sems
fi
if test "$SEMS_RUN" = "no" ; then
log_failure_msg "Sems start disabled by default file"
exit 0
fi
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/sems
NAME=sems
DESC=sems
PARAMS=""
if ! test -d $SEMS_RUNDIR ; then
mkdir $SEMS_RUNDIR
fi
chown $SEMS_USER:$SEMS_GROUP $SEMS_RUNDIR
if test "$SEMS_PIDFILE" ; then
PARAMS="$PARAMS -P $SEMS_PIDFILE"
fi
if test "$SEMS_USER" ; then
PARAMS="$PARAMS -u $SEMS_USER"
fi
if test "$SEMS_GROUP" ; then
PARAMS="$PARAMS -g $SEMS_GROUP"
fi
if test "$SEMS_CFG_FILE" ; then
PARAMS="$PARAMS -f $SEMS_CFG_FILE"
CFGPARAMS="-f $SEMS_CFG_FILE"
fi
if test "$SEMS_CREATE_CORE" = "yes" ; then
# directory for the core dump files
[ -d $SEMS_COREDIR ] || mkdir $SEMS_COREDIR
chmod 777 $SEMS_COREDIR
echo "$SEMS_COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
echo 2 > /proc/sys/fs/suid_dumpable
ulimit -c unlimited
fi
# raise file descriptors limit - call hold consumes two fds for RTP ports and one for moh file
ulimit -n 100000
if ! test -f $DAEMON ; then
log_failure_msg "Error: cannot find $DAEMON"
exit 1
fi
LD_LIBRARY_PATH=/usr/lib/sems
export LD_LIBRARY_PATH
set -e
case "$1" in
start)
log_daemon_msg "Starting $DESC: $NAME "
start-stop-daemon --start --quiet --oknodo --pidfile $SEMS_PIDFILE \
--exec $DAEMON -- $PARAMS
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping $DESC: $NAME "
start-stop-daemon --oknodo --stop --quiet --pidfile $SEMS_PIDFILE \
--exec $DAEMON
log_end_msg $?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC: $NAME "
start-stop-daemon --oknodo --stop --quiet --pidfile \
$SEMS_PIDFILE --exec $DAEMON
sleep 5
start-stop-daemon --start --quiet --pidfile \
$SEMS_PIDFILE --exec $DAEMON -- $PARAMS
echo "."
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0

@ -0,0 +1 @@
sems: possible-gpl-code-linked-with-openssl

@ -0,0 +1,25 @@
#!/bin/sh
set -e
# don't do anything when called with other argument than configure
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
exit 0
;;
*)
echo "postinst called with unknown argument \$1'" >&2
exit 1
;;
esac
# add sems user
adduser --quiet --system --group --disabled-password --shell /bin/false \
--gecos "SIP Express Media Server" --home /var/run/sems sems || true
#DEBHELPER#
exit 0

@ -0,0 +1,18 @@
#!/bin/sh
set -e
#DEBHELPER#
if [ "$1" = "purge" ] ; then
# remove user/group on purge
if [ -x "$(command -v deluser)" ]; then
deluser --quiet --remove-home sems >/dev/null 2>&1 || true
else
echo >&2 "not removing sems system account because deluser command was not found"
fi
# remove /etc/sems if empty
rmdir /etc/sems || true
fi
exit 0

@ -40,3 +40,10 @@ override_dh_auto_install:
override_dh_strip:
dh_strip --dbg-package=sems-dbg
# those binaries aren't automatically stripped
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getarch
test -r $(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos && \
strip --remove-section=.comment --remove-section=.note --strip-unneeded \
$(CURDIR)/debian/libsems1-dev/usr/include/sems/compat/getos

@ -85,6 +85,24 @@ case "$1" in
--exec $DAEMON
log_end_msg $?
;;
restart-graceful)
log_daemon_msg "Activating shutdown mode: "
/usr/sbin/sems-stats -c "set_shutdownmode 1"
CALLS=`/usr/sbin/sems-stats | grep 'Active calls' | awk -F' ' '{print $3}'`
while [ $CALLS -ne "0" ]
do
echo "Current calls $CALLS, waiting..."
sleep 5
CALLS=`/usr/sbin/sems-stats | grep 'Active calls' | awk -F' ' '{print $3}'`
done
log_daemon_msg "Restarting $DESC: $NAME "
start-stop-daemon --oknodo --stop --quiet --pidfile \
$SEMS_PIDFILE --exec $DAEMON
sleep 5
start-stop-daemon --start --quiet --pidfile \
$SEMS_PIDFILE --exec $DAEMON -- $PARAMS
echo "."
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC: $NAME "
start-stop-daemon --oknodo --stop --quiet --pidfile \
@ -99,7 +117,7 @@ case "$1" in
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
echo "Usage: $N {start|stop|restart|restart-graceful|force-reload|status}" >&2
exit 1
;;
esac

Loading…
Cancel
Save