diff --git a/CMakeLists.txt b/CMakeLists.txt index 7998e33d..8f83c5d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,12 +108,10 @@ ENDIF(SEMS_USE_LIBSAMPLERATE) # ZRTP support? (see zfoneproject.com) IF(SEMS_USE_ZRTP) - # TODO - SET(ZRTP_FOUND TRUE) + FIND_PACKAGE(Libzrtp REQUIRED) MESSAGE(STATUS "Using libzrtp: YES") ADD_DEFINITIONS(-DWITH_ZRTP -DBUILD_ZRTP_MUTEXES -DBUILD_DEFAULT_CACHE -DBUILD_DEFAULT_TIMER -DUNIX -DBUILD_ZRTP_MUTEXES) ELSE(SEMS_USE_ZRTP) - SET(ZRTP_FOUND FALSE) MESSAGE(STATUS "Using libzrtp: NO (default)") ENDIF(SEMS_USE_ZRTP) diff --git a/apps/click2dial/Click2Dial.cpp b/apps/click2dial/Click2Dial.cpp index fb06d47d..cdc79b40 100644 --- a/apps/click2dial/Click2Dial.cpp +++ b/apps/click2dial/Click2Dial.cpp @@ -182,7 +182,7 @@ AmSession* Click2DialFactory::onInvite(const AmSipRequest& req, AmArg& session_p AmSession* Click2DialFactory::onInvite(const AmSipRequest& req) { - return new C2DCallerDialog(req, getAnnounceFile(req), NULL, NULL); + return new C2DCallerDialog(req, getAnnounceFile(req), "", NULL); } @@ -200,6 +200,8 @@ void C2DCallerDialog::onSessionStart(const AmSipReply& rep) { setReceiving(false); invite_req.body = rep.body; + invite_req.content_type = rep.content_type; + invite_req.cseq = rep.cseq; if(wav_file.open(filename,AmAudioFile::Read)) throw string("AnnouncementDialog::onSessionStart: Cannot open file\n"); @@ -231,8 +233,13 @@ void C2DCallerDialog::process(AmEvent* event) void C2DCallerDialog::createCalleeSession() { - UACAuthCred* c = new UACAuthCred(cred.get()->realm, - cred.get()->user, cred.get()->pwd); + + UACAuthCred* c; + if (cred.get()){ + c = new UACAuthCred(cred->realm, cred->user, cred->pwd); + } else { + c = new UACAuthCred(); + } AmB2BCalleeSession* callee_session = new C2DCalleeDialog(this, c); AmSipDialog& callee_dlg = callee_session->dlg; diff --git a/apps/webconference/WebConference.cpp b/apps/webconference/WebConference.cpp index a9e54542..4ea69c48 100644 --- a/apps/webconference/WebConference.cpp +++ b/apps/webconference/WebConference.cpp @@ -884,7 +884,9 @@ void WebConferenceFactory::listRooms(const AmArg& args, AmArg& ret) { rooms_mut.lock(); for (map::iterator it = rooms.begin(); it != rooms.end(); it++) { - room_list.push(it->first.c_str()); + if (!it->second.expired()) { + room_list.push(it->first.c_str()); + } } rooms_mut.unlock(); diff --git a/apps/webconference/WebConferenceDialog.cpp b/apps/webconference/WebConferenceDialog.cpp index 7622cc3f..7e73bb36 100644 --- a/apps/webconference/WebConferenceDialog.cpp +++ b/apps/webconference/WebConferenceDialog.cpp @@ -248,6 +248,18 @@ void WebConferenceDialog::onBye(const AmSipRequest& req) disconnectConference(); } +void WebConferenceDialog::onRtpTimeout() { + DBG("RTP timeout, removing from conference\n"); + disconnectConference(); + AmSession::onRtpTimeout(); +} + +void WebConferenceDialog::onSessionTimeout() { + DBG("Session Timer: Timeout, removing from conference.\n"); + disconnectConference(); + AmSession::onSessionTimeout(); +} + void WebConferenceDialog::disconnectConference() { play_list.close(); setInOut(NULL,NULL); diff --git a/apps/webconference/WebConferenceDialog.h b/apps/webconference/WebConferenceDialog.h index 4923792b..0185b11b 100644 --- a/apps/webconference/WebConferenceDialog.h +++ b/apps/webconference/WebConferenceDialog.h @@ -105,6 +105,9 @@ public: void onDtmf(int event, int duration); void onBye(const AmSipRequest& req); + void onSessionTimeout(); + void onRtpTimeout(); + UACAuthCred* getCredentials() { return cred; } }; diff --git a/cmake/FindLibev.cmake b/cmake/FindLibev.cmake index fd90af63..5bf3504f 100644 --- a/cmake/FindLibev.cmake +++ b/cmake/FindLibev.cmake @@ -6,12 +6,12 @@ IF(LIBEV_INCLUDE_DIR AND LIBEV_LIBRARIES) ENDIF(LIBEV_INCLUDE_DIR AND LIBEV_LIBRARIES) IF(LIBEV_FOUND) - IF (NOT Speex_FIND_QUIETLY) + IF (NOT Libev_FIND_QUIETLY) MESSAGE(STATUS "Found libev includes: ${LIBEV_INCLUDE_DIR}/libev/ev.h") MESSAGE(STATUS "Found libev library: ${LIBEV_LIBRARIES}") - ENDIF (NOT Speex_FIND_QUIETLY) + ENDIF (NOT Libev_FIND_QUIETLY) ELSE(LIBEV_FOUND) - IF (Speex_FIND_REQUIRED) + IF (Libev_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could NOT find libev development files") - ENDIF (Speex_FIND_REQUIRED) + ENDIF (Libev_FIND_REQUIRED) ENDIF(LIBEV_FOUND) diff --git a/cmake/FindLibzrtp.cmake b/cmake/FindLibzrtp.cmake new file mode 100644 index 00000000..967c9d48 --- /dev/null +++ b/cmake/FindLibzrtp.cmake @@ -0,0 +1,17 @@ +FIND_PATH(LIBZRTP_INCLUDE_DIR zrtp.h HINTS /usr/include/zrtp ) +FIND_LIBRARY(LIBZRTP_LIBRARIES NAMES zrtp) + +IF(LIBZRTP_INCLUDE_DIR AND LIBZRTP_LIBRARIES) + SET(LIBZRTP_FOUND TRUE) +ENDIF(LIBZRTP_INCLUDE_DIR AND LIBZRTP_LIBRARIES) + +IF(LIBZRTP_FOUND) + IF (NOT Libzrtp_FIND_QUIETLY) + MESSAGE(STATUS "Found libzrtp includes: ${LIBZRTP_INCLUDE_DIR}/zrtp/zrtp.h") + MESSAGE(STATUS "Found libzrtp library: ${LIBZRTP_LIBRARIES}") + ENDIF (NOT Libzrtp_FIND_QUIETLY) +ELSE(LIBZRTP_FOUND) + IF (Libzrtp_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could NOT find libzrtp development files") + ENDIF (Libzrtp_FIND_REQUIRED) +ENDIF(LIBZRTP_FOUND) diff --git a/core/AmB2BSession.cpp b/core/AmB2BSession.cpp index 6a78e67f..90172713 100644 --- a/core/AmB2BSession.cpp +++ b/core/AmB2BSession.cpp @@ -124,6 +124,7 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev) n_reply.code = 491; n_reply.reason = "Request Pending"; n_reply.cseq = req_ev->req.cseq; + n_reply.local_tag = dlg.local_tag; relayEvent(new B2BSipReplyEvent(n_reply, true, SIP_METH_INVITE)); return; } diff --git a/core/AmMediaProcessor.cpp b/core/AmMediaProcessor.cpp index a52129b8..b881d81d 100644 --- a/core/AmMediaProcessor.cpp +++ b/core/AmMediaProcessor.cpp @@ -395,6 +395,7 @@ void AmMediaProcessorThread::process(AmEvent* e) case AmMediaProcessor::InsertSession: DBG("Session inserted to the scheduler\n"); sessions.insert(sr->s); + sr->s->RTPStream()->clearRTPTimeout(); break; case AmMediaProcessor::RemoveSession:{ diff --git a/core/AmRtpStream.cpp b/core/AmRtpStream.cpp index 651d19ff..bb2b0a4f 100644 --- a/core/AmRtpStream.cpp +++ b/core/AmRtpStream.cpp @@ -678,6 +678,10 @@ void AmRtpStream::clearRTPTimeout(struct timeval* recv_time) { memcpy(&last_recv_time, recv_time, sizeof(struct timeval)); } +void AmRtpStream::clearRTPTimeout() { + gettimeofday(&last_recv_time,NULL); +} + unsigned int AmRtpStream::bytes2samples(unsigned int) const { ERROR("bytes2samples called on AmRtpStream\n"); return 0; diff --git a/core/AmRtpStream.h b/core/AmRtpStream.h index 497a6213..7e839e58 100644 --- a/core/AmRtpStream.h +++ b/core/AmRtpStream.h @@ -308,6 +308,11 @@ public: */ void clearRTPTimeout(struct timeval* recv_time); + /* + * clear RTP timeout to current time + */ + void clearRTPTimeout(); + virtual unsigned int bytes2samples(unsigned int) const; /** set relay stream for RTP relaying */ diff --git a/core/AmSdp.cpp b/core/AmSdp.cpp index fca56313..86fb8780 100644 --- a/core/AmSdp.cpp +++ b/core/AmSdp.cpp @@ -23,6 +23,9 @@ using std::string; using std::map; +#include +#include + // Not on Solaris! #if !defined (__SVR4) && !defined (__sun) #include "strings.h" @@ -42,8 +45,8 @@ static char* parse_until(char* s, char* end, char c); static bool contains(char* s, char* next_line, char c); static bool is_wsp(char s); -static int media_type(std::string media); -static int transport_type(std::string transport); +static MediaType media_type(std::string media); +static TransProt transport_type(std::string transport); static bool attr_check(std::string attr); enum parse_st {SDP_DESCR, SDP_MEDIA}; @@ -81,6 +84,7 @@ inline string media_t_2_str(int mt) case MT_APPLICATION: return "application"; case MT_TEXT: return "text"; case MT_MESSAGE: return "message"; + case MT_IMAGE: return "image"; default: return ""; } } @@ -91,6 +95,7 @@ inline string transport_p_2_str(int tp) case TP_RTPAVP: return "RTP/AVP"; case TP_UDP: return "udp"; case TP_RTPSAVP: return "RTP/SAVP"; + case TP_UDPTL: return "udptl"; default: return ""; } } @@ -175,12 +180,24 @@ SdpPayload* AmSdp::telephoneEventPayload() const { void AmSdp::print(string& body) const { - string out_buf = - "v="+int2str(version)+"\r\n" - "o="+origin.user+" "+int2str(origin.sessId)+" "+int2str(origin.sessV)+" IN IP4 "+conn.address+"\r\n" - "s="+sessionName+"\r\n" - "c=IN IP4 "+conn.address+"\r\n" - "t=0 0\r\n"; + string out_buf = "v="+int2str(version)+"\r\n" + "o="+origin.user+" "+int2str(origin.sessId)+" "+ + int2str(origin.sessV)+" IN IP4 "; + if (!origin.conn.address.empty()) + out_buf += origin.conn.address+"\r\n"; + else if (!conn.address.empty()) + out_buf += conn.address+"\r\n"; + else if (media.size() && !media[0].conn.address.empty()) + out_buf += media[0].conn.address+"\r\n"; + else + out_buf += "0.0.0.0\r\n"; + + out_buf += + "s="+sessionName+"\r\n"; + if (!conn.address.empty()) + out_buf += "c=IN IP4 "+conn.address+"\r\n"; + + out_buf += "t=0 0\r\n"; // add attributes (session level) for (std::vector::const_iterator a_it= @@ -193,37 +210,43 @@ void AmSdp::print(string& body) const out_buf += "m=" + media_t_2_str(media_it->type) + " " + int2str(media_it->port) + " " + transport_p_2_str(media_it->transport); - string options; - for(std::vector::const_iterator pl_it = media_it->payloads.begin(); - pl_it != media_it->payloads.end(); pl_it++) { + if (media_it->transport == TP_RTPAVP || media_it->transport == TP_RTPSAVP) { + string options; + for(std::vector::const_iterator pl_it = media_it->payloads.begin(); + pl_it != media_it->payloads.end(); pl_it++) { out_buf += " " + int2str(pl_it->payload_type); + if (!media_it->conn.address.empty()) + options += "c=IN IP4 "+media_it->conn.address+"\r\n"; + if (pl_it->encoding_name.empty()) // don't add rtpmap if no encoding name given - continue; + continue; // "a=rtpmap:" line options += "a=rtpmap:" + int2str(pl_it->payload_type) + " " - + pl_it->encoding_name + "/" + int2str(pl_it->clock_rate); + + pl_it->encoding_name + "/" + int2str(pl_it->clock_rate); if(pl_it->encoding_param > 0){ - options += "/" + int2str(pl_it->encoding_param); + options += "/" + int2str(pl_it->encoding_param); } options += "\r\n"; // "a=fmtp:" line if(pl_it->sdp_format_parameters.size()){ - options += "a=fmtp:" + int2str(pl_it->payload_type) + " " - + pl_it->sdp_format_parameters + "\r\n"; + options += "a=fmtp:" + int2str(pl_it->payload_type) + " " + + pl_it->sdp_format_parameters + "\r\n"; } - } + } - out_buf += "\r\n" + options; + out_buf += "\r\n" + options; - if(remote_active /* dir == SdpMedia::DirActive */) - out_buf += "a=direction:passive\r\n"; + } else { + // for other transports (UDP/UDPTL) just print out fmt + out_buf += " " + media_it->fmt + "\r\n"; + } // add attributes (media level) for (std::vector::const_iterator a_it= @@ -231,6 +254,12 @@ void AmSdp::print(string& body) const out_buf += a_it->print(); } + switch (media_it->dir) { + case SdpMedia::DirActive: out_buf += "a=direction:active\r\n"; break; + case SdpMedia::DirPassive: out_buf += "a=direction:passive\r\n"; break; + case SdpMedia::DirBoth: out_buf += "a=direction:both\r\n"; break; + case SdpMedia::DirUndefined: break; + } } body = out_buf; @@ -727,7 +756,6 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s) SdpPayload payload; unsigned int payload_type; DBG("parse_sdp_line_ex: parse_sdp_media: parsing media description...\n"); - m.dir = SdpMedia::DirBoth; while(parsing){ switch(state){ @@ -738,7 +766,7 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s) if (next > media_line) media = string(media_line, int(next-media_line)-1); m.type = media_type(media); - if(m.type < 0) { + if(m.type == MT_NONE) { ERROR("parse_sdp_media: Unknown media type\n"); } media_line = next; @@ -787,7 +815,7 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s) // break; // } m.transport = transport_type(proto); - if(m.transport < 0){ + if(m.transport == TP_NONE){ DBG("Unknown transport protocol: %s\n",proto.c_str()); } media_line = next; @@ -796,41 +824,49 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s) } case FMT: { - if (contains(media_line, line_end, ' ')) { - next = parse_until(media_line, ' '); - string value; - if (next > media_line) - value = string(media_line, int(next-media_line)-1); - - if (!value.empty()) { - payload.type = m.type; - str2i(value, payload_type); - payload.payload_type = payload_type; - m.payloads.push_back(payload); - } - - media_line = next; - state = FMT; - } else { - string last_value; - if (line_end>media_line) { - if (*line_end == '\0') { - // last line in message - last_value = string(media_line, int(line_end-media_line)); - } else { - last_value = string(media_line, int(line_end-media_line)-1); + if (m.transport == TP_RTPAVP || m.transport == TP_RTPSAVP) { + if (contains(media_line, line_end, ' ')) { + next = parse_until(media_line, ' '); + string value; + if (next > media_line) + value = string(media_line, int(next-media_line)-1); + + if (!value.empty()) { + payload.type = m.type; + str2i(value, payload_type); + payload.payload_type = payload_type; + m.payloads.push_back(payload); } + media_line = next; + } else { + string last_value; + if (line_end>media_line) { + if (*line_end == '\0') { + // last line in message + last_value = string(media_line, int(line_end-media_line)); + } else { + last_value = string(media_line, int(line_end-media_line)-1); + } + } + if (!last_value.empty()) { + payload.type = m.type; + str2i(last_value, payload_type); + payload.payload_type = payload_type; + m.payloads.push_back(payload); + } + parsing = 0; } - if (!last_value.empty()) { - payload.type = m.type; - str2i(last_value, payload_type); - payload.payload_type = payload_type; - m.payloads.push_back(payload); - } + } else { + line_end--; + while (line_end > media_line && + (*line_end == '\r' || *line_end == '\n')) + line_end--; + if (line_end>media_line) + m.fmt = string(media_line, line_end-media_line+1); + DBG("set media fmt to '%s'\n", m.fmt.c_str()); parsing = 0; } - break; - } + } break; } } sdp_msg->media.push_back(m); @@ -1053,32 +1089,28 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s) }else{ attr_check(attr); next = parse_until(attr_line, '\r'); - if(next < line_end){ - string value(attr_line, int(next-attr_line)-1); - DBG("found media attr '%s' value '%s'\n", - (char*)attr.c_str(), (char*)value.c_str()); - media.attributes.push_back(SdpAttribute(attr, value)); - } else { + if(next >= line_end){ DBG("found media attr '%s', but value is not followed by cr\n", (char *)attr.c_str()); } + string value(attr_line, int(next-attr_line)-1); + DBG("found media attr '%s' value '%s'\n", + (char*)attr.c_str(), (char*)value.c_str()); + media.attributes.push_back(SdpAttribute(attr, value)); } } else { next = parse_until(attr_line, '\r'); - if(next < line_end){ - string attr(attr_line, int(next-attr_line)-1); - attr_check(attr); - DBG("found media attr '%s'\n", (char*)attr.c_str()); - media.attributes.push_back(SdpAttribute(attr)); - } else { + if(next >= line_end){ DBG("found media attr line '%s', which is not followed by cr\n", attr_line); } + string attr(attr_line, int(next-attr_line)-1); + attr_check(attr); + DBG("found media attr '%s'\n", (char*)attr.c_str()); + media.attributes.push_back(SdpAttribute(attr)); } - - return; } static void parse_sdp_origin(AmSdp* sdp_msg, char* s) @@ -1172,10 +1204,10 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s) next = parse_until(origin_line, ' '); //check if line contains more values than allowed if(next > line_end){ - string unicast_addr(origin_line, int(line_end-origin_line)-1); + 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"); - string unicast_addr(origin_line, int(next-origin_line)-1); + origin.conn.address = string(origin_line, int(next-origin_line)-1); } parsing = 0; break; @@ -1263,32 +1295,39 @@ inline char* get_next_line(char* s) /* *Check if known media type is used */ -static int media_type(std::string media) +static MediaType media_type(std::string media) { if(media == "audio") - return 1; + return MT_AUDIO; else if(media == "video") - return 2; + return MT_VIDEO; else if(media == "application") - return 3; + return MT_APPLICATION; else if(media == "text") - return 4; + return MT_TEXT; else if(media == "message") - return 5; + return MT_MESSAGE; + else if(media == "image") + return MT_IMAGE; else - return -1; + return MT_NONE; } -static int transport_type(std::string transport) +static TransProt transport_type(string transport) { - if(transport == "RTP/AVP") - return 1; - else if(transport == "UDP") - return 2; - else if(transport == "RTP/SAVP") - return 3; + string transport_uc = transport; + std::transform(transport_uc.begin(), transport_uc.end(), transport_uc.begin(), toupper); + + if(transport_uc == "RTP/AVP") + return TP_RTPAVP; + else if(transport_uc == "UDP") + return TP_UDP; + else if(transport_uc == "RTP/SAVP") + return TP_RTPSAVP; + else if(transport_uc == "UDPTL") + return TP_UDPTL; else - return -1; + return TP_NONE; } /* @@ -1336,7 +1375,7 @@ static bool attr_check(std::string attr) return true; else { - DBG("sdp_parse_attr: Unknown attribute name used:%s, plz see RFC4566\n", + DBG("sdp_parse_attr: Unknown attribute name used: %s, plz see RFC4566\n", (char*)attr.c_str()); return false; } diff --git a/core/AmSdp.h b/core/AmSdp.h index 91205390..ee89f8a7 100644 --- a/core/AmSdp.h +++ b/core/AmSdp.h @@ -53,9 +53,9 @@ enum NetworkType { NT_OTHER=0, NT_IN }; /** address type */ enum AddressType { AT_NONE=0, AT_V4, AT_V6 }; /** media type */ -enum MediaType { MT_NONE=0, MT_AUDIO, MT_VIDEO, MT_APPLICATION, MT_TEXT, MT_MESSAGE }; +enum MediaType { MT_NONE=0, MT_AUDIO, MT_VIDEO, MT_APPLICATION, MT_TEXT, MT_MESSAGE, MT_IMAGE }; /** transport protocol */ -enum TransProt { TP_NONE=0, TP_RTPAVP, TP_UDP, TP_RTPSAVP }; +enum TransProt { TP_NONE=0, TP_RTPAVP, TP_UDP, TP_RTPSAVP, TP_UDPTL }; /** \brief c=... line in SDP*/ struct SdpConnection @@ -131,7 +131,8 @@ struct SdpMedia enum Direction { DirBoth=0, DirActive=1, - DirPassive=2 + DirPassive=2, + DirUndefined=3 }; int type; @@ -140,12 +141,13 @@ struct SdpMedia int transport; SdpConnection conn; // c= Direction dir; // a=direction + string fmt; // format in case proto != RTP/AVP or RTP/SAVP std::vector payloads; std::vector attributes; // unknown attributes - SdpMedia() : conn() {} + SdpMedia() : conn(), dir(DirUndefined), type(MT_NONE), transport(TP_NONE) {} }; /** diff --git a/core/AmSession.cpp b/core/AmSession.cpp index bc8999e7..86a8a39e 100644 --- a/core/AmSession.cpp +++ b/core/AmSession.cpp @@ -1111,7 +1111,8 @@ void AmSession::onSendReply(const AmSipRequest& req, unsigned int code, void AmSession::onRtpTimeout() { - DBG("stopping Session.\n"); + DBG("RTP timeout, stopping Session\n"); + dlg.bye(); setStopped(); } diff --git a/core/AmSessionContainer.cpp b/core/AmSessionContainer.cpp index aa69882e..09972900 100644 --- a/core/AmSessionContainer.cpp +++ b/core/AmSessionContainer.cpp @@ -248,7 +248,7 @@ string AmSessionContainer::startSessionUAC(AmSipRequest& req, AmArg* session_par ERROR("INVITE could not be sent: error code = %d.\n", err); AmEventDispatcher::instance()->delEventQueue(req.from_tag); MONITORING_MARK_FINISHED(req.from_tag.c_str()); - return NULL; + return ""; } if (AmConfig::LogSessions) { diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 0829e879..1c8f6127 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -112,7 +112,14 @@ void AmSipDialog::updateStatus(const AmSipRequest& req) if (r_cseq_i && req.cseq <= r_cseq){ INFO("remote cseq lower than previous ones - refusing request\n"); // see 12.2.2 - reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR, "", + string hdrs; + if (req.method == "NOTIFY") { + // clever trick to not break subscription dialog usage + // for implementations which follow 3265 instead of 5057 + hdrs = SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER) "0" CRLF; + } + + reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR, hdrs, next_hop_for_replies ? next_hop_ip : "", next_hop_for_replies ? next_hop_port : 0); return; @@ -121,7 +128,7 @@ void AmSipDialog::updateStatus(const AmSipRequest& req) if (req.method == "INVITE") { if (pending_invites) { reply_error(req,500, SIP_REPLY_SERVER_INTERNAL_ERROR, - "Retry-After: " + int2str(get_random() % 10) + CRLF, + SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER) + int2str(get_random() % 10) + CRLF, next_hop_for_replies ? next_hop_ip : "", next_hop_for_replies ? next_hop_port : 0); return; diff --git a/core/AmSipHeaders.h b/core/AmSipHeaders.h index 00b14703..39e59743 100644 --- a/core/AmSipHeaders.h +++ b/core/AmSipHeaders.h @@ -34,6 +34,7 @@ #define SIP_HDR_PROXY_AUTHENTICATE "Proxy-Authenticate" #define SIP_HDR_WWW_AUTHENTICATE "WWW-Authenticate" #define SIP_HDR_ALLOW "Allow" +#define SIP_HDR_RETRY_AFTER "Retry-After" #define SIP_HDR_COL(_hdr) _hdr ":" #define SIP_HDR_COLSP(_hdr) SIP_HDR_COL(_hdr) " " diff --git a/core/AmSipMsg.cpp b/core/AmSipMsg.cpp index 1626e373..94a4abb9 100644 --- a/core/AmSipMsg.cpp +++ b/core/AmSipMsg.cpp @@ -66,8 +66,16 @@ bool findHeader(const string& hdrs,const string& hdr_name, const size_t skip, hdrs_c++; } - if(hdr_c == hdr_end) - break; + if(hdr_c == hdr_end) { + // matched whole of needle. + // ...all of current header? + const char* srccol = hdrs_c; + while (*srccol==' ' || *srccol=='\t') + srccol++; + if (*srccol == ':') + break; // was end of current hdr + // current hdr just starts with hdr, continue search + } while((hdrs_c != hdrs_end) && (*hdrs_c != '\n')) hdrs_c++; diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e1eb469c..bd107c85 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -27,6 +27,10 @@ IF(LIBSAMPLERATE_FOUND) TARGET_LINK_LIBRARIES(sems ${CMAKE_DL_LIBS} samplerate) ENDIF(LIBSAMPLERATE_FOUND) +IF(LIBZRTP_FOUND) + TARGET_LINK_LIBRARIES(sems ${CMAKE_DL_LIBS} zrtp) +ENDIF(LIBZRTP_FOUND) + ADD_SUBDIRECTORY(plug-in) # Create config-file from template @@ -39,9 +43,9 @@ INSTALL(TARGETS sems RUNTIME DESTINATION ${SEMS_EXEC_PREFIX}/sbin) # Installation of config-files INSTALL(FILES ./etc/sems.conf DESTINATION ${SEMS_CFG_PREFIX}/etc/sems/) INSTALL(FILES ./etc/app_mapping.conf DESTINATION ${SEMS_CFG_PREFIX}/etc/sems/etc/) -IF(ZRTP_FOUND) +IF(LIBZRTP_FOUND) INSTALL(FILES ./etc/zrtp.conf DESTINATION ${SEMS_CFG_PREFIX}/etc/sems/etc/) -ENDIF(ZRTP_FOUND) +ENDIF(LIBZRTP_FOUND) INCLUDE(${CMAKE_SOURCE_DIR}/cmake/doc.rules.txt) diff --git a/core/plug-in/stats/query_stats.cxx b/core/plug-in/stats/query_stats.cxx index f226be5c..6bb1444c 100644 --- a/core/plug-in/stats/query_stats.cxx +++ b/core/plug-in/stats/query_stats.cxx @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/core/tests/test_headers.cpp b/core/tests/test_headers.cpp index 5805534a..e1790eee 100644 --- a/core/tests/test_headers.cpp +++ b/core/tests/test_headers.cpp @@ -59,6 +59,29 @@ FCTMF_SUITE_BGN(test_headers) { fct_chk(get_header_keyvalue("u=sayer;d=iptel.org;p=abcdef", "d") == "iptel.org"); } FCT_TEST_END(); + + FCT_TEST_BGN(getHeader_allow) { + fct_chk(getHeader("Subject: Performance Test\n" + "Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH", "Allow") == "INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH"); + } FCT_TEST_END(); + + FCT_TEST_BGN(getHeader_allow_substr) { + fct_chk(getHeader("Subject: Performance Test\n" + "Allow-Events: telephone-event,refer\n" + "Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH", "Allow") == "INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH"); + } FCT_TEST_END(); + + FCT_TEST_BGN(getHeader_allow3) { + fct_chk(getHeader("Subject: Performance Test\n" + "Allow : INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH", "Allow") == "INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH"); + } FCT_TEST_END(); + + FCT_TEST_BGN(getHeader_allow4) { + fct_chk(getHeader("Subject: Performance Test\n" + "Allow-Events : telephone-event,refer\n" + "Allow : INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH", "Allow") == "INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH"); + } FCT_TEST_END(); + FCT_TEST_BGN(addOptionTag) { string hdrs = "Supported: timer" CRLF diff --git a/pkg/rpm/sems.init b/pkg/rpm/sems.init index 9e6080f6..15e98479 100755 --- a/pkg/rpm/sems.init +++ b/pkg/rpm/sems.init @@ -53,7 +53,7 @@ start() { return 0 fi - daemon $sems -P $pidfile -f $conffile $OPTIONS + daemon $sems -P $pidfile -u sems -g sems -f $conffile $OPTIONS RETVAL=$? echo [ $RETVAL = 0 ] && touch $lockfile diff --git a/pkg/rpm/sems.systemd.service b/pkg/rpm/sems.systemd.service new file mode 100644 index 00000000..ffe2a606 --- /dev/null +++ b/pkg/rpm/sems.systemd.service @@ -0,0 +1,11 @@ +[Unit] +Description=SIP Media Server +After=network.target + +[Service] +Type=simple +User=sems +Group=sems +EnvironmentFile=-/etc/sysconfig/sems +PIDFile=/var/run/sems/sems.pid +ExecStart=/usr/sbin/sems -E -u sems -g sems -P /var/run/sems/sems.pid $OPTIONS diff --git a/pkg/rpm/sems.systemd.tmpfiles.d.conf b/pkg/rpm/sems.systemd.tmpfiles.d.conf new file mode 100644 index 00000000..d1428ea7 --- /dev/null +++ b/pkg/rpm/sems.systemd.tmpfiles.d.conf @@ -0,0 +1 @@ +d /var/run/sems 0755 sems sems