Remove webrtc/libjingle/{examples,session}.

webrtc/libjingle/ is deprecated and these targets (unlike xmllite/xmpp)
are not currently in use in Chromium (which blocks removing the whole
webrtc/libjingle/ folder).

BUG=
R=juberti@webrtc.org

Review URL: https://codereview.webrtc.org/1175243003.

Cr-Commit-Position: refs/heads/master@{#9428}
This commit is contained in:
Peter Boström 2015-06-12 13:13:36 +02:00
parent 36b7cc3264
commit f5642913c9
55 changed files with 0 additions and 20021 deletions

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.google.call</string>
<key>CFBundleName</key>
<string>call</string>
</dict>
</plist>

View File

@ -1,484 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <iomanip>
#include <iostream>
#include <vector>
#include "webrtc/base/flags.h"
#include "webrtc/base/logging.h"
#ifdef OSX
#include "webrtc/base/maccocoasocketserver.h"
#endif
#include "talk/examples/call/callclient.h"
#include "talk/examples/call/console.h"
#include "talk/examples/call/mediaenginefactory.h"
#include "talk/session/media/srtpfilter.h"
#include "webrtc/base/pathutils.h"
#include "webrtc/base/ssladapter.h"
#include "webrtc/base/stream.h"
#include "webrtc/base/win32socketserver.h"
#include "webrtc/libjingle/session/media/mediasessionclient.h"
#include "webrtc/libjingle/xmpp/xmppauth.h"
#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
#include "webrtc/libjingle/xmpp/xmpppump.h"
#include "webrtc/libjingle/xmpp/xmppsocket.h"
#include "webrtc/p2p/base/constants.h"
class DebugLog : public sigslot::has_slots<> {
public:
DebugLog() :
debug_input_buf_(NULL), debug_input_len_(0), debug_input_alloc_(0),
debug_output_buf_(NULL), debug_output_len_(0), debug_output_alloc_(0),
censor_password_(false)
{}
char * debug_input_buf_;
int debug_input_len_;
int debug_input_alloc_;
char * debug_output_buf_;
int debug_output_len_;
int debug_output_alloc_;
bool censor_password_;
void Input(const char * data, int len) {
if (debug_input_len_ + len > debug_input_alloc_) {
char * old_buf = debug_input_buf_;
debug_input_alloc_ = 4096;
while (debug_input_alloc_ < debug_input_len_ + len) {
debug_input_alloc_ *= 2;
}
debug_input_buf_ = new char[debug_input_alloc_];
memcpy(debug_input_buf_, old_buf, debug_input_len_);
delete[] old_buf;
}
memcpy(debug_input_buf_ + debug_input_len_, data, len);
debug_input_len_ += len;
DebugPrint(debug_input_buf_, &debug_input_len_, false);
}
void Output(const char * data, int len) {
if (debug_output_len_ + len > debug_output_alloc_) {
char * old_buf = debug_output_buf_;
debug_output_alloc_ = 4096;
while (debug_output_alloc_ < debug_output_len_ + len) {
debug_output_alloc_ *= 2;
}
debug_output_buf_ = new char[debug_output_alloc_];
memcpy(debug_output_buf_, old_buf, debug_output_len_);
delete[] old_buf;
}
memcpy(debug_output_buf_ + debug_output_len_, data, len);
debug_output_len_ += len;
DebugPrint(debug_output_buf_, &debug_output_len_, true);
}
static bool IsAuthTag(const char * str, size_t len) {
if (str[0] == '<' && str[1] == 'a' &&
str[2] == 'u' &&
str[3] == 't' &&
str[4] == 'h' &&
str[5] <= ' ') {
std::string tag(str, len);
if (tag.find("mechanism") != std::string::npos)
return true;
}
return false;
}
void DebugPrint(char * buf, int * plen, bool output) {
int len = *plen;
if (len > 0) {
time_t tim = time(NULL);
struct tm * now = localtime(&tim);
char *time_string = asctime(now);
if (time_string) {
size_t time_len = strlen(time_string);
if (time_len > 0) {
time_string[time_len-1] = 0; // trim off terminating \n
}
}
LOG(INFO) << (output ? "SEND >>>>>>>>>>>>>>>>" : "RECV <<<<<<<<<<<<<<<<")
<< " : " << time_string;
bool indent;
int start = 0, nest = 3;
for (int i = 0; i < len; i += 1) {
if (buf[i] == '>') {
if ((i > 0) && (buf[i-1] == '/')) {
indent = false;
} else if ((start + 1 < len) && (buf[start + 1] == '/')) {
indent = false;
nest -= 2;
} else {
indent = true;
}
// Output a tag
LOG(INFO) << std::setw(nest) << " "
<< std::string(buf + start, i + 1 - start);
if (indent)
nest += 2;
// Note if it's a PLAIN auth tag
if (IsAuthTag(buf + start, i + 1 - start)) {
censor_password_ = true;
}
// incr
start = i + 1;
}
if (buf[i] == '<' && start < i) {
if (censor_password_) {
LOG(INFO) << std::setw(nest) << " " << "## TEXT REMOVED ##";
censor_password_ = false;
} else {
LOG(INFO) << std::setw(nest) << " "
<< std::string(buf + start, i - start);
}
start = i;
}
}
len = len - start;
memcpy(buf, buf + start, len);
*plen = len;
}
}
};
static DebugLog debug_log_;
static const int DEFAULT_PORT = 5222;
#ifdef ANDROID
static std::vector<cricket::AudioCodec> codecs;
static const cricket::AudioCodec ISAC(103, "ISAC", 40000, 16000, 1, 0);
cricket::MediaEngineInterface *CreateAndroidMediaEngine() {
cricket::FakeMediaEngine *engine = new cricket::FakeMediaEngine();
codecs.push_back(ISAC);
engine->SetAudioCodecs(codecs);
return engine;
}
#endif
// TODO: Move this into Console.
void Print(const char* chars) {
printf("%s", chars);
fflush(stdout);
}
bool GetSecurePolicy(const std::string& in, cricket::SecurePolicy* out) {
if (in == "disable") {
*out = cricket::SEC_DISABLED;
} else if (in == "enable") {
*out = cricket::SEC_ENABLED;
} else if (in == "require") {
*out = cricket::SEC_REQUIRED;
} else {
return false;
}
return true;
}
int main(int argc, char **argv) {
// This app has three threads. The main thread will run the XMPP client,
// which will print to the screen in its own thread. A second thread
// will get input from the console, parse it, and pass the appropriate
// message back to the XMPP client's thread. A third thread is used
// by MediaSessionClient as its worker thread.
// define options
DEFINE_string(s, "talk.google.com", "The connection server to use.");
DEFINE_string(tls, "require",
"Select connection encryption: disable, enable, require.");
DEFINE_bool(allowplain, false, "Allow plain authentication.");
DEFINE_bool(testserver, false, "Use test server.");
DEFINE_string(oauth, "", "OAuth2 access token.");
DEFINE_bool(a, false, "Turn on auto accept for incoming calls.");
DEFINE_string(signaling, "hybrid",
"Initial signaling protocol to use: jingle, gingle, or hybrid.");
DEFINE_string(transport, "hybrid",
"Initial transport protocol to use: ice, gice, or hybrid.");
DEFINE_string(sdes, "enable",
"Select SDES media encryption: disable, enable, require.");
DEFINE_string(dtls, "disable",
"Select DTLS transport encryption: disable, enable, require.");
DEFINE_int(portallocator, 0, "Filter out unwanted connection types.");
DEFINE_string(pmuc, "groupchat.google.com", "The persistant muc domain.");
DEFINE_string(capsnode, "http://code.google.com/p/libjingle/call",
"Caps node: A URI identifying the app.");
DEFINE_string(capsver, "0.6",
"Caps ver: A string identifying the version of the app.");
DEFINE_string(voiceinput, NULL, "RTP dump file for voice input.");
DEFINE_string(voiceoutput, NULL, "RTP dump file for voice output.");
DEFINE_string(videoinput, NULL, "RTP dump file for video input.");
DEFINE_string(videooutput, NULL, "RTP dump file for video output.");
DEFINE_bool(render, true, "Renders the video.");
DEFINE_string(datachannel, "",
"Enable a data channel, and choose the type: rtp or sctp.");
DEFINE_bool(d, false, "Turn on debugging.");
DEFINE_bool(debugsrtp, false, "Enable debugging for srtp.");
DEFINE_bool(help, false, "Prints this message");
DEFINE_bool(multisession, false,
"Enable support for multiple sessions in calls.");
DEFINE_bool(roster, false,
"Enable roster messages printed in console.");
// parse options
rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
if (FLAG_help) {
rtc::FlagList::Print(NULL, false);
return 0;
}
bool auto_accept = FLAG_a;
bool debug = FLAG_d;
std::string signaling = FLAG_signaling;
std::string transport = FLAG_transport;
bool test_server = FLAG_testserver;
bool allow_plain = FLAG_allowplain;
std::string tls = FLAG_tls;
std::string oauth_token = FLAG_oauth;
int32 portallocator_flags = FLAG_portallocator;
std::string pmuc_domain = FLAG_pmuc;
std::string server = FLAG_s;
std::string sdes = FLAG_sdes;
std::string dtls = FLAG_dtls;
std::string caps_node = FLAG_capsnode;
std::string caps_ver = FLAG_capsver;
bool debugsrtp = FLAG_debugsrtp;
bool render = FLAG_render;
std::string data_channel = FLAG_datachannel;
bool multisession_enabled = FLAG_multisession;
rtc::SSLIdentity* ssl_identity = NULL;
bool show_roster_messages = FLAG_roster;
// Set up debugging.
if (debug) {
rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE);
}
if (debugsrtp) {
cricket::EnableSrtpDebugging();
}
// Set up the crypto subsystem.
rtc::InitializeSSL();
// Parse username and password, if present.
buzz::Jid jid;
std::string username;
rtc::InsecureCryptStringImpl pass;
if (argc > 1) {
username = argv[1];
if (argc > 2) {
pass.password() = argv[2];
}
}
if (username.empty()) {
Print("JID: ");
std::cin >> username;
}
if (username.find('@') == std::string::npos) {
username.append("@localhost");
}
jid = buzz::Jid(username);
if (!jid.IsValid() || jid.node() == "") {
Print("Invalid JID. JIDs should be in the form user@domain\n");
return 1;
}
if (pass.password().empty() && !test_server && oauth_token.empty()) {
Console::SetEcho(false);
Print("Password: ");
std::cin >> pass.password();
Console::SetEcho(true);
Print("\n");
}
// Decide on the connection settings.
buzz::XmppClientSettings xcs;
xcs.set_user(jid.node());
xcs.set_resource("call");
xcs.set_host(jid.domain());
xcs.set_allow_plain(allow_plain);
if (tls == "disable") {
xcs.set_use_tls(buzz::TLS_DISABLED);
} else if (tls == "enable") {
xcs.set_use_tls(buzz::TLS_ENABLED);
} else if (tls == "require") {
xcs.set_use_tls(buzz::TLS_REQUIRED);
} else {
Print("Invalid TLS option, must be enable, disable, or require.\n");
return 1;
}
if (test_server) {
pass.password() = jid.node();
xcs.set_allow_plain(true);
xcs.set_use_tls(buzz::TLS_DISABLED);
xcs.set_test_server_domain("google.com");
}
xcs.set_pass(rtc::CryptString(pass));
if (!oauth_token.empty()) {
xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2, oauth_token);
}
std::string host;
int port;
int colon = server.find(':');
if (colon == -1) {
host = server;
port = DEFAULT_PORT;
} else {
host = server.substr(0, colon);
port = atoi(server.substr(colon + 1).c_str());
}
xcs.set_server(rtc::SocketAddress(host, port));
// Decide on the signaling and crypto settings.
cricket::SignalingProtocol signaling_protocol = cricket::PROTOCOL_HYBRID;
if (signaling == "jingle") {
signaling_protocol = cricket::PROTOCOL_JINGLE;
} else if (signaling == "gingle") {
signaling_protocol = cricket::PROTOCOL_GINGLE;
} else if (signaling == "hybrid") {
signaling_protocol = cricket::PROTOCOL_HYBRID;
} else {
Print("Invalid signaling protocol. Must be jingle, gingle, or hybrid.\n");
return 1;
}
cricket::TransportProtocol transport_protocol = cricket::ICEPROTO_HYBRID;
if (transport == "ice") {
transport_protocol = cricket::ICEPROTO_RFC5245;
} else if (transport == "gice") {
transport_protocol = cricket::ICEPROTO_GOOGLE;
} else if (transport == "hybrid") {
transport_protocol = cricket::ICEPROTO_HYBRID;
} else {
Print("Invalid transport protocol. Must be ice, gice, or hybrid.\n");
return 1;
}
cricket::DataChannelType data_channel_type = cricket::DCT_NONE;
if (data_channel == "rtp") {
data_channel_type = cricket::DCT_RTP;
} else if (data_channel == "sctp") {
data_channel_type = cricket::DCT_SCTP;
} else if (!data_channel.empty()) {
Print("Invalid data channel type. Must be rtp or sctp.\n");
return 1;
}
cricket::SecurePolicy sdes_policy, dtls_policy;
if (!GetSecurePolicy(sdes, &sdes_policy)) {
Print("Invalid SDES policy. Must be enable, disable, or require.\n");
return 1;
}
if (!GetSecurePolicy(dtls, &dtls_policy)) {
Print("Invalid DTLS policy. Must be enable, disable, or require.\n");
return 1;
}
if (dtls_policy != cricket::SEC_DISABLED) {
ssl_identity = rtc::SSLIdentity::Generate(jid.Str());
if (!ssl_identity) {
Print("Failed to generate identity for DTLS.\n");
return 1;
}
}
#ifdef ANDROID
MediaEngineFactory::SetCreateFunction(&CreateAndroidMediaEngine);
#endif
#if WIN32
// Need to pump messages on our main thread on Windows.
rtc::Win32Thread w32_thread;
rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread);
#endif
rtc::Thread* main_thread = rtc::Thread::Current();
#ifdef OSX
rtc::MacCocoaSocketServer ss;
rtc::SocketServerScope ss_scope(&ss);
#endif
buzz::XmppPump pump;
CallClient *client = new CallClient(pump.client(), caps_node, caps_ver);
if (FLAG_voiceinput || FLAG_voiceoutput ||
FLAG_videoinput || FLAG_videooutput) {
// If any dump file is specified, we use a FileMediaEngine.
cricket::MediaEngineInterface* engine =
MediaEngineFactory::CreateFileMediaEngine(
FLAG_voiceinput, FLAG_voiceoutput,
FLAG_videoinput, FLAG_videooutput);
client->SetMediaEngine(engine);
}
Console *console = new Console(main_thread, client);
client->SetConsole(console);
client->SetAutoAccept(auto_accept);
client->SetPmucDomain(pmuc_domain);
client->SetPortAllocatorFlags(portallocator_flags);
client->SetAllowLocalIps(true);
client->SetSignalingProtocol(signaling_protocol);
client->SetTransportProtocol(transport_protocol);
client->SetSecurePolicy(sdes_policy, dtls_policy);
client->SetSslIdentity(ssl_identity);
client->SetRender(render);
client->SetDataChannelType(data_channel_type);
client->SetMultiSessionEnabled(multisession_enabled);
client->SetShowRosterMessages(show_roster_messages);
console->Start();
if (debug) {
pump.client()->SignalLogInput.connect(&debug_log_, &DebugLog::Input);
pump.client()->SignalLogOutput.connect(&debug_log_, &DebugLog::Output);
}
Print(("Logging in to " + server + " as " + jid.Str() + "\n").c_str());
pump.DoLogin(xcs, new buzz::XmppSocket(buzz::TLS_REQUIRED), new XmppAuth());
main_thread->Run();
pump.DoDisconnect();
console->Stop();
delete console;
delete client;
return 0;
}

View File

@ -1,37 +0,0 @@
/*
* libjingle
* Copyright 2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Main function for all unit tests in talk/examples/call
#include "testing/base/public/gunit.h"
#include "webrtc/base/logging.h"
int main(int argc, char **argv) {
rtc::LogMessage::LogToDebug(rtc::LogMessage::NO_LOGGING);
testing::ParseGUnitFlags(&argc, argv);
return RUN_ALL_TESTS();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,352 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_
#include <map>
#include <string>
#include <vector>
#include "talk/examples/call/console.h"
#include "talk/media/base/mediachannel.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/sslidentity.h"
#include "webrtc/libjingle/session/media/mediamessages.h"
#include "webrtc/libjingle/session/media/mediasessionclient.h"
#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
#include "webrtc/libjingle/xmpp/presencestatus.h"
#include "webrtc/libjingle/xmpp/xmppclient.h"
#include "webrtc/p2p/base/session.h"
namespace buzz {
class PresencePushTask;
class PresenceOutTask;
class MucInviteRecvTask;
class MucInviteSendTask;
class FriendInviteSendTask;
class DiscoInfoQueryTask;
class Muc;
class PresenceStatus;
class IqTask;
class MucRoomConfigTask;
class MucRoomLookupTask;
class MucPresenceStatus;
class XmlElement;
class HangoutPubSubClient;
struct AvailableMediaEntry;
struct MucRoomInfo;
} // namespace buzz
namespace rtc {
class Thread;
class NetworkManager;
} // namespace rtc
namespace cricket {
class PortAllocator;
class MediaEngineInterface;
class MediaSessionClient;
class Call;
class SessionManagerTask;
struct CallOptions;
struct MediaStreams;
struct StreamParams;
} // namespace cricket
struct RosterItem {
buzz::Jid jid;
buzz::PresenceStatus::Show show;
std::string status;
};
struct StaticRenderedView {
StaticRenderedView(const cricket::StaticVideoView& view,
cricket::VideoRenderer* renderer) :
view(view),
renderer(renderer) {
}
cricket::StaticVideoView view;
cricket::VideoRenderer* renderer;
};
// Maintain a mapping of (session, ssrc) to rendered view.
typedef std::map<std::pair<cricket::Session*, uint32>,
StaticRenderedView> StaticRenderedViews;
class CallClient: public sigslot::has_slots<> {
public:
CallClient(buzz::XmppClient* xmpp_client,
const std::string& caps_node,
const std::string& version);
~CallClient();
cricket::MediaSessionClient* media_client() const { return media_client_; }
void SetMediaEngine(cricket::MediaEngineInterface* media_engine) {
media_engine_ = media_engine;
}
void SetAutoAccept(bool auto_accept) {
auto_accept_ = auto_accept;
}
void SetPmucDomain(const std::string &pmuc_domain) {
pmuc_domain_ = pmuc_domain;
}
void SetRender(bool render) {
render_ = render;
}
void SetDataChannelType(cricket::DataChannelType data_channel_type) {
data_channel_type_ = data_channel_type;
}
void SetMultiSessionEnabled(bool multisession_enabled) {
multisession_enabled_ = multisession_enabled;
}
void SetConsole(Console *console) {
console_ = console;
}
void SetPriority(int priority) {
my_status_.set_priority(priority);
}
void SendStatus() {
SendStatus(my_status_);
}
void SendStatus(const buzz::PresenceStatus& status);
void ParseLine(const std::string &str);
void SendChat(const std::string& to, const std::string msg);
void SendData(const std::string& stream_name,
const std::string& text);
void InviteFriend(const std::string& user);
void JoinMuc(const buzz::Jid& room_jid);
void JoinMuc(const std::string& room_jid_str);
void LookupAndJoinMuc(const std::string& room_name);
void InviteToMuc(const std::string& user, const std::string& room);
bool InMuc();
const buzz::Jid* FirstMucJid();
void LeaveMuc(const std::string& room);
void SetNick(const std::string& muc_nick);
void SetPortAllocatorFlags(uint32 flags) { portallocator_flags_ = flags; }
void SetAllowLocalIps(bool allow_local_ips) {
allow_local_ips_ = allow_local_ips;
}
void SetSignalingProtocol(cricket::SignalingProtocol protocol) {
signaling_protocol_ = protocol;
}
void SetTransportProtocol(cricket::TransportProtocol protocol) {
transport_protocol_ = protocol;
}
void SetSecurePolicy(cricket::SecurePolicy sdes_policy,
cricket::SecurePolicy dtls_policy) {
sdes_policy_ = sdes_policy;
dtls_policy_ = dtls_policy;
}
void SetSslIdentity(rtc::SSLIdentity* identity) {
ssl_identity_.reset(identity);
}
typedef std::map<buzz::Jid, buzz::Muc*> MucMap;
const MucMap& mucs() const {
return mucs_;
}
void SetShowRosterMessages(bool show_roster_messages) {
show_roster_messages_ = show_roster_messages;
}
private:
void AddStream(uint32 audio_src_id, uint32 video_src_id);
void RemoveStream(uint32 audio_src_id, uint32 video_src_id);
void OnStateChange(buzz::XmppEngine::State state);
void InitMedia();
void InitPresence();
void StartXmppPing();
void OnPingTimeout();
void OnRequestSignaling();
void OnSessionCreate(cricket::Session* session, bool initiate);
void OnCallCreate(cricket::Call* call);
void OnCallDestroy(cricket::Call* call);
void OnSessionState(cricket::Call* call,
cricket::Session* session,
cricket::Session::State state);
void OnStatusUpdate(const buzz::PresenceStatus& status);
void OnMucInviteReceived(const buzz::Jid& inviter, const buzz::Jid& room,
const std::vector<buzz::AvailableMediaEntry>& avail);
void OnMucJoined(const buzz::Jid& endpoint);
void OnMucStatusUpdate(const buzz::Jid& jid,
const buzz::MucPresenceStatus& status);
void OnMucLeft(const buzz::Jid& endpoint, int error);
void OnPresenterStateChange(const std::string& nick,
bool was_presenting, bool is_presenting);
void OnAudioMuteStateChange(const std::string& nick,
bool was_muted, bool is_muted);
void OnRecordingStateChange(const std::string& nick,
bool was_recording, bool is_recording);
void OnRemoteMuted(const std::string& mutee_nick,
const std::string& muter_nick,
bool should_mute_locally);
void OnMediaBlocked(const std::string& blockee_nick,
const std::string& blocker_nick);
void OnHangoutRequestError(const std::string& node,
const buzz::XmlElement* stanza);
void OnHangoutPublishAudioMuteError(const std::string& task_id,
const buzz::XmlElement* stanza);
void OnHangoutPublishPresenterError(const std::string& task_id,
const buzz::XmlElement* stanza);
void OnHangoutPublishRecordingError(const std::string& task_id,
const buzz::XmlElement* stanza);
void OnHangoutRemoteMuteError(const std::string& task_id,
const std::string& mutee_nick,
const buzz::XmlElement* stanza);
void OnDevicesChange();
void OnMediaStreamsUpdate(cricket::Call* call,
cricket::Session* session,
const cricket::MediaStreams& added,
const cricket::MediaStreams& removed);
void OnSpeakerChanged(cricket::Call* call,
cricket::Session* session,
const cricket::StreamParams& speaker_stream);
void OnRoomLookupResponse(buzz::MucRoomLookupTask* task,
const buzz::MucRoomInfo& room_info);
void OnRoomLookupError(buzz::IqTask* task,
const buzz::XmlElement* stanza);
void OnRoomConfigResult(buzz::MucRoomConfigTask* task);
void OnRoomConfigError(buzz::IqTask* task,
const buzz::XmlElement* stanza);
void OnDataReceived(cricket::Call*,
const cricket::ReceiveDataParams& params,
const rtc::Buffer& payload);
buzz::Jid GenerateRandomMucJid();
// Depending on |enable|, render (or don't) all the streams in |session|.
void RenderAllStreams(cricket::Call* call,
cricket::Session* session,
bool enable);
// Depending on |enable|, render (or don't) the streams in |video_streams|.
void RenderStreams(cricket::Call* call,
cricket::Session* session,
const std::vector<cricket::StreamParams>& video_streams,
bool enable);
// Depending on |enable|, render (or don't) the supplied |stream|.
void RenderStream(cricket::Call* call,
cricket::Session* session,
const cricket::StreamParams& stream,
bool enable);
void AddStaticRenderedView(
cricket::Session* session,
uint32 ssrc, int width, int height, int framerate,
int x_offset, int y_offset);
bool RemoveStaticRenderedView(uint32 ssrc);
void RemoveCallsStaticRenderedViews(cricket::Call* call);
void SendViewRequest(cricket::Call* call, cricket::Session* session);
bool SelectFirstDesktopScreencastId(cricket::ScreencastId* screencastid);
static const std::string strerror(buzz::XmppEngine::Error err);
void PrintRoster();
bool FindJid(const std::string& name,
buzz::Jid* found_jid,
cricket::CallOptions* options);
bool PlaceCall(const std::string& name, cricket::CallOptions options);
bool InitiateAdditionalSession(const std::string& name,
cricket::CallOptions options);
void TerminateAndRemoveSession(cricket::Call* call, const std::string& id);
void PrintCalls();
void SwitchToCall(uint32 call_id);
void Accept(const cricket::CallOptions& options);
void Reject();
void Quit();
void GetDevices();
void PrintDevices(const std::vector<std::string>& names);
void SetVolume(const std::string& level);
cricket::Session* GetFirstSession() { return sessions_[call_->id()][0]; }
void AddSession(cricket::Session* session) {
sessions_[call_->id()].push_back(session);
}
void PrintStats() const;
void SetupAcceptedCall();
typedef std::map<std::string, RosterItem> RosterMap;
Console *console_;
buzz::XmppClient* xmpp_client_;
rtc::Thread* worker_thread_;
rtc::NetworkManager* network_manager_;
cricket::PortAllocator* port_allocator_;
cricket::SessionManager* session_manager_;
cricket::SessionManagerTask* session_manager_task_;
cricket::MediaEngineInterface* media_engine_;
cricket::DataEngineInterface* data_engine_;
cricket::MediaSessionClient* media_client_;
MucMap mucs_;
cricket::Call* call_;
typedef std::map<uint32, std::vector<cricket::Session *> > SessionMap;
SessionMap sessions_;
buzz::HangoutPubSubClient* hangout_pubsub_client_;
bool incoming_call_;
bool auto_accept_;
std::string pmuc_domain_;
bool render_;
cricket::DataChannelType data_channel_type_;
bool multisession_enabled_;
cricket::VideoRenderer* local_renderer_;
StaticRenderedViews static_rendered_views_;
uint32 static_views_accumulated_count_;
uint32 screencast_ssrc_;
buzz::PresenceStatus my_status_;
buzz::PresencePushTask* presence_push_;
buzz::PresenceOutTask* presence_out_;
buzz::MucInviteRecvTask* muc_invite_recv_;
buzz::MucInviteSendTask* muc_invite_send_;
buzz::FriendInviteSendTask* friend_invite_send_;
RosterMap* roster_;
uint32 portallocator_flags_;
bool allow_local_ips_;
cricket::SignalingProtocol signaling_protocol_;
cricket::TransportProtocol transport_protocol_;
cricket::SecurePolicy sdes_policy_;
cricket::SecurePolicy dtls_policy_;
rtc::scoped_ptr<rtc::SSLIdentity> ssl_identity_;
std::string last_sent_to_;
bool show_roster_messages_;
};
#endif // WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_

View File

@ -1,47 +0,0 @@
/*
* libjingle
* Copyright 2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Unit tests for CallClient
#include "talk/examples/call/callclient.h"
#include "talk/media/base/filemediaengine.h"
#include "talk/media/base/mediaengine.h"
#include "webrtc/libjingle/xmpp/xmppthread.h"
#include "webrtc/base/gunit.h"
TEST(CallClientTest, CreateCallClientWithDefaultMediaEngine) {
buzz::XmppPump pump;
CallClient *client = new CallClient(pump.client(), "app", "version");
delete client;
}
TEST(CallClientTest, CreateCallClientWithFileMediaEngine) {
buzz::XmppPump pump;
CallClient *client = new CallClient(pump.client(), "app", "version");
client->SetMediaEngine(new cricket::FileMediaEngine);
delete client;
}

View File

@ -1,169 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _CRT_SECURE_NO_DEPRECATE 1
#include <assert.h>
#if defined(WEBRTC_POSIX)
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#endif // WEBRTC_POSIX
#include "talk/examples/call/callclient.h"
#include "talk/examples/call/console.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/messagequeue.h"
#include "webrtc/base/stringutils.h"
#ifdef WEBRTC_POSIX
static void DoNothing(int unused) {}
#endif
Console::Console(rtc::Thread *thread, CallClient *client) :
client_(client),
client_thread_(thread),
stopped_(false) {}
Console::~Console() {
Stop();
}
void Console::Start() {
if (stopped_) {
// stdin was closed in Stop(), so we can't restart.
LOG(LS_ERROR) << "Cannot re-start";
return;
}
if (console_thread_) {
LOG(LS_WARNING) << "Already started";
return;
}
console_thread_.reset(new rtc::Thread());
console_thread_->Start();
console_thread_->Post(this, MSG_START);
}
void Console::Stop() {
if (console_thread_) {
#ifdef WIN32
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
#else
close(fileno(stdin));
// This forces the read() in fgets() to return with errno = EINTR. fgets()
// will retry the read() and fail, thus returning.
pthread_kill(console_thread_->GetPThread(), SIGUSR1);
#endif
console_thread_->Stop();
console_thread_.reset();
stopped_ = true;
}
}
void Console::SetEcho(bool on) {
#ifdef WIN32
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
return;
DWORD mode;
if (!GetConsoleMode(hIn, &mode))
return;
if (on) {
mode = mode | ENABLE_ECHO_INPUT;
} else {
mode = mode & ~ENABLE_ECHO_INPUT;
}
SetConsoleMode(hIn, mode);
#else
const int fd = fileno(stdin);
if (fd == -1)
return;
struct termios tcflags;
if (tcgetattr(fd, &tcflags) == -1)
return;
if (on) {
tcflags.c_lflag |= ECHO;
} else {
tcflags.c_lflag &= ~ECHO;
}
tcsetattr(fd, TCSANOW, &tcflags);
#endif
}
void Console::PrintLine(const char* format, ...) {
va_list ap;
va_start(ap, format);
char buf[4096];
int size = vsnprintf(buf, sizeof(buf), format, ap);
assert(size >= 0);
assert(size < static_cast<int>(sizeof(buf)));
buf[size] = '\0';
printf("%s\n", buf);
fflush(stdout);
va_end(ap);
}
void Console::RunConsole() {
char input_buffer[128];
while (fgets(input_buffer, sizeof(input_buffer), stdin) != NULL) {
client_thread_->Post(this, MSG_INPUT,
new rtc::TypedMessageData<std::string>(input_buffer));
}
}
void Console::OnMessage(rtc::Message *msg) {
switch (msg->message_id) {
case MSG_START:
#if defined(WEBRTC_POSIX)
// Install a no-op signal so that we can abort RunConsole() by raising
// SIGUSR1.
struct sigaction act;
act.sa_handler = &DoNothing;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
LOG(LS_WARNING) << "Can't install signal";
}
#endif
RunConsole();
break;
case MSG_INPUT:
rtc::TypedMessageData<std::string> *data =
static_cast<rtc::TypedMessageData<std::string>*>(msg->pdata);
client_->ParseLine(data->data());
break;
}
}

View File

@ -1,70 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_CONSOLE_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_CONSOLE_H_
#include <stdio.h>
#include "webrtc/base/messagequeue.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread.h"
class CallClient;
class Console : public rtc::MessageHandler {
public:
Console(rtc::Thread *thread, CallClient *client);
~Console();
// Starts reading lines from the console and giving them to the CallClient.
void Start();
// Stops reading lines. Cannot be restarted.
void Stop();
virtual void OnMessage(rtc::Message *msg);
void PrintLine(const char* format, ...);
static void SetEcho(bool on);
private:
enum {
MSG_START,
MSG_INPUT,
};
void RunConsole();
void ParseLine(std::string &str);
CallClient *client_;
rtc::Thread *client_thread_;
rtc::scoped_ptr<rtc::Thread> console_thread_;
bool stopped_;
};
#endif // TALK_EXAMPLES_CALL_CONSOLE_H_

View File

@ -1,76 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/examples/call/friendinvitesendtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace buzz {
XmppReturnStatus
FriendInviteSendTask::Send(const Jid& user) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
// Need to first add to roster, then subscribe to presence.
XmlElement* iq = new XmlElement(QN_IQ);
iq->AddAttr(QN_TYPE, STR_SET);
XmlElement* query = new XmlElement(QN_ROSTER_QUERY);
XmlElement* item = new XmlElement(QN_ROSTER_ITEM);
item->AddAttr(QN_JID, user.Str());
item->AddAttr(QN_NAME, user.node());
query->AddElement(item);
iq->AddElement(query);
QueueStanza(iq);
// Subscribe to presence
XmlElement* presence = new XmlElement(QN_PRESENCE);
presence->AddAttr(QN_TO, user.Str());
presence->AddAttr(QN_TYPE, STR_SUBSCRIBE);
XmlElement* invitation = new XmlElement(QN_INVITATION);
invitation->AddAttr(QN_INVITE_MESSAGE,
"I've been using Google Talk and thought you might like to try it out. "
"We can use it to call each other for free over the internet. Here's an "
"invitation to download Google Talk. Give it a try!");
presence->AddElement(invitation);
QueueStanza(presence);
return XMPP_RETURN_OK;
}
int
FriendInviteSendTask::ProcessStart() {
const XmlElement* stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
if (SendStanza(stanza) != XMPP_RETURN_OK)
return STATE_ERROR;
return STATE_START;
}
}

View File

@ -1,49 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_FRIENDINVITESENDTASK_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_FRIENDINVITESENDTASK_H_
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
class FriendInviteSendTask : public XmppTask {
public:
explicit FriendInviteSendTask(XmppTaskParentInterface* parent)
: XmppTask(parent) {}
virtual ~FriendInviteSendTask() {}
XmppReturnStatus Send(const Jid& user);
virtual int ProcessStart();
};
}
#endif

View File

@ -1,81 +0,0 @@
//
// libjingle
// Copyright 2004--2007, Google Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "talk/examples/call/mediaenginefactory.h"
#include "talk/media/base/fakemediaengine.h"
#include "talk/media/base/filemediaengine.h"
#include "talk/media/base/mediaengine.h"
#include "webrtc/base/stringutils.h"
std::vector<cricket::AudioCodec> RequiredAudioCodecs() {
std::vector<cricket::AudioCodec> audio_codecs;
audio_codecs.push_back(
cricket::AudioCodec(9, "G722", 16000, 0, 1, 0));
audio_codecs.push_back(
cricket::AudioCodec(0, "PCMU", 8000, 0, 1, 0));
audio_codecs.push_back(
cricket::AudioCodec(13, "CN", 8000, 0, 1, 0));
audio_codecs.push_back(
cricket::AudioCodec(105, "CN", 16000, 0, 1, 0));
return audio_codecs;
}
std::vector<cricket::VideoCodec> RequiredVideoCodecs() {
std::vector<cricket::VideoCodec> video_codecs;
video_codecs.push_back(
cricket::VideoCodec(97, "H264", 320, 240, 30, 0));
video_codecs.push_back(
cricket::VideoCodec(99, "H264-SVC", 640, 360, 30, 0));
return video_codecs;
}
cricket::MediaEngineInterface* MediaEngineFactory::CreateFileMediaEngine(
const char* voice_in, const char* voice_out,
const char* video_in, const char* video_out) {
cricket::FileMediaEngine* file_media_engine = new cricket::FileMediaEngine;
// Set the RTP dump file names.
if (voice_in) {
file_media_engine->set_voice_input_filename(voice_in);
}
if (voice_out) {
file_media_engine->set_voice_output_filename(voice_out);
}
if (video_in) {
file_media_engine->set_video_input_filename(video_in);
}
if (video_out) {
file_media_engine->set_video_output_filename(video_out);
}
// Set voice and video codecs. TODO: The codecs actually depend on
// the the input voice and video streams.
file_media_engine->set_voice_codecs(RequiredAudioCodecs());
file_media_engine->set_video_codecs(RequiredVideoCodecs());
return file_media_engine;
}

View File

@ -1,40 +0,0 @@
/*
* libjingle
* Copyright 2011, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_
#include "talk/media/base/mediaengine.h"
class MediaEngineFactory {
public:
static cricket::MediaEngineInterface* CreateFileMediaEngine(
const char* voice_in, const char* voice_out,
const char* video_in, const char* video_out);
};
#endif // WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_

View File

@ -1,66 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUC_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUC_H_
#include <map>
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/libjingle/xmpp/presencestatus.h"
namespace buzz {
class Muc {
public:
Muc(const Jid& jid, const std::string& nick) : state_(MUC_JOINING),
jid_(jid), local_jid_(Jid(jid.Str() + "/" + nick)) {}
~Muc() {};
enum State { MUC_JOINING, MUC_JOINED, MUC_LEAVING };
State state() const { return state_; }
void set_state(State state) { state_ = state; }
const Jid & jid() const { return jid_; }
const Jid & local_jid() const { return local_jid_; }
typedef std::map<std::string, MucPresenceStatus> MemberMap;
// All the intelligence about how to manage the members is in
// CallClient, so we completely expose the map.
MemberMap& members() {
return members_;
}
private:
State state_;
Jid jid_;
Jid local_jid_;
MemberMap members_;
};
}
#endif

View File

@ -1,124 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/examples/call/mucinviterecvtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace buzz {
const char* types[] = {
"unknown",
"audio",
"video",
};
const char* statuses[] = {
"unknown",
"sendrecv",
"sendonly",
"recvonly",
"inactive",
};
const char*
AvailableMediaEntry::TypeAsString(type_t type) {
// The values of the constants have been chosen such that this is correct.
return types[type];
}
const char*
AvailableMediaEntry::StatusAsString(status_t status) {
// The values of the constants have been chosen such that this is correct.
return statuses[status];
}
int bodytext_to_array_pos(const XmlElement* elem, const char* array[],
int len, int defval = -1) {
if (elem) {
const std::string& body(elem->BodyText());
for (int i = 0; i < len; ++i) {
if (body == array[i]) {
// Found it.
return i;
}
}
}
// If we get here, it's not any value in the array.
return defval;
}
bool
MucInviteRecvTask::HandleStanza(const XmlElement* stanza) {
// Figuring out that we want to handle this is a lot of the work of
// actually handling it, so we handle it right here instead of queueing it.
const XmlElement* xstanza;
const XmlElement* invite;
if (stanza->Name() != QN_MESSAGE) return false;
xstanza = stanza->FirstNamed(QN_MUC_USER_X);
if (!xstanza) return false;
invite = xstanza->FirstNamed(QN_MUC_USER_INVITE);
if (!invite) return false;
// Else it's an invite and we definitely want to handle it. Parse the
// available-media, if any.
std::vector<AvailableMediaEntry> v;
const XmlElement* avail =
invite->FirstNamed(QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA);
if (avail) {
for (const XmlElement* entry = avail->FirstNamed(QN_GOOGLE_MUC_USER_ENTRY);
entry;
entry = entry->NextNamed(QN_GOOGLE_MUC_USER_ENTRY)) {
AvailableMediaEntry tmp;
// In the interest of debugging, we accept as much valid-looking data
// as we can.
tmp.label = atoi(entry->Attr(QN_LABEL).c_str());
tmp.type = static_cast<AvailableMediaEntry::type_t>(
bodytext_to_array_pos(
entry->FirstNamed(QN_GOOGLE_MUC_USER_TYPE),
types,
sizeof(types)/sizeof(const char*),
AvailableMediaEntry::TYPE_UNKNOWN));
tmp.status = static_cast<AvailableMediaEntry::status_t>(
bodytext_to_array_pos(
entry->FirstNamed(QN_GOOGLE_MUC_USER_STATUS),
statuses,
sizeof(statuses)/sizeof(const char*),
AvailableMediaEntry::STATUS_UNKNOWN));
v.push_back(tmp);
}
}
SignalInviteReceived(Jid(invite->Attr(QN_FROM)), Jid(stanza->Attr(QN_FROM)),
v);
return true;
}
int
MucInviteRecvTask::ProcessStart() {
// We never queue anything so we are always blocked.
return STATE_BLOCKED;
}
}

View File

@ -1,82 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITERECVTASK_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITERECVTASK_H_
#include <vector>
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
#include "webrtc/base/sigslot.h"
namespace buzz {
struct AvailableMediaEntry {
enum type_t {
// SIP defines other media types, but these are the only ones we use in
// multiway jingle.
// These numbers are important; see .cc file
TYPE_UNKNOWN = 0, // indicates invalid string
TYPE_AUDIO = 1,
TYPE_VIDEO = 2,
};
enum status_t {
// These numbers are important; see .cc file
STATUS_UNKNOWN = 0, // indicates invalid string
STATUS_SENDRECV = 1,
STATUS_SENDONLY = 2,
STATUS_RECVONLY = 3,
STATUS_INACTIVE = 4,
};
uint32 label;
type_t type;
status_t status;
static const char* TypeAsString(type_t type);
static const char* StatusAsString(status_t status);
};
class MucInviteRecvTask : public XmppTask {
public:
explicit MucInviteRecvTask(XmppTaskParentInterface* parent)
: XmppTask(parent, XmppEngine::HL_TYPE) {}
virtual int ProcessStart();
// First arg is inviter's JID; second is MUC's JID.
sigslot::signal3<const Jid&, const Jid&, const std::vector<AvailableMediaEntry>& > SignalInviteReceived;
protected:
virtual bool HandleStanza(const XmlElement* stanza);
};
}
#endif

View File

@ -1,63 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/examples/call/mucinvitesendtask.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/xmppclient.h"
namespace buzz {
XmppReturnStatus
MucInviteSendTask::Send(const Jid& to, const Jid& invitee) {
if (GetState() != STATE_INIT && GetState() != STATE_START)
return XMPP_RETURN_BADSTATE;
XmlElement* message = new XmlElement(QN_MESSAGE);
message->AddAttr(QN_TO, to.Str());
XmlElement* xstanza = new XmlElement(QN_MUC_USER_X);
XmlElement* invite = new XmlElement(QN_MUC_USER_INVITE);
invite->AddAttr(QN_TO, invitee.Str());
xstanza->AddElement(invite);
message->AddElement(xstanza);
QueueStanza(message);
return XMPP_RETURN_OK;
}
int
MucInviteSendTask::ProcessStart() {
const XmlElement* stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
if (SendStanza(stanza) != XMPP_RETURN_OK)
return STATE_ERROR;
return STATE_START;
}
}

View File

@ -1,50 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITESENDTASK_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITESENDTASK_H_
#include "talk/examples/call/muc.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace buzz {
class MucInviteSendTask : public XmppTask {
public:
explicit MucInviteSendTask(XmppTaskParentInterface* parent)
: XmppTask(parent) {}
virtual ~MucInviteSendTask() {}
XmppReturnStatus Send(const Jid& to, const Jid& invitee);
virtual int ProcessStart();
};
}
#endif

View File

@ -1,222 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/examples/call/presencepushtask.h"
#include "talk/examples/call/muc.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/stringencode.h"
namespace buzz {
// string helper functions -----------------------------------------------------
static bool
IsXmlSpace(int ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
static bool ListContainsToken(const std::string & list,
const std::string & token) {
size_t i = list.find(token);
if (i == std::string::npos || token.empty())
return false;
bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
bool boundary_after = (i == list.length() - token.length() ||
IsXmlSpace(list[i + token.length()]));
return boundary_before && boundary_after;
}
bool PresencePushTask::HandleStanza(const XmlElement * stanza) {
if (stanza->Name() != QN_PRESENCE)
return false;
QueueStanza(stanza);
return true;
}
static bool IsUtf8FirstByte(int c) {
return (((c)&0x80)==0) || // is single byte
((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
}
int PresencePushTask::ProcessStart() {
const XmlElement * stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
Jid from(stanza->Attr(QN_FROM));
std::map<Jid, buzz::Muc*>::const_iterator elem =
client_->mucs().find(from.BareJid());
if (elem == client_->mucs().end()) {
HandlePresence(from, stanza);
} else {
HandleMucPresence(elem->second, from, stanza);
}
return STATE_START;
}
void PresencePushTask::HandlePresence(const Jid& from,
const XmlElement* stanza) {
if (stanza->Attr(QN_TYPE) == STR_ERROR)
return;
PresenceStatus s;
FillStatus(from, stanza, &s);
SignalStatusUpdate(s);
}
void PresencePushTask::HandleMucPresence(buzz::Muc* muc,
const Jid& from,
const XmlElement* stanza) {
if (from == muc->local_jid()) {
if (!stanza->HasAttr(QN_TYPE)) {
// We joined the MUC.
const XmlElement* elem = stanza->FirstNamed(QN_MUC_USER_X);
// Status code=110 or 100 is not guaranteed to be present, so we
// only check the item element and Muc join status.
if (elem) {
if (elem->FirstNamed(QN_MUC_USER_ITEM) &&
muc->state() == buzz::Muc::MUC_JOINING) {
SignalMucJoined(muc->jid());
}
}
} else {
// We've been kicked. Bye.
int error = 0;
if (stanza->Attr(QN_TYPE) == STR_ERROR) {
const XmlElement* elem = stanza->FirstNamed(QN_ERROR);
if (elem && elem->HasAttr(QN_CODE)) {
error = atoi(elem->Attr(QN_CODE).c_str());
}
}
SignalMucLeft(muc->jid(), error);
}
} else {
MucPresenceStatus s;
FillMucStatus(from, stanza, &s);
SignalMucStatusUpdate(muc->jid(), s);
}
}
void PresencePushTask::FillStatus(const Jid& from, const XmlElement* stanza,
PresenceStatus* s) {
s->set_jid(from);
if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
s->set_available(false);
} else {
s->set_available(true);
const XmlElement * status = stanza->FirstNamed(QN_STATUS);
if (status != NULL) {
s->set_status(status->BodyText());
// Truncate status messages longer than 300 bytes
if (s->status().length() > 300) {
size_t len = 300;
// Be careful not to split legal utf-8 chars in half
while (!IsUtf8FirstByte(s->status()[len]) && len > 0) {
len -= 1;
}
std::string truncated(s->status(), 0, len);
s->set_status(truncated);
}
}
const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
if (priority != NULL) {
int pri;
if (rtc::FromString(priority->BodyText(), &pri)) {
s->set_priority(pri);
}
}
const XmlElement * show = stanza->FirstNamed(QN_SHOW);
if (show == NULL || show->FirstChild() == NULL) {
s->set_show(PresenceStatus::SHOW_ONLINE);
}
else {
if (show->BodyText() == "away") {
s->set_show(PresenceStatus::SHOW_AWAY);
}
else if (show->BodyText() == "xa") {
s->set_show(PresenceStatus::SHOW_XA);
}
else if (show->BodyText() == "dnd") {
s->set_show(PresenceStatus::SHOW_DND);
}
else if (show->BodyText() == "chat") {
s->set_show(PresenceStatus::SHOW_CHAT);
}
else {
s->set_show(PresenceStatus::SHOW_ONLINE);
}
}
const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
if (caps != NULL) {
std::string node = caps->Attr(QN_NODE);
std::string ver = caps->Attr(QN_VER);
std::string exts = caps->Attr(QN_EXT);
s->set_know_capabilities(true);
s->set_caps_node(node);
s->set_version(ver);
if (ListContainsToken(exts, "voice-v1")) {
s->set_voice_capability(true);
}
if (ListContainsToken(exts, "video-v1")) {
s->set_video_capability(true);
}
}
const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
if (delay != NULL) {
// Ideally we would parse this according to the Psuedo ISO-8601 rules
// that are laid out in JEP-0082:
// http://www.jabber.org/jeps/jep-0082.html
std::string stamp = delay->Attr(kQnStamp);
s->set_sent_time(stamp);
}
const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME);
if (nick) {
s->set_nick(nick->BodyText());
}
}
}
void PresencePushTask::FillMucStatus(const Jid& from, const XmlElement* stanza,
MucPresenceStatus* s) {
FillStatus(from, stanza, s);
}
}

View File

@ -1,70 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_PRESENCEPUSHTASK_H_
#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_PRESENCEPUSHTASK_H_
#include <vector>
#include "talk/examples/call/callclient.h"
#include "webrtc/libjingle/xmpp/presencestatus.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
#include "webrtc/base/sigslot.h"
namespace buzz {
class PresencePushTask : public XmppTask {
public:
PresencePushTask(XmppTaskParentInterface* parent, CallClient* client)
: XmppTask(parent, XmppEngine::HL_TYPE),
client_(client) {}
virtual int ProcessStart();
sigslot::signal1<const PresenceStatus&> SignalStatusUpdate;
sigslot::signal1<const Jid&> SignalMucJoined;
sigslot::signal2<const Jid&, int> SignalMucLeft;
sigslot::signal2<const Jid&, const MucPresenceStatus&> SignalMucStatusUpdate;
protected:
virtual bool HandleStanza(const XmlElement * stanza);
void HandlePresence(const Jid& from, const XmlElement * stanza);
void HandleMucPresence(buzz::Muc* muc,
const Jid& from, const XmlElement * stanza);
static void FillStatus(const Jid& from, const XmlElement * stanza,
PresenceStatus* status);
static void FillMucStatus(const Jid& from, const XmlElement * stanza,
MucPresenceStatus* status);
private:
CallClient* client_;
};
}
#endif

View File

@ -1,67 +0,0 @@
/*
* libjingle
* Copyright 2004--2005, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <iostream>
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmppthread.h"
#include "webrtc/base/thread.h"
int main(int argc, char **argv) {
std::cout << "OAuth Access Token: ";
std::string auth_token;
std::getline(std::cin, auth_token);
std::cout << "User Name: ";
std::string username;
std::getline(std::cin, username);
// Start xmpp on a different thread
buzz::XmppThread thread;
thread.Start();
buzz::XmppClientSettings xcs;
xcs.set_user(username.c_str());
xcs.set_host("gmail.com");
xcs.set_use_tls(buzz::TLS_DISABLED);
xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2,
auth_token.c_str());
xcs.set_server(rtc::SocketAddress("talk.google.com", 5222));
thread.Login(xcs);
// Use main thread for console input
std::string line;
while (std::getline(std::cin, line)) {
if (line == "quit")
break;
}
return 0;
}

View File

@ -31,164 +31,5 @@
'xmpp/jingleinfotask.h',
],
}, # target libjingle_xmpphelp
{
'target_name': 'jingle_session',
'type': 'static_library',
'dependencies': [
'<(talk_root)/libjingle.gyp:libjingle_media',
'<(webrtc_root)/base/base.gyp:rtc_base',
'<(webrtc_root)/common.gyp:webrtc_common',
'<(webrtc_root)/libjingle/xmpp/xmpp.gyp:rtc_xmpp',
],
'cflags_cc!': [
'-Wnon-virtual-dtor',
],
'sources': [
'session/constants.cc',
'session/constants.h',
'session/p2ptransportparser.cc',
'session/p2ptransportparser.h',
'session/parsing.cc',
'session/parsing.h',
'session/rawtransportparser.cc',
'session/rawtransportparser.h',
'session/sessionclient.h',
'session/sessionmanager.h',
'session/sessionmanager.cc',
'session/sessionmanagertask.h',
'session/sessionmessages.cc',
'session/sessionmessages.h',
'session/sessionsendtask.h',
'session/transportparser.cc',
'session/transportparser.h',
'session/media/call.cc',
'session/media/call.h',
'session/media/mediasessionclient.cc',
'session/media/mediasessionclient.h',
'session/media/mediamessages.cc',
'session/media/mediamessages.h',
'session/tunnel/pseudotcpchannel.cc',
'session/tunnel/pseudotcpchannel.h',
'session/tunnel/tunnelsessionclient.cc',
'session/tunnel/tunnelsessionclient.h',
'session/tunnel/securetunnelsessionclient.cc',
'session/tunnel/securetunnelsessionclient.h',
],
'direct_dependent_settings': {
'cflags_cc!': [
'-Wnon-virtual-dtor',
],
'defines': [
'FEATURE_ENABLE_VOICEMAIL',
],
},
'conditions': [
['build_with_chromium==0', {
'defines': [
'FEATURE_ENABLE_VOICEMAIL',
'FEATURE_ENABLE_PSTN',
],
}],
['build_expat==1', {
'dependencies': [
'<(DEPTH)/third_party/expat/expat.gyp:expat',
],
'export_dependent_settings': [
'<(DEPTH)/third_party/expat/expat.gyp:expat',
],
}],
],
},
{
'target_name': 'jingle_session_unittest',
'type': 'executable',
'dependencies': [
'jingle_session',
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
'<(talk_root)/libjingle.gyp:libjingle',
'<(talk_root)/libjingle.gyp:libjingle_p2p',
'<(talk_root)/libjingle_tests.gyp:libjingle_unittest_main',
],
'sources': [
'session/media/mediamessages_unittest.cc',
'session/media/mediasessionclient_unittest.cc',
'session/session_unittest.cc',
'session/transportparser_unittest.cc',
],
'conditions': [
['OS=="win"', {
'msvs_settings': {
'VCLinkerTool': {
'AdditionalDependencies': [
'strmiids.lib',
],
},
},
}],
],
}, # target jingle_session_unittest
{
'target_name': 'login',
'type': 'executable',
'dependencies': [
'libjingle_xmpphelp',
'<(talk_root)/libjingle.gyp:libjingle',
],
'sources': [
'examples/login/login_main.cc',
],
}, # target login
],
'conditions': [
# TODO(ronghuawu): Reenable building call.
# ['OS!="android"', {
# 'targets': [
# {
# 'target_name': 'call',
# 'type': 'executable',
# 'dependencies': [
# 'libjingle.gyp:libjingle_p2p',
# 'libjingle_xmpphelp',
# ],
# 'sources': [
# 'examples/call/call_main.cc',
# 'examples/call/callclient.cc',
# 'examples/call/callclient.h',
# 'examples/call/console.cc',
# 'examples/call/console.h',
# 'examples/call/friendinvitesendtask.cc',
# 'examples/call/friendinvitesendtask.h',
# 'examples/call/mediaenginefactory.cc',
# 'examples/call/mediaenginefactory.h',
# 'examples/call/muc.h',
# 'examples/call/mucinviterecvtask.cc',
# 'examples/call/mucinviterecvtask.h',
# 'examples/call/mucinvitesendtask.cc',
# 'examples/call/mucinvitesendtask.h',
# 'examples/call/presencepushtask.cc',
# 'examples/call/presencepushtask.h',
# ],
# 'conditions': [
# ['OS=="linux"', {
# 'link_settings': {
# 'libraries': [
# '<!@(pkg-config --libs-only-l gobject-2.0 gthread-2.0'
# ' gtk+-2.0)',
# ],
# },
# }],
# ['OS=="win"', {
# 'msvs_settings': {
# 'VCLinkerTool': {
# 'AdditionalDependencies': [
# 'strmiids.lib',
# ],
# },
# },
# }],
# ], # conditions
# }, # target call
# ], # targets
# }], # OS!="android"
],
}

View File

@ -1,217 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/session/constants.h"
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/p2p/base/constants.h"
namespace cricket {
const char NS_EMPTY[] = "";
const char NS_JINGLE[] = "urn:xmpp:jingle:1";
const char NS_JINGLE_DRAFT[] = "google:jingle";
const char NS_GINGLE[] = "http://www.google.com/session";
// actions (aka <session> or <jingle>)
const buzz::StaticQName QN_ACTION = { NS_EMPTY, "action" };
const char LN_INITIATOR[] = "initiator";
const buzz::StaticQName QN_INITIATOR = { NS_EMPTY, LN_INITIATOR };
const buzz::StaticQName QN_CREATOR = { NS_EMPTY, "creator" };
const buzz::StaticQName QN_JINGLE = { NS_JINGLE, "jingle" };
const buzz::StaticQName QN_JINGLE_CONTENT = { NS_JINGLE, "content" };
const buzz::StaticQName QN_JINGLE_CONTENT_NAME = { NS_EMPTY, "name" };
const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA = { NS_EMPTY, "media" };
const buzz::StaticQName QN_JINGLE_REASON = { NS_JINGLE, "reason" };
const buzz::StaticQName QN_JINGLE_DRAFT_GROUP = { NS_JINGLE_DRAFT, "group" };
const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE = { NS_EMPTY, "type" };
const char JINGLE_CONTENT_MEDIA_AUDIO[] = "audio";
const char JINGLE_CONTENT_MEDIA_VIDEO[] = "video";
const char JINGLE_CONTENT_MEDIA_DATA[] = "data";
const char JINGLE_ACTION_SESSION_INITIATE[] = "session-initiate";
const char JINGLE_ACTION_SESSION_INFO[] = "session-info";
const char JINGLE_ACTION_SESSION_ACCEPT[] = "session-accept";
const char JINGLE_ACTION_SESSION_TERMINATE[] = "session-terminate";
const char JINGLE_ACTION_TRANSPORT_INFO[] = "transport-info";
const char JINGLE_ACTION_TRANSPORT_ACCEPT[] = "transport-accept";
const char JINGLE_ACTION_DESCRIPTION_INFO[] = "description-info";
const buzz::StaticQName QN_GINGLE_SESSION = { NS_GINGLE, "session" };
const char GINGLE_ACTION_INITIATE[] = "initiate";
const char GINGLE_ACTION_INFO[] = "info";
const char GINGLE_ACTION_ACCEPT[] = "accept";
const char GINGLE_ACTION_REJECT[] = "reject";
const char GINGLE_ACTION_TERMINATE[] = "terminate";
const char GINGLE_ACTION_CANDIDATES[] = "candidates";
const char GINGLE_ACTION_UPDATE[] = "update";
const char LN_ERROR[] = "error";
const buzz::StaticQName QN_GINGLE_REDIRECT = { NS_GINGLE, "redirect" };
const char STR_REDIRECT_PREFIX[] = "xmpp:";
// Session Contents (aka Gingle <session><description>
// or Jingle <content><description>)
const char LN_DESCRIPTION[] = "description";
const char LN_PAYLOADTYPE[] = "payload-type";
const buzz::StaticQName QN_ID = { NS_EMPTY, "id" };
const buzz::StaticQName QN_SID = { NS_EMPTY, "sid" };
const buzz::StaticQName QN_NAME = { NS_EMPTY, "name" };
const buzz::StaticQName QN_CLOCKRATE = { NS_EMPTY, "clockrate" };
const buzz::StaticQName QN_BITRATE = { NS_EMPTY, "bitrate" };
const buzz::StaticQName QN_CHANNELS = { NS_EMPTY, "channels" };
const buzz::StaticQName QN_WIDTH = { NS_EMPTY, "width" };
const buzz::StaticQName QN_HEIGHT = { NS_EMPTY, "height" };
const buzz::StaticQName QN_FRAMERATE = { NS_EMPTY, "framerate" };
const char LN_NAME[] = "name";
const char LN_VALUE[] = "value";
const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME = { NS_EMPTY, LN_NAME };
const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE = { NS_EMPTY, LN_VALUE };
const char PAYLOADTYPE_PARAMETER_BITRATE[] = "bitrate";
const char PAYLOADTYPE_PARAMETER_HEIGHT[] = "height";
const char PAYLOADTYPE_PARAMETER_WIDTH[] = "width";
const char PAYLOADTYPE_PARAMETER_FRAMERATE[] = "framerate";
const char LN_BANDWIDTH[] = "bandwidth";
const buzz::StaticQName QN_JINGLE_RTP_CONTENT =
{ NS_JINGLE_RTP, LN_DESCRIPTION };
const buzz::StaticQName QN_SSRC = { NS_EMPTY, "ssrc" };
const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE =
{ NS_JINGLE_RTP, LN_PAYLOADTYPE };
const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH =
{ NS_JINGLE_RTP, LN_BANDWIDTH };
const buzz::StaticQName QN_JINGLE_RTCP_MUX = { NS_JINGLE_RTP, "rtcp-mux" };
const buzz::StaticQName QN_JINGLE_RTCP_FB = { NS_JINGLE_RTP, "rtcp-fb" };
const buzz::StaticQName QN_SUBTYPE = { NS_EMPTY, "subtype" };
const buzz::StaticQName QN_PARAMETER = { NS_JINGLE_RTP, "parameter" };
const buzz::StaticQName QN_JINGLE_RTP_HDREXT =
{ NS_JINGLE_RTP, "rtp-hdrext" };
const buzz::StaticQName QN_URI = { NS_EMPTY, "uri" };
const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT =
{ NS_JINGLE_DRAFT_SCTP, LN_DESCRIPTION };
const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM =
{ NS_JINGLE_DRAFT_SCTP, "stream" };
const char NS_GINGLE_AUDIO[] = "http://www.google.com/session/phone";
const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT =
{ NS_GINGLE_AUDIO, LN_DESCRIPTION };
const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE =
{ NS_GINGLE_AUDIO, LN_PAYLOADTYPE };
const buzz::StaticQName QN_GINGLE_AUDIO_SRCID = { NS_GINGLE_AUDIO, "src-id" };
const char NS_GINGLE_VIDEO[] = "http://www.google.com/session/video";
const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT =
{ NS_GINGLE_VIDEO, LN_DESCRIPTION };
const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE =
{ NS_GINGLE_VIDEO, LN_PAYLOADTYPE };
const buzz::StaticQName QN_GINGLE_VIDEO_SRCID = { NS_GINGLE_VIDEO, "src-id" };
const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH =
{ NS_GINGLE_VIDEO, LN_BANDWIDTH };
// Crypto support.
const buzz::StaticQName QN_ENCRYPTION = { NS_JINGLE_RTP, "encryption" };
const buzz::StaticQName QN_ENCRYPTION_REQUIRED = { NS_EMPTY, "required" };
const buzz::StaticQName QN_CRYPTO = { NS_JINGLE_RTP, "crypto" };
const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE =
{ NS_GINGLE_AUDIO, "usage" };
const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE =
{ NS_GINGLE_VIDEO, "usage" };
const buzz::StaticQName QN_CRYPTO_SUITE = { NS_EMPTY, "crypto-suite" };
const buzz::StaticQName QN_CRYPTO_KEY_PARAMS = { NS_EMPTY, "key-params" };
const buzz::StaticQName QN_CRYPTO_TAG = { NS_EMPTY, "tag" };
const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS =
{ NS_EMPTY, "session-params" };
// Transports and candidates.
const char LN_TRANSPORT[] = "transport";
const char LN_CANDIDATE[] = "candidate";
const buzz::StaticQName QN_UFRAG = { cricket::NS_EMPTY, "ufrag" };
const buzz::StaticQName QN_PWD = { cricket::NS_EMPTY, "pwd" };
const buzz::StaticQName QN_COMPONENT = { cricket::NS_EMPTY, "component" };
const buzz::StaticQName QN_IP = { cricket::NS_EMPTY, "ip" };
const buzz::StaticQName QN_PORT = { cricket::NS_EMPTY, "port" };
const buzz::StaticQName QN_NETWORK = { cricket::NS_EMPTY, "network" };
const buzz::StaticQName QN_GENERATION = { cricket::NS_EMPTY, "generation" };
const buzz::StaticQName QN_PRIORITY = { cricket::NS_EMPTY, "priority" };
const buzz::StaticQName QN_PROTOCOL = { cricket::NS_EMPTY, "protocol" };
const char ICE_CANDIDATE_TYPE_PEER_STUN[] = "prflx";
const char ICE_CANDIDATE_TYPE_SERVER_STUN[] = "srflx";
const buzz::StaticQName QN_FINGERPRINT = { cricket::NS_EMPTY, "fingerprint" };
const buzz::StaticQName QN_FINGERPRINT_ALGORITHM =
{ cricket::NS_EMPTY, "algorithm" };
const buzz::StaticQName QN_FINGERPRINT_DIGEST = { cricket::NS_EMPTY, "digest" };
const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT =
{ NS_GINGLE_P2P, LN_TRANSPORT };
const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE =
{ NS_GINGLE_P2P, LN_CANDIDATE };
const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME =
{ NS_GINGLE_P2P, "unknown-channel-name" };
const buzz::StaticQName QN_GINGLE_CANDIDATE = { NS_GINGLE, LN_CANDIDATE };
const buzz::StaticQName QN_ADDRESS = { cricket::NS_EMPTY, "address" };
const buzz::StaticQName QN_USERNAME = { cricket::NS_EMPTY, "username" };
const buzz::StaticQName QN_PASSWORD = { cricket::NS_EMPTY, "password" };
const buzz::StaticQName QN_PREFERENCE = { cricket::NS_EMPTY, "preference" };
// terminate reasons and errors
const char JINGLE_ERROR_BAD_REQUEST[] = "bad-request";
const char JINGLE_ERROR_OUT_OF_ORDER[] = "out-of-order";
const char JINGLE_ERROR_UNKNOWN_SESSION[] = "unknown-session";
// Call terminate reasons from XEP-166
const char STR_TERMINATE_DECLINE[] = "decline";
const char STR_TERMINATE_SUCCESS[] = "success";
const char STR_TERMINATE_ERROR[] = "general-error";
const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[] = "incompatible-parameters";
// Old terminate reasons used by cricket
const char STR_TERMINATE_CALL_ENDED[] = "call-ended";
const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[] = "recipient-unavailable";
const char STR_TERMINATE_RECIPIENT_BUSY[] = "recipient-busy";
const char STR_TERMINATE_INSUFFICIENT_FUNDS[] = "insufficient-funds";
const char STR_TERMINATE_NUMBER_MALFORMED[] = "number-malformed";
const char STR_TERMINATE_NUMBER_DISALLOWED[] = "number-disallowed";
const char STR_TERMINATE_PROTOCOL_ERROR[] = "protocol-error";
const char STR_TERMINATE_INTERNAL_SERVER_ERROR[] = "internal-server-error";
const char STR_TERMINATE_UNKNOWN_ERROR[] = "unknown-error";
// Draft view and notify messages.
const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[] = "video";
const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[] = "audio";
const buzz::StaticQName QN_NICK = { cricket::NS_EMPTY, "nick" };
const buzz::StaticQName QN_TYPE = { cricket::NS_EMPTY, "type" };
const buzz::StaticQName QN_JINGLE_DRAFT_VIEW = { NS_JINGLE_DRAFT, "view" };
const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[] = "none";
const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[] = "static";
const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS = { NS_JINGLE_DRAFT, "params" };
const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS = { NS_JINGLE_DRAFT, "streams" };
const buzz::StaticQName QN_JINGLE_DRAFT_STREAM = { NS_JINGLE_DRAFT, "stream" };
const buzz::StaticQName QN_DISPLAY = { cricket::NS_EMPTY, "display" };
const buzz::StaticQName QN_CNAME = { cricket::NS_EMPTY, "cname" };
const buzz::StaticQName QN_JINGLE_DRAFT_SSRC = { NS_JINGLE_DRAFT, "ssrc" };
const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP =
{ NS_JINGLE_DRAFT, "ssrc-group" };
const buzz::StaticQName QN_SEMANTICS = { cricket::NS_EMPTY, "semantics" };
const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY = { NS_JINGLE_DRAFT, "notify" };
const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE = { NS_JINGLE_DRAFT, "source" };
const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT = { NS_GINGLE_RAW, "transport" };
const buzz::StaticQName QN_GINGLE_RAW_CHANNEL = { NS_GINGLE_RAW, "channel" };
// old stuff
#ifdef FEATURE_ENABLE_VOICEMAIL
const char NS_VOICEMAIL[] = "http://www.google.com/session/voicemail";
const buzz::StaticQName QN_VOICEMAIL_REGARDING = { NS_VOICEMAIL, "regarding" };
#endif
} // namespace cricket

View File

@ -1,219 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_
#define WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_
#include <string>
#include "webrtc/libjingle/xmllite/qname.h"
// This file contains constants related to signaling that are used in various
// classes in this directory.
namespace cricket {
// NS_ == namespace
// QN_ == buzz::QName (namespace + name)
// LN_ == "local name" == QName::LocalPart()
// these are useful when you need to find a tag
// that has different namespaces (like <description> or <transport>)
extern const char NS_EMPTY[];
extern const char NS_JINGLE[];
extern const char NS_JINGLE_DRAFT[];
extern const char NS_GINGLE[];
enum SignalingProtocol {
PROTOCOL_JINGLE,
PROTOCOL_GINGLE,
PROTOCOL_HYBRID,
};
// actions (aka Gingle <session> or Jingle <jingle>)
extern const buzz::StaticQName QN_ACTION;
extern const char LN_INITIATOR[];
extern const buzz::StaticQName QN_INITIATOR;
extern const buzz::StaticQName QN_CREATOR;
extern const buzz::StaticQName QN_JINGLE;
extern const buzz::StaticQName QN_JINGLE_CONTENT;
extern const buzz::StaticQName QN_JINGLE_CONTENT_NAME;
extern const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA;
extern const buzz::StaticQName QN_JINGLE_REASON;
extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP;
extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE;
extern const char JINGLE_CONTENT_MEDIA_AUDIO[];
extern const char JINGLE_CONTENT_MEDIA_VIDEO[];
extern const char JINGLE_CONTENT_MEDIA_DATA[];
extern const char JINGLE_ACTION_SESSION_INITIATE[];
extern const char JINGLE_ACTION_SESSION_INFO[];
extern const char JINGLE_ACTION_SESSION_ACCEPT[];
extern const char JINGLE_ACTION_SESSION_TERMINATE[];
extern const char JINGLE_ACTION_TRANSPORT_INFO[];
extern const char JINGLE_ACTION_TRANSPORT_ACCEPT[];
extern const char JINGLE_ACTION_DESCRIPTION_INFO[];
extern const buzz::StaticQName QN_GINGLE_SESSION;
extern const char GINGLE_ACTION_INITIATE[];
extern const char GINGLE_ACTION_INFO[];
extern const char GINGLE_ACTION_ACCEPT[];
extern const char GINGLE_ACTION_REJECT[];
extern const char GINGLE_ACTION_TERMINATE[];
extern const char GINGLE_ACTION_CANDIDATES[];
extern const char GINGLE_ACTION_UPDATE[];
extern const char LN_ERROR[];
extern const buzz::StaticQName QN_GINGLE_REDIRECT;
extern const char STR_REDIRECT_PREFIX[];
// Session Contents (aka Gingle <session><description>
// or Jingle <content><description>)
extern const char LN_DESCRIPTION[];
extern const char LN_PAYLOADTYPE[];
extern const buzz::StaticQName QN_ID;
extern const buzz::StaticQName QN_SID;
extern const buzz::StaticQName QN_NAME;
extern const buzz::StaticQName QN_CLOCKRATE;
extern const buzz::StaticQName QN_BITRATE;
extern const buzz::StaticQName QN_CHANNELS;
extern const buzz::StaticQName QN_PARAMETER;
extern const char LN_NAME[];
extern const char LN_VALUE[];
extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME;
extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE;
extern const char PAYLOADTYPE_PARAMETER_BITRATE[];
extern const char PAYLOADTYPE_PARAMETER_HEIGHT[];
extern const char PAYLOADTYPE_PARAMETER_WIDTH[];
extern const char PAYLOADTYPE_PARAMETER_FRAMERATE[];
extern const char LN_BANDWIDTH[];
extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT;
extern const buzz::StaticQName QN_SSRC;
extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE;
extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH;
extern const buzz::StaticQName QN_JINGLE_RTCP_MUX;
extern const buzz::StaticQName QN_JINGLE_RTCP_FB;
extern const buzz::StaticQName QN_SUBTYPE;
extern const buzz::StaticQName QN_JINGLE_RTP_HDREXT;
extern const buzz::StaticQName QN_URI;
extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT;
extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM;
extern const char NS_GINGLE_AUDIO[];
extern const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT;
extern const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE;
extern const buzz::StaticQName QN_GINGLE_AUDIO_SRCID;
extern const char NS_GINGLE_VIDEO[];
extern const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT;
extern const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE;
extern const buzz::StaticQName QN_GINGLE_VIDEO_SRCID;
extern const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH;
// Crypto support.
extern const buzz::StaticQName QN_ENCRYPTION;
extern const buzz::StaticQName QN_ENCRYPTION_REQUIRED;
extern const buzz::StaticQName QN_CRYPTO;
extern const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE;
extern const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE;
extern const buzz::StaticQName QN_CRYPTO_SUITE;
extern const buzz::StaticQName QN_CRYPTO_KEY_PARAMS;
extern const buzz::StaticQName QN_CRYPTO_TAG;
extern const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS;
// Transports and candidates.
extern const char LN_TRANSPORT[];
extern const char LN_CANDIDATE[];
extern const buzz::StaticQName QN_JINGLE_P2P_TRANSPORT;
extern const buzz::StaticQName QN_JINGLE_P2P_CANDIDATE;
extern const buzz::StaticQName QN_UFRAG;
extern const buzz::StaticQName QN_COMPONENT;
extern const buzz::StaticQName QN_PWD;
extern const buzz::StaticQName QN_IP;
extern const buzz::StaticQName QN_PORT;
extern const buzz::StaticQName QN_NETWORK;
extern const buzz::StaticQName QN_GENERATION;
extern const buzz::StaticQName QN_PRIORITY;
extern const buzz::StaticQName QN_PROTOCOL;
extern const char ICE_CANDIDATE_TYPE_PEER_STUN[];
extern const char ICE_CANDIDATE_TYPE_SERVER_STUN[];
extern const buzz::StaticQName QN_FINGERPRINT;
extern const buzz::StaticQName QN_FINGERPRINT_ALGORITHM;
extern const buzz::StaticQName QN_FINGERPRINT_DIGEST;
extern const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT;
extern const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE;
extern const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME;
extern const buzz::StaticQName QN_GINGLE_CANDIDATE;
extern const buzz::StaticQName QN_ADDRESS;
extern const buzz::StaticQName QN_USERNAME;
extern const buzz::StaticQName QN_PASSWORD;
extern const buzz::StaticQName QN_PREFERENCE;
extern const char GINGLE_CANDIDATE_TYPE_STUN[];
extern const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT;
extern const buzz::StaticQName QN_GINGLE_RAW_CHANNEL;
// terminate reasons and errors: see http://xmpp.org/extensions/xep-0166.html
extern const char JINGLE_ERROR_BAD_REQUEST[]; // like parse error
// got transport-info before session-initiate, for example
extern const char JINGLE_ERROR_OUT_OF_ORDER[];
extern const char JINGLE_ERROR_UNKNOWN_SESSION[];
// Call terminate reasons from XEP-166
extern const char STR_TERMINATE_DECLINE[]; // polite reject
extern const char STR_TERMINATE_SUCCESS[]; // polite hangup
extern const char STR_TERMINATE_ERROR[]; // something bad happened
extern const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[]; // no codecs?
// Old terminate reasons used by cricket
extern const char STR_TERMINATE_CALL_ENDED[];
extern const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[];
extern const char STR_TERMINATE_RECIPIENT_BUSY[];
extern const char STR_TERMINATE_INSUFFICIENT_FUNDS[];
extern const char STR_TERMINATE_NUMBER_MALFORMED[];
extern const char STR_TERMINATE_NUMBER_DISALLOWED[];
extern const char STR_TERMINATE_PROTOCOL_ERROR[];
extern const char STR_TERMINATE_INTERNAL_SERVER_ERROR[];
extern const char STR_TERMINATE_UNKNOWN_ERROR[];
// Draft view and notify messages.
extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[];
extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[];
extern const buzz::StaticQName QN_NICK;
extern const buzz::StaticQName QN_TYPE;
extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW;
extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[];
extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[];
extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS;
extern const buzz::StaticQName QN_WIDTH;
extern const buzz::StaticQName QN_HEIGHT;
extern const buzz::StaticQName QN_FRAMERATE;
extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM;
extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS;
extern const buzz::StaticQName QN_DISPLAY;
extern const buzz::StaticQName QN_CNAME;
extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC;
extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP;
extern const buzz::StaticQName QN_SEMANTICS;
extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY;
extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE;
// old stuff
#ifdef FEATURE_ENABLE_VOICEMAIL
extern const char NS_VOICEMAIL[];
extern const buzz::StaticQName QN_VOICEMAIL_REGARDING;
#endif
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,308 +0,0 @@
/*
* libjingle
* Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_
#define WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_
#include <deque>
#include <map>
#include <string>
#include <vector>
#include "talk/media/base/mediachannel.h"
#include "talk/media/base/screencastid.h"
#include "talk/media/base/streamparams.h"
#include "talk/media/base/videocommon.h"
#include "talk/session/media/audiomonitor.h"
#include "talk/session/media/currentspeakermonitor.h"
#include "talk/session/media/mediasession.h"
#include "webrtc/base/messagequeue.h"
#include "webrtc/libjingle/session/media/mediamessages.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/xmpp/jid.h"
#include "webrtc/p2p/client/socketmonitor.h"
#include "webrtc/p2p/client/socketmonitor.h"
namespace cricket {
struct AudioInfo;
class Call;
class MediaSessionClient;
class BaseChannel;
class VoiceChannel;
class VideoChannel;
class DataChannel;
// Can't typedef this easily since it's forward declared as struct elsewhere.
struct CallOptions : public MediaSessionOptions {
};
// CurrentSpeakerMonitor used to have a dependency on Call. To remove this
// dependency, we create AudioSourceContext. CurrentSpeakerMonitor depends on
// AudioSourceContext.
// AudioSourceProxy acts as a proxy so that when SignalAudioMonitor
// in Call is triggered, SignalAudioMonitor in AudioSourceContext is triggered.
// Likewise, when OnMediaStreamsUpdate in Call is triggered,
// OnMediaStreamsUpdate in AudioSourceContext is triggered.
class AudioSourceProxy: public AudioSourceContext, public sigslot::has_slots<> {
public:
explicit AudioSourceProxy(Call* call);
private:
void OnAudioMonitor(Call* call, const AudioInfo& info);
void OnMediaStreamsUpdate(Call* call, cricket::Session*,
const cricket::MediaStreams&, const cricket::MediaStreams&);
Call* call_;
};
class Call : public rtc::MessageHandler, public sigslot::has_slots<> {
public:
explicit Call(MediaSessionClient* session_client);
~Call();
// |initiator| can be empty.
Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator,
const CallOptions& options);
Session* InitiateSession(const std::string& id, const buzz::Jid& to,
const CallOptions& options);
void AcceptSession(Session* session, const CallOptions& options);
void RejectSession(Session* session);
void TerminateSession(Session* session);
void Terminate();
bool SendViewRequest(Session* session,
const ViewRequest& view_request);
void SetVideoRenderer(Session* session, uint32 ssrc,
VideoRenderer* renderer);
void StartConnectionMonitor(Session* session, int cms);
void StopConnectionMonitor(Session* session);
void StartAudioMonitor(Session* session, int cms);
void StopAudioMonitor(Session* session);
bool IsAudioMonitorRunning(Session* session);
void StartSpeakerMonitor(Session* session);
void StopSpeakerMonitor(Session* session);
void Mute(bool mute);
void MuteVideo(bool mute);
bool SendData(Session* session,
const SendDataParams& params,
const rtc::Buffer& payload,
SendDataResult* result);
void PressDTMF(int event);
bool StartScreencast(Session* session,
const std::string& stream_name, uint32 ssrc,
const ScreencastId& screenid, int fps);
bool StopScreencast(Session* session,
const std::string& stream_name, uint32 ssrc);
std::vector<Session*> sessions();
uint32 id();
bool has_video() const { return has_video_; }
bool has_data() const { return has_data_; }
bool muted() const { return muted_; }
bool video() const { return has_video_; }
bool secure() const;
bool video_muted() const { return video_muted_; }
const std::vector<StreamParams>* GetDataRecvStreams(Session* session) const {
MediaStreams* recv_streams = GetMediaStreams(session);
return recv_streams ? &recv_streams->data() : NULL;
}
const std::vector<StreamParams>* GetVideoRecvStreams(Session* session) const {
MediaStreams* recv_streams = GetMediaStreams(session);
return recv_streams ? &recv_streams->video() : NULL;
}
const std::vector<StreamParams>* GetAudioRecvStreams(Session* session) const {
MediaStreams* recv_streams = GetMediaStreams(session);
return recv_streams ? &recv_streams->audio() : NULL;
}
VoiceChannel* GetVoiceChannel(Session* session) const;
VideoChannel* GetVideoChannel(Session* session) const;
DataChannel* GetDataChannel(Session* session) const;
// Public just for unit tests
VideoContentDescription* CreateVideoStreamUpdate(const StreamParams& stream);
// Takes ownership of video.
void SendVideoStreamUpdate(Session* session, VideoContentDescription* video);
// Setting this to false will cause the call to have a longer timeout and
// for the SignalSetupToCallVoicemail to never fire.
void set_send_to_voicemail(bool send_to_voicemail) {
send_to_voicemail_ = send_to_voicemail;
}
bool send_to_voicemail() { return send_to_voicemail_; }
const VoiceMediaInfo& last_voice_media_info() const {
return last_voice_media_info_;
}
// Sets a flag on the chatapp that will redirect the call to voicemail once
// the call has been terminated
sigslot::signal0<> SignalSetupToCallVoicemail;
sigslot::signal2<Call*, Session*> SignalAddSession;
sigslot::signal2<Call*, Session*> SignalRemoveSession;
sigslot::signal3<Call*, Session*, Session::State>
SignalSessionState;
sigslot::signal3<Call*, Session*, Session::Error>
SignalSessionError;
sigslot::signal3<Call*, Session*, const std::string &>
SignalReceivedTerminateReason;
sigslot::signal2<Call*, const std::vector<ConnectionInfo> &>
SignalConnectionMonitor;
sigslot::signal2<Call*, const VoiceMediaInfo&> SignalMediaMonitor;
sigslot::signal2<Call*, const AudioInfo&> SignalAudioMonitor;
// Empty nick on StreamParams means "unknown".
// No ssrcs in StreamParams means "no current speaker".
sigslot::signal3<Call*,
Session*,
const StreamParams&> SignalSpeakerMonitor;
sigslot::signal2<Call*, const std::vector<ConnectionInfo> &>
SignalVideoConnectionMonitor;
sigslot::signal2<Call*, const VideoMediaInfo&> SignalVideoMediaMonitor;
// Gives added streams and removed streams, in that order.
sigslot::signal4<Call*,
Session*,
const MediaStreams&,
const MediaStreams&> SignalMediaStreamsUpdate;
sigslot::signal3<Call*,
const ReceiveDataParams&,
const rtc::Buffer&> SignalDataReceived;
AudioSourceProxy* GetAudioSourceProxy();
private:
void OnMessage(rtc::Message* message);
void OnSessionState(BaseSession* base_session, BaseSession::State state);
void OnSessionError(BaseSession* base_session, BaseSession::Error error);
void OnSessionInfoMessage(
Session* session, const buzz::XmlElement* action_elem);
void OnViewRequest(
Session* session, const ViewRequest& view_request);
void OnRemoteDescriptionUpdate(
BaseSession* base_session, const ContentInfos& updated_contents);
void OnReceivedTerminateReason(Session* session, const std::string &reason);
void IncomingSession(Session* session, const SessionDescription* offer);
// Returns true on success.
bool AddSession(Session* session, const SessionDescription* offer);
void RemoveSession(Session* session);
void EnableChannels(bool enable);
void EnableSessionChannels(Session* session, bool enable);
void Join(Call* call, bool enable);
void OnConnectionMonitor(VoiceChannel* channel,
const std::vector<ConnectionInfo> &infos);
void OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info);
void OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info);
void OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc);
void OnConnectionMonitor(VideoChannel* channel,
const std::vector<ConnectionInfo> &infos);
void OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info);
void OnDataReceived(DataChannel* channel,
const ReceiveDataParams& params,
const rtc::Buffer& payload);
MediaStreams* GetMediaStreams(Session* session) const;
void UpdateRemoteMediaStreams(Session* session,
const ContentInfos& updated_contents,
bool update_channels);
bool UpdateVoiceChannelRemoteContent(Session* session,
const AudioContentDescription* audio);
bool UpdateVideoChannelRemoteContent(Session* session,
const VideoContentDescription* video);
bool UpdateDataChannelRemoteContent(Session* session,
const DataContentDescription* data);
void UpdateRecvStreams(const std::vector<StreamParams>& update_streams,
BaseChannel* channel,
std::vector<StreamParams>* recv_streams,
std::vector<StreamParams>* added_streams,
std::vector<StreamParams>* removed_streams);
void AddRecvStreams(const std::vector<StreamParams>& added_streams,
BaseChannel* channel,
std::vector<StreamParams>* recv_streams);
void AddRecvStream(const StreamParams& stream,
BaseChannel* channel,
std::vector<StreamParams>* recv_streams);
void RemoveRecvStreams(const std::vector<StreamParams>& removed_streams,
BaseChannel* channel,
std::vector<StreamParams>* recv_streams);
void RemoveRecvStream(const StreamParams& stream,
BaseChannel* channel,
std::vector<StreamParams>* recv_streams);
void ContinuePlayDTMF();
bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc);
bool StopAllScreencastsWithoutSendingUpdate(Session* session);
bool SessionDescriptionContainsCrypto(const SessionDescription* sdesc) const;
Session* InternalInitiateSession(const std::string& id,
const buzz::Jid& to,
const std::string& initiator_name,
const CallOptions& options);
uint32 id_;
MediaSessionClient* session_client_;
struct StartedCapture {
StartedCapture(cricket::VideoCapturer* capturer,
const cricket::VideoFormat& format) :
capturer(capturer),
format(format) {
}
cricket::VideoCapturer* capturer;
cricket::VideoFormat format;
};
typedef std::map<uint32, StartedCapture> StartedScreencastMap;
struct MediaSession {
Session* session;
VoiceChannel* voice_channel;
VideoChannel* video_channel;
DataChannel* data_channel;
MediaStreams* recv_streams;
StartedScreencastMap started_screencasts;
};
// Create a map of media sessions, keyed off session->id().
typedef std::map<std::string, MediaSession> MediaSessionMap;
MediaSessionMap media_session_map_;
std::map<std::string, CurrentSpeakerMonitor*> speaker_monitor_map_;
bool has_video_;
bool has_data_;
bool muted_;
bool video_muted_;
bool send_to_voicemail_;
// DTMF tones have to be queued up so that we don't flood the call. We
// keep a deque (doubely ended queue) of them around. While one is playing we
// set the playing_dtmf_ bit and schedule a message in XX msec to clear that
// bit or start the next tone playing.
std::deque<int> queued_dtmf_;
bool playing_dtmf_;
VoiceMediaInfo last_voice_media_info_;
rtc::scoped_ptr<AudioSourceProxy> audio_source_proxy_;
friend class MediaSessionClient;
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_

View File

@ -1,332 +0,0 @@
/*
* libjingle
* Copyright 2010 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Documentation is in mediamessages.h.
*/
#include "webrtc/libjingle/session/media/mediamessages.h"
#include "webrtc/p2p/base/constants.h"
#include "webrtc/libjingle/session/media/mediasessionclient.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/stringencode.h"
namespace cricket {
namespace {
bool ParseSsrc(const std::string& string, uint32* ssrc) {
return rtc::FromString(string, ssrc);
}
// Builds a <view> element according to the following spec:
// goto/jinglemuc
buzz::XmlElement* CreateViewElem(const std::string& name,
const std::string& type) {
buzz::XmlElement* view_elem =
new buzz::XmlElement(QN_JINGLE_DRAFT_VIEW, true);
view_elem->AddAttr(QN_NAME, name);
view_elem->SetAttr(QN_TYPE, type);
return view_elem;
}
buzz::XmlElement* CreateVideoViewElem(const std::string& content_name,
const std::string& type) {
return CreateViewElem(content_name, type);
}
buzz::XmlElement* CreateNoneVideoViewElem(const std::string& content_name) {
return CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_NONE);
}
buzz::XmlElement* CreateStaticVideoViewElem(const std::string& content_name,
const StaticVideoView& view) {
buzz::XmlElement* view_elem =
CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_STATIC);
AddXmlAttr(view_elem, QN_SSRC, view.selector.ssrc);
buzz::XmlElement* params_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_PARAMS);
AddXmlAttr(params_elem, QN_WIDTH, view.width);
AddXmlAttr(params_elem, QN_HEIGHT, view.height);
AddXmlAttr(params_elem, QN_FRAMERATE, view.framerate);
AddXmlAttr(params_elem, QN_PREFERENCE, view.preference);
view_elem->AddElement(params_elem);
return view_elem;
}
} // namespace
bool IsJingleViewRequest(const buzz::XmlElement* action_elem) {
return action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW) != NULL;
}
bool ParseStaticVideoView(const buzz::XmlElement* view_elem,
StaticVideoView* view,
ParseError* error) {
uint32 ssrc;
if (!ParseSsrc(view_elem->Attr(QN_SSRC), &ssrc)) {
return BadParse("Invalid or missing view ssrc.", error);
}
view->selector = StreamSelector(ssrc);
const buzz::XmlElement* params_elem =
view_elem->FirstNamed(QN_JINGLE_DRAFT_PARAMS);
if (params_elem) {
view->width = GetXmlAttr(params_elem, QN_WIDTH, 0);
view->height = GetXmlAttr(params_elem, QN_HEIGHT, 0);
view->framerate = GetXmlAttr(params_elem, QN_FRAMERATE, 0);
view->preference = GetXmlAttr(params_elem, QN_PREFERENCE, 0);
} else {
return BadParse("Missing view params.", error);
}
return true;
}
bool ParseJingleViewRequest(const buzz::XmlElement* action_elem,
ViewRequest* view_request,
ParseError* error) {
for (const buzz::XmlElement* view_elem =
action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW);
view_elem != NULL;
view_elem = view_elem->NextNamed(QN_JINGLE_DRAFT_VIEW)) {
std::string type = view_elem->Attr(QN_TYPE);
if (STR_JINGLE_DRAFT_VIEW_TYPE_NONE == type) {
view_request->static_video_views.clear();
return true;
} else if (STR_JINGLE_DRAFT_VIEW_TYPE_STATIC == type) {
StaticVideoView static_video_view(StreamSelector(0), 0, 0, 0);
if (!ParseStaticVideoView(view_elem, &static_video_view, error)) {
return false;
}
view_request->static_video_views.push_back(static_video_view);
} else {
LOG(LS_INFO) << "Ingnoring unknown view type: " << type;
}
}
return true;
}
bool WriteJingleViewRequest(const std::string& content_name,
const ViewRequest& request,
XmlElements* elems,
WriteError* error) {
if (request.static_video_views.empty()) {
elems->push_back(CreateNoneVideoViewElem(content_name));
} else {
for (StaticVideoViews::const_iterator view =
request.static_video_views.begin();
view != request.static_video_views.end(); ++view) {
elems->push_back(CreateStaticVideoViewElem(content_name, *view));
}
}
return true;
}
bool ParseSsrcAsLegacyStream(const buzz::XmlElement* desc_elem,
std::vector<StreamParams>* streams,
ParseError* error) {
const std::string ssrc_str = desc_elem->Attr(QN_SSRC);
if (!ssrc_str.empty()) {
uint32 ssrc;
if (!ParseSsrc(ssrc_str, &ssrc)) {
return BadParse("Missing or invalid ssrc.", error);
}
streams->push_back(StreamParams::CreateLegacy(ssrc));
}
return true;
}
bool ParseSsrcs(const buzz::XmlElement* parent_elem,
std::vector<uint32>* ssrcs,
ParseError* error) {
for (const buzz::XmlElement* ssrc_elem =
parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC);
ssrc_elem != NULL;
ssrc_elem = ssrc_elem->NextNamed(QN_JINGLE_DRAFT_SSRC)) {
uint32 ssrc;
if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) {
return BadParse("Missing or invalid ssrc.", error);
}
ssrcs->push_back(ssrc);
}
return true;
}
bool ParseSsrcGroups(const buzz::XmlElement* parent_elem,
std::vector<SsrcGroup>* ssrc_groups,
ParseError* error) {
for (const buzz::XmlElement* group_elem =
parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC_GROUP);
group_elem != NULL;
group_elem = group_elem->NextNamed(QN_JINGLE_DRAFT_SSRC_GROUP)) {
std::string semantics = group_elem->Attr(QN_SEMANTICS);
std::vector<uint32> ssrcs;
if (!ParseSsrcs(group_elem, &ssrcs, error)) {
return false;
}
ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
}
return true;
}
bool ParseJingleStream(const buzz::XmlElement* stream_elem,
std::vector<StreamParams>* streams,
ParseError* error) {
StreamParams stream;
// We treat the nick as a stream groupid.
stream.groupid = stream_elem->Attr(QN_NICK);
stream.id = stream_elem->Attr(QN_NAME);
stream.type = stream_elem->Attr(QN_TYPE);
stream.display = stream_elem->Attr(QN_DISPLAY);
stream.cname = stream_elem->Attr(QN_CNAME);
if (!ParseSsrcs(stream_elem, &(stream.ssrcs), error)) {
return false;
}
std::vector<SsrcGroup> ssrc_groups;
if (!ParseSsrcGroups(stream_elem, &(stream.ssrc_groups), error)) {
return false;
}
streams->push_back(stream);
return true;
}
bool ParseJingleRtpHeaderExtensions(const buzz::XmlElement* parent_elem,
std::vector<RtpHeaderExtension>* hdrexts,
ParseError* error) {
for (const buzz::XmlElement* hdrext_elem =
parent_elem->FirstNamed(QN_JINGLE_RTP_HDREXT);
hdrext_elem != NULL;
hdrext_elem = hdrext_elem->NextNamed(QN_JINGLE_RTP_HDREXT)) {
std::string uri = hdrext_elem->Attr(QN_URI);
int id = GetXmlAttr(hdrext_elem, QN_ID, 0);
if (id <= 0) {
return BadParse("Invalid RTP header extension id.", error);
}
hdrexts->push_back(RtpHeaderExtension(uri, id));
}
return true;
}
bool HasJingleStreams(const buzz::XmlElement* desc_elem) {
const buzz::XmlElement* streams_elem =
desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
return (streams_elem != NULL);
}
bool ParseJingleStreams(const buzz::XmlElement* desc_elem,
std::vector<StreamParams>* streams,
ParseError* error) {
const buzz::XmlElement* streams_elem =
desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
if (streams_elem == NULL) {
return BadParse("Missing streams element.", error);
}
for (const buzz::XmlElement* stream_elem =
streams_elem->FirstNamed(QN_JINGLE_DRAFT_STREAM);
stream_elem != NULL;
stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_STREAM)) {
if (!ParseJingleStream(stream_elem, streams, error)) {
return false;
}
}
return true;
}
void WriteSsrcs(const std::vector<uint32>& ssrcs,
buzz::XmlElement* parent_elem) {
for (std::vector<uint32>::const_iterator ssrc = ssrcs.begin();
ssrc != ssrcs.end(); ++ssrc) {
buzz::XmlElement* ssrc_elem =
new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC, false);
SetXmlBody(ssrc_elem, *ssrc);
parent_elem->AddElement(ssrc_elem);
}
}
void WriteSsrcGroups(const std::vector<SsrcGroup>& groups,
buzz::XmlElement* parent_elem) {
for (std::vector<SsrcGroup>::const_iterator group = groups.begin();
group != groups.end(); ++group) {
buzz::XmlElement* group_elem =
new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC_GROUP, false);
AddXmlAttrIfNonEmpty(group_elem, QN_SEMANTICS, group->semantics);
WriteSsrcs(group->ssrcs, group_elem);
parent_elem->AddElement(group_elem);
}
}
void WriteJingleStream(const StreamParams& stream,
buzz::XmlElement* parent_elem) {
buzz::XmlElement* stream_elem =
new buzz::XmlElement(QN_JINGLE_DRAFT_STREAM, false);
// We treat the nick as a stream groupid.
AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream.groupid);
AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream.id);
AddXmlAttrIfNonEmpty(stream_elem, QN_TYPE, stream.type);
AddXmlAttrIfNonEmpty(stream_elem, QN_DISPLAY, stream.display);
AddXmlAttrIfNonEmpty(stream_elem, QN_CNAME, stream.cname);
WriteSsrcs(stream.ssrcs, stream_elem);
WriteSsrcGroups(stream.ssrc_groups, stream_elem);
parent_elem->AddElement(stream_elem);
}
void WriteJingleStreams(const std::vector<StreamParams>& streams,
buzz::XmlElement* parent_elem) {
buzz::XmlElement* streams_elem =
new buzz::XmlElement(QN_JINGLE_DRAFT_STREAMS, true);
for (std::vector<StreamParams>::const_iterator stream = streams.begin();
stream != streams.end(); ++stream) {
WriteJingleStream(*stream, streams_elem);
}
parent_elem->AddElement(streams_elem);
}
void WriteJingleRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& hdrexts,
buzz::XmlElement* parent_elem) {
for (std::vector<RtpHeaderExtension>::const_iterator hdrext = hdrexts.begin();
hdrext != hdrexts.end(); ++hdrext) {
buzz::XmlElement* hdrext_elem =
new buzz::XmlElement(QN_JINGLE_RTP_HDREXT, false);
AddXmlAttr(hdrext_elem, QN_URI, hdrext->uri);
AddXmlAttr(hdrext_elem, QN_ID, hdrext->id);
parent_elem->AddElement(hdrext_elem);
}
}
} // namespace cricket

View File

@ -1,98 +0,0 @@
/*
* libjingle
* Copyright 2010 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* A collection of functions and types for serializing and
* deserializing Jingle session messages related to media.
* Specificially, the <notify> and <view> messages. They are not yet
* standardized, but their current documentation can be found at:
* goto/jinglemuc
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_
#define WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_
#include <string>
#include <vector>
#include "talk/media/base/mediachannel.h" // For RtpHeaderExtension
#include "talk/media/base/streamparams.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/p2p/base/sessiondescription.h"
namespace cricket {
// If the parent element (usually <jingle>) is a jingle view.
bool IsJingleViewRequest(const buzz::XmlElement* action_elem);
// Parses a view request from the parent element (usually
// <jingle>). If it fails, it returns false and fills an error
// message.
bool ParseJingleViewRequest(const buzz::XmlElement* action_elem,
ViewRequest* view_request,
ParseError* error);
// Serializes a view request to XML. If it fails, returns false and
// fills in an error message.
bool WriteJingleViewRequest(const std::string& content_name,
const ViewRequest& view,
XmlElements* elems,
WriteError* error);
// TODO(pthatcher): Get rid of legacy source notify and replace with
// description-info as soon as reflector is capable of sending it.
bool IsSourcesNotify(const buzz::XmlElement* action_elem);
// If the given elem has <streams>.
bool HasJingleStreams(const buzz::XmlElement* desc_elem);
// Parses streams from a jingle <description>. If it fails, returns
// false and fills an error message.
bool ParseJingleStreams(const buzz::XmlElement* desc_elem,
std::vector<StreamParams>* streams,
ParseError* error);
// Write a <streams> element to the parent_elem.
void WriteJingleStreams(const std::vector<StreamParams>& streams,
buzz::XmlElement* parent_elem);
// Parses rtp header extensions from a jingle <description>. If it
// fails, returns false and fills an error message.
bool ParseJingleRtpHeaderExtensions(
const buzz::XmlElement* desc_elem,
std::vector<RtpHeaderExtension>* hdrexts,
ParseError* error);
// Writes <rtp-hdrext> elements to the parent_elem.
void WriteJingleRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& hdrexts,
buzz::XmlElement* parent_elem);
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_

View File

@ -1,363 +0,0 @@
/*
* libjingle
* Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "webrtc/libjingle/session/media/mediamessages.h"
#include <string>
#include <vector>
#include "webrtc/p2p/base/constants.h"
#include "webrtc/libjingle/session/media/mediasessionclient.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/scoped_ptr.h"
// Unit tests for mediamessages.cc.
namespace cricket {
namespace {
static const char kViewVideoNoneXml[] =
"<view xmlns='google:jingle'"
" name='video1'"
" type='none'"
"/>";
class MediaMessagesTest : public testing::Test {
public:
// CreateMediaSessionDescription uses a static variable cricket::NS_JINGLE_RTP
// defined in another file and cannot be used to initialize another static
// variable (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14)
MediaMessagesTest()
: remote_description_(CreateMediaSessionDescription("audio1", "video1")) {
}
protected:
static std::string ViewVideoStaticVgaXml(const std::string& ssrc) {
return "<view xmlns='google:jingle'"
" name='video1'"
" type='static'"
" ssrc='" + ssrc + "'"
">"
"<params"
" width='640'"
" height='480'"
" framerate='30'"
" preference='0'"
" />"
"</view>";
}
static cricket::StreamParams CreateStream(const std::string& nick,
const std::string& name,
uint32 ssrc1,
uint32 ssrc2,
const std::string& semantics,
const std::string& type,
const std::string& display) {
StreamParams stream;
stream.groupid = nick;
stream.id = name;
stream.ssrcs.push_back(ssrc1);
stream.ssrcs.push_back(ssrc2);
stream.ssrc_groups.push_back(
cricket::SsrcGroup(semantics, stream.ssrcs));
stream.type = type;
stream.display = display;
return stream;
}
static std::string StreamsXml(const std::string& stream1,
const std::string& stream2) {
return "<streams xmlns='google:jingle'>"
+ stream1
+ stream2 +
"</streams>";
}
static std::string StreamXml(const std::string& nick,
const std::string& name,
const std::string& ssrc1,
const std::string& ssrc2,
const std::string& semantics,
const std::string& type,
const std::string& display) {
return "<stream"
" nick='" + nick + "'"
" name='" + name + "'"
" type='" + type + "'"
" display='" + display + "'"
">"
"<ssrc>" + ssrc1 + "</ssrc>"
"<ssrc>" + ssrc2 + "</ssrc>"
"<ssrc-group"
" semantics='" + semantics + "'"
">"
"<ssrc>" + ssrc1 + "</ssrc>"
"<ssrc>" + ssrc2 + "</ssrc>"
"</ssrc-group>"
"</stream>";
}
static std::string HeaderExtensionsXml(const std::string& hdrext1,
const std::string& hdrext2) {
return "<rtp:description xmlns:rtp=\"urn:xmpp:jingle:apps:rtp:1\">"
+ hdrext1
+ hdrext2 +
"</rtp:description>";
}
static std::string HeaderExtensionXml(const std::string& uri,
const std::string& id) {
return "<rtp:rtp-hdrext"
" uri='" + uri + "'"
" id='" + id + "'"
"/>";
}
static cricket::SessionDescription* CreateMediaSessionDescription(
const std::string& audio_content_name,
const std::string& video_content_name) {
cricket::SessionDescription* desc = new cricket::SessionDescription();
desc->AddContent(audio_content_name, cricket::NS_JINGLE_RTP,
new cricket::AudioContentDescription());
desc->AddContent(video_content_name, cricket::NS_JINGLE_RTP,
new cricket::VideoContentDescription());
return desc;
}
size_t ClearXmlElements(cricket::XmlElements* elements) {
size_t size = elements->size();
for (size_t i = 0; i < size; i++) {
delete elements->at(i);
}
elements->clear();
return size;
}
rtc::scoped_ptr<cricket::SessionDescription> remote_description_;
};
} // anonymous namespace
// Test serializing/deserializing an empty <view> message.
TEST_F(MediaMessagesTest, ViewNoneToFromXml) {
buzz::XmlElement* expected_view_elem =
buzz::XmlElement::ForStr(kViewVideoNoneXml);
rtc::scoped_ptr<buzz::XmlElement> action_elem(
new buzz::XmlElement(QN_JINGLE));
EXPECT_FALSE(cricket::IsJingleViewRequest(action_elem.get()));
action_elem->AddElement(expected_view_elem);
EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get()));
cricket::ViewRequest view_request;
cricket::XmlElements actual_view_elems;
cricket::WriteError error;
ASSERT_TRUE(cricket::WriteJingleViewRequest(
"video1", view_request, &actual_view_elems, &error));
ASSERT_EQ(1U, actual_view_elems.size());
EXPECT_EQ(expected_view_elem->Str(), actual_view_elems[0]->Str());
ClearXmlElements(&actual_view_elems);
cricket::ParseError parse_error;
EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get()));
ASSERT_TRUE(cricket::ParseJingleViewRequest(
action_elem.get(), &view_request, &parse_error));
EXPECT_EQ(0U, view_request.static_video_views.size());
}
// Test serializing/deserializing an a simple vga <view> message.
TEST_F(MediaMessagesTest, ViewVgaToFromXml) {
rtc::scoped_ptr<buzz::XmlElement> action_elem(
new buzz::XmlElement(QN_JINGLE));
buzz::XmlElement* expected_view_elem1 =
buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("1234"));
buzz::XmlElement* expected_view_elem2 =
buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("2468"));
action_elem->AddElement(expected_view_elem1);
action_elem->AddElement(expected_view_elem2);
cricket::ViewRequest view_request;
cricket::XmlElements actual_view_elems;
cricket::WriteError error;
view_request.static_video_views.push_back(cricket::StaticVideoView(
cricket::StreamSelector(1234), 640, 480, 30));
view_request.static_video_views.push_back(cricket::StaticVideoView(
cricket::StreamSelector(2468), 640, 480, 30));
ASSERT_TRUE(cricket::WriteJingleViewRequest(
"video1", view_request, &actual_view_elems, &error));
ASSERT_EQ(2U, actual_view_elems.size());
EXPECT_EQ(expected_view_elem1->Str(), actual_view_elems[0]->Str());
EXPECT_EQ(expected_view_elem2->Str(), actual_view_elems[1]->Str());
ClearXmlElements(&actual_view_elems);
view_request.static_video_views.clear();
cricket::ParseError parse_error;
EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get()));
ASSERT_TRUE(cricket::ParseJingleViewRequest(
action_elem.get(), &view_request, &parse_error));
EXPECT_EQ(2U, view_request.static_video_views.size());
EXPECT_EQ(1234U, view_request.static_video_views[0].selector.ssrc);
EXPECT_EQ(640, view_request.static_video_views[0].width);
EXPECT_EQ(480, view_request.static_video_views[0].height);
EXPECT_EQ(30, view_request.static_video_views[0].framerate);
EXPECT_EQ(2468U, view_request.static_video_views[1].selector.ssrc);
}
// Test deserializing bad view XML.
TEST_F(MediaMessagesTest, ParseBadViewXml) {
rtc::scoped_ptr<buzz::XmlElement> action_elem(
new buzz::XmlElement(QN_JINGLE));
buzz::XmlElement* view_elem =
buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("not-an-ssrc"));
action_elem->AddElement(view_elem);
cricket::ViewRequest view_request;
cricket::ParseError parse_error;
ASSERT_FALSE(cricket::ParseJingleViewRequest(
action_elem.get(), &view_request, &parse_error));
}
// Test serializing/deserializing typical streams xml.
TEST_F(MediaMessagesTest, StreamsToFromXml) {
rtc::scoped_ptr<buzz::XmlElement> expected_streams_elem(
buzz::XmlElement::ForStr(
StreamsXml(
StreamXml("nick1", "stream1", "101", "102",
"semantics1", "type1", "display1"),
StreamXml("nick2", "stream2", "201", "202",
"semantics2", "type2", "display2"))));
std::vector<cricket::StreamParams> expected_streams;
expected_streams.push_back(CreateStream("nick1", "stream1", 101U, 102U,
"semantics1", "type1", "display1"));
expected_streams.push_back(CreateStream("nick2", "stream2", 201U, 202U,
"semantics2", "type2", "display2"));
rtc::scoped_ptr<buzz::XmlElement> actual_desc_elem(
new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
cricket::WriteJingleStreams(expected_streams, actual_desc_elem.get());
const buzz::XmlElement* actual_streams_elem =
actual_desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
ASSERT_TRUE(actual_streams_elem != NULL);
EXPECT_EQ(expected_streams_elem->Str(), actual_streams_elem->Str());
rtc::scoped_ptr<buzz::XmlElement> expected_desc_elem(
new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
expected_desc_elem->AddElement(new buzz::XmlElement(
*expected_streams_elem));
std::vector<cricket::StreamParams> actual_streams;
cricket::ParseError parse_error;
EXPECT_TRUE(cricket::HasJingleStreams(expected_desc_elem.get()));
ASSERT_TRUE(cricket::ParseJingleStreams(
expected_desc_elem.get(), &actual_streams, &parse_error));
EXPECT_EQ(2U, actual_streams.size());
EXPECT_EQ(expected_streams[0], actual_streams[0]);
EXPECT_EQ(expected_streams[1], actual_streams[1]);
}
// Test deserializing bad streams xml.
TEST_F(MediaMessagesTest, StreamsFromBadXml) {
rtc::scoped_ptr<buzz::XmlElement> streams_elem(
buzz::XmlElement::ForStr(
StreamsXml(
StreamXml("nick1", "name1", "101", "not-an-ssrc",
"semantics1", "type1", "display1"),
StreamXml("nick2", "name2", "202", "not-an-ssrc",
"semantics2", "type2", "display2"))));
rtc::scoped_ptr<buzz::XmlElement> desc_elem(
new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
desc_elem->AddElement(new buzz::XmlElement(*streams_elem));
std::vector<cricket::StreamParams> actual_streams;
cricket::ParseError parse_error;
ASSERT_FALSE(cricket::ParseJingleStreams(
desc_elem.get(), &actual_streams, &parse_error));
}
// Test serializing/deserializing typical RTP Header Extension xml.
TEST_F(MediaMessagesTest, HeaderExtensionsToFromXml) {
rtc::scoped_ptr<buzz::XmlElement> expected_desc_elem(
buzz::XmlElement::ForStr(
HeaderExtensionsXml(
HeaderExtensionXml("abc", "123"),
HeaderExtensionXml("def", "456"))));
std::vector<cricket::RtpHeaderExtension> expected_hdrexts;
expected_hdrexts.push_back(RtpHeaderExtension("abc", 123));
expected_hdrexts.push_back(RtpHeaderExtension("def", 456));
rtc::scoped_ptr<buzz::XmlElement> actual_desc_elem(
new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
cricket::WriteJingleRtpHeaderExtensions(expected_hdrexts, actual_desc_elem.get());
ASSERT_TRUE(actual_desc_elem != NULL);
EXPECT_EQ(expected_desc_elem->Str(), actual_desc_elem->Str());
std::vector<cricket::RtpHeaderExtension> actual_hdrexts;
cricket::ParseError parse_error;
ASSERT_TRUE(cricket::ParseJingleRtpHeaderExtensions(
expected_desc_elem.get(), &actual_hdrexts, &parse_error));
EXPECT_EQ(2U, actual_hdrexts.size());
EXPECT_EQ(expected_hdrexts[0], actual_hdrexts[0]);
EXPECT_EQ(expected_hdrexts[1], actual_hdrexts[1]);
}
// Test deserializing bad RTP header extension xml.
TEST_F(MediaMessagesTest, HeaderExtensionsFromBadXml) {
std::vector<cricket::RtpHeaderExtension> actual_hdrexts;
cricket::ParseError parse_error;
rtc::scoped_ptr<buzz::XmlElement> desc_elem(
buzz::XmlElement::ForStr(
HeaderExtensionsXml(
HeaderExtensionXml("abc", "123"),
HeaderExtensionXml("def", "not-an-id"))));
ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions(
desc_elem.get(), &actual_hdrexts, &parse_error));
desc_elem.reset(
buzz::XmlElement::ForStr(
HeaderExtensionsXml(
HeaderExtensionXml("abc", "123"),
HeaderExtensionXml("def", "-1"))));
ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions(
desc_elem.get(), &actual_hdrexts, &parse_error));
}
} // namespace cricket

File diff suppressed because it is too large Load Diff

View File

@ -1,175 +0,0 @@
/*
* libjingle
* Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_
#define WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include "talk/media/base/cryptoparams.h"
#include "talk/session/media/channelmanager.h"
#include "talk/session/media/mediasession.h"
#include "webrtc/base/messagequeue.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/sigslotrepeater.h"
#include "webrtc/base/thread.h"
#include "webrtc/libjingle/session/media/call.h"
#include "webrtc/libjingle/session/sessionclient.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/p2p/base/sessiondescription.h"
namespace cricket {
class Call;
class MediaSessionClient : public SessionClient, public sigslot::has_slots<> {
public:
#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager);
#endif
// Alternative constructor, allowing injection of media_engine
// and device_manager.
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager,
MediaEngineInterface* media_engine,
DataEngineInterface* data_media_engine,
DeviceManagerInterface* device_manager);
~MediaSessionClient();
const buzz::Jid &jid() const { return jid_; }
SessionManager* session_manager() const { return session_manager_; }
ChannelManager* channel_manager() const { return channel_manager_; }
// Return mapping of call ids to Calls.
const std::map<uint32, Call *>& calls() const { return calls_; }
// The settings below combine with the settings on SessionManager to choose
// whether SDES-SRTP, DTLS-SRTP, or no security should be used. The possible
// combinations are shown in the following table. Note that where either DTLS
// or SDES is possible, DTLS is preferred. Thus to require either SDES or
// DTLS, but not mandate DTLS, set SDES to require and DTLS to enable.
//
// | SDES:Disable | SDES:Enable | SDES:Require |
// ----------------------------------------------------------------|
// DTLS:Disable | No SRTP | SDES Optional | SDES Mandatory |
// DTLS:Enable | DTLS Optional | DTLS/SDES Opt | DTLS/SDES Mand |
// DTLS:Require | DTLS Mandatory | DTLS Mandatory | DTLS Mandatory |
// Control use of SDES-SRTP.
SecurePolicy secure() const { return desc_factory_.secure(); }
void set_secure(SecurePolicy s) { desc_factory_.set_secure(s); }
// Control use of multiple sessions in a call.
void set_multisession_enabled(bool multisession_enabled) {
multisession_enabled_ = multisession_enabled;
}
int GetCapabilities() { return channel_manager_->GetCapabilities(); }
Call *CreateCall();
void DestroyCall(Call *call);
Call *GetFocus();
void SetFocus(Call *call);
void JoinCalls(Call *call_to_join, Call *call);
bool GetAudioInputDevices(std::vector<std::string>* names) {
return channel_manager_->GetAudioInputDevices(names);
}
bool GetAudioOutputDevices(std::vector<std::string>* names) {
return channel_manager_->GetAudioOutputDevices(names);
}
bool GetVideoCaptureDevices(std::vector<std::string>* names) {
return channel_manager_->GetVideoCaptureDevices(names);
}
bool SetAudioOptions(const std::string& in_name, const std::string& out_name,
const AudioOptions& options) {
return channel_manager_->SetAudioOptions(in_name, out_name, options);
}
bool SetOutputVolume(int level) {
return channel_manager_->SetOutputVolume(level);
}
bool SetCaptureDevice(const std::string& cam_device) {
return channel_manager_->SetCaptureDevice(cam_device);
}
SessionDescription* CreateOffer(const CallOptions& options) {
return desc_factory_.CreateOffer(options, NULL);
}
SessionDescription* CreateAnswer(const SessionDescription* offer,
const CallOptions& options) {
return desc_factory_.CreateAnswer(offer, options, NULL);
}
sigslot::signal2<Call *, Call *> SignalFocus;
sigslot::signal1<Call *> SignalCallCreate;
sigslot::signal1<Call *> SignalCallDestroy;
sigslot::repeater0<> SignalDevicesChange;
virtual bool ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error);
virtual bool IsWritable(SignalingProtocol protocol,
const ContentDescription* content);
virtual bool WriteContent(SignalingProtocol protocol,
const ContentDescription* content,
buzz::XmlElement** elem,
WriteError* error);
private:
void Construct();
void OnSessionCreate(Session *session, bool received_initiate);
void OnSessionState(BaseSession *session, BaseSession::State state);
void OnSessionDestroy(Session *session);
Session *CreateSession(Call *call);
Session *CreateSession(const std::string& id, Call* call);
Call *FindCallByRemoteName(const std::string &remote_name);
buzz::Jid jid_;
SessionManager* session_manager_;
Call *focus_call_;
ChannelManager *channel_manager_;
MediaSessionDescriptionFactory desc_factory_;
bool multisession_enabled_;
std::map<uint32, Call *> calls_;
// Maintain a mapping of session id to call.
typedef std::map<std::string, Call *> SessionMap;
SessionMap session_map_;
friend class Call;
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/session/p2ptransportparser.h"
#include <vector>
#include "webrtc/p2p/base/constants.h"
#include "webrtc/libjingle/session/constants.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/session/sessionmessages.h"
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/base/base64.h"
#include "webrtc/base/common.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/base/stringutils.h"
namespace cricket {
static buzz::XmlElement* NewTransportElement(const std::string& name) {
return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true);
}
bool P2PTransportParser::ParseTransportDescription(
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
TransportDescription* desc,
ParseError* error) {
ASSERT(elem->Name().LocalPart() == LN_TRANSPORT);
desc->transport_type = elem->Name().Namespace();
if (desc->transport_type != NS_GINGLE_P2P)
return BadParse("Unsupported transport type", error);
for (const buzz::XmlElement* candidate_elem = elem->FirstElement();
candidate_elem != NULL;
candidate_elem = candidate_elem->NextElement()) {
// Only look at local part because the namespace might (eventually)
// be NS_GINGLE_P2P or NS_JINGLE_ICE_UDP.
if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) {
Candidate candidate;
if (!ParseCandidate(ICEPROTO_GOOGLE, candidate_elem, translator,
&candidate, error)) {
return false;
}
desc->candidates.push_back(candidate);
}
}
return true;
}
bool P2PTransportParser::WriteTransportDescription(
const TransportDescription& desc,
const CandidateTranslator* translator,
buzz::XmlElement** out_elem,
WriteError* error) {
TransportProtocol proto = TransportProtocolFromDescription(&desc);
rtc::scoped_ptr<buzz::XmlElement> trans_elem(
NewTransportElement(desc.transport_type));
// Fail if we get HYBRID or ICE right now.
// TODO(juberti): Add ICE and HYBRID serialization.
if (proto != ICEPROTO_GOOGLE) {
LOG(LS_ERROR) << "Failed to serialize non-GICE TransportDescription";
return false;
}
for (std::vector<Candidate>::const_iterator iter = desc.candidates.begin();
iter != desc.candidates.end(); ++iter) {
rtc::scoped_ptr<buzz::XmlElement> cand_elem(
new buzz::XmlElement(QN_GINGLE_P2P_CANDIDATE));
if (!WriteCandidate(proto, *iter, translator, cand_elem.get(), error)) {
return false;
}
trans_elem->AddElement(cand_elem.release());
}
*out_elem = trans_elem.release();
return true;
}
bool P2PTransportParser::ParseGingleCandidate(
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidate* candidate,
ParseError* error) {
return ParseCandidate(ICEPROTO_GOOGLE, elem, translator, candidate, error);
}
bool P2PTransportParser::WriteGingleCandidate(
const Candidate& candidate,
const CandidateTranslator* translator,
buzz::XmlElement** out_elem,
WriteError* error) {
rtc::scoped_ptr<buzz::XmlElement> elem(
new buzz::XmlElement(QN_GINGLE_CANDIDATE));
bool ret = WriteCandidate(ICEPROTO_GOOGLE, candidate, translator, elem.get(),
error);
if (ret) {
*out_elem = elem.release();
}
return ret;
}
bool P2PTransportParser::VerifyUsernameFormat(TransportProtocol proto,
const std::string& username,
ParseError* error) {
if (proto == ICEPROTO_GOOGLE || proto == ICEPROTO_HYBRID) {
if (username.size() > GICE_UFRAG_MAX_LENGTH)
return BadParse("candidate username is too long", error);
if (!rtc::Base64::IsBase64Encoded(username))
return BadParse("candidate username has non-base64 encoded characters",
error);
} else if (proto == ICEPROTO_RFC5245) {
if (username.size() > ICE_UFRAG_MAX_LENGTH)
return BadParse("candidate username is too long", error);
}
return true;
}
bool P2PTransportParser::ParseCandidate(TransportProtocol proto,
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidate* candidate,
ParseError* error) {
ASSERT(proto == ICEPROTO_GOOGLE);
ASSERT(translator != NULL);
if (!elem->HasAttr(buzz::QN_NAME) ||
!elem->HasAttr(QN_ADDRESS) ||
!elem->HasAttr(QN_PORT) ||
!elem->HasAttr(QN_USERNAME) ||
!elem->HasAttr(QN_PROTOCOL) ||
!elem->HasAttr(QN_GENERATION)) {
return BadParse("candidate missing required attribute", error);
}
rtc::SocketAddress address;
if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, &address, error))
return false;
std::string channel_name = elem->Attr(buzz::QN_NAME);
int component = 0;
if (!translator ||
!translator->GetComponentFromChannelName(channel_name, &component)) {
return BadParse("candidate has unknown channel name " + channel_name,
error);
}
float preference = 0.0;
if (!GetXmlAttr(elem, QN_PREFERENCE, 0.0f, &preference)) {
return BadParse("candidate has unknown preference", error);
}
candidate->set_component(component);
candidate->set_address(address);
candidate->set_username(elem->Attr(QN_USERNAME));
candidate->set_preference(preference);
candidate->set_protocol(elem->Attr(QN_PROTOCOL));
candidate->set_generation_str(elem->Attr(QN_GENERATION));
if (elem->HasAttr(QN_PASSWORD))
candidate->set_password(elem->Attr(QN_PASSWORD));
if (elem->HasAttr(buzz::QN_TYPE))
candidate->set_type(elem->Attr(buzz::QN_TYPE));
if (elem->HasAttr(QN_NETWORK))
candidate->set_network_name(elem->Attr(QN_NETWORK));
if (!VerifyUsernameFormat(proto, candidate->username(), error))
return false;
return true;
}
bool P2PTransportParser::WriteCandidate(TransportProtocol proto,
const Candidate& candidate,
const CandidateTranslator* translator,
buzz::XmlElement* elem,
WriteError* error) {
ASSERT(proto == ICEPROTO_GOOGLE);
ASSERT(translator != NULL);
std::string channel_name;
if (!translator ||
!translator->GetChannelNameFromComponent(
candidate.component(), &channel_name)) {
return BadWrite("Cannot write candidate because of unknown component.",
error);
}
elem->SetAttr(buzz::QN_NAME, channel_name);
elem->SetAttr(QN_ADDRESS, candidate.address().ipaddr().ToString());
elem->SetAttr(QN_PORT, candidate.address().PortAsString());
AddXmlAttr(elem, QN_PREFERENCE, candidate.preference());
elem->SetAttr(QN_USERNAME, candidate.username());
elem->SetAttr(QN_PROTOCOL, candidate.protocol());
elem->SetAttr(QN_GENERATION, candidate.generation_str());
if (!candidate.password().empty())
elem->SetAttr(QN_PASSWORD, candidate.password());
elem->SetAttr(buzz::QN_TYPE, candidate.type());
if (!candidate.network_name().empty())
elem->SetAttr(QN_NETWORK, candidate.network_name());
return true;
}
} // namespace cricket

View File

@ -1,67 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_
#define WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_
#include <string>
#include "webrtc/libjingle/session/transportparser.h"
namespace cricket {
class P2PTransportParser : public TransportParser {
public:
P2PTransportParser() {}
// Translator may be null, in which case ParseCandidates should
// return false if there are candidates to parse. We can't not call
// ParseCandidates because there's no way to know ahead of time if
// there are candidates or not.
// Jingle-specific functions; can be used with either ICE, GICE, or HYBRID.
virtual bool ParseTransportDescription(const buzz::XmlElement* elem,
const CandidateTranslator* translator,
TransportDescription* desc,
ParseError* error);
virtual bool WriteTransportDescription(const TransportDescription& desc,
const CandidateTranslator* translator,
buzz::XmlElement** elem,
WriteError* error);
// Legacy Gingle functions; only can be used with GICE.
virtual bool ParseGingleCandidate(const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidate* candidate,
ParseError* error);
virtual bool WriteGingleCandidate(const Candidate& candidate,
const CandidateTranslator* translator,
buzz::XmlElement** elem,
WriteError* error);
private:
bool ParseCandidate(TransportProtocol proto,
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidate* candidate,
ParseError* error);
bool WriteCandidate(TransportProtocol proto,
const Candidate& candidate,
const CandidateTranslator* translator,
buzz::XmlElement* elem,
WriteError* error);
bool VerifyUsernameFormat(TransportProtocol proto,
const std::string& username,
ParseError* error);
DISALLOW_COPY_AND_ASSIGN(P2PTransportParser);
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_

View File

@ -1,141 +0,0 @@
/*
* Copyright 2010 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/session/parsing.h"
#include <stdlib.h>
#include <algorithm>
#include "webrtc/base/stringutils.h"
namespace {
static const char kTrue[] = "true";
static const char kOne[] = "1";
}
namespace cricket {
bool BadParse(const std::string& text, ParseError* err) {
if (err != NULL) {
err->text = text;
}
return false;
}
bool BadWrite(const std::string& text, WriteError* err) {
if (err != NULL) {
err->text = text;
}
return false;
}
std::string GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
const std::string& def) {
std::string val = elem->Attr(name);
return val.empty() ? def : val;
}
std::string GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
const char* def) {
return GetXmlAttr(elem, name, std::string(def));
}
bool GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name, bool def) {
std::string val = elem->Attr(name);
std::transform(val.begin(), val.end(), val.begin(), tolower);
return val.empty() ? def : (val == kTrue || val == kOne);
}
int GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name, int def) {
std::string val = elem->Attr(name);
return val.empty() ? def : atoi(val.c_str());
}
const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent,
const std::string& name) {
for (const buzz::XmlElement* child = parent->FirstElement();
child != NULL;
child = child->NextElement()) {
if (child->Name().LocalPart() == name) {
return child;
}
}
return NULL;
}
bool RequireXmlChild(const buzz::XmlElement* parent,
const std::string& name,
const buzz::XmlElement** child,
ParseError* error) {
*child = GetXmlChild(parent, name);
if (*child == NULL) {
return BadParse("element '" + parent->Name().Merged() +
"' missing required child '" + name,
error);
} else {
return true;
}
}
bool RequireXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
std::string* value,
ParseError* error) {
if (!elem->HasAttr(name)) {
return BadParse("element '" + elem->Name().Merged() +
"' missing required attribute '"
+ name.Merged() + "'",
error);
} else {
*value = elem->Attr(name);
return true;
}
}
void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
const buzz::QName name,
const std::string& value) {
if (!value.empty()) {
elem->AddAttr(name, value);
}
}
void AddXmlChildren(buzz::XmlElement* parent,
const std::vector<buzz::XmlElement*>& children) {
for (std::vector<buzz::XmlElement*>::const_iterator iter = children.begin();
iter != children.end();
iter++) {
parent->AddElement(*iter);
}
}
void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest) {
for (const buzz::XmlElement* child = source->FirstElement();
child != NULL;
child = child->NextElement()) {
dest->AddElement(new buzz::XmlElement(*child));
}
}
std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem) {
std::vector<buzz::XmlElement*> children;
for (const buzz::XmlElement* child = elem->FirstElement();
child != NULL;
child = child->NextElement()) {
children.push_back(new buzz::XmlElement(*child));
}
return children;
}
} // namespace cricket

View File

@ -1,140 +0,0 @@
/*
* Copyright 2010 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_PARSING_H_
#define WEBRTC_LIBJINGLE_SESSION_PARSING_H_
#include <string>
#include <vector>
#include "webrtc/libjingle/xmllite/xmlelement.h" // Needed to delete ParseError.extra.
#include "webrtc/base/basictypes.h"
#include "webrtc/base/stringencode.h"
namespace cricket {
typedef std::vector<buzz::XmlElement*> XmlElements;
// We decided "bool Parse(in, out*, error*)" is generally the best
// parse signature. "out Parse(in)" doesn't allow for errors.
// "error* Parse(in, out*)" doesn't allow flexible memory management.
// The error type for parsing.
struct ParseError {
public:
// explains the error
std::string text;
// provide details about what wasn't parsable
const buzz::XmlElement* extra;
ParseError() : extra(NULL) {}
~ParseError() {
delete extra;
}
void SetText(const std::string& text) {
this->text = text;
}
};
// The error type for writing.
struct WriteError {
std::string text;
void SetText(const std::string& text) {
this->text = text;
}
};
// Convenience method for returning a message when parsing fails.
bool BadParse(const std::string& text, ParseError* err);
// Convenience method for returning a message when writing fails.
bool BadWrite(const std::string& text, WriteError* error);
// helper XML functions
std::string GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
const std::string& def);
std::string GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
const char* def);
// Return true if the value is "true" or "1".
bool GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name, bool def);
int GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name, int def);
template <class T>
bool GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
T* val_out) {
if (!elem->HasAttr(name)) {
return false;
}
std::string unparsed = elem->Attr(name);
return rtc::FromString(unparsed, val_out);
}
template <class T>
bool GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
const T& def,
T* val_out) {
if (!elem->HasAttr(name)) {
*val_out = def;
return true;
}
return GetXmlAttr(elem, name, val_out);
}
template <class T>
bool AddXmlAttr(buzz::XmlElement* elem,
const buzz::QName& name, const T& val) {
std::string buf;
if (!rtc::ToString(val, &buf)) {
return false;
}
elem->AddAttr(name, buf);
return true;
}
template <class T>
bool SetXmlBody(buzz::XmlElement* elem, const T& val) {
std::string buf;
if (!rtc::ToString(val, &buf)) {
return false;
}
elem->SetBodyText(buf);
return true;
}
const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent,
const std::string& name);
bool RequireXmlChild(const buzz::XmlElement* parent,
const std::string& name,
const buzz::XmlElement** child,
ParseError* error);
bool RequireXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
std::string* value,
ParseError* error);
void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
const buzz::QName name,
const std::string& value);
void AddXmlChildren(buzz::XmlElement* parent,
const std::vector<buzz::XmlElement*>& children);
void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest);
std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem);
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_PARSING_H_

View File

@ -1,92 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/session/rawtransportparser.h"
#include <string>
#include <vector>
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/p2p/base/constants.h"
#if defined(FEATURE_ENABLE_PSTN)
namespace cricket {
bool RawTransportParser::ParseCandidates(SignalingProtocol protocol,
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidates* candidates,
ParseError* error) {
for (const buzz::XmlElement* cand_elem = elem->FirstElement();
cand_elem != NULL;
cand_elem = cand_elem->NextElement()) {
if (cand_elem->Name() == QN_GINGLE_RAW_CHANNEL) {
if (!cand_elem->HasAttr(buzz::QN_NAME)) {
return BadParse("no channel name given", error);
}
if (NS_GINGLE_RAW != cand_elem->Attr(buzz::QN_NAME)) {
return BadParse("channel named does not exist", error);
}
rtc::SocketAddress addr;
if (!ParseRawAddress(cand_elem, &addr, error))
return false;
Candidate candidate;
candidate.set_component(1);
candidate.set_address(addr);
candidates->push_back(candidate);
}
}
return true;
}
bool RawTransportParser::WriteCandidates(SignalingProtocol protocol,
const Candidates& candidates,
const CandidateTranslator* translator,
XmlElements* candidate_elems,
WriteError* error) {
for (std::vector<Candidate>::const_iterator
cand = candidates.begin();
cand != candidates.end();
++cand) {
ASSERT(cand->component() == 1);
ASSERT(cand->protocol() == "udp");
rtc::SocketAddress addr = cand->address();
buzz::XmlElement* elem = new buzz::XmlElement(QN_GINGLE_RAW_CHANNEL);
elem->SetAttr(buzz::QN_NAME, NS_GINGLE_RAW);
elem->SetAttr(QN_ADDRESS, addr.ipaddr().ToString());
elem->SetAttr(QN_PORT, addr.PortAsString());
candidate_elems->push_back(elem);
}
return true;
}
bool RawTransportParser::ParseRawAddress(const buzz::XmlElement* elem,
rtc::SocketAddress* addr,
ParseError* error) {
// Make sure the required attributes exist
if (!elem->HasAttr(QN_ADDRESS) ||
!elem->HasAttr(QN_PORT)) {
return BadParse("channel missing required attribute", error);
}
// Parse the address.
if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, addr, error))
return false;
return true;
}
} // namespace cricket
#endif // defined(FEATURE_ENABLE_PSTN)

View File

@ -1,49 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_
#define WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_
#include <string>
#include "webrtc/p2p/base/constants.h"
#include "webrtc/libjingle/session/constants.h"
#include "webrtc/libjingle/session/transportparser.h"
namespace cricket {
class RawTransportParser : public TransportParser {
public:
RawTransportParser() {}
virtual bool ParseCandidates(SignalingProtocol protocol,
const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidates* candidates,
ParseError* error);
virtual bool WriteCandidates(SignalingProtocol protocol,
const Candidates& candidates,
const CandidateTranslator* translator,
XmlElements* candidate_elems,
WriteError* error);
private:
// Parses the given element, which should describe the address to use for a
// given channel. This will return false and signal an error if the address
// or channel name is bad.
bool ParseRawAddress(const buzz::XmlElement* elem,
rtc::SocketAddress* addr,
ParseError* error);
DISALLOW_COPY_AND_ASSIGN(RawTransportParser);
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_P2P_BASE_SESSIONCLIENT_H_
#define WEBRTC_P2P_BASE_SESSIONCLIENT_H_
#include "webrtc/libjingle/session/constants.h"
#include "webrtc/p2p/base/constants.h"
namespace buzz {
class XmlElement;
}
namespace cricket {
struct ParseError;
struct WriteError;
class Session;
class ContentDescription;
class ContentParser {
public:
virtual bool ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error) = 0;
// If not IsWriteable, then a given content should be "skipped" when
// writing in the given protocol, as if it didn't exist. We assume
// most things are writeable. We do this to avoid strange cases
// like data contents in Gingle, which aren't writable.
virtual bool IsWritable(SignalingProtocol protocol,
const ContentDescription* content) {
return true;
}
virtual bool WriteContent(SignalingProtocol protocol,
const ContentDescription* content,
buzz::XmlElement** elem,
WriteError* error) = 0;
virtual ~ContentParser() {}
};
// A SessionClient exists in 1-1 relation with each session. The implementor
// of this interface is the one that understands *what* the two sides are
// trying to send to one another. The lower-level layers only know how to send
// data; they do not know what is being sent.
class SessionClient : public ContentParser {
public:
// Notifies the client of the creation / destruction of sessions of this type.
//
// IMPORTANT: The SessionClient, in its handling of OnSessionCreate, must
// create whatever channels are indicate in the description. This is because
// the remote client may already be attempting to connect those channels. If
// we do not create our channel right away, then connection may fail or be
// delayed.
virtual void OnSessionCreate(Session* session, bool received_initiate) = 0;
virtual void OnSessionDestroy(Session* session) = 0;
virtual bool ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error) = 0;
virtual bool WriteContent(SignalingProtocol protocol,
const ContentDescription* content,
buzz::XmlElement** elem,
WriteError* error) = 0;
protected:
// The SessionClient interface explicitly does not include destructor
virtual ~SessionClient() { }
};
} // namespace cricket
#endif // WEBRTC_P2P_BASE_SESSIONCLIENT_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,436 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_
#define WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "webrtc/base/sigslot.h"
#include "webrtc/base/thread.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/session/sessionclient.h"
#include "webrtc/libjingle/session/sessionmessages.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/p2p/base/portallocator.h"
#include "webrtc/p2p/base/session.h"
#include "webrtc/p2p/base/transportdescriptionfactory.h"
namespace buzz {
class QName;
class XmlElement;
}
namespace cricket {
class BaseSession;
class SessionClient;
class SessionManager;
// Used for errors that will send back a specific error message to the
// remote peer. We add "type" to the errors because it's needed for
// SignalErrorMessage.
struct MessageError : ParseError {
buzz::QName type;
// if unset, assume type is a parse error
MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {}
void SetType(const buzz::QName type) {
this->type = type;
}
};
// Used for errors that may be returned by public session methods that
// can fail.
// TODO: Use this error in Session::Initiate and
// Session::Accept.
struct SessionError : WriteError {
};
// A specific Session created by the SessionManager, using XMPP for protocol.
class Session : public BaseSession {
public:
// Returns the manager that created and owns this session.
SessionManager* session_manager() const { return session_manager_; }
// Returns the client that is handling the application data of this session.
SessionClient* client() const { return client_; }
// Returns the JID of this client.
const std::string& local_name() const { return local_name_; }
// Returns the JID of the other peer in this session.
const std::string& remote_name() const { return remote_name_; }
// Set the JID of the other peer in this session.
// Typically the remote_name_ is set when the session is initiated.
// However, sometimes (e.g when a proxy is used) the peer name is
// known after the BaseSession has been initiated and it must be updated
// explicitly.
void set_remote_name(const std::string& name) { remote_name_ = name; }
// Set the JID of the initiator of this session. Allows for the overriding
// of the initiator to be a third-party, eg. the MUC JID when creating p2p
// sessions.
void set_initiator_name(const std::string& name) { initiator_name_ = name; }
// Indicates the JID of the entity who initiated this session.
// In special cases, may be different than both local_name and remote_name.
const std::string& initiator_name() const { return initiator_name_; }
SignalingProtocol current_protocol() const { return current_protocol_; }
void set_current_protocol(SignalingProtocol protocol) {
current_protocol_ = protocol;
}
// Updates the error state, signaling if necessary.
virtual void SetError(Error error, const std::string& error_desc);
// When the session needs to send signaling messages, it beings by requesting
// signaling. The client should handle this by calling OnSignalingReady once
// it is ready to send the messages.
// (These are called only by SessionManager.)
sigslot::signal1<Session*> SignalRequestSignaling;
void OnSignalingReady() { BaseSession::OnSignalingReady(); }
// Takes ownership of session description.
// TODO: Add an error argument to pass back to the caller.
bool Initiate(const std::string& to,
const SessionDescription* sdesc);
// When we receive an initiate, we create a session in the
// RECEIVEDINITIATE state and respond by accepting or rejecting.
// Takes ownership of session description.
// TODO: Add an error argument to pass back to the caller.
bool Accept(const SessionDescription* sdesc);
bool Reject(const std::string& reason);
bool Terminate() {
return TerminateWithReason(STR_TERMINATE_SUCCESS);
}
bool TerminateWithReason(const std::string& reason);
// Fired whenever we receive a terminate message along with a reason
sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
// The two clients in the session may also send one another
// arbitrary XML messages, which are called "info" messages. Sending
// takes ownership of the given elements. The signal does not; the
// parent element will be deleted after the signal.
bool SendInfoMessage(const XmlElements& elems,
const std::string& remote_name);
bool SendDescriptionInfoMessage(const ContentInfos& contents);
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
private:
// Creates or destroys a session. (These are called only SessionManager.)
Session(SessionManager *session_manager,
const std::string& local_name, const std::string& initiator_name,
const std::string& sid, const std::string& content_type,
SessionClient* client);
~Session();
// For each transport info, create a transport proxy. Can fail for
// incompatible transport types.
bool CreateTransportProxies(const TransportInfos& tinfos,
SessionError* error);
bool OnRemoteCandidates(const TransportInfos& tinfos,
ParseError* error);
// Returns a TransportInfo without candidates for each content name.
// Uses the transport_type_ of the session.
TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
// Maps passed to serialization functions.
TransportParserMap GetTransportParsers();
ContentParserMap GetContentParsers();
CandidateTranslatorMap GetCandidateTranslators();
virtual void OnTransportRequestSignaling(Transport* transport);
virtual void OnTransportConnecting(Transport* transport);
virtual void OnTransportWritable(Transport* transport);
virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
const Candidates& candidates);
virtual void OnMessage(rtc::Message *pmsg);
// Send various kinds of session messages.
bool SendInitiateMessage(const SessionDescription* sdesc,
SessionError* error);
bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error);
bool SendRejectMessage(const std::string& reason, SessionError* error);
bool SendTerminateMessage(const std::string& reason, SessionError* error);
bool SendTransportInfoMessage(const TransportInfo& tinfo,
SessionError* error);
bool SendTransportInfoMessage(const TransportProxy* transproxy,
const Candidates& candidates,
SessionError* error);
bool ResendAllTransportInfoMessages(SessionError* error);
bool SendAllUnsentTransportInfoMessages(SessionError* error);
// All versions of SendMessage send a message of the given type to
// the other client. Can pass either a set of elements or an
// "action", which must have a WriteSessionAction method to go along
// with it. Sending with an action supports sending a "hybrid"
// message. Sending with elements must be sent as Jingle or Gingle.
// When passing elems, must be either Jingle or Gingle protocol.
// Takes ownership of action_elems.
bool SendMessage(ActionType type, const XmlElements& action_elems,
SessionError* error);
// Sends a messge, but overrides the remote name.
bool SendMessage(ActionType type, const XmlElements& action_elems,
const std::string& remote_name,
SessionError* error);
// When passing an action, may be Hybrid protocol.
template <typename Action>
bool SendMessage(ActionType type, const Action& action,
SessionError* error);
// Helper methods to write the session message stanza.
template <typename Action>
bool WriteActionMessage(ActionType type, const Action& action,
buzz::XmlElement* stanza, WriteError* error);
template <typename Action>
bool WriteActionMessage(SignalingProtocol protocol,
ActionType type, const Action& action,
buzz::XmlElement* stanza, WriteError* error);
// Sending messages in hybrid form requires being able to write them
// on a per-protocol basis with a common method signature, which all
// of these have.
bool WriteSessionAction(SignalingProtocol protocol,
const SessionInitiate& init,
XmlElements* elems, WriteError* error);
bool WriteSessionAction(SignalingProtocol protocol,
const TransportInfo& tinfo,
XmlElements* elems, WriteError* error);
bool WriteSessionAction(SignalingProtocol protocol,
const SessionTerminate& term,
XmlElements* elems, WriteError* error);
// Sends a message back to the other client indicating that we have received
// and accepted their message.
void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
// Once signaling is ready, the session will use this signal to request the
// sending of each message. When messages are received by the other client,
// they should be handed to OnIncomingMessage.
// (These are called only by SessionManager.)
sigslot::signal2<Session* , const buzz::XmlElement*> SignalOutgoingMessage;
void OnIncomingMessage(const SessionMessage& msg);
void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* response_stanza,
const SessionMessage& msg);
void OnInitiateAcked();
void OnFailedSend(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* error_stanza);
// Invoked when an error is found in an incoming message. This is translated
// into the appropriate XMPP response by SessionManager.
sigslot::signal6<BaseSession*,
const buzz::XmlElement*,
const buzz::QName&,
const std::string&,
const std::string&,
const buzz::XmlElement*> SignalErrorMessage;
// Handlers for the various types of messages. These functions may take
// pointers to the whole stanza or to just the session element.
bool OnInitiateMessage(const SessionMessage& msg, MessageError* error);
bool OnAcceptMessage(const SessionMessage& msg, MessageError* error);
bool OnRejectMessage(const SessionMessage& msg, MessageError* error);
bool OnInfoMessage(const SessionMessage& msg);
bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error);
bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
// Verifies that we are in the appropriate state to receive this message.
bool CheckState(State state, MessageError* error);
SessionManager* session_manager_;
bool initiate_acked_;
std::string local_name_;
std::string initiator_name_;
std::string remote_name_;
SessionClient* client_;
TransportParser* transport_parser_;
// Keeps track of what protocol we are speaking.
SignalingProtocol current_protocol_;
friend class SessionManager; // For access to constructor, destructor,
// and signaling related methods.
};
// SessionManager manages session instances.
class SessionManager : public sigslot::has_slots<> {
public:
SessionManager(PortAllocator *allocator,
rtc::Thread *worker_thread = NULL);
virtual ~SessionManager();
PortAllocator *port_allocator() const { return allocator_; }
rtc::Thread *worker_thread() const { return worker_thread_; }
rtc::Thread *signaling_thread() const { return signaling_thread_; }
int session_timeout() const { return timeout_; }
void set_session_timeout(int timeout) { timeout_ = timeout; }
// Set what transport protocol we want to default to.
void set_transport_protocol(TransportProtocol proto) {
transport_desc_factory_.set_protocol(proto);
}
// Control use of DTLS. An identity must be supplied if DTLS is enabled.
void set_secure(SecurePolicy policy) {
transport_desc_factory_.set_secure(policy);
}
void set_identity(rtc::SSLIdentity* identity) {
transport_desc_factory_.set_identity(identity);
}
const TransportDescriptionFactory* transport_desc_factory() const {
return &transport_desc_factory_;
}
// Registers support for the given client. If we receive an initiate
// describing a session of the given type, we will automatically create a
// Session object and notify this client. The client may then accept or
// reject the session.
void AddClient(const std::string& content_type, SessionClient* client);
void RemoveClient(const std::string& content_type);
SessionClient* GetClient(const std::string& content_type);
// Creates a new session. The given name is the JID of the client on whose
// behalf we initiate the session.
Session *CreateSession(const std::string& local_name,
const std::string& content_type);
Session *CreateSession(const std::string& id,
const std::string& local_name,
const std::string& content_type);
// Destroys the given session.
void DestroySession(Session *session);
// Returns the session with the given ID or NULL if none exists.
Session *GetSession(const std::string& sid);
// Terminates all of the sessions created by this manager.
void TerminateAll();
// These are signaled whenever the set of existing sessions changes.
sigslot::signal2<Session *, bool> SignalSessionCreate;
sigslot::signal1<Session *> SignalSessionDestroy;
// Determines whether the given stanza is intended for some session.
bool IsSessionMessage(const buzz::XmlElement* stanza);
// Given a sid, initiator, and remote_name, this finds the matching Session
Session* FindSession(const std::string& sid,
const std::string& remote_name);
// Called when we receive a stanza for which IsSessionMessage is true.
void OnIncomingMessage(const buzz::XmlElement* stanza);
// Called when we get a response to a message that we sent.
void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* response_stanza);
// Called if an attempted to send times out or an error is returned. In the
// timeout case error_stanza will be NULL
void OnFailedSend(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* error_stanza);
// Signalled each time a session generates a signaling message to send.
// Also signalled on errors, but with a NULL session.
sigslot::signal2<SessionManager*,
const buzz::XmlElement*> SignalOutgoingMessage;
// Signaled before sessions try to send certain signaling messages. The
// client should call OnSignalingReady once it is safe to send them. These
// steps are taken so that we don't send signaling messages trying to
// re-establish the connectivity of a session when the client cannot send
// the messages (and would probably just drop them on the floor).
//
// Note: you can connect this directly to OnSignalingReady(), if a signalling
// check is not supported.
sigslot::signal0<> SignalRequestSignaling;
void OnSignalingReady();
// Signaled when this SessionManager is deleted.
sigslot::signal0<> SignalDestroyed;
private:
typedef std::map<std::string, Session*> SessionMap;
typedef std::map<std::string, SessionClient*> ClientMap;
// Helper function for CreateSession. This is also invoked when we receive
// a message attempting to initiate a session with this client.
Session *CreateSession(const std::string& local_name,
const std::string& initiator,
const std::string& sid,
const std::string& content_type,
bool received_initiate);
// Attempts to find a registered session type whose description appears as
// a child of the session element. Such a child should be present indicating
// the application they hope to initiate.
std::string FindClient(const buzz::XmlElement* session);
// Sends a message back to the other client indicating that we found an error
// in the stanza they sent. name identifies the error, type is one of the
// standard XMPP types (cancel, continue, modify, auth, wait), and text is a
// description for debugging purposes.
void SendErrorMessage(const buzz::XmlElement* stanza,
const buzz::QName& name,
const std::string& type,
const std::string& text,
const buzz::XmlElement* extra_info);
// Creates and returns an error message from the given components. The
// caller is responsible for deleting this.
buzz::XmlElement* CreateErrorMessage(
const buzz::XmlElement* stanza,
const buzz::QName& name,
const std::string& type,
const std::string& text,
const buzz::XmlElement* extra_info);
// Called each time a session requests signaling.
void OnRequestSignaling(Session* session);
// Called each time a session has an outgoing message.
void OnOutgoingMessage(Session* session, const buzz::XmlElement* stanza);
// Called each time a session has an error to send.
void OnErrorMessage(BaseSession* session,
const buzz::XmlElement* stanza,
const buzz::QName& name,
const std::string& type,
const std::string& text,
const buzz::XmlElement* extra_info);
PortAllocator *allocator_;
rtc::Thread *signaling_thread_;
rtc::Thread *worker_thread_;
int timeout_;
TransportDescriptionFactory transport_desc_factory_;
SessionMap session_map_;
ClientMap client_map_;
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_

View File

@ -1,76 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGERTASK_H_
#define WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGERTASK_H_
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/session/sessionsendtask.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
namespace cricket {
// This class handles sending and receiving XMPP messages on behalf of the
// SessionManager. The sending part is handed over to SessionSendTask.
class SessionManagerTask : public buzz::XmppTask {
public:
SessionManagerTask(buzz::XmppTaskParentInterface* parent,
SessionManager* session_manager)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
session_manager_(session_manager) {
}
~SessionManagerTask() {
}
// Turns on simple support for sending messages, using SessionSendTask.
void EnableOutgoingMessages() {
session_manager_->SignalOutgoingMessage.connect(
this, &SessionManagerTask::OnOutgoingMessage);
session_manager_->SignalRequestSignaling.connect(
session_manager_, &SessionManager::OnSignalingReady);
}
virtual int ProcessStart() {
const buzz::XmlElement *stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
session_manager_->OnIncomingMessage(stanza);
return STATE_START;
}
protected:
virtual bool HandleStanza(const buzz::XmlElement *stanza) {
if (!session_manager_->IsSessionMessage(stanza))
return false;
// Responses are handled by the SessionSendTask that sent the request.
//if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET)
// return false;
QueueStanza(stanza);
return true;
}
private:
void OnOutgoingMessage(SessionManager* manager,
const buzz::XmlElement* stanza) {
cricket::SessionSendTask* sender =
new cricket::SessionSendTask(parent_, session_manager_);
sender->Send(stanza);
sender->Start();
}
SessionManager* session_manager_;
};
} // namespace cricket
#endif // WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,219 +0,0 @@
/*
* Copyright 2010 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_
#define WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_
#include <map>
#include <string>
#include <vector>
#include "webrtc/base/basictypes.h"
#include "webrtc/libjingle/session/constants.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/session/transportparser.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/p2p/base/candidate.h"
#include "webrtc/p2p/base/constants.h"
#include "webrtc/p2p/base/sessiondescription.h" // Needed to delete contents.
#include "webrtc/p2p/base/transport.h"
#include "webrtc/p2p/base/transportinfo.h"
namespace cricket {
struct ParseError;
struct WriteError;
class Candidate;
class ContentParser;
class TransportParser;
typedef std::vector<Candidate> Candidates;
typedef std::map<std::string, ContentParser*> ContentParserMap;
typedef std::map<std::string, TransportParser*> TransportParserMap;
enum ActionType {
ACTION_UNKNOWN,
ACTION_SESSION_INITIATE,
ACTION_SESSION_INFO,
ACTION_SESSION_ACCEPT,
ACTION_SESSION_REJECT,
ACTION_SESSION_TERMINATE,
ACTION_TRANSPORT_INFO,
ACTION_TRANSPORT_ACCEPT,
ACTION_DESCRIPTION_INFO,
};
// Abstraction of a <jingle> element within an <iq> stanza, per XMPP
// standard XEP-166. Can be serialized into multiple protocols,
// including the standard (Jingle) and the draft standard (Gingle).
// In general, used to communicate actions related to a p2p session,
// such accept, initiate, terminate, etc.
struct SessionMessage {
SessionMessage() : action_elem(NULL), stanza(NULL) {}
SessionMessage(SignalingProtocol protocol, ActionType type,
const std::string& sid, const std::string& initiator) :
protocol(protocol), type(type), sid(sid), initiator(initiator),
action_elem(NULL), stanza(NULL) {}
std::string id;
std::string from;
std::string to;
SignalingProtocol protocol;
ActionType type;
std::string sid; // session id
std::string initiator;
// Used for further parsing when necessary.
// Represents <session> or <jingle>.
const buzz::XmlElement* action_elem;
// Mostly used for debugging.
const buzz::XmlElement* stanza;
};
// TODO: Break up this class so we don't have to typedef it into
// different classes.
struct ContentMessage {
ContentMessage() : owns_contents(false) {}
~ContentMessage() {
if (owns_contents) {
for (ContentInfos::iterator content = contents.begin();
content != contents.end(); content++) {
delete content->description;
}
}
}
// Caller takes ownership of contents.
ContentInfos ClearContents() {
ContentInfos out;
contents.swap(out);
owns_contents = false;
return out;
}
bool owns_contents;
ContentInfos contents;
TransportInfos transports;
ContentGroups groups;
};
typedef ContentMessage SessionInitiate;
typedef ContentMessage SessionAccept;
// Note that a DescriptionInfo does not have TransportInfos.
typedef ContentMessage DescriptionInfo;
struct SessionTerminate {
SessionTerminate() {}
explicit SessionTerminate(const std::string& reason) :
reason(reason) {}
std::string reason;
std::string debug_reason;
};
struct SessionRedirect {
std::string target;
};
// Content name => translator
typedef std::map<std::string, CandidateTranslator*> CandidateTranslatorMap;
bool IsSessionMessage(const buzz::XmlElement* stanza);
bool ParseSessionMessage(const buzz::XmlElement* stanza,
SessionMessage* msg,
ParseError* error);
// Will return an error if there is more than one content type.
bool ParseContentType(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
std::string* content_type,
ParseError* error);
void WriteSessionMessage(const SessionMessage& msg,
const XmlElements& action_elems,
buzz::XmlElement* stanza);
bool ParseSessionInitiate(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
const CandidateTranslatorMap& translators,
SessionInitiate* init,
ParseError* error);
bool WriteSessionInitiate(SignalingProtocol protocol,
const ContentInfos& contents,
const TransportInfos& tinfos,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
const CandidateTranslatorMap& translators,
const ContentGroups& groups,
XmlElements* elems,
WriteError* error);
bool ParseSessionAccept(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
const CandidateTranslatorMap& translators,
SessionAccept* accept,
ParseError* error);
bool WriteSessionAccept(SignalingProtocol protocol,
const ContentInfos& contents,
const TransportInfos& tinfos,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
const CandidateTranslatorMap& translators,
const ContentGroups& groups,
XmlElements* elems,
WriteError* error);
bool ParseSessionTerminate(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
SessionTerminate* term,
ParseError* error);
void WriteSessionTerminate(SignalingProtocol protocol,
const SessionTerminate& term,
XmlElements* elems);
bool ParseDescriptionInfo(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentParserMap& content_parsers,
const TransportParserMap& transport_parsers,
const CandidateTranslatorMap& translators,
DescriptionInfo* description_info,
ParseError* error);
bool WriteDescriptionInfo(SignalingProtocol protocol,
const ContentInfos& contents,
const ContentParserMap& content_parsers,
XmlElements* elems,
WriteError* error);
// Since a TransportInfo is not a transport-info message, and a
// transport-info message is just a collection of TransportInfos, we
// say Parse/Write TransportInfos for transport-info messages.
bool ParseTransportInfos(SignalingProtocol protocol,
const buzz::XmlElement* action_elem,
const ContentInfos& contents,
const TransportParserMap& trans_parsers,
const CandidateTranslatorMap& translators,
TransportInfos* tinfos,
ParseError* error);
bool WriteTransportInfos(SignalingProtocol protocol,
const TransportInfos& tinfos,
const TransportParserMap& trans_parsers,
const CandidateTranslatorMap& translators,
XmlElements* elems,
WriteError* error);
// Handles both Gingle and Jingle syntax.
bool FindSessionRedirect(const buzz::XmlElement* stanza,
SessionRedirect* redirect);
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_

View File

@ -1,128 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONSENDTASK_H_
#define WEBRTC_LIBJINGLE_SESSION_SESSIONSENDTASK_H_
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/libjingle/xmpp/xmppclient.h"
#include "webrtc/libjingle/xmpp/xmppengine.h"
#include "webrtc/libjingle/xmpp/xmpptask.h"
#include "webrtc/base/common.h"
namespace cricket {
// The job of this task is to send an IQ stanza out (after stamping it with
// an ID attribute) and then wait for a response. If not response happens
// within 5 seconds, it will signal failure on a SessionManager. If an error
// happens it will also signal failure. If, however, the send succeeds this
// task will quietly go away.
class SessionSendTask : public buzz::XmppTask {
public:
SessionSendTask(buzz::XmppTaskParentInterface* parent,
SessionManager* session_manager)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
session_manager_(session_manager) {
set_timeout_seconds(15);
session_manager_->SignalDestroyed.connect(
this, &SessionSendTask::OnSessionManagerDestroyed);
}
virtual ~SessionSendTask() {
SignalDone(this);
}
void Send(const buzz::XmlElement* stanza) {
ASSERT(stanza_.get() == NULL);
// This should be an IQ of type set, result, or error. In the first case,
// we supply an ID. In the others, it should be present.
ASSERT(stanza->Name() == buzz::QN_IQ);
ASSERT(stanza->HasAttr(buzz::QN_TYPE));
if (stanza->Attr(buzz::QN_TYPE) == "set") {
ASSERT(!stanza->HasAttr(buzz::QN_ID));
} else {
ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") ||
(stanza->Attr(buzz::QN_TYPE) == "error"));
ASSERT(stanza->HasAttr(buzz::QN_ID));
}
stanza_.reset(new buzz::XmlElement(*stanza));
if (stanza_->HasAttr(buzz::QN_ID)) {
set_task_id(stanza_->Attr(buzz::QN_ID));
} else {
stanza_->SetAttr(buzz::QN_ID, task_id());
}
}
void OnSessionManagerDestroyed() {
// If the session manager doesn't exist anymore, we should still try to
// send the message, but avoid calling back into the SessionManager.
session_manager_ = NULL;
}
sigslot::signal1<SessionSendTask *> SignalDone;
protected:
virtual int OnTimeout() {
if (session_manager_ != NULL) {
session_manager_->OnFailedSend(stanza_.get(), NULL);
}
return XmppTask::OnTimeout();
}
virtual int ProcessStart() {
SendStanza(stanza_.get());
if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) {
return STATE_RESPONSE;
} else {
return STATE_DONE;
}
}
virtual int ProcessResponse() {
const buzz::XmlElement* next = NextStanza();
if (next == NULL)
return STATE_BLOCKED;
if (session_manager_ != NULL) {
if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) {
session_manager_->OnIncomingResponse(stanza_.get(), next);
} else {
session_manager_->OnFailedSend(stanza_.get(), next);
}
}
return STATE_DONE;
}
virtual bool HandleStanza(const buzz::XmlElement *stanza) {
if (!MatchResponseIq(stanza,
buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id()))
return false;
if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT ||
stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) {
QueueStanza(stanza);
return true;
}
return false;
}
private:
SessionManager *session_manager_;
rtc::scoped_ptr<buzz::XmlElement> stanza_;
};
}
#endif // WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_

View File

@ -1,38 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/libjingle/session/transportparser.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
namespace cricket {
bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
const buzz::QName& address_name,
const buzz::QName& port_name,
rtc::SocketAddress* address,
ParseError* error) {
if (!elem->HasAttr(address_name))
return BadParse("address does not have " + address_name.LocalPart(), error);
if (!elem->HasAttr(port_name))
return BadParse("address does not have " + port_name.LocalPart(), error);
address->SetIP(elem->Attr(address_name));
std::istringstream ist(elem->Attr(port_name));
int port = 0;
ist >> port;
address->SetPort(port);
return true;
}
} // namespace cricket

View File

@ -1,78 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_
#define WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_
#include <string>
#include <vector>
#include "webrtc/p2p/base/transportinfo.h"
namespace buzz {
class QName;
class XmlElement;
}
namespace cricket {
struct ParseError;
struct WriteError;
class CandidateTranslator;
typedef std::vector<buzz::XmlElement*> XmlElements;
class TransportParser {
public:
// The incoming Translator value may be null, in which case
// ParseCandidates should return false if there are candidates to
// parse (indicating a failure to parse). If the Translator is null
// and there are no candidates to parse, then return true,
// indicating a successful parse of 0 candidates.
// Parse or write a transport description, including ICE credentials and
// any DTLS fingerprint. Since only Jingle has transport descriptions, these
// functions are only used when serializing to Jingle.
virtual bool ParseTransportDescription(const buzz::XmlElement* elem,
const CandidateTranslator* translator,
TransportDescription* tdesc,
ParseError* error) = 0;
virtual bool WriteTransportDescription(const TransportDescription& tdesc,
const CandidateTranslator* translator,
buzz::XmlElement** tdesc_elem,
WriteError* error) = 0;
// Parse a single candidate. This must be used when parsing Gingle
// candidates, since there is no enclosing transport description.
virtual bool ParseGingleCandidate(const buzz::XmlElement* elem,
const CandidateTranslator* translator,
Candidate* candidates,
ParseError* error) = 0;
virtual bool WriteGingleCandidate(const Candidate& candidate,
const CandidateTranslator* translator,
buzz::XmlElement** candidate_elem,
WriteError* error) = 0;
// Helper function to parse an element describing an address. This
// retrieves the IP and port from the given element and verifies
// that they look like plausible values.
bool ParseAddress(const buzz::XmlElement* elem,
const buzz::QName& address_name,
const buzz::QName& port_name,
rtc::SocketAddress* address,
ParseError* error);
virtual ~TransportParser() {}
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_

View File

@ -1,136 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/gunit.h"
#include "webrtc/libjingle/session/p2ptransportparser.h"
#include "webrtc/libjingle/session/parsing.h"
#include "webrtc/libjingle/session/sessionmessages.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/p2p/base/constants.h"
using cricket::Candidate;
using cricket::Candidates;
using cricket::ParseError;
using cricket::WriteError;
class TransportParserTest : public testing::Test {
};
class FakeCandidateTranslator : public cricket::CandidateTranslator {
public:
void AddMapping(int component, const std::string& channel_name) {
name_to_component[channel_name] = component;
component_to_name[component] = channel_name;
}
bool GetChannelNameFromComponent(
int component, std::string* channel_name) const {
if (component_to_name.find(component) == component_to_name.end()) {
return false;
}
*channel_name = component_to_name.find(component)->second;
return true;
}
bool GetComponentFromChannelName(
const std::string& channel_name, int* component) const {
if (name_to_component.find(channel_name) == name_to_component.end()) {
return false;
}
*component = name_to_component.find(channel_name)->second;
return true;
}
std::map<std::string, int> name_to_component;
std::map<int, std::string> component_to_name;
};
// Tests that we can properly serialize/deserialize candidates.
TEST_F(TransportParserTest, TestP2PTransportWriteAndParseCandidate) {
Candidate test_candidate(
"", 1, "udp",
rtc::SocketAddress("2001:db8:fefe::1", 9999),
738197504, "abcdef", "ghijkl", "foo", 50, "");
test_candidate.set_network_name("testnet");
Candidate test_candidate2(
"", 2, "tcp",
rtc::SocketAddress("192.168.7.1", 9999),
1107296256, "mnopqr", "stuvwx", "bar", 100, "");
test_candidate2.set_network_name("testnet2");
rtc::SocketAddress host_address("www.google.com", 24601);
host_address.SetResolvedIP(rtc::IPAddress(0x0A000001));
Candidate test_candidate3(
"", 3, "spdy", host_address, 1476395008, "yzabcd",
"efghij", "baz", 150, "");
test_candidate3.set_network_name("testnet3");
WriteError write_error;
ParseError parse_error;
rtc::scoped_ptr<buzz::XmlElement> elem;
cricket::Candidate parsed_candidate;
cricket::P2PTransportParser parser;
FakeCandidateTranslator translator;
translator.AddMapping(1, "test");
translator.AddMapping(2, "test2");
translator.AddMapping(3, "test3");
EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate, &translator,
elem.accept(), &write_error));
EXPECT_EQ("", write_error.text);
EXPECT_EQ("test", elem->Attr(buzz::QN_NAME));
EXPECT_EQ("udp", elem->Attr(cricket::QN_PROTOCOL));
EXPECT_EQ("2001:db8:fefe::1", elem->Attr(cricket::QN_ADDRESS));
EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT));
EXPECT_EQ("0.34", elem->Attr(cricket::QN_PREFERENCE));
EXPECT_EQ("abcdef", elem->Attr(cricket::QN_USERNAME));
EXPECT_EQ("ghijkl", elem->Attr(cricket::QN_PASSWORD));
EXPECT_EQ("foo", elem->Attr(cricket::QN_TYPE));
EXPECT_EQ("testnet", elem->Attr(cricket::QN_NETWORK));
EXPECT_EQ("50", elem->Attr(cricket::QN_GENERATION));
EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
&parsed_candidate, &parse_error));
EXPECT_TRUE(test_candidate.IsEquivalent(parsed_candidate));
EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate2, &translator,
elem.accept(), &write_error));
EXPECT_EQ("test2", elem->Attr(buzz::QN_NAME));
EXPECT_EQ("tcp", elem->Attr(cricket::QN_PROTOCOL));
EXPECT_EQ("192.168.7.1", elem->Attr(cricket::QN_ADDRESS));
EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT));
EXPECT_EQ("0.51", elem->Attr(cricket::QN_PREFERENCE));
EXPECT_EQ("mnopqr", elem->Attr(cricket::QN_USERNAME));
EXPECT_EQ("stuvwx", elem->Attr(cricket::QN_PASSWORD));
EXPECT_EQ("bar", elem->Attr(cricket::QN_TYPE));
EXPECT_EQ("testnet2", elem->Attr(cricket::QN_NETWORK));
EXPECT_EQ("100", elem->Attr(cricket::QN_GENERATION));
EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
&parsed_candidate, &parse_error));
EXPECT_TRUE(test_candidate2.IsEquivalent(parsed_candidate));
// Check that an ip is preferred over hostname.
EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate3, &translator,
elem.accept(), &write_error));
EXPECT_EQ("test3", elem->Attr(cricket::QN_NAME));
EXPECT_EQ("spdy", elem->Attr(cricket::QN_PROTOCOL));
EXPECT_EQ("10.0.0.1", elem->Attr(cricket::QN_ADDRESS));
EXPECT_EQ("24601", elem->Attr(cricket::QN_PORT));
EXPECT_EQ("0.69", elem->Attr(cricket::QN_PREFERENCE));
EXPECT_EQ("yzabcd", elem->Attr(cricket::QN_USERNAME));
EXPECT_EQ("efghij", elem->Attr(cricket::QN_PASSWORD));
EXPECT_EQ("baz", elem->Attr(cricket::QN_TYPE));
EXPECT_EQ("testnet3", elem->Attr(cricket::QN_NETWORK));
EXPECT_EQ("150", elem->Attr(cricket::QN_GENERATION));
EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
&parsed_candidate, &parse_error));
EXPECT_TRUE(test_candidate3.IsEquivalent(parsed_candidate));
}

View File

@ -1,605 +0,0 @@
/*
* libjingle
* Copyright 2004--2006, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include <string>
#include "pseudotcpchannel.h"
#include "webrtc/p2p/base/candidate.h"
#include "webrtc/p2p/base/transportchannel.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/common.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/stringutils.h"
using namespace rtc;
namespace cricket {
extern const rtc::ConstantLabel SESSION_STATES[];
// MSG_WK_* - worker thread messages
// MSG_ST_* - stream thread messages
// MSG_SI_* - signal thread messages
enum {
MSG_WK_CLOCK = 1,
MSG_WK_PURGE,
MSG_ST_EVENT,
MSG_SI_DESTROYCHANNEL,
MSG_SI_DESTROY,
};
struct EventData : public MessageData {
int event, error;
EventData(int ev, int err = 0) : event(ev), error(err) { }
};
///////////////////////////////////////////////////////////////////////////////
// PseudoTcpChannel::InternalStream
///////////////////////////////////////////////////////////////////////////////
class PseudoTcpChannel::InternalStream : public StreamInterface {
public:
InternalStream(PseudoTcpChannel* parent);
virtual ~InternalStream();
virtual StreamState GetState() const;
virtual StreamResult Read(void* buffer, size_t buffer_len,
size_t* read, int* error);
virtual StreamResult Write(const void* data, size_t data_len,
size_t* written, int* error);
virtual void Close();
private:
// parent_ is accessed and modified exclusively on the event thread, to
// avoid thread contention. This means that the PseudoTcpChannel cannot go
// away until after it receives a Close() from TunnelStream.
PseudoTcpChannel* parent_;
};
///////////////////////////////////////////////////////////////////////////////
// PseudoTcpChannel
// Member object lifetime summaries:
// session_ - passed in constructor, cleared when channel_ goes away.
// channel_ - created in Connect, destroyed when session_ or tcp_ goes away.
// tcp_ - created in Connect, destroyed when channel_ goes away, or connection
// closes.
// worker_thread_ - created when channel_ is created, purged when channel_ is
// destroyed.
// stream_ - created in GetStream, destroyed by owner at arbitrary time.
// this - created in constructor, destroyed when worker_thread_ and stream_
// are both gone.
///////////////////////////////////////////////////////////////////////////////
//
// Signal thread methods
//
PseudoTcpChannel::PseudoTcpChannel(Thread* stream_thread, Session* session)
: signal_thread_(session->session_manager()->signaling_thread()),
worker_thread_(NULL),
stream_thread_(stream_thread),
session_(session), channel_(NULL), tcp_(NULL), stream_(NULL),
stream_readable_(false), pending_read_event_(false),
ready_to_connect_(false) {
ASSERT(signal_thread_->IsCurrent());
ASSERT(NULL != session_);
}
PseudoTcpChannel::~PseudoTcpChannel() {
ASSERT(signal_thread_->IsCurrent());
ASSERT(worker_thread_ == NULL);
ASSERT(session_ == NULL);
ASSERT(channel_ == NULL);
ASSERT(stream_ == NULL);
ASSERT(tcp_ == NULL);
}
bool PseudoTcpChannel::Connect(const std::string& content_name,
const std::string& channel_name,
int component) {
ASSERT(signal_thread_->IsCurrent());
CritScope lock(&cs_);
if (channel_)
return false;
ASSERT(session_ != NULL);
worker_thread_ = session_->session_manager()->worker_thread();
content_name_ = content_name;
channel_ = session_->CreateChannel(
content_name, channel_name, component);
channel_name_ = channel_name;
channel_->SetOption(Socket::OPT_DONTFRAGMENT, 1);
channel_->SignalDestroyed.connect(this,
&PseudoTcpChannel::OnChannelDestroyed);
channel_->SignalWritableState.connect(this,
&PseudoTcpChannel::OnChannelWritableState);
channel_->SignalReadPacket.connect(this,
&PseudoTcpChannel::OnChannelRead);
channel_->SignalRouteChange.connect(this,
&PseudoTcpChannel::OnChannelConnectionChanged);
ASSERT(tcp_ == NULL);
tcp_ = new PseudoTcp(this, 0);
if (session_->initiator()) {
// Since we may try several protocols and network adapters that won't work,
// waiting until we get our first writable notification before initiating
// TCP negotiation.
ready_to_connect_ = true;
}
return true;
}
StreamInterface* PseudoTcpChannel::GetStream() {
ASSERT(signal_thread_->IsCurrent());
CritScope lock(&cs_);
ASSERT(NULL != session_);
if (!stream_)
stream_ = new PseudoTcpChannel::InternalStream(this);
//TODO("should we disallow creation of new stream at some point?");
return stream_;
}
void PseudoTcpChannel::OnChannelDestroyed(TransportChannel* channel) {
LOG_F(LS_INFO) << "(" << channel->component() << ")";
ASSERT(signal_thread_->IsCurrent());
CritScope lock(&cs_);
ASSERT(channel == channel_);
signal_thread_->Clear(this, MSG_SI_DESTROYCHANNEL);
// When MSG_WK_PURGE is received, we know there will be no more messages from
// the worker thread.
worker_thread_->Clear(this, MSG_WK_CLOCK);
worker_thread_->Post(this, MSG_WK_PURGE);
session_ = NULL;
channel_ = NULL;
if ((stream_ != NULL)
&& ((tcp_ == NULL) || (tcp_->State() != PseudoTcp::TCP_CLOSED)))
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, 0));
if (tcp_) {
tcp_->Close(true);
AdjustClock();
}
SignalChannelClosed(this);
}
void PseudoTcpChannel::OnSessionTerminate(Session* session) {
// When the session terminates before we even connected
CritScope lock(&cs_);
if (session_ != NULL && channel_ == NULL) {
ASSERT(session == session_);
ASSERT(worker_thread_ == NULL);
ASSERT(tcp_ == NULL);
LOG(LS_INFO) << "Destroying unconnected PseudoTcpChannel";
session_ = NULL;
if (stream_ != NULL)
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, -1));
}
// Even though session_ is being destroyed, we mustn't clear the pointer,
// since we'll need it to tear down channel_.
//
// TODO: Is it always the case that if channel_ != NULL then we'll get
// a channel-destroyed notification?
}
void PseudoTcpChannel::GetOption(PseudoTcp::Option opt, int* value) {
ASSERT(signal_thread_->IsCurrent());
CritScope lock(&cs_);
ASSERT(tcp_ != NULL);
tcp_->GetOption(opt, value);
}
void PseudoTcpChannel::SetOption(PseudoTcp::Option opt, int value) {
ASSERT(signal_thread_->IsCurrent());
CritScope lock(&cs_);
ASSERT(tcp_ != NULL);
tcp_->SetOption(opt, value);
}
//
// Stream thread methods
//
StreamState PseudoTcpChannel::GetState() const {
ASSERT(stream_ != NULL && stream_thread_->IsCurrent());
CritScope lock(&cs_);
if (!session_)
return SS_CLOSED;
if (!tcp_)
return SS_OPENING;
switch (tcp_->State()) {
case PseudoTcp::TCP_LISTEN:
case PseudoTcp::TCP_SYN_SENT:
case PseudoTcp::TCP_SYN_RECEIVED:
return SS_OPENING;
case PseudoTcp::TCP_ESTABLISHED:
return SS_OPEN;
case PseudoTcp::TCP_CLOSED:
default:
return SS_CLOSED;
}
}
StreamResult PseudoTcpChannel::Read(void* buffer, size_t buffer_len,
size_t* read, int* error) {
ASSERT(stream_ != NULL && stream_thread_->IsCurrent());
CritScope lock(&cs_);
if (!tcp_)
return SR_BLOCK;
stream_readable_ = false;
int result = tcp_->Recv(static_cast<char*>(buffer), buffer_len);
//LOG_F(LS_VERBOSE) << "Recv returned: " << result;
if (result > 0) {
if (read)
*read = result;
// PseudoTcp doesn't currently support repeated Readable signals. Simulate
// them here.
stream_readable_ = true;
if (!pending_read_event_) {
pending_read_event_ = true;
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ), true);
}
return SR_SUCCESS;
} else if (IsBlockingError(tcp_->GetError())) {
return SR_BLOCK;
} else {
if (error)
*error = tcp_->GetError();
return SR_ERROR;
}
// This spot is never reached.
}
StreamResult PseudoTcpChannel::Write(const void* data, size_t data_len,
size_t* written, int* error) {
ASSERT(stream_ != NULL && stream_thread_->IsCurrent());
CritScope lock(&cs_);
if (!tcp_)
return SR_BLOCK;
int result = tcp_->Send(static_cast<const char*>(data), data_len);
//LOG_F(LS_VERBOSE) << "Send returned: " << result;
if (result > 0) {
if (written)
*written = result;
return SR_SUCCESS;
} else if (IsBlockingError(tcp_->GetError())) {
return SR_BLOCK;
} else {
if (error)
*error = tcp_->GetError();
return SR_ERROR;
}
// This spot is never reached.
}
void PseudoTcpChannel::Close() {
ASSERT(stream_ != NULL && stream_thread_->IsCurrent());
CritScope lock(&cs_);
stream_ = NULL;
// Clear out any pending event notifications
stream_thread_->Clear(this, MSG_ST_EVENT);
if (tcp_) {
tcp_->Close(false);
AdjustClock();
} else {
CheckDestroy();
}
}
//
// Worker thread methods
//
void PseudoTcpChannel::OnChannelWritableState(TransportChannel* channel) {
LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]";
ASSERT(worker_thread_->IsCurrent());
CritScope lock(&cs_);
if (!channel_) {
LOG_F(LS_WARNING) << "NULL channel";
return;
}
ASSERT(channel == channel_);
if (!tcp_) {
LOG_F(LS_WARNING) << "NULL tcp";
return;
}
if (!ready_to_connect_ || !channel->writable())
return;
ready_to_connect_ = false;
tcp_->Connect();
AdjustClock();
}
void PseudoTcpChannel::OnChannelRead(TransportChannel* channel,
const char* data, size_t size,
const rtc::PacketTime& packet_time,
int flags) {
//LOG_F(LS_VERBOSE) << "(" << size << ")";
ASSERT(worker_thread_->IsCurrent());
CritScope lock(&cs_);
if (!channel_) {
LOG_F(LS_WARNING) << "NULL channel";
return;
}
ASSERT(channel == channel_);
if (!tcp_) {
LOG_F(LS_WARNING) << "NULL tcp";
return;
}
tcp_->NotifyPacket(data, size);
AdjustClock();
}
void PseudoTcpChannel::OnChannelConnectionChanged(TransportChannel* channel,
const Candidate& candidate) {
LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]";
ASSERT(worker_thread_->IsCurrent());
CritScope lock(&cs_);
if (!channel_) {
LOG_F(LS_WARNING) << "NULL channel";
return;
}
ASSERT(channel == channel_);
if (!tcp_) {
LOG_F(LS_WARNING) << "NULL tcp";
return;
}
uint16 mtu = 1280; // safe default
int family = candidate.address().family();
Socket* socket =
worker_thread_->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM);
rtc::scoped_ptr<Socket> mtu_socket(socket);
if (socket == NULL) {
LOG_F(LS_WARNING) << "Couldn't create socket while estimating MTU.";
} else {
if (mtu_socket->Connect(candidate.address()) < 0 ||
mtu_socket->EstimateMTU(&mtu) < 0) {
LOG_F(LS_WARNING) << "Failed to estimate MTU, error="
<< mtu_socket->GetError();
}
}
LOG_F(LS_VERBOSE) << "Using MTU of " << mtu << " bytes";
tcp_->NotifyMTU(mtu);
AdjustClock();
}
void PseudoTcpChannel::OnTcpOpen(PseudoTcp* tcp) {
LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]";
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(worker_thread_->IsCurrent());
ASSERT(tcp == tcp_);
if (stream_) {
stream_readable_ = true;
pending_read_event_ = true;
stream_thread_->Post(this, MSG_ST_EVENT,
new EventData(SE_OPEN | SE_READ | SE_WRITE));
}
}
void PseudoTcpChannel::OnTcpReadable(PseudoTcp* tcp) {
//LOG_F(LS_VERBOSE);
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(worker_thread_->IsCurrent());
ASSERT(tcp == tcp_);
if (stream_) {
stream_readable_ = true;
if (!pending_read_event_) {
pending_read_event_ = true;
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ));
}
}
}
void PseudoTcpChannel::OnTcpWriteable(PseudoTcp* tcp) {
//LOG_F(LS_VERBOSE);
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(worker_thread_->IsCurrent());
ASSERT(tcp == tcp_);
if (stream_)
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_WRITE));
}
void PseudoTcpChannel::OnTcpClosed(PseudoTcp* tcp, uint32 nError) {
LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]";
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(worker_thread_->IsCurrent());
ASSERT(tcp == tcp_);
if (stream_)
stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, nError));
}
//
// Multi-thread methods
//
void PseudoTcpChannel::OnMessage(Message* pmsg) {
if (pmsg->message_id == MSG_WK_CLOCK) {
ASSERT(worker_thread_->IsCurrent());
//LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_WK_CLOCK)";
CritScope lock(&cs_);
if (tcp_) {
tcp_->NotifyClock(PseudoTcp::Now());
AdjustClock(false);
}
} else if (pmsg->message_id == MSG_WK_PURGE) {
ASSERT(worker_thread_->IsCurrent());
LOG_F(LS_INFO) << "(MSG_WK_PURGE)";
// At this point, we know there are no additional worker thread messages.
CritScope lock(&cs_);
ASSERT(NULL == session_);
ASSERT(NULL == channel_);
worker_thread_ = NULL;
CheckDestroy();
} else if (pmsg->message_id == MSG_ST_EVENT) {
ASSERT(stream_thread_->IsCurrent());
//LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_ST_EVENT, "
// << data->event << ", " << data->error << ")";
ASSERT(stream_ != NULL);
EventData* data = static_cast<EventData*>(pmsg->pdata);
if (data->event & SE_READ) {
CritScope lock(&cs_);
pending_read_event_ = false;
}
stream_->SignalEvent(stream_, data->event, data->error);
delete data;
} else if (pmsg->message_id == MSG_SI_DESTROYCHANNEL) {
ASSERT(signal_thread_->IsCurrent());
LOG_F(LS_INFO) << "(MSG_SI_DESTROYCHANNEL)";
ASSERT(session_ != NULL);
ASSERT(channel_ != NULL);
session_->DestroyChannel(content_name_, channel_->component());
} else if (pmsg->message_id == MSG_SI_DESTROY) {
ASSERT(signal_thread_->IsCurrent());
LOG_F(LS_INFO) << "(MSG_SI_DESTROY)";
// The message queue is empty, so it is safe to destroy ourselves.
delete this;
} else {
ASSERT(false);
}
}
IPseudoTcpNotify::WriteResult PseudoTcpChannel::TcpWritePacket(
PseudoTcp* tcp, const char* buffer, size_t len) {
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(tcp == tcp_);
ASSERT(NULL != channel_);
rtc::PacketOptions packet_options;
int sent = channel_->SendPacket(buffer, len, packet_options);
if (sent > 0) {
//LOG_F(LS_VERBOSE) << "(" << sent << ") Sent";
return IPseudoTcpNotify::WR_SUCCESS;
} else if (IsBlockingError(channel_->GetError())) {
LOG_F(LS_VERBOSE) << "Blocking";
return IPseudoTcpNotify::WR_SUCCESS;
} else if (channel_->GetError() == EMSGSIZE) {
LOG_F(LS_ERROR) << "EMSGSIZE";
return IPseudoTcpNotify::WR_TOO_LARGE;
} else {
PLOG(LS_ERROR, channel_->GetError()) << "PseudoTcpChannel::TcpWritePacket";
ASSERT(false);
return IPseudoTcpNotify::WR_FAIL;
}
}
void PseudoTcpChannel::AdjustClock(bool clear) {
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(NULL != tcp_);
long timeout = 0;
if (tcp_->GetNextClock(PseudoTcp::Now(), timeout)) {
ASSERT(NULL != channel_);
// Reset the next clock, by clearing the old and setting a new one.
if (clear)
worker_thread_->Clear(this, MSG_WK_CLOCK);
worker_thread_->PostDelayed(std::max(timeout, 0L), this, MSG_WK_CLOCK);
return;
}
delete tcp_;
tcp_ = NULL;
ready_to_connect_ = false;
if (channel_) {
// If TCP has failed, no need for channel_ anymore
signal_thread_->Post(this, MSG_SI_DESTROYCHANNEL);
}
}
void PseudoTcpChannel::CheckDestroy() {
ASSERT(cs_.CurrentThreadIsOwner());
if ((worker_thread_ != NULL) || (stream_ != NULL))
return;
signal_thread_->Post(this, MSG_SI_DESTROY);
}
///////////////////////////////////////////////////////////////////////////////
// PseudoTcpChannel::InternalStream
///////////////////////////////////////////////////////////////////////////////
PseudoTcpChannel::InternalStream::InternalStream(PseudoTcpChannel* parent)
: parent_(parent) {
}
PseudoTcpChannel::InternalStream::~InternalStream() {
Close();
}
StreamState PseudoTcpChannel::InternalStream::GetState() const {
if (!parent_)
return SS_CLOSED;
return parent_->GetState();
}
StreamResult PseudoTcpChannel::InternalStream::Read(
void* buffer, size_t buffer_len, size_t* read, int* error) {
if (!parent_) {
if (error)
*error = ENOTCONN;
return SR_ERROR;
}
return parent_->Read(buffer, buffer_len, read, error);
}
StreamResult PseudoTcpChannel::InternalStream::Write(
const void* data, size_t data_len, size_t* written, int* error) {
if (!parent_) {
if (error)
*error = ENOTCONN;
return SR_ERROR;
}
return parent_->Write(data, data_len, written, error);
}
void PseudoTcpChannel::InternalStream::Close() {
if (!parent_)
return;
parent_->Close();
parent_ = NULL;
}
///////////////////////////////////////////////////////////////////////////////
} // namespace cricket

View File

@ -1,140 +0,0 @@
/*
* libjingle
* Copyright 2004--2006, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_
#define WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/messagequeue.h"
#include "webrtc/base/stream.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/p2p/base/pseudotcp.h"
namespace rtc {
class Thread;
}
namespace cricket {
class Candidate;
class TransportChannel;
///////////////////////////////////////////////////////////////////////////////
// PseudoTcpChannel
// Note: The PseudoTcpChannel must persist until both of:
// 1) The StreamInterface provided via GetStream has been closed.
// This is tracked via non-null stream_.
// 2) The PseudoTcp session has completed.
// This is tracked via non-null worker_thread_. When PseudoTcp is done,
// the TransportChannel is signalled to tear-down. Once the channel is
// torn down, the worker thread is purged.
// These indicators are checked by CheckDestroy, invoked whenever one of them
// changes.
///////////////////////////////////////////////////////////////////////////////
// PseudoTcpChannel::GetStream
// Note: The stream pointer returned by GetStream is owned by the caller.
// They can close & immediately delete the stream while PseudoTcpChannel still
// has cleanup work to do. They can also close the stream but not delete it
// until long after PseudoTcpChannel has finished. We must cope with both.
///////////////////////////////////////////////////////////////////////////////
class PseudoTcpChannel
: public IPseudoTcpNotify,
public rtc::MessageHandler,
public sigslot::has_slots<> {
public:
// Signal thread methods
PseudoTcpChannel(rtc::Thread* stream_thread,
Session* session);
bool Connect(const std::string& content_name,
const std::string& channel_name,
int component);
rtc::StreamInterface* GetStream();
sigslot::signal1<PseudoTcpChannel*> SignalChannelClosed;
// Call this when the Session used to create this channel is being torn
// down, to ensure that things get cleaned up properly.
void OnSessionTerminate(Session* session);
// See the PseudoTcp class for available options.
void GetOption(PseudoTcp::Option opt, int* value);
void SetOption(PseudoTcp::Option opt, int value);
private:
class InternalStream;
friend class InternalStream;
virtual ~PseudoTcpChannel();
// Stream thread methods
rtc::StreamState GetState() const;
rtc::StreamResult Read(void* buffer, size_t buffer_len,
size_t* read, int* error);
rtc::StreamResult Write(const void* data, size_t data_len,
size_t* written, int* error);
void Close();
// Multi-thread methods
void OnMessage(rtc::Message* pmsg);
void AdjustClock(bool clear = true);
void CheckDestroy();
// Signal thread methods
void OnChannelDestroyed(TransportChannel* channel);
// Worker thread methods
void OnChannelWritableState(TransportChannel* channel);
void OnChannelRead(TransportChannel* channel, const char* data, size_t size,
const rtc::PacketTime& packet_time, int flags);
void OnChannelConnectionChanged(TransportChannel* channel,
const Candidate& candidate);
virtual void OnTcpOpen(PseudoTcp* ptcp);
virtual void OnTcpReadable(PseudoTcp* ptcp);
virtual void OnTcpWriteable(PseudoTcp* ptcp);
virtual void OnTcpClosed(PseudoTcp* ptcp, uint32 nError);
virtual IPseudoTcpNotify::WriteResult TcpWritePacket(PseudoTcp* tcp,
const char* buffer,
size_t len);
rtc::Thread* signal_thread_, * worker_thread_, * stream_thread_;
Session* session_;
TransportChannel* channel_;
std::string content_name_;
std::string channel_name_;
PseudoTcp* tcp_;
InternalStream* stream_;
bool stream_readable_, pending_read_event_;
bool ready_to_connect_;
mutable rtc::CriticalSection cs_;
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_

View File

@ -1,397 +0,0 @@
/*
* libjingle
* Copyright 2004--2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// SecureTunnelSessionClient and SecureTunnelSession implementation.
#include "webrtc/p2p/base/transportchannel.h"
#include "webrtc/libjingle/session/tunnel/pseudotcpchannel.h"
#include "webrtc/libjingle/session/tunnel/securetunnelsessionclient.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "webrtc/base/basicdefs.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/common.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/sslidentity.h"
#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/base/stringutils.h"
namespace cricket {
// XML elements and namespaces for XMPP stanzas used in content exchanges.
const char NS_SECURE_TUNNEL[] = "http://www.google.com/talk/securetunnel";
const buzz::StaticQName QN_SECURE_TUNNEL_DESCRIPTION =
{ NS_SECURE_TUNNEL, "description" };
const buzz::StaticQName QN_SECURE_TUNNEL_TYPE =
{ NS_SECURE_TUNNEL, "type" };
const buzz::StaticQName QN_SECURE_TUNNEL_CLIENT_CERT =
{ NS_SECURE_TUNNEL, "client-cert" };
const buzz::StaticQName QN_SECURE_TUNNEL_SERVER_CERT =
{ NS_SECURE_TUNNEL, "server-cert" };
const char CN_SECURE_TUNNEL[] = "securetunnel";
// SecureTunnelContentDescription
// TunnelContentDescription is extended to hold string forms of the
// client and server certificate, PEM encoded.
struct SecureTunnelContentDescription : public ContentDescription {
std::string description;
std::string client_pem_certificate;
std::string server_pem_certificate;
SecureTunnelContentDescription(const std::string& desc,
const std::string& client_pem_cert,
const std::string& server_pem_cert)
: description(desc),
client_pem_certificate(client_pem_cert),
server_pem_certificate(server_pem_cert) {
}
virtual ContentDescription* Copy() const {
return new SecureTunnelContentDescription(*this);
}
};
// SecureTunnelSessionClient
SecureTunnelSessionClient::SecureTunnelSessionClient(
const buzz::Jid& jid, SessionManager* manager)
: TunnelSessionClient(jid, manager, NS_SECURE_TUNNEL) {
}
void SecureTunnelSessionClient::SetIdentity(rtc::SSLIdentity* identity) {
ASSERT(identity_.get() == NULL);
identity_.reset(identity);
}
bool SecureTunnelSessionClient::GenerateIdentity() {
ASSERT(identity_.get() == NULL);
identity_.reset(rtc::SSLIdentity::Generate(
// The name on the certificate does not matter: the peer will
// make sure the cert it gets during SSL negotiation matches the
// one it got from XMPP. It would be neat to put something
// recognizable in there such as the JID, except this will show
// in clear during the SSL negotiation and so it could be a
// privacy issue. Specifying an empty string here causes
// it to use a random string.
#ifdef _DEBUG
jid().Str()
#else
""
#endif
));
if (identity_.get() == NULL) {
LOG(LS_ERROR) << "Failed to generate SSL identity";
return false;
}
return true;
}
rtc::SSLIdentity& SecureTunnelSessionClient::GetIdentity() const {
ASSERT(identity_.get() != NULL);
return *identity_;
}
// Parses a certificate from a PEM encoded string.
// Returns NULL on failure.
// The caller is responsible for freeing the returned object.
static rtc::SSLCertificate* ParseCertificate(
const std::string& pem_cert) {
if (pem_cert.empty())
return NULL;
return rtc::SSLCertificate::FromPEMString(pem_cert);
}
TunnelSession* SecureTunnelSessionClient::MakeTunnelSession(
Session* session, rtc::Thread* stream_thread,
TunnelSessionRole role) {
return new SecureTunnelSession(this, session, stream_thread, role);
}
bool FindSecureTunnelContent(const cricket::SessionDescription* sdesc,
std::string* name,
const SecureTunnelContentDescription** content) {
const ContentInfo* cinfo = sdesc->FirstContentByType(NS_SECURE_TUNNEL);
if (cinfo == NULL)
return false;
*name = cinfo->name;
*content = static_cast<const SecureTunnelContentDescription*>(
cinfo->description);
return true;
}
void SecureTunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
Session *session) {
std::string content_name;
const SecureTunnelContentDescription* content = NULL;
if (!FindSecureTunnelContent(session->remote_description(),
&content_name, &content)) {
ASSERT(false);
}
// Validate the certificate
rtc::scoped_ptr<rtc::SSLCertificate> peer_cert(
ParseCertificate(content->client_pem_certificate));
if (peer_cert.get() == NULL) {
LOG(LS_ERROR)
<< "Rejecting incoming secure tunnel with invalid cetificate";
DeclineTunnel(session);
return;
}
// If there were a convenient place we could have cached the
// peer_cert so as not to have to parse it a second time when
// configuring the tunnel.
SignalIncomingTunnel(this, jid, content->description, session);
}
// The XML representation of a session initiation request (XMPP IQ),
// containing the initiator's SecureTunnelContentDescription,
// looks something like this:
// <iq from="INITIATOR@gmail.com/pcpE101B7F4"
// to="RECIPIENT@gmail.com/pcp8B87F0A3"
// type="set" id="3">
// <session xmlns="http://www.google.com/session"
// type="initiate" id="2508605813"
// initiator="INITIATOR@gmail.com/pcpE101B7F4">
// <description xmlns="http://www.google.com/talk/securetunnel">
// <type>send:filename</type>
// <client-cert>
// -----BEGIN CERTIFICATE-----
// INITIATOR'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH)
// -----END CERTIFICATE-----
// </client-cert>
// </description>
// <transport xmlns="http://www.google.com/transport/p2p"/>
// </session>
// </iq>
// The session accept iq, containing the recipient's certificate and
// echoing the initiator's certificate, looks something like this:
// <iq from="RECIPIENT@gmail.com/pcpE101B7F4"
// to="INITIATOR@gmail.com/pcpE101B7F4"
// type="set" id="5">
// <session xmlns="http://www.google.com/session"
// type="accept" id="2508605813"
// initiator="sdoyon911@gmail.com/pcpE101B7F4">
// <description xmlns="http://www.google.com/talk/securetunnel">
// <type>send:FILENAME</type>
// <client-cert>
// -----BEGIN CERTIFICATE-----
// INITIATOR'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH)
// -----END CERTIFICATE-----
// </client-cert>
// <server-cert>
// -----BEGIN CERTIFICATE-----
// RECIPIENT'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH)
// -----END CERTIFICATE-----
// </server-cert>
// </description>
// </session>
// </iq>
bool SecureTunnelSessionClient::ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error) {
const buzz::XmlElement* type_elem = elem->FirstNamed(QN_SECURE_TUNNEL_TYPE);
if (type_elem == NULL)
// Missing mandatory XML element.
return false;
// Here we consider the certificate components to be optional. In
// practice the client certificate is always present, and the server
// certificate is initially missing from the session description
// sent during session initiation. OnAccept() will enforce that we
// have a certificate for our peer.
const buzz::XmlElement* client_cert_elem =
elem->FirstNamed(QN_SECURE_TUNNEL_CLIENT_CERT);
const buzz::XmlElement* server_cert_elem =
elem->FirstNamed(QN_SECURE_TUNNEL_SERVER_CERT);
*content = new SecureTunnelContentDescription(
type_elem->BodyText(),
client_cert_elem ? client_cert_elem->BodyText() : "",
server_cert_elem ? server_cert_elem->BodyText() : "");
return true;
}
bool SecureTunnelSessionClient::WriteContent(
SignalingProtocol protocol, const ContentDescription* untyped_content,
buzz::XmlElement** elem, WriteError* error) {
const SecureTunnelContentDescription* content =
static_cast<const SecureTunnelContentDescription*>(untyped_content);
buzz::XmlElement* root =
new buzz::XmlElement(QN_SECURE_TUNNEL_DESCRIPTION, true);
buzz::XmlElement* type_elem = new buzz::XmlElement(QN_SECURE_TUNNEL_TYPE);
type_elem->SetBodyText(content->description);
root->AddElement(type_elem);
if (!content->client_pem_certificate.empty()) {
buzz::XmlElement* client_cert_elem =
new buzz::XmlElement(QN_SECURE_TUNNEL_CLIENT_CERT);
client_cert_elem->SetBodyText(content->client_pem_certificate);
root->AddElement(client_cert_elem);
}
if (!content->server_pem_certificate.empty()) {
buzz::XmlElement* server_cert_elem =
new buzz::XmlElement(QN_SECURE_TUNNEL_SERVER_CERT);
server_cert_elem->SetBodyText(content->server_pem_certificate);
root->AddElement(server_cert_elem);
}
*elem = root;
return true;
}
SessionDescription* NewSecureTunnelSessionDescription(
const std::string& content_name, ContentDescription* content) {
SessionDescription* sdesc = new SessionDescription();
sdesc->AddContent(content_name, NS_SECURE_TUNNEL, content);
return sdesc;
}
SessionDescription* SecureTunnelSessionClient::CreateOffer(
const buzz::Jid &jid, const std::string &description) {
// We are the initiator so we are the client. Put our cert into the
// description.
std::string pem_cert = GetIdentity().certificate().ToPEMString();
return NewSecureTunnelSessionDescription(
CN_SECURE_TUNNEL,
new SecureTunnelContentDescription(description, pem_cert, ""));
}
SessionDescription* SecureTunnelSessionClient::CreateAnswer(
const SessionDescription* offer) {
std::string content_name;
const SecureTunnelContentDescription* offer_tunnel = NULL;
if (!FindSecureTunnelContent(offer, &content_name, &offer_tunnel))
return NULL;
// We are accepting a session request. We need to add our cert, the
// server cert, into the description. The client cert was validated
// in OnIncomingTunnel().
ASSERT(!offer_tunnel->client_pem_certificate.empty());
return NewSecureTunnelSessionDescription(
content_name,
new SecureTunnelContentDescription(
offer_tunnel->description,
offer_tunnel->client_pem_certificate,
GetIdentity().certificate().ToPEMString()));
}
// SecureTunnelSession
SecureTunnelSession::SecureTunnelSession(
SecureTunnelSessionClient* client, Session* session,
rtc::Thread* stream_thread, TunnelSessionRole role)
: TunnelSession(client, session, stream_thread),
role_(role) {
}
rtc::StreamInterface* SecureTunnelSession::MakeSecureStream(
rtc::StreamInterface* stream) {
rtc::SSLStreamAdapter* ssl_stream =
rtc::SSLStreamAdapter::Create(stream);
rtc::SSLIdentity* identity =
static_cast<SecureTunnelSessionClient*>(client_)->
GetIdentity().GetReference();
ssl_stream->SetIdentity(identity);
if (role_ == RESPONDER)
ssl_stream->SetServerRole();
ssl_stream->StartSSLWithPeer();
// SSL negotiation will start on the stream as soon as it
// opens. However our SSLStreamAdapter still hasn't been told what
// certificate to allow for our peer. If we are the initiator, we do
// not have the peer's certificate yet: we will obtain it from the
// session accept message which we will receive later (see
// OnAccept()). We won't Connect() the PseudoTcpChannel until we get
// that, so the stream will stay closed until then. Keep a handle
// on the streem so we can configure the peer certificate later.
ssl_stream_reference_.reset(new rtc::StreamReference(ssl_stream));
return ssl_stream_reference_->NewReference();
}
rtc::StreamInterface* SecureTunnelSession::GetStream() {
ASSERT(channel_ != NULL);
ASSERT(ssl_stream_reference_.get() == NULL);
return MakeSecureStream(channel_->GetStream());
}
void SecureTunnelSession::OnAccept() {
// We have either sent or received a session accept: it's time to
// connect the tunnel. First we must set the peer certificate.
ASSERT(channel_ != NULL);
ASSERT(session_ != NULL);
std::string content_name;
const SecureTunnelContentDescription* remote_tunnel = NULL;
if (!FindSecureTunnelContent(session_->remote_description(),
&content_name, &remote_tunnel)) {
session_->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
return;
}
const std::string& cert_pem =
role_ == INITIATOR ? remote_tunnel->server_pem_certificate :
remote_tunnel->client_pem_certificate;
rtc::scoped_ptr<rtc::SSLCertificate> peer_cert(
ParseCertificate(cert_pem));
if (peer_cert == NULL) {
ASSERT(role_ == INITIATOR); // when RESPONDER we validated it earlier
LOG(LS_ERROR)
<< "Rejecting secure tunnel accept with invalid cetificate";
session_->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
return;
}
ASSERT(ssl_stream_reference_.get() != NULL);
rtc::SSLStreamAdapter* ssl_stream =
static_cast<rtc::SSLStreamAdapter*>(
ssl_stream_reference_->GetStream());
std::string algorithm;
if (!peer_cert->GetSignatureDigestAlgorithm(&algorithm)) {
LOG(LS_ERROR) << "Failed to get the algorithm for the peer cert signature";
return;
}
unsigned char digest[rtc::MessageDigest::kMaxSize];
size_t digest_len;
peer_cert->ComputeDigest(algorithm, digest, ARRAY_SIZE(digest), &digest_len);
ssl_stream->SetPeerCertificateDigest(algorithm, digest, digest_len);
// We no longer need our handle to the ssl stream.
ssl_stream_reference_.reset();
LOG(LS_INFO) << "Connecting tunnel";
// This will try to connect the PseudoTcpChannel. If and when that
// succeeds, then ssl negotiation will take place, and when that
// succeeds, the tunnel stream will finally open.
VERIFY(channel_->Connect(
content_name, "tcp", ICE_CANDIDATE_COMPONENT_DEFAULT));
}
} // namespace cricket

View File

@ -1,165 +0,0 @@
/*
* libjingle
* Copyright 2004--2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// SecureTunnelSessionClient and SecureTunnelSession.
// SecureTunnelSessionClient extends TunnelSessionClient to exchange
// certificates as part of the session description.
// SecureTunnelSession is a TunnelSession that wraps the underlying
// tunnel stream into an SSLStreamAdapter.
#ifndef WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_
#define WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_
#include <string>
#include "webrtc/libjingle/session/tunnel/tunnelsessionclient.h"
#include "webrtc/base/sslidentity.h"
#include "webrtc/base/sslstreamadapter.h"
namespace cricket {
class SecureTunnelSession; // below
// SecureTunnelSessionClient
// This TunnelSessionClient establishes secure tunnels protected by
// SSL/TLS. The PseudoTcpChannel stream is wrapped with an
// SSLStreamAdapter. An SSLIdentity must be set or generated.
//
// The TunnelContentDescription is extended to include the client and
// server certificates. The initiator acts as the client. The session
// initiate stanza carries a description that contains the client's
// certificate, and the session accept response's description has the
// server certificate added to it.
class SecureTunnelSessionClient : public TunnelSessionClient {
public:
// The jid is used as the name for sessions for outgoing tunnels.
// manager is the SessionManager to which we register this client
// and its sessions.
SecureTunnelSessionClient(const buzz::Jid& jid, SessionManager* manager);
// Configures this client to use a preexisting SSLIdentity.
// The client takes ownership of the identity object.
// Use either SetIdentity or GenerateIdentity, and only once.
void SetIdentity(rtc::SSLIdentity* identity);
// Generates an identity from nothing.
// Returns true if generation was successful.
// Use either SetIdentity or GenerateIdentity, and only once.
bool GenerateIdentity();
// Returns our identity for SSL purposes, as either set by
// SetIdentity() or generated by GenerateIdentity(). Call this
// method only after our identity has been successfully established
// by one of those methods.
rtc::SSLIdentity& GetIdentity() const;
// Inherited methods
virtual void OnIncomingTunnel(const buzz::Jid& jid, Session *session);
virtual bool ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error);
virtual bool WriteContent(SignalingProtocol protocol,
const ContentDescription* content,
buzz::XmlElement** elem,
WriteError* error);
virtual SessionDescription* CreateOffer(
const buzz::Jid &jid, const std::string &description);
virtual SessionDescription* CreateAnswer(
const SessionDescription* offer);
protected:
virtual TunnelSession* MakeTunnelSession(
Session* session, rtc::Thread* stream_thread,
TunnelSessionRole role);
private:
// Our identity (key and certificate) for SSL purposes. The
// certificate part will be communicated within the session
// description. The identity will be passed to the SSLStreamAdapter
// and used for SSL authentication.
rtc::scoped_ptr<rtc::SSLIdentity> identity_;
DISALLOW_COPY_AND_ASSIGN(SecureTunnelSessionClient);
};
// SecureTunnelSession:
// A TunnelSession represents one session for one client. It
// provides the actual tunnel stream and handles state changes.
// A SecureTunnelSession is a TunnelSession that wraps the underlying
// tunnel stream into an SSLStreamAdapter.
class SecureTunnelSession : public TunnelSession {
public:
// This TunnelSession will tie together the given client and session.
// stream_thread is passed to the PseudoTCPChannel: it's the thread
// designated to interact with the tunnel stream.
// role is either INITIATOR or RESPONDER, depending on who is
// initiating the session.
SecureTunnelSession(SecureTunnelSessionClient* client, Session* session,
rtc::Thread* stream_thread,
TunnelSessionRole role);
// Returns the stream that implements the actual P2P tunnel.
// This may be called only once. Caller is responsible for freeing
// the returned object.
virtual rtc::StreamInterface* GetStream();
protected:
// Inherited method: callback on accepting a session.
virtual void OnAccept();
// Helper method for GetStream() that Instantiates the
// SSLStreamAdapter to wrap the PseudoTcpChannel's stream, and
// configures it with our identity and role.
rtc::StreamInterface* MakeSecureStream(
rtc::StreamInterface* stream);
// Our role in requesting the tunnel: INITIATOR or
// RESPONDER. Translates to our role in SSL negotiation:
// respectively client or server. Also indicates which slot of the
// SecureTunnelContentDescription our cert goes into: client-cert or
// server-cert respectively.
TunnelSessionRole role_;
// This is the stream representing the usable tunnel endpoint. It's
// a StreamReference wrapping the SSLStreamAdapter instance, which
// further wraps a PseudoTcpChannel::InternalStream. The
// StreamReference is because in the case of CreateTunnel(), the
// stream endpoint is returned early, but we need to keep a handle
// on it so we can setup the peer certificate when we receive it
// later.
rtc::scoped_ptr<rtc::StreamReference> ssl_stream_reference_;
DISALLOW_COPY_AND_ASSIGN(SecureTunnelSession);
};
} // namespace cricket
#endif // WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_

View File

@ -1,432 +0,0 @@
/*
* libjingle
* Copyright 2004--2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pseudotcpchannel.h"
#include "webrtc/p2p/base/constants.h"
#include "webrtc/p2p/base/transportchannel.h"
#include "webrtc/libjingle/xmllite/xmlelement.h"
#include "tunnelsessionclient.h"
#include "webrtc/base/basicdefs.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/common.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/stringutils.h"
namespace cricket {
const char NS_TUNNEL[] = "http://www.google.com/talk/tunnel";
const buzz::StaticQName QN_TUNNEL_DESCRIPTION = { NS_TUNNEL, "description" };
const buzz::StaticQName QN_TUNNEL_TYPE = { NS_TUNNEL, "type" };
const char CN_TUNNEL[] = "tunnel";
enum {
MSG_CLOCK = 1,
MSG_DESTROY,
MSG_TERMINATE,
MSG_EVENT,
MSG_CREATE_TUNNEL,
};
struct EventData : public rtc::MessageData {
int event, error;
EventData(int ev, int err = 0) : event(ev), error(err) { }
};
struct CreateTunnelData : public rtc::MessageData {
buzz::Jid jid;
std::string description;
rtc::Thread* thread;
rtc::StreamInterface* stream;
};
extern const rtc::ConstantLabel SESSION_STATES[];
const rtc::ConstantLabel SESSION_STATES[] = {
KLABEL(Session::STATE_INIT),
KLABEL(Session::STATE_SENTINITIATE),
KLABEL(Session::STATE_RECEIVEDINITIATE),
KLABEL(Session::STATE_SENTACCEPT),
KLABEL(Session::STATE_RECEIVEDACCEPT),
KLABEL(Session::STATE_SENTMODIFY),
KLABEL(Session::STATE_RECEIVEDMODIFY),
KLABEL(Session::STATE_SENTREJECT),
KLABEL(Session::STATE_RECEIVEDREJECT),
KLABEL(Session::STATE_SENTREDIRECT),
KLABEL(Session::STATE_SENTTERMINATE),
KLABEL(Session::STATE_RECEIVEDTERMINATE),
KLABEL(Session::STATE_INPROGRESS),
KLABEL(Session::STATE_DEINIT),
LASTLABEL
};
///////////////////////////////////////////////////////////////////////////////
// TunnelContentDescription
///////////////////////////////////////////////////////////////////////////////
struct TunnelContentDescription : public ContentDescription {
std::string description;
TunnelContentDescription(const std::string& desc) : description(desc) { }
virtual ContentDescription* Copy() const {
return new TunnelContentDescription(*this);
}
};
///////////////////////////////////////////////////////////////////////////////
// TunnelSessionClientBase
///////////////////////////////////////////////////////////////////////////////
TunnelSessionClientBase::TunnelSessionClientBase(const buzz::Jid& jid,
SessionManager* manager, const std::string &ns)
: jid_(jid), session_manager_(manager), namespace_(ns), shutdown_(false) {
session_manager_->AddClient(namespace_, this);
}
TunnelSessionClientBase::~TunnelSessionClientBase() {
shutdown_ = true;
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
it != sessions_.end();
++it) {
Session* session = (*it)->ReleaseSession(true);
session_manager_->DestroySession(session);
}
session_manager_->RemoveClient(namespace_);
}
void TunnelSessionClientBase::OnSessionCreate(Session* session, bool received) {
LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionCreate: received="
<< received;
ASSERT(session_manager_->signaling_thread()->IsCurrent());
if (received)
sessions_.push_back(
MakeTunnelSession(session, rtc::Thread::Current(), RESPONDER));
}
void TunnelSessionClientBase::OnSessionDestroy(Session* session) {
LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionDestroy";
ASSERT(session_manager_->signaling_thread()->IsCurrent());
if (shutdown_)
return;
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
it != sessions_.end();
++it) {
if ((*it)->HasSession(session)) {
VERIFY((*it)->ReleaseSession(false) == session);
sessions_.erase(it);
return;
}
}
}
rtc::StreamInterface* TunnelSessionClientBase::CreateTunnel(
const buzz::Jid& to, const std::string& description) {
// Valid from any thread
CreateTunnelData data;
data.jid = to;
data.description = description;
data.thread = rtc::Thread::Current();
data.stream = NULL;
session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data);
return data.stream;
}
rtc::StreamInterface* TunnelSessionClientBase::AcceptTunnel(
Session* session) {
ASSERT(session_manager_->signaling_thread()->IsCurrent());
TunnelSession* tunnel = NULL;
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
it != sessions_.end();
++it) {
if ((*it)->HasSession(session)) {
tunnel = *it;
break;
}
}
ASSERT(tunnel != NULL);
SessionDescription* answer = CreateAnswer(session->remote_description());
if (answer == NULL)
return NULL;
session->Accept(answer);
return tunnel->GetStream();
}
void TunnelSessionClientBase::DeclineTunnel(Session* session) {
ASSERT(session_manager_->signaling_thread()->IsCurrent());
session->Reject(STR_TERMINATE_DECLINE);
}
void TunnelSessionClientBase::OnMessage(rtc::Message* pmsg) {
if (pmsg->message_id == MSG_CREATE_TUNNEL) {
ASSERT(session_manager_->signaling_thread()->IsCurrent());
CreateTunnelData* data = static_cast<CreateTunnelData*>(pmsg->pdata);
SessionDescription* offer = CreateOffer(data->jid, data->description);
if (offer == NULL) {
return;
}
Session* session = session_manager_->CreateSession(jid_.Str(), namespace_);
TunnelSession* tunnel = MakeTunnelSession(session, data->thread,
INITIATOR);
sessions_.push_back(tunnel);
session->Initiate(data->jid.Str(), offer);
data->stream = tunnel->GetStream();
}
}
TunnelSession* TunnelSessionClientBase::MakeTunnelSession(
Session* session, rtc::Thread* stream_thread,
TunnelSessionRole /*role*/) {
return new TunnelSession(this, session, stream_thread);
}
///////////////////////////////////////////////////////////////////////////////
// TunnelSessionClient
///////////////////////////////////////////////////////////////////////////////
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
SessionManager* manager,
const std::string &ns)
: TunnelSessionClientBase(jid, manager, ns) {
}
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
SessionManager* manager)
: TunnelSessionClientBase(jid, manager, NS_TUNNEL) {
}
TunnelSessionClient::~TunnelSessionClient() {
}
bool TunnelSessionClient::ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error) {
if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) {
*content = new TunnelContentDescription(type_elem->BodyText());
return true;
}
return false;
}
bool TunnelSessionClient::WriteContent(
SignalingProtocol protocol,
const ContentDescription* untyped_content,
buzz::XmlElement** elem, WriteError* error) {
const TunnelContentDescription* content =
static_cast<const TunnelContentDescription*>(untyped_content);
buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true);
buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE);
type_elem->SetBodyText(content->description);
root->AddElement(type_elem);
*elem = root;
return true;
}
SessionDescription* NewTunnelSessionDescription(
const std::string& content_name, ContentDescription* content) {
SessionDescription* sdesc = new SessionDescription();
sdesc->AddContent(content_name, NS_TUNNEL, content);
return sdesc;
}
bool FindTunnelContent(const cricket::SessionDescription* sdesc,
std::string* name,
const TunnelContentDescription** content) {
const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL);
if (cinfo == NULL)
return false;
*name = cinfo->name;
*content = static_cast<const TunnelContentDescription*>(
cinfo->description);
return true;
}
void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
Session *session) {
std::string content_name;
const TunnelContentDescription* content = NULL;
if (!FindTunnelContent(session->remote_description(),
&content_name, &content)) {
session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
return;
}
SignalIncomingTunnel(this, jid, content->description, session);
}
SessionDescription* TunnelSessionClient::CreateOffer(
const buzz::Jid &jid, const std::string &description) {
SessionDescription* offer = NewTunnelSessionDescription(
CN_TUNNEL, new TunnelContentDescription(description));
rtc::scoped_ptr<TransportDescription> tdesc(
session_manager_->transport_desc_factory()->CreateOffer(
TransportOptions(), NULL));
if (tdesc.get()) {
offer->AddTransportInfo(TransportInfo(CN_TUNNEL, *tdesc));
} else {
delete offer;
offer = NULL;
}
return offer;
}
SessionDescription* TunnelSessionClient::CreateAnswer(
const SessionDescription* offer) {
std::string content_name;
const TunnelContentDescription* offer_tunnel = NULL;
if (!FindTunnelContent(offer, &content_name, &offer_tunnel))
return NULL;
SessionDescription* answer = NewTunnelSessionDescription(
content_name, new TunnelContentDescription(offer_tunnel->description));
const TransportInfo* tinfo = offer->GetTransportInfoByName(content_name);
if (tinfo) {
const TransportDescription* offer_tdesc = &tinfo->description;
ASSERT(offer_tdesc != NULL);
rtc::scoped_ptr<TransportDescription> tdesc(
session_manager_->transport_desc_factory()->CreateAnswer(
offer_tdesc, TransportOptions(), NULL));
if (tdesc.get()) {
answer->AddTransportInfo(TransportInfo(content_name, *tdesc));
} else {
delete answer;
answer = NULL;
}
}
return answer;
}
///////////////////////////////////////////////////////////////////////////////
// TunnelSession
///////////////////////////////////////////////////////////////////////////////
//
// Signalling thread methods
//
TunnelSession::TunnelSession(TunnelSessionClientBase* client, Session* session,
rtc::Thread* stream_thread)
: client_(client), session_(session), channel_(NULL) {
ASSERT(client_ != NULL);
ASSERT(session_ != NULL);
session_->SignalState.connect(this, &TunnelSession::OnSessionState);
channel_ = new PseudoTcpChannel(stream_thread, session_);
channel_->SignalChannelClosed.connect(this, &TunnelSession::OnChannelClosed);
}
TunnelSession::~TunnelSession() {
ASSERT(client_ != NULL);
ASSERT(session_ == NULL);
ASSERT(channel_ == NULL);
}
rtc::StreamInterface* TunnelSession::GetStream() {
ASSERT(channel_ != NULL);
return channel_->GetStream();
}
bool TunnelSession::HasSession(Session* session) {
ASSERT(NULL != session_);
return (session_ == session);
}
Session* TunnelSession::ReleaseSession(bool channel_exists) {
ASSERT(NULL != session_);
ASSERT(NULL != channel_);
Session* session = session_;
session_->SignalState.disconnect(this);
session_ = NULL;
if (channel_exists)
channel_->SignalChannelClosed.disconnect(this);
channel_ = NULL;
delete this;
return session;
}
void TunnelSession::OnSessionState(BaseSession* session,
BaseSession::State state) {
LOG(LS_INFO) << "TunnelSession::OnSessionState("
<< rtc::nonnull(
rtc::FindLabel(state, SESSION_STATES), "Unknown")
<< ")";
ASSERT(session == session_);
switch (state) {
case Session::STATE_RECEIVEDINITIATE:
OnInitiate();
break;
case Session::STATE_SENTACCEPT:
case Session::STATE_RECEIVEDACCEPT:
OnAccept();
break;
case Session::STATE_SENTTERMINATE:
case Session::STATE_RECEIVEDTERMINATE:
OnTerminate();
break;
case Session::STATE_DEINIT:
// ReleaseSession should have been called before this.
ASSERT(false);
break;
default:
break;
}
}
void TunnelSession::OnInitiate() {
ASSERT(client_ != NULL);
ASSERT(session_ != NULL);
client_->OnIncomingTunnel(buzz::Jid(session_->remote_name()), session_);
}
void TunnelSession::OnAccept() {
ASSERT(channel_ != NULL);
const ContentInfo* content =
session_->remote_description()->FirstContentByType(NS_TUNNEL);
ASSERT(content != NULL);
VERIFY(channel_->Connect(
content->name, "tcp", ICE_CANDIDATE_COMPONENT_DEFAULT));
}
void TunnelSession::OnTerminate() {
ASSERT(channel_ != NULL);
channel_->OnSessionTerminate(session_);
}
void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) {
ASSERT(channel_ == channel);
ASSERT(session_ != NULL);
session_->Terminate();
}
///////////////////////////////////////////////////////////////////////////////
} // namespace cricket

View File

@ -1,182 +0,0 @@
/*
* libjingle
* Copyright 2004--2008, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TUNNELSESSIONCLIENT_H__
#define __TUNNELSESSIONCLIENT_H__
#include <vector>
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/stream.h"
#include "webrtc/libjingle/session/sessionclient.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/xmllite/qname.h"
#include "webrtc/libjingle/xmpp/constants.h"
#include "webrtc/p2p/base/constants.h"
#include "webrtc/p2p/base/pseudotcp.h"
#include "webrtc/p2p/base/session.h"
#include "webrtc/p2p/base/sessiondescription.h"
namespace cricket {
class TunnelSession;
class TunnelStream;
enum TunnelSessionRole { INITIATOR, RESPONDER };
///////////////////////////////////////////////////////////////////////////////
// TunnelSessionClient
///////////////////////////////////////////////////////////////////////////////
// Base class is still abstract
class TunnelSessionClientBase
: public SessionClient, public rtc::MessageHandler {
public:
TunnelSessionClientBase(const buzz::Jid& jid, SessionManager* manager,
const std::string &ns);
virtual ~TunnelSessionClientBase();
const buzz::Jid& jid() const { return jid_; }
SessionManager* session_manager() const { return session_manager_; }
void OnSessionCreate(Session* session, bool received);
void OnSessionDestroy(Session* session);
// This can be called on any thread. The stream interface is
// thread-safe, but notifications must be registered on the creating
// thread.
rtc::StreamInterface* CreateTunnel(const buzz::Jid& to,
const std::string& description);
rtc::StreamInterface* AcceptTunnel(Session* session);
void DeclineTunnel(Session* session);
// Invoked on an incoming tunnel
virtual void OnIncomingTunnel(const buzz::Jid &jid, Session *session) = 0;
// Invoked on an outgoing session request
virtual SessionDescription* CreateOffer(
const buzz::Jid &jid, const std::string &description) = 0;
// Invoked on a session request accept to create
// the local-side session description
virtual SessionDescription* CreateAnswer(
const SessionDescription* offer) = 0;
protected:
void OnMessage(rtc::Message* pmsg);
// helper method to instantiate TunnelSession. By overriding this,
// subclasses of TunnelSessionClient are able to instantiate
// subclasses of TunnelSession instead.
virtual TunnelSession* MakeTunnelSession(Session* session,
rtc::Thread* stream_thread,
TunnelSessionRole role);
buzz::Jid jid_;
SessionManager* session_manager_;
std::vector<TunnelSession*> sessions_;
std::string namespace_;
bool shutdown_;
};
class TunnelSessionClient
: public TunnelSessionClientBase, public sigslot::has_slots<> {
public:
TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager);
TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager,
const std::string &ns);
virtual ~TunnelSessionClient();
virtual bool ParseContent(SignalingProtocol protocol,
const buzz::XmlElement* elem,
ContentDescription** content,
ParseError* error);
virtual bool WriteContent(SignalingProtocol protocol,
const ContentDescription* content,
buzz::XmlElement** elem,
WriteError* error);
// Signal arguments are this, initiator, description, session
sigslot::signal4<TunnelSessionClient*, buzz::Jid, std::string, Session*>
SignalIncomingTunnel;
virtual void OnIncomingTunnel(const buzz::Jid &jid,
Session *session);
virtual SessionDescription* CreateOffer(
const buzz::Jid &jid, const std::string &description);
virtual SessionDescription* CreateAnswer(
const SessionDescription* offer);
};
///////////////////////////////////////////////////////////////////////////////
// TunnelSession
// Note: The lifetime of TunnelSession is complicated. It needs to survive
// until the following three conditions are true:
// 1) TunnelStream has called Close (tracked via non-null stream_)
// 2) PseudoTcp has completed (tracked via non-null tcp_)
// 3) Session has been destroyed (tracked via non-null session_)
// This is accomplished by calling CheckDestroy after these indicators change.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// TunnelStream
// Note: Because TunnelStream provides a stream interface, its lifetime is
// controlled by the owner of the stream pointer. As a result, we must support
// both the TunnelSession disappearing before TunnelStream, and vice versa.
///////////////////////////////////////////////////////////////////////////////
class PseudoTcpChannel;
class TunnelSession : public sigslot::has_slots<> {
public:
// Signalling thread methods
TunnelSession(TunnelSessionClientBase* client, Session* session,
rtc::Thread* stream_thread);
virtual rtc::StreamInterface* GetStream();
bool HasSession(Session* session);
Session* ReleaseSession(bool channel_exists);
protected:
virtual ~TunnelSession();
virtual void OnSessionState(BaseSession* session, BaseSession::State state);
virtual void OnInitiate();
virtual void OnAccept();
virtual void OnTerminate();
virtual void OnChannelClosed(PseudoTcpChannel* channel);
TunnelSessionClientBase* client_;
Session* session_;
PseudoTcpChannel* channel_;
};
///////////////////////////////////////////////////////////////////////////////
} // namespace cricket
#endif // __TUNNELSESSIONCLIENT_H__

View File

@ -1,226 +0,0 @@
/*
* libjingle
* Copyright 2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string>
#include "webrtc/base/gunit.h"
#include "webrtc/base/messagehandler.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/stream.h"
#include "webrtc/base/thread.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/libjingle/session/sessionmanager.h"
#include "webrtc/libjingle/session/tunnel/tunnelsessionclient.h"
#include "webrtc/p2p/base/transport.h"
#include "webrtc/p2p/client/fakeportallocator.h"
static const int kTimeoutMs = 10000;
static const int kBlockSize = 4096;
static const buzz::Jid kLocalJid("local@localhost");
static const buzz::Jid kRemoteJid("remote@localhost");
// This test fixture creates the necessary plumbing to create and run
// two TunnelSessionClients that talk to each other.
class TunnelSessionClientTest : public testing::Test,
public rtc::MessageHandler,
public sigslot::has_slots<> {
public:
TunnelSessionClientTest()
: local_pa_(rtc::Thread::Current(), NULL),
remote_pa_(rtc::Thread::Current(), NULL),
local_sm_(&local_pa_, rtc::Thread::Current()),
remote_sm_(&remote_pa_, rtc::Thread::Current()),
local_client_(kLocalJid, &local_sm_),
remote_client_(kRemoteJid, &remote_sm_),
done_(false) {
local_sm_.SignalRequestSignaling.connect(this,
&TunnelSessionClientTest::OnLocalRequestSignaling);
local_sm_.SignalOutgoingMessage.connect(this,
&TunnelSessionClientTest::OnOutgoingMessage);
remote_sm_.SignalRequestSignaling.connect(this,
&TunnelSessionClientTest::OnRemoteRequestSignaling);
remote_sm_.SignalOutgoingMessage.connect(this,
&TunnelSessionClientTest::OnOutgoingMessage);
remote_client_.SignalIncomingTunnel.connect(this,
&TunnelSessionClientTest::OnIncomingTunnel);
}
// Transfer the desired amount of data from the local to the remote client.
void TestTransfer(int size) {
// Create some dummy data to send.
send_stream_.ReserveSize(size);
for (int i = 0; i < size; ++i) {
char ch = static_cast<char>(i);
send_stream_.Write(&ch, 1, NULL, NULL);
}
send_stream_.Rewind();
// Prepare the receive stream.
recv_stream_.ReserveSize(size);
// Create the tunnel and set things in motion.
local_tunnel_.reset(local_client_.CreateTunnel(kRemoteJid, "test"));
local_tunnel_->SignalEvent.connect(this,
&TunnelSessionClientTest::OnStreamEvent);
EXPECT_TRUE_WAIT(done_, kTimeoutMs);
// Make sure we received the right data.
EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(),
recv_stream_.GetBuffer(), size));
}
private:
enum { MSG_LSIGNAL, MSG_RSIGNAL };
// There's no SessionManager* argument in this callback, so we need 2 of them.
void OnLocalRequestSignaling() {
local_sm_.OnSignalingReady();
}
void OnRemoteRequestSignaling() {
remote_sm_.OnSignalingReady();
}
// Post a message, to avoid problems with directly connecting the callbacks.
void OnOutgoingMessage(cricket::SessionManager* manager,
const buzz::XmlElement* stanza) {
if (manager == &local_sm_) {
rtc::Thread::Current()->Post(this, MSG_LSIGNAL,
rtc::WrapMessageData(*stanza));
} else if (manager == &remote_sm_) {
rtc::Thread::Current()->Post(this, MSG_RSIGNAL,
rtc::WrapMessageData(*stanza));
}
}
// Need to add a "from=" attribute (normally added by the server)
// Then route the incoming signaling message to the "other" session manager.
virtual void OnMessage(rtc::Message* message) {
rtc::TypedMessageData<buzz::XmlElement>* data =
static_cast<rtc::TypedMessageData<buzz::XmlElement>*>(
message->pdata);
bool response = data->data().Attr(buzz::QN_TYPE) == buzz::STR_RESULT;
if (message->message_id == MSG_RSIGNAL) {
data->data().AddAttr(buzz::QN_FROM, remote_client_.jid().Str());
if (!response) {
local_sm_.OnIncomingMessage(&data->data());
} else {
local_sm_.OnIncomingResponse(NULL, &data->data());
}
} else if (message->message_id == MSG_LSIGNAL) {
data->data().AddAttr(buzz::QN_FROM, local_client_.jid().Str());
if (!response) {
remote_sm_.OnIncomingMessage(&data->data());
} else {
remote_sm_.OnIncomingResponse(NULL, &data->data());
}
}
delete data;
}
// Accept the tunnel when it arrives and wire up the stream.
void OnIncomingTunnel(cricket::TunnelSessionClient* client,
buzz::Jid jid, std::string description,
cricket::Session* session) {
remote_tunnel_.reset(remote_client_.AcceptTunnel(session));
remote_tunnel_->SignalEvent.connect(this,
&TunnelSessionClientTest::OnStreamEvent);
}
// Send from send_stream_ as long as we're not flow-controlled.
// Read bytes out into recv_stream_ as they arrive.
// End the test when we are notified that the local side has closed the
// tunnel. All data has been read out at this point.
void OnStreamEvent(rtc::StreamInterface* stream, int events,
int error) {
if (events & rtc::SE_READ) {
if (stream == remote_tunnel_.get()) {
ReadData();
}
}
if (events & rtc::SE_WRITE) {
if (stream == local_tunnel_.get()) {
bool done = false;
WriteData(&done);
if (done) {
local_tunnel_->Close();
}
}
}
if (events & rtc::SE_CLOSE) {
if (stream == remote_tunnel_.get()) {
remote_tunnel_->Close();
done_ = true;
}
}
}
// Spool from the tunnel into recv_stream.
// Flow() doesn't work here because it won't write if the read blocks.
void ReadData() {
char block[kBlockSize];
size_t read, position;
rtc::StreamResult res;
while ((res = remote_tunnel_->Read(block, sizeof(block), &read, NULL)) ==
rtc::SR_SUCCESS) {
recv_stream_.Write(block, read, NULL, NULL);
}
ASSERT(res != rtc::SR_EOS);
recv_stream_.GetPosition(&position);
LOG(LS_VERBOSE) << "Recv position: " << position;
}
// Spool from send_stream into the tunnel. Back up if we get flow controlled.
void WriteData(bool* done) {
char block[kBlockSize];
size_t leftover = 0, position;
rtc::StreamResult res = rtc::Flow(&send_stream_,
block, sizeof(block), local_tunnel_.get(), &leftover);
if (res == rtc::SR_BLOCK) {
send_stream_.GetPosition(&position);
send_stream_.SetPosition(position - leftover);
LOG(LS_VERBOSE) << "Send position: " << position - leftover;
*done = false;
} else if (res == rtc::SR_SUCCESS) {
*done = true;
} else {
ASSERT(false); // shouldn't happen
}
}
private:
cricket::FakePortAllocator local_pa_;
cricket::FakePortAllocator remote_pa_;
cricket::SessionManager local_sm_;
cricket::SessionManager remote_sm_;
cricket::TunnelSessionClient local_client_;
cricket::TunnelSessionClient remote_client_;
rtc::scoped_ptr<rtc::StreamInterface> local_tunnel_;
rtc::scoped_ptr<rtc::StreamInterface> remote_tunnel_;
rtc::MemoryStream send_stream_;
rtc::MemoryStream recv_stream_;
bool done_;
};
// Test the normal case of sending data from one side to the other.
TEST_F(TunnelSessionClientTest, TestTransfer) {
TestTransfer(1000000);
}