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:
parent
36b7cc3264
commit
f5642913c9
@ -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>
|
||||
|
@ -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;
|
||||
}
|
@ -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
@ -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_
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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_
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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"
|
||||
],
|
||||
}
|
||||
|
@ -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
|
@ -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
@ -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_
|
@ -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
|
@ -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_
|
@ -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
@ -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
@ -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
|
@ -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_
|
@ -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
|
@ -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_
|
@ -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)
|
@ -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
@ -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
@ -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_
|
@ -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
@ -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_
|
@ -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_
|
@ -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
|
@ -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_
|
@ -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));
|
||||
}
|
@ -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
|
@ -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_
|
@ -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
|
@ -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_
|
@ -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
|
@ -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__
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user