3
* Copyright 2004--2005, Google Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
8
* 1. Redistributions of source code must retain the above copyright notice,
9
* this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
13
* 3. The name of the author may not be used to endorse or promote products
14
* derived from this software without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
#include "talk/base/flags.h"
36
#include "talk/base/logging.h"
38
#include "talk/base/macsocketserver.h"
40
#include "talk/base/pathutils.h"
41
#include "talk/base/stream.h"
42
#include "talk/base/ssladapter.h"
43
#include "talk/base/win32socketserver.h"
44
#include "talk/examples/login/xmppthread.h"
45
#include "talk/examples/login/xmppauth.h"
46
#include "talk/examples/login/xmpppump.h"
47
#include "talk/examples/call/callclient.h"
48
#include "talk/examples/call/console.h"
49
#include "talk/examples/call/mediaenginefactory.h"
50
#include "talk/p2p/base/constants.h"
52
#include "talk/session/phone/androidmediaengine.h"
54
#include "talk/session/phone/mediasessionclient.h"
55
#include "talk/session/phone/srtpfilter.h"
56
#include "talk/xmpp/xmppclientsettings.h"
58
class DebugLog : public sigslot::has_slots<> {
61
debug_input_buf_(NULL), debug_input_len_(0), debug_input_alloc_(0),
62
debug_output_buf_(NULL), debug_output_len_(0), debug_output_alloc_(0),
63
censor_password_(false)
65
char * debug_input_buf_;
67
int debug_input_alloc_;
68
char * debug_output_buf_;
69
int debug_output_len_;
70
int debug_output_alloc_;
71
bool censor_password_;
73
void Input(const char * data, int len) {
74
if (debug_input_len_ + len > debug_input_alloc_) {
75
char * old_buf = debug_input_buf_;
76
debug_input_alloc_ = 4096;
77
while (debug_input_alloc_ < debug_input_len_ + len) {
78
debug_input_alloc_ *= 2;
80
debug_input_buf_ = new char[debug_input_alloc_];
81
memcpy(debug_input_buf_, old_buf, debug_input_len_);
84
memcpy(debug_input_buf_ + debug_input_len_, data, len);
85
debug_input_len_ += len;
86
DebugPrint(debug_input_buf_, &debug_input_len_, false);
89
void Output(const char * data, int len) {
90
if (debug_output_len_ + len > debug_output_alloc_) {
91
char * old_buf = debug_output_buf_;
92
debug_output_alloc_ = 4096;
93
while (debug_output_alloc_ < debug_output_len_ + len) {
94
debug_output_alloc_ *= 2;
96
debug_output_buf_ = new char[debug_output_alloc_];
97
memcpy(debug_output_buf_, old_buf, debug_output_len_);
100
memcpy(debug_output_buf_ + debug_output_len_, data, len);
101
debug_output_len_ += len;
102
DebugPrint(debug_output_buf_, &debug_output_len_, true);
105
static bool IsAuthTag(const char * str, size_t len) {
106
if (str[0] == '<' && str[1] == 'a' &&
111
std::string tag(str, len);
113
if (tag.find("mechanism") != std::string::npos)
119
void DebugPrint(char * buf, int * plen, bool output) {
122
time_t tim = time(NULL);
123
struct tm * now = localtime(&tim);
124
char *time_string = asctime(now);
126
size_t time_len = strlen(time_string);
128
time_string[time_len-1] = 0; // trim off terminating \n
131
LOG(INFO) << (output ? "SEND >>>>>>>>>>>>>>>>" : "RECV <<<<<<<<<<<<<<<<")
132
<< " : " << time_string;
135
int start = 0, nest = 3;
136
for (int i = 0; i < len; i += 1) {
138
if ((i > 0) && (buf[i-1] == '/')) {
140
} else if ((start + 1 < len) && (buf[start + 1] == '/')) {
148
LOG(INFO) << std::setw(nest) << " "
149
<< std::string(buf + start, i + 1 - start);
154
// Note if it's a PLAIN auth tag
155
if (IsAuthTag(buf + start, i + 1 - start)) {
156
censor_password_ = true;
163
if (buf[i] == '<' && start < i) {
164
if (censor_password_) {
165
LOG(INFO) << std::setw(nest) << " " << "## TEXT REMOVED ##";
166
censor_password_ = false;
168
LOG(INFO) << std::setw(nest) << " "
169
<< std::string(buf + start, i - start);
175
memcpy(buf, buf + start, len);
181
static DebugLog debug_log_;
182
static const int DEFAULT_PORT = 5222;
185
static std::vector<cricket::AudioCodec> codecs;
186
static const cricket::AudioCodec ISAC(103, "ISAC", 40000, 16000, 1, 0);
188
cricket::MediaEngine *AndroidMediaEngineFactory() {
189
cricket::FakeMediaEngine *engine = new cricket::FakeMediaEngine();
191
codecs.push_back(ISAC);
192
engine->SetAudioCodecs(codecs);
197
// TODO: Move this into Console.
198
void Print(const char* chars) {
203
bool SSLVerificationCallback(void* cert) {
207
int main(int argc, char **argv) {
208
// This app has three threads. The main thread will run the XMPP client,
209
// which will print to the screen in its own thread. A second thread
210
// will get input from the console, parse it, and pass the appropriate
211
// message back to the XMPP client's thread. A third thread is used
212
// by MediaSessionClient as its worker thread.
215
DEFINE_bool(a, false, "Turn on auto accept.");
216
DEFINE_bool(d, false, "Turn on debugging.");
217
DEFINE_string(protocol, "hybrid",
218
"Initial signaling protocol to use: jingle, gingle, or hybrid.");
219
DEFINE_string(secure, "enable",
220
"Disable or enable encryption: disable, enable, require.");
221
DEFINE_string(tls, "enable",
222
"Disable or enable tls: disable, enable, require.");
223
DEFINE_bool(allowplain, false, "Allow plain authentication");
224
DEFINE_bool(testserver, false, "Use test server");
225
DEFINE_int(portallocator, 0, "Filter out unwanted connection types.");
226
DEFINE_string(filterhost, NULL, "Filter out the host from all candidates.");
227
DEFINE_string(pmuc, "groupchat.google.com", "The persistant muc domain.");
228
DEFINE_string(s, "talk.google.com", "The connection server to use.");
229
DEFINE_string(capsnode, "http://code.google.com/p/libjingle/call",
230
"Caps node: A URI identifying the app.");
231
DEFINE_string(capsver, "0.6",
232
"Caps ver: A string identifying the version of the app.");
233
DEFINE_string(voiceinput, NULL, "RTP dump file for voice input.");
234
DEFINE_string(voiceoutput, NULL, "RTP dump file for voice output.");
235
DEFINE_string(videoinput, NULL, "RTP dump file for video input.");
236
DEFINE_string(videooutput, NULL, "RTP dump file for video output.");
237
DEFINE_bool(render, true, "Renders the video.");
238
DEFINE_bool(datachannel, false, "Enable an RTP data channel.");
239
DEFINE_bool(debugsrtp, false, "Enable debugging for srtp.");
240
DEFINE_bool(help, false, "Prints this message");
243
FlagList::SetFlagsFromCommandLine(&argc, argv, true);
245
FlagList::Print(NULL, false);
249
bool auto_accept = FLAG_a;
251
std::string protocol = FLAG_protocol;
252
bool test_server = FLAG_testserver;
253
bool allow_plain = FLAG_allowplain;
254
std::string tls = FLAG_tls;
255
int32 portallocator_flags = FLAG_portallocator;
256
std::string pmuc_domain = FLAG_pmuc;
257
std::string server = FLAG_s;
258
std::string secure = FLAG_secure;
259
std::string caps_node = FLAG_capsnode;
260
std::string caps_ver = FLAG_capsver;
261
bool debugsrtp = FLAG_debugsrtp;
262
bool render = FLAG_render;
263
bool data_channel_enabled = FLAG_datachannel;
266
cricket::EnableSrtpDebugging();
269
cricket::SignalingProtocol initial_protocol = cricket::PROTOCOL_HYBRID;
270
if (protocol == "jingle") {
271
initial_protocol = cricket::PROTOCOL_JINGLE;
272
} else if (protocol == "gingle") {
273
initial_protocol = cricket::PROTOCOL_GINGLE;
274
} else if (protocol == "hybrid") {
275
initial_protocol = cricket::PROTOCOL_HYBRID;
277
Print("Invalid protocol. Must be jingle, gingle, or hybrid.\n");
281
cricket::SecureMediaPolicy secure_policy = cricket::SEC_ENABLED;
282
if (secure == "disable") {
283
secure_policy = cricket::SEC_DISABLED;
284
} else if (secure == "enable") {
285
secure_policy = cricket::SEC_ENABLED;
286
} else if (secure == "require") {
287
secure_policy = cricket::SEC_REQUIRED;
289
Print("Invalid encryption. Must be enable, disable, or require.\n");
293
// parse username and password, if present
295
std::string username;
296
talk_base::InsecureCryptStringImpl pass;
300
pass.password() = argv[2];
305
talk_base::LogMessage::LogToDebug(talk_base::LS_VERBOSE);
307
if (username.empty()) {
309
std::cin >> username;
311
if (username.find('@') == std::string::npos) {
312
username.append("@localhost");
314
jid = buzz::Jid(username);
315
if (!jid.IsValid() || jid.node() == "") {
316
Print("Invalid JID. JIDs should be in the form user@domain\n");
319
if (pass.password().empty() && !test_server) {
320
Console::SetEcho(false);
322
std::cin >> pass.password();
323
Console::SetEcho(true);
327
buzz::XmppClientSettings xcs;
328
xcs.set_user(jid.node());
329
xcs.set_resource("call");
330
xcs.set_host(jid.domain());
331
xcs.set_allow_plain(allow_plain);
333
if(tls == "disable") {
334
xcs.set_use_tls(buzz::TLS_DISABLED);
335
} else if (tls == "enable") {
336
xcs.set_use_tls(buzz::TLS_ENABLED);
337
} else if (tls == "require") {
338
xcs.set_use_tls(buzz::TLS_REQUIRED);
340
Print("Invalid TLS option, must be enable, disable, or require.\n");
345
pass.password() = jid.node();
346
xcs.set_allow_plain(true);
347
xcs.set_use_tls(buzz::TLS_DISABLED);
348
xcs.set_test_server_domain("google.com");
350
xcs.set_pass(talk_base::CryptString(pass));
355
int colon = server.find(':');
360
host = server.substr(0, colon);
361
port = atoi(server.substr(colon + 1).c_str());
364
xcs.set_server(talk_base::SocketAddress(host, port));
365
Print(("Logging in to " + server + " as " + jid.Str() + "\n").c_str());
367
talk_base::InitializeSSL(SSLVerificationCallback);
370
InitAndroidMediaEngineFactory(AndroidMediaEngineFactory);
374
// Need to pump messages on our main thread on Windows.
375
talk_base::Win32Thread w32_thread;
376
talk_base::ThreadManager::Instance()->SetCurrentThread(&w32_thread);
378
talk_base::Thread* main_thread = talk_base::Thread::Current();
380
talk_base::MacCarbonAppSocketServer ss;
381
talk_base::SocketServerScope ss_scope(&ss);
385
CallClient *client = new CallClient(pump.client(), caps_node, caps_ver);
387
if (FLAG_voiceinput || FLAG_voiceoutput ||
388
FLAG_videoinput || FLAG_videooutput) {
389
// If any dump file is specified, we use a FileMediaEngine.
390
cricket::MediaEngineInterface* engine =
391
MediaEngineFactory::CreateFileMediaEngine(
392
FLAG_voiceinput, FLAG_voiceoutput,
393
FLAG_videoinput, FLAG_videooutput);
394
client->SetMediaEngine(engine);
397
Console *console = new Console(main_thread, client);
398
client->SetConsole(console);
399
client->SetAutoAccept(auto_accept);
400
client->SetPmucDomain(pmuc_domain);
401
client->SetPortAllocatorFlags(portallocator_flags);
402
client->SetAllowLocalIps(true);
403
client->SetInitialProtocol(initial_protocol);
404
client->SetSecurePolicy(secure_policy);
405
client->SetRender(render);
406
client->SetDataChannelEnabled(data_channel_enabled);
410
pump.client()->SignalLogInput.connect(&debug_log_, &DebugLog::Input);
411
pump.client()->SignalLogOutput.connect(&debug_log_, &DebugLog::Output);
414
pump.DoLogin(xcs, new XmppSocket(buzz::TLS_REQUIRED), NULL);