summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-03 01:19:53 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-03 01:19:53 +0000
commit97f2db27a730693ac0711894dcff741c1b1451a3 (patch)
treef0190c3eceeb38ade4856272b50c6d195f1ffe1d /third_party
parentde5834cf1962af5607b459731f8960cfd3baa4c2 (diff)
downloadchromium_src-97f2db27a730693ac0711894dcff741c1b1451a3.zip
chromium_src-97f2db27a730693ac0711894dcff741c1b1451a3.tar.gz
chromium_src-97f2db27a730693ac0711894dcff741c1b1451a3.tar.bz2
Revert 48798 - New libjingle integrated to chrome.
BUG=none TEST=Chrome Sync works Review URL: http://codereview.chromium.org/2255007 TBR=sergeyu@chromium.org git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48800 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
-rw-r--r--third_party/libjingle/README.chromium43
-rw-r--r--third_party/libjingle/files/AUTHORS1
-rw-r--r--third_party/libjingle/files/COPYING25
-rw-r--r--third_party/libjingle/files/ChangeLog13
-rw-r--r--third_party/libjingle/files/DOCUMENTATION1
-rw-r--r--third_party/libjingle/files/INSTALL229
-rw-r--r--third_party/libjingle/files/Makefile.am8
-rw-r--r--third_party/libjingle/files/NEWS15
-rw-r--r--third_party/libjingle/files/README57
-rw-r--r--third_party/libjingle/files/README.win24
-rw-r--r--third_party/libjingle/files/config.h113
-rw-r--r--third_party/libjingle/files/configure.ac182
-rw-r--r--third_party/libjingle/files/talk/Makefile.am3
-rw-r--r--third_party/libjingle/files/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h55
-rw-r--r--third_party/libjingle/files/talk/base/Makefile.am152
-rw-r--r--third_party/libjingle/files/talk/base/asyncfile.h56
-rw-r--r--third_party/libjingle/files/talk/base/asynchttprequest.cc161
-rw-r--r--third_party/libjingle/files/talk/base/asynchttprequest.h147
-rw-r--r--third_party/libjingle/files/talk/base/asyncpacketsocket.cc84
-rw-r--r--third_party/libjingle/files/talk/base/asyncpacketsocket.h63
-rw-r--r--third_party/libjingle/files/talk/base/asyncsocket.h91
-rw-r--r--third_party/libjingle/files/talk/base/asynctcpsocket.cc202
-rw-r--r--third_party/libjingle/files/talk/base/asynctcpsocket.h68
-rw-r--r--third_party/libjingle/files/talk/base/asyncudpsocket.cc85
-rw-r--r--third_party/libjingle/files/talk/base/asyncudpsocket.h59
-rw-r--r--third_party/libjingle/files/talk/base/autodetectproxy.cc178
-rw-r--r--third_party/libjingle/files/talk/base/autodetectproxy.h68
-rw-r--r--third_party/libjingle/files/talk/base/base64.cc196
-rw-r--r--third_party/libjingle/files/talk/base/base64.h32
-rw-r--r--third_party/libjingle/files/talk/base/basicdefs.h37
-rw-r--r--third_party/libjingle/files/talk/base/basictypes.h85
-rw-r--r--third_party/libjingle/files/talk/base/bytebuffer.cc166
-rw-r--r--third_party/libjingle/files/talk/base/bytebuffer.h71
-rw-r--r--third_party/libjingle/files/talk/base/byteorder.h63
-rw-r--r--third_party/libjingle/files/talk/base/common.cc62
-rw-r--r--third_party/libjingle/files/talk/base/common.h114
-rw-r--r--third_party/libjingle/files/talk/base/convert.h149
-rw-r--r--third_party/libjingle/files/talk/base/criticalsection.h133
-rw-r--r--third_party/libjingle/files/talk/base/cryptstring.h186
-rw-r--r--third_party/libjingle/files/talk/base/diskcache.cc362
-rw-r--r--third_party/libjingle/files/talk/base/diskcache.h142
-rw-r--r--third_party/libjingle/files/talk/base/diskcache_win32.cc76
-rw-r--r--third_party/libjingle/files/talk/base/diskcache_win32.h28
-rw-r--r--third_party/libjingle/files/talk/base/diskcachestd.cc30
-rw-r--r--third_party/libjingle/files/talk/base/diskcachestd.h28
-rw-r--r--third_party/libjingle/files/talk/base/event.h79
-rw-r--r--third_party/libjingle/files/talk/base/fileutils.cc273
-rw-r--r--third_party/libjingle/files/talk/base/fileutils.h185
-rw-r--r--third_party/libjingle/files/talk/base/firewallsocketserver.cc213
-rw-r--r--third_party/libjingle/files/talk/base/firewallsocketserver.h95
-rw-r--r--third_party/libjingle/files/talk/base/helpers.cc149
-rw-r--r--third_party/libjingle/files/talk/base/helpers.h55
-rw-r--r--third_party/libjingle/files/talk/base/host.cc101
-rw-r--r--third_party/libjingle/files/talk/base/host.h59
-rw-r--r--third_party/libjingle/files/talk/base/httpbase.cc591
-rw-r--r--third_party/libjingle/files/talk/base/httpbase.h142
-rw-r--r--third_party/libjingle/files/talk/base/httpclient.cc716
-rw-r--r--third_party/libjingle/files/talk/base/httpclient.h155
-rw-r--r--third_party/libjingle/files/talk/base/httpcommon-inl.h114
-rw-r--r--third_party/libjingle/files/talk/base/httpcommon.cc940
-rw-r--r--third_party/libjingle/files/talk/base/httpcommon.h373
-rw-r--r--third_party/libjingle/files/talk/base/httpserver.cc261
-rw-r--r--third_party/libjingle/files/talk/base/httpserver.h143
-rw-r--r--third_party/libjingle/files/talk/base/linked_ptr.h115
-rw-r--r--third_party/libjingle/files/talk/base/logging.cc350
-rw-r--r--third_party/libjingle/files/talk/base/logging.h (renamed from third_party/libjingle/overrides/talk/base/logging.h)235
-rw-r--r--third_party/libjingle/files/talk/base/md5.h45
-rw-r--r--third_party/libjingle/files/talk/base/md5c.c256
-rw-r--r--third_party/libjingle/files/talk/base/messagequeue.cc359
-rw-r--r--third_party/libjingle/files/talk/base/messagequeue.h213
-rw-r--r--third_party/libjingle/files/talk/base/nat_unittest.cc223
-rw-r--r--third_party/libjingle/files/talk/base/natserver.cc211
-rw-r--r--third_party/libjingle/files/talk/base/natserver.h114
-rw-r--r--third_party/libjingle/files/talk/base/natserver_main.cc57
-rw-r--r--third_party/libjingle/files/talk/base/natsocketfactory.cc229
-rw-r--r--third_party/libjingle/files/talk/base/natsocketfactory.h51
-rw-r--r--third_party/libjingle/files/talk/base/nattypes.cc72
-rw-r--r--third_party/libjingle/files/talk/base/nattypes.h62
-rw-r--r--third_party/libjingle/files/talk/base/network.cc381
-rw-r--r--third_party/libjingle/files/talk/base/network.h139
-rw-r--r--third_party/libjingle/files/talk/base/openssladapter.cc809
-rw-r--r--third_party/libjingle/files/talk/base/openssladapter.h94
-rw-r--r--third_party/libjingle/files/talk/base/pathutils.cc426
-rw-r--r--third_party/libjingle/files/talk/base/pathutils.h110
-rw-r--r--third_party/libjingle/files/talk/base/physicalsocketserver.cc1147
-rw-r--r--third_party/libjingle/files/talk/base/physicalsocketserver.h81
-rw-r--r--third_party/libjingle/files/talk/base/proxydetect.cc827
-rw-r--r--third_party/libjingle/files/talk/base/proxydetect.h13
-rw-r--r--third_party/libjingle/files/talk/base/proxyinfo.cc37
-rw-r--r--third_party/libjingle/files/talk/base/proxyinfo.h51
-rw-r--r--third_party/libjingle/files/talk/base/schanneladapter.cc749
-rw-r--r--third_party/libjingle/files/talk/base/schanneladapter.h94
-rw-r--r--third_party/libjingle/files/talk/base/scoped_ptr.h38
-rw-r--r--third_party/libjingle/files/talk/base/sec_buffer.h173
-rw-r--r--third_party/libjingle/files/talk/base/signalthread.cc128
-rw-r--r--third_party/libjingle/files/talk/base/signalthread.h125
-rw-r--r--third_party/libjingle/files/talk/base/sigslot.h2699
-rw-r--r--third_party/libjingle/files/talk/base/socket.h161
-rw-r--r--third_party/libjingle/files/talk/base/socketadapters.cc679
-rw-r--r--third_party/libjingle/files/talk/base/socketadapters.h170
-rw-r--r--third_party/libjingle/files/talk/base/socketaddress.cc312
-rw-r--r--third_party/libjingle/files/talk/base/socketaddress.h174
-rw-r--r--third_party/libjingle/files/talk/base/socketaddresspair.cc58
-rw-r--r--third_party/libjingle/files/talk/base/socketaddresspair.h58
-rw-r--r--third_party/libjingle/files/talk/base/socketfactory.h57
-rw-r--r--third_party/libjingle/files/talk/base/socketpool.cc261
-rw-r--r--third_party/libjingle/files/talk/base/socketpool.h161
-rw-r--r--third_party/libjingle/files/talk/base/socketserver.h57
-rw-r--r--third_party/libjingle/files/talk/base/socketstream.h153
-rw-r--r--third_party/libjingle/files/talk/base/ssladapter.cc196
-rw-r--r--third_party/libjingle/files/talk/base/ssladapter.h74
-rw-r--r--third_party/libjingle/files/talk/base/stl_decl.h84
-rw-r--r--third_party/libjingle/files/talk/base/stream.cc665
-rw-r--r--third_party/libjingle/files/talk/base/stream.h396
-rw-r--r--third_party/libjingle/files/talk/base/streamutils.cc194
-rw-r--r--third_party/libjingle/files/talk/base/streamutils.h94
-rw-r--r--third_party/libjingle/files/talk/base/stringdigest.cc49
-rw-r--r--third_party/libjingle/files/talk/base/stringdigest.h47
-rw-r--r--third_party/libjingle/files/talk/base/stringencode.cc580
-rw-r--r--third_party/libjingle/files/talk/base/stringencode.h166
-rw-r--r--third_party/libjingle/files/talk/base/stringutils.cc84
-rw-r--r--third_party/libjingle/files/talk/base/stringutils.h294
-rw-r--r--third_party/libjingle/files/talk/base/tarstream.cc601
-rw-r--r--third_party/libjingle/files/talk/base/tarstream.h104
-rw-r--r--third_party/libjingle/files/talk/base/task.cc299
-rw-r--r--third_party/libjingle/files/talk/base/task.h218
-rw-r--r--third_party/libjingle/files/talk/base/taskrunner.cc176
-rw-r--r--third_party/libjingle/files/talk/base/taskrunner.h83
-rw-r--r--third_party/libjingle/files/talk/base/testclient.cc162
-rw-r--r--third_party/libjingle/files/talk/base/testclient.h89
-rw-r--r--third_party/libjingle/files/talk/base/thread.cc375
-rw-r--r--third_party/libjingle/files/talk/base/thread.h164
-rw-r--r--third_party/libjingle/files/talk/base/time.cc91
-rw-r--r--third_party/libjingle/files/talk/base/time.h53
-rw-r--r--third_party/libjingle/files/talk/base/unixfilesystem.cc223
-rw-r--r--third_party/libjingle/files/talk/base/unixfilesystem.h86
-rw-r--r--third_party/libjingle/files/talk/base/urlencode.cc122
-rw-r--r--third_party/libjingle/files/talk/base/urlencode.h12
-rw-r--r--third_party/libjingle/files/talk/base/virtualsocket_unittest.cc239
-rw-r--r--third_party/libjingle/files/talk/base/virtualsocketserver.cc616
-rw-r--r--third_party/libjingle/files/talk/base/virtualsocketserver.h156
-rw-r--r--third_party/libjingle/files/talk/base/win32.h70
-rw-r--r--third_party/libjingle/files/talk/base/win32filesystem.cc194
-rw-r--r--third_party/libjingle/files/talk/base/win32filesystem.h91
-rw-r--r--third_party/libjingle/files/talk/base/win32window.cc137
-rw-r--r--third_party/libjingle/files/talk/base/win32window.h72
-rw-r--r--third_party/libjingle/files/talk/base/winfirewall.cc141
-rw-r--r--third_party/libjingle/files/talk/base/winfirewall.h64
-rw-r--r--third_party/libjingle/files/talk/base/winping.cc317
-rw-r--r--third_party/libjingle/files/talk/base/winping.h105
-rw-r--r--third_party/libjingle/files/talk/base/winsock_initializer.cc65
-rw-r--r--third_party/libjingle/files/talk/base/winsock_initializer.h40
-rw-r--r--third_party/libjingle/files/talk/pkg.m457
-rw-r--r--third_party/libjingle/files/talk/xmllite/Makefile.am18
-rw-r--r--third_party/libjingle/files/talk/xmllite/qname.cc90
-rw-r--r--third_party/libjingle/files/talk/xmllite/qname.h59
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlbuilder.cc149
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlbuilder.h75
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlconstants.cc65
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlconstants.h61
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlelement.cc509
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlelement.h238
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlnsstack.cc205
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlnsstack.h62
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlparser.cc291
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlparser.h115
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlprinter.cc199
-rw-r--r--third_party/libjingle/files/talk/xmllite/xmlprinter.h49
-rw-r--r--third_party/libjingle/files/talk/xmpp/Makefile.am33
-rw-r--r--third_party/libjingle/files/talk/xmpp/asyncsocket.h86
-rw-r--r--third_party/libjingle/files/talk/xmpp/jid.cc506
-rw-r--r--third_party/libjingle/files/talk/xmpp/jid.h148
-rw-r--r--third_party/libjingle/files/talk/xmpp/plainsaslhandler.h82
-rw-r--r--third_party/libjingle/files/talk/xmpp/prexmppauth.h86
-rw-r--r--third_party/libjingle/files/talk/xmpp/ratelimitmanager.cc77
-rw-r--r--third_party/libjingle/files/talk/xmpp/ratelimitmanager.h146
-rw-r--r--third_party/libjingle/files/talk/xmpp/saslcookiemechanism.h87
-rw-r--r--third_party/libjingle/files/talk/xmpp/saslhandler.h59
-rw-r--r--third_party/libjingle/files/talk/xmpp/saslmechanism.cc70
-rw-r--r--third_party/libjingle/files/talk/xmpp/saslmechanism.h74
-rw-r--r--third_party/libjingle/files/talk/xmpp/saslplainmechanism.h65
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppclient.cc421
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppclient.h163
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppclientsettings.h116
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppconstants.cc402
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppconstants.h360
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppengine.h338
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppengineimpl.cc498
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppengineimpl.h276
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppengineimpl_iq.cc277
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmpplogintask.cc386
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmpplogintask.h100
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppstanzaparser.cc104
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmppstanzaparser.h96
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmpptask.cc174
-rw-r--r--third_party/libjingle/files/talk/xmpp/xmpptask.h130
-rw-r--r--third_party/libjingle/libjingle.gyp487
-rw-r--r--third_party/libjingle/overrides/talk/base/basictypes.h4
-rw-r--r--third_party/libjingle/overrides/talk/base/winsock_initializer.cc (renamed from third_party/libjingle/overrides/talk/base/win32socketinit.cc)2
-rw-r--r--third_party/libjingle/overrides/talk/xmllite/qname.cc65
-rw-r--r--third_party/libjingle/overrides/talk/xmllite/qname.h37
201 files changed, 37496 insertions, 590 deletions
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 297aa71..3005571 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -2,11 +2,50 @@ Name: libjingle
URL: http://code.google.com/p/libjingle/
Version: 2.7.0
License: BSD
-License File: source/COPYING
+License File: files/COPYING
Description:
Libjingle provides xmpp support to the sync code, which
lives at chrome/browser/sync/notifier.
Libjingle is distributed under a Berkeley-style license detailed in
- source/COPYING.
+ files/COPYING.
+
+Local Modifications:
+ Applied changes per the patchfile mods-since-v0_4_0.diff. That
+ includes the following items.
+ * Added support to specify the token_service in the auth stanza.
+ * Added support for non-gaia ids associated with gaia accounts.
+ * A bug fix in the task code to prevent infinite looping of aborted
+ tasks.
+ * Removed the definition of DISALLOW_EVIL_CONSTRUCTORS from common.h
+ * Introduction of #undef ETIMEDOUT to get around a conflict versus
+ pthreads.h.
+ * We use an "overrides" directory for some headers, for example,
+ scoped_ptr.h and basic_types.h, to avoid a duplicate functionality.
+ The overrides typically pull an implementation from src/base, and
+ then supplement this with any additional defines not found
+ in Chromium.
+ * Edits to config.h, changing some #defines.
+ * Removed some scripts and build files not needed by Chromium: aclocal.m4,
+ config.guess, config.h.in, config.sub, configure, depcomp, install-sh,
+ ltmain.sh, missing.
+ * Removed Makefile.in files, *.sln, *.vcproj.
+ * Removed "examples", "thirdparty", and "sessions" directories.
+ * Removed a number of unneeded scope specifications to appease gcc.
+ * Renamed "talk/xmpp/constants.*" to "talk/xmpp/xmppconstants.*" to get
+ around an IncrediBuild link error. Apparently IncrediBuild can become
+ confused when two compilation units have the same filename.
+ * Added a #define guard to libjingle's base/logging.h to prevent the
+ LOG() macros from being redefined when included by users of the
+ library. The #define guard is SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS.
+ * Updated signalthread.* and dependencies to add threadcounting and
+ improve multithread safety.
+ * Added a CreateSSLAdapter() function to SocketFactory to allow SSL
+ adapter creation behavior to be overridden.
+ * Improved handling and error-checking of SSL adapters.
+ * Changed uses of Windows-only debug variable _DEBUG to use the
+ cross-platform NDEBUG variable instead.
+ * Fixed error-checking bugs in xmppclient.cc and physicalsocketserver.cc.
+ * Made some XmppTask member functions static.
+ * Cleaned up several sscanf/printf format strings/arguments.
diff --git a/third_party/libjingle/files/AUTHORS b/third_party/libjingle/files/AUTHORS
new file mode 100644
index 0000000..e491a9e
--- /dev/null
+++ b/third_party/libjingle/files/AUTHORS
@@ -0,0 +1 @@
+Google Inc.
diff --git a/third_party/libjingle/files/COPYING b/third_party/libjingle/files/COPYING
new file mode 100644
index 0000000..d11f105
--- /dev/null
+++ b/third_party/libjingle/files/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2004--2005, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * 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.
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. \ No newline at end of file
diff --git a/third_party/libjingle/files/ChangeLog b/third_party/libjingle/files/ChangeLog
new file mode 100644
index 0000000..ce00334
--- /dev/null
+++ b/third_party/libjingle/files/ChangeLog
@@ -0,0 +1,13 @@
+Libjingle
+
+0.2.0 - Jan 27 2006
+ - Windows build fixes with Visual Studio Express project files
+ - Pseudo-TCP support provides TCP-like reliability over a P2PSocket
+ - TunnelSessionClient establishes sessions for reliably sending data
+ using Pseudo-TCP
+ - A new pcp example application transfers files from one user to
+ another using TunnelSessionClient
+ - TLS login support for both example applications
+
+0.1.0 - Dec 15 2005
+ - Initial release
diff --git a/third_party/libjingle/files/DOCUMENTATION b/third_party/libjingle/files/DOCUMENTATION
new file mode 100644
index 0000000..7739aef
--- /dev/null
+++ b/third_party/libjingle/files/DOCUMENTATION
@@ -0,0 +1 @@
+Documentation for libjingle can be found at http://code.google.com/apis/talk/libjingle/
diff --git a/third_party/libjingle/files/INSTALL b/third_party/libjingle/files/INSTALL
new file mode 100644
index 0000000..a4b3414
--- /dev/null
+++ b/third_party/libjingle/files/INSTALL
@@ -0,0 +1,229 @@
+Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/third_party/libjingle/files/Makefile.am b/third_party/libjingle/files/Makefile.am
new file mode 100644
index 0000000..d4cf1cb
--- /dev/null
+++ b/third_party/libjingle/files/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS=talk
+
+noinst_HEADERS = config.h
+
+EXTRA_DIST=README.win DOCUMENTATION
+
+dist-hook:
+ sed -i -f talk/sanitize.sed `find $(distdir) -type f`
diff --git a/third_party/libjingle/files/NEWS b/third_party/libjingle/files/NEWS
new file mode 100644
index 0000000..bccf886
--- /dev/null
+++ b/third_party/libjingle/files/NEWS
@@ -0,0 +1,15 @@
+0.4.0
+* File transfer support
+* Protocol updates
+* Proxy detection
+* Relay server support
+* Many other assorted changes
+
+0.2.0
+* Windows build files
+* TCP-like reliable stream support
+* pcp example application using pseudo-TCP streams
+* Support for TLS login on both example applications
+
+0.1.0
+* Initial source release
diff --git a/third_party/libjingle/files/README b/third_party/libjingle/files/README
new file mode 100644
index 0000000..5861c98
--- /dev/null
+++ b/third_party/libjingle/files/README
@@ -0,0 +1,57 @@
+Libjingle
+
+Libjingle is a set of components provided by Google to interoperate with Google
+Talk's peer-to-peer and voice capabilities. This package will create several
+static libraries you may link to your project as needed.
+
+-talk - No source files in talk/, just these subdirectories
+|-base - Contains basic low-level portable utility functions for
+| things like threads and sockets
+|-p2p - The P2P stack
+ |-base - Base p2p functionality
+ |-client - Hooks to tie it into XMPP
+|-session - Signaling
+ |-phone - Signaling code specific to making phone calls
+|-third_party - Components that aren't ours
+ |-mediastreamer - Media components for dealing with sound hardware and
+ | voice codecs
+|-xmllite - XML parser
+|-xmpp - XMPP engine
+
+In addition, this package contains two examples in talk/examples which
+illustrate the basic concepts of how the provided classes work.
+
+The xmllite component of libjingle depends on expat. You can download expat
+from http://expat.sourceforge.net/.
+
+mediastreamer, the media components used by the example applications depend on
+the oRTP and iLBC components from linphone, which can be found at
+http://www.linphone.org. Linphone, in turn depends on GLib, which can be found
+at http://www.gtk.org. This GLib dependency should be removed in future
+releases.
+
+Building Libjingle
+
+Once the dependencies are installed, run ./configure. ./configure will return
+an error if it failed to locate the proper dependencies. If ./configure
+succeeds, run 'make' to build the components and examples.
+
+When the build is complete, you can run the call example from
+talk/examples/call and the pcp example from talk/examples/pcp.
+
+Relay Server
+
+Libjingle will also build a relay server that may be used to relay traffic
+when a direct peer-to-peer connection could not be established. The relay
+server will build in talk/p2p/base/relayserver and will listen on UDP
+ports 5000 and 5001. See the Libjingle Developer Guide at
+http://code.google.com/apis/talk/index.html for information about configuring
+a client to use this relay server.
+
+STUN Server
+
+Lastly, Libjingle builds a STUN server which implements the STUN protocol for
+Simple Traversal of UDP over NAT. The STUN server is built as
+talk/p2p/base/stunserver and listens on UDP port 7000. See the Libjingle
+Developer Guide at http://code.google.com/apis/talk/index.html for information
+about configuring a client to use this STUN server.
diff --git a/third_party/libjingle/files/README.win b/third_party/libjingle/files/README.win
new file mode 100644
index 0000000..1f45b72
--- /dev/null
+++ b/third_party/libjingle/files/README.win
@@ -0,0 +1,24 @@
+1. Install Visual C++ Express 2005. It is free from this link:
+ http://msdn.microsoft.com/vstudio/express/visualc/
+
+2. Install the platform SDK and integrate it into VC++ express
+ http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/
+
+3. Download and install binary package for expat:
+ http://sourceforge.net/project/showfiles.php?group_id=10127&package_id=11277
+
+4. Update the Visual C++ directories in the Projects and Solutions section in the Options dialog box
+ Library files: C:\expat-VERSION\StaticLibs
+ Include files: C:\expat-VERSION\Source\Lib
+ where VERSION is the version of expat you've downoaded
+
+5. Unzip the libjingle files and open the solution.
+
+6. If you wish to build the call example with GIPS Voice Engine Lite, download Voice Engine Lite from http://developer.globalipsound.com
+
+7. Extract the Interface and Library directories from the Voice Engine Lite zip file into talk\third_party\gips
+
+8. Open talk\third_party\gips\expiration.h and set the GIPS_EXPIRATION #defines to the expiration date provided by GIPS and remove the #error directive
+
+9. Build the solution
+
diff --git a/third_party/libjingle/files/config.h b/third_party/libjingle/files/config.h
new file mode 100644
index 0000000..ddc8182
--- /dev/null
+++ b/third_party/libjingle/files/config.h
@@ -0,0 +1,113 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Chat archving */
+#define FEATURE_ENABLE_CHAT_ARCHIVING 1
+
+/* Enable SSL */
+#define FEATURE_ENABLE_SSL 1
+
+/* voice mail */
+#define FEATURE_ENABLE_VOICEMAIL 1
+
+/* Define to 1 if you have the <alsa/asoundlib.h> header file. */
+/* #undef HAVE_ALSA_ASOUNDLIB_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Have GIPS Voice Engine */
+/* #undef HAVE_GIPS */
+
+/* Glib is required for oRTP code */
+/* #undef HAVE_GLIB */
+
+/* Defined when we have ilbc codec lib */
+/* #undef HAVE_ILBC */
+
+/* Define to 1 if you have the <iLBC_decode.h> header file. */
+/* #undef HAVE_ILBC_DECODE_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* oRTP provides RTP supprt */
+/* #undef HAVE_ORTP */
+
+/* has speex */
+/* #undef HAVE_SPEEX */
+
+/* Define to 1 if you have the <speex.h> header file. */
+/* #undef HAVE_SPEEX_H */
+
+/* Define to 1 if you have the <speex/speex.h> header file. */
+/* #undef HAVE_SPEEX_SPEEX_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Building on Linux */
+/* #undef LINUX */
+
+/* Logging */
+#define LOGGING 1
+
+/* Building on OSX */
+/* #undef OSX */
+
+/* Name of package */
+#define PACKAGE "libjingle"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "google-talk-open@googlegroups.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libjingle"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libjingle 0.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libjingle"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.4.0"
+
+/* If we're using configure, we're on POSIX */
+#define POSIX 1
+
+/* Build as a production build */
+#define PRODUCTION 1
+
+/* Build as a production build */
+#define PRODUCTION_BUILD 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.4.0"
+
+/* Defined when alsa support is enabled */
+/* #undef __ALSA_ENABLED__ */
diff --git a/third_party/libjingle/files/configure.ac b/third_party/libjingle/files/configure.ac
new file mode 100644
index 0000000..b3daac4
--- /dev/null
+++ b/third_party/libjingle/files/configure.ac
@@ -0,0 +1,182 @@
+AC_INIT([libjingle], [0.4.0], [google-talk-open@googlegroups.com])
+AC_CANONICAL_SYSTEM
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE([dist-zip])
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_LIBTOOL
+LIBTOOL="$LIBTOOL --silent"
+AC_PROG_INSTALL
+AC_DEFINE(PRODUCTION_BUILD, 1, [Build as a production build])
+AC_DEFINE(PRODUCTION, 1, [Build as a production build])
+AC_DEFINE(POSIX, 1, [If we're using configure, we're on POSIX])
+AC_DEFINE(FEATURE_ENABLE_SSL, 1, [Enable SSL])
+AC_DEFINE(FEATURE_ENABLE_CHAT_ARCHIVING, 1, [Chat archving])
+AC_DEFINE(FEATURE_ENABLE_VOICEMAIL, 1, [voice mail])
+AC_DEFINE(LOGGING, 1, [Logging])
+
+HAVE_EXPAT=no
+AC_CHECK_LIB(expat, XML_ParserCreate, HAVE_EXPAT="yes")
+if test "x$HAVE_EXPAT" = xyes ; then
+ EXPAT_LIBS="-lexpat"
+ AC_SUBST(EXPAT_LIBS)
+else
+ AC_ERROR([Expat is required to build libjingle. You can get it from http://expat.sourceforge.net/])
+fi
+
+enable_phone=yes
+if test `uname -s` = Linux ; then
+ AC_DEFINE(LINUX, 1, [Building on Linux])
+ if test x`ls talk/third_party/gips/VoiceEngine_Linux_gcc.a` != x ; then
+ enable_gips=yes
+ MEDIA_LIBS=$PWD/talk/third_party/gips/VoiceEngine_Linux_gcc.a
+ fi
+elif test `uname -s` = Darwin ; then
+ AC_DEFINE(OSX, 1, [Building on OSX])
+ if test x`ls talk/third_party/gips/VoiceEngine_mac_gcc.a` != x ; then
+ enable_gips=yes
+ MEDIA_LIBS="$PWD/talk/third_party/gips/VoiceEngine_mac_gcc.a -framework CoreAudio -framework AudioToolbox"
+ fi
+fi
+
+if test x$enable_gips = xyes ; then
+ AC_DEFINE(HAVE_GIPS, 1, [Have GIPS Voice Engine])
+elif test `uname -s` = Linux ; then
+
+AC_CHECK_HEADERS(alsa/asoundlib.h,
+ [AC_CHECK_LIB(asound, snd_pcm_open,
+ [ALSA_LIBS="-lasound" ; AC_DEFINE(__ALSA_ENABLED__,1,[Defined when alsa support is enabled]) ])
+ ]
+)
+AC_SUBST(ALSA_LIBS)
+
+PKG_CHECK_MODULES(GLIB, glib-2.0 gmodule-2.0 gthread-2.0, enable_glib=yes, enable_glib=no)
+if test x$enable_glib = xno; then
+ enable_phone=no
+ AC_MSG_NOTICE([GLib 2.0 is required to build libjingle. You can get it from http://www.gtk.org/])
+else
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+ AC_DEFINE(HAVE_GLIB, 1, [Glib is required for oRTP code])
+fi
+
+PKG_CHECK_MODULES(ORTP, ortp >= 0.7.0, enable_ortp=yes, enable_ortp=no)
+if test x$enable_ortp = xno ; then
+ enable_phone=no
+ AC_MSG_NOTICE([oRTP is required to build libjingle. You can get it from http://www.linphone.org/ortp/])
+else
+ AC_SUBST(ORTP_CFLAGS)
+ AC_SUBST(ORTP_LIBS)
+ AC_DEFINE(HAVE_ORTP, 1, [oRTP provides RTP supprt])
+fi
+
+MEDIA_LIBS="$PWD/talk/third_party/mediastreamer/libmediastreamer.la -lasound"
+
+dnl only accept speex>=1.1.6 or 1.0.5 (the versions that have speex_encode_int )
+AC_ARG_WITH( speex,
+ [ --with-speex Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ],
+ [ speex_prefix=${withval}],[ speex_prefix="/usr" ])
+
+AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)
+],speex_found=no)
+
+if test "$speex_found" = "no" ; then
+AC_CHECK_HEADERS(speex/speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no)
+],speex_found=no)
+fi
+
+if test "$speex_found" = "no" ; then
+AC_MSG_WARN([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6 from http://www.speex.org/])
+else
+SPEEX_CFLAGS=" -I${speex_prefix}/include -I${speex_prefix}/include/speex"
+SPEEX_LIBS="-L${speex_prefix}/lib -L${speex_prefix}/speex/lib -lspeex -lm"
+CPPFLAGS_save=$CPPFLAGS
+CPPFLAGS=$SPEEX_CFLAGS
+LDFLAGS_save=$LDFLAGS
+LDFLAGS=$SPEEX_LIBS
+AC_DEFINE(HAVE_SPEEX,1,[has speex])
+fi
+
+AC_SUBST(SPEEX_CFLAGS)
+AC_SUBST(SPEEX_LIBS)
+CPPFLAGS+=$CPPFLAGS_save
+LDFLAGS+=$LDFLAGS_save
+
+AC_ARG_WITH( ilbc,
+ [ --with-ilbc Set prefix where ilbc headers and libs can be found (ex:/usr, /usr/local, none to disable ilbc support) [default=/usr] ],
+ [ ilbc_prefix=${withval}],[ ilbc_prefix="/usr" ])
+
+if test "$ilbc_prefix" = "none" ; then
+ AC_MSG_NOTICE([iLBC codec support disabled. ])
+else
+ ILBC_CFLAGS=" -I${ilbc_prefix}/include/ilbc"
+ ILBC_LIBS="-L${ilbc_prefix}/lib -lilbc -lm"
+ CPPFLAGS_save=$CPPFLAGS
+ CPPFLAGS=$ILBC_CFLAGS
+ LDFLAGS_save=$LDFLAGS
+ LDFLAGS=$ILBC_LIBS
+ AC_CHECK_HEADERS(iLBC_decode.h,[AC_CHECK_LIB(ilbc,iLBC_decode,ilbc_found=yes,ilbc_found=no)
+ ],ilbc_found=no)
+
+ CPPFLAGS=$CPPFLAGS_save
+ LDFLAGS=$LDFLAGS_save
+
+ if test "$ilbc_found" = "no" ; then
+ AC_MSG_WARN([Could not find ilbc headers or libs. Please install ilbc package from http://www.linphone.org if you want iLBC codec support in libjingle.])
+ ILBC_CFLAGS=
+ ILBC_LIBS=
+ else
+ AC_DEFINE(HAVE_ILBC,1,[Defined when we have ilbc codec lib])
+ AC_SUBST(ILBC_CFLAGS)
+ AC_SUBST(ILBC_LIBS)
+ fi
+fi
+
+else
+ enable_phone=no
+fi # Linux check
+
+AM_CONDITIONAL(GIPS, test x$enable_gips = xyes)
+AM_CONDITIONAL(PHONE, test x$enable_phone = xyes)
+AC_SUBST(MEDIA_LIBS)
+
+AC_OUTPUT([Makefile
+ talk/Makefile
+ talk/base/Makefile
+ talk/third_party/Makefile
+ talk/third_party/gips/Makefile
+ talk/third_party/mediastreamer/Makefile
+ talk/examples/Makefile
+ talk/examples/login/Makefile
+ talk/examples/call/Makefile
+ talk/examples/pcp/Makefile
+ talk/p2p/Makefile
+ talk/p2p/base/Makefile
+ talk/p2p/client/Makefile
+ talk/session/Makefile
+ talk/session/fileshare/Makefile
+ talk/session/tunnel/Makefile
+ talk/session/phone/Makefile
+ talk/xmllite/Makefile
+ talk/xmpp/Makefile
+ ])
+
+echo
+echo $PACKAGE $VERSION
+echo
+
+if test x$enable_phone = xyes ; then
+ echo
+ echo Supported Examples: call pcp
+ echo Supported Codecs:
+ if test x$enable_gips = xyes ; then
+ echo GIPS: yes
+ else
+ echo Speex: $speex_found
+ echo iLBC: $ilbc_found
+ echo MULAW: yes
+ fi
+else
+ echo Supported Examples: pcp
+fi
+echo
diff --git a/third_party/libjingle/files/talk/Makefile.am b/third_party/libjingle/files/talk/Makefile.am
new file mode 100644
index 0000000..dc6cc26
--- /dev/null
+++ b/third_party/libjingle/files/talk/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS=base xmllite xmpp p2p session third_party examples
+
+EXTRA_DIST=libjingle.sln libjingle.vcproj
diff --git a/third_party/libjingle/files/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h b/third_party/libjingle/files/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h
new file mode 100644
index 0000000..6ff97a6
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h
@@ -0,0 +1,55 @@
+// This file is the Equifax Secure global eBusiness CA-1 certificate
+// in C form.
+
+// It was generated with the following command line:
+// > openssl x509 -in Equifax_Secure_Global_eBusiness_CA-1.cer -noout -C
+
+// The certificate was retrieved from:
+// http://www.geotrust.com/resources/root_certificates/certificates/Equifax_Secure_Global_eBusiness_CA-1.cer
+
+/* subject:/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */
+/* issuer :/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */
+unsigned char EquifaxSecureGlobalEBusinessCA1_certificate[660]={
+0x30,0x82,0x02,0x90,0x30,0x82,0x01,0xF9,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,
+0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30,
+0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,
+0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78,
+0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,
+0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,
+0x65,0x63,0x75,0x72,0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75,
+0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x1E,0x17,0x0D,0x39,
+0x39,0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,
+0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x30,0x5A,0x31,0x0B,0x30,
+0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,
+0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,
+0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,
+0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,
+0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,
+0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,
+0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,
+0x02,0x81,0x81,0x00,0xBA,0xE7,0x17,0x90,0x02,0x65,0xB1,0x34,0x55,0x3C,0x49,0xC2,
+0x51,0xD5,0xDF,0xA7,0xD1,0x37,0x8F,0xD1,0xE7,0x81,0x73,0x41,0x52,0x60,0x9B,0x9D,
+0xA1,0x17,0x26,0x78,0xAD,0xC7,0xB1,0xE8,0x26,0x94,0x32,0xB5,0xDE,0x33,0x8D,0x3A,
+0x2F,0xDB,0xF2,0x9A,0x7A,0x5A,0x73,0x98,0xA3,0x5C,0xE9,0xFB,0x8A,0x73,0x1B,0x5C,
+0xE7,0xC3,0xBF,0x80,0x6C,0xCD,0xA9,0xF4,0xD6,0x2B,0xC0,0xF7,0xF9,0x99,0xAA,0x63,
+0xA2,0xB1,0x47,0x02,0x0F,0xD4,0xE4,0x51,0x3A,0x12,0x3C,0x6C,0x8A,0x5A,0x54,0x84,
+0x70,0xDB,0xC1,0xC5,0x90,0xCF,0x72,0x45,0xCB,0xA8,0x59,0xC0,0xCD,0x33,0x9D,0x3F,
+0xA3,0x96,0xEB,0x85,0x33,0x21,0x1C,0x3E,0x1E,0x3E,0x60,0x6E,0x76,0x9C,0x67,0x85,
+0xC5,0xC8,0xC3,0x61,0x02,0x03,0x01,0x00,0x01,0xA3,0x66,0x30,0x64,0x30,0x11,0x06,
+0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,
+0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,
+0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xBE,0xA8,
+0xA0,0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B,
+0x68,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBE,0xA8,0xA0,
+0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B,0x68,
+0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,
+0x03,0x81,0x81,0x00,0x30,0xE2,0x01,0x51,0xAA,0xC7,0xEA,0x5F,0xDA,0xB9,0xD0,0x65,
+0x0F,0x30,0xD6,0x3E,0xDA,0x0D,0x14,0x49,0x6E,0x91,0x93,0x27,0x14,0x31,0xEF,0xC4,
+0xF7,0x2D,0x45,0xF8,0xEC,0xC7,0xBF,0xA2,0x41,0x0D,0x23,0xB4,0x92,0xF9,0x19,0x00,
+0x67,0xBD,0x01,0xAF,0xCD,0xE0,0x71,0xFC,0x5A,0xCF,0x64,0xC4,0xE0,0x96,0x98,0xD0,
+0xA3,0x40,0xE2,0x01,0x8A,0xEF,0x27,0x07,0xF1,0x65,0x01,0x8A,0x44,0x2D,0x06,0x65,
+0x75,0x52,0xC0,0x86,0x10,0x20,0x21,0x5F,0x6C,0x6B,0x0F,0x6C,0xAE,0x09,0x1C,0xAF,
+0xF2,0xA2,0x18,0x34,0xC4,0x75,0xA4,0x73,0x1C,0xF1,0x8D,0xDC,0xEF,0xAD,0xF9,0xB3,
+0x76,0xB4,0x92,0xBF,0xDC,0x95,0x10,0x1E,0xBE,0xCB,0xC8,0x3B,0x5A,0x84,0x60,0x19,
+0x56,0x94,0xA9,0x55,
+};
diff --git a/third_party/libjingle/files/talk/base/Makefile.am b/third_party/libjingle/files/talk/base/Makefile.am
new file mode 100644
index 0000000..4a1e321
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/Makefile.am
@@ -0,0 +1,152 @@
+libcricketbase_la_SOURCES = socketaddress.cc \
+ time.cc \
+ asyncudpsocket.cc \
+ messagequeue.cc \
+ thread.cc \
+ physicalsocketserver.cc \
+ bytebuffer.cc \
+ asyncpacketsocket.cc \
+ network.cc \
+ asynctcpsocket.cc \
+ socketadapters.cc \
+ md5c.c \
+ base64.cc \
+ task.cc \
+ taskrunner.cc \
+ host.cc \
+ proxydetect.cc \
+ socketaddresspair.cc \
+ stringencode.cc \
+ stringdigest.cc \
+ stringutils.cc \
+ proxyinfo.cc \
+ common.cc \
+ logging.cc \
+ stream.cc \
+ ssladapter.cc \
+ openssladapter.cc \
+ helpers.cc \
+ asynchttprequest.cc \
+ firewallsocketserver.cc \
+ httpcommon.cc \
+ httpbase.cc \
+ httpclient.cc \
+ httpserver.cc \
+ socketpool.cc \
+ signalthread.cc \
+ autodetectproxy.cc \
+ urlencode.cc \
+ pathutils.cc \
+ fileutils.cc \
+ unixfilesystem.cc \
+ tarstream.cc \
+ streamutils.cc \
+ diskcache.cc \
+ diskcachestd.cc
+
+libcrickettest_la_SOURCES = testclient.cc \
+ natserver.cc \
+ natsocketfactory.cc \
+ nattypes.cc \
+ virtualsocketserver.cc
+
+noinst_HEADERS = asyncfile.h \
+ common.h \
+ convert.h \
+ asyncpacketsocket.h \
+ socketfactory.h \
+ asyncsocket.h \
+ socket.h \
+ asynctcpsocket.h \
+ linked_ptr.h \
+ asyncudpsocket.h \
+ logging.h \
+ socketserver.h \
+ base64.h \
+ md5.h \
+ stl_decl.h \
+ basicdefs.h \
+ messagequeue.h \
+ basictypes.h \
+ stringdigest.h \
+ stringencode.h \
+ stringutils.h \
+ bytebuffer.h \
+ task.h \
+ byteorder.h \
+ taskrunner.h \
+ criticalsection.h \
+ network.h \
+ thread.h \
+ time.h \
+ physicalsocketserver.h \
+ proxyinfo.h \
+ host.h \
+ scoped_ptr.h \
+ sigslot.h \
+ winping.h \
+ socketadapters.h \
+ socketaddress.h \
+ host.h \
+ socketaddresspair.h \
+ Equifax_Secure_Global_eBusiness_CA-1.h \
+ stream.h \
+ ssladapter.h \
+ openssladapter.h \
+ cryptstring.h \
+ httpbase.h \
+ httpclient.h \
+ httpcommon.h \
+ httpserver.h \
+ httpcommon-inl.h \
+ proxydetect.h \
+ helpers.h \
+ socketpool.h \
+ asynchttprequest.h \
+ signalthread.h \
+ firewallsocketserver.h \
+ diskcache.h \
+ pathutils.h \
+ socketstream.h \
+ autodetectproxy.h \
+ urlencode.h \
+ fileutils.h \
+ unixfilesystem.h \
+ win32filesystem.h \
+ tarstream.h \
+ streamutils.h \
+ diskcachestd.h \
+ testclient.h \
+ natserver.h \
+ nattypes.h \
+ natsocketfactory.h \
+ virtualsocketserver.h \
+ event.h
+
+AM_CXXFLAGS = -DPOSIX
+DEFAULT_INCLUDES = -I$(top_srcdir) `pkg-config --cflags gtk+-2.0`
+
+noinst_LTLIBRARIES = libcricketbase.la libcrickettest.la
+noinst_PROGRAMS = natserver nat_unittest virtualsocket_unittest
+
+natserver_SOURCES = natserver_main.cc
+natserver_LDADD = libcrickettest.la libcricketbase.la -lpthread
+nat_unittest_SOURCES = nat_unittest.cc
+nat_unittest_LDADD = libcrickettest.la libcricketbase.la -lpthread
+virtualsocket_unittest_SOURCES = virtualsocket_unittest.cc
+virtualsocket_unittest_LDADD = libcrickettest.la libcricketbase.la -lpthread
+
+EXTRA_DIST = diskcache_win32.h \
+ diskcache_win32.cc \
+ win32.h \
+ winping.h \
+ winping.cc \
+ win32filesystem.cc \
+ win32socketserver.cc \
+ win32socketserver.h \
+ win32window.h \
+ winfirewall.h \
+ winfirewall.cc \
+ schanneladapter.h \
+ schanneladapter.cc \
+ sec_buffer.h
diff --git a/third_party/libjingle/files/talk/base/asyncfile.h b/third_party/libjingle/files/talk/base/asyncfile.h
new file mode 100644
index 0000000..1437979
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncfile.h
@@ -0,0 +1,56 @@
+/*
+ * 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 TALK_BASE_ASYNCFILE_H__
+#define TALK_BASE_ASYNCFILE_H__
+
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+// Provides the ability to perform file I/O asynchronously.
+// TODO: Create a common base class with AsyncSocket.
+class AsyncFile {
+public:
+ virtual ~AsyncFile() {}
+
+ // Determines whether the file will receive read events.
+ virtual bool readable() = 0;
+ virtual void set_readable(bool value) = 0;
+
+ // Determines whether the file will receive write events.
+ virtual bool writable() = 0;
+ virtual void set_writable(bool value) = 0;
+
+ sigslot::signal1<AsyncFile*> SignalReadEvent;
+ sigslot::signal1<AsyncFile*> SignalWriteEvent;
+ sigslot::signal2<AsyncFile*,int> SignalCloseEvent;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCFILE_H__
diff --git a/third_party/libjingle/files/talk/base/asynchttprequest.cc b/third_party/libjingle/files/talk/base/asynchttprequest.cc
new file mode 100644
index 0000000..9b3d414
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asynchttprequest.cc
@@ -0,0 +1,161 @@
+#include "talk/base/common.h"
+#include "talk/base/firewallsocketserver.h"
+#include "talk/base/httpclient.h"
+#include "talk/base/logging.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/socketadapters.h"
+#include "talk/base/socketpool.h"
+#include "talk/base/ssladapter.h"
+#include "talk/base/asynchttprequest.h"
+
+using namespace talk_base;
+
+///////////////////////////////////////////////////////////////////////////////
+// HttpMonitor
+///////////////////////////////////////////////////////////////////////////////
+
+HttpMonitor::HttpMonitor(SocketServer *ss) {
+ ASSERT(talk_base::Thread::Current() != NULL);
+ ss_ = ss;
+ reset();
+}
+
+void HttpMonitor::Connect(talk_base::HttpClient *http) {
+ http->SignalHttpClientComplete.connect(this,
+ &HttpMonitor::OnHttpClientComplete);
+}
+
+void HttpMonitor::OnHttpClientComplete(talk_base::HttpClient * http, int err) {
+ complete_ = true;
+ err_ = err;
+ ss_->WakeUp();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SslSocketFactory
+///////////////////////////////////////////////////////////////////////////////
+
+talk_base::Socket * SslSocketFactory::CreateSocket(int type) {
+ return factory_->CreateSocket(type);
+}
+
+talk_base::AsyncSocket * SslSocketFactory::CreateAsyncSocket(int type) {
+ talk_base::AsyncSocket * socket = factory_->CreateAsyncSocket(type);
+ if (!socket)
+ return 0;
+
+ // Binary logging happens at the lowest level
+ if (!logging_label_.empty() && binary_mode_) {
+ socket = new talk_base::LoggingSocketAdapter(socket, logging_level_,
+ logging_label_.c_str(),
+ binary_mode_);
+ }
+
+ if (proxy_.type) {
+ talk_base::AsyncSocket * proxy_socket = 0;
+ if (proxy_.type == talk_base::PROXY_SOCKS5) {
+ proxy_socket = new talk_base::AsyncSocksProxySocket(socket, proxy_.address,
+ proxy_.username, proxy_.password);
+ } else {
+ // Note: we are trying unknown proxies as HTTPS currently
+ proxy_socket = new talk_base::AsyncHttpsProxySocket(socket,
+ agent_, proxy_.address,
+ proxy_.username, proxy_.password);
+ }
+ if (!proxy_socket) {
+ delete socket;
+ return 0;
+ }
+ socket = proxy_socket; // for our purposes the proxy is now the socket
+ }
+
+ if (!hostname_.empty()) {
+ talk_base::SSLAdapter * ssl_adapter = factory_->CreateSSLAdapter(socket);
+ ssl_adapter->set_ignore_bad_cert(ignore_bad_cert_);
+ int error = ssl_adapter->StartSSL(hostname_.c_str(),
+ use_restartable_ssl_sockets_);
+ if (error != 0) {
+ LOG(LS_WARNING) << "Could not start SSL; error = " << error;
+ delete ssl_adapter;
+ return 0;
+ }
+ socket = ssl_adapter;
+ }
+
+ // Regular logging occurs at the highest level
+ if (!logging_label_.empty() && !binary_mode_) {
+ socket = new talk_base::LoggingSocketAdapter(socket, logging_level_,
+ logging_label_.c_str(),
+ binary_mode_);
+ }
+ return socket;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AsyncHttpRequest
+///////////////////////////////////////////////////////////////////////////////
+
+const int kDefaultHTTPTimeout = 30 * 1000; // 30 sec
+
+AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
+: firewall_(0), port_(80), secure_(false),
+ timeout_(kDefaultHTTPTimeout), fail_redirect_(false),
+ client_(user_agent.c_str(), NULL)
+{
+}
+
+void AsyncHttpRequest::DoWork() {
+ // TODO: Rewrite this to use the thread's native socket server, and a more
+ // natural flow?
+
+ talk_base::PhysicalSocketServer physical;
+ talk_base::SocketServer * ss = &physical;
+ if (firewall_) {
+ ss = new talk_base::FirewallSocketServer(ss, firewall_);
+ }
+
+ SslSocketFactory factory(ss, client_.agent());
+ factory.SetProxy(proxy_);
+ if (secure_)
+ factory.UseSSL(host_.c_str());
+
+ //factory.SetLogging("AsyncHttpRequest");
+
+ talk_base::ReuseSocketPool pool(&factory);
+ client_.set_pool(&pool);
+
+ bool transparent_proxy = (port_ == 80)
+ && ((proxy_.type == talk_base::PROXY_HTTPS)
+ || (proxy_.type == talk_base::PROXY_UNKNOWN));
+
+ if (transparent_proxy) {
+ client_.set_proxy(proxy_);
+ }
+ client_.set_fail_redirect(fail_redirect_);
+
+ talk_base::SocketAddress server(host_, port_);
+ client_.set_server(server);
+
+ HttpMonitor monitor(ss);
+ monitor.Connect(&client_);
+ client_.start();
+ ss->Wait(timeout_, true);
+ if (!monitor.done()) {
+ LOG(LS_INFO) << "AsyncHttpRequest request timed out";
+ client_.reset();
+ return;
+ }
+
+ if (monitor.error()) {
+ LOG(LS_INFO) << "AsyncHttpRequest request error: " << monitor.error();
+ if (monitor.error() == talk_base::HE_AUTH) {
+ //proxy_auth_required_ = true;
+ }
+ return;
+ }
+
+ std::string value;
+ if (client_.response().hasHeader(HH_LOCATION, &value)) {
+ response_redirect_ = value.c_str();
+ }
+}
diff --git a/third_party/libjingle/files/talk/base/asynchttprequest.h b/third_party/libjingle/files/talk/base/asynchttprequest.h
new file mode 100644
index 0000000..543210d
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asynchttprequest.h
@@ -0,0 +1,147 @@
+#ifndef _ASYNCHTTPREQUEST_H_
+#define _ASYNCHTTPREQUEST_H_
+
+#include "talk/base/httpclient.h"
+#include "talk/base/logging.h"
+#include "talk/base/proxyinfo.h"
+#include "talk/base/socketserver.h"
+#include "talk/base/thread.h"
+#include "talk/base/signalthread.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// AsyncHttpRequest
+// Performs an HTTP request on a background thread. Notifies on the foreground
+// thread once the request is done (successfully or unsuccessfully).
+///////////////////////////////////////////////////////////////////////////////
+
+class FirewallManager;
+class MemoryStream;
+
+class AsyncHttpRequest:
+ public SignalThread {
+public:
+ AsyncHttpRequest(const std::string &user_agent);
+
+ void set_proxy(const talk_base::ProxyInfo& proxy) {
+ proxy_ = proxy;
+ }
+ void set_firewall(talk_base::FirewallManager * firewall) {
+ firewall_ = firewall;
+ }
+
+ // The DNS name of the host to connect to.
+ const std::string& host() { return host_; }
+ void set_host(const std::string& host) { host_ = host; }
+
+ // The port to connect to on the target host.
+ int port() { return port_; }
+ void set_port(int port) { port_ = port; }
+
+ // Whether the request should use SSL.
+ bool secure() { return secure_; }
+ void set_secure(bool secure) { secure_ = secure; }
+
+ // Returns the redirect when redirection occurs
+ const std::string& response_redirect() { return response_redirect_; }
+
+ // Time to wait on the download, in ms. Default is 5000 (5s)
+ int timeout() { return timeout_; }
+ void set_timeout(int timeout) { timeout_ = timeout; }
+
+ // Fail redirects to allow analysis of redirect urls, etc.
+ bool fail_redirect() const { return fail_redirect_; }
+ void set_fail_redirect(bool fail_redirect) { fail_redirect_ = fail_redirect; }
+
+ HttpRequestData& request() { return client_.request(); }
+ HttpResponseData& response() { return client_.response(); }
+
+private:
+ // SignalThread Interface
+ virtual void DoWork();
+
+ talk_base::ProxyInfo proxy_;
+ talk_base::FirewallManager * firewall_;
+ std::string host_;
+ int port_;
+ bool secure_;
+ int timeout_;
+ bool fail_redirect_;
+ HttpClient client_;
+ std::string response_redirect_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// HttpMonitor
+///////////////////////////////////////////////////////////////////////////////
+
+class HttpMonitor : public sigslot::has_slots<> {
+public:
+ HttpMonitor(SocketServer *ss);
+
+ void reset() { complete_ = false; }
+
+ bool done() const { return complete_; }
+ int error() const { return err_; }
+
+ void Connect(talk_base::HttpClient* http);
+ void OnHttpClientComplete(talk_base::HttpClient * http, int err);
+
+private:
+ bool complete_;
+ int err_;
+ SocketServer *ss_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SslSocketFactory
+///////////////////////////////////////////////////////////////////////////////
+
+class SslSocketFactory : public talk_base::SocketFactory {
+ public:
+ SslSocketFactory(talk_base::SocketFactory * factory, const std::string &user_agent)
+ : factory_(factory), logging_level_(talk_base::LS_VERBOSE),
+ binary_mode_(false), agent_(user_agent),
+ ignore_bad_cert_(false), use_restartable_ssl_sockets_(false) { }
+
+ void UseSSL(const char * hostname) { hostname_ = hostname; }
+ void DisableSSL() { hostname_.clear(); }
+
+ void SetProxy(const talk_base::ProxyInfo& proxy) { proxy_ = proxy; }
+ const talk_base::ProxyInfo& proxy() const { return proxy_; }
+ bool ignore_bad_cert() {return ignore_bad_cert_;}
+ void SetIgnoreBadCert(bool ignore) { ignore_bad_cert_ = ignore; }
+ bool use_restartable_ssl_sockets() const {
+ return use_restartable_ssl_sockets_;
+ }
+ void SetUseRestartableSSLSockets(bool use_restartable_ssl_sockets) {
+ use_restartable_ssl_sockets_ = use_restartable_ssl_sockets;
+ }
+
+ void SetLogging(talk_base::LoggingSeverity level, const std::string& label,
+ bool binary_mode = false) {
+ logging_level_ = level;
+ logging_label_ = label;
+ binary_mode_ = binary_mode;
+ }
+
+ virtual talk_base::Socket * CreateSocket(int type);
+ virtual talk_base::AsyncSocket * CreateAsyncSocket(int type);
+
+private:
+ talk_base::SocketFactory * factory_;
+ talk_base::ProxyInfo proxy_;
+ std::string hostname_, logging_label_;
+ talk_base::LoggingSeverity logging_level_;
+ bool binary_mode_;
+ std::string agent_;
+ bool ignore_bad_cert_;
+ bool use_restartable_ssl_sockets_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base_
+
+#endif // _ASYNCHTTPREQUEST_H_
diff --git a/third_party/libjingle/files/talk/base/asyncpacketsocket.cc b/third_party/libjingle/files/talk/base/asyncpacketsocket.cc
new file mode 100644
index 0000000..37ba058
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncpacketsocket.cc
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include "talk/base/asyncpacketsocket.h"
+
+namespace talk_base {
+
+AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) {
+}
+
+AsyncPacketSocket::~AsyncPacketSocket() {
+ delete socket_;
+}
+
+SocketAddress AsyncPacketSocket::GetLocalAddress() const {
+ return socket_->GetLocalAddress();
+}
+
+SocketAddress AsyncPacketSocket::GetRemoteAddress() const {
+ return socket_->GetRemoteAddress();
+}
+
+int AsyncPacketSocket::Bind(const SocketAddress& addr) {
+ return socket_->Bind(addr);
+}
+
+int AsyncPacketSocket::Connect(const SocketAddress& addr) {
+ return socket_->Connect(addr);
+}
+
+int AsyncPacketSocket::Send(const void *pv, size_t cb) {
+ return socket_->Send(pv, cb);
+}
+
+int AsyncPacketSocket::SendTo(
+ const void *pv, size_t cb, const SocketAddress& addr) {
+ return socket_->SendTo(pv, cb, addr);
+}
+
+int AsyncPacketSocket::Close() {
+ return socket_->Close();
+}
+
+int AsyncPacketSocket::SetOption(Socket::Option opt, int value) {
+ return socket_->SetOption(opt, value);
+}
+
+int AsyncPacketSocket::GetError() const {
+ return socket_->GetError();
+}
+
+void AsyncPacketSocket::SetError(int error) {
+ return socket_->SetError(error);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/asyncpacketsocket.h b/third_party/libjingle/files/talk/base/asyncpacketsocket.h
new file mode 100644
index 0000000..c6172a7
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncpacketsocket.h
@@ -0,0 +1,63 @@
+/*
+ * 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 TALK_BASE_ASYNCPACKETSOCKET_H__
+#define TALK_BASE_ASYNCPACKETSOCKET_H__
+
+#include "talk/base/asyncsocket.h"
+
+namespace talk_base {
+
+// Provides the ability to receive packets asynchronously. Sends are not
+// buffered since it is acceptable to drop packets under high load.
+class AsyncPacketSocket : public sigslot::has_slots<> {
+public:
+ AsyncPacketSocket(AsyncSocket* socket);
+ virtual ~AsyncPacketSocket();
+
+ // Relevant socket methods:
+ virtual SocketAddress GetLocalAddress() const;
+ virtual SocketAddress GetRemoteAddress() const;
+ virtual int Bind(const SocketAddress& addr);
+ virtual int Connect(const SocketAddress& addr);
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+ virtual int Close();
+ virtual int SetOption(Socket::Option opt, int value);
+ virtual int GetError() const;
+ virtual void SetError(int error);
+
+ // Emitted each time a packet is read.
+ sigslot::signal4<const char*, size_t, const SocketAddress&, AsyncPacketSocket*> SignalReadPacket;
+
+protected:
+ AsyncSocket* socket_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCPACKETSOCKET_H__
diff --git a/third_party/libjingle/files/talk/base/asyncsocket.h b/third_party/libjingle/files/talk/base/asyncsocket.h
new file mode 100644
index 0000000..ad0dfb4
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncsocket.h
@@ -0,0 +1,91 @@
+/*
+ * 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 TALK_BASE_ASYNCSOCKET_H__
+#define TALK_BASE_ASYNCSOCKET_H__
+
+#include "talk/base/sigslot.h"
+#include "talk/base/socket.h"
+
+namespace talk_base {
+
+// Provides the ability to perform socket I/O asynchronously.
+class AsyncSocket : public Socket, public sigslot::has_slots<> {
+public:
+ virtual ~AsyncSocket() {}
+
+ sigslot::signal1<AsyncSocket*> SignalReadEvent; // ready to read
+ sigslot::signal1<AsyncSocket*> SignalWriteEvent; // ready to write
+ sigslot::signal1<AsyncSocket*> SignalConnectEvent; // connected
+ sigslot::signal2<AsyncSocket*,int> SignalCloseEvent; // closed
+ // TODO: error
+};
+
+class AsyncSocketAdapter : public AsyncSocket {
+public:
+ AsyncSocketAdapter(Socket * socket) : socket_(socket) {
+ }
+ AsyncSocketAdapter(AsyncSocket * socket) : socket_(socket) {
+ socket->SignalConnectEvent.connect(this, &AsyncSocketAdapter::OnConnectEvent);
+ socket->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent);
+ socket->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent);
+ socket->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent);
+ }
+ virtual ~AsyncSocketAdapter() { delete socket_; }
+
+ virtual SocketAddress GetLocalAddress() const { return socket_->GetLocalAddress(); }
+ virtual SocketAddress GetRemoteAddress() const { return socket_->GetRemoteAddress(); }
+
+ virtual int Bind(const SocketAddress& addr) { return socket_->Bind(addr); }
+ virtual int Connect(const SocketAddress& addr) {return socket_->Connect(addr); }
+ virtual int Send(const void *pv, size_t cb) { return socket_->Send(pv, cb); }
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { return socket_->SendTo(pv, cb, addr); }
+ virtual int Recv(void *pv, size_t cb) { return socket_->Recv(pv, cb); }
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { return socket_->RecvFrom(pv, cb, paddr); }
+ virtual int Listen(int backlog) { return socket_->Listen(backlog); }
+ virtual Socket *Accept(SocketAddress *paddr) { return socket_->Accept(paddr); }
+ virtual int Close() { return socket_->Close(); }
+ virtual int GetError() const { return socket_->GetError(); }
+ virtual void SetError(int error) { return socket_->SetError(error); }
+
+ virtual ConnState GetState() const { return socket_->GetState(); }
+
+ virtual int EstimateMTU(uint16* mtu) { return socket_->EstimateMTU(mtu); }
+ virtual int SetOption(Option opt, int value) { return socket_->SetOption(opt, value); }
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket) { SignalConnectEvent(this); }
+ virtual void OnReadEvent(AsyncSocket * socket) { SignalReadEvent(this); }
+ virtual void OnWriteEvent(AsyncSocket * socket) { SignalWriteEvent(this); }
+ virtual void OnCloseEvent(AsyncSocket * socket, int err) { SignalCloseEvent(this, err); }
+
+ Socket * socket_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCSOCKET_H__
diff --git a/third_party/libjingle/files/talk/base/asynctcpsocket.cc b/third_party/libjingle/files/talk/base/asynctcpsocket.cc
new file mode 100644
index 0000000..19f507a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asynctcpsocket.cc
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <cstring>
+
+#include "talk/base/asynctcpsocket.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+namespace talk_base {
+
+const size_t MAX_PACKET_SIZE = 64 * 1024;
+
+typedef uint16 PacketLength;
+const size_t PKT_LEN_SIZE = sizeof(PacketLength);
+
+const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
+
+AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) {
+ inbuf_ = new char[insize_];
+ outbuf_ = new char[outsize_];
+
+ ASSERT(socket_ != NULL);
+ socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent);
+ socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent);
+ socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent);
+ socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent);
+}
+
+AsyncTCPSocket::~AsyncTCPSocket() {
+ delete [] inbuf_;
+ delete [] outbuf_;
+}
+
+int AsyncTCPSocket::Send(const void *pv, size_t cb) {
+ if (cb > MAX_PACKET_SIZE) {
+ socket_->SetError(EMSGSIZE);
+ return -1;
+ }
+
+ // If we are blocking on send, then silently drop this packet
+ if (outpos_)
+ return static_cast<int>(cb);
+
+ PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
+ memcpy(outbuf_, &pkt_len, PKT_LEN_SIZE);
+ memcpy(outbuf_ + PKT_LEN_SIZE, pv, cb);
+ outpos_ = PKT_LEN_SIZE + cb;
+
+ int res = Flush();
+ if (res <= 0) {
+ // drop packet if we made no progress
+ outpos_ = 0;
+ return res;
+ }
+
+ // We claim to have sent the whole thing, even if we only sent partial
+ return static_cast<int>(cb);
+}
+
+int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ if (addr == GetRemoteAddress())
+ return Send(pv, cb);
+
+ ASSERT(false);
+ socket_->SetError(ENOTCONN);
+ return -1;
+}
+
+int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) {
+ if (outpos_ + cb > outsize_) {
+ socket_->SetError(EMSGSIZE);
+ return -1;
+ }
+
+ memcpy(outbuf_ + outpos_, pv, cb);
+ outpos_ += cb;
+
+ return Flush();
+}
+
+void AsyncTCPSocket::ProcessInput(char * data, size_t& len) {
+ SocketAddress remote_addr(GetRemoteAddress());
+
+ while (true) {
+ if (len < PKT_LEN_SIZE)
+ return;
+
+ PacketLength pkt_len;
+ memcpy(&pkt_len, data, PKT_LEN_SIZE);
+ pkt_len = NetworkToHost16(pkt_len);
+
+ if (len < PKT_LEN_SIZE + pkt_len)
+ return;
+
+ SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this);
+
+ len -= PKT_LEN_SIZE + pkt_len;
+ if (len > 0) {
+ memmove(data, data + PKT_LEN_SIZE + pkt_len, len);
+ }
+ }
+}
+
+int AsyncTCPSocket::Flush() {
+ int res = socket_->Send(outbuf_, outpos_);
+ if (res <= 0) {
+ return res;
+ }
+ if (static_cast<size_t>(res) <= outpos_) {
+ outpos_ -= res;
+ } else {
+ ASSERT(false);
+ return -1;
+ }
+ if (outpos_ > 0) {
+ memmove(outbuf_, outbuf_ + res, outpos_);
+ }
+ return res;
+}
+
+void AsyncTCPSocket::OnConnectEvent(AsyncSocket* socket) {
+ SignalConnect(this);
+}
+
+void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+
+ int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ if (!socket_->IsBlocking()) {
+ LOG(LS_ERROR) << "recvfrom: " << errno << " " << std::strerror(errno);
+ }
+ return;
+ }
+
+ inpos_ += len;
+
+ ProcessInput(inbuf_, inpos_);
+
+ if (inpos_ >= insize_) {
+ LOG(INFO) << "input buffer overflow";
+ ASSERT(false);
+ inpos_ = 0;
+ }
+}
+
+void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+
+ if (outpos_ > 0) {
+ Flush();
+ }
+}
+
+void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) {
+ SignalClose(this, error);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/asynctcpsocket.h b/third_party/libjingle/files/talk/base/asynctcpsocket.h
new file mode 100644
index 0000000..2509451
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asynctcpsocket.h
@@ -0,0 +1,68 @@
+/*
+ * 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 TALK_BASE_ASYNCTCPSOCKET_H__
+#define TALK_BASE_ASYNCTCPSOCKET_H__
+
+#include "talk/base/asyncpacketsocket.h"
+
+namespace talk_base {
+
+// Simulates UDP semantics over TCP. Send and Recv packet sizes
+// are preserved, and drops packets silently on Send, rather than
+// buffer them in user space.
+class AsyncTCPSocket : public AsyncPacketSocket {
+public:
+ AsyncTCPSocket(AsyncSocket* socket);
+ virtual ~AsyncTCPSocket();
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+
+ sigslot::signal1<AsyncTCPSocket*> SignalConnect;
+ sigslot::signal2<AsyncTCPSocket*,int> SignalClose;
+
+protected:
+ int SendRaw(const void * pv, size_t cb);
+ virtual void ProcessInput(char * data, size_t& len);
+
+private:
+ char* inbuf_, * outbuf_;
+ size_t insize_, inpos_, outsize_, outpos_;
+
+ int Flush();
+
+ // Called by the underlying socket
+ void OnConnectEvent(AsyncSocket* socket);
+ void OnReadEvent(AsyncSocket* socket);
+ void OnWriteEvent(AsyncSocket* socket);
+ void OnCloseEvent(AsyncSocket* socket, int error);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCTCPSOCKET_H__
diff --git a/third_party/libjingle/files/talk/base/asyncudpsocket.cc b/third_party/libjingle/files/talk/base/asyncudpsocket.cc
new file mode 100644
index 0000000..a0c967d
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncudpsocket.cc
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/logging.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+}
+#endif
+
+namespace talk_base {
+
+const int BUF_SIZE = 64 * 1024;
+
+AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket) {
+ size_ = BUF_SIZE;
+ buf_ = new char[size_];
+
+ assert(socket_);
+ // The socket should start out readable but not writable.
+ socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
+}
+
+AsyncUDPSocket::~AsyncUDPSocket() {
+ delete [] buf_;
+}
+
+void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
+ assert(socket == socket_);
+
+ SocketAddress remote_addr;
+ int len = socket_->RecvFrom(buf_, size_, &remote_addr);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ PLOG(LS_ERROR, socket_->GetError()) << "recvfrom";
+ return;
+ }
+
+ // TODO: Make sure that we got all of the packet. If we did not, then we
+ // should resize our buffer to be large enough.
+
+ SignalReadPacket(buf_, (size_t)len, remote_addr, this);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/asyncudpsocket.h b/third_party/libjingle/files/talk/base/asyncudpsocket.h
new file mode 100644
index 0000000..8232938
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/asyncudpsocket.h
@@ -0,0 +1,59 @@
+/*
+ * 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 TALK_BASE_ASYNCUDPSOCKET_H__
+#define TALK_BASE_ASYNCUDPSOCKET_H__
+
+#include "talk/base/asyncpacketsocket.h"
+#include "talk/base/socketfactory.h"
+
+namespace talk_base {
+
+// Provides the ability to receive packets asynchronously. Sends are not
+// buffered since it is acceptable to drop packets under high load.
+class AsyncUDPSocket : public AsyncPacketSocket {
+public:
+ AsyncUDPSocket(AsyncSocket* socket);
+ virtual ~AsyncUDPSocket();
+
+private:
+ char* buf_;
+ size_t size_;
+
+ // Called when the underlying socket is ready to be read from.
+ void OnReadEvent(AsyncSocket* socket);
+};
+
+// Creates a new socket for sending asynchronous UDP packets using an
+// asynchronous socket from the given factory.
+inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) {
+ return new AsyncUDPSocket(factory->CreateAsyncSocket(SOCK_DGRAM));
+}
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCUDPSOCKET_H__
diff --git a/third_party/libjingle/files/talk/base/autodetectproxy.cc b/third_party/libjingle/files/talk/base/autodetectproxy.cc
new file mode 100644
index 0000000..cda405f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/autodetectproxy.cc
@@ -0,0 +1,178 @@
+/*
+ * 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 "talk/base/autodetectproxy.h"
+#include "talk/base/httpcommon-inl.h"
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/base/proxydetect.h"
+
+using namespace talk_base;
+
+enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE };
+
+const talk_base::ProxyType TEST_ORDER[] = {
+ talk_base::PROXY_HTTPS, /*talk_base::PROXY_SOCKS5,*/ talk_base::PROXY_UNKNOWN
+};
+
+AutoDetectProxy::AutoDetectProxy(const std::string& user_agent)
+: agent_(user_agent), socket_(NULL), next_(0)
+{
+}
+
+AutoDetectProxy::~AutoDetectProxy() {
+ delete socket_;
+}
+
+void AutoDetectProxy::DoWork() {
+ if (!server_url_.empty()) {
+ LOG(LS_INFO) << "GetProxySettingsForUrl(" << server_url_ << ") - start";
+ GetProxySettingsForUrl(agent_.c_str(), server_url_.c_str(), proxy_, true);
+ LOG(LS_INFO) << "GetProxySettingsForUrl - stop";
+ }
+ talk_base::Url<char> url(proxy_.address.IPAsString());
+ if (url.valid()) {
+ LOG(LS_WARNING) << "AutoDetectProxy removing http prefix on proxy host";
+ proxy_.address.SetIP(url.server());
+ }
+ if (proxy_.type == talk_base::PROXY_UNKNOWN) {
+ //LOG(LS_INFO) << "Proxy classification start";
+ Next();
+ // Process I/O until Stop()
+ Thread::Current()->ProcessMessages(kForever);
+ }
+}
+
+void AutoDetectProxy::OnMessage(Message *msg) {
+ if (MSG_TIMEOUT == msg->message_id) {
+ OnCloseEvent(socket_, ETIMEDOUT);
+ } else {
+ SignalThread::OnMessage(msg);
+ }
+}
+
+void AutoDetectProxy::Next() {
+ if (TEST_ORDER[next_] >= talk_base::PROXY_UNKNOWN) {
+ Complete(talk_base::PROXY_UNKNOWN);
+ return;
+ }
+
+ LOG(LS_VERBOSE) << "AutoDetectProxy connecting to "
+ << proxy_.address.ToString();
+
+ if (socket_) {
+ Thread::Current()->Clear(this, MSG_TIMEOUT);
+ socket_->Close();
+ Thread::Current()->Dispose(socket_);
+ socket_ = NULL;
+ }
+
+ socket_ = Thread::Current()->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+ socket_->SignalConnectEvent.connect(this, &AutoDetectProxy::OnConnectEvent);
+ socket_->SignalReadEvent.connect(this, &AutoDetectProxy::OnReadEvent);
+ socket_->SignalCloseEvent.connect(this, &AutoDetectProxy::OnCloseEvent);
+ socket_->Connect(proxy_.address);
+
+ // Timeout after 2 seconds
+ Thread::Current()->PostDelayed(2000, this, MSG_TIMEOUT);
+}
+
+void AutoDetectProxy::Complete(talk_base::ProxyType type) {
+ Thread::Current()->Clear(this, MSG_TIMEOUT);
+ socket_->Close();
+
+ proxy_.type = type;
+ talk_base::LoggingSeverity sev
+ = (proxy_.type == talk_base::PROXY_UNKNOWN)
+ ? talk_base::LS_ERROR : talk_base::LS_VERBOSE;
+ LOG_V(sev) << "AutoDetectProxy detected " << proxy_.address.ToString()
+ << " as type " << proxy_.type;
+
+ Thread::Current()->Quit();
+}
+
+void AutoDetectProxy::OnConnectEvent(talk_base::AsyncSocket * socket) {
+ std::string probe;
+
+ switch (TEST_ORDER[next_]) {
+ case talk_base::PROXY_HTTPS:
+ probe.assign("\005\001"
+ "CONNECT www.google.com:443 HTTP/1.0\r\n"
+ "User-Agent: ");
+ probe.append(agent_);
+ probe.append("\r\n"
+ "Host: www.google.com\r\n"
+ "Content-Length: 0\r\n"
+ "Proxy-Connection: Keep-Alive\r\n"
+ "\r\n");
+ //probe = "CONNECT www.google.com:443 HTTP/1.0\r\n\r\n";
+ break;
+ case talk_base::PROXY_SOCKS5:
+ probe.assign("\005\001\000", 3);
+ break;
+ }
+
+ LOG(LS_VERBOSE) << "AutoDetectProxy probing type " << TEST_ORDER[next_]
+ << " sending " << probe.size() << " bytes";
+ socket_->Send(probe.data(), probe.size());
+}
+
+void AutoDetectProxy::OnReadEvent(talk_base::AsyncSocket * socket) {
+ char data[257];
+ int len = socket_->Recv(data, 256);
+ if (len > 0) {
+ data[len] = 0;
+ LOG(LS_VERBOSE) << "AutoDetectProxy read " << len << " bytes";
+ }
+
+ switch (TEST_ORDER[next_]) {
+ case talk_base::PROXY_HTTPS:
+ if ((len >= 2) && (data[0] == '\x05')) {
+ Complete(talk_base::PROXY_SOCKS5);
+ return;
+ }
+ if ((len >= 5) && (strncmp(data, "HTTP/", 5) == 0)) {
+ Complete(talk_base::PROXY_HTTPS);
+ return;
+ }
+ break;
+ case talk_base::PROXY_SOCKS5:
+ if ((len >= 2) && (data[0] == '\x05')) {
+ Complete(talk_base::PROXY_SOCKS5);
+ return;
+ }
+ break;
+ }
+
+ ++next_;
+ Next();
+}
+
+void AutoDetectProxy::OnCloseEvent(talk_base::AsyncSocket * socket, int error) {
+ LOG(LS_VERBOSE) << "AutoDetectProxy closed with error: " << error;
+ ++next_;
+ Next();
+}
diff --git a/third_party/libjingle/files/talk/base/autodetectproxy.h b/third_party/libjingle/files/talk/base/autodetectproxy.h
new file mode 100644
index 0000000..43d765e
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/autodetectproxy.h
@@ -0,0 +1,68 @@
+#ifndef _AUTODETECTPROXY_H_
+#define _AUTODETECTPROXY_H_
+
+#include "talk/base/sigslot.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/proxyinfo.h"
+#include "talk/base/signalthread.h"
+#include "talk/base/cryptstring.h"
+
+namespace buzz {
+class XmppClientSettings;
+}
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoDetectProxy
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncSocket;
+
+class AutoDetectProxy : public SignalThread {
+public:
+ AutoDetectProxy(const std::string& user_agent);
+
+ const talk_base::ProxyInfo& proxy() const { return proxy_; }
+
+ void set_server_url(const std::string& url) {
+ server_url_ = url;
+ }
+ void set_proxy(const SocketAddress& proxy) {
+ proxy_.type = PROXY_UNKNOWN;
+ proxy_.address = proxy;
+ }
+ void set_auth_info(bool use_auth, const std::string& username,
+ const CryptString& password) {
+ if (use_auth) {
+ proxy_.username = username;
+ proxy_.password = password;
+ }
+ }
+
+protected:
+ virtual ~AutoDetectProxy();
+
+ // SignalThread Interface
+ virtual void DoWork();
+ virtual void OnMessage(Message *msg);
+
+ void Next();
+ void Complete(ProxyType type);
+
+ void OnConnectEvent(AsyncSocket * socket);
+ void OnReadEvent(AsyncSocket * socket);
+ void OnCloseEvent(AsyncSocket * socket, int error);
+
+private:
+ std::string agent_, server_url_;
+ ProxyInfo proxy_;
+ AsyncSocket * socket_;
+ int next_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // _AUTODETECTPROXY_H_
diff --git a/third_party/libjingle/files/talk/base/base64.cc b/third_party/libjingle/files/talk/base/base64.cc
new file mode 100644
index 0000000..53e5bac
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/base64.cc
@@ -0,0 +1,196 @@
+
+//*********************************************************************
+//* Base64 - a simple base64 encoder and decoder.
+//*
+//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
+//*
+//* This code may be freely used for any purpose, either personal
+//* or commercial, provided the authors copyright notice remains
+//* intact.
+//*
+//* Enhancements by Stanley Yamane:
+//* o reverse lookup table for the decode function
+//* o reserve string buffer space in advance
+//*
+//*********************************************************************
+
+#include "talk/base/base64.h"
+
+using std::string;
+
+namespace talk_base {
+
+static const char fillchar = '=';
+static const string::size_type np = string::npos;
+
+const string Base64::Base64Table(
+ // 0000000000111111111122222222223333333333444444444455555555556666
+ // 0123456789012345678901234567890123456789012345678901234567890123
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+
+// Decode Table gives the index of any valid base64 character in the
+// Base64 table
+// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
+
+const string::size_type Base64::DecodeTable[] = {
+// 0 1 2 3 4 5 6 7 8 9
+ np,np,np,np,np,np,np,np,np,np, // 0 - 9
+ np,np,np,np,np,np,np,np,np,np, //10 -19
+ np,np,np,np,np,np,np,np,np,np, //20 -29
+ np,np,np,np,np,np,np,np,np,np, //30 -39
+ np,np,np,62,np,np,np,63,52,53, //40 -49
+ 54,55,56,57,58,59,60,61,np,np, //50 -59
+ np,np,np,np,np, 0, 1, 2, 3, 4, //60 -69
+ 5, 6, 7, 8, 9,10,11,12,13,14, //70 -79
+ 15,16,17,18,19,20,21,22,23,24, //80 -89
+ 25,np,np,np,np,np,np,26,27,28, //90 -99
+ 29,30,31,32,33,34,35,36,37,38, //100 -109
+ 39,40,41,42,43,44,45,46,47,48, //110 -119
+ 49,50,51,np,np,np,np,np,np,np, //120 -129
+ np,np,np,np,np,np,np,np,np,np, //130 -139
+ np,np,np,np,np,np,np,np,np,np, //140 -149
+ np,np,np,np,np,np,np,np,np,np, //150 -159
+ np,np,np,np,np,np,np,np,np,np, //160 -169
+ np,np,np,np,np,np,np,np,np,np, //170 -179
+ np,np,np,np,np,np,np,np,np,np, //180 -189
+ np,np,np,np,np,np,np,np,np,np, //190 -199
+ np,np,np,np,np,np,np,np,np,np, //200 -209
+ np,np,np,np,np,np,np,np,np,np, //210 -219
+ np,np,np,np,np,np,np,np,np,np, //220 -229
+ np,np,np,np,np,np,np,np,np,np, //230 -239
+ np,np,np,np,np,np,np,np,np,np, //240 -249
+ np,np,np,np,np,np //250 -256
+};
+
+string Base64::encodeFromArray(const char * data, size_t len) {
+ size_t i;
+ char c;
+ string ret;
+
+ ret.reserve(len * 2);
+
+ for (i = 0; i < len; ++i) {
+ c = (data[i] >> 2) & 0x3f;
+ ret.append(1, Base64Table[c]);
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 4) & 0x0f;
+ }
+
+ ret.append(1, Base64Table[c]);
+ if (i < len) {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 6) & 0x03;
+ }
+ ret.append(1, Base64Table[c]);
+ } else {
+ ++i;
+ ret.append(1, fillchar);
+ }
+
+ if (i < len) {
+ c = data[i] & 0x3f;
+ ret.append(1, Base64Table[c]);
+ } else {
+ ret.append(1, fillchar);
+ }
+ }
+
+ return(ret);
+}
+
+string Base64::encode(const string& data) {
+ string::size_type i;
+ char c;
+ string::size_type len = data.length();
+ string ret;
+
+ ret.reserve(len * 2);
+
+ for (i = 0; i < len; ++i) {
+ c = (data[i] >> 2) & 0x3f;
+ ret.append(1, Base64Table[c]);
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 4) & 0x0f;
+ }
+
+ ret.append(1, Base64Table[c]);
+ if (i < len) {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 6) & 0x03;
+ }
+
+ ret.append(1, Base64Table[c]);
+ } else {
+ ++i;
+ ret.append(1, fillchar);
+ }
+
+ if (i < len) {
+ c = data[i] & 0x3f;
+ ret.append(1, Base64Table[c]);
+ } else {
+ ret.append(1, fillchar);
+ }
+ }
+
+ return(ret);
+}
+
+string Base64::decode(const string& data) {
+ string::size_type i;
+ char c;
+ char c1;
+ string::size_type len = data.length();
+ string ret;
+
+ ret.reserve(len);
+
+ for (i = 0; i < len; ++i) {
+ do {
+ c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ } while (c == np && ++i < len);
+
+ ++i;
+
+ do {
+ c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ } while (c == np && ++i < len);
+
+ c = (c << 2) | ((c1 >> 4) & 0x3);
+ ret.append(1, c);
+ if (++i < len) {
+ c = data[i];
+ if (fillchar == c) {
+ break;
+ }
+
+ do {
+ c = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ } while (c == np && ++i < len);
+ c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
+ ret.append(1, c1);
+ }
+
+ if (++i < len) {
+ c1 = data[i];
+ if (fillchar == c1) {
+ break;
+ }
+
+ do {
+ c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(data[i])]);
+ } while (c == np && ++i < len);
+
+ c = ((c << 6) & 0xc0) | c1;
+ ret.append(1, c);
+ }
+ }
+
+ return(ret);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/base64.h b/third_party/libjingle/files/talk/base/base64.h
new file mode 100644
index 0000000..5b09eb2
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/base64.h
@@ -0,0 +1,32 @@
+
+//*********************************************************************
+//* C_Base64 - a simple base64 encoder and decoder.
+//*
+//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
+//*
+//* This code may be freely used for any purpose, either personal
+//* or commercial, provided the authors copyright notice remains
+//* intact.
+//*********************************************************************
+
+#ifndef TALK_BASE_BASE64_H__
+#define TALK_BASE_BASE64_H__
+
+#include <string>
+
+namespace talk_base {
+
+class Base64
+{
+public:
+ static std::string encode(const std::string & data);
+ static std::string decode(const std::string & data);
+ static std::string encodeFromArray(const char * data, size_t len);
+private:
+ static const std::string Base64Table;
+ static const std::string::size_type DecodeTable[];
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_BASE64_H__
diff --git a/third_party/libjingle/files/talk/base/basicdefs.h b/third_party/libjingle/files/talk/base/basicdefs.h
new file mode 100644
index 0000000..886c287
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/basicdefs.h
@@ -0,0 +1,37 @@
+/*
+ * 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 TALK_BASE_BASICDEFS_H__
+#define TAKL_BASE_BASICDEFS_H__
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
+
+#endif // TAKL_BASE_BASICDEFS_H__
diff --git a/third_party/libjingle/files/talk/base/basictypes.h b/third_party/libjingle/files/talk/base/basictypes.h
new file mode 100644
index 0000000..47588ad
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/basictypes.h
@@ -0,0 +1,85 @@
+/*
+ * 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 TALK_BASE_BASICTYPES_H__
+#define TALK_BASE_BASICTYPES_H__
+
+#ifdef COMPILER_MSVC
+typedef __int64 int64;
+#else
+typedef long long int64;
+#endif /* COMPILER_MSVC */
+typedef long int32;
+typedef short int16;
+typedef char int8;
+
+#ifdef COMPILER_MSVC
+typedef unsigned __int64 uint64;
+typedef __int64 int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif /* COMPILER_MSVC */
+typedef unsigned long uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+
+#ifdef WIN32
+typedef int socklen_t;
+#endif
+
+namespace talk_base {
+ template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
+ template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
+}
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ DISALLOW_EVIL_CONSTRUCTORS(TypeName)
+
+#ifndef UNUSED
+#define UNUSED(x) Unused(static_cast<const void *>(&x))
+#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
+#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
+#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
+#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
+inline void Unused(const void *) { }
+#endif // UNUSED
+
+#endif // TALK_BASE_BASICTYPES_H__
diff --git a/third_party/libjingle/files/talk/base/bytebuffer.cc b/third_party/libjingle/files/talk/base/bytebuffer.cc
new file mode 100644
index 0000000..7082e1a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/bytebuffer.cc
@@ -0,0 +1,166 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/bytebuffer.h"
+#include "talk/base/byteorder.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::memcpy;
+}
+#endif
+
+namespace talk_base {
+
+static const int DEFAULT_SIZE = 4096;
+
+ByteBuffer::ByteBuffer() {
+ start_ = 0;
+ end_ = 0;
+ size_ = DEFAULT_SIZE;
+ bytes_ = new char[size_];
+}
+
+ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
+ start_ = 0;
+ end_ = len;
+ size_ = len;
+ bytes_ = new char[size_];
+ memcpy(bytes_, bytes, end_);
+}
+
+ByteBuffer::ByteBuffer(const char* bytes) {
+ start_ = 0;
+ end_ = strlen(bytes);
+ size_ = end_;
+ bytes_ = new char[size_];
+ memcpy(bytes_, bytes, end_);
+}
+
+ByteBuffer::~ByteBuffer() {
+ delete bytes_;
+}
+
+bool ByteBuffer::ReadUInt8(uint8& val) {
+ return ReadBytes(reinterpret_cast<char*>(&val), 1);
+}
+
+bool ByteBuffer::ReadUInt16(uint16& val) {
+ uint16 v;
+ if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
+ return false;
+ } else {
+ val = NetworkToHost16(v);
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadUInt32(uint32& val) {
+ uint32 v;
+ if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
+ return false;
+ } else {
+ val = NetworkToHost32(v);
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadString(std::string& val, size_t len) {
+ if (len > Length()) {
+ return false;
+ } else {
+ val.append(bytes_ + start_, len);
+ start_ += len;
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadBytes(char* val, size_t len) {
+ if (len > Length()) {
+ return false;
+ } else {
+ memcpy(val, bytes_ + start_, len);
+ start_ += len;
+ return true;
+ }
+}
+
+void ByteBuffer::WriteUInt8(uint8 val) {
+ WriteBytes(reinterpret_cast<const char*>(&val), 1);
+}
+
+void ByteBuffer::WriteUInt16(uint16 val) {
+ uint16 v = HostToNetwork16(val);
+ WriteBytes(reinterpret_cast<const char*>(&v), 2);
+}
+
+void ByteBuffer::WriteUInt32(uint32 val) {
+ uint32 v = HostToNetwork32(val);
+ WriteBytes(reinterpret_cast<const char*>(&v), 4);
+}
+
+void ByteBuffer::WriteString(const std::string& val) {
+ WriteBytes(val.c_str(), val.size());
+}
+
+void ByteBuffer::WriteBytes(const char* val, size_t len) {
+ if (Length() + len > Capacity())
+ Resize(Length() + len);
+
+ memcpy(bytes_ + end_, val, len);
+ end_ += len;
+}
+
+void ByteBuffer::Resize(size_t size) {
+ if (size > size_)
+ size = _max(size, 3 * size_ / 2);
+
+ size_t len = _min(end_ - start_, size);
+ char* new_bytes = new char[size];
+ memcpy(new_bytes, bytes_ + start_, len);
+ delete [] bytes_;
+
+ start_ = 0;
+ end_ = len;
+ size_ = size;
+ bytes_ = new_bytes;
+}
+
+void ByteBuffer::Shift(size_t size) {
+ if (size > Length())
+ return;
+
+ end_ = Length() - size;
+ memmove(bytes_, bytes_ + start_ + size, end_);
+ start_ = 0;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/bytebuffer.h b/third_party/libjingle/files/talk/base/bytebuffer.h
new file mode 100644
index 0000000..0a93194
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/bytebuffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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 TALK_BASE_BYTEBUFFER_H__
+#define TALK_BASE_BYTEBUFFER_H__
+
+#include <string>
+#include "talk/base/basictypes.h"
+
+namespace talk_base {
+
+class ByteBuffer {
+public:
+ ByteBuffer();
+ ByteBuffer(const char* bytes, size_t len);
+ ByteBuffer(const char* bytes); // uses strlen
+ ~ByteBuffer();
+
+ const char* Data() const { return bytes_ + start_; }
+ size_t Length() { return end_ - start_; }
+ size_t Capacity() { return size_ - start_; }
+
+ bool ReadUInt8(uint8& val);
+ bool ReadUInt16(uint16& val);
+ bool ReadUInt32(uint32& val);
+ bool ReadString(std::string& val, size_t len); // append to val
+ bool ReadBytes(char* val, size_t len);
+
+ void WriteUInt8(uint8 val);
+ void WriteUInt16(uint16 val);
+ void WriteUInt32(uint32 val);
+ void WriteString(const std::string& val);
+ void WriteBytes(const char* val, size_t len);
+
+ void Resize(size_t size);
+ void Shift(size_t size);
+
+private:
+ char* bytes_;
+ size_t size_;
+ size_t start_;
+ size_t end_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_BYTEBUFFER_H__
diff --git a/third_party/libjingle/files/talk/base/byteorder.h b/third_party/libjingle/files/talk/base/byteorder.h
new file mode 100644
index 0000000..16834c2
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/byteorder.h
@@ -0,0 +1,63 @@
+/*
+ * 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 TALK_BASE_BYTEORDER_H__
+#define TALK_BASE_BYTEORDER_H__
+
+#include "talk/base/basictypes.h"
+
+#ifdef POSIX
+extern "C" {
+#include <arpa/inet.h>
+}
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+namespace talk_base {
+
+inline uint16 HostToNetwork16(uint16 n) {
+ return htons(n);
+}
+
+inline uint32 HostToNetwork32(uint32 n) {
+ return htonl(n);
+}
+
+inline uint16 NetworkToHost16(uint16 n) {
+ return ntohs(n);
+}
+
+inline uint32 NetworkToHost32(uint32 n) {
+ return ntohl(n);
+}
+
+} // namespace talk_base
+
+#endif // TALK_BASE_BYTEORDER_H__
diff --git a/third_party/libjingle/files/talk/base/common.cc b/third_party/libjingle/files/talk/base/common.cc
new file mode 100644
index 0000000..6d1f147
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/common.cc
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif // WIN32
+
+#include <algorithm>
+
+#include "talk/base/common.h"
+
+//////////////////////////////////////////////////////////////////////
+// Assertions
+//////////////////////////////////////////////////////////////////////
+
+namespace talk_base {
+
+void Break() {
+#ifdef WIN32
+ ::DebugBreak();
+#else // !WIN32
+#if _DEBUG_HAVE_BACKTRACE
+ OutputTrace();
+#endif
+ abort();
+#endif // !WIN32
+}
+
+void LogAssert(const char * function, const char * file, int line, const char * expression) {
+ // TODO - if we put hooks in here, we can do a lot fancier logging
+ fprintf(stderr, "%s(%d): %s @ %s\n", file, line, expression, function);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/common.h b/third_party/libjingle/files/talk/base/common.h
new file mode 100644
index 0000000..f85bf89
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/common.h
@@ -0,0 +1,114 @@
+/*
+ * 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 TALK_BASE_COMMON_H__
+#define TALK_BASE_COMMON_H__
+
+#if defined(_MSC_VER)
+// warning C4355: 'this' : used in base member initializer list
+#pragma warning(disable:4355)
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// General Utilities
+//////////////////////////////////////////////////////////////////////
+
+#ifndef UNUSED
+#define UNUSED(x) Unused(static_cast<const void *>(&x))
+#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
+#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
+#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
+#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
+inline void Unused(const void *) { }
+#endif // UNUSED
+
+#ifndef WIN32
+#define strnicmp(x,y,n) strncasecmp(x,y,n)
+#define stricmp(x,y) strcasecmp(x,y)
+#define stdmax(x,y) std::max(x,y)
+#else
+#define stdmax(x,y) _max(x,y)
+#endif
+
+
+#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
+
+/////////////////////////////////////////////////////////////////////////////
+// Assertions
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef ENABLE_DEBUG
+
+namespace talk_base {
+
+// Break causes the debugger to stop executing, or the program to abort
+void Break();
+
+// LogAssert writes information about an assertion to the log
+void LogAssert(const char * function, const char * file, int line, const char * expression);
+
+inline void Assert(bool result, const char * function, const char * file, int line, const char * expression) {
+ if (!result) {
+ LogAssert(function, file, line, expression);
+ Break();
+ }
+}
+
+}; // namespace talk_base
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#define __FUNCTION__ ""
+#endif
+
+#ifndef ASSERT
+#define ASSERT(x) talk_base::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
+#endif
+
+#ifndef VERIFY
+#define VERIFY(x) talk_base::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
+#endif
+
+#else // !ENABLE_DEBUG
+
+#ifndef ASSERT
+#define ASSERT(x) (void)0
+#endif
+
+#ifndef VERIFY
+#define VERIFY(x) (void)(x)
+#endif
+
+#endif // !ENABLE_DEBUG
+
+#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr]
+#define CTA_UNIQUE_NAME MAKE_NAME(__LINE__)
+#define CTA_MAKE_NAME(line) MAKE_NAME2(line)
+#define CTA_MAKE_NAME2(line) constraint_ ## line
+
+//////////////////////////////////////////////////////////////////////
+
+#endif // TALK_BASE_COMMON_H__
diff --git a/third_party/libjingle/files/talk/base/convert.h b/third_party/libjingle/files/talk/base/convert.h
new file mode 100644
index 0000000..26c6d32
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/convert.h
@@ -0,0 +1,149 @@
+/*
+ * libjingle
+ * Copyright 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.
+ */
+
+#ifndef _CONVERT_H_
+#define _CONVERT_H_
+
+#include <string>
+#include <windows.h>
+
+#ifndef NO_ATL
+#include <atlstr.h>
+#endif // NO_ATL
+
+#include "talk/base/basictypes.h"
+
+class Utf8 {
+public:
+#ifndef NO_ATL
+ explicit Utf8(const CString & str) {
+ *this = str;
+ }
+#else
+ explicit Utf8(const wchar_t *str) {
+ *this = str;
+ }
+#endif
+
+ explicit Utf8() {}
+#ifndef NO_ATL
+ inline Utf8& operator =(const CString & str) {
+ // TODO: deal with errors
+ int len8 = WideCharToMultiByte(CP_UTF8, 0, str.GetString(), str.GetLength(),
+ NULL, 0, NULL, NULL);
+ char * ns = static_cast<char*>(_alloca(len8));
+ WideCharToMultiByte(CP_UTF8, 0, str.GetString(), str.GetLength(),
+ ns, len8, NULL, NULL);
+ str_.assign(ns, len8);
+ return *this;
+ }
+#else
+inline Utf8& operator =(const wchar_t *str) {
+ // TODO: deal with errors
+ int len8 = WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str),
+ NULL, 0, NULL, NULL);
+ char * ns = static_cast<char*>(_alloca(len8));
+ WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str),
+ ns, len8, NULL, NULL);
+ str_.assign(ns, len8);
+ return *this;
+ }
+#endif // NO_ATL
+
+ inline operator const std::string & () const {
+ return str_;
+ }
+
+ inline const char * AsSz() const {
+ return str_.c_str();
+ }
+
+ // Deprecated
+ inline const std::string & AsString() const {
+ return str_;
+ }
+
+ // Deprecated
+ inline int Len8() const {
+ return (int)str_.length();
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Utf8);
+ std::string str_;
+};
+
+class Utf16 {
+public:
+ explicit Utf16(const std::string & str) {
+ // TODO: deal with errors
+ int len16 = MultiByteToWideChar(CP_UTF8, 0, str.data(), -1,
+ NULL, 0);
+#ifndef NO_ATL
+ wchar_t * ws = cstr_.GetBuffer(len16);
+ MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), ws, len16);
+ cstr_.ReleaseBuffer(len16);
+#else
+ str_ = new wchar_t[len16];
+ MultiByteToWideChar(CP_UTF8, 0, str.data(), -1, str_, len16);
+#endif
+ }
+
+#ifndef NO_ATL
+ inline operator const CString & () const {
+ return cstr_;
+ }
+ // Deprecated
+ inline const CString & AsCString() const {
+ return cstr_;
+ }
+ // Deprecated
+ inline int Len16() const {
+ return cstr_.GetLength();
+ }
+ inline const wchar_t * AsWz() const {
+ return cstr_.GetString();
+ }
+#else
+ ~Utf16() {
+ delete[] str_;
+ }
+ inline const wchar_t * AsWz() const {
+ return str_;
+ }
+#endif
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Utf16);
+#ifndef NO_ATL
+ CString cstr_;
+#else
+ wchar_t *str_;
+#endif
+};
+
+#endif // _CONVERT_H_
diff --git a/third_party/libjingle/files/talk/base/criticalsection.h b/third_party/libjingle/files/talk/base/criticalsection.h
new file mode 100644
index 0000000..9fa5aa5
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/criticalsection.h
@@ -0,0 +1,133 @@
+/*
+ * 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 TALK_BASE_CRITICALSECTION_H__
+#define TALK_BASE_CRITICALSECTION_H__
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+#ifdef POSIX
+#include <pthread.h>
+#endif
+
+#if !defined(NDEBUG)
+#define CS_TRACK_OWNER 1
+#endif // !defined(NDEBUG)
+
+#if CS_TRACK_OWNER
+#define TRACK_OWNER(x) x
+#else // !CS_TRACK_OWNER
+#define TRACK_OWNER(x)
+#endif // !CS_TRACK_OWNER
+
+namespace talk_base {
+
+#ifdef WIN32
+class CriticalSection {
+public:
+ CriticalSection() {
+ InitializeCriticalSection(&crit_);
+ // Windows docs say 0 is not a valid thread id
+ TRACK_OWNER(thread_ = 0);
+ }
+ ~CriticalSection() {
+ DeleteCriticalSection(&crit_);
+ }
+ void Enter() {
+ EnterCriticalSection(&crit_);
+ TRACK_OWNER(thread_ = GetCurrentThreadId());
+ }
+ void Leave() {
+ TRACK_OWNER(thread_ = 0);
+ LeaveCriticalSection(&crit_);
+ }
+
+#if CS_TRACK_OWNER
+ bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
+#endif // CS_TRACK_OWNER
+
+private:
+ CRITICAL_SECTION crit_;
+ TRACK_OWNER(DWORD thread_); // The section's owning thread id
+};
+#endif // WIN32
+
+#ifdef POSIX
+class CriticalSection {
+ public:
+ CriticalSection() {
+ pthread_mutexattr_t mutex_attribute;
+ pthread_mutexattr_init(&mutex_attribute);
+ pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mutex_, &mutex_attribute);
+ pthread_mutexattr_destroy(&mutex_attribute);
+ TRACK_OWNER(thread_ = 0);
+ }
+ ~CriticalSection() {
+ pthread_mutex_destroy(&mutex_);
+ }
+ void Enter() {
+ pthread_mutex_lock(&mutex_);
+ TRACK_OWNER(thread_ = pthread_self());
+ }
+ void Leave() {
+ TRACK_OWNER(thread_ = 0);
+ pthread_mutex_unlock(&mutex_);
+ }
+
+#if CS_TRACK_OWNER
+ bool CurrentThreadIsOwner() const {
+ return pthread_equal(thread_, pthread_self());
+ }
+#endif // CS_TRACK_OWNER
+
+ private:
+ pthread_mutex_t mutex_;
+ TRACK_OWNER(pthread_t thread_);
+};
+#endif // POSIX
+
+// CritScope, for serializing exection through a scope
+
+class CritScope {
+public:
+ CritScope(CriticalSection *pcrit) {
+ pcrit_ = pcrit;
+ pcrit_->Enter();
+ }
+ ~CritScope() {
+ pcrit_->Leave();
+ }
+private:
+ CriticalSection *pcrit_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_CRITICALSECTION_H__
diff --git a/third_party/libjingle/files/talk/base/cryptstring.h b/third_party/libjingle/files/talk/base/cryptstring.h
new file mode 100644
index 0000000..119483f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/cryptstring.h
@@ -0,0 +1,186 @@
+/*
+ * 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 _TALK_BASE_CRYPTSTRING_H_
+#define _TALK_BASE_CRYPTSTRING_H_
+
+#include <string.h>
+#include <string>
+#include "talk/base/linked_ptr.h"
+#include "talk/base/scoped_ptr.h"
+
+namespace talk_base {
+
+class CryptStringImpl {
+public:
+ virtual ~CryptStringImpl() {}
+ virtual size_t GetLength() const = 0;
+ virtual void CopyTo(char * dest, bool nullterminate) const = 0;
+ virtual std::string UrlEncode() const = 0;
+ virtual CryptStringImpl * Copy() const = 0;
+};
+
+class EmptyCryptStringImpl : public CryptStringImpl {
+public:
+ virtual ~EmptyCryptStringImpl() {}
+ virtual size_t GetLength() const { return 0; }
+ virtual void CopyTo(char * dest, bool nullterminate) const {
+ if (nullterminate) {
+ *dest = '\0';
+ }
+ }
+ virtual std::string UrlEncode() const { return ""; }
+ virtual CryptStringImpl * Copy() const { return new EmptyCryptStringImpl(); }
+};
+
+class CryptString {
+public:
+ CryptString() : impl_(new EmptyCryptStringImpl()) {}
+ size_t GetLength() const { return impl_->GetLength(); }
+ void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
+ CryptString(const CryptString & other) : impl_(other.impl_->Copy()) {}
+ explicit CryptString(const CryptStringImpl & impl) : impl_(impl.Copy()) {}
+ CryptString & operator=(const CryptString & other) {
+ if (this != &other) {
+ impl_.reset(other.impl_->Copy());
+ }
+ return *this;
+ }
+ void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
+ std::string UrlEncode() const { return impl_->UrlEncode(); }
+
+private:
+ scoped_ptr<const CryptStringImpl> impl_;
+};
+
+
+// Used for constructing strings where a password is involved and we
+// need to ensure that we zero memory afterwards
+class FormatCryptString {
+public:
+ FormatCryptString() {
+ storage_ = new char[32];
+ capacity_ = 32;
+ length_ = 0;
+ storage_[0] = 0;
+ }
+
+ void Append(const std::string & text) {
+ Append(text.data(), text.length());
+ }
+
+ void Append(const char * data, size_t length) {
+ EnsureStorage(length_ + length + 1);
+ memcpy(storage_ + length_, data, length);
+ length_ += length;
+ storage_[length_] = '\0';
+ }
+
+ void Append(const CryptString * password) {
+ size_t len = password->GetLength();
+ EnsureStorage(length_ + len + 1);
+ password->CopyTo(storage_ + length_, true);
+ length_ += len;
+ }
+
+ size_t GetLength() {
+ return length_;
+ }
+
+ const char * GetData() {
+ return storage_;
+ }
+
+
+ // Ensures storage of at least n bytes
+ void EnsureStorage(size_t n) {
+ if (capacity_ >= n) {
+ return;
+ }
+
+ size_t old_capacity = capacity_;
+ char * old_storage = storage_;
+
+ for (;;) {
+ capacity_ *= 2;
+ if (capacity_ >= n)
+ break;
+ }
+
+ storage_ = new char[capacity_];
+
+ if (old_capacity) {
+ memcpy(storage_, old_storage, length_);
+
+ // zero memory in a way that an optimizer won't optimize it out
+ old_storage[0] = 0;
+ for (size_t i = 1; i < old_capacity; i++) {
+ old_storage[i] = old_storage[i - 1];
+ }
+ delete[] old_storage;
+ }
+ }
+
+ ~FormatCryptString() {
+ if (capacity_) {
+ storage_[0] = 0;
+ for (size_t i = 1; i < capacity_; i++) {
+ storage_[i] = storage_[i - 1];
+ }
+ }
+ delete[] storage_;
+ }
+private:
+ char * storage_;
+ size_t capacity_;
+ size_t length_;
+};
+
+class InsecureCryptStringImpl : public CryptStringImpl {
+ public:
+ std::string& password() { return password_; }
+ const std::string& password() const { return password_; }
+
+ virtual ~InsecureCryptStringImpl() {}
+ virtual size_t GetLength() const { return password_.size(); }
+ virtual void CopyTo(char * dest, bool nullterminate) const {
+ memcpy(dest, password_.data(), password_.size());
+ if (nullterminate) dest[password_.size()] = 0;
+ }
+ virtual std::string UrlEncode() const { return password_; }
+ virtual CryptStringImpl * Copy() const {
+ InsecureCryptStringImpl * copy = new InsecureCryptStringImpl;
+ copy->password() = password_;
+ return copy;
+ }
+ private:
+ std::string password_;
+};
+
+}
+
+#endif // _TALK_BASE_CRYPTSTRING_H_
diff --git a/third_party/libjingle/files/talk/base/diskcache.cc b/third_party/libjingle/files/talk/base/diskcache.cc
new file mode 100644
index 0000000..3700d8e
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcache.cc
@@ -0,0 +1,362 @@
+/*
+ * 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 <time.h>
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+#include "talk/base/basicdefs.h"
+#include "talk/base/common.h"
+#include "talk/base/diskcache.h"
+#include "talk/base/fileutils.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/stream.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
+
+#if !defined(NDEBUG)
+#define TRANSPARENT_CACHE_NAMES 1
+#else // defined(NDEBUG)
+#define TRANSPARENT_CACHE_NAMES 0
+#endif // !defined(NDEBUG)
+
+namespace talk_base {
+
+class DiskCache;
+
+///////////////////////////////////////////////////////////////////////////////
+// DiskCacheAdapter
+///////////////////////////////////////////////////////////////////////////////
+
+class DiskCacheAdapter : public StreamAdapterInterface {
+public:
+ DiskCacheAdapter(const DiskCache* cache, const std::string& id, size_t index,
+ StreamInterface* stream)
+ : StreamAdapterInterface(stream), cache_(cache), id_(id), index_(index)
+ { }
+ virtual ~DiskCacheAdapter() {
+ Close();
+ cache_->ReleaseResource(id_, index_);
+ }
+
+private:
+ const DiskCache* cache_;
+ std::string id_;
+ size_t index_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// DiskCache
+///////////////////////////////////////////////////////////////////////////////
+
+DiskCache::DiskCache() : max_cache_(0), total_size_(0), total_accessors_(0) {
+}
+
+DiskCache::~DiskCache() {
+ ASSERT(0 == total_accessors_);
+}
+
+bool DiskCache::Initialize(const std::string& folder, size_t size) {
+ if (!folder_.empty() || !Filesystem::CreateFolder(folder))
+ return false;
+
+ folder_ = folder;
+ max_cache_ = size;
+ ASSERT(0 == total_size_);
+
+ if (!InitializeEntries())
+ return false;
+
+ return CheckLimit();
+}
+
+bool DiskCache::Purge() {
+ if (folder_.empty())
+ return false;
+
+ if (total_accessors_ > 0) {
+ LOG_F(LS_WARNING) << "Cache files open";
+ return false;
+ }
+
+ if (!PurgeFiles())
+ return false;
+
+ map_.clear();
+ return true;
+}
+
+bool DiskCache::LockResource(const std::string& id) {
+ Entry* entry = GetOrCreateEntry(id, true);
+ if (LS_LOCKED == entry->lock_state)
+ return false;
+ if ((LS_UNLOCKED == entry->lock_state) && (entry->accessors > 0))
+ return false;
+ if ((total_size_ > max_cache_) && !CheckLimit()) {
+ LOG_F(LS_WARNING) << "Cache overfull";
+ return false;
+ }
+ entry->lock_state = LS_LOCKED;
+ return true;
+}
+
+StreamInterface* DiskCache::WriteResource(const std::string& id, size_t index) {
+ Entry* entry = GetOrCreateEntry(id, false);
+ if (LS_LOCKED != entry->lock_state)
+ return NULL;
+
+ size_t previous_size = 0;
+ std::string filename(IdToFilename(id, index));
+ FileStream::GetSize(filename, &previous_size);
+ ASSERT(previous_size <= entry->size);
+ if (previous_size > entry->size) {
+ previous_size = entry->size;
+ }
+
+ scoped_ptr<FileStream> file(new FileStream);
+ if (!file->Open(filename, "wb")) {
+ LOG_F(LS_ERROR) << "Couldn't create cache file";
+ return NULL;
+ }
+
+ entry->streams = stdmax(entry->streams, index + 1);
+ entry->size -= previous_size;
+ total_size_ -= previous_size;
+
+ entry->accessors += 1;
+ total_accessors_ += 1;
+ return new DiskCacheAdapter(this, id, index, file.release());
+}
+
+bool DiskCache::UnlockResource(const std::string& id) {
+ Entry* entry = GetOrCreateEntry(id, false);
+ if (LS_LOCKED != entry->lock_state)
+ return false;
+
+ if (entry->accessors > 0) {
+ entry->lock_state = LS_UNLOCKING;
+ } else {
+ entry->lock_state = LS_UNLOCKED;
+ entry->last_modified = time(0);
+ CheckLimit();
+ }
+ return true;
+}
+
+StreamInterface* DiskCache::ReadResource(const std::string& id,
+ size_t index) const {
+ const Entry* entry = GetEntry(id);
+ if (LS_UNLOCKED != entry->lock_state)
+ return NULL;
+ if (index >= entry->streams)
+ return NULL;
+
+ scoped_ptr<FileStream> file(new FileStream);
+ if (!file->Open(IdToFilename(id, index), "rb"))
+ return NULL;
+
+ entry->accessors += 1;
+ total_accessors_ += 1;
+ return new DiskCacheAdapter(this, id, index, file.release());
+}
+
+bool DiskCache::HasResource(const std::string& id) const {
+ const Entry* entry = GetEntry(id);
+ return (NULL != entry) && (entry->streams > 0);
+}
+
+bool DiskCache::HasResourceStream(const std::string& id, size_t index) const {
+ const Entry* entry = GetEntry(id);
+ if ((NULL == entry) || (index >= entry->streams))
+ return false;
+
+ std::string filename = IdToFilename(id, index);
+
+ return FileExists(filename);
+}
+
+bool DiskCache::DeleteResource(const std::string& id) {
+ Entry* entry = GetOrCreateEntry(id, false);
+ if (!entry)
+ return true;
+
+ if ((LS_UNLOCKED != entry->lock_state) || (entry->accessors > 0))
+ return false;
+
+ bool success = true;
+ for (size_t index = 0; index < entry->streams; ++index) {
+ std::string filename = IdToFilename(id, index);
+
+ if (!FileExists(filename))
+ continue;
+
+ if (!DeleteFile(filename)) {
+ LOG_F(LS_ERROR) << "Couldn't remove cache file: " << filename;
+ success = false;
+ }
+ }
+
+ total_size_ -= entry->size;
+ map_.erase(id);
+ return success;
+}
+
+bool DiskCache::CheckLimit() {
+#if !defined(NDEBUG)
+ // Temporary check to make sure everything is working correctly.
+ size_t cache_size = 0;
+ for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) {
+ cache_size += it->second.size;
+ }
+ ASSERT(cache_size == total_size_);
+#endif // !defined(NDEBUG)
+
+ // TODO: Replace this with a non-brain-dead algorithm for clearing out the
+ // oldest resources... something that isn't O(n^2)
+ while (total_size_ > max_cache_) {
+ EntryMap::iterator oldest = map_.end();
+ for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) {
+ if ((LS_UNLOCKED != it->second.lock_state) || (it->second.accessors > 0))
+ continue;
+ oldest = it;
+ break;
+ }
+ if (oldest == map_.end()) {
+ LOG_F(LS_WARNING) << "All resources are locked!";
+ return false;
+ }
+ for (EntryMap::iterator it = oldest++; it != map_.end(); ++it) {
+ if (it->second.last_modified < oldest->second.last_modified) {
+ oldest = it;
+ }
+ }
+ if (!DeleteResource(oldest->first)) {
+ LOG_F(LS_ERROR) << "Couldn't delete from cache!";
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string DiskCache::IdToFilename(const std::string& id, size_t index) const {
+#ifdef TRANSPARENT_CACHE_NAMES
+ // This escapes colons and other filesystem characters, so the user can't open
+ // special devices (like "COM1:"), or access other directories.
+ size_t buffer_size = id.length()*3 + 1;
+ char* buffer = new char[buffer_size];
+ encode(buffer, buffer_size, id.data(), id.length(),
+ unsafe_filename_characters(), '%');
+ // TODO: ASSERT(strlen(buffer) < FileSystem::MaxBasenameLength());
+#else // !TRANSPARENT_CACHE_NAMES
+ // We might want to just use a hash of the filename at some point, both for
+ // obfuscation, and to avoid both filename length and escaping issues.
+ ASSERT(false);
+#endif // !TRANSPARENT_CACHE_NAMES
+
+ char extension[32];
+ sprintfn(extension, ARRAY_SIZE(extension), ".%u", index);
+
+ Pathname pathname;
+ pathname.SetFolder(folder_);
+ pathname.SetBasename(buffer);
+ pathname.SetExtension(extension);
+
+#ifdef TRANSPARENT_CACHE_NAMES
+ delete [] buffer;
+#endif // TRANSPARENT_CACHE_NAMES
+
+ return pathname.pathname();
+}
+
+bool DiskCache::FilenameToId(const std::string& filename, std::string* id,
+ size_t* index) const {
+ Pathname pathname(filename);
+ if (1 != sscanf(pathname.extension().c_str(), ".%zu", index))
+ return false;
+
+ size_t buffer_size = pathname.basename().length() + 1;
+ char* buffer = new char[buffer_size];
+ decode(buffer, buffer_size, pathname.basename().data(),
+ pathname.basename().length(), '%');
+ id->assign(buffer);
+ delete [] buffer;
+ return true;
+}
+
+DiskCache::Entry* DiskCache::GetOrCreateEntry(const std::string& id,
+ bool create) {
+ EntryMap::iterator it = map_.find(id);
+ if (it != map_.end())
+ return &it->second;
+ if (!create)
+ return NULL;
+ Entry e;
+ e.lock_state = LS_UNLOCKED;
+ e.accessors = 0;
+ e.size = 0;
+ e.streams = 0;
+ e.last_modified = time(0);
+ it = map_.insert(EntryMap::value_type(id, e)).first;
+ return &it->second;
+}
+
+void DiskCache::ReleaseResource(const std::string& id, size_t index) const {
+ const Entry* entry = GetEntry(id);
+ if (!entry) {
+ LOG_F(LS_WARNING) << "Missing cache entry";
+ ASSERT(false);
+ return;
+ }
+
+ entry->accessors -= 1;
+ total_accessors_ -= 1;
+
+ if (LS_UNLOCKED != entry->lock_state) {
+ // This is safe, because locked resources only issue WriteResource, which
+ // is non-const. Think about a better way to handle it.
+ DiskCache* this2 = const_cast<DiskCache*>(this);
+ Entry* entry2 = this2->GetOrCreateEntry(id, false);
+
+ size_t new_size = 0;
+ std::string filename(IdToFilename(id, index));
+ FileStream::GetSize(filename, &new_size);
+ entry2->size += new_size;
+ this2->total_size_ += new_size;
+
+ if ((LS_UNLOCKING == entry->lock_state) && (0 == entry->accessors)) {
+ entry2->last_modified = time(0);
+ entry2->lock_state = LS_UNLOCKED;
+ this2->CheckLimit();
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/diskcache.h b/third_party/libjingle/files/talk/base/diskcache.h
new file mode 100644
index 0000000..b42e3e0
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcache.h
@@ -0,0 +1,142 @@
+/*
+ * 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 TALK_BASE_DISKCACHE_H__
+#define TALK_BASE_DISKCACHE_H__
+
+#include <map>
+#include <string>
+
+#ifdef WIN32
+#undef UnlockResource
+#endif // WIN32
+
+namespace talk_base {
+
+class StreamInterface;
+
+///////////////////////////////////////////////////////////////////////////////
+// DiskCache - An LRU cache of streams, stored on disk.
+//
+// Streams are identified by a unique resource id. Multiple streams can be
+// associated with each resource id, distinguished by an index. When old
+// resources are flushed from the cache, all streams associated with those
+// resources are removed together.
+// DiskCache is designed to persist across executions of the program. It is
+// safe for use from an arbitrary number of users on a single thread, but not
+// from multiple threads or other processes.
+///////////////////////////////////////////////////////////////////////////////
+
+class DiskCache {
+public:
+ DiskCache();
+ ~DiskCache();
+
+ bool Initialize(const std::string& folder, size_t size);
+ bool Purge();
+
+ bool LockResource(const std::string& id);
+ StreamInterface* WriteResource(const std::string& id, size_t index);
+ bool UnlockResource(const std::string& id);
+
+ StreamInterface* ReadResource(const std::string& id, size_t index) const;
+
+ bool HasResource(const std::string& id) const;
+ bool HasResourceStream(const std::string& id, size_t index) const;
+ bool DeleteResource(const std::string& id);
+
+ protected:
+ virtual bool InitializeEntries() = 0;
+ virtual bool PurgeFiles() = 0;
+
+ virtual bool FileExists(const std::string& filename) const = 0;
+ virtual bool DeleteFile(const std::string& filename) const = 0;
+
+ enum LockState { LS_UNLOCKED, LS_LOCKED, LS_UNLOCKING };
+ struct Entry {
+ LockState lock_state;
+ mutable size_t accessors;
+ size_t size;
+ size_t streams;
+ time_t last_modified;
+ };
+ typedef std::map<std::string, Entry> EntryMap;
+ friend class DiskCacheAdapter;
+
+ bool CheckLimit();
+
+ std::string IdToFilename(const std::string& id, size_t index) const;
+ bool FilenameToId(const std::string& filename, std::string* id,
+ size_t* index) const;
+
+ const Entry* GetEntry(const std::string& id) const {
+ return const_cast<DiskCache*>(this)->GetOrCreateEntry(id, false);
+ }
+ Entry* GetOrCreateEntry(const std::string& id, bool create);
+
+ void ReleaseResource(const std::string& id, size_t index) const;
+
+ std::string folder_;
+ size_t max_cache_, total_size_;
+ EntryMap map_;
+ mutable size_t total_accessors_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CacheLock - Automatically manage locking and unlocking, with optional
+// rollback semantics
+///////////////////////////////////////////////////////////////////////////////
+
+class CacheLock {
+public:
+ CacheLock(DiskCache* cache, const std::string& id, bool rollback = false)
+ : cache_(cache), id_(id), rollback_(rollback)
+ {
+ locked_ = cache_->LockResource(id_);
+ }
+ ~CacheLock() {
+ if (locked_) {
+ cache_->UnlockResource(id_);
+ if (rollback_) {
+ cache_->DeleteResource(id_);
+ }
+ }
+ }
+ bool IsLocked() const { return locked_; }
+ void Commit() { rollback_ = false; }
+
+private:
+ DiskCache* cache_;
+ std::string id_;
+ bool rollback_, locked_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_DISKCACHE_H__
diff --git a/third_party/libjingle/files/talk/base/diskcache_win32.cc b/third_party/libjingle/files/talk/base/diskcache_win32.cc
new file mode 100644
index 0000000..ddc99ef
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcache_win32.cc
@@ -0,0 +1,76 @@
+#include "talk/base/win32.h"
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+
+#include <time.h>
+
+#include "talk/base/common.h"
+#include "talk/base/diskcache.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/stream.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
+
+#include "talk/base/diskcache_win32.h"
+
+namespace talk_base {
+
+bool DiskCacheWin32::InitializeEntries() {
+ // Note: We could store the cache information in a separate file, for faster
+ // initialization. Figuring it out empirically works, too.
+
+ std::wstring path16 = ToUtf16(folder_);
+ path16.append(1, '*');
+
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle = FindFirstFile(path16.c_str(), &find_data);
+ if (find_handle != INVALID_HANDLE_VALUE) {
+ do {
+ size_t index;
+ std::string id;
+ if (!FilenameToId(ToUtf8(find_data.cFileName), &id, &index))
+ continue;
+
+ Entry* entry = GetOrCreateEntry(id, true);
+ entry->size += find_data.nFileSizeLow;
+ total_size_ += find_data.nFileSizeLow;
+ entry->streams = _max(entry->streams, index + 1);
+ FileTimeToUnixTime(find_data.ftLastWriteTime, &entry->last_modified);
+
+ } while (FindNextFile(find_handle, &find_data));
+
+ FindClose(find_handle);
+ }
+
+ return true;
+}
+
+bool DiskCacheWin32::PurgeFiles() {
+ std::wstring path16 = ToUtf16(folder_);
+ path16.append(1, '*');
+ path16.append(1, '\0');
+
+ SHFILEOPSTRUCT file_op = { 0 };
+ file_op.wFunc = FO_DELETE;
+ file_op.pFrom = path16.c_str();
+ file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT
+ | FOF_NORECURSION | FOF_FILESONLY;
+ if (0 != SHFileOperation(&file_op)) {
+ LOG_F(LS_ERROR) << "Couldn't delete cache files";
+ return false;
+ }
+
+ return true;
+}
+
+bool DiskCacheWin32::FileExists(const std::string& filename) const {
+ DWORD result = ::GetFileAttributes(ToUtf16(filename).c_str());
+ return (INVALID_FILE_ATTRIBUTES != result);
+}
+
+bool DiskCacheWin32::DeleteFile(const std::string& filename) const {
+ return ::DeleteFile(ToUtf16(filename).c_str()) != 0;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/base/diskcache_win32.h b/third_party/libjingle/files/talk/base/diskcache_win32.h
new file mode 100644
index 0000000..aa5a1b6
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcache_win32.h
@@ -0,0 +1,28 @@
+//
+// DiskCacheWin32.h
+// Macshroom
+//
+// Created by Moishe Lettvin on 11/7/06.
+// Copyright (C) 2006 Google Inc. All rights reserved.
+//
+//
+
+#ifndef TALK_BASE_DISKCACHEWIN32_H__
+#define TALK_BASE_DISKCACHEWIN32_H__
+
+#include "talk/base/diskcache.h"
+
+namespace talk_base {
+
+class DiskCacheWin32 : public DiskCache {
+ protected:
+ virtual bool InitializeEntries();
+ virtual bool PurgeFiles();
+
+ virtual bool FileExists(const std::string& filename) const;
+ virtual bool DeleteFile(const std::string& filename) const;
+};
+
+}
+
+#endif // TALK_BASE_DISKCACHEWIN32_H__
diff --git a/third_party/libjingle/files/talk/base/diskcachestd.cc b/third_party/libjingle/files/talk/base/diskcachestd.cc
new file mode 100644
index 0000000..f50c7d7
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcachestd.cc
@@ -0,0 +1,30 @@
+//
+// DiskCacheStd.cc
+// Macshroom
+//
+// Created by Moishe Lettvin on 11/7/06.
+// Copyright (C) 2006 Google Inc. All rights reserved.
+//
+//
+
+#include "diskcachestd.h"
+
+namespace talk_base {
+
+bool DiskCacheStd::InitializeEntries() {
+ return false;
+}
+
+bool DiskCacheStd::PurgeFiles() {
+ return false;
+}
+
+bool DiskCacheStd::FileExists(const std::string& filename) const {
+ return false;
+}
+
+bool DiskCacheStd::DeleteFile(const std::string& filename) const {
+ return false;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/base/diskcachestd.h b/third_party/libjingle/files/talk/base/diskcachestd.h
new file mode 100644
index 0000000..b676771
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/diskcachestd.h
@@ -0,0 +1,28 @@
+//
+// DiskCacheStd.h
+// Macshroom
+//
+// Created by Moishe Lettvin on 11/7/06.
+// Copyright (C) 2006 Google Inc. All rights reserved.
+//
+//
+
+#ifndef TALK_BASE_DISKCACHESTD_H__
+#define TALK_BASE_DISKCACHESTD_H__
+
+#include "talk/base/diskcache.h"
+
+namespace talk_base {
+
+class DiskCacheStd : public DiskCache {
+ protected:
+ virtual bool InitializeEntries();
+ virtual bool PurgeFiles();
+
+ virtual bool FileExists(const std::string& filename) const;
+ virtual bool DeleteFile(const std::string& filename) const;
+};
+
+}
+
+#endif // TALK_BASE_DISKCACHESTD_H__
diff --git a/third_party/libjingle/files/talk/base/event.h b/third_party/libjingle/files/talk/base/event.h
new file mode 100644
index 0000000..ca15c38
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/event.h
@@ -0,0 +1,79 @@
+/*
+ * 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 TALK_BASE_EVENT_H__
+#define TALK_BASE_EVENT_H__
+
+namespace talk_base {
+
+#ifdef WIN32
+class Event {
+public:
+ Event() {
+ event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
+ }
+ ~Event() {
+ CloseHandle(event_);
+ }
+ void Set() {
+ SetEvent(event_);
+ }
+ void Reset() {
+ ResetEvent(event_);
+ }
+ void Wait() {
+ WaitForSingleObject(event_, INFINITE);
+ }
+private:
+ HANDLE event_;
+};
+#endif
+
+#ifdef POSIX
+#include <cassert>
+class Event {
+ Event() {
+ assert(false);
+ }
+ ~Event() {
+ assert(false);
+ }
+ void Set() {
+ assert(false);
+ }
+ void Reset() {
+ assert(false);
+ }
+ void Wait() {
+ assert(false);
+ }
+};
+#endif
+
+} // namespace talk_base
+
+#endif // TALK_BASE_EVENT_H__
diff --git a/third_party/libjingle/files/talk/base/fileutils.cc b/third_party/libjingle/files/talk/base/fileutils.cc
new file mode 100644
index 0000000..12c2576
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/fileutils.cc
@@ -0,0 +1,273 @@
+/*
+ * 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 <errno.h>
+#include <cassert>
+
+#ifdef WIN32
+#include "talk/base/convert.h"
+#endif
+
+#include "talk/base/pathutils.h"
+#include "talk/base/fileutils.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/stream.h"
+
+#include "talk/base/unixfilesystem.h"
+#include "talk/base/win32filesystem.h"
+
+#ifndef WIN32
+#define MAX_PATH 256
+#endif
+
+namespace talk_base {
+
+//////////////////////////
+// Directory Iterator //
+//////////////////////////
+
+// A Directoryraverser is created with a given directory. It originally points to
+// the first file in the directory, and can be advanecd with Next(). This allows you
+// to get information about each file.
+
+ // Constructor
+DirectoryIterator::DirectoryIterator() :
+#ifdef _WIN32
+ handle_(INVALID_HANDLE_VALUE)
+#else
+ dir_(NULL), dirent_(NULL)
+#endif
+{}
+
+ // Destructor
+DirectoryIterator::~DirectoryIterator() {
+#ifdef WIN32
+ if (handle_ != INVALID_HANDLE_VALUE)
+ ::FindClose(handle_);
+#else
+ if (dir_)
+ closedir(dir_);
+#endif
+}
+
+ // Starts traversing a directory.
+ // dir is the directory to traverse
+ // returns true if the directory exists and is valid
+bool DirectoryIterator::Iterate(const Pathname &dir) {
+ directory_ = dir.pathname();
+#ifdef WIN32
+ if (handle_ != INVALID_HANDLE_VALUE)
+ ::FindClose(handle_);
+ std::string d = dir.pathname() + '*';
+ handle_ = ::FindFirstFile(Utf16(d).AsWz(), &data_);
+ if (handle_ == INVALID_HANDLE_VALUE)
+ return false;
+#else
+ if (dir_ != NULL)
+ closedir(dir_);
+ dir_ = ::opendir(directory_.c_str());
+ if (dir_ == NULL)
+ return false;
+ dirent_ = readdir(dir_);
+ if (dirent_ == NULL)
+ return false;
+
+ if (::stat(std::string(directory_ + Name()).c_str(), &stat_) != 0)
+ return false;
+#endif
+ return true;
+}
+
+ // Advances to the next file
+ // returns true if there were more files in the directory.
+bool DirectoryIterator::Next() {
+#ifdef WIN32
+ return ::FindNextFile(handle_, &data_) == TRUE;
+#else
+ dirent_ = ::readdir(dir_);
+ if (dirent_ == NULL)
+ return false;
+
+ return ::stat(std::string(directory_ + Name()).c_str(), &stat_) == 0;
+#endif
+}
+
+ // returns true if the file currently pointed to is a directory
+bool DirectoryIterator::IsDirectory() const {
+#ifdef WIN32
+ return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
+#else
+ return S_ISDIR(stat_.st_mode);
+#endif
+}
+
+ // returns the name of the file currently pointed to
+std::string DirectoryIterator::Name() const {
+#ifdef WIN32
+ return Utf8(data_.cFileName).AsString();
+#else
+ assert(dirent_ != NULL);
+ return dirent_->d_name;
+#endif
+}
+
+ // returns the size of the file currently pointed to
+size_t DirectoryIterator::FileSize() const {
+#ifndef WIN32
+ return stat_.st_size;
+#else
+ return data_.nFileSizeLow;
+#endif
+}
+
+ // returns the last modified time of this file
+time_t DirectoryIterator::FileModifyTime() const {
+#ifdef WIN32
+return 0;
+#else
+ return stat_.st_mtime;
+#endif
+}
+
+Filesystem *Filesystem::default_filesystem_ = 0;
+
+
+bool Filesystem::CreateFolder(const Pathname &pathname)
+{
+ return EnsureDefaultFilesystem()->CreateFolderI(pathname);
+}
+
+FileStream *Filesystem::OpenFile(const Pathname &filename,
+ const std::string &mode)
+{
+ return EnsureDefaultFilesystem()->OpenFileI(filename, mode);
+}
+
+bool Filesystem::DeleteFile(const Pathname &filename)
+{
+ return EnsureDefaultFilesystem()->DeleteFileI(filename);
+}
+
+bool Filesystem::MoveFile(const Pathname &old_path, const Pathname &new_path)
+{
+ return EnsureDefaultFilesystem()->MoveFileI(old_path, new_path);
+}
+
+bool Filesystem::CopyFile(const Pathname &old_path, const Pathname &new_path)
+{
+ return EnsureDefaultFilesystem()->CopyFileI(old_path, new_path);
+}
+
+bool Filesystem::IsFolder(const Pathname& pathname)
+{
+ return EnsureDefaultFilesystem()->IsFolderI(pathname);
+}
+
+bool Filesystem::FileExists(const Pathname& pathname)
+{
+ return EnsureDefaultFilesystem()->FileExistsI(pathname);
+}
+
+bool Filesystem::IsTemporaryPath(const Pathname& pathname)
+{
+ return EnsureDefaultFilesystem()->IsTemporaryPathI(pathname);
+}
+
+bool Filesystem::GetTemporaryFolder(Pathname &path, bool create,
+ const std::string *append)
+{
+ return EnsureDefaultFilesystem()->GetTemporaryFolderI(path,create, append);
+}
+
+std::string Filesystem::TempFilename(const Pathname &dir, const std::string &prefix)
+{
+ return EnsureDefaultFilesystem()->TempFilenameI(dir, prefix);
+}
+
+bool Filesystem::GetFileSize(const Pathname &dir, size_t *size)
+{
+ return EnsureDefaultFilesystem()->GetFileSizeI(dir, size);
+}
+
+Filesystem *Filesystem::EnsureDefaultFilesystem()
+{
+ if (!default_filesystem_)
+#ifdef WIN32
+ default_filesystem_ = new Win32Filesystem();
+#else
+ default_filesystem_ = new UnixFilesystem();
+#endif
+ return default_filesystem_;
+}
+
+bool CreateUniqueFile(Pathname& path, bool create_empty) {
+ LOG(LS_INFO) << "Path " << path.pathname() << std::endl;
+ // If not folder is supplied, use the temporary folder
+ if (path.folder().empty()) {
+ Pathname temporary_path;
+ if (!Filesystem::GetTemporaryFolder(temporary_path, true, NULL)) {
+ printf("Get temp failed\n");
+ return false;
+ }
+ path.SetFolder(temporary_path.pathname());
+ }
+
+ // If not filename is supplied, use a temporary name
+ if (path.filename().empty()) {
+ std::string folder(path.folder());
+ std::string filename = Filesystem::TempFilename(folder, "gt");
+ path.SetFilename(filename);
+ if (!create_empty) {
+ Filesystem::DeleteFile(path.pathname());
+ }
+ return true;
+ }
+
+ // Otherwise, create a unique name based on the given filename
+ // foo.txt -> foo-N.txt
+ const std::string basename = path.basename();
+ const size_t MAX_VERSION = 100;
+ size_t version = 0;
+ while (version < MAX_VERSION) {
+ std::string pathname = path.pathname();
+
+ if (!Filesystem::FileExists(pathname)) {
+ if (create_empty) {
+ FileStream* fs = Filesystem::OpenFile(pathname,"w");
+ delete fs;
+ }
+ return true;
+ }
+ version += 1;
+ char version_base[MAX_PATH];
+ talk_base::sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u",
+ basename.c_str(), version);
+ path.SetBasename(version_base);
+ }
+ return true;
+}
+}
diff --git a/third_party/libjingle/files/talk/base/fileutils.h b/third_party/libjingle/files/talk/base/fileutils.h
new file mode 100644
index 0000000..868f4c2
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/fileutils.h
@@ -0,0 +1,185 @@
+/*
+ * 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 TALK_BASE_FILEUTILS_H__
+#define TALK_BASE_FILEUTILS_H__
+
+#include <string>
+
+#ifdef _WINDOWS
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include "talk/base/common.h"
+
+namespace talk_base {
+
+class FileStream;
+class Pathname;
+
+//////////////////////////
+// Directory Iterator //
+//////////////////////////
+
+// A DirectoryTraverser is created with a given directory. It originally points to
+// the first file in the directory, and can be advanecd with Next(). This allows you
+// to get information about each file.
+
+class DirectoryIterator {
+
+ public:
+ // Constructor
+ DirectoryIterator();
+
+ // Destructor
+ ~DirectoryIterator();
+
+ // Starts traversing a directory
+ // dir is the directory to traverse
+ // returns true if the directory exists and is valid
+ // The iterator will point to the first entry in the directory
+ bool Iterate(const Pathname &path);
+
+ // Advances to the next file
+ // returns true if there were more files in the directory.
+ bool Next();
+
+ // returns true if the file currently pointed to is a directory
+ bool IsDirectory() const;
+
+ // returns the name of the file currently pointed to
+ std::string Name() const;
+
+ // returns the size of the file currently pointed to
+ size_t FileSize() const;
+
+ // returns the last modified time of the file currently poitned to
+ time_t FileModifyTime() const;
+
+ private:
+ std::string directory_;
+#ifdef _WINDOWS
+ WIN32_FIND_DATA data_;
+ HANDLE handle_;
+#else
+ DIR *dir_;
+ struct dirent *dirent_;
+ struct stat stat_;
+#endif
+};
+
+class Filesystem {
+ public:
+
+ virtual bool CreateFolderI(const Pathname &pathname) = 0;
+
+ // Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
+ // returns NULL.
+ virtual FileStream *OpenFileI(const Pathname &filename,
+ const std::string &mode) = 0;
+
+ // This will attempt to delete the path located at filename. If filename is a file,
+ // it will be unlinked. If the path is a directory, it will recursively unlink and remove
+ // all the files and directory within it
+ virtual bool DeleteFileI(const Pathname &filename) = 0;
+
+ // Creates a directory. This will call itself recursively to create /foo/bar even if
+ // /foo does not exist.
+ // Returns TRUE if function succeeds
+
+ // This moves a file from old_path to new_path, where "file" can be a plain file
+ // or directory, which will be moved recursively.
+ // Returns true if function succeeds.
+ virtual bool MoveFileI(const Pathname &old_path, const Pathname &new_path) = 0;
+
+ // This copies a file from old_path to _new_path where "file" can be a plain file
+ // or directory, which will be copied recursively.
+ // Returns true if function succeeds
+ virtual bool CopyFileI(const Pathname &old_path, const Pathname &new_path) = 0;
+
+ // Returns true if a pathname is a directory
+ virtual bool IsFolderI(const Pathname& pathname) = 0;
+
+ // Returns true if a file exists at this path
+ virtual bool FileExistsI(const Pathname& pathname) = 0;
+
+ // Returns true if pathname represents a temporary location on the system.
+ virtual bool IsTemporaryPathI(const Pathname& pathname) = 0;
+
+ // A folder appropriate for storing temporary files (Contents are
+ // automatically deleted when the program exists)
+ virtual bool GetTemporaryFolderI(Pathname &path, bool create,
+ const std::string *append) = 0;
+
+ virtual std::string TempFilenameI(const Pathname &dir, const std::string &prefix) = 0;
+
+ virtual bool GetFileSizeI(const Pathname &dir, size_t *size) = 0;
+
+ static Filesystem *default_filesystem(void) { ASSERT(default_filesystem_!=NULL); return default_filesystem_; }
+ static void set_default_filesystem(Filesystem *filesystem) {default_filesystem_ = filesystem; }
+
+
+ static bool CreateFolder(const Pathname &pathname);
+
+ static FileStream *OpenFile(const Pathname &filename,
+ const std::string &mode);
+ static bool DeleteFile(const Pathname &filename);
+ static bool MoveFile(const Pathname &old_path, const Pathname &new_path);
+ static bool CopyFile(const Pathname &old_path, const Pathname &new_path);
+ static bool IsFolder(const Pathname& pathname);
+ static bool FileExists(const Pathname &pathname);
+ static bool IsTemporaryPath(const Pathname& pathname);
+ static bool GetTemporaryFolder(Pathname &path, bool create,
+ const std::string *append);
+ static std::string TempFilename(const Pathname &dir, const std::string &prefix);
+ static bool GetFileSize(const Pathname &dir, size_t *size);
+
+ private:
+ static Filesystem *default_filesystem_;
+ static Filesystem *EnsureDefaultFilesystem();
+
+};
+
+// Generates a unique temporary filename in 'directory' with the given 'prefix'
+ std::string TempFilename(const Pathname &dir, const std::string &prefix);
+
+ // Generates a unique filename based on the input path. If no path component
+ // is specified, it uses the temporary directory. If a filename is provided,
+ // up to 100 variations of form basename-N.extension are tried. When
+ // create_empty is true, an empty file of this name is created (which
+ // decreases the chance of a temporary filename collision with another
+ // process).
+ bool CreateUniqueFile(talk_base::Pathname& path, bool create_empty);
+
+}
+
+#endif // TALK_BASE_FILEUTILS_H__
diff --git a/third_party/libjingle/files/talk/base/firewallsocketserver.cc b/third_party/libjingle/files/talk/base/firewallsocketserver.cc
new file mode 100644
index 0000000..49db8a8
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/firewallsocketserver.cc
@@ -0,0 +1,213 @@
+/*
+ * 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 <cassert>
+#include <algorithm>
+#ifdef OSX
+#include <errno.h>
+#endif
+
+#include "talk/base/firewallsocketserver.h"
+#include "talk/base/asyncsocket.h"
+#include "talk/base/logging.h"
+
+namespace talk_base {
+
+class FirewallSocket : public AsyncSocketAdapter {
+public:
+ FirewallSocket(FirewallSocketServer * server, AsyncSocket * socket, int type)
+ : AsyncSocketAdapter(socket), server_(server), type_(type) {
+ }
+ FirewallSocket(FirewallSocketServer * server, Socket * socket, int type)
+ : AsyncSocketAdapter(socket), server_(server), type_(type) {
+ }
+
+ virtual int Connect(const SocketAddress& addr) {
+ if (type_ == SOCK_STREAM) {
+ if (!server_->Check(FP_TCP, FD_OUT, addr)) {
+ //LOG(INFO) << "FirewallSocket::Connect - Outbound TCP connection denied";
+ // Note: handle this asynchronously?
+ SetError(EHOSTUNREACH);
+ return SOCKET_ERROR;
+ }
+ }
+ return AsyncSocketAdapter::Connect(addr);
+ }
+ virtual int Send(const void * pv, size_t cb) {
+ if (type_ == SOCK_DGRAM) {
+ if (!server_->Check(FP_UDP, FD_OUT, GetRemoteAddress())) {
+ //LOG(INFO) << "FirewallSocket::Send - Outbound UDP packet dropped";
+ return static_cast<int>(cb);
+ }
+ }
+ return AsyncSocketAdapter::Send(pv, cb);
+ }
+ virtual int SendTo(const void * pv, size_t cb, const SocketAddress& addr) {
+ if (type_ == SOCK_DGRAM) {
+ if (!server_->Check(FP_UDP, FD_OUT, addr)) {
+ //LOG(INFO) << "FirewallSocket::SendTo - Outbound UDP packet dropped";
+ return static_cast<int>(cb);
+ }
+ }
+ return AsyncSocketAdapter::SendTo(pv, cb, addr);
+ }
+ virtual int Recv(void * pv, size_t cb) {
+ if (type_ == SOCK_DGRAM) {
+ if (!server_->Check(FP_UDP, FD_IN, GetRemoteAddress())) {
+ while (true) {
+ int res = AsyncSocketAdapter::Recv(pv, cb);
+ if (res <= 0)
+ return res;
+ //LOG(INFO) << "FirewallSocket::Recv - Inbound UDP packet dropped";
+ }
+ }
+ }
+ return AsyncSocketAdapter::Recv(pv, cb);
+ }
+ virtual int RecvFrom(void * pv, size_t cb, SocketAddress * paddr) {
+ if (type_ == SOCK_DGRAM) {
+ while (true) {
+ int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
+ if (res <= 0)
+ return res;
+ if (server_->Check(FP_UDP, FD_IN, *paddr))
+ return res;
+ //LOG(INFO) << "FirewallSocket::RecvFrom - Inbound UDP packet dropped";
+ }
+ }
+ return AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
+ }
+ virtual Socket * Accept(SocketAddress *paddr) {
+ while (Socket * sock = AsyncSocketAdapter::Accept(paddr)) {
+ if (server_->Check(FP_TCP, FD_IN, *paddr))
+ return sock;
+ sock->Close();
+ delete sock;
+ //LOG(INFO) << "FirewallSocket::Accept - Inbound TCP connection denied";
+ }
+ return 0;
+ }
+
+private:
+ FirewallSocketServer * server_;
+ int type_;
+};
+
+FirewallSocketServer::FirewallSocketServer(SocketServer * server, FirewallManager * manager) : server_(server), manager_(manager) {
+ if (manager_)
+ manager_->AddServer(this);
+}
+
+FirewallSocketServer::~FirewallSocketServer() {
+ if (manager_)
+ manager_->RemoveServer(this);
+}
+
+void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p, FirewallDirection d, const SocketAddress& addr) {
+ Rule r;
+ r.allow = allow;
+ r.p = p;
+ r.d = d;
+ r.addr = addr;
+ CritScope scope(&crit_);
+ rules_.push_back(r);
+}
+
+void FirewallSocketServer::ClearRules() {
+ CritScope scope(&crit_);
+ rules_.clear();
+}
+
+bool FirewallSocketServer::Check(FirewallProtocol p, FirewallDirection d, const SocketAddress& addr) {
+ CritScope scope(&crit_);
+ for (size_t i=0; i<rules_.size(); ++i) {
+ const Rule& r = rules_[i];
+ if ((r.p != p) && (r.p != FP_ANY))
+ continue;
+ if ((r.d != d) && (r.d != FD_ANY))
+ continue;
+ if ((r.addr.ip() != addr.ip()) && !r.addr.IsAny())
+ continue;
+ if ((r.addr.port() != addr.port()) && (r.addr.port() != 0))
+ continue;
+ return r.allow;
+ }
+ return true;
+}
+
+Socket* FirewallSocketServer::CreateSocket(int type) {
+ return WrapSocket(server_->CreateSocket(type), type);
+}
+
+AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
+ return WrapSocket(server_->CreateAsyncSocket(type), type);
+}
+
+Socket * FirewallSocketServer::WrapSocket(Socket * sock, int type) {
+ if (!sock)
+ return NULL;
+ return new FirewallSocket(this, sock, type);
+}
+
+AsyncSocket * FirewallSocketServer::WrapSocket(AsyncSocket * sock, int type) {
+ if (!sock)
+ return NULL;
+ return new FirewallSocket(this, sock, type);
+}
+
+FirewallManager::FirewallManager() {
+}
+
+FirewallManager::~FirewallManager() {
+ assert(servers_.empty());
+}
+
+void FirewallManager::AddServer(FirewallSocketServer * server) {
+ CritScope scope(&crit_);
+ servers_.push_back(server);
+}
+
+void FirewallManager::RemoveServer(FirewallSocketServer * server) {
+ CritScope scope(&crit_);
+ servers_.erase(std::remove(servers_.begin(), servers_.end(), server), servers_.end());
+}
+
+void FirewallManager::AddRule(bool allow, FirewallProtocol p, FirewallDirection d, const SocketAddress& addr) {
+ CritScope scope(&crit_);
+ for (std::vector<FirewallSocketServer *>::const_iterator it = servers_.begin(); it != servers_.end(); ++it) {
+ (*it)->AddRule(allow, p, d, addr);
+ }
+}
+
+void FirewallManager::ClearRules() {
+ CritScope scope(&crit_);
+ for (std::vector<FirewallSocketServer *>::const_iterator it = servers_.begin(); it != servers_.end(); ++it) {
+ (*it)->ClearRules();
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/firewallsocketserver.h b/third_party/libjingle/files/talk/base/firewallsocketserver.h
new file mode 100644
index 0000000..10c07e6
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/firewallsocketserver.h
@@ -0,0 +1,95 @@
+/*
+ * 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 TALK_BASE_FIREWALLSOCKETSERVER_H__
+#define TALK_BASE_FIREWALLSOCKETSERVER_H__
+
+#include <vector>
+#include "talk/base/socketserver.h"
+#include "talk/base/criticalsection.h"
+
+namespace talk_base {
+
+class FirewallManager;
+
+// This SocketServer shim simulates a rule-based firewall server
+
+enum FirewallProtocol { FP_UDP, FP_TCP, FP_ANY };
+enum FirewallDirection { FD_IN, FD_OUT, FD_ANY };
+
+class FirewallSocketServer : public SocketServer {
+public:
+ FirewallSocketServer(SocketServer * server, FirewallManager * manager = 0);
+ virtual ~FirewallSocketServer();
+
+ void AddRule(bool allow, FirewallProtocol p = FP_ANY, FirewallDirection d = FD_ANY, const SocketAddress& addr = SocketAddress());
+ void ClearRules();
+
+ bool Check(FirewallProtocol p, FirewallDirection d, const SocketAddress& addr);
+
+ virtual Socket* CreateSocket(int type);
+ virtual AsyncSocket* CreateAsyncSocket(int type);
+ virtual bool Wait(int cms, bool process_io) { return server_->Wait(cms, process_io); }
+ virtual void WakeUp() { return server_->WakeUp(); }
+
+ Socket * WrapSocket(Socket * sock, int type);
+ AsyncSocket * WrapSocket(AsyncSocket * sock, int type);
+
+private:
+ SocketServer * server_;
+ FirewallManager * manager_;
+ CriticalSection crit_;
+ struct Rule {
+ bool allow;
+ FirewallProtocol p;
+ FirewallDirection d;
+ SocketAddress addr;
+ };
+ std::vector<Rule> rules_;
+};
+
+// FirewallManager allows you to manage firewalls in multiple threads together
+
+class FirewallManager {
+public:
+ FirewallManager();
+ ~FirewallManager();
+
+ void AddServer(FirewallSocketServer * server);
+ void RemoveServer(FirewallSocketServer * server);
+
+ void AddRule(bool allow, FirewallProtocol p = FP_ANY, FirewallDirection d = FD_ANY, const SocketAddress& addr = SocketAddress());
+ void ClearRules();
+
+private:
+ CriticalSection crit_;
+ std::vector<FirewallSocketServer *> servers_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_FIREWALLSOCKETSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/helpers.cc b/third_party/libjingle/files/talk/base/helpers.cc
new file mode 100644
index 0000000..58b5485
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/helpers.cc
@@ -0,0 +1,149 @@
+/*
+ * 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/base/helpers.h"
+#include "talk/base/time.h"
+#include <cstdlib>
+#include <cassert>
+
+// TODO: Change this implementation to use OpenSSL's RAND_bytes. That will
+// give cryptographically random values on all platforms.
+
+#ifdef WIN32
+#include <time.h>
+#include <windows.h>
+#include <wincrypt.h>
+#endif
+
+namespace cricket {
+
+static long g_seed = 1L;
+
+int GetRandom() {
+ return ((g_seed = g_seed * 214013L + 2531011L) >> 16) & 0x7fff;
+}
+
+static bool s_initrandom;
+
+long GetRandomSeed() {
+ return g_seed;
+}
+
+void SetRandomSeed(unsigned long seed)
+{
+ s_initrandom = true;
+ g_seed = (long)seed;
+}
+
+void InitRandom(const char *client_unique, size_t len) {
+ // Hash this string - unique per client
+
+ uint32 hash = 0;
+ if (client_unique != NULL) {
+ for (int i = 0; i < (int)len; i++)
+ hash = ((hash << 2) + hash) + client_unique[i];
+ }
+
+ // Now initialize the seed against a high resolution
+ // counter
+
+ unsigned long seed = GetRandomSeed();
+
+#ifdef WIN32
+ bool success = false;
+ HCRYPTPROV hProv = NULL;
+ if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ success = (FALSE != CryptGenRandom(hProv,
+ sizeof(seed),
+ reinterpret_cast<BYTE*>(&seed)));
+ CryptReleaseContext(hProv, 0);
+ }
+
+ if (!success) {
+ LARGE_INTEGER big;
+ QueryPerformanceCounter(&big);
+ seed = big.LowPart;
+ }
+#else
+ seed = talk_base::Time();
+#endif
+
+ SetRandomSeed(seed ^ hash);
+}
+
+const char BASE64[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+// Generates a random string of the given length. We generate base64 values so
+// that they will be printable, though that's not necessary.
+
+std::string CreateRandomString(int len) {
+ // Random number generator should of been initialized!
+ assert(s_initrandom);
+ if (!s_initrandom)
+ InitRandom(0, 0);
+
+ std::string str;
+ for (int i = 0; i < len; i++)
+#if defined(_MSC_VER) && _MSC_VER < 1300
+ str.insert(str.end(), BASE64[GetRandom() & 63]);
+#else
+ str.push_back(BASE64[GetRandom() & 63]);
+#endif
+ return str;
+}
+
+uint32 CreateRandomId() {
+ uint8 b1 = (uint8)(GetRandom() & 255);
+ uint8 b2 = (uint8)(GetRandom() & 255);
+ uint8 b3 = (uint8)(GetRandom() & 255);
+ uint8 b4 = (uint8)(GetRandom() & 255);
+ return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+}
+
+bool IsBase64Char(char ch) {
+ return (('A' <= ch) && (ch <= 'Z')) ||
+ (('a' <= ch) && (ch <= 'z')) ||
+ (('0' <= ch) && (ch <= '9')) ||
+ (ch == '+') || (ch == '/');
+}
+
+bool IsBase64Encoded(const std::string& str) {
+ for (size_t i = 0; i < str.size(); ++i) {
+ if (!IsBase64Char(str.at(i)))
+ return false;
+ }
+ return true;
+}
+
+} // namespace cricket
diff --git a/third_party/libjingle/files/talk/base/helpers.h b/third_party/libjingle/files/talk/base/helpers.h
new file mode 100644
index 0000000..696edbe
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/helpers.h
@@ -0,0 +1,55 @@
+/*
+ * 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 __HELPERS_H__
+#define __HELPERS_H__
+
+#include "talk/base/basictypes.h"
+#include <string>
+
+namespace cricket {
+
+// srand initializer
+void InitRandom(const char *client_unique, size_t len);
+
+// For testing, the random seed can be directly accessed.
+long GetRandomSeed();
+void SetRandomSeed(unsigned long seed);
+
+// Generates a (cryptographically) random string of the given length.
+std::string CreateRandomString(int length);
+
+// Generates a random id
+uint32 CreateRandomId();
+
+// Determines whether the given string consists entirely of valid base64
+// encoded characters.
+bool IsBase64Encoded(const std::string& str);
+
+} // namespace cricket
+
+#endif // __HELPERS_H__
diff --git a/third_party/libjingle/files/talk/base/host.cc b/third_party/libjingle/files/talk/base/host.cc
new file mode 100644
index 0000000..e6fe648
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/host.cc
@@ -0,0 +1,101 @@
+/*
+ * 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 <string>
+#include <iostream>
+#include <cassert>
+#include <cstdlib>
+#include <errno.h>
+
+#ifdef POSIX
+extern "C" {
+#include <sys/utsname.h>
+}
+#endif // POSIX
+
+#include "talk/base/host.h"
+#include "talk/base/logging.h"
+#include "talk/base/network.h"
+#include "talk/base/socket.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std {
+ using ::strerror;
+ using ::exit;
+}
+#endif
+
+namespace talk_base {
+
+namespace {
+
+void FatalError(const std::string& name, int err) {
+ PLOG(LERROR, err) << name;
+ std::exit(1);
+}
+
+}
+
+#ifdef POSIX
+std::string GetHostName() {
+ struct utsname nm;
+ if (uname(&nm) < 0)
+ FatalError("uname", errno);
+ return std::string(nm.nodename);
+}
+#endif
+
+#ifdef WIN32
+std::string GetHostName() {
+ // TODO: fix this
+ return "cricket";
+}
+#endif
+
+// Records information about the local host.
+Host* gLocalHost = 0;
+
+const Host& LocalHost() {
+ if (!gLocalHost) {
+ std::vector<Network*>* networks = new std::vector<Network*>;
+ NetworkManager::CreateNetworks(*networks);
+#ifdef WIN32
+ // This is sort of problematic... one part of the code (the unittests) wants
+ // 127.0.0.1 to be present and another part (port allocators) don't. Right
+ // now, they use different APIs, so we can have different behavior. But
+ // there is something wrong with this.
+ networks->push_back(new Network("localhost",
+ SocketAddress::StringToIP("127.0.0.1")));
+#endif
+ gLocalHost = new Host(GetHostName(), networks);
+ assert(gLocalHost->networks().size() > 0);
+ }
+
+ return *gLocalHost;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/host.h b/third_party/libjingle/files/talk/base/host.h
new file mode 100644
index 0000000..7ee603d
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/host.h
@@ -0,0 +1,59 @@
+/*
+ * 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 TALK_BASE_HOST_H__
+#define TALK_BASE_HOST_H__
+
+#include <string>
+#include <vector>
+#include "talk/base/network.h"
+
+namespace talk_base {
+
+// Provides information about a host in the network.
+class Host {
+public:
+ Host(const std::string& name, std::vector<Network*>* networks)
+ : name_(name), networks_(networks) { }
+
+ const std::string& name() const { return name_; }
+ const std::vector<Network*>& networks() const { return *networks_; }
+
+private:
+ std::string name_;
+ std::vector<Network*>* networks_;
+};
+
+// Returns a reference to the description of the local host.
+const Host& LocalHost();
+
+// Returns the name of the local host.
+std::string GetHostName();
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HOST_H__
diff --git a/third_party/libjingle/files/talk/base/httpbase.cc b/third_party/libjingle/files/talk/base/httpbase.cc
new file mode 100644
index 0000000..4524036
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpbase.cc
@@ -0,0 +1,591 @@
+/*
+ * 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.
+ */
+
+#ifdef OSX
+#include <errno.h>
+#endif
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#else // !WIN32
+#define SEC_E_CERT_EXPIRED (-2146893016)
+#endif // !WIN32
+
+#include "talk/base/common.h"
+#include "talk/base/httpbase.h"
+#include "talk/base/logging.h"
+#include "talk/base/socket.h"
+#include "talk/base/stringutils.h"
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// Helpers
+//////////////////////////////////////////////////////////////////////
+
+bool MatchHeader(const char* str, size_t len, HttpHeader header) {
+ const char* const header_str = ToString(header);
+ const size_t header_len = strlen(header_str);
+ return (len == header_len) && (_strnicmp(str, header_str, header_len) == 0);
+}
+
+//////////////////////////////////////////////////////////////////////
+// HttpParser
+//////////////////////////////////////////////////////////////////////
+
+HttpParser::HttpParser() {
+ reset();
+}
+
+HttpParser::~HttpParser() {
+}
+
+void
+HttpParser::reset() {
+ state_ = ST_LEADER;
+ chunked_ = false;
+ data_size_ = SIZE_UNKNOWN;
+}
+
+bool
+HttpParser::process(const char* buffer, size_t len, size_t& processed,
+ HttpError& err) {
+ processed = 0;
+ err = HE_NONE;
+
+ if (state_ >= ST_COMPLETE) {
+ ASSERT(false);
+ return false;
+ }
+
+ while (true) {
+ if (state_ < ST_DATA) {
+ size_t pos = processed;
+ while ((pos < len) && (buffer[pos] != '\n')) {
+ pos += 1;
+ }
+ if (pos >= len) {
+ break; // don't have a full header
+ }
+ const char* line = buffer + processed;
+ size_t len = (pos - processed);
+ processed = pos + 1;
+ while ((len > 0) && isspace(static_cast<unsigned char>(line[len-1]))) {
+ len -= 1;
+ }
+ if (!process_line(line, len, err)) {
+ return false; // no more processing
+ }
+ } else if (data_size_ == 0) {
+ if (chunked_) {
+ state_ = ST_CHUNKTERM;
+ } else {
+ return false;
+ }
+ } else {
+ size_t available = len - processed;
+ if (available <= 0) {
+ break; // no more data
+ }
+ if ((data_size_ != SIZE_UNKNOWN) && (available > data_size_)) {
+ available = data_size_;
+ }
+ size_t read = 0;
+ err = onHttpRecvData(buffer + processed, available, read);
+ if (err != HE_NONE) {
+ return false; // error occurred
+ }
+ processed += read;
+ if (data_size_ != SIZE_UNKNOWN) {
+ data_size_ -= read;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+HttpParser::process_line(const char* line, size_t len, HttpError& err) {
+ switch (state_) {
+ case ST_LEADER:
+ state_ = ST_HEADERS;
+ err = onHttpRecvLeader(line, len);
+ break;
+
+ case ST_HEADERS:
+ if (len > 0) {
+ const char* value = strchrn(line, len, ':');
+ if (!value) {
+ err = HE_PROTOCOL;
+ break;
+ }
+ size_t nlen = (value - line);
+ const char* eol = line + len;
+ do {
+ value += 1;
+ } while ((value < eol) && isspace(static_cast<unsigned char>(*value)));
+ size_t vlen = eol - value;
+ if (MatchHeader(line, nlen, HH_CONTENT_LENGTH)) {
+ if (sscanf(value, "%zu", &data_size_) != 1) {
+ err = HE_PROTOCOL;
+ break;
+ }
+ } else if (MatchHeader(line, nlen, HH_TRANSFER_ENCODING)) {
+ if ((vlen == 7) && (_strnicmp(value, "chunked", 7) == 0)) {
+ chunked_ = true;
+ } else if ((vlen == 8) && (_strnicmp(value, "identity", 8) == 0)) {
+ chunked_ = false;
+ } else {
+ err = HE_PROTOCOL;
+ break;
+ }
+ }
+ err = onHttpRecvHeader(line, nlen, value, vlen);
+ } else {
+ state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
+ err = onHttpRecvHeaderComplete(chunked_, data_size_);
+ }
+ break;
+
+ case ST_CHUNKSIZE:
+ if (len > 0) {
+ char* ptr = NULL;
+ data_size_ = strtoul(line, &ptr, 16);
+ if (ptr != line + len) {
+ err = HE_PROTOCOL;
+ break;
+ }
+ state_ = (data_size_ == 0) ? ST_TRAILERS : ST_DATA;
+ } else {
+ err = HE_PROTOCOL;
+ }
+ break;
+
+ case ST_CHUNKTERM:
+ if (len > 0) {
+ err = HE_PROTOCOL;
+ } else {
+ state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
+ }
+ break;
+
+ case ST_TRAILERS:
+ if (len == 0) {
+ return false;
+ }
+ // err = onHttpRecvTrailer();
+ break;
+
+ default:
+ break;
+ }
+
+ return (err == HE_NONE);
+}
+
+void
+HttpParser::end_of_input() {
+ if ((state_ == ST_DATA) && (data_size_ == SIZE_UNKNOWN)) {
+ complete(HE_NONE);
+ } else {
+ complete(HE_DISCONNECTED);
+ }
+}
+
+void
+HttpParser::complete(HttpError err) {
+ if (state_ < ST_COMPLETE) {
+ state_ = ST_COMPLETE;
+ onHttpRecvComplete(err);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// HttpBase
+//////////////////////////////////////////////////////////////////////
+
+HttpBase::HttpBase() : mode_(HM_NONE), data_(NULL), notify_(NULL),
+ stream_(NULL) {
+}
+
+HttpBase::~HttpBase() {
+}
+
+bool
+HttpBase::isConnected() const {
+ return (stream_ != NULL) && (stream_->GetState() == SS_OPEN);
+}
+
+bool
+HttpBase::attach(StreamInterface* stream) {
+ if ((mode_ != HM_NONE) || (stream_ != NULL) || (stream == NULL)) {
+ ASSERT(false);
+ return false;
+ }
+ stream_ = stream;
+ stream_->SignalEvent.connect(this, &HttpBase::OnEvent);
+ mode_ = (stream_->GetState() == SS_OPENING) ? HM_CONNECT : HM_NONE;
+ return true;
+}
+
+StreamInterface*
+HttpBase::detach() {
+ if (mode_ != HM_NONE) {
+ ASSERT(false);
+ return NULL;
+ }
+ StreamInterface* stream = stream_;
+ stream_ = NULL;
+ if (stream) {
+ stream->SignalEvent.disconnect(this);
+ }
+ return stream;
+}
+
+/*
+bool
+HttpBase::accept(PNSocket& socket) {
+ if (mode_ != HM_NONE) {
+ ASSERT(false);
+ return false;
+ }
+
+ return socket.accept(stream_);
+}
+
+void
+HttpBase::connect(const SocketAddress& addr) {
+ if (mode_ != HM_NONE) {
+ ASSERT(false);
+ return;
+ }
+
+ mode_ = HM_CONNECT;
+
+ SocketAddress local;
+ if (!stream_.connect(local, addr) && !stream_.isBlocking()) {
+ onSocketConnect(&stream_, stream_.getError());
+ }
+}
+*/
+void
+HttpBase::send(HttpData* data) {
+ if (mode_ != HM_NONE) {
+ ASSERT(false);
+ return;
+ } else if (!isConnected()) {
+ OnEvent(stream_, SE_CLOSE, HE_DISCONNECTED);
+ return;
+ }
+
+ mode_ = HM_SEND;
+ data_ = data;
+ len_ = 0;
+ ignore_data_ = chunk_data_ = false;
+
+ std::string encoding;
+ if (data_->hasHeader(HH_TRANSFER_ENCODING, &encoding)
+ && (encoding == "chunked")) {
+ chunk_data_ = true;
+ }
+
+ len_ = data_->formatLeader(buffer_, sizeof(buffer_));
+ len_ += strcpyn(buffer_ + len_, sizeof(buffer_) - len_, "\r\n");
+ header_ = data_->begin();
+ queue_headers();
+
+ OnEvent(stream_, SE_WRITE, 0);
+}
+
+void
+HttpBase::recv(HttpData* data) {
+ if (mode_ != HM_NONE) {
+ ASSERT(false);
+ return;
+ } else if (!isConnected()) {
+ OnEvent(stream_, SE_CLOSE, HE_DISCONNECTED);
+ return;
+ }
+
+ mode_ = HM_RECV;
+ data_ = data;
+ len_ = 0;
+ ignore_data_ = chunk_data_ = false;
+
+ reset();
+ OnEvent(stream_, SE_READ, 0);
+}
+
+void
+HttpBase::abort(HttpError err) {
+ if (mode_ != HM_NONE) {
+ if (stream_ != NULL) {
+ stream_->Close();
+ }
+ do_complete(err);
+ }
+}
+
+void
+HttpBase::flush_data() {
+ while (true) {
+ for (size_t start = 0; start < len_; ) {
+ size_t written;
+ int error;
+ StreamResult result = stream_->Write(buffer_ + start, len_ - start,
+ &written, &error);
+ if (result == SR_SUCCESS) {
+ //LOG_F(LS_INFO) << "wrote " << res << " bytes";
+ start += written;
+ continue;
+ } else if (result == SR_BLOCK) {
+ //LOG_F(LS_INFO) << "blocking";
+ len_ -= start;
+ memmove(buffer_, buffer_ + start, len_);
+ return;
+ } else {
+ ASSERT(result == SR_ERROR);
+ LOG_F(LS_ERROR) << "error";
+ OnEvent(stream_, SE_CLOSE, error);
+ return;
+ }
+ }
+ len_ = 0;
+
+ // Check for more headers
+ if (header_ != data_->end()) {
+ queue_headers();
+ continue;
+ }
+
+ // Check for document data
+ if (!data_->document.get())
+ break;
+
+ size_t offset = 0, reserve = 0;
+ if (chunk_data_) {
+ // Reserve 10 characters at the start for 8-byte hex value and \r\n
+ offset = 10;
+ // ... and 2 characters at the end for \r\n
+ reserve = offset + 2;
+ ASSERT(reserve < sizeof(buffer_));
+ }
+
+ int error = 0;
+ StreamResult result = data_->document->Read(buffer_ + offset,
+ sizeof(buffer_) - reserve,
+ &len_, &error);
+ if (result == SR_SUCCESS) {
+ if (!chunk_data_)
+ continue;
+
+ // Prepend the length and append \r\n
+ sprintfn(buffer_, offset, "%.*x", (offset - 2), len_);
+ memcpy(buffer_ + offset - 2, "\r\n", 2);
+ memcpy(buffer_ + offset + len_, "\r\n", 2);
+ ASSERT(len_ + reserve <= sizeof(buffer_));
+ len_ += reserve;
+ } else if (result == SR_EOS) {
+ if (!chunk_data_)
+ break;
+
+ // Append the empty chunk and empty trailers, then turn off chunking.
+ len_ = sprintfn(buffer_, sizeof(buffer_), "0\r\n\r\n");
+ chunk_data_ = false;
+ } else {
+ LOG_F(LS_ERROR) << "Read error: " << error;
+ do_complete(HE_STREAM);
+ return;
+ }
+ }
+
+ do_complete();
+}
+
+void
+HttpBase::queue_headers() {
+ while (header_ != data_->end()) {
+ size_t len = sprintfn(buffer_ + len_, sizeof(buffer_) - len_,
+ "%.*s: %.*s\r\n",
+ header_->first.size(), header_->first.data(),
+ header_->second.size(), header_->second.data());
+ if (len_ + len < sizeof(buffer_) - 3) {
+ len_ += len;
+ ++header_;
+ } else if (len_ == 0) {
+ LOG(WARNING) << "discarding header that is too long: " << header_->first;
+ ++header_;
+ } else {
+ break;
+ }
+ }
+ if (header_ == data_->end()) {
+ len_ += strcpyn(buffer_ + len_, sizeof(buffer_) - len_, "\r\n");
+ }
+}
+
+void
+HttpBase::do_complete(HttpError err) {
+ ASSERT(mode_ != HM_NONE);
+ HttpMode mode = mode_;
+ mode_ = HM_NONE;
+ data_ = NULL;
+ if (notify_) {
+ notify_->onHttpComplete(mode, err);
+ }
+}
+
+void
+HttpBase::OnEvent(StreamInterface* stream, int events, int error) {
+ if ((events & SE_OPEN) && (mode_ == HM_CONNECT)) {
+ do_complete();
+ return;
+ }
+
+ if ((events & SE_WRITE) && (mode_ == HM_SEND)) {
+ flush_data();
+ return;
+ }
+
+ if ((events & SE_READ) && (mode_ == HM_RECV)) {
+ // Do to the latency between receiving read notifications from
+ // pseudotcpchannel, we rely on repeated calls to read in order to acheive
+ // ideal throughput. The number of reads is limited to prevent starving
+ // the caller.
+ size_t loop_count = 0;
+ const size_t kMaxReadCount = 20;
+ while (true) {
+ if (len_ >= sizeof(buffer_)) {
+ do_complete(HE_OVERFLOW);
+ return;
+ }
+ size_t read;
+ int error;
+ StreamResult result = stream_->Read(buffer_ + len_,
+ sizeof(buffer_) - len_,
+ &read, &error);
+ if ((result == SR_BLOCK) || (result == SR_EOS))
+ return;
+ if (result == SR_ERROR) {
+ OnEvent(stream_, SE_CLOSE, error);
+ return;
+ }
+ ASSERT(result == SR_SUCCESS);
+ //LOG(INFO) << "HttpBase << " << std::string(buffer_ + len_, res);
+ len_ += read;
+ HttpError herr;
+ bool more = process(buffer_, len_, read, herr);
+ len_ -= read;
+ memcpy(buffer_, buffer_ + read, len_);
+ if (!more) {
+ complete(herr);
+ return;
+ }
+ if (++loop_count > kMaxReadCount) {
+ LOG_F(LS_WARNING) << "danger of starvation";
+ break;
+ }
+ }
+ return;
+ }
+
+ if ((events & SE_CLOSE) == 0)
+ return;
+
+ if (stream_ != NULL) {
+ stream_->Close();
+ }
+ HttpError herr;
+ // TODO: Pass through errors instead of translating them?
+ if (error == 0) {
+ herr = HE_DISCONNECTED;
+ } else if (error == SOCKET_EACCES) {
+ herr = HE_AUTH;
+ } else if (error == SEC_E_CERT_EXPIRED) {
+ herr = HE_CERTIFICATE_EXPIRED;
+ } else {
+ LOG_F(LS_ERROR) << "SE_CLOSE error: " << error;
+ herr = HE_SOCKET;
+ }
+ if ((mode_ == HM_RECV) && (error == HE_NONE)) {
+ end_of_input();
+ } else if (mode_ != HM_NONE) {
+ do_complete(mkerr(herr, HE_DISCONNECTED));
+ } else if (notify_) {
+ notify_->onHttpClosed(mkerr(herr, HE_DISCONNECTED));
+ }
+}
+
+//
+// HttpParser Implementation
+//
+
+HttpError
+HttpBase::onHttpRecvLeader(const char* line, size_t len) {
+ return data_->parseLeader(line, len);
+}
+
+HttpError
+HttpBase::onHttpRecvHeader(const char* name, size_t nlen, const char* value,
+ size_t vlen) {
+ std::string sname(name, nlen), svalue(value, vlen);
+ data_->addHeader(sname, svalue);
+ //LOG(INFO) << sname << ": " << svalue;
+ return HE_NONE;
+}
+
+HttpError
+HttpBase::onHttpRecvHeaderComplete(bool chunked, size_t& data_size) {
+ return notify_ ? notify_->onHttpHeaderComplete(chunked, data_size) : HE_NONE;
+}
+
+HttpError
+HttpBase::onHttpRecvData(const char* data, size_t len, size_t& read) {
+ if (ignore_data_ || !data_->document.get()) {
+ read = len;
+ return HE_NONE;
+ }
+ int error = 0;
+ switch (data_->document->Write(data, len, &read, &error)) {
+ case SR_SUCCESS:
+ return HE_NONE;
+ case SR_EOS:
+ case SR_BLOCK:
+ LOG_F(LS_ERROR) << "Write EOS or block";
+ return HE_STREAM;
+ }
+ LOG_F(LS_ERROR) << "Write error: " << error;
+ return HE_STREAM;
+}
+
+void
+HttpBase::onHttpRecvComplete(HttpError err) {
+ do_complete(err);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/httpbase.h b/third_party/libjingle/files/talk/base/httpbase.h
new file mode 100644
index 0000000..64aefe9
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpbase.h
@@ -0,0 +1,142 @@
+/*
+ * 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 TALK_BASE_HTTPBASE_H__
+#define TALK_BASE_HTTPBASE_H__
+
+#include "talk/base/httpcommon.h"
+
+namespace talk_base {
+
+class StreamInterface;
+
+//////////////////////////////////////////////////////////////////////
+// HttpParser
+//////////////////////////////////////////////////////////////////////
+
+class HttpParser {
+public:
+ HttpParser();
+ virtual ~HttpParser();
+
+ void reset();
+ bool process(const char* buffer, size_t len, size_t& read, HttpError& err);
+ void end_of_input();
+ void complete(HttpError err);
+
+protected:
+ bool process_line(const char* line, size_t len, HttpError& err);
+
+ // HttpParser Interface
+ virtual HttpError onHttpRecvLeader(const char* line, size_t len) = 0;
+ virtual HttpError onHttpRecvHeader(const char* name, size_t nlen,
+ const char* value, size_t vlen) = 0;
+ virtual HttpError onHttpRecvHeaderComplete(bool chunked, size_t& data_size) = 0;
+ virtual HttpError onHttpRecvData(const char* data, size_t len, size_t& read) = 0;
+ virtual void onHttpRecvComplete(HttpError err) = 0;
+
+private:
+ enum State {
+ ST_LEADER, ST_HEADERS,
+ ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS,
+ ST_DATA, ST_COMPLETE
+ } state_;
+ bool chunked_;
+ size_t data_size_;
+};
+
+//////////////////////////////////////////////////////////////////////
+// IHttpNotify
+//////////////////////////////////////////////////////////////////////
+
+enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND };
+
+class IHttpNotify {
+public:
+ virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0;
+ virtual void onHttpComplete(HttpMode mode, HttpError err) = 0;
+ virtual void onHttpClosed(HttpError err) = 0;
+};
+
+//////////////////////////////////////////////////////////////////////
+// HttpBase
+//////////////////////////////////////////////////////////////////////
+
+class HttpBase : private HttpParser, public sigslot::has_slots<> {
+public:
+ HttpBase();
+ virtual ~HttpBase();
+
+ void notify(IHttpNotify* notify) { notify_ = notify; }
+ bool attach(StreamInterface* stream);
+ StreamInterface* stream() { return stream_; }
+ StreamInterface* detach();
+ bool isConnected() const;
+
+ void send(HttpData* data);
+ void recv(HttpData* data);
+ void abort(HttpError err);
+
+ HttpMode mode() const { return mode_; }
+
+ void set_ignore_data(bool ignore) { ignore_data_ = ignore; }
+ bool ignore_data() const { return ignore_data_; }
+
+protected:
+ void flush_data();
+ void queue_headers();
+ void do_complete(HttpError err = HE_NONE);
+
+ void OnEvent(StreamInterface* stream, int events, int error);
+
+ // HttpParser Interface
+ virtual HttpError onHttpRecvLeader(const char* line, size_t len);
+ virtual HttpError onHttpRecvHeader(const char* name, size_t nlen,
+ const char* value, size_t vlen);
+ virtual HttpError onHttpRecvHeaderComplete(bool chunked, size_t& data_size);
+ virtual HttpError onHttpRecvData(const char* data, size_t len, size_t& read);
+ virtual void onHttpRecvComplete(HttpError err);
+
+private:
+ enum { kBufferSize = 32 * 1024 };
+
+ HttpMode mode_;
+ HttpData* data_;
+ IHttpNotify* notify_;
+ StreamInterface* stream_;
+ char buffer_[kBufferSize];
+ size_t len_;
+
+ bool ignore_data_, chunk_data_;
+ HttpData::const_iterator header_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HTTPBASE_H__
diff --git a/third_party/libjingle/files/talk/base/httpclient.cc b/third_party/libjingle/files/talk/base/httpclient.cc
new file mode 100644
index 0000000..b833007
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpclient.cc
@@ -0,0 +1,716 @@
+/*
+ * 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 <time.h>
+
+#include "talk/base/httpcommon-inl.h"
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/common.h"
+#include "talk/base/diskcache.h"
+#include "talk/base/httpclient.h"
+#include "talk/base/logging.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/socketstream.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/basicdefs.h"
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// Helpers
+//////////////////////////////////////////////////////////////////////
+
+namespace {
+
+const size_t kCacheHeader = 0;
+const size_t kCacheBody = 1;
+
+std::string HttpAddress(const SocketAddress& address) {
+ return (address.port() == HTTP_DEFAULT_PORT)
+ ? address.hostname() : address.ToString();
+}
+
+// Convert decimal string to integer
+bool HttpStringToInt(const std::string& str, unsigned long* val) {
+ ASSERT(NULL != val);
+ char* eos = NULL;
+ *val = strtoul(str.c_str(), &eos, 10);
+ return (*eos == '\0');
+}
+
+bool HttpShouldCache(const HttpRequestData& request,
+ const HttpResponseData& response) {
+ bool verb_allows_cache = (request.verb == HV_GET)
+ || (request.verb == HV_HEAD);
+ bool is_range_response = response.hasHeader(HH_CONTENT_RANGE, NULL);
+ bool has_expires = response.hasHeader(HH_EXPIRES, NULL);
+ bool request_allows_cache =
+ has_expires || (std::string::npos != request.path.find('?'));
+ bool response_allows_cache =
+ has_expires || HttpCodeIsCacheable(response.scode);
+
+ bool may_cache = verb_allows_cache
+ && request_allows_cache
+ && response_allows_cache
+ && !is_range_response;
+
+ std::string value;
+ if (response.hasHeader(HH_CACHE_CONTROL, &value)) {
+ HttpAttributeList directives;
+ HttpParseAttributes(value.data(), value.size(), directives);
+ // Response Directives Summary:
+ // public - always cacheable
+ // private - do not cache in a shared cache
+ // no-cache - may cache, but must revalidate whether fresh or stale
+ // no-store - sensitive information, do not cache or store in any way
+ // max-age - supplants Expires for staleness
+ // s-maxage - use as max-age for shared caches, ignore otherwise
+ // must-revalidate - may cache, but must revalidate after stale
+ // proxy-revalidate - shared cache must revalidate
+ if (HttpHasAttribute(directives, "no-store", NULL)) {
+ may_cache = false;
+ } else if (HttpHasAttribute(directives, "public", NULL)) {
+ may_cache = true;
+ }
+ }
+ return may_cache;
+}
+
+enum HttpCacheState {
+ HCS_FRESH, // In cache, may use
+ HCS_STALE, // In cache, must revalidate
+ HCS_NONE // Not in cache
+};
+
+HttpCacheState HttpGetCacheState(const HttpRequestData& request,
+ const HttpResponseData& response) {
+ // Temporaries
+ std::string s_temp;
+ unsigned long i_temp;
+
+ // Current time
+ unsigned long now = time(0);
+
+ HttpAttributeList cache_control;
+ if (response.hasHeader(HH_CACHE_CONTROL, &s_temp)) {
+ HttpParseAttributes(s_temp.data(), s_temp.size(), cache_control);
+ }
+
+ // Compute age of cache document
+ unsigned long date;
+ if (!response.hasHeader(HH_DATE, &s_temp)
+ || !HttpDateToSeconds(s_temp, &date))
+ return HCS_NONE;
+
+ // TODO: Timestamp when cache request sent and response received?
+ unsigned long request_time = date;
+ unsigned long response_time = date;
+
+ unsigned long apparent_age = 0;
+ if (response_time > date) {
+ apparent_age = response_time - date;
+ }
+
+ unsigned long corrected_received_age = apparent_age;
+ if (response.hasHeader(HH_AGE, &s_temp)
+ && HttpStringToInt(s_temp, &i_temp)) {
+ corrected_received_age = stdmax(apparent_age, i_temp);
+ }
+
+ unsigned long response_delay = response_time - request_time;
+ unsigned long corrected_initial_age = corrected_received_age + response_delay;
+ unsigned long resident_time = now - response_time;
+ unsigned long current_age = corrected_initial_age + resident_time;
+
+ // Compute lifetime of document
+ unsigned long lifetime;
+ if (HttpHasAttribute(cache_control, "max-age", &s_temp)) {
+ lifetime = atoi(s_temp.c_str());
+ } else if (response.hasHeader(HH_EXPIRES, &s_temp)
+ && HttpDateToSeconds(s_temp, &i_temp)) {
+ lifetime = i_temp - date;
+ } else if (response.hasHeader(HH_LAST_MODIFIED, &s_temp)
+ && HttpDateToSeconds(s_temp, &i_temp)) {
+ // TODO: Issue warning 113 if age > 24 hours
+ lifetime = (now - i_temp) / 10;
+ } else {
+ return HCS_STALE;
+ }
+
+ return (lifetime > current_age) ? HCS_FRESH : HCS_STALE;
+}
+
+enum HttpValidatorStrength {
+ HVS_NONE,
+ HVS_WEAK,
+ HVS_STRONG
+};
+
+HttpValidatorStrength
+HttpRequestValidatorLevel(const HttpRequestData& request) {
+ if (HV_GET != request.verb)
+ return HVS_STRONG;
+ return request.hasHeader(HH_RANGE, NULL) ? HVS_STRONG : HVS_WEAK;
+}
+
+HttpValidatorStrength
+HttpResponseValidatorLevel(const HttpResponseData& response) {
+ std::string value;
+ if (response.hasHeader(HH_ETAG, &value)) {
+ bool is_weak = (strnicmp(value.c_str(), "W/", 2) == 0);
+ return is_weak ? HVS_WEAK : HVS_STRONG;
+ }
+ if (response.hasHeader(HH_LAST_MODIFIED, &value)) {
+ unsigned long last_modified, date;
+ if (HttpDateToSeconds(value, &last_modified)
+ && response.hasHeader(HH_DATE, &value)
+ && HttpDateToSeconds(value, &date)
+ && (last_modified + 60 < date)) {
+ return HVS_STRONG;
+ }
+ return HVS_WEAK;
+ }
+ return HVS_NONE;
+}
+
+std::string GetCacheID(const SocketAddress& server,
+ const HttpRequestData& request) {
+ std::string url;
+ url.append(ToString(request.verb));
+ url.append("_");
+ if ((_strnicmp(request.path.c_str(), "http://", 7) == 0)
+ || (_strnicmp(request.path.c_str(), "https://", 8) == 0)) {
+ url.append(request.path);
+ } else {
+ url.append("http://");
+ url.append(HttpAddress(server));
+ url.append(request.path);
+ }
+ return url;
+}
+
+} // anonymous namespace
+
+//////////////////////////////////////////////////////////////////////
+// HttpClient
+//////////////////////////////////////////////////////////////////////
+
+HttpClient::HttpClient(const std::string& agent, StreamPool* pool)
+: agent_(agent), pool_(pool), fail_redirect_(false), absolute_uri_(false),
+ cache_(NULL), cache_state_(CS_READY)
+{
+ base_.notify(this);
+}
+
+HttpClient::~HttpClient() {
+ base_.notify(NULL);
+ base_.abort(HE_SHUTDOWN);
+ release();
+}
+
+void HttpClient::reset() {
+ server_.Clear();
+ request_.clear(true);
+ response_.clear(true);
+ context_.reset();
+ base_.abort(HE_OPERATION_CANCELLED);
+}
+
+void HttpClient::set_server(const SocketAddress& address) {
+ server_ = address;
+ // Setting 'Host' here allows it to be overridden before starting the request,
+ // if necessary.
+ request_.setHeader(HH_HOST, HttpAddress(server_), true);
+}
+
+void HttpClient::start() {
+ if (base_.mode() != HM_NONE) {
+ // call reset() to abort an in-progress request
+ ASSERT(false);
+ return;
+ }
+
+ ASSERT(!IsCacheActive());
+
+ if (request_.hasHeader(HH_TRANSFER_ENCODING, NULL)) {
+ // Exact size must be known on the client. Instead of using chunked
+ // encoding, wrap data with auto-caching file or memory stream.
+ ASSERT(false);
+ return;
+ }
+
+ // If no content has been specified, using length of 0.
+ request_.setHeader(HH_CONTENT_LENGTH, "0", false);
+
+ request_.setHeader(HH_USER_AGENT, agent_, false);
+ request_.setHeader(HH_CONNECTION, "Keep-Alive", false);
+ if (_strnicmp(request_.path.c_str(), "http", 4) == 0) {
+ request_.setHeader(HH_PROXY_CONNECTION, "Keep-Alive", false);
+ }
+
+ bool absolute_uri = absolute_uri_;
+ if (PROXY_HTTPS == proxy_.type) {
+ request().version = HVER_1_0;
+ // Proxies require canonical form
+ absolute_uri = true;
+ }
+
+ // Convert to canonical form (if not already)
+ if (absolute_uri && (_strnicmp(request().path.c_str(), "http://", 7) != 0)) {
+ std::string canonical_path("http://");
+ canonical_path.append(HttpAddress(server_));
+ canonical_path.append(request().path);
+ request().path = canonical_path;
+ }
+
+ if ((NULL != cache_) && CheckCache()) {
+ return;
+ }
+
+ int stream_err;
+ StreamInterface* stream = pool_->RequestConnectedStream(server_, &stream_err);
+ if (stream == NULL) {
+ if (stream_err)
+ LOG(LS_ERROR) << "RequestConnectedStream returned: " << stream_err;
+ onHttpComplete(HM_CONNECT, (stream_err == 0) ? HE_NONE : HE_SOCKET);
+ } else {
+ base_.attach(stream);
+ if (stream->GetState() == SS_OPEN) {
+ base_.send(&request_);
+ }
+ }
+}
+
+void HttpClient::prepare_get(const std::string& url) {
+ reset();
+ Url<char> purl(url);
+ set_server(SocketAddress(purl.server(), purl.port(), false));
+ request().verb = HV_GET;
+ request().path = purl.full_path();
+}
+
+void HttpClient::prepare_post(const std::string& url,
+ const std::string& content_type,
+ StreamInterface* request_doc) {
+ reset();
+ Url<char> purl(url);
+ set_server(SocketAddress(purl.server(), purl.port(), false));
+ request().verb = HV_POST;
+ request().path = purl.full_path();
+ request().setContent(content_type, request_doc);
+}
+
+void HttpClient::release() {
+ if (StreamInterface* stream = base_.detach()) {
+ pool_->ReturnConnectedStream(stream);
+ }
+}
+
+bool HttpClient::BeginCacheFile() {
+ ASSERT(NULL != cache_);
+ ASSERT(CS_READY == cache_state_);
+
+ std::string id = GetCacheID(server_, request_);
+ CacheLock lock(cache_, id, true);
+ if (!lock.IsLocked()) {
+ LOG_F(LS_WARNING) << "Couldn't lock cache";
+ return false;
+ }
+
+ if (HE_NONE != WriteCacheHeaders(id)) {
+ return false;
+ }
+
+ scoped_ptr<StreamInterface> stream(cache_->WriteResource(id, kCacheBody));
+ if (!stream.get()) {
+ LOG_F(LS_ERROR) << "Couldn't open body cache";
+ return false;
+ }
+ lock.Commit();
+
+ // Let's secretly replace the response document with Folgers Crystals,
+ // er, StreamTap, so that we can mirror the data to our cache.
+ StreamInterface* output = response_.document.release();
+ if (!output) {
+ output = new NullStream;
+ }
+ StreamTap* tap = new StreamTap(output, stream.release());
+ response_.document.reset(tap);
+ return true;
+}
+
+HttpError HttpClient::WriteCacheHeaders(const std::string& id) {
+ scoped_ptr<StreamInterface> stream(cache_->WriteResource(id, kCacheHeader));
+ if (!stream.get()) {
+ LOG_F(LS_ERROR) << "Couldn't open header cache";
+ return HE_CACHE;
+ }
+
+ // Write all unknown and end-to-end headers to a cache file
+ for (HttpData::const_iterator it = response_.begin();
+ it != response_.end(); ++it) {
+ HttpHeader header;
+ if (FromString(header, it->first) && !HttpHeaderIsEndToEnd(header))
+ continue;
+ std::string formatted_header(it->first);
+ formatted_header.append(": ");
+ formatted_header.append(it->second);
+ formatted_header.append("\r\n");
+ StreamResult result = stream->WriteAll(formatted_header.data(),
+ formatted_header.length(),
+ NULL, NULL);
+ if (SR_SUCCESS != result) {
+ LOG_F(LS_ERROR) << "Couldn't write header cache";
+ return HE_CACHE;
+ }
+ }
+
+ return HE_NONE;
+}
+
+void HttpClient::CompleteCacheFile() {
+ // Restore previous response document
+ StreamTap* tap = static_cast<StreamTap*>(response_.document.release());
+ response_.document.reset(tap->Detach());
+
+ int error;
+ StreamResult result = tap->GetTapResult(&error);
+
+ // Delete the tap and cache stream (which completes cache unlock)
+ delete tap;
+
+ if (SR_SUCCESS != result) {
+ LOG(LS_ERROR) << "Cache file error: " << error;
+ cache_->DeleteResource(GetCacheID(server_, request_));
+ }
+}
+
+bool HttpClient::CheckCache() {
+ ASSERT(NULL != cache_);
+ ASSERT(CS_READY == cache_state_);
+
+ std::string id = GetCacheID(server_, request_);
+ if (!cache_->HasResource(id)) {
+ // No cache file available
+ return false;
+ }
+
+ HttpError error = ReadCacheHeaders(id, true);
+
+ if (HE_NONE == error) {
+ switch (HttpGetCacheState(request_, response_)) {
+ case HCS_FRESH:
+ // Cache content is good, read from cache
+ break;
+ case HCS_STALE:
+ // Cache content may be acceptable. Issue a validation request.
+ if (PrepareValidate()) {
+ return false;
+ }
+ // Couldn't validate, fall through.
+ case HCS_NONE:
+ // Cache content is not useable. Issue a regular request.
+ response_.clear(false);
+ return false;
+ }
+ }
+
+ if (HE_NONE == error) {
+ error = ReadCacheBody(id);
+ cache_state_ = CS_READY;
+ }
+
+ if (HE_CACHE == error) {
+ LOG_F(LS_WARNING) << "Cache failure, continuing with normal request";
+ response_.clear(false);
+ return false;
+ }
+
+ SignalHttpClientComplete(this, error);
+ return true;
+}
+
+HttpError HttpClient::ReadCacheHeaders(const std::string& id, bool override) {
+ scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheHeader));
+ if (!stream.get()) {
+ return HE_CACHE;
+ }
+
+ HttpData::HeaderCombine combine =
+ override ? HttpData::HC_REPLACE : HttpData::HC_AUTO;
+
+ while (true) {
+ std::string formatted_header;
+ StreamResult result = stream->ReadLine(&formatted_header);
+ if (SR_EOS == result)
+ break;
+
+ if (SR_SUCCESS != result) {
+ LOG_F(LS_ERROR) << "ReadLine error in cache headers";
+ return HE_CACHE;
+ }
+ size_t end_of_name = formatted_header.find(':');
+ if (std::string::npos == end_of_name) {
+ LOG_F(LS_WARNING) << "Malformed cache header";
+ continue;
+ }
+ size_t start_of_value = end_of_name + 1;
+ size_t end_of_value = formatted_header.length();
+ while ((start_of_value < end_of_value)
+ && isspace(formatted_header[start_of_value]))
+ ++start_of_value;
+ while ((start_of_value < end_of_value)
+ && isspace(formatted_header[end_of_value-1]))
+ --end_of_value;
+ size_t value_length = end_of_value - start_of_value;
+
+ std::string name(formatted_header.substr(0, end_of_name));
+ std::string value(formatted_header.substr(start_of_value, value_length));
+ response_.changeHeader(name, value, combine);
+ }
+
+ response_.scode = HC_OK;
+ return HE_NONE;
+}
+
+HttpError HttpClient::ReadCacheBody(const std::string& id) {
+ cache_state_ = CS_READING;
+
+ HttpError error = HE_NONE;
+
+ size_t data_size;
+ scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheBody));
+ if (!stream.get() || !stream->GetSize(&data_size)) {
+ LOG_F(LS_ERROR) << "Unavailable cache body";
+ error = HE_CACHE;
+ } else {
+ error = OnHeaderAvailable(false, false, data_size);
+ }
+
+ if ((HE_NONE == error)
+ && (HV_HEAD != request_.verb)
+ && (NULL != response_.document.get())) {
+ char buffer[1024 * 64];
+ StreamResult result = Flow(stream.get(), buffer, ARRAY_SIZE(buffer),
+ response_.document.get());
+ if (SR_SUCCESS != result) {
+ error = HE_STREAM;
+ }
+ }
+
+ return error;
+}
+
+bool HttpClient::PrepareValidate() {
+ ASSERT(CS_READY == cache_state_);
+ // At this point, request_ contains the pending request, and response_
+ // contains the cached response headers. Reformat the request to validate
+ // the cached content.
+ HttpValidatorStrength vs_required = HttpRequestValidatorLevel(request_);
+ HttpValidatorStrength vs_available = HttpResponseValidatorLevel(response_);
+ if (vs_available < vs_required) {
+ return false;
+ }
+ std::string value;
+ if (response_.hasHeader(HH_ETAG, &value)) {
+ request_.addHeader(HH_IF_NONE_MATCH, value);
+ }
+ if (response_.hasHeader(HH_LAST_MODIFIED, &value)) {
+ request_.addHeader(HH_IF_MODIFIED_SINCE, value);
+ }
+ response_.clear(false);
+ cache_state_ = CS_VALIDATING;
+ return true;
+}
+
+HttpError HttpClient::CompleteValidate() {
+ ASSERT(CS_VALIDATING == cache_state_);
+
+ std::string id = GetCacheID(server_, request_);
+
+ // Merge cached headers with new headers
+ HttpError error = ReadCacheHeaders(id, false);
+ if (HE_NONE != error) {
+ // Rewrite merged headers to cache
+ CacheLock lock(cache_, id);
+ error = WriteCacheHeaders(id);
+ }
+ if (HE_NONE != error) {
+ error = ReadCacheBody(id);
+ }
+ return error;
+}
+
+HttpError HttpClient::OnHeaderAvailable(bool ignore_data, bool chunked,
+ size_t data_size) {
+ if (!ignore_data && !chunked && response_.document.get()) {
+ // Attempt to pre-allocate space for the downloaded data.
+ if (!response_.document->ReserveSize(data_size)) {
+ return HE_OVERFLOW;
+ }
+ }
+ SignalHeaderAvailable(this, chunked, data_size);
+ return HE_NONE;
+}
+
+//
+// HttpBase Implementation
+//
+
+HttpError HttpClient::onHttpHeaderComplete(bool chunked, size_t& data_size) {
+ if (CS_VALIDATING == cache_state_) {
+ if (HC_NOT_MODIFIED == response_.scode) {
+ return CompleteValidate();
+ }
+ // Should we remove conditional headers from request?
+ cache_state_ = CS_READY;
+ cache_->DeleteResource(GetCacheID(server_, request_));
+ // Continue processing response as normal
+ }
+
+ ASSERT(!IsCacheActive());
+ if ((request_.verb == HV_HEAD) || !HttpCodeHasBody(response_.scode)) {
+ // HEAD requests and certain response codes contain no body
+ data_size = 0;
+ }
+ if ((HttpCodeIsRedirection(response_.scode) && !fail_redirect_)
+ || ((HC_PROXY_AUTHENTICATION_REQUIRED == response_.scode)
+ && (PROXY_HTTPS == proxy_.type))) {
+ // We're going to issue another request, so ignore the incoming data.
+ base_.set_ignore_data(true);
+ }
+
+ HttpError error = OnHeaderAvailable(base_.ignore_data(), chunked, data_size);
+ if (HE_NONE != error) {
+ return error;
+ }
+
+ if ((NULL != cache_)
+ && !base_.ignore_data()
+ && HttpShouldCache(request_, response_)) {
+ if (BeginCacheFile()) {
+ cache_state_ = CS_WRITING;
+ }
+ }
+ return HE_NONE;
+}
+
+void HttpClient::onHttpComplete(HttpMode mode, HttpError err) {
+ if (err != HE_NONE) {
+ // fall through
+ } else if (mode == HM_CONNECT) {
+ base_.send(&request_);
+ return;
+ } else if ((mode == HM_SEND) || HttpCodeIsInformational(response_.scode)) {
+ // If you're interested in informational headers, catch
+ // SignalHeaderAvailable.
+ base_.recv(&response_);
+ return;
+ } else {
+ if (!HttpShouldKeepAlive(response_)) {
+ LOG(INFO) << "HttpClient: closing socket";
+ base_.stream()->Close();
+ }
+ if (HttpCodeIsRedirection(response_.scode) && !fail_redirect_) {
+ std::string value;
+ if (!response_.hasHeader(HH_LOCATION, &value)) {
+ err = HE_PROTOCOL;
+ } else {
+ Url<char> purl(value);
+ set_server(SocketAddress(purl.server(), purl.port(), false));
+ request_.path = purl.full_path();
+ if (response_.scode == HC_SEE_OTHER) {
+ request_.verb = HV_GET;
+ request_.clearHeader(HH_CONTENT_TYPE);
+ request_.clearHeader(HH_CONTENT_LENGTH);
+ request_.document.reset();
+ } else if (request_.document.get() && !request_.document->Rewind()) {
+ // Unable to replay the request document.
+ err = HE_STREAM;
+ }
+ }
+ if (err == HE_NONE) {
+ context_.reset();
+ response_.clear(false);
+ release();
+ start();
+ return;
+ }
+ } else if ((HC_PROXY_AUTHENTICATION_REQUIRED == response_.scode)
+ && (PROXY_HTTPS == proxy_.type)) {
+ std::string response, auth_method;
+ HttpData::const_iterator begin = response_.begin(HH_PROXY_AUTHENTICATE);
+ HttpData::const_iterator end = response_.end(HH_PROXY_AUTHENTICATE);
+ for (HttpData::const_iterator it = begin; it != end; ++it) {
+ HttpAuthContext *context = context_.get();
+ HttpAuthResult res = HttpAuthenticate(
+ it->second.data(), it->second.size(),
+ proxy_.address,
+ ToString(request_.verb), request_.path,
+ proxy_.username, proxy_.password,
+ context, response, auth_method);
+ context_.reset(context);
+ if (res == HAR_RESPONSE) {
+ request_.setHeader(HH_PROXY_AUTHORIZATION, response);
+ if (request_.document.get() && !request_.document->Rewind()) {
+ err = HE_STREAM;
+ } else {
+ // Explicitly do not reset the HttpAuthContext
+ response_.clear(false);
+ // TODO: Reuse socket when authenticating?
+ release();
+ start();
+ return;
+ }
+ } else if (res == HAR_IGNORE) {
+ LOG(INFO) << "Ignoring Proxy-Authenticate: " << auth_method;
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if (CS_WRITING == cache_state_) {
+ CompleteCacheFile();
+ cache_state_ = CS_READY;
+ } else if (CS_READING == cache_state_) {
+ cache_state_ = CS_READY;
+ }
+ release();
+ SignalHttpClientComplete(this, err);
+}
+
+void HttpClient::onHttpClosed(HttpError err) {
+ SignalHttpClientClosed(this, err);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/httpclient.h b/third_party/libjingle/files/talk/base/httpclient.h
new file mode 100644
index 0000000..789cb59
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpclient.h
@@ -0,0 +1,155 @@
+/*
+ * 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 TALK_BASE_HTTPCLIENT_H__
+#define TALK_BASE_HTTPCLIENT_H__
+
+#include "talk/base/common.h"
+#include "talk/base/httpbase.h"
+#include "talk/base/proxyinfo.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/socketaddress.h"
+#include "talk/base/socketpool.h"
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// HttpClient
+//////////////////////////////////////////////////////////////////////
+
+class DiskCache;
+class HttpClient;
+class IPNetPool;
+
+class HttpClient : private IHttpNotify {
+public:
+ HttpClient(const std::string& agent, StreamPool* pool);
+ virtual ~HttpClient();
+
+ void set_pool(StreamPool* pool) { pool_ = pool; }
+
+ const std::string& agent() const { return agent_; }
+
+ void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; }
+ const ProxyInfo& proxy() const { return proxy_; }
+
+ void set_fail_redirect(bool fail_redirect) { fail_redirect_ = fail_redirect; }
+ bool fail_redirect() const { return fail_redirect_; }
+
+ void use_absolute_uri(bool absolute_uri) { absolute_uri_ = absolute_uri; }
+ bool absolute_uri() const { return absolute_uri_; }
+
+ void set_cache(DiskCache* cache) { ASSERT(!IsCacheActive()); cache_ = cache; }
+ bool cache_enabled() const { return (NULL != cache_); }
+
+ // reset clears the server, request, and response structures. It will also
+ // abort an active request.
+ void reset();
+
+ void set_server(const SocketAddress& address);
+ const SocketAddress& server() const { return server_; }
+
+ HttpRequestData& request() { return request_; }
+ const HttpRequestData& request() const { return request_; }
+ HttpResponseData& response() { return response_; }
+ const HttpResponseData& response() const { return response_; }
+
+ // convenience methods
+ void prepare_get(const std::string& url);
+ void prepare_post(const std::string& url, const std::string& content_type,
+ StreamInterface* request_doc);
+
+ // After you finish setting up your request, call start.
+ void start();
+
+ // Signalled when the header has finished downloading, before the document
+ // content is processed. This notification is for informational purposes
+ // only. Do not modify the client in response to this.
+ sigslot::signal3<const HttpClient*,bool,size_t> SignalHeaderAvailable;
+ // Signalled when the current 'call' finishes. On success, err is 0.
+ sigslot::signal2<HttpClient*,int> SignalHttpClientComplete;
+ // Signalled when the network connection goes down while a call is not
+ // in progress.
+ sigslot::signal2<HttpClient*,int> SignalHttpClientClosed;
+
+protected:
+ void release();
+
+ bool BeginCacheFile();
+ HttpError WriteCacheHeaders(const std::string& id);
+ void CompleteCacheFile();
+
+ bool CheckCache();
+ HttpError ReadCacheHeaders(const std::string& id, bool override);
+ HttpError ReadCacheBody(const std::string& id);
+
+ bool PrepareValidate();
+ HttpError CompleteValidate();
+
+ HttpError OnHeaderAvailable(bool ignore_data, bool chunked, size_t data_size);
+
+ // IHttpNotify Interface
+ virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size);
+ virtual void onHttpComplete(HttpMode mode, HttpError err);
+ virtual void onHttpClosed(HttpError err);
+
+private:
+ enum CacheState { CS_READY, CS_WRITING, CS_READING, CS_VALIDATING };
+ bool IsCacheActive() const { return (cache_state_ > CS_READY); }
+
+ std::string agent_;
+ StreamPool* pool_;
+ HttpBase base_;
+ SocketAddress server_;
+ ProxyInfo proxy_;
+ HttpRequestData request_;
+ HttpResponseData response_;
+ bool fail_redirect_, absolute_uri_;
+ scoped_ptr<HttpAuthContext> context_;
+ DiskCache* cache_;
+ CacheState cache_state_;
+};
+
+//////////////////////////////////////////////////////////////////////
+// Default implementation of HttpClient
+//////////////////////////////////////////////////////////////////////
+
+class HttpClientDefault : public ReuseSocketPool, public HttpClient {
+public:
+ HttpClientDefault(SocketFactory* factory, const std::string& agent)
+ : ReuseSocketPool(factory), HttpClient(agent, NULL)
+ {
+ set_pool(this);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HTTPCLIENT_H__
diff --git a/third_party/libjingle/files/talk/base/httpcommon-inl.h b/third_party/libjingle/files/talk/base/httpcommon-inl.h
new file mode 100644
index 0000000..5235b89
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpcommon-inl.h
@@ -0,0 +1,114 @@
+/*
+ * 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 TALK_BASE_HTTPCOMMON_INL_H__
+#define TALK_BASE_HTTPCOMMON_INL_H__
+
+#include "talk/base/common.h"
+#include "talk/base/httpcommon.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// Url
+///////////////////////////////////////////////////////////////////////////////
+
+template<class CTYPE>
+Url<CTYPE>::Url(const string& url) {
+ const CTYPE* raw_url = url.c_str();
+ if (ascnicmp(raw_url, "http://", 7) == 0) {
+ raw_url += 7;
+ m_secure = false;
+ } else if (ascnicmp(raw_url, "https://", 8) == 0) {
+ raw_url += 8;
+ m_secure = true;
+ } else {
+ return;
+ }
+ m_port = UrlDefaultPort(m_secure);
+ const CTYPE* colon = ::strchr(raw_url, static_cast<CTYPE>(':'));
+ const CTYPE* slash = ::strchr(raw_url, static_cast<CTYPE>('/'));
+ if (!colon && !slash) {
+ m_server = url;
+ // TODO: rethink this slash
+ m_path.append(1, static_cast<CTYPE>('/'));
+ } else {
+ const CTYPE* ptr;
+ if (colon == 0) {
+ ptr = slash;
+ } else if (slash == 0) {
+ ptr = colon;
+ } else {
+ ptr = _min(colon, slash);
+ }
+ m_server.assign(raw_url, ptr - raw_url);
+ if (ptr == colon) {
+ CTYPE* tmp = 0;
+ m_port = static_cast<uint16>(::strtoul(ptr + 1, &tmp, 10));
+ ptr = tmp;
+ }
+ const CTYPE* query = ::strchr(ptr, static_cast<CTYPE>('?'));
+ if (!query) {
+ m_path.assign(ptr);
+ } else {
+ m_path.assign(ptr, query - ptr);
+ m_query.assign(query);
+ }
+ }
+ ASSERT(m_path.empty() || (m_path[0] == static_cast<CTYPE>('/')));
+ ASSERT(m_query.empty() || (m_query[0] == static_cast<CTYPE>('?')));
+}
+
+template<class CTYPE>
+typename Traits<CTYPE>::string Url<CTYPE>::full_path() {
+ string full_path(m_path);
+ full_path.append(m_query);
+ return full_path;
+}
+
+template<class CTYPE>
+typename Traits<CTYPE>::string Url<CTYPE>::url() {
+ CTYPE protocol[9];
+ asccpyn(protocol, ARRAY_SIZE(protocol), m_secure ? "https://" : "http://");
+ string url(protocol);
+ url.append(m_server);
+ if (m_port != UrlDefaultPort(m_secure)) {
+ CTYPE format[5], port[32];
+ asccpyn(format, ARRAY_SIZE(format), ":%hu");
+ sprintfn(port, ARRAY_SIZE(port), format, m_port);
+ url.append(port);
+ }
+ url.append(m_path);
+ url.append(m_query);
+ return url;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HTTPCOMMON_INL_H__
diff --git a/third_party/libjingle/files/talk/base/httpcommon.cc b/third_party/libjingle/files/talk/base/httpcommon.cc
new file mode 100644
index 0000000..aabf22e
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpcommon.cc
@@ -0,0 +1,940 @@
+/*
+ * 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 <time.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#endif
+
+#include "talk/base/base64.h"
+#include "talk/base/common.h"
+#include "talk/base/cryptstring.h"
+#include "talk/base/httpcommon.h"
+#include "talk/base/socketaddress.h"
+#include "talk/base/stringdigest.h"
+#include "talk/base/stringutils.h"
+
+namespace talk_base {
+
+#ifdef WIN32
+extern const ConstantLabel SECURITY_ERRORS[];
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Enum - TODO: expose globally later?
+//////////////////////////////////////////////////////////////////////
+
+bool find_string(size_t& index, const std::string& needle,
+ const char* const haystack[], size_t max_index) {
+ for (index=0; index<max_index; ++index) {
+ if (_stricmp(needle.c_str(), haystack[index]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<class E>
+struct Enum {
+ static const char** Names;
+ static size_t Size;
+
+ static inline const char* Name(E val) { return Names[val]; }
+ static inline bool Parse(E& val, const std::string& name) {
+ size_t index;
+ if (!find_string(index, name, Names, Size))
+ return false;
+ val = static_cast<E>(index);
+ return true;
+ }
+
+ E val;
+
+ inline operator E&() { return val; }
+ inline Enum& operator=(E rhs) { val = rhs; return *this; }
+
+ inline const char* name() const { return Name(val); }
+ inline bool assign(const std::string& name) { return Parse(val, name); }
+ inline Enum& operator=(const std::string& rhs) { assign(rhs); return *this; }
+};
+
+#define ENUM(e,n) \
+ template<> const char** Enum<e>::Names = n; \
+ template<> size_t Enum<e>::Size = sizeof(n)/sizeof(n[0])
+
+//////////////////////////////////////////////////////////////////////
+// HttpCommon
+//////////////////////////////////////////////////////////////////////
+
+static const char* kHttpVersions[HVER_LAST+1] = {
+ "1.0", "1.1"
+};
+ENUM(HttpVersion, kHttpVersions);
+
+static const char* kHttpVerbs[HV_LAST+1] = {
+ "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD"
+};
+ENUM(HttpVerb, kHttpVerbs);
+
+static const char* kHttpHeaders[HH_LAST+1] = {
+ "Age",
+ "Cache-Control",
+ "Connection",
+ "Content-Length",
+ "Content-Range",
+ "Content-Type",
+ "Cookie",
+ "Date",
+ "ETag",
+ "Expires",
+ "Host",
+ "If-Modified-Since",
+ "If-None-Match",
+ "Keep-Alive",
+ "Last-Modified",
+ "Location",
+ "Proxy-Authenticate",
+ "Proxy-Authorization",
+ "Proxy-Connection",
+ "Range",
+ "Set-Cookie",
+ "TE",
+ "Trailers",
+ "Transfer-Encoding",
+ "Upgrade",
+ "User-Agent",
+ "WWW-Authenticate",
+};
+ENUM(HttpHeader, kHttpHeaders);
+
+const char* ToString(HttpVersion version) {
+ return Enum<HttpVersion>::Name(version);
+}
+
+bool FromString(HttpVersion& version, const std::string& str) {
+ return Enum<HttpVersion>::Parse(version, str);
+}
+
+const char* ToString(HttpVerb verb) {
+ return Enum<HttpVerb>::Name(verb);
+}
+
+bool FromString(HttpVerb& verb, const std::string& str) {
+ return Enum<HttpVerb>::Parse(verb, str);
+}
+
+const char* ToString(HttpHeader header) {
+ return Enum<HttpHeader>::Name(header);
+}
+
+bool FromString(HttpHeader& header, const std::string& str) {
+ return Enum<HttpHeader>::Parse(header, str);
+}
+
+bool HttpCodeHasBody(uint32 code) {
+ return !HttpCodeIsInformational(code)
+ && (code != HC_NO_CONTENT) || (code != HC_NOT_MODIFIED);
+}
+
+bool HttpCodeIsCacheable(uint32 code) {
+ switch (code) {
+ case HC_OK:
+ case HC_NON_AUTHORITATIVE:
+ case HC_PARTIAL_CONTENT:
+ case HC_MULTIPLE_CHOICES:
+ case HC_MOVED_PERMANENTLY:
+ case HC_GONE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool HttpHeaderIsEndToEnd(HttpHeader header) {
+ switch (header) {
+ case HH_CONNECTION:
+ case HH_KEEP_ALIVE:
+ case HH_PROXY_AUTHENTICATE:
+ case HH_PROXY_AUTHORIZATION:
+ //case HH_PROXY_CONNECTION:??
+ case HH_TE:
+ case HH_TRAILERS:
+ case HH_TRANSFER_ENCODING:
+ case HH_UPGRADE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool HttpHeaderIsCollapsible(HttpHeader header) {
+ switch (header) {
+ case HH_SET_COOKIE:
+ case HH_PROXY_AUTHENTICATE:
+ case HH_WWW_AUTHENTICATE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool HttpShouldKeepAlive(const HttpData& data) {
+ std::string connection;
+ if ((data.hasHeader(HH_PROXY_CONNECTION, &connection)
+ || data.hasHeader(HH_CONNECTION, &connection))) {
+ return (_stricmp(connection.c_str(), "Keep-Alive") == 0);
+ }
+ return (data.version >= HVER_1_1);
+}
+
+namespace {
+
+inline bool IsEndOfAttributeName(size_t pos, size_t len, const char * data) {
+ if (pos >= len)
+ return true;
+ if (isspace(static_cast<unsigned char>(data[pos])))
+ return true;
+ // The reason for this complexity is that some attributes may contain trailing
+ // equal signs (like base64 tokens in Negotiate auth headers)
+ if ((pos+1 < len) && (data[pos] == '=') &&
+ !isspace(static_cast<unsigned char>(data[pos+1])) &&
+ (data[pos+1] != '=')) {
+ return true;
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+void HttpParseAttributes(const char * data, size_t len,
+ HttpAttributeList& attributes) {
+ size_t pos = 0;
+ while (true) {
+ // Skip leading whitespace
+ while ((pos < len) && isspace(static_cast<unsigned char>(data[pos]))) {
+ ++pos;
+ }
+
+ // End of attributes?
+ if (pos >= len)
+ return;
+
+ // Find end of attribute name
+ size_t start = pos;
+ while (!IsEndOfAttributeName(pos, len, data)) {
+ ++pos;
+ }
+
+ HttpAttribute attribute;
+ attribute.first.assign(data + start, data + pos);
+
+ // Attribute has value?
+ if ((pos < len) && (data[pos] == '=')) {
+ ++pos; // Skip '='
+ // Check if quoted value
+ if ((pos < len) && (data[pos] == '"')) {
+ while (++pos < len) {
+ if (data[pos] == '"') {
+ ++pos;
+ break;
+ }
+ if ((data[pos] == '\\') && (pos + 1 < len))
+ ++pos;
+ attribute.second.append(1, data[pos]);
+ }
+ } else {
+ while ((pos < len) &&
+ !isspace(static_cast<unsigned char>(data[pos])) &&
+ (data[pos] != ',')) {
+ attribute.second.append(1, data[pos++]);
+ }
+ }
+ }
+
+ attributes.push_back(attribute);
+ if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ','
+ }
+}
+
+bool HttpHasAttribute(const HttpAttributeList& attributes,
+ const std::string& name,
+ std::string* value) {
+ for (HttpAttributeList::const_iterator it = attributes.begin();
+ it != attributes.end(); ++it) {
+ if (it->first == name) {
+ if (value) {
+ *value = it->second;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HttpHasNthAttribute(HttpAttributeList& attributes,
+ size_t index,
+ std::string* name,
+ std::string* value) {
+ if (index >= attributes.size())
+ return false;
+
+ if (name)
+ *name = attributes[index].first;
+ if (value)
+ *value = attributes[index].second;
+ return true;
+}
+
+bool HttpDateToSeconds(const std::string& date, unsigned long* seconds) {
+ const char* const kTimeZones[] = {
+ "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT",
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"
+ };
+ const int kTimeZoneOffsets[] = {
+ 0, 0, -5, -4, -6, -5, -7, -6, -8, -7,
+ -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+ };
+
+ ASSERT(NULL != seconds);
+ struct tm tval;
+ memset(&tval, 0, sizeof(tval));
+ char month[4], zone[6];
+ memset(month, 0, sizeof(month));
+ memset(zone, 0, sizeof(zone));
+
+ if (7 != sscanf(date.c_str(), "%*3s, %d %3s %d %d:%d:%d %5c",
+ &tval.tm_mday, month, &tval.tm_year,
+ &tval.tm_hour, &tval.tm_min, &tval.tm_sec, zone)) {
+ return false;
+ }
+ switch (toupper(month[2])) {
+ case 'N': tval.tm_mon = (month[1] == 'A') ? 0 : 5; break;
+ case 'B': tval.tm_mon = 1; break;
+ case 'R': tval.tm_mon = (month[0] == 'M') ? 2 : 3; break;
+ case 'Y': tval.tm_mon = 4; break;
+ case 'L': tval.tm_mon = 6; break;
+ case 'G': tval.tm_mon = 7; break;
+ case 'P': tval.tm_mon = 8; break;
+ case 'T': tval.tm_mon = 9; break;
+ case 'V': tval.tm_mon = 10; break;
+ case 'C': tval.tm_mon = 11; break;
+ }
+ tval.tm_year -= 1900;
+ unsigned long gmt, non_gmt = mktime(&tval);
+ if ((zone[0] == '+') || (zone[0] == '-')) {
+ if (!isdigit(zone[1]) || !isdigit(zone[2])
+ || !isdigit(zone[3]) || !isdigit(zone[4])) {
+ return false;
+ }
+ int hours = (zone[1] - '0') * 10 + (zone[2] - '0');
+ int minutes = (zone[3] - '0') * 10 + (zone[4] - '0');
+ int offset = (hours * 60 + minutes) * 60;
+ gmt = non_gmt + (zone[0] == '+') ? offset : -offset;
+ } else {
+ size_t zindex;
+ if (!find_string(zindex, zone, kTimeZones, ARRAY_SIZE(kTimeZones))) {
+ return false;
+ }
+ gmt = non_gmt + kTimeZoneOffsets[zindex] * 60 * 60;
+ }
+#ifdef OSX
+ tm *tm_for_timezone = localtime((time_t *)&gmt);
+ *seconds = gmt + tm_for_timezone->tm_gmtoff;
+#else
+ *seconds = gmt - timezone;
+#endif
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+// HttpData
+//////////////////////////////////////////////////////////////////////
+
+void
+HttpData::clear(bool release_document) {
+ if (release_document) {
+ document.reset();
+ }
+ m_headers.clear();
+}
+
+void
+HttpData::changeHeader(const std::string& name, const std::string& value,
+ HeaderCombine combine) {
+ if (combine == HC_AUTO) {
+ HttpHeader header;
+ // Unrecognized headers are collapsible
+ combine = !FromString(header, name) || HttpHeaderIsCollapsible(header)
+ ? HC_YES : HC_NO;
+ } else if (combine == HC_REPLACE) {
+ m_headers.erase(name);
+ combine = HC_NO;
+ }
+ // At this point, combine is one of (YES, NO, NEW)
+ if (combine != HC_NO) {
+ HeaderMap::iterator it = m_headers.find(name);
+ if (it != m_headers.end()) {
+ if (combine == HC_YES) {
+ it->second.append(",");
+ it->second.append(value);
+ }
+ return;
+ }
+ }
+ m_headers.insert(HeaderMap::value_type(name, value));
+}
+
+void
+HttpData::clearHeader(const std::string& name) {
+ m_headers.erase(name);
+}
+
+bool
+HttpData::hasHeader(const std::string& name, std::string* value) const {
+ HeaderMap::const_iterator it = m_headers.find(name);
+ if (it == m_headers.end()) {
+ return false;
+ } else if (value) {
+ *value = it->second;
+ }
+ return true;
+}
+
+void
+HttpData::setContent(const std::string& content_type,
+ StreamInterface* document) {
+ ASSERT(document != NULL);
+ this->document.reset(document);
+ setHeader(HH_CONTENT_TYPE, content_type);
+ size_t content_length = 0;
+ if (this->document->GetSize(&content_length)) {
+ char buffer[32];
+ sprintfn(buffer, sizeof(buffer), "%d", content_length);
+ setHeader(HH_CONTENT_LENGTH, buffer);
+ } else {
+ setHeader(HH_TRANSFER_ENCODING, "chunked");
+ }
+}
+
+//
+// HttpRequestData
+//
+
+void
+HttpRequestData::clear(bool release_document) {
+ HttpData::clear(release_document);
+ verb = HV_GET;
+ path.clear();
+}
+
+size_t
+HttpRequestData::formatLeader(char* buffer, size_t size) {
+ ASSERT(path.find(' ') == std::string::npos);
+ return sprintfn(buffer, size, "%s %.*s HTTP/%s", ToString(verb), path.size(),
+ path.data(), ToString(version));
+}
+
+HttpError
+HttpRequestData::parseLeader(const char* line, size_t len) {
+ UNUSED(len);
+ unsigned long vmajor, vminor;
+ int vend, dstart, dend;
+ if ((sscanf(line, "%*s%n %n%*s%n HTTP/%lu.%lu", &vend, &dstart, &dend,
+ &vmajor, &vminor) != 2)
+ || (vmajor != 1)) {
+ return HE_PROTOCOL;
+ }
+ if (vminor == 0) {
+ version = HVER_1_0;
+ } else if (vminor == 1) {
+ version = HVER_1_1;
+ } else {
+ return HE_PROTOCOL;
+ }
+ std::string sverb(line, vend);
+ if (!FromString(verb, sverb.c_str())) {
+ return HE_PROTOCOL; // !?! HC_METHOD_NOT_SUPPORTED?
+ }
+ path.assign(line + dstart, line + dend);
+ return HE_NONE;
+}
+
+//
+// HttpResponseData
+//
+
+void
+HttpResponseData::clear(bool release_document) {
+ HttpData::clear(release_document);
+ scode = HC_INTERNAL_SERVER_ERROR;
+ message.clear();
+}
+
+void
+HttpResponseData::set_success(uint32 scode) {
+ this->scode = scode;
+ message.clear();
+ setHeader(HH_CONTENT_LENGTH, "0");
+}
+
+void
+HttpResponseData::set_success(const std::string& content_type,
+ StreamInterface* document,
+ uint32 scode) {
+ this->scode = scode;
+ message.erase(message.begin(), message.end());
+ setContent(content_type, document);
+}
+
+void
+HttpResponseData::set_redirect(const std::string& location, uint32 scode) {
+ this->scode = scode;
+ message.clear();
+ setHeader(HH_LOCATION, location);
+ setHeader(HH_CONTENT_LENGTH, "0");
+}
+
+void
+HttpResponseData::set_error(uint32 scode) {
+ this->scode = scode;
+ message.clear();
+ setHeader(HH_CONTENT_LENGTH, "0");
+}
+
+size_t
+HttpResponseData::formatLeader(char* buffer, size_t size) {
+ size_t len = sprintfn(buffer, size, "HTTP/%s %lu", ToString(version), scode);
+ if (!message.empty()) {
+ len += sprintfn(buffer + len, size - len, " %.*s",
+ message.size(), message.data());
+ }
+ return len;
+}
+
+HttpError
+HttpResponseData::parseLeader(const char* line, size_t len) {
+ size_t pos = 0;
+ unsigned long vmajor, vminor;
+ if ((sscanf(line, "HTTP/%lu.%lu %lu%zu", &vmajor, &vminor, &scode, &pos) != 3)
+ || (vmajor != 1)) {
+ return HE_PROTOCOL;
+ }
+ if (vminor == 0) {
+ version = HVER_1_0;
+ } else if (vminor == 1) {
+ version = HVER_1_1;
+ } else {
+ return HE_PROTOCOL;
+ }
+ while ((pos < len) && isspace(static_cast<unsigned char>(line[pos]))) ++pos;
+ message.assign(line + pos, len - pos);
+ return HE_NONE;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Http Authentication
+//////////////////////////////////////////////////////////////////////
+
+#define TEST_DIGEST 0
+#if TEST_DIGEST
+/*
+const char * const DIGEST_CHALLENGE =
+ "Digest realm=\"testrealm@host.com\","
+ " qop=\"auth,auth-int\","
+ " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
+ " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+const char * const DIGEST_METHOD = "GET";
+const char * const DIGEST_URI =
+ "/dir/index.html";;
+const char * const DIGEST_CNONCE =
+ "0a4f113b";
+const char * const DIGEST_RESPONSE =
+ "6629fae49393a05397450978507c4ef1";
+//user_ = "Mufasa";
+//pass_ = "Circle Of Life";
+*/
+const char * const DIGEST_CHALLENGE =
+ "Digest realm=\"Squid proxy-caching web server\","
+ " nonce=\"Nny4QuC5PwiSDixJ\","
+ " qop=\"auth\","
+ " stale=false";
+const char * const DIGEST_URI =
+ "/";
+const char * const DIGEST_CNONCE =
+ "6501d58e9a21cee1e7b5fec894ded024";
+const char * const DIGEST_RESPONSE =
+ "edffcb0829e755838b073a4a42de06bc";
+#endif
+
+static std::string quote(const std::string& str) {
+ std::string result;
+ result.push_back('"');
+ for (size_t i=0; i<str.size(); ++i) {
+ if ((str[i] == '"') || (str[i] == '\\'))
+ result.push_back('\\');
+ result.push_back(str[i]);
+ }
+ result.push_back('"');
+ return result;
+}
+
+#ifdef WIN32
+struct NegotiateAuthContext : public HttpAuthContext {
+ CredHandle cred;
+ CtxtHandle ctx;
+ size_t steps;
+ bool specified_credentials;
+
+ NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
+ : HttpAuthContext(auth), cred(c1), ctx(c2), steps(0),
+ specified_credentials(false)
+ { }
+
+ virtual ~NegotiateAuthContext() {
+ DeleteSecurityContext(&ctx);
+ FreeCredentialsHandle(&cred);
+ }
+};
+#endif // WIN32
+
+HttpAuthResult HttpAuthenticate(
+ const char * challenge, size_t len,
+ const SocketAddress& server,
+ const std::string& method, const std::string& uri,
+ const std::string& username, const CryptString& password,
+ HttpAuthContext *& context, std::string& response, std::string& auth_method)
+{
+#if TEST_DIGEST
+ challenge = DIGEST_CHALLENGE;
+ len = strlen(challenge);
+#endif
+
+ HttpAttributeList args;
+ HttpParseAttributes(challenge, len, args);
+ HttpHasNthAttribute(args, 0, &auth_method, NULL);
+
+ if (context && (context->auth_method != auth_method))
+ return HAR_IGNORE;
+
+ // BASIC
+ if (_stricmp(auth_method.c_str(), "basic") == 0) {
+ if (context)
+ return HAR_CREDENTIALS; // Bad credentials
+ if (username.empty())
+ return HAR_CREDENTIALS; // Missing credentials
+
+ context = new HttpAuthContext(auth_method);
+
+ // TODO: convert sensitive to a secure buffer that gets securely deleted
+ //std::string decoded = username + ":" + password;
+ size_t len = username.size() + password.GetLength() + 2;
+ char * sensitive = new char[len];
+ size_t pos = strcpyn(sensitive, len, username.data(), username.size());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ password.CopyTo(sensitive + pos, true);
+
+ response = auth_method;
+ response.append(" ");
+ // TODO: create a sensitive-source version of Base64::encode
+ response.append(Base64::encode(sensitive));
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ return HAR_RESPONSE;
+ }
+
+ // DIGEST
+ if (_stricmp(auth_method.c_str(), "digest") == 0) {
+ if (context)
+ return HAR_CREDENTIALS; // Bad credentials
+ if (username.empty())
+ return HAR_CREDENTIALS; // Missing credentials
+
+ context = new HttpAuthContext(auth_method);
+
+ std::string cnonce, ncount;
+#if TEST_DIGEST
+ method = DIGEST_METHOD;
+ uri = DIGEST_URI;
+ cnonce = DIGEST_CNONCE;
+#else
+ char buffer[256];
+ sprintf(buffer, "%ld", time(0));
+ cnonce = MD5(buffer);
+#endif
+ ncount = "00000001";
+
+ std::string realm, nonce, qop, opaque;
+ HttpHasAttribute(args, "realm", &realm);
+ HttpHasAttribute(args, "nonce", &nonce);
+ bool has_qop = HttpHasAttribute(args, "qop", &qop);
+ bool has_opaque = HttpHasAttribute(args, "opaque", &opaque);
+
+ // TODO: convert sensitive to be secure buffer
+ //std::string A1 = username + ":" + realm + ":" + password;
+ size_t len = username.size() + realm.size() + password.GetLength() + 3;
+ char * sensitive = new char[len]; // A1
+ size_t pos = strcpyn(sensitive, len, username.data(), username.size());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ pos += strcpyn(sensitive + pos, len - pos, realm.c_str());
+ pos += strcpyn(sensitive + pos, len - pos, ":");
+ password.CopyTo(sensitive + pos, true);
+
+ std::string A2 = method + ":" + uri;
+ std::string middle;
+ if (has_qop) {
+ qop = "auth";
+ middle = nonce + ":" + ncount + ":" + cnonce + ":" + qop;
+ } else {
+ middle = nonce;
+ }
+ std::string HA1 = MD5(sensitive);
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ std::string HA2 = MD5(A2);
+ std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
+
+#if TEST_DIGEST
+ assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
+#endif
+
+ std::stringstream ss;
+ ss << auth_method;
+ ss << " username=" << quote(username);
+ ss << ", realm=" << quote(realm);
+ ss << ", nonce=" << quote(nonce);
+ ss << ", uri=" << quote(uri);
+ if (has_qop) {
+ ss << ", qop=" << qop;
+ ss << ", nc=" << ncount;
+ ss << ", cnonce=" << quote(cnonce);
+ }
+ ss << ", response=\"" << dig_response << "\"";
+ if (has_opaque) {
+ ss << ", opaque=" << quote(opaque);
+ }
+ response = ss.str();
+ return HAR_RESPONSE;
+ }
+
+#ifdef WIN32
+#if 1
+ bool want_negotiate = (_stricmp(auth_method.c_str(), "negotiate") == 0);
+ bool want_ntlm = (_stricmp(auth_method.c_str(), "ntlm") == 0);
+ // SPNEGO & NTLM
+ if (want_negotiate || want_ntlm) {
+ const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
+ char out_buf[MAX_MESSAGE], spn[MAX_SPN];
+
+#if 0 // Requires funky windows versions
+ DWORD len = MAX_SPN;
+ if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(),
+ 0, &len, spn) != ERROR_SUCCESS) {
+ LOG_F(WARNING) << "(Negotiate) - DsMakeSpn failed";
+ return HAR_IGNORE;
+ }
+#else
+ sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());
+#endif
+
+ SecBuffer out_sec;
+ out_sec.pvBuffer = out_buf;
+ out_sec.cbBuffer = sizeof(out_buf);
+ out_sec.BufferType = SECBUFFER_TOKEN;
+
+ SecBufferDesc out_buf_desc;
+ out_buf_desc.ulVersion = 0;
+ out_buf_desc.cBuffers = 1;
+ out_buf_desc.pBuffers = &out_sec;
+
+ const ULONG NEG_FLAGS_DEFAULT =
+ //ISC_REQ_ALLOCATE_MEMORY
+ ISC_REQ_CONFIDENTIALITY
+ //| ISC_REQ_EXTENDED_ERROR
+ //| ISC_REQ_INTEGRITY
+ | ISC_REQ_REPLAY_DETECT
+ | ISC_REQ_SEQUENCE_DETECT
+ //| ISC_REQ_STREAM
+ //| ISC_REQ_USE_SUPPLIED_CREDS
+ ;
+
+ TimeStamp lifetime;
+ SECURITY_STATUS ret = S_OK;
+ ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT;
+
+ bool specify_credentials = !username.empty();
+ size_t steps = 0;
+
+ //uint32 now = Time();
+
+ NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context);
+ if (neg) {
+ const size_t max_steps = 10;
+ if (++neg->steps >= max_steps) {
+ LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries";
+ return HAR_ERROR;
+ }
+ steps = neg->steps;
+
+ std::string decoded_challenge;
+ HttpHasNthAttribute(args, 1, &decoded_challenge, NULL);
+ decoded_challenge = Base64::decode(decoded_challenge);
+ if (!decoded_challenge.empty()) {
+ SecBuffer in_sec;
+ in_sec.pvBuffer = const_cast<char *>(decoded_challenge.data());
+ in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size());
+ in_sec.BufferType = SECBUFFER_TOKEN;
+
+ SecBufferDesc in_buf_desc;
+ in_buf_desc.ulVersion = 0;
+ in_buf_desc.cBuffers = 1;
+ in_buf_desc.pBuffers = &in_sec;
+
+ ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
+ //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeDiff(talk_base::Time(), now);
+ if (FAILED(ret)) {
+ LOG(LS_ERROR) << "InitializeSecurityContext returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ return HAR_ERROR;
+ }
+ } else if (neg->specified_credentials) {
+ // Try again with default credentials
+ specify_credentials = false;
+ delete context;
+ context = neg = 0;
+ } else {
+ return HAR_CREDENTIALS;
+ }
+ }
+
+ if (!neg) {
+ unsigned char userbuf[256], passbuf[256], domainbuf[16];
+ SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0;
+ if (specify_credentials) {
+ memset(&auth_id, 0, sizeof(auth_id));
+ size_t len = password.GetLength()+1;
+ char * sensitive = new char[len];
+ password.CopyTo(sensitive, true);
+ std::string::size_type pos = username.find('\\');
+ if (pos == std::string::npos) {
+ auth_id.UserLength = static_cast<unsigned long>(
+ _min(sizeof(userbuf) - 1, username.size()));
+ memcpy(userbuf, username.c_str(), auth_id.UserLength);
+ userbuf[auth_id.UserLength] = 0;
+ auth_id.DomainLength = 0;
+ domainbuf[auth_id.DomainLength] = 0;
+ auth_id.PasswordLength = static_cast<unsigned long>(
+ _min(sizeof(passbuf) - 1, password.GetLength()));
+ memcpy(passbuf, sensitive, auth_id.PasswordLength);
+ passbuf[auth_id.PasswordLength] = 0;
+ } else {
+ auth_id.UserLength = static_cast<unsigned long>(
+ _min(sizeof(userbuf) - 1, username.size() - pos - 1));
+ memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength);
+ userbuf[auth_id.UserLength] = 0;
+ auth_id.DomainLength = static_cast<unsigned long>(
+ _min(sizeof(domainbuf) - 1, pos));
+ memcpy(domainbuf, username.c_str(), auth_id.DomainLength);
+ domainbuf[auth_id.DomainLength] = 0;
+ auth_id.PasswordLength = static_cast<unsigned long>(
+ _min(sizeof(passbuf) - 1, password.GetLength()));
+ memcpy(passbuf, sensitive, auth_id.PasswordLength);
+ passbuf[auth_id.PasswordLength] = 0;
+ }
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ auth_id.User = userbuf;
+ auth_id.Domain = domainbuf;
+ auth_id.Password = passbuf;
+ auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+ pauth_id = &auth_id;
+ LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials";
+ } else {
+ LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials";
+ }
+
+ CredHandle cred;
+ ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime);
+ //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << TimeDiff(talk_base::Time(), now);
+ if (ret != SEC_E_OK) {
+ LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ return HAR_IGNORE;
+ }
+
+ //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
+
+ CtxtHandle ctx;
+ ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime);
+ //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeDiff(talk_base::Time(), now);
+ if (FAILED(ret)) {
+ LOG(LS_ERROR) << "InitializeSecurityContext returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ FreeCredentialsHandle(&cred);
+ return HAR_IGNORE;
+ }
+
+ assert(!context);
+ context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
+ neg->specified_credentials = specify_credentials;
+ neg->steps = steps;
+ }
+
+ if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
+ ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
+ //LOG(INFO) << "$$$ CompleteAuthToken @ " << TimeDiff(talk_base::Time(), now);
+ LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ if (FAILED(ret)) {
+ return HAR_ERROR;
+ }
+ }
+
+ //LOG(INFO) << "$$$ NEGOTIATE took " << TimeDiff(talk_base::Time(), now) << "ms";
+
+ std::string decoded(out_buf, out_buf + out_sec.cbBuffer);
+ response = auth_method;
+ response.append(" ");
+ response.append(Base64::encode(decoded));
+ return HAR_RESPONSE;
+ }
+#endif
+#endif // WIN32
+
+ return HAR_IGNORE;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/httpcommon.h b/third_party/libjingle/files/talk/base/httpcommon.h
new file mode 100644
index 0000000..8cadd7f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpcommon.h
@@ -0,0 +1,373 @@
+/*
+ * 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 TALK_BASE_HTTPCOMMON_H__
+#define TALK_BASE_HTTPCOMMON_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include "talk/base/basictypes.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/stream.h"
+
+namespace talk_base {
+
+class CryptString;
+class SocketAddress;
+
+//////////////////////////////////////////////////////////////////////
+// Constants
+//////////////////////////////////////////////////////////////////////
+
+enum HttpCode {
+ HC_OK = 200,
+ HC_NON_AUTHORITATIVE = 203,
+ HC_NO_CONTENT = 204,
+ HC_PARTIAL_CONTENT = 206,
+
+ HC_MULTIPLE_CHOICES = 300,
+ HC_MOVED_PERMANENTLY = 301,
+ HC_FOUND = 302,
+ HC_SEE_OTHER = 303,
+ HC_NOT_MODIFIED = 304,
+ HC_MOVED_TEMPORARILY = 307,
+
+ HC_BAD_REQUEST = 400,
+ HC_UNAUTHORIZED = 401,
+ HC_FORBIDDEN = 403,
+ HC_NOT_FOUND = 404,
+ HC_PROXY_AUTHENTICATION_REQUIRED = 407,
+ HC_GONE = 410,
+
+ HC_INTERNAL_SERVER_ERROR = 500
+};
+
+enum HttpVersion {
+ HVER_1_0, HVER_1_1,
+ HVER_LAST = HVER_1_1
+};
+
+enum HttpVerb {
+ HV_GET, HV_POST, HV_PUT, HV_DELETE, HV_CONNECT, HV_HEAD,
+ HV_LAST = HV_HEAD
+};
+
+enum HttpError {
+ HE_NONE,
+ HE_PROTOCOL, HE_DISCONNECTED, HE_OVERFLOW,
+ HE_SOCKET, HE_SHUTDOWN, HE_OPERATION_CANCELLED,
+ HE_AUTH, // Proxy Authentication Required
+ HE_CERTIFICATE_EXPIRED, // During SSL negotiation
+ HE_STREAM, // Problem reading or writing to the document
+ HE_CACHE, // Problem reading from cache
+ HE_DEFAULT
+};
+
+enum HttpHeader {
+ HH_AGE,
+ HH_CACHE_CONTROL,
+ HH_CONNECTION,
+ HH_CONTENT_LENGTH,
+ HH_CONTENT_RANGE,
+ HH_CONTENT_TYPE,
+ HH_COOKIE,
+ HH_DATE,
+ HH_ETAG,
+ HH_EXPIRES,
+ HH_HOST,
+ HH_IF_MODIFIED_SINCE,
+ HH_IF_NONE_MATCH,
+ HH_KEEP_ALIVE,
+ HH_LAST_MODIFIED,
+ HH_LOCATION,
+ HH_PROXY_AUTHENTICATE,
+ HH_PROXY_AUTHORIZATION,
+ HH_PROXY_CONNECTION,
+ HH_RANGE,
+ HH_SET_COOKIE,
+ HH_TE,
+ HH_TRAILERS,
+ HH_TRANSFER_ENCODING,
+ HH_UPGRADE,
+ HH_USER_AGENT,
+ HH_WWW_AUTHENTICATE,
+ HH_LAST = HH_WWW_AUTHENTICATE
+};
+
+const uint16 HTTP_DEFAULT_PORT = 80;
+const uint16 HTTP_SECURE_PORT = 443;
+
+//////////////////////////////////////////////////////////////////////
+// Utility Functions
+//////////////////////////////////////////////////////////////////////
+
+inline HttpError mkerr(HttpError err, HttpError def_err = HE_DEFAULT) {
+ return (err != HE_NONE) ? err : def_err;
+}
+
+const char* ToString(HttpVersion version);
+bool FromString(HttpVersion& version, const std::string& str);
+
+const char* ToString(HttpVerb verb);
+bool FromString(HttpVerb& verb, const std::string& str);
+
+const char* ToString(HttpHeader header);
+bool FromString(HttpHeader& header, const std::string& str);
+
+inline bool HttpCodeIsInformational(uint32 code) { return ((code / 100) == 1); }
+inline bool HttpCodeIsSuccessful(uint32 code) { return ((code / 100) == 2); }
+inline bool HttpCodeIsRedirection(uint32 code) { return ((code / 100) == 3); }
+inline bool HttpCodeIsClientError(uint32 code) { return ((code / 100) == 4); }
+inline bool HttpCodeIsServerError(uint32 code) { return ((code / 100) == 5); }
+
+bool HttpCodeHasBody(uint32 code);
+bool HttpCodeIsCacheable(uint32 code);
+bool HttpHeaderIsEndToEnd(HttpHeader header);
+bool HttpHeaderIsCollapsible(HttpHeader header);
+
+struct HttpData;
+bool HttpShouldKeepAlive(const HttpData& data);
+
+typedef std::pair<std::string, std::string> HttpAttribute;
+typedef std::vector<HttpAttribute> HttpAttributeList;
+void HttpParseAttributes(const char * data, size_t len,
+ HttpAttributeList& attributes);
+bool HttpHasAttribute(const HttpAttributeList& attributes,
+ const std::string& name,
+ std::string* value);
+bool HttpHasNthAttribute(HttpAttributeList& attributes,
+ size_t index,
+ std::string* name,
+ std::string* value);
+
+// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp
+bool HttpDateToSeconds(const std::string& date, unsigned long* seconds);
+
+inline uint16 UrlDefaultPort(bool secure) {
+ return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT;
+}
+
+// functional for insensitive std::string compare
+struct iless {
+ bool operator()(const std::string& lhs, const std::string& rhs) const {
+ return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+// Url
+//////////////////////////////////////////////////////////////////////
+
+template<class CTYPE>
+class Url {
+public:
+ typedef typename Traits<CTYPE>::string string;
+
+ // TODO: Implement Encode/Decode
+ static int Encode(const CTYPE* source, CTYPE* destination, size_t len);
+ static int Encode(const string& source, string& destination);
+ static int Decode(const CTYPE* source, CTYPE* destination, size_t len);
+ static int Decode(const string& source, string& destination);
+
+ Url(const string& url);
+ Url(const string& path, const string& server, uint16 port = HTTP_DEFAULT_PORT)
+ : m_server(server), m_path(path), m_port(port),
+ m_secure(HTTP_SECURE_PORT == port)
+ {
+ ASSERT(m_path.empty() || (m_path[0] == static_cast<CTYPE>('/')));
+ }
+
+ bool valid() const { return !m_server.empty(); }
+ const string& server() const { return m_server; }
+ // Note: path() was renamed to path_, because it now uses the stricter sense
+ // of not including a query string. I'm trying to think of a clearer name.
+ const string& path_() const { return m_path; }
+ const string& query() const { return m_query; }
+ string full_path();
+ string url();
+ uint16 port() const { return m_port; }
+ bool secure() const { return m_secure; }
+
+ void set_server(const string& val) { m_server = val; }
+ void set_path(const string& val) {
+ ASSERT(val.empty() || (val[0] == static_cast<CTYPE>('/')));
+ m_path = val;
+ }
+ void set_query(const string& val) {
+ ASSERT(val.empty() || (val[0] == static_cast<CTYPE>('?')));
+ m_query = val;
+ }
+ void set_port(uint16 val) { m_port = val; }
+ void set_secure(bool val) { m_secure = val; }
+
+private:
+ string m_server, m_path, m_query;
+ uint16 m_port;
+ bool m_secure;
+};
+
+//////////////////////////////////////////////////////////////////////
+// HttpData
+//////////////////////////////////////////////////////////////////////
+
+struct HttpData {
+ typedef std::multimap<std::string, std::string, iless> HeaderMap;
+ typedef HeaderMap::const_iterator const_iterator;
+
+ HttpVersion version;
+ scoped_ptr<StreamInterface> document;
+
+ HttpData() : version(HVER_1_1) { }
+
+ enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW };
+ void changeHeader(const std::string& name, const std::string& value,
+ HeaderCombine combine);
+ inline void addHeader(const std::string& name, const std::string& value,
+ bool append = true) {
+ changeHeader(name, value, append ? HC_AUTO : HC_NO);
+ }
+ inline void setHeader(const std::string& name, const std::string& value,
+ bool overwrite = true) {
+ changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW);
+ }
+ void clearHeader(const std::string& name);
+
+ // keep in mind, this may not do what you want in the face of multiple headers
+ bool hasHeader(const std::string& name, std::string* value) const;
+
+ inline const_iterator begin() const {
+ return m_headers.begin();
+ }
+ inline const_iterator end() const {
+ return m_headers.end();
+ }
+ inline const_iterator begin(const std::string& name) const {
+ return m_headers.lower_bound(name);
+ }
+ inline const_iterator end(const std::string& name) const {
+ return m_headers.upper_bound(name);
+ }
+
+ // Convenience methods using HttpHeader
+ inline void changeHeader(HttpHeader header, const std::string& value,
+ HeaderCombine combine) {
+ changeHeader(ToString(header), value, combine);
+ }
+ inline void addHeader(HttpHeader header, const std::string& value,
+ bool append = true) {
+ addHeader(ToString(header), value, append);
+ }
+ inline void setHeader(HttpHeader header, const std::string& value,
+ bool overwrite = true) {
+ setHeader(ToString(header), value, overwrite);
+ }
+ inline void clearHeader(HttpHeader header) {
+ clearHeader(ToString(header));
+ }
+ inline bool hasHeader(HttpHeader header, std::string* value) const {
+ return hasHeader(ToString(header), value);
+ }
+ inline const_iterator begin(HttpHeader header) const {
+ return m_headers.lower_bound(ToString(header));
+ }
+ inline const_iterator end(HttpHeader header) const {
+ return m_headers.upper_bound(ToString(header));
+ }
+
+ void setContent(const std::string& content_type, StreamInterface* document);
+
+ virtual size_t formatLeader(char* buffer, size_t size) = 0;
+ virtual HttpError parseLeader(const char* line, size_t len) = 0;
+
+protected:
+ virtual ~HttpData() { }
+ void clear(bool release_document);
+
+private:
+ HeaderMap m_headers;
+};
+
+struct HttpRequestData : public HttpData {
+ HttpVerb verb;
+ std::string path;
+
+ HttpRequestData() : verb(HV_GET) { }
+
+ void clear(bool release_document);
+
+ virtual size_t formatLeader(char* buffer, size_t size);
+ virtual HttpError parseLeader(const char* line, size_t len);
+};
+
+struct HttpResponseData : public HttpData {
+ unsigned long scode;
+ std::string message;
+
+ HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { }
+ void clear(bool release_document);
+
+ // Convenience methods
+ void set_success(uint32 scode = HC_OK);
+ void set_success(const std::string& content_type, StreamInterface* document,
+ uint32 scode = HC_OK);
+ void set_redirect(const std::string& location,
+ uint32 scode = HC_MOVED_TEMPORARILY);
+ void set_error(uint32 scode);
+
+ virtual size_t formatLeader(char* buffer, size_t size);
+ virtual HttpError parseLeader(const char* line, size_t len);
+};
+
+//////////////////////////////////////////////////////////////////////
+// Http Authentication
+//////////////////////////////////////////////////////////////////////
+
+struct HttpAuthContext {
+ std::string auth_method;
+ HttpAuthContext(const std::string& auth) : auth_method(auth) { }
+ virtual ~HttpAuthContext() { }
+};
+
+enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR };
+
+// 'context' is used by this function to record information between calls.
+// Start by passing a null pointer, then pass the same pointer each additional
+// call. When the authentication attempt is finished, delete the context.
+HttpAuthResult HttpAuthenticate(
+ const char * challenge, size_t len,
+ const SocketAddress& server,
+ const std::string& method, const std::string& uri,
+ const std::string& username, const CryptString& password,
+ HttpAuthContext *& context, std::string& response, std::string& auth_method);
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HTTPCOMMON_H__
diff --git a/third_party/libjingle/files/talk/base/httpserver.cc b/third_party/libjingle/files/talk/base/httpserver.cc
new file mode 100644
index 0000000..9c27b5c
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpserver.cc
@@ -0,0 +1,261 @@
+/*
+ * 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 <algorithm>
+
+#include "talk/base/httpcommon-inl.h"
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/common.h"
+#include "talk/base/httpserver.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketstream.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// HttpServer
+///////////////////////////////////////////////////////////////////////////////
+
+HttpServer::HttpServer() : next_connection_id_(1) {
+}
+
+HttpServer::~HttpServer() {
+ for (ConnectionMap::iterator it = connections_.begin();
+ it != connections_.end();
+ ++it) {
+ StreamInterface* stream = it->second->EndProcess();
+ delete stream;
+ delete it->second;
+ }
+}
+
+int
+HttpServer::HandleConnection(StreamInterface* stream) {
+ int connection_id = next_connection_id_++;
+ ASSERT(connection_id != HTTP_INVALID_CONNECTION_ID);
+ Connection* connection = new Connection(connection_id, this);
+ connections_.insert(ConnectionMap::value_type(connection_id, connection));
+ connection->BeginProcess(stream);
+ return connection_id;
+}
+
+void
+HttpServer::Respond(HttpTransaction* transaction) {
+ int connection_id = transaction->connection_id();
+ if (Connection* connection = Find(connection_id)) {
+ connection->Respond(transaction);
+ } else {
+ delete transaction;
+ // We may be tempted to SignalHttpComplete, but that implies that a
+ // connection still exists.
+ }
+}
+
+void
+HttpServer::Close(int connection_id, bool force) {
+ if (Connection* connection = Find(connection_id)) {
+ connection->InitiateClose(force);
+ }
+}
+
+void
+HttpServer::CloseAll(bool force) {
+ std::list<Connection*> connections;
+ for (ConnectionMap::const_iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ connections.push_back(it->second);
+ }
+ for (std::list<Connection*>::const_iterator it = connections.begin();
+ it != connections.end(); ++it) {
+ (*it)->InitiateClose(force);
+ }
+}
+
+HttpServer::Connection*
+HttpServer::Find(int connection_id) {
+ ConnectionMap::iterator it = connections_.find(connection_id);
+ if (it == connections_.end())
+ return NULL;
+ return it->second;
+}
+
+void
+HttpServer::Remove(int connection_id) {
+ ConnectionMap::iterator it = connections_.find(connection_id);
+ if (it == connections_.end()) {
+ ASSERT(false);
+ return;
+ }
+ Connection* connection = it->second;
+ connections_.erase(it);
+ SignalConnectionClosed(this, connection_id, connection->EndProcess());
+ delete connection;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// HttpServer::Connection
+///////////////////////////////////////////////////////////////////////////////
+
+HttpServer::Connection::Connection(int connection_id, HttpServer* server)
+ : connection_id_(connection_id), server_(server),
+ current_(NULL), signalling_(false), close_(false) {
+}
+
+HttpServer::Connection::~Connection() {
+ delete current_;
+}
+
+void
+HttpServer::Connection::BeginProcess(StreamInterface* stream) {
+ base_.notify(this);
+ base_.attach(stream);
+ current_ = new HttpTransaction(connection_id_);
+ current_->request()->document.reset(new MemoryStream);
+ if (base_.mode() != HM_CONNECT)
+ base_.recv(current_->request());
+}
+
+StreamInterface*
+HttpServer::Connection::EndProcess() {
+ base_.notify(NULL);
+ base_.abort(HE_DISCONNECTED);
+ return base_.detach();
+}
+
+void
+HttpServer::Connection::Respond(HttpTransaction* transaction) {
+ ASSERT(current_ == NULL);
+ current_ = transaction;
+ if (current_->response()->begin() == current_->response()->end()) {
+ current_->response()->set_error(HC_INTERNAL_SERVER_ERROR);
+ }
+ bool keep_alive = HttpShouldKeepAlive(*transaction->request());
+ current_->response()->setHeader(HH_CONNECTION,
+ keep_alive ? "Keep-Alive" : "Close",
+ false);
+ close_ = !HttpShouldKeepAlive(*transaction->response());
+ base_.send(current_->response());
+}
+
+void
+HttpServer::Connection::InitiateClose(bool force) {
+ if (!signalling_ && (force || (base_.mode() != HM_SEND))) {
+ server_->Remove(connection_id_);
+ } else {
+ close_ = true;
+ }
+}
+
+//
+// IHttpNotify Implementation
+//
+
+HttpError
+HttpServer::Connection::onHttpHeaderComplete(bool chunked, size_t& data_size) {
+ if (data_size == SIZE_UNKNOWN) {
+ data_size = 0;
+ }
+ return HE_NONE;
+}
+
+void
+HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) {
+ if (mode == HM_SEND) {
+ ASSERT(current_ != NULL);
+ signalling_ = true;
+ server_->SignalHttpRequestComplete(server_, current_, err);
+ signalling_ = false;
+ if (close_) {
+ // Force a close
+ err = HE_DISCONNECTED;
+ }
+ }
+ if (err != HE_NONE) {
+ server_->Remove(connection_id_);
+ } else if (mode == HM_CONNECT) {
+ base_.recv(current_->request());
+ } else if (mode == HM_RECV) {
+ ASSERT(current_ != NULL);
+ // TODO: do we need this?
+ //request_.document_->rewind();
+ HttpTransaction* transaction = current_;
+ current_ = NULL;
+ server_->SignalHttpRequest(server_, transaction);
+ } else if (mode == HM_SEND) {
+ current_->request()->clear(true);
+ current_->request()->document.reset(new MemoryStream);
+ current_->response()->clear(true);
+ base_.recv(current_->request());
+ } else {
+ ASSERT(false);
+ }
+}
+
+void
+HttpServer::Connection::onHttpClosed(HttpError err) {
+ UNUSED(err);
+ server_->Remove(connection_id_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// HttpListenServer
+///////////////////////////////////////////////////////////////////////////////
+
+HttpListenServer::HttpListenServer(AsyncSocket* listener)
+ : listener_(listener) {
+ listener_->SignalReadEvent.connect(this, &HttpListenServer::OnReadEvent);
+}
+
+HttpListenServer::~HttpListenServer() {
+}
+
+int
+HttpListenServer::Listen(const SocketAddress& address) {
+ if ((listener_->Bind(address) != SOCKET_ERROR) &&
+ (listener_->Listen(5) != SOCKET_ERROR))
+ return 0;
+ return listener_->GetError();
+}
+
+bool
+HttpListenServer::GetAddress(SocketAddress& address) {
+ address = listener_->GetLocalAddress();
+ return !address.IsNil();
+}
+
+void
+HttpListenServer::OnReadEvent(AsyncSocket* socket) {
+ ASSERT(socket == listener_);
+ AsyncSocket* incoming = static_cast<AsyncSocket*>(listener_->Accept(NULL));
+ if (incoming)
+ HandleConnection(new SocketStream(incoming));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/httpserver.h b/third_party/libjingle/files/talk/base/httpserver.h
new file mode 100644
index 0000000..a09218c
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/httpserver.h
@@ -0,0 +1,143 @@
+/*
+ * 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 TALK_BASE_HTTPSERVER_H__
+#define TALK_BASE_HTTPSERVER_H__
+
+#include <map>
+#include "talk/base/httpbase.h"
+
+namespace talk_base {
+
+class AsyncSocket;
+class HttpServer;
+class SocketAddress;
+
+//////////////////////////////////////////////////////////////////////
+// HttpServer
+//////////////////////////////////////////////////////////////////////
+
+const int HTTP_INVALID_CONNECTION_ID = 0;
+
+class HttpTransaction {
+public:
+ HttpTransaction(int connection_id) : connection_id_(connection_id) { }
+ ~HttpTransaction() { }
+
+ int connection_id() const { return connection_id_; }
+
+ HttpRequestData* request() { return &request_; }
+ HttpResponseData* response() { return &response_; }
+
+private:
+ int connection_id_;
+ HttpRequestData request_;
+ HttpResponseData response_;
+};
+
+class HttpServer {
+public:
+ HttpServer();
+ virtual ~HttpServer();
+
+ int HandleConnection(StreamInterface* stream);
+ // Due to sigslot issues, we can't destroy some streams at an arbitrary time.
+ sigslot::signal3<HttpServer*, int, StreamInterface*> SignalConnectionClosed;
+
+ // An HTTP request has been made, and is available in the transaction object.
+ // Populate the transaction's response, and then return the object via the
+ // Respond method. Note that during this time, ownership of the transaction
+ // object is transferred, so it may be passed between threads, although
+ // respond must be called on the server's active thread.
+ sigslot::signal2<HttpServer*, HttpTransaction*> SignalHttpRequest;
+ void Respond(HttpTransaction* transaction);
+
+ // If you want to know when a request completes, listen to this event.
+ sigslot::signal3<HttpServer*, HttpTransaction*, int>
+ SignalHttpRequestComplete;
+
+ // Stop processing the connection indicated by connection_id.
+ // Unless force is true, the server will complete sending a response that is
+ // in progress.
+ void Close(int connection_id, bool force);
+ void CloseAll(bool force);
+
+private:
+ class Connection : private IHttpNotify {
+ public:
+ Connection(int connection_id, HttpServer* server);
+ virtual ~Connection();
+
+ void BeginProcess(StreamInterface* stream);
+ StreamInterface* EndProcess();
+
+ void Respond(HttpTransaction* transaction);
+ void InitiateClose(bool force);
+
+ // IHttpNotify Interface
+ virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size);
+ virtual void onHttpComplete(HttpMode mode, HttpError err);
+ virtual void onHttpClosed(HttpError err);
+
+ int connection_id_;
+ HttpServer* server_;
+ HttpBase base_;
+ HttpTransaction* current_;
+ bool signalling_, close_;
+ };
+
+ Connection* Find(int connection_id);
+ void Remove(int connection_id);
+
+ friend class Connection;
+ typedef std::map<int,Connection*> ConnectionMap;
+
+ ConnectionMap connections_;
+ int next_connection_id_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class HttpListenServer : public HttpServer, public sigslot::has_slots<> {
+public:
+ HttpListenServer(AsyncSocket* listener);
+ virtual ~HttpListenServer();
+
+ int Listen(const SocketAddress& address);
+ bool GetAddress(SocketAddress& address);
+
+private:
+ void OnReadEvent(AsyncSocket* socket);
+
+ AsyncSocket* listener_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_HTTPSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/linked_ptr.h b/third_party/libjingle/files/talk/base/linked_ptr.h
new file mode 100644
index 0000000..8d5ce49
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/linked_ptr.h
@@ -0,0 +1,115 @@
+/*
+ * linked_ptr - simple reference linked pointer
+ * (like reference counting, just using a linked list of the references
+ * instead of their count.)
+ *
+ * The implementation stores three pointers for every linked_ptr, but
+ * does not allocate anything on the free store.
+ */
+
+#ifndef TALK_BASE_LINKED_PTR_H__
+#define TALK_BASE_LINKED_PTR_H__
+
+namespace talk_base {
+
+/* For ANSI-challenged compilers, you may want to #define
+ * NO_MEMBER_TEMPLATES, explicit or mutable */
+#define NO_MEMBER_TEMPLATES
+
+template <class X> class linked_ptr
+{
+public:
+
+#ifndef NO_MEMBER_TEMPLATES
+# define TEMPLATE_FUNCTION template <class Y>
+ TEMPLATE_FUNCTION friend class linked_ptr<Y>;
+#else
+# define TEMPLATE_FUNCTION
+ typedef X Y;
+#endif
+
+ typedef X element_type;
+
+ explicit linked_ptr(X* p = 0) throw()
+ : itsPtr(p) {itsPrev = itsNext = this;}
+ ~linked_ptr()
+ {release();}
+ linked_ptr(const linked_ptr& r) throw()
+ {acquire(r);}
+ linked_ptr& operator=(const linked_ptr& r)
+ {
+ if (this != &r) {
+ release();
+ acquire(r);
+ }
+ return *this;
+ }
+
+#ifndef NO_MEMBER_TEMPLATES
+ template <class Y> friend class linked_ptr<Y>;
+ template <class Y> linked_ptr(const linked_ptr<Y>& r) throw()
+ {acquire(r);}
+ template <class Y> linked_ptr& operator=(const linked_ptr<Y>& r)
+ {
+ if (this != &r) {
+ release();
+ acquire(r);
+ }
+ return *this;
+ }
+#endif // NO_MEMBER_TEMPLATES
+
+ X& operator*() const throw() {return *itsPtr;}
+ X* operator->() const throw() {return itsPtr;}
+ X* get() const throw() {return itsPtr;}
+ bool unique() const throw() {return itsPrev ? itsPrev==this : true;}
+
+private:
+ X* itsPtr;
+ mutable const linked_ptr* itsPrev;
+ mutable const linked_ptr* itsNext;
+
+ void acquire(const linked_ptr& r) throw()
+ { // insert this to the list
+ itsPtr = r.itsPtr;
+ itsNext = r.itsNext;
+ itsNext->itsPrev = this;
+ itsPrev = &r;
+#ifndef mutable
+ r.itsNext = this;
+#else // for ANSI-challenged compilers
+ (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
+#endif
+ }
+
+#ifndef NO_MEMBER_TEMPLATES
+ template <class Y> void acquire(const linked_ptr<Y>& r) throw()
+ { // insert this to the list
+ itsPtr = r.itsPtr;
+ itsNext = r.itsNext;
+ itsNext->itsPrev = this;
+ itsPrev = &r;
+#ifndef mutable
+ r.itsNext = this;
+#else // for ANSI-challenged compilers
+ (const_cast<linked_ptr<X>*>(&r))->itsNext = this;
+#endif
+ }
+#endif // NO_MEMBER_TEMPLATES
+
+ void release()
+ { // erase this from the list, delete if unique
+ if (unique()) delete itsPtr;
+ else {
+ itsPrev->itsNext = itsNext;
+ itsNext->itsPrev = itsPrev;
+ itsPrev = itsNext = 0;
+ }
+ itsPtr = 0;
+ }
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_LINKED_PTR_H__
+
diff --git a/third_party/libjingle/files/talk/base/logging.cc b/third_party/libjingle/files/talk/base/logging.cc
new file mode 100644
index 0000000..3f3a3f9
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/logging.cc
@@ -0,0 +1,350 @@
+/*
+ * 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>
+#ifdef WIN32
+#include <windows.h>
+#define snprintf _snprintf
+#undef ERROR // wingdi.h
+#endif
+
+#include <iostream>
+#include <iomanip>
+
+#include "talk/base/logging.h"
+#include "talk/base/stream.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/time.h"
+
+namespace talk_base {
+
+/////////////////////////////////////////////////////////////////////////////
+// Constant Labels
+/////////////////////////////////////////////////////////////////////////////
+
+const char * FindLabel(int value, const talk_base::ConstantLabel entries[]) {
+ for (int i=0; entries[i].label; ++i) {
+ if (value == entries[i].value) {
+ return entries[i].label;
+ }
+ }
+ return 0;
+}
+
+std::string ErrorName(int err, const talk_base::ConstantLabel * err_table) {
+ const char * value = 0;
+ if (err == 0)
+ return "No error";
+
+ if (err_table != 0) {
+ if (const char * value = FindLabel(err, err_table))
+ return value;
+ }
+
+ char buffer[16];
+ snprintf(buffer, sizeof(buffer), "0x%08x", err);
+ return buffer;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// LogMessage
+/////////////////////////////////////////////////////////////////////////////
+
+#if LOGGING
+static const int LOG_DEFAULT = LS_INFO;
+#else
+static const int LOG_DEFAULT = LogMessage::NO_LOGGING;
+#endif
+
+// By default, release builds don't log, debug builds at info level
+int LogMessage::min_sev_ = LOG_DEFAULT;
+int LogMessage::dbg_sev_ = LOG_DEFAULT;
+
+// No file logging by default
+int LogMessage::stream_sev_ = NO_LOGGING;
+
+// Don't bother printing context for the ubiquitous INFO log messages
+int LogMessage::ctx_sev_ = LS_WARNING;
+
+// stream_ defaults to NULL
+// Note: we explicitly do not clean this up, because of the uncertain ordering
+// of destructors at program exit. Let the person who sets the stream trigger
+// cleanup by setting to NULL, or let it leak (safe at program exit).
+StreamInterface* LogMessage::stream_;
+
+// Boolean options default to false (0)
+bool LogMessage::thread_, LogMessage::timestamp_;
+
+// Program start time
+uint32 LogMessage::start_ = StartTime();
+
+// if we're in diagnostic mode, we'll be explicitly set that way. default to false
+bool LogMessage::is_diagnostic_mode_ = false;
+
+LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
+ LogErrorContext err_ctx, int err, const char* module)
+ : severity_(sev) {
+ if (timestamp_) {
+ uint32 time = TimeDiff(Time(), start_);
+ print_stream_ << "[" << std::setfill('0') << std::setw(3) << (time / 1000)
+ << ":" << std::setw(3) << (time % 1000) << std::setfill(' ')
+ << "] ";
+ }
+
+ if (thread_) {
+#ifdef WIN32
+ DWORD id = GetCurrentThreadId();
+ print_stream_ << "[" << std::hex << id << std::dec << "] ";
+#endif // WIN32
+ }
+
+ if (severity_ >= ctx_sev_) {
+ print_stream_ << Describe(sev) << "(" << DescribeFile(file)
+ << ":" << line << "): ";
+ }
+
+ if (err_ctx != ERRCTX_NONE) {
+ std::ostringstream tmp;
+ tmp << "[0x" << std::setfill('0') << std::hex << std::setw(8) << err << "]";
+ switch (err_ctx) {
+ case ERRCTX_ERRNO:
+ tmp << " " << strerror(err);
+ break;
+ #ifdef WIN32
+ case ERRCTX_HRESULT: {
+ char msgbuf[256];
+ DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
+ HMODULE hmod = GetModuleHandleA(module);
+ if (hmod)
+ flags |= FORMAT_MESSAGE_FROM_HMODULE;
+ if (DWORD len = FormatMessageA(
+ flags, hmod, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), NULL)) {
+ while ((len > 0) &&
+ isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
+ msgbuf[--len] = 0;
+ }
+ tmp << " " << msgbuf;
+ }
+ break; }
+ #endif // WIN32
+ default:
+ break;
+ }
+ extra_ = tmp.str();
+ }
+}
+
+LogMessage::~LogMessage() {
+ if (!extra_.empty())
+ print_stream_ << " : " << extra_;
+ print_stream_ << std::endl;
+ const std::string& str = print_stream_.str();
+
+ if (severity_ >= dbg_sev_) {
+ bool log_to_stderr = true;
+#ifdef WIN32
+ static bool debugger_present = (IsDebuggerPresent() != FALSE);
+ if (debugger_present) {
+ log_to_stderr = false;
+ OutputDebugStringA(str.c_str());
+ }
+ if (log_to_stderr) {
+ // This handles dynamically allocated consoles, too.
+ if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
+ log_to_stderr = false;
+ unsigned long written;
+ ::WriteFile(error_handle, str.data(), str.size(), &written, 0);
+ }
+ }
+#endif // WIN32
+ if (log_to_stderr) {
+ std::cerr << str;
+ std::cerr.flush();
+ }
+ }
+
+ if (severity_ >= stream_sev_) {
+ // If write isn't fully successful, what are we going to do, log it? :)
+ stream_->WriteAll(str.data(), str.size(), NULL, NULL);
+ }
+}
+
+void LogMessage::LogContext(int min_sev) {
+ ctx_sev_ = min_sev;
+}
+
+void LogMessage::LogThreads(bool on) {
+ thread_ = on;
+}
+
+void LogMessage::LogTimestamps(bool on) {
+ timestamp_ = on;
+}
+
+void LogMessage::ResetTimestamps() {
+ start_ = Time();
+}
+
+void LogMessage::LogToDebug(int min_sev) {
+ dbg_sev_ = min_sev;
+ min_sev_ = _min(dbg_sev_, stream_sev_);
+}
+
+void LogMessage::LogToStream(StreamInterface* stream, int min_sev) {
+ delete stream_;
+ stream_ = stream;
+ stream_sev_ = (stream_ == 0) ? NO_LOGGING : min_sev;
+ min_sev_ = _min(dbg_sev_, stream_sev_);
+}
+
+const char* LogMessage::Describe(LoggingSeverity sev) {
+ switch (sev) {
+ case LS_SENSITIVE: return "Sensitive";
+ case LS_VERBOSE: return "Verbose";
+ case LS_INFO: return "Info";
+ case LS_WARNING: return "Warning";
+ case LS_ERROR: return "Error";
+ default: return "<unknown>";
+ }
+}
+
+const char* LogMessage::DescribeFile(const char* file) {
+ const char* end1 = ::strrchr(file, '/');
+ const char* end2 = ::strrchr(file, '\\');
+ if (!end1 && !end2)
+ return file;
+ else
+ return (end1 > end2) ? end1 + 1 : end2 + 1;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Logging Helpers
+//////////////////////////////////////////////////////////////////////
+
+void LogMultiline(LoggingSeverity level, const char* label, bool input,
+ const char * data, size_t len, bool hex_mode,
+ LogMultilineState* state) {
+ if (!LOG_CHECK_LEVEL_V(level))
+ return;
+
+ const char * direction = (input ? " << " : " >> ");
+ if (hex_mode) {
+ const size_t LINE_SIZE = 24;
+ char hex_line[LINE_SIZE * 9 / 4 + 2], asc_line[LINE_SIZE + 1];
+ while (len > 0) {
+ memset(asc_line, ' ', sizeof(asc_line));
+ memset(hex_line, ' ', sizeof(hex_line));
+ size_t line_len = _min(len, LINE_SIZE);
+ for (size_t i=0; i<line_len; ++i) {
+ unsigned char ch = static_cast<unsigned char>(data[i]);
+ asc_line[i] = isprint(ch) ? data[i] : '.';
+ hex_line[i*2 + i/4] = hex_encode(ch >> 4);
+ hex_line[i*2 + i/4 + 1] = hex_encode(ch & 0xf);
+ }
+ asc_line[sizeof(asc_line)-1] = 0;
+ hex_line[sizeof(hex_line)-1] = 0;
+ LOG_V(level) << label << direction
+ << asc_line << " " << hex_line << " ";
+ data += line_len;
+ len -= line_len;
+ }
+ return;
+ }
+
+ size_t consecutive_unprintable = state ? state->unprintable_count_ : 0;
+
+ std::string str(data, len);
+ while (!str.empty()) {
+ size_t line_end_length = 0;
+ std::string::size_type pos = str.find('\n');
+ std::string substr = str;
+ if (pos == std::string::npos) {
+ substr = str;
+ str.clear();
+ } else if ((pos > 0) && (str[pos-1] == '\r')) {
+ line_end_length = 2;
+ substr = str.substr(0, pos - 1);
+ str = str.substr(pos + 1);
+ } else {
+ line_end_length = 1;
+ substr = str.substr(0, pos);
+ str = str.substr(pos + 1);
+ }
+
+ // Any lines which consist entirely of ascii characters are printed. Other
+ // lines are considered binary, and we just count the number of bytes.
+ // This algorithm should be very compatible with HTTP transfers of binary
+ // data.
+ bool is_ascii = true, is_whitespace = true;
+ for (size_t i=0; i<substr.size(); ++i) {
+ unsigned char ch = static_cast<unsigned char>(substr[i]);
+ if (!isprint(ch)) {
+ is_ascii = false;
+ break;
+ } else if (!isspace(static_cast<unsigned char>(ch))) {
+ is_whitespace = false;
+ }
+ }
+ // Treat an empty line following binary data as binary.
+ if (is_whitespace && consecutive_unprintable) {
+ is_ascii = false;
+ }
+ if (!is_ascii) {
+ consecutive_unprintable += substr.size() + line_end_length;
+ }
+ if (consecutive_unprintable && (is_ascii || str.empty())) {
+ LOG_V(level) << label << direction << "## " << consecutive_unprintable
+ << " consecutive unprintable ##";
+ }
+ if (is_ascii) {
+ consecutive_unprintable = 0;
+ } else {
+ continue;
+ }
+
+ // Filter out any private data
+ std::string::size_type pos_private = substr.find("Email");
+ if (pos_private == std::string::npos) {
+ pos_private = substr.find("Passwd");
+ }
+ if (pos_private == std::string::npos) {
+ LOG_V(level) << label << direction << substr;
+ } else {
+ LOG_V(level) << label << direction << "## omitted for privacy ##";
+ }
+ }
+
+ if (state) {
+ state->unprintable_count_ = consecutive_unprintable;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/overrides/talk/base/logging.h b/third_party/libjingle/files/talk/base/logging.h
index 4b051b3..189c8dd7 100644
--- a/third_party/libjingle/overrides/talk/base/logging.h
+++ b/third_party/libjingle/files/talk/base/logging.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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
+ * 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
+ * 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,
+ * 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
+ * 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.
*/
@@ -35,42 +35,15 @@
// There are several variations on the LOG macro which facilitate logging
// of common error conditions, detailed below.
-// LOG(sev) logs the given stream at severity "sev", which must be a
-// compile-time constant of the LoggingSeverity type, without the namespace
-// prefix.
-// LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity
-// type (basically, it just doesn't prepend the namespace).
-// LOG_F(sev) Like LOG(), but includes the name of the current function.
-// LOG_GLE(M)(sev [, mod]) attempt to add a string description of the
-// HRESULT returned by GetLastError. The "M" variant allows searching of a
-// DLL's string table for the error description.
-// LOG_ERRNO(sev) attempts to add a string description of an errno-derived
-// error. errno and associated facilities exist on both Windows and POSIX,
-// but on Windows they only apply to the C/C++ runtime.
-// LOG_ERR(sev) is an alias for the platform's normal error system, i.e. _GLE on
-// Windows and _ERRNO on POSIX.
-// (The above three also all have _EX versions that let you specify the error
-// code, rather than using the last one.)
-// LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the
-// specified context.
-// LOG_CHECK_LEVEL(sev) (and LOG_CHECK_LEVEL_V(sev)) can be used as a test
-// before performing expensive or sensitive operations whose sole purpose is
-// to output logging data at the desired level.
-// Lastly, PLOG(sev, err) is an alias for LOG_ERR_EX.
-
-#ifndef TALK_BASE_LOGGING_H_
-#define TALK_BASE_LOGGING_H_
+#ifndef TALK_BASE_LOGGING_H__
+#define TALK_BASE_LOGGING_H__
#ifdef HAVE_CONFIG_H
-#include "config.h" // NOLINT
+#include <config.h>
#endif
-#include <list>
#include <sstream>
-#include <string>
-#include <utility>
#include "talk/base/basictypes.h"
-#include "talk/base/criticalsection.h"
namespace talk_base {
@@ -95,9 +68,9 @@ struct ConstantLabel { int value; const char * label; };
#if defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS)
#define KLABEL(x) { x, #x }
-#define TLABEL(x, y) { x, y }
+#define TLABEL(x,y) { x, y }
#define LASTLABEL { 0, 0 }
-#endif // defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS)
+#endif // defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS)
const char * FindLabel(int value, const ConstantLabel entries[]);
std::string ErrorName(int err, const ConstantLabel* err_table);
@@ -120,22 +93,12 @@ enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR,
LERROR = LS_ERROR };
// LogErrorContext assists in interpreting the meaning of an error value.
-enum LogErrorContext {
- ERRCTX_NONE,
- ERRCTX_ERRNO, // System-local errno
- ERRCTX_HRESULT, // Windows HRESULT
- ERRCTX_OSSTATUS, // MacOS OSStatus
-
- // Abbreviations for LOG_E macro
- ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x)
- ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x)
- ERRCTX_OS = ERRCTX_OSSTATUS, // LOG_E(sev, OS, x)
-};
+// ERRCTX_ERRNO: the value was read from global 'errno'
+// ERRCTX_HRESULT: the value is a Windows HRESULT
+enum LogErrorContext { ERRCTX_NONE, ERRCTX_ERRNO, ERRCTX_HRESULT };
class LogMessage {
public:
- static const int NO_LOGGING;
-
LogMessage(const char* file, int line, LoggingSeverity sev,
LogErrorContext err_ctx = ERRCTX_NONE, int err = 0,
const char* module = NULL);
@@ -144,6 +107,8 @@ class LogMessage {
static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); }
std::ostream& stream() { return print_stream_; }
+ enum { NO_LOGGING = LS_ERROR + 1 };
+
// These are attributes which apply to all logging channels
// LogContext: Display the file and line number of the message
static void LogContext(int min_sev);
@@ -161,18 +126,10 @@ class LogMessage {
// Debug: Debug console on Windows, otherwise stderr
static void LogToDebug(int min_sev);
static int GetLogToDebug() { return dbg_sev_; }
-
// Stream: Any non-blocking stream interface. LogMessage takes ownership of
- // the stream. Multiple streams may be specified by using AddLogToStream.
- // LogToStream is retained for backwards compatibility; when invoked, it
- // will discard any previously set streams and install the specified stream.
- // GetLogToStream gets the severity for the specified stream, of if none
- // is specified, the minimum stream severity.
- // RemoveLogToStream removes the specified stream, without destroying it.
+ // the stream.
static void LogToStream(StreamInterface* stream, int min_sev);
- static int GetLogToStream(StreamInterface* stream = NULL);
- static void AddLogToStream(StreamInterface* stream, int min_sev);
- static void RemoveLogToStream(StreamInterface* stream);
+ static int GetLogToStream() { return stream_sev_; }
// Testing against MinLogSeverity allows code to avoid potentially expensive
// logging operations by pre-checking the logging level.
@@ -181,28 +138,11 @@ class LogMessage {
static void SetDiagnosticMode(bool f) { is_diagnostic_mode_ = f; }
static bool IsDiagnosticMode() { return is_diagnostic_mode_; }
- // Parses the provided parameter stream to configure the options above.
- // Useful for configuring logging from the command line. If file logging
- // is enabled, it is output to the specified filename.
- static void ConfigureLogging(const char* params, const char* filename);
-
- // Convert the string to a LS_ value; also accept numeric values.
- static int ParseLogSeverity(const std::string& value);
-
private:
- typedef std::list<std::pair<StreamInterface*, int> > StreamList;
-
- // Updates min_sev_ appropriately when debug sinks change.
- static void UpdateMinLogSeverity();
-
// These assist in formatting some parts of the debug output.
static const char* Describe(LoggingSeverity sev);
static const char* DescribeFile(const char* file);
- // These write out the actual log messages.
- static void OutputToDebug(const std::string& msg, LoggingSeverity severity_);
- static void OutputToStream(StreamInterface* stream, const std::string& msg);
-
// The ostream that buffers the formatted message before output
std::ostringstream print_stream_;
@@ -213,18 +153,15 @@ class LogMessage {
// the message before output.
std::string extra_;
- // Global lock for the logging subsystem
- static CriticalSection crit_;
-
- // dbg_sev_ is the thresholds for those output targets
+ // dbg_sev_ and stream_sev_ are the thresholds for those output targets
// min_sev_ is the minimum (most verbose) of those levels, and is used
// as a short-circuit in the logging macros to identify messages that won't
// be logged.
// ctx_sev_ is the minimum level at which file context is displayed
- static int min_sev_, dbg_sev_, ctx_sev_;
+ static int min_sev_, dbg_sev_, stream_sev_, ctx_sev_;
- // The output streams and their associated severities
- static StreamList streams_;
+ // The output stream, if any
+ static StreamInterface * stream_;
// Flags for formatting options
static bool thread_, timestamp_;
@@ -243,17 +180,15 @@ class LogMessage {
//////////////////////////////////////////////////////////////////////
class LogMultilineState {
- public:
- size_t unprintable_count_[2];
- LogMultilineState() {
- unprintable_count_[0] = unprintable_count_[1] = 0;
- }
+public:
+ size_t unprintable_count_;
+ LogMultilineState() : unprintable_count_(0) { }
};
// When possible, pass optional state variable to track various data across
// multiple calls to LogMultiline. Otherwise, pass NULL.
void LogMultiline(LoggingSeverity level, const char* label, bool input,
- const void* data, size_t len, bool hex_mode,
+ const char * data, size_t len, bool hex_mode,
LogMultilineState* state);
//////////////////////////////////////////////////////////////////////
@@ -263,7 +198,7 @@ void LogMultiline(LoggingSeverity level, const char* label, bool input,
// If LOGGING is not explicitly defined, default to enabled in debug mode
#if defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS)
#if !defined(LOGGING)
-#if defined(_DEBUG) && !defined(NDEBUG)
+#if !defined(NDEBUG)
#define LOGGING 1
#else
#define LOGGING 0
@@ -273,43 +208,22 @@ void LogMultiline(LoggingSeverity level, const char* label, bool input,
#ifndef LOG
#if LOGGING
-// The following non-obvious technique for implementation of a
-// conditional log stream was stolen from google3/base/logging.h.
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros. This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-
-class LogMessageVoidify {
- public:
- LogMessageVoidify() { }
- // This has to be an operator with a precedence lower than << but
- // higher than ?:
- void operator&(std::ostream&) { }
-};
-
-#define LOG_SEVERITY_PRECONDITION(sev) \
- !(talk_base::LogMessage::Loggable(sev)) \
- ? (void) 0 \
- : talk_base::LogMessageVoidify() &
-
#define LOG(sev) \
- LOG_SEVERITY_PRECONDITION(talk_base::sev) \
+ if (talk_base::LogMessage::Loggable(talk_base::sev)) \
talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev).stream()
// The _V version is for when a variable is passed in. It doesn't do the
// namespace concatination.
#define LOG_V(sev) \
- LOG_SEVERITY_PRECONDITION(sev) \
+ if (talk_base::LogMessage::Loggable(sev)) \
talk_base::LogMessage(__FILE__, __LINE__, sev).stream()
// The _F version prefixes the message with the current function name.
-#if defined(__GNUC__) && defined(_DEBUG)
-#define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": "
-#else
#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": "
-#endif
+// LOG_CHECK_LEVEL can be used as a test before performing expensive or
+// sensitive operations whose sole purpose is to output logging data at the
+// desired level.
#define LOG_CHECK_LEVEL(sev) \
talk_base::LogCheckLevel(talk_base::sev)
#define LOG_CHECK_LEVEL_V(sev) \
@@ -318,11 +232,34 @@ inline bool LogCheckLevel(LoggingSeverity sev) {
return (LogMessage::GetMinLogSeverity() <= sev);
}
-#define LOG_E(sev, ctx, err, ...) \
- LOG_SEVERITY_PRECONDITION(talk_base::sev) \
+// PLOG and LOG_ERR attempt to provide a string description of an errno derived
+// error. LOG_ERR reads errno directly, so care must be taken to call it before
+// errno is reset.
+#define PLOG(sev, err) \
+ if (talk_base::LogMessage::Loggable(talk_base::sev)) \
+ talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \
+ talk_base::ERRCTX_ERRNO, err).stream()
+#define LOG_ERR(sev) \
+ if (talk_base::LogMessage::Loggable(sev)) \
+ talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \
+ talk_base::ERRCTX_ERRNO, errno).stream()
+
+// LOG_GLE(M) attempt to provide a string description of the HRESULT returned
+// by GetLastError. The second variant allows searching of a dll's string
+// table for the error description.
+#ifdef WIN32
+#define LOG_GLE(sev) \
+ if (talk_base::LogMessage::Loggable(talk_base::sev)) \
talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \
- talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \
- .stream()
+ talk_base::ERRCTX_HRESULT, GetLastError()).stream()
+#define LOG_GLEM(sev, mod) \
+ if (talk_base::LogMessage::Loggable(talk_base::sev)) \
+ talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \
+ talk_base::ERRCTX_HRESULT, GetLastError(), mod) \
+ .stream()
+#endif // WIN32
+
+// TODO: Add an "assert" wrapper that logs in the same manner.
#else // !LOGGING
@@ -338,49 +275,27 @@ inline bool LogCheckLevel(LoggingSeverity sev) {
false
#define LOG_CHECK_LEVEL_V(sev) \
false
-
-#define LOG_E(sev, ctx, err, ...) \
- while (false) talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \
- talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \
- .stream()
-
-#endif // !LOGGING
-
-#define LOG_ERRNO_EX(sev, err) \
- LOG_E(sev, ERRNO, err)
-#define LOG_ERRNO(sev) \
- LOG_ERRNO_EX(sev, errno)
-
+#define PLOG(sev, err) \
+ while (false) talk_base::LogMessage(NULL, 0, talk_base::sev, \
+ talk_base::ERRCTX_ERRNO, 0).stream()
+#define LOG_ERR(sev) \
+ while (false) talk_base::LogMessage(NULL, 0, talk_base::sev, \
+ talk_base::ERRCTX_ERRNO, 0).stream()
#ifdef WIN32
-#define LOG_GLE_EX(sev, err) \
- LOG_E(sev, HRESULT, err)
#define LOG_GLE(sev) \
- LOG_GLE_EX(sev, GetLastError())
+ while (false) talk_base::LogMessage(NULL, 0, talk_base::sev, \
+ talk_base::ERRCTX_HRESULT, 0).stream()
#define LOG_GLEM(sev, mod) \
- LOG_E(sev, HRESULT, GetLastError(), mod)
-#define LOG_ERR_EX(sev, err) \
- LOG_GLE_EX(sev, err)
-#define LOG_ERR(sev) \
- LOG_GLE(sev)
-#define LAST_SYSTEM_ERROR \
- (::GetLastError())
-#elif POSIX
-#define LOG_ERR_EX(sev, err) \
- LOG_ERRNO_EX(sev, err)
-#define LOG_ERR(sev) \
- LOG_ERRNO(sev)
-#define LAST_SYSTEM_ERROR \
- (errno)
+ while (false) talk_base::LogMessage(NULL, 0, talk_base::sev, \
+ talk_base::ERRCTX_HRESULT, 0).stream()
#endif // WIN32
-#define PLOG(sev, err) \
- LOG_ERR_EX(sev, err)
-
-// TODO(?): Add an "assert" wrapper that logs in the same manner.
-
+#endif // !LOGGING
#endif // LOG
#endif // defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS)
-} // namespace talk_base
+//////////////////////////////////////////////////////////////////////
+
+} // talk_base
-#endif // TALK_BASE_LOGGING_H_
+#endif // TALK_BASE_LOGGING_H__
diff --git a/third_party/libjingle/files/talk/base/md5.h b/third_party/libjingle/files/talk/base/md5.h
new file mode 100644
index 0000000..ec458d1
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/md5.h
@@ -0,0 +1,45 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ */
+
+#ifndef TALK_BASE_MD5_H__
+#define TALK_BASE_MD5_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef long unsigned int uint32;
+typedef struct MD5Context MD5_CTX;
+
+#define md5byte unsigned char
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ uint32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // TALK_BASE_MD5_H__
diff --git a/third_party/libjingle/files/talk/base/md5c.c b/third_party/libjingle/files/talk/base/md5c.c
new file mode 100644
index 0000000..eb2c034
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/md5c.c
@@ -0,0 +1,256 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+ ((unsigned)buf[1]<<8 | buf[0]);
+ *(uint32 *)buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = (unsigned char *)ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = (unsigned char*)(ctx->in) + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
+ ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ byteReverse((unsigned char *)ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
diff --git a/third_party/libjingle/files/talk/base/messagequeue.cc b/third_party/libjingle/files/talk/base/messagequeue.cc
new file mode 100644
index 0000000..171f324
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/messagequeue.cc
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#ifdef POSIX
+extern "C" {
+#include <sys/time.h>
+}
+#endif
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/messagequeue.h"
+#include "talk/base/physicalsocketserver.h"
+
+
+namespace talk_base {
+
+const uint32 kMaxMsgLatency = 150; // 150 ms
+
+//------------------------------------------------------------------
+// MessageQueueManager
+
+MessageQueueManager* MessageQueueManager::instance_;
+
+MessageQueueManager* MessageQueueManager::Instance() {
+ // Note: This is not thread safe, but it is first called before threads are
+ // spawned.
+ if (!instance_)
+ instance_ = new MessageQueueManager;
+ return instance_;
+}
+
+MessageQueueManager::MessageQueueManager() {
+}
+
+MessageQueueManager::~MessageQueueManager() {
+}
+
+void MessageQueueManager::Add(MessageQueue *message_queue) {
+ // MessageQueueManager methods should be non-reentrant, so we
+ // ASSERT that is the case.
+ ASSERT(!crit_.CurrentThreadIsOwner());
+ CritScope cs(&crit_);
+ message_queues_.push_back(message_queue);
+}
+
+void MessageQueueManager::Remove(MessageQueue *message_queue) {
+ ASSERT(!crit_.CurrentThreadIsOwner()); // See note above.
+ CritScope cs(&crit_);
+ std::vector<MessageQueue *>::iterator iter;
+ iter = std::find(message_queues_.begin(), message_queues_.end(), message_queue);
+ if (iter != message_queues_.end())
+ message_queues_.erase(iter);
+}
+
+void MessageQueueManager::Clear(MessageHandler *handler) {
+ ASSERT(!crit_.CurrentThreadIsOwner()); // See note above.
+ CritScope cs(&crit_);
+ std::vector<MessageQueue *>::iterator iter;
+ for (iter = message_queues_.begin(); iter != message_queues_.end(); iter++)
+ (*iter)->Clear(handler);
+}
+
+//------------------------------------------------------------------
+// MessageQueue
+
+MessageQueue::MessageQueue(SocketServer* ss)
+ : ss_(ss), new_ss(false), fStop_(false), fPeekKeep_(false), active_(false) {
+ if (!ss_) {
+ default_ss_.reset(new PhysicalSocketServer());
+ ss_ = default_ss_.get();
+ }
+}
+
+MessageQueue::~MessageQueue() {
+ // The signal is done from here to ensure
+ // that it always gets called when the queue
+ // is going away.
+ SignalQueueDestroyed();
+ if (active_) {
+ MessageQueueManager::Instance()->Remove(this);
+ Clear(NULL);
+ }
+}
+
+void MessageQueue::set_socketserver(SocketServer* ss) {
+ ss_ = ss;
+}
+
+void MessageQueue::Quit() {
+ fStop_ = true;
+ ss_->WakeUp();
+}
+
+bool MessageQueue::IsQuitting() {
+ return fStop_;
+}
+
+void MessageQueue::Restart() {
+ fStop_ = false;
+}
+
+bool MessageQueue::Peek(Message *pmsg, int cmsWait) {
+ if (fPeekKeep_) {
+ *pmsg = msgPeek_;
+ return true;
+ }
+ if (!Get(pmsg, cmsWait))
+ return false;
+ msgPeek_ = *pmsg;
+ fPeekKeep_ = true;
+ return true;
+}
+
+bool MessageQueue::Get(Message *pmsg, int cmsWait) {
+ // Return and clear peek if present
+ // Always return the peek if it exists so there is Peek/Get symmetry
+
+ if (fPeekKeep_) {
+ *pmsg = msgPeek_;
+ fPeekKeep_ = false;
+ return true;
+ }
+
+ // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch
+
+ int cmsTotal = cmsWait;
+ int cmsElapsed = 0;
+ uint32 msStart = Time();
+ uint32 msCurrent = msStart;
+ while (true) {
+ // Check for sent messages
+
+ ReceiveSends();
+
+ // Check queues
+
+ int cmsDelayNext = kForever;
+ {
+ CritScope cs(&crit_);
+
+ // Check for delayed messages that have been triggered
+ // Calc the next trigger too
+
+ while (!dmsgq_.empty()) {
+ if (msCurrent < dmsgq_.top().msTrigger_) {
+ cmsDelayNext = dmsgq_.top().msTrigger_ - msCurrent;
+ break;
+ }
+ msgq_.push(dmsgq_.top().msg_);
+ dmsgq_.pop();
+ }
+
+ // Check for posted events
+
+ while (!msgq_.empty()) {
+ *pmsg = msgq_.front();
+ if (pmsg->ts_sensitive) {
+ long delay = TimeDiff(msCurrent, pmsg->ts_sensitive);
+ if (delay > 0) {
+ LOG_F(LS_WARNING) << "id: " << pmsg->message_id << " delay: "
+ << (delay + kMaxMsgLatency) << "ms";
+ }
+ }
+ msgq_.pop();
+ if (MQID_DISPOSE == pmsg->message_id) {
+ ASSERT(NULL == pmsg->phandler);
+ delete pmsg->pdata;
+ continue;
+ }
+ return true;
+ }
+ }
+
+ if (fStop_)
+ break;
+
+ // Which is shorter, the delay wait or the asked wait?
+
+ int cmsNext;
+ if (cmsWait == kForever) {
+ cmsNext = cmsDelayNext;
+ } else {
+ cmsNext = cmsTotal - cmsElapsed;
+ if (cmsNext < 0)
+ cmsNext = 0;
+ if ((cmsDelayNext != kForever) && (cmsDelayNext < cmsNext))
+ cmsNext = cmsDelayNext;
+ }
+
+ // Wait and multiplex in the meantime
+ ss_->Wait(cmsNext, true);
+
+ // If the specified timeout expired, return
+
+ msCurrent = Time();
+ cmsElapsed = msCurrent - msStart;
+ if (cmsWait != kForever) {
+ if (cmsElapsed >= cmsWait)
+ return false;
+ }
+ }
+ return false;
+}
+
+void MessageQueue::ReceiveSends() {
+}
+
+void MessageQueue::Post(MessageHandler *phandler, uint32 id,
+ MessageData *pdata, bool time_sensitive) {
+ if (fStop_)
+ return;
+
+ // Keep thread safe
+ // Add the message to the end of the queue
+ // Signal for the multiplexer to return
+
+ CritScope cs(&crit_);
+ EnsureActive();
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ if (time_sensitive) {
+ msg.ts_sensitive = Time() + kMaxMsgLatency;
+ }
+ msgq_.push(msg);
+ ss_->WakeUp();
+}
+
+void MessageQueue::PostDelayed(int cmsDelay, MessageHandler *phandler,
+ uint32 id, MessageData *pdata) {
+ if (fStop_)
+ return;
+
+ // Keep thread safe
+ // Add to the priority queue. Gets sorted soonest first.
+ // Signal for the multiplexer to return.
+
+ CritScope cs(&crit_);
+ EnsureActive();
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ dmsgq_.push(DelayedMessage(cmsDelay, &msg));
+ ss_->WakeUp();
+}
+
+int MessageQueue::GetDelay() {
+ CritScope cs(&crit_);
+
+ if (!msgq_.empty())
+ return 0;
+
+ if (!dmsgq_.empty()) {
+ int delay = dmsgq_.top().msTrigger_ - Time();
+ if (delay < 0)
+ delay = 0;
+ return delay;
+ }
+
+ return kForever;
+}
+
+void MessageQueue::Clear(MessageHandler *phandler, uint32 id) {
+ CritScope cs(&crit_);
+
+ // Remove messages with phandler
+
+ if (fPeekKeep_) {
+ if (phandler == NULL || msgPeek_.phandler == phandler) {
+ if (id == MQID_ANY || msgPeek_.message_id == id) {
+ delete msgPeek_.pdata;
+ fPeekKeep_ = false;
+ }
+ }
+ }
+
+ // Remove from ordered message queue
+
+ size_t c = msgq_.size();
+ while (c-- != 0) {
+ Message msg = msgq_.front();
+ msgq_.pop();
+ if (phandler != NULL && msg.phandler != phandler) {
+ msgq_.push(msg);
+ } else {
+ if (id == MQID_ANY || msg.message_id == id) {
+ delete msg.pdata;
+ } else {
+ msgq_.push(msg);
+ }
+ }
+ }
+
+ // Remove from priority queue. Not directly iterable, so use this approach
+
+ std::queue<DelayedMessage> dmsgs;
+ while (!dmsgq_.empty()) {
+ DelayedMessage dmsg = dmsgq_.top();
+ dmsgq_.pop();
+ if (phandler != NULL && dmsg.msg_.phandler != phandler) {
+ dmsgs.push(dmsg);
+ } else {
+ if (id == MQID_ANY || dmsg.msg_.message_id == id) {
+ delete dmsg.msg_.pdata;
+ } else {
+ dmsgs.push(dmsg);
+ }
+ }
+ }
+ while (!dmsgs.empty()) {
+ dmsgq_.push(dmsgs.front());
+ dmsgs.pop();
+ }
+}
+
+void MessageQueue::Dispatch(Message *pmsg) {
+ pmsg->phandler->OnMessage(pmsg);
+}
+
+void MessageQueue::EnsureActive() {
+ ASSERT(crit_.CurrentThreadIsOwner());
+ if (!active_) {
+ active_ = true;
+ MessageQueueManager::Instance()->Add(this);
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/messagequeue.h b/third_party/libjingle/files/talk/base/messagequeue.h
new file mode 100644
index 0000000..d39aab8
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/messagequeue.h
@@ -0,0 +1,213 @@
+/*
+ * 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 TALK_BASE_MESSAGEQUEUE_H__
+#define TALK_BASE_MESSAGEQUEUE_H__
+
+#include <vector>
+#include <queue>
+#include <algorithm>
+#include "talk/base/basictypes.h"
+#include "talk/base/criticalsection.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/socketserver.h"
+#include "talk/base/time.h"
+
+namespace talk_base {
+
+struct Message;
+class MessageQueue;
+class MessageHandler;
+
+// MessageQueueManager does cleanup of of message queues
+
+class MessageQueueManager {
+public:
+ static MessageQueueManager* Instance();
+
+ void Add(MessageQueue *message_queue);
+ void Remove(MessageQueue *message_queue);
+ void Clear(MessageHandler *handler);
+
+private:
+ MessageQueueManager();
+ ~MessageQueueManager();
+
+ static MessageQueueManager* instance_;
+ // This list contains 'active' MessageQueues.
+ std::vector<MessageQueue *> message_queues_;
+ CriticalSection crit_;
+};
+
+// Messages get dispatched to a MessageHandler
+
+class MessageHandler {
+public:
+ virtual ~MessageHandler() {
+ MessageQueueManager::Instance()->Clear(this);
+ }
+
+ virtual void OnMessage(Message *pmsg) = 0;
+};
+
+// Derive from this for specialized data
+// App manages lifetime, except when messages are purged
+
+class MessageData {
+public:
+ MessageData() {}
+ virtual ~MessageData() {}
+};
+
+template <class T>
+class TypedMessageData : public MessageData {
+public:
+ TypedMessageData(const T& data) : data_(data) { }
+ const T& data() const { return data_; }
+ T& data() { return data_; }
+private:
+ T data_;
+};
+
+template<class T>
+inline MessageData* WrapMessageData(const T& data) {
+ return new TypedMessageData<T>(data);
+}
+
+template<class T>
+inline const T& UseMessageData(MessageData* data) {
+ return static_cast< TypedMessageData<T>* >(data)->data();
+}
+
+template<class T>
+class DisposeData : public MessageData {
+public:
+ DisposeData(T* data) : data_(data) { }
+ virtual ~DisposeData() { delete data_; }
+private:
+ T* data_;
+};
+
+const uint32 MQID_ANY = static_cast<uint32>(-1);
+const uint32 MQID_DISPOSE = static_cast<uint32>(-2);
+
+// No destructor
+
+struct Message {
+ Message() {
+ memset(this, 0, sizeof(*this));
+ }
+ MessageHandler *phandler;
+ uint32 message_id;
+ MessageData *pdata;
+ uint32 ts_sensitive;
+};
+
+// DelayedMessage goes into a priority queue, sorted by trigger time
+
+class DelayedMessage {
+public:
+ DelayedMessage(int cmsDelay, Message *pmsg) {
+ cmsDelay_ = cmsDelay;
+ msTrigger_ = GetMillisecondCount() + cmsDelay;
+ msg_ = *pmsg;
+ }
+
+ bool operator< (const DelayedMessage& dmsg) const {
+ return dmsg.msTrigger_ < msTrigger_;
+ }
+
+ int cmsDelay_; // for debugging
+ uint32 msTrigger_;
+ Message msg_;
+};
+
+class MessageQueue {
+public:
+ MessageQueue(SocketServer* ss = 0);
+ virtual ~MessageQueue();
+
+ SocketServer* socketserver() { return ss_; }
+ void set_socketserver(SocketServer* ss);
+
+ // Note: The behavior of MessageQueue has changed. When a MQ is stopped,
+ // futher Posts and Sends will fail. However, any pending Sends and *ready*
+ // Posts (as opposed to unexpired delayed Posts) will be delivered before
+ // Get (or Peek) returns false. By guaranteeing delivery of those messages,
+ // we eliminate the race condition when an MessageHandler and MessageQueue
+ // may be destroyed independently of each other.
+ virtual void Quit();
+ virtual bool IsQuitting();
+ virtual void Restart();
+
+ // Get() will process I/O until:
+ // 1) A message is available (returns true)
+ // 2) cmsWait seconds have elapsed (returns false)
+ // 3) Stop() is called (returns false)
+ virtual bool Get(Message *pmsg, int cmsWait = kForever);
+ virtual bool Peek(Message *pmsg, int cmsWait = 0);
+ virtual void Post(MessageHandler *phandler, uint32 id = 0,
+ MessageData *pdata = NULL, bool time_sensitive = false);
+ virtual void PostDelayed(int cmsDelay, MessageHandler *phandler,
+ uint32 id = 0, MessageData *pdata = NULL);
+ virtual void Clear(MessageHandler *phandler, uint32 id = MQID_ANY);
+ virtual void Dispatch(Message *pmsg);
+ virtual void ReceiveSends();
+ virtual int GetDelay();
+
+ // Internally posts a message which causes the doomed object to be deleted
+ template<class T> void Dispose(T* doomed) {
+ if (doomed) {
+ Post(NULL, MQID_DISPOSE, new talk_base::DisposeData<T>(doomed));
+ }
+ }
+
+ // When this signal is sent out, any references to this queue should
+ // no longer be used.
+ sigslot::signal0<> SignalQueueDestroyed;
+
+protected:
+ void EnsureActive();
+
+ SocketServer* ss_;
+ // If a server isn't supplied in the constructor, use this one.
+ scoped_ptr<SocketServer> default_ss_;
+ bool new_ss;
+ bool fStop_;
+ bool fPeekKeep_;
+ Message msgPeek_;
+ // A message queue is active if it has ever had a message posted to it.
+ // This also corresponds to being in MessageQueueManager's global list.
+ bool active_;
+ std::queue<Message> msgq_;
+ std::priority_queue<DelayedMessage> dmsgq_;
+ CriticalSection crit_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_MESSAGEQUEUE_H__
diff --git a/third_party/libjingle/files/talk/base/nat_unittest.cc b/third_party/libjingle/files/talk/base/nat_unittest.cc
new file mode 100644
index 0000000..23c122b
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/nat_unittest.cc
@@ -0,0 +1,223 @@
+#include <string>
+#include <cstring>
+#include <iostream>
+#include <cassert>
+
+#include "talk/base/natserver.h"
+#include "talk/base/testclient.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/virtualsocketserver.h"
+#include "talk/base/natsocketfactory.h"
+#include "talk/base/host.h"
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+using namespace talk_base;
+
+#define CHECK(arg) Check(arg, #arg)
+
+void Check(int result, const char* desc) {
+ if (result < 0) {
+ std::cerr << desc << ": " << std::strerror(errno) << std::endl;
+ exit(1);
+ }
+}
+
+void CheckTest(bool act_val, bool exp_val, std::string desc) {
+ if (act_val && !exp_val) {
+ std::cerr << "error: " << desc << " was true, expected false" << std::endl;
+ exit(1);
+ } else if (!act_val && exp_val) {
+ std::cerr << "error: " << desc << " was false, expected true" << std::endl;
+ exit(1);
+ }
+}
+
+void CheckReceive(
+ TestClient* client, bool should_receive, const char* buf, size_t size) {
+ if (should_receive)
+ client->CheckNextPacket(buf, size, 0);
+ else
+ client->CheckNoPacket();
+}
+
+TestClient* CreateTestClient(
+ SocketFactory* factory, const SocketAddress& local_addr) {
+ AsyncUDPSocket* socket = CreateAsyncUDPSocket(factory);
+ CHECK(socket->Bind(local_addr));
+ return new TestClient(socket);
+}
+
+void TestNATPorts(
+ SocketServer* internal, const SocketAddress& internal_addr,
+ SocketServer* external, const SocketAddress external_addrs[4],
+ NATType nat_type, bool exp_same) {
+
+ Thread th_int(internal);
+ Thread th_ext(external);
+
+ SocketAddress server_addr = internal_addr;
+ server_addr.SetPort(NAT_SERVER_PORT);
+ NATServer* nat = new NATServer(
+ nat_type, internal, server_addr, external, external_addrs[0]);
+ NATSocketFactory* natsf = new NATSocketFactory(internal, server_addr);
+
+ TestClient* in = CreateTestClient(natsf, internal_addr);
+ TestClient* out[4];
+ for (int i = 0; i < 4; i++)
+ out[i] = CreateTestClient(external, external_addrs[i]);
+
+ th_int.Start();
+ th_ext.Start();
+
+ const char* buf = "filter_test";
+ size_t len = strlen(buf);
+
+ in->SendTo(buf, len, external_addrs[0]);
+ SocketAddress trans_addr;
+ out[0]->CheckNextPacket(buf, len, &trans_addr);
+
+ for (int i = 1; i < 4; i++) {
+ in->SendTo(buf, len, external_addrs[i]);
+ SocketAddress trans_addr2;
+ out[i]->CheckNextPacket(buf, len, &trans_addr2);
+ bool are_same = (trans_addr == trans_addr2);
+ CheckTest(are_same, exp_same, "same translated address");
+ }
+
+ th_int.Stop();
+ th_ext.Stop();
+
+ delete nat;
+ delete natsf;
+ delete in;
+ for (int i = 0; i < 4; i++)
+ delete out[i];
+}
+
+void TestPorts(
+ SocketServer* internal, const SocketAddress& internal_addr,
+ SocketServer* external, const SocketAddress external_addrs[4]) {
+ TestNATPorts(internal, internal_addr, external, external_addrs,
+ NAT_OPEN_CONE, true);
+ TestNATPorts(internal, internal_addr, external, external_addrs,
+ NAT_ADDR_RESTRICTED, true);
+ TestNATPorts(internal, internal_addr, external, external_addrs,
+ NAT_PORT_RESTRICTED, true);
+ TestNATPorts(internal, internal_addr, external, external_addrs,
+ NAT_SYMMETRIC, false);
+}
+
+void TestNATFilters(
+ SocketServer* internal, const SocketAddress& internal_addr,
+ SocketServer* external, const SocketAddress external_addrs[4],
+ NATType nat_type, bool filter_ip, bool filter_port) {
+
+ Thread th_int(internal);
+ Thread th_ext(external);
+
+ SocketAddress server_addr = internal_addr;
+ server_addr.SetPort(NAT_SERVER_PORT);
+ NATServer* nat = new NATServer(
+ nat_type, internal, server_addr, external, external_addrs[0]);
+ NATSocketFactory* natsf = new NATSocketFactory(internal, server_addr);
+
+ TestClient* in = CreateTestClient(natsf, internal_addr);
+ TestClient* out[4];
+ for (int i = 0; i < 4; i++)
+ out[i] = CreateTestClient(external, external_addrs[i]);
+
+ th_int.Start();
+ th_ext.Start();
+
+ const char* buf = "filter_test";
+ size_t len = strlen(buf);
+
+ in->SendTo(buf, len, external_addrs[0]);
+ SocketAddress trans_addr;
+ out[0]->CheckNextPacket(buf, len, &trans_addr);
+
+ out[1]->SendTo(buf, len, trans_addr);
+ CheckReceive(in, !filter_ip, buf, len);
+
+ out[2]->SendTo(buf, len, trans_addr);
+ CheckReceive(in, !filter_port, buf, len);
+
+ out[3]->SendTo(buf, len, trans_addr);
+ CheckReceive(in, !filter_ip && !filter_port, buf, len);
+
+ th_int.Stop();
+ th_ext.Stop();
+
+ delete nat;
+ delete natsf;
+ delete in;
+ for (int i = 0; i < 4; i++)
+ delete out[i];
+}
+
+void TestFilters(
+ SocketServer* internal, const SocketAddress& internal_addr,
+ SocketServer* external, const SocketAddress external_addrs[4]) {
+ TestNATFilters(internal, internal_addr, external, external_addrs,
+ NAT_OPEN_CONE, false, false);
+ TestNATFilters(internal, internal_addr, external, external_addrs,
+ NAT_ADDR_RESTRICTED, true, false);
+ TestNATFilters(internal, internal_addr, external, external_addrs,
+ NAT_PORT_RESTRICTED, true, true);
+ TestNATFilters(internal, internal_addr, external, external_addrs,
+ NAT_SYMMETRIC, true, true);
+}
+
+const int PORT0 = 7405;
+const int PORT1 = 7450;
+const int PORT2 = 7505;
+
+int main(int argc, char* argv[]) {
+ assert(LocalHost().networks().size() >= 2);
+ SocketAddress int_addr(LocalHost().networks()[1]->ip(), PORT0);
+
+ std::string ext_ip1 =
+ SocketAddress::IPToString(LocalHost().networks()[0]->ip()); // 127.0.0.1
+ std::string ext_ip2 =
+ SocketAddress::IPToString(LocalHost().networks()[1]->ip()); // 127.0.0.2
+ assert(int_addr.IPAsString() != ext_ip1);
+ //assert(int_addr.IPAsString() != ext_ip2); // uncomment
+
+ SocketAddress ext_addrs[4] = {
+ SocketAddress(ext_ip1, PORT1),
+ SocketAddress(ext_ip2, PORT1),
+ SocketAddress(ext_ip1, PORT2),
+ SocketAddress(ext_ip2, PORT2)
+ };
+
+ PhysicalSocketServer* int_pss = new PhysicalSocketServer();
+ PhysicalSocketServer* ext_pss = new PhysicalSocketServer();
+
+ std::cout << "Testing on physical network:" << std::endl;
+ TestPorts(int_pss, int_addr, ext_pss, ext_addrs);
+ std::cout << "ports: PASS" << std::endl;
+ TestFilters(int_pss, int_addr, ext_pss, ext_addrs);
+ std::cout << "filters: PASS" << std::endl;
+
+ VirtualSocketServer* int_vss = new VirtualSocketServer();
+ VirtualSocketServer* ext_vss = new VirtualSocketServer();
+
+ int_addr.SetIP(int_vss->GetNextIP());
+ ext_addrs[0].SetIP(ext_vss->GetNextIP());
+ ext_addrs[1].SetIP(ext_vss->GetNextIP());
+ ext_addrs[2].SetIP(ext_addrs[0].ip());
+ ext_addrs[3].SetIP(ext_addrs[1].ip());
+
+ std::cout << "Testing on virtual network:" << std::endl;
+ TestPorts(int_vss, int_addr, ext_vss, ext_addrs);
+ std::cout << "ports: PASS" << std::endl;
+ TestFilters(int_vss, int_addr, ext_vss, ext_addrs);
+ std::cout << "filters: PASS" << std::endl;
+
+ return 0;
+}
diff --git a/third_party/libjingle/files/talk/base/natserver.cc b/third_party/libjingle/files/talk/base/natserver.cc
new file mode 100644
index 0000000..66696a1
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/natserver.cc
@@ -0,0 +1,211 @@
+/*
+ * 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 <cassert>
+#include <cstring>
+#include <iostream>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+#include "talk/base/natserver.h"
+
+namespace talk_base {
+
+RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {
+}
+
+size_t RouteCmp::operator()(const SocketAddressPair& r) const {
+ size_t h = r.source().Hash();
+ if (symmetric)
+ h ^= r.destination().Hash();
+ return h;
+}
+
+bool RouteCmp::operator()(
+ const SocketAddressPair& r1, const SocketAddressPair& r2) const {
+ if (r1.source() < r2.source())
+ return true;
+ if (r2.source() < r1.source())
+ return false;
+ if (symmetric && (r1.destination() < r2.destination()))
+ return true;
+ if (symmetric && (r2.destination() < r1.destination()))
+ return false;
+ return false;
+}
+
+AddrCmp::AddrCmp(NAT* nat)
+ : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {
+}
+
+size_t AddrCmp::operator()(const SocketAddress& a) const {
+ size_t h = 0;
+ if (use_ip)
+ h ^= a.ip();
+ if (use_port)
+ h ^= a.port() | (a.port() << 16);
+ return h;
+}
+
+bool AddrCmp::operator()(
+ const SocketAddress& a1, const SocketAddress& a2) const {
+ if (use_ip && (a1.ip() < a2.ip()))
+ return true;
+ if (use_ip && (a2.ip() < a1.ip()))
+ return false;
+ if (use_port && (a1.port() < a2.port()))
+ return true;
+ if (use_port && (a2.port() < a1.port()))
+ return false;
+ return false;
+}
+
+NATServer::NATServer(
+ NATType type, SocketFactory* internal, const SocketAddress& internal_addr,
+ SocketFactory* external, const SocketAddress& external_ip)
+ : external_(external), external_ip_(external_ip) {
+ nat_ = NAT::Create(type);
+
+ server_socket_ = CreateAsyncUDPSocket(internal);
+ server_socket_->Bind(internal_addr);
+ server_socket_->SignalReadPacket.connect(this, &NATServer::OnInternalPacket);
+
+ int_map_ = new InternalMap(RouteCmp(nat_));
+ ext_map_ = new ExternalMap();
+}
+
+NATServer::~NATServer() {
+ for (InternalMap::iterator iter = int_map_->begin();
+ iter != int_map_->end();
+ iter++)
+ delete iter->second;
+
+ delete nat_;
+ delete server_socket_;
+ delete int_map_;
+ delete ext_map_;
+}
+
+void NATServer::OnInternalPacket(
+ const char* buf, size_t size, const SocketAddress& addr,
+ AsyncPacketSocket* socket) {
+
+ // Read the intended destination from the wire.
+ SocketAddress dest_addr;
+ dest_addr.Read_(buf, size);
+
+ // Find the translation for these addresses (allocating one if necessary).
+ SocketAddressPair route(addr, dest_addr);
+ InternalMap::iterator iter = int_map_->find(route);
+ if (iter == int_map_->end()) {
+ Translate(route);
+ iter = int_map_->find(route);
+ }
+ assert(iter != int_map_->end());
+
+ // Allow the destination to send packets back to the source.
+ iter->second->whitelist->insert(dest_addr);
+
+ // Send the packet to its intended destination.
+ iter->second->socket->SendTo(
+ buf + dest_addr.Size_(), size - dest_addr.Size_(), dest_addr);
+}
+
+void NATServer::OnExternalPacket(
+ const char* buf, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+
+ SocketAddress local_addr = socket->GetLocalAddress();
+
+ // Find the translation for this addresses.
+ ExternalMap::iterator iter = ext_map_->find(local_addr);
+ assert(iter != ext_map_->end());
+
+ // Allow the NAT to reject this packet.
+ if (Filter(iter->second, remote_addr)) {
+ std::cerr << "Packet from " << remote_addr.ToString()
+ << " was filtered out by the NAT." << std::endl;
+ return;
+ }
+
+ // Forward this packet to the internal address.
+
+ size_t real_size = size + remote_addr.Size_();
+ char* real_buf = new char[real_size];
+
+ remote_addr.Write_(real_buf, real_size);
+ std::memcpy(real_buf + remote_addr.Size_(), buf, size);
+
+ server_socket_->SendTo(real_buf, real_size, iter->second->route.source());
+
+ delete[] real_buf;
+}
+
+void NATServer::Translate(const SocketAddressPair& route) {
+ AsyncUDPSocket* socket = CreateAsyncUDPSocket(external_);
+
+ SocketAddress ext_addr = external_ip_;
+ for (int i = 0; i < 65536; i++) {
+ ext_addr.SetPort((route.source().port() + i) % 65536);
+ if (ext_map_->find(ext_addr) == ext_map_->end()) {
+ int result = socket->Bind(ext_addr);
+ if ((result < 0) && (socket->GetError() == EADDRINUSE))
+ continue;
+ assert(result >= 0); // TODO: do something better
+
+ TransEntry* entry = new TransEntry(route, socket, nat_);
+ (*int_map_)[route] = entry;
+ (*ext_map_)[ext_addr] = entry;
+ socket->SignalReadPacket.connect(this, &NATServer::OnExternalPacket);
+ return;
+ }
+ }
+
+ std::cerr << "Couldn't find a free port!" << std::endl;
+ delete socket;
+ exit(1);
+}
+
+bool NATServer::Filter(TransEntry* entry, const SocketAddress& ext_addr) {
+ return entry->whitelist->find(ext_addr) == entry->whitelist->end();
+}
+
+NATServer::TransEntry::TransEntry(
+ const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat)
+ : route(r), socket(s) {
+ whitelist = new AddressSet(AddrCmp(nat));
+}
+
+NATServer::TransEntry::~TransEntry() {
+ delete socket;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/natserver.h b/third_party/libjingle/files/talk/base/natserver.h
new file mode 100644
index 0000000..61c1dd3
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/natserver.h
@@ -0,0 +1,114 @@
+/*
+ * 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 TALK_BASE_NATSERVER_H__
+#define TALK_BASE_NATSERVER_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/socketaddresspair.h"
+#include "talk/base/thread.h"
+#include "talk/base/socketfactory.h"
+#include "talk/base/nattypes.h"
+#include <map>
+
+namespace talk_base {
+
+// Change how routes (socketaddress pairs) are compared based on the type of
+// NAT. The NAT server maintains a hashtable of the routes that it knows
+// about. So these affect which routes are treated the same.
+struct RouteCmp {
+ RouteCmp(NAT* nat);
+ size_t operator()(const SocketAddressPair& r) const;
+ bool operator()(
+ const SocketAddressPair& r1, const SocketAddressPair& r2) const;
+
+ bool symmetric;
+};
+
+// Changes how addresses are compared based on the filtering rules of the NAT.
+struct AddrCmp {
+ AddrCmp(NAT* nat);
+ size_t operator()(const SocketAddress& r) const;
+ bool operator()(const SocketAddress& r1, const SocketAddress& r2) const;
+
+ bool use_ip;
+ bool use_port;
+};
+
+// Implements the NAT device. It listens for packets on the internal network,
+// translates them, and sends them out over the external network.
+
+const int NAT_SERVER_PORT = 4237;
+
+class NATServer : public sigslot::has_slots<> {
+public:
+ NATServer(
+ NATType type, SocketFactory* internal, const SocketAddress& internal_addr,
+ SocketFactory* external, const SocketAddress& external_ip);
+ ~NATServer();
+
+ // Packets received on one of the networks.
+ void OnInternalPacket(
+ const char* buf, size_t size, const SocketAddress& addr,
+ AsyncPacketSocket* socket);
+ void OnExternalPacket(
+ const char* buf, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+
+private:
+ typedef std::set<SocketAddress,AddrCmp> AddressSet;
+
+ /* Records a translation and the associated external socket. */
+ struct TransEntry {
+ TransEntry(const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat);
+ ~TransEntry();
+
+ SocketAddressPair route;
+ AsyncUDPSocket* socket;
+ AddressSet* whitelist;
+ };
+
+ typedef std::map<SocketAddressPair,TransEntry*,RouteCmp> InternalMap;
+ typedef std::map<SocketAddress,TransEntry*> ExternalMap;
+
+ NAT* nat_;
+ AsyncUDPSocket* server_socket_;
+ SocketFactory* external_;
+ SocketAddress external_ip_;
+ InternalMap* int_map_;
+ ExternalMap* ext_map_;
+
+ /* Creates a new entry that translates the given route. */
+ void Translate(const SocketAddressPair& route);
+
+ /* Determines whether the NAT would filter out a packet from this address. */
+ bool Filter(TransEntry* entry, const SocketAddress& ext_addr);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_NATSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/natserver_main.cc b/third_party/libjingle/files/talk/base/natserver_main.cc
new file mode 100644
index 0000000..a748108
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/natserver_main.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 <iostream>
+
+#include "talk/base/natserver.h"
+#include "talk/base/host.h"
+#include "talk/base/physicalsocketserver.h"
+
+using namespace talk_base;
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "usage: natserver <internal-ip> <external-ip>" << std::endl;
+ exit(1);
+ }
+
+ SocketAddress internal = SocketAddress(argv[1]);
+ SocketAddress external = SocketAddress(argv[2]);
+ if (internal.EqualIPs(external)) {
+ std::cerr << "internal and external IPs must differ" << std::endl;
+ exit(1);
+ }
+
+ Thread* pthMain = Thread::Current();
+ PhysicalSocketServer* ss = new PhysicalSocketServer();
+ pthMain->set_socketserver(ss);
+ NATServer* server = new NATServer(NAT_OPEN_CONE, ss, internal, ss, external);
+ server = server;
+
+ pthMain->Run();
+ return 0;
+}
diff --git a/third_party/libjingle/files/talk/base/natsocketfactory.cc b/third_party/libjingle/files/talk/base/natsocketfactory.cc
new file mode 100644
index 0000000..59a0d87
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/natsocketfactory.cc
@@ -0,0 +1,229 @@
+/*
+ * 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 <iostream>
+#include <cassert>
+#include <cstring>
+#include "talk/base/natsocketfactory.h"
+
+namespace talk_base {
+
+class NATSocket : public AsyncSocket {
+public:
+ NATSocket(Socket* socket, const SocketAddress& server_addr)
+ : async_(false), connected_(false), server_addr_(server_addr),
+ socket_(socket), buf_(0), size_(0) {
+ }
+
+ NATSocket(AsyncSocket* socket, const SocketAddress& server_addr)
+ : async_(true), connected_(false), server_addr_(server_addr),
+ socket_(socket), buf_(0), size_(0) {
+ socket->SignalReadEvent.connect(this, &NATSocket::OnReadEvent);
+ socket->SignalWriteEvent.connect(this, &NATSocket::OnWriteEvent);
+ }
+
+ virtual ~NATSocket() {
+ delete socket_;
+ delete buf_;
+ }
+
+ SocketAddress GetLocalAddress() const {
+ return socket_->GetLocalAddress();
+ }
+
+ SocketAddress GetRemoteAddress() const {
+ return remote_addr_; // will be ANY if not connected
+ }
+
+ int Bind(const SocketAddress& addr) {
+ return socket_->Bind(addr);
+ }
+
+ int Connect(const SocketAddress& addr) {
+ connected_ = true;
+ remote_addr_ = addr;
+ return 0;
+ }
+
+ int Send(const void *pv, size_t cb) {
+ assert(connected_);
+ return SendInternal(pv, cb, remote_addr_);
+ }
+
+ int SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ assert(!connected_);
+ return SendInternal(pv, cb, addr);
+ }
+
+ int SendInternal(const void *pv, size_t cb, const SocketAddress& addr) {
+ size_t size = cb + addr.Size_();
+ char* buf = new char[size];
+ Encode(static_cast<const char*>(pv), cb, buf, size, addr);
+
+ int result = socket_->SendTo(buf, size, server_addr_);
+ delete buf;
+ if (result < 0) {
+ return result;
+ } else {
+ assert(result == static_cast<int>(size)); // TODO: This isn't fair.
+ return (int)((size_t)result - addr.Size_());
+ }
+ }
+
+ int Recv(void *pv, size_t cb) {
+ SocketAddress addr;
+ return RecvFrom(pv, cb, &addr);
+ }
+
+ int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ // Make sure we have enough room to read the requested amount plus the
+ // header address.
+ SocketAddress remote_addr;
+ Grow(cb + remote_addr.Size_());
+
+ // Read the packet from the socket.
+ int result = socket_->RecvFrom(buf_, size_, &remote_addr);
+ if (result < 0)
+ return result;
+ assert(remote_addr == server_addr_);
+
+ // TODO: we need better framing so that we know how many bytes we can
+ // return before we need to read the next address. For UDP, this will be
+ // fine as long as the reader always reads everything in the packet.
+ assert((size_t)result < size_);
+
+ // Decode the wire packet into the actual results.
+ SocketAddress real_remote_addr;
+ size_t real_size = cb;
+ Decode(buf_, result, pv, &real_size, &real_remote_addr);
+
+ // Make sure this packet should be delivered before returning it.
+ if (!connected_ || (real_remote_addr == remote_addr_)) {
+ if (paddr)
+ *paddr = real_remote_addr;
+ return (int)real_size;
+ } else {
+ std::cerr << "Dropping packet from unknown remote address: "
+ << real_remote_addr.ToString() << std::endl;
+ return 0; // Tell the caller we didn't read anything
+ }
+ }
+
+ int Close() {
+ connected_ = false;
+ remote_addr_ = SocketAddress();
+ return socket_->Close();
+ }
+
+ int Listen(int backlog) {
+ assert(false); // not yet implemented
+ return 0;
+ }
+
+ Socket* Accept(SocketAddress *paddr) {
+ assert(false); // not yet implemented
+ return 0;
+ }
+
+ AsyncSocket* asyncsocket() {
+ assert(async_);
+ return static_cast<AsyncSocket*>(socket_);
+ }
+
+ int GetError() const { return socket_->GetError(); }
+ void SetError(int error) { socket_->SetError(error); }
+
+ ConnState GetState() const { return connected_ ? CS_CONNECTED : CS_CLOSED; }
+
+ virtual int EstimateMTU(uint16* mtu) { return socket_->EstimateMTU(mtu); }
+ virtual int SetOption(Option opt, int value) { return socket_->SetOption(opt, value); }
+
+ void OnReadEvent(AsyncSocket* socket) {
+ assert(socket == socket_);
+ SignalReadEvent(this);
+ }
+
+ void OnWriteEvent(AsyncSocket* socket) {
+ assert(socket == socket_);
+ SignalWriteEvent(this);
+ }
+
+private:
+ // Makes sure the buffer is at least the given size.
+ void Grow(size_t new_size) {
+ if (size_ < new_size) {
+ delete buf_;
+ size_ = new_size;
+ buf_ = new char[size_];
+ }
+ }
+
+ // Encodes the given data and intended remote address into a packet to send
+ // to the NAT server.
+ void Encode(const char* data, size_t data_size, char* buf, size_t buf_size,
+ const SocketAddress& remote_addr) {
+ assert(buf_size == data_size + remote_addr.Size_());
+ remote_addr.Write_(buf, (int)buf_size);
+ std::memcpy(buf + remote_addr.Size_(), data, data_size);
+ }
+
+ // Decodes the given packet from the NAT server into the actual remote
+ // address and data.
+ void Decode(const char* data, size_t data_size, void* buf, size_t* buf_size,
+ SocketAddress* remote_addr) {
+ assert(data_size >= remote_addr->Size_());
+ assert(data_size <= *buf_size + remote_addr->Size_());
+ remote_addr->Read_(data, (int)data_size);
+ *buf_size = data_size - remote_addr->Size_();
+ std::memcpy(buf, data + remote_addr->Size_(), *buf_size);
+ }
+
+ bool async_;
+ bool connected_;
+ SocketAddress remote_addr_;
+ SocketAddress server_addr_; // address of the NAT server
+ Socket* socket_;
+ char* buf_;
+ size_t size_;
+};
+
+NATSocketFactory::NATSocketFactory(
+ SocketFactory* factory, const SocketAddress& nat_addr)
+ : factory_(factory), nat_addr_(nat_addr) {
+}
+
+Socket* NATSocketFactory::CreateSocket(int type) {
+ assert(type == SOCK_DGRAM); // TCP is not yet suported
+ return new NATSocket(factory_->CreateSocket(type), nat_addr_);
+}
+
+AsyncSocket* NATSocketFactory::CreateAsyncSocket(int type) {
+ assert(type == SOCK_DGRAM); // TCP is not yet suported
+ return new NATSocket(factory_->CreateAsyncSocket(type), nat_addr_);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/natsocketfactory.h b/third_party/libjingle/files/talk/base/natsocketfactory.h
new file mode 100644
index 0000000..a689158
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/natsocketfactory.h
@@ -0,0 +1,51 @@
+/*
+ * 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 TALK_BASE_NATSOCKETFACTORY_H__
+#define TALK_BASE_NATSOCKETFACTORY_H__
+
+#include "talk/base/socketfactory.h"
+
+namespace talk_base {
+
+// Creates sockets that will send all traffic through a NAT. The actual data
+// is sent using sockets from a socket factory, given to the constructor.
+class NATSocketFactory : public SocketFactory {
+public:
+ NATSocketFactory(SocketFactory* factory, const SocketAddress& nat_addr);
+
+ virtual Socket* CreateSocket(int type);
+ virtual AsyncSocket* CreateAsyncSocket(int type);
+
+private:
+ SocketFactory* factory_;
+ SocketAddress nat_addr_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_NATSOCKETFACTORY_H__
diff --git a/third_party/libjingle/files/talk/base/nattypes.cc b/third_party/libjingle/files/talk/base/nattypes.cc
new file mode 100644
index 0000000..290c3ad
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/nattypes.cc
@@ -0,0 +1,72 @@
+/*
+ * 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 <cassert>
+
+#include "talk/base/nattypes.h"
+
+namespace talk_base {
+
+class SymmetricNAT : public NAT {
+public:
+ bool IsSymmetric() { return true; }
+ bool FiltersIP() { return true; }
+ bool FiltersPort() { return true; }
+};
+
+class OpenConeNAT : public NAT {
+public:
+ bool IsSymmetric() { return false; }
+ bool FiltersIP() { return false; }
+ bool FiltersPort() { return false; }
+};
+
+class AddressRestrictedNAT : public NAT {
+public:
+ bool IsSymmetric() { return false; }
+ bool FiltersIP() { return true; }
+ bool FiltersPort() { return false; }
+};
+
+class PortRestrictedNAT : public NAT {
+public:
+ bool IsSymmetric() { return false; }
+ bool FiltersIP() { return true; }
+ bool FiltersPort() { return true; }
+};
+
+NAT* NAT::Create(NATType type) {
+ switch (type) {
+ case NAT_OPEN_CONE: return new OpenConeNAT();
+ case NAT_ADDR_RESTRICTED: return new AddressRestrictedNAT();
+ case NAT_PORT_RESTRICTED: return new PortRestrictedNAT();
+ case NAT_SYMMETRIC: return new SymmetricNAT();
+ default: assert(0); return 0;
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/nattypes.h b/third_party/libjingle/files/talk/base/nattypes.h
new file mode 100644
index 0000000..aad11bb
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/nattypes.h
@@ -0,0 +1,62 @@
+/*
+ * 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 TALK_BASE_NATTYPE_H__
+#define TALK_BASE_NATTYPE_H__
+
+namespace talk_base {
+
+/* Identifies each type of NAT that can be simulated. */
+enum NATType {
+ NAT_OPEN_CONE,
+ NAT_ADDR_RESTRICTED,
+ NAT_PORT_RESTRICTED,
+ NAT_SYMMETRIC
+};
+
+// Implements the rules for each specific type of NAT.
+class NAT {
+public:
+ // Determines whether this NAT uses both source and destination address when
+ // checking whether a mapping already exists.
+ virtual bool IsSymmetric() = 0;
+
+ // Determines whether this NAT drops packets received from a different IP
+ // the one last sent to.
+ virtual bool FiltersIP() = 0;
+
+ // Determines whether this NAT drops packets received from a different port
+ // the one last sent to.
+ virtual bool FiltersPort() = 0;
+
+ // Returns an implementation of the given type of NAT.
+ static NAT* Create(NATType type);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_NATTYPE_H__
diff --git a/third_party/libjingle/files/talk/base/network.cc b/third_party/libjingle/files/talk/base/network.cc
new file mode 100644
index 0000000..d5a7d24
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/network.cc
@@ -0,0 +1,381 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+#include <cfloat>
+#include <cmath>
+#include <sstream>
+
+#ifdef POSIX
+extern "C" {
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <errno.h>
+}
+#endif // POSIX
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#include <Iphlpapi.h>
+#endif
+
+#include "talk/base/host.h"
+#include "talk/base/logging.h"
+#include "talk/base/network.h"
+#include "talk/base/socket.h" // this includes something that makes windows happy
+#include "talk/base/stringencode.h"
+#include "talk/base/time.h"
+#include "talk/base/basicdefs.h"
+
+namespace {
+
+const double kAlpha = 0.5; // weight for data infinitely far in the past
+const double kHalfLife = 2000; // half life of exponential decay (in ms)
+const double kLog2 = 0.693147180559945309417;
+const double kLambda = kLog2 / kHalfLife;
+
+// assume so-so quality unless data says otherwise
+const double kDefaultQuality = talk_base::QUALITY_FAIR;
+
+typedef std::map<std::string,std::string> StrMap;
+
+void BuildMap(const StrMap& map, std::string& str) {
+ str.append("{");
+ bool first = true;
+ for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) {
+ if (!first) str.append(",");
+ str.append(i->first);
+ str.append("=");
+ str.append(i->second);
+ first = false;
+ }
+ str.append("}");
+}
+
+void ParseCheck(std::istringstream& ist, char ch) {
+ if (ist.get() != ch)
+ LOG(LERROR) << "Expecting '" << ch << "'";
+}
+
+std::string ParseString(std::istringstream& ist) {
+ std::string str;
+ int count = 0;
+ while (ist) {
+ char ch = ist.peek();
+ if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) {
+ break;
+ } else if (ch == '{') {
+ count += 1;
+ } else if (ch == '}') {
+ count -= 1;
+ if (count < 0)
+ LOG(LERROR) << "mismatched '{' and '}'";
+ }
+ str.append(1, static_cast<char>(ist.get()));
+ }
+ return str;
+}
+
+void ParseMap(const std::string& str, StrMap& map) {
+ if (str.size() == 0)
+ return;
+ std::istringstream ist(str);
+ ParseCheck(ist, '{');
+ for (;;) {
+ std::string key = ParseString(ist);
+ ParseCheck(ist, '=');
+ std::string val = ParseString(ist);
+ map[key] = val;
+ if (ist.peek() == ',')
+ ist.get();
+ else
+ break;
+ }
+ ParseCheck(ist, '}');
+ if (ist.rdbuf()->in_avail() != 0)
+ LOG(LERROR) << "Unexpected characters at end";
+}
+
+#if 0
+const std::string TEST_MAP0_IN = "";
+const std::string TEST_MAP0_OUT = "{}";
+const std::string TEST_MAP1 = "{a=12345}";
+const std::string TEST_MAP2 = "{a=12345,b=67890}";
+const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}";
+const std::string TEST_MAP4 = "{a={d=12345,e=67890}}";
+const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}";
+const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}";
+const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}";
+
+class MyTest {
+public:
+ MyTest() {
+ test(TEST_MAP0_IN, TEST_MAP0_OUT);
+ test(TEST_MAP1, TEST_MAP1);
+ test(TEST_MAP2, TEST_MAP2);
+ test(TEST_MAP3, TEST_MAP3);
+ test(TEST_MAP4, TEST_MAP4);
+ test(TEST_MAP5, TEST_MAP5);
+ test(TEST_MAP6, TEST_MAP6);
+ test(TEST_MAP7, TEST_MAP7);
+ }
+ void test(const std::string& input, const std::string& exp_output) {
+ StrMap map;
+ ParseMap(input, map);
+ std::string output;
+ BuildMap(map, output);
+ LOG(INFO) << " ******** " << (output == exp_output);
+ }
+};
+
+static MyTest myTest;
+#endif
+
+} // namespace
+
+namespace talk_base {
+
+#ifdef POSIX
+void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
+ int fd;
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ PLOG(LERROR, errno) << "socket";
+ return;
+ }
+
+ struct ifconf ifc;
+ ifc.ifc_len = 64 * sizeof(struct ifreq);
+ ifc.ifc_buf = new char[ifc.ifc_len];
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ PLOG(LERROR, errno) << "ioctl";
+ return;
+ }
+ assert(ifc.ifc_len < static_cast<int>(64 * sizeof(struct ifreq)));
+
+ struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf);
+ struct ifreq* end =
+ reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len);
+
+ while (ptr < end) {
+ if (strcmp(ptr->ifr_name, "lo")) { // Ignore the loopback device
+ struct sockaddr_in* inaddr =
+ reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr);
+ if (inaddr->sin_family == AF_INET) {
+ uint32 ip = ntohl(inaddr->sin_addr.s_addr);
+ networks.push_back(new Network(std::string(ptr->ifr_name), ip));
+ }
+ }
+#ifdef _SIZEOF_ADDR_IFREQ
+ ptr = reinterpret_cast<struct ifreq*>(
+ reinterpret_cast<char*>(ptr) + _SIZEOF_ADDR_IFREQ(*ptr));
+#else
+ ptr++;
+#endif
+ }
+
+ delete [] ifc.ifc_buf;
+ close(fd);
+}
+#endif
+
+#ifdef WIN32
+void NetworkManager::CreateNetworks(std::vector<Network*>& networks) {
+ IP_ADAPTER_INFO info_temp;
+ ULONG len = 0;
+
+ if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW)
+ return;
+ IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len];
+ if (GetAdaptersInfo(infos, &len) != NO_ERROR)
+ return;
+
+ int count = 0;
+ for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) {
+ if (info->Type == MIB_IF_TYPE_LOOPBACK)
+ continue;
+ if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0)
+ continue;
+
+ // In production, don't transmit the network name because of
+ // privacy concerns. Transmit a number instead.
+
+ std::string name;
+#if defined(PRODUCTION)
+ std::ostringstream ost;
+ ost << count;
+ name = ost.str();
+ count++;
+#else
+ name = info->Description;
+#endif
+
+ networks.push_back(new Network(name,
+ SocketAddress::StringToIP(info->IpAddressList.IpAddress.String)));
+ }
+
+ delete infos;
+}
+#endif
+
+void NetworkManager::GetNetworks(std::vector<Network*>& result) {
+ std::vector<Network*> list;
+ CreateNetworks(list);
+
+ for (uint32 i = 0; i < list.size(); ++i) {
+ NetworkMap::iterator iter = networks_.find(list[i]->name());
+
+ Network* network;
+ if (iter == networks_.end()) {
+ network = list[i];
+ } else {
+ network = iter->second;
+ network->set_ip(list[i]->ip());
+ delete list[i];
+ }
+
+ networks_[network->name()] = network;
+ result.push_back(network);
+ }
+}
+
+std::string NetworkManager::GetState() {
+ StrMap map;
+ for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i)
+ map[i->first] = i->second->GetState();
+
+ std::string str;
+ BuildMap(map, str);
+ return str;
+}
+
+void NetworkManager::SetState(std::string str) {
+ StrMap map;
+ ParseMap(str, map);
+
+ for (StrMap::iterator i = map.begin(); i != map.end(); ++i) {
+ std::string name = i->first;
+ std::string state = i->second;
+
+ Network* network = new Network(name, 0);
+ network->SetState(state);
+ networks_[name] = network;
+ }
+}
+
+Network::Network(const std::string& name, uint32 ip)
+ : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0),
+ exponential_numerator_(0), exponential_denominator_(0),
+ quality_(kDefaultQuality) {
+
+ last_data_time_ = Time();
+
+ // TODO: seed the historical data with one data point based on the link speed
+ // metric from XP (4.0 if < 50, 3.0 otherwise).
+}
+
+void Network::StartSession(NetworkSession* session) {
+ assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end());
+ sessions_.push_back(session);
+}
+
+void Network::StopSession(NetworkSession* session) {
+ SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session);
+ if (iter != sessions_.end())
+ sessions_.erase(iter);
+}
+
+void Network::EstimateQuality() {
+ uint32 now = Time();
+
+ // Add new data points for the current time.
+ for (uint32 i = 0; i < sessions_.size(); ++i) {
+ if (sessions_[i]->HasQuality())
+ AddDataPoint(now, sessions_[i]->GetCurrentQuality());
+ }
+
+ // Construct the weighted average using both uniform and exponential weights.
+
+ double exp_shift = exp(-kLambda * (now - last_data_time_));
+ double numerator = uniform_numerator_ + exp_shift * exponential_numerator_;
+ double denominator = uniform_denominator_ + exp_shift * exponential_denominator_;
+
+ if (denominator < DBL_EPSILON)
+ quality_ = kDefaultQuality;
+ else
+ quality_ = numerator / denominator;
+}
+
+std::string Network::ToString() const {
+ std::stringstream ss;
+ // Print out the first space-terminated token of the network name, plus
+ // the IP address.
+ ss << "Net[" << name_.substr(0, name_.find(' '))
+ << ":" << SocketAddress::IPToString(ip_) << "]";
+ return ss.str();
+}
+
+void Network::AddDataPoint(uint32 time, double quality) {
+ uniform_numerator_ += kAlpha * quality;
+ uniform_denominator_ += kAlpha;
+
+ double exp_shift = exp(-kLambda * (time - last_data_time_));
+ exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_;
+ exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_;
+
+ last_data_time_ = time;
+}
+
+std::string Network::GetState() {
+ StrMap map;
+ map["lt"] = talk_base::ToString<uint32>(last_data_time_);
+ map["un"] = talk_base::ToString<double>(uniform_numerator_);
+ map["ud"] = talk_base::ToString<double>(uniform_denominator_);
+ map["en"] = talk_base::ToString<double>(exponential_numerator_);
+ map["ed"] = talk_base::ToString<double>(exponential_denominator_);
+
+ std::string str;
+ BuildMap(map, str);
+ return str;
+}
+
+void Network::SetState(std::string str) {
+ StrMap map;
+ ParseMap(str, map);
+
+ last_data_time_ = FromString<uint32>(map["lt"]);
+ uniform_numerator_ = FromString<double>(map["un"]);
+ uniform_denominator_ = FromString<double>(map["ud"]);
+ exponential_numerator_ = FromString<double>(map["en"]);
+ exponential_denominator_ = FromString<double>(map["ed"]);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/network.h b/third_party/libjingle/files/talk/base/network.h
new file mode 100644
index 0000000..52785ba
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/network.h
@@ -0,0 +1,139 @@
+/*
+ * 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 TALK_BASE_NETWORK_H__
+#define TALK_BASE_NETWORK_H__
+
+#include <deque>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "talk/base/basictypes.h"
+
+namespace talk_base {
+
+class Network;
+class NetworkSession;
+
+// Keeps track of the available network interfaces over time so that quality
+// information can be aggregated and recorded.
+class NetworkManager {
+public:
+
+ // Updates and returns the current list of networks available on this machine.
+ // This version will make sure that repeated calls return the same object for
+ // a given network, so that quality is tracked appropriately.
+ void GetNetworks(std::vector<Network*>& networks);
+
+ // Reads and writes the state of the quality database in a string format.
+ std::string GetState();
+ void SetState(std::string str);
+
+ // Creates a network object for each network available on the machine.
+ static void CreateNetworks(std::vector<Network*>& networks);
+
+private:
+ typedef std::map<std::string,Network*> NetworkMap;
+
+ NetworkMap networks_;
+};
+
+// Represents a Unix-type network interface, with a name and single address.
+// It also includes the ability to track and estimate quality.
+class Network {
+public:
+ Network(const std::string& name, uint32 ip);
+
+ // Returns the OS name of this network. This is considered the primary key
+ // that identifies each network.
+ const std::string& name() const { return name_; }
+
+ // Identifies the current IP address used by this network.
+ uint32 ip() const { return ip_; }
+ void set_ip(uint32 ip) { ip_ = ip; }
+
+ // Updates the list of sessions that are ongoing.
+ void StartSession(NetworkSession* session);
+ void StopSession(NetworkSession* session);
+
+ // Re-computes the estimate of near-future quality based on the information
+ // as of this exact moment.
+ void EstimateQuality();
+
+ // Returns the current estimate of the near-future quality of connections
+ // that use this local interface.
+ double quality() { return quality_; }
+
+ // Debugging description of this network
+ std::string ToString() const;
+
+private:
+ typedef std::vector<NetworkSession*> SessionList;
+
+ std::string name_;
+ uint32 ip_;
+ SessionList sessions_;
+ double uniform_numerator_;
+ double uniform_denominator_;
+ double exponential_numerator_;
+ double exponential_denominator_;
+ uint32 last_data_time_;
+ double quality_;
+
+ // Updates the statistics maintained to include the given estimate.
+ void AddDataPoint(uint32 time, double quality);
+
+ // Converts the internal state to and from a string. This is used to record
+ // quality information into a permanent store.
+ void SetState(std::string str);
+ std::string GetState();
+
+ friend class NetworkManager;
+};
+
+// Represents a session that is in progress using a particular network and can
+// provide data about the quality of the network at any given moment.
+class NetworkSession {
+public:
+ // Determines whether this session has an estimate at this moment. We will
+ // only call GetCurrentQuality when this returns true.
+ virtual bool HasQuality() = 0;
+
+ // Returns an estimate of the quality at this exact moment. The result should
+ // be a MOS (mean opinion score) value.
+ virtual float GetCurrentQuality() = 0;
+
+};
+
+const double QUALITY_BAD = 3.0;
+const double QUALITY_FAIR = 3.35;
+const double QUALITY_GOOD = 3.7;
+
+} // namespace talk_base
+
+#endif // TALK_BASE_NETWORK_H__
diff --git a/third_party/libjingle/files/talk/base/openssladapter.cc b/third_party/libjingle/files/talk/base/openssladapter.cc
new file mode 100644
index 0000000..40ec6f1
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/openssladapter.cc
@@ -0,0 +1,809 @@
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/openssladapter.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/Equifax_Secure_Global_eBusiness_CA-1.h"
+
+//////////////////////////////////////////////////////////////////////
+// StreamBIO
+//////////////////////////////////////////////////////////////////////
+
+#if 0
+static int stream_write(BIO* h, const char* buf, int num);
+static int stream_read(BIO* h, char* buf, int size);
+static int stream_puts(BIO* h, const char* str);
+static long stream_ctrl(BIO* h, int cmd, long arg1, void* arg2);
+static int stream_new(BIO* h);
+static int stream_free(BIO* data);
+
+static BIO_METHOD methods_stream = {
+ BIO_TYPE_BIO,
+ "stream",
+ stream_write,
+ stream_read,
+ stream_puts,
+ 0,
+ stream_ctrl,
+ stream_new,
+ stream_free,
+ NULL,
+};
+
+BIO_METHOD* BIO_s_stream() { return(&methods_stream); }
+
+BIO* BIO_new_stream(StreamInterface* stream) {
+ BIO* ret = BIO_new(BIO_s_stream());
+ if (ret == NULL)
+ return NULL;
+ ret->ptr = stream;
+ return ret;
+}
+
+static int stream_new(BIO* b) {
+ b->shutdown = 0;
+ b->init = 1;
+ b->num = 0; // 1 means end-of-stream
+ b->ptr = 0;
+ return 1;
+}
+
+static int stream_free(BIO* b) {
+ if (b == NULL)
+ return 0;
+ return 1;
+}
+
+static int stream_read(BIO* b, char* out, int outl) {
+ if (!out)
+ return -1;
+ StreamInterface* stream = static_cast<StreamInterface*>(b->ptr);
+ BIO_clear_retry_flags(b);
+ size_t read;
+ int error;
+ StreamResult result = stream->Read(out, outl, &read, &error);
+ if (result == SR_SUCCESS) {
+ return read;
+ } else if (result == SR_EOS) {
+ b->num = 1;
+ } else if (result == SR_BLOCK) {
+ BIO_set_retry_read(b);
+ }
+ return -1;
+}
+
+static int stream_write(BIO* b, const char* in, int inl) {
+ if (!in)
+ return -1;
+ StreamInterface* stream = static_cast<StreamInterface*>(b->ptr);
+ BIO_clear_retry_flags(b);
+ size_t written;
+ int error;
+ StreamResult result = stream->Write(in, inl, &written, &error);
+ if (result == SR_SUCCESS) {
+ return written;
+ } else if (result == SR_BLOCK) {
+ BIO_set_retry_write(b);
+ }
+ return -1;
+}
+
+static int stream_puts(BIO* b, const char* str) {
+ return stream_write(b, str, strlen(str));
+}
+
+static long stream_ctrl(BIO* b, int cmd, long num, void* ptr) {
+ UNUSED(num);
+ UNUSED(ptr);
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ return 0;
+ case BIO_CTRL_EOF:
+ return b->num;
+ case BIO_CTRL_WPENDING:
+ case BIO_CTRL_PENDING:
+ return 0;
+ case BIO_CTRL_FLUSH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// SocketBIO
+//////////////////////////////////////////////////////////////////////
+
+static int socket_write(BIO* h, const char* buf, int num);
+static int socket_read(BIO* h, char* buf, int size);
+static int socket_puts(BIO* h, const char* str);
+static long socket_ctrl(BIO* h, int cmd, long arg1, void* arg2);
+static int socket_new(BIO* h);
+static int socket_free(BIO* data);
+
+static BIO_METHOD methods_socket = {
+ BIO_TYPE_BIO,
+ "socket",
+ socket_write,
+ socket_read,
+ socket_puts,
+ 0,
+ socket_ctrl,
+ socket_new,
+ socket_free,
+ NULL,
+};
+
+BIO_METHOD* BIO_s_socket2() { return(&methods_socket); }
+
+BIO* BIO_new_socket(talk_base::AsyncSocket* socket) {
+ BIO* ret = BIO_new(BIO_s_socket2());
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->ptr = socket;
+ return ret;
+}
+
+static int socket_new(BIO* b) {
+ b->shutdown = 0;
+ b->init = 1;
+ b->num = 0; // 1 means socket closed
+ b->ptr = 0;
+ return 1;
+}
+
+static int socket_free(BIO* b) {
+ if (b == NULL)
+ return 0;
+ return 1;
+}
+
+static int socket_read(BIO* b, char* out, int outl) {
+ if (!out)
+ return -1;
+ talk_base::AsyncSocket* socket = static_cast<talk_base::AsyncSocket*>(b->ptr);
+ BIO_clear_retry_flags(b);
+ int result = socket->Recv(out, outl);
+ if (result > 0) {
+ return result;
+ } else if (result == 0) {
+ b->num = 1;
+ } else if (socket->IsBlocking()) {
+ BIO_set_retry_read(b);
+ }
+ return -1;
+}
+
+static int socket_write(BIO* b, const char* in, int inl) {
+ if (!in)
+ return -1;
+ talk_base::AsyncSocket* socket = static_cast<talk_base::AsyncSocket*>(b->ptr);
+ BIO_clear_retry_flags(b);
+ int result = socket->Send(in, inl);
+ if (result > 0) {
+ return result;
+ } else if (socket->IsBlocking()) {
+ BIO_set_retry_write(b);
+ }
+ return -1;
+}
+
+static int socket_puts(BIO* b, const char* str) {
+ return socket_write(b, str, strlen(str));
+}
+
+static long socket_ctrl(BIO* b, int cmd, long num, void* ptr) {
+ UNUSED(num);
+ UNUSED(ptr);
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ return 0;
+ case BIO_CTRL_EOF:
+ return b->num;
+ case BIO_CTRL_WPENDING:
+ case BIO_CTRL_PENDING:
+ return 0;
+ case BIO_CTRL_FLUSH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// OpenSSLAdapter
+/////////////////////////////////////////////////////////////////////////////
+
+namespace talk_base {
+
+OpenSSLAdapter::OpenSSLAdapter(AsyncSocket* socket)
+ : SSLAdapter(socket),
+ state_(SSL_NONE),
+ ssl_read_needs_write_(false),
+ ssl_write_needs_read_(false),
+ restartable_(false),
+ ssl_(NULL), ssl_ctx_(NULL) {
+}
+
+OpenSSLAdapter::~OpenSSLAdapter() {
+ Cleanup();
+}
+
+int
+OpenSSLAdapter::StartSSL(const char* hostname, bool restartable) {
+ if (state_ != SSL_NONE)
+ return -1;
+
+ ssl_host_name_ = hostname;
+ restartable_ = restartable;
+
+ if (socket_->GetState() != Socket::CS_CONNECTED) {
+ state_ = SSL_WAIT;
+ return 0;
+ }
+
+ state_ = SSL_CONNECTING;
+ if (int err = BeginSSL()) {
+ Error("BeginSSL", err, false);
+ return err;
+ }
+
+ return 0;
+}
+
+int
+OpenSSLAdapter::BeginSSL() {
+ LOG(LS_INFO) << "BeginSSL: " << ssl_host_name_;
+ ASSERT(state_ == SSL_CONNECTING);
+
+ int err = 0;
+ BIO* bio = NULL;
+
+ // First set up the context
+ if (!ssl_ctx_)
+ ssl_ctx_ = SetupSSLContext();
+
+ if (!ssl_ctx_) {
+ err = -1;
+ goto ssl_error;
+ }
+
+ bio = BIO_new_socket(static_cast<talk_base::AsyncSocketAdapter*>(socket_));
+ if (!bio) {
+ err = -1;
+ goto ssl_error;
+ }
+
+ ssl_ = SSL_new(ssl_ctx_);
+ if (!ssl_) {
+ err = -1;
+ goto ssl_error;
+ }
+
+ SSL_set_app_data(ssl_, this);
+
+ SSL_set_bio(ssl_, bio, bio);
+ SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ // the SSL object owns the bio now
+ bio = NULL;
+
+ // Do the connect
+ err = ContinueSSL();
+ if (err != 0)
+ goto ssl_error;
+
+ return err;
+
+ssl_error:
+ Cleanup();
+ if (bio)
+ BIO_free(bio);
+
+ return err;
+}
+
+int
+OpenSSLAdapter::ContinueSSL() {
+ LOG(LS_INFO) << "ContinueSSL";
+ ASSERT(state_ == SSL_CONNECTING);
+
+ int code = SSL_connect(ssl_);
+ switch (SSL_get_error(ssl_, code)) {
+ case SSL_ERROR_NONE:
+ LOG(LS_INFO) << " -- success";
+
+ if (!SSLPostConnectionCheck(ssl_, ssl_host_name_.c_str())) {
+ LOG(LS_ERROR) << "TLS post connection check failed";
+ // make sure we close the socket
+ Cleanup();
+ // The connect failed so return -1 to shut down the socket
+ return -1;
+ }
+
+ state_ = SSL_CONNECTED;
+ AsyncSocketAdapter::OnConnectEvent(this);
+#if 0 // TODO: worry about this
+ // Don't let ourselves go away during the callbacks
+ PRefPtr<OpenSSLAdapter> lock(this);
+ LOG(LS_INFO) << " -- onStreamReadable";
+ AsyncSocketAdapter::OnReadEvent(this);
+ LOG(LS_INFO) << " -- onStreamWriteable";
+ AsyncSocketAdapter::OnWriteEvent(this);
+#endif
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ LOG(LS_INFO) << " -- error want read";
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ LOG(LS_INFO) << " -- error want write";
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ LOG(LS_INFO) << " -- error " << code;
+ return (code != 0) ? code : -1;
+ }
+
+ return 0;
+}
+
+void
+OpenSSLAdapter::Error(const char* context, int err, bool signal) {
+ LOG(LS_WARNING) << "SChannelAdapter::Error("
+ << context << ", " << err << ")";
+ state_ = SSL_ERROR;
+ SetError(err);
+ if (signal)
+ AsyncSocketAdapter::OnCloseEvent(this, err);
+}
+
+void
+OpenSSLAdapter::Cleanup() {
+ LOG(LS_INFO) << "Cleanup";
+
+ state_ = SSL_NONE;
+ ssl_read_needs_write_ = false;
+ ssl_write_needs_read_ = false;
+
+ if (ssl_) {
+ SSL_free(ssl_);
+ ssl_ = NULL;
+ }
+
+ if (ssl_ctx_) {
+ SSL_CTX_free(ssl_ctx_);
+ ssl_ctx_ = NULL;
+ }
+}
+
+//
+// AsyncSocket Implementation
+//
+
+int
+OpenSSLAdapter::Send(const void* pv, size_t cb) {
+ //LOG(LS_INFO) << "OpenSSLAdapter::Send(" << cb << ")";
+
+ switch (state_) {
+ case SSL_NONE:
+ return AsyncSocketAdapter::Send(pv, cb);
+
+ case SSL_WAIT:
+ case SSL_CONNECTING:
+ SetError(EWOULDBLOCK);
+ return SOCKET_ERROR;
+
+ case SSL_CONNECTED:
+ break;
+
+ case SSL_ERROR:
+ default:
+ return SOCKET_ERROR;
+ }
+
+ // OpenSSL will return an error if we try to write zero bytes
+ if (cb == 0)
+ return 0;
+
+ ssl_write_needs_read_ = false;
+
+ int code = SSL_write(ssl_, pv, cb);
+ switch (SSL_get_error(ssl_, code)) {
+ case SSL_ERROR_NONE:
+ //LOG(LS_INFO) << " -- success";
+ return code;
+ case SSL_ERROR_WANT_READ:
+ //LOG(LS_INFO) << " -- error want read";
+ ssl_write_needs_read_ = true;
+ SetError(EWOULDBLOCK);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ //LOG(LS_INFO) << " -- error want write";
+ SetError(EWOULDBLOCK);
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ //LOG(LS_INFO) << " -- remote side closed";
+ SetError(EWOULDBLOCK);
+ // do we need to signal closure?
+ break;
+ default:
+ //LOG(LS_INFO) << " -- error " << code;
+ Error("SSL_write", (code ? code : -1), false);
+ break;
+ }
+
+ return SOCKET_ERROR;
+}
+
+int
+OpenSSLAdapter::Recv(void* pv, size_t cb) {
+ //LOG(LS_INFO) << "OpenSSLAdapter::Recv(" << cb << ")";
+ switch (state_) {
+
+ case SSL_NONE:
+ return AsyncSocketAdapter::Recv(pv, cb);
+
+ case SSL_WAIT:
+ case SSL_CONNECTING:
+ SetError(EWOULDBLOCK);
+ return SOCKET_ERROR;
+
+ case SSL_CONNECTED:
+ break;
+
+ case SSL_ERROR:
+ default:
+ return SOCKET_ERROR;
+ }
+
+ // Don't trust OpenSSL with zero byte reads
+ if (cb == 0)
+ return 0;
+
+ ssl_read_needs_write_ = false;
+
+ int code = SSL_read(ssl_, pv, cb);
+ switch (SSL_get_error(ssl_, code)) {
+ case SSL_ERROR_NONE:
+ //LOG(LS_INFO) << " -- success";
+ return code;
+ case SSL_ERROR_WANT_READ:
+ //LOG(LS_INFO) << " -- error want read";
+ SetError(EWOULDBLOCK);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ //LOG(LS_INFO) << " -- error want write";
+ ssl_read_needs_write_ = true;
+ SetError(EWOULDBLOCK);
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ //LOG(LS_INFO) << " -- remote side closed";
+ SetError(EWOULDBLOCK);
+ // do we need to signal closure?
+ break;
+ default:
+ //LOG(LS_INFO) << " -- error " << code;
+ Error("SSL_read", (code ? code : -1), false);
+ break;
+ }
+
+ return SOCKET_ERROR;
+}
+
+int
+OpenSSLAdapter::Close() {
+ Cleanup();
+ state_ = restartable_ ? SSL_WAIT : SSL_NONE;
+ return AsyncSocketAdapter::Close();
+}
+
+Socket::ConnState
+OpenSSLAdapter::GetState() const {
+ //if (signal_close_)
+ // return CS_CONNECTED;
+ ConnState state = socket_->GetState();
+ if ((state == CS_CONNECTED)
+ && ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING)))
+ state = CS_CONNECTING;
+ return state;
+}
+
+void
+OpenSSLAdapter::OnConnectEvent(AsyncSocket* socket) {
+ LOG(LS_INFO) << "OpenSSLAdapter::OnConnectEvent";
+ if (state_ != SSL_WAIT) {
+ ASSERT(state_ == SSL_NONE);
+ AsyncSocketAdapter::OnConnectEvent(socket);
+ return;
+ }
+
+ state_ = SSL_CONNECTING;
+ if (int err = BeginSSL()) {
+ AsyncSocketAdapter::OnCloseEvent(socket, err);
+ }
+}
+
+void
+OpenSSLAdapter::OnReadEvent(AsyncSocket* socket) {
+ //LOG(LS_INFO) << "OpenSSLAdapter::OnReadEvent";
+
+ if (state_ == SSL_NONE) {
+ AsyncSocketAdapter::OnReadEvent(socket);
+ return;
+ }
+
+ if (state_ == SSL_CONNECTING) {
+ if (int err = ContinueSSL()) {
+ Error("ContinueSSL", err);
+ }
+ return;
+ }
+
+ if (state_ != SSL_CONNECTED)
+ return;
+
+ // Don't let ourselves go away during the callbacks
+ //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this
+ if (ssl_write_needs_read_) {
+ //LOG(LS_INFO) << " -- onStreamWriteable";
+ AsyncSocketAdapter::OnWriteEvent(socket);
+ }
+
+ //LOG(LS_INFO) << " -- onStreamReadable";
+ AsyncSocketAdapter::OnReadEvent(socket);
+}
+
+void
+OpenSSLAdapter::OnWriteEvent(AsyncSocket* socket) {
+ //LOG(LS_INFO) << "OpenSSLAdapter::OnWriteEvent";
+
+ if (state_ == SSL_NONE) {
+ AsyncSocketAdapter::OnWriteEvent(socket);
+ return;
+ }
+
+ if (state_ == SSL_CONNECTING) {
+ if (int err = ContinueSSL()) {
+ Error("ContinueSSL", err);
+ }
+ return;
+ }
+
+ if (state_ != SSL_CONNECTED)
+ return;
+
+ // Don't let ourselves go away during the callbacks
+ //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this
+
+ if (ssl_read_needs_write_) {
+ //LOG(LS_INFO) << " -- onStreamReadable";
+ AsyncSocketAdapter::OnReadEvent(socket);
+ }
+
+ //LOG(LS_INFO) << " -- onStreamWriteable";
+ AsyncSocketAdapter::OnWriteEvent(socket);
+}
+
+void
+OpenSSLAdapter::OnCloseEvent(AsyncSocket* socket, int err) {
+ LOG(LS_INFO) << "OpenSSLAdapter::OnCloseEvent(" << err << ")";
+ AsyncSocketAdapter::OnCloseEvent(socket, err);
+}
+
+// This code is taken from the "Network Security with OpenSSL"
+// sample in chapter 5
+bool
+OpenSSLAdapter::SSLPostConnectionCheck(SSL* ssl, const char* host) {
+ if (!host)
+ return false;
+
+ // Checking the return from SSL_get_peer_certificate here is not strictly
+ // necessary. With our setup, it is not possible for it to return
+ // NULL. However, it is good form to check the return.
+ X509* certificate = SSL_get_peer_certificate(ssl);
+ if (!certificate)
+ return false;
+
+#if !defined(NDEBUG)
+ {
+ LOG(LS_INFO) << "Certificate from server:";
+ BIO* mem = BIO_new(BIO_s_mem());
+ X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
+ BIO_write(mem, "\0", 1);
+ char* buffer;
+ BIO_get_mem_data(mem, &buffer);
+ LOG(LS_INFO) << buffer;
+ BIO_free(mem);
+
+ char* cipher_description =
+ SSL_CIPHER_description(SSL_get_current_cipher(ssl), NULL, 128);
+ LOG(LS_INFO) << "Cipher: " << cipher_description;
+ OPENSSL_free(cipher_description);
+ }
+#endif
+
+ bool ok = false;
+ int extension_count = X509_get_ext_count(certificate);
+ for (int i = 0; i < extension_count; ++i) {
+ X509_EXTENSION* extension = X509_get_ext(certificate, i);
+ int extension_nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
+
+ if (extension_nid == NID_subject_alt_name) {
+ X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
+ if (!meth)
+ break;
+
+ void* ext_str = NULL;
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+ const unsigned char **ext_value_data = (const_cast<const unsigned char **>
+ (&extension->value->data));
+#else
+ unsigned char **ext_value_data = &extension->value->data;
+#endif
+
+ if (meth->it) {
+ ext_str = ASN1_item_d2i(NULL, ext_value_data, extension->value->length,
+ ASN1_ITEM_ptr(meth->it));
+ } else {
+ ext_str = meth->d2i(NULL, ext_value_data, extension->value->length);
+ }
+
+ STACK_OF(CONF_VALUE)* value = meth->i2v(meth, ext_str, NULL);
+ for (int j = 0; j < sk_CONF_VALUE_num(value); ++j) {
+ CONF_VALUE* nval = sk_CONF_VALUE_value(value, j);
+ if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, host)) {
+ ok = true;
+ break;
+ }
+ }
+ }
+ if (ok)
+ break;
+ }
+
+ char data[256];
+ X509_name_st* subject;
+ if (!ok
+ && (subject = X509_get_subject_name(certificate))
+ && (X509_NAME_get_text_by_NID(subject, NID_commonName,
+ data, sizeof(data)) > 0)) {
+ data[sizeof(data)-1] = 0;
+ if (_stricmp(data, host) == 0)
+ ok = true;
+ }
+
+ X509_free(certificate);
+
+ if (!ok && ignore_bad_cert()) {
+ LOG(LS_WARNING) << "TLS certificate check FAILED. "
+ << "Allowing connection anyway.";
+ ok = true;
+ }
+
+ if (ok)
+ ok = (SSL_get_verify_result(ssl) == X509_V_OK);
+
+ if (!ok && ignore_bad_cert()) {
+ LOG(LS_INFO) << "Other TLS post connection checks failed.";
+ ok = true;
+ }
+
+ return ok;
+}
+
+#if !defined(NDEBUG)
+
+// We only use this for tracing and so it is only needed in debug mode
+
+void
+OpenSSLAdapter::SSLInfoCallback(const SSL* s, int where, int ret) {
+ const char* str = "undefined";
+ int w = where & ~SSL_ST_MASK;
+ if (w & SSL_ST_CONNECT) {
+ str = "SSL_connect";
+ } else if (w & SSL_ST_ACCEPT) {
+ str = "SSL_accept";
+ }
+ if (where & SSL_CB_LOOP) {
+ LOG(LS_INFO) << str << ":" << SSL_state_string_long(s);
+ } else if (where & SSL_CB_ALERT) {
+ str = (where & SSL_CB_READ) ? "read" : "write";
+ LOG(LS_INFO) << "SSL3 alert " << str
+ << ":" << SSL_alert_type_string_long(ret)
+ << ":" << SSL_alert_desc_string_long(ret);
+ } else if (where & SSL_CB_EXIT) {
+ if (ret == 0) {
+ LOG(LS_INFO) << str << ":failed in " << SSL_state_string_long(s);
+ } else if (ret < 0) {
+ LOG(LS_INFO) << str << ":error in " << SSL_state_string_long(s);
+ }
+ }
+}
+
+#endif // !defined(NDEBUG)
+
+int
+OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
+#if !defined(NDEBUG)
+ if (!ok) {
+ char data[256];
+ X509* cert = X509_STORE_CTX_get_current_cert(store);
+ int depth = X509_STORE_CTX_get_error_depth(store);
+ int err = X509_STORE_CTX_get_error(store);
+
+ LOG(LS_INFO) << "Error with certificate at depth: " << depth;
+ X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof(data));
+ LOG(LS_INFO) << " issuer = " << data;
+ X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof(data));
+ LOG(LS_INFO) << " subject = " << data;
+ LOG(LS_INFO) << " err = " << err
+ << ":" << X509_verify_cert_error_string(err);
+ }
+#endif
+
+ // Get our stream pointer from the store
+ SSL* ssl = reinterpret_cast<SSL*>(
+ X509_STORE_CTX_get_ex_data(store,
+ SSL_get_ex_data_X509_STORE_CTX_idx()));
+
+ OpenSSLAdapter* stream =
+ reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
+
+ if (!ok && stream->ignore_bad_cert()) {
+ LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
+ ok = 1;
+ }
+
+ return ok;
+}
+
+SSL_CTX*
+OpenSSLAdapter::SetupSSLContext() {
+ SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
+ if (ctx == NULL)
+ return NULL;
+
+ // Add the root cert to the SSL context
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+ const unsigned char* cert_buffer
+#else
+ unsigned char* cert_buffer
+#endif
+ = EquifaxSecureGlobalEBusinessCA1_certificate;
+ size_t cert_buffer_len = sizeof(EquifaxSecureGlobalEBusinessCA1_certificate);
+ X509* cert = d2i_X509(NULL, &cert_buffer, cert_buffer_len);
+ if (cert == NULL) {
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert)) {
+ X509_free(cert);
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+
+#if !defined(NDEBUG)
+ SSL_CTX_set_info_callback(ctx, SSLInfoCallback);
+#endif
+
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback);
+ SSL_CTX_set_verify_depth(ctx, 4);
+ SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+
+ return ctx;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/openssladapter.h b/third_party/libjingle/files/talk/base/openssladapter.h
new file mode 100644
index 0000000..33ffdeb
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/openssladapter.h
@@ -0,0 +1,94 @@
+/*
+ * 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 TALK_BASE_OPENSSLADAPTER_H__
+#define TALK_BASE_OPENSSLADAPTER_H__
+
+#include <string>
+#include "talk/base/ssladapter.h"
+
+typedef struct ssl_st SSL;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct x509_store_ctx_st X509_STORE_CTX;
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class OpenSSLAdapter : public SSLAdapter {
+public:
+ OpenSSLAdapter(AsyncSocket* socket);
+ virtual ~OpenSSLAdapter();
+
+ virtual int StartSSL(const char* hostname, bool restartable);
+ virtual int Send(const void* pv, size_t cb);
+ virtual int Recv(void* pv, size_t cb);
+ virtual int Close();
+
+ // Note that the socket returns ST_CONNECTING while SSL is being negotiated.
+ virtual ConnState GetState() const;
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket* socket);
+ virtual void OnReadEvent(AsyncSocket* socket);
+ virtual void OnWriteEvent(AsyncSocket* socket);
+ virtual void OnCloseEvent(AsyncSocket* socket, int err);
+
+private:
+ enum SSLState {
+ SSL_NONE, SSL_WAIT, SSL_CONNECTING, SSL_CONNECTED, SSL_ERROR
+ };
+
+ int BeginSSL();
+ int ContinueSSL();
+ void Error(const char* context, int err, bool signal = true);
+ void Cleanup();
+
+ bool SSLPostConnectionCheck(SSL* ssl, const char* host);
+#if !defined(NDEBUG)
+ static void SSLInfoCallback(const SSL* s, int where, int ret);
+#endif // !defined(NDEBUG)
+ static int SSLVerifyCallback(int ok, X509_STORE_CTX* store);
+
+ static SSL_CTX* SetupSSLContext();
+
+ SSLState state_;
+ bool ssl_read_needs_write_;
+ bool ssl_write_needs_read_;
+ // If true, socket will retain SSL configuration after Close.
+ bool restartable_;
+
+ SSL* ssl_;
+ SSL_CTX* ssl_ctx_;
+ std::string ssl_host_name_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_OPENSSLADAPTER_H__
diff --git a/third_party/libjingle/files/talk/base/pathutils.cc b/third_party/libjingle/files/talk/base/pathutils.cc
new file mode 100644
index 0000000..4a77879
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/pathutils.cc
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ */
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#endif // WIN32
+
+#include "talk/base/common.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/urlencode.h"
+
+namespace talk_base {
+
+std::string const EMPTY_STR = "";
+
+// EXT_DELIM separates a file basename from extension
+const char EXT_DELIM = '.';
+
+// FOLDER_DELIMS separate folder segments and the filename
+const char* const FOLDER_DELIMS = "/\\";
+
+// DEFAULT_FOLDER_DELIM is the preferred delimiter for this platform
+#if WIN32
+const char DEFAULT_FOLDER_DELIM = '\\';
+#else // !WIN32
+const char DEFAULT_FOLDER_DELIM = '/';
+#endif // !WIN32
+
+///////////////////////////////////////////////////////////////////////////////
+// Pathname - parsing of pathnames into components, and vice versa
+///////////////////////////////////////////////////////////////////////////////
+
+bool Pathname::IsFolderDelimiter(char ch) {
+ return (NULL != ::strchr(FOLDER_DELIMS, ch));
+}
+
+Pathname::Pathname()
+ : folder_delimiter_(DEFAULT_FOLDER_DELIM) {
+}
+
+Pathname::Pathname(const std::string& pathname)
+ : folder_delimiter_(DEFAULT_FOLDER_DELIM) {
+ SetPathname(pathname);
+}
+
+void Pathname::SetFolderDelimiter(char delimiter) {
+ ASSERT(IsFolderDelimiter(delimiter));
+ folder_delimiter_ = delimiter;
+}
+
+void Pathname::Normalize() {
+ for (size_t i=0; i<folder_.length(); ++i) {
+ if (IsFolderDelimiter(folder_[i])) {
+ folder_[i] = folder_delimiter_;
+ }
+ }
+}
+
+void Pathname::clear() {
+ folder_.clear();
+ basename_.clear();
+ extension_.clear();
+}
+
+std::string Pathname::pathname() const {
+ std::string pathname(folder_);
+ pathname.append(basename_);
+ pathname.append(extension_);
+ return pathname;
+}
+
+std::string Pathname::url() const {
+ std::string s = "file://";
+ for (size_t i=0; i<folder_.length(); ++i) {
+ if (i == 1 && folder_[i] == ':') // drive letter
+ s += '|';
+ else if (IsFolderDelimiter(folder_[i]))
+ s += '/';
+ else
+ s += folder_[i];
+ }
+ s += basename_;
+ s += extension_;
+ return UrlEncodeString(s);
+}
+
+void Pathname::SetPathname(const std::string &pathname) {
+ std::string::size_type pos = pathname.find_last_of(FOLDER_DELIMS);
+ if (pos != std::string::npos) {
+ SetFolder(pathname.substr(0, pos + 1));
+ SetFilename(pathname.substr(pos + 1));
+ } else {
+ SetFolder(EMPTY_STR);
+ SetFilename(pathname);
+ }
+}
+
+void Pathname::AppendPathname(const Pathname& pathname) {
+ std::string full_pathname(folder_);
+ full_pathname.append(pathname.pathname());
+ SetPathname(full_pathname);
+}
+
+std::string Pathname::folder() const {
+ return folder_;
+}
+
+std::string Pathname::folder_name() const {
+ std::string::size_type pos = std::string::npos;
+ if (folder_.size() >= 2) {
+ pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2);
+ }
+ if (pos != std::string::npos) {
+ return folder_.substr(pos + 1);
+ } else {
+ return folder_;
+ }
+}
+
+std::string Pathname::parent_folder() const {
+ std::string::size_type pos = std::string::npos;
+ if (folder_.size() >= 2) {
+ pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2);
+ }
+ if (pos != std::string::npos) {
+ return folder_.substr(0, pos + 1);
+ } else {
+ return EMPTY_STR;
+ }
+}
+
+void Pathname::SetFolder(const std::string& folder) {
+ folder_.assign(folder);
+ // Ensure folder ends in a path delimiter
+ if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) {
+ folder_.push_back(folder_delimiter_);
+ }
+}
+
+void Pathname::AppendFolder(const std::string& folder) {
+ folder_.append(folder);
+ // Ensure folder ends in a path delimiter
+ if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) {
+ folder_.push_back(folder_delimiter_);
+ }
+}
+
+std::string Pathname::basename() const {
+ return basename_;
+}
+
+void Pathname::SetBasename(const std::string& basename) {
+ ASSERT(basename.find_first_of(FOLDER_DELIMS) == std::string::npos);
+ basename_.assign(basename);
+}
+
+std::string Pathname::extension() const {
+ return extension_;
+}
+
+void Pathname::SetExtension(const std::string& extension) {
+ ASSERT(extension.find_first_of(FOLDER_DELIMS) == std::string::npos);
+ ASSERT(extension.find_first_of(EXT_DELIM, 1) == std::string::npos);
+ extension_.assign(extension);
+ // Ensure extension begins with the extension delimiter
+ if (!extension_.empty() && (extension_[0] != EXT_DELIM)) {
+ extension_.insert(extension_.begin(), EXT_DELIM);
+ }
+}
+
+std::string Pathname::filename() const {
+ std::string filename(basename_);
+ filename.append(extension_);
+ return filename;
+}
+
+void Pathname::SetFilename(const std::string& filename) {
+ std::string::size_type pos = filename.rfind(EXT_DELIM);
+ if ((pos == std::string::npos) || (pos == 0)) {
+ SetBasename(filename);
+ SetExtension(EMPTY_STR);
+ } else {
+ SetBasename(filename.substr(0, pos));
+ SetExtension(filename.substr(pos));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CreateUniqueFile
+///////////////////////////////////////////////////////////////////////////////
+
+std::string g_organization_name;
+std::string g_application_name;
+
+void SetOrganizationName(const std::string& organization) {
+ g_organization_name = organization;
+}
+
+void SetApplicationName(const std::string& application) {
+ g_application_name = application;
+}
+
+bool CreateFolder(const talk_base::Pathname& path) {
+#ifdef WIN32
+ if (!path.filename().empty())
+ return false;
+
+ std::wstring pathname16 = ToUtf16(path.pathname());
+ if (!pathname16.empty() && (pathname16[0] != '\\')) {
+ pathname16 = L"\\\\?\\" + pathname16;
+ }
+
+ DWORD res = ::GetFileAttributes(pathname16.c_str());
+ if (res != INVALID_FILE_ATTRIBUTES) {
+ // Something exists at this location, check if it is a directory
+ return ((res & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ } else if ((GetLastError() != ERROR_FILE_NOT_FOUND)
+ && (GetLastError() != ERROR_PATH_NOT_FOUND)) {
+ // Unexpected error
+ return false;
+ }
+
+ // Directory doesn't exist, look up one directory level
+ if (!path.parent_folder().empty()) {
+ talk_base::Pathname parent(path);
+ parent.SetFolder(path.parent_folder());
+ if (!CreateFolder(parent)) {
+ return false;
+ }
+ }
+
+ return (::CreateDirectory(pathname16.c_str(), NULL) != 0);
+#else // !WIN32
+ return false;
+#endif // !WIN32
+}
+
+bool FinishPath(talk_base::Pathname& path, bool create,
+ const std::string& append) {
+ if (!append.empty()) {
+ path.AppendFolder(append);
+ }
+ if (create && !CreateFolder(path))
+ return false;
+ return true;
+}
+
+bool GetTemporaryFolder(talk_base::Pathname& path, bool create,
+ const std::string& append) {
+ ASSERT(!g_application_name.empty());
+#ifdef WIN32
+ TCHAR buffer[MAX_PATH + 1];
+ if (!::GetTempPath(ARRAY_SIZE(buffer), buffer))
+ return false;
+ if (!::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
+ return false;
+ size_t len = strlen(buffer);
+ if ((len > 0) && (buffer[len-1] != __T('\\'))) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ __T("\\"));
+ }
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ ToUtf16(g_application_name).c_str());
+ if ((len > 0) && (buffer[len-1] != __T('\\'))) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ __T("\\"));
+ }
+ if (len >= ARRAY_SIZE(buffer) - 1)
+ return false;
+ path.clear();
+ path.SetFolder(ToUtf8(buffer));
+ return FinishPath(path, create, append);
+#else // !WIN32
+ return false;
+#endif // !WIN32
+}
+
+bool GetAppDataFolder(talk_base::Pathname& path, bool create,
+ const std::string& append) {
+ ASSERT(!g_organization_name.empty());
+ ASSERT(!g_application_name.empty());
+#ifdef WIN32
+ TCHAR buffer[MAX_PATH + 1];
+ if (!::SHGetSpecialFolderPath(NULL, buffer, CSIDL_LOCAL_APPDATA, TRUE))
+ return false;
+ if (!::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
+ return false;
+ size_t len = talk_base::strcatn(buffer, ARRAY_SIZE(buffer), _T("\\"));
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ ToUtf16(g_organization_name).c_str());
+ if ((len > 0) && (buffer[len-1] != __T('\\'))) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ __T("\\"));
+ }
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ ToUtf16(g_application_name).c_str());
+ if ((len > 0) && (buffer[len-1] != __T('\\'))) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ __T("\\"));
+ }
+ if (len >= ARRAY_SIZE(buffer) - 1)
+ return false;
+ path.clear();
+ path.SetFolder(ToUtf8(buffer));
+ return FinishPath(path, create, append);
+#else // !WIN32
+ return false;
+#endif // !WIN32
+}
+
+bool CleanupTemporaryFolder() {
+#ifdef WIN32
+ talk_base::Pathname temp_path;
+ if (!GetTemporaryFolder(temp_path, false, ""))
+ return false;
+
+ std::wstring temp_path16 = ToUtf16(temp_path.pathname());
+ temp_path16.append(1, '*');
+ temp_path16.append(1, '\0');
+
+ SHFILEOPSTRUCT file_op = { 0 };
+ file_op.wFunc = FO_DELETE;
+ file_op.pFrom = temp_path16.c_str();
+ file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
+ return (0 == SHFileOperation(&file_op));
+#else // !WIN32
+ return false;
+#endif // !WIN32
+}
+#if 0
+bool CreateUnijqueFile(talk_base::Pathname& path, bool create_empty) {
+#ifdef WIN32
+ // If not folder is supplied, use the temporary folder
+ if (path.folder().empty()) {
+ talk_base::Pathname temp_path;
+ if (!GetTemporaryFolder(temp_path, true, "")) {
+
+ return false;
+ }
+ path.SetFolder(temp_path.folder());
+ }
+ printf("path: %s\n", path.pathname());
+ // If not filename is supplied, use a temporary name
+ if (path.filename().empty()) {
+ TCHAR filename[MAX_PATH];
+ std::wstring folder((ToUtf16)(path.folder()));
+ if (!::GetTempFileName(folder.c_str(), __T("gt"), 0, filename))
+ return false;
+ ASSERT(wcsncmp(folder.c_str(), filename, folder.length()) == 0);
+ path.SetFilename(ToUtf8(filename + folder.length()));
+ if (!create_empty) {
+ VERIFY(::DeleteFile(ToUtf16(path.pathname()).c_str()) != FALSE);
+ }
+ return true;
+ }
+ // Otherwise, create a unique name based on the given filename
+ // foo.txt -> foo-N.txt
+ const std::string basename = path.basename();
+ const size_t MAX_VERSION = 100;
+ size_t version = 0;
+ while (version < MAX_VERSION) {
+ std::string pathname = path.pathname();
+ std::wstring pathname16 = ToUtf16(pathname).c_str();
+
+ if (pathname16[0] != __T('\\'))
+ pathname16 = __T("\\\\?\\") + pathname16;
+
+ HANDLE hfile = CreateFile(pathname16.c_str(), GENERIC_WRITE, 0,
+ NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hfile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hfile);
+ if (!create_empty) {
+ VERIFY(::DeleteFile(pathname16.c_str()) != FALSE);
+ }
+ return true;
+ } else {
+ int err = GetLastError();
+ if (err != ERROR_FILE_EXISTS && err != ERROR_ACCESS_DENIED) {
+ return false;
+ }
+ }
+
+ version += 1;
+ char version_base[MAX_PATH];
+ talk_base::sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u",
+ basename.c_str(), version);
+ path.SetBasename(version_base);
+ }
+ return false;
+#else // !WIN32
+ // TODO: Make this better.
+ path.SetBasename("/tmp/temp-1");
+#endif // !WIN32
+}
+#endif
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/pathutils.h b/third_party/libjingle/files/talk/base/pathutils.h
new file mode 100644
index 0000000..eb33edf
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/pathutils.h
@@ -0,0 +1,110 @@
+/*
+ * 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 TALK_BASE_PATHUTILS_H__
+#define TALK_BASE_PATHUTILS_H__
+
+#include <string>
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// Pathname - parsing of pathnames into components, and vice versa.
+//
+// To establish consistent terminology, a filename never contains a folder
+// component. A folder never contains a filename. A pathname may include
+// a folder and/or filename component. Here are some examples:
+//
+// pathname() /home/john/example.txt
+// folder() /home/john/
+// filename() example.txt
+// parent_folder() /home/
+// folder_name() john/
+// basename() example
+// extension() .txt
+//
+// Basename may begin, end, and/or include periods, but no folder delimiters.
+// If extension exists, it consists of a period followed by zero or more
+// non-period/non-delimiter characters, and basename is non-empty.
+///////////////////////////////////////////////////////////////////////////////
+
+class Pathname {
+public:
+ // Folder delimiters are slash and backslash
+ static bool IsFolderDelimiter(char ch);
+
+ Pathname();
+ Pathname(const std::string& pathname);
+
+ // Set's the default folder delimiter for this Pathname
+ char folder_delimiter() const { return folder_delimiter_; }
+ void SetFolderDelimiter(char delimiter);
+
+ // Normalize changes all folder delimiters to folder_delimiter()
+ void Normalize();
+
+ // Reset to the empty pathname
+ void clear();
+
+ std::string url() const;
+
+ std::string pathname() const;
+ void SetPathname(const std::string& pathname);
+
+ // Append pathname to the current folder (if any). Any existing filename
+ // will be discarded.
+ void AppendPathname(const Pathname& pathname);
+
+ std::string folder() const;
+ std::string folder_name() const;
+ std::string parent_folder() const;
+ // SetFolder and AppendFolder will append a folder delimiter, if needed.
+ void SetFolder(const std::string& folder);
+ void AppendFolder(const std::string& folder);
+
+ std::string basename() const;
+ void SetBasename(const std::string& basename);
+
+ std::string extension() const;
+ // SetExtension will prefix a period, if needed.
+ void SetExtension(const std::string& extension);
+
+ std::string filename() const;
+ void SetFilename(const std::string& filename);
+
+private:
+
+ std::string folder_, basename_, extension_;
+ char folder_delimiter_;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_PATHUTILS_H__
diff --git a/third_party/libjingle/files/talk/base/physicalsocketserver.cc b/third_party/libjingle/files/talk/base/physicalsocketserver.cc
new file mode 100644
index 0000000..fe7da7a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/physicalsocketserver.cc
@@ -0,0 +1,1147 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+
+#ifdef POSIX
+extern "C" {
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <unistd.h>
+}
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#undef SetPort
+#endif
+
+#include <algorithm>
+#include <iostream>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/time.h"
+#include "talk/base/winping.h"
+#include "talk/base/winsock_initializer.h"
+
+#ifdef __linux
+#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h
+#endif // __linux
+
+namespace talk_base {
+
+const int kfRead = 0x0001;
+const int kfWrite = 0x0002;
+const int kfConnect = 0x0004;
+const int kfClose = 0x0008;
+
+// Standard MTUs
+const uint16 PACKET_MAXIMUMS[] = {
+ 65535, // Theoretical maximum, Hyperchannel
+ 32000, // Nothing
+ 17914, // 16Mb IBM Token Ring
+ 8166, // IEEE 802.4
+ //4464, // IEEE 802.5 (4Mb max)
+ 4352, // FDDI
+ //2048, // Wideband Network
+ 2002, // IEEE 802.5 (4Mb recommended)
+ //1536, // Expermental Ethernet Networks
+ //1500, // Ethernet, Point-to-Point (default)
+ 1492, // IEEE 802.3
+ 1006, // SLIP, ARPANET
+ //576, // X.25 Networks
+ //544, // DEC IP Portal
+ //512, // NETBIOS
+ 508, // IEEE 802/Source-Rt Bridge, ARCNET
+ 296, // Point-to-Point (low delay)
+ 68, // Official minimum
+ 0, // End of list marker
+};
+
+const uint32 IP_HEADER_SIZE = 20;
+const uint32 ICMP_HEADER_SIZE = 8;
+
+class PhysicalSocket : public AsyncSocket {
+public:
+ PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET)
+ : ss_(ss), s_(s), enabled_events_(0), error_(0),
+ state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED) {
+#ifdef WIN32
+ EnsureWinsockInit();
+#endif
+ if (s != INVALID_SOCKET)
+ enabled_events_ = kfRead | kfWrite;
+ }
+
+ virtual ~PhysicalSocket() {
+ Close();
+ }
+
+ // Creates the underlying OS socket (same as the "socket" function).
+ virtual bool Create(int type) {
+ Close();
+ s_ = ::socket(AF_INET, type, 0);
+ UpdateLastError();
+ if (type != SOCK_STREAM)
+ enabled_events_ = kfRead | kfWrite;
+ return s_ != INVALID_SOCKET;
+ }
+
+ SocketAddress GetLocalAddress() const {
+ sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ int result = ::getsockname(s_, (sockaddr*)&addr, &addrlen);
+ ASSERT(addrlen == sizeof(addr));
+ talk_base::SocketAddress address;
+ if (result >= 0) {
+ address.FromSockAddr(addr);
+ } else {
+ ASSERT(result >= 0);
+ }
+ return address;
+ }
+
+ SocketAddress GetRemoteAddress() const {
+ sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ int result = ::getpeername(s_, (sockaddr*)&addr, &addrlen);
+ ASSERT(addrlen == sizeof(addr));
+ talk_base::SocketAddress address;
+ if (result >= 0) {
+ address.FromSockAddr(addr);
+ } else {
+ ASSERT(errno == ENOTCONN);
+ }
+ return address;
+ }
+
+ int Bind(const SocketAddress& addr) {
+ sockaddr_in saddr;
+ addr.ToSockAddr(&saddr);
+ int err = ::bind(s_, (sockaddr*)&saddr, sizeof(saddr));
+ UpdateLastError();
+ return err;
+ }
+
+ int Connect(const SocketAddress& addr) {
+ // TODO: Implicit creation is required to reconnect...
+ // ...but should we make it more explicit?
+ if ((s_ == INVALID_SOCKET) && !Create(SOCK_STREAM))
+ return SOCKET_ERROR;
+ SocketAddress addr2(addr);
+ if (addr2.IsUnresolved()) {
+ LOG(INFO) << "Resolving addr in PhysicalSocket::Connect";
+ // TODO: Do this async later?
+ if (!addr2.Resolve()) {
+ LOG(LS_ERROR) << "Resolving addr failed";
+ UpdateLastError();
+ Close();
+ return SOCKET_ERROR;
+ }
+ }
+ sockaddr_in saddr;
+ addr2.ToSockAddr(&saddr);
+ int err = ::connect(s_, (sockaddr*)&saddr, sizeof(saddr));
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_;
+ if (err == 0) {
+ state_ = CS_CONNECTED;
+ } else if (IsBlockingError(error_)) {
+ state_ = CS_CONNECTING;
+ enabled_events_ |= kfConnect;
+ }
+ enabled_events_ |= kfRead | kfWrite;
+ return err;
+ }
+
+ int GetError() const {
+ return error_;
+ }
+
+ void SetError(int error) {
+ error_ = error;
+ }
+
+ ConnState GetState() const {
+ return state_;
+ }
+
+ int SetOption(Option opt, int value) {
+ assert(opt == OPT_DONTFRAGMENT);
+#ifdef WIN32
+ value = (value == 0) ? 0 : 1;
+ return ::setsockopt(
+ s_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast<char*>(&value),
+ sizeof(value));
+#endif
+#ifdef __linux
+ value = (value == 0) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO;
+ return ::setsockopt(
+ s_, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value));
+#endif
+#ifdef OSX
+ // This is not possible on OSX.
+ return -1;
+#endif
+ }
+
+ int Send(const void *pv, size_t cb) {
+ int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, 0);
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_;
+ ASSERT(sent <= static_cast<int>(cb)); // We have seen minidumps where this may be false
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= kfWrite;
+ }
+ return sent;
+ }
+
+ int SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ sockaddr_in saddr;
+ addr.ToSockAddr(&saddr);
+ int sent = ::sendto(
+ s_, (const char *)pv, (int)cb, 0, (sockaddr*)&saddr,
+ sizeof(saddr));
+ UpdateLastError();
+ ASSERT(sent <= static_cast<int>(cb)); // We have seen minidumps where this may be false
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= kfWrite;
+ }
+ return sent;
+ }
+
+ int Recv(void *pv, size_t cb) {
+ int received = ::recv(s_, (char *)pv, (int)cb, 0);
+ if ((received == 0) && (cb != 0)) {
+ // Note: on graceful shutdown, recv can return 0. In this case, we
+ // pretend it is blocking, and then signal close, so that simplifying
+ // assumptions can be made about Recv.
+ LOG(LS_WARNING) << "EOF from socket; deferring close event";
+ // Must turn this back on so that the select() loop will notice the close
+ // event.
+ enabled_events_ |= kfRead;
+ error_ = EWOULDBLOCK;
+ return SOCKET_ERROR;
+ }
+ UpdateLastError();
+ if ((received >= 0) || IsBlockingError(error_)) {
+ enabled_events_ |= kfRead;
+ }
+ return received;
+ }
+
+ int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ sockaddr_in saddr;
+ socklen_t cbAddr = sizeof(saddr);
+ int received = ::recvfrom(s_, (char *)pv, (int)cb, 0, (sockaddr*)&saddr,
+ &cbAddr);
+ UpdateLastError();
+ if ((received >= 0) && (paddr != NULL))
+ paddr->FromSockAddr(saddr);
+ if ((received >= 0) || IsBlockingError(error_)) {
+ enabled_events_ |= kfRead;
+ }
+ return received;
+ }
+
+ int Listen(int backlog) {
+ int err = ::listen(s_, backlog);
+ UpdateLastError();
+ if (err == 0)
+ state_ = CS_CONNECTING;
+ enabled_events_ |= kfRead;
+
+ return err;
+ }
+
+ Socket* Accept(SocketAddress *paddr) {
+ sockaddr_in saddr;
+ socklen_t cbAddr = sizeof(saddr);
+ SOCKET s = ::accept(s_, (sockaddr*)&saddr, &cbAddr);
+ UpdateLastError();
+ if (s == INVALID_SOCKET)
+ return NULL;
+ if (paddr != NULL)
+ paddr->FromSockAddr(saddr);
+ enabled_events_ |= kfRead | kfWrite;
+ return ss_->WrapSocket(s);
+ }
+
+ int Close() {
+ if (s_ == INVALID_SOCKET)
+ return 0;
+ int err = ::closesocket(s_);
+ UpdateLastError();
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Close() Ret: " << err << " Error: " << error_;
+ s_ = INVALID_SOCKET;
+ state_ = CS_CLOSED;
+ enabled_events_ = 0;
+ return err;
+ }
+
+ int EstimateMTU(uint16* mtu) {
+ SocketAddress addr = GetRemoteAddress();
+ if (addr.IsAny()) {
+ error_ = ENOTCONN;
+ return -1;
+ }
+
+#ifdef WIN32
+
+ WinPing ping;
+ if (!ping.IsValid()) {
+ error_ = EINVAL; // can't think of a better error ID
+ return -1;
+ }
+
+ for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) {
+ int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
+ WinPing::PingResult result = ping.Ping(addr.ip(), size, 0, 1, false);
+ if (result == WinPing::PING_FAIL) {
+ error_ = EINVAL; // can't think of a better error ID
+ return -1;
+ }
+ if (result != WinPing::PING_TOO_LARGE) {
+ *mtu = PACKET_MAXIMUMS[level];
+ return 0;
+ }
+ }
+
+ assert(false);
+ return 0;
+
+#endif // WIN32
+
+#ifdef __linux
+
+ int value;
+ socklen_t vlen = sizeof(value);
+ int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen);
+ if (err < 0) {
+ UpdateLastError();
+ return err;
+ }
+
+ assert((0 <= value) && (value <= 65536));
+ *mtu = uint16(value);
+ return 0;
+
+#endif // __linux
+
+ // TODO: OSX support
+ }
+
+ SocketServer* socketserver() { return ss_; }
+
+protected:
+ PhysicalSocketServer* ss_;
+ SOCKET s_;
+ uint32 enabled_events_;
+ int error_;
+ ConnState state_;
+
+ void UpdateLastError() {
+#ifdef WIN32
+ error_ = WSAGetLastError();
+#endif
+#ifdef POSIX
+ error_ = errno;
+#endif
+ }
+};
+
+#ifdef POSIX
+class Dispatcher {
+public:
+ virtual uint32 GetRequestedEvents() = 0;
+ virtual void OnPreEvent(uint32 ff) = 0;
+ virtual void OnEvent(uint32 ff, int err) = 0;
+ virtual int GetDescriptor() = 0;
+ virtual bool IsDescriptorClosed() = 0;
+};
+
+class EventDispatcher : public Dispatcher {
+public:
+ EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
+ if (pipe(afd_) < 0)
+ LOG(LERROR) << "pipe failed";
+ ss_->Add(this);
+ }
+
+ virtual ~EventDispatcher() {
+ ss_->Remove(this);
+ close(afd_[0]);
+ close(afd_[1]);
+ }
+
+ virtual void Signal() {
+ CritScope cs(&crit_);
+ if (!fSignaled_) {
+ uint8 b = 0;
+ if (write(afd_[1], &b, sizeof(b)) < 0)
+ LOG(LERROR) << "write failed";
+ fSignaled_ = true;
+ }
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return kfRead;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ // It is not possible to perfectly emulate an auto-resetting event with
+ // pipes. This simulates it by resetting before the event is handled.
+
+ CritScope cs(&crit_);
+ if (fSignaled_) {
+ uint8 b;
+ read(afd_[0], &b, sizeof(b));
+ fSignaled_ = false;
+ }
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ assert(false);
+ }
+
+ virtual int GetDescriptor() {
+ return afd_[0];
+ }
+
+ virtual bool IsDescriptorClosed() {
+ return false;
+ }
+
+private:
+ PhysicalSocketServer *ss_;
+ int afd_[2];
+ bool fSignaled_;
+ CriticalSection crit_;
+};
+
+class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+public:
+ SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
+ ss_->Add(this);
+ }
+ SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) {
+ ss_->Add(this);
+ }
+
+ virtual ~SocketDispatcher() {
+ Close();
+ }
+
+ bool Initialize() {
+ ss_->Add(this);
+ fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK);
+ return true;
+ }
+
+ virtual bool Create(int type) {
+ // Change the socket to be non-blocking.
+ if (!PhysicalSocket::Create(type))
+ return false;
+
+ return Initialize();
+ }
+
+ virtual int GetDescriptor() {
+ return s_;
+ }
+
+ virtual bool IsDescriptorClosed() {
+ // We don't have a reliable way of distinguishing end-of-stream
+ // from readability. So test on each readable call. Is this
+ // inefficient? Probably.
+ char ch;
+ return (0 == ::recv(s_, &ch, 1, MSG_PEEK));
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return enabled_events_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ if ((ff & kfConnect) != 0)
+ state_ = CS_CONNECTED;
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ if ((ff & kfRead) != 0) {
+ enabled_events_ &= ~kfRead;
+ SignalReadEvent(this);
+ }
+ if ((ff & kfWrite) != 0) {
+ enabled_events_ &= ~kfWrite;
+ SignalWriteEvent(this);
+ }
+ if ((ff & kfConnect) != 0) {
+ enabled_events_ &= ~kfConnect;
+ SignalConnectEvent(this);
+ }
+ if ((ff & kfClose) != 0)
+ SignalCloseEvent(this, err);
+ }
+
+ virtual int Close() {
+ if (s_ == INVALID_SOCKET)
+ return 0;
+
+ ss_->Remove(this);
+ return PhysicalSocket::Close();
+ }
+
+};
+
+class FileDispatcher: public Dispatcher, public AsyncFile {
+public:
+ FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) {
+ set_readable(true);
+
+ ss_->Add(this);
+
+ fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK);
+ }
+
+ virtual ~FileDispatcher() {
+ ss_->Remove(this);
+ }
+
+ SocketServer* socketserver() { return ss_; }
+
+ virtual int GetDescriptor() {
+ return fd_;
+ }
+
+ virtual bool IsDescriptorClosed() {
+ return false;
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return flags_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ if ((ff & kfRead) != 0)
+ SignalReadEvent(this);
+ if ((ff & kfWrite) != 0)
+ SignalWriteEvent(this);
+ if ((ff & kfClose) != 0)
+ SignalCloseEvent(this, err);
+ }
+
+ virtual bool readable() {
+ return (flags_ & kfRead) != 0;
+ }
+
+ virtual void set_readable(bool value) {
+ flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead);
+ }
+
+ virtual bool writable() {
+ return (flags_ & kfWrite) != 0;
+ }
+
+ virtual void set_writable(bool value) {
+ flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite);
+ }
+
+private:
+ PhysicalSocketServer* ss_;
+ int fd_;
+ int flags_;
+};
+
+AsyncFile* PhysicalSocketServer::CreateFile(int fd) {
+ return new FileDispatcher(fd, this);
+}
+
+#endif // POSIX
+
+#ifdef WIN32
+class Dispatcher {
+public:
+ virtual uint32 GetRequestedEvents() = 0;
+ virtual void OnPreEvent(uint32 ff) = 0;
+ virtual void OnEvent(uint32 ff, int err) = 0;
+ virtual WSAEVENT GetWSAEvent() = 0;
+ virtual SOCKET GetSocket() = 0;
+ virtual bool CheckSignalClose() = 0;
+};
+
+uint32 FlagsToEvents(uint32 events) {
+ uint32 ffFD = FD_CLOSE | FD_ACCEPT;
+ if (events & kfRead)
+ ffFD |= FD_READ;
+ if (events & kfWrite)
+ ffFD |= FD_WRITE;
+ if (events & kfConnect)
+ ffFD |= FD_CONNECT;
+ return ffFD;
+}
+
+class EventDispatcher : public Dispatcher {
+public:
+ EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) {
+ if (hev_ = WSACreateEvent()) {
+ ss_->Add(this);
+ }
+ }
+
+ ~EventDispatcher() {
+ if (hev_ != NULL) {
+ ss_->Remove(this);
+ WSACloseEvent(hev_);
+ hev_ = NULL;
+ }
+ }
+
+ virtual void Signal() {
+ if (hev_ != NULL)
+ WSASetEvent(hev_);
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return 0;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ WSAResetEvent(hev_);
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ }
+
+ virtual WSAEVENT GetWSAEvent() {
+ return hev_;
+ }
+
+ virtual SOCKET GetSocket() {
+ return INVALID_SOCKET;
+ }
+
+ virtual bool CheckSignalClose() { return false; }
+
+private:
+ PhysicalSocketServer* ss_;
+ WSAEVENT hev_;
+};
+
+class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+public:
+ static int next_id_;
+ int id_;
+ bool signal_close_;
+ int signal_err_;
+
+ SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) {
+ }
+ SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) {
+ }
+
+ virtual ~SocketDispatcher() {
+ Close();
+ }
+
+ bool Initialize() {
+ assert(s_ != INVALID_SOCKET);
+ // Must be a non-blocking
+ u_long argp = 1;
+ ioctlsocket(s_, FIONBIO, &argp);
+ ss_->Add(this);
+ return true;
+ }
+
+ virtual bool Create(int type) {
+ // Create socket
+ if (!PhysicalSocket::Create(type))
+ return false;
+
+ if (!Initialize())
+ return false;
+
+ do { id_ = ++next_id_; } while (id_ == 0);
+ return true;
+ }
+
+ virtual int Close() {
+ if (s_ == INVALID_SOCKET)
+ return 0;
+
+ id_ = 0;
+ signal_close_ = false;
+ ss_->Remove(this);
+ return PhysicalSocket::Close();
+ }
+
+ virtual uint32 GetRequestedEvents() {
+ return enabled_events_;
+ }
+
+ virtual void OnPreEvent(uint32 ff) {
+ if ((ff & kfConnect) != 0)
+ state_ = CS_CONNECTED;
+ }
+
+ virtual void OnEvent(uint32 ff, int err) {
+ int cache_id = id_;
+ if ((ff & kfRead) != 0) {
+ enabled_events_ &= ~kfRead;
+ SignalReadEvent(this);
+ }
+ if (((ff & kfWrite) != 0) && (id_ == cache_id)) {
+ enabled_events_ &= ~kfWrite;
+ SignalWriteEvent(this);
+ }
+ if (((ff & kfConnect) != 0) && (id_ == cache_id)) {
+ if (ff != kfConnect)
+ LOG(LS_VERBOSE) << "Signalled with kfConnect: " << ff;
+ enabled_events_ &= ~kfConnect;
+ SignalConnectEvent(this);
+ }
+ if (((ff & kfClose) != 0) && (id_ == cache_id)) {
+ //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] OnClose() Error: " << err;
+ signal_close_ = true;
+ signal_err_ = err;
+ }
+ }
+
+ virtual WSAEVENT GetWSAEvent() {
+ return WSA_INVALID_EVENT;
+ }
+
+ virtual SOCKET GetSocket() {
+ return s_;
+ }
+
+ virtual bool CheckSignalClose() {
+ if (!signal_close_)
+ return false;
+
+ char ch;
+ if (recv(s_, &ch, 1, MSG_PEEK) > 0)
+ return false;
+
+ signal_close_ = false;
+ SignalCloseEvent(this, signal_err_);
+ return true;
+ }
+};
+
+int SocketDispatcher::next_id_ = 0;
+
+#endif // WIN32
+
+// Sets the value of a boolean value to false when signaled.
+class Signaler : public EventDispatcher {
+public:
+ Signaler(PhysicalSocketServer* ss, bool* pf)
+ : EventDispatcher(ss), pf_(pf) {
+ }
+ virtual ~Signaler() { }
+
+ void OnEvent(uint32 ff, int err) {
+ if (pf_)
+ *pf_ = false;
+ }
+
+private:
+ bool *pf_;
+};
+
+PhysicalSocketServer::PhysicalSocketServer() : fWait_(false),
+ last_tick_tracked_(0), last_tick_dispatch_count_(0) {
+ signal_wakeup_ = new Signaler(this, &fWait_);
+}
+
+PhysicalSocketServer::~PhysicalSocketServer() {
+ delete signal_wakeup_;
+ // ASSERT(dispatchers_.empty());
+}
+
+void PhysicalSocketServer::WakeUp() {
+ signal_wakeup_->Signal();
+}
+
+Socket* PhysicalSocketServer::CreateSocket(int type) {
+ PhysicalSocket* socket = new PhysicalSocket(this);
+ if (socket->Create(type)) {
+ return socket;
+ } else {
+ delete socket;
+ return 0;
+ }
+}
+
+AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) {
+ SocketDispatcher* dispatcher = new SocketDispatcher(this);
+ if (dispatcher->Create(type)) {
+ return dispatcher;
+ } else {
+ delete dispatcher;
+ return 0;
+ }
+}
+
+AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) {
+ SocketDispatcher* dispatcher = new SocketDispatcher(s, this);
+ if (dispatcher->Initialize()) {
+ return dispatcher;
+ } else {
+ delete dispatcher;
+ return 0;
+ }
+}
+
+void PhysicalSocketServer::Add(Dispatcher *pdispatcher) {
+ CritScope cs(&crit_);
+ dispatchers_.push_back(pdispatcher);
+}
+
+void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) {
+ CritScope cs(&crit_);
+ dispatchers_.erase(std::remove(dispatchers_.begin(), dispatchers_.end(), pdispatcher), dispatchers_.end());
+}
+
+#ifdef POSIX
+bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
+ // Calculate timing information
+
+ struct timeval *ptvWait = NULL;
+ struct timeval tvWait;
+ struct timeval tvStop;
+ if (cmsWait != kForever) {
+ // Calculate wait timeval
+ tvWait.tv_sec = cmsWait / 1000;
+ tvWait.tv_usec = (cmsWait % 1000) * 1000;
+ ptvWait = &tvWait;
+
+ // Calculate when to return in a timeval
+ gettimeofday(&tvStop, NULL);
+ tvStop.tv_sec += tvWait.tv_sec;
+ tvStop.tv_usec += tvWait.tv_usec;
+ if (tvStop.tv_usec >= 1000000) {
+ tvStop.tv_usec -= 1000000;
+ tvStop.tv_sec += 1;
+ }
+ }
+
+ // Zero all fd_sets. Don't need to do this inside the loop since
+ // select() zeros the descriptors not signaled
+
+ fd_set fdsRead;
+ FD_ZERO(&fdsRead);
+ fd_set fdsWrite;
+ FD_ZERO(&fdsWrite);
+
+ fWait_ = true;
+
+ while (fWait_) {
+ int fdmax = -1;
+ {
+ CritScope cr(&crit_);
+ for (unsigned i = 0; i < dispatchers_.size(); i++) {
+ // Query dispatchers for read and write wait state
+
+ Dispatcher *pdispatcher = dispatchers_[i];
+ assert(pdispatcher);
+ if (!process_io && (pdispatcher != signal_wakeup_))
+ continue;
+ int fd = pdispatcher->GetDescriptor();
+ if (fd > fdmax)
+ fdmax = fd;
+ uint32 ff = pdispatcher->GetRequestedEvents();
+ if (ff & kfRead)
+ FD_SET(fd, &fdsRead);
+ if (ff & (kfWrite | kfConnect))
+ FD_SET(fd, &fdsWrite);
+ }
+ }
+
+ // Wait then call handlers as appropriate
+ // < 0 means error
+ // 0 means timeout
+ // > 0 means count of descriptors ready
+ int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait);
+ // If error, return error
+ // todo: do something intelligent
+ if (n < 0)
+ return false;
+
+ // If timeout, return success
+
+ if (n == 0)
+ return true;
+
+ // We have signaled descriptors
+
+ {
+ CritScope cr(&crit_);
+ for (unsigned i = 0; i < dispatchers_.size(); i++) {
+ Dispatcher *pdispatcher = dispatchers_[i];
+ int fd = pdispatcher->GetDescriptor();
+ uint32 ff = 0;
+ if (FD_ISSET(fd, &fdsRead)) {
+ FD_CLR(fd, &fdsRead);
+ if (pdispatcher->IsDescriptorClosed()) {
+ ff |= kfClose;
+ } else {
+ ff |= kfRead;
+ }
+ }
+ if (FD_ISSET(fd, &fdsWrite)) {
+ FD_CLR(fd, &fdsWrite);
+ if (pdispatcher->GetRequestedEvents() & kfConnect) {
+ ff |= kfConnect;
+ } else {
+ ff |= kfWrite;
+ }
+ }
+ if (ff != 0) {
+ pdispatcher->OnPreEvent(ff);
+ pdispatcher->OnEvent(ff, 0);
+ }
+ }
+ }
+
+ // Recalc the time remaining to wait. Doing it here means it doesn't get
+ // calced twice the first time through the loop
+
+ if (cmsWait != kForever) {
+ ptvWait->tv_sec = 0;
+ ptvWait->tv_usec = 0;
+ struct timeval tvT;
+ gettimeofday(&tvT, NULL);
+ if (tvStop.tv_sec >= tvT.tv_sec) {
+ ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
+ ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
+ if (ptvWait->tv_usec < 0) {
+ ptvWait->tv_usec += 1000000;
+ ptvWait->tv_sec -= 1;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+#endif // POSIX
+
+#ifdef WIN32
+bool PhysicalSocketServer::Wait(int cmsWait, bool process_io)
+{
+ int cmsTotal = cmsWait;
+ int cmsElapsed = 0;
+ uint32 msStart = GetMillisecondCount();
+
+#if LOGGING
+ if (last_tick_dispatch_count_ == 0) {
+ last_tick_tracked_ = msStart;
+ }
+#endif
+
+ WSAEVENT socket_ev = WSACreateEvent();
+
+ fWait_ = true;
+ while (fWait_) {
+ std::vector<WSAEVENT> events;
+ std::vector<Dispatcher *> event_owners;
+
+ events.push_back(socket_ev);
+
+ {
+ CritScope cr(&crit_);
+ for (size_t i = 0; i < dispatchers_.size(); ++i) {
+ Dispatcher * disp = dispatchers_[i];
+ if (!process_io && (disp != signal_wakeup_))
+ continue;
+ SOCKET s = disp->GetSocket();
+ if (disp->CheckSignalClose()) {
+ // We just signalled close, don't poll this socket
+ } else if (s != INVALID_SOCKET) {
+ WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents()));
+ } else {
+ events.push_back(disp->GetWSAEvent());
+ event_owners.push_back(disp);
+ }
+ }
+ }
+
+ // Which is shorter, the delay wait or the asked wait?
+
+ int cmsNext;
+ if (cmsWait == kForever) {
+ cmsNext = cmsWait;
+ } else {
+ cmsNext = cmsTotal - cmsElapsed;
+ if (cmsNext < 0)
+ cmsNext = 0;
+ }
+
+ // Wait for one of the events to signal
+ DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0], false, cmsNext, false);
+
+#if 0 // LOGGING
+ // we track this information purely for logging purposes.
+ last_tick_dispatch_count_++;
+ if (last_tick_dispatch_count_ >= 1000) {
+ uint32 now = GetMillisecondCount();
+ LOG(INFO) << "PhysicalSocketServer took " << TimeDiff(now, last_tick_tracked_) << "ms for 1000 events";
+
+ // If we get more than 1000 events in a second, we are spinning badly
+ // (normally it should take about 8-20 seconds).
+ assert(TimeDiff(now, last_tick_tracked_) > 1000);
+
+ last_tick_tracked_ = now;
+ last_tick_dispatch_count_ = 0;
+ }
+#endif
+
+ // Failed?
+ // todo: need a better strategy than this!
+
+ if (dw == WSA_WAIT_FAILED) {
+ int error = WSAGetLastError();
+ assert(false);
+ WSACloseEvent(socket_ev);
+ return false;
+ }
+
+ // Timeout?
+
+ if (dw == WSA_WAIT_TIMEOUT) {
+ WSACloseEvent(socket_ev);
+ return true;
+ }
+
+ // Figure out which one it is and call it
+
+ {
+ CritScope cr(&crit_);
+ int index = dw - WSA_WAIT_EVENT_0;
+ if (index > 0) {
+ --index; // The first event is the socket event
+ event_owners[index]->OnPreEvent(0);
+ event_owners[index]->OnEvent(0, 0);
+ } else if (process_io) {
+ for (size_t i = 0; i < dispatchers_.size(); ++i) {
+ Dispatcher * disp = dispatchers_[i];
+ SOCKET s = disp->GetSocket();
+ if (s == INVALID_SOCKET)
+ continue;
+
+ WSANETWORKEVENTS wsaEvents;
+ int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents);
+ if (err == 0) {
+
+#if LOGGING
+ {
+ if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
+ }
+ if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
+ LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT];
+ }
+ }
+#endif
+ uint32 ff = 0;
+ int errcode = 0;
+ if (wsaEvents.lNetworkEvents & FD_READ)
+ ff |= kfRead;
+ if (wsaEvents.lNetworkEvents & FD_WRITE)
+ ff |= kfWrite;
+ if (wsaEvents.lNetworkEvents & FD_CONNECT) {
+ if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
+ ff |= kfConnect;
+ } else {
+ // TODO: Decide whether we want to signal connect, but with an error code
+ ff |= kfClose;
+ errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
+ }
+ }
+ if (wsaEvents.lNetworkEvents & FD_ACCEPT)
+ ff |= kfRead;
+ if (wsaEvents.lNetworkEvents & FD_CLOSE) {
+ ff |= kfClose;
+ errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
+ }
+ if (ff != 0) {
+ disp->OnPreEvent(ff);
+ disp->OnEvent(ff, errcode);
+ }
+ }
+ }
+ }
+
+ // Reset the network event until new activity occurs
+ WSAResetEvent(socket_ev);
+ }
+
+ // Break?
+
+ if (!fWait_)
+ break;
+ cmsElapsed = GetMillisecondCount() - msStart;
+ if ((cmsWait != kForever) && (cmsElapsed >= cmsWait)) {
+ break;
+ }
+ }
+
+ // Done
+
+ WSACloseEvent(socket_ev);
+ return true;
+}
+#endif // WIN32
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/physicalsocketserver.h b/third_party/libjingle/files/talk/base/physicalsocketserver.h
new file mode 100644
index 0000000..cc2e707
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/physicalsocketserver.h
@@ -0,0 +1,81 @@
+/*
+ * 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 TALK_BASE_PHYSICALSOCKETSERVER_H__
+#define TALK_BASE_PHYSICALSOCKETSERVER_H__
+
+#include <vector>
+
+#include "talk/base/asyncfile.h"
+#include "talk/base/socketserver.h"
+#include "talk/base/criticalsection.h"
+
+#ifdef POSIX
+typedef int SOCKET;
+#endif // POSIX
+
+namespace talk_base {
+
+class Dispatcher;
+class Signaler;
+
+// A socket server that provides the real sockets of the underlying OS.
+class PhysicalSocketServer : public SocketServer {
+public:
+ PhysicalSocketServer();
+ virtual ~PhysicalSocketServer();
+
+ // SocketFactory:
+ virtual Socket* CreateSocket(int type);
+ virtual AsyncSocket* CreateAsyncSocket(int type);
+
+ // Internal Factory for Accept
+ AsyncSocket* WrapSocket(SOCKET s);
+
+ // SocketServer:
+ virtual bool Wait(int cms, bool process_io);
+ virtual void WakeUp();
+
+ void Add(Dispatcher* dispatcher);
+ void Remove(Dispatcher* dispatcher);
+
+#ifdef POSIX
+ AsyncFile* CreateFile(int fd);
+#endif
+
+private:
+ std::vector<Dispatcher*> dispatchers_;
+ Signaler* signal_wakeup_;
+ CriticalSection crit_;
+ bool fWait_;
+ uint32 last_tick_tracked_;
+ int last_tick_dispatch_count_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_PHYSICALSOCKETSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/proxydetect.cc b/third_party/libjingle/files/talk/base/proxydetect.cc
new file mode 100644
index 0000000..2b52315
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/proxydetect.cc
@@ -0,0 +1,827 @@
+// TODO: Abstract this better for cross-platformability
+
+#ifdef _WINDOWS
+#include "talk/base/win32.h"
+#include <shlobj.h>
+#endif
+
+#include "talk/base/httpcommon.h"
+#include "talk/base/httpcommon-inl.h"
+#include "talk/base/proxydetect.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/basicdefs.h"
+
+#if _WINDOWS
+#define _TRY_FIREFOX 1
+#define _TRY_WINHTTP 1
+#define _TRY_JSPROXY 0
+#define _TRY_WM_FINDPROXY 0
+#define _TRY_IE_LAN_SETTINGS 1
+#endif // _WINDOWS
+
+#if _TRY_WINHTTP
+//#include <winhttp.h>
+// Note: From winhttp.h
+
+const char WINHTTP[] = "winhttp";
+typedef LPVOID HINTERNET;
+
+typedef struct {
+ DWORD dwAccessType; // see WINHTTP_ACCESS_* types below
+ LPWSTR lpszProxy; // proxy server list
+ LPWSTR lpszProxyBypass; // proxy bypass list
+} WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO;
+
+typedef struct {
+ DWORD dwFlags;
+ DWORD dwAutoDetectFlags;
+ LPCWSTR lpszAutoConfigUrl;
+ LPVOID lpvReserved;
+ DWORD dwReserved;
+ BOOL fAutoLogonIfChallenged;
+} WINHTTP_AUTOPROXY_OPTIONS;
+
+typedef struct {
+ BOOL fAutoDetect;
+ LPWSTR lpszAutoConfigUrl;
+ LPWSTR lpszProxy;
+ LPWSTR lpszProxyBypass;
+} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
+
+extern "C" {
+typedef HINTERNET (WINAPI * pfnWinHttpOpen)
+(
+ IN LPCWSTR pwszUserAgent,
+ IN DWORD dwAccessType,
+ IN LPCWSTR pwszProxyName OPTIONAL,
+ IN LPCWSTR pwszProxyBypass OPTIONAL,
+ IN DWORD dwFlags
+);
+typedef BOOL (STDAPICALLTYPE * pfnWinHttpCloseHandle)
+(
+ IN HINTERNET hInternet
+);
+typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetProxyForUrl)
+(
+ IN HINTERNET hSession,
+ IN LPCWSTR lpcwszUrl,
+ IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
+ OUT WINHTTP_PROXY_INFO * pProxyInfo
+);
+typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetIEProxyConfig)
+(
+ IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig
+);
+
+} // extern "C"
+
+#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
+#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
+#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
+#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
+#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
+#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
+#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
+#define WINHTTP_ACCESS_TYPE_NO_PROXY 1
+#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
+#define WINHTTP_NO_PROXY_NAME NULL
+#define WINHTTP_NO_PROXY_BYPASS NULL
+
+#endif // _TRY_WINHTTP
+
+#if _TRY_JSPROXY
+extern "C" {
+typedef BOOL (STDAPICALLTYPE * pfnInternetGetProxyInfo)
+(
+ LPCSTR lpszUrl,
+ DWORD dwUrlLength,
+ LPSTR lpszUrlHostName,
+ DWORD dwUrlHostNameLength,
+ LPSTR * lplpszProxyHostName,
+ LPDWORD lpdwProxyHostNameLength
+ );
+} // extern "C"
+#endif // _TRY_JSPROXY
+
+#if _TRY_WM_FINDPROXY
+#include <comutil.h>
+#include <wmnetsourcecreator.h>
+#include <wmsinternaladminnetsource.h>
+#endif // _TRY_WM_FINDPROXY
+
+#if _TRY_IE_LAN_SETTINGS
+#include <wininet.h>
+#include <string>
+#endif // _TRY_IE_LAN_SETTINGS
+
+using namespace talk_base;
+
+//////////////////////////////////////////////////////////////////////
+// Utility Functions
+//////////////////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+#ifdef _UNICODE
+
+typedef std::wstring tstring;
+std::string Utf8String(const tstring& str) { return ToUtf8(str); }
+
+#else // !_UNICODE
+
+typedef std::string tstring;
+std::string Utf8String(const tstring& str) { return str; }
+
+#endif // !_UNICODE
+#endif // _WINDOWS
+
+//////////////////////////////////////////////////////////////////////
+// GetProxySettingsForUrl
+//////////////////////////////////////////////////////////////////////
+
+bool WildMatch(const char * target, const char * pattern) {
+ while (*pattern) {
+ if (*pattern == '*') {
+ if (!*++pattern) {
+ return true;
+ }
+ while (*target) {
+ if ((toupper(*pattern) == toupper(*target)) && WildMatch(target + 1, pattern + 1)) {
+ return true;
+ }
+ ++target;
+ }
+ return false;
+ } else {
+ if (toupper(*pattern) != toupper(*target)) {
+ return false;
+ }
+ ++target;
+ ++pattern;
+ }
+ }
+ return !*target;
+}
+
+bool ProxyItemMatch(const Url<char>& url, char * item, size_t len) {
+ // hostname:443
+ if (char * port = strchr(item, ':')) {
+ *port++ = '\0';
+ if (url.port() != atol(port)) {
+ return false;
+ }
+ }
+
+ // A.B.C.D or A.B.C.D/24
+ int a, b, c, d, m;
+ int match = sscanf(item, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m);
+ if (match >= 4) {
+ uint32 ip = ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF);
+ if ((match < 5) || (m > 32))
+ m = 32;
+ else if (m < 0)
+ m = 0;
+ uint32 mask = (m == 0) ? 0 : (~0UL) << (32 - m);
+ SocketAddress addr(url.server());
+ return !addr.IsUnresolved() && ((addr.ip() & mask) == (ip & mask));
+ }
+
+ // .foo.com
+ if (*item == '.') {
+ size_t hostlen = url.server().length();
+ return (hostlen > len)
+ && (stricmp(url.server().c_str() + (hostlen - len), item) == 0);
+ }
+
+ // localhost or www.*.com
+ if (!WildMatch(url.server().c_str(), item))
+ return false;
+
+ return true;
+}
+
+bool ProxyListMatch(const Url<char>& url, const std::string& slist, char sep) {
+ const size_t BUFSIZE = 256;
+ char buffer[BUFSIZE];
+ const char* clist = slist.c_str();
+ while (*clist) {
+ // Remove leading space
+ if (isspace(*clist)) {
+ ++clist;
+ continue;
+ }
+ // Break on separator
+ size_t len;
+ const char * start = clist;
+ if (const char * end = strchr(clist, sep)) {
+ len = (end - clist);
+ clist += len + 1;
+ } else {
+ len = strlen(clist);
+ clist += len;
+ }
+ // Remove trailing space
+ while ((len > 0) && isspace(start[len-1]))
+ --len;
+ // Check for oversized entry
+ if (len >= BUFSIZE)
+ continue;
+ memcpy(buffer, start, len);
+ buffer[len] = 0;
+ if (!ProxyItemMatch(url, buffer, len))
+ continue;
+ return true;
+ }
+ return false;
+}
+
+bool Better(ProxyType lhs, const ProxyType rhs) {
+ // PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
+ const int PROXY_VALUE[4] = { 0, 2, 3, 1 };
+ return (PROXY_VALUE[lhs] > PROXY_VALUE[rhs]);
+}
+
+bool ParseProxy(const std::string& saddress, ProxyInfo& proxy) {
+ const size_t kMaxAddressLength = 1024;
+ // Allow semicolon, space, or tab as an address separator
+ const char* const kAddressSeparator = " ;\t";
+
+ ProxyType ptype;
+ std::string host;
+ uint16 port;
+
+ const char* address = saddress.c_str();
+ while (*address) {
+ size_t len;
+ const char * start = address;
+ if (const char * sep = strchr(address, kAddressSeparator)) {
+ len = (sep - address);
+ address += len + 1;
+ while (strchr(kAddressSeparator, *address)) {
+ address += 1;
+ }
+ } else {
+ len = strlen(address);
+ address += len;
+ }
+
+ if (len > kMaxAddressLength - 1) {
+ LOG(LS_WARNING) << "Proxy address too long [" << start << "]";
+ continue;
+ }
+
+ char buffer[kMaxAddressLength];
+ memcpy(buffer, start, len);
+ buffer[len] = 0;
+
+ char * colon = strchr(buffer, ':');
+ if (!colon) {
+ LOG(LS_WARNING) << "Proxy address without port [" << buffer << "]";
+ continue;
+ }
+
+ *colon = 0;
+ char * endptr;
+ port = static_cast<uint16>(strtol(colon + 1, &endptr, 0));
+ if (*endptr != 0) {
+ LOG(LS_WARNING) << "Proxy address with invalid port [" << buffer << "]";
+ continue;
+ }
+
+ if (char * equals = strchr(buffer, '=')) {
+ *equals = 0;
+ host = equals + 1;
+ if (_stricmp(buffer, "socks") == 0) {
+ ptype = PROXY_SOCKS5;
+ } else if (_stricmp(buffer, "https") == 0) {
+ ptype = PROXY_HTTPS;
+ } else {
+ LOG(LS_WARNING) << "Proxy address with unknown protocol ["
+ << buffer << "]";
+ ptype = PROXY_UNKNOWN;
+ }
+ } else {
+ host = buffer;
+ ptype = PROXY_UNKNOWN;
+ }
+
+ if (Better(ptype, proxy.type)) {
+ proxy.type = ptype;
+ proxy.address.SetIP(host);
+ proxy.address.SetPort((int)port);
+ }
+ }
+
+ return (proxy.type != PROXY_NONE);
+}
+
+#if _WINDOWS
+bool IsDefaultBrowserFirefox() {
+ HKEY key;
+ LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command",
+ 0, KEY_READ, &key);
+ if (ERROR_SUCCESS != result)
+ return false;
+
+ wchar_t* value = NULL;
+ DWORD size, type;
+ result = RegQueryValueEx(key, L"", 0, &type, NULL, &size);
+ if (REG_SZ != type) {
+ result = ERROR_ACCESS_DENIED; // Any error is fine
+ } else if (ERROR_SUCCESS == result) {
+ value = new wchar_t[size+1];
+ BYTE* buffer = reinterpret_cast<BYTE*>(value);
+ result = RegQueryValueEx(key, L"", 0, &type, buffer, &size);
+ }
+ RegCloseKey(key);
+
+ bool success = false;
+ if (ERROR_SUCCESS == result) {
+ value[size] = L'\0';
+ for (size_t i=0; i<size; ++i) {
+ value[i] = tolowercase(value[i]);
+ }
+ success = (NULL != strstr(value, L"firefox.exe"));
+ }
+ delete [] value;
+ return success;
+}
+#endif
+
+#if _TRY_FIREFOX
+
+#define USE_FIREFOX_PROFILES_INI 1
+
+bool GetDefaultFirefoxProfile(std::wstring* profile) {
+ ASSERT(NULL != profile);
+
+ wchar_t path[MAX_PATH];
+ if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, path) != S_OK)
+ return false;
+
+ std::wstring profile_root(path);
+ profile_root.append(L"\\Mozilla\\Firefox\\");
+
+#if USE_FIREFOX_PROFILES_INI
+ std::wstring tmp(profile_root);
+ tmp.append(L"profiles.ini");
+
+ FILE * fp = _wfopen(tmp.c_str(), L"rb");
+ if (!fp)
+ return false;
+
+ // [Profile0]
+ // Name=default
+ // IsRelative=1
+ // Path=Profiles/2de53ejb.default
+ // Default=1
+
+ // Note: we are looking for the first entry with "Default=1", or the last entry in the file
+
+ std::wstring candidate;
+ bool relative = true;
+
+ char buffer[1024];
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ size_t len = strlen(buffer);
+ while ((len > 0) && isspace(buffer[len-1]))
+ buffer[--len] = 0;
+ if (buffer[0] == '[') {
+ relative = true;
+ candidate.clear();
+ } else if (strnicmp(buffer, "IsRelative=", 11) == 0) {
+ relative = (buffer[11] != '0');
+ } else if (strnicmp(buffer, "Path=", 5) == 0) {
+ if (relative) {
+ candidate = profile_root;
+ } else {
+ candidate.clear();
+ }
+ candidate.append(ToUtf16(buffer + 5));
+ candidate.append(L"\\");
+ } else if (strnicmp(buffer, "Default=", 8) == 0) {
+ if ((buffer[8] != '0') && !candidate.empty()) {
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ if (candidate.empty())
+ return false;
+ *profile = candidate;
+
+#else // !USE_FIREFOX_PROFILES_INI
+ std::wstring tmp(profile_root);
+ tmp.append(L"Profiles\\*.default");
+ WIN32_FIND_DATA fdata;
+ HANDLE hFind = FindFirstFile(tmp.c_str(), &fdata);
+ if (hFind == INVALID_HANDLE_VALUE)
+ return false;
+
+ profile->assign(profile_root);
+ profile->append(L"Profiles\\");
+ profile->append(fdata.cFileName);
+ profile->append(L"\\");
+ FindClose(hFind);
+#endif // !USE_FIREFOX_PROFILES_INI
+
+ return true;
+}
+
+struct StringMap {
+public:
+ void Add(const char * name, const char * value) { map_[name] = value; }
+ const std::string& Get(const char * name, const char * def = "") const {
+ std::map<std::string, std::string>::const_iterator it =
+ map_.find(name);
+ if (it != map_.end())
+ return it->second;
+ def_ = def;
+ return def_;
+ }
+ bool IsSet(const char * name) const {
+ return (map_.find(name) != map_.end());
+ }
+private:
+ std::map<std::string, std::string> map_;
+ mutable std::string def_;
+};
+
+bool ReadFirefoxPrefs(const std::wstring& filename,
+ const char * prefix,
+ StringMap& settings) {
+ FILE * fp = _wfopen(filename.c_str(), L"rb");
+ if (!fp)
+ return false;
+
+ size_t prefix_len = strlen(prefix);
+ bool overlong_line = false;
+
+ char buffer[1024];
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ size_t len = strlen(buffer);
+ bool missing_newline = (len > 0) && (buffer[len-1] != '\n');
+
+ if (missing_newline) {
+ overlong_line = true;
+ continue;
+ } else if (overlong_line) {
+ LOG_F(LS_INFO) << "Skipping long line";
+ overlong_line = false;
+ continue;
+ }
+
+ while ((len > 0) && isspace(buffer[len-1]))
+ buffer[--len] = 0;
+
+ // Skip blank lines
+ if ((len == 0) || (buffer[0] == '#')
+ || (strncmp(buffer, "/*", 2) == 0)
+ || (strncmp(buffer, " *", 2) == 0))
+ continue;
+
+ int nstart = 0, nend = 0, vstart = 0, vend = 0;
+ sscanf(buffer, "user_pref(\"%n%*[^\"]%n\", %n%*[^)]%n);",
+ &nstart, &nend, &vstart, &vend);
+ if (vend > 0) {
+ char * name = buffer + nstart;
+ name[nend - nstart] = 0;
+ if ((vend - vstart >= 2) && (buffer[vstart] == '"')) {
+ vstart += 1;
+ vend -= 1;
+ }
+ char * value = buffer + vstart;
+ value[vend - vstart] = 0;
+ if ((strncmp(name, prefix, prefix_len) == 0) && *value) {
+ settings.Add(name + prefix_len, value);
+ }
+ } else {
+ LOG_F(LS_WARNING) << "Unparsed pref [" << buffer << "]";
+ }
+ }
+ fclose(fp);
+ return true;
+}
+#endif // _TRY_FIREFOX
+
+#ifdef WIN32
+BOOL MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,
+ HINTERNET hWinHttp, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
+ WINHTTP_PROXY_INFO *info) {
+ // WinHttpGetProxyForUrl() can call plugins which can crash.
+ // In the case of McAfee scriptproxy.dll, it does crash in
+ // older versions. Try to catch crashes here and treat as an
+ // error.
+ BOOL success = FALSE;
+
+#if (_HAS_EXCEPTIONS == 0)
+ __try {
+ success = pWHGPFU(hWinHttp, url, options, info);
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetProxyForUrl faulted!!";
+ }
+#else
+ success = pWHGPFU(hWinHttp, url, options, info);
+#endif
+
+ return success;
+}
+#endif
+
+bool GetProxySettingsForUrl(const char* agent, const char* url,
+ ProxyInfo& proxy,
+ bool long_operation) {
+ bool success = false;
+ Url<char> purl(url);
+
+#if 0
+ assert( WildMatch(_T("A.B.C.D"), _T("a.b.c.d")));
+ assert( WildMatch(_T("127.0.0.1"), _T("12*.0.*1")));
+ assert(!WildMatch(_T("127.0.0.0"), _T("12*.0.*1")));
+ assert(!WildMatch(_T("127.0.0.0"), _T("12*.0.*1")));
+ assert( WildMatch(_T("127.1.0.21"), _T("12*.0.*1")));
+ assert(!WildMatch(_T("127.1.1.21"), _T("12*.0.*1")));
+ purl = PUrl(_T("http://a.b.c:500/"));
+ wchar_t item[256];
+ _tcscpy(item, _T("a.b.c"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("a.x.c"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("a.b.*"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("a.x.*"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T(".b.c"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T(".x.c"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("a.b.c:500"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("a.b.c:501"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+ purl = PUrl(_T("http://1.2.3.4/"));
+ _tcscpy(item, _T("1.2.3.4"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("1.2.3.5"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("1.2.3.5/31"));
+ assert( ProxyItemMatch(purl, item, _tcslen(item)));
+ _tcscpy(item, _T("1.2.3.5/32"));
+ assert(!ProxyItemMatch(purl, item, _tcslen(item)));
+#endif
+
+ bool autoconfig = false;
+ bool use_firefox = false;
+ std::string autoconfig_url;
+
+#if _TRY_FIREFOX
+ use_firefox = IsDefaultBrowserFirefox();
+
+ if (use_firefox) {
+ std::wstring tmp;
+ if (GetDefaultFirefoxProfile(&tmp)) {
+ bool complete = true;
+
+ StringMap settings;
+ tmp.append(L"prefs.js");
+ if (ReadFirefoxPrefs(tmp, "network.proxy.", settings)) {
+ success = true;
+ if (settings.Get("type") == "1") {
+ if (ProxyListMatch(purl, settings.Get("no_proxies_on", "localhost, 127.0.0.1").c_str(), ',')) {
+ // Bypass proxy
+ } else if (settings.Get("share_proxy_settings") == "true") {
+ proxy.type = PROXY_UNKNOWN;
+ proxy.address.SetIP(settings.Get("http"));
+ proxy.address.SetPort(atoi(settings.Get("http_port").c_str()));
+ } else if (settings.IsSet("socks")) {
+ proxy.type = PROXY_SOCKS5;
+ proxy.address.SetIP(settings.Get("socks"));
+ proxy.address.SetPort(atoi(settings.Get("socks_port").c_str()));
+ } else if (settings.IsSet("ssl")) {
+ proxy.type = PROXY_HTTPS;
+ proxy.address.SetIP(settings.Get("ssl"));
+ proxy.address.SetPort(atoi(settings.Get("ssl_port").c_str()));
+ } else if (settings.IsSet("http")) {
+ proxy.type = PROXY_HTTPS;
+ proxy.address.SetIP(settings.Get("http"));
+ proxy.address.SetPort(atoi(settings.Get("http_port").c_str()));
+ }
+ } else if (settings.Get("type") == "2") {
+ complete = success = false;
+ autoconfig_url = settings.Get("autoconfig_url").c_str();
+ } else if (settings.Get("type") == "4") {
+ complete = success = false;
+ autoconfig = true;
+ }
+ }
+ if (complete) { // Otherwise fall through to IE autoproxy code
+ return success;
+ }
+ }
+ }
+#endif // _TRY_FIREFOX
+
+#if _TRY_WINHTTP
+ if (!success) {
+ if (HMODULE hModWH = LoadLibrary(L"winhttp.dll")) {
+ pfnWinHttpOpen pWHO = reinterpret_cast<pfnWinHttpOpen>(GetProcAddress(hModWH, "WinHttpOpen"));
+ pfnWinHttpCloseHandle pWHCH = reinterpret_cast<pfnWinHttpCloseHandle>(GetProcAddress(hModWH, "WinHttpCloseHandle"));
+ pfnWinHttpGetProxyForUrl pWHGPFU = reinterpret_cast<pfnWinHttpGetProxyForUrl>(GetProcAddress(hModWH, "WinHttpGetProxyForUrl"));
+ pfnWinHttpGetIEProxyConfig pWHGIEPC = reinterpret_cast<pfnWinHttpGetIEProxyConfig>(GetProcAddress(hModWH, "WinHttpGetIEProxyConfigForCurrentUser"));
+ if (pWHO && pWHCH && pWHGPFU && pWHGIEPC) {
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG iecfg;
+ memset(&iecfg, 0, sizeof(iecfg));
+ if (!use_firefox && !pWHGIEPC(&iecfg)) {
+ LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetIEProxyConfigForCurrentUser";
+ } else {
+ success = true;
+ if (!use_firefox) {
+ if (iecfg.fAutoDetect) {
+ autoconfig = true;
+ }
+ if (iecfg.lpszAutoConfigUrl) {
+ autoconfig_url = ToUtf8(iecfg.lpszAutoConfigUrl);
+ }
+ }
+ if (!long_operation) {
+ // Unless we perform this operation in the background, don't allow
+ // it to take a long time.
+ autoconfig = false;
+ }
+ if (autoconfig || !autoconfig_url.empty()) {
+ if (HINTERNET hWinHttp = pWHO(ToUtf16(agent).c_str(),
+ WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0)) {
+ WINHTTP_AUTOPROXY_OPTIONS options;
+ memset(&options, 0, sizeof(options));
+ if (autoconfig) {
+ options.dwFlags |= WINHTTP_AUTOPROXY_AUTO_DETECT;
+ options.dwAutoDetectFlags |= WINHTTP_AUTO_DETECT_TYPE_DHCP
+ | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ }
+ std::wstring autoconfig_url16((ToUtf16)(autoconfig_url));
+ if (!autoconfig_url.empty()) {
+ options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
+ options.lpszAutoConfigUrl = autoconfig_url16.c_str();
+ }
+ options.fAutoLogonIfChallenged = TRUE;
+ WINHTTP_PROXY_INFO info;
+ memset(&info, 0, sizeof(info));
+
+ BOOL success = MyWinHttpGetProxyForUrl(pWHGPFU,
+ hWinHttp, ToUtf16(url).c_str(), &options, &info);
+
+ if (!success) {
+ LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetProxyForUrl";
+ } else {
+ if (iecfg.lpszProxy)
+ GlobalFree(iecfg.lpszProxy);
+ if (iecfg.lpszProxyBypass)
+ GlobalFree(iecfg.lpszProxyBypass);
+ iecfg.lpszProxy = info.lpszProxy;
+ iecfg.lpszProxyBypass = info.lpszProxyBypass;
+ }
+ pWHCH(hWinHttp);
+ }
+ }
+ if (!ProxyListMatch(purl, ToUtf8(nonnull(iecfg.lpszProxyBypass)), ' ')) {
+ ParseProxy(ToUtf8(nonnull(iecfg.lpszProxy)), proxy);
+ }
+ if (iecfg.lpszAutoConfigUrl)
+ GlobalFree(iecfg.lpszAutoConfigUrl);
+ if (iecfg.lpszProxy)
+ GlobalFree(iecfg.lpszProxy);
+ if (iecfg.lpszProxyBypass)
+ GlobalFree(iecfg.lpszProxyBypass);
+ }
+ }
+ FreeLibrary(hModWH);
+ }
+ }
+#endif // _TRY_WINHTTP
+
+#if _TRY_JSPROXY
+ if (!success) {
+ if (HMODULE hModJS = LoadLibrary(_T("jsproxy.dll"))) {
+ pfnInternetGetProxyInfo pIGPI = reinterpret_cast<pfnInternetGetProxyInfo>(GetProcAddress(hModJS, "InternetGetProxyInfo"));
+ if (pIGPI) {
+ char proxy[256], host[256];
+ memset(proxy, 0, sizeof(proxy));
+ char * ptr = proxy;
+ DWORD proxylen = sizeof(proxy);
+ std::string surl = Utf8String(url);
+ DWORD hostlen = _snprintf(host, sizeof(host), "http%s://%S", purl.secure() ? "s" : "", purl.server());
+ if (pIGPI(surl.data(), surl.size(), host, hostlen, &ptr, &proxylen)) {
+ LOG(INFO) << "Proxy: " << proxy;
+ } else {
+ LOG_GLE(INFO) << "InternetGetProxyInfo";
+ }
+ }
+ FreeLibrary(hModJS);
+ }
+ }
+#endif // _TRY_JSPROXY
+
+#if _TRY_WM_FINDPROXY
+ if (!success) {
+ INSNetSourceCreator * nsc = 0;
+ HRESULT hr = CoCreateInstance(CLSID_ClientNetManager, 0, CLSCTX_ALL, IID_INSNetSourceCreator, (LPVOID *) &nsc);
+ if (SUCCEEDED(hr)) {
+ if (SUCCEEDED(hr = nsc->Initialize())) {
+ VARIANT dispatch;
+ VariantInit(&dispatch);
+ if (SUCCEEDED(hr = nsc->GetNetSourceAdminInterface(L"http", &dispatch))) {
+ IWMSInternalAdminNetSource * ians = 0;
+ if (SUCCEEDED(hr = dispatch.pdispVal->QueryInterface(IID_IWMSInternalAdminNetSource, (LPVOID *) &ians))) {
+ _bstr_t host(purl.server());
+ BSTR proxy = 0;
+ BOOL bProxyEnabled = FALSE;
+ DWORD port, context = 0;
+ if (SUCCEEDED(hr = ians->FindProxyForURL(L"http", host, &bProxyEnabled, &proxy, &port, &context))) {
+ success = true;
+ if (bProxyEnabled) {
+ _bstr_t sproxy = proxy;
+ proxy.ptype = PT_HTTPS;
+ proxy.host = sproxy;
+ proxy.port = port;
+ }
+ }
+ SysFreeString(proxy);
+ if (FAILED(hr = ians->ShutdownProxyContext(context))) {
+ LOG(LS_INFO) << "IWMSInternalAdminNetSource::ShutdownProxyContext failed: " << hr;
+ }
+ ians->Release();
+ }
+ }
+ VariantClear(&dispatch);
+ if (FAILED(hr = nsc->Shutdown())) {
+ LOG(LS_INFO) << "INSNetSourceCreator::Shutdown failed: " << hr;
+ }
+ }
+ nsc->Release();
+ }
+ }
+#endif // _TRY_WM_FINDPROXY
+
+#if _TRY_IE_LAN_SETTINGS
+ if (!success) {
+ wchar_t buffer[1024];
+ memset(buffer, 0, sizeof(buffer));
+ INTERNET_PROXY_INFO * info = reinterpret_cast<INTERNET_PROXY_INFO *>(buffer);
+ DWORD dwSize = sizeof(buffer);
+
+ if (!InternetQueryOption(0, INTERNET_OPTION_PROXY, info, &dwSize)) {
+ LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
+ } else if (info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
+ success = true;
+ } else if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
+ success = true;
+ if (!ProxyListMatch(purl, nonnull(reinterpret_cast<const char*>(info->lpszProxyBypass)), ' ')) {
+ ParseProxy(nonnull(reinterpret_cast<const char*>(info->lpszProxy)), proxy);
+ }
+ } else {
+ LOG(LS_INFO) << "unknown internet access type: " << info->dwAccessType;
+ }
+ }
+#endif // _TRY_IE_LAN_SETTINGS
+
+#if 0
+ if (!success) {
+ INTERNET_PER_CONN_OPTION_LIST list;
+ INTERNET_PER_CONN_OPTION options[3];
+ memset(&list, 0, sizeof(list));
+ memset(&options, 0, sizeof(options));
+
+ list.dwSize = sizeof(list);
+ list.dwOptionCount = 3;
+ list.pOptions = options;
+ options[0].dwOption = INTERNET_PER_CONN_FLAGS;
+ options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
+ options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
+ DWORD dwSize = sizeof(list);
+
+ if (!InternetQueryOption(0, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, &dwSize)) {
+ LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
+ } else if ((options[0].Value.dwValue & PROXY_TYPE_PROXY) != 0) {
+ success = true;
+ if (!ProxyListMatch(purl, nonnull(options[2].Value.pszValue), _T(';'))) {
+ ParseProxy(nonnull(options[1].Value.pszValue), proxy);
+ }
+ } else if ((options[0].Value.dwValue & PROXY_TYPE_DIRECT) != 0) {
+ success = true;
+ } else {
+ LOG(LS_INFO) << "unknown internet access type: "
+ << options[0].Value.dwValue;
+ }
+ if (options[1].Value.pszValue) {
+ GlobalFree(options[1].Value.pszValue);
+ }
+ if (options[2].Value.pszValue) {
+ GlobalFree(options[2].Value.pszValue);
+ }
+ }
+#endif // 0
+
+ return success;
+}
diff --git a/third_party/libjingle/files/talk/base/proxydetect.h b/third_party/libjingle/files/talk/base/proxydetect.h
new file mode 100644
index 0000000..3de2598
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/proxydetect.h
@@ -0,0 +1,13 @@
+#ifndef _PROXYDETECT_H_
+#define _PROXYDETECT_H_
+
+#include "talk/base/proxyinfo.h"
+
+// Auto-detect the proxy server. Returns true if a proxy is configured,
+// although hostname may be empty if the proxy is not required for the given URL.
+
+bool GetProxySettingsForUrl(const char* agent, const char* url,
+ talk_base::ProxyInfo& proxy,
+ bool long_operation = false);
+
+#endif // _PROXYDETECT_H_
diff --git a/third_party/libjingle/files/talk/base/proxyinfo.cc b/third_party/libjingle/files/talk/base/proxyinfo.cc
new file mode 100644
index 0000000..1d9c588
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/proxyinfo.cc
@@ -0,0 +1,37 @@
+/*
+ * 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/base/proxyinfo.h"
+
+namespace talk_base {
+
+const char * ProxyToString(ProxyType proxy) {
+ const char * const PROXY_NAMES[] = { "none", "https", "socks5", "unknown" };
+ return PROXY_NAMES[proxy];
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/proxyinfo.h b/third_party/libjingle/files/talk/base/proxyinfo.h
new file mode 100644
index 0000000..834ec4f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/proxyinfo.h
@@ -0,0 +1,51 @@
+/*
+ * 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 TALK_BASE_PROXYINFO_H__
+#define TALK_BASE_PROXYINFO_H__
+
+#include <string>
+#include "talk/base/socketaddress.h"
+#include "talk/base/cryptstring.h"
+
+namespace talk_base {
+
+enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN };
+const char * ProxyToString(ProxyType proxy);
+
+struct ProxyInfo {
+ ProxyType type;
+ SocketAddress address;
+ std::string username;
+ CryptString password;
+
+ ProxyInfo() : type(PROXY_NONE) { }
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_PROXYINFO_H__
diff --git a/third_party/libjingle/files/talk/base/schanneladapter.cc b/third_party/libjingle/files/talk/base/schanneladapter.cc
new file mode 100644
index 0000000..1a24c0c
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/schanneladapter.cc
@@ -0,0 +1,749 @@
+/*
+ * 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/base/win32.h"
+#define SECURITY_WIN32
+#include <security.h>
+#include <schannel.h>
+
+#include <iomanip>
+#include <vector>
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/schanneladapter.h"
+#include "talk/base/sec_buffer.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+/////////////////////////////////////////////////////////////////////////////
+// SChannelAdapter
+/////////////////////////////////////////////////////////////////////////////
+
+extern const ConstantLabel SECURITY_ERRORS[];
+
+const ConstantLabel SECURITY_ERRORS[] = {
+ KLABEL(SEC_I_COMPLETE_AND_CONTINUE),
+ KLABEL(SEC_I_COMPLETE_NEEDED),
+ KLABEL(SEC_I_CONTEXT_EXPIRED),
+ KLABEL(SEC_I_CONTINUE_NEEDED),
+ KLABEL(SEC_I_INCOMPLETE_CREDENTIALS),
+ KLABEL(SEC_I_RENEGOTIATE),
+ KLABEL(SEC_E_CERT_EXPIRED),
+ KLABEL(SEC_E_INCOMPLETE_MESSAGE),
+ KLABEL(SEC_E_INSUFFICIENT_MEMORY),
+ KLABEL(SEC_E_INTERNAL_ERROR),
+ KLABEL(SEC_E_INVALID_HANDLE),
+ KLABEL(SEC_E_INVALID_TOKEN),
+ KLABEL(SEC_E_LOGON_DENIED),
+ KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+ KLABEL(SEC_E_NO_CREDENTIALS),
+ KLABEL(SEC_E_NOT_OWNER),
+ KLABEL(SEC_E_OK),
+ KLABEL(SEC_E_SECPKG_NOT_FOUND),
+ KLABEL(SEC_E_TARGET_UNKNOWN),
+ KLABEL(SEC_E_UNKNOWN_CREDENTIALS),
+ KLABEL(SEC_E_UNSUPPORTED_FUNCTION),
+ KLABEL(SEC_E_UNTRUSTED_ROOT),
+ KLABEL(SEC_E_WRONG_PRINCIPAL),
+ LASTLABEL
+};
+
+const ConstantLabel SCHANNEL_BUFFER_TYPES[] = {
+ KLABEL(SECBUFFER_EMPTY), // 0
+ KLABEL(SECBUFFER_DATA), // 1
+ KLABEL(SECBUFFER_TOKEN), // 2
+ KLABEL(SECBUFFER_PKG_PARAMS), // 3
+ KLABEL(SECBUFFER_MISSING), // 4
+ KLABEL(SECBUFFER_EXTRA), // 5
+ KLABEL(SECBUFFER_STREAM_TRAILER), // 6
+ KLABEL(SECBUFFER_STREAM_HEADER), // 7
+ KLABEL(SECBUFFER_MECHLIST), // 11
+ KLABEL(SECBUFFER_MECHLIST_SIGNATURE), // 12
+ KLABEL(SECBUFFER_TARGET), // 13
+ KLABEL(SECBUFFER_CHANNEL_BINDINGS), // 14
+ LASTLABEL
+};
+
+void DescribeBuffer(LoggingSeverity severity, const char* prefix,
+ const SecBuffer& sb) {
+ LOG_V(severity)
+ << prefix
+ << "(" << sb.cbBuffer
+ << ", " << FindLabel(sb.BufferType & ~SECBUFFER_ATTRMASK,
+ SCHANNEL_BUFFER_TYPES)
+ << ", " << sb.pvBuffer << ")";
+}
+
+void DescribeBuffers(LoggingSeverity severity, const char* prefix,
+ const SecBufferDesc* sbd) {
+ if (!LOG_CHECK_LEVEL_V(severity))
+ return;
+ LOG_V(severity) << prefix << "(";
+ for (size_t i=0; i<sbd->cBuffers; ++i) {
+ DescribeBuffer(severity, " ", sbd->pBuffers[i]);
+ }
+ LOG_V(severity) << ")";
+}
+
+const ULONG SSL_FLAGS_DEFAULT = ISC_REQ_ALLOCATE_MEMORY
+ | ISC_REQ_CONFIDENTIALITY
+ | ISC_REQ_EXTENDED_ERROR
+ | ISC_REQ_INTEGRITY
+ | ISC_REQ_REPLAY_DETECT
+ | ISC_REQ_SEQUENCE_DETECT
+ | ISC_REQ_STREAM;
+ //| ISC_REQ_USE_SUPPLIED_CREDS;
+
+typedef std::vector<char> SChannelBuffer;
+
+struct SChannelAdapter::SSLImpl {
+ CredHandle cred;
+ CtxtHandle ctx;
+ bool cred_init, ctx_init;
+ SChannelBuffer inbuf, outbuf, readable;
+ SecPkgContext_StreamSizes sizes;
+
+ SSLImpl() : cred_init(false), ctx_init(false) { }
+};
+
+SChannelAdapter::SChannelAdapter(AsyncSocket* socket)
+ : SSLAdapter(socket), state_(SSL_NONE),
+ restartable_(false), signal_close_(false), message_pending_(false),
+ impl_(new SSLImpl) {
+}
+
+SChannelAdapter::~SChannelAdapter() {
+ Cleanup();
+}
+
+int
+SChannelAdapter::StartSSL(const char* hostname, bool restartable) {
+ if (state_ != SSL_NONE)
+ return ERROR_ALREADY_INITIALIZED;
+
+ ssl_host_name_ = hostname;
+ restartable_ = restartable;
+
+ if (socket_->GetState() != Socket::CS_CONNECTED) {
+ state_ = SSL_WAIT;
+ return 0;
+ }
+
+ state_ = SSL_CONNECTING;
+ if (int err = BeginSSL()) {
+ Error("BeginSSL", err, false);
+ return err;
+ }
+
+ return 0;
+}
+
+int
+SChannelAdapter::BeginSSL() {
+ LOG(LS_VERBOSE) << "BeginSSL: " << ssl_host_name_;
+ ASSERT(state_ == SSL_CONNECTING);
+
+ SECURITY_STATUS ret;
+
+ SCHANNEL_CRED sc_cred = { 0 };
+ sc_cred.dwVersion = SCHANNEL_CRED_VERSION;
+ //sc_cred.dwMinimumCipherStrength = 128; // Note: use system default
+ sc_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_AUTO_CRED_VALIDATION;
+
+ ret = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL,
+ &sc_cred, NULL, NULL, &impl_->cred, NULL);
+ if (ret != SEC_E_OK) {
+ LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
+ << ErrorName(ret, SECURITY_ERRORS);
+ return ret;
+ }
+ impl_->cred_init = true;
+
+ if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
+ SecPkgCred_CipherStrengths cipher_strengths = { 0 };
+ ret = QueryCredentialsAttributes(&impl_->cred,
+ SECPKG_ATTR_CIPHER_STRENGTHS,
+ &cipher_strengths);
+ if (SUCCEEDED(ret)) {
+ LOG(LS_VERBOSE) << "SChannel cipher strength: "
+ << cipher_strengths.dwMinimumCipherStrength << " - "
+ << cipher_strengths.dwMaximumCipherStrength;
+ }
+
+ SecPkgCred_SupportedAlgs supported_algs = { 0 };
+ ret = QueryCredentialsAttributes(&impl_->cred,
+ SECPKG_ATTR_SUPPORTED_ALGS,
+ &supported_algs);
+ if (SUCCEEDED(ret)) {
+ LOG(LS_VERBOSE) << "SChannel supported algorithms:";
+ for (DWORD i=0; i<supported_algs.cSupportedAlgs; ++i) {
+ ALG_ID alg_id = supported_algs.palgSupportedAlgs[i];
+ PCCRYPT_OID_INFO oinfo = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,
+ &alg_id, 0);
+ LPCWSTR alg_name = (NULL != oinfo) ? oinfo->pwszName : L"Unknown";
+ LOG(LS_VERBOSE) << " " << talk_base::ToUtf8(alg_name)
+ << " (" << alg_id << ")";
+ }
+ }
+ }
+
+ ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;
+ if (ignore_bad_cert())
+ flags |= ISC_REQ_MANUAL_CRED_VALIDATION;
+
+ CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;
+ ret = InitializeSecurityContextA(&impl_->cred, NULL,
+ const_cast<char*>(ssl_host_name_.c_str()),
+ flags, 0, 0, NULL, 0,
+ &impl_->ctx, sb_out.desc(),
+ &ret_flags, NULL);
+ if (SUCCEEDED(ret))
+ impl_->ctx_init = true;
+ return ProcessContext(ret, NULL, sb_out.desc());
+}
+
+int
+SChannelAdapter::ContinueSSL() {
+ LOG(LS_VERBOSE) << "ContinueSSL";
+ ASSERT(state_ == SSL_CONNECTING);
+
+ SECURITY_STATUS ret;
+
+ CSecBufferBundle<2> sb_in;
+ sb_in[0].BufferType = SECBUFFER_TOKEN;
+ sb_in[0].cbBuffer = static_cast<unsigned long>(impl_->inbuf.size());
+ sb_in[0].pvBuffer = &impl_->inbuf[0];
+ //DescribeBuffers(LS_VERBOSE, "Input Buffer ", sb_in.desc());
+
+ ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;
+ if (ignore_bad_cert())
+ flags |= ISC_REQ_MANUAL_CRED_VALIDATION;
+
+ CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;
+ ret = InitializeSecurityContextA(&impl_->cred, &impl_->ctx,
+ const_cast<char*>(ssl_host_name_.c_str()),
+ flags, 0, 0, sb_in.desc(), 0,
+ NULL, sb_out.desc(),
+ &ret_flags, NULL);
+ return ProcessContext(ret, sb_in.desc(), sb_out.desc());
+}
+
+int
+SChannelAdapter::ProcessContext(long int status, _SecBufferDesc* sbd_in,
+ _SecBufferDesc* sbd_out) {
+ LoggingSeverity level = LS_ERROR;
+ if ((status == SEC_E_OK)
+ || (status != SEC_I_CONTINUE_NEEDED)
+ || (status != SEC_E_INCOMPLETE_MESSAGE)) {
+ level = LS_VERBOSE; // Expected messages
+ }
+ LOG_V(level)
+ << "InitializeSecurityContext error: "
+ << ErrorName(status, SECURITY_ERRORS);
+ //if (sbd_in)
+ // DescribeBuffers(LS_VERBOSE, "Input Buffer ", sbd_in);
+ //if (sbd_out)
+ // DescribeBuffers(LS_VERBOSE, "Output Buffer ", sbd_out);
+
+ if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ // Wait for more input from server.
+ return Flush();
+ }
+
+ if (FAILED(status)) {
+ // We can't continue. Common errors:
+ // SEC_E_CERT_EXPIRED - Typically, this means the computer clock is wrong.
+ return status;
+ }
+
+ // Note: we check both input and output buffers for SECBUFFER_EXTRA.
+ // Experience shows it appearing in the input, but the documentation claims
+ // it should appear in the output.
+ size_t extra = 0;
+ if (sbd_in) {
+ for (size_t i=0; i<sbd_in->cBuffers; ++i) {
+ SecBuffer& buffer = sbd_in->pBuffers[i];
+ if (buffer.BufferType == SECBUFFER_EXTRA) {
+ extra += buffer.cbBuffer;
+ }
+ }
+ }
+ if (sbd_out) {
+ for (size_t i=0; i<sbd_out->cBuffers; ++i) {
+ SecBuffer& buffer = sbd_out->pBuffers[i];
+ if (buffer.BufferType == SECBUFFER_EXTRA) {
+ extra += buffer.cbBuffer;
+ } else if (buffer.BufferType == SECBUFFER_TOKEN) {
+ impl_->outbuf.insert(impl_->outbuf.end(),
+ reinterpret_cast<char*>(buffer.pvBuffer),
+ reinterpret_cast<char*>(buffer.pvBuffer) + buffer.cbBuffer);
+ }
+ }
+ }
+
+ if (extra) {
+ ASSERT(extra <= impl_->inbuf.size());
+ size_t consumed = impl_->inbuf.size() - extra;
+ memmove(&impl_->inbuf[0], &impl_->inbuf[consumed], extra);
+ impl_->inbuf.resize(extra);
+ } else {
+ impl_->inbuf.clear();
+ }
+
+ if (SEC_I_CONTINUE_NEEDED == status) {
+ // Send data to server and wait for response.
+ // Note: ContinueSSL will result in a Flush, anyway.
+ return impl_->inbuf.empty() ? Flush() : ContinueSSL();
+ }
+
+ if (SEC_E_OK == status) {
+ LOG(LS_VERBOSE) << "QueryContextAttributes";
+ status = QueryContextAttributes(&impl_->ctx, SECPKG_ATTR_STREAM_SIZES,
+ &impl_->sizes);
+ if (FAILED(status)) {
+ LOG(LS_ERROR) << "QueryContextAttributes error: "
+ << ErrorName(status, SECURITY_ERRORS);
+ return status;
+ }
+
+ state_ = SSL_CONNECTED;
+
+ if (int err = DecryptData()) {
+ return err;
+ } else if (int err = Flush()) {
+ return err;
+ } else {
+ // If we decrypted any data, queue up a notification here
+ PostEvent();
+ // Signal our connectedness
+ AsyncSocketAdapter::OnConnectEvent(this);
+ }
+ return 0;
+ }
+
+ if (SEC_I_INCOMPLETE_CREDENTIALS == status) {
+ // We don't support client authentication in schannel.
+ return status;
+ }
+
+ // We don't expect any other codes
+ ASSERT(false);
+ return status;
+}
+
+int
+SChannelAdapter::DecryptData() {
+ SChannelBuffer& inbuf = impl_->inbuf;
+ SChannelBuffer& readable = impl_->readable;
+
+ while (!inbuf.empty()) {
+ CSecBufferBundle<4> in_buf;
+ in_buf[0].BufferType = SECBUFFER_DATA;
+ in_buf[0].cbBuffer = static_cast<unsigned long>(inbuf.size());
+ in_buf[0].pvBuffer = &inbuf[0];
+
+ //DescribeBuffers(LS_VERBOSE, "Decrypt In ", in_buf.desc());
+ SECURITY_STATUS status = DecryptMessage(&impl_->ctx, in_buf.desc(), 0, 0);
+ //DescribeBuffers(LS_VERBOSE, "Decrypt Out ", in_buf.desc());
+
+ // Note: We are explicitly treating SEC_E_OK, SEC_I_CONTEXT_EXPIRED, and
+ // any other successful results as continue.
+ if (SUCCEEDED(status)) {
+ size_t data_len = 0, extra_len = 0;
+ for (size_t i=0; i<in_buf.desc()->cBuffers; ++i) {
+ if (in_buf[i].BufferType == SECBUFFER_DATA) {
+ data_len += in_buf[i].cbBuffer;
+ readable.insert(readable.end(),
+ reinterpret_cast<char*>(in_buf[i].pvBuffer),
+ reinterpret_cast<char*>(in_buf[i].pvBuffer) + in_buf[i].cbBuffer);
+ } else if (in_buf[i].BufferType == SECBUFFER_EXTRA) {
+ extra_len += in_buf[i].cbBuffer;
+ }
+ }
+ // There is a bug on Win2K where SEC_I_CONTEXT_EXPIRED is misclassified.
+ if ((data_len == 0) && (inbuf[0] == 0x15)) {
+ status = SEC_I_CONTEXT_EXPIRED;
+ }
+ if (extra_len) {
+ size_t consumed = inbuf.size() - extra_len;
+ memmove(&inbuf[0], &inbuf[consumed], extra_len);
+ inbuf.resize(extra_len);
+ } else {
+ inbuf.clear();
+ }
+ // TODO: Handle SEC_I_CONTEXT_EXPIRED to do clean shutdown
+ if (status != SEC_E_OK) {
+ LOG(LS_INFO) << "DecryptMessage returned continuation code: "
+ << ErrorName(status, SECURITY_ERRORS);
+ }
+ continue;
+ }
+
+ if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ break;
+ } else {
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+void
+SChannelAdapter::Cleanup() {
+ if (impl_->ctx_init)
+ DeleteSecurityContext(&impl_->ctx);
+ if (impl_->cred_init)
+ FreeCredentialsHandle(&impl_->cred);
+ delete impl_;
+}
+
+void
+SChannelAdapter::PostEvent() {
+ // Check if there's anything notable to signal
+ if (impl_->readable.empty() && !signal_close_)
+ return;
+
+ // Only one post in the queue at a time
+ if (message_pending_)
+ return;
+
+ if (Thread* thread = Thread::Current()) {
+ message_pending_ = true;
+ thread->Post(this);
+ } else {
+ LOG(LS_ERROR) << "No thread context available for SChannelAdapter";
+ ASSERT(false);
+ }
+}
+
+void
+SChannelAdapter::Error(const char* context, int err, bool signal) {
+ LOG(LS_WARNING) << "SChannelAdapter::Error("
+ << context << ", "
+ << ErrorName(err, SECURITY_ERRORS) << ")";
+ state_ = SSL_ERROR;
+ SetError(err);
+ if (signal)
+ AsyncSocketAdapter::OnCloseEvent(this, err);
+}
+
+int
+SChannelAdapter::Read() {
+ char buffer[4096];
+ SChannelBuffer& inbuf = impl_->inbuf;
+ while (true) {
+ int ret = AsyncSocketAdapter::Recv(buffer, sizeof(buffer));
+ if (ret > 0) {
+ inbuf.insert(inbuf.end(), buffer, buffer + ret);
+ } else if (GetError() == EWOULDBLOCK) {
+ return 0; // Blocking
+ } else {
+ return GetError();
+ }
+ }
+}
+
+int
+SChannelAdapter::Flush() {
+ int result = 0;
+ size_t pos = 0;
+ SChannelBuffer& outbuf = impl_->outbuf;
+ while (pos < outbuf.size()) {
+ int sent = AsyncSocketAdapter::Send(&outbuf[pos], outbuf.size() - pos);
+ if (sent > 0) {
+ pos += sent;
+ } else if (GetError() == EWOULDBLOCK) {
+ break; // Blocking
+ } else {
+ result = GetError();
+ break;
+ }
+ }
+ if (int remainder = outbuf.size() - pos) {
+ memmove(&outbuf[0], &outbuf[pos], remainder);
+ outbuf.resize(remainder);
+ } else {
+ outbuf.clear();
+ }
+ return result;
+}
+
+//
+// AsyncSocket Implementation
+//
+
+int
+SChannelAdapter::Send(const void* pv, size_t cb) {
+ switch (state_) {
+ case SSL_NONE:
+ return AsyncSocketAdapter::Send(pv, cb);
+
+ case SSL_WAIT:
+ case SSL_CONNECTING:
+ SetError(EWOULDBLOCK);
+ return SOCKET_ERROR;
+
+ case SSL_CONNECTED:
+ break;
+
+ case SSL_ERROR:
+ default:
+ return SOCKET_ERROR;
+ }
+
+ size_t written = 0;
+ SChannelBuffer& outbuf = impl_->outbuf;
+ while (written < cb) {
+ const size_t encrypt_len = std::min<size_t>(cb - written,
+ impl_->sizes.cbMaximumMessage);
+
+ CSecBufferBundle<4> out_buf;
+ out_buf[0].BufferType = SECBUFFER_STREAM_HEADER;
+ out_buf[0].cbBuffer = impl_->sizes.cbHeader;
+ out_buf[1].BufferType = SECBUFFER_DATA;
+ out_buf[1].cbBuffer = static_cast<unsigned long>(encrypt_len);
+ out_buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+ out_buf[2].cbBuffer = impl_->sizes.cbTrailer;
+
+ size_t packet_len = out_buf[0].cbBuffer
+ + out_buf[1].cbBuffer
+ + out_buf[2].cbBuffer;
+
+ SChannelBuffer message;
+ message.resize(packet_len);
+ out_buf[0].pvBuffer = &message[0];
+ out_buf[1].pvBuffer = &message[out_buf[0].cbBuffer];
+ out_buf[2].pvBuffer = &message[out_buf[0].cbBuffer + out_buf[1].cbBuffer];
+
+ memcpy(out_buf[1].pvBuffer,
+ static_cast<const char*>(pv) + written,
+ encrypt_len);
+
+ //DescribeBuffers(LS_VERBOSE, "Encrypt In ", out_buf.desc());
+ SECURITY_STATUS res = EncryptMessage(&impl_->ctx, 0, out_buf.desc(), 0);
+ //DescribeBuffers(LS_VERBOSE, "Encrypt Out ", out_buf.desc());
+
+ if (FAILED(res)) {
+ Error("EncryptMessage", res, false);
+ return SOCKET_ERROR;
+ }
+
+ // We assume that the header and data segments do not change length,
+ // or else encrypting the concatenated packet in-place is wrong.
+ ASSERT(out_buf[0].cbBuffer == impl_->sizes.cbHeader);
+ ASSERT(out_buf[1].cbBuffer == static_cast<unsigned long>(encrypt_len));
+
+ // However, the length of the trailer may change due to padding.
+ ASSERT(out_buf[2].cbBuffer <= impl_->sizes.cbTrailer);
+
+ packet_len = out_buf[0].cbBuffer
+ + out_buf[1].cbBuffer
+ + out_buf[2].cbBuffer;
+
+ written += encrypt_len;
+ outbuf.insert(outbuf.end(), &message[0], &message[packet_len-1]+1);
+ }
+
+ if (int err = Flush()) {
+ state_ = SSL_ERROR;
+ SetError(err);
+ return SOCKET_ERROR;
+ }
+
+ return static_cast<int>(written);
+}
+
+int
+SChannelAdapter::Recv(void* pv, size_t cb) {
+ switch (state_) {
+ case SSL_NONE:
+ return AsyncSocketAdapter::Recv(pv, cb);
+
+ case SSL_WAIT:
+ case SSL_CONNECTING:
+ SetError(EWOULDBLOCK);
+ return SOCKET_ERROR;
+
+ case SSL_CONNECTED:
+ break;
+
+ case SSL_ERROR:
+ default:
+ return SOCKET_ERROR;
+ }
+
+ SChannelBuffer& readable = impl_->readable;
+ if (readable.empty()) {
+ SetError(EWOULDBLOCK);
+ return SOCKET_ERROR;
+ }
+ size_t read = _min(cb, readable.size());
+ memcpy(pv, &readable[0], read);
+ if (size_t remaining = readable.size() - read) {
+ memmove(&readable[0], &readable[read], remaining);
+ readable.resize(remaining);
+ } else {
+ readable.clear();
+ }
+
+ PostEvent();
+ return static_cast<int>(read);
+}
+
+int
+SChannelAdapter::Close() {
+ if (!impl_->readable.empty()) {
+ LOG(WARNING) << "SChannelAdapter::Close with readable data";
+ // Note: this isn't strictly an error, but we're using it temporarily to
+ // track bugs.
+ //ASSERT(false);
+ }
+ if (state_ == SSL_CONNECTED) {
+ DWORD token = SCHANNEL_SHUTDOWN;
+ CSecBufferBundle<1> sb_in;
+ sb_in[0].BufferType = SECBUFFER_TOKEN;
+ sb_in[0].cbBuffer = sizeof(token);
+ sb_in[0].pvBuffer = &token;
+ ApplyControlToken(&impl_->ctx, sb_in.desc());
+ // TODO: In theory, to do a nice shutdown, we need to begin shutdown
+ // negotiation with more calls to InitializeSecurityContext. Since the
+ // socket api doesn't support nice shutdown at this point, we don't bother.
+ }
+ Cleanup();
+ impl_ = new SSLImpl;
+ state_ = restartable_ ? SSL_WAIT : SSL_NONE;
+ signal_close_ = false;
+ message_pending_ = false;
+ return AsyncSocketAdapter::Close();
+}
+
+Socket::ConnState
+SChannelAdapter::GetState() const {
+ if (signal_close_)
+ return CS_CONNECTED;
+ ConnState state = socket_->GetState();
+ if ((state == CS_CONNECTED)
+ && ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING)))
+ state = CS_CONNECTING;
+ return state;
+}
+
+void
+SChannelAdapter::OnConnectEvent(AsyncSocket* socket) {
+ LOG(LS_VERBOSE) << "SChannelAdapter::OnConnectEvent";
+ if (state_ != SSL_WAIT) {
+ ASSERT(state_ == SSL_NONE);
+ AsyncSocketAdapter::OnConnectEvent(socket);
+ return;
+ }
+
+ state_ = SSL_CONNECTING;
+ if (int err = BeginSSL()) {
+ Error("BeginSSL", err);
+ }
+}
+
+void
+SChannelAdapter::OnReadEvent(AsyncSocket* socket) {
+ if (state_ == SSL_NONE) {
+ AsyncSocketAdapter::OnReadEvent(socket);
+ return;
+ }
+
+ if (int err = Read()) {
+ Error("Read", err);
+ return;
+ }
+
+ if (impl_->inbuf.empty())
+ return;
+
+ if (state_ == SSL_CONNECTED) {
+ if (int err = DecryptData()) {
+ Error("DecryptData", err);
+ } else if (!impl_->readable.empty()) {
+ AsyncSocketAdapter::OnReadEvent(this);
+ }
+ } else if (state_ == SSL_CONNECTING) {
+ if (int err = ContinueSSL()) {
+ Error("ContinueSSL", err);
+ }
+ }
+}
+
+void
+SChannelAdapter::OnWriteEvent(AsyncSocket* socket) {
+ if (state_ == SSL_NONE) {
+ AsyncSocketAdapter::OnWriteEvent(socket);
+ return;
+ }
+
+ if (int err = Flush()) {
+ Error("Flush", err);
+ return;
+ }
+
+ // See if we have more data to write
+ if (!impl_->outbuf.empty())
+ return;
+
+ // Buffer is empty, submit notification
+ if (state_ == SSL_CONNECTED) {
+ AsyncSocketAdapter::OnWriteEvent(socket);
+ }
+}
+
+void
+SChannelAdapter::OnCloseEvent(AsyncSocket* socket, int err) {
+ if ((state_ == SSL_NONE) || impl_->readable.empty()) {
+ AsyncSocketAdapter::OnCloseEvent(socket, err);
+ return;
+ }
+
+ // If readable is non-empty, then we have a pending Message
+ // that will allow us to signal close (eventually).
+ signal_close_ = true;
+}
+
+void
+SChannelAdapter::OnMessage(Message* pmsg) {
+ if (!message_pending_)
+ return; // This occurs when socket is closed
+
+ message_pending_ = false;
+ if (!impl_->readable.empty()) {
+ AsyncSocketAdapter::OnReadEvent(this);
+ } else if (signal_close_) {
+ signal_close_ = false;
+ AsyncSocketAdapter::OnCloseEvent(this, 0); // TODO: cache this error?
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/schanneladapter.h b/third_party/libjingle/files/talk/base/schanneladapter.h
new file mode 100644
index 0000000..a5ab7b3
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/schanneladapter.h
@@ -0,0 +1,94 @@
+/*
+ * 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 TALK_BASE_SCHANNELADAPTER_H__
+#define TALK_BASE_SCHANNELADAPTER_H__
+
+#include <string>
+#include "talk/base/ssladapter.h"
+#include "talk/base/messagequeue.h"
+struct _SecBufferDesc;
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SChannelAdapter : public SSLAdapter, public MessageHandler {
+public:
+ SChannelAdapter(AsyncSocket* socket);
+ virtual ~SChannelAdapter();
+
+ virtual int StartSSL(const char* hostname, bool restartable);
+ virtual int Send(const void* pv, size_t cb);
+ virtual int Recv(void* pv, size_t cb);
+ virtual int Close();
+
+ // Note that the socket returns ST_CONNECTING while SSL is being negotiated.
+ virtual ConnState GetState() const;
+
+protected:
+ enum SSLState {
+ SSL_NONE, SSL_WAIT, SSL_CONNECTING, SSL_CONNECTED, SSL_ERROR
+ };
+ struct SSLImpl;
+
+ virtual void OnConnectEvent(AsyncSocket* socket);
+ virtual void OnReadEvent(AsyncSocket* socket);
+ virtual void OnWriteEvent(AsyncSocket* socket);
+ virtual void OnCloseEvent(AsyncSocket* socket, int err);
+ virtual void OnMessage(Message* pmsg);
+
+ int BeginSSL();
+ int ContinueSSL();
+ int ProcessContext(long int status, _SecBufferDesc* sbd_in,
+ _SecBufferDesc* sbd_out);
+ int DecryptData();
+
+ int Read();
+ int Flush();
+ void Error(const char* context, int err, bool signal = true);
+ void Cleanup();
+
+ void PostEvent();
+
+private:
+ SSLState state_;
+ std::string ssl_host_name_;
+ // If true, socket will retain SSL configuration after Close.
+ bool restartable_;
+ // If true, we are delaying signalling close until all data is read.
+ bool signal_close_;
+ // If true, we are waiting to be woken up to signal readability or closure.
+ bool message_pending_;
+ SSLImpl* impl_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SCHANNELADAPTER_H__
diff --git a/third_party/libjingle/files/talk/base/scoped_ptr.h b/third_party/libjingle/files/talk/base/scoped_ptr.h
new file mode 100644
index 0000000..9a9d378
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/scoped_ptr.h
@@ -0,0 +1,38 @@
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// Copyright (c) 2001, 2002 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
+//
+
+// scoped_ptr mimics a built-in pointer except that it guarantees deletion
+// of the object pointed to, either on destruction of the scoped_ptr or via
+// an explicit reset(). scoped_ptr is a simple solution for simple needs;
+// use shared_ptr or std::auto_ptr if your needs are more complex.
+
+// scoped_ptr_malloc added in by Google. When one of
+// these goes out of scope, instead of doing a delete or delete[], it
+// calls free(). scoped_ptr_malloc<char> is likely to see much more
+// use than any other specializations.
+
+// release() added in by Google. Use this to conditionally
+// transfer ownership of a heap-allocated object to the caller, usually on
+// method success.
+#ifndef TALK_BASE_SCOPED_PTR_H__
+#define TALK_BASE_SCOPED_PTR_H__
+
+#include <cstddef> // for std::ptrdiff_t
+#include <assert.h> // for assert
+#include <stdlib.h> // for free() decl
+
+#ifdef _WIN32
+namespace std { using ::ptrdiff_t; };
+#endif // _WIN32
+
+#include "base/scoped_ptr.h"
+
+#endif // #ifndef TALK_BASE_SCOPED_PTR_H__
diff --git a/third_party/libjingle/files/talk/base/sec_buffer.h b/third_party/libjingle/files/talk/base/sec_buffer.h
new file mode 100644
index 0000000..585e27f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/sec_buffer.h
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+// @file Contains utility classes that make it easier to use SecBuffers
+
+#ifndef TALK_BASE_SEC_BUFFER_H__
+#define TALK_BASE_SEC_BUFFER_H__
+
+namespace talk_base {
+
+// A base class for CSecBuffer<T>. Contains
+// all implementation that does not require
+// template arguments.
+class CSecBufferBase : public SecBuffer {
+ public:
+ CSecBufferBase() {
+ Clear();
+ }
+
+ // Uses the SSPI to free a pointer, must be
+ // used for buffers returned from SSPI APIs.
+ static void FreeSSPI(void *ptr) {
+ if ( ptr ) {
+ SECURITY_STATUS status;
+ status = ::FreeContextBuffer(ptr);
+ ASSERT(SEC_E_OK == status); // "Freeing context buffer"
+ }
+ }
+
+ // Deletes a buffer with operator delete
+ static void FreeDelete(void *ptr) {
+ delete [] reinterpret_cast<char*>(ptr);
+ }
+
+ // A noop delete, for buffers over other
+ // people's memory
+ static void FreeNone(void *ptr) {
+ }
+
+ protected:
+ // Clears the buffer to EMPTY & NULL
+ void Clear() {
+ this->BufferType = SECBUFFER_EMPTY;
+ this->cbBuffer = 0;
+ this->pvBuffer = NULL;
+ }
+};
+
+// Wrapper class for SecBuffer to take care
+// of initialization and destruction.
+template <void (*pfnFreeBuffer)(void *ptr)>
+class CSecBuffer: public CSecBufferBase {
+ public:
+ // Initializes buffer to empty & NULL
+ CSecBuffer() {
+ }
+
+ // Frees any allocated memory
+ ~CSecBuffer() {
+ Release();
+ }
+
+ // Frees the buffer appropriately, and re-nulls
+ void Release() {
+ pfnFreeBuffer(this->pvBuffer);
+ Clear();
+ }
+
+ private:
+ // A placeholder function for compile-time asserts on the class
+ void CompileAsserts() {
+ // never invoked...
+ assert(false); // _T("Notreached")
+
+ // This class must not extend the size of SecBuffer, since
+ // we use arrays of CSecBuffer in CSecBufferBundle below
+ cassert(sizeof(CSecBuffer<SSPIFree> == sizeof(SecBuffer)));
+ }
+};
+
+// Contains all generic implementation for the
+// SecBufferBundle class
+class SecBufferBundleBase {
+ public:
+};
+
+// A template class that bundles a SecBufferDesc with
+// one or more SecBuffers for convenience. Can take
+// care of deallocating buffers appropriately, as indicated
+// by pfnFreeBuffer function.
+// By default does no deallocation.
+template <int num_buffers,
+ void (*pfnFreeBuffer)(void *ptr) = CSecBufferBase::FreeNone>
+class CSecBufferBundle : public SecBufferBundleBase {
+ public:
+ // Constructs a security buffer bundle with num_buffers
+ // buffers, all of which are empty and nulled.
+ CSecBufferBundle() {
+ desc_.ulVersion = SECBUFFER_VERSION;
+ desc_.cBuffers = num_buffers;
+ desc_.pBuffers = buffers_;
+ }
+
+ // Frees all currently used buffers.
+ ~CSecBufferBundle() {
+ Release();
+ }
+
+ // Accessor for the descriptor
+ PSecBufferDesc desc() {
+ return &desc_;
+ }
+
+ // Accessor for the descriptor
+ const PSecBufferDesc desc() const {
+ return &desc_;
+ }
+
+ // returns the i-th security buffer
+ SecBuffer &operator[] (size_t num) {
+ ASSERT(num < num_buffers); // "Buffer index out of bounds"
+ return buffers_[num];
+ }
+
+ // returns the i-th security buffer
+ const SecBuffer &operator[] (size_t num) const {
+ ASSERT(num < num_buffers); // "Buffer index out of bounds"
+ return buffers_[num];
+ }
+
+ // Frees all non-NULL security buffers,
+ // using the deallocation function
+ void Release() {
+ for ( size_t i = 0; i < num_buffers; ++i ) {
+ buffers_[i].Release();
+ }
+ }
+
+ private:
+ // Our descriptor
+ SecBufferDesc desc_;
+ // Our bundled buffers, each takes care of its own
+ // initialization and destruction
+ CSecBuffer<pfnFreeBuffer> buffers_[num_buffers];
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SEC_BUFFER_H__
diff --git a/third_party/libjingle/files/talk/base/signalthread.cc b/third_party/libjingle/files/talk/base/signalthread.cc
new file mode 100644
index 0000000..c9ac86a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/signalthread.cc
@@ -0,0 +1,128 @@
+#include "talk/base/common.h"
+#include "talk/base/signalthread.h"
+
+using namespace talk_base;
+
+///////////////////////////////////////////////////////////////////////////////
+// SignalThread
+///////////////////////////////////////////////////////////////////////////////
+
+SignalThread::SignalThread()
+: main_(Thread::Current()), state_(kInit)
+{
+ main_->SignalQueueDestroyed.connect(this,
+ &SignalThread::OnMainThreadDestroyed);
+ refcount_ = 1;
+ worker_.parent_ = this;
+}
+
+void SignalThread::OnMainThreadDestroyed() {
+ EnterExit ee(this);
+ main_ = NULL;
+}
+
+SignalThread::~SignalThread() {
+}
+
+void SignalThread::SetPriority(ThreadPriority priority) {
+ EnterExit ee(this);
+ ASSERT(main_->IsCurrent());
+ ASSERT(kInit == state_);
+ worker_.SetPriority(priority);
+}
+
+void SignalThread::Start() {
+ EnterExit ee(this);
+ ASSERT(main_->IsCurrent());
+ if (kInit == state_ || kComplete == state_) {
+ state_ = kRunning;
+ OnWorkStart();
+ worker_.Start();
+ } else {
+ ASSERT(false);
+ }
+}
+
+void SignalThread::Destroy(bool wait) {
+ EnterExit ee(this);
+ ASSERT(main_->IsCurrent());
+ if ((kInit == state_) || (kComplete == state_)) {
+ refcount_--;
+ } else if (kRunning == state_ || kReleasing == state_) {
+ state_ = kStopping;
+ // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
+ // OWS(), ContinueWork() will return false.
+ if (wait) {
+ // Release the thread's lock so that it can return from ::Run.
+ cs_.Leave();
+ worker_.Stop();
+ cs_.Enter();
+ refcount_--;
+ } else {
+ worker_.Quit();
+ }
+ OnWorkStop();
+ } else {
+ ASSERT(false);
+ }
+}
+
+void SignalThread::Release() {
+ EnterExit ee(this);
+ ASSERT(main_->IsCurrent());
+ if (kComplete == state_) {
+ refcount_--;
+ } else if (kRunning == state_) {
+ state_ = kReleasing;
+ } else {
+ // if (kInit == state_) use Destroy()
+ ASSERT(false);
+ }
+}
+
+bool SignalThread::ContinueWork() {
+ EnterExit ee(this);
+ ASSERT(worker_.IsCurrent());
+ return worker_.ProcessMessages(0);
+}
+
+void SignalThread::OnMessage(Message *msg) {
+ EnterExit ee(this);
+ if (ST_MSG_WORKER_DONE == msg->message_id) {
+ ASSERT(main_->IsCurrent());
+ OnWorkDone();
+ bool do_delete = false;
+ if (kRunning == state_) {
+ state_ = kComplete;
+ } else {
+ do_delete = true;
+ }
+ if (kStopping != state_) {
+ // Before signaling that the work is done, make sure that the worker
+ // thread actually is done. We got here because DoWork() finished and
+ // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
+ // thread is about to go away anyway, but sometimes it doesn't actually
+ // finish before SignalWorkDone is processed, and for a reusable
+ // SignalThread this makes an assert in thread.cc fire.
+ //
+ // Calling Stop() on the worker ensures that the OS thread that underlies
+ // the worker will finish, and will be set to NULL, enabling us to call
+ // Start() again.
+ worker_.Stop();
+ SignalWorkDone(this);
+ }
+ if (do_delete) {
+ refcount_--;
+ }
+ }
+}
+
+void SignalThread::Run() {
+ DoWork();
+ {
+ EnterExit ee(this);
+ if (main_) {
+ main_->Post(this, ST_MSG_WORKER_DONE);
+ }
+ }
+}
diff --git a/third_party/libjingle/files/talk/base/signalthread.h b/third_party/libjingle/files/talk/base/signalthread.h
new file mode 100644
index 0000000..ad6b46a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/signalthread.h
@@ -0,0 +1,125 @@
+#ifndef _SIGNALTHREAD_H_
+#define _SIGNALTHREAD_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// SignalThread - Base class for worker threads. The main thread should call
+// Start() to begin work, and then follow one of these models:
+// Normal: Wait for SignalWorkDone, and then call Release to destroy.
+// Cancellation: Call Release(true), to abort the worker thread.
+// Fire-and-forget: Call Release(false), which allows the thread to run to
+// completion, and then self-destruct without further notification.
+// Periodic tasks: Wait for SignalWorkDone, then eventually call Start()
+// again to repeat the task. When the instance isn't needed anymore,
+// call Release. DoWork, OnWorkStart and OnWorkStop are called again,
+// on a new thread.
+// The subclass should override DoWork() to perform the background task. By
+// periodically calling ContinueWork(), it can check for cancellation.
+// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work
+// tasks in the context of the main thread.
+///////////////////////////////////////////////////////////////////////////////
+
+class SignalThread : public sigslot::has_slots<>, protected MessageHandler {
+public:
+ SignalThread();
+
+ // Context: Main Thread. Call before Start to change the worker's priority.
+ void SetPriority(ThreadPriority priority);
+
+ // Context: Main Thread. Call to begin the worker thread.
+ void Start();
+
+ // Context: Main Thread. If the worker thread is not running, deletes the
+ // object immediately. Otherwise, asks the worker thread to abort processing,
+ // and schedules the object to be deleted once the worker exits.
+ // SignalWorkDone will not be signalled. If wait is true, does not return
+ // until the thread is deleted.
+ void Destroy(bool wait);
+
+ // Context: Main Thread. If the worker thread is complete, deletes the
+ // object immediately. Otherwise, schedules the object to be deleted once
+ // the worker thread completes. SignalWorkDone will be signalled.
+ void Release();
+
+ // Context: Main Thread. Signalled when work is complete.
+ sigslot::signal1<SignalThread *> SignalWorkDone;
+
+ enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE };
+
+protected:
+ virtual ~SignalThread();
+
+ // Context: Main Thread. Subclass should override to do pre-work setup.
+ virtual void OnWorkStart() { }
+
+ // Context: Worker Thread. Subclass should override to do work.
+ virtual void DoWork() = 0;
+
+ // Context: Worker Thread. Subclass should call periodically to
+ // dispatch messages and determine if the thread should terminate.
+ bool ContinueWork();
+
+ // Context: Worker Thread. Subclass should override when extra work is
+ // needed to abort the worker thread.
+ virtual void OnWorkStop() { }
+
+ // Context: Main Thread. Subclass should override to do post-work cleanup.
+ virtual void OnWorkDone() { }
+
+ // Context: Any Thread. If subclass overrides, be sure to call the base
+ // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE)
+ virtual void OnMessage(Message *msg);
+
+private:
+ friend class Worker;
+ class Worker : public Thread {
+ public:
+ SignalThread* parent_;
+ virtual void Run() { parent_->Run(); }
+ };
+
+ class EnterExit {
+ friend class SignalThread;
+
+ SignalThread * t_;
+
+ EnterExit(SignalThread * t) : t_(t) {
+ t_->cs_.Enter();
+ t_->refcount_ += 1;
+ }
+ ~EnterExit() {
+ bool d = (0 == (--(t_->refcount_)));
+ t_->cs_.Leave();
+ if (d)
+ delete t_;
+ }
+ };
+
+ friend class EnterExit;
+
+ CriticalSection cs_;
+ int refcount_;
+
+ void Run();
+ void OnMainThreadDestroyed();
+
+ Thread* main_;
+ Worker worker_;
+ enum State {
+ kInit, // Initialized, but not started
+ kRunning, // Started and doing work
+ kReleasing, // Same as running, but to be deleted when work is done
+ kComplete, // Work is done
+ kStopping, // Work is being interrupted
+ } state_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // _SIGNALTHREAD_H_
diff --git a/third_party/libjingle/files/talk/base/sigslot.h b/third_party/libjingle/files/talk/base/sigslot.h
new file mode 100644
index 0000000..c9f9645
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/sigslot.h
@@ -0,0 +1,2699 @@
+// sigslot.h: Signal/Slot classes
+//
+// Written by Sarah Thompson (sarah@telergy.com) 2002.
+//
+// License: Public domain. You are free to use this code however you like, with the proviso that
+// the author takes on no responsibility or liability for any use.
+//
+// QUICK DOCUMENTATION
+//
+// (see also the full documentation at http://sigslot.sourceforge.net/)
+//
+// #define switches
+// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables
+// all of the thread safety support on platforms where it is
+// available.
+//
+// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than
+// gcc on a platform that supports Posix threads. (When using gcc,
+// this is the default - use SIGSLOT_PURE_ISO to disable this if
+// necessary)
+//
+// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global.
+// Otherwise, the default is single_threaded. #define this yourself to
+// override the default. In pure ISO mode, anything other than
+// single_threaded will cause a compiler error.
+//
+// PLATFORM NOTES
+//
+// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream
+// compilers do this by default, but you may need to define it
+// yourself if your build environment is less standard. This causes
+// the Win32 thread support to be compiled in and used automatically.
+//
+// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads
+// available, so they are used automatically. You can override this
+// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
+// something other than gcc but still want to use Posix threads, you
+// need to #define SIGSLOT_USE_POSIX_THREADS.
+//
+// ISO C++ - If none of the supported platforms are detected, or if
+// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
+// along with any code that might cause a pure ISO C++ environment to
+// complain. Before you ask, gcc -ansi -pedantic won't compile this
+// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
+// errors that aren't really there. If you feel like investigating this,
+// please contact the author.
+//
+//
+// THREADING MODES
+//
+// single_threaded - Your program is assumed to be single threaded from the point of view
+// of signal/slot usage (i.e. all objects using signals and slots are
+// created and destroyed from a single thread). Behaviour if objects are
+// destroyed concurrently is undefined (i.e. you'll get the occasional
+// segmentation fault/memory exception).
+//
+// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and
+// slots can be safely created and destroyed from any thread, even when
+// connections exist. In multi_threaded_global mode, this is achieved by a
+// single global mutex (actually a critical section on Windows because they
+// are faster). This option uses less OS resources, but results in more
+// opportunities for contention, possibly resulting in more context switches
+// than are strictly necessary.
+//
+// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global,
+// except that each signal, and each object that inherits has_slots, all
+// have their own mutex/critical section. In practice, this means that
+// mutex collisions (and hence context switches) only happen if they are
+// absolutely essential. However, on some platforms, creating a lot of
+// mutexes can slow down the whole OS, so use this option with care.
+//
+// USING THE LIBRARY
+//
+// See the full documentation at http://sigslot.sourceforge.net/
+//
+//
+
+#ifndef TALK_BASE_SIGSLOT_H__
+#define TALK_BASE_SIGSLOT_H__
+
+#include <set>
+#include <list>
+
+// On our copy of sigslot.h, we force single threading
+#define SIGSLOT_PURE_ISO
+
+#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
+# define _SIGSLOT_SINGLE_THREADED
+#elif defined(WIN32)
+# define _SIGSLOT_HAS_WIN32_THREADS
+# include <windows.h>
+#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
+# define _SIGSLOT_HAS_POSIX_THREADS
+# include <pthread.h>
+#else
+# define _SIGSLOT_SINGLE_THREADED
+#endif
+
+#ifndef SIGSLOT_DEFAULT_MT_POLICY
+# ifdef _SIGSLOT_SINGLE_THREADED
+# define SIGSLOT_DEFAULT_MT_POLICY single_threaded
+# else
+# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
+# endif
+#endif
+
+// TODO: change this namespace to talk_base?
+namespace sigslot {
+
+ class single_threaded
+ {
+ public:
+ single_threaded()
+ {
+ ;
+ }
+
+ virtual ~single_threaded()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ ;
+ }
+
+ virtual void unlock()
+ {
+ ;
+ }
+ };
+
+#ifdef _SIGSLOT_HAS_WIN32_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ static bool isinitialised = false;
+
+ if(!isinitialised)
+ {
+ InitializeCriticalSection(get_critsec());
+ isinitialised = true;
+ }
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ virtual ~multi_threaded_global()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ EnterCriticalSection(get_critsec());
+ }
+
+ virtual void unlock()
+ {
+ LeaveCriticalSection(get_critsec());
+ }
+
+ private:
+ CRITICAL_SECTION* get_critsec()
+ {
+ static CRITICAL_SECTION g_critsec;
+ return &g_critsec;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ virtual ~multi_threaded_local()
+ {
+ DeleteCriticalSection(&m_critsec);
+ }
+
+ virtual void lock()
+ {
+ EnterCriticalSection(&m_critsec);
+ }
+
+ virtual void unlock()
+ {
+ LeaveCriticalSection(&m_critsec);
+ }
+
+ private:
+ CRITICAL_SECTION m_critsec;
+ };
+#endif // _SIGSLOT_HAS_WIN32_THREADS
+
+#ifdef _SIGSLOT_HAS_POSIX_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ pthread_mutex_init(get_mutex(), NULL);
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ virtual ~multi_threaded_global()
+ {
+ ;
+ }
+
+ virtual void lock()
+ {
+ pthread_mutex_lock(get_mutex());
+ }
+
+ virtual void unlock()
+ {
+ pthread_mutex_unlock(get_mutex());
+ }
+
+ private:
+ pthread_mutex_t* get_mutex()
+ {
+ static pthread_mutex_t g_mutex;
+ return &g_mutex;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ virtual ~multi_threaded_local()
+ {
+ pthread_mutex_destroy(&m_mutex);
+ }
+
+ virtual void lock()
+ {
+ pthread_mutex_lock(&m_mutex);
+ }
+
+ virtual void unlock()
+ {
+ pthread_mutex_unlock(&m_mutex);
+ }
+
+ private:
+ pthread_mutex_t m_mutex;
+ };
+#endif // _SIGSLOT_HAS_POSIX_THREADS
+
+ template<class mt_policy>
+ class lock_block
+ {
+ public:
+ mt_policy *m_mutex;
+
+ lock_block(mt_policy *mtx)
+ : m_mutex(mtx)
+ {
+ m_mutex->lock();
+ }
+
+ ~lock_block()
+ {
+ m_mutex->unlock();
+ }
+ };
+
+ template<class mt_policy>
+ class has_slots;
+
+ template<class mt_policy>
+ class _connection_base0
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit() = 0;
+ virtual _connection_base0* clone() = 0;
+ virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _connection_base1
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type) = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* clone() = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _connection_base2
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type) = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection_base3
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type) = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _connection_base4
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _connection_base5
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type) = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone() = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _connection_base6
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type) = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone() = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection_base7
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type) = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _connection_base8
+ {
+ public:
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type, arg8_type) = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class mt_policy>
+ class _signal_base : public mt_policy
+ {
+ public:
+ virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
+ virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0;
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class has_slots : public mt_policy
+ {
+ private:
+ typedef typename std::set<_signal_base<mt_policy> *> sender_set;
+ typedef typename sender_set::const_iterator const_iterator;
+
+ public:
+ has_slots()
+ {
+ ;
+ }
+
+ has_slots(const has_slots& hs)
+ : mt_policy(hs)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = hs.m_senders.begin();
+ const_iterator itEnd = hs.m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_duplicate(&hs, this);
+ m_senders.insert(*it);
+ ++it;
+ }
+ }
+
+ void signal_connect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.insert(sender);
+ }
+
+ void signal_disconnect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.erase(sender);
+ }
+
+ virtual ~has_slots()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_senders.begin();
+ const_iterator itEnd = m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_disconnect(this);
+ ++it;
+ }
+
+ m_senders.erase(m_senders.begin(), m_senders.end());
+ }
+
+ private:
+ sender_set m_senders;
+ };
+
+ template<class mt_policy>
+ class _signal_base0 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base0<mt_policy> *> connections_list;
+
+ _signal_base0()
+ {
+ ;
+ }
+
+ _signal_base0(const _signal_base0& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ ~_signal_base0()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _signal_base1 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base1<arg1_type, mt_policy> *> connections_list;
+
+ _signal_base1()
+ {
+ ;
+ }
+
+ _signal_base1(const _signal_base1<arg1_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base1()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _signal_base2 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>
+ connections_list;
+
+ _signal_base2()
+ {
+ ;
+ }
+
+ _signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base2()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _signal_base3 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>
+ connections_list;
+
+ _signal_base3()
+ {
+ ;
+ }
+
+ _signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base3()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _signal_base4 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy> *> connections_list;
+
+ _signal_base4()
+ {
+ ;
+ }
+
+ _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base4()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _signal_base5 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy> *> connections_list;
+
+ _signal_base5()
+ {
+ ;
+ }
+
+ _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base5()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _signal_base6 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy> *> connections_list;
+
+ _signal_base6()
+ {
+ ;
+ }
+
+ _signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base6()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _signal_base7 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *> connections_list;
+
+ _signal_base7()
+ {
+ ;
+ }
+
+ _signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base7()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _signal_base8 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>
+ connections_list;
+
+ _signal_base8()
+ {
+ ;
+ }
+
+ _signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = s.m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base8()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+#if !defined(NDEBUG)
+ bool connected(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+ if ((*it)->getdest() == pclass)
+ return true;
+ it = itNext;
+ }
+ return false;
+ }
+#endif
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::iterator it = m_connected_slots.begin();
+ typename connections_list::iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ typename connections_list::iterator itNext = it;
+ ++itNext;
+
+ if((*it)->getdest() == pslot)
+ {
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+
+ template<class dest_type, class mt_policy>
+ class _connection0 : public _connection_base0<mt_policy>
+ {
+ public:
+ _connection0()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection0(dest_type* pobject, void (dest_type::*pmemfun)())
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base0<mt_policy>* clone()
+ {
+ return new _connection0<dest_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit()
+ {
+ (m_pobject->*m_pmemfun)();
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)();
+ };
+
+ template<class dest_type, class arg1_type, class mt_policy>
+ class _connection1 : public _connection_base1<arg1_type, mt_policy>
+ {
+ public:
+ _connection1()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* clone()
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1)
+ {
+ (m_pobject->*m_pmemfun)(a1);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class mt_policy>
+ class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ _connection2()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ _connection3()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class mt_policy>
+ class _connection4 : public _connection_base4<arg1_type, arg2_type,
+ arg3_type, arg4_type, mt_policy>
+ {
+ public:
+ _connection4()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3,
+ arg4_type a4)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,
+ arg4_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class mt_policy>
+ class _connection5 : public _connection_base5<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ _connection5()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone()
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class mt_policy>
+ class _connection6 : public _connection_base6<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ _connection6()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone()
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection7 : public _connection_base7<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ _connection7()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone()
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type,
+ class arg8_type, class mt_policy>
+ class _connection8 : public _connection_base8<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ _connection8()
+ {
+ m_pobject = NULL;
+ m_pmemfun = NULL;
+ }
+
+ _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type);
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal0 : public _signal_base0<mt_policy>
+ {
+ public:
+ typedef _signal_base0<mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal0()
+ {
+ ;
+ }
+
+ signal0(const signal0<mt_policy>& s)
+ : _signal_base0<mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)())
+ {
+ lock_block<mt_policy> lock(this);
+ _connection0<desttype, mt_policy>* conn =
+ new _connection0<desttype, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+
+ void operator()()
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal1 : public _signal_base1<arg1_type, mt_policy>
+ {
+ public:
+ typedef _signal_base1<arg1_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal1()
+ {
+ ;
+ }
+
+ signal1(const signal1<arg1_type, mt_policy>& s)
+ : _signal_base1<arg1_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection1<desttype, arg1_type, mt_policy>* conn =
+ new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ typedef _signal_base2<arg1_type, arg2_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal2()
+ {
+ ;
+ }
+
+ signal2(const signal2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base2<arg1_type, arg2_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ typedef _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal3()
+ {
+ ;
+ }
+
+ signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn =
+ new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,
+ pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>
+ {
+ public:
+ typedef _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal4()
+ {
+ ;
+ }
+
+ signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*
+ conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ typedef _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal5()
+ {
+ ;
+ }
+
+ signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+ };
+
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ typedef _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal6()
+ {
+ ;
+ }
+
+ signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* conn =
+ new _connection6<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ typedef _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal7()
+ {
+ ;
+ }
+
+ signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* conn =
+ new _connection7<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ typedef _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> base;
+ typedef typename base::connections_list connections_list;
+ using base::m_connected_slots;
+
+ signal8()
+ {
+ ;
+ }
+
+ signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn =
+ new _connection8<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type,
+ arg8_type, mt_policy>(pclass, pmemfun);
+ m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
+ typename connections_list::const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+ };
+
+}; // namespace sigslot
+
+#endif // TALK_BASE_SIGSLOT_H__
diff --git a/third_party/libjingle/files/talk/base/socket.h b/third_party/libjingle/files/talk/base/socket.h
new file mode 100644
index 0000000..f81bbe8
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socket.h
@@ -0,0 +1,161 @@
+/*
+ * 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 TALK_BASE_SOCKET_H__
+#define TALK_BASE_SOCKET_H__
+
+#include <errno.h>
+
+#ifdef POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#define SOCKET_EACCES EACCES
+#endif
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+#include "talk/base/basictypes.h"
+#include "talk/base/socketaddress.h"
+
+// Rather than converting errors into a private namespace,
+// Reuse the POSIX socket api errors. Note this depends on
+// Win32 compatibility.
+
+#ifdef WIN32
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#undef ETIMEDOUT // remove pthread.h's definition
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+#undef ENAMETOOLONG // remove errno.h's definition
+#define ENAMETOOLONG WSAENAMETOOLONG
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#undef ENOTEMPTY // remove errno.h's definition
+#define ENOTEMPTY WSAENOTEMPTY
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+#undef EACCES
+#define SOCKET_EACCES WSAEACCES
+#endif // WIN32
+
+#ifdef POSIX
+#define INVALID_SOCKET (-1)
+#define SOCKET_ERROR (-1)
+#define closesocket(s) close(s)
+#endif // POSIX
+
+namespace talk_base {
+
+inline bool IsBlockingError(int e) {
+ return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS);
+}
+
+// General interface for the socket implementations of various networks. The
+// methods match those of normal UNIX sockets very closely.
+class Socket {
+public:
+ virtual ~Socket() {}
+
+ // Returns the address to which the socket is bound. If the socket is not
+ // bound, then the any-address is returned.
+ virtual SocketAddress GetLocalAddress() const = 0;
+
+ // Returns the address to which the socket is connected. If the socket is
+ // not connected, then the any-address is returned.
+ virtual SocketAddress GetRemoteAddress() const = 0;
+
+ virtual int Bind(const SocketAddress& addr) = 0;
+ virtual int Connect(const SocketAddress& addr) = 0;
+ virtual int Send(const void *pv, size_t cb) = 0;
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
+ virtual int Recv(void *pv, size_t cb) = 0;
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) = 0;
+ virtual int Listen(int backlog) = 0;
+ virtual Socket *Accept(SocketAddress *paddr) = 0;
+ virtual int Close() = 0;
+ virtual int GetError() const = 0;
+ virtual void SetError(int error) = 0;
+ inline bool IsBlocking() const { return IsBlockingError(GetError()); }
+
+ enum ConnState {
+ CS_CLOSED,
+ CS_CONNECTING,
+ CS_CONNECTED
+ };
+ virtual ConnState GetState() const = 0;
+
+ // Fills in the given uint16 with the current estimate of the MTU along the
+ // path to the address to which this socket is connected.
+ virtual int EstimateMTU(uint16* mtu) = 0;
+
+ enum Option {
+ OPT_DONTFRAGMENT
+ };
+ virtual int SetOption(Option opt, int value) = 0;
+
+protected:
+ Socket() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Socket);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKET_H__
diff --git a/third_party/libjingle/files/talk/base/socketadapters.cc b/third_party/libjingle/files/talk/base/socketadapters.cc
new file mode 100644
index 0000000..bd948ed
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketadapters.cc
@@ -0,0 +1,679 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+#pragma warning(disable:4786)
+#endif
+
+#include <time.h>
+#include <errno.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#endif
+
+#include <cstring>
+
+#include "talk/base/basicdefs.h"
+#include "talk/base/bytebuffer.h"
+#include "talk/base/common.h"
+#include "talk/base/httpcommon.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketadapters.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
+
+#ifdef WIN32
+#include "talk/base/sec_buffer.h"
+#endif // WIN32
+
+namespace talk_base {
+
+BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size)
+ : AsyncSocketAdapter(socket), buffer_size_(buffer_size), data_len_(0), buffering_(false) {
+ buffer_ = new char[buffer_size_];
+}
+
+BufferedReadAdapter::~BufferedReadAdapter() {
+ delete [] buffer_;
+}
+
+int BufferedReadAdapter::Send(const void *pv, size_t cb) {
+ if (buffering_) {
+ // TODO: Spoof error better; Signal Writeable
+ socket_->SetError(EWOULDBLOCK);
+ return -1;
+ }
+ return AsyncSocketAdapter::Send(pv, cb);
+}
+
+int BufferedReadAdapter::Recv(void *pv, size_t cb) {
+ if (buffering_) {
+ socket_->SetError(EWOULDBLOCK);
+ return -1;
+ }
+
+ size_t read = 0;
+
+ if (data_len_) {
+ read = _min(cb, data_len_);
+ memcpy(pv, buffer_, read);
+ data_len_ -= read;
+ if (data_len_ > 0) {
+ memmove(buffer_, buffer_ + read, data_len_);
+ }
+ pv = static_cast<char *>(pv) + read;
+ cb -= read;
+ }
+
+ // FIX: If cb == 0, we won't generate another read event
+
+ int res = AsyncSocketAdapter::Recv(pv, cb);
+ if (res < 0)
+ return res;
+
+ return res + static_cast<int>(read);
+}
+
+void BufferedReadAdapter::BufferInput(bool on) {
+ buffering_ = on;
+}
+
+void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
+ ASSERT(socket == socket_);
+
+ if (!buffering_) {
+ AsyncSocketAdapter::OnReadEvent(socket);
+ return;
+ }
+
+ if (data_len_ >= buffer_size_) {
+ LOG(INFO) << "Input buffer overflow";
+ ASSERT(false);
+ data_len_ = 0;
+ }
+
+ int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_);
+ if (len < 0) {
+ // TODO: Do something better like forwarding the error to the user.
+ LOG(INFO) << "Recv: " << errno << " " << std::strerror(errno);
+ return;
+ }
+
+ data_len_ += len;
+
+ ProcessInput(buffer_, data_len_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const uint8 SSL_SERVER_HELLO[] = {
+ 22,3,1,0,74,2,0,0,70,3,1,66,133,69,167,39,169,93,160,
+ 179,197,231,83,218,72,43,63,198,90,202,137,193,88,82,
+ 161,120,60,91,23,70,0,133,63,32,14,211,6,114,91,91,
+ 27,95,21,172,19,249,136,83,157,155,232,61,123,12,48,
+ 50,110,56,77,162,117,87,65,108,52,92,0,4,0
+};
+
+const char SSL_CLIENT_HELLO[] = {
+ -128,70,1,3,1,0,45,0,0,0,16,1,0,-128,3,0,-128,7,0,-64,6,0,64,2,0,
+ -128,4,0,-128,0,0,4,0,-2,-1,0,0,10,0,-2,-2,0,0,9,0,0,100,0,0,98,0,
+ 0,3,0,0,6,31,23,12,-90,47,0,120,-4,70,85,46,-79,-125,57,-15,-22
+};
+
+AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) : BufferedReadAdapter(socket, 1024) {
+}
+
+int AsyncSSLSocket::Connect(const SocketAddress& addr) {
+ // Begin buffering before we connect, so that there isn't a race condition between
+ // potential senders and receiving the OnConnectEvent signal
+ BufferInput(true);
+ return BufferedReadAdapter::Connect(addr);
+}
+
+void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
+ ASSERT(socket == socket_);
+
+ // TODO: we could buffer output too...
+ int res = DirectSend(SSL_CLIENT_HELLO, sizeof(SSL_CLIENT_HELLO));
+ ASSERT(res == sizeof(SSL_CLIENT_HELLO));
+}
+
+void AsyncSSLSocket::ProcessInput(char * data, size_t& len) {
+ if (len < sizeof(SSL_SERVER_HELLO))
+ return;
+
+ if (memcmp(SSL_SERVER_HELLO, data, sizeof(SSL_SERVER_HELLO)) != 0) {
+ Close();
+ SignalCloseEvent(this, 0); // TODO: error code?
+ return;
+ }
+
+ len -= sizeof(SSL_SERVER_HELLO);
+ if (len > 0) {
+ memmove(data, data + sizeof(SSL_SERVER_HELLO), len);
+ }
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
+ const std::string& user_agent,
+ const SocketAddress& proxy,
+ const std::string& username,
+ const CryptString& password)
+ : BufferedReadAdapter(socket, 1024), proxy_(proxy), agent_(user_agent),
+ user_(username), pass_(password), state_(PS_ERROR), context_(0) {
+}
+
+AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
+ delete context_;
+}
+
+int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
+ << proxy_.ToString() << ")";
+ dest_ = addr;
+ if (dest_.port() != 80) {
+ BufferInput(true);
+ }
+ return BufferedReadAdapter::Connect(proxy_);
+}
+
+SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
+ return dest_;
+}
+
+int AsyncHttpsProxySocket::Close() {
+ headers_.clear();
+ state_ = PS_ERROR;
+ delete context_;
+ context_ = 0;
+ return BufferedReadAdapter::Close();
+}
+
+void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
+ // TODO: Decide whether tunneling or not should be explicitly set,
+ // or indicated by destination port (as below)
+ if (dest_.port() == 80) {
+ state_ = PS_TUNNEL;
+ BufferedReadAdapter::OnConnectEvent(socket);
+ return;
+ }
+ SendRequest();
+}
+
+void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
+ if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
+ state_ = PS_ERROR;
+ Connect(dest_);
+ } else {
+ BufferedReadAdapter::OnCloseEvent(socket, err);
+ }
+}
+
+void AsyncHttpsProxySocket::ProcessInput(char * data, size_t& len) {
+ size_t start = 0;
+ for (size_t pos = start; (state_ < PS_TUNNEL) && (pos < len); ) {
+ if (state_ == PS_SKIP_BODY) {
+ size_t consume = _min(len - pos, content_length_);
+ pos += consume;
+ start = pos;
+ content_length_ -= consume;
+ if (content_length_ == 0) {
+ EndResponse();
+ }
+ continue;
+ }
+
+ if (data[pos++] != '\n')
+ continue;
+
+ size_t len = pos - start - 1;
+ if ((len > 0) && (data[start + len - 1] == '\r'))
+ --len;
+
+ data[start + len] = 0;
+ ProcessLine(data + start, len);
+ start = pos;
+ }
+
+ len -= start;
+ if (len > 0) {
+ memmove(data, data + start, len);
+ }
+
+ if (state_ != PS_TUNNEL)
+ return;
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this); // TODO: signal this??
+}
+
+void AsyncHttpsProxySocket::SendRequest() {
+ std::stringstream ss;
+ ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
+ ss << "User-Agent: " << agent_ << "\r\n";
+ ss << "Host: " << dest_.IPAsString() << "\r\n";
+ ss << "Content-Length: 0\r\n";
+ ss << "Proxy-Connection: Keep-Alive\r\n";
+ ss << headers_;
+ ss << "\r\n";
+ std::string str = ss.str();
+ DirectSend(str.c_str(), str.size());
+ state_ = PS_LEADER;
+ expect_close_ = true;
+ content_length_ = 0;
+ headers_.clear();
+
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
+}
+
+void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
+ LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
+
+ if (len == 0) {
+ if (state_ == PS_TUNNEL_HEADERS) {
+ state_ = PS_TUNNEL;
+ } else if (state_ == PS_ERROR_HEADERS) {
+ Error(defer_error_);
+ return;
+ } else if (state_ == PS_SKIP_HEADERS) {
+ if (content_length_) {
+ state_ = PS_SKIP_BODY;
+ } else {
+ EndResponse();
+ return;
+ }
+ } else {
+ static bool report = false;
+ if (!unknown_mechanisms_.empty() && !report) {
+ report = true;
+ std::string msg(
+ "Unable to connect to the Google Talk service due to an incompatibility "
+ "with your proxy.\r\nPlease help us resolve this issue by submitting the "
+ "following information to us using our technical issue submission form "
+ "at:\r\n\r\n"
+ "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
+ "We apologize for the inconvenience.\r\n\r\n"
+ "Information to submit to Google: "
+ );
+ //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: ");
+ msg.append(unknown_mechanisms_);
+#ifdef WIN32
+ MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
+#endif
+#ifdef POSIX
+ //TODO: Raise a signal or something so the UI can be separated.
+ LOG(LS_ERROR) << "Oops!\n\n" << msg;
+#endif
+ }
+ // Unexpected end of headers
+ Error(0);
+ return;
+ }
+ } else if (state_ == PS_LEADER) {
+ unsigned long code;
+ if (sscanf(data, "HTTP/%*u.%*u %lu", &code) != 1) {
+ Error(0);
+ return;
+ }
+ switch (code) {
+ case 200:
+ // connection good!
+ state_ = PS_TUNNEL_HEADERS;
+ return;
+#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
+#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
+#endif
+ case 407: // HTTP_STATUS_PROXY_AUTH_REQ
+ state_ = PS_AUTHENTICATE;
+ return;
+ default:
+ defer_error_ = 0;
+ state_ = PS_ERROR_HEADERS;
+ return;
+ }
+ } else if ((state_ == PS_AUTHENTICATE)
+ && (_strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
+ std::string response, auth_method;
+ switch (HttpAuthenticate(data + 19, len - 19,
+ proxy_, "CONNECT", "/",
+ user_, pass_, context_, response, auth_method)) {
+ case HAR_IGNORE:
+ LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
+ if (!unknown_mechanisms_.empty())
+ unknown_mechanisms_.append(", ");
+ unknown_mechanisms_.append(auth_method);
+ break;
+ case HAR_RESPONSE:
+ headers_ = "Proxy-Authorization: ";
+ headers_.append(response);
+ headers_.append("\r\n");
+ state_ = PS_SKIP_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ case HAR_CREDENTIALS:
+ defer_error_ = SOCKET_EACCES;
+ state_ = PS_ERROR_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ case HAR_ERROR:
+ defer_error_ = 0;
+ state_ = PS_ERROR_HEADERS;
+ unknown_mechanisms_.clear();
+ break;
+ }
+ } else if (_strnicmp(data, "Content-Length:", 15) == 0) {
+ content_length_ = strtoul(data + 15, 0, 0);
+ } else if (_strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) {
+ expect_close_ = false;
+ /*
+ } else if (_strnicmp(data, "Connection: close", 17) == 0) {
+ expect_close_ = true;
+ */
+ }
+}
+
+void AsyncHttpsProxySocket::EndResponse() {
+ if (!expect_close_) {
+ SendRequest();
+ return;
+ }
+
+ // No point in waiting for the server to close... let's close now
+ // TODO: Refactor out PS_WAIT_CLOSE
+ state_ = PS_WAIT_CLOSE;
+ BufferedReadAdapter::Close();
+ OnCloseEvent(this, 0);
+}
+
+void AsyncHttpsProxySocket::Error(int error) {
+ BufferInput(false);
+ Close();
+ SetError(error);
+ SignalCloseEvent(this, error);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const CryptString& password)
+ : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password),
+ state_(SS_ERROR) {
+}
+
+int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
+ dest_ = addr;
+ BufferInput(true);
+ return BufferedReadAdapter::Connect(proxy_);
+}
+
+SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
+ return dest_;
+}
+
+void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket * socket) {
+ SendHello();
+}
+
+void AsyncSocksProxySocket::ProcessInput(char * data, size_t& len) {
+ ASSERT(state_ < SS_TUNNEL);
+
+ ByteBuffer response(data, len);
+
+ if (state_ == SS_HELLO) {
+ uint8 ver, method;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(method))
+ return;
+
+ if (ver != 5) {
+ Error(0);
+ return;
+ }
+
+ if (method == 0) {
+ SendConnect();
+ } else if (method == 2) {
+ SendAuth();
+ } else {
+ Error(0);
+ return;
+ }
+ } else if (state_ == SS_AUTH) {
+ uint8 ver, status;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(status))
+ return;
+
+ if ((ver != 1) || (status != 0)) {
+ Error(SOCKET_EACCES);
+ return;
+ }
+
+ SendConnect();
+ } else if (state_ == SS_CONNECT) {
+ uint8 ver, rep, rsv, atyp;
+ if (!response.ReadUInt8(ver) ||
+ !response.ReadUInt8(rep) ||
+ !response.ReadUInt8(rsv) ||
+ !response.ReadUInt8(atyp))
+ return;
+
+ if ((ver != 5) || (rep != 0)) {
+ Error(0);
+ return;
+ }
+
+ uint16 port;
+ if (atyp == 1) {
+ uint32 addr;
+ if (!response.ReadUInt32(addr) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
+ } else if (atyp == 3) {
+ uint8 len;
+ std::string addr;
+ if (!response.ReadUInt8(len) ||
+ !response.ReadString(addr, len) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
+ } else if (atyp == 4) {
+ std::string addr;
+ if (!response.ReadString(addr, 16) ||
+ !response.ReadUInt16(port))
+ return;
+ LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
+ } else {
+ Error(0);
+ return;
+ }
+
+ state_ = SS_TUNNEL;
+ }
+
+ // Consume parsed data
+ len = response.Length();
+ memcpy(data, response.Data(), len);
+
+ if (state_ != SS_TUNNEL)
+ return;
+
+ bool remainder = (len > 0);
+ BufferInput(false);
+ SignalConnectEvent(this);
+
+ // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
+ if (remainder)
+ SignalReadEvent(this); // TODO: signal this??
+}
+
+void AsyncSocksProxySocket::SendHello() {
+ ByteBuffer request;
+ request.WriteUInt8(5); // Socks Version
+ if (user_.empty()) {
+ request.WriteUInt8(1); // Authentication Mechanisms
+ request.WriteUInt8(0); // No authentication
+ } else {
+ request.WriteUInt8(2); // Authentication Mechanisms
+ request.WriteUInt8(0); // No authentication
+ request.WriteUInt8(2); // Username/Password
+ }
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_HELLO;
+}
+
+void AsyncSocksProxySocket::SendAuth() {
+ ByteBuffer request;
+ request.WriteUInt8(1); // Negotiation Version
+ request.WriteUInt8(static_cast<uint8>(user_.size()));
+ request.WriteString(user_); // Username
+ request.WriteUInt8(static_cast<uint8>(pass_.GetLength()));
+ size_t len = pass_.GetLength() + 1;
+ char * sensitive = new char[len];
+ pass_.CopyTo(sensitive, true);
+ request.WriteString(sensitive); // Password
+ memset(sensitive, 0, len);
+ delete [] sensitive;
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_AUTH;
+}
+
+void AsyncSocksProxySocket::SendConnect() {
+ ByteBuffer request;
+ request.WriteUInt8(5); // Socks Version
+ request.WriteUInt8(1); // CONNECT
+ request.WriteUInt8(0); // Reserved
+ if (dest_.IsUnresolved()) {
+ std::string hostname = dest_.IPAsString();
+ request.WriteUInt8(3); // DOMAINNAME
+ request.WriteUInt8(static_cast<uint8>(hostname.size()));
+ request.WriteString(hostname); // Destination Hostname
+ } else {
+ request.WriteUInt8(1); // IPV4
+ request.WriteUInt32(dest_.ip()); // Destination IP
+ }
+ request.WriteUInt16(dest_.port()); // Destination Port
+ DirectSend(request.Data(), request.Length());
+ state_ = SS_CONNECT;
+}
+
+void AsyncSocksProxySocket::Error(int error) {
+ state_ = SS_ERROR;
+ BufferInput(false);
+ Close();
+ SetError(SOCKET_EACCES);
+ SignalCloseEvent(this, error);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+LoggingSocketAdapter::LoggingSocketAdapter(AsyncSocket* socket,
+ LoggingSeverity level,
+ const char * label, bool hex_mode)
+: AsyncSocketAdapter(socket), level_(level), hex_mode_(hex_mode)
+{
+ label_.append("[");
+ label_.append(label);
+ label_.append("]");
+}
+
+int
+LoggingSocketAdapter::Send(const void *pv, size_t cb) {
+ int res = AsyncSocketAdapter::Send(pv, cb);
+ if (res > 0)
+ LogMultiline(level_, label_.c_str(), false,
+ static_cast<const char *>(pv), res, hex_mode_, &lms_);
+ return res;
+}
+
+int
+LoggingSocketAdapter::SendTo(const void *pv, size_t cb,
+ const SocketAddress& addr) {
+ int res = AsyncSocketAdapter::SendTo(pv, cb, addr);
+ if (res > 0)
+ LogMultiline(level_, label_.c_str(), false,
+ static_cast<const char *>(pv), res, hex_mode_, &lms_);
+ return res;
+}
+
+int
+LoggingSocketAdapter::Recv(void *pv, size_t cb) {
+ int res = AsyncSocketAdapter::Recv(pv, cb);
+ if (res > 0)
+ LogMultiline(level_, label_.c_str(), true,
+ static_cast<const char *>(pv), res, hex_mode_, &lms_);
+ return res;
+}
+
+int
+LoggingSocketAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
+ if (res > 0)
+ LogMultiline(level_, label_.c_str(), true,
+ static_cast<const char *>(pv), res, hex_mode_, &lms_);
+ return res;
+}
+
+void
+LoggingSocketAdapter::OnConnectEvent(AsyncSocket * socket) {
+ LOG_V(level_) << label_ << " Connected";
+ AsyncSocketAdapter::OnConnectEvent(socket);
+}
+
+void
+LoggingSocketAdapter::OnCloseEvent(AsyncSocket * socket, int err) {
+ LOG_V(level_) << label_ << " Closed with error: " << err;
+ AsyncSocketAdapter::OnCloseEvent(socket, err);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/socketadapters.h b/third_party/libjingle/files/talk/base/socketadapters.h
new file mode 100644
index 0000000..6cd6a8f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketadapters.h
@@ -0,0 +1,170 @@
+/*
+ * 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 TALK_BASE_SOCKETADAPTERS_H__
+#define TALK_BASE_SOCKETADAPTERS_H__
+
+#include <map>
+#include <string>
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/cryptstring.h"
+#include "talk/base/logging.h"
+
+namespace talk_base {
+
+struct HttpAuthContext;
+
+///////////////////////////////////////////////////////////////////////////////
+
+class BufferedReadAdapter : public AsyncSocketAdapter {
+public:
+ BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size);
+ virtual ~BufferedReadAdapter();
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int Recv(void *pv, size_t cb);
+
+protected:
+ int DirectSend(const void *pv, size_t cb) { return AsyncSocketAdapter::Send(pv, cb); }
+
+ void BufferInput(bool on = true);
+ virtual void ProcessInput(char * data, size_t& len) = 0;
+
+ virtual void OnReadEvent(AsyncSocket * socket);
+
+private:
+ char * buffer_;
+ size_t buffer_size_, data_len_;
+ bool buffering_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncSSLSocket : public BufferedReadAdapter {
+public:
+ AsyncSSLSocket(AsyncSocket* socket);
+
+ virtual int Connect(const SocketAddress& addr);
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void ProcessInput(char * data, size_t& len);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncHttpsProxySocket : public BufferedReadAdapter {
+public:
+ AsyncHttpsProxySocket(AsyncSocket* socket, const std::string& user_agent,
+ const SocketAddress& proxy,
+ const std::string& username, const CryptString& password);
+ virtual ~AsyncHttpsProxySocket();
+
+ virtual int Connect(const SocketAddress& addr);
+ virtual SocketAddress GetRemoteAddress() const;
+ virtual int Close();
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void OnCloseEvent(AsyncSocket * socket, int err);
+ virtual void ProcessInput(char * data, size_t& len);
+
+ void SendRequest();
+ void ProcessLine(char * data, size_t len);
+ void EndResponse();
+ void Error(int error);
+
+private:
+ SocketAddress proxy_, dest_;
+ std::string agent_, user_, headers_;
+ CryptString pass_;
+ size_t content_length_;
+ int defer_error_;
+ bool expect_close_;
+ enum ProxyState {
+ PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS,
+ PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR
+ } state_;
+ HttpAuthContext * context_;
+ std::string unknown_mechanisms_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AsyncSocksProxySocket : public BufferedReadAdapter {
+public:
+ AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
+ const std::string& username, const CryptString& password);
+
+ virtual int Connect(const SocketAddress& addr);
+ virtual SocketAddress GetRemoteAddress() const;
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void ProcessInput(char * data, size_t& len);
+
+ void SendHello();
+ void SendConnect();
+ void SendAuth();
+ void Error(int error);
+
+private:
+ SocketAddress proxy_, dest_;
+ std::string user_;
+ CryptString pass_;
+ enum SocksState { SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR } state_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class LoggingSocketAdapter : public AsyncSocketAdapter {
+public:
+ LoggingSocketAdapter(AsyncSocket* socket, LoggingSeverity level,
+ const char * label, bool hex_mode = false);
+
+ virtual int Send(const void *pv, size_t cb);
+ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+ virtual int Recv(void *pv, size_t cb);
+ virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr);
+
+protected:
+ virtual void OnConnectEvent(AsyncSocket * socket);
+ virtual void OnCloseEvent(AsyncSocket * socket, int err);
+
+private:
+ LoggingSeverity level_;
+ std::string label_;
+ bool hex_mode_;
+ LogMultilineState lms_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETADAPTERS_H__
diff --git a/third_party/libjingle/files/talk/base/socketaddress.cc b/third_party/libjingle/files/talk/base/socketaddress.cc
new file mode 100644
index 0000000..a6f0dd8
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketaddress.cc
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+#ifdef POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include <cstring>
+#include <sstream>
+
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketaddress.h"
+
+#ifdef WIN32
+#undef SetPort
+int inet_aton(const char * cp, struct in_addr * inp) {
+ inp->s_addr = inet_addr(cp);
+ return (inp->s_addr == INADDR_NONE) ? 0 : 1;
+}
+#endif // WIN32
+
+#if !defined(NDEBUG)
+#define DISABLE_DNS 0
+#else // defined(NDEBUG)
+#define DISABLE_DNS 0
+#endif // !defined(NDEBUG)
+
+namespace talk_base {
+
+SocketAddress::SocketAddress() {
+ Clear();
+}
+
+SocketAddress::SocketAddress(const std::string& hostname, int port, bool use_dns) {
+ SetIP(hostname, use_dns);
+ SetPort(port);
+}
+
+SocketAddress::SocketAddress(uint32 ip, int port) {
+ SetIP(ip);
+ SetPort(port);
+}
+
+SocketAddress::SocketAddress(const SocketAddress& addr) {
+ this->operator=(addr);
+}
+
+void SocketAddress::Clear() {
+ hostname_.clear();
+ ip_ = 0;
+ port_ = 0;
+}
+
+SocketAddress& SocketAddress::operator=(const SocketAddress& addr) {
+ hostname_ = addr.hostname_;
+ ip_ = addr.ip_;
+ port_ = addr.port_;
+ return *this;
+}
+
+void SocketAddress::SetIP(uint32 ip) {
+ hostname_.clear();
+ ip_ = ip;
+}
+
+bool SocketAddress::SetIP(const std::string& hostname, bool use_dns) {
+ hostname_ = hostname;
+ ip_ = 0;
+ return Resolve(true, use_dns);
+}
+
+void SocketAddress::SetResolvedIP(uint32 ip) {
+ ip_ = ip;
+}
+
+void SocketAddress::SetPort(int port) {
+ ASSERT((0 <= port) && (port < 65536));
+ port_ = port;
+}
+
+uint32 SocketAddress::ip() const {
+ return ip_;
+}
+
+uint16 SocketAddress::port() const {
+ return port_;
+}
+
+std::string SocketAddress::IPAsString() const {
+ if (!hostname_.empty())
+ return hostname_;
+ return IPToString(ip_);
+}
+
+std::string SocketAddress::PortAsString() const {
+ std::ostringstream ost;
+ ost << port_;
+ return ost.str();
+}
+
+std::string SocketAddress::ToString() const {
+ std::ostringstream ost;
+ ost << IPAsString();
+ ost << ":";
+ ost << port();
+ return ost.str();
+}
+
+bool SocketAddress::IsAny() const {
+ return (ip_ == 0);
+}
+
+bool SocketAddress::IsLocalIP() const {
+ return (ip_ >> 24) == 127;
+}
+
+bool SocketAddress::IsPrivateIP() const {
+ return ((ip_ >> 24) == 127) ||
+ ((ip_ >> 24) == 10) ||
+ ((ip_ >> 20) == ((172 << 4) | 1)) ||
+ ((ip_ >> 16) == ((192 << 8) | 168));
+}
+
+bool SocketAddress::IsUnresolved() const {
+ return IsAny() && !hostname_.empty();
+}
+
+bool SocketAddress::Resolve(bool force, bool use_dns) {
+ if (hostname_.empty()) {
+ // nothing to resolve
+ } else if (!force && !IsAny()) {
+ // already resolved
+ } else if (uint32 ip = StringToIP(hostname_, use_dns)) {
+ ip_ = ip;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool SocketAddress::operator ==(const SocketAddress& addr) const {
+ return EqualIPs(addr) && EqualPorts(addr);
+}
+
+bool SocketAddress::operator <(const SocketAddress& addr) const {
+ if (ip_ < addr.ip_)
+ return true;
+ else if (addr.ip_ < ip_)
+ return false;
+
+ // We only check hostnames if both IPs are zero. This matches EqualIPs()
+ if (addr.ip_ == 0) {
+ if (hostname_ < addr.hostname_)
+ return true;
+ else if (addr.hostname_ < hostname_)
+ return false;
+ }
+
+ return port_ < addr.port_;
+}
+
+bool SocketAddress::EqualIPs(const SocketAddress& addr) const {
+ return (ip_ == addr.ip_) && ((ip_ != 0) || (hostname_ == addr.hostname_));
+}
+
+bool SocketAddress::EqualPorts(const SocketAddress& addr) const {
+ return (port_ == addr.port_);
+}
+
+size_t SocketAddress::Hash() const {
+ size_t h = 0;
+ h ^= ip_;
+ h ^= port_ | (port_ << 16);
+ return h;
+}
+
+size_t SocketAddress::Size_() const {
+ return sizeof(ip_) + sizeof(port_);
+}
+
+void SocketAddress::Write_(char* buf, int len) const {
+ // TODO: Depending on how this is used, we may want/need to write hostname
+ ASSERT((size_t)len >= Size_());
+ reinterpret_cast<uint32*>(buf)[0] = ip_;
+ buf += sizeof(ip_);
+ reinterpret_cast<uint16*>(buf)[0] = port_;
+}
+
+void SocketAddress::Read_(const char* buf, int len) {
+ ASSERT((size_t)len >= Size_());
+ ip_ = reinterpret_cast<const uint32*>(buf)[0];
+ buf += sizeof(ip_);
+ port_ = reinterpret_cast<const uint16*>(buf)[0];
+}
+
+void SocketAddress::ToSockAddr(sockaddr_in* saddr) const {
+ memset(saddr, 0, sizeof(*saddr));
+ saddr->sin_family = AF_INET;
+ saddr->sin_port = HostToNetwork16(port_);
+ if (0 == ip_) {
+ saddr->sin_addr.s_addr = INADDR_ANY;
+ } else {
+ saddr->sin_addr.s_addr = HostToNetwork32(ip_);
+ }
+}
+
+void SocketAddress::FromSockAddr(const sockaddr_in& saddr) {
+ SetIP(NetworkToHost32(saddr.sin_addr.s_addr));
+ SetPort(NetworkToHost16(saddr.sin_port));
+}
+
+std::string SocketAddress::IPToString(uint32 ip) {
+ std::ostringstream ost;
+ ost << ((ip >> 24) & 0xff);
+ ost << '.';
+ ost << ((ip >> 16) & 0xff);
+ ost << '.';
+ ost << ((ip >> 8) & 0xff);
+ ost << '.';
+ ost << ((ip >> 0) & 0xff);
+ return ost.str();
+}
+
+uint32 SocketAddress::StringToIP(const std::string& hostname, bool use_dns) {
+ uint32 ip = 0;
+ in_addr addr;
+ if (inet_aton(hostname.c_str(), &addr) != 0) {
+ ip = NetworkToHost32(addr.s_addr);
+ } else if (use_dns) {
+ // Note: this is here so we can spot spurious DNS resolutions for a while
+ LOG(INFO) << "=== DNS RESOLUTION (" << hostname << ") ===";
+#if DISABLE_DNS
+ LOG(WARNING) << "*** DNS DISABLED ***";
+#if WIN32
+ WSASetLastError(WSAHOST_NOT_FOUND);
+#endif // WIN32
+#endif // DISABLE_DNS
+ if (hostent * pHost = gethostbyname(hostname.c_str())) {
+ ip = NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[0]));
+ } else {
+#if WIN32
+ LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError();
+#else
+ LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno);
+#endif
+ }
+ LOG(INFO) << hostname << " resolved to " << IPToString(ip);
+ }
+ return ip;
+}
+
+std::string SocketAddress::GetHostname() {
+ char hostname[256];
+ if (gethostname(hostname, ARRAY_SIZE(hostname)) == 0)
+ return hostname;
+ return "";
+}
+
+bool SocketAddress::GetLocalIPs(std::vector<uint32>& ips) {
+ ips.clear();
+
+ const std::string hostname = GetHostname();
+ if (hostname.empty())
+ return false;
+
+ if (hostent * pHost = gethostbyname(hostname.c_str())) {
+ for (size_t i=0; pHost->h_addr_list[i]; ++i) {
+ uint32 ip =
+ NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[i]));
+ ips.push_back(ip);
+ }
+ return !ips.empty();
+ }
+#if WIN32
+ LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError();
+#else
+ LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno);
+#endif
+ return false;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/socketaddress.h b/third_party/libjingle/files/talk/base/socketaddress.h
new file mode 100644
index 0000000..7fdc22f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketaddress.h
@@ -0,0 +1,174 @@
+/*
+ * 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 TALK_BASE_SOCKETADDRESS_H__
+#define TALK_BASE_SOCKETADDRESS_H__
+
+#include <string>
+#include <vector>
+#include "talk/base/basictypes.h"
+struct sockaddr_in;
+
+#undef SetPort
+
+namespace talk_base {
+
+// Records an IP address and port, which are 32 and 16 bit integers,
+// respectively, both in <b>host byte-order</b>.
+class SocketAddress {
+public:
+ // Creates a missing / unknown address.
+ SocketAddress();
+
+ // Creates the address with the given host and port. If use_dns is true,
+ // the hostname will be immediately resolved to an IP (which may block for
+ // several seconds if DNS is not available). Alternately, set use_dns to
+ // false, and then call Resolve() to complete resolution later, or use
+ // SetResolvedIP to set the IP explictly.
+ SocketAddress(const std::string& hostname, int port = 0, bool use_dns = true);
+
+ // Creates the address with the given IP and port.
+ SocketAddress(uint32 ip, int port);
+
+ // Creates a copy of the given address.
+ SocketAddress(const SocketAddress& addr);
+
+ // Resets to missing / unknown address.
+ void Clear();
+
+ // Replaces our address with the given one.
+ SocketAddress& operator =(const SocketAddress& addr);
+
+ // Changes the IP of this address to the given one, and clears the hostname.
+ void SetIP(uint32 ip);
+
+ // Changes the hostname of this address to the given one.
+ // Calls Resolve and returns the result.
+ bool SetIP(const std::string& hostname, bool use_dns = true);
+
+ // Sets the IP address while retaining the hostname. Useful for bypassing
+ // DNS for a pre-resolved IP.
+ void SetResolvedIP(uint32 ip);
+
+ // Changes the port of this address to the given one.
+ void SetPort(int port);
+
+ // Returns the IP address.
+ uint32 ip() const;
+
+ // Returns the port part of this address.
+ uint16 port() const;
+
+ // Returns the hostname
+ const std::string& hostname() const { return hostname_; };
+
+ // Returns the IP address in dotted form.
+ std::string IPAsString() const;
+
+ // Returns the port as a string
+ std::string PortAsString() const;
+
+ // Returns a display version of the IP/port.
+ std::string ToString() const;
+
+ // Determines whether this represents a missing / any address.
+ bool IsAny() const;
+
+ // Synomym for missing / any.
+ bool IsNil() const { return IsAny(); }
+
+ // Determines whether the IP address refers to the local host, i.e. within
+ // the range 127.0.0.0/8.
+ bool IsLocalIP() const;
+
+ // Determines whether the IP address is in one of the private ranges:
+ // 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12.
+ bool IsPrivateIP() const;
+
+ // Determines whether the hostname has been resolved to an IP
+ bool IsUnresolved() const;
+
+ // Attempt to resolve a hostname to IP address.
+ // Returns false if resolution is required but failed.
+ // 'force' will cause re-resolution of hostname.
+ //
+ bool Resolve(bool force = false, bool use_dns = true);
+
+ // Determines whether this address is identical to the given one.
+ bool operator ==(const SocketAddress& addr) const;
+
+ inline bool operator !=(const SocketAddress& addr) const {
+ return !this->operator ==(addr);
+ }
+
+ // Compares based on IP and then port.
+ bool operator <(const SocketAddress& addr) const;
+
+ // Determines whether this address has the same IP as the one given.
+ bool EqualIPs(const SocketAddress& addr) const;
+
+ // Deteremines whether this address has the same port as the one given.
+ bool EqualPorts(const SocketAddress& addr) const;
+
+ // Hashes this address into a small number.
+ size_t Hash() const;
+
+ // Returns the size of this address when written.
+ size_t Size_() const;
+
+ // Writes this address into the given buffer.
+ void Write_(char* buf, int len) const;
+
+ // Reads this address from the given buffer.
+ void Read_(const char* buf, int len);
+
+ // Convert to and from sockaddr_in
+ void ToSockAddr(sockaddr_in* saddr) const;
+ void FromSockAddr(const sockaddr_in& saddr);
+
+ // Converts the IP address given in compact form into dotted form.
+ static std::string IPToString(uint32 ip);
+
+ // Converts the IP address given in dotted form into compact form.
+ // Without 'use_dns', only dotted names (A.B.C.D) are resolved.
+ static uint32 StringToIP(const std::string& str, bool use_dns = true);
+
+ // Get local machine's hostname
+ static std::string GetHostname();
+
+ // Get a list of the local machine's ip addresses
+ static bool GetLocalIPs(std::vector<uint32>& ips);
+
+private:
+ std::string hostname_;
+ uint32 ip_;
+ uint16 port_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETADDRESS_H__
diff --git a/third_party/libjingle/files/talk/base/socketaddresspair.cc b/third_party/libjingle/files/talk/base/socketaddresspair.cc
new file mode 100644
index 0000000..7f190a9
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketaddresspair.cc
@@ -0,0 +1,58 @@
+/*
+ * 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/base/socketaddresspair.h"
+
+namespace talk_base {
+
+SocketAddressPair::SocketAddressPair(
+ const SocketAddress& src, const SocketAddress& dest)
+ : src_(src), dest_(dest) {
+}
+
+
+bool SocketAddressPair::operator ==(const SocketAddressPair& p) const {
+ return (src_ == p.src_) && (dest_ == p.dest_);
+}
+
+bool SocketAddressPair::operator <(const SocketAddressPair& p) const {
+ if (src_ < p.src_)
+ return true;
+ if (p.src_ < src_)
+ return false;
+ if (dest_ < p.dest_)
+ return true;
+ if (p.dest_ < dest_)
+ return false;
+ return false;
+}
+
+size_t SocketAddressPair::Hash() const {
+ return src_.Hash() ^ dest_.Hash();
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/socketaddresspair.h b/third_party/libjingle/files/talk/base/socketaddresspair.h
new file mode 100644
index 0000000..10f5d304
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketaddresspair.h
@@ -0,0 +1,58 @@
+/*
+ * 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 TALK_BASE_SOCKETADDRESSPAIR_H__
+#define TALK_BASE_SOCKETADDRESSPAIR_H__
+
+#include "talk/base/socketaddress.h"
+
+namespace talk_base {
+
+// Records a pair (source,destination) of socket addresses. The two addresses
+// identify a connection between two machines. (For UDP, this "connection" is
+// not maintained explicitly in a socket.)
+class SocketAddressPair {
+public:
+ SocketAddressPair() {}
+ SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest);
+
+ const SocketAddress& source() const { return src_; }
+ const SocketAddress& destination() const { return dest_; }
+
+ bool operator ==(const SocketAddressPair& r) const;
+ bool operator <(const SocketAddressPair& r) const;
+
+ size_t Hash() const;
+
+private:
+ SocketAddress src_;
+ SocketAddress dest_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETADDRESSPAIR_H__
diff --git a/third_party/libjingle/files/talk/base/socketfactory.h b/third_party/libjingle/files/talk/base/socketfactory.h
new file mode 100644
index 0000000..fd12375
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketfactory.h
@@ -0,0 +1,57 @@
+/*
+ * 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 TALK_BASE_SOCKETFACTORY_H__
+#define TALK_BASE_SOCKETFACTORY_H__
+
+#include "talk/base/socket.h"
+#include "talk/base/asyncsocket.h"
+#include "talk/base/ssladapter.h"
+
+namespace talk_base {
+
+class SocketFactory {
+public:
+ virtual ~SocketFactory() {}
+
+ // Returns a new socket for blocking communication. The type can be
+ // SOCK_DGRAM and SOCK_STREAM.
+ virtual Socket* CreateSocket(int type) = 0;
+
+ // Returns a new socket for nonblocking communication. The type can be
+ // SOCK_DGRAM and SOCK_STREAM.
+ virtual AsyncSocket* CreateAsyncSocket(int type) = 0;
+
+ // Wraps the given socket in an SSL adapter.
+ virtual SSLAdapter* CreateSSLAdapter(AsyncSocket* socket) {
+ return SSLAdapter::Create(socket);
+ }
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETFACTORY_H__
diff --git a/third_party/libjingle/files/talk/base/socketpool.cc b/third_party/libjingle/files/talk/base/socketpool.cc
new file mode 100644
index 0000000..b90b2c9
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketpool.cc
@@ -0,0 +1,261 @@
+/*
+ * 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 <errno.h>
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketfactory.h"
+#include "talk/base/socketpool.h"
+#include "talk/base/socketstream.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamCache - Caches a set of open streams, defers creation to a separate
+// StreamPool.
+///////////////////////////////////////////////////////////////////////////////
+
+StreamCache::StreamCache(StreamPool* pool) : pool_(pool) {
+}
+
+StreamCache::~StreamCache() {
+ for (ConnectedList::iterator it = active_.begin(); it != active_.end();
+ ++it) {
+ delete it->second;
+ }
+ for (ConnectedList::iterator it = cached_.begin(); it != cached_.end();
+ ++it) {
+ delete it->second;
+ }
+}
+
+StreamInterface* StreamCache::RequestConnectedStream(
+ const SocketAddress& remote, int* err) {
+ LOG_F(LS_VERBOSE) << "(" << remote.ToString() << ")";
+ for (ConnectedList::iterator it = cached_.begin(); it != cached_.end();
+ ++it) {
+ if (remote == it->first) {
+ it->second->SignalEvent.disconnect(this);
+ // Move from cached_ to active_
+ active_.push_front(*it);
+ cached_.erase(it);
+ if (err)
+ *err = 0;
+ LOG_F(LS_VERBOSE) << "Providing cached stream";
+ return active_.front().second;
+ }
+ }
+ if (StreamInterface* stream = pool_->RequestConnectedStream(remote, err)) {
+ // We track active streams so that we can remember their address
+ active_.push_front(ConnectedStream(remote, stream));
+ LOG_F(LS_VERBOSE) << "Providing new stream";
+ return active_.front().second;
+ }
+ return NULL;
+}
+
+void StreamCache::ReturnConnectedStream(StreamInterface* stream) {
+ for (ConnectedList::iterator it = active_.begin(); it != active_.end();
+ ++it) {
+ if (stream == it->second) {
+ LOG_F(LS_VERBOSE) << "(" << it->first.ToString() << ")";
+ if (stream->GetState() == SS_CLOSED) {
+ // Return closed streams
+ LOG_F(LS_VERBOSE) << "Returning closed stream";
+ pool_->ReturnConnectedStream(it->second);
+ } else {
+ // Monitor open streams
+ stream->SignalEvent.connect(this, &StreamCache::OnStreamEvent);
+ LOG_F(LS_VERBOSE) << "Caching stream";
+ cached_.push_front(*it);
+ }
+ active_.erase(it);
+ return;
+ }
+ }
+ ASSERT(false);
+}
+
+void StreamCache::OnStreamEvent(StreamInterface* stream, int events, int err) {
+ if ((events & SE_CLOSE) == 0) {
+ LOG_F(LS_WARNING) << "(" << events << ", " << err
+ << ") received non-close event";
+ return;
+ }
+ for (ConnectedList::iterator it = cached_.begin(); it != cached_.end();
+ ++it) {
+ if (stream == it->second) {
+ LOG_F(LS_VERBOSE) << "(" << it->first.ToString() << ")";
+ // We don't cache closed streams, so return it.
+ it->second->SignalEvent.disconnect(this);
+ LOG_F(LS_VERBOSE) << "Returning closed stream";
+ pool_->ReturnConnectedStream(it->second);
+ cached_.erase(it);
+ return;
+ }
+ }
+ ASSERT(false);
+}
+
+//////////////////////////////////////////////////////////////////////
+// NewSocketPool
+//////////////////////////////////////////////////////////////////////
+
+NewSocketPool::NewSocketPool(SocketFactory* factory) : factory_(factory) {
+}
+
+NewSocketPool::~NewSocketPool() {
+ for (size_t i = 0; i < used_.size(); ++i) {
+ delete used_[i];
+ }
+}
+
+StreamInterface*
+NewSocketPool::RequestConnectedStream(const SocketAddress& remote, int* err) {
+ AsyncSocket* socket = factory_->CreateAsyncSocket(SOCK_STREAM);
+ if (!socket) {
+ if (err)
+ *err = -1;
+ return NULL;
+ }
+ if ((socket->Connect(remote) != 0) && !socket->IsBlocking()) {
+ if (err)
+ *err = socket->GetError();
+ delete socket;
+ return NULL;
+ }
+ if (err)
+ *err = 0;
+ return new SocketStream(socket);
+}
+
+void
+NewSocketPool::ReturnConnectedStream(StreamInterface* stream) {
+ used_.push_back(stream);
+}
+
+//////////////////////////////////////////////////////////////////////
+// ReuseSocketPool
+//////////////////////////////////////////////////////////////////////
+
+ReuseSocketPool::ReuseSocketPool(SocketFactory* factory, AsyncSocket* socket)
+ : factory_(factory), stream_(NULL) {
+ stream_ = socket ? new SocketStream(socket) : NULL;
+}
+
+ReuseSocketPool::~ReuseSocketPool() {
+ delete stream_;
+}
+
+void
+ReuseSocketPool::setSocket(AsyncSocket* socket) {
+ ASSERT(false); // TODO: need ref-counting to make this work
+ delete stream_;
+ stream_ = socket ? new SocketStream(socket) : NULL;
+}
+
+StreamInterface*
+ReuseSocketPool::RequestConnectedStream(const SocketAddress& remote, int* err) {
+ if (!stream_) {
+ LOG(LS_INFO) << "ReuseSocketPool - Creating new socket";
+ AsyncSocket* socket = factory_->CreateAsyncSocket(SOCK_STREAM);
+ if (!socket) {
+ if (err)
+ *err = -1;
+ return NULL;
+ }
+ stream_ = new SocketStream(socket);
+ }
+ if ((stream_->GetState() == SS_OPEN) &&
+ (stream_->GetSocket()->GetRemoteAddress() == remote)) {
+ LOG(LS_INFO) << "ReuseSocketPool - Reusing connection to: "
+ << remote.ToString();
+ } else {
+ stream_->Close();
+ if ((stream_->GetSocket()->Connect(remote) != 0)
+ && !stream_->GetSocket()->IsBlocking()) {
+ if (err)
+ *err = stream_->GetSocket()->GetError();
+ return NULL;
+ } else {
+ LOG(LS_INFO) << "ReuseSocketPool - Opening connection to: "
+ << remote.ToString();
+ }
+ }
+ if (err)
+ *err = 0;
+ return stream_;
+}
+
+void
+ReuseSocketPool::ReturnConnectedStream(StreamInterface* stream) {
+ // Note: this might not be true with the advent of setSocket
+ ASSERT(stream == stream_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// LoggingPoolAdapter - Adapts a StreamPool to supply streams with attached
+// LoggingAdapters.
+///////////////////////////////////////////////////////////////////////////////
+
+LoggingPoolAdapter::LoggingPoolAdapter(
+ StreamPool* pool, LoggingSeverity level, const std::string& label,
+ bool binary_mode)
+ : pool_(pool), level_(level), label_(label), binary_mode_(binary_mode) {
+}
+
+LoggingPoolAdapter::~LoggingPoolAdapter() {
+ for (StreamList::iterator it = recycle_bin_.begin();
+ it != recycle_bin_.end(); ++it) {
+ delete *it;
+ }
+}
+
+StreamInterface* LoggingPoolAdapter::RequestConnectedStream(
+ const SocketAddress& remote, int* err) {
+ if (StreamInterface* stream = pool_->RequestConnectedStream(remote, err)) {
+ if (recycle_bin_.empty()) {
+ return new LoggingAdapter(stream, level_, label_, binary_mode_);
+ }
+ LoggingAdapter* logging = recycle_bin_.front();
+ recycle_bin_.pop_front();
+ logging->Attach(stream);
+ return logging;
+ }
+ return NULL;
+}
+
+void LoggingPoolAdapter::ReturnConnectedStream(StreamInterface* stream) {
+ LoggingAdapter* logging = static_cast<LoggingAdapter*>(stream);
+ pool_->ReturnConnectedStream(logging->Detach());
+ recycle_bin_.push_back(logging);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/socketpool.h b/third_party/libjingle/files/talk/base/socketpool.h
new file mode 100644
index 0000000..edeebaa
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketpool.h
@@ -0,0 +1,161 @@
+/*
+ * 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 TALK_BASE_SOCKETPOOL_H__
+#define TALK_BASE_SOCKETPOOL_H__
+
+#include <deque>
+#include <vector>
+#include "talk/base/logging.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+class AsyncSocket;
+class LoggingAdapter;
+class SocketAddress;
+class SocketFactory;
+class SocketStream;
+class StreamInterface;
+
+//////////////////////////////////////////////////////////////////////
+// StreamPool
+//////////////////////////////////////////////////////////////////////
+
+class StreamPool {
+public:
+ virtual ~StreamPool() { }
+
+ virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote,
+ int* err) = 0;
+ virtual void ReturnConnectedStream(StreamInterface* stream) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamCache - Caches a set of open streams, defers creation/destruction to
+// the supplied StreamPool.
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamCache : public StreamPool, public sigslot::has_slots<> {
+public:
+ StreamCache(StreamPool* pool);
+ virtual ~StreamCache();
+
+ // StreamPool Interface
+ virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote,
+ int* err);
+ virtual void ReturnConnectedStream(StreamInterface* stream);
+
+private:
+ typedef std::pair<SocketAddress, StreamInterface*> ConnectedStream;
+ typedef std::list<ConnectedStream> ConnectedList;
+
+ void OnStreamEvent(StreamInterface* stream, int events, int err);
+
+ // We delegate stream creation and deletion to this pool.
+ StreamPool* pool_;
+ // Streams that are in use (returned from RequestConnectedStream).
+ ConnectedList active_;
+ // Streams which were returned to us, but are still open.
+ ConnectedList cached_;
+};
+
+//////////////////////////////////////////////////////////////////////
+// NewSocketPool //
+///////////////////
+// Creates a new PTcpSocket every time
+//////////////////////////////////////////////////////////////////////
+
+class NewSocketPool : public StreamPool {
+public:
+ NewSocketPool(SocketFactory* factory);
+ virtual ~NewSocketPool();
+
+ // StreamPool Interface
+ virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote,
+ int* err);
+ virtual void ReturnConnectedStream(StreamInterface* stream);
+
+private:
+ SocketFactory* factory_;
+ std::vector<StreamInterface*> used_;
+};
+
+//////////////////////////////////////////////////////////////////////
+// ReuseSocketPool //
+/////////////////////
+// Pass a PTcpSocket chain to the constructor, and if the connection
+// is still open, it will be reused.
+//////////////////////////////////////////////////////////////////////
+
+class ReuseSocketPool : public StreamPool {
+public:
+ ReuseSocketPool(SocketFactory* factory, AsyncSocket* socket = 0);
+ virtual ~ReuseSocketPool();
+
+ void setSocket(AsyncSocket* socket);
+
+ // StreamPool Interface
+ virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote,
+ int* err);
+ virtual void ReturnConnectedStream(StreamInterface* stream);
+
+private:
+ SocketFactory* factory_;
+ SocketStream* stream_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// LoggingPoolAdapter - Adapts a StreamPool to supply streams with attached
+// LoggingAdapters.
+///////////////////////////////////////////////////////////////////////////////
+
+class LoggingPoolAdapter : public StreamPool {
+public:
+ LoggingPoolAdapter(StreamPool* pool, LoggingSeverity level,
+ const std::string& label, bool binary_mode);
+ virtual ~LoggingPoolAdapter();
+
+ // StreamPool Interface
+ virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote,
+ int* err);
+ virtual void ReturnConnectedStream(StreamInterface* stream);
+
+private:
+ StreamPool* pool_;
+ LoggingSeverity level_;
+ std::string label_;
+ bool binary_mode_;
+ typedef std::deque<LoggingAdapter*> StreamList;
+ StreamList recycle_bin_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETPOOL_H__
diff --git a/third_party/libjingle/files/talk/base/socketserver.h b/third_party/libjingle/files/talk/base/socketserver.h
new file mode 100644
index 0000000..e06dd6b
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketserver.h
@@ -0,0 +1,57 @@
+/*
+ * 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 TALK_BASE_SOCKETSERVER_H__
+#define TALK_BASE_SOCKETSERVER_H__
+
+#include "talk/base/socketfactory.h"
+
+namespace talk_base {
+
+const int kForever = -1;
+
+// Provides the ability to wait for activity on a set of sockets. The Thread
+// class provides a nice wrapper on a socket server.
+//
+// The server is also a socket factory. The sockets it creates will be
+// notified of asynchronous I/O from this server's Wait method.
+class SocketServer : public SocketFactory {
+public:
+
+ // Sleeps until:
+ // 1) cms milliseconds have elapsed (unless cms == kForever)
+ // 2) WakeUp() is called
+ // While sleeping, I/O is performed if process_io is true.
+ virtual bool Wait(int cms, bool process_io) = 0;
+
+ // Causes the current wait (if one is in progress) to wake up.
+ virtual void WakeUp() = 0;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKETSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/socketstream.h b/third_party/libjingle/files/talk/base/socketstream.h
new file mode 100644
index 0000000..4d56b75
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/socketstream.h
@@ -0,0 +1,153 @@
+/*
+ * 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 TALK_BASE_SOCKET_STREAM_H__
+#define TALK_BASE_SOCKET_STREAM_H__
+
+#include "talk/base/asyncsocket.h"
+#include "talk/base/common.h"
+#include "talk/base/stream.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SocketStream : public StreamInterface, public sigslot::has_slots<> {
+ public:
+ SocketStream(AsyncSocket* socket) : socket_(NULL) {
+ Attach(socket);
+ }
+ virtual ~SocketStream() { delete socket_; }
+
+ void Attach(AsyncSocket* socket) {
+ if (socket_)
+ delete socket_;
+ socket_ = socket;
+ if (socket_) {
+ socket_->SignalConnectEvent.connect(this, &SocketStream::OnConnectEvent);
+ socket_->SignalReadEvent.connect(this, &SocketStream::OnReadEvent);
+ socket_->SignalWriteEvent.connect(this, &SocketStream::OnWriteEvent);
+ socket_->SignalCloseEvent.connect(this, &SocketStream::OnCloseEvent);
+ }
+ }
+
+ AsyncSocket* Detach() {
+ AsyncSocket* socket = socket_;
+ if (socket_) {
+ socket_->SignalConnectEvent.disconnect(this);
+ socket_->SignalReadEvent.disconnect(this);
+ socket_->SignalWriteEvent.disconnect(this);
+ socket_->SignalCloseEvent.disconnect(this);
+ socket_ = NULL;
+ }
+ return socket;
+ }
+
+ AsyncSocket* GetSocket() { return socket_; }
+
+ virtual StreamState GetState() const {
+ ASSERT(socket_ != NULL);
+ switch (socket_->GetState()) {
+ case Socket::CS_CONNECTED:
+ return SS_OPEN;
+ case Socket::CS_CONNECTING:
+ return SS_OPENING;
+ case Socket::CS_CLOSED:
+ default:
+ return SS_CLOSED;
+ }
+ }
+
+ virtual StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ ASSERT(socket_ != NULL);
+ int result = socket_->Recv(buffer, buffer_len);
+ if (result < 0) {
+ if (socket_->IsBlocking())
+ return SR_BLOCK;
+ if (error)
+ *error = socket_->GetError();
+ return SR_ERROR;
+ }
+ if ((result > 0) || (buffer_len == 0)) {
+ if (read)
+ *read = result;
+ return SR_SUCCESS;
+ }
+ return SR_EOS;
+ }
+
+ virtual StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ ASSERT(socket_ != NULL);
+ int result = socket_->Send(data, data_len);
+ if (result < 0) {
+ if (socket_->IsBlocking())
+ return SR_BLOCK;
+ if (error)
+ *error = socket_->GetError();
+ return SR_ERROR;
+ }
+ if (written)
+ *written = result;
+ return SR_SUCCESS;
+ }
+
+ virtual void Close() { ASSERT(socket_ != NULL); socket_->Close(); }
+
+ virtual bool GetSize(size_t* size) const { return false; }
+ virtual bool ReserveSize(size_t size) { return true; }
+ virtual bool Rewind() { return false; }
+
+ private:
+ void OnConnectEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+ SignalEvent(this, SE_OPEN | SE_READ | SE_WRITE, 0);
+ }
+ void OnReadEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+ SignalEvent(this, SE_READ, 0);
+ }
+ void OnWriteEvent(AsyncSocket* socket) {
+ ASSERT(socket == socket_);
+ SignalEvent(this, SE_WRITE, 0);
+ }
+ void OnCloseEvent(AsyncSocket* socket, int err) {
+ ASSERT(socket == socket_);
+ SignalEvent(this, SE_CLOSE, err);
+ }
+
+ AsyncSocket* socket_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SocketStream);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SOCKET_STREAM_H__
diff --git a/third_party/libjingle/files/talk/base/ssladapter.cc b/third_party/libjingle/files/talk/base/ssladapter.cc
new file mode 100644
index 0000000..e03a183
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/ssladapter.cc
@@ -0,0 +1,196 @@
+/*
+ * 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/base/ssladapter.h"
+
+#if !defined(SSL_USE_SCHANNEL) && !defined(SSL_USE_OPENSSL)
+#ifdef WIN32
+#define SSL_USE_SCHANNEL 1
+#else // !WIN32
+// Turn off OpenSSL
+//#define SSL_USE_OPENSSL 1
+#endif // !WIN32
+#endif
+
+#if SSL_USE_SCHANNEL
+#include "schanneladapter.h"
+namespace talk_base {
+ typedef SChannelAdapter DefaultSSLAdapter;
+}
+#endif // SSL_USE_SCHANNEL
+
+#if SSL_USE_OPENSSL
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include "openssladapter.h"
+namespace talk_base {
+ typedef OpenSSLAdapter DefaultSSLAdapter;
+}
+#if defined(WIN32)
+ #define MUTEX_TYPE HANDLE
+ #define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL)
+ #define MUTEX_CLEANUP(x) CloseHandle(x)
+ #define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
+ #define MUTEX_UNLOCK(x) ReleaseMutex(x)
+ #define THREAD_ID GetCurrentThreadId()
+#elif defined(_POSIX_THREADS)
+ // _POSIX_THREADS is normally defined in unistd.h if pthreads are available
+ // on your platform.
+ #define MUTEX_TYPE pthread_mutex_t
+ #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
+ #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
+ #define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+ #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+ #define THREAD_ID pthread_self()
+#else
+ #error You must define mutex operations appropriate for your platform!
+#endif
+
+struct CRYPTO_dynlock_value {
+ MUTEX_TYPE mutex;
+};
+
+#endif // SSL_USE_OPENSSL
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace talk_base {
+
+SSLAdapter*
+SSLAdapter::Create(AsyncSocket* socket) {
+#if SSL_USE_OPENSSL || SSL_USE_SCHANNEL
+ return new DefaultSSLAdapter(socket);
+#else
+ return NULL;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if SSL_USE_OPENSSL
+
+
+
+// This array will store all of the mutexes available to OpenSSL.
+static MUTEX_TYPE* mutex_buf = NULL;
+
+static void locking_function(int mode, int n, const char * file, int line) {
+ if (mode & CRYPTO_LOCK) {
+ MUTEX_LOCK(mutex_buf[n]);
+ } else {
+ MUTEX_UNLOCK(mutex_buf[n]);
+ }
+}
+
+static pthread_t id_function() {
+ return THREAD_ID;
+}
+
+static CRYPTO_dynlock_value* dyn_create_function(const char* file, int line) {
+ CRYPTO_dynlock_value* value = new CRYPTO_dynlock_value;
+ if (!value)
+ return NULL;
+ MUTEX_SETUP(value->mutex);
+ return value;
+}
+
+static void dyn_lock_function(int mode, CRYPTO_dynlock_value* l,
+ const char* file, int line) {
+ if (mode & CRYPTO_LOCK) {
+ MUTEX_LOCK(l->mutex);
+ } else {
+ MUTEX_UNLOCK(l->mutex);
+ }
+}
+
+static void dyn_destroy_function(CRYPTO_dynlock_value* l,
+ const char* file, int line) {
+ MUTEX_CLEANUP(l->mutex);
+ delete l;
+}
+
+bool InitializeSSL() {
+ if (!InitializeSSLThread() || !SSL_library_init())
+ return false;
+ SSL_load_error_strings();
+ ERR_load_BIO_strings();
+ OpenSSL_add_all_algorithms();
+ RAND_poll();
+ return true;
+}
+
+bool InitializeSSLThread() {
+ mutex_buf = new MUTEX_TYPE[CRYPTO_num_locks()];
+ if (!mutex_buf)
+ return false;
+ for (int i = 0; i < CRYPTO_num_locks(); ++i)
+ MUTEX_SETUP(mutex_buf[i]);
+
+ // we need to cast our id_function to return an unsigned long -- pthread_t is a pointer
+ CRYPTO_set_id_callback((unsigned long (*)())id_function);
+ CRYPTO_set_locking_callback(locking_function);
+ CRYPTO_set_dynlock_create_callback(dyn_create_function);
+ CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
+ CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
+ return true;
+}
+
+bool CleanupSSL() {
+ if (!mutex_buf)
+ return false;
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_dynlock_create_callback(NULL);
+ CRYPTO_set_dynlock_lock_callback(NULL);
+ CRYPTO_set_dynlock_destroy_callback(NULL);
+ for (int i = 0; i < CRYPTO_num_locks(); ++i)
+ MUTEX_CLEANUP(mutex_buf[i]);
+ delete [] mutex_buf;
+ mutex_buf = NULL;
+ return true;
+}
+
+#else // !SSL_USE_OPENSSL
+
+bool InitializeSSL() {
+ return true;
+}
+
+bool InitializeSSLThread() {
+ return true;
+}
+
+bool CleanupSSL() {
+ return true;
+}
+
+#endif // !SSL_USE_OPENSSL
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/ssladapter.h b/third_party/libjingle/files/talk/base/ssladapter.h
new file mode 100644
index 0000000..0f0155c
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/ssladapter.h
@@ -0,0 +1,74 @@
+/*
+ * 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 TALK_BASE_SSLADAPTER_H__
+#define TALK_BASE_SSLADAPTER_H__
+
+#include "talk/base/asyncsocket.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SSLAdapter : public AsyncSocketAdapter {
+public:
+ SSLAdapter(AsyncSocket* socket)
+ : AsyncSocketAdapter(socket), ignore_bad_cert_(false) { }
+
+ bool ignore_bad_cert() const { return ignore_bad_cert_; }
+ void set_ignore_bad_cert(bool ignore) { ignore_bad_cert_ = ignore; }
+
+ // StartSSL returns 0 if successful.
+ // If StartSSL is called while the socket is closed or connecting, the SSL
+ // negotiation will begin as soon as the socket connects.
+ virtual int StartSSL(const char* hostname, bool restartable) = 0;
+
+ // Create the default SSL adapter for this platform
+ static SSLAdapter* Create(AsyncSocket* socket);
+
+private:
+ // If true, the server certificate need not match the configured hostname.
+ bool ignore_bad_cert_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Call this on the main thread, before using SSL.
+// Call CleanupSSLThread when finished with SSL.
+bool InitializeSSL();
+
+// Call to initialize additional threads.
+bool InitializeSSLThread();
+
+// Call to cleanup additional threads, and also the main thread.
+bool CleanupSSL();
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SSLADAPTER_H__
diff --git a/third_party/libjingle/files/talk/base/stl_decl.h b/third_party/libjingle/files/talk/base/stl_decl.h
new file mode 100644
index 0000000..193e7af
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stl_decl.h
@@ -0,0 +1,84 @@
+/*
+ * 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 TALK_BASE_STL_DECL_H__
+#define TALK_BASE_STL_DECL_H__
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
+#pragma warning(disable:4786)
+#endif
+
+#include <sys/types.h>
+
+namespace std {
+ template <class Key> struct hash;
+ template <class Key> struct equal_to;
+ template <class Key> struct less;
+ template <class T> class allocator;
+ template <class Key, class Val,
+ class Compare,
+ class Alloc> class map;
+ template <class T, class Alloc> class vector;
+ template <class T, class Alloc> class list;
+ template <class T, class Alloc> class slist;
+ template <class T, class Sequence> class stack;
+ template <class T, class Sequence> class queue;
+ template <class T, class Sequence, class Compare> class priority_queue;
+ template <class T1, class T2> struct pair;
+ template <class Key, class Compare, class Alloc> class set;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Workaround declaration problem with defaults
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0
+
+#define STD_MAP(T1, T2) \
+ std::map<T1 , T2, std::less<T1>, std::allocator<T2> >
+
+#define STD_VECTOR(T1) \
+ std::vector<T1, std::allocator<T1> >
+
+#define STD_SET(T1) \
+ std::set<T1, std::less<T1>, std::allocator<T1> >
+
+#else
+
+#define STD_MAP(T1, T2) \
+ std::map<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2 > > >
+
+#define STD_VECTOR(T1) \
+ std::vector<T1, std::allocator<T1> >
+
+#define STD_SET(T1) \
+ std::set<T1, std::less<T1>, std::allocator<T1> >
+
+#endif
+
+
+#endif // TALK_BASE_STL_DECL_H__
diff --git a/third_party/libjingle/files/talk/base/stream.cc b/third_party/libjingle/files/talk/base/stream.cc
new file mode 100644
index 0000000..e94de26
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stream.cc
@@ -0,0 +1,665 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string>
+#include "talk/base/basictypes.h"
+#include "talk/base/common.h"
+#include "talk/base/stream.h"
+#include "talk/base/stringencode.h"
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#define fileno _fileno
+#endif
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+StreamResult StreamInterface::WriteAll(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ StreamResult result = SR_SUCCESS;
+ size_t total_written = 0, current_written;
+ while (total_written < data_len) {
+ result = Write(static_cast<const char*>(data) + total_written,
+ data_len - total_written, &current_written, error);
+ if (result != SR_SUCCESS)
+ break;
+ total_written += current_written;
+ }
+ if (written)
+ *written = total_written;
+ return result;
+}
+
+StreamResult StreamInterface::ReadAll(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ StreamResult result = SR_SUCCESS;
+ size_t total_read = 0, current_read;
+ while (total_read < buffer_len) {
+ result = Read(static_cast<char*>(buffer) + total_read,
+ buffer_len - total_read, &current_read, error);
+ if (result != SR_SUCCESS)
+ break;
+ total_read += current_read;
+ }
+ if (read)
+ *read = total_read;
+ return result;
+}
+
+StreamResult StreamInterface::ReadLine(std::string* line) {
+ StreamResult result = SR_SUCCESS;
+ while (true) {
+ char ch;
+ result = Read(&ch, sizeof(ch), NULL, NULL);
+ if (result != SR_SUCCESS) {
+ break;
+ }
+ if (ch == '\n') {
+ break;
+ }
+ line->push_back(ch);
+ }
+ if (!line->empty()) { // give back the line we've collected so far with
+ result = SR_SUCCESS; // a success code. Otherwise return the last code
+ }
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamTap
+///////////////////////////////////////////////////////////////////////////////
+
+StreamTap::StreamTap(StreamInterface* stream, StreamInterface* tap)
+: StreamAdapterInterface(stream), tap_(NULL), tap_result_(SR_SUCCESS),
+ tap_error_(0)
+{
+ AttachTap(tap);
+}
+
+void StreamTap::AttachTap(StreamInterface* tap) {
+ tap_.reset(tap);
+}
+
+StreamInterface* StreamTap::DetachTap() {
+ return tap_.release();
+}
+
+StreamResult StreamTap::GetTapResult(int* error) {
+ if (error) {
+ *error = tap_error_;
+ }
+ return tap_result_;
+}
+
+StreamResult StreamTap::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ size_t backup_read;
+ if (!read) {
+ read = &backup_read;
+ }
+ StreamResult res = StreamAdapterInterface::Read(buffer, buffer_len,
+ read, error);
+ if ((res == SR_SUCCESS) && (tap_result_ == SR_SUCCESS)) {
+ tap_result_ = tap_->WriteAll(buffer, *read, NULL, &tap_error_);
+ }
+ return res;
+}
+
+StreamResult StreamTap::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ size_t backup_written;
+ if (!written) {
+ written = &backup_written;
+ }
+ StreamResult res = StreamAdapterInterface::Write(data, data_len,
+ written, error);
+ if ((res == SR_SUCCESS) && (tap_result_ == SR_SUCCESS)) {
+ tap_result_ = tap_->WriteAll(data, *written, NULL, &tap_error_);
+ }
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NullStream
+///////////////////////////////////////////////////////////////////////////////
+
+NullStream::NullStream() {
+}
+
+NullStream::~NullStream() {
+}
+
+StreamState NullStream::GetState() const {
+ return SS_OPEN;
+}
+
+StreamResult NullStream::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ if (error) *error = -1;
+ return SR_ERROR;
+}
+
+
+StreamResult NullStream::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ if (written) *written = data_len;
+ return SR_SUCCESS;
+}
+
+void NullStream::Close() {
+}
+
+bool NullStream::GetSize(size_t* size) const {
+ if (size)
+ *size = 0;
+ return true;
+}
+
+bool NullStream::ReserveSize(size_t size) {
+ return true;
+}
+
+bool NullStream::Rewind() {
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FileStream
+///////////////////////////////////////////////////////////////////////////////
+
+FileStream::FileStream() : file_(NULL) {
+}
+
+FileStream::~FileStream() {
+ FileStream::Close();
+}
+
+bool FileStream::Open(const std::string& filename, const char* mode) {
+ Close();
+#ifdef WIN32
+ int filenamelen = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(),
+ filename.length() + 1, NULL, 0);
+ int modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
+ wchar_t *wfilename = new wchar_t[filenamelen+4]; // 4 for "\\?\"
+ wchar_t *wfilename_dest = wfilename;
+ wchar_t *wmode = new wchar_t[modelen];
+
+ if (!filename.empty() && (filename[0] != '\\')) {
+ wcscpy(wfilename, L"\\\\?\\");
+ wfilename_dest = wfilename + 4;
+ }
+
+ if ((MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), filename.length() + 1,
+ wfilename_dest, filenamelen) > 0) &&
+ (MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen) > 0)) {
+ file_ = _wfopen(wfilename, wmode);
+ } else {
+ file_ = NULL;
+ }
+
+ delete[] wfilename;
+ delete[] wmode;
+#else
+ file_ = fopen(filename.c_str(), mode);
+#endif
+ return (file_ != NULL);
+}
+
+bool FileStream::OpenShare(const std::string& filename, const char* mode,
+ int shflag) {
+ Close();
+#ifdef WIN32
+ int filenamelen = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(),
+ filename.length() + 1, NULL, 0);
+ int modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
+ wchar_t *wfilename = new wchar_t[filenamelen+4]; // 4 for "\\?\"
+ wchar_t *wfilename_dest = wfilename;
+ wchar_t *wmode = new wchar_t[modelen];
+
+ if (!filename.empty() && (filename[0] != '\\')) {
+ wcscpy(wfilename, L"\\\\?\\");
+ wfilename_dest = wfilename + 4;
+ }
+
+ if ((MultiByteToWideChar(CP_UTF8, 0, filename.c_str(), filename.length() + 1,
+ wfilename_dest, filenamelen) > 0) &&
+ (MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen) > 0)) {
+ file_ = _wfsopen(wfilename, wmode, shflag);
+ } else {
+ file_ = NULL;
+ }
+
+ delete[] wfilename;
+ delete[] wmode;
+#else
+ return Open(filename, mode);
+#endif
+ return (file_ != NULL);
+}
+
+bool FileStream::DisableBuffering() {
+ if (!file_)
+ return false;
+ return (setvbuf(file_, NULL, _IONBF, 0) == 0);
+}
+
+StreamState FileStream::GetState() const {
+ return (file_ == NULL) ? SS_CLOSED : SS_OPEN;
+}
+
+StreamResult FileStream::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ if (!file_)
+ return SR_EOS;
+ size_t result = fread(buffer, 1, buffer_len, file_);
+ if ((result == 0) && (buffer_len > 0)) {
+ if (feof(file_))
+ return SR_EOS;
+ if (error)
+ *error = errno;
+ return SR_ERROR;
+ }
+ if (read)
+ *read = result;
+ return SR_SUCCESS;
+}
+
+StreamResult FileStream::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ if (!file_)
+ return SR_EOS;
+ size_t result = fwrite(data, 1, data_len, file_);
+ if ((result == 0) && (data_len > 0)) {
+ if (error)
+ *error = errno;
+ return SR_ERROR;
+ }
+ if (written)
+ *written = result;
+ return SR_SUCCESS;
+}
+
+void FileStream::Close() {
+ if (file_) {
+ fclose(file_);
+ file_ = NULL;
+ }
+}
+
+bool FileStream::SetPosition(size_t position) {
+ if (!file_)
+ return false;
+ return (fseek(file_, position, SEEK_SET) == 0);
+}
+
+bool FileStream::GetPosition(size_t * position) const {
+ ASSERT(position != NULL);
+ if (!file_ || !position)
+ return false;
+ long result = ftell(file_);
+ if (result < 0)
+ return false;
+ *position = result;
+ return true;
+}
+
+bool FileStream::GetSize(size_t * size) const {
+ ASSERT(size != NULL);
+ if (!file_ || !size)
+ return false;
+ struct stat file_stats;
+ if (fstat(fileno(file_), &file_stats) != 0)
+ return false;
+ *size = file_stats.st_size;
+ return true;
+}
+
+bool FileStream::ReserveSize(size_t size) {
+ // TODO: extend the file to the proper length
+ return true;
+}
+
+bool FileStream::GetSize(const std::string& filename, size_t* size) {
+ struct stat file_stats;
+ if (stat(filename.c_str(), &file_stats) != 0)
+ return false;
+ *size = file_stats.st_size;
+ return true;
+}
+
+int FileStream::Flush() {
+ if (file_) {
+ return fflush (file_);
+ }
+ // try to flush empty file?
+ ASSERT(false);
+ return 0;
+}
+///////////////////////////////////////////////////////////////////////////////
+
+
+MemoryStream::MemoryStream()
+ : allocated_length_(0), buffer_(NULL), data_length_(0), seek_position_(0) {
+}
+
+MemoryStream::MemoryStream(const char* data)
+ : allocated_length_(0), buffer_(NULL), data_length_(0), seek_position_(0) {
+ SetContents(data, strlen(data));
+}
+
+MemoryStream::MemoryStream(const char* data, size_t length)
+ : allocated_length_(0), buffer_(NULL), data_length_(0), seek_position_(0) {
+ SetContents(data, length);
+}
+
+MemoryStream::~MemoryStream() {
+ delete [] buffer_;
+}
+
+void MemoryStream::SetContents(const char* data, size_t length) {
+ delete [] buffer_;
+ data_length_ = allocated_length_ = length;
+ buffer_ = new char[allocated_length_];
+ memcpy(buffer_, data, data_length_);
+}
+
+StreamState MemoryStream::GetState() const {
+ return SS_OPEN;
+}
+
+StreamResult MemoryStream::Read(void *buffer, size_t bytes,
+ size_t *bytes_read, int *error) {
+ if (seek_position_ >= data_length_) {
+ // At end of stream
+ if (error) {
+ *error = EOF;
+ }
+ return SR_EOS;
+ }
+
+ size_t remaining_length = data_length_ - seek_position_;
+ if (bytes > remaining_length) {
+ // Read partial buffer
+ bytes = remaining_length;
+ }
+ memcpy(buffer, &buffer_[seek_position_], bytes);
+ seek_position_ += bytes;
+ if (bytes_read) {
+ *bytes_read = bytes;
+ }
+ return SR_SUCCESS;
+}
+
+StreamResult MemoryStream::Write(const void *buffer,
+ size_t bytes, size_t *bytes_written, int *error) {
+ StreamResult sr = SR_SUCCESS;
+ int error_value = 0;
+ size_t bytes_written_value = 0;
+
+ size_t new_position = seek_position_ + bytes;
+ if (new_position > allocated_length_) {
+ // Increase buffer size to the larger of:
+ // a) new position rounded up to next 256 bytes
+ // b) double the previous length
+ size_t new_allocated_length = _max((new_position | 0xFF) + 1,
+ allocated_length_ * 2);
+ if (char* new_buffer = new char[new_allocated_length]) {
+ memcpy(new_buffer, buffer_, data_length_);
+ delete [] buffer_;
+ buffer_ = new_buffer;
+ allocated_length_ = new_allocated_length;
+ } else {
+ error_value = ENOMEM;
+ sr = SR_ERROR;
+ }
+ }
+
+ if (sr == SR_SUCCESS) {
+ bytes_written_value = bytes;
+ memcpy(&buffer_[seek_position_], buffer, bytes);
+ seek_position_ = new_position;
+ if (data_length_ < seek_position_) {
+ data_length_ = seek_position_;
+ }
+ }
+
+ if (bytes_written) {
+ *bytes_written = bytes_written_value;
+ }
+ if (error) {
+ *error = error_value;
+ }
+
+ return sr;
+}
+
+void MemoryStream::Close() {
+ // nothing to do
+}
+
+bool MemoryStream::SetPosition(size_t position) {
+ if (position <= data_length_) {
+ seek_position_ = position;
+ return true;
+ }
+ return false;
+}
+
+bool MemoryStream::GetPosition(size_t *position) const {
+ if (!position) {
+ return false;
+ }
+ *position = seek_position_;
+ return true;
+}
+
+bool MemoryStream::GetSize(size_t *size) const {
+ if (!size) {
+ return false;
+ }
+ *size = data_length_;
+ return true;
+}
+
+bool MemoryStream::ReserveSize(size_t size) {
+ if (allocated_length_ >= size)
+ return true;
+
+ if (char* new_buffer = new char[size]) {
+ memcpy(new_buffer, buffer_, data_length_);
+ delete [] buffer_;
+ buffer_ = new_buffer;
+ allocated_length_ = size;
+ return true;
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+StreamResult Flow(StreamInterface* source,
+ char* buffer, size_t buffer_len,
+ StreamInterface* sink) {
+ ASSERT(buffer_len > 0);
+
+ StreamResult result;
+ size_t count, read_pos, write_pos;
+
+ bool end_of_stream = false;
+ do {
+ // Read until buffer is full, end of stream, or error
+ read_pos = 0;
+ do {
+ result = source->Read(buffer + read_pos, buffer_len - read_pos,
+ &count, NULL);
+ if (result == SR_EOS) {
+ end_of_stream = true;
+ } else if (result != SR_SUCCESS) {
+ return result;
+ } else {
+ read_pos += count;
+ }
+ } while (!end_of_stream && (read_pos < buffer_len));
+
+ // Write until buffer is empty, or error (including end of stream)
+ write_pos = 0;
+ do {
+ result = sink->Write(buffer + write_pos, read_pos - write_pos,
+ &count, NULL);
+ if (result != SR_SUCCESS)
+ return result;
+
+ write_pos += count;
+ } while (write_pos < read_pos);
+ } while (!end_of_stream);
+
+ return SR_SUCCESS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+LoggingAdapter::LoggingAdapter(StreamInterface* stream, LoggingSeverity level,
+ const std::string& label, bool hex_mode)
+: StreamAdapterInterface(stream), level_(level), hex_mode_(hex_mode)
+{
+ label_.append("[");
+ label_.append(label);
+ label_.append("]");
+}
+
+StreamResult LoggingAdapter::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ size_t local_read; if (!read) read = &local_read;
+ StreamResult result = StreamAdapterInterface::Read(buffer, buffer_len, read, error);
+ if (result == SR_SUCCESS) {
+ LogMultiline(level_, label_.c_str(), true,
+ static_cast<const char *>(buffer), *read, hex_mode_, &lms_);
+ }
+ return result;
+}
+
+StreamResult LoggingAdapter::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ size_t local_written; if (!written) written = &local_written;
+ StreamResult result = StreamAdapterInterface::Write(data, data_len, written, error);
+ if (result == SR_SUCCESS) {
+ LogMultiline(level_, label_.c_str(), false,
+ static_cast<const char *>(data), *written, hex_mode_, &lms_);
+ }
+ return result;
+}
+
+void LoggingAdapter::Close() {
+ LOG_V(level_) << label_ << " Closed locally";
+ StreamAdapterInterface::Close();
+}
+
+void LoggingAdapter::OnEvent(StreamInterface* stream, int events, int err) {
+ if (events & SE_OPEN) {
+ LOG_V(level_) << label_ << " Open";
+ } else if (events & SE_CLOSE) {
+ LOG_V(level_) << label_ << " Closed with error: " << err;
+ }
+ StreamAdapterInterface::OnEvent(stream, events, err);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream - Reads/Writes to an external std::string
+///////////////////////////////////////////////////////////////////////////////
+
+StringStream::StringStream(std::string& str)
+: str_(str), read_pos_(0), read_only_(false)
+{
+}
+
+StringStream::StringStream(const std::string& str)
+: str_(const_cast<std::string&>(str)), read_pos_(0), read_only_(true)
+{
+}
+
+StreamState StringStream::GetState() const {
+ return SS_OPEN;
+}
+
+StreamResult StringStream::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ size_t available = talk_base::_min(buffer_len, str_.size() - read_pos_);
+ if (!available)
+ return SR_EOS;
+ memcpy(buffer, str_.data() + read_pos_, available);
+ read_pos_ += available;
+ if (read)
+ *read = available;
+ return SR_SUCCESS;
+}
+
+StreamResult StringStream::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ if (read_only_) {
+ if (error) {
+ *error = -1;
+ }
+ return SR_ERROR;
+ }
+ str_.append(static_cast<const char*>(data),
+ static_cast<const char*>(data) + data_len);
+ if (written)
+ *written = data_len;
+ return SR_SUCCESS;
+}
+
+void StringStream::Close() {
+}
+
+bool StringStream::GetSize(size_t* size) const {
+ ASSERT(size != NULL);
+ *size = str_.size();
+ return true;
+}
+
+bool StringStream::ReserveSize(size_t size) {
+ if (read_only_)
+ return false;
+ str_.reserve(size);
+ return true;
+}
+
+bool StringStream::Rewind() {
+ read_pos_ = 0;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/stream.h b/third_party/libjingle/files/talk/base/stream.h
new file mode 100644
index 0000000..cb91bb74
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stream.h
@@ -0,0 +1,396 @@
+/*
+ * 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 TALK_BASE_STREAM_H__
+#define TALK_BASE_STREAM_H__
+
+#include "talk/base/basictypes.h"
+#include "talk/base/logging.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamInterface is a generic asynchronous stream interface, supporting read,
+// write, and close operations, and asynchronous signalling of state changes.
+// The interface is designed with file, memory, and socket implementations in
+// mind.
+///////////////////////////////////////////////////////////////////////////////
+
+// The following enumerations are declared outside of the StreamInterface
+// class for brevity in use.
+
+// The SS_OPENING state indicates that the stream will signal open or closed
+// in the future.
+enum StreamState { SS_CLOSED, SS_OPENING, SS_OPEN };
+
+// Stream read/write methods return this value to indicate various success
+// and failure conditions described below.
+enum StreamResult { SR_ERROR, SR_SUCCESS, SR_BLOCK, SR_EOS };
+
+// StreamEvents are used to asynchronously signal state transitionss. The flags
+// may be combined.
+// SE_OPEN: The stream has transitioned to the SS_OPEN state
+// SE_CLOSE: The stream has transitioned to the SS_CLOSED state
+// SE_READ: Data is available, so Read is likely to not return SR_BLOCK
+// SE_WRITE: Data can be written, so Write is likely to not return SR_BLOCK
+enum StreamEvent { SE_OPEN = 1, SE_READ = 2, SE_WRITE = 4, SE_CLOSE = 8 };
+
+class StreamInterface {
+ public:
+ virtual ~StreamInterface() { }
+
+ virtual StreamState GetState() const = 0;
+
+ // Read attempts to fill buffer of size buffer_len. Write attempts to send
+ // data_len bytes stored in data. The variables read and write are set only
+ // on SR_SUCCESS (see below). Likewise, error is only set on SR_ERROR.
+ // Read and Write return a value indicating:
+ // SR_ERROR: an error occurred, which is returned in a non-null error
+ // argument. Interpretation of the error requires knowledge of the
+ // stream's concrete type, which limits its usefulness.
+ // SR_SUCCESS: some number of bytes were successfully written, which is
+ // returned in a non-null read/write argument.
+ // SR_BLOCK: the stream is in non-blocking mode, and the operation would
+ // block, or the stream is in SS_OPENING state.
+ // SR_EOS: the end-of-stream has been reached, or the stream is in the
+ // SS_CLOSED state.
+ virtual StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) = 0;
+ virtual StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error) = 0;
+
+ // Attempt to transition to the SS_CLOSED state. SE_CLOSE will not be
+ // signalled as a result of this call.
+ virtual void Close() = 0;
+
+ // Return the number of bytes that will be returned by Read, if known.
+ virtual bool GetSize(size_t* size) const = 0;
+
+ // Communicates the amount of data which will be written to the stream. The
+ // stream may choose to preallocate memory to accomodate this data. The
+ // stream may return false to indicate that there is not enough room (ie,
+ // Write will return SR_EOS/SR_ERROR at some point). Note that calling this
+ // function should not affect the existing state of data in the stream.
+ virtual bool ReserveSize(size_t size) = 0;
+
+ // Returns true if stream could be repositioned to the beginning.
+ virtual bool Rewind() = 0;
+
+ // WriteAll is a helper function which repeatedly calls Write until all the
+ // data is written, or something other than SR_SUCCESS is returned. Note that
+ // unlike Write, the argument 'written' is always set, and may be non-zero
+ // on results other than SR_SUCCESS. The remaining arguments have the
+ // same semantics as Write.
+ StreamResult WriteAll(const void* data, size_t data_len,
+ size_t* written, int* error);
+
+ // Similar to ReadAll. Calls Read until buffer_len bytes have been read, or
+ // until a non-SR_SUCCESS result is returned. 'read' is always set.
+ StreamResult ReadAll(void* buffer, size_t buffer_len,
+ size_t* read, int* error);
+
+ // ReadLine is a helper function which repeatedly calls Read until it hits
+ // the end-of-line character, or something other than SR_SUCCESS.
+ // TODO: this is too inefficient to keep here. Break this out into a buffered
+ // readline object or adapter
+ StreamResult ReadLine(std::string *line);
+
+ // Streams may signal one or more StreamEvents to indicate state changes.
+ // The first argument identifies the stream on which the state change occured.
+ // The second argument is a bit-wise combination of StreamEvents.
+ // If SE_CLOSE is signalled, then the third argument is the associated error
+ // code. Otherwise, the value is undefined.
+ // Note: Not all streams will support asynchronous event signalling. However,
+ // SS_OPENING and SR_BLOCK returned from stream member functions imply that
+ // certain events will be raised in the future.
+ sigslot::signal3<StreamInterface*, int, int> SignalEvent;
+
+ protected:
+ StreamInterface() { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(StreamInterface);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamAdapterInterface is a convenient base-class for adapting a stream.
+// By default, all operations are pass-through. Override the methods that you
+// require adaptation. Note that the adapter will delete the adapted stream.
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamAdapterInterface : public StreamInterface,
+ public sigslot::has_slots<> {
+ public:
+ explicit StreamAdapterInterface(StreamInterface* stream) {
+ Attach(stream);
+ }
+
+ virtual StreamState GetState() const {
+ return stream_->GetState();
+ }
+ virtual StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ return stream_->Read(buffer, buffer_len, read, error);
+ }
+ virtual StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ return stream_->Write(data, data_len, written, error);
+ }
+ virtual void Close() {
+ stream_->Close();
+ }
+ virtual bool GetSize(size_t* size) const {
+ return stream_->GetSize(size);
+ }
+ virtual bool ReserveSize(size_t size) {
+ return stream_->ReserveSize(size);
+ }
+ virtual bool Rewind() {
+ return stream_->Rewind();
+ }
+
+ void Attach(StreamInterface* stream) {
+ if (NULL != stream_.get())
+ stream_->SignalEvent.disconnect(this);
+ stream_.reset(stream);
+ if (NULL != stream_.get())
+ stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
+ }
+ StreamInterface* Detach() {
+ if (NULL == stream_.get())
+ return NULL;
+ stream_->SignalEvent.disconnect(this);
+ return stream_.release();
+ }
+
+ protected:
+ // Note that the adapter presents itself as the origin of the stream events,
+ // since users of the adapter may not recognize the adapted object.
+ virtual void OnEvent(StreamInterface* stream, int events, int err) {
+ SignalEvent(this, events, err);
+ }
+
+ private:
+ scoped_ptr<StreamInterface> stream_;
+ DISALLOW_EVIL_CONSTRUCTORS(StreamAdapterInterface);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamTap is a non-modifying, pass-through adapter, which copies all data
+// in either direction to the tap. Note that errors or blocking on writing to
+// the tap will prevent further tap writes from occurring.
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamTap : public StreamAdapterInterface {
+ public:
+ explicit StreamTap(StreamInterface* stream, StreamInterface* tap);
+
+ void AttachTap(StreamInterface* tap);
+ StreamInterface* DetachTap();
+ StreamResult GetTapResult(int* error);
+
+ // StreamAdapterInterface Interface
+ 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);
+
+ private:
+ scoped_ptr<StreamInterface> tap_;
+ StreamResult tap_result_;
+ int tap_error_;
+ DISALLOW_EVIL_CONSTRUCTORS(StreamTap);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NullStream gives errors on read, and silently discards all written data.
+///////////////////////////////////////////////////////////////////////////////
+
+class NullStream : public StreamInterface {
+ public:
+ NullStream();
+ virtual ~NullStream();
+
+ // StreamInterface Interface
+ 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();
+ virtual bool GetSize(size_t* size) const;
+ virtual bool ReserveSize(size_t size);
+ virtual bool Rewind();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// FileStream is a simple implementation of a StreamInterface, which does not
+// support asynchronous notification.
+///////////////////////////////////////////////////////////////////////////////
+
+class FileStream : public StreamInterface {
+ public:
+ FileStream();
+ virtual ~FileStream();
+
+ // The semantics of filename and mode are the same as stdio's fopen
+ virtual bool Open(const std::string& filename, const char* mode);
+ virtual bool OpenShare(const std::string& filename, const char* mode,
+ int shflag);
+
+ // By default, reads and writes are buffered for efficiency. Disabling
+ // buffering causes writes to block until the bytes on disk are updated.
+ virtual bool DisableBuffering();
+
+ 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();
+ virtual bool GetSize(size_t* size) const;
+ virtual bool ReserveSize(size_t size);
+ virtual bool Rewind() { return SetPosition(0); }
+
+ bool SetPosition(size_t position);
+ bool GetPosition(size_t* position) const;
+ int Flush();
+ static bool GetSize(const std::string& filename, size_t* size);
+
+ private:
+ FILE* file_;
+ DISALLOW_EVIL_CONSTRUCTORS(FileStream);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryStream is a simple implementation of a StreamInterface over in-memory
+// data. It does not support asynchronous notification.
+///////////////////////////////////////////////////////////////////////////////
+
+class MemoryStream : public StreamInterface {
+ public:
+ MemoryStream();
+ // Pre-populate stream with the provided data.
+ MemoryStream(const char* data);
+ MemoryStream(const char* data, size_t length);
+ virtual ~MemoryStream();
+
+ virtual StreamState GetState() const;
+ virtual StreamResult Read(void *buffer, size_t bytes, size_t *bytes_read, int *error);
+ virtual StreamResult Write(const void *buffer, size_t bytes, size_t *bytes_written, int *error);
+ virtual void Close();
+ virtual bool GetSize(size_t* size) const;
+ virtual bool ReserveSize(size_t size);
+ virtual bool Rewind() { return SetPosition(0); }
+
+ char* GetBuffer() { return buffer_; }
+ const char* GetBuffer() const { return buffer_; }
+ bool SetPosition(size_t position);
+ bool GetPosition(size_t* position) const;
+
+ private:
+ void SetContents(const char* data, size_t length);
+
+ size_t allocated_length_;
+ char* buffer_;
+ size_t data_length_;
+ size_t seek_position_;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(MemoryStream);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class LoggingAdapter : public StreamAdapterInterface {
+public:
+ LoggingAdapter(StreamInterface* stream, LoggingSeverity level,
+ const std::string& label, bool hex_mode = false);
+
+ 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();
+
+ protected:
+ virtual void OnEvent(StreamInterface* stream, int events, int err);
+
+ private:
+ LoggingSeverity level_;
+ std::string label_;
+ bool hex_mode_;
+ LogMultilineState lms_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(LoggingAdapter);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream - Reads/Writes to an external std::string
+///////////////////////////////////////////////////////////////////////////////
+
+class StringStream : public StreamInterface {
+public:
+ StringStream(std::string& str);
+ StringStream(const std::string& str);
+
+ 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();
+ virtual bool GetSize(size_t* size) const;
+ virtual bool ReserveSize(size_t size);
+ virtual bool Rewind();
+
+private:
+ std::string& str_;
+ size_t read_pos_;
+ bool read_only_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Flow attempts to move bytes from source to sink via buffer of size
+// buffer_len. The function returns SR_SUCCESS when source reaches
+// end-of-stream (returns SR_EOS), and all the data has been written successful
+// to sink. Alternately, if source returns SR_BLOCK or SR_ERROR, or if sink
+// returns SR_BLOCK, SR_ERROR, or SR_EOS, then the function immediately returns
+// with the unexpected StreamResult value.
+
+StreamResult Flow(StreamInterface* source,
+ char* buffer, size_t buffer_len,
+ StreamInterface* sink);
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_STREAM_H__
diff --git a/third_party/libjingle/files/talk/base/streamutils.cc b/third_party/libjingle/files/talk/base/streamutils.cc
new file mode 100644
index 0000000..52e6da7
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/streamutils.cc
@@ -0,0 +1,194 @@
+/*
+ * 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 "talk/base/common.h"
+#include "talk/base/streamutils.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// TODO: Extend so that one side can close, and other side can send
+// buffered data.
+
+StreamRelay::StreamRelay(talk_base::StreamInterface* s1,
+ talk_base::StreamInterface* s2,
+ size_t buffer_size) : buffer_size_(buffer_size) {
+ dir_[0].stream = s1;
+ dir_[1].stream = s2;
+
+ ASSERT(s1->GetState() != talk_base::SS_CLOSED);
+ ASSERT(s2->GetState() != talk_base::SS_CLOSED);
+
+ for (size_t i=0; i<2; ++i) {
+ dir_[i].stream->SignalEvent.connect(this, &StreamRelay::OnEvent);
+ dir_[i].buffer = new char[buffer_size_];
+ dir_[i].data_len = 0;
+ }
+}
+
+StreamRelay::~StreamRelay() {
+ for (size_t i=0; i<2; ++i) {
+ delete dir_[i].stream;
+ delete [] dir_[i].buffer;
+ }
+}
+
+void
+StreamRelay::Circulate() {
+ int error = 0;
+ if (!Flow(0, &error) || !Flow(1, &error)) {
+ Close();
+ SignalClosed(this, error);
+ }
+}
+
+void
+StreamRelay::Close() {
+ for (size_t i=0; i<2; ++i) {
+ dir_[i].stream->SignalEvent.disconnect(this);
+ dir_[i].stream->Close();
+ }
+}
+
+bool
+StreamRelay::Flow(int read_index, int* error) {
+ Direction& reader = dir_[read_index];
+ Direction& writer = dir_[Complement(read_index)];
+
+ bool progress;
+ do {
+ progress = false;
+
+ while (reader.stream->GetState() == talk_base::SS_OPEN) {
+ size_t available = buffer_size_ - reader.data_len;
+ if (available == 0)
+ break;
+
+ *error = 0;
+ size_t read = 0;
+ talk_base::StreamResult result
+ = reader.stream->Read(reader.buffer + reader.data_len, available,
+ &read, error);
+ if ((result == talk_base::SR_BLOCK) || (result == talk_base::SR_EOS))
+ break;
+
+ if (result == talk_base::SR_ERROR)
+ return false;
+
+ progress = true;
+ ASSERT((read > 0) && (read <= available));
+ reader.data_len += read;
+ }
+
+ size_t total_written = 0;
+ while (writer.stream->GetState() == talk_base::SS_OPEN) {
+ size_t available = reader.data_len - total_written;
+ if (available == 0)
+ break;
+
+ *error = 0;
+ size_t written = 0;
+ talk_base::StreamResult result
+ = writer.stream->Write(reader.buffer + total_written,
+ available, &written, error);
+ if ((result == talk_base::SR_BLOCK) || (result == talk_base::SR_EOS))
+ break;
+
+ if (result == talk_base::SR_ERROR)
+ return false;
+
+ progress = true;
+ ASSERT((written > 0) && (written <= available));
+ total_written += written;
+ }
+
+ reader.data_len -= total_written;
+ if (reader.data_len > 0) {
+ memmove(reader.buffer, reader.buffer + total_written, reader.data_len);
+ }
+ } while (progress);
+
+ return true;
+}
+
+void StreamRelay::OnEvent(talk_base::StreamInterface* stream, int events,
+ int error) {
+ int index = Index(stream);
+
+ // Note: In the following cases, we are treating the open event as both
+ // readable and writeable, for robustness. It won't hurt if we are wrong.
+
+ if ((events & talk_base::SE_OPEN | talk_base::SE_READ)
+ && !Flow(index, &error)) {
+ events = talk_base::SE_CLOSE;
+ }
+
+ if ((events & talk_base::SE_OPEN | talk_base::SE_WRITE)
+ && !Flow(Complement(index), &error)) {
+ events = talk_base::SE_CLOSE;
+ }
+
+ if (events & talk_base::SE_CLOSE) {
+ Close();
+ SignalClosed(this, error);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamCounter - counts the number of bytes which are transferred in either
+// direction.
+///////////////////////////////////////////////////////////////////////////////
+
+StreamCounter::StreamCounter(talk_base::StreamInterface* stream)
+ : StreamAdapterInterface(stream), count_(0) {
+}
+
+talk_base::StreamResult StreamCounter::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ size_t tmp;
+ if (!read)
+ read = &tmp;
+ talk_base::StreamResult result
+ = StreamAdapterInterface::Read(buffer, buffer_len,
+ read, error);
+ if (result == talk_base::SR_SUCCESS)
+ count_ += *read;
+ SignalUpdateByteCount(count_);
+ return result;
+}
+
+talk_base::StreamResult StreamCounter::Write(
+ const void* data, size_t data_len, size_t* written, int* error) {
+ size_t tmp;
+ if (!written)
+ written = &tmp;
+ talk_base::StreamResult result
+ = StreamAdapterInterface::Write(data, data_len, written, error);
+ if (result == talk_base::SR_SUCCESS)
+ count_ += *written;
+ SignalUpdateByteCount(count_);
+ return result;
+}
diff --git a/third_party/libjingle/files/talk/base/streamutils.h b/third_party/libjingle/files/talk/base/streamutils.h
new file mode 100644
index 0000000..7bb07a3
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/streamutils.h
@@ -0,0 +1,94 @@
+/*
+ * 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 TALK_APP_STREAMUTILS_H__
+#define TALK_APP_STREAMUTILS_H__
+
+#include "talk/base/sigslot.h"
+#include "talk/base/stream.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamRelay - acts as an intermediary between two asynchronous streams,
+// reading from one stream and writing to the other, using a pre-specified
+// amount of buffering in both directions.
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamRelay : public sigslot::has_slots<> {
+public:
+ StreamRelay(talk_base::StreamInterface* s1,
+ talk_base::StreamInterface* s2, size_t buffer_size);
+ virtual ~StreamRelay();
+
+ void Circulate(); // Simulate events to get things flowing
+ void Close();
+
+ sigslot::signal2<StreamRelay*, int> SignalClosed;
+
+private:
+ inline int Index(talk_base::StreamInterface* s) const
+ { return (s == dir_[1].stream); }
+ inline int Complement(int index) const { return (1-index); }
+
+ bool Flow(int read_index, int* error);
+ void OnEvent(talk_base::StreamInterface* stream, int events, int error);
+
+ struct Direction {
+ talk_base::StreamInterface* stream;
+ char* buffer;
+ size_t data_len;
+ };
+ Direction dir_[2];
+ size_t buffer_size_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamCounter - counts the number of bytes which are transferred in either
+// direction.
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamCounter : public talk_base::StreamAdapterInterface {
+ public:
+ explicit StreamCounter(talk_base::StreamInterface* stream);
+
+ inline void ResetByteCount() { count_ = 0; }
+ inline size_t GetByteCount() const { return count_; }
+
+ sigslot::signal1<size_t> SignalUpdateByteCount;
+
+ // StreamAdapterInterface
+ virtual talk_base::StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error);
+ virtual talk_base::StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error);
+
+ private:
+ size_t count_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#endif // TALK_APP_STREAMUTILS_H__
diff --git a/third_party/libjingle/files/talk/base/stringdigest.cc b/third_party/libjingle/files/talk/base/stringdigest.cc
new file mode 100644
index 0000000..1f98124
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringdigest.cc
@@ -0,0 +1,49 @@
+/*
+ * 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/base/md5.h"
+#include "talk/base/stringdigest.h"
+#include "talk/base/stringencode.h"
+
+namespace talk_base {
+
+std::string MD5(const std::string& data) {
+ MD5_CTX ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx, const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(data.data())), static_cast<unsigned int>(data.size()));
+ unsigned char digest[16];
+ MD5Final(digest, &ctx);
+ std::string hex_digest;
+ for (int i=0; i<16; ++i) {
+ hex_digest += hex_encode(digest[i] >> 4);
+ hex_digest += hex_encode(digest[i] & 0xf);
+ }
+ return hex_digest;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/stringdigest.h b/third_party/libjingle/files/talk/base/stringdigest.h
new file mode 100644
index 0000000..d75d845
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringdigest.h
@@ -0,0 +1,47 @@
+/*
+ * 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 TALK_BASE_STRINGDIGEST_H__
+#define TALK_BASE_STRINGDIGEST_H__
+
+#include <string>
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// Message Digest Utilities
+//////////////////////////////////////////////////////////////////////
+
+// Compute the MD5 message digest of data, and return it in
+std::string MD5(const std::string& data);
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_STRINGDIGEST_H__
diff --git a/third_party/libjingle/files/talk/base/stringencode.cc b/third_party/libjingle/files/talk/base/stringencode.cc
new file mode 100644
index 0000000..ffae6fe
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringencode.cc
@@ -0,0 +1,580 @@
+/*
+ * 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.
+ */
+
+#ifdef WIN32
+#include <malloc.h>
+#endif // WIN32
+#ifdef POSIX
+#include <alloca.h>
+#define _alloca alloca
+#endif // POSIX
+#include <stdlib.h>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/common.h"
+#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
+
+namespace talk_base {
+
+/////////////////////////////////////////////////////////////////////////////
+// String Encoding Utilities
+/////////////////////////////////////////////////////////////////////////////
+
+static const char HEX[] = "0123456789abcdef";
+
+char hex_encode(unsigned char val) {
+ ASSERT(val < 16);
+ return (val < 16) ? HEX[val] : '!';
+}
+
+unsigned char hex_decode(char ch) {
+ char lower = tolower(ch);
+ ASSERT(((ch >= '0') && (ch <= '9')) || ((lower >= 'a') && (lower <= 'z')));
+ return (ch <= '9') ? (ch - '0') : ((lower - 'a') + 10);
+}
+
+size_t escape(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ const char * illegal, char escape) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ char ch = source[srcpos++];
+ if ((ch == escape) || ::strchr(illegal, ch)) {
+ if (bufpos + 2 >= buflen)
+ break;
+ buffer[bufpos++] = escape;
+ }
+ buffer[bufpos++] = ch;
+ }
+
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t unescape(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ char escape) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ char ch = source[srcpos++];
+ if ((ch == escape) && (srcpos < srclen)) {
+ ch = source[srcpos++];
+ }
+ buffer[bufpos++] = ch;
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ const char * illegal, char escape) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ char ch = source[srcpos++];
+ if ((ch != escape) && !::strchr(illegal, ch)) {
+ buffer[bufpos++] = ch;
+ } else if (bufpos + 3 >= buflen) {
+ break;
+ } else {
+ buffer[bufpos+0] = escape;
+ buffer[bufpos+1] = hex_encode((static_cast<unsigned char>(ch) >> 4) & 0xF);
+ buffer[bufpos+2] = hex_encode((static_cast<unsigned char>(ch) ) & 0xF);
+ bufpos += 3;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ char escape) {
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ char ch = source[srcpos++];
+ if ((ch == escape) && (srcpos + 1 < srclen)) {
+ buffer[bufpos++] = (hex_decode(source[srcpos]) << 4)
+ | hex_decode(source[srcpos+1]);
+ srcpos += 2;
+ } else {
+ buffer[bufpos++] = ch;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+const char* unsafe_filename_characters() {
+ // It might be better to have a single specification which is the union of
+ // all operating systems, unless one system is overly restrictive.
+#ifdef WIN32
+ return "\\/:*?\"<>|";
+#else // !WIN32
+ // TODO
+#endif // !WIN23
+}
+
+const unsigned char URL_UNSAFE = 0x1; // 0-33 "#$%&+,/:;<=>?@[\]^`{|} 127
+const unsigned char XML_UNSAFE = 0x2; // "&'<>
+const unsigned char HTML_UNSAFE = 0x2; // "&'<>
+
+// ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 6 5 7 8 9 : ; < = > ?
+//@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
+//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
+
+const unsigned char ASCII_CLASS[128] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,0,3,1,1,1,3,2,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,3,1,3,1,
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,
+};
+
+size_t url_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ if (NULL == buffer)
+ return srclen * 3 + 1;
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char ch = source[srcpos++];
+ if ((ch < 128) && (ASCII_CLASS[ch] & URL_UNSAFE)) {
+ if (bufpos + 3 >= buflen) {
+ break;
+ }
+ buffer[bufpos+0] = '%';
+ buffer[bufpos+1] = hex_encode((ch >> 4) & 0xF);
+ buffer[bufpos+2] = hex_encode((ch ) & 0xF);
+ bufpos += 3;
+ } else {
+ buffer[bufpos++] = ch;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t url_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ if (NULL == buffer)
+ return srclen + 1;
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char ch = source[srcpos++];
+ if (ch == '+') {
+ buffer[bufpos++] = ' ';
+ } else if ((ch == '%') && (srcpos + 1 < srclen)) {
+ buffer[bufpos++] = (hex_decode(source[srcpos]) << 4)
+ | hex_decode(source[srcpos+1]);
+ srcpos += 2;
+ } else {
+ buffer[bufpos++] = ch;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t utf8_decode(const char* source, size_t srclen, unsigned long* value) {
+ const unsigned char* s = reinterpret_cast<const unsigned char*>(source);
+ if ((s[0] & 0x80) == 0x00) { // Check s[0] == 0xxxxxxx
+ *value = s[0];
+ return 1;
+ }
+ if ((srclen < 2) || ((s[1] & 0xC0) != 0x80)) { // Check s[1] != 10xxxxxx
+ return 0;
+ }
+ // Accumulate the trailer byte values in value16, and combine it with the
+ // relevant bits from s[0], once we've determined the sequence length.
+ unsigned long value16 = (s[1] & 0x3F);
+ if ((s[0] & 0xE0) == 0xC0) { // Check s[0] == 110xxxxx
+ *value = ((s[0] & 0x1F) << 6) | value16;
+ return 2;
+ }
+ if ((srclen < 3) || ((s[2] & 0xC0) != 0x80)) { // Check s[2] != 10xxxxxx
+ return 0;
+ }
+ value16 = (value16 << 6) | (s[2] & 0x3F);
+ if ((s[0] & 0xF0) == 0xE0) { // Check s[0] == 1110xxxx
+ *value = ((s[0] & 0x0F) << 12) | value16;
+ return 3;
+ }
+ if ((srclen < 4) || ((s[3] & 0xC0) != 0x80)) { // Check s[3] != 10xxxxxx
+ return 0;
+ }
+ value16 = (value16 << 6) | (s[3] & 0x3F);
+ if ((s[0] & 0xF8) == 0xF0) { // Check s[0] == 11110xxx
+ *value = ((s[0] & 0x07) << 18) | value16;
+ return 4;
+ }
+ return 0;
+}
+
+size_t utf8_encode(char* buffer, size_t buflen, unsigned long value) {
+ if ((value <= 0x7F) && (buflen >= 1)) {
+ buffer[0] = static_cast<unsigned char>(value);
+ return 1;
+ }
+ if ((value <= 0x7FF) && (buflen >= 2)) {
+ buffer[0] = 0xC0 | static_cast<unsigned char>(value >> 6);
+ buffer[1] = 0x80 | static_cast<unsigned char>(value & 0x3F);
+ return 2;
+ }
+ if ((value <= 0xFFFF) && (buflen >= 3)) {
+ buffer[0] = 0xE0 | static_cast<unsigned char>(value >> 12);
+ buffer[1] = 0x80 | static_cast<unsigned char>((value >> 6) & 0x3F);
+ buffer[2] = 0x80 | static_cast<unsigned char>(value & 0x3F);
+ return 3;
+ }
+ if ((value <= 0x1FFFFF) && (buflen >= 4)) {
+ buffer[0] = 0xF0 | static_cast<unsigned char>(value >> 18);
+ buffer[1] = 0x80 | static_cast<unsigned char>((value >> 12) & 0x3F);
+ buffer[2] = 0x80 | static_cast<unsigned char>((value >> 6) & 0x3F);
+ buffer[3] = 0x80 | static_cast<unsigned char>(value & 0x3F);
+ return 4;
+ }
+ return 0;
+}
+
+size_t html_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char ch = source[srcpos];
+ if (ch < 128) {
+ srcpos += 1;
+ if (ASCII_CLASS[ch] & HTML_UNSAFE) {
+ const char * escseq = 0;
+ size_t esclen = 0;
+ switch (ch) {
+ case '<': escseq = "&lt;"; esclen = 4; break;
+ case '>': escseq = "&gt;"; esclen = 4; break;
+ case '\'': escseq = "&#39;"; esclen = 5; break;
+ case '\"': escseq = "&quot;"; esclen = 6; break;
+ case '&': escseq = "&amp;"; esclen = 5; break;
+ default: ASSERT(false);
+ }
+ if (bufpos + esclen >= buflen) {
+ break;
+ }
+ memcpy(buffer + bufpos, escseq, esclen);
+ bufpos += esclen;
+ } else {
+ buffer[bufpos++] = ch;
+ }
+ } else {
+ // Largest value is 0x1FFFFF => &#2097151; (10 characters)
+ char escseq[11];
+ unsigned long val;
+ if (size_t vallen = utf8_decode(&source[srcpos], srclen - srcpos, &val)) {
+ srcpos += vallen;
+ } else {
+ // Not a valid utf8 sequence, just use the raw character.
+ val = static_cast<unsigned char>(source[srcpos++]);
+ }
+ size_t esclen = sprintfn(escseq, ARRAY_SIZE(escseq), "&#%lu;", val);
+ if (bufpos + esclen >= buflen) {
+ break;
+ }
+ memcpy(buffer + bufpos, escseq, esclen);
+ bufpos += esclen;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t html_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ return xml_decode(buffer, buflen, source, srclen);
+}
+
+size_t xml_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char ch = source[srcpos++];
+ if ((ch < 128) && (ASCII_CLASS[ch] & XML_UNSAFE)) {
+ const char * escseq = 0;
+ size_t esclen = 0;
+ switch (ch) {
+ case '<': escseq = "&lt;"; esclen = 4; break;
+ case '>': escseq = "&gt;"; esclen = 4; break;
+ case '\'': escseq = "&apos;"; esclen = 6; break;
+ case '\"': escseq = "&quot;"; esclen = 6; break;
+ case '&': escseq = "&amp;"; esclen = 5; break;
+ default: ASSERT(false);
+ }
+ if (bufpos + esclen >= buflen) {
+ break;
+ }
+ memcpy(buffer + bufpos, escseq, esclen);
+ bufpos += esclen;
+ } else {
+ buffer[bufpos++] = ch;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t xml_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char ch = source[srcpos++];
+ if (ch != '&') {
+ buffer[bufpos++] = ch;
+ } else if ((srcpos + 2 < srclen)
+ && (memcmp(source + srcpos, "lt;", 3) == 0)) {
+ buffer[bufpos++] = '<';
+ srcpos += 3;
+ } else if ((srcpos + 2 < srclen)
+ && (memcmp(source + srcpos, "gt;", 3) == 0)) {
+ buffer[bufpos++] = '>';
+ srcpos += 3;
+ } else if ((srcpos + 4 < srclen)
+ && (memcmp(source + srcpos, "apos;", 5) == 0)) {
+ buffer[bufpos++] = '\'';
+ srcpos += 5;
+ } else if ((srcpos + 4 < srclen)
+ && (memcmp(source + srcpos, "quot;", 5) == 0)) {
+ buffer[bufpos++] = '\"';
+ srcpos += 5;
+ } else if ((srcpos + 3 < srclen)
+ && (memcmp(source + srcpos, "amp;", 4) == 0)) {
+ buffer[bufpos++] = '&';
+ srcpos += 4;
+ } else if ((srcpos < srclen) && (source[srcpos] == '#')) {
+ int int_base = 10;
+ if ((srcpos + 1 < srclen) && (source[srcpos+1] == 'x')) {
+ int_base = 16;
+ srcpos += 1;
+ }
+ char * ptr;
+ // TODO: Fix hack (ptr may go past end of data)
+ unsigned long val = strtoul(source + srcpos + 1, &ptr, int_base);
+ if ((static_cast<size_t>(ptr - source) < srclen) && (*ptr == ';')) {
+ srcpos = ptr - source + 1;
+ } else {
+ // Not a valid escape sequence.
+ break;
+ }
+ if (size_t esclen = utf8_encode(buffer + bufpos, buflen - bufpos, val)) {
+ bufpos += esclen;
+ } else {
+ // Not enough room to encode the character, or illegal character
+ break;
+ }
+ } else {
+ // Unrecognized escape sequence.
+ break;
+ }
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t hex_encode(char * buffer, size_t buflen,
+ const char * csource, size_t srclen) {
+ ASSERT(NULL != buffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ const unsigned char * bsource =
+ reinterpret_cast<const unsigned char *>(csource);
+
+ size_t srcpos = 0, bufpos = 0;
+ srclen = _min(srclen, (buflen - 1) / 2);
+ while (srcpos < srclen) {
+ unsigned char ch = bsource[srcpos++];
+ buffer[bufpos ] = hex_encode((ch >> 4) & 0xF);
+ buffer[bufpos+1] = hex_encode((ch ) & 0xF);
+ bufpos += 2;
+ }
+ buffer[bufpos] = '\0';
+ return bufpos;
+}
+
+size_t hex_decode(char * cbuffer, size_t buflen,
+ const char * source, size_t srclen) {
+ ASSERT(NULL != cbuffer); // TODO: estimate output size
+ if (buflen <= 0)
+ return 0;
+
+ unsigned char * bbuffer = reinterpret_cast<unsigned char *>(cbuffer);
+
+ size_t srcpos = 0, bufpos = 0;
+ while ((srcpos + 1 < srclen) && (bufpos + 1 < buflen)) {
+ unsigned char v1 = (hex_decode(source[srcpos]) << 4);
+ unsigned char v2 = hex_decode(source[srcpos+1]);
+ bbuffer[bufpos++] = v1 | v2;
+ srcpos += 2;
+ }
+ bbuffer[bufpos] = '\0';
+ return bufpos;
+}
+
+void transform(std::string& value, size_t maxlen, const std::string& source,
+ Transform t) {
+ char * buffer = static_cast<char *>(_alloca(maxlen + 1));
+ value.assign(buffer, t(buffer, maxlen + 1, source.data(), source.length()));
+}
+
+std::string s_transform(const std::string& source, Transform t) {
+ // Ask transformation function to approximate the destination size (returns upper bound)
+ size_t maxlen = t(NULL, 0, source.data(), source.length());
+ char * buffer = static_cast<char *>(_alloca(maxlen));
+ size_t len = t(buffer, maxlen, source.data(), source.length());
+ std::string result(buffer, len);
+ return result;
+}
+
+char make_char_safe_for_filename(char c) {
+ if (c < 32)
+ return '_';
+
+ switch (c) {
+ case '<':
+ case '>':
+ case ':':
+ case '"':
+ case '/':
+ case '\\':
+ case '|':
+ case '*':
+ case '?':
+ return '_';
+
+ default:
+ return c;
+ }
+}
+
+/*
+void sprintf(std::string& value, size_t maxlen, const char * format, ...) {
+ char * buffer = static_cast<char *>(alloca(maxlen + 1));
+ va_list args;
+ va_start(args, format);
+ value.assign(buffer, vsprintfn(buffer, maxlen + 1, format, args));
+ va_end(args);
+}
+*/
+
+/////////////////////////////////////////////////////////////////////////////
+// Unit Tests
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(NDEBUG)
+
+static int utf8_unittest() {
+ const struct Utf8Test {
+ const char* encoded;
+ size_t encsize, enclen;
+ unsigned long decoded;
+ } kTests[] = {
+ { "a ", 5, 1, 'a' },
+ { "\x7F ", 5, 1, 0x7F },
+ { "\xC2\x80 ", 5, 2, 0x80 },
+ { "\xDF\xBF ", 5, 2, 0x7FF },
+ { "\xE0\xA0\x80 ", 5, 3, 0x800 },
+ { "\xEF\xBF\xBF ", 5, 3, 0xFFFF },
+ { "\xF0\x90\x80\x80 ", 5, 4, 0x10000 },
+ { "\xF0\x90\x80\x80 ", 3, 0, 0x10000 },
+ { "\xF0\xF0\x80\x80 ", 5, 0, 0 },
+ { "\xF0\x90\x80 ", 5, 0, 0 },
+ { "\x90\x80\x80 ", 5, 0, 0 },
+ { NULL, 0, 0 },
+ };
+ for (size_t i=0; kTests[i].encoded; ++i) {
+ unsigned long val = 0;
+ ASSERT(kTests[i].enclen == utf8_decode(kTests[i].encoded,
+ kTests[i].encsize,
+ &val));
+ unsigned long result = (kTests[i].enclen == 0) ? 0 : kTests[i].decoded;
+ ASSERT(val == result);
+
+ if (kTests[i].decoded == 0) {
+ // Not an interesting encoding test case
+ continue;
+ }
+
+ char buffer[5];
+ memset(buffer, 0x01, ARRAY_SIZE(buffer));
+ ASSERT(kTests[i].enclen == utf8_encode(buffer,
+ kTests[i].encsize,
+ kTests[i].decoded));
+ ASSERT(memcmp(buffer, kTests[i].encoded, kTests[i].enclen) == 0);
+ // Make sure remainder of buffer is unchanged
+ ASSERT(memory_check(buffer + kTests[i].enclen,
+ 0x1,
+ ARRAY_SIZE(buffer) - kTests[i].enclen));
+ }
+ return 1;
+}
+
+int test = utf8_unittest();
+
+#endif // !defined(NDEBUG)
+
+/////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/stringencode.h b/third_party/libjingle/files/talk/base/stringencode.h
new file mode 100644
index 0000000..08e5e4f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringencode.h
@@ -0,0 +1,166 @@
+/*
+ * 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 TALK_BASE_STRINGENCODE_H__
+#define TALK_BASE_STRINGENCODE_H__
+
+#include <string>
+#include <sstream>
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// String Encoding Utilities
+//////////////////////////////////////////////////////////////////////
+
+// Convert an unsigned value from 0 to 15 to the hex character equivalent...
+char hex_encode(unsigned char val);
+// ...and vice-versa.
+unsigned char hex_decode(char ch);
+
+// Convert an unsigned value to it's utf8 representation. Returns the length
+// of the encoded string, or 0 if the encoding is longer than buflen - 1.
+size_t utf8_encode(char* buffer, size_t buflen, unsigned long value);
+// Decode the utf8 encoded value pointed to by source. Returns the number of
+// bytes used by the encoding, or 0 if the encoding is invalid.
+size_t utf8_decode(const char* source, size_t srclen, unsigned long* value);
+
+// Escaping prefixes illegal characters with the escape character. Compact, but
+// illegal characters still appear in the string.
+size_t escape(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ const char * illegal, char escape);
+// Note: in-place unescaping (buffer == source) is allowed.
+size_t unescape(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ char escape);
+
+// Encoding replaces illegal characters with the escape character and 2 hex
+// chars, so it's a little less compact than escape, but completely removes
+// illegal characters. note that hex digits should not be used as illegal
+// characters.
+size_t encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ const char * illegal, char escape);
+// Note: in-place decoding (buffer == source) is allowed.
+size_t decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+ char escape);
+
+// Returns a list of characters that may be unsafe for use in the name of a
+// file, suitable for passing to the 'illegal' member of escape or encode.
+const char* unsafe_filename_characters();
+
+// url_encode is an encode operation with a predefined set of illegal characters
+// and escape character (for use in URLs, obviously).
+size_t url_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+// Note: in-place decoding (buffer == source) is allowed.
+size_t url_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+
+// html_encode prevents data embedded in html from containing markup.
+size_t html_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+// Note: in-place decoding (buffer == source) is allowed.
+size_t html_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+
+// xml_encode makes data suitable for inside xml attributes and values.
+size_t xml_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+// Note: in-place decoding (buffer == source) is allowed.
+size_t xml_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+
+// hex_encode shows the hex representation of binary data in ascii.
+size_t hex_encode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+size_t hex_decode(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+
+// Apply any suitable string transform (including the ones above) to an STL
+// string. Stack-allocated temporary space is used for the transformation,
+// so value and source may refer to the same string.
+typedef size_t (*Transform)(char * buffer, size_t buflen,
+ const char * source, size_t srclen);
+void transform(std::string& value, size_t maxlen, const std::string& source,
+ Transform t);
+
+// Return the result of applying transform t to source.
+std::string s_transform(const std::string& source, Transform t);
+
+// Convenience wrappers
+inline std::string s_url_encode(const std::string& source) {
+ return s_transform(source, url_encode);
+}
+inline std::string s_url_decode(const std::string& source) {
+ return s_transform(source, url_decode);
+}
+
+// Safe sprintf to std::string
+//void sprintf(std::string& value, size_t maxlen, const char * format, ...)
+// PRINTF_FORMAT(3);
+
+// Convert arbitrary values to/from a string.
+
+template <class T>
+static bool ToString(const T &t, std::string* s) {
+ std::ostringstream oss;
+ oss << t;
+ *s = oss.str();
+ return !oss.fail();
+}
+
+template <class T>
+static bool FromString(const std::string& s, T* t) {
+ std::istringstream iss(s);
+ iss >> *t;
+ return !iss.fail();
+}
+
+// Inline versions of the string conversion routines.
+
+template<typename T>
+static inline std::string ToString(T val) {
+ std::string str; ToString(val, &str); return str;
+}
+
+template<typename T>
+static inline T FromString(const std::string& str) {
+ T val; FromString(str, &val); return val;
+}
+
+// simple function to strip out characters which shouldn't be
+// used in filenames
+char make_char_safe_for_filename(char c);
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_STRINGENCODE_H__
diff --git a/third_party/libjingle/files/talk/base/stringutils.cc b/third_party/libjingle/files/talk/base/stringutils.cc
new file mode 100644
index 0000000..7ade7e5
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringutils.cc
@@ -0,0 +1,84 @@
+/*
+ * 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/base/stringutils.h"
+#include "talk/base/common.h"
+
+namespace talk_base {
+
+bool memory_check(const void* memory, int c, size_t count) {
+ const char* char_memory = static_cast<const char*>(memory);
+ char char_c = static_cast<char>(c);
+ for (size_t i=0; i<count; ++i) {
+ if (char_memory[i] != char_c) {
+ return false;
+ }
+ }
+ return true;
+}
+
+#ifdef WIN32
+int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
+ CharacterTransformation transformation) {
+ wchar_t c1, c2;
+ while (true) {
+ if (n-- == 0) return 0;
+ c1 = transformation(*s1);
+ // Double check that characters are not UTF-8
+ ASSERT(static_cast<unsigned char>(*s2) < 128);
+ // Note: *s2 gets implicitly promoted to wchar_t
+ c2 = transformation(*s2);
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
+ if (!c1) return 0;
+ ++s1;
+ ++s2;
+ }
+}
+
+size_t asccpyn(wchar_t* buffer, size_t buflen,
+ const char* source, size_t srclen) {
+ if (buflen <= 0)
+ return 0;
+
+ if (srclen == SIZE_UNKNOWN) {
+ srclen = strlenn(source, buflen - 1);
+ } else if (srclen >= buflen) {
+ srclen = buflen - 1;
+ }
+#if !defined(NDEBUG)
+ // Double check that characters are not UTF-8
+ for (size_t pos = 0; pos < srclen; ++pos)
+ ASSERT(static_cast<unsigned char>(source[pos]) < 128);
+#endif // !defined(NDEBUG)
+ std::copy(source, source + srclen, buffer);
+ buffer[srclen] = 0;
+ return srclen;
+}
+
+#endif // WIN32
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/stringutils.h b/third_party/libjingle/files/talk/base/stringutils.h
new file mode 100644
index 0000000..03fb749
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/stringutils.h
@@ -0,0 +1,294 @@
+/*
+ * 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 TALK_BASE_STRINGUTILS_H__
+#define TALK_BASE_STRINGUTILS_H__
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#include <wchar.h>
+#endif // WIN32
+
+#include <string>
+
+///////////////////////////////////////////////////////////////////////////////
+// Generic string/memory utilities
+///////////////////////////////////////////////////////////////////////////////
+
+namespace talk_base {
+
+// Complement to memset. Verifies memory consists of count bytes of value c.
+bool memory_check(const void* memory, int c, size_t count);
+
+} // namespace talk_base
+
+///////////////////////////////////////////////////////////////////////////////
+// Rename a bunch of common string functions so they are consistent across
+// platforms and between char and wchar_t variants.
+// Here is the full list of functions that are unified:
+// strlen, strcmp, stricmp, strncmp, strnicmp
+// strchr, vsnprintf, strtoul, tolowercase
+// tolowercase is like tolower, but not compatible with end-of-file value
+// Note that the wchar_t versions are not available on Linux
+///////////////////////////////////////////////////////////////////////////////
+
+inline char tolowercase(char c) {
+ return static_cast<char>(tolower(c));
+}
+
+#ifdef WIN32
+
+inline size_t strlen(const wchar_t* s) {
+ return wcslen(s);
+}
+inline int strcmp(const wchar_t* s1, const wchar_t* s2) {
+ return wcscmp(s1, s2);
+}
+inline int stricmp(const wchar_t* s1, const wchar_t* s2) {
+ return _wcsicmp(s1, s2);
+}
+inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
+ return wcsncmp(s1, s2, n);
+}
+inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
+ return _wcsnicmp(s1, s2, n);
+}
+inline const wchar_t* strchr(const wchar_t* s, wchar_t c) {
+ return wcschr(s, c);
+}
+inline const wchar_t* strstr(const wchar_t* haystack, const wchar_t* needle) {
+ return wcsstr(haystack, needle);
+}
+#if 0
+inline int vsnprintf(char* buf, size_t n, const char* fmt, va_list args) {
+ return _vsnprintf(buf, n, fmt, args);
+}
+inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) {
+ return _vsnwprintf(buf, n, fmt, args);
+}
+#endif
+inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) {
+ return wcstoul(snum, end, base);
+}
+inline wchar_t tolowercase(wchar_t c) {
+ return static_cast<wchar_t>(towlower(c));
+}
+
+#endif // WIN32
+
+#ifdef POSIX
+
+inline int _stricmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline int _strnicmp(const char* s1, const char* s2, size_t n) {
+ return strncasecmp(s1, s2, n);
+}
+
+#endif // POSIX
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits simplifies porting string functions to be CTYPE-agnostic
+///////////////////////////////////////////////////////////////////////////////
+
+namespace talk_base {
+
+const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
+
+template<class CTYPE>
+struct Traits {
+ // STL string type
+ //typedef XXX string;
+ // Null-terminated string
+ //inline static const CTYPE* empty_str();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// String utilities which work with char or wchar_t
+///////////////////////////////////////////////////////////////////////////////
+
+template<class CTYPE>
+inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) {
+ return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
+}
+
+template<class CTYPE>
+const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
+ for (size_t i=0; str[i]; ++i) {
+ for (size_t j=0; chs[j]; ++j) {
+ if (str[i] == chs[j]) {
+ return str + i;
+ }
+ }
+ }
+ return 0;
+}
+
+template<class CTYPE>
+const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
+ for (size_t i=0; i<slen && str[i]; ++i) {
+ if (str[i] == ch) {
+ return str + i;
+ }
+ }
+ return 0;
+}
+
+template<class CTYPE>
+size_t strlenn(const CTYPE* buffer, size_t buflen) {
+ size_t bufpos = 0;
+ while (buffer[bufpos] && (bufpos < buflen)) {
+ ++bufpos;
+ }
+ return bufpos;
+}
+
+// Safe versions of strncpy, strncat, snprintf and vsnprintf that always
+// null-terminate.
+
+template<class CTYPE>
+size_t strcpyn(CTYPE* buffer, size_t buflen,
+ const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
+ if (buflen <= 0)
+ return 0;
+
+ if (srclen == SIZE_UNKNOWN) {
+ srclen = strlenn(source, buflen - 1);
+ } else if (srclen >= buflen) {
+ srclen = buflen - 1;
+ }
+ memcpy(buffer, source, srclen * sizeof(CTYPE));
+ buffer[srclen] = 0;
+ return srclen;
+}
+
+template<class CTYPE>
+size_t strcatn(CTYPE* buffer, size_t buflen,
+ const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
+ if (buflen <= 0)
+ return 0;
+
+ size_t bufpos = strlenn(buffer, buflen - 1);
+ return bufpos + strcpyn(buffer + bufpos, buflen - bufpos, source, srclen);
+}
+
+template<class CTYPE>
+size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format,
+ va_list args) {
+ int len = vsnprintf(buffer, buflen, format, args);
+ if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
+ len = static_cast<int>(buflen - 1);
+ buffer[len] = 0;
+ }
+ return len;
+}
+
+template<class CTYPE>
+size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
+ va_list args;
+ va_start(args, format);
+ size_t len = vsprintfn(buffer, buflen, format, args);
+ va_end(args);
+ return len;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Allow safe comparing and copying ascii (not UTF-8) with both wide and
+// non-wide character strings.
+///////////////////////////////////////////////////////////////////////////////
+
+inline int asccmp(const char* s1, const char* s2) {
+ return strcmp(s1, s2);
+}
+inline int ascicmp(const char* s1, const char* s2) {
+ return _stricmp(s1, s2);
+}
+inline int ascncmp(const char* s1, const char* s2, size_t n) {
+ return strncmp(s1, s2, n);
+}
+inline int ascnicmp(const char* s1, const char* s2, size_t n) {
+ return _strnicmp(s1, s2, n);
+}
+inline size_t asccpyn(char* buffer, size_t buflen,
+ const char* source, size_t srclen = SIZE_UNKNOWN) {
+ return strcpyn(buffer, buflen, source, srclen);
+}
+
+#ifdef WIN32
+
+typedef wchar_t(*CharacterTransformation)(wchar_t);
+inline wchar_t identity(wchar_t c) { return c; }
+int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
+ CharacterTransformation transformation);
+
+inline int asccmp(const wchar_t* s1, const char* s2) {
+ return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity);
+}
+inline int ascicmp(const wchar_t* s1, const char* s2) {
+ return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase);
+}
+inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) {
+ return ascii_string_compare(s1, s2, n, identity);
+}
+inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
+ return ascii_string_compare(s1, s2, n, tolowercase);
+}
+size_t asccpyn(wchar_t* buffer, size_t buflen,
+ const char* source, size_t srclen = SIZE_UNKNOWN);
+
+#endif // WIN32
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits<char> specializations
+///////////////////////////////////////////////////////////////////////////////
+
+template<>
+struct Traits<char> {
+ typedef std::string string;
+ inline static const char* empty_str() { return ""; }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits<wchar_t> specializations (Windows only, currently)
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef WIN32
+
+template<>
+struct Traits<wchar_t> {
+ typedef std::wstring string;
+ inline static const wchar_t* Traits<wchar_t>::empty_str() { return L""; }
+};
+
+#endif // WIN32
+
+} // namespace talk_base
+
+#endif // TALK_BASE_STRINGUTILS_H__
diff --git a/third_party/libjingle/files/talk/base/tarstream.cc b/third_party/libjingle/files/talk/base/tarstream.cc
new file mode 100644
index 0000000..e1f17b1
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/tarstream.cc
@@ -0,0 +1,601 @@
+#include "talk/base/basicdefs.h"
+#include "talk/base/basictypes.h"
+#include "talk/base/tarstream.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/common.h"
+
+using namespace talk_base;
+
+///////////////////////////////////////////////////////////////////////////////
+// TarStream
+///////////////////////////////////////////////////////////////////////////////
+
+TarStream::TarStream() : mode_(M_NONE), next_block_(NB_NONE), block_pos_(0),
+ current_(NULL), current_bytes_(0) {
+}
+
+TarStream::~TarStream() {
+ Close();
+}
+
+bool TarStream::AddFilter(const std::string& pathname) {
+ if (pathname.empty())
+ return false;
+ Pathname archive_path(pathname);
+ archive_path.SetFolderDelimiter('/');
+ archive_path.Normalize();
+ filters_.push_back(archive_path.pathname());
+ return true;
+}
+
+bool TarStream::Open(const std::string& folder, bool read) {
+ Close();
+
+ Pathname root_folder;
+ root_folder.SetFolder(folder);
+ root_folder.Normalize();
+ root_folder_.assign(root_folder.folder());
+
+ if (read) {
+ std::string pattern(root_folder_);
+ DirectoryIterator *iter = new DirectoryIterator();
+
+ if (iter->Iterate(pattern) == false) {
+ delete iter;
+ return false;
+ }
+ mode_ = M_READ;
+ find_.push_front(iter);
+ next_block_ = NB_FILE_HEADER;
+ block_pos_ = BLOCK_SIZE;
+ int error;
+ if (SR_SUCCESS != ProcessNextEntry(find_.front(), &error)) {
+ return false;
+ }
+ } else {
+ if (!Filesystem::CreateFolder(root_folder_)) {
+ return false;
+ }
+
+ mode_ = M_WRITE;
+ next_block_ = NB_FILE_HEADER;
+ block_pos_ = 0;
+ }
+ return true;
+}
+
+StreamState TarStream::GetState() const {
+ return (M_NONE == mode_) ? SS_CLOSED : SS_OPEN;
+}
+
+StreamResult TarStream::Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) {
+ if (M_READ != mode_) {
+ return SR_EOS;
+ }
+ return ProcessBuffer(buffer, buffer_len, read, error);
+}
+
+StreamResult TarStream::Write(const void* data, size_t data_len,
+ size_t* written, int* error) {
+ if (M_WRITE != mode_) {
+ return SR_EOS;
+ }
+ // Note: data is not modified unless M_READ == mode_
+ return ProcessBuffer(const_cast<void*>(data), data_len, written, error);
+}
+
+void TarStream::Close() {
+ root_folder_.clear();
+ next_block_ = NB_NONE;
+ block_pos_ = 0;
+ delete current_;
+ current_ = NULL;
+ current_bytes_ = 0;
+ for (DirectoryList::iterator it = find_.begin(); it != find_.end(); ++it) {
+ delete(*it);
+ }
+ find_.clear();
+ subfolder_.clear();
+}
+
+StreamResult TarStream::ProcessBuffer(void* buffer, size_t buffer_len,
+ size_t* consumed, int* error) {
+ size_t local_consumed;
+ if (!consumed) consumed = &local_consumed;
+ int local_error;
+ if (!error) error = &local_error;
+
+ StreamResult result = SR_SUCCESS;
+ *consumed = 0;
+
+ while (*consumed < buffer_len) {
+ size_t available = BLOCK_SIZE - block_pos_;
+ if (available == 0) {
+ result = ProcessNextBlock(error);
+ if (SR_SUCCESS != result) {
+ break;
+ }
+ } else {
+ size_t bytes_to_copy = talk_base::_min(available, buffer_len - *consumed);
+ char* buffer_ptr = static_cast<char*>(buffer) + *consumed;
+ char* block_ptr = block_ + block_pos_;
+ if (M_READ == mode_) {
+ memcpy(buffer_ptr, block_ptr, bytes_to_copy);
+ } else {
+ memcpy(block_ptr, buffer_ptr, bytes_to_copy);
+ }
+ *consumed += bytes_to_copy;
+ block_pos_ += bytes_to_copy;
+ }
+ }
+
+ // SR_EOS means no data was consumed on this operation. So we may need to
+ // return SR_SUCCESS instead, and then we will return SR_EOS next time.
+ if ((SR_EOS == result) && (*consumed > 0)) {
+ result = SR_SUCCESS;
+ }
+
+ return result;
+}
+
+StreamResult TarStream::ProcessNextBlock(int* error) {
+ ASSERT(NULL != error);
+ ASSERT(M_NONE != mode_);
+ ASSERT(BLOCK_SIZE == block_pos_);
+
+ StreamResult result;
+ if (NB_NONE == next_block_) {
+
+ return SR_EOS;
+
+ } else if (NB_TRAILER == next_block_) {
+
+ // Trailer block is zeroed
+ result = ProcessEmptyBlock(0, error);
+ if (SR_SUCCESS != result)
+ return result;
+ next_block_ = NB_NONE;
+
+ } else if (NB_FILE_HEADER == next_block_) {
+
+ if (M_READ == mode_) {
+ result = ReadNextFile(error);
+ } else {
+ result = WriteNextFile(error);
+ }
+
+ // If there are no more files, we are at the first trailer block
+ if (SR_EOS == result) {
+ block_pos_ = 0;
+ next_block_ = NB_TRAILER;
+ result = ProcessEmptyBlock(0, error);
+ }
+ if (SR_SUCCESS != result)
+ return result;
+
+ } else if (NB_DATA == next_block_) {
+
+ size_t block_consumed = 0;
+ size_t block_available = talk_base::_min<size_t>(BLOCK_SIZE, current_bytes_);
+ while (block_consumed < block_available) {
+ void* block_ptr = static_cast<char*>(block_) + block_consumed;
+ size_t available = block_available - block_consumed, consumed;
+ if (M_READ == mode_) {
+ ASSERT(NULL != current_);
+ result = current_->Read(block_ptr, available, &consumed, error);
+ } else if (current_) {
+ result = current_->Write(block_ptr, available, &consumed, error);
+ } else {
+ consumed = available;
+ result = SR_SUCCESS;
+ }
+ switch (result) {
+ case SR_ERROR:
+ return result;
+ case SR_BLOCK:
+ case SR_EOS:
+ ASSERT(false);
+ *error = 0; // TODO: make errors
+ return SR_ERROR;
+ case SR_SUCCESS:
+ block_consumed += consumed;
+ break;
+ }
+ }
+
+ current_bytes_ -= block_consumed;
+ if (current_bytes_ == 0) {
+ // The remainder of the block is zeroed
+ result = ProcessEmptyBlock(block_consumed, error);
+ if (SR_SUCCESS != result)
+ return result;
+ delete current_;
+ current_ = NULL;
+ next_block_ = NB_FILE_HEADER;
+ }
+
+ } else {
+ ASSERT(false);
+ }
+
+ block_pos_ = 0;
+ return SR_SUCCESS;
+}
+
+StreamResult TarStream::ProcessEmptyBlock(size_t start, int* error) {
+ ASSERT(NULL != error);
+ ASSERT(M_NONE != mode_);
+ if (M_READ == mode_) {
+ memset(block_ + start, 0, BLOCK_SIZE - start);
+ } else {
+ if (!talk_base::memory_check(block_ + start, 0, BLOCK_SIZE - start)) {
+ *error = 0; // TODO: make errors
+ return SR_ERROR;
+ }
+ }
+ return SR_SUCCESS;
+}
+
+StreamResult TarStream::ReadNextFile(int* error) {
+ ASSERT(NULL != error);
+ ASSERT(M_READ == mode_);
+ ASSERT(NB_FILE_HEADER == next_block_);
+ ASSERT(BLOCK_SIZE == block_pos_);
+ ASSERT(NULL == current_);
+
+ // ReadNextFile conducts a depth-first recursive search through the directory
+ // tree. find_ maintains a stack of open directory handles, which
+ // corresponds to our current position in the tree. At any point, the
+ // directory at the top (front) of the stack is being enumerated. If a
+ // directory is found, it is opened and pushed onto the top of the stack.
+ // When a directory enumeration completes, that directory is popped off the
+ // top of the stack.
+
+ // Note: Since ReadNextFile can only return one block of data at a time, we
+ // cannot simultaneously return the entry for a directory, and the entry for
+ // the first element in that directory at the same time. In this case, we
+ // push a NULL entry onto the find_ stack, which indicates that the next
+ // iteration should begin enumeration of the "new" directory.
+ StreamResult result = SR_SUCCESS;
+ while (BLOCK_SIZE == block_pos_) {
+ ASSERT(!find_.empty());
+
+ if (NULL != find_.front()) {
+ if (find_.front()->Next()) {
+ result = ProcessNextEntry(find_.front(), error);
+ if (SR_SUCCESS != result) {
+ return result;
+ }
+ continue;
+ }
+ delete(find_.front());
+ } else {
+ Pathname pattern(root_folder_);
+ pattern.AppendFolder(subfolder_);
+ find_.front() = new DirectoryIterator();
+ if (find_.front()->Iterate(pattern.pathname())) {
+ result = ProcessNextEntry(find_.front(), error);
+ if (SR_SUCCESS != result) {
+ return result;
+ }
+ continue;
+ }
+ // TODO: should this be an error?
+ LOG_F(LS_WARNING) << "Couldn't open folder: " << pattern.pathname();
+ }
+
+ find_.pop_front();
+ subfolder_ = Pathname(subfolder_).parent_folder();
+
+ if (find_.empty()) {
+ return SR_EOS;
+ }
+ }
+
+ ASSERT(0 == block_pos_);
+ return SR_SUCCESS;
+}
+
+StreamResult TarStream::WriteNextFile(int* error) {
+ ASSERT(NULL != error);
+ ASSERT(M_WRITE == mode_);
+ ASSERT(NB_FILE_HEADER == next_block_);
+ ASSERT(BLOCK_SIZE == block_pos_);
+ ASSERT(NULL == current_);
+ ASSERT(0 == current_bytes_);
+
+ std::string pathname, link, linked_name, magic, mversion;
+ size_t file_size, modify_time, unused, checksum;
+
+ size_t block_data = 0;
+ ReadFieldS(block_data, 100, &pathname);
+ ReadFieldN(block_data, 8, &unused); // mode
+ ReadFieldN(block_data, 8, &unused); // owner uid
+ ReadFieldN(block_data, 8, &unused); // owner gid
+ ReadFieldN(block_data, 12, &file_size);
+ ReadFieldN(block_data, 12, &modify_time);
+ ReadFieldN(block_data, 8, &checksum);
+ if (checksum == 0)
+ block_data -= 8; // back-compatiblity
+ ReadFieldS(block_data, 1, &link);
+ ReadFieldS(block_data, 100, &linked_name); // name of linked file
+ ReadFieldS(block_data, 6, &magic);
+ ReadFieldS(block_data, 2, &mversion);
+
+ if (pathname.empty())
+ return SR_EOS;
+
+ std::string user, group, dev_major, dev_minor, prefix;
+ if (magic == "ustar" || magic == "ustar ") {
+ ReadFieldS(block_data, 32, &user);
+ ReadFieldS(block_data, 32, &group);
+ ReadFieldS(block_data, 8, &dev_major);
+ ReadFieldS(block_data, 8, &dev_minor);
+ ReadFieldS(block_data, 155, &prefix);
+
+ pathname = prefix + pathname;
+ }
+
+ // Rest of the block must be empty
+ StreamResult result = ProcessEmptyBlock(block_data, error);
+ if (SR_SUCCESS != result) {
+ return result;
+ }
+
+ Pathname archive_path(pathname);
+ archive_path.SetFolderDelimiter('/');
+ archive_path.Normalize();
+
+ bool is_folder = archive_path.filename().empty();
+ if (is_folder) {
+ ASSERT(NB_FILE_HEADER == next_block_);
+ ASSERT(0 == file_size);
+ } else if (file_size > 0) {
+ // We assign current_bytes_ because we must skip over the upcoming data
+ // segments, regardless of whether we want to write them.
+ next_block_ = NB_DATA;
+ current_bytes_ = file_size;
+ }
+
+ if (!CheckFilter(archive_path.pathname())) {
+ // If it's a directory, we will ignore it and all children by nature of
+ // filter prefix matching. If it is a file, we will ignore it because
+ // current_ is NULL.
+ return SR_SUCCESS;
+ }
+
+ // Sanity checks:
+ // 1) No .. path segments
+ if (archive_path.pathname().find("../") != std::string::npos) {
+ LOG_F(LS_WARNING) << "Skipping path with .. entry: "
+ << archive_path.pathname();
+ return SR_SUCCESS;
+ }
+ // 2) No drive letters
+ if (archive_path.pathname().find(':') != std::string::npos) {
+ LOG_F(LS_WARNING) << "Skipping path with drive letter: "
+ << archive_path.pathname();
+ return SR_SUCCESS;
+ }
+ // 3) No absolute paths
+ if (archive_path.pathname().find("//") != std::string::npos) {
+ LOG_F(LS_WARNING) << "Skipping absolute path: "
+ << archive_path.pathname();
+ return SR_SUCCESS;
+ }
+
+ Pathname local_path(root_folder_);
+ local_path.AppendPathname(archive_path.pathname());
+ local_path.Normalize();
+
+ if (is_folder) {
+ if (!Filesystem::CreateFolder(local_path)) {
+ LOG_F(LS_WARNING) << "Couldn't create folder: " << local_path.pathname();
+ *error = 0; // TODO
+ return SR_ERROR;
+ }
+ } else {
+ FileStream* stream = new FileStream;
+
+ if (!stream->Open(local_path.pathname().c_str(), "wb")) {
+ LOG_F(LS_WARNING) << "Couldn't create file: " << local_path.pathname();
+ *error = 0; // TODO
+ delete stream;
+ return SR_ERROR;
+ }
+ if (file_size > 0) {
+ current_ = stream;
+ } else {
+ stream->Close();
+ delete stream;
+ }
+ }
+
+ SignalNextEntry(archive_path.filename(), current_bytes_);
+
+
+ return SR_SUCCESS;
+}
+
+StreamResult TarStream::ProcessNextEntry(const DirectoryIterator *data, int *error) {
+ ASSERT(M_READ == mode_);
+ ASSERT(NB_FILE_HEADER == next_block_);
+ ASSERT(BLOCK_SIZE == block_pos_);
+ ASSERT(NULL == current_);
+ ASSERT(0 == current_bytes_);
+
+ if (data->IsDirectory() &&
+ (data->Name() == "." || data->Name() == ".."))
+ return SR_SUCCESS;
+
+ Pathname archive_path;
+ archive_path.SetFolder(subfolder_);
+ if (data->IsDirectory()) {
+ archive_path.AppendFolder(data->Name());
+ } else {
+ archive_path.SetFilename(data->Name());
+ }
+ archive_path.SetFolderDelimiter('/');
+ archive_path.Normalize();
+
+ if (!CheckFilter(archive_path.pathname()))
+ return SR_SUCCESS;
+
+ if (archive_path.pathname().length() > 255) {
+ // Cannot send a file name longer than 255 (yet)
+ return SR_ERROR;
+ }
+
+ Pathname local_path(root_folder_);
+ local_path.AppendPathname(archive_path.pathname());
+ local_path.Normalize();
+
+ if (data->IsDirectory()) {
+ // Note: the NULL handle indicates that we need to open the folder next
+ // time.
+ find_.push_front(NULL);
+ subfolder_ = archive_path.pathname();
+ } else {
+ FileStream* stream = new FileStream;
+ if (!stream->Open(local_path.pathname().c_str(), "rb")) {
+ // TODO: Should this be an error?
+ LOG_F(LS_WARNING) << "Couldn't open file: " << local_path.pathname();
+ delete stream;
+ return SR_SUCCESS;
+ }
+ current_ = stream;
+ current_bytes_ = data->FileSize();
+ }
+
+ time_t modify_time = data->FileModifyTime();
+
+ std::string pathname = archive_path.pathname();
+ std::string magic, user, group, dev_major, dev_minor, prefix;
+ std::string name = pathname;
+ bool ustar = false;
+ if (name.length() > 100) {
+ ustar = true;
+ // Put last 100 characters into the name, and rest in prefix
+ size_t path_length = pathname.length();
+ prefix = pathname.substr(0, path_length - 100);
+ name = pathname.substr(path_length - 100);
+ }
+
+ size_t block_data = 0;
+ memset(block_, 0, BLOCK_SIZE);
+ WriteFieldS(block_data, 100, name.c_str());
+ WriteFieldS(block_data, 8, data->IsDirectory() ? "777" : "666"); // mode
+ WriteFieldS(block_data, 8, "5"); // owner uid
+ WriteFieldS(block_data, 8, "5"); // owner gid
+ WriteFieldN(block_data, 12, current_bytes_);
+ WriteFieldN(block_data, 12, modify_time);
+ WriteFieldS(block_data, 8, " "); // Checksum. To be filled in later.
+ WriteFieldS(block_data, 1, data->IsDirectory() ? "5" : "0"); // link indicator (0 == normal file, 5 == directory)
+ WriteFieldS(block_data, 100, ""); // name of linked file
+
+ if (ustar) {
+ WriteFieldS(block_data, 6, "ustar");
+ WriteFieldS(block_data, 2, "");
+ WriteFieldS(block_data, 32, user.c_str());
+ WriteFieldS(block_data, 32, group.c_str());
+ WriteFieldS(block_data, 8, dev_major.c_str());
+ WriteFieldS(block_data, 8, dev_minor.c_str());
+ WriteFieldS(block_data, 155, prefix.c_str());
+ }
+
+ // Rest of the block must be empty
+ StreamResult result = ProcessEmptyBlock(block_data, error);
+ WriteChecksum();
+
+ block_pos_ = 0;
+ if (current_bytes_ > 0) {
+ next_block_ = data->IsDirectory() ? NB_FILE_HEADER : NB_DATA;
+ }
+
+ SignalNextEntry(archive_path.filename(), current_bytes_);
+
+ return result;
+}
+
+void TarStream::WriteChecksum() {
+ unsigned int sum = 0;
+
+ for (int i = 0; i < BLOCK_SIZE; i++)
+ sum += static_cast<unsigned char>(block_[i]);
+
+ sprintf(block_ + 148, "%06o", sum);
+}
+
+bool TarStream::CheckFilter(const std::string& pathname) {
+ if (filters_.empty())
+ return true;
+
+ // pathname is allowed when there is a filter which:
+ // A) Equals name
+ // B) Matches a folder prefix of name
+ for (size_t i=0; i<filters_.size(); ++i) {
+ const std::string& filter = filters_[i];
+ // Make sure the filter is a prefix of name
+ if (_strnicmp(pathname.c_str(), filter.data(), filter.length()) != 0)
+ continue;
+
+ // If the filter is not a directory, must match exactly
+ if (!Pathname::IsFolderDelimiter(filter[filter.length()-1])
+ && (filter.length() != pathname.length()))
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+void TarStream::WriteFieldN(size_t& pos, size_t max_len, size_t numeric_field) {
+ WriteFieldF(pos, max_len, "%.*o", max_len - 1, numeric_field);
+}
+
+void TarStream::WriteFieldS(size_t& pos, size_t max_len,
+ const char* string_field) {
+ ASSERT(pos + max_len <= BLOCK_SIZE);
+ size_t len = strlen(string_field);
+ size_t use_len = _min(len, max_len);
+ memcpy(block_ + pos, string_field, use_len);
+ pos += max_len;
+}
+
+void TarStream::WriteFieldF(size_t& pos, size_t max_len,
+ const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ char buffer[BLOCK_SIZE];
+ vsprintfn(buffer, ARRAY_SIZE(buffer), format, args);
+ WriteFieldS(pos, max_len, buffer);
+ va_end(args);
+}
+
+void TarStream::ReadFieldN(size_t& pos, size_t max_len, size_t* numeric_field) {
+ ASSERT(NULL != numeric_field);
+ std::string buffer;
+ ReadFieldS(pos, max_len, &buffer);
+
+ int value;
+ if (!buffer.empty() && (1 == sscanf(buffer.c_str(), "%o", &value))) {
+ *numeric_field = value;
+ } else {
+ *numeric_field = 0;
+ }
+}
+
+void TarStream::ReadFieldS(size_t& pos, size_t max_len,
+ std::string* string_field) {
+ ASSERT(NULL != string_field);
+ ASSERT(pos + max_len <= BLOCK_SIZE);
+ size_t value_len = talk_base::strlenn(block_ + pos, max_len);
+ string_field->assign(block_ + pos, value_len);
+ ASSERT(talk_base::memory_check(block_ + pos + value_len,
+ 0,
+ max_len - value_len));
+ pos += max_len;
+}
diff --git a/third_party/libjingle/files/talk/base/tarstream.h b/third_party/libjingle/files/talk/base/tarstream.h
new file mode 100644
index 0000000..772fb14
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/tarstream.h
@@ -0,0 +1,104 @@
+#ifndef TALK_APP_WIN32_TARSTREAM_H__
+#define TALK_APP_WIN32_TARSTREAM_H__
+
+#include <string>
+#include <vector>
+#include "talk/base/fileutils.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/stream.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// TarStream - acts as a source or sink for a tar-encoded collection of files
+// and directories. Operates synchronously.
+///////////////////////////////////////////////////////////////////////////////
+
+class TarStream : public StreamInterface {
+ public:
+ TarStream();
+ virtual ~TarStream();
+
+ // AddFilter is used to limit the elements which will be read or written.
+ // In general, all members of the parent folder are read, and all members
+ // of a tarfile are written. However, if any filters are added, only those
+ // items (and their contents, in the case of folders) are processed. Filters
+ // must be added before opening the stream.
+ bool AddFilter(const std::string& pathname);
+
+ // 'folder' is parent of the tar contents. All paths will be evaluated
+ // relative to it. When 'read' is true, the specified folder will be
+ // traversed, and a tar stream will be generated (via Read). Otherwise, a
+ // tar stream is consumed (via Write), and files and folders will be created.
+ bool Open(const std::string& folder, bool read);
+
+ virtual talk_base::StreamState GetState() const;
+ virtual talk_base::StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error);
+ virtual talk_base::StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error);
+ virtual void Close();
+
+ virtual bool GetSize(size_t* size) const { return false; }
+ virtual bool ReserveSize(size_t size) { return true; }
+ virtual bool Rewind() { return false; }
+
+ // Every time a new entry header is read/written, this signal is fired with
+ // the entry's name and size.
+ sigslot::signal2<const std::string&, size_t> SignalNextEntry;
+
+ private:
+ typedef std::list<DirectoryIterator*> DirectoryList;
+ enum ModeType { M_NONE, M_READ, M_WRITE };
+ enum NextBlockType { NB_NONE, NB_FILE_HEADER, NB_DATA, NB_TRAILER };
+ enum { BLOCK_SIZE = 512 };
+
+ talk_base::StreamResult ProcessBuffer(void* buffer, size_t buffer_len,
+ size_t* consumed, int* error);
+ talk_base::StreamResult ProcessNextBlock(int* error);
+ talk_base::StreamResult ProcessEmptyBlock(size_t start, int* error);
+ talk_base::StreamResult ReadNextFile(int* error);
+ talk_base::StreamResult WriteNextFile(int* error);
+
+ talk_base::StreamResult ProcessNextEntry(const DirectoryIterator *data,
+ int *error);
+
+ // Determine whether the given entry is allowed by our filters
+ bool CheckFilter(const std::string& pathname);
+
+ void WriteFieldN(size_t& pos, size_t max_len, size_t numeric_field);
+ void WriteFieldS(size_t& pos, size_t max_len, const char* string_field);
+ void WriteFieldF(size_t& pos, size_t max_len, const char* format, ...);
+
+ void ReadFieldN(size_t& pos, size_t max_len, size_t* numeric_field);
+ void ReadFieldS(size_t& pos, size_t max_len, std::string* string_field);
+
+ void WriteChecksum(void);
+
+ // Files and/or folders that should be processed
+ std::vector<std::string> filters_;
+ // Folder passed to Open
+ std::string root_folder_;
+ // Open for read or write?
+ ModeType mode_;
+ // The expected type of the next block
+ NextBlockType next_block_;
+ // The partial contents of the current block
+ char block_[BLOCK_SIZE];
+ size_t block_pos_;
+ // The file which is currently being read or written
+ talk_base::FileStream* current_;
+ // Bytes remaining to be processed for current_
+ size_t current_bytes_;
+ // Note: the following variables are used in M_READ mode only.
+ // Stack of open directory handles, representing depth-first search
+ DirectoryList find_;
+ // Subfolder path corresponding to current position in the directory tree
+ std::string subfolder_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_APP_WIN32_TARSTREAM_H__
diff --git a/third_party/libjingle/files/talk/base/task.cc b/third_party/libjingle/files/talk/base/task.cc
new file mode 100644
index 0000000..70059da
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/task.cc
@@ -0,0 +1,299 @@
+/*
+ * 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 "talk/base/task.h"
+#include "talk/base/common.h"
+#include "talk/base/taskrunner.h"
+
+namespace talk_base {
+
+int32 Task::unique_id_seed_ = 0;
+
+Task::Task(Task *parent)
+ : state_(STATE_INIT),
+ parent_(parent),
+ blocked_(false),
+ done_(false),
+ aborted_(false),
+ busy_(false),
+ error_(false),
+ child_error_(false),
+ start_time_(0),
+ timeout_seconds_(0),
+ timeout_time_(0),
+ timeout_suspended_(false) {
+ children_.reset(new ChildSet());
+ runner_ = ((parent == NULL) ?
+ reinterpret_cast<TaskRunner *>(this) :
+ parent->GetRunner());
+ if (parent_ != NULL) {
+ parent_->AddChild(this);
+ }
+
+ unique_id_ = unique_id_seed_++;
+
+ // sanity check that we didn't roll-over our id seed
+ ASSERT(unique_id_ < unique_id_seed_);
+}
+
+int64 Task::CurrentTime() {
+ return runner_->CurrentTime();
+}
+
+int64 Task::ElapsedTime() {
+ return CurrentTime() - start_time_;
+}
+
+void Task::Start() {
+ if (state_ != STATE_INIT)
+ return;
+ // Set the start time before starting the task. Otherwise if the task
+ // finishes quickly and deletes the Task object, setting start_time_
+ // will crash.
+ start_time_ = CurrentTime();
+ GetRunner()->StartTask(this);
+}
+
+void Task::Step() {
+ if (done_) {
+#ifdef DEBUG
+ // we do not know how !blocked_ happens when done_ - should be impossible.
+ // But it causes problems, so in retail build, we force blocked_, and
+ // under debug we assert.
+ assert(blocked_);
+#else
+ blocked_ = true;
+#endif
+ return;
+ }
+
+ // Async Error() was called
+ if (error_) {
+ done_ = true;
+ state_ = STATE_ERROR;
+ blocked_ = true;
+// obsolete - an errored task is not considered done now
+// SignalDone();
+ Stop();
+ return;
+ }
+
+ busy_ = true;
+ int new_state = Process(state_);
+ busy_ = false;
+
+ if (aborted_) {
+ Abort(true); // no need to wake because we're awake
+ return;
+ }
+
+ if (new_state == STATE_BLOCKED) {
+ blocked_ = true;
+ // Let the timeout continue
+ } else {
+ state_ = new_state;
+ blocked_ = false;
+ ResetTimeout();
+ }
+
+ if (new_state == STATE_DONE) {
+ done_ = true;
+ } else if (new_state == STATE_ERROR) {
+ done_ = true;
+ error_ = true;
+ }
+
+ if (done_) {
+// obsolete - call this yourself
+// SignalDone();
+ Stop();
+ blocked_ = true;
+ }
+}
+
+void Task::Abort(bool nowake) {
+ if (done_)
+ return;
+ aborted_ = true;
+ if (!busy_) {
+ done_ = true;
+ blocked_ = true;
+ error_ = true;
+ Stop();
+ if (!nowake)
+ GetRunner()->WakeTasks();
+ }
+}
+
+void Task::Wake() {
+ if (done_)
+ return;
+ if (blocked_) {
+ blocked_ = false;
+ GetRunner()->WakeTasks();
+ }
+}
+
+void Task::Error() {
+ if (error_ || done_)
+ return;
+ error_ = true;
+ Wake();
+}
+
+std::string Task::GetStateName(int state) const {
+ static const std::string STR_BLOCKED("BLOCKED");
+ static const std::string STR_INIT("INIT");
+ static const std::string STR_START("START");
+ static const std::string STR_DONE("DONE");
+ static const std::string STR_ERROR("ERROR");
+ static const std::string STR_RESPONSE("RESPONSE");
+ static const std::string STR_HUH("??");
+ switch (state) {
+ case STATE_BLOCKED: return STR_BLOCKED;
+ case STATE_INIT: return STR_INIT;
+ case STATE_START: return STR_START;
+ case STATE_DONE: return STR_DONE;
+ case STATE_ERROR: return STR_ERROR;
+ case STATE_RESPONSE: return STR_RESPONSE;
+ }
+ return STR_HUH;
+}
+
+int Task::Process(int state) {
+ int newstate = STATE_ERROR;
+
+ if (TimedOut()) {
+ ClearTimeout();
+ newstate = OnTimeout();
+ SignalTimeout();
+ } else {
+ switch (state) {
+ case STATE_INIT:
+ newstate = STATE_START;
+ break;
+ case STATE_START:
+ newstate = ProcessStart();
+ break;
+ case STATE_RESPONSE:
+ newstate = ProcessResponse();
+ break;
+ case STATE_DONE:
+ case STATE_ERROR:
+ newstate = STATE_BLOCKED;
+ break;
+ }
+ }
+
+ return newstate;
+}
+
+void Task::AddChild(Task *child) {
+ children_->insert(child);
+}
+
+bool Task::AllChildrenDone() {
+ for (ChildSet::iterator it = children_->begin();
+ it != children_->end();
+ ++it) {
+ if (!(*it)->IsDone())
+ return false;
+ }
+ return true;
+}
+
+bool Task::AnyChildError() {
+ return child_error_;
+}
+
+void Task::AbortAllChildren() {
+ if (children_->size() > 0) {
+ ChildSet copy = *children_;
+ for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) {
+ (*it)->Abort(true); // Note we do not wake
+ }
+ }
+}
+
+void Task::Stop() {
+ // No need to wake because we're either awake or in abort
+ AbortAllChildren();
+ parent_->OnChildStopped(this);
+}
+
+void Task::OnChildStopped(Task *child) {
+ if (child->HasError())
+ child_error_ = true;
+ children_->erase(child);
+}
+
+void Task::set_timeout_seconds(const int timeout_seconds) {
+ timeout_seconds_ = timeout_seconds;
+ ResetTimeout();
+}
+
+bool Task::TimedOut() {
+ return timeout_seconds_ &&
+ timeout_time_ &&
+ CurrentTime() > timeout_time_;
+}
+
+void Task::ResetTimeout() {
+ bool timeout_allowed = (state_ != STATE_INIT)
+ && (state_ != STATE_DONE)
+ && (state_ != STATE_ERROR);
+ if (timeout_seconds_ && timeout_allowed && !timeout_suspended_)
+ timeout_time_ = CurrentTime() +
+ (timeout_seconds_ * kSecToMsec * kMsecTo100ns);
+ else
+ timeout_time_ = 0;
+
+ GetRunner()->UpdateTaskTimeout(this);
+}
+
+void Task::ClearTimeout() {
+ timeout_time_ = 0;
+ GetRunner()->UpdateTaskTimeout(this);
+}
+
+void Task::SuspendTimeout() {
+ if (!timeout_suspended_) {
+ timeout_suspended_ = true;
+ ResetTimeout();
+ }
+}
+
+void Task::ResumeTimeout() {
+ if (timeout_suspended_) {
+ timeout_suspended_ = false;
+ ResetTimeout();
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/task.h b/third_party/libjingle/files/talk/base/task.h
new file mode 100644
index 0000000..b524ab7
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/task.h
@@ -0,0 +1,218 @@
+/*
+ * 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 TALK_BASE_TASK_H__
+#define TALK_BASE_TASK_H__
+
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/basictypes.h"
+#include "talk/base/sigslot.h"
+
+/////////////////////////////////////////////////////////////////////
+//
+// TASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// Task is a state machine infrastructure. States are pushed forward by
+// pushing forwards a TaskRunner that holds on to all Tasks. The purpose
+// of Task is threefold:
+//
+// (1) It manages ongoing work on the UI thread. Multitasking without
+// threads, keeping it easy, keeping it real. :-) It does this by
+// organizing a set of states for each task. When you return from your
+// Process*() function, you return an integer for the next state. You do
+// not go onto the next state yourself. Every time you enter a state,
+// you check to see if you can do anything yet. If not, you return
+// STATE_BLOCKED. If you _could_ do anything, do not return
+// STATE_BLOCKED - even if you end up in the same state, return
+// STATE_mysamestate. When you are done, return STATE_DONE and then the
+// task will self-delete sometimea afterwards.
+//
+// (2) It helps you avoid all those reentrancy problems when you chain
+// too many triggers on one thread. Basically if you want to tell a task
+// to process something for you, you feed your task some information and
+// then you Wake() it. Don't tell it to process it right away. If it
+// might be working on something as you send it infomration, you may want
+// to have a queue in the task.
+//
+// (3) Finally it helps manage parent tasks and children. If a parent
+// task gets aborted, all the children tasks are too. The nice thing
+// about this, for example, is if you have one parent task that
+// represents, say, and Xmpp connection, then you can spawn a whole bunch
+// of infinite lifetime child tasks and now worry about cleaning them up.
+// When the parent task goes to STATE_DONE, the task engine will make
+// sure all those children are aborted and get deleted.
+//
+// Notice that Task has a few built-in states, e.g.,
+//
+// STATE_INIT - the task isn't running yet
+// STATE_START - the task is in its first state
+// STATE_RESPONSE - the task is in its second state
+// STATE_DONE - the task is done
+//
+// STATE_ERROR - indicates an error - we should audit the error code in
+// light of any usage of it to see if it should be improved. When I
+// first put down the task stuff I didn't have a good sense of what was
+// needed for Abort and Error, and now the subclasses of Task will ground
+// the design in a stronger way.
+//
+// STATE_NEXT - the first undefined state number. (like WM_USER) - you
+// can start defining more task states there.
+//
+// When you define more task states, just override Process(int state) and
+// add your own switch statement. If you want to delegate to
+// Task::Process, you can effectively delegate to its switch statement.
+// No fancy method pointers or such - this is all just pretty low tech,
+// easy to debug, and fast.
+//
+// Also notice that Task has some primitive built-in timeout functionality.
+//
+// A timeout is defined as "the task stays in STATE_BLOCKED longer than
+// timeout_seconds_."
+//
+// Descendant classes can override this behavior by calling the
+// various protected methods to change the timeout behavior. For
+// instance, a descendand might call SuspendTimeout() when it knows
+// that it isn't waiting for anything that might timeout, but isn't
+// yet in the STATE_DONE state.
+//
+
+namespace talk_base {
+
+class TaskRunner;
+
+// A task executes a sequence of steps
+
+class Task;
+class RootTask;
+
+class Task {
+ public:
+ Task(Task *parent);
+ virtual ~Task() {}
+
+ int32 get_unique_id() { return unique_id_; }
+
+ void Start();
+ void Step();
+ int GetState() const { return state_; }
+ bool HasError() const { return (GetState() == STATE_ERROR); }
+ bool Blocked() const { return blocked_; }
+ bool IsDone() const { return done_; }
+ int64 ElapsedTime();
+
+ Task *GetParent() { return parent_; }
+ TaskRunner *GetRunner() { return runner_; }
+ virtual Task *GetParent(int code) { return parent_->GetParent(code); }
+
+ // Called from outside to stop task without any more callbacks
+ void Abort(bool nowake = false);
+
+ // For managing children
+ bool AllChildrenDone();
+ bool AnyChildError();
+
+ bool TimedOut();
+
+ int64 get_timeout_time() { return timeout_time_; }
+ void set_timeout_seconds(int timeout_seconds);
+
+ sigslot::signal0<> SignalTimeout;
+
+ // Called inside the task to signal that the task may be unblocked
+ void Wake();
+
+ protected:
+
+ enum {
+ STATE_BLOCKED = -1,
+ STATE_INIT = 0,
+ STATE_START = 1,
+ STATE_DONE = 2,
+ STATE_ERROR = 3,
+ STATE_RESPONSE = 4,
+ STATE_NEXT = 5, // Subclasses which need more states start here and higher
+ };
+
+ // Called inside to advise that the task should wake and signal an error
+ void Error();
+
+ int64 CurrentTime();
+
+ virtual std::string GetStateName(int state) const;
+ virtual int Process(int state);
+ virtual void Stop();
+ virtual int ProcessStart() = 0;
+ virtual int ProcessResponse() { return STATE_DONE; }
+
+ // for managing children (if any)
+ void AddChild(Task *child);
+ void AbortAllChildren();
+
+ void ResetTimeout();
+ void ClearTimeout();
+
+ void SuspendTimeout();
+ void ResumeTimeout();
+
+ protected:
+ virtual int OnTimeout() {
+ // by default, we are finished after timing out
+ return STATE_DONE;
+ }
+
+ private:
+ void Done();
+ void OnChildStopped(Task *child);
+
+ int state_;
+ Task *parent_;
+ TaskRunner *runner_;
+ bool blocked_;
+ bool done_;
+ bool aborted_;
+ bool busy_;
+ bool error_;
+ bool child_error_;
+ int64 start_time_;
+ int64 timeout_time_;
+ int timeout_seconds_;
+ bool timeout_suspended_;
+ int32 unique_id_;
+
+ static int32 unique_id_seed_;
+
+ // for managing children
+ typedef std::set<Task *> ChildSet;
+ scoped_ptr<ChildSet> children_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_TASK_H__
diff --git a/third_party/libjingle/files/talk/base/taskrunner.cc b/third_party/libjingle/files/talk/base/taskrunner.cc
new file mode 100644
index 0000000..050171f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/taskrunner.cc
@@ -0,0 +1,176 @@
+/*
+ * 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 "talk/base/taskrunner.h"
+
+#include "talk/base/common.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/task.h"
+#include "talk/base/logging.h"
+
+namespace talk_base {
+
+TaskRunner::TaskRunner()
+ : Task(NULL),
+ tasks_running_(false),
+ next_timeout_task_(NULL) {
+}
+
+TaskRunner::~TaskRunner() {
+ // this kills and deletes children silently!
+ AbortAllChildren();
+ RunTasks();
+}
+
+void TaskRunner::StartTask(Task * task) {
+ tasks_.push_back(task);
+
+ // the task we just started could be about to timeout --
+ // make sure our "next timeout task" is correct
+ UpdateTaskTimeout(task);
+
+ WakeTasks();
+}
+
+void TaskRunner::RunTasks() {
+ // Running continues until all tasks are Blocked (ok for a small # of tasks)
+ if (tasks_running_) {
+ return; // don't reenter
+ }
+
+ tasks_running_ = true;
+
+ int did_run = true;
+ while (did_run) {
+ did_run = false;
+ // use indexing instead of iterators because tasks_ may grow
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ while (!tasks_[i]->Blocked()) {
+ tasks_[i]->Step();
+ did_run = true;
+ }
+ }
+ }
+ // Tasks are deleted when running has paused
+ bool need_timeout_recalc = false;
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ if (tasks_[i]->IsDone()) {
+ Task* task = tasks_[i];
+ if (next_timeout_task_ &&
+ task->get_unique_id() == next_timeout_task_->get_unique_id()) {
+ next_timeout_task_ = NULL;
+ need_timeout_recalc = true;
+ }
+
+ delete task;
+ tasks_[i] = NULL;
+ }
+ }
+ // Finally, remove nulls
+ std::vector<Task *>::iterator it;
+ it = std::remove(tasks_.begin(),
+ tasks_.end(),
+ reinterpret_cast<Task *>(NULL));
+
+ tasks_.erase(it, tasks_.end());
+
+ if (need_timeout_recalc)
+ RecalcNextTimeout(NULL);
+
+ tasks_running_ = false;
+}
+
+void TaskRunner::PollTasks() {
+ // see if our "next potentially timed-out task" has indeed timed out.
+ // If it has, wake it up, then queue up the next task in line
+ if (next_timeout_task_ &&
+ next_timeout_task_->TimedOut()) {
+ next_timeout_task_->Wake();
+ WakeTasks();
+ }
+}
+
+// this function gets called frequently -- when each task changes
+// state to something other than DONE, ERROR or BLOCKED, it calls
+// ResetTimeout(), which will call this function to make sure that
+// the next timeout-able task hasn't changed. The logic in this function
+// prevents RecalcNextTimeout() from getting called in most cases,
+// effectively making the task scheduler O-1 instead of O-N
+
+void TaskRunner::UpdateTaskTimeout(Task *task) {
+ ASSERT(task != NULL);
+
+ // if the relevant task has a timeout, then
+ // check to see if it's closer than the current
+ // "about to timeout" task
+ if (task->get_timeout_time()) {
+ if (next_timeout_task_ == NULL ||
+ (task->get_timeout_time() <=
+ next_timeout_task_->get_timeout_time())) {
+ next_timeout_task_ = task;
+ }
+ } else if (next_timeout_task_ != NULL &&
+ task->get_unique_id() == next_timeout_task_->get_unique_id()) {
+ // otherwise, if the task doesn't have a timeout,
+ // and it used to be our "about to timeout" task,
+ // walk through all the tasks looking for the real
+ // "about to timeout" task
+ RecalcNextTimeout(task);
+ }
+}
+
+void TaskRunner::RecalcNextTimeout(Task *exclude_task) {
+ // walk through all the tasks looking for the one
+ // which satisfies the following:
+ // it's not finished already
+ // we're not excluding it
+ // it has the closest timeout time
+
+ int64 next_timeout_time = 0;
+ next_timeout_task_ = NULL;
+
+ for (size_t i = 0; i < tasks_.size(); ++i) {
+ Task *task = tasks_[i];
+ // if the task isn't complete, and it actually has a timeout time
+ if (!task->IsDone() &&
+ (task->get_timeout_time() > 0))
+ // if it doesn't match our "exclude" task
+ if (exclude_task == NULL ||
+ exclude_task->get_unique_id() != task->get_unique_id())
+ // if its timeout time is sooner than our current timeout time
+ if (next_timeout_time == 0 ||
+ task->get_timeout_time() <= next_timeout_time) {
+ // set this task as our next-to-timeout
+ next_timeout_time = task->get_timeout_time();
+ next_timeout_task_ = task;
+ }
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/taskrunner.h b/third_party/libjingle/files/talk/base/taskrunner.h
new file mode 100644
index 0000000..96a1a75
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/taskrunner.h
@@ -0,0 +1,83 @@
+/*
+ * 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 TALK_BASE_TASKRUNNER_H__
+#define TALK_BASE_TASKRUNNER_H__
+
+#include <vector>
+
+#include "talk/base/sigslot.h"
+#include "talk/base/task.h"
+
+namespace talk_base {
+
+class Task;
+
+const int64 kSecToMsec = 1000;
+const int64 kMsecTo100ns = 10000;
+const int64 kSecTo100ns = kSecToMsec * kMsecTo100ns;
+
+class TaskRunner : public Task, public sigslot::has_slots<> {
+ public:
+ TaskRunner();
+ virtual ~TaskRunner();
+
+ virtual void WakeTasks() = 0;
+
+ // This method returns the current time in 100ns units since 1/1/1601. This
+ // Is the GetSystemTimeAsFileTime method on windows.
+ virtual int64 CurrentTime() = 0 ;
+
+ void StartTask(Task *task);
+ void RunTasks();
+ void PollTasks();
+
+ void UpdateTaskTimeout(Task *task);
+
+ // dummy state machine - never run.
+ virtual int ProcessStart() { return STATE_DONE; }
+
+ bool HasTimeoutTask() {
+ return next_timeout_task_ != NULL;
+ }
+
+ bool HasPendingTimeoutTask() {
+ return next_timeout_task_ != NULL &&
+ next_timeout_task_->TimedOut();
+ }
+
+ private:
+ std::vector<Task *> tasks_;
+ Task *next_timeout_task_;
+ bool tasks_running_;
+
+ void RecalcNextTimeout(Task *exclude_task);
+};
+
+} // namespace talk_base
+
+#endif // TASK_BASE_TASKRUNNER_H__
diff --git a/third_party/libjingle/files/talk/base/testclient.cc b/third_party/libjingle/files/talk/base/testclient.cc
new file mode 100644
index 0000000..c963782
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/testclient.cc
@@ -0,0 +1,162 @@
+/*
+ * 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 <iostream>
+#include <cassert>
+#include <cstring>
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+#include "talk/base/testclient.h"
+#include "talk/base/time.h"
+
+
+namespace talk_base {
+
+// DESIGN: Each packet received is posted to ourselves as a message on the
+// thread given to the constructor. When we receive the message, we
+// put it into a list of packets. We take the latter step so that we
+// can wait for a new packet to arrive by calling Get/Dispatch on the
+// thread.
+
+TestClient::TestClient(AsyncPacketSocket* socket, Thread* thread)
+ : thread_(thread), socket_(socket) {
+ if (!thread_)
+ thread_ = Thread::Current();
+ packets_ = new std::vector<Packet*>();
+ socket_->SignalReadPacket.connect(this, &TestClient::OnPacket);
+}
+
+TestClient::~TestClient() {
+ delete socket_;
+ for (unsigned i = 0; i < packets_->size(); i++)
+ delete (*packets_)[i];
+}
+
+void TestClient::Send(const char* buf, size_t size) {
+ int result = socket_->Send(buf, size);
+ if (result < 0) {
+ std::cerr << "send: " << std::strerror(errno) << std::endl;
+ exit(1);
+ }
+}
+
+void TestClient::SendTo(
+ const char* buf, size_t size, const SocketAddress& dest) {
+ int result = socket_->SendTo(buf, size, dest);
+ if (result < 0) {
+ std::cerr << "sendto: " << std::strerror(errno) << std::endl;
+ exit(1);
+ }
+}
+
+void TestClient::OnPacket(
+ const char* buf, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket) {
+ thread_->Post(this, 0, new Packet(remote_addr, buf, size));
+}
+
+void TestClient::OnMessage(Message *pmsg) {
+ assert(pmsg->pdata);
+ packets_->push_back(new Packet(*static_cast<Packet*>(pmsg->pdata)));
+}
+
+TestClient::Packet* TestClient::NextPacket() {
+
+ // If no packets are currently available, we go into a get/dispatch loop for
+ // at most 1 second. If, during the loop, a packet arrives, then we can stop
+ // early and return it.
+ //
+ // Note that the case where no packet arrives is important. We often want to
+ // test that a packet does not arrive.
+
+ if (packets_->size() == 0) {
+ uint32 msNext = 1000;
+ uint32 msEnd = GetMillisecondCount() + msNext;
+
+ while (true) {
+ Message msg;
+ if (!thread_->Get(&msg, msNext))
+ break;
+ thread_->Dispatch(&msg);
+
+ uint32 msCur = GetMillisecondCount();
+ if (msCur >= msEnd)
+ break;
+ msNext = msEnd - msCur;
+
+ if (packets_->size() > 0)
+ break;
+ }
+ }
+
+ if (packets_->size() == 0) {
+ return 0;
+ } else {
+ // Return the first packet placed in the queue.
+ Packet* packet = packets_->front();
+ packets_->erase(packets_->begin());
+ return packet;
+ }
+}
+
+void TestClient::CheckNextPacket(
+ const char* buf, size_t size, SocketAddress* addr) {
+ Packet* packet = NextPacket();
+ assert(packet);
+ assert(packet->size == size);
+ assert(std::memcmp(packet->buf, buf, size) == 0);
+ if (addr)
+ *addr = packet->addr;
+}
+
+void TestClient::CheckNoPacket() {
+ Packet* packet = NextPacket();
+ assert(!packet);
+}
+
+TestClient::Packet::Packet(const SocketAddress& a, const char* b, size_t s)
+ : addr(a), buf(0), size(s) {
+ buf = new char[size];
+ memcpy(buf, b, size);
+}
+
+TestClient::Packet::Packet(const Packet& p)
+ : addr(p.addr), buf(0), size(p.size) {
+ buf = new char[size];
+ memcpy(buf, p.buf, size);
+}
+
+TestClient::Packet::~Packet() {
+ delete buf;
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/testclient.h b/third_party/libjingle/files/talk/base/testclient.h
new file mode 100644
index 0000000..012e8583
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/testclient.h
@@ -0,0 +1,89 @@
+/*
+ * 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 TALK_BASE_TESTCLIENT_H__
+#define TALK_BASE_TESTCLIENT_H__
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/thread.h"
+#include <vector>
+
+namespace talk_base {
+
+class TestClient : public MessageHandler, public sigslot::has_slots<> {
+public:
+ // Creates a client that will send and receive with the given socket and
+ // will post itself messages with the given thread.
+ TestClient(AsyncPacketSocket* socket, Thread* thread = 0);
+ ~TestClient();
+
+ // Sends using the clients socket.
+ void Send(const char* buf, size_t size);
+
+ // Sends using the clients socket to the given destination.
+ void SendTo(const char* buf, size_t size, const SocketAddress& dest);
+
+ // Records the contents of a packet that was received.
+ struct Packet : public MessageData {
+ Packet(const SocketAddress& a, const char* b, size_t s);
+ Packet(const Packet& p);
+ virtual ~Packet();
+
+ SocketAddress addr;
+ char* buf;
+ size_t size;
+ };
+
+ // Returns the next packet received by the client or 0 if none is received
+ // within a reasonable amount of time. The caller must delete the packet
+ // when done with it.
+ Packet* NextPacket();
+
+ // Checks that the next packet has the given contents. Returns the remote
+ // address that the packet was sent from.
+ void CheckNextPacket(const char* buf, size_t len, SocketAddress* addr);
+
+ // Checks that no packets have arrived or will arrive in the next second.
+ void CheckNoPacket();
+
+ // Messagehandler:
+ void OnMessage(Message *pmsg);
+
+private:
+ Thread* thread_;
+ AsyncPacketSocket* socket_;
+ std::vector<Packet*>* packets_;
+
+ // Slot for packets read on the socket.
+ void OnPacket(
+ const char* buf, size_t len, const SocketAddress& remote_addr,
+ AsyncPacketSocket* socket);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_TESTCLIENT_H__
diff --git a/third_party/libjingle/files/talk/base/thread.cc b/third_party/libjingle/files/talk/base/thread.cc
new file mode 100644
index 0000000..fa2d23c
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/thread.cc
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+#ifdef POSIX
+extern "C" {
+#include <sys/time.h>
+}
+#endif
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/thread.h"
+#include "talk/base/time.h"
+
+#define MSDEV_SET_THREAD_NAME 0x406D1388
+
+namespace talk_base {
+
+ThreadManager g_thmgr;
+
+#ifdef POSIX
+pthread_key_t ThreadManager::key_;
+
+ThreadManager::ThreadManager() {
+ pthread_key_create(&key_, NULL);
+ main_thread_ = new Thread();
+ SetCurrent(main_thread_);
+}
+
+ThreadManager::~ThreadManager() {
+ pthread_key_delete(key_);
+ delete main_thread_;
+}
+
+Thread *ThreadManager::CurrentThread() {
+ return (Thread *)pthread_getspecific(key_);
+}
+
+void ThreadManager::SetCurrent(Thread *thread) {
+ pthread_setspecific(key_, thread);
+}
+#endif
+
+#ifdef WIN32
+DWORD ThreadManager::key_;
+
+ThreadManager::ThreadManager() {
+ key_ = TlsAlloc();
+ main_thread_ = new Thread();
+ SetCurrent(main_thread_);
+}
+
+ThreadManager::~ThreadManager() {
+ TlsFree(key_);
+ delete main_thread_;
+}
+
+Thread *ThreadManager::CurrentThread() {
+ return (Thread *)TlsGetValue(key_);
+}
+
+void ThreadManager::SetCurrent(Thread *thread) {
+ TlsSetValue(key_, thread);
+}
+#endif
+
+void ThreadManager::Add(Thread *thread) {
+ CritScope cs(&crit_);
+ threads_.push_back(thread);
+}
+
+void ThreadManager::Remove(Thread *thread) {
+ CritScope cs(&crit_);
+ threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end());
+}
+
+bool ThreadManager::ThreadActive(Thread *thread) {
+ CritScope cs(&crit_);
+ return(std::find(threads_.begin(), threads_.end(), thread) != threads_.end());
+}
+
+Thread::Thread(SocketServer* ss) : MessageQueue(ss), priority_(PRIORITY_NORMAL) {
+ g_thmgr.Add(this);
+ started_ = false;
+ stopped_ = false;
+ has_sends_ = false;
+}
+
+Thread::~Thread() {
+ Stop();
+ if (active_)
+ Clear(NULL);
+ g_thmgr.Remove(this);
+}
+
+#ifdef POSIX
+void Thread::Start() {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if (priority_ == PRIORITY_IDLE) {
+ struct sched_param param;
+ pthread_attr_getschedparam(&attr, &param);
+ param.sched_priority = 15; // +15 =
+ pthread_attr_setschedparam(&attr, &param);
+ }
+ CritScope cs(&started_crit_);
+ // Make sure Join() hasn't been called yet.
+ if (stopped_)
+ return;
+ if (pthread_create(&thread_, &attr, PreRun, this) == 0)
+ started_ = true;
+}
+
+void Thread::Join() {
+ CritScope cs(&started_crit_);
+ stopped_ = true;
+ if (started_) {
+ void *pv;
+ pthread_join(thread_, &pv);
+ started_ = false;
+ }
+}
+#endif
+
+#ifdef WIN32
+
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType;
+ LPCSTR szName;
+ DWORD dwThreadID;
+ DWORD dwFlags;
+} THREADNAME_INFO;
+
+void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
+{
+ THREADNAME_INFO info;
+ {
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+ }
+ __try
+ {
+ RaiseException(MSDEV_SET_THREAD_NAME, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
+ }
+ __except(EXCEPTION_CONTINUE_EXECUTION)
+ {
+ }
+}
+
+void Thread::Start() {
+ DWORD flags = 0;
+ if (priority_ != PRIORITY_NORMAL) {
+ flags = CREATE_SUSPENDED;
+ }
+ CritScope cs(&started_crit_);
+ // Make sure Join() hasn't been called yet.
+ if (stopped_)
+ return;
+ thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, this, flags, NULL);
+ if (thread_) {
+ if (priority_ != PRIORITY_NORMAL) {
+ if (priority_ == PRIORITY_IDLE) {
+ ::SetThreadPriority(thread_, THREAD_PRIORITY_IDLE);
+ }
+ ::ResumeThread(thread_);
+ }
+ }
+ started_ = true;
+}
+
+void Thread::Join() {
+ CritScope cs(&started_crit_);
+ stopped_ = true;
+ if (started_) {
+ WaitForSingleObject(thread_, INFINITE);
+ CloseHandle(thread_);
+ started_ = false;
+ }
+}
+#endif
+
+void *Thread::PreRun(void *pv) {
+ Thread *thread = (Thread *)pv;
+ // Make sure the thread hasn't been deleted.
+ if (!g_thmgr.ThreadActive(thread))
+ return NULL;
+ ThreadManager::SetCurrent(thread);
+#if defined(WIN32) && defined(_DEBUG)
+ char buf[256];
+ _snprintf(buf, sizeof(buf), "Thread 0x%.8x", thread);
+ SetThreadName(GetCurrentThreadId(), buf);
+#endif
+ thread->Run();
+ return NULL;
+}
+
+void Thread::Run() {
+ ProcessMessages(kForever);
+}
+
+void Thread::Stop() {
+ MessageQueue::Quit();
+ Join();
+}
+
+void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) {
+ if (fStop_)
+ return;
+
+ // Sent messages are sent to the MessageHandler directly, in the context
+ // of "thread", like Win32 SendMessage. If in the right context,
+ // call the handler directly.
+
+ Message msg;
+ msg.phandler = phandler;
+ msg.message_id = id;
+ msg.pdata = pdata;
+ if (IsCurrent()) {
+ phandler->OnMessage(&msg);
+ return;
+ }
+
+ AutoThread thread;
+ Thread *current_thread = Thread::Current();
+ ASSERT(current_thread != NULL); // AutoThread ensures this
+
+ bool ready = false;
+ {
+ CritScope cs(&crit_);
+ EnsureActive();
+ _SendMessage smsg;
+ smsg.thread = current_thread;
+ smsg.msg = msg;
+ smsg.ready = &ready;
+ sendlist_.push_back(smsg);
+ has_sends_ = true;
+ }
+
+ // Wait for a reply
+
+ ss_->WakeUp();
+
+ bool waited = false;
+ while (!ready) {
+ current_thread->ReceiveSends();
+ current_thread->socketserver()->Wait(kForever, false);
+ waited = true;
+ }
+
+ // Our Wait loop above may have consumed some WakeUp events for this
+ // MessageQueue, that weren't relevant to this Send. Losing these WakeUps can
+ // cause problems for some SocketServers.
+ //
+ // Concrete example:
+ // Win32SocketServer on thread A calls Send on thread B. While processing the
+ // message, thread B Posts a message to A. We consume the wakeup for that
+ // Post while waiting for the Send to complete, which means that when we exit
+ // this loop, we need to issue another WakeUp, or else the Posted message
+ // won't be processed in a timely manner.
+
+ if (waited) {
+ current_thread->socketserver()->WakeUp();
+ }
+}
+
+void Thread::ReceiveSends() {
+ // Before entering critical section, check boolean.
+
+ if (!has_sends_)
+ return;
+
+ // Receive a sent message. Cleanup scenarios:
+ // - thread sending exits: We don't allow this, since thread can exit
+ // only via Join, so Send must complete.
+ // - thread receiving exits: Wakeup/set ready in Thread::Clear()
+ // - object target cleared: Wakeup/set ready in Thread::Clear()
+ crit_.Enter();
+ while (!sendlist_.empty()) {
+ _SendMessage smsg = sendlist_.front();
+ sendlist_.pop_front();
+ crit_.Leave();
+ smsg.msg.phandler->OnMessage(&smsg.msg);
+ crit_.Enter();
+ *smsg.ready = true;
+ smsg.thread->socketserver()->WakeUp();
+ }
+ has_sends_ = false;
+ crit_.Leave();
+}
+
+void Thread::Clear(MessageHandler *phandler, uint32 id) {
+ CritScope cs(&crit_);
+
+ // Remove messages on sendlist_ with phandler
+ // Object target cleared: remove from send list, wakeup/set ready
+ // if sender not NULL.
+
+ std::list<_SendMessage>::iterator iter = sendlist_.begin();
+ while (iter != sendlist_.end()) {
+ _SendMessage smsg = *iter;
+ if (phandler == NULL || smsg.msg.phandler == phandler) {
+ if (id == (uint32)-1 || smsg.msg.message_id == id) {
+ iter = sendlist_.erase(iter);
+ *smsg.ready = true;
+ smsg.thread->socketserver()->WakeUp();
+ continue;
+ }
+ }
+ ++iter;
+ }
+
+ MessageQueue::Clear(phandler, id);
+}
+
+bool Thread::ProcessMessages(int cmsLoop) {
+ uint32 msEnd;
+ if (cmsLoop != kForever)
+ msEnd = GetMillisecondCount() + cmsLoop;
+ int cmsNext = cmsLoop;
+
+ while (true) {
+ Message msg;
+ if (!Get(&msg, cmsNext))
+ return !IsQuitting();
+ Dispatch(&msg);
+
+ if (cmsLoop != kForever) {
+ uint32 msCur = GetMillisecondCount();
+ if (msCur >= msEnd)
+ return true;
+ cmsNext = msEnd - msCur;
+ }
+ }
+}
+
+AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
+ if (!ThreadManager::CurrentThread()) {
+ ThreadManager::SetCurrent(this);
+ }
+}
+
+AutoThread::~AutoThread() {
+ if (ThreadManager::CurrentThread() == this) {
+ ThreadManager::SetCurrent(NULL);
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/thread.h b/third_party/libjingle/files/talk/base/thread.h
new file mode 100644
index 0000000..a2642f0
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/thread.h
@@ -0,0 +1,164 @@
+/*
+ * 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 TALK_BASE_THREAD_H__
+#define TALK_BASE_THREAD_H__
+
+#include <algorithm>
+#include <list>
+#include <vector>
+
+#ifdef POSIX
+#include <pthread.h>
+#endif
+
+#include "talk/base/messagequeue.h"
+
+#ifdef WIN32
+#include "talk/base/win32.h"
+#endif
+
+namespace talk_base {
+
+class Thread;
+
+class ThreadManager {
+public:
+ ThreadManager();
+ ~ThreadManager();
+
+ static Thread *CurrentThread();
+ static void SetCurrent(Thread *thread);
+ void Add(Thread *thread);
+ void Remove(Thread *thread);
+ bool ThreadActive(Thread *thread);
+
+private:
+ Thread *main_thread_;
+ std::vector<Thread *> threads_;
+ CriticalSection crit_;
+
+#ifdef POSIX
+ static pthread_key_t key_;
+#endif
+
+#ifdef WIN32
+ static DWORD key_;
+#endif
+};
+
+class Thread;
+
+struct _SendMessage {
+ _SendMessage() {}
+ Thread *thread;
+ Message msg;
+ bool *ready;
+};
+
+enum ThreadPriority {
+ PRIORITY_NORMAL,
+ PRIORITY_IDLE,
+};
+
+class Thread : public MessageQueue {
+public:
+ Thread(SocketServer* ss = 0);
+ virtual ~Thread();
+
+ static inline Thread* Current() {
+ return ThreadManager::CurrentThread();
+ }
+ inline bool IsCurrent() const {
+ return (ThreadManager::CurrentThread() == this);
+ }
+
+ void SetPriority(ThreadPriority priority) {
+ priority_ = priority;
+ }
+
+ virtual void Start();
+ virtual void Stop();
+
+ // By default, Thread::Run() calls ProcessMessages(kForever). To do other
+ // work, override Run(). To receive and dispatch messages, call
+ // ProcessMessages occasionally.
+ virtual void Run();
+
+ virtual void Send(MessageHandler *phandler, uint32 id = 0,
+ MessageData *pdata = NULL);
+
+ // From MessageQueue
+ virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1);
+ virtual void ReceiveSends();
+
+ // ProcessMessages will process I/O and dispatch messages until:
+ // 1) cms milliseconds have elapsed (returns true)
+ // 2) Stop() is called (returns false)
+ bool ProcessMessages(int cms);
+
+#ifdef WIN32
+ HANDLE GetHandle() {
+ return thread_;
+ }
+#endif
+
+private:
+ static void *PreRun(void *pv);
+ void Join();
+
+ std::list<_SendMessage> sendlist_;
+ ThreadPriority priority_;
+ CriticalSection started_crit_;
+ bool started_;
+ bool stopped_;
+ bool has_sends_;
+
+#ifdef POSIX
+ pthread_t thread_;
+#endif
+
+#ifdef WIN32
+ HANDLE thread_;
+#endif
+
+ friend class ThreadManager;
+};
+
+// AutoThread automatically installs itself at construction
+// uninstalls at destruction, if a Thread object is
+// _not already_ associated with the current OS thread.
+
+class AutoThread : public Thread {
+public:
+ AutoThread(SocketServer* ss = 0);
+ virtual ~AutoThread();
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_THREAD_H__
diff --git a/third_party/libjingle/files/talk/base/time.cc b/third_party/libjingle/files/talk/base/time.cc
new file mode 100644
index 0000000..d4a61ac
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/time.cc
@@ -0,0 +1,91 @@
+/*
+ * 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 <iostream>
+#include <cstdlib>
+#include <cstring>
+
+#include "talk/base/time.h"
+
+namespace talk_base {
+
+#ifdef POSIX
+#include <sys/time.h>
+uint32 Time() {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+uint32 Time() {
+ return GetTickCount();
+}
+#endif
+
+uint32 StartTime() {
+ // Close to program execution time
+ static const uint32 g_start = Time();
+ return g_start;
+}
+
+// Make sure someone calls it so that it gets initialized
+static uint32 ignore = StartTime();
+
+uint32 ElapsedTime() {
+ return TimeDiff(Time(), StartTime());
+}
+
+bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier) {
+ if (earlier <= later) {
+ return ((earlier <= middle) && (middle <= later));
+ } else {
+ return !((later < middle) && (middle < earlier));
+ }
+}
+
+int32 TimeDiff(uint32 later, uint32 earlier) {
+ uint32 LAST = 0xFFFFFFFF;
+ uint32 HALF = 0x80000000;
+ if (TimeIsBetween(earlier + HALF, later, earlier)) {
+ if (earlier <= later) {
+ return static_cast<long>(later - earlier);
+ } else {
+ return static_cast<long>(later + (LAST - earlier) + 1);
+ }
+ } else {
+ if (later <= earlier) {
+ return -static_cast<long>(earlier - later);
+ } else {
+ return -static_cast<long>(earlier + (LAST - later) + 1);
+ }
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/time.h b/third_party/libjingle/files/talk/base/time.h
new file mode 100644
index 0000000..9088aae
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/time.h
@@ -0,0 +1,53 @@
+/*
+ * 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 TALK_BASE_TIME_H__
+#define TALK_BASE_TIME_H__
+
+#include "talk/base/basictypes.h"
+
+namespace talk_base {
+
+// Returns the current time in milliseconds.
+uint32 Time();
+
+// Approximate time when the program started.
+uint32 StartTime();
+
+// Elapsed milliseconds since StartTime()
+uint32 ElapsedTime();
+
+// TODO: Delete this old version.
+#define GetMillisecondCount Time
+
+// Comparisons between time values, which can wrap around.
+bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier);
+int32 TimeDiff(uint32 later, uint32 earlier);
+
+} // namespace talk_base
+
+#endif // TALK_BASE_TIME_H__
diff --git a/third_party/libjingle/files/talk/base/unixfilesystem.cc b/third_party/libjingle/files/talk/base/unixfilesystem.cc
new file mode 100644
index 0000000..2c2732f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/unixfilesystem.cc
@@ -0,0 +1,223 @@
+/*
+ * 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 <errno.h>
+#include <cassert>
+
+#include "talk/base/basicdefs.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/fileutils.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/stream.h"
+
+#include "talk/base/unixfilesystem.h"
+
+namespace talk_base {
+
+bool UnixFilesystem::CreateFolderI(const Pathname &path) {
+ LOG(LS_INFO) << "Creating folder: " << path.pathname();
+ int len = path.pathname().length();
+ const char *pathname = path.pathname().c_str();
+ if ((len <= 0) || (pathname[len-1] != '/'))
+ return false;
+ struct stat st;
+ int res = ::stat(pathname, &st);
+ if (res == 0) {
+ // Something exists at this location, check if it is a directory
+ return S_ISDIR(st.st_mode) != 0;
+ } else if (errno != ENOENT) {
+ // Unexpected error
+ return false;
+ }
+ // Directory doesn't exist, look up one directory level
+ do {
+ --len;
+ } while ((len > 0) && (pathname[len-1] !='/'));
+
+ char *newstring = new char[len+1];
+ strncpy(newstring, pathname, len);
+ newstring[len] = '\0';
+
+ if (!CreateFolder(Pathname(newstring))) {
+ delete[] newstring;
+ return false;
+ }
+ delete[] newstring;
+ std::string no_slash(path.pathname(), 0, path.pathname().length()-1);
+
+ return (::mkdir(no_slash.c_str(), 0755) == 0);
+ }
+
+FileStream *UnixFilesystem::OpenFileI(const Pathname &filename,
+ const std::string &mode) {
+ talk_base::FileStream *fs = new talk_base::FileStream();
+ if (fs)
+ fs->Open(filename.pathname().c_str(), mode.c_str());
+ return fs;
+}
+
+bool UnixFilesystem::DeleteFileI(const Pathname &filename) {
+ LOG(LS_INFO) << "Deleting " << filename.pathname();
+
+ if (IsFolder(filename)) {
+ Pathname dir;
+ dir.SetFolder(filename.pathname());
+ DirectoryIterator di;
+ di.Iterate(dir.pathname());
+ while(di.Next()) {
+ if (di.Name() == "." || di.Name() == "..")
+ continue;
+ Pathname subdir;
+ subdir.SetFolder(filename.pathname());
+ subdir.SetFilename(di.Name());
+
+ if (!DeleteFile(subdir.pathname()))
+ return false;
+ }
+ std::string no_slash(filename.pathname(), 0, filename.pathname().length()-1);
+ return ::rmdir(no_slash.c_str()) == 0;
+ }
+ return ::unlink(filename.pathname().c_str()) == 0;
+}
+
+bool UnixFilesystem::GetTemporaryFolderI(Pathname &pathname, bool create,
+ const std::string *append) {
+ pathname.SetPathname("/tmp");
+ if (append) {
+ pathname.AppendFolder(*append);
+ if (create)
+ CreateFolder(pathname);
+ }
+}
+
+std::string UnixFilesystem::TempFilenameI(const Pathname &dir, const std::string &prefix) {
+ int len = dir.pathname().size() + prefix.size() + 2 + 6;
+ char *tempname = new char[len];
+
+ snprintf(tempname, len, "%s/%sXXXXXX", dir.pathname().c_str(), prefix.c_str());
+ int fd = ::mkstemp(tempname);
+ if (fd != -1)
+ ::close(fd);
+ std::string ret(tempname);
+ delete[] tempname;
+
+ return ret;
+}
+
+bool UnixFilesystem::MoveFileI(const Pathname &old_path, const Pathname &new_path)
+{
+ LOG(LS_INFO) << "Moving " << old_path.pathname() << " to " << new_path.pathname();
+ if (rename(old_path.pathname().c_str(), new_path.pathname().c_str()) != 0) {
+ if (errno != EXDEV)
+ return false;
+ if (!CopyFile(old_path, new_path))
+ return false;
+ if (!DeleteFile(old_path))
+ return false;
+ }
+ return true;
+}
+
+bool UnixFilesystem::IsFolderI(const Pathname &path)
+{
+ struct stat st;
+ if (stat(path.pathname().c_str(), &st) < 0)
+ return false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+bool UnixFilesystem::CopyFileI(const Pathname &old_path, const Pathname &new_path)
+{
+ LOG(LS_INFO) << "Copying " << old_path.pathname() << " to " << new_path.pathname();
+ char buf[256];
+ size_t len;
+ if (IsFolder(old_path)) {
+ Pathname new_dir;
+ new_dir.SetFolder(new_path.pathname());
+ Pathname old_dir;
+ old_dir.SetFolder(old_path.pathname());
+
+ if (!CreateFolder(new_dir))
+ return false;
+ DirectoryIterator di;
+ di.Iterate(old_dir.pathname());
+ while(di.Next()) {
+ if (di.Name() == "." || di.Name() == "..")
+ continue;
+ Pathname source;
+ Pathname dest;
+ source.SetFolder(old_dir.pathname());
+ dest.SetFolder(new_path.pathname());
+ source.SetFilename(di.Name());
+ dest.SetFilename(di.Name());
+
+ if (!CopyFile(source, dest))
+ return false;
+ }
+ return true;
+ }
+
+ StreamInterface *source = OpenFile(old_path, "rb");
+ if (!source)
+ return false;
+
+ StreamInterface *dest = OpenFile(new_path, "wb");
+ if (!dest) {
+ delete source;
+ return false;
+ }
+
+ while (source->Read(buf, sizeof(buf), &len, NULL) == talk_base::SR_SUCCESS)
+ dest->Write(buf, len, NULL, NULL);
+
+ delete source;
+ delete dest;
+ return true;
+}
+
+bool UnixFilesystem::IsTemporaryPathI(const Pathname& pathname)
+{
+ return (!strncmp(pathname.pathname().c_str(), "/tmp/", strlen("/tmp/")));
+}
+
+bool UnixFilesystem::FileExistsI(const Pathname& pathname)
+{
+ struct stat st;
+ int res = ::stat(pathname.pathname().c_str(), &st);
+ return res == 0;
+}
+
+bool UnixFilesystem::GetFileSizeI(const Pathname& pathname, size_t *size)
+{
+ struct stat st;
+ if (::stat(pathname.pathname().c_str(), &st) != 0)
+ return false;
+ *size = st.st_size;
+ return true;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/base/unixfilesystem.h b/third_party/libjingle/files/talk/base/unixfilesystem.h
new file mode 100644
index 0000000..bd145bb
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/unixfilesystem.h
@@ -0,0 +1,86 @@
+/*
+ * 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 _TALK_BASE_UNIXFILESYSTEM_H__
+#define _TALK_BASE_UNIXFILESYSTEM_H__
+
+#include "fileutils.h"
+
+namespace talk_base {
+
+class UnixFilesystem : public Filesystem{
+ public:
+
+ virtual bool CreateFolderI(const Pathname &pathname);
+
+ // Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
+ // returns NULL.
+ virtual FileStream *OpenFileI(const Pathname &filename,
+ const std::string &mode);
+
+ // This will attempt to delete the path located at filename. If filename is a file,
+ // it will be unlinked. If the path is a directory, it will recursively unlink and remove
+ // all the files and directory within it
+ virtual bool DeleteFileI(const Pathname &filename);
+
+ // Creates a directory. This will call itself recursively to create /foo/bar even if
+ // /foo does not exist.
+ // Returns TRUE if function succeeds
+
+ // This moves a file from old_path to new_path, where "file" can be a plain file
+ // or directory, which will be moved recursively.
+ // Returns true if function succeeds.
+ virtual bool MoveFileI(const Pathname &old_path, const Pathname &new_path);
+
+ // This copies a file from old_path to _new_path where "file" can be a plain file
+ // or directory, which will be copied recursively.
+ // Returns true if function succeeds
+ virtual bool CopyFileI(const Pathname &old_path, const Pathname &new_path);
+
+ // Returns true if a pathname is a directory
+ virtual bool IsFolderI(const Pathname& pathname);
+
+ // Returns true if pathname represents a temporary location on the system.
+ virtual bool IsTemporaryPathI(const Pathname& pathname);
+
+ // Returns true of pathname represents an existing file
+ virtual bool FileExistsI(const Pathname& pathname);
+
+ virtual std::string TempFilenameI(const Pathname &dir, const std::string &prefix);
+
+ // A folder appropriate for storing temporary files (Contents are
+ // automatically deleted when the program exists)
+ virtual bool GetTemporaryFolderI(Pathname &path, bool create,
+ const std::string *append);
+
+ virtual bool GetFileSizeI(const Pathname &path, size_t *size);
+
+ };
+
+}
+
+#endif // _UNIXFILESYSTEM_H__
diff --git a/third_party/libjingle/files/talk/base/urlencode.cc b/third_party/libjingle/files/talk/base/urlencode.cc
new file mode 100644
index 0000000..d80fbe1
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/urlencode.cc
@@ -0,0 +1,122 @@
+#include <stdlib.h>
+#include <string.h>
+#include "talk/base/urlencode.h"
+
+static int HexPairValue(const char * code) {
+ int value = 0;
+ const char * pch = code;
+ for (;;) {
+ int digit = *pch++;
+ if (digit >= '0' && digit <= '9') {
+ value += digit - '0';
+ }
+ else if (digit >= 'A' && digit <= 'F') {
+ value += digit - 'A' + 10;
+ }
+ else if (digit >= 'a' && digit <= 'f') {
+ value += digit - 'a' + 10;
+ }
+ else {
+ return -1;
+ }
+ if (pch == code + 2)
+ return value;
+ value <<= 4;
+ }
+}
+
+int UrlDecode(const char *source, char *dest)
+{
+ char * start = dest;
+
+ while (*source) {
+ switch (*source) {
+ case '+':
+ *(dest++) = ' ';
+ break;
+ case '%':
+ if (source[1] && source[2]) {
+ int value = HexPairValue(source + 1);
+ if (value >= 0) {
+ *(dest++) = value;
+ source += 2;
+ }
+ else {
+ *dest++ = '?';
+ }
+ }
+ else {
+ *dest++ = '?';
+ }
+ break;
+ default:
+ *dest++ = *source;
+ }
+ source++;
+ }
+
+ *dest = 0;
+ return dest - start;
+}
+
+int UrlEncode(const char *source, char *dest, unsigned max)
+{
+ static const char *digits = "0123456789ABCDEF";
+ unsigned char ch;
+ unsigned len = 0;
+ char *start = dest;
+
+ while (len < max - 4 && *source)
+ {
+ ch = (unsigned char)*source;
+ if (*source == ' ') {
+ *dest++ = '+';
+ }
+ else if (isalnum(ch) || strchr("-_.!~*'()", ch)) {
+ *dest++ = *source;
+ }
+ else {
+ *dest++ = '%';
+ *dest++ = digits[(ch >> 4) & 0x0F];
+ *dest++ = digits[ ch & 0x0F];
+ }
+ source++;
+ }
+ *dest = 0;
+ return start - dest;
+}
+
+std::string
+UrlDecodeString(const std::string & encoded) {
+ const char * sz_encoded = encoded.c_str();
+ size_t needed_length = encoded.length();
+ for (const char * pch = sz_encoded; *pch; pch++) {
+ if (*pch == '%')
+ needed_length += 2;
+ }
+ needed_length += 10;
+ char stackalloc[64];
+ char * buf = needed_length > sizeof(stackalloc)/sizeof(*stackalloc) ?
+ (char *)malloc(needed_length) : stackalloc;
+ UrlDecode(encoded.c_str(), buf);
+ std::string result(buf);
+ if (buf != stackalloc) {
+ free(buf);
+ }
+ return result;
+}
+
+std::string
+UrlEncodeString(const std::string & decoded) {
+ const char * sz_decoded = decoded.c_str();
+ size_t needed_length = decoded.length() * 3 + 3;
+ char stackalloc[64];
+ char * buf = needed_length > sizeof(stackalloc)/sizeof(*stackalloc) ?
+ (char *)malloc(needed_length) : stackalloc;
+ UrlEncode(decoded.c_str(), buf, needed_length);
+ std::string result(buf);
+ if (buf != stackalloc) {
+ free(buf);
+ }
+ return result;
+}
diff --git a/third_party/libjingle/files/talk/base/urlencode.h b/third_party/libjingle/files/talk/base/urlencode.h
new file mode 100644
index 0000000..9d2b3f6
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/urlencode.h
@@ -0,0 +1,12 @@
+#ifndef _URLENCODE_H_
+#define _URLENCODE_H_
+
+#include <string>
+
+int UrlDecode(const char *source, char *dest);
+int UrlEncode(const char *source, char *dest, unsigned max);
+std::string UrlDecodeString(const std::string & encoded);
+std::string UrlEncodeString(const std::string & decoded);
+
+#endif
+
diff --git a/third_party/libjingle/files/talk/base/virtualsocket_unittest.cc b/third_party/libjingle/files/talk/base/virtualsocket_unittest.cc
new file mode 100644
index 0000000..16456a2
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/virtualsocket_unittest.cc
@@ -0,0 +1,239 @@
+// Copyright 2006, Google Inc.
+
+#include <complex>
+#include <iostream>
+#include <cassert>
+
+#include "talk/base/thread.h"
+#include "talk/base/virtualsocketserver.h"
+#include "talk/base/testclient.h"
+#include "talk/base/time.h"
+
+#ifdef POSIX
+extern "C" {
+#include <errno.h>
+}
+#endif // POSIX
+
+using namespace talk_base;
+
+void test_basic(Thread* thread, VirtualSocketServer* ss) {
+ std::cout << "basic: ";
+ std::cout.flush();
+
+ SocketAddress addr1(ss->GetNextIP(), 5000);
+ AsyncUDPSocket* socket = CreateAsyncUDPSocket(ss);
+ socket->Bind(addr1);
+
+ TestClient* client1 = new TestClient(socket);
+ TestClient* client2 = new TestClient(CreateAsyncUDPSocket(ss));
+
+ SocketAddress addr2;
+ client2->SendTo("foo", 3, addr1);
+ client1->CheckNextPacket("foo", 3, &addr2);
+
+ SocketAddress addr3;
+ client1->SendTo("bizbaz", 6, addr2);
+ client2->CheckNextPacket("bizbaz", 6, &addr3);
+ assert(addr3 == addr1);
+
+ for (int i = 0; i < 10; i++) {
+ client2 = new TestClient(CreateAsyncUDPSocket(ss));
+
+ SocketAddress addr4;
+ client2->SendTo("foo", 3, addr1);
+ client1->CheckNextPacket("foo", 3, &addr4);
+ assert((addr4.ip() == addr2.ip()) && (addr4.port() == addr2.port() + 1));
+
+ SocketAddress addr5;
+ client1->SendTo("bizbaz", 6, addr4);
+ client2->CheckNextPacket("bizbaz", 6, &addr5);
+ assert(addr5 == addr1);
+
+ addr2 = addr4;
+ }
+
+ std::cout << "PASS" << std::endl;
+}
+
+// Sends at a constant rate but with random packet sizes.
+struct Sender : public MessageHandler {
+ Sender(Thread* th, AsyncUDPSocket* s, uint32 rt)
+ : thread(th), socket(s), done(false), rate(rt), count(0) {
+ last_send = GetMillisecondCount();
+ thread->PostDelayed(NextDelay(), this, 1);
+ }
+
+ uint32 NextDelay() {
+ uint32 size = (rand() % 4096) + 1;
+ return 1000 * size / rate;
+ }
+
+ void OnMessage(Message* pmsg) {
+ assert(pmsg->message_id == 1);
+
+ if (done)
+ return;
+
+ uint32 cur_time = GetMillisecondCount();
+ uint32 delay = cur_time - last_send;
+ uint32 size = rate * delay / 1000;
+ size = std::min(size, uint32(4096));
+ size = std::max(size, uint32(4));
+
+ count += size;
+ *reinterpret_cast<uint32*>(dummy) = cur_time;
+ socket->Send(dummy, size);
+
+ last_send = cur_time;
+ thread->PostDelayed(NextDelay(), this, 1);
+ }
+
+ Thread* thread;
+ AsyncUDPSocket* socket;
+ bool done;
+ uint32 rate; // bytes per second
+ uint32 count;
+ uint32 last_send;
+ char dummy[4096];
+};
+
+struct Receiver : public MessageHandler, public sigslot::has_slots<> {
+ Receiver(Thread* th, AsyncUDPSocket* s, uint32 bw)
+ : thread(th), socket(s), bandwidth(bw), done(false), count(0),
+ sec_count(0), sum(0), sum_sq(0), samples(0) {
+ socket->SignalReadPacket.connect(this, &Receiver::OnReadPacket);
+ thread->PostDelayed(1000, this, 1);
+ }
+
+ ~Receiver() {
+ thread->Clear(this);
+ }
+
+ void OnReadPacket(
+ const char* data, size_t size, const SocketAddress& remote_addr,
+ AsyncPacketSocket* s) {
+ assert(s == socket);
+ assert(size >= 4);
+
+ count += size;
+ sec_count += size;
+
+ uint32 send_time = *reinterpret_cast<const uint32*>(data);
+ uint32 recv_time = GetMillisecondCount();
+ uint32 delay = recv_time - send_time;
+ sum += delay;
+ sum_sq += delay * delay;
+ samples += 1;
+ }
+
+ void OnMessage(Message* pmsg) {
+ assert(pmsg->message_id == 1);
+ // It is always possible for us to receive more than expected because
+ // packets can be further delayed in delivery.
+ if (bandwidth > 0)
+ assert(sec_count <= 5 * bandwidth / 4);
+ sec_count = 0;
+ thread->PostDelayed(1000, this, 1);
+ }
+
+ Thread* thread;
+ AsyncUDPSocket* socket;
+ uint32 bandwidth;
+ bool done;
+ uint32 count;
+ uint32 sec_count;
+ double sum;
+ double sum_sq;
+ uint32 samples;
+};
+
+void test_bandwidth(Thread* thread, VirtualSocketServer* ss) {
+ std::cout << "bandwidth: ";
+ std::cout.flush();
+
+ AsyncUDPSocket* send_socket = CreateAsyncUDPSocket(ss);
+ AsyncUDPSocket* recv_socket = CreateAsyncUDPSocket(ss);
+ assert(send_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0);
+ assert(recv_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0);
+ assert(send_socket->Connect(recv_socket->GetLocalAddress()) >= 0);
+
+ uint32 bandwidth = 64 * 1024;
+ ss->set_bandwidth(bandwidth);
+
+ Sender sender(thread, send_socket, 80 * 1024);
+ Receiver receiver(thread, recv_socket, bandwidth);
+
+ Thread* pthMain = Thread::Current();
+ pthMain->ProcessMessages(5000);
+ sender.done = true;
+ pthMain->ProcessMessages(5000);
+
+ assert(receiver.count >= 5 * 3 * bandwidth / 4);
+ assert(receiver.count <= 6 * bandwidth); // queue could drain for 1 sec
+
+ delete send_socket;
+ delete recv_socket;
+
+ ss->set_bandwidth(0);
+
+ std::cout << "PASS" << std::endl;
+}
+
+void test_delay(Thread* thread, VirtualSocketServer* ss) {
+ std::cout << "delay: ";
+ std::cout.flush();
+
+ uint32 mean = 2000;
+ uint32 stddev = 500;
+
+ ss->set_delay_mean(mean);
+ ss->set_delay_stddev(stddev);
+ ss->UpdateDelayDistribution();
+
+ AsyncUDPSocket* send_socket = CreateAsyncUDPSocket(ss);
+ AsyncUDPSocket* recv_socket = CreateAsyncUDPSocket(ss);
+ assert(send_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0);
+ assert(recv_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0);
+ assert(send_socket->Connect(recv_socket->GetLocalAddress()) >= 0);
+
+ Sender sender(thread, send_socket, 64 * 1024);
+ Receiver receiver(thread, recv_socket, 0);
+
+ Thread* pthMain = Thread::Current();
+ pthMain->ProcessMessages(5000);
+ sender.done = true;
+ pthMain->ProcessMessages(5000);
+
+ double sample_mean = receiver.sum / receiver.samples;
+ double num = receiver.sum_sq - 2 * sample_mean * receiver.sum +
+ receiver.samples * sample_mean * sample_mean;
+ double sample_stddev = std::sqrt(num / (receiver.samples - 1));
+std::cout << "mean=" << sample_mean << " dev=" << sample_stddev << std::endl;
+
+ assert(0.9 * mean <= sample_mean);
+ assert(sample_mean <= 1.1 * mean);
+ assert(0.9 * stddev <= sample_stddev);
+ assert(sample_stddev <= 1.1 * stddev);
+
+ delete send_socket;
+ delete recv_socket;
+
+ ss->set_delay_mean(0);
+ ss->set_delay_stddev(0);
+ ss->UpdateDelayDistribution();
+
+ std::cout << "PASS" << std::endl;
+}
+
+int main(int argc, char* argv) {
+ Thread *pthMain = Thread::Current();
+ VirtualSocketServer* ss = new VirtualSocketServer();
+ pthMain->set_socketserver(ss);
+
+ test_basic(pthMain, ss);
+ test_bandwidth(pthMain, ss);
+ test_delay(pthMain, ss);
+
+ return 0;
+}
diff --git a/third_party/libjingle/files/talk/base/virtualsocketserver.cc b/third_party/libjingle/files/talk/base/virtualsocketserver.cc
new file mode 100644
index 0000000..884b324
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/virtualsocketserver.cc
@@ -0,0 +1,616 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include <iostream>
+#include <vector>
+#include <errno.h>
+
+#include "talk/base/virtualsocketserver.h"
+#include "talk/base/common.h"
+#include "talk/base/time.h"
+
+namespace talk_base {
+
+const uint32 HEADER_SIZE = 28; // IP + UDP headers
+
+const uint32 MSG_ID_PACKET = 1;
+// TODO: Add a message type for new connections.
+
+// Packets are passed between sockets as messages. We copy the data just like
+// the kernel does.
+class Packet : public MessageData {
+public:
+ Packet(const char* data, size_t size, const SocketAddress& from)
+ : size_(size), from_(from) {
+ assert(data);
+ assert(size_ >= 0);
+ data_ = new char[size_];
+ std::memcpy(data_, data, size_);
+ }
+
+ virtual ~Packet() {
+ delete data_;
+ }
+
+ const char* data() const { return data_; }
+ size_t size() const { return size_; }
+ const SocketAddress& from() const { return from_; }
+
+ // Remove the first size bytes from the data.
+ void Consume(size_t size) {
+ assert(size < size_);
+ size_ -= size;
+ char* new_data = new char[size_];
+ std::memcpy(new_data, data_, size);
+ delete[] data_;
+ data_ = new_data;
+ }
+
+private:
+ char* data_;
+ size_t size_;
+ SocketAddress from_;
+};
+
+// Implements the socket interface using the virtual network. Packets are
+// passed as messages using the message queue of the socket server.
+class VirtualSocket : public AsyncSocket, public MessageHandler {
+public:
+ VirtualSocket(
+ VirtualSocketServer* server, int type, bool async, uint32 ip)
+ : server_(server), type_(type), async_(async), connected_(false),
+ local_ip_(ip), readable_(true), queue_size_(0) {
+ assert((type_ == SOCK_DGRAM) || (type_ == SOCK_STREAM));
+ packets_ = new std::vector<Packet*>();
+ }
+
+ ~VirtualSocket() {
+ Close();
+
+ for (unsigned i = 0; i < packets_->size(); i++)
+ delete (*packets_)[i];
+ delete packets_;
+ }
+
+ SocketAddress GetLocalAddress() const {
+ return local_addr_;
+ }
+
+ SocketAddress GetRemoteAddress() const {
+ return remote_addr_;
+ }
+
+ int Bind(const SocketAddress& addr) {
+ assert(addr.port() != 0);
+ int result = server_->Bind(addr, this);
+ if (result >= 0)
+ local_addr_ = addr;
+ else
+ error_ = EADDRINUSE;
+ return result;
+ }
+
+ int Connect(const SocketAddress& addr) {
+ assert(!connected_);
+ connected_ = true;
+ remote_addr_ = addr;
+ assert(type_ == SOCK_DGRAM); // stream not yet implemented
+ return 0;
+ }
+
+ int Close() {
+ if (!local_addr_.IsAny())
+ server_->Unbind(local_addr_, this);
+
+ connected_ = false;
+ local_addr_ = SocketAddress();
+ remote_addr_ = SocketAddress();
+ return 0;
+ }
+
+ int Send(const void *pv, size_t cb) {
+ assert(connected_);
+ return SendInternal(pv, cb, remote_addr_);
+ }
+
+ int SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+ assert(!connected_);
+ return SendInternal(pv, cb, addr);
+ }
+
+ int SendInternal(const void *pv, size_t cb, const SocketAddress& addr) {
+ // If we have not been assigned a local port, then get one.
+ if (local_addr_.IsAny()) {
+ local_addr_.SetIP(local_ip_);
+ int result = server_->Bind(this, &local_addr_);
+ if (result < 0) {
+ local_addr_.SetIP(0);
+ error_ = EADDRINUSE;
+ return result;
+ }
+ }
+
+ // Send the data in a message to the appropriate socket.
+ return server_->Send(this, pv, cb, local_addr_, addr);
+ }
+
+ int Recv(void *pv, size_t cb) {
+ SocketAddress addr;
+ return RecvFrom(pv, cb, &addr);
+ }
+
+ int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
+ // If we don't have a packet, then either error or wait for one to arrive.
+ if (packets_->size() == 0) {
+ if (async_) {
+ error_ = EAGAIN;
+ return -1;
+ }
+ while (packets_->size() == 0) {
+ Message msg;
+ server_->msg_queue_->Get(&msg);
+ server_->msg_queue_->Dispatch(&msg);
+ }
+ }
+
+ // Return the packet at the front of the queue.
+ Packet* packet = packets_->front();
+ *paddr = packet->from();
+ int size = (int)packet->size();
+ if (size <= (int)cb) {
+ std::memcpy(pv, packet->data(), size);
+ packets_->erase(packets_->begin());
+ delete packet;
+ return size;
+ } else {
+ std::memcpy(pv, packet->data(), cb);
+ packet->Consume(cb);
+ return (int)cb;
+ }
+ }
+
+ int Listen(int backlog) {
+ assert(false); // not yet implemented
+ return 0;
+ }
+
+ Socket* Accept(SocketAddress *paddr) {
+ assert(false); // not yet implemented
+ return 0;
+ }
+
+ bool readable() { return readable_; }
+ void set_readable(bool value) { readable_ = value; }
+
+ bool writable() { return false; }
+ void set_writable(bool value) {
+ // TODO: Send ourselves messages (delayed after the first) to give them a
+ // chance to write.
+ assert(false);
+ }
+
+ int GetError() const {
+ return error_;
+ }
+
+ void SetError(int error) {
+ error_ = error;
+ }
+
+ ConnState GetState() const {
+ return connected_ ? CS_CONNECTED : CS_CLOSED;
+ }
+
+ int SetOption(Option opt, int value) {
+ return 0;
+ }
+
+ int EstimateMTU(uint16* mtu) {
+ if (!connected_)
+ return ENOTCONN;
+ else
+ return 65536;
+ }
+
+ void OnMessage(Message *pmsg) {
+ if (pmsg->message_id == MSG_ID_PACKET) {
+ assert(pmsg->pdata);
+ Packet* packet = static_cast<Packet*>(pmsg->pdata);
+
+ if (!readable_)
+ return;
+
+ packets_->push_back(packet);
+
+ if (async_) {
+ SignalReadEvent(this);
+
+ // TODO: If the listeners don't want to read this packet now, we will
+ // need to send ourselves delayed messages to try again.
+ assert(packets_->size() == 0);
+ }
+ } else {
+ assert(false);
+ }
+ }
+
+private:
+ struct QueueEntry {
+ uint32 size;
+ uint32 done_time;
+ };
+
+ typedef std::deque<QueueEntry> SendQueue;
+
+ VirtualSocketServer* server_;
+ int type_;
+ bool async_;
+ bool connected_;
+ uint32 local_ip_;
+ bool readable_;
+ SocketAddress local_addr_;
+ SocketAddress remote_addr_;
+ std::vector<Packet*>* packets_;
+ int error_;
+ SendQueue queue_;
+ uint32 queue_size_;
+ CriticalSection queue_crit_;
+
+ friend class VirtualSocketServer;
+};
+
+VirtualSocketServer::VirtualSocketServer()
+ : fWait_(false), wait_version_(0), next_ip_(1), next_port_(45000),
+ bandwidth_(0), queue_capacity_(64 * 1024), delay_mean_(0),
+ delay_stddev_(0), delay_dist_(0), drop_prob_(0.0) {
+ msg_queue_ = new MessageQueue(); // uses physical socket server for Wait
+ bindings_ = new AddressMap();
+
+ UpdateDelayDistribution();
+}
+
+VirtualSocketServer::~VirtualSocketServer() {
+ delete bindings_;
+ delete msg_queue_;
+ delete delay_dist_;
+}
+
+uint32 VirtualSocketServer::GetNextIP() {
+ return next_ip_++;
+}
+
+Socket* VirtualSocketServer::CreateSocket(int type) {
+ return CreateSocketInternal(type);
+}
+
+AsyncSocket* VirtualSocketServer::CreateAsyncSocket(int type) {
+ return CreateSocketInternal(type);
+}
+
+VirtualSocket* VirtualSocketServer::CreateSocketInternal(int type) {
+ uint32 ip = (next_ip_ > 1) ? next_ip_ - 1 : 1;
+ return new VirtualSocket(this, type, true, ip);
+}
+
+bool VirtualSocketServer::Wait(int cmsWait, bool process_io) {
+ ASSERT(process_io); // This can't be easily supported.
+
+ uint32 msEnd;
+ if (cmsWait != kForever)
+ msEnd = GetMillisecondCount() + cmsWait;
+ uint32 cmsNext = cmsWait;
+
+ fWait_ = true;
+ wait_version_ += 1;
+
+ while (fWait_) {
+ Message msg;
+ if (!msg_queue_->Get(&msg, cmsNext))
+ return true;
+ msg_queue_->Dispatch(&msg);
+
+ if (cmsWait != kForever) {
+ uint32 msCur = GetMillisecondCount();
+ if (msCur >= msEnd)
+ return true;
+ cmsNext = msEnd - msCur;
+ }
+ }
+ return true;
+}
+
+const uint32 MSG_WAKE_UP = 1;
+
+struct WakeUpMessage : public MessageData {
+ WakeUpMessage(uint32 ver) : wait_version(ver) {}
+ virtual ~WakeUpMessage() {}
+
+ uint32 wait_version;
+};
+
+void VirtualSocketServer::WakeUp() {
+ msg_queue_->Post(this, MSG_WAKE_UP, new WakeUpMessage(wait_version_));
+}
+
+void VirtualSocketServer::OnMessage(Message* pmsg) {
+ assert(pmsg->message_id == MSG_WAKE_UP);
+ assert(pmsg->pdata);
+ WakeUpMessage* wmsg = static_cast<WakeUpMessage*>(pmsg->pdata);
+ if (wmsg->wait_version == wait_version_)
+ fWait_ = false;
+ delete pmsg->pdata;
+}
+
+int VirtualSocketServer::Bind(
+ const SocketAddress& addr, VirtualSocket* socket) {
+ assert(addr.ip() > 0); // don't support any-address right now
+ assert(addr.port() > 0);
+ assert(socket);
+
+ if (bindings_->find(addr) == bindings_->end()) {
+ (*bindings_)[addr] = socket;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int VirtualSocketServer::Bind(VirtualSocket* socket, SocketAddress* addr) {
+ assert(addr->ip() > 0); // don't support any-address right now
+ assert(socket);
+
+ for (int i = 0; i < 65536; i++) {
+ addr->SetPort(next_port_++);
+ if (addr->port() > 0) {
+ AddressMap::iterator iter = bindings_->find(*addr);
+ if (iter == bindings_->end()) {
+ (*bindings_)[*addr] = socket;
+ return 0;
+ }
+ }
+ }
+
+ errno = EADDRINUSE; // TODO: is there a better error number?
+ return -1;
+}
+
+int VirtualSocketServer::Unbind(
+ const SocketAddress& addr, VirtualSocket* socket) {
+ assert((*bindings_)[addr] == socket);
+ bindings_->erase(bindings_->find(addr));
+ return 0;
+}
+
+static double Random() {
+ return double(rand()) / RAND_MAX;
+}
+
+int VirtualSocketServer::Send(
+ VirtualSocket* socket, const void *pv, size_t cb,
+ const SocketAddress& local_addr, const SocketAddress& remote_addr) {
+
+ // See if we want to drop this packet.
+ if (Random() < drop_prob_) {
+ std::cerr << "Dropping packet: bad luck" << std::endl;
+ return 0;
+ }
+
+ uint32 cur_time = GetMillisecondCount();
+ uint32 send_delay;
+
+ // Determine whether we have enough bandwidth to accept this packet. To do
+ // this, we need to update the send queue. Once we know it's current size,
+ // we know whether we can fit this packet.
+ //
+ // NOTE: There are better algorithms for maintaining such a queue (such as
+ // "Derivative Random Drop"); however, this algorithm is a more accurate
+ // simulation of what a normal network would do.
+ {
+ CritScope cs(&socket->queue_crit_);
+
+ while ((socket->queue_.size() > 0) &&
+ (socket->queue_.front().done_time <= cur_time)) {
+ assert(socket->queue_size_ >= socket->queue_.front().size);
+ socket->queue_size_ -= socket->queue_.front().size;
+ socket->queue_.pop_front();
+ }
+
+ VirtualSocket::QueueEntry entry;
+ entry.size = uint32(cb) + HEADER_SIZE;
+
+ if (socket->queue_size_ + entry.size > queue_capacity_) {
+ std::cerr << "Dropping packet: queue capacity exceeded" << std::endl;
+ return 0; // not an error
+ }
+
+ socket->queue_size_ += entry.size;
+ send_delay = SendDelay(socket->queue_size_);
+ entry.done_time = cur_time + send_delay;
+ socket->queue_.push_back(entry);
+ }
+
+ // Find the delay for crossing the many virtual hops of the network.
+ uint32 transit_delay = GetRandomTransitDelay();
+
+ // Post the packet as a message to be delivered (on our own thread)
+
+ AddressMap::iterator iter = bindings_->find(remote_addr);
+ if (iter != bindings_->end()) {
+ Packet* p = new Packet(static_cast<const char*>(pv), cb, local_addr);
+ uint32 delay = send_delay + transit_delay;
+ msg_queue_->PostDelayed(delay, iter->second, MSG_ID_PACKET, p);
+ } else {
+ std::cerr << "No one listening at " << remote_addr.ToString() << std::endl;
+ }
+ return (int)cb;
+}
+
+uint32 VirtualSocketServer::SendDelay(uint32 size) {
+ if (bandwidth_ == 0)
+ return 0;
+ else
+ return 1000 * size / bandwidth_;
+}
+
+void PrintFunction(std::vector<std::pair<double,double> >* f) {
+ for (uint32 i = 0; i < f->size(); i++)
+ std::cout << (*f)[i].first << '\t' << (*f)[i].second << std::endl;
+}
+
+void VirtualSocketServer::UpdateDelayDistribution() {
+ Function* dist = GetDelayDistribution();
+ dist = Resample(Invert(Accumulate(dist)), 0, 1);
+
+ // We take a lock just to make sure we don't leak memory.
+ {
+ CritScope cs(&delay_crit_);
+ delete delay_dist_;
+ delay_dist_ = dist;
+ }
+}
+
+const int NUM_SAMPLES = 100; // 1000;
+
+static double PI = 4 * std::atan(1.0);
+
+static double Normal(double x, double mean, double stddev) {
+ double a = (x - mean) * (x - mean) / (2 * stddev * stddev);
+ return std::exp(-a) / (stddev * sqrt(2 * PI));
+}
+
+#if 0 // static unused gives a warning
+static double Pareto(double x, double min, double k) {
+ if (x < min)
+ return 0;
+ else
+ return k * std::pow(min, k) / std::pow(x, k+1);
+}
+#endif
+
+VirtualSocketServer::Function* VirtualSocketServer::GetDelayDistribution() {
+ Function* f = new Function();
+
+ if (delay_stddev_ == 0) {
+
+ f->push_back(Point(delay_mean_, 1.0));
+
+ } else {
+
+ double start = 0;
+ if (delay_mean_ >= 4 * double(delay_stddev_))
+ start = delay_mean_ - 4 * double(delay_stddev_);
+ double end = delay_mean_ + 4 * double(delay_stddev_);
+
+ double delay_min = 0;
+ if (delay_mean_ >= 1.0 * delay_stddev_)
+ delay_min = delay_mean_ - 1.0 * delay_stddev_;
+
+ for (int i = 0; i < NUM_SAMPLES; i++) {
+ double x = start + (end - start) * i / (NUM_SAMPLES - 1);
+ double y = Normal(x, delay_mean_, delay_stddev_);
+ f->push_back(Point(x, y));
+ }
+
+ }
+
+ return f;
+}
+
+uint32 VirtualSocketServer::GetRandomTransitDelay() {
+ double delay = (*delay_dist_)[rand() % delay_dist_->size()].second;
+ return uint32(delay);
+}
+
+struct FunctionDomainCmp {
+ bool operator ()(const VirtualSocketServer::Point& p1, const VirtualSocketServer::Point& p2) {
+ return p1.first < p2.first;
+ }
+ bool operator ()(double v1, const VirtualSocketServer::Point& p2) {
+ return v1 < p2.first;
+ }
+ bool operator ()(const VirtualSocketServer::Point& p1, double v2) {
+ return p1.first < v2;
+ }
+};
+
+VirtualSocketServer::Function* VirtualSocketServer::Accumulate(Function* f) {
+ assert(f->size() >= 1);
+ double v = 0;
+ for (Function::size_type i = 0; i < f->size() - 1; ++i) {
+ double dx = (*f)[i].second * ((*f)[i+1].first - (*f)[i].first);
+ v = (*f)[i].second = v + dx;
+ }
+ (*f)[f->size()-1].second = v;
+ return f;
+}
+
+VirtualSocketServer::Function* VirtualSocketServer::Invert(Function* f) {
+ for (Function::size_type i = 0; i < f->size(); ++i)
+ std::swap((*f)[i].first, (*f)[i].second);
+
+ std::sort(f->begin(), f->end(), FunctionDomainCmp());
+ return f;
+}
+
+VirtualSocketServer::Function* VirtualSocketServer::Resample(
+ Function* f, double x1, double x2) {
+ Function* g = new Function();
+
+ for (int i = 0; i < NUM_SAMPLES; i++) {
+ double x = x1 + (x2 - x1) * i / (NUM_SAMPLES - 1);
+ double y = Evaluate(f, x);
+ g->push_back(Point(x, y));
+ }
+
+ delete f;
+ return g;
+}
+
+double VirtualSocketServer::Evaluate(Function* f, double x) {
+ Function::iterator iter =
+ std::lower_bound(f->begin(), f->end(), x, FunctionDomainCmp());
+ if (iter == f->begin()) {
+ return (*f)[0].second;
+ } else if (iter == f->end()) {
+ assert(f->size() >= 1);
+ return (*f)[f->size() - 1].second;
+ } else if (iter->first == x) {
+ return iter->second;
+ } else {
+ double x1 = (iter - 1)->first;
+ double y1 = (iter - 1)->second;
+ double x2 = iter->first;
+ double y2 = iter->second;
+ return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+ }
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/virtualsocketserver.h b/third_party/libjingle/files/talk/base/virtualsocketserver.h
new file mode 100644
index 0000000..d2e894a
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/virtualsocketserver.h
@@ -0,0 +1,156 @@
+/*
+ * 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 TALK_BASE_VIRTUALSOCKETSERVER_H__
+#define TALK_BASE_VIRTUALSOCKETSERVER_H__
+
+#include <cassert>
+#include <deque>
+#include <map>
+
+#include "talk/base/messagequeue.h"
+#include "talk/base/socketserver.h"
+
+namespace talk_base {
+
+class VirtualSocket;
+
+// Simulates a network in the same manner as a loopback interface. The
+// interface can create as many addresses as you want. All of the sockets
+// created by this network will be able to communicate with one another.
+class VirtualSocketServer : public SocketServer, public MessageHandler {
+public:
+ VirtualSocketServer();
+ virtual ~VirtualSocketServer();
+
+ // Returns a new IP not used before in this network.
+ uint32 GetNextIP();
+
+ // Limits the network bandwidth (maximum bytes per second). Zero means that
+ // all sends occur instantly.
+ uint32 bandwidth() { return bandwidth_; }
+ void set_bandwidth(uint32 bandwidth) { bandwidth_ = bandwidth; }
+
+ // Limits the total size of packets that will be kept in the send queue,
+ // waiting for their turn to be written to the network Defaults to 64 KB.
+ uint32 queue_capacity() { return queue_capacity_; }
+ void set_queue_capacity(uint32 queue_capacity) {
+ queue_capacity_ = queue_capacity;
+ }
+
+ // Controls the (transit) delay for packets sent in the network. This does
+ // not inclue the time required to sit in the send queue. Both of these
+ // values are measured in milliseconds.
+ uint32 delay_mean() { return delay_mean_; }
+ uint32 delay_stddev() { return delay_stddev_; }
+ void set_delay_mean(uint32 delay_mean) { delay_mean_ = delay_mean; }
+ void set_delay_stddev(uint32 delay_stddev) {
+ delay_stddev_ = delay_stddev;
+ }
+
+ // If the (transit) delay parameters are modified, this method should be
+ // called to recompute the new distribution.
+ void UpdateDelayDistribution();
+
+ // Controls the (uniform) probability that any sent packet is dropped. This
+ // is separate from calculations to drop based on queue size.
+ double drop_probability() { return drop_prob_; }
+ void set_drop_probability(double drop_prob) {
+ assert((0 <= drop_prob) && (drop_prob <= 1));
+ drop_prob_ = drop_prob;
+ }
+
+ // SocketFactory:
+ virtual Socket* CreateSocket(int type);
+ virtual AsyncSocket* CreateAsyncSocket(int type);
+
+ // SocketServer:
+ virtual bool Wait(int cms, bool process_io);
+ virtual void WakeUp();
+
+ // Used to send internal wake-up messages.
+ virtual void OnMessage(Message* msg);
+
+ typedef std::pair<double,double> Point;
+ typedef std::vector<Point> Function;
+
+private:
+ friend class VirtualSocket;
+
+ typedef std::map<SocketAddress, VirtualSocket*> AddressMap;
+
+ MessageQueue* msg_queue_;
+ bool fWait_;
+ uint32 wait_version_;
+ uint32 next_ip_;
+ uint16 next_port_;
+ AddressMap* bindings_;
+
+ uint32 bandwidth_;
+ uint32 queue_capacity_;
+ uint32 delay_mean_;
+ uint32 delay_stddev_;
+ Function* delay_dist_;
+ CriticalSection delay_crit_;
+
+ double drop_prob_;
+
+ VirtualSocket* CreateSocketInternal(int type);
+
+ // Attempts to bind the given socket to the given (non-zero) address.
+ int Bind(const SocketAddress& addr, VirtualSocket* socket);
+
+ // Binds the given socket to the given (non-zero) IP on an unused port.
+ int Bind(VirtualSocket* socket, SocketAddress* addr);
+
+ // Removes the binding for the given socket.
+ int Unbind(const SocketAddress& addr, VirtualSocket* socket);
+
+ // Sends the given packet to the socket at the given address (if one exists).
+ int Send(VirtualSocket* socket, const void *pv, size_t cb,
+ const SocketAddress& local_addr, const SocketAddress& remote_addr);
+
+ // Computes the number of milliseconds required to send a packet of this size.
+ uint32 SendDelay(uint32 size);
+
+ // Returns the probability density function for the transit delay.
+ Function* GetDelayDistribution();
+
+ // Returns a random transit delay chosen from the appropriate distribution.
+ uint32 GetRandomTransitDelay();
+
+ // Basic operations on functions. Those that return a function also take
+ // ownership of the function given (and hence, may modify or delete it).
+ Function* Accumulate(Function* f);
+ Function* Invert(Function* f);
+ Function* Resample(Function* f, double x1, double x2);
+ double Evaluate(Function* f, double x);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_VIRTUALSOCKETSERVER_H__
diff --git a/third_party/libjingle/files/talk/base/win32.h b/third_party/libjingle/files/talk/base/win32.h
new file mode 100644
index 0000000..082e84f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/win32.h
@@ -0,0 +1,70 @@
+/*
+ * 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 TALK_BASE_WIN32_H__
+#define TALK_BASE_WIN32_H__
+
+#include <winsock2.h>
+#include <windows.h>
+#include <malloc.h>
+
+#include <string>
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline std::wstring ToUtf16(const std::string& str) {
+ int len16 = ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(),
+ NULL, 0);
+ wchar_t *ws = static_cast<wchar_t*>(_alloca(len16 * sizeof(wchar_t)));
+ ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), ws, len16);
+ std::wstring result(ws, len16);
+ return result;
+}
+
+inline std::string ToUtf8(const std::wstring& wstr) {
+ int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.length(),
+ NULL, 0, NULL, NULL);
+ char* ns = static_cast<char*>(_alloca(len8));
+ ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.length(),
+ ns, len8, NULL, NULL);
+ std::string result(ns, len8);
+ return result;
+}
+
+// Convert FILETIME to time_t
+void FileTimeToUnixTime(const FILETIME& ft, time_t* ut);
+
+// Convert time_t to FILETIME
+void UnixTimeToFileTime(const time_t& ut, FILETIME * ft);
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_WIN32_H__
diff --git a/third_party/libjingle/files/talk/base/win32filesystem.cc b/third_party/libjingle/files/talk/base/win32filesystem.cc
new file mode 100644
index 0000000..5b8b023
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/win32filesystem.cc
@@ -0,0 +1,194 @@
+/*
+ * 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 <errno.h>
+#include <cassert>
+
+#include "talk/base/basicdefs.h"
+#include "talk/base/convert.h"
+#include "talk/base/pathutils.h"
+#include "talk/base/fileutils.h"
+#include "talk/base/stringutils.h"
+#include "talk/base/stream.h"
+
+#include "talk/base/win32filesystem.h"
+
+namespace talk_base {
+
+bool Win32Filesystem::CreateFolderI(const Pathname &pathname) {
+ int len = pathname.pathname().length();
+
+ if ((len <= 0) || (pathname.pathname().c_str()[len-1] != '\\')) {
+ return false;
+ }
+
+ DWORD res = ::GetFileAttributes(Utf16(pathname.pathname()).AsWz());
+ if (res != INVALID_FILE_ATTRIBUTES) {
+ // Something exists at this location, check if it is a directory
+ return ((res & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ } else if ((GetLastError() != ERROR_FILE_NOT_FOUND)
+ && (GetLastError() != ERROR_PATH_NOT_FOUND)) {
+ // Unexpected error
+ return false;
+ }
+ // Directory doesn't exist, look up one directory level
+ do {
+ --len;
+ } while ((len > 0) && (pathname.pathname().c_str()[len-1] != '\\'));
+
+ if (!CreateFolder(std::string(pathname.pathname().c_str(),len)))
+ return false;
+
+ if (pathname.pathname().c_str()[0] != '\\') {
+ std::string long_path = std::string("\\\\?\\") + pathname.pathname();
+ return (::CreateDirectory(Utf16(long_path).AsWz(), NULL) != 0);
+ } else {
+ return (::CreateDirectory(Utf16(pathname.pathname()).AsWz(), NULL) != 0);
+ }
+}
+
+FileStream *Win32Filesystem::OpenFileI(const Pathname &filename,
+ const std::string &mode) {
+ talk_base::FileStream *fs = new talk_base::FileStream();
+ if (fs)
+ fs->Open(filename.pathname().c_str(), mode.c_str());
+ return fs;
+}
+
+bool Win32Filesystem::DeleteFileI(const Pathname &filename) {
+ LOG(LS_INFO) << "Deleting " << filename.pathname();
+
+ if (IsFolder(filename)) {
+ Pathname dir;
+ dir.SetFolder(filename.pathname());
+ DirectoryIterator di;
+ di.Iterate(dir.pathname());
+ while(di.Next()) {
+ if (di.Name() == "." || di.Name() == "..")
+ continue;
+ Pathname subdir;
+ subdir.SetFolder(filename.pathname());
+ subdir.SetFilename(di.Name());
+
+ if (!DeleteFile(subdir.pathname()))
+ return false;
+ }
+ std::string no_slash(filename.pathname(), 0, filename.pathname().length()-1);
+ return ::RemoveDirectory(Utf16(no_slash).AsWz()) == 0;
+ }
+ return ::DeleteFile(Utf16(filename.pathname()).AsWz()) == 0;
+}
+
+bool Win32Filesystem::GetTemporaryFolderI(Pathname &pathname, bool create,
+ const std::string *append) {
+ ASSERT(!g_application_name_.empty());
+ wchar_t buffer[MAX_PATH + 1];
+ if (!::GetTempPath(ARRAY_SIZE(buffer), buffer))
+ return false;
+ if (!::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
+ return false;
+ size_t len = strlen(buffer);
+ if ((len > 0) && (buffer[len-1] != '\\')) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ L"\\");
+ }
+ if ((len > 0) && (buffer[len-1] != '\\')) {
+ len += talk_base::strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
+ L"\\");
+ }
+ if (len >= ARRAY_SIZE(buffer) - 1)
+ return false;
+ pathname.clear();
+ pathname.SetFolder(Utf8(buffer).AsSz());
+ if (append != NULL)
+ pathname.AppendFolder(*append);
+ if (create)
+ CreateFolderI(pathname);
+ return true;
+}
+
+std::string Win32Filesystem::TempFilenameI(const Pathname &dir, const std::string &prefix) {
+ wchar_t filename[MAX_PATH];
+ if (::GetTempFileName(Utf16(dir.pathname()).AsWz(), Utf16(prefix).AsWz(), 0, filename) == 0)
+ return Utf8(filename).AsString();
+ return "";
+}
+
+bool Win32Filesystem::MoveFileI(const Pathname &old_path, const Pathname &new_path)
+{
+ LOG(LS_INFO) << "Moving " << old_path.pathname() << " to " << new_path.pathname();
+ if (_wrename(Utf16(old_path.pathname()).AsWz(), Utf16(new_path.pathname()).AsWz()) != 0) {
+ if (errno != EXDEV) {
+ printf("errno: %d\n", errno);
+ return false;
+ }
+ if (!CopyFile(old_path, new_path))
+ return false;
+ if (!DeleteFile(old_path))
+ return false;
+ }
+ return true;
+}
+
+bool Win32Filesystem::IsFolderI(const Pathname &path)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data = {0};
+ if (0 == ::GetFileAttributesEx(Utf16(path.pathname()).AsWz(), GetFileExInfoStandard, &data))
+ return false;
+ return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
+}
+
+bool Win32Filesystem::FileExistsI(const Pathname &path)
+{
+ DWORD res = ::GetFileAttributes(Utf16(path.pathname()).AsWz());
+ return res != INVALID_FILE_ATTRIBUTES;
+}
+
+bool Win32Filesystem::CopyFileI(const Pathname &old_path, const Pathname &new_path)
+{
+ return ::CopyFile(Utf16(old_path.pathname()).AsWz(), Utf16(new_path.pathname()).AsWz(), TRUE) == 0;
+}
+
+bool Win32Filesystem::IsTemporaryPathI(const Pathname& pathname)
+{
+ TCHAR buffer[MAX_PATH + 1];
+ if (!::GetTempPath(ARRAY_SIZE(buffer), buffer))
+ return false;
+ if (!::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
+ return false;
+ return (::strnicmp(Utf16(pathname.pathname()).AsWz(), buffer, strlen(buffer)) == 0);
+}
+
+bool Win32Filesystem::GetFileSizeI(const Pathname &pathname, size_t *size)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data = {0};
+ if (::GetFileAttributesEx(Utf16(pathname.pathname()).AsWz(), GetFileExInfoStandard, &data) == 0)
+ return false;
+ *size = data.nFileSizeLow;
+ return true;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/base/win32filesystem.h b/third_party/libjingle/files/talk/base/win32filesystem.h
new file mode 100644
index 0000000..1c13157
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/win32filesystem.h
@@ -0,0 +1,91 @@
+/*
+ * 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 _TALK_BASE_WIN32FILESYSTEM_H__
+#define _TALK_BASE_WIN32FILESYSTEM_H__
+
+#include "fileutils.h"
+
+namespace talk_base {
+
+class Win32Filesystem : public Filesystem{
+ public:
+
+ virtual bool CreateFolderI(const Pathname &pathname);
+
+ // Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
+ // returns NULL.
+ virtual FileStream *OpenFileI(const Pathname &filename,
+ const std::string &mode);
+
+ // This will attempt to delete the path located at filename. If filename is a file,
+ // it will be unlinked. If the path is a directory, it will recursively unlink and remove
+ // all the files and directory within it
+ virtual bool DeleteFileI(const Pathname &filename);
+
+ // Creates a directory. This will call itself recursively to create /foo/bar even if
+ // /foo does not exist.
+ // Returns TRUE if function succeeds
+
+ // This moves a file from old_path to new_path, where "file" can be a plain file
+ // or directory, which will be moved recursively.
+ // Returns true if function succeeds.
+ virtual bool MoveFileI(const Pathname &old_path, const Pathname &new_path);
+
+ // This copies a file from old_path to _new_path where "file" can be a plain file
+ // or directory, which will be copied recursively.
+ // Returns true if function succeeds
+ virtual bool CopyFileI(const Pathname &old_path, const Pathname &new_path);
+
+ // Returns true if a pathname is a directory
+ virtual bool IsFolderI(const Pathname& pathname);
+
+ // Returns true if a file exists at path
+ virtual bool FileExistsI(const Pathname &path);
+
+ // Returns true if pathname represents a temporary location on the system.
+ virtual bool IsTemporaryPathI(const Pathname& pathname);
+
+
+ // All of the following functions set pathname and return true if successful.
+ // Returned paths always include a trailing backslash.
+ // If create is true, the path will be recursively created.
+ // If append is non-NULL, it will be appended (and possibly created).
+
+ virtual std::string TempFilenameI(const Pathname &dir, const std::string &prefix);
+
+ virtual bool GetFileSizeI(const Pathname &pathname, size_t *size);
+
+ // A folder appropriate for storing temporary files (Contents are
+ // automatically deleted when the program exists)
+ virtual bool GetTemporaryFolderI(Pathname &path, bool create,
+ const std::string *append);
+ };
+
+}
+
+#endif // _WIN32FILESYSTEM_H__
diff --git a/third_party/libjingle/files/talk/base/win32window.cc b/third_party/libjingle/files/talk/base/win32window.cc
new file mode 100644
index 0000000..05d639b
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/win32window.cc
@@ -0,0 +1,137 @@
+/*
+ * 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/base/win32window.h"
+
+#include "talk/base/logging.h"
+#include "talk/base/common.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// Win32Window
+///////////////////////////////////////////////////////////////////////////////
+
+static const wchar_t kWindowBaseClassName[] = L"WindowBaseClass";
+HINSTANCE instance_ = GetModuleHandle(NULL);
+ATOM window_class_ = 0;
+
+Win32Window::Win32Window() : wnd_(NULL) {
+}
+
+Win32Window::~Win32Window() {
+ ASSERT(NULL == wnd_);
+}
+
+bool Win32Window::Create(HWND parent, const wchar_t* title, DWORD style,
+ DWORD exstyle, int x, int y, int cx, int cy) {
+ if (wnd_) {
+ // Window already exists.
+ return false;
+ }
+
+ if (!window_class_) {
+ // Class not registered, register it.
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(wcex));
+ wcex.cbSize = sizeof(wcex);
+ wcex.hInstance = instance_;
+ wcex.lpfnWndProc = &Win32Window::WndProc;
+ wcex.lpszClassName = kWindowBaseClassName;
+ window_class_ = ::RegisterClassEx(&wcex);
+ if (!window_class_) {
+ LOG(LS_ERROR) << "RegisterClassEx failed: " << GetLastError();
+ return false;
+ }
+ }
+ wnd_ = ::CreateWindowEx(exstyle, kWindowBaseClassName, title, style,
+ x, y, cx, cy, parent, NULL, instance_, this);
+ return (NULL != wnd_);
+}
+
+void Win32Window::Destroy() {
+ VERIFY(::DestroyWindow(wnd_) != FALSE);
+}
+
+#if 0
+void Win32Window::SetInstance(HINSTANCE instance) {
+ instance_ = instance;
+}
+
+void Win32Window::Shutdown() {
+ if (window_class_) {
+ ::UnregisterClass(MAKEINTATOM(window_class_), instance_);
+ window_class_ = 0;
+ }
+}
+#endif
+
+bool Win32Window::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
+ LRESULT& result) {
+ switch (uMsg) {
+ case WM_CLOSE:
+ if (!OnClose()) {
+ result = 0;
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+LRESULT Win32Window::WndProc(HWND hwnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam) {
+ Win32Window* that = reinterpret_cast<Win32Window*>(
+ ::GetWindowLongPtr(hwnd, GWL_USERDATA));
+ if (!that && (WM_CREATE == uMsg)) {
+ CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
+ that = static_cast<Win32Window*>(cs->lpCreateParams);
+ that->wnd_ = hwnd;
+ ::SetWindowLongPtr(hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(that));
+ }
+ if (that) {
+ LRESULT result;
+ bool handled = that->OnMessage(uMsg, wParam, lParam, result);
+ if (WM_DESTROY == uMsg) {
+ for (HWND child = ::GetWindow(hwnd, GW_CHILD); child;
+ child = ::GetWindow(child, GW_HWNDNEXT)) {
+ LOG(LS_INFO) << "Child window: " << static_cast<void*>(child);
+ }
+ }
+ if (WM_NCDESTROY == uMsg) {
+ ::SetWindowLongPtr(hwnd, GWL_USERDATA, NULL);
+ that->wnd_ = NULL;
+ that->OnDestroyed();
+ }
+ if (handled) {
+ return result;
+ }
+ }
+ return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/win32window.h b/third_party/libjingle/files/talk/base/win32window.h
new file mode 100644
index 0000000..a4cdb47
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/win32window.h
@@ -0,0 +1,72 @@
+/*
+ * 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 TALK_BASE_WIN32WINDOW_H__
+#define TALK_BASE_WIN32WINDOW_H__
+
+#ifdef WIN32
+
+#include "talk/base/win32.h"
+
+namespace talk_base {
+
+///////////////////////////////////////////////////////////////////////////////
+// Win32Window
+///////////////////////////////////////////////////////////////////////////////
+
+class Win32Window {
+public:
+ Win32Window();
+ virtual ~Win32Window();
+
+ HWND handle() { return wnd_; }
+
+ bool Create(HWND parent, const wchar_t* title, DWORD style, DWORD exstyle,
+ int x, int y, int cx, int cy);
+ void Destroy();
+
+protected:
+ virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
+ LRESULT& result);
+
+ virtual bool OnClose() { return true; }
+ virtual void OnDestroyed() { }
+
+private:
+ static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
+ LPARAM lParam);
+
+ HWND wnd_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // WIN32
+
+#endif // TALK_BASE_WIN32WINDOW_H__
diff --git a/third_party/libjingle/files/talk/base/winfirewall.cc b/third_party/libjingle/files/talk/base/winfirewall.cc
new file mode 100644
index 0000000..9323d01
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winfirewall.cc
@@ -0,0 +1,141 @@
+/*
+ * 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 <comdef.h>
+#include "netfw.h"
+#include "winfirewall.h"
+
+#define RELEASE(lpUnk) do \
+ { if ((lpUnk) != NULL) { (lpUnk)->Release(); (lpUnk) = NULL; } } while (0)
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// WinFirewall
+//////////////////////////////////////////////////////////////////////
+
+WinFirewall::WinFirewall() : mgr_(NULL), policy_(NULL), profile_(NULL) {
+}
+
+WinFirewall::~WinFirewall() {
+ Shutdown();
+}
+
+bool
+WinFirewall::Initialize() {
+ if (mgr_)
+ return true;
+
+ HRESULT hr = CoCreateInstance(__uuidof(NetFwMgr),
+ 0, CLSCTX_INPROC_SERVER,
+ __uuidof(INetFwMgr),
+ reinterpret_cast<void **>(&mgr_));
+ if (SUCCEEDED(hr) && (mgr_ != NULL))
+ hr = mgr_->get_LocalPolicy(&policy_);
+ if (SUCCEEDED(hr) && (policy_ != NULL))
+ hr = policy_->get_CurrentProfile(&profile_);
+ return SUCCEEDED(hr) && (profile_ != NULL);
+}
+
+void
+WinFirewall::Shutdown() {
+ RELEASE(profile_);
+ RELEASE(policy_);
+ RELEASE(mgr_);
+}
+
+bool
+WinFirewall::Enabled() {
+ if (!profile_)
+ return false;
+
+ VARIANT_BOOL fwEnabled = VARIANT_FALSE;
+ profile_->get_FirewallEnabled(&fwEnabled);
+ return (fwEnabled != VARIANT_FALSE);
+}
+
+bool
+WinFirewall::Authorized(const char * filename, bool * known) {
+ if (known) {
+ *known = false;
+ }
+
+ if (!profile_)
+ return false;
+
+ VARIANT_BOOL fwEnabled = VARIANT_FALSE;
+ _bstr_t bfilename = filename;
+
+ INetFwAuthorizedApplications * apps = NULL;
+ HRESULT hr = profile_->get_AuthorizedApplications(&apps);
+ if (SUCCEEDED(hr) && (apps != NULL)) {
+ INetFwAuthorizedApplication * app = NULL;
+ hr = apps->Item(bfilename, &app);
+ if (SUCCEEDED(hr) && (app != NULL)) {
+ hr = app->get_Enabled(&fwEnabled);
+ app->Release();
+ if (known) {
+ *known = true;
+ }
+ } else if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
+ // Unexpected error
+ }
+ apps->Release();
+ }
+
+ return (fwEnabled != VARIANT_FALSE);
+}
+
+bool
+WinFirewall::AddApplication(const char * filename, const char * friendly_name,
+ bool authorized) {
+ INetFwAuthorizedApplications * apps = NULL;
+ HRESULT hr = profile_->get_AuthorizedApplications(&apps);
+ if (SUCCEEDED(hr) && (apps != NULL)) {
+ INetFwAuthorizedApplication * app = NULL;
+ hr = CoCreateInstance(__uuidof(NetFwAuthorizedApplication),
+ 0, CLSCTX_INPROC_SERVER,
+ __uuidof(INetFwAuthorizedApplication),
+ reinterpret_cast<void **>(&app));
+ if (SUCCEEDED(hr) && (app != NULL)) {
+ _bstr_t bstr = filename;
+ hr = app->put_ProcessImageFileName(bstr);
+ bstr = friendly_name;
+ if (SUCCEEDED(hr))
+ hr = app->put_Name(bstr);
+ if (SUCCEEDED(hr))
+ hr = app->put_Enabled(authorized ? VARIANT_TRUE : VARIANT_FALSE);
+ if (SUCCEEDED(hr))
+ hr = apps->Add(app);
+ app->Release();
+ }
+ apps->Release();
+ }
+ return SUCCEEDED(hr);
+}
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/winfirewall.h b/third_party/libjingle/files/talk/base/winfirewall.h
new file mode 100644
index 0000000..09d5a2f
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winfirewall.h
@@ -0,0 +1,64 @@
+/*
+ * 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 TALK_BASE_WINFIREWALL_H__
+#define TALK_BASE_WINFIREWALL_H__
+
+struct INetFwMgr;
+struct INetFwPolicy;
+struct INetFwProfile;
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// WinFirewall
+//////////////////////////////////////////////////////////////////////
+
+class WinFirewall {
+public:
+ WinFirewall();
+ ~WinFirewall();
+
+ bool Initialize();
+ void Shutdown();
+
+ bool Enabled();
+ bool Authorized(const char * filename, bool * known = 0);
+
+ bool AddApplication(const char * filename, const char * friendly_name, bool authorized = true);
+
+private:
+ INetFwMgr * mgr_;
+ INetFwPolicy * policy_;
+ INetFwProfile * profile_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
+
+#endif // TALK_BASE_WINFIREWALL_H__
diff --git a/third_party/libjingle/files/talk/base/winping.cc b/third_party/libjingle/files/talk/base/winping.cc
new file mode 100644
index 0000000..703e6a5
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winping.cc
@@ -0,0 +1,317 @@
+/*
+ * 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/base/byteorder.h"
+#include "talk/base/socketaddress.h"
+#include "talk/base/winping.h"
+#include "talk/base/logging.h"
+#include <cassert>
+
+namespace talk_base {
+
+//////////////////////////////////////////////////////////////////////
+// Found in IPExport.h
+//////////////////////////////////////////////////////////////////////
+
+typedef struct icmp_echo_reply {
+ ULONG Address; // Replying address
+ ULONG Status; // Reply IP_STATUS
+ ULONG RoundTripTime; // RTT in milliseconds
+ USHORT DataSize; // Reply data size in bytes
+ USHORT Reserved; // Reserved for system use
+ PVOID Data; // Pointer to the reply data
+ struct ip_option_information Options; // Reply options
+} ICMP_ECHO_REPLY, * PICMP_ECHO_REPLY;
+
+//
+// IP_STATUS codes returned from IP APIs
+//
+
+#define IP_STATUS_BASE 11000
+
+#define IP_SUCCESS 0
+#define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1)
+#define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2)
+#define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3)
+#define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4)
+#define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5)
+#define IP_NO_RESOURCES (IP_STATUS_BASE + 6)
+#define IP_BAD_OPTION (IP_STATUS_BASE + 7)
+#define IP_HW_ERROR (IP_STATUS_BASE + 8)
+#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9)
+#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10)
+#define IP_BAD_REQ (IP_STATUS_BASE + 11)
+#define IP_BAD_ROUTE (IP_STATUS_BASE + 12)
+#define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13)
+#define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14)
+#define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15)
+#define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16)
+#define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17)
+#define IP_BAD_DESTINATION (IP_STATUS_BASE + 18)
+
+#define IP_ADDR_DELETED (IP_STATUS_BASE + 19)
+#define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20)
+#define IP_MTU_CHANGE (IP_STATUS_BASE + 21)
+#define IP_UNLOAD (IP_STATUS_BASE + 22)
+#define IP_ADDR_ADDED (IP_STATUS_BASE + 23)
+#define IP_MEDIA_CONNECT (IP_STATUS_BASE + 24)
+#define IP_MEDIA_DISCONNECT (IP_STATUS_BASE + 25)
+#define IP_BIND_ADAPTER (IP_STATUS_BASE + 26)
+#define IP_UNBIND_ADAPTER (IP_STATUS_BASE + 27)
+#define IP_DEVICE_DOES_NOT_EXIST (IP_STATUS_BASE + 28)
+#define IP_DUPLICATE_ADDRESS (IP_STATUS_BASE + 29)
+#define IP_INTERFACE_METRIC_CHANGE (IP_STATUS_BASE + 30)
+#define IP_RECONFIG_SECFLTR (IP_STATUS_BASE + 31)
+#define IP_NEGOTIATING_IPSEC (IP_STATUS_BASE + 32)
+#define IP_INTERFACE_WOL_CAPABILITY_CHANGE (IP_STATUS_BASE + 33)
+#define IP_DUPLICATE_IPADD (IP_STATUS_BASE + 34)
+
+#define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50)
+#define MAX_IP_STATUS IP_GENERAL_FAILURE
+#define IP_PENDING (IP_STATUS_BASE + 255)
+
+//
+// Values used in the IP header Flags field.
+//
+#define IP_FLAG_DF 0x2 // Don't fragment this packet.
+
+//
+// Supported IP Option Types.
+//
+// These types define the options which may be used in the OptionsData field
+// of the ip_option_information structure. See RFC 791 for a complete
+// description of each.
+//
+#define IP_OPT_EOL 0 // End of list option
+#define IP_OPT_NOP 1 // No operation
+#define IP_OPT_SECURITY 0x82 // Security option
+#define IP_OPT_LSRR 0x83 // Loose source route
+#define IP_OPT_SSRR 0x89 // Strict source route
+#define IP_OPT_RR 0x7 // Record route
+#define IP_OPT_TS 0x44 // Timestamp
+#define IP_OPT_SID 0x88 // Stream ID (obsolete)
+#define IP_OPT_ROUTER_ALERT 0x94 // Router Alert Option
+
+#define MAX_OPT_SIZE 40 // Maximum length of IP options in bytes
+
+//////////////////////////////////////////////////////////////////////
+// Global Constants and Types
+//////////////////////////////////////////////////////////////////////
+
+const char * const ICMP_DLL_NAME = "icmp.dll";
+const char * const ICMP_CREATE_FUNC = "IcmpCreateFile";
+const char * const ICMP_CLOSE_FUNC = "IcmpCloseHandle";
+const char * const ICMP_SEND_FUNC = "IcmpSendEcho";
+
+inline uint32 ReplySize(uint32 data_size) {
+ // A ping error message is 8 bytes long, so make sure we allow for at least
+ // 8 bytes of reply data.
+ return sizeof(ICMP_ECHO_REPLY) + _max((uint32)(8UL), data_size);
+}
+
+//////////////////////////////////////////////////////////////////////
+// WinPing
+//////////////////////////////////////////////////////////////////////
+
+WinPing::WinPing()
+ : dll_(0), hping_(INVALID_HANDLE_VALUE), create_(0), close_(0), send_(0),
+ data_(0), dlen_(0), reply_(0), rlen_(0), valid_(false) {
+
+ dll_ = LoadLibraryA(ICMP_DLL_NAME);
+ if (!dll_) {
+ LOG(LERROR) << "LoadLibrary: " << GetLastError();
+ return;
+ }
+
+ create_ = (PIcmpCreateFile) GetProcAddress(dll_, ICMP_CREATE_FUNC);
+ close_ = (PIcmpCloseHandle) GetProcAddress(dll_, ICMP_CLOSE_FUNC);
+ send_ = (PIcmpSendEcho) GetProcAddress(dll_, ICMP_SEND_FUNC);
+ if (!create_ || !close_ || !send_) {
+ LOG(LERROR) << "GetProcAddress(ICMP_*): " << GetLastError();
+ return;
+ }
+
+ hping_ = create_();
+ if (hping_ == INVALID_HANDLE_VALUE) {
+ LOG(LERROR) << "IcmpCreateFile: " << GetLastError();
+ return;
+ }
+
+ dlen_ = 0;
+ rlen_ = ReplySize(dlen_);
+ data_ = new char[dlen_];
+ reply_ = new char[rlen_];
+
+ valid_ = true;
+}
+
+WinPing::~WinPing() {
+ if (dll_)
+ FreeLibrary(dll_);
+
+ if ((hping_ != INVALID_HANDLE_VALUE) && close_) {
+ if (!close_(hping_))
+ LOG(WARNING) << "IcmpCloseHandle: " << GetLastError();
+ }
+
+ delete[] data_;
+ delete reply_;
+}
+
+WinPing::PingResult WinPing::Ping(
+ uint32 ip, uint32 data_size, uint32 timeout, uint8 ttl,
+ bool allow_fragments) {
+
+ assert(IsValid());
+
+ IP_OPTION_INFORMATION ipopt;
+ memset(&ipopt, 0, sizeof(ipopt));
+ if (!allow_fragments)
+ ipopt.Flags |= IP_FLAG_DF;
+ ipopt.Ttl = ttl;
+
+ uint32 reply_size = ReplySize(data_size);
+
+ if (data_size > dlen_) {
+ delete [] data_;
+ dlen_ = data_size;
+ data_ = new char[dlen_];
+ memset(data_, 'z', dlen_);
+ }
+
+ if (reply_size > rlen_) {
+ delete [] reply_;
+ rlen_ = reply_size;
+ reply_ = new char[rlen_];
+ }
+
+ DWORD result = send_(hping_, talk_base::HostToNetwork32(ip),
+ data_, uint16(data_size), &ipopt,
+ reply_, reply_size, timeout);
+ if (result == 0) {
+ long error = GetLastError();
+ if (error == IP_PACKET_TOO_BIG)
+ return PING_TOO_LARGE;
+ if (error == IP_REQ_TIMED_OUT)
+ return PING_TIMEOUT;
+ LOG(LERROR) << "IcmpSendEcho(" << talk_base::SocketAddress::IPToString(ip)
+ << ", " << data_size << "): " << error;
+ return PING_FAIL;
+ }
+
+ return PING_SUCCESS;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Microsoft Documenation
+//////////////////////////////////////////////////////////////////////
+//
+// Routine Name:
+//
+// IcmpCreateFile
+//
+// Routine Description:
+//
+// Opens a handle on which ICMP Echo Requests can be issued.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// An open file handle or INVALID_HANDLE_VALUE. Extended error information
+// is available by calling GetLastError().
+//
+//////////////////////////////////////////////////////////////////////
+//
+// Routine Name:
+//
+// IcmpCloseHandle
+//
+// Routine Description:
+//
+// Closes a handle opened by ICMPOpenFile.
+//
+// Arguments:
+//
+// IcmpHandle - The handle to close.
+//
+// Return Value:
+//
+// TRUE if the handle was closed successfully, otherwise FALSE. Extended
+// error information is available by calling GetLastError().
+//
+//////////////////////////////////////////////////////////////////////
+//
+// Routine Name:
+//
+// IcmpSendEcho
+//
+// Routine Description:
+//
+// Sends an ICMP Echo request and returns any replies. The
+// call returns when the timeout has expired or the reply buffer
+// is filled.
+//
+// Arguments:
+//
+// IcmpHandle - An open handle returned by ICMPCreateFile.
+//
+// DestinationAddress - The destination of the echo request.
+//
+// RequestData - A buffer containing the data to send in the
+// request.
+//
+// RequestSize - The number of bytes in the request data buffer.
+//
+// RequestOptions - Pointer to the IP header options for the request.
+// May be NULL.
+//
+// ReplyBuffer - A buffer to hold any replies to the request.
+// On return, the buffer will contain an array of
+// ICMP_ECHO_REPLY structures followed by the
+// options and data for the replies. The buffer
+// should be large enough to hold at least one
+// ICMP_ECHO_REPLY structure plus
+// MAX(RequestSize, 8) bytes of data since an ICMP
+// error message contains 8 bytes of data.
+//
+// ReplySize - The size in bytes of the reply buffer.
+//
+// Timeout - The time in milliseconds to wait for replies.
+//
+// Return Value:
+//
+// Returns the number of ICMP_ECHO_REPLY structures stored in ReplyBuffer.
+// The status of each reply is contained in the structure. If the return
+// value is zero, extended error information is available via
+// GetLastError().
+//
+//////////////////////////////////////////////////////////////////////
+
+} // namespace talk_base
diff --git a/third_party/libjingle/files/talk/base/winping.h b/third_party/libjingle/files/talk/base/winping.h
new file mode 100644
index 0000000..0d0b051
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winping.h
@@ -0,0 +1,105 @@
+/*
+ * 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 TALK_BASE_WINPING_H__
+#define TALK_BASE_WINPING_H__
+
+#ifdef WIN32
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include <winsock2.h>
+#define _WINSOCKAPI_
+#include <windows.h>
+#undef SetPort
+
+#include "talk/base/basictypes.h"
+
+namespace talk_base {
+
+// This class wraps a Win32 API for doing ICMP pinging. This API, unlike the
+// the normal socket APIs (as implemented on Win9x), will return an error if
+// an ICMP packet with the dont-fragment bit set is too large. This means this
+// class can be used to detect the MTU to a given address.
+
+typedef struct ip_option_information {
+ UCHAR Ttl; // Time To Live
+ UCHAR Tos; // Type Of Service
+ UCHAR Flags; // IP header flags
+ UCHAR OptionsSize; // Size in bytes of options data
+ PUCHAR OptionsData; // Pointer to options data
+} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;
+
+typedef HANDLE (WINAPI *PIcmpCreateFile)();
+
+typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle);
+
+typedef DWORD (WINAPI *PIcmpSendEcho)(
+ HANDLE IcmpHandle,
+ ULONG DestinationAddress,
+ LPVOID RequestData,
+ WORD RequestSize,
+ PIP_OPTION_INFORMATION RequestOptions,
+ LPVOID ReplyBuffer,
+ DWORD ReplySize,
+ DWORD Timeout);
+
+class WinPing {
+public:
+ WinPing();
+ ~WinPing();
+
+ // Determines whether the class was initialized correctly.
+ bool IsValid() { return valid_; }
+
+ // Attempts to send a ping with the given parameters.
+ enum PingResult { PING_FAIL, PING_TOO_LARGE, PING_TIMEOUT, PING_SUCCESS };
+ PingResult Ping(
+ uint32 ip, uint32 data_size, uint32 timeout_millis, uint8 ttl,
+ bool allow_fragments);
+
+private:
+ HMODULE dll_;
+ HANDLE hping_;
+ PIcmpCreateFile create_;
+ PIcmpCloseHandle close_;
+ PIcmpSendEcho send_;
+ char* data_;
+ uint32 dlen_;
+ char* reply_;
+ uint32 rlen_;
+ bool valid_;
+};
+
+} // namespace talk_base
+
+#endif // WIN32
+
+#endif // TALK_BASE_WINPING_H__
+
diff --git a/third_party/libjingle/files/talk/base/winsock_initializer.cc b/third_party/libjingle/files/talk/base/winsock_initializer.cc
new file mode 100644
index 0000000..f61ec80
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winsock_initializer.cc
@@ -0,0 +1,65 @@
+/*
+ * libjingle
+ * Copyright 2009, 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/base/winsock_init.h"
+
+#ifndef WIN32
+#error "Only compile this on Windows"
+#endif
+
+#include <winsock2.h>
+
+namespace talk_base {
+
+void EnsureWinsockInit() {
+ // The default implementation uses a global initializer, so WSAStartup
+ // happens at module load time. Thus we don't need to do anything here.
+ // The hook is provided so that a client that statically links with
+ // libjingle can override it, to provide its own initialization.
+}
+
+class WinsockInitializer {
+ public:
+ WinsockInitializer() {
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(1, 0);
+ err_ = WSAStartup(wVersionRequested, &wsaData);
+ }
+ ~WinsockInitializer() {
+ WSACleanup();
+ }
+ int error() {
+ return err_;
+ }
+ private:
+ int err_;
+};
+WinsockInitializer g_winsockinit;
+
+} // namespace talk_base
+
+#endif // TALK_BASE_WINSOCK_INIT_H__
diff --git a/third_party/libjingle/files/talk/base/winsock_initializer.h b/third_party/libjingle/files/talk/base/winsock_initializer.h
new file mode 100644
index 0000000..5a7c499
--- /dev/null
+++ b/third_party/libjingle/files/talk/base/winsock_initializer.h
@@ -0,0 +1,40 @@
+/*
+ * libjingle
+ * Copyright 2009, 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 TALK_BASE_WINSOCK_INIT_H__
+#define TALK_BASE_WINSOCK_INIT_H__
+
+namespace talk_base {
+
+#ifdef WIN32
+// Make sure that Winsock is initialized, calling WSAStartup if needed.
+void EnsureWinsockInit();
+#endif
+
+} // namespace talk_base
+
+#endif // TALK_BASE_WINSOCK_INIT_H__
diff --git a/third_party/libjingle/files/talk/pkg.m4 b/third_party/libjingle/files/talk/pkg.m4
new file mode 100644
index 0000000..c80e0ac
--- /dev/null
+++ b/third_party/libjingle/files/talk/pkg.m4
@@ -0,0 +1,57 @@
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN(PKG_CHECK_MODULES, [
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ AC_MSG_CHECKING(for $2)
+
+ if $PKG_CONFIG --exists "$2" ; then
+ AC_MSG_RESULT(yes)
+ succeeded=yes
+
+ AC_MSG_CHECKING($1_CFLAGS)
+ $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+ AC_MSG_RESULT($$1_CFLAGS)
+
+ AC_MSG_CHECKING($1_LIBS)
+ $1_LIBS=`$PKG_CONFIG --libs "$2"`
+ AC_MSG_RESULT($$1_LIBS)
+ else
+ $1_CFLAGS=""
+ $1_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ ifelse([$4], ,echo $$1_PKG_ERRORS,)
+ fi
+
+ AC_SUBST($1_CFLAGS)
+ AC_SUBST($1_LIBS)
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ ifelse([$3], , :, [$3])
+ else
+ ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+ fi
+])
+
+
diff --git a/third_party/libjingle/files/talk/xmllite/Makefile.am b/third_party/libjingle/files/talk/xmllite/Makefile.am
new file mode 100644
index 0000000..deaf2bf
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/Makefile.am
@@ -0,0 +1,18 @@
+libcricketxmllite_la_SOURCES = qname.cc \
+ xmlbuilder.cc \
+ xmlconstants.cc \
+ xmlelement.cc \
+ xmlnsstack.cc \
+ xmlparser.cc \
+ xmlprinter.cc
+
+noinst_HEADERS = qname.h \
+ xmlbuilder.h \
+ xmlconstants.h \
+ xmlelement.h \
+ xmlnsstack.h \
+ xmlparser.h \
+ xmlprinter.h
+AM_CPPFLAGS = -DPOSIX
+
+noinst_LTLIBRARIES = libcricketxmllite.la
diff --git a/third_party/libjingle/files/talk/xmllite/qname.cc b/third_party/libjingle/files/talk/xmllite/qname.cc
new file mode 100644
index 0000000..c60d0c0
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/qname.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 <string>
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlconstants.h"
+
+//#define new TRACK_NEW
+
+namespace buzz {
+
+QName::QName() : namespace_(QN_EMPTY.namespace_),
+ localPart_(QN_EMPTY.localPart_) {}
+
+QName::QName(const std::string & ns, const std::string & local) :
+ namespace_(ns), localPart_(local) {}
+
+static std::string
+QName_LocalPart(const std::string & name) {
+ size_t i = name.rfind(':');
+ if (i == std::string::npos)
+ return name;
+ return name.substr(i + 1);
+}
+
+static std::string
+QName_Namespace(const std::string & name) {
+ size_t i = name.rfind(':');
+ if (i == std::string::npos)
+ return STR_EMPTY;
+ return name.substr(0, i);
+}
+
+QName::QName(const std::string & mergedOrLocal) :
+ namespace_(QName_Namespace(mergedOrLocal)),
+ localPart_(QName_LocalPart(mergedOrLocal)) {}
+
+std::string
+QName::Merged() const {
+ if (namespace_ == STR_EMPTY)
+ return localPart_;
+ return namespace_ + ':' + localPart_;
+}
+
+bool
+QName::operator==(const QName & other) const {
+ return
+ localPart_ == other.localPart_ &&
+ namespace_ == other.namespace_;
+}
+
+int
+QName::Compare(const QName & other) const {
+ int result = localPart_.compare(other.localPart_);
+ if (result)
+ return result;
+
+ return namespace_.compare(other.namespace_);
+}
+
+}
+
+
+
diff --git a/third_party/libjingle/files/talk/xmllite/qname.h b/third_party/libjingle/files/talk/xmllite/qname.h
new file mode 100644
index 0000000..6600043
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/qname.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _qname_h_
+#define _qname_h_
+
+#include <string>
+
+namespace buzz {
+
+
+class QName
+{
+public:
+ QName();
+ QName(const std::string & ns, const std::string & local);
+ explicit QName(const std::string & mergedOrLocal);
+
+ const std::string & Namespace() const { return namespace_; }
+ const std::string & LocalPart() const { return localPart_; }
+ std::string Merged() const;
+ int Compare(const QName & other) const;
+ bool operator==(const QName & other) const;
+ bool operator!=(const QName & other) const { return !operator==(other); }
+ bool operator<(const QName & other) const { return Compare(other) < 0; }
+
+private:
+ std::string namespace_;
+ std::string localPart_;
+};
+
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmllite/xmlbuilder.cc b/third_party/libjingle/files/talk/xmllite/xmlbuilder.cc
new file mode 100644
index 0000000..3e2964f
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlbuilder.cc
@@ -0,0 +1,149 @@
+/*
+ * 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/base/stl_decl.h"
+#include <vector>
+#include <set>
+#include <expat.h>
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlbuilder.h"
+
+namespace buzz {
+
+XmlBuilder::XmlBuilder() :
+ pelCurrent_(NULL),
+ pelRoot_(NULL),
+ pvParents_(new std::vector<XmlElement *>()) {
+}
+
+void
+XmlBuilder::Reset() {
+ pelRoot_.reset();
+ pelCurrent_ = NULL;
+ pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::BuildElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) {
+ QName tagName(pctx->ResolveQName(name, false));
+ if (tagName == QN_EMPTY)
+ return NULL;
+
+ XmlElement * pelNew = new XmlElement(tagName);
+
+ if (!*atts)
+ return pelNew;
+
+ std::set<QName> seenNonlocalAtts;
+
+ while (*atts) {
+ QName attName(pctx->ResolveQName(*atts, true));
+ if (attName == QN_EMPTY) {
+ delete pelNew;
+ return NULL;
+ }
+
+ // verify that namespaced names are unique
+ if (!attName.Namespace().empty()) {
+ if (seenNonlocalAtts.count(attName)) {
+ delete pelNew;
+ return NULL;
+ }
+ seenNonlocalAtts.insert(attName);
+ }
+
+ pelNew->AddAttr(attName, std::string(*(atts + 1)));
+ atts += 2;
+ }
+
+ return pelNew;
+}
+
+void
+XmlBuilder::StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) {
+ XmlElement * pelNew = BuildElement(pctx, name, atts);
+ if (pelNew == NULL) {
+ pctx->RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (!pelCurrent_) {
+ pelCurrent_ = pelNew;
+ pelRoot_.reset(pelNew);
+ pvParents_->push_back(NULL);
+ } else {
+ pelCurrent_->AddElement(pelNew);
+ pvParents_->push_back(pelCurrent_);
+ pelCurrent_ = pelNew;
+ }
+}
+
+void
+XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
+ UNUSED(pctx);
+ UNUSED(name);
+ pelCurrent_ = pvParents_->back();
+ pvParents_->pop_back();
+}
+
+void
+XmlBuilder::CharacterData(XmlParseContext * pctx,
+ const char * text, int len) {
+ UNUSED(pctx);
+ if (pelCurrent_) {
+ pelCurrent_->AddParsedText(text, len);
+ }
+}
+
+void
+XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
+ UNUSED(pctx);
+ UNUSED(err);
+ pelRoot_.reset(NULL);
+ pelCurrent_ = NULL;
+ pvParents_->clear();
+}
+
+XmlElement *
+XmlBuilder::CreateElement() {
+ return pelRoot_.release();
+}
+
+XmlElement *
+XmlBuilder::BuiltElement() {
+ return pelRoot_.get();
+}
+
+XmlBuilder::~XmlBuilder() {
+}
+
+
+
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlbuilder.h b/third_party/libjingle/files/talk/xmllite/xmlbuilder.h
new file mode 100644
index 0000000..5de31b2
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlbuilder.h
@@ -0,0 +1,75 @@
+/*
+ * 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 _xmlbuilder_h_
+#define _xmlbuilder_h_
+
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stl_decl.h"
+#include "talk/xmllite/xmlparser.h"
+
+#include <expat.h>
+
+namespace buzz {
+
+class XmlElement;
+class XmlParseContext;
+
+
+class XmlBuilder : public XmlParseHandler {
+public:
+ XmlBuilder();
+
+ static XmlElement * BuildElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ virtual void EndElement(XmlParseContext * pctx, const char * name);
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len);
+ virtual void Error(XmlParseContext * pctx, XML_Error);
+ virtual ~XmlBuilder();
+
+ void Reset();
+
+ // Take ownership of the built element; second call returns NULL
+ XmlElement * CreateElement();
+
+ // Peek at the built element without taking ownership
+ XmlElement * BuiltElement();
+
+private:
+ XmlElement * pelCurrent_;
+ scoped_ptr<XmlElement> pelRoot_;
+ scoped_ptr<std::vector<XmlElement *, std::allocator<XmlElement *> > >
+ pvParents_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmllite/xmlconstants.cc b/third_party/libjingle/files/talk/xmllite/xmlconstants.cc
new file mode 100644
index 0000000..503f832
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlconstants.cc
@@ -0,0 +1,65 @@
+/*
+ * 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 "xmlconstants.h"
+
+using namespace buzz;
+
+const std::string & XmlConstants::str_empty() {
+ static const std::string str_empty_;
+ return str_empty_;
+}
+
+const std::string & XmlConstants::ns_xml() {
+ static const std::string ns_xml_("http://www.w3.org/XML/1998/namespace");
+ return ns_xml_;
+}
+
+const std::string & XmlConstants::ns_xmlns() {
+ static const std::string ns_xmlns_("http://www.w3.org/2000/xmlns/");
+ return ns_xmlns_;
+}
+
+const std::string & XmlConstants::str_xmlns() {
+ static const std::string str_xmlns_("xmlns");
+ return str_xmlns_;
+}
+
+const std::string & XmlConstants::str_xml() {
+ static const std::string str_xml_("xml");
+ return str_xml_;
+}
+
+const std::string & XmlConstants::str_version() {
+ static const std::string str_version_("version");
+ return str_version_;
+}
+
+const std::string & XmlConstants::str_encoding() {
+ static const std::string str_encoding_("encoding");
+ return str_encoding_;
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlconstants.h b/third_party/libjingle/files/talk/xmllite/xmlconstants.h
new file mode 100644
index 0000000..8514d6f
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlconstants.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+// Because global constant initialization order is undefined
+// globals cannot depend on other objects to be instantiated.
+// This class creates string objects within static methods
+// such that globals may refer to these constants by the
+// accessor function and they are guaranteed to be initialized.
+
+#ifndef TALK_XMLLITE_CONSTANTS_H_
+#define TALK_XMLLITE_CONSTANTS_H_
+
+#include <string>
+
+#define STR_EMPTY XmlConstants::str_empty()
+#define NS_XML XmlConstants::ns_xml()
+#define NS_XMLNS XmlConstants::ns_xmlns()
+#define STR_XMLNS XmlConstants::str_xmlns()
+#define STR_XML XmlConstants::str_xml()
+#define STR_VERSION XmlConstants::str_version()
+#define STR_ENCODING XmlConstants::str_encoding()
+namespace buzz {
+
+class XmlConstants {
+ public:
+ static const std::string & str_empty();
+ static const std::string & ns_xml();
+ static const std::string & ns_xmlns();
+ static const std::string & str_xmlns();
+ static const std::string & str_xml();
+ static const std::string & str_version();
+ static const std::string & str_encoding();
+};
+
+}
+
+#endif // TALK_XMLLITE_CONSTANTS_H_
diff --git a/third_party/libjingle/files/talk/xmllite/xmlelement.cc b/third_party/libjingle/files/talk/xmllite/xmlelement.cc
new file mode 100644
index 0000000..8c8611a
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlelement.cc
@@ -0,0 +1,509 @@
+/*
+ * 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 <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlparser.h"
+#include "talk/xmllite/xmlbuilder.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+const QName QN_EMPTY(STR_EMPTY, STR_EMPTY);
+const QName QN_XMLNS(STR_EMPTY, STR_XMLNS);
+
+
+XmlChild::~XmlChild() {
+}
+
+bool
+XmlText::IsTextImpl() const {
+ return true;
+}
+
+XmlElement *
+XmlText::AsElementImpl() const {
+ return NULL;
+}
+
+XmlText *
+XmlText::AsTextImpl() const {
+ return const_cast<XmlText *>(this);
+}
+
+void
+XmlText::SetText(const std::string & text) {
+ text_ = text;
+}
+
+void
+XmlText::AddParsedText(const char * buf, int len) {
+ text_.append(buf, len);
+}
+
+void
+XmlText::AddText(const std::string & text) {
+ text_ += text;
+}
+
+XmlText::~XmlText() {
+}
+
+XmlElement::XmlElement(const QName & name) :
+ name_(name),
+ pFirstAttr_(NULL),
+ pLastAttr_(NULL),
+ pFirstChild_(NULL),
+ pLastChild_(NULL),
+ cdata_(false) {
+}
+
+XmlElement::XmlElement(const XmlElement & elt) :
+ XmlChild(),
+ name_(elt.name_),
+ pFirstAttr_(NULL),
+ pLastAttr_(NULL),
+ pFirstChild_(NULL),
+ pLastChild_(NULL),
+ cdata_(false) {
+
+ // copy attributes
+ XmlAttr * pAttr;
+ XmlAttr ** ppLastAttr = &pFirstAttr_;
+ XmlAttr * newAttr = NULL;
+ for (pAttr = elt.pFirstAttr_; pAttr; pAttr = pAttr->NextAttr()) {
+ newAttr = new XmlAttr(*pAttr);
+ *ppLastAttr = newAttr;
+ ppLastAttr = &(newAttr->pNextAttr_);
+ }
+ pLastAttr_ = newAttr;
+
+ // copy children
+ XmlChild * pChild;
+ XmlChild ** ppLast = &pFirstChild_;
+ XmlChild * newChild = NULL;
+
+ for (pChild = elt.pFirstChild_; pChild; pChild = pChild->NextChild()) {
+ if (pChild->IsText()) {
+ newChild = new XmlText(*(pChild->AsText()));
+ } else {
+ newChild = new XmlElement(*(pChild->AsElement()));
+ }
+ *ppLast = newChild;
+ ppLast = &(newChild->pNextChild_);
+ }
+ pLastChild_ = newChild;
+
+ cdata_ = elt.cdata_;
+}
+
+XmlElement::XmlElement(const QName & name, bool useDefaultNs) :
+ name_(name),
+ pFirstAttr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
+ pLastAttr_(pFirstAttr_),
+ pFirstChild_(NULL),
+ pLastChild_(NULL),
+ cdata_(false) {
+}
+
+bool
+XmlElement::IsTextImpl() const {
+ return false;
+}
+
+XmlElement *
+XmlElement::AsElementImpl() const {
+ return const_cast<XmlElement *>(this);
+}
+
+XmlText *
+XmlElement::AsTextImpl() const {
+ return NULL;
+}
+
+const std::string &
+XmlElement::BodyText() const {
+ if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
+ return pFirstChild_->AsText()->Text();
+ }
+
+ return STR_EMPTY;
+}
+
+void
+XmlElement::SetBodyText(const std::string & text) {
+ if (text == STR_EMPTY) {
+ ClearChildren();
+ } else if (pFirstChild_ == NULL) {
+ AddText(text);
+ } else if (pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
+ pFirstChild_->AsText()->SetText(text);
+ } else {
+ ClearChildren();
+ AddText(text);
+ }
+}
+
+const QName &
+XmlElement::FirstElementName() const {
+ const XmlElement * element = FirstElement();
+ if (element == NULL)
+ return QN_EMPTY;
+ return element->Name();
+}
+
+XmlAttr *
+XmlElement::FirstAttr() {
+ return pFirstAttr_;
+}
+
+const std::string &
+XmlElement::Attr(const QName & name) const {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ return pattr->value_;
+ }
+ return STR_EMPTY;
+}
+
+bool
+XmlElement::HasAttr(const QName & name) const {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ return true;
+ }
+ return false;
+}
+
+void
+XmlElement::SetAttr(const QName & name, const std::string & value) {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ break;
+ }
+ if (!pattr) {
+ pattr = new XmlAttr(name, value);
+ if (pLastAttr_)
+ pLastAttr_->pNextAttr_ = pattr;
+ else
+ pFirstAttr_ = pattr;
+ pLastAttr_ = pattr;
+ return;
+ }
+ pattr->value_ = value;
+}
+
+void
+XmlElement::ClearAttr(const QName & name) {
+ XmlAttr * pattr;
+ XmlAttr *pLastAttr = NULL;
+ for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
+ if (pattr->name_ == name)
+ break;
+ pLastAttr = pattr;
+ }
+ if (!pattr)
+ return;
+ if (!pLastAttr)
+ pFirstAttr_ = pattr->pNextAttr_;
+ else
+ pLastAttr->pNextAttr_ = pattr->pNextAttr_;
+ if (pLastAttr_ == pattr)
+ pLastAttr_ = pLastAttr;
+ delete pattr;
+}
+
+XmlChild *
+XmlElement::FirstChild() {
+ return pFirstChild_;
+}
+
+XmlElement *
+XmlElement::FirstElement() {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText())
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextElement() {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText())
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::FirstWithNamespace(const std::string & ns) {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextWithNamespace(const std::string & ns) {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::FirstNamed(const QName & name) {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement *
+XmlElement::NextNamed(const QName & name) {
+ XmlChild * pChild;
+ for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement();
+ }
+ return NULL;
+}
+
+XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
+ XmlElement* child = FirstNamed(name);
+ if (!child) {
+ child = new XmlElement(name);
+ AddElement(child);
+ }
+
+ return child;
+}
+
+const std::string &
+XmlElement::TextNamed(const QName & name) const {
+ XmlChild * pChild;
+ for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
+ if (!pChild->IsText() && pChild->AsElement()->Name() == name)
+ return pChild->AsElement()->BodyText();
+ }
+ return STR_EMPTY;
+}
+
+void
+XmlElement::InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNext) {
+ if (pPredecessor == NULL) {
+ pNext->pNextChild_ = pFirstChild_;
+ pFirstChild_ = pNext;
+ }
+ else {
+ pNext->pNextChild_ = pPredecessor->pNextChild_;
+ pPredecessor->pNextChild_ = pNext;
+ }
+}
+
+void
+XmlElement::RemoveChildAfter(XmlChild * pPredecessor) {
+ XmlChild * pNext;
+
+ if (pPredecessor == NULL) {
+ pNext = pFirstChild_;
+ pFirstChild_ = pNext->pNextChild_;
+ }
+ else {
+ pNext = pPredecessor->pNextChild_;
+ pPredecessor->pNextChild_ = pNext->pNextChild_;
+ }
+
+ if (pLastChild_ == pNext)
+ pLastChild_ = pPredecessor;
+
+ delete pNext;
+}
+
+void
+XmlElement::AddAttr(const QName & name, const std::string & value) {
+ ASSERT(!HasAttr(name));
+
+ XmlAttr ** pprev = pLastAttr_ ? &(pLastAttr_->pNextAttr_) : &pFirstAttr_;
+ pLastAttr_ = (*pprev = new XmlAttr(name, value));
+}
+
+void
+XmlElement::AddAttr(const QName & name, const std::string & value,
+ int depth) {
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddAttr(name, value);
+}
+
+void
+XmlElement::AddParsedText(const char * cstr, int len) {
+ if (len == 0)
+ return;
+
+ if (pLastChild_ && pLastChild_->IsText()) {
+ pLastChild_->AsText()->AddParsedText(cstr, len);
+ return;
+ }
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = new XmlText(cstr, len);
+}
+
+void
+XmlElement::AddCDATAText(const char * buf, int len) {
+ cdata_ = true;
+ AddParsedText(buf, len);
+}
+
+void
+XmlElement::AddText(const std::string & text) {
+ if (text == STR_EMPTY)
+ return;
+
+ if (pLastChild_ && pLastChild_->IsText()) {
+ pLastChild_->AsText()->AddText(text);
+ return;
+ }
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = new XmlText(text);
+}
+
+void
+XmlElement::AddText(const std::string & text, int depth) {
+ // note: the first syntax is ambigious for msvc 6
+ // XmlElement * pel(this);
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddText(text);
+}
+
+void
+XmlElement::AddElement(XmlElement *pelChild) {
+ if (pelChild == NULL)
+ return;
+
+ XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
+ pLastChild_ = *pprev = pelChild;
+ pelChild->pNextChild_ = NULL;
+}
+
+void
+XmlElement::AddElement(XmlElement *pelChild, int depth) {
+ XmlElement * element = this;
+ while (depth--) {
+ element = element->pLastChild_->AsElement();
+ }
+ element->AddElement(pelChild);
+}
+
+void
+XmlElement::ClearNamedChildren(const QName & name) {
+ XmlChild * prev_child = NULL;
+ XmlChild * next_child;
+ XmlChild * child;
+ for (child = FirstChild(); child; child = next_child) {
+ next_child = child->NextChild();
+ if (!child->IsText() && child->AsElement()->Name() == name)
+ {
+ RemoveChildAfter(prev_child);
+ continue;
+ }
+ prev_child = child;
+ }
+}
+
+void
+XmlElement::ClearChildren() {
+ XmlChild * pchild;
+ for (pchild = pFirstChild_; pchild; ) {
+ XmlChild * pToDelete = pchild;
+ pchild = pchild->pNextChild_;
+ delete pToDelete;
+ }
+ pFirstChild_ = pLastChild_ = NULL;
+}
+
+std::string
+XmlElement::Str() const {
+ std::stringstream ss;
+ Print(&ss, NULL, 0);
+ return ss.str();
+}
+
+XmlElement *
+XmlElement::ForStr(const std::string & str) {
+ XmlBuilder builder;
+ XmlParser::ParseXml(&builder, str);
+ return builder.CreateElement();
+}
+
+void
+XmlElement::Print(
+ std::ostream * pout, std::string xmlns[], int xmlnsCount) const {
+ XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount);
+}
+
+XmlElement::~XmlElement() {
+ XmlAttr * pattr;
+ for (pattr = pFirstAttr_; pattr; ) {
+ XmlAttr * pToDelete = pattr;
+ pattr = pattr->pNextAttr_;
+ delete pToDelete;
+ }
+
+ XmlChild * pchild;
+ for (pchild = pFirstChild_; pchild; ) {
+ XmlChild * pToDelete = pchild;
+ pchild = pchild->pNextChild_;
+ delete pToDelete;
+ }
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlelement.h b/third_party/libjingle/files/talk/xmllite/xmlelement.h
new file mode 100644
index 0000000..5f8e616a
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlelement.h
@@ -0,0 +1,238 @@
+/*
+ * 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 _xmlelement_h_
+#define _xmlelement_h_
+
+#include <iosfwd>
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmllite/qname.h"
+
+namespace buzz {
+
+extern const QName QN_EMPTY;
+extern const QName QN_XMLNS;
+
+
+class XmlChild;
+class XmlText;
+class XmlElement;
+class XmlAttr;
+
+class XmlChild {
+friend class XmlElement;
+
+public:
+
+ XmlChild * NextChild() { return pNextChild_; }
+ const XmlChild * NextChild() const { return pNextChild_; }
+
+ bool IsText() const { return IsTextImpl(); }
+
+ XmlElement * AsElement() { return AsElementImpl(); }
+ const XmlElement * AsElement() const { return AsElementImpl(); }
+
+ XmlText * AsText() { return AsTextImpl(); }
+ const XmlText * AsText() const { return AsTextImpl(); }
+
+
+protected:
+
+ XmlChild() :
+ pNextChild_(NULL) {
+ }
+
+ virtual bool IsTextImpl() const = 0;
+ virtual XmlElement * AsElementImpl() const = 0;
+ virtual XmlText * AsTextImpl() const = 0;
+
+
+ virtual ~XmlChild();
+
+private:
+ XmlChild(const XmlChild & noimpl);
+
+ XmlChild * pNextChild_;
+
+};
+
+class XmlText : public XmlChild {
+public:
+ explicit XmlText(const std::string & text) :
+ XmlChild(),
+ text_(text) {
+ }
+ explicit XmlText(const XmlText & t) :
+ XmlChild(),
+ text_(t.text_) {
+ }
+ explicit XmlText(const char * cstr, size_t len) :
+ XmlChild(),
+ text_(cstr, len) {
+ }
+ virtual ~XmlText();
+
+ const std::string & Text() const { return text_; }
+ void SetText(const std::string & text);
+ void AddParsedText(const char * buf, int len);
+ void AddText(const std::string & text);
+
+protected:
+ virtual bool IsTextImpl() const;
+ virtual XmlElement * AsElementImpl() const;
+ virtual XmlText * AsTextImpl() const;
+
+private:
+ std::string text_;
+};
+
+class XmlAttr {
+friend class XmlElement;
+
+public:
+ XmlAttr * NextAttr() const { return pNextAttr_; }
+ const QName & Name() const { return name_; }
+ const std::string & Value() const { return value_; }
+
+private:
+ explicit XmlAttr(const QName & name, const std::string & value) :
+ pNextAttr_(NULL),
+ name_(name),
+ value_(value) {
+ }
+ explicit XmlAttr(const XmlAttr & att) :
+ pNextAttr_(NULL),
+ name_(att.name_),
+ value_(att.value_) {
+ }
+
+ XmlAttr * pNextAttr_;
+ QName name_;
+ std::string value_;
+};
+
+class XmlElement : public XmlChild {
+public:
+ explicit XmlElement(const QName & name);
+ explicit XmlElement(const QName & name, bool useDefaultNs);
+ explicit XmlElement(const XmlElement & elt);
+
+ virtual ~XmlElement();
+
+ const QName& Name() const { return name_; }
+ void SetName(const QName& name) { name_ = name; }
+
+ const std::string & BodyText() const;
+ void SetBodyText(const std::string & text);
+
+ const QName & FirstElementName() const;
+
+ XmlAttr * FirstAttr();
+ const XmlAttr * FirstAttr() const
+ { return const_cast<XmlElement *>(this)->FirstAttr(); }
+
+ //! Attr will return STR_EMPTY if the attribute isn't there:
+ //! use HasAttr to test presence of an attribute.
+ const std::string & Attr(const QName & name) const;
+ bool HasAttr(const QName & name) const;
+ void SetAttr(const QName & name, const std::string & value);
+ void ClearAttr(const QName & name);
+
+ XmlChild * FirstChild();
+ const XmlChild * FirstChild() const
+ { return const_cast<XmlElement *>(this)->FirstChild(); }
+
+ XmlElement * FirstElement();
+ const XmlElement * FirstElement() const
+ { return const_cast<XmlElement *>(this)->FirstElement(); }
+
+ XmlElement * NextElement();
+ const XmlElement * NextElement() const
+ { return const_cast<XmlElement *>(this)->NextElement(); }
+
+ XmlElement * FirstWithNamespace(const std::string & ns);
+ const XmlElement * FirstWithNamespace(const std::string & ns) const
+ { return const_cast<XmlElement *>(this)->FirstWithNamespace(ns); }
+
+ XmlElement * NextWithNamespace(const std::string & ns);
+ const XmlElement * NextWithNamespace(const std::string & ns) const
+ { return const_cast<XmlElement *>(this)->NextWithNamespace(ns); }
+
+ XmlElement * FirstNamed(const QName & name);
+ const XmlElement * FirstNamed(const QName & name) const
+ { return const_cast<XmlElement *>(this)->FirstNamed(name); }
+
+ XmlElement * NextNamed(const QName & name);
+ const XmlElement * NextNamed(const QName & name) const
+ { return const_cast<XmlElement *>(this)->NextNamed(name); }
+
+ // Finds the first element named 'name'. If that element can't be found then
+ // adds one and returns it.
+ XmlElement* FindOrAddNamedChild(const QName& name);
+
+ const std::string & TextNamed(const QName & name) const;
+
+ void InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNewChild);
+ void RemoveChildAfter(XmlChild * pPredecessor);
+
+ void AddParsedText(const char * buf, int len);
+ // Note: CDATA is not supported by XMPP, therefore using this function will
+ // generate non-XMPP compatible XML.
+ void AddCDATAText(const char * buf, int len);
+ void AddText(const std::string & text);
+ void AddText(const std::string & text, int depth);
+ void AddElement(XmlElement * pelChild);
+ void AddElement(XmlElement * pelChild, int depth);
+ void AddAttr(const QName & name, const std::string & value);
+ void AddAttr(const QName & name, const std::string & value, int depth);
+ void ClearNamedChildren(const QName & name);
+ void ClearChildren();
+
+ static XmlElement * ForStr(const std::string & str);
+ std::string Str() const;
+
+ void Print(std::ostream * pout, std::string xmlns[], int xmlnsCount) const;
+
+ bool IsCDATA() const { return cdata_; }
+
+protected:
+ virtual bool IsTextImpl() const;
+ virtual XmlElement * AsElementImpl() const;
+ virtual XmlText * AsTextImpl() const;
+
+private:
+ QName name_;
+ XmlAttr * pFirstAttr_;
+ XmlAttr * pLastAttr_;
+ XmlChild * pFirstChild_;
+ XmlChild * pLastChild_;
+ bool cdata_;
+};
+
+}
+#endif
diff --git a/third_party/libjingle/files/talk/xmllite/xmlnsstack.cc b/third_party/libjingle/files/talk/xmllite/xmlnsstack.cc
new file mode 100644
index 0000000..4dcb649
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlnsstack.cc
@@ -0,0 +1,205 @@
+/*
+ * 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/base/stl_decl.h"
+#include <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+XmlnsStack::XmlnsStack() :
+ pxmlnsStack_(new std::vector<std::string>),
+ pxmlnsDepthStack_(new std::vector<size_t>) {
+}
+
+XmlnsStack::~XmlnsStack() {}
+
+void
+XmlnsStack::PushFrame() {
+ pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
+}
+
+void
+XmlnsStack::PopFrame() {
+ size_t prev_size = pxmlnsDepthStack_->back();
+ pxmlnsDepthStack_->pop_back();
+ if (prev_size < pxmlnsStack_->size()) {
+ pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
+ pxmlnsStack_->end());
+ }
+}
+const std::pair<std::string, bool> NS_NOT_FOUND(STR_EMPTY, false);
+const std::pair<std::string, bool> EMPTY_NS_FOUND(STR_EMPTY, true);
+const std::pair<std::string, bool> XMLNS_DEFINITION_FOUND(NS_XMLNS, true);
+
+const std::string *
+XmlnsStack::NsForPrefix(const std::string & prefix) {
+ if (prefix.length() >= 3 &&
+ (prefix[0] == 'x' || prefix[0] == 'X') &&
+ (prefix[1] == 'm' || prefix[1] == 'M') &&
+ (prefix[2] == 'l' || prefix[2] == 'L')) {
+ if (prefix == "xml")
+ return &(NS_XML);
+ if (prefix == "xmlns")
+ return &(NS_XMLNS);
+ return NULL;
+ }
+
+ std::vector<std::string>::iterator pos;
+ for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+ pos -= 2;
+ if (*pos == prefix)
+ return &(*(pos + 1));
+ }
+
+ if (prefix == STR_EMPTY)
+ return &(STR_EMPTY); // default namespace
+
+ return NULL; // none found
+}
+
+bool
+XmlnsStack::PrefixMatchesNs(const std::string & prefix, const std::string & ns) {
+ const std::string * match = NsForPrefix(prefix);
+ if (match == NULL)
+ return false;
+ return (*match == ns);
+}
+
+std::pair<std::string, bool>
+XmlnsStack::PrefixForNs(const std::string & ns, bool isattr) {
+ if (ns == NS_XML)
+ return std::make_pair(std::string("xml"), true);
+ if (ns == NS_XMLNS)
+ return std::make_pair(std::string("xmlns"), true);
+ if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
+ return std::make_pair(STR_EMPTY, true);
+
+ std::vector<std::string>::iterator pos;
+ for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
+ pos -= 2;
+ if (*(pos + 1) == ns &&
+ (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
+ return std::make_pair(*pos, true);
+ }
+
+ return std::make_pair(STR_EMPTY, false); // none found
+}
+
+std::string
+XmlnsStack::FormatQName(const QName & name, bool isAttr) {
+ std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
+ if (prefix == STR_EMPTY)
+ return name.LocalPart();
+ else
+ return prefix + ':' + name.LocalPart();
+}
+
+void
+XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
+ pxmlnsStack_->push_back(prefix);
+ pxmlnsStack_->push_back(ns);
+}
+
+void
+XmlnsStack::RemoveXmlns() {
+ pxmlnsStack_->pop_back();
+ pxmlnsStack_->pop_back();
+}
+
+static bool IsAsciiLetter(char ch) {
+ return ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z'));
+}
+
+static std::string AsciiLower(const std::string & s) {
+ std::string result(s);
+ size_t i;
+ for (i = 0; i < result.length(); i++) {
+ if (result[i] >= 'A' && result[i] <= 'Z')
+ result[i] += 'a' - 'A';
+ }
+ return result;
+}
+
+static std::string SuggestPrefix(const std::string & ns) {
+ size_t len = ns.length();
+ size_t i = ns.find_last_of('.');
+ if (i != std::string::npos && len - i <= 4 + 1)
+ len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
+ size_t last = len;
+ while (last > 0) {
+ last -= 1;
+ if (IsAsciiLetter(ns[last])) {
+ size_t first = last;
+ last += 1;
+ while (first > 0) {
+ if (!IsAsciiLetter(ns[first - 1]))
+ break;
+ first -= 1;
+ }
+ if (last - first > 4)
+ last = first + 3;
+ std::string candidate(AsciiLower(ns.substr(first, last - first)));
+ if (candidate.find("xml") != 0)
+ return candidate;
+ break;
+ }
+ }
+ return "ns";
+}
+
+
+std::pair<std::string, bool>
+XmlnsStack::AddNewPrefix(const std::string & ns, bool isAttr) {
+ if (PrefixForNs(ns, isAttr).second)
+ return std::make_pair(STR_EMPTY, false);
+
+ std::string base(SuggestPrefix(ns));
+ std::string result(base);
+ int i = 2;
+ while (NsForPrefix(result) != NULL) {
+ std::stringstream ss;
+ ss << base;
+ ss << (i++);
+ ss >> result;
+ }
+ AddXmlns(result, ns);
+ return std::make_pair(result, true);
+}
+
+void XmlnsStack::Reset() {
+ pxmlnsStack_->clear();
+ pxmlnsDepthStack_->clear();
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlnsstack.h b/third_party/libjingle/files/talk/xmllite/xmlnsstack.h
new file mode 100644
index 0000000..299ec1c
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlnsstack.h
@@ -0,0 +1,62 @@
+/*
+ * 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 _xmlnsstack_h_
+#define _xmlnsstack_h_
+
+#include <string>
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stl_decl.h"
+#include "talk/xmllite/qname.h"
+
+namespace buzz {
+
+class XmlnsStack {
+public:
+ XmlnsStack();
+ ~XmlnsStack();
+
+ void AddXmlns(const std::string & prefix, const std::string & ns);
+ void RemoveXmlns();
+ void PushFrame();
+ void PopFrame();
+ void Reset();
+
+ const std::string * NsForPrefix(const std::string & prefix);
+ bool PrefixMatchesNs(const std::string & prefix, const std::string & ns);
+ std::pair<std::string, bool> PrefixForNs(const std::string & ns, bool isAttr);
+ std::pair<std::string, bool> AddNewPrefix(const std::string & ns, bool isAttr);
+ std::string FormatQName(const QName & name, bool isAttr);
+
+private:
+
+ scoped_ptr<std::vector<std::string, std::allocator<std::string> > > pxmlnsStack_;
+ scoped_ptr<std::vector<size_t, std::allocator<size_t> > > pxmlnsDepthStack_;
+};
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmllite/xmlparser.cc b/third_party/libjingle/files/talk/xmllite/xmlparser.cc
new file mode 100644
index 0000000..7486e2d
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlparser.cc
@@ -0,0 +1,291 @@
+/*
+ * 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/base/stl_decl.h"
+#include <string>
+#include <vector>
+#include <iostream>
+#include <expat.h>
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlconstants.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlparser.h"
+
+#include <expat.h>
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+
+static void
+StartElementCallback(void * userData, const char *name, const char **atts) {
+ (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
+}
+
+static void
+EndElementCallback(void * userData, const char *name) {
+ (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
+}
+
+static void
+CharacterDataCallback(void * userData, const char *text, int len) {
+ (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
+}
+
+static void
+XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
+ (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
+}
+
+XmlParser::XmlParser(XmlParseHandler *pxph) :
+ context_(this), pxph_(pxph), sentError_(false) {
+ expat_ = XML_ParserCreate(NULL);
+ XML_SetUserData(expat_, this);
+ XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+ XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+ XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+}
+
+void
+XmlParser::Reset() {
+ if (!XML_ParserReset(expat_, NULL)) {
+ XML_ParserFree(expat_);
+ expat_ = XML_ParserCreate(NULL);
+ }
+ XML_SetUserData(expat_, this);
+ XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
+ XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
+ XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
+ context_.Reset();
+ sentError_ = false;
+}
+
+static bool
+XmlParser_StartsWithXmlns(const char *name) {
+ return name[0] == 'x' &&
+ name[1] == 'm' &&
+ name[2] == 'l' &&
+ name[3] == 'n' &&
+ name[4] == 's';
+}
+
+void
+XmlParser::ExpatStartElement(const char *name, const char **atts) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ const char **att;
+ context_.StartElement();
+ for (att = atts; *att; att += 2) {
+ if (XmlParser_StartsWithXmlns(*att)) {
+ if ((*att)[5] == '\0') {
+ context_.StartNamespace("", *(att + 1));
+ }
+ else if ((*att)[5] == ':') {
+ if (**(att + 1) == '\0') {
+ // In XML 1.0 empty namespace illegal with prefix (not in 1.1)
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+ context_.StartNamespace((*att) + 6, *(att + 1));
+ }
+ }
+ }
+ context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+ XML_GetCurrentColumnNumber(expat_),
+ XML_GetCurrentByteIndex(expat_));
+ pxph_->StartElement(&context_, name, atts);
+}
+
+void
+XmlParser::ExpatEndElement(const char *name) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ context_.EndElement();
+ context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+ XML_GetCurrentColumnNumber(expat_),
+ XML_GetCurrentByteIndex(expat_));
+ pxph_->EndElement(&context_, name);
+}
+
+void
+XmlParser::ExpatCharacterData(const char *text, int len) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+ context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+ XML_GetCurrentColumnNumber(expat_),
+ XML_GetCurrentByteIndex(expat_));
+ pxph_->CharacterData(&context_, text, len);
+}
+
+void
+XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
+ if (context_.RaisedError() != XML_ERROR_NONE)
+ return;
+
+ if (ver && std::string("1.0") != ver) {
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (standalone == 0) {
+ context_.RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+
+ if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
+ (enc[1] == 'T' || enc[1] == 't') &&
+ (enc[2] == 'F' || enc[2] == 'f') &&
+ enc[3] == '-' && enc[4] =='8')) {
+ context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
+ return;
+ }
+
+}
+
+bool
+XmlParser::Parse(const char *data, size_t len, bool isFinal) {
+ if (sentError_)
+ return false;
+
+ if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) !=
+ XML_STATUS_OK) {
+ context_.SetPosition(XML_GetCurrentLineNumber(expat_),
+ XML_GetCurrentColumnNumber(expat_),
+ XML_GetCurrentByteIndex(expat_));
+ context_.RaiseError(XML_GetErrorCode(expat_));
+ }
+
+ if (context_.RaisedError() != XML_ERROR_NONE) {
+ sentError_ = true;
+ pxph_->Error(&context_, context_.RaisedError());
+ return false;
+ }
+
+ return true;
+}
+
+XmlParser::~XmlParser() {
+ XML_ParserFree(expat_);
+}
+
+void
+XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
+ XmlParser parser(pxph);
+ parser.Parse(text.c_str(), text.length(), true);
+}
+
+XmlParser::ParseContext::ParseContext(XmlParser *parser) :
+ parser_(parser),
+ xmlnsstack_(),
+ raised_(XML_ERROR_NONE),
+ line_number_(0),
+ column_number_(0),
+ byte_index_(0) {
+}
+
+void
+XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
+ xmlnsstack_.AddXmlns(
+ *prefix ? std::string(prefix) : STR_EMPTY,
+// ns == NS_CLIENT ? NS_CLIENT :
+// ns == NS_ROSTER ? NS_ROSTER :
+// ns == NS_GR ? NS_GR :
+ std::string(ns));
+}
+
+void
+XmlParser::ParseContext::StartElement() {
+ xmlnsstack_.PushFrame();
+}
+
+void
+XmlParser::ParseContext::EndElement() {
+ xmlnsstack_.PopFrame();
+}
+
+QName
+XmlParser::ParseContext::ResolveQName(const char *qname, bool isAttr) {
+ const char *c;
+ for (c = qname; *c; ++c) {
+ if (*c == ':') {
+ const std::string * result;
+ result = xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
+ if (result == NULL)
+ return QN_EMPTY;
+ const char * localname = c + 1;
+ return QName(*result, localname);
+ }
+ }
+ if (isAttr) {
+ return QName(STR_EMPTY, qname);
+ }
+
+ const std::string * result;
+ result = xmlnsstack_.NsForPrefix(STR_EMPTY);
+ if (result == NULL)
+ return QN_EMPTY;
+
+ return QName(*result, qname);
+}
+
+void
+XmlParser::ParseContext::Reset() {
+ xmlnsstack_.Reset();
+ raised_ = XML_ERROR_NONE;
+}
+
+void
+XmlParser::ParseContext::SetPosition(XML_Size line, XML_Size column,
+ XML_Index byte_index) {
+ line_number_ = line;
+ column_number_ = column;
+ byte_index_ = byte_index;
+}
+
+void
+XmlParser::ParseContext::GetPosition(unsigned long * line,
+ unsigned long * column,
+ unsigned long * byte_index) {
+ if (line != NULL) {
+ *line = static_cast<unsigned long>(line_number_);
+ }
+
+ if (column != NULL) {
+ *column = static_cast<unsigned long>(column_number_);
+ }
+
+ if (byte_index != NULL) {
+ *byte_index = static_cast<unsigned long>(byte_index_);
+ }
+}
+
+XmlParser::ParseContext::~ParseContext() {
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlparser.h b/third_party/libjingle/files/talk/xmllite/xmlparser.h
new file mode 100644
index 0000000..2541013
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlparser.h
@@ -0,0 +1,115 @@
+/*
+ * 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 _xmlparser_h_
+#define _xmlparser_h_
+
+#include <string>
+#include <expat.h>
+
+#include "talk/xmllite/xmlnsstack.h"
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct* XML_Parser;
+
+namespace buzz {
+
+class XmlParseHandler;
+class XmlParseContext;
+class XmlParser;
+
+class XmlParseContext {
+public:
+ virtual QName ResolveQName(const char * qname, bool isAttr) = 0;
+ virtual void RaiseError(XML_Error err) = 0;
+ virtual void GetPosition(unsigned long * line, unsigned long * column,
+ unsigned long * byte_index) = 0;
+};
+
+class XmlParseHandler {
+public:
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts) = 0;
+ virtual void EndElement(XmlParseContext * pctx,
+ const char * name) = 0;
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len) = 0;
+ virtual void Error(XmlParseContext * pctx,
+ XML_Error errorCode) = 0;
+};
+
+class XmlParser {
+public:
+ static void ParseXml(XmlParseHandler * pxph, std::string text);
+
+ explicit XmlParser(XmlParseHandler * pxph);
+ bool Parse(const char * data, size_t len, bool isFinal);
+ void Reset();
+ virtual ~XmlParser();
+
+ // expat callbacks
+ void ExpatStartElement(const char * name, const char ** atts);
+ void ExpatEndElement(const char * name);
+ void ExpatCharacterData(const char * text, int len);
+ void ExpatXmlDecl(const char * ver, const char * enc, int standalone);
+
+private:
+
+ class ParseContext : public XmlParseContext {
+ public:
+ ParseContext(XmlParser * parser);
+ virtual ~ParseContext();
+ virtual QName ResolveQName(const char * qname, bool isAttr);
+ virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
+ virtual void GetPosition(unsigned long * line, unsigned long * column,
+ unsigned long * byte_index);
+ XML_Error RaisedError() { return raised_; }
+ void Reset();
+
+ void StartElement();
+ void EndElement();
+ void StartNamespace(const char * prefix, const char * ns);
+ void SetPosition(XML_Size line, XML_Size column, XML_Index byte_index);
+
+ private:
+ const XmlParser * parser_;
+ XmlnsStack xmlnsstack_;
+ XML_Error raised_;
+ XML_Size line_number_;
+ XML_Size column_number_;
+ XML_Index byte_index_;
+ };
+
+ ParseContext context_;
+ XML_Parser expat_;
+ XmlParseHandler * pxph_;
+ bool sentError_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmllite/xmlprinter.cc b/third_party/libjingle/files/talk/xmllite/xmlprinter.cc
new file mode 100644
index 0000000..05c62c8
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlprinter.cc
@@ -0,0 +1,199 @@
+/*
+ * 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/base/stl_decl.h"
+#include <string>
+#include <iostream>
+#include <vector>
+#include <sstream>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmllite/xmlnsstack.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+class XmlPrinterImpl {
+public:
+ XmlPrinterImpl(std::ostream * pout,
+ const std::string * const xmlns, int xmlnsCount);
+ void PrintElement(const XmlElement * element);
+ void PrintQuotedValue(const std::string & text);
+ void PrintBodyText(const std::string & text);
+ void PrintCDATAText(const std::string & text);
+
+private:
+ std::ostream *pout_;
+ XmlnsStack xmlnsStack_;
+};
+
+void
+XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element) {
+ PrintXml(pout, element, NULL, 0);
+}
+
+void
+XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element,
+ const std::string * const xmlns, int xmlnsCount) {
+ XmlPrinterImpl printer(pout, xmlns, xmlnsCount);
+ printer.PrintElement(element);
+}
+
+XmlPrinterImpl::XmlPrinterImpl(std::ostream * pout,
+ const std::string * const xmlns, int xmlnsCount) :
+ pout_(pout),
+ xmlnsStack_() {
+ int i;
+ for (i = 0; i < xmlnsCount; i += 2) {
+ xmlnsStack_.AddXmlns(xmlns[i], xmlns[i + 1]);
+ }
+}
+
+void
+XmlPrinterImpl::PrintElement(const XmlElement * element) {
+ xmlnsStack_.PushFrame();
+
+ // first go through attrs of pel to add xmlns definitions
+ const XmlAttr * pattr;
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ if (pattr->Name() == QN_XMLNS)
+ xmlnsStack_.AddXmlns(STR_EMPTY, pattr->Value());
+ else if (pattr->Name().Namespace() == NS_XMLNS)
+ xmlnsStack_.AddXmlns(pattr->Name().LocalPart(),
+ pattr->Value());
+ }
+
+ // then go through qnames to make sure needed xmlns definitons are added
+ std::vector<std::string> newXmlns;
+ std::pair<std::string, bool> prefix;
+ prefix = xmlnsStack_.AddNewPrefix(element->Name().Namespace(), false);
+ if (prefix.second) {
+ newXmlns.push_back(prefix.first);
+ newXmlns.push_back(element->Name().Namespace());
+ }
+
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ prefix = xmlnsStack_.AddNewPrefix(pattr->Name().Namespace(), true);
+ if (prefix.second) {
+ newXmlns.push_back(prefix.first);
+ newXmlns.push_back(pattr->Name().Namespace());
+ }
+ }
+
+ // print the element name
+ *pout_ << '<' << xmlnsStack_.FormatQName(element->Name(), false);
+
+ // and the attributes
+ for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
+ *pout_ << ' ' << xmlnsStack_.FormatQName(pattr->Name(), true) << "=\"";
+ PrintQuotedValue(pattr->Value());
+ *pout_ << '"';
+ }
+
+ // and the extra xmlns declarations
+ std::vector<std::string>::iterator i(newXmlns.begin());
+ while (i < newXmlns.end()) {
+ if (*i == STR_EMPTY)
+ *pout_ << " xmlns=\"" << *(i + 1) << '"';
+ else
+ *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
+ i += 2;
+ }
+
+ // now the children
+ const XmlChild * pchild = element->FirstChild();
+
+ if (pchild == NULL)
+ *pout_ << "/>";
+ else {
+ *pout_ << '>';
+ while (pchild) {
+ if (pchild->IsText()) {
+ if (element->IsCDATA()) {
+ PrintCDATAText(pchild->AsText()->Text());
+ } else {
+ PrintBodyText(pchild->AsText()->Text());
+ }
+ } else
+ PrintElement(pchild->AsElement());
+ pchild = pchild->NextChild();
+ }
+ *pout_ << "</" << xmlnsStack_.FormatQName(element->Name(), false) << '>';
+ }
+
+ xmlnsStack_.PopFrame();
+}
+
+void
+XmlPrinterImpl::PrintQuotedValue(const std::string & text) {
+ size_t safe = 0;
+ for (;;) {
+ size_t unsafe = text.find_first_of("<>&\"", safe);
+ if (unsafe == std::string::npos)
+ unsafe = text.length();
+ *pout_ << text.substr(safe, unsafe - safe);
+ if (unsafe == text.length())
+ return;
+ switch (text[unsafe]) {
+ case '<': *pout_ << "&lt;"; break;
+ case '>': *pout_ << "&gt;"; break;
+ case '&': *pout_ << "&amp;"; break;
+ case '"': *pout_ << "&quot;"; break;
+ }
+ safe = unsafe + 1;
+ if (safe == text.length())
+ return;
+ }
+}
+
+void
+XmlPrinterImpl::PrintBodyText(const std::string & text) {
+ size_t safe = 0;
+ for (;;) {
+ size_t unsafe = text.find_first_of("<>&", safe);
+ if (unsafe == std::string::npos)
+ unsafe = text.length();
+ *pout_ << text.substr(safe, unsafe - safe);
+ if (unsafe == text.length())
+ return;
+ switch (text[unsafe]) {
+ case '<': *pout_ << "&lt;"; break;
+ case '>': *pout_ << "&gt;"; break;
+ case '&': *pout_ << "&amp;"; break;
+ }
+ safe = unsafe + 1;
+ if (safe == text.length())
+ return;
+ }
+}
+
+void
+XmlPrinterImpl::PrintCDATAText(const std::string & text) {
+ *pout_ << "<![CDATA[" << text << "]]>";
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmllite/xmlprinter.h b/third_party/libjingle/files/talk/xmllite/xmlprinter.h
new file mode 100644
index 0000000..96900d0
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmllite/xmlprinter.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _xmlprinter_h_
+#define _xmlprinter_h_
+
+#include <iosfwd>
+#include <string>
+#include "talk/base/scoped_ptr.h"
+
+namespace buzz {
+
+class XmlElement;
+
+class XmlPrinter {
+public:
+ static void PrintXml(std::ostream * pout, const XmlElement * pelt);
+
+ static void PrintXml(std::ostream * pout, const XmlElement * pelt,
+ const std::string * const xmlns, int xmlnsCount);
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/Makefile.am b/third_party/libjingle/files/talk/xmpp/Makefile.am
new file mode 100644
index 0000000..ad75fbc
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/Makefile.am
@@ -0,0 +1,33 @@
+libcricketxmpp_la_SOURCES = constants.cc \
+ jid.cc \
+ saslmechanism.cc \
+ xmppclient.cc \
+ xmppengineimpl.cc \
+ xmppengineimpl_iq.cc \
+ xmpplogintask.cc \
+ xmppstanzaparser.cc \
+ xmpptask.cc \
+ ratelimitmanager.cc
+
+noinst_HEADERS = asyncsocket.h \
+ prexmppauth.h \
+ saslhandler.h \
+ xmpplogintask.h \
+ jid.h \
+ saslmechanism.h \
+ xmppclient.h \
+ constants.h \
+ saslplainmechanism.h \
+ xmppclientsettings.h \
+ xmppstanzaparser.h \
+ xmppengine.h \
+ xmpptask.h \
+ plainsaslhandler.h \
+ saslcookiemechanism.h \
+ xmppengineimpl.h \
+ ratelimitmanager.h
+
+
+AM_CPPFLAGS = -DPOSIX
+
+noinst_LTLIBRARIES = libcricketxmpp.la
diff --git a/third_party/libjingle/files/talk/xmpp/asyncsocket.h b/third_party/libjingle/files/talk/xmpp/asyncsocket.h
new file mode 100644
index 0000000..e4bce7f
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/asyncsocket.h
@@ -0,0 +1,86 @@
+/*
+ * 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 _ASYNCSOCKET_H_
+#define _ASYNCSOCKET_H_
+
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+ class SocketAddress;
+}
+
+namespace buzz {
+
+class AsyncSocket {
+public:
+ enum State {
+ STATE_CLOSED = 0, //!< Socket is not open.
+ STATE_CLOSING, //!< Socket is closing but can have buffered data
+ STATE_CONNECTING, //!< In the process of
+ STATE_OPEN, //!< Socket is connected
+#if defined(FEATURE_ENABLE_SSL)
+ STATE_TLS_CONNECTING, //!< Establishing TLS connection
+ STATE_TLS_OPEN, //!< TLS connected
+#endif
+ };
+
+ enum Error {
+ ERROR_NONE = 0, //!< No error
+ ERROR_WINSOCK, //!< Winsock error
+ ERROR_DNS, //!< Couldn't resolve host name
+ ERROR_WRONGSTATE, //!< Call made while socket is in the wrong state
+#if defined(FEATURE_ENABLE_SSL)
+ ERROR_SSL, //!< Something went wrong with OpenSSL
+#endif
+ };
+
+ virtual ~AsyncSocket() {}
+ virtual State state() = 0;
+ virtual Error error() = 0;
+ virtual int GetError() = 0; // winsock error code
+
+ virtual bool Connect(const talk_base::SocketAddress& addr) = 0;
+ virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
+ virtual bool Write(const char * data, size_t len) = 0;
+ virtual bool Close() = 0;
+#if defined(FEATURE_ENABLE_SSL)
+ // We allow matching any passed domain.
+ // If both names are passed as empty, we do not require a match.
+ virtual bool StartTls(const std::string & domainname) = 0;
+#endif
+
+ sigslot::signal0<> SignalConnected;
+ sigslot::signal0<> SignalSSLConnected;
+ sigslot::signal0<> SignalClosed;
+ sigslot::signal0<> SignalRead;
+ sigslot::signal0<> SignalError;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/jid.cc b/third_party/libjingle/files/talk/xmpp/jid.cc
new file mode 100644
index 0000000..eb5b7e3
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/jid.cc
@@ -0,0 +1,506 @@
+/*
+ * 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.
+ */
+
+extern "C" {
+#include <ctype.h>
+}
+#include <string>
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/base/common.h"
+#include <algorithm>
+#include "talk/base/logging.h"
+
+namespace buzz {
+
+static int AsciiToLower(int x) {
+ return (x <= 'Z' && x >= 'A') ? (x + ('a' - 'A')) : x;
+}
+
+Jid::Jid() : data_(NULL) {
+}
+
+Jid::Jid(bool is_special, const std::string & special) {
+ data_ = is_special ? new Data(special, STR_EMPTY, STR_EMPTY) : NULL;
+}
+
+Jid::Jid(const std::string & jid_string) {
+ if (jid_string == STR_EMPTY) {
+ data_ = NULL;
+ return;
+ }
+
+ // First find the slash and slice of that part
+ size_t slash = jid_string.find('/');
+ std::string resource_name = (slash == std::string::npos ? STR_EMPTY :
+ jid_string.substr(slash + 1));
+
+ // Now look for the node
+ std::string node_name;
+ size_t at = jid_string.find('@');
+ size_t domain_begin;
+ if (at < slash && at != std::string::npos) {
+ node_name = jid_string.substr(0, at);
+ domain_begin = at + 1;
+ } else {
+ domain_begin = 0;
+ }
+
+ // Now take what is left as the domain
+ size_t domain_length =
+ ( slash == std::string::npos
+ ? jid_string.length() - domain_begin
+ : slash - domain_begin);
+
+ // avoid allocating these constants repeatedly
+ std::string domain_name;
+
+ if (domain_length == 9 && jid_string.find("gmail.com", domain_begin) == domain_begin) {
+ domain_name = STR_GMAIL_COM;
+ }
+ else if (domain_length == 14 && jid_string.find("googlemail.com", domain_begin) == domain_begin) {
+ domain_name = STR_GOOGLEMAIL_COM;
+ }
+ else if (domain_length == 10 && jid_string.find("google.com", domain_begin) == domain_begin) {
+ domain_name = STR_GOOGLE_COM;
+ }
+ else {
+ domain_name = jid_string.substr(domain_begin, domain_length);
+ }
+
+ // If the domain is empty we have a non-valid jid and we should empty
+ // everything else out
+ if (domain_name.empty()) {
+ data_ = NULL;
+ return;
+ }
+
+ bool valid_node;
+ std::string validated_node = prepNode(node_name,
+ node_name.begin(), node_name.end(), &valid_node);
+ bool valid_domain;
+ std::string validated_domain = prepDomain(domain_name,
+ domain_name.begin(), domain_name.end(), &valid_domain);
+ bool valid_resource;
+ std::string validated_resource = prepResource(resource_name,
+ resource_name.begin(), resource_name.end(), &valid_resource);
+
+ if (!valid_node || !valid_domain || !valid_resource) {
+ data_ = NULL;
+ return;
+ }
+
+ data_ = new Data(validated_node, validated_domain, validated_resource);
+}
+
+Jid::Jid(const std::string & node_name,
+ const std::string & domain_name,
+ const std::string & resource_name) {
+ if (domain_name.empty()) {
+ data_ = NULL;
+ return;
+ }
+
+ bool valid_node;
+ std::string validated_node = prepNode(node_name,
+ node_name.begin(), node_name.end(), &valid_node);
+ bool valid_domain;
+ std::string validated_domain = prepDomain(domain_name,
+ domain_name.begin(), domain_name.end(), &valid_domain);
+ bool valid_resource;
+ std::string validated_resource = prepResource(resource_name,
+ resource_name.begin(), resource_name.end(), &valid_resource);
+
+ if (!valid_node || !valid_domain || !valid_resource) {
+ data_ = NULL;
+ return;
+ }
+
+ data_ = new Data(validated_node, validated_domain, validated_resource);
+}
+
+std::string Jid::Str() const {
+ if (!IsValid())
+ return STR_EMPTY;
+
+ std::string ret;
+
+ if (!data_->node_name_.empty())
+ ret = data_->node_name_ + "@";
+
+ ASSERT(data_->domain_name_ != STR_EMPTY);
+ ret += data_->domain_name_;
+
+ if (!data_->resource_name_.empty())
+ ret += "/" + data_->resource_name_;
+
+ return ret;
+}
+
+bool
+Jid::IsValid() const {
+ return data_ != NULL && !data_->domain_name_.empty();
+}
+
+bool
+Jid::IsBare() const {
+ if (Compare(JID_EMPTY) == 0) {
+ LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid";
+ return true;
+ }
+ return IsValid() &&
+ data_->resource_name_.empty();
+}
+
+bool
+Jid::IsFull() const {
+ return IsValid() &&
+ !data_->resource_name_.empty();
+}
+
+Jid
+Jid::BareJid() const {
+ if (!IsValid())
+ return Jid();
+ if (!IsFull())
+ return *this;
+ return Jid(data_->node_name_, data_->domain_name_, STR_EMPTY);
+}
+
+#if 0
+void
+Jid::set_node(const std::string & node_name) {
+ data_->node_name_ = node_name;
+}
+void
+Jid::set_domain(const std::string & domain_name) {
+ data_->domain_name_ = domain_name;
+}
+void
+Jid::set_resource(const std::string & res_name) {
+ data_->resource_name_ = res_name;
+}
+#endif
+
+bool
+Jid::BareEquals(const Jid & other) const {
+ return (other.data_ == data_ ||
+ data_ != NULL &&
+ other.data_ != NULL &&
+ other.data_->node_name_ == data_->node_name_ &&
+ other.data_->domain_name_ == data_->domain_name_);
+}
+
+bool
+Jid::operator==(const Jid & other) const {
+ return (other.data_ == data_ ||
+ data_ != NULL &&
+ other.data_ != NULL &&
+ other.data_->node_name_ == data_->node_name_ &&
+ other.data_->domain_name_ == data_->domain_name_ &&
+ other.data_->resource_name_ == data_->resource_name_);
+}
+
+int
+Jid::Compare(const Jid & other) const {
+ if (other.data_ == data_)
+ return 0;
+ if (data_ == NULL)
+ return -1;
+ if (other.data_ == NULL)
+ return 1;
+
+ int compare_result;
+ compare_result = data_->node_name_.compare(other.data_->node_name_);
+ if (0 != compare_result)
+ return compare_result;
+ compare_result = data_->domain_name_.compare(other.data_->domain_name_);
+ if (0 != compare_result)
+ return compare_result;
+ compare_result = data_->resource_name_.compare(other.data_->resource_name_);
+ return compare_result;
+}
+
+uint32 Jid::ComputeLameHash() const {
+ uint32 hash = 0;
+ // Hash the node portion
+ {
+ const std::string &str = node();
+ for (int i = 0; i < static_cast<int>(str.size()); ++i) {
+ hash = ((hash << 2) + hash) + str[i];
+ }
+ }
+
+ // Hash the domain portion
+ {
+ const std::string &str = domain();
+ for (int i = 0; i < static_cast<int>(str.size()); ++i)
+ hash = ((hash << 2) + hash) + str[i];
+ }
+
+ // Hash the resource portion
+ {
+ const std::string &str = resource();
+ for (int i = 0; i < static_cast<int>(str.size()); ++i)
+ hash = ((hash << 2) + hash) + str[i];
+ }
+
+ return hash;
+}
+
+// --- JID parsing code: ---
+
+// Checks and normalizes the node part of a JID.
+std::string
+Jid::prepNode(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ unsigned char ch = *i;
+ if (ch <= 0x7F) {
+ result += prepNodeAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement the correct stringprep protocol for these
+ result += tolower(ch);
+ }
+ if (!char_valid) {
+ return STR_EMPTY;
+ }
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a node.
+char
+Jid::prepNodeAscii(char ch, bool *valid) {
+ *valid = true;
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ return (char)(ch + ('a' - 'A'));
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
+ case '\"': case '\'':
+ case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+
+// Checks and normalizes the resource part of a JID.
+std::string
+Jid::prepResource(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ unsigned char ch = *i;
+ if (ch <= 0x7F) {
+ result += prepResourceAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement the correct stringprep protocol for these
+ result += ch;
+ }
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+// Returns the appropriate mapping for an ASCII character in a resource.
+char
+Jid::prepResourceAscii(char ch, bool *valid) {
+ *valid = true;
+ switch (ch) {
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+// Checks and normalizes the domain part of a JID.
+std::string
+Jid::prepDomain(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, bool *valid) {
+ *valid = false;
+ std::string result;
+
+ // TODO: if the domain contains a ':', then we should parse it
+ // as an IPv6 address rather than giving an error about illegal domain.
+ prepDomain(str, start, end, &result, valid);
+ if (!*valid) {
+ return STR_EMPTY;
+ }
+
+ if (result.length() > 1023) {
+ return STR_EMPTY;
+ }
+ *valid = true;
+ return result;
+}
+
+
+// Checks and normalizes an IDNA domain.
+void
+Jid::prepDomain(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, std::string *buf, bool *valid) {
+ *valid = false;
+ std::string::const_iterator last = start;
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool label_valid = true;
+ char ch = *i;
+ switch (ch) {
+ case 0x002E:
+#if 0 // FIX: This isn't UTF-8-aware.
+ case 0x3002:
+ case 0xFF0E:
+ case 0xFF61:
+#endif
+ prepDomainLabel(str, last, i, buf, &label_valid);
+ *buf += '.';
+ last = i + 1;
+ break;
+ }
+ if (!label_valid) {
+ return;
+ }
+ }
+ prepDomainLabel(str, last, end, buf, valid);
+}
+
+// Checks and normalizes a domain label.
+void
+Jid::prepDomainLabel(const std::string str, std::string::const_iterator start,
+ std::string::const_iterator end, std::string *buf, bool *valid) {
+ *valid = false;
+
+ int startLen = buf->length();
+ for (std::string::const_iterator i = start; i < end; i++) {
+ bool char_valid = true;
+ unsigned char ch = *i;
+ if (ch <= 0x7F) {
+ *buf += prepDomainLabelAscii(ch, &char_valid);
+ }
+ else {
+ // TODO: implement ToASCII for these
+ *buf += ch;
+ }
+ if (!char_valid) {
+ return;
+ }
+ }
+
+ int count = buf->length() - startLen;
+ if (count == 0) {
+ return;
+ }
+ else if (count > 63) {
+ return;
+ }
+
+ // Is this check needed? See comment in prepDomainLabelAscii.
+ if ((*buf)[startLen] == '-') {
+ return;
+ }
+ if ((*buf)[buf->length() - 1] == '-') {
+ return;
+ }
+ *valid = true;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a domain label.
+char
+Jid::prepDomainLabelAscii(char ch, bool *valid) {
+ *valid = true;
+ // TODO: A literal reading of the spec seems to say that we do
+ // not need to check for these illegal characters (an "internationalized
+ // domain label" runs ToASCII with UseSTD3... set to false). But that
+ // can't be right. We should at least be checking that there are no '/'
+ // or '@' characters in the domain. Perhaps we should see what others
+ // do in this case.
+
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ return (char)(ch + ('a' - 'A'));
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+ case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+ case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
+ case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
+ case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
+ case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
+ case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
+ case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
+ *valid = false;
+ return 0;
+
+ default:
+ return ch;
+ }
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/jid.h b/third_party/libjingle/files/talk/xmpp/jid.h
new file mode 100644
index 0000000..6831bda
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/jid.h
@@ -0,0 +1,148 @@
+/*
+ * 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 _jid_h_
+#define _jid_h_
+
+#include <string>
+#include "talk/base/basictypes.h"
+#include "talk/xmllite/xmlconstants.h"
+
+namespace buzz {
+
+//! The Jid class encapsulates and provides parsing help for Jids
+//! A Jid consists of three parts. The node, the domain and the resource.
+//!
+//! node@domain/resource
+//!
+//! The node and resource are both optional. A valid jid is defined to have
+//! a domain. A bare jid is defined to not have a resource and a full jid
+//! *does* have a resource.
+class Jid {
+public:
+ explicit Jid();
+ explicit Jid(const std::string & jid_string);
+ explicit Jid(const std::string & node_name,
+ const std::string & domain_name,
+ const std::string & resource_name);
+ explicit Jid(bool special, const std::string & special_string);
+ Jid(const Jid & jid) : data_(jid.data_) {
+ if (data_ != NULL) {
+ data_->AddRef();
+ }
+ }
+ Jid & operator=(const Jid & jid) {
+ if (jid.data_ != NULL) {
+ jid.data_->AddRef();
+ }
+ if (data_ != NULL) {
+ data_->Release();
+ }
+ data_ = jid.data_;
+ return *this;
+ }
+ ~Jid() {
+ if (data_ != NULL) {
+ data_->Release();
+ }
+ }
+
+
+ const std::string & node() const { return !data_ ? STR_EMPTY : data_->node_name_; }
+ // void set_node(const std::string & node_name);
+ const std::string & domain() const { return !data_ ? STR_EMPTY : data_->domain_name_; }
+ // void set_domain(const std::string & domain_name);
+ const std::string & resource() const { return !data_ ? STR_EMPTY : data_->resource_name_; }
+ // void set_resource(const std::string & res_name);
+
+ std::string Str() const;
+ Jid BareJid() const;
+
+ bool IsValid() const;
+ bool IsBare() const;
+ bool IsFull() const;
+
+ bool BareEquals(const Jid & other) const;
+
+ bool operator==(const Jid & other) const;
+ bool operator!=(const Jid & other) const { return !operator==(other); }
+
+ bool operator<(const Jid & other) const { return Compare(other) < 0; };
+ bool operator>(const Jid & other) const { return Compare(other) > 0; };
+
+ int Compare(const Jid & other) const;
+
+ // A quick and dirty hash. Don't count on this producing a great
+ // distribution.
+ uint32 ComputeLameHash() const;
+
+private:
+
+ static std::string prepNode(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static char prepNodeAscii(char ch, bool *valid);
+ static std::string prepResource(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static char prepResourceAscii(char ch, bool *valid);
+ static std::string prepDomain(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ bool *valid);
+ static void prepDomain(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ std::string *buf, bool *valid);
+ static void prepDomainLabel(const std::string str,
+ std::string::const_iterator start, std::string::const_iterator end,
+ std::string *buf, bool *valid);
+ static char prepDomainLabelAscii(char ch, bool *valid);
+
+ class Data {
+ public:
+ Data() : refcount_(1) {}
+ Data(const std::string & node, const std::string &domain, const std::string & resource) :
+ node_name_(node),
+ domain_name_(domain),
+ resource_name_(resource),
+ refcount_(1) {}
+ const std::string node_name_;
+ const std::string domain_name_;
+ const std::string resource_name_;
+
+ void AddRef() { refcount_++; }
+ void Release() { if (!--refcount_) delete this; }
+ private:
+ int refcount_;
+ };
+
+ Data * data_;
+};
+
+}
+
+
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/plainsaslhandler.h b/third_party/libjingle/files/talk/xmpp/plainsaslhandler.h
new file mode 100644
index 0000000..8cf1ed8
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/plainsaslhandler.h
@@ -0,0 +1,82 @@
+/*
+ * 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 _PLAINSASLHANDLER_H_
+#define _PLAINSASLHANDLER_H_
+
+#include <algorithm>
+#include <string>
+
+#include "talk/xmpp/saslhandler.h"
+
+namespace buzz {
+
+class PlainSaslHandler : public SaslHandler {
+public:
+ PlainSaslHandler(const Jid & jid, const talk_base::CryptString & password,
+ bool allow_plain) : jid_(jid), password_(password),
+ allow_plain_(allow_plain) {}
+
+ virtual ~PlainSaslHandler() {}
+
+ // Should pick the best method according to this handler
+ // returns the empty string if none are suitable
+ virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+
+ if (!encrypted && !allow_plain_) {
+ return "";
+ }
+
+ std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
+ if (it == mechanisms.end()) {
+ return "";
+ }
+ else {
+ return "PLAIN";
+ }
+ }
+
+ // Creates a SaslMechanism for the given mechanism name (you own it
+ // once you get it). If not handled, return NULL.
+ virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
+ if (mechanism == "PLAIN") {
+ return new SaslPlainMechanism(jid_, password_);
+ }
+ return NULL;
+ }
+
+private:
+ Jid jid_;
+ talk_base::CryptString password_;
+ bool allow_plain_;
+};
+
+
+}
+
+#endif
+
diff --git a/third_party/libjingle/files/talk/xmpp/prexmppauth.h b/third_party/libjingle/files/talk/xmpp/prexmppauth.h
new file mode 100644
index 0000000..f94bd3d
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/prexmppauth.h
@@ -0,0 +1,86 @@
+/*
+ * 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 _PREXMPPAUTH_H_
+#define _PREXMPPAUTH_H_
+
+#include "talk/base/cryptstring.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/saslhandler.h"
+
+namespace talk_base {
+ class SocketAddress;
+}
+
+namespace buzz {
+
+class Jid;
+class SaslMechanism;
+
+class CaptchaChallenge {
+ public:
+ CaptchaChallenge() : captcha_needed_(false) {}
+ CaptchaChallenge(const std::string& token, const std::string& url)
+ : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
+ }
+
+ bool captcha_needed() const { return captcha_needed_; }
+ const std::string& captcha_token() const { return captcha_token_; }
+
+ // This url is relative to the gaia server. Once we have better tools
+ // for cracking URLs, we should probably make this a full URL
+ const std::string& captcha_image_url() const { return captcha_image_url_; }
+
+ private:
+ bool captcha_needed_;
+ std::string captcha_token_;
+ std::string captcha_image_url_;
+};
+
+class PreXmppAuth : public SaslHandler {
+public:
+ virtual ~PreXmppAuth() {}
+
+ virtual void StartPreXmppAuth(
+ const Jid & jid,
+ const talk_base::SocketAddress & server,
+ const talk_base::CryptString & pass,
+ const std::string & auth_cookie) = 0;
+
+ sigslot::signal0<> SignalAuthDone;
+
+ virtual bool IsAuthDone() = 0;
+ virtual bool IsAuthorized() = 0;
+ virtual bool HadError() = 0;
+ virtual int GetError() = 0;
+ virtual CaptchaChallenge GetCaptchaChallenge() = 0;
+ virtual std::string GetAuthCookie() = 0;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/ratelimitmanager.cc b/third_party/libjingle/files/talk/xmpp/ratelimitmanager.cc
new file mode 100644
index 0000000..81c55ac
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/ratelimitmanager.cc
@@ -0,0 +1,77 @@
+/*
+ * 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 "talk/xmpp/ratelimitmanager.h"
+
+namespace buzz {
+
+RateLimitManager::RateLimit* RateLimitManager::GetRateLimit(
+ const std::string event_name) {
+ RateLimitMap::iterator it = rate_limits_.find(event_name);
+ if (it != rate_limits_.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+bool RateLimitManager::IsWithinRateLimit(const std::string event_name) {
+ RateLimit* current_rate = GetRateLimit(event_name);
+ if (current_rate) {
+ return current_rate->IsWithinRateLimit();
+ }
+ return true; // If no rate limit is set, then you must be under the limit
+}
+
+void RateLimitManager::UpdateRateLimit(const std::string event_name,
+ int max_count,
+ int per_x_seconds) {
+ RateLimit* current_rate = GetRateLimit(event_name);
+ if (!current_rate) {
+ current_rate = new RateLimit(max_count, per_x_seconds);
+ rate_limits_[event_name] = current_rate;
+ }
+ current_rate->UpdateRateLimit();
+}
+
+bool RateLimitManager::VerifyRateLimit(const std::string event_name,
+ int max_count,
+ int per_x_seconds) {
+ return VerifyRateLimit(event_name, max_count, per_x_seconds, false);
+}
+
+bool RateLimitManager::VerifyRateLimit(const std::string event_name,
+ int max_count,
+ int per_x_seconds,
+ bool always_update) {
+ bool within_rate_limit = IsWithinRateLimit(event_name);
+ if (within_rate_limit || always_update) {
+ UpdateRateLimit(event_name, max_count, per_x_seconds);
+ }
+ return within_rate_limit;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/ratelimitmanager.h b/third_party/libjingle/files/talk/xmpp/ratelimitmanager.h
new file mode 100644
index 0000000..79960d8
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/ratelimitmanager.h
@@ -0,0 +1,146 @@
+/*
+ * 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 _RATELIMITMANAGER_H_
+#define _RATELIMITMANAGER_H_
+
+#include "talk/base/time.h"
+#include "talk/base/taskrunner.h"
+#include <map>
+
+namespace buzz {
+
+/////////////////////////////////////////////////////////////////////
+//
+// RATELIMITMANAGER
+//
+/////////////////////////////////////////////////////////////////////
+//
+// RateLimitManager imposes client-side rate limiting for xmpp tasks and
+// other events. It ensures that no more than i events with a given name
+// can occur within k seconds.
+//
+// A buffer tracks the previous max_count events. Before an event is allowed
+// to occur, it can check its rate limit with a call to VerifyRateLimit.
+// VerifyRateLimit will look up the i-th to last event and if more than
+// k seconds have passed since then, it will return true and update the
+// appropriate rate limits. Else, it will return false.
+//
+/////////////////////////////////////////////////////////////////////
+
+class RateLimitManager {
+ public:
+
+ RateLimitManager() { };
+ ~RateLimitManager() {
+ for (RateLimitMap::iterator it = rate_limits_.begin();
+ it != rate_limits_.end(); ++it) {
+ delete it->second;
+ }
+ };
+
+ // Checks if the event is under the defined rate limit and updates the
+ // rate limit if so. Returns true if it's under the rate limit.
+ bool VerifyRateLimit(const std::string event_name, int max_count,
+ int per_x_seconds);
+
+ // Checks if the event is under the defined rate limit and updates the
+ // rate limit if so *or* if always_update = true.
+ bool VerifyRateLimit(const std::string event_name, int max_count,
+ int per_x_seconds, bool always_update);
+
+ private:
+ class RateLimit {
+ public:
+ RateLimit(int max, int per_x_secs) : counter_(0), max_count_(max),
+ per_x_seconds_(per_x_secs) {
+ event_times_ = new uint32[max_count_];
+ for (int i = 0; i < max_count_; i++) {
+ event_times_[i] = 0;
+ }
+ }
+
+ ~RateLimit() {
+ if (event_times_) {
+ delete[] event_times_;
+ }
+ }
+
+ // True iff the current time >= to the next song allowed time
+ bool IsWithinRateLimit() {
+ uint32 current_time = talk_base::Time();
+ if (talk_base::TimeDiff(current_time, NextTimeAllowedForCounter()) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Updates time and counter for rate limit
+ void UpdateRateLimit() {
+ event_times_[counter_] = talk_base::Time();
+ counter_ = (counter_ + 1) % max_count_;
+ }
+
+ private:
+
+ // The time at which the i-th (where i = max_count) event occured
+ uint32 PreviousTimeAtCounter() {
+ return event_times_[counter_];
+ }
+
+ // The time that the next event is allowed to occur
+ uint32 NextTimeAllowedForCounter() {
+ return PreviousTimeAtCounter() + per_x_seconds_ * talk_base::kSecToMsec;
+ }
+
+ int counter_; // count modulo max_count of the current event
+ int max_count_; // max number of events that can occur within per_x_seconds
+ int per_x_seconds_; // interval size for rate limit
+ uint32* event_times_; // buffer of previous max_count event
+ };
+
+ typedef std::map<const std::string, RateLimit*> RateLimitMap;
+
+ // Maps from event name to its rate limit
+ RateLimitMap rate_limits_;
+
+ // Returns rate limit for event with specified name
+ RateLimit* GetRateLimit(const std::string event_name);
+
+ // True iff the current time >= to the next song allowed time
+ bool IsWithinRateLimit(const std::string event_name);
+
+ // Updates time and counter for rate limit
+ void UpdateRateLimit(const std::string event_name, int max_count,
+ int per_x_seconds);
+
+};
+
+}
+
+#endif //_RATELIMITMANAGER_H_
diff --git a/third_party/libjingle/files/talk/xmpp/saslcookiemechanism.h b/third_party/libjingle/files/talk/xmpp/saslcookiemechanism.h
new file mode 100644
index 0000000..e3e4509
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/saslcookiemechanism.h
@@ -0,0 +1,87 @@
+/*
+ * 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 _SASLCOOKIEMECHANISM_H_
+#define _SASLCOOKIEMECHANISM_H_
+
+#include "talk/xmpp/saslmechanism.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/xmppconstants.h"
+
+namespace buzz {
+
+class SaslCookieMechanism : public SaslMechanism {
+
+public:
+ SaslCookieMechanism(const std::string & mechanism,
+ const std::string & username,
+ const std::string & cookie,
+ const std::string & token_service)
+ : mechanism_(mechanism),
+ username_(username),
+ cookie_(cookie),
+ token_service_(token_service) {}
+
+ SaslCookieMechanism(const std::string & mechanism,
+ const std::string & username,
+ const std::string & cookie)
+ : mechanism_(mechanism),
+ username_(username),
+ cookie_(cookie),
+ token_service_("") {}
+
+ virtual std::string GetMechanismName() { return mechanism_; }
+
+ virtual XmlElement * StartSaslAuth() {
+ // send initial request
+ XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+ el->AddAttr(QN_MECHANISM, mechanism_);
+ if (!token_service_.empty()) {
+ el->AddAttr(
+ QName("http://www.google.com/talk/protocol/auth", "service"),
+ token_service_);
+ }
+
+ std::string credential;
+ credential.append("\0", 1);
+ credential.append(username_);
+ credential.append("\0", 1);
+ credential.append(cookie_);
+ el->AddText(Base64Encode(credential));
+ return el;
+ }
+
+private:
+ std::string mechanism_;
+ std::string username_;
+ std::string cookie_;
+ std::string token_service_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/saslhandler.h b/third_party/libjingle/files/talk/xmpp/saslhandler.h
new file mode 100644
index 0000000..acccd76
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/saslhandler.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _SASLHANDLER_H_
+#define _SASLHANDLER_H_
+
+#include <string>
+#include <vector>
+
+namespace buzz {
+
+class SaslMechanism;
+
+// Creates mechanisms to deal with a given mechanism
+class SaslHandler {
+
+public:
+
+ // Intended to be subclassed
+ virtual ~SaslHandler() {}
+
+ // Should pick the best method according to this handler
+ // returns the empty string if none are suitable
+ virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
+
+ // Creates a SaslMechanism for the given mechanism name (you own it
+ // once you get it).
+ // If not handled, return NULL.
+ virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
+};
+
+}
+
+#endif
+
diff --git a/third_party/libjingle/files/talk/xmpp/saslmechanism.cc b/third_party/libjingle/files/talk/xmpp/saslmechanism.cc
new file mode 100644
index 0000000..6c2b781
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/saslmechanism.cc
@@ -0,0 +1,70 @@
+/*
+ * 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/base/base64.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/xmpp/saslmechanism.h"
+
+using talk_base::Base64;
+
+namespace buzz {
+
+XmlElement *
+SaslMechanism::StartSaslAuth() {
+ return new XmlElement(QN_SASL_AUTH, true);
+}
+
+XmlElement *
+SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
+ return new XmlElement(QN_SASL_ABORT, true);
+}
+
+void
+SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
+}
+
+void
+SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
+}
+
+std::string
+SaslMechanism::Base64Encode(const std::string & plain) {
+ return Base64::encode(plain);
+}
+
+std::string
+SaslMechanism::Base64Decode(const std::string & encoded) {
+ return Base64::decode(encoded);
+}
+
+std::string
+SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
+ return Base64::encodeFromArray(plain, length);
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/saslmechanism.h b/third_party/libjingle/files/talk/xmpp/saslmechanism.h
new file mode 100644
index 0000000..f2e5adc
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/saslmechanism.h
@@ -0,0 +1,74 @@
+/*
+ * 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 _SASLMECHANISM_H_
+#define _SASLMECHANISM_H_
+
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+
+
+// Defines a mechnanism to do SASL authentication.
+// Subclass instances should have a self-contained way to present
+// credentials.
+class SaslMechanism {
+
+public:
+
+ // Intended to be subclassed
+ virtual ~SaslMechanism() {}
+
+ // Should return the name of the SASL mechanism, e.g., "PLAIN"
+ virtual std::string GetMechanismName() = 0;
+
+ // Should generate the initial "auth" request. Default is just <auth/>.
+ virtual XmlElement * StartSaslAuth();
+
+ // Should respond to a SASL "<challenge>" request. Default is
+ // to abort (for mechanisms that do not do challenge-response)
+ virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
+
+ // Notification of a SASL "<success>". Sometimes information
+ // is passed on success.
+ virtual void HandleSaslSuccess(const XmlElement * success);
+
+ // Notification of a SASL "<failure>". Sometimes information
+ // for the user is passed on failure.
+ virtual void HandleSaslFailure(const XmlElement * failure);
+
+protected:
+ static std::string Base64Encode(const std::string & plain);
+ static std::string Base64Decode(const std::string & encoded);
+ static std::string Base64EncodeFromArray(const char * plain, size_t length);
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/saslplainmechanism.h b/third_party/libjingle/files/talk/xmpp/saslplainmechanism.h
new file mode 100644
index 0000000..72532e6e
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/saslplainmechanism.h
@@ -0,0 +1,65 @@
+/*
+ * 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 _SASLPLAINMECHANISM_H_
+#define _SASLPLAINMECHANISM_H_
+
+#include "talk/base/cryptstring.h"
+#include "talk/xmpp/saslmechanism.h"
+
+namespace buzz {
+
+class SaslPlainMechanism : public SaslMechanism {
+
+public:
+ SaslPlainMechanism(const buzz::Jid user_jid, const talk_base::CryptString & password) :
+ user_jid_(user_jid), password_(password) {}
+
+ virtual std::string GetMechanismName() { return "PLAIN"; }
+
+ virtual XmlElement * StartSaslAuth() {
+ // send initial request
+ XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+ el->AddAttr(QN_MECHANISM, "PLAIN");
+
+ talk_base::FormatCryptString credential;
+ credential.Append("\0", 1);
+ credential.Append(user_jid_.node());
+ credential.Append("\0", 1);
+ credential.Append(&password_);
+ el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
+ return el;
+ }
+
+private:
+ Jid user_jid_;
+ talk_base::CryptString password_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppclient.cc b/third_party/libjingle/files/talk/xmpp/xmppclient.cc
new file mode 100644
index 0000000..5f63b67
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppclient.cc
@@ -0,0 +1,421 @@
+/*
+ * 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 "xmppclient.h"
+#include "xmpptask.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/saslplainmechanism.h"
+#include "talk/xmpp/prexmppauth.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmpp/plainsaslhandler.h"
+
+namespace buzz {
+
+talk_base::Task* XmppClient::GetParent(int code) {
+ if (code == XMPP_CLIENT_TASK_CODE)
+ return this;
+ else
+ return talk_base::Task::GetParent(code);
+}
+
+class XmppClient::Private :
+ public sigslot::has_slots<>,
+ public XmppSessionHandler,
+ public XmppOutputHandler {
+public:
+
+ Private(XmppClient * client) :
+ client_(client),
+ socket_(NULL),
+ engine_(NULL),
+ proxy_port_(0),
+ pre_engine_error_(XmppEngine::ERROR_NONE),
+ pre_engine_subcode_(0),
+ signal_closed_(false),
+ allow_plain_(false) {}
+
+ // the owner
+ XmppClient * const client_;
+
+ // the two main objects
+ scoped_ptr<AsyncSocket> socket_;
+ scoped_ptr<XmppEngine> engine_;
+ scoped_ptr<PreXmppAuth> pre_auth_;
+ talk_base::CryptString pass_;
+ std::string auth_cookie_;
+ talk_base::SocketAddress server_;
+ std::string proxy_host_;
+ int proxy_port_;
+ XmppEngine::Error pre_engine_error_;
+ int pre_engine_subcode_;
+ CaptchaChallenge captcha_challenge_;
+ bool signal_closed_;
+ bool allow_plain_;
+
+ // implementations of interfaces
+ void OnStateChange(int state);
+ void WriteOutput(const char * bytes, size_t len);
+ void StartTls(const std::string & domainname);
+ void CloseConnection();
+
+ // slots for socket signals
+ void OnSocketConnected();
+ void OnSocketRead();
+ void OnSocketClosed();
+};
+
+XmppReturnStatus
+XmppClient::Connect(const XmppClientSettings & settings,
+ const std::string & lang,
+ AsyncSocket * socket,
+ PreXmppAuth * pre_auth) {
+ if (socket == NULL)
+ return XMPP_RETURN_BADARGUMENT;
+ if (d_->socket_.get() != NULL)
+ return XMPP_RETURN_BADSTATE;
+
+ d_->socket_.reset(socket);
+
+ d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
+ d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
+ d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
+
+ d_->engine_.reset(XmppEngine::Create());
+ d_->engine_->SetSessionHandler(d_.get());
+ d_->engine_->SetOutputHandler(d_.get());
+ if (!settings.resource().empty()) {
+ d_->engine_->SetRequestedResource(settings.resource());
+ }
+ d_->engine_->SetUseTls(settings.use_tls());
+
+ //
+ // The talk.google.com server expects you to use "gmail.com" in the
+ // stream, and expects the domain certificate to be "gmail.com" as well.
+ // For all other servers, we leave the strings empty, which causes
+ // the jid's domain to be used. "foo@example.com" -> stream to="example.com"
+ // tls certificate for "example.com"
+ //
+ // This is only true when using Gaia auth, so let's say if there's
+ // no sasl_handler, we should use the actual server name
+ if ((settings.server().IPAsString() == buzz::STR_TALK_GOOGLE_COM ||
+ settings.server().IPAsString() == buzz::STR_TALKX_L_GOOGLE_COM) &&
+ pre_auth != NULL) {
+ d_->engine_->SetTlsServer(buzz::STR_GMAIL_COM, buzz::STR_GMAIL_COM);
+ }
+
+ // Set language
+ d_->engine_->SetLanguage(lang);
+
+ d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
+
+ d_->pass_ = settings.pass();
+ d_->auth_cookie_ = settings.auth_cookie();
+ d_->server_ = settings.server();
+ d_->proxy_host_ = settings.proxy_host();
+ d_->proxy_port_ = settings.proxy_port();
+ d_->allow_plain_ = settings.allow_plain();
+ d_->pre_auth_.reset(pre_auth);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppEngine::State
+XmppClient::GetState() {
+ if (d_->engine_.get() == NULL)
+ return XmppEngine::STATE_NONE;
+ return d_->engine_->GetState();
+}
+
+XmppEngine::Error
+XmppClient::GetError(int *subcode) {
+ if (subcode) {
+ *subcode = 0;
+ }
+ if (d_->engine_.get() == NULL)
+ return XmppEngine::ERROR_NONE;
+ if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) {
+ if (subcode) {
+ *subcode = d_->pre_engine_subcode_;
+ }
+ return d_->pre_engine_error_;
+ }
+ return d_->engine_->GetError(subcode);
+}
+
+const XmlElement *
+XmppClient::GetStreamError() {
+ if (d_->engine_.get() == NULL) {
+ return NULL;
+ }
+ return d_->engine_->GetStreamError();
+}
+
+CaptchaChallenge XmppClient::GetCaptchaChallenge() {
+ if (d_->engine_.get() == NULL)
+ return CaptchaChallenge();
+ return d_->captcha_challenge_;
+}
+
+std::string
+XmppClient::GetAuthCookie() {
+ if (d_->engine_.get() == NULL)
+ return "";
+ return d_->auth_cookie_;
+}
+
+static void
+ForgetPassword(std::string & to_erase) {
+ size_t len = to_erase.size();
+ for (size_t i = 0; i < len; i++) {
+ // get rid of characters
+ to_erase[i] = 'x';
+ }
+ // get rid of length
+ to_erase.erase();
+}
+
+int
+XmppClient::ProcessStart() {
+ if (d_->pre_auth_.get()) {
+ d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
+ d_->pre_auth_->StartPreXmppAuth(
+ d_->engine_->GetUser(), d_->server_, d_->pass_, d_->auth_cookie_);
+ d_->pass_.Clear(); // done with this;
+ return STATE_PRE_XMPP_LOGIN;
+ }
+ else {
+ d_->engine_->SetSaslHandler(new PlainSaslHandler(
+ d_->engine_->GetUser(), d_->pass_, d_->allow_plain_));
+ d_->pass_.Clear(); // done with this;
+ return STATE_START_XMPP_LOGIN;
+ }
+}
+
+void
+XmppClient::OnAuthDone() {
+ Wake();
+}
+
+int
+XmppClient::ProcessCookieLogin() {
+ // Don't know how this could happen, but crash reports show it as NULL
+ if (!d_->pre_auth_.get()) {
+ d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ // Wait until pre authentication is done is done
+ if (!d_->pre_auth_->IsAuthDone())
+ return STATE_BLOCKED;
+
+ if (!d_->pre_auth_->IsAuthorized()) {
+ // maybe split out a case when gaia is down?
+ if (d_->pre_auth_->HadError()) {
+ d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+ d_->pre_engine_subcode_ = d_->pre_auth_->GetError();
+ }
+ else {
+ d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
+ d_->pre_engine_subcode_ = 0;
+ d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
+ }
+ d_->pre_auth_.reset(NULL); // done with this
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ // Save auth cookie as a result
+ d_->auth_cookie_ = d_->pre_auth_->GetAuthCookie();
+
+ // transfer ownership of pre_auth_ to engine
+ d_->engine_->SetSaslHandler(d_->pre_auth_.release());
+ return STATE_START_XMPP_LOGIN;
+}
+
+int
+XmppClient::ProcessStartXmppLogin() {
+ // Done with pre-connect tasks - connect!
+ if (!d_->socket_->Connect(d_->server_)) {
+ d_->pre_engine_error_ = XmppEngine::ERROR_SOCKET;
+ d_->pre_engine_subcode_ = d_->socket_->GetError();
+ EnsureClosed();
+ return STATE_ERROR;
+ }
+
+ return STATE_RESPONSE;
+}
+
+int
+XmppClient::ProcessResponse() {
+ // Hang around while we are connected.
+ if (!delivering_signal_ && (d_->engine_.get() == NULL ||
+ d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
+ return STATE_DONE;
+ return STATE_BLOCKED;
+}
+
+XmppReturnStatus
+XmppClient::Disconnect() {
+ if (d_->socket_.get() == NULL)
+ return XMPP_RETURN_BADSTATE;
+ d_->engine_->Disconnect();
+ return XMPP_RETURN_OK;
+}
+
+XmppClient::XmppClient(Task * parent)
+ : Task(parent),
+ delivering_signal_(false),
+ valid_(false) {
+ d_.reset(new Private(this));
+ valid_ = true;
+}
+
+XmppClient::~XmppClient() {
+ valid_ = false;
+}
+
+const Jid &
+XmppClient::jid() {
+ return d_->engine_->FullJid();
+}
+
+
+std::string
+XmppClient::NextId() {
+ return d_->engine_->NextId();
+}
+
+XmppReturnStatus
+XmppClient::SendStanza(const XmlElement * stanza) {
+ return d_->engine_->SendStanza(stanza);
+}
+
+XmppReturnStatus
+XmppClient::SendStanzaError(const XmlElement * old_stanza, XmppStanzaError xse, const std::string & message) {
+ return d_->engine_->SendStanzaError(old_stanza, xse, message);
+}
+
+XmppReturnStatus
+XmppClient::SendRaw(const std::string & text) {
+ return d_->engine_->SendRaw(text);
+}
+
+XmppEngine*
+XmppClient::engine() {
+ return d_->engine_.get();
+}
+
+void
+XmppClient::Private::OnSocketConnected() {
+ engine_->Connect();
+}
+
+void
+XmppClient::Private::OnSocketRead() {
+ char bytes[4096];
+ size_t bytes_read;
+ for (;;) {
+ if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
+ // TODO: deal with error information
+ return;
+ }
+
+ if (bytes_read == 0)
+ return;
+
+//#if !defined(NDEBUG)
+ client_->SignalLogInput(bytes, bytes_read);
+//#endif
+
+ engine_->HandleInput(bytes, bytes_read);
+ }
+}
+
+void
+XmppClient::Private::OnSocketClosed() {
+ int code = socket_->GetError();
+ engine_->ConnectionClosed(code);
+}
+
+void
+XmppClient::Private::OnStateChange(int state) {
+ if (state == XmppEngine::STATE_CLOSED) {
+ client_->EnsureClosed();
+ }
+ else {
+ client_->SignalStateChange((XmppEngine::State)state);
+ }
+ client_->Wake();
+}
+
+void
+XmppClient::Private::WriteOutput(const char * bytes, size_t len) {
+
+//#if !defined(NDEBUG)
+ client_->SignalLogOutput(bytes, len);
+//#endif
+
+ socket_->Write(bytes, len);
+ // TODO: deal with error information
+}
+
+void
+XmppClient::Private::StartTls(const std::string & domain) {
+#if defined(FEATURE_ENABLE_SSL)
+ socket_->StartTls(domain);
+#endif
+}
+
+void
+XmppClient::Private::CloseConnection() {
+ socket_->Close();
+}
+
+void
+XmppClient::AddXmppTask(XmppTask * task, XmppEngine::HandlerLevel level) {
+ d_->engine_->AddStanzaHandler(task, level);
+}
+
+void
+XmppClient::RemoveXmppTask(XmppTask * task) {
+ d_->engine_->RemoveStanzaHandler(task);
+}
+
+void
+XmppClient::EnsureClosed() {
+ if (!d_->signal_closed_) {
+ d_->signal_closed_ = true;
+ delivering_signal_ = true;
+ SignalStateChange(XmppEngine::STATE_CLOSED);
+ delivering_signal_ = false;
+ }
+}
+
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmppclient.h b/third_party/libjingle/files/talk/xmpp/xmppclient.h
new file mode 100644
index 0000000..1ca6fec
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppclient.h
@@ -0,0 +1,163 @@
+/*
+ * 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 _XMPPCLIENT_H_
+#define _XMPPCLIENT_H_
+
+#include <string>
+#include "talk/base/basicdefs.h"
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/asyncsocket.h"
+#include "talk/xmpp/xmppclientsettings.h"
+#include "talk/base/task.h"
+
+namespace buzz {
+
+class XmppTask;
+class PreXmppAuth;
+class CaptchaChallenge;
+
+// Just some non-colliding number. Could have picked "1".
+#define XMPP_CLIENT_TASK_CODE 0x366c1e47
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPCLIENT
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task first. XmppClient is a parent task for XmppTasks.
+//
+// XmppClient is a task which is designed to be the parent task for
+// all tasks that depend on a single Xmpp connection. If you want to,
+// for example, listen for subscription requests forever, then your
+// listener should be a task that is a child of the XmppClient that owns
+// the connection you are using. XmppClient has all the utility methods
+// that basically drill through to XmppEngine.
+//
+// XmppClient is just a wrapper for XmppEngine, and if I were writing it
+// all over again, I would make XmppClient == XmppEngine. Why?
+// XmppEngine needs tasks too, for example it has an XmppLoginTask which
+// should just be the same kind of Task instead of an XmppEngine specific
+// thing. It would help do certain things like GAIA auth cleaner.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient : public talk_base::Task, public sigslot::has_slots<>
+{
+public:
+ XmppClient(talk_base::Task * parent);
+ ~XmppClient();
+
+ XmppReturnStatus Connect(const XmppClientSettings & settings,
+ const std::string & lang,
+ AsyncSocket * socket,
+ PreXmppAuth * preauth);
+
+ virtual talk_base::Task* GetParent(int code);
+ virtual int ProcessStart();
+ virtual int ProcessResponse();
+ XmppReturnStatus Disconnect();
+ const Jid & jid();
+
+ sigslot::signal1<XmppEngine::State> SignalStateChange;
+ XmppEngine::State GetState();
+ XmppEngine::Error GetError(int *subcode);
+
+ // When there is a <stream:error> stanza, return the stanza
+ // so that they can be handled.
+ const XmlElement *GetStreamError();
+
+ // When there is an authentication error, we may have captcha info
+ // that the user can use to unlock their account
+ CaptchaChallenge GetCaptchaChallenge();
+
+ // When authentication is successful, this returns the service cookie
+ // (if we used GAIA authentication)
+ std::string GetAuthCookie();
+
+ std::string NextId();
+ XmppReturnStatus SendStanza(const XmlElement *stanza);
+ XmppReturnStatus SendRaw(const std::string & text);
+ XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text);
+
+ XmppEngine* engine();
+
+ sigslot::signal2<const char *, int> SignalLogInput;
+ sigslot::signal2<const char *, int> SignalLogOutput;
+
+private:
+ friend class XmppTask;
+
+ void OnAuthDone();
+
+ // managed tasks and dispatching
+ void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
+ void RemoveXmppTask(XmppTask *);
+
+ sigslot::signal0<> SignalDisconnected;
+
+private:
+ // Internal state management
+ enum {
+ STATE_PRE_XMPP_LOGIN = STATE_NEXT,
+ STATE_START_XMPP_LOGIN = STATE_NEXT + 1,
+ };
+ int Process(int state) {
+ switch (state) {
+ case STATE_PRE_XMPP_LOGIN: return ProcessCookieLogin();
+ case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
+ default: return Task::Process(state);
+ }
+ }
+
+ std::string GetStateName(int state) const {
+ switch (state) {
+ case STATE_PRE_XMPP_LOGIN: return "PRE_XMPP_LOGIN";
+ case STATE_START_XMPP_LOGIN: return "START_XMPP_LOGIN";
+ default: return Task::GetStateName(state);
+ }
+ }
+
+ int ProcessCookieLogin();
+ int ProcessStartXmppLogin();
+ void EnsureClosed();
+
+ class Private;
+ friend class Private;
+ scoped_ptr<Private> d_;
+
+ bool delivering_signal_;
+ bool valid_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppclientsettings.h b/third_party/libjingle/files/talk/xmpp/xmppclientsettings.h
new file mode 100644
index 0000000..fa81d5d
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppclientsettings.h
@@ -0,0 +1,116 @@
+/*
+ * 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 _XMPPCLIENTSETTINGS_H_
+#define _XMPPCLIENTSETTINGS_H_
+
+#include "talk/base/cryptstring.h"
+#include "talk/base/proxyinfo.h"
+
+namespace cricket {
+
+// This enum was taken from talk/p2p/base/port.h, which is the only
+// thing we actually need from the p2p directory.
+enum ProtocolType {
+ PROTO_UDP,
+ PROTO_TCP,
+ PROTO_SSLTCP,
+ PROTO_LAST = PROTO_SSLTCP
+};
+
+} // namespace cricket
+
+namespace buzz {
+
+class XmppClientSettings {
+public:
+ XmppClientSettings() :
+ use_tls_(false), use_cookie_auth_(false), protocol_(cricket::PROTO_TCP),
+ proxy_(talk_base::PROXY_NONE), proxy_port_(80), use_proxy_auth_(false),
+ allow_plain_(false) {}
+
+ void set_user(const std::string & user) { user_ = user; }
+ void set_host(const std::string & host) { host_ = host; }
+ void set_pass(const talk_base::CryptString & pass) { pass_ = pass; }
+ void set_auth_cookie(const std::string & cookie) { auth_cookie_ = cookie; }
+ void set_resource(const std::string & resource) { resource_ = resource; }
+ void set_use_tls(bool use_tls) { use_tls_ = use_tls; }
+ void set_server(const talk_base::SocketAddress & server) {
+ server_ = server;
+ }
+ void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
+ void set_proxy(talk_base::ProxyType f) { proxy_ = f; }
+ void set_proxy_host(const std::string & host) { proxy_host_ = host; }
+ void set_proxy_port(int port) { proxy_port_ = port; };
+ void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
+ void set_proxy_user(const std::string & user) { proxy_user_ = user; }
+ void set_proxy_pass(const talk_base::CryptString & pass) { proxy_pass_ = pass; }
+ void set_allow_plain(bool f) { allow_plain_ = f; }
+ void set_token_service(const std::string & token_service) {
+ token_service_ = token_service;
+ }
+
+ const std::string & user() const { return user_; }
+ const std::string & host() const { return host_; }
+ const talk_base::CryptString & pass() const { return pass_; }
+ const std::string & auth_cookie() const { return auth_cookie_; }
+ const std::string & resource() const { return resource_; }
+ bool use_tls() const { return use_tls_; }
+ const talk_base::SocketAddress & server() const { return server_; }
+ cricket::ProtocolType protocol() const { return protocol_; }
+ talk_base::ProxyType proxy() const { return proxy_; }
+ const std::string & proxy_host() const { return proxy_host_; }
+ int proxy_port() const { return proxy_port_; }
+ bool use_proxy_auth() const { return use_proxy_auth_; }
+ const std::string & proxy_user() const { return proxy_user_; }
+ const talk_base::CryptString & proxy_pass() const { return proxy_pass_; }
+ bool allow_plain() const { return allow_plain_; }
+ const std::string & token_service() const { return token_service_; }
+
+private:
+ std::string user_;
+ std::string host_;
+ talk_base::CryptString pass_;
+ std::string auth_cookie_;
+ std::string resource_;
+ bool use_tls_;
+ bool use_cookie_auth_;
+ talk_base::SocketAddress server_;
+ cricket::ProtocolType protocol_;
+ talk_base::ProxyType proxy_;
+ std::string proxy_host_;
+ int proxy_port_;
+ bool use_proxy_auth_;
+ std::string proxy_user_;
+ talk_base::CryptString proxy_pass_;
+ bool allow_plain_;
+ std::string token_service_;
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppconstants.cc b/third_party/libjingle/files/talk/xmpp/xmppconstants.cc
new file mode 100644
index 0000000..934d10e
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppconstants.cc
@@ -0,0 +1,402 @@
+/*
+ * 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 <string>
+#include "talk/base/basicdefs.h"
+#include "talk/xmllite/xmlconstants.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/xmppconstants.h"
+namespace buzz {
+
+const Jid JID_EMPTY(STR_EMPTY);
+
+const std::string & Constants::ns_client() {
+ static const std::string ns_client_("jabber:client");
+ return ns_client_;
+}
+
+const std::string & Constants::ns_server() {
+ static const std::string ns_server_("jabber:server");
+ return ns_server_;
+}
+
+const std::string & Constants::ns_stream() {
+ static const std::string ns_stream_("http://etherx.jabber.org/streams");
+ return ns_stream_;
+}
+
+const std::string & Constants::ns_xstream() {
+ static const std::string ns_xstream_("urn:ietf:params:xml:ns:xmpp-streams");
+ return ns_xstream_;
+}
+
+const std::string & Constants::ns_tls() {
+ static const std::string ns_tls_("urn:ietf:params:xml:ns:xmpp-tls");
+ return ns_tls_;
+}
+
+const std::string & Constants::ns_sasl() {
+ static const std::string ns_sasl_("urn:ietf:params:xml:ns:xmpp-sasl");
+ return ns_sasl_;
+}
+
+const std::string & Constants::ns_bind() {
+ static const std::string ns_bind_("urn:ietf:params:xml:ns:xmpp-bind");
+ return ns_bind_;
+}
+
+const std::string & Constants::ns_dialback() {
+ static const std::string ns_dialback_("jabber:server:dialback");
+ return ns_dialback_;
+}
+
+const std::string & Constants::ns_session() {
+ static const std::string ns_session_("urn:ietf:params:xml:ns:xmpp-session");
+ return ns_session_;
+}
+
+const std::string & Constants::ns_stanza() {
+ static const std::string ns_stanza_("urn:ietf:params:xml:ns:xmpp-stanzas");
+ return ns_stanza_;
+}
+
+const std::string & Constants::ns_privacy() {
+ static const std::string ns_privacy_("jabber:iq:privacy");
+ return ns_privacy_;
+}
+
+const std::string & Constants::ns_roster() {
+ static const std::string ns_roster_("jabber:iq:roster");
+ return ns_roster_;
+}
+
+const std::string & Constants::ns_vcard() {
+ static const std::string ns_vcard_("vcard-temp");
+ return ns_vcard_;
+}
+
+const std::string & Constants::ns_avatar_hash() {
+ static const std::string ns_avatar_hash_("google:avatar");
+ return ns_avatar_hash_;
+}
+
+const std::string & Constants::ns_vcard_update() {
+ static const std::string ns_vcard_update_("vcard-temp:x:update");
+ return ns_vcard_update_;
+}
+
+const std::string & Constants::str_client() {
+ static const std::string str_client_("client");
+ return str_client_;
+}
+
+const std::string & Constants::str_server() {
+ static const std::string str_server_("server");
+ return str_server_;
+}
+
+const std::string & Constants::str_stream() {
+ static const std::string str_stream_("stream");
+ return str_stream_;
+}
+
+const std::string STR_GET("get");
+const std::string STR_SET("set");
+const std::string STR_RESULT("result");
+const std::string STR_ERROR("error");
+
+
+const std::string STR_FROM("from");
+const std::string STR_TO("to");
+const std::string STR_BOTH("both");
+const std::string STR_REMOVE("remove");
+
+const std::string STR_UNAVAILABLE("unavailable");
+
+const std::string STR_GOOGLE_COM("google.com");
+const std::string STR_GMAIL_COM("gmail.com");
+const std::string STR_GOOGLEMAIL_COM("googlemail.com");
+const std::string STR_DEFAULT_DOMAIN("default.talk.google.com");
+const std::string STR_TALK_GOOGLE_COM("talk.google.com");
+const std::string STR_TALKX_L_GOOGLE_COM("talkx.l.google.com");
+
+const std::string STR_X("x");
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+const std::string STR_VOICEMAIL("voicemail");
+const std::string STR_OUTGOINGVOICEMAIL("outgoingvoicemail");
+#endif
+
+const QName QN_STREAM_STREAM(NS_STREAM, STR_STREAM);
+const QName QN_STREAM_FEATURES(NS_STREAM, "features");
+const QName QN_STREAM_ERROR(NS_STREAM, "error");
+
+const QName QN_XSTREAM_BAD_FORMAT(NS_XSTREAM, "bad-format");
+const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX(NS_XSTREAM, "bad-namespace-prefix");
+const QName QN_XSTREAM_CONFLICT(NS_XSTREAM, "conflict");
+const QName QN_XSTREAM_CONNECTION_TIMEOUT(NS_XSTREAM, "connection-timeout");
+const QName QN_XSTREAM_HOST_GONE(NS_XSTREAM, "host-gone");
+const QName QN_XSTREAM_HOST_UNKNOWN(NS_XSTREAM, "host-unknown");
+const QName QN_XSTREAM_IMPROPER_ADDRESSIING(NS_XSTREAM, "improper-addressing");
+const QName QN_XSTREAM_INTERNAL_SERVER_ERROR(NS_XSTREAM, "internal-server-error");
+const QName QN_XSTREAM_INVALID_FROM(NS_XSTREAM, "invalid-from");
+const QName QN_XSTREAM_INVALID_ID(NS_XSTREAM, "invalid-id");
+const QName QN_XSTREAM_INVALID_NAMESPACE(NS_XSTREAM, "invalid-namespace");
+const QName QN_XSTREAM_INVALID_XML(NS_XSTREAM, "invalid-xml");
+const QName QN_XSTREAM_NOT_AUTHORIZED(NS_XSTREAM, "not-authorized");
+const QName QN_XSTREAM_POLICY_VIOLATION(NS_XSTREAM, "policy-violation");
+const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED(NS_XSTREAM, "remote-connection-failed");
+const QName QN_XSTREAM_RESOURCE_CONSTRAINT(NS_XSTREAM, "resource-constraint");
+const QName QN_XSTREAM_RESTRICTED_XML(NS_XSTREAM, "restricted-xml");
+const QName QN_XSTREAM_SEE_OTHER_HOST(NS_XSTREAM, "see-other-host");
+const QName QN_XSTREAM_SYSTEM_SHUTDOWN(NS_XSTREAM, "system-shutdown");
+const QName QN_XSTREAM_UNDEFINED_CONDITION(NS_XSTREAM, "undefined-condition");
+const QName QN_XSTREAM_UNSUPPORTED_ENCODING(NS_XSTREAM, "unsupported-encoding");
+const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE(NS_XSTREAM, "unsupported-stanza-type");
+const QName QN_XSTREAM_UNSUPPORTED_VERSION(NS_XSTREAM, "unsupported-version");
+const QName QN_XSTREAM_XML_NOT_WELL_FORMED(NS_XSTREAM, "xml-not-well-formed");
+const QName QN_XSTREAM_TEXT(NS_XSTREAM, "text");
+
+const QName QN_TLS_STARTTLS(NS_TLS, "starttls");
+const QName QN_TLS_REQUIRED(NS_TLS, "required");
+const QName QN_TLS_PROCEED(NS_TLS, "proceed");
+const QName QN_TLS_FAILURE(NS_TLS, "failure");
+
+const QName QN_SASL_MECHANISMS(NS_SASL, "mechanisms");
+const QName QN_SASL_MECHANISM(NS_SASL, "mechanism");
+const QName QN_SASL_AUTH(NS_SASL, "auth");
+const QName QN_SASL_CHALLENGE(NS_SASL, "challenge");
+const QName QN_SASL_RESPONSE(NS_SASL, "response");
+const QName QN_SASL_ABORT(NS_SASL, "abort");
+const QName QN_SASL_SUCCESS(NS_SASL, "success");
+const QName QN_SASL_FAILURE(NS_SASL, "failure");
+const QName QN_SASL_ABORTED(NS_SASL, "aborted");
+const QName QN_SASL_INCORRECT_ENCODING(NS_SASL, "incorrect-encoding");
+const QName QN_SASL_INVALID_AUTHZID(NS_SASL, "invalid-authzid");
+const QName QN_SASL_INVALID_MECHANISM(NS_SASL, "invalid-mechanism");
+const QName QN_SASL_MECHANISM_TOO_WEAK(NS_SASL, "mechanism-too-weak");
+const QName QN_SASL_NOT_AUTHORIZED(NS_SASL, "not-authorized");
+const QName QN_SASL_TEMPORARY_AUTH_FAILURE(NS_SASL, "temporary-auth-failure");
+
+const std::string NS_GOOGLE_AUTH_PROTOCOL("http://www.google.com/talk/protocol/auth");
+const QName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT(NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result");
+
+const std::string NS_GOOGLE_AUTH("google:auth");
+const QName QN_MISSING_USERNAME(NS_GOOGLE_AUTH, "missing-username");
+const QName QN_GOOGLE_ALLOW_GENERATED_JID_XMPP_LOGIN(NS_GOOGLE_AUTH_PROTOCOL, "allow-generated-jid");
+
+const QName QN_DIALBACK_RESULT(NS_DIALBACK, "result");
+const QName QN_DIALBACK_VERIFY(NS_DIALBACK, "verify");
+
+const QName QN_STANZA_BAD_REQUEST(NS_STANZA, "bad-request");
+const QName QN_STANZA_CONFLICT(NS_STANZA, "conflict");
+const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED(NS_STANZA, "feature-not-implemented");
+const QName QN_STANZA_FORBIDDEN(NS_STANZA, "forbidden");
+const QName QN_STANZA_GONE(NS_STANZA, "gone");
+const QName QN_STANZA_INTERNAL_SERVER_ERROR(NS_STANZA, "internal-server-error");
+const QName QN_STANZA_ITEM_NOT_FOUND(NS_STANZA, "item-not-found");
+const QName QN_STANZA_JID_MALFORMED(NS_STANZA, "jid-malformed");
+const QName QN_STANZA_NOT_ACCEPTABLE(NS_STANZA, "not-acceptable");
+const QName QN_STANZA_NOT_ALLOWED(NS_STANZA, "not-allowed");
+const QName QN_STANZA_PAYMENT_REQUIRED(NS_STANZA, "payment-required");
+const QName QN_STANZA_RECIPIENT_UNAVAILABLE(NS_STANZA, "recipient-unavailable");
+const QName QN_STANZA_REDIRECT(NS_STANZA, "redirect");
+const QName QN_STANZA_REGISTRATION_REQUIRED(NS_STANZA, "registration-required");
+const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND(NS_STANZA, "remote-server-not-found");
+const QName QN_STANZA_REMOTE_SERVER_TIMEOUT(NS_STANZA, "remote-server-timeout");
+const QName QN_STANZA_RESOURCE_CONSTRAINT(NS_STANZA, "resource-constraint");
+const QName QN_STANZA_SERVICE_UNAVAILABLE(NS_STANZA, "service-unavailable");
+const QName QN_STANZA_SUBSCRIPTION_REQUIRED(NS_STANZA, "subscription-required");
+const QName QN_STANZA_UNDEFINED_CONDITION(NS_STANZA, "undefined-condition");
+const QName QN_STANZA_UNEXPECTED_REQUEST(NS_STANZA, "unexpected-request");
+const QName QN_STANZA_TEXT(NS_STANZA, "text");
+
+const QName QN_BIND_BIND(NS_BIND, "bind");
+const QName QN_BIND_RESOURCE(NS_BIND, "resource");
+const QName QN_BIND_JID(NS_BIND, "jid");
+
+const QName QN_MESSAGE(NS_CLIENT, "message");
+const QName QN_BODY(NS_CLIENT, "body");
+const QName QN_SUBJECT(NS_CLIENT, "subject");
+const QName QN_THREAD(NS_CLIENT, "thread");
+const QName QN_PRESENCE(NS_CLIENT, "presence");
+const QName QN_SHOW(NS_CLIENT, "show");
+const QName QN_STATUS(NS_CLIENT, "status");
+const QName QN_LANG(NS_CLIENT, "lang");
+const QName QN_PRIORITY(NS_CLIENT, "priority");
+const QName QN_IQ(NS_CLIENT, "iq");
+const QName QN_ERROR(NS_CLIENT, "error");
+
+const QName QN_SERVER_MESSAGE(NS_SERVER, "message");
+const QName QN_SERVER_BODY(NS_SERVER, "body");
+const QName QN_SERVER_SUBJECT(NS_SERVER, "subject");
+const QName QN_SERVER_THREAD(NS_SERVER, "thread");
+const QName QN_SERVER_PRESENCE(NS_SERVER, "presence");
+const QName QN_SERVER_SHOW(NS_SERVER, "show");
+const QName QN_SERVER_STATUS(NS_SERVER, "status");
+const QName QN_SERVER_LANG(NS_SERVER, "lang");
+const QName QN_SERVER_PRIORITY(NS_SERVER, "priority");
+const QName QN_SERVER_IQ(NS_SERVER, "iq");
+const QName QN_SERVER_ERROR(NS_SERVER, "error");
+
+const QName QN_SESSION_SESSION(NS_SESSION, "session");
+
+const QName QN_PRIVACY_QUERY(NS_PRIVACY, "query");
+const QName QN_PRIVACY_ACTIVE(NS_PRIVACY, "active");
+const QName QN_PRIVACY_DEFAULT(NS_PRIVACY, "default");
+const QName QN_PRIVACY_LIST(NS_PRIVACY, "list");
+const QName QN_PRIVACY_ITEM(NS_PRIVACY, "item");
+const QName QN_PRIVACY_IQ(NS_PRIVACY, "iq");
+const QName QN_PRIVACY_MESSAGE(NS_PRIVACY, "message");
+const QName QN_PRIVACY_PRESENCE_IN(NS_PRIVACY, "presence-in");
+const QName QN_PRIVACY_PRESENCE_OUT(NS_PRIVACY, "presence-out");
+
+const QName QN_ROSTER_QUERY(NS_ROSTER, "query");
+const QName QN_ROSTER_ITEM(NS_ROSTER, "item");
+const QName QN_ROSTER_GROUP(NS_ROSTER, "group");
+
+const QName QN_VCARD(NS_VCARD, "vCard");
+const QName QN_VCARD_FN(NS_VCARD, "FN");
+const QName QN_VCARD_PHOTO(NS_VCARD, "PHOTO");
+const QName QN_VCARD_PHOTO_BINVAL(NS_VCARD, "BINVAL");
+const QName QN_VCARD_AVATAR_HASH(NS_AVATAR_HASH, "hash");
+const QName QN_VCARD_AVATAR_HASH_MODIFIED(NS_AVATAR_HASH, "modified");
+
+const buzz::QName QN_NAME(STR_EMPTY, "name");
+const QName QN_XML_LANG(NS_XML, "lang");
+
+const std::string STR_TYPE("type");
+const std::string STR_ID("id");
+const std::string STR_NAME("name");
+const std::string STR_JID("jid");
+const std::string STR_SUBSCRIPTION("subscription");
+const std::string STR_ASK("ask");
+
+const QName QN_ENCODING(STR_EMPTY, STR_ENCODING);
+const QName QN_VERSION(STR_EMPTY, STR_VERSION);
+const QName QN_TO(STR_EMPTY, "to");
+const QName QN_FROM(STR_EMPTY, "from");
+const QName QN_TYPE(STR_EMPTY, "type");
+const QName QN_ID(STR_EMPTY, "id");
+const QName QN_CODE(STR_EMPTY, "code");
+
+const QName QN_VALUE(STR_EMPTY, "value");
+const QName QN_ACTION(STR_EMPTY, "action");
+const QName QN_ORDER(STR_EMPTY, "order");
+const QName QN_MECHANISM(STR_EMPTY, "mechanism");
+const QName QN_ASK(STR_EMPTY, "ask");
+const QName QN_JID(STR_EMPTY, "jid");
+const QName QN_SUBSCRIPTION(STR_EMPTY, "subscription");
+const QName QN_TITLE1(STR_EMPTY, "title1");
+const QName QN_TITLE2(STR_EMPTY, "title2");
+const QName QN_SOURCE(STR_EMPTY, "source");
+
+const QName QN_XMLNS_CLIENT(NS_XMLNS, STR_CLIENT);
+const QName QN_XMLNS_SERVER(NS_XMLNS, STR_SERVER);
+const QName QN_XMLNS_STREAM(NS_XMLNS, STR_STREAM);
+
+
+
+// Presence
+const std::string STR_SHOW_AWAY("away");
+const std::string STR_SHOW_CHAT("chat");
+const std::string STR_SHOW_DND("dnd");
+const std::string STR_SHOW_XA("xa");
+const std::string STR_SHOW_OFFLINE("offline");
+
+// Subscription
+const std::string STR_SUBSCRIBE("subscribe");
+const std::string STR_SUBSCRIBED("subscribed");
+const std::string STR_UNSUBSCRIBE("unsubscribe");
+const std::string STR_UNSUBSCRIBED("unsubscribed");
+
+
+// JEP 0030
+const QName QN_NODE(STR_EMPTY, "node");
+const QName QN_CATEGORY(STR_EMPTY, "category");
+const QName QN_VAR(STR_EMPTY, "var");
+const std::string NS_DISCO_INFO("http://jabber.org/protocol/disco#info");
+const std::string NS_DISCO_ITEMS("http://jabber.org/protocol/disco#items");
+const QName QN_DISCO_INFO_QUERY(NS_DISCO_INFO, "query");
+const QName QN_DISCO_IDENTITY(NS_DISCO_INFO, "identity");
+const QName QN_DISCO_FEATURE(NS_DISCO_INFO, "feature");
+
+const QName QN_DISCO_ITEMS_QUERY(NS_DISCO_ITEMS, "query");
+const QName QN_DISCO_ITEM(NS_DISCO_ITEMS, "item");
+
+
+// JEP 0115
+const std::string NS_CAPS("http://jabber.org/protocol/caps");
+const QName QN_CAPS_C(NS_CAPS, "c");
+const QName QN_VER(STR_EMPTY, "ver");
+const QName QN_EXT(STR_EMPTY, "ext");
+
+// JEP 0153
+const std::string kNSVCard("vcard-temp:x:update");
+const QName kQnVCardX(kNSVCard, "x");
+const QName kQnVCardPhoto(kNSVCard, "photo");
+
+// JEP 0172 User Nickname
+const std::string kNSNickname("http://jabber.org/protocol/nick");
+const QName kQnNickname(kNSNickname, "nick");
+
+
+// JEP 0085 chat state
+const std::string NS_CHATSTATE("http://jabber.org/protocol/chatstates");
+const QName QN_CS_ACTIVE(NS_CHATSTATE, "active");
+const QName QN_CS_COMPOSING(NS_CHATSTATE, "composing");
+const QName QN_CS_PAUSED(NS_CHATSTATE, "paused");
+const QName QN_CS_INACTIVE(NS_CHATSTATE, "inactive");
+const QName QN_CS_GONE(NS_CHATSTATE, "gone");
+
+// JEP 0091 Delayed Delivery
+const std::string kNSDelay("jabber:x:delay");
+const QName kQnDelayX(kNSDelay, "x");
+const QName kQnStamp(STR_EMPTY, "stamp");
+
+// Google time stamping (higher resolution)
+const std::string kNSTimestamp("google:timestamp");
+const QName kQnTime(kNSTimestamp, "time");
+const QName kQnMilliseconds(STR_EMPTY, "ms");
+
+
+
+// Jingle Info
+const std::string NS_JINGLE_INFO("google:jingleinfo");
+const QName QN_JINGLE_INFO_QUERY(NS_JINGLE_INFO, "query");
+const QName QN_JINGLE_INFO_STUN(NS_JINGLE_INFO, "stun");
+const QName QN_JINGLE_INFO_RELAY(NS_JINGLE_INFO, "relay");
+const QName QN_JINGLE_INFO_SERVER(NS_JINGLE_INFO, "server");
+const QName QN_JINGLE_INFO_TOKEN(NS_JINGLE_INFO, "token");
+const QName QN_JINGLE_INFO_HOST(STR_EMPTY, "host");
+const QName QN_JINGLE_INFO_TCP(STR_EMPTY, "tcp");
+const QName QN_JINGLE_INFO_UDP(STR_EMPTY, "udp");
+const QName QN_JINGLE_INFO_TCPSSL(STR_EMPTY, "tcpssl");
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmppconstants.h b/third_party/libjingle/files/talk/xmpp/xmppconstants.h
new file mode 100644
index 0000000..a53217b
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppconstants.h
@@ -0,0 +1,360 @@
+/*
+ * 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 _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
+#define _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
+
+#include <string>
+#include "talk/xmllite/qname.h"
+#include "talk/xmpp/jid.h"
+
+#define NS_CLIENT Constants::ns_client()
+#define NS_SERVER Constants::ns_server()
+#define NS_STREAM Constants::ns_stream()
+#define NS_XSTREAM Constants::ns_xstream()
+#define NS_TLS Constants::ns_tls()
+#define NS_SASL Constants::ns_sasl()
+#define NS_BIND Constants::ns_bind()
+#define NS_DIALBACK Constants::ns_dialback()
+#define NS_SESSION Constants::ns_session()
+#define NS_STANZA Constants::ns_stanza()
+#define NS_PRIVACY Constants::ns_privacy()
+#define NS_ROSTER Constants::ns_roster()
+#define NS_VCARD Constants::ns_vcard()
+#define NS_AVATAR_HASH Constants::ns_avatar_hash()
+#define NS_VCARD_UPDATE Constants::ns_vcard_update()
+#define STR_CLIENT Constants::str_client()
+#define STR_SERVER Constants::str_server()
+#define STR_STREAM Constants::str_stream()
+
+
+namespace buzz {
+
+extern const Jid JID_EMPTY;
+
+class Constants {
+ public:
+ static const std::string & ns_client();
+ static const std::string & ns_server();
+ static const std::string & ns_stream();
+ static const std::string & ns_xstream();
+ static const std::string & ns_tls();
+ static const std::string & ns_sasl();
+ static const std::string & ns_bind();
+ static const std::string & ns_dialback();
+ static const std::string & ns_session();
+ static const std::string & ns_stanza();
+ static const std::string & ns_privacy();
+ static const std::string & ns_roster();
+ static const std::string & ns_vcard();
+ static const std::string & ns_avatar_hash();
+ static const std::string & ns_vcard_update();
+
+ static const std::string & str_client();
+ static const std::string & str_server();
+ static const std::string & str_stream();
+};
+
+extern const std::string STR_GET;
+extern const std::string STR_SET;
+extern const std::string STR_RESULT;
+extern const std::string STR_ERROR;
+
+
+extern const std::string STR_FROM;
+extern const std::string STR_TO;
+extern const std::string STR_BOTH;
+extern const std::string STR_REMOVE;
+
+extern const std::string STR_MESSAGE;
+extern const std::string STR_BODY;
+extern const std::string STR_PRESENCE;
+extern const std::string STR_STATUS;
+extern const std::string STR_SHOW;
+extern const std::string STR_PRIOIRTY;
+extern const std::string STR_IQ;
+
+extern const std::string STR_TYPE;
+extern const std::string STR_NAME;
+extern const std::string STR_ID;
+extern const std::string STR_JID;
+extern const std::string STR_SUBSCRIPTION;
+extern const std::string STR_ASK;
+extern const std::string STR_X;
+extern const std::string STR_GOOGLE_COM;
+extern const std::string STR_GMAIL_COM;
+extern const std::string STR_GOOGLEMAIL_COM;
+extern const std::string STR_DEFAULT_DOMAIN;
+extern const std::string STR_TALK_GOOGLE_COM;
+extern const std::string STR_TALKX_L_GOOGLE_COM;
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+extern const std::string STR_VOICEMAIL;
+extern const std::string STR_OUTGOINGVOICEMAIL;
+#endif
+
+extern const std::string STR_UNAVAILABLE;
+
+extern const QName QN_STREAM_STREAM;
+extern const QName QN_STREAM_FEATURES;
+extern const QName QN_STREAM_ERROR;
+
+extern const QName QN_XSTREAM_BAD_FORMAT;
+extern const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
+extern const QName QN_XSTREAM_CONFLICT;
+extern const QName QN_XSTREAM_CONNECTION_TIMEOUT;
+extern const QName QN_XSTREAM_HOST_GONE;
+extern const QName QN_XSTREAM_HOST_UNKNOWN;
+extern const QName QN_XSTREAM_IMPROPER_ADDRESSIING;
+extern const QName QN_XSTREAM_INTERNAL_SERVER_ERROR;
+extern const QName QN_XSTREAM_INVALID_FROM;
+extern const QName QN_XSTREAM_INVALID_ID;
+extern const QName QN_XSTREAM_INVALID_NAMESPACE;
+extern const QName QN_XSTREAM_INVALID_XML;
+extern const QName QN_XSTREAM_NOT_AUTHORIZED;
+extern const QName QN_XSTREAM_POLICY_VIOLATION;
+extern const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
+extern const QName QN_XSTREAM_RESOURCE_CONSTRAINT;
+extern const QName QN_XSTREAM_RESTRICTED_XML;
+extern const QName QN_XSTREAM_SEE_OTHER_HOST;
+extern const QName QN_XSTREAM_SYSTEM_SHUTDOWN;
+extern const QName QN_XSTREAM_UNDEFINED_CONDITION;
+extern const QName QN_XSTREAM_UNSUPPORTED_ENCODING;
+extern const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
+extern const QName QN_XSTREAM_UNSUPPORTED_VERSION;
+extern const QName QN_XSTREAM_XML_NOT_WELL_FORMED;
+extern const QName QN_XSTREAM_TEXT;
+
+extern const QName QN_TLS_STARTTLS;
+extern const QName QN_TLS_REQUIRED;
+extern const QName QN_TLS_PROCEED;
+extern const QName QN_TLS_FAILURE;
+
+extern const QName QN_SASL_MECHANISMS;
+extern const QName QN_SASL_MECHANISM;
+extern const QName QN_SASL_AUTH;
+extern const QName QN_SASL_CHALLENGE;
+extern const QName QN_SASL_RESPONSE;
+extern const QName QN_SASL_ABORT;
+extern const QName QN_SASL_SUCCESS;
+extern const QName QN_SASL_FAILURE;
+extern const QName QN_SASL_ABORTED;
+extern const QName QN_SASL_INCORRECT_ENCODING;
+extern const QName QN_SASL_INVALID_AUTHZID;
+extern const QName QN_SASL_INVALID_MECHANISM;
+extern const QName QN_SASL_MECHANISM_TOO_WEAK;
+extern const QName QN_SASL_NOT_AUTHORIZED;
+extern const QName QN_SASL_TEMPORARY_AUTH_FAILURE;
+
+extern const std::string NS_GOOGLE_AUTH;
+extern const QName QN_MISSING_USERNAME;
+extern const std::string NS_GOOGLE_AUTH_PROTOCOL;
+extern const QName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT;
+extern const QName QN_GOOGLE_ALLOW_GENERATED_JID_XMPP_LOGIN;
+
+extern const QName QN_DIALBACK_RESULT;
+extern const QName QN_DIALBACK_VERIFY;
+
+extern const QName QN_STANZA_BAD_REQUEST;
+extern const QName QN_STANZA_CONFLICT;
+extern const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
+extern const QName QN_STANZA_FORBIDDEN;
+extern const QName QN_STANZA_GONE;
+extern const QName QN_STANZA_INTERNAL_SERVER_ERROR;
+extern const QName QN_STANZA_ITEM_NOT_FOUND;
+extern const QName QN_STANZA_JID_MALFORMED;
+extern const QName QN_STANZA_NOT_ACCEPTABLE;
+extern const QName QN_STANZA_NOT_ALLOWED;
+extern const QName QN_STANZA_PAYMENT_REQUIRED;
+extern const QName QN_STANZA_RECIPIENT_UNAVAILABLE;
+extern const QName QN_STANZA_REDIRECT;
+extern const QName QN_STANZA_REGISTRATION_REQUIRED;
+extern const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
+extern const QName QN_STANZA_REMOTE_SERVER_TIMEOUT;
+extern const QName QN_STANZA_RESOURCE_CONSTRAINT;
+extern const QName QN_STANZA_SERVICE_UNAVAILABLE;
+extern const QName QN_STANZA_SUBSCRIPTION_REQUIRED;
+extern const QName QN_STANZA_UNDEFINED_CONDITION;
+extern const QName QN_STANZA_UNEXPECTED_REQUEST;
+extern const QName QN_STANZA_TEXT;
+
+extern const QName QN_BIND_BIND;
+extern const QName QN_BIND_RESOURCE;
+extern const QName QN_BIND_JID;
+
+extern const QName QN_MESSAGE;
+extern const QName QN_BODY;
+extern const QName QN_SUBJECT;
+extern const QName QN_THREAD;
+extern const QName QN_PRESENCE;
+extern const QName QN_SHOW;
+extern const QName QN_STATUS;
+extern const QName QN_LANG;
+extern const QName QN_PRIORITY;
+extern const QName QN_IQ;
+extern const QName QN_ERROR;
+
+extern const QName QN_SERVER_MESSAGE;
+extern const QName QN_SERVER_BODY;
+extern const QName QN_SERVER_SUBJECT;
+extern const QName QN_SERVER_THREAD;
+extern const QName QN_SERVER_PRESENCE;
+extern const QName QN_SERVER_SHOW;
+extern const QName QN_SERVER_STATUS;
+extern const QName QN_SERVER_LANG;
+extern const QName QN_SERVER_PRIORITY;
+extern const QName QN_SERVER_IQ;
+extern const QName QN_SERVER_ERROR;
+
+extern const QName QN_SESSION_SESSION;
+
+extern const QName QN_PRIVACY_QUERY;
+extern const QName QN_PRIVACY_ACTIVE;
+extern const QName QN_PRIVACY_DEFAULT;
+extern const QName QN_PRIVACY_LIST;
+extern const QName QN_PRIVACY_ITEM;
+extern const QName QN_PRIVACY_IQ;
+extern const QName QN_PRIVACY_MESSAGE;
+extern const QName QN_PRIVACY_PRESENCE_IN;
+extern const QName QN_PRIVACY_PRESENCE_OUT;
+
+extern const QName QN_ROSTER_QUERY;
+extern const QName QN_ROSTER_ITEM;
+extern const QName QN_ROSTER_GROUP;
+
+extern const QName QN_VCARD;
+extern const QName QN_VCARD_FN;
+extern const QName QN_VCARD_PHOTO;
+extern const QName QN_VCARD_PHOTO_BINVAL;
+extern const QName QN_VCARD_AVATAR_HASH;
+extern const QName QN_VCARD_AVATAR_HASH_MODIFIED;
+
+
+extern const QName QN_XML_LANG;
+
+extern const QName QN_ENCODING;
+extern const QName QN_VERSION;
+extern const QName QN_TO;
+extern const QName QN_FROM;
+extern const QName QN_TYPE;
+extern const QName QN_ID;
+extern const QName QN_CODE;
+extern const QName QN_NAME;
+extern const QName QN_VALUE;
+extern const QName QN_ACTION;
+extern const QName QN_ORDER;
+extern const QName QN_MECHANISM;
+extern const QName QN_ASK;
+extern const QName QN_JID;
+extern const QName QN_SUBSCRIPTION;
+extern const QName QN_TITLE1;
+extern const QName QN_TITLE2;
+
+
+extern const QName QN_XMLNS_CLIENT;
+extern const QName QN_XMLNS_SERVER;
+extern const QName QN_XMLNS_STREAM;
+
+// Presence
+extern const std::string STR_SHOW_AWAY;
+extern const std::string STR_SHOW_CHAT;
+extern const std::string STR_SHOW_DND;
+extern const std::string STR_SHOW_XA;
+extern const std::string STR_SHOW_OFFLINE;
+
+// Subscription
+extern const std::string STR_SUBSCRIBE;
+extern const std::string STR_SUBSCRIBED;
+extern const std::string STR_UNSUBSCRIBE;
+extern const std::string STR_UNSUBSCRIBED;
+
+
+// JEP 0030
+extern const QName QN_NODE;
+extern const QName QN_CATEGORY;
+extern const QName QN_VAR;
+extern const std::string NS_DISCO_INFO;
+extern const std::string NS_DISCO_ITEMS;
+
+extern const QName QN_DISCO_INFO_QUERY;
+extern const QName QN_DISCO_IDENTITY;
+extern const QName QN_DISCO_FEATURE;
+
+extern const QName QN_DISCO_ITEMS_QUERY;
+extern const QName QN_DISCO_ITEM;
+
+
+// JEP 0115
+extern const std::string NS_CAPS;
+extern const QName QN_CAPS_C;
+extern const QName QN_VER;
+extern const QName QN_EXT;
+
+
+// Avatar - JEP 0153
+extern const std::string kNSVCard;
+extern const QName kQnVCardX;
+extern const QName kQnVCardPhoto;
+
+// JEP 0172 User Nickname
+extern const std::string kNSNickname;
+extern const QName kQnNickname;
+
+
+// JEP 0085 chat state
+extern const std::string NS_CHATSTATE;
+extern const QName QN_CS_ACTIVE;
+extern const QName QN_CS_COMPOSING;
+extern const QName QN_CS_PAUSED;
+extern const QName QN_CS_INACTIVE;
+extern const QName QN_CS_GONE;
+
+// JEP 0091 Delayed Delivery
+extern const std::string kNSDelay;
+extern const QName kQnDelayX;
+extern const QName kQnStamp;
+
+// Google time stamping (higher resolution)
+extern const std::string kNSTimestamp;
+extern const QName kQnTime;
+extern const QName kQnMilliseconds;
+
+
+extern const std::string NS_JINGLE_INFO;
+extern const QName QN_JINGLE_INFO_QUERY;
+extern const QName QN_JINGLE_INFO_STUN;
+extern const QName QN_JINGLE_INFO_RELAY;
+extern const QName QN_JINGLE_INFO_SERVER;
+extern const QName QN_JINGLE_INFO_TOKEN;
+extern const QName QN_JINGLE_INFO_HOST;
+extern const QName QN_JINGLE_INFO_TCP;
+extern const QName QN_JINGLE_INFO_UDP;
+extern const QName QN_JINGLE_INFO_TCPSSL;
+
+}
+
+#endif // _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_
diff --git a/third_party/libjingle/files/talk/xmpp/xmppengine.h b/third_party/libjingle/files/talk/xmpp/xmppengine.h
new file mode 100644
index 0000000..45d2875
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppengine.h
@@ -0,0 +1,338 @@
+/*
+ * 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 _xmppengine_h_
+#define _xmppengine_h_
+
+// also part of the API
+#include "talk/xmpp/jid.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlelement.h"
+
+
+namespace buzz {
+
+class XmppEngine;
+class SaslHandler;
+typedef void * XmppIqCookie;
+
+//! XMPP stanza error codes.
+//! Used in XmppEngine.SendStanzaError().
+enum XmppStanzaError {
+ XSE_BAD_REQUEST,
+ XSE_CONFLICT,
+ XSE_FEATURE_NOT_IMPLEMENTED,
+ XSE_FORBIDDEN,
+ XSE_GONE,
+ XSE_INTERNAL_SERVER_ERROR,
+ XSE_ITEM_NOT_FOUND,
+ XSE_JID_MALFORMED,
+ XSE_NOT_ACCEPTABLE,
+ XSE_NOT_ALLOWED,
+ XSE_PAYMENT_REQUIRED,
+ XSE_RECIPIENT_UNAVAILABLE,
+ XSE_REDIRECT,
+ XSE_REGISTRATION_REQUIRED,
+ XSE_SERVER_NOT_FOUND,
+ XSE_SERVER_TIMEOUT,
+ XSE_RESOURCE_CONSTRAINT,
+ XSE_SERVICE_UNAVAILABLE,
+ XSE_SUBSCRIPTION_REQUIRED,
+ XSE_UNDEFINED_CONDITION,
+ XSE_UNEXPECTED_REQUEST,
+};
+
+// XmppReturnStatus
+// This is used by API functions to synchronously return status.
+enum XmppReturnStatus {
+ XMPP_RETURN_OK,
+ XMPP_RETURN_BADARGUMENT,
+ XMPP_RETURN_BADSTATE,
+ XMPP_RETURN_PENDING,
+ XMPP_RETURN_UNEXPECTED,
+ XMPP_RETURN_NOTYETIMPLEMENTED,
+};
+
+//! Callback for socket output for an XmppEngine connection.
+//! Register via XmppEngine.SetOutputHandler. An XmppEngine
+//! can call back to this handler while it is processing
+//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
+class XmppOutputHandler {
+public:
+
+ //! Deliver the specified bytes to the XMPP socket.
+ virtual void WriteOutput(const char * bytes, size_t len) = 0;
+
+ //! Initiate TLS encryption on the socket.
+ //! The implementation must verify that the SSL
+ //! certificate matches the given domainname.
+ virtual void StartTls(const std::string & domainname) = 0;
+
+ //! Called when engine wants the connecton closed.
+ virtual void CloseConnection() = 0;
+};
+
+//! Callback to deliver engine state change notifications
+//! to the object managing the engine.
+class XmppSessionHandler {
+public:
+ //! Called when engine changes state. Argument is new state.
+ virtual void OnStateChange(int state) = 0;
+};
+
+//! Callback to deliver stanzas to an Xmpp application module.
+//! Register via XmppEngine.SetDefaultSessionHandler or via
+//! XmppEngine.AddSessionHAndler.
+class XmppStanzaHandler {
+public:
+
+ //! Process the given stanza.
+ //! The handler must return true if it has handled the stanza.
+ //! A false return value causes the stanza to be passed on to
+ //! the next registered handler.
+ virtual bool HandleStanza(const XmlElement * stanza) = 0;
+};
+
+//! Callback to deliver iq responses (results and errors).
+//! Register while sending an iq via XmppEngine.SendIq.
+//! Iq responses are routed to matching XmppIqHandlers in preference
+//! to sending to any registered SessionHandlers.
+class XmppIqHandler {
+public:
+ //! Called to handle the iq response.
+ //! The response may be either a result or an error, and will have
+ //! an 'id' that matches the request and a 'from' that matches the
+ //! 'to' of the request. Called no more than once; once this is
+ //! called, the handler is automatically unregistered.
+ virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
+};
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput. Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngine {
+public:
+ static XmppEngine * Create();
+ virtual ~XmppEngine() {}
+
+ //! Error codes. See GetError().
+ enum Error {
+ ERROR_NONE = 0, //!< No error
+ ERROR_XML, //!< Malformed XML or encoding error
+ ERROR_STREAM, //!< XMPP stream error - see GetStreamError()
+ ERROR_VERSION, //!< XMPP version error
+ ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials)
+ ERROR_TLS, //!< TLS could not be negotiated
+ ERROR_AUTH, //!< Authentication could not be negotiated
+ ERROR_BIND, //!< Resource or session binding could not be negotiated
+ ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
+ ERROR_DOCUMENT_CLOSED, //!< Closed by </stream:stream>
+ ERROR_SOCKET, //!< Socket error
+ ERROR_NETWORK_TIMEOUT, //!< Some sort of timeout (eg., we never got the roster)
+ ERROR_MISSING_USERNAME //!< User has a Google Account but no nickname
+ };
+
+ //! States. See GetState().
+ enum State {
+ STATE_NONE = 0, //!< Nonexistent state
+ STATE_START, //!< Initial state.
+ STATE_OPENING, //!< Exchanging stream headers, authenticating and so on.
+ STATE_OPEN, //!< Authenticated and bound.
+ STATE_CLOSED, //!< Session closed, possibly due to error.
+ };
+
+ // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+ //! Registers the handler for socket output
+ virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
+
+ //! Provides socket input to the engine
+ virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
+
+ //! Advises the engine that the socket has closed
+ virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
+
+ // SESSION SETUP ---------------------------------------------------------
+
+ //! Indicates the (bare) JID for the user to use.
+ virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
+
+ //! Get the login (bare) JID.
+ virtual const Jid & GetUser() = 0;
+
+ //! Provides different methods for credentials for login.
+ //! Takes ownership of this object; deletes when login is done
+ virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
+
+ //! Sets whether TLS will be used within the connection (default true).
+ virtual XmppReturnStatus SetUseTls(bool useTls) = 0;
+
+ //! Sets an alternate domain from which we allows TLS certificates.
+ //! This is for use in the case where a we want to allow a proxy to
+ //! serve up its own certificate rather than one owned by the underlying
+ //! domain.
+ virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
+ const std::string & proxy_domain) = 0;
+
+ //! Gets whether TLS will be used within the connection.
+ virtual bool GetUseTls() = 0;
+
+ //! Sets the request resource name, if any (optional).
+ //! Note that the resource name may be overridden by the server; after
+ //! binding, the actual resource name is available as part of FullJid().
+ virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
+
+ //! Gets the request resource name.
+ virtual const std::string & GetRequestedResource() = 0;
+
+ //! Sets language
+ virtual void SetLanguage(const std::string & lang) = 0;
+
+ // SESSION MANAGEMENT ---------------------------------------------------
+
+ //! Set callback for state changes.
+ virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
+
+ //! Initiates the XMPP connection.
+ //! After supplying connection settings, call this once to initiate,
+ //! (optionally) encrypt, authenticate, and bind the connection.
+ virtual XmppReturnStatus Connect() = 0;
+
+ //! The current engine state.
+ virtual State GetState() = 0;
+
+ //! Returns true if the connection is encrypted (under TLS)
+ virtual bool IsEncrypted() = 0;
+
+ //! The error code.
+ //! Consult this after XmppOutputHandler.OnClose().
+ virtual Error GetError(int *subcode) = 0;
+
+ //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+ //! Notice the stanza returned is owned by the XmppEngine and
+ //! is deleted when the engine is destroyed.
+ virtual const XmlElement * GetStreamError() = 0;
+
+ //! Closes down the connection.
+ //! Sends CloseConnection to output, and disconnects and registered
+ //! session handlers. After Disconnect completes, it is guaranteed
+ //! that no further callbacks will be made.
+ virtual XmppReturnStatus Disconnect() = 0;
+
+ // APPLICATION USE -------------------------------------------------------
+
+ enum HandlerLevel {
+ HL_NONE = 0,
+ HL_PEEK, //!< Sees messages before all other processing; cannot abort
+ HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
+ HL_SENDER, //!< Watches for a type of message from a specific sender
+ HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs
+ HL_ALL, //!< Watches all messages - gets last shot
+ HL_COUNT, //!< Count of handler levels
+ };
+
+ //! Adds a listener for session events.
+ //! Stanza delivery is chained to session handlers; the first to
+ //! return 'true' is the last to get each stanza.
+ virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
+
+ //! Removes a listener for session events.
+ virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
+
+ //! Sends a stanza to the server.
+ virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
+
+ //! Sends raw text to the server
+ virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
+
+ //! Sends an iq to the server, and registers a callback for the result.
+ //! Returns the cookie passed to the result handler.
+ virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+ XmppIqHandler* iq_handler,
+ XmppIqCookie* cookie) = 0;
+
+ //! Unregisters an iq callback handler given its cookie.
+ //! No callback will come to this handler after it's unregistered.
+ virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler** iq_handler) = 0;
+
+
+ //! Forms and sends an error in response to the given stanza.
+ //! Swaps to and from, sets type to "error", and adds error information
+ //! based on the passed code. Text is optional and may be STR_EMPTY.
+ virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text) = 0;
+
+ //! The fullly bound JID.
+ //! This JID is only valid after binding has succeeded. If the value
+ //! is JID_NULL, the binding has not succeeded.
+ virtual const Jid & FullJid() = 0;
+
+ //! The next unused iq id for this connection.
+ //! Call this when building iq stanzas, to ensure that each iq
+ //! gets its own unique id.
+ virtual std::string NextId() = 0;
+
+};
+
+}
+
+
+// Move these to a better location
+
+#define XMPP_FAILED(x) \
+ ( (x) == buzz::XMPP_RETURN_OK ? false : true) \
+
+
+#define XMPP_SUCCEEDED(x) \
+ ( (x) == buzz::XMPP_RETURN_OK ? true : false) \
+
+#define IFR(x) \
+ do { \
+ xmpp_status = (x); \
+ if (XMPP_FAILED(xmpp_status)) { \
+ return xmpp_status; \
+ } \
+ } while (false) \
+
+
+#define IFC(x) \
+ do { \
+ xmpp_status = (x); \
+ if (XMPP_FAILED(xmpp_status)) { \
+ goto Cleanup; \
+ } \
+ } while (false) \
+
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppengineimpl.cc b/third_party/libjingle/files/talk/xmpp/xmppengineimpl.cc
new file mode 100644
index 0000000..c44b6db
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppengineimpl.cc
@@ -0,0 +1,498 @@
+/*
+ * 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 TRACK_ARRAY_ALLOC_PROBLEM
+
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/xmpplogintask.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmpp/saslhandler.h"
+
+namespace buzz {
+
+static const std::string XMPP_CLIENT_NAMESPACES[] = {
+ "stream", "http://etherx.jabber.org/streams",
+ "", "jabber:client",
+};
+
+static const size_t XMPP_CLIENT_NAMESPACES_LEN = 4;
+
+XmppEngine * XmppEngine::Create() {
+ return new XmppEngineImpl();
+}
+
+
+XmppEngineImpl::XmppEngineImpl() :
+ stanzaParseHandler_(this),
+ stanzaParser_(&stanzaParseHandler_),
+ engine_entered_(0),
+ user_jid_(JID_EMPTY),
+ password_(),
+ requested_resource_(STR_EMPTY),
+ tls_needed_(true),
+ login_task_(new XmppLoginTask(this)),
+ next_id_(0),
+ bound_jid_(JID_EMPTY),
+ state_(STATE_START),
+ encrypted_(false),
+ error_code_(ERROR_NONE),
+ subcode_(0),
+ stream_error_(NULL),
+ raised_reset_(false),
+ output_handler_(NULL),
+ session_handler_(NULL),
+ iq_entries_(new IqEntryVector()),
+ output_(new std::stringstream()),
+ sasl_handler_(NULL) {
+ for (int i = 0; i < HL_COUNT; i+= 1) {
+ stanza_handlers_[i].reset(new StanzaHandlerVector());
+ }
+}
+
+XmppEngineImpl::~XmppEngineImpl() {
+ DeleteIqCookies();
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetOutputHandler(XmppOutputHandler* output_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ output_handler_ = output_handler;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetSessionHandler(XmppSessionHandler* session_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ session_handler_ = session_handler;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::HandleInput(const char * bytes, size_t len) {
+ if (state_ < STATE_OPENING || state_ > STATE_OPEN)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ // TODO(jliaw): The return value of the xml parser is not checked.
+ stanzaParser_.Parse(bytes, len, false);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::ConnectionClosed(int subcode) {
+ if (state_ != STATE_CLOSED) {
+ EnterExit ee(this);
+ // If told that connection closed and not already closed,
+ // then connection was unpexectedly dropped.
+ if (subcode) {
+ SignalError(ERROR_SOCKET, subcode);
+ } else {
+ SignalError(ERROR_CONNECTION_CLOSED, 0); // no subcode
+ }
+ }
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetUseTls(bool useTls) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ tls_needed_ = useTls;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetTlsServer(const std::string & tls_server_hostname,
+ const std::string & tls_server_domain) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ tls_server_hostname_ = tls_server_hostname;
+ tls_server_domain_= tls_server_domain;
+
+ return XMPP_RETURN_OK;
+}
+
+bool
+XmppEngineImpl::GetUseTls() {
+ return tls_needed_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetUser(const Jid & jid) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ user_jid_ = jid;
+
+ return XMPP_RETURN_OK;
+}
+
+const Jid &
+XmppEngineImpl::GetUser() {
+ return user_jid_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetSaslHandler(SaslHandler * sasl_handler) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ sasl_handler_.reset(sasl_handler);
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SetRequestedResource(const std::string & resource) {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ requested_resource_ = resource;
+
+ return XMPP_RETURN_OK;
+}
+
+const std::string &
+XmppEngineImpl::GetRequestedResource() {
+ return requested_resource_;
+}
+
+XmppReturnStatus
+XmppEngineImpl::AddStanzaHandler(XmppStanzaHandler * stanza_handler,
+ XmppEngine::HandlerLevel level) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ stanza_handlers_[level]->push_back(stanza_handler);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::RemoveStanzaHandler(XmppStanzaHandler * stanza_handler) {
+
+ bool found = false;
+
+ for (int level = 0; level < HL_COUNT; level += 1) {
+ StanzaHandlerVector::iterator new_end =
+ std::remove(stanza_handlers_[level]->begin(),
+ stanza_handlers_[level]->end(),
+ stanza_handler);
+
+ if (new_end != stanza_handlers_[level]->end()) {
+ stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return XMPP_RETURN_BADARGUMENT;
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::Connect() {
+ if (state_ != STATE_START)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ // get the login task started
+ state_ = STATE_OPENING;
+ if (login_task_.get()) {
+ login_task_->IncomingStanza(NULL, false);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SendStanza(const XmlElement * element) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ if (login_task_.get()) {
+ // still handshaking - then outbound stanzas are queued
+ login_task_->OutgoingStanza(element);
+ } else {
+ // handshake done - send straight through
+ InternalSendStanza(element);
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppEngineImpl::SendRaw(const std::string & text) {
+ if (state_ == STATE_CLOSED || login_task_.get())
+ return XMPP_RETURN_BADSTATE;
+
+ EnterExit ee(this);
+
+ (*output_) << text;
+
+ return XMPP_RETURN_OK;
+}
+
+std::string
+XmppEngineImpl::NextId() {
+ std::stringstream ss;
+ ss << next_id_++;
+ return ss.str();
+}
+
+XmppReturnStatus
+XmppEngineImpl::Disconnect() {
+
+ if (state_ != STATE_CLOSED) {
+ EnterExit ee(this);
+ if (state_ == STATE_OPEN)
+ *output_ << "</stream:stream>";
+ state_ = STATE_CLOSED;
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::IncomingStart(const XmlElement * pelStart) {
+ if (HasError() || raised_reset_)
+ return;
+
+ if (login_task_.get()) {
+ // start-stream should go to login task
+ login_task_->IncomingStanza(pelStart, true);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ }
+ else {
+ // if not logging in, it's an error to see a start
+ SignalError(ERROR_XML, 0);
+ }
+}
+
+void
+XmppEngineImpl::IncomingStanza(const XmlElement * stanza) {
+ if (HasError() || raised_reset_)
+ return;
+
+ if (stanza->Name() == QN_STREAM_ERROR) {
+ // Explicit XMPP stream error
+ SignalStreamError(stanza);
+ } else if (login_task_.get()) {
+ // Handle login handshake
+ login_task_->IncomingStanza(stanza, false);
+ if (login_task_->IsDone())
+ login_task_.reset();
+ } else if (HandleIqResponse(stanza)) {
+ // iq is handled by above call
+ } else {
+ // give every "peek" handler a shot at all stanzas
+ for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
+ (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
+ }
+
+ // give other handlers a shot in precedence order, stopping after handled
+ for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
+ for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
+ if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
+ goto Handled;
+ }
+ }
+
+ // If nobody wants to handle a stanza then send back an error.
+ // Only do this for IQ stanzas as messages should probably just be dropped
+ // and presence stanzas should certainly be dropped.
+ std::string type = stanza->Attr(QN_TYPE);
+ if (stanza->Name() == QN_IQ &&
+ !(type == "error" || type == "result")) {
+ SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
+ }
+ }
+ Handled:
+ ; // handled - we're done
+}
+
+void
+XmppEngineImpl::IncomingEnd(bool isError) {
+ if (HasError() || raised_reset_)
+ return;
+
+ SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0);
+}
+
+void
+XmppEngineImpl::InternalSendStart(const std::string & to) {
+ std::string hostname = tls_server_hostname_;
+ if (hostname.empty()) {
+ hostname = to;
+ }
+
+ // If not language is specified, the spec says use *
+ std::string lang = lang_;
+ if (lang.length() == 0)
+ lang = "*";
+
+ // send stream-beginning
+ // note, we put a \r\n at tne end fo the first line to cause non-XMPP
+ // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
+ *output_ << "<stream:stream to=\"" << hostname << "\" "
+ << "xml:lang=\"" << lang << "\" "
+ << "version=\"1.0\" "
+ << "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+ << "xmlns=\"jabber:client\">\r\n";
+}
+
+void
+XmppEngineImpl::InternalSendStanza(const XmlElement * element) {
+ // It should really never be necessary to set a FROM attribute on a stanza.
+ // It is implied by the bind on the stream and if you get it wrong
+ // (by flipping from/to on a message?) the server will close the stream.
+ ASSERT(!element->HasAttr(QN_FROM));
+
+ // TODO: consider caching the XmlPrinter
+ XmlPrinter::PrintXml(output_.get(), element,
+ XMPP_CLIENT_NAMESPACES, XMPP_CLIENT_NAMESPACES_LEN);
+}
+
+std::string
+XmppEngineImpl::ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+ return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
+}
+
+SaslMechanism *
+XmppEngineImpl::GetSaslMechanism(const std::string & name) {
+ return sasl_handler_->CreateSaslMechanism(name);
+}
+
+void
+XmppEngineImpl::SignalBound(const Jid & fullJid) {
+ if (state_ == STATE_OPENING) {
+ bound_jid_ = fullJid;
+ state_ = STATE_OPEN;
+ }
+}
+
+void
+XmppEngineImpl::SignalStreamError(const XmlElement * pelStreamError) {
+ if (state_ != STATE_CLOSED) {
+ stream_error_.reset(new XmlElement(*pelStreamError));
+ SignalError(ERROR_STREAM, 0);
+ }
+}
+
+void
+XmppEngineImpl::SignalError(Error errorCode, int subCode) {
+ if (state_ != STATE_CLOSED) {
+ error_code_ = errorCode;
+ subcode_ = subCode;
+ state_ = STATE_CLOSED;
+ }
+}
+
+bool
+XmppEngineImpl::HasError() {
+ return error_code_ != ERROR_NONE;
+}
+
+void
+XmppEngineImpl::StartTls(const std::string & domain) {
+ if (output_handler_) {
+ output_handler_->StartTls(
+ tls_server_domain_.empty() ? domain : tls_server_domain_);
+ encrypted_ = true;
+ }
+}
+
+XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
+ : engine_(engine),
+ state_(engine->state_),
+ error_(engine->error_code_) {
+ engine->engine_entered_ += 1;
+}
+
+XmppEngineImpl::EnterExit::~EnterExit() {
+ XmppEngineImpl* engine = engine_;
+
+ engine->engine_entered_ -= 1;
+
+ bool closing = (engine->state_ != state_ &&
+ engine->state_ == STATE_CLOSED);
+ bool flushing = closing || (engine->engine_entered_ == 0);
+
+ if (engine->output_handler_ && flushing) {
+ std::string output = engine->output_->str();
+ if (output.length() > 0)
+ engine->output_handler_->WriteOutput(output.c_str(), output.length());
+ engine->output_->str("");
+
+ if (closing) {
+ engine->output_handler_->CloseConnection();
+ engine->output_handler_ = 0;
+ }
+ }
+
+ if (engine->engine_entered_)
+ return;
+
+ if (engine->raised_reset_) {
+ engine->stanzaParser_.Reset();
+ engine->raised_reset_ = false;
+ }
+
+ if (engine->session_handler_) {
+ if (engine->state_ != state_)
+ engine->session_handler_->OnStateChange(engine->state_);
+ // Note: Handling of OnStateChange(CLOSED) should allow for the
+ // deletion of the engine, so no members should be accessed
+ // after this line.
+ }
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmppengineimpl.h b/third_party/libjingle/files/talk/xmpp/xmppengineimpl.h
new file mode 100644
index 0000000..1981035
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppengineimpl.h
@@ -0,0 +1,276 @@
+/*
+ * 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 _xmppengineimpl_h_
+#define _xmppengineimpl_h_
+
+#include <sstream>
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmppstanzaparser.h"
+
+namespace buzz {
+
+class XmppLoginTask;
+class XmppEngine;
+class XmppIqEntry;
+class SaslHandler;
+class SaslMechanism;
+
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput. Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngineImpl : public XmppEngine {
+public:
+ XmppEngineImpl();
+ virtual ~XmppEngineImpl();
+
+ // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+ //! Registers the handler for socket output
+ virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
+
+ //! Provides socket input to the engine
+ virtual XmppReturnStatus HandleInput(const char * bytes, size_t len);
+
+ //! Advises the engine that the socket has closed
+ virtual XmppReturnStatus ConnectionClosed(int subcode);
+
+ // SESSION SETUP ---------------------------------------------------------
+
+ //! Indicates the (bare) JID for the user to use.
+ virtual XmppReturnStatus SetUser(const Jid & jid);
+
+ //! Get the login (bare) JID.
+ virtual const Jid & GetUser();
+
+ //! Indicates the autentication to use. Takes ownership of the object.
+ virtual XmppReturnStatus SetSaslHandler(SaslHandler * sasl_handler);
+
+ //! Sets whether TLS will be used within the connection (default true).
+ virtual XmppReturnStatus SetUseTls(bool useTls);
+
+ //! Sets an alternate domain from which we allows TLS certificates.
+ //! This is for use in the case where a we want to allow a proxy to
+ //! serve up its own certificate rather than one owned by the underlying
+ //! domain.
+ virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
+ const std::string & proxy_domain);
+
+ //! Gets whether TLS will be used within the connection.
+ virtual bool GetUseTls();
+
+ //! Sets the request resource name, if any (optional).
+ //! Note that the resource name may be overridden by the server; after
+ //! binding, the actual resource name is available as part of FullJid().
+ virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
+
+ //! Gets the request resource name.
+ virtual const std::string & GetRequestedResource();
+
+ //! Sets language
+ virtual void SetLanguage(const std::string & lang) {
+ lang_ = lang;
+ }
+
+ // SESSION MANAGEMENT ---------------------------------------------------
+
+ //! Set callback for state changes.
+ virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
+
+ //! Initiates the XMPP connection.
+ //! After supplying connection settings, call this once to initiate,
+ //! (optionally) encrypt, authenticate, and bind the connection.
+ virtual XmppReturnStatus Connect();
+
+ //! The current engine state.
+ virtual State GetState() { return state_; }
+
+ //! Returns true if the connection is encrypted (under TLS)
+ virtual bool IsEncrypted() { return encrypted_; }
+
+ //! The error code.
+ //! Consult this after XmppOutputHandler.OnClose().
+ virtual Error GetError(int *subcode) {
+ if (subcode) {
+ *subcode = subcode_;
+ }
+ return error_code_;
+ }
+
+ //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+ //! Notice the stanza returned is owned by the XmppEngine and
+ //! is deleted when the engine is destroyed.
+ virtual const XmlElement * GetStreamError() { return stream_error_.get(); }
+
+ //! Closes down the connection.
+ //! Sends CloseConnection to output, and disconnects and registered
+ //! session handlers. After Disconnect completes, it is guaranteed
+ //! that no further callbacks will be made.
+ virtual XmppReturnStatus Disconnect();
+
+ // APPLICATION USE -------------------------------------------------------
+
+ //! Adds a listener for session events.
+ //! Stanza delivery is chained to session handlers; the first to
+ //! return 'true' is the last to get each stanza.
+ virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
+ XmppEngine::HandlerLevel level);
+
+ //! Removes a listener for session events.
+ virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
+
+ //! Sends a stanza to the server.
+ virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza);
+
+ //! Sends raw text to the server
+ virtual XmppReturnStatus SendRaw(const std::string & text);
+
+ //! Sends an iq to the server, and registers a callback for the result.
+ //! Returns the cookie passed to the result handler.
+ virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+ XmppIqHandler* iq_handler,
+ XmppIqCookie* cookie);
+
+ //! Unregisters an iq callback handler given its cookie.
+ //! No callback will come to this handler after it's unregistered.
+ virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler** iq_handler);
+
+ //! Forms and sends an error in response to the given stanza.
+ //! Swaps to and from, sets type to "error", and adds error information
+ //! based on the passed code. Text is optional and may be STR_EMPTY.
+ virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+ XmppStanzaError code,
+ const std::string & text);
+
+ //! The fullly bound JID.
+ //! This JID is only valid after binding has succeeded. If the value
+ //! is JID_NULL, the binding has not succeeded.
+ virtual const Jid & FullJid() { return bound_jid_; }
+
+ //! The next unused iq id for this connection.
+ //! Call this when building iq stanzas, to ensure that each iq
+ //! gets its own unique id.
+ virtual std::string NextId();
+
+private:
+ friend class XmppLoginTask;
+ friend class XmppIqEntry;
+
+ void IncomingStanza(const XmlElement *pelStanza);
+ void IncomingStart(const XmlElement *pelStanza);
+ void IncomingEnd(bool isError);
+
+ void InternalSendStart(const std::string & domainName);
+ void InternalSendStanza(const XmlElement * pelStanza);
+ std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted);
+ SaslMechanism * GetSaslMechanism(const std::string & name);
+ void SignalBound(const Jid & fullJid);
+ void SignalStreamError(const XmlElement * pelStreamError);
+ void SignalError(Error errorCode, int subCode);
+ bool HasError();
+ void DeleteIqCookies();
+ bool HandleIqResponse(const XmlElement * element);
+ void StartTls(const std::string & domain);
+ void RaiseReset() { raised_reset_ = true; }
+
+ class StanzaParseHandler : public XmppStanzaParseHandler {
+ public:
+ StanzaParseHandler(XmppEngineImpl * outer) : outer_(outer) {}
+ virtual void StartStream(const XmlElement * pelStream)
+ { outer_->IncomingStart(pelStream); }
+ virtual void Stanza(const XmlElement * pelStanza)
+ { outer_->IncomingStanza(pelStanza); }
+ virtual void EndStream()
+ { outer_->IncomingEnd(false); }
+ virtual void XmlError()
+ { outer_->IncomingEnd(true); }
+ private:
+ XmppEngineImpl * const outer_;
+ };
+
+ class EnterExit {
+ public:
+ EnterExit(XmppEngineImpl* engine);
+ ~EnterExit();
+ private:
+ XmppEngineImpl* engine_;
+ State state_;
+ Error error_;
+
+ };
+
+ friend class StanzaParseHandler;
+ friend class EnterExit;
+
+ StanzaParseHandler stanzaParseHandler_;
+ XmppStanzaParser stanzaParser_;
+
+
+ // state
+ int engine_entered_;
+ Jid user_jid_;
+ std::string password_;
+ std::string requested_resource_;
+ bool tls_needed_;
+ std::string tls_server_hostname_;
+ std::string tls_server_domain_;
+ scoped_ptr<XmppLoginTask> login_task_;
+ std::string lang_;
+
+ int next_id_;
+ Jid bound_jid_;
+ State state_;
+ bool encrypted_;
+ Error error_code_;
+ int subcode_;
+ scoped_ptr<XmlElement> stream_error_;
+ bool raised_reset_;
+ XmppOutputHandler* output_handler_;
+ XmppSessionHandler* session_handler_;
+
+ typedef STD_VECTOR(XmppStanzaHandler*) StanzaHandlerVector;
+ scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
+
+ typedef STD_VECTOR(XmppIqEntry*) IqEntryVector;
+ scoped_ptr<IqEntryVector> iq_entries_;
+
+ scoped_ptr<SaslHandler> sasl_handler_;
+
+ scoped_ptr<std::stringstream> output_;
+};
+
+}
+
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppengineimpl_iq.cc b/third_party/libjingle/files/talk/xmpp/xmppengineimpl_iq.cc
new file mode 100644
index 0000000..86bc28e
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppengineimpl_iq.cc
@@ -0,0 +1,277 @@
+/*
+ * 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 <vector>
+#include <algorithm>
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/xmppconstants.h"
+
+namespace buzz {
+
+class XmppIqEntry {
+ XmppIqEntry(const std::string & id, const std::string & to,
+ XmppEngine * pxce, XmppIqHandler * iq_handler) :
+ id_(id),
+ to_(to),
+ engine_(pxce),
+ iq_handler_(iq_handler) {
+ }
+
+private:
+ friend class XmppEngineImpl;
+
+ const std::string id_;
+ const std::string to_;
+ XmppEngine * const engine_;
+ XmppIqHandler * const iq_handler_;
+};
+
+
+XmppReturnStatus
+XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler,
+ XmppIqCookie* cookie) {
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+ if (NULL == iq_handler)
+ return XMPP_RETURN_BADARGUMENT;
+ if (!element || element->Name() != QN_IQ)
+ return XMPP_RETURN_BADARGUMENT;
+
+ const std::string& type = element->Attr(QN_TYPE);
+ if (type != "get" && type != "set")
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!element->HasAttr(QN_ID))
+ return XMPP_RETURN_BADARGUMENT;
+ const std::string& id = element->Attr(QN_ID);
+
+ XmppIqEntry * iq_entry = new XmppIqEntry(id,
+ element->Attr(QN_TO),
+ this, iq_handler);
+ iq_entries_->push_back(iq_entry);
+ SendStanza(element);
+
+ if (cookie)
+ *cookie = iq_entry;
+
+ return XMPP_RETURN_OK;
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie,
+ XmppIqHandler ** iq_handler) {
+
+ std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos;
+
+ pos = std::find(iq_entries_->begin(),
+ iq_entries_->end(),
+ reinterpret_cast<XmppIqEntry*>(cookie));
+
+ if (pos == iq_entries_->end())
+ return XMPP_RETURN_BADARGUMENT;
+
+ XmppIqEntry* entry = *pos;
+ iq_entries_->erase(pos);
+ if (iq_handler)
+ *iq_handler = entry->iq_handler_;
+ delete entry;
+
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::DeleteIqCookies() {
+ for (size_t i = 0; i < iq_entries_->size(); i += 1) {
+ XmppIqEntry * iq_entry_ = (*iq_entries_)[i];
+ (*iq_entries_)[i] = NULL;
+ delete iq_entry_;
+ }
+ iq_entries_->clear();
+}
+
+static void
+AecImpl(XmlElement * error_element, const QName & name,
+ const char * type, const char * code) {
+ error_element->AddElement(new XmlElement(QN_ERROR));
+ error_element->AddAttr(QN_CODE, code, 1);
+ error_element->AddAttr(QN_TYPE, type, 1);
+ error_element->AddElement(new XmlElement(name, true), 1);
+}
+
+
+static void
+AddErrorCode(XmlElement * error_element, XmppStanzaError code) {
+ switch (code) {
+ case XSE_BAD_REQUEST:
+ AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400");
+ break;
+ case XSE_CONFLICT:
+ AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409");
+ break;
+ case XSE_FEATURE_NOT_IMPLEMENTED:
+ AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED,
+ "cancel", "501");
+ break;
+ case XSE_FORBIDDEN:
+ AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403");
+ break;
+ case XSE_GONE:
+ AecImpl(error_element, QN_STANZA_GONE, "modify", "302");
+ break;
+ case XSE_INTERNAL_SERVER_ERROR:
+ AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500");
+ break;
+ case XSE_ITEM_NOT_FOUND:
+ AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404");
+ break;
+ case XSE_JID_MALFORMED:
+ AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400");
+ break;
+ case XSE_NOT_ACCEPTABLE:
+ AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406");
+ break;
+ case XSE_NOT_ALLOWED:
+ AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405");
+ break;
+ case XSE_PAYMENT_REQUIRED:
+ AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402");
+ break;
+ case XSE_RECIPIENT_UNAVAILABLE:
+ AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404");
+ break;
+ case XSE_REDIRECT:
+ AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302");
+ break;
+ case XSE_REGISTRATION_REQUIRED:
+ AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407");
+ break;
+ case XSE_SERVER_NOT_FOUND:
+ AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND,
+ "cancel", "404");
+ break;
+ case XSE_SERVER_TIMEOUT:
+ AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502");
+ break;
+ case XSE_RESOURCE_CONSTRAINT:
+ AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500");
+ break;
+ case XSE_SERVICE_UNAVAILABLE:
+ AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503");
+ break;
+ case XSE_SUBSCRIPTION_REQUIRED:
+ AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407");
+ break;
+ case XSE_UNDEFINED_CONDITION:
+ AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500");
+ break;
+ case XSE_UNEXPECTED_REQUEST:
+ AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400");
+ break;
+ }
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::SendStanzaError(const XmlElement * element_original,
+ XmppStanzaError code,
+ const std::string & text) {
+
+ if (state_ == STATE_CLOSED)
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement error_element(element_original->Name());
+ error_element.AddAttr(QN_TYPE, "error");
+
+ // copy attrs, copy 'from' to 'to' and strip 'from'
+ for (const XmlAttr * attribute = element_original->FirstAttr();
+ attribute; attribute = attribute->NextAttr()) {
+ QName name = attribute->Name();
+ if (name == QN_TO)
+ continue; // no need to put a from attr. Server will stamp stanza
+ else if (name == QN_FROM)
+ name = QN_TO;
+ else if (name == QN_TYPE)
+ continue;
+ error_element.AddAttr(name, attribute->Value());
+ }
+
+ // copy children
+ for (const XmlChild * child = element_original->FirstChild();
+ child;
+ child = child->NextChild()) {
+ if (child->IsText()) {
+ error_element.AddText(child->AsText()->Text());
+ } else {
+ error_element.AddElement(new XmlElement(*(child->AsElement())));
+ }
+ }
+
+ // add error information
+ AddErrorCode(&error_element, code);
+ if (text != STR_EMPTY) {
+ XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true);
+ text_element->AddText(text);
+ error_element.AddElement(text_element);
+ }
+
+ SendStanza(&error_element);
+
+ return XMPP_RETURN_OK;
+}
+
+
+bool
+XmppEngineImpl::HandleIqResponse(const XmlElement * element) {
+ if (iq_entries_->empty())
+ return false;
+ if (element->Name() != QN_IQ)
+ return false;
+ std::string type = element->Attr(QN_TYPE);
+ if (type != "result" && type != "error")
+ return false;
+ if (!element->HasAttr(QN_ID))
+ return false;
+ std::string id = element->Attr(QN_ID);
+ std::string from = element->Attr(QN_FROM);
+
+ for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin();
+ it != iq_entries_->end(); it += 1) {
+ XmppIqEntry * iq_entry = *it;
+ if (iq_entry->id_ == id && iq_entry->to_ == from) {
+ iq_entries_->erase(it);
+ iq_entry->iq_handler_->IqResponse(iq_entry, element);
+ delete iq_entry;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmpplogintask.cc b/third_party/libjingle/files/talk/xmpp/xmpplogintask.cc
new file mode 100644
index 0000000..2b6ddce
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmpplogintask.cc
@@ -0,0 +1,386 @@
+/*
+ * 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 <iostream>
+#include <string>
+#include <vector>
+#include "talk/base/base64.h"
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/saslmechanism.h"
+#include "talk/xmpp/xmppengineimpl.h"
+#include "talk/xmpp/xmpplogintask.h"
+
+using talk_base::ConstantLabel;
+
+namespace buzz {
+
+#if !defined(NDEBUG)
+const ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
+ KLABEL(LOGINSTATE_INIT),
+ KLABEL(LOGINSTATE_STREAMSTART_SENT),
+ KLABEL(LOGINSTATE_STARTED_XMPP),
+ KLABEL(LOGINSTATE_TLS_INIT),
+ KLABEL(LOGINSTATE_AUTH_INIT),
+ KLABEL(LOGINSTATE_BIND_INIT),
+ KLABEL(LOGINSTATE_TLS_REQUESTED),
+ KLABEL(LOGINSTATE_SASL_RUNNING),
+ KLABEL(LOGINSTATE_BIND_REQUESTED),
+ KLABEL(LOGINSTATE_SESSION_REQUESTED),
+ KLABEL(LOGINSTATE_DONE),
+ LASTLABEL
+};
+#endif // !defined(NDEBUG)
+
+XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
+ pctx_(pctx),
+ authNeeded_(true),
+ state_(LOGINSTATE_INIT),
+ pelStanza_(NULL),
+ isStart_(false),
+ iqId_(STR_EMPTY),
+ pelFeatures_(NULL),
+ fullJid_(STR_EMPTY),
+ streamId_(STR_EMPTY),
+ pvecQueuedStanzas_(new std::vector<XmlElement *>()),
+ sasl_mech_(NULL) {
+}
+
+XmppLoginTask::~XmppLoginTask() {
+ for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
+ delete (*pvecQueuedStanzas_)[i];
+}
+
+void
+XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
+ pelStanza_ = element;
+ isStart_ = isStart;
+ Advance();
+ pelStanza_ = NULL;
+ isStart_ = false;
+}
+
+const XmlElement *
+XmppLoginTask::NextStanza() {
+ const XmlElement * result = pelStanza_;
+ pelStanza_ = NULL;
+ return result;
+}
+
+bool
+XmppLoginTask::Advance() {
+
+ for (;;) {
+
+ const XmlElement * element = NULL;
+
+#if !defined(NDEBUG)
+ LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
+ << talk_base::ErrorName(state_, LOGINTASK_STATES);
+#endif // !defined(NDEBUG)
+
+ switch (state_) {
+
+ case LOGINSTATE_INIT: {
+ pctx_->RaiseReset();
+ pelFeatures_.reset(NULL);
+
+ // The proper domain to verify against is the real underlying
+ // domain - i.e., the domain that owns the JID. Our XmppEngineImpl
+ // also allows matching against a proxy domain instead, if it is told
+ // to do so - see the implementation of XmppEngineImpl::StartTls and
+ // XmppEngine::SetTlsServerDomain to see how you can use that feature
+ pctx_->InternalSendStart(pctx_->user_jid_.domain());
+ state_ = LOGINSTATE_STREAMSTART_SENT;
+ break;
+ }
+
+ case LOGINSTATE_STREAMSTART_SENT: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (!isStart_ || !HandleStartStream(element))
+ return Failure(XmppEngine::ERROR_VERSION);
+
+ state_ = LOGINSTATE_STARTED_XMPP;
+ return true;
+ }
+
+ case LOGINSTATE_STARTED_XMPP: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (!HandleFeatures(element))
+ return Failure(XmppEngine::ERROR_VERSION);
+
+ // Use TLS if forced, or if available
+ if (pctx_->tls_needed_ || GetFeature(QN_TLS_STARTTLS) != NULL) {
+ state_ = LOGINSTATE_TLS_INIT;
+ continue;
+ }
+
+ if (authNeeded_) {
+ state_ = LOGINSTATE_AUTH_INIT;
+ continue;
+ }
+
+ state_ = LOGINSTATE_BIND_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_TLS_INIT: {
+ const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
+ if (!pelTls)
+ return Failure(XmppEngine::ERROR_TLS);
+
+ XmlElement el(QN_TLS_STARTTLS, true);
+ pctx_->InternalSendStanza(&el);
+ state_ = LOGINSTATE_TLS_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_TLS_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name() != QN_TLS_PROCEED)
+ return Failure(XmppEngine::ERROR_TLS);
+
+ // The proper domain to verify against is the real underlying
+ // domain - i.e., the domain that owns the JID. Our XmppEngineImpl
+ // also allows matching against a proxy domain instead, if it is told
+ // to do so - see the implementation of XmppEngineImpl::StartTls and
+ // XmppEngine::SetTlsServerDomain to see how you can use that feature
+ pctx_->StartTls(pctx_->user_jid_.domain());
+ pctx_->tls_needed_ = false;
+ state_ = LOGINSTATE_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_AUTH_INIT: {
+ const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
+ if (!pelSaslAuth) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // Collect together the SASL auth mechanisms presented by the server
+ std::vector<std::string> mechanisms;
+ for (const XmlElement * pelMech =
+ pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
+ pelMech;
+ pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
+
+ mechanisms.push_back(pelMech->BodyText());
+ }
+
+ // Given all the mechanisms, choose the best
+ std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
+ if (choice.empty()) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // No recognized auth mechanism - that's an error
+ sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
+ if (sasl_mech_.get() == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ // OK, let's start it.
+ XmlElement * auth = sasl_mech_->StartSaslAuth();
+ if (auth == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+
+ auth->SetAttr(QN_GOOGLE_ALLOW_GENERATED_JID_XMPP_LOGIN, "true");
+ auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
+
+ pctx_->InternalSendStanza(auth);
+ delete auth;
+ state_ = LOGINSTATE_SASL_RUNNING;
+ continue;
+ }
+
+ case LOGINSTATE_SASL_RUNNING: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name().Namespace() != NS_SASL)
+ return Failure(XmppEngine::ERROR_AUTH);
+ if (element->Name() == QN_SASL_CHALLENGE) {
+ XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
+ if (response == NULL) {
+ return Failure(XmppEngine::ERROR_AUTH);
+ }
+ pctx_->InternalSendStanza(response);
+ delete response;
+ state_ = LOGINSTATE_SASL_RUNNING;
+ continue;
+ }
+ if (element->Name() != QN_SASL_SUCCESS) {
+ if (element->FirstNamed(QN_MISSING_USERNAME) != NULL) {
+ return Failure(XmppEngine::ERROR_MISSING_USERNAME);
+ }
+ return Failure(XmppEngine::ERROR_UNAUTHORIZED);
+ }
+
+ // Authenticated!
+ authNeeded_ = false;
+ state_ = LOGINSTATE_INIT;
+ continue;
+ }
+
+ case LOGINSTATE_BIND_INIT: {
+ const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
+ const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
+ if (!pelBindFeature || !pelSessionFeature)
+ return Failure(XmppEngine::ERROR_BIND);
+
+ XmlElement iq(QN_IQ);
+ iq.AddAttr(QN_TYPE, "set");
+
+ iqId_ = pctx_->NextId();
+ iq.AddAttr(QN_ID, iqId_);
+ iq.AddElement(new XmlElement(QN_BIND_BIND, true));
+
+ if (pctx_->requested_resource_ != STR_EMPTY) {
+ iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
+ iq.AddText(pctx_->requested_resource_, 2);
+ }
+ pctx_->InternalSendStanza(&iq);
+ state_ = LOGINSTATE_BIND_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_BIND_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+
+ if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+ element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+ return true;
+
+ if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
+ element->FirstElement()->Name() != QN_BIND_BIND)
+ return Failure(XmppEngine::ERROR_BIND);
+
+ fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
+ if (!fullJid_.IsFull()) {
+ return Failure(XmppEngine::ERROR_BIND);
+ }
+
+ // now request session
+ XmlElement iq(QN_IQ);
+ iq.AddAttr(QN_TYPE, "set");
+
+ iqId_ = pctx_->NextId();
+ iq.AddAttr(QN_ID, iqId_);
+ iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
+ pctx_->InternalSendStanza(&iq);
+
+ state_ = LOGINSTATE_SESSION_REQUESTED;
+ continue;
+ }
+
+ case LOGINSTATE_SESSION_REQUESTED: {
+ if (NULL == (element = NextStanza()))
+ return true;
+ if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+ element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+ return false;
+
+ if (element->Attr(QN_TYPE) != "result")
+ return Failure(XmppEngine::ERROR_BIND);
+
+ pctx_->SignalBound(fullJid_);
+ FlushQueuedStanzas();
+ state_ = LOGINSTATE_DONE;
+ return true;
+ }
+
+ case LOGINSTATE_DONE:
+ return false;
+ }
+ }
+}
+
+bool
+XmppLoginTask::HandleStartStream(const XmlElement *element) {
+
+ if (element->Name() != QN_STREAM_STREAM)
+ return false;
+
+ if (element->Attr(QN_XMLNS) != "jabber:client")
+ return false;
+
+ if (element->Attr(QN_VERSION) != "1.0")
+ return false;
+
+ if (!element->HasAttr(QN_ID))
+ return false;
+
+ streamId_ = element->Attr(QN_ID);
+
+ return true;
+}
+
+bool
+XmppLoginTask::HandleFeatures(const XmlElement *element) {
+ if (element->Name() != QN_STREAM_FEATURES)
+ return false;
+
+ pelFeatures_.reset(new XmlElement(*element));
+ return true;
+}
+
+const XmlElement *
+XmppLoginTask::GetFeature(const QName & name) {
+ return pelFeatures_->FirstNamed(name);
+}
+
+bool
+XmppLoginTask::Failure(XmppEngine::Error reason) {
+ state_ = LOGINSTATE_DONE;
+ pctx_->SignalError(reason, 0);
+ return false;
+}
+
+void
+XmppLoginTask::OutgoingStanza(const XmlElement * element) {
+ XmlElement * pelCopy = new XmlElement(*element);
+ pvecQueuedStanzas_->push_back(pelCopy);
+}
+
+void
+XmppLoginTask::FlushQueuedStanzas() {
+ for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
+ pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
+ delete (*pvecQueuedStanzas_)[i];
+ }
+ pvecQueuedStanzas_->clear();
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmpplogintask.h b/third_party/libjingle/files/talk/xmpp/xmpplogintask.h
new file mode 100644
index 0000000..f6c7d20
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmpplogintask.h
@@ -0,0 +1,100 @@
+/*
+ * 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 _logintask_h_
+#define _logintask_h_
+
+#include <string>
+#include "talk/base/logging.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stl_decl.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/xmppengine.h"
+
+namespace buzz {
+
+class XmlElement;
+class XmppEngineImpl;
+class SaslMechanism;
+
+
+class XmppLoginTask {
+
+public:
+ XmppLoginTask(XmppEngineImpl *pctx);
+ ~XmppLoginTask();
+
+ bool IsDone()
+ { return state_ == LOGINSTATE_DONE; }
+ void IncomingStanza(const XmlElement * element, bool isStart);
+ void OutgoingStanza(const XmlElement *element);
+
+private:
+ enum LoginTaskState {
+ LOGINSTATE_INIT = 0,
+ LOGINSTATE_STREAMSTART_SENT,
+ LOGINSTATE_STARTED_XMPP,
+ LOGINSTATE_TLS_INIT,
+ LOGINSTATE_AUTH_INIT,
+ LOGINSTATE_BIND_INIT,
+ LOGINSTATE_TLS_REQUESTED,
+ LOGINSTATE_SASL_RUNNING,
+ LOGINSTATE_BIND_REQUESTED,
+ LOGINSTATE_SESSION_REQUESTED,
+ LOGINSTATE_DONE,
+ };
+
+ const XmlElement * NextStanza();
+ bool Advance();
+ bool HandleStartStream(const XmlElement * element);
+ bool HandleFeatures(const XmlElement * element);
+ const XmlElement * GetFeature(const QName & name);
+ bool Failure(XmppEngine::Error reason);
+ void FlushQueuedStanzas();
+
+ XmppEngineImpl * pctx_;
+ bool authNeeded_;
+ LoginTaskState state_;
+ const XmlElement * pelStanza_;
+ bool isStart_;
+ std::string iqId_;
+ scoped_ptr<XmlElement> pelFeatures_;
+ Jid fullJid_;
+ std::string streamId_;
+ scoped_ptr<std::vector<XmlElement *,
+ std::allocator<XmlElement *> > > pvecQueuedStanzas_;
+
+ scoped_ptr<SaslMechanism> sasl_mech_;
+
+#if !defined(NDEBUG)
+ static const talk_base::ConstantLabel LOGINTASK_STATES[];
+#endif // !defined(NDEBUG)
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.cc b/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.cc
new file mode 100644
index 0000000..739e6ee4
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.cc
@@ -0,0 +1,104 @@
+/*
+ * 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 <expat.h>
+#include "talk/xmllite/xmlelement.h"
+#include "talk/base/common.h"
+#include "talk/xmpp/xmppstanzaparser.h"
+#include "talk/xmpp/xmppconstants.h"
+
+#define new TRACK_NEW
+
+namespace buzz {
+
+XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) :
+ psph_(psph),
+ innerHandler_(this),
+ parser_(&innerHandler_),
+ depth_(0),
+ builder_() {
+}
+
+void
+XmppStanzaParser::Reset() {
+ parser_.Reset();
+ depth_ = 0;
+ builder_.Reset();
+}
+
+void
+XmppStanzaParser::IncomingStartElement(
+ XmlParseContext * pctx, const char * name, const char ** atts) {
+ if (depth_++ == 0) {
+ XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts);
+ if (pelStream == NULL) {
+ pctx->RaiseError(XML_ERROR_SYNTAX);
+ return;
+ }
+ psph_->StartStream(pelStream);
+ delete pelStream;
+ return;
+ }
+
+ builder_.StartElement(pctx, name, atts);
+}
+
+void
+XmppStanzaParser::IncomingCharacterData(
+ XmlParseContext * pctx, const char * text, int len) {
+ if (depth_ > 1) {
+ builder_.CharacterData(pctx, text, len);
+ }
+}
+
+void
+XmppStanzaParser::IncomingEndElement(
+ XmlParseContext * pctx, const char * name) {
+ if (--depth_ == 0) {
+ psph_->EndStream();
+ return;
+ }
+
+ builder_.EndElement(pctx, name);
+
+ if (depth_ == 1) {
+ XmlElement *element = builder_.CreateElement();
+ psph_->Stanza(element);
+ delete element;
+ }
+}
+
+void
+XmppStanzaParser::IncomingError(
+ XmlParseContext * pctx, XML_Error errCode) {
+ UNUSED(pctx);
+ UNUSED(errCode);
+ psph_->XmlError();
+}
+
+}
+
diff --git a/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.h b/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.h
new file mode 100644
index 0000000..1e109a3
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmppstanzaparser.h
@@ -0,0 +1,96 @@
+/*
+ * 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 _xmppstanzaparser_h_
+#define _xmppstanzaparser_h_
+
+#include "talk/xmllite/xmlparser.h"
+#include "talk/xmllite/xmlbuilder.h"
+
+
+namespace buzz {
+
+class XmlElement;
+
+class XmppStanzaParseHandler {
+public:
+ virtual void StartStream(const XmlElement * pelStream) = 0;
+ virtual void Stanza(const XmlElement * pelStanza) = 0;
+ virtual void EndStream() = 0;
+ virtual void XmlError() = 0;
+};
+
+class XmppStanzaParser {
+public:
+ XmppStanzaParser(XmppStanzaParseHandler *psph);
+ bool Parse(const char * data, size_t len, bool isFinal)
+ { return parser_.Parse(data, len, isFinal); }
+ void Reset();
+
+private:
+ class ParseHandler : public XmlParseHandler {
+ public:
+ ParseHandler(XmppStanzaParser * outer) : outer_(outer) {}
+ virtual void StartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts)
+ { outer_->IncomingStartElement(pctx, name, atts); }
+ virtual void EndElement(XmlParseContext * pctx,
+ const char * name)
+ { outer_->IncomingEndElement(pctx, name); }
+ virtual void CharacterData(XmlParseContext * pctx,
+ const char * text, int len)
+ { outer_->IncomingCharacterData(pctx, text, len); }
+ virtual void Error(XmlParseContext * pctx,
+ XML_Error errCode)
+ { outer_->IncomingError(pctx, errCode); }
+ private:
+ XmppStanzaParser * const outer_;
+ };
+
+ friend class ParseHandler;
+
+ void IncomingStartElement(XmlParseContext * pctx,
+ const char * name, const char ** atts);
+ void IncomingEndElement(XmlParseContext * pctx,
+ const char * name);
+ void IncomingCharacterData(XmlParseContext * pctx,
+ const char * text, int len);
+ void IncomingError(XmlParseContext * pctx,
+ XML_Error errCode);
+
+ XmppStanzaParseHandler * psph_;
+ ParseHandler innerHandler_;
+ XmlParser parser_;
+ int depth_;
+ XmlBuilder builder_;
+
+ };
+
+
+}
+
+#endif
diff --git a/third_party/libjingle/files/talk/xmpp/xmpptask.cc b/third_party/libjingle/files/talk/xmpp/xmpptask.cc
new file mode 100644
index 0000000..fe8aebe
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmpptask.cc
@@ -0,0 +1,174 @@
+/*
+ * 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 "talk/xmpp/xmpptask.h"
+#include "talk/xmpp/xmppclient.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmppconstants.h"
+#include "talk/xmpp/ratelimitmanager.h"
+
+namespace buzz {
+
+RateLimitManager task_rate_manager;
+
+XmppTask::XmppTask(Task* parent, XmppEngine::HandlerLevel level)
+ : Task(parent), client_(NULL) {
+#if !defined(NDEBUG)
+ debug_force_timeout_ = false;
+#endif
+
+ XmppClient* client = (XmppClient*)parent->GetParent(XMPP_CLIENT_TASK_CODE);
+ client_ = client;
+ id_ = client->NextId();
+ client->AddXmppTask(this, level);
+ client->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
+}
+
+XmppTask::~XmppTask() {
+ StopImpl();
+}
+
+void XmppTask::StopImpl() {
+ while (NextStanza() != NULL) {}
+ if (client_) {
+ client_->RemoveXmppTask(this);
+ client_->SignalDisconnected.disconnect(this);
+ client_ = NULL;
+ }
+}
+
+XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) {
+ if (client_ == NULL)
+ return XMPP_RETURN_BADSTATE;
+ return client_->SendStanza(stanza);
+}
+
+XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original,
+ XmppStanzaError code,
+ const std::string& text) {
+ if (client_ == NULL)
+ return XMPP_RETURN_BADSTATE;
+ return client_->SendStanzaError(element_original, code, text);
+}
+
+void XmppTask::Stop() {
+ StopImpl();
+ Task::Stop();
+}
+
+void XmppTask::OnDisconnect() {
+ Error();
+}
+
+void XmppTask::QueueStanza(const XmlElement* stanza) {
+#if !defined(NDEBUG)
+ if (debug_force_timeout_)
+ return;
+#endif
+
+ stanza_queue_.push_back(new XmlElement(*stanza));
+ Wake();
+}
+
+const XmlElement* XmppTask::NextStanza() {
+ XmlElement* result = NULL;
+ if (!stanza_queue_.empty()) {
+ result = stanza_queue_.front();
+ stanza_queue_.pop_front();
+ }
+ next_stanza_.reset(result);
+ return result;
+}
+
+XmlElement* XmppTask::MakeIq(const std::string& type,
+ const buzz::Jid& to,
+ const std::string id) {
+ XmlElement* result = new XmlElement(QN_IQ);
+ if (!type.empty())
+ result->AddAttr(QN_TYPE, type);
+ if (to != JID_EMPTY)
+ result->AddAttr(QN_TO, to.Str());
+ if (!id.empty())
+ result->AddAttr(QN_ID, id);
+ return result;
+}
+
+XmlElement* XmppTask::MakeIqResult(const XmlElement * query) {
+ XmlElement* result = new XmlElement(QN_IQ);
+ result->AddAttr(QN_TYPE, STR_RESULT);
+ if (query->HasAttr(QN_FROM)) {
+ result->AddAttr(QN_TO, query->Attr(QN_FROM));
+ }
+ result->AddAttr(QN_ID, query->Attr(QN_ID));
+ return result;
+}
+
+bool XmppTask::MatchResponseIq(const XmlElement* stanza,
+ const Jid& to,
+ const std::string& id) {
+ if (stanza->Name() != QN_IQ)
+ return false;
+
+ if (stanza->Attr(QN_ID) != id)
+ return false;
+
+ Jid from(stanza->Attr(QN_FROM));
+ if (from == to)
+ return true;
+
+ // We address the server as "", check if we are doing so here.
+ if (to != JID_EMPTY)
+ return false;
+
+ // It is legal for the server to identify itself with "domain" or
+ // "myself@domain"
+ Jid me = client_->jid();
+ return (from == Jid(me.domain())) || (from == me.BareJid());
+}
+
+bool XmppTask::MatchRequestIq(const XmlElement* stanza,
+ const std::string& type,
+ const QName& qn) {
+ if (stanza->Name() != QN_IQ)
+ return false;
+
+ if (stanza->Attr(QN_TYPE) != type)
+ return false;
+
+ if (stanza->FirstNamed(qn) == NULL)
+ return false;
+
+ return true;
+}
+
+bool XmppTask::VerifyTaskRateLimit(const std::string task_name, int max_count,
+ int per_x_seconds) {
+ return task_rate_manager.VerifyRateLimit(task_name, max_count,
+ per_x_seconds);
+}
+
+}
diff --git a/third_party/libjingle/files/talk/xmpp/xmpptask.h b/third_party/libjingle/files/talk/xmpp/xmpptask.h
new file mode 100644
index 0000000..d92c123
--- /dev/null
+++ b/third_party/libjingle/files/talk/xmpp/xmpptask.h
@@ -0,0 +1,130 @@
+/*
+ * 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 _XMPPTASK_H_
+#define _XMPPTASK_H_
+
+#include <string>
+#include <deque>
+#include "talk/base/sigslot.h"
+#include "talk/xmpp/xmppengine.h"
+#include "talk/base/task.h"
+
+namespace buzz {
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPTASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task and XmppClient first.
+//
+// XmppTask is a task that is designed to go underneath XmppClient and be
+// useful there. It has a way of finding its XmppClient parent so you
+// can have it nested arbitrarily deep under an XmppClient and it can
+// still find the XMPP services.
+//
+// Tasks register themselves to listen to particular kinds of stanzas
+// that are sent out by the client. Rather than processing stanzas
+// right away, they should decide if they own the sent stanza,
+// and if so, queue it and Wake() the task, or if a stanza does not belong
+// to you, return false right away so the next XmppTask can take a crack.
+// This technique (synchronous recognize, but asynchronous processing)
+// allows you to have arbitrary logic for recognizing stanzas yet still,
+// for example, disconnect a client while processing a stanza -
+// without reentrancy problems.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient;
+
+class XmppTask :
+ public talk_base::Task,
+ public XmppStanzaHandler,
+ public sigslot::has_slots<>
+{
+ public:
+ XmppTask(talk_base::Task* parent,
+ XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
+ virtual ~XmppTask();
+
+ virtual XmppClient* GetClient() const { return client_; }
+ std::string task_id() const { return id_; }
+ void set_task_id(std::string id) { id_ = id; }
+
+#if !defined(NDEBUG)
+ void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; }
+#endif
+
+ protected:
+ friend class XmppClient;
+
+ XmppReturnStatus SendStanza(const XmlElement* stanza);
+ XmppReturnStatus SetResult(const std::string& code);
+ XmppReturnStatus SendStanzaError(const XmlElement* element_original,
+ XmppStanzaError code,
+ const std::string& text);
+
+ virtual void Stop();
+ virtual bool HandleStanza(const XmlElement* stanza) { return false; }
+ virtual void OnDisconnect();
+ virtual int ProcessReponse() { return STATE_DONE; }
+
+ virtual void QueueStanza(const XmlElement* stanza);
+ const XmlElement* NextStanza();
+
+ bool MatchResponseIq(const XmlElement* stanza, const Jid& to,
+ const std::string& task_id);
+
+ bool MatchRequestIq(const XmlElement* stanza, const std::string& type,
+ const QName& qn);
+ static XmlElement *MakeIqResult(const XmlElement* query);
+ static XmlElement *MakeIq(const std::string& type,
+ const Jid& to, const std::string task_id);
+
+ // Returns true if the task is under the specified rate limit and updates the
+ // rate limit accordingly
+ bool VerifyTaskRateLimit(const std::string task_name, int max_count,
+ int per_x_seconds);
+
+private:
+ void StopImpl();
+
+ XmppClient* client_;
+ std::deque<XmlElement*> stanza_queue_;
+ scoped_ptr<XmlElement> next_stanza_;
+ std::string id_;
+
+#if !defined(NDEBUG)
+ bool debug_force_timeout_;
+#endif
+};
+
+}
+
+#endif
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index bcf8eb8..9473385 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -9,28 +9,23 @@
'FEATURE_ENABLE_VOICEMAIL', # TODO(ncarter): Do we really need this?
'_USE_32BIT_TIME_T',
'SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS',
- 'EXPAT_RELATIVE_PATH',
],
'include_dirs': [
'./overrides',
- './source',
- '../../third_party/expat/files'
+ './files',
],
'dependencies': [
'../expat/expat.gyp:expat',
'../../base/base.gyp:base',
- '../../net/net.gyp:net_base',
],
'direct_dependent_settings': {
'include_dirs': [
'./overrides',
- './source',
- '../../third_party/expat/files'
+ './files',
],
'defines': [
'FEATURE_ENABLE_SSL',
'FEATURE_ENABLE_VOICEMAIL',
- 'EXPAT_RELATIVE_PATH',
],
'conditions': [
['OS=="win"', {
@@ -38,67 +33,22 @@
'libraries': [
'-lsecur32.lib',
'-lcrypt32.lib',
- '-liphlpapi.lib',
],
},
}],
- ['OS=="win"', {
- 'include_dirs': [
- '../third_party/platformsdk_win7/files/Include',
- ],
- 'defines': [
- '_CRT_SECURE_NO_WARNINGS', # Suppres warnings about _vsnprinf
- ],
- }],
- ['OS=="linux"', {
- 'defines': [
- 'LINUX',
- ],
- }],
- ['OS=="mac"', {
- 'defines': [
- 'OSX',
- ],
- }],
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
'defines': [
'POSIX',
],
}],
- ['OS=="openbsd" or OS=="freebsd"', {
- 'defines': [
- 'BSD',
- ],
- }],
],
},
- 'all_dependent_settings': {
- 'configurations': {
- 'Debug': {
- 'defines': [
- # TODO(sergeyu): Fix libjingle to use NDEBUG instead of
- # _DEBUG and remove this define.
- '_DEBUG',
- ],
- }
- },
- },
'conditions': [
['OS=="win"', {
'include_dirs': [
'../third_party/platformsdk_win7/files/Include',
],
}],
- ['OS=="linux"', {
- 'defines': [
- 'LINUX',
- ],
- }],
- ['OS=="mac"', {
- 'defines': [
- 'OSX',
- ],
- }],
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
'defines': [
'POSIX',
@@ -116,288 +66,183 @@
'target_name': 'libjingle',
'type': '<(library)',
'sources': [
+
+ # everything in files/talk/p2p is unneeded and has been removed
+ # 'files/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h', # openssl
+ # 'files/talk/base/basictypes.h', # overridden
+ # 'files/talk/base/natserver_main.cc', # has a main()
+ # 'files/talk/base/openssladapter.cc', # openssl
+ # 'files/talk/base/openssladapter.h', # openssl
+ # 'files/talk/base/winsock_initializer.cc', # overridden
+ 'files/talk/base/asynchttprequest.cc',
+ 'files/talk/base/asynchttprequest.h',
+ 'files/talk/base/asyncpacketsocket.cc',
+ 'files/talk/base/asyncpacketsocket.h',
+ 'files/talk/base/asynctcpsocket.h',
+ 'files/talk/base/asynctcpsocket.cc',
+ 'files/talk/base/asyncudpsocket.cc',
+ 'files/talk/base/asyncudpsocket.h',
+ 'files/talk/base/autodetectproxy.cc',
+ 'files/talk/base/autodetectproxy.h',
+ 'files/talk/base/base64.cc',
+ 'files/talk/base/base64.h',
+ 'files/talk/base/basicdefs.h',
+ 'files/talk/base/bytebuffer.cc',
+ 'files/talk/base/bytebuffer.h',
+ 'files/talk/base/common.cc',
+ 'files/talk/base/common.h',
+ 'files/talk/base/criticalsection.h',
+ 'files/talk/base/cryptstring.h',
+ 'files/talk/base/diskcache.cc',
+ 'files/talk/base/diskcache.h',
+ 'files/talk/base/diskcachestd.cc',
+ 'files/talk/base/diskcachestd.h',
+ 'files/talk/base/fileutils.cc',
+ 'files/talk/base/fileutils.h',
+ 'files/talk/base/firewallsocketserver.cc',
+ 'files/talk/base/firewallsocketserver.h',
+ 'files/talk/base/helpers.cc',
+ 'files/talk/base/helpers.h',
+ 'files/talk/base/host.cc',
+ 'files/talk/base/host.h',
+ 'files/talk/base/httpbase.cc',
+ 'files/talk/base/httpbase.h',
+ 'files/talk/base/httpclient.cc',
+ 'files/talk/base/httpclient.h',
+ 'files/talk/base/httpcommon-inl.h',
+ 'files/talk/base/httpcommon.cc',
+ 'files/talk/base/httpcommon.h',
+ 'files/talk/base/httpserver.cc',
+ 'files/talk/base/httpserver.h',
+ 'files/talk/base/logging.cc',
+ 'files/talk/base/logging.h',
+ 'files/talk/base/md5c.c',
+ 'files/talk/base/md5c.h',
+ 'files/talk/base/messagequeue.cc',
+ 'files/talk/base/messagequeue.h',
+ 'files/talk/base/natserver.cc',
+ 'files/talk/base/natserver.h',
+ 'files/talk/base/natsocketfactory.cc',
+ 'files/talk/base/natsocketfactory.h',
+ 'files/talk/base/nattypes.cc',
+ 'files/talk/base/nattypes.h',
+ 'files/talk/base/network.cc',
+ 'files/talk/base/network.h',
+ 'files/talk/base/pathutils.cc',
+ 'files/talk/base/pathutils.h',
+ 'files/talk/base/physicalsocketserver.cc',
+ 'files/talk/base/physicalsocketserver.h',
+ 'files/talk/base/proxydetect.cc',
+ 'files/talk/base/proxydetect.h',
+ 'files/talk/base/proxyinfo.cc',
+ 'files/talk/base/proxyinfo.h',
+ 'files/talk/base/signalthread.cc',
+ 'files/talk/base/signalthread.h',
+ 'files/talk/base/socketadapters.cc',
+ 'files/talk/base/socketadapters.h',
+ 'files/talk/base/socketaddress.cc',
+ 'files/talk/base/socketaddress.h',
+ 'files/talk/base/socketaddresspair.cc',
+ 'files/talk/base/socketaddresspair.h',
+ 'files/talk/base/socketfactory.h',
+ 'files/talk/base/socketpool.cc',
+ 'files/talk/base/socketpool.h',
+ 'files/talk/base/socketserver.h',
+ 'files/talk/base/socketstream.h',
+ 'files/talk/base/ssladapter.cc',
+ 'files/talk/base/ssladapter.h',
+ 'files/talk/base/stl_decl.h',
+ 'files/talk/base/stream.cc',
+ 'files/talk/base/stream.h',
+ 'files/talk/base/streamutils.cc',
+ 'files/talk/base/streamutils.h',
+ 'files/talk/base/stringdigest.cc',
+ 'files/talk/base/stringdigest.h',
+ 'files/talk/base/stringencode.cc',
+ 'files/talk/base/stringencode.h',
+ 'files/talk/base/stringutils.cc',
+ 'files/talk/base/stringutils.h',
+ 'files/talk/base/tarstream.cc',
+ 'files/talk/base/tarstream.h',
+ 'files/talk/base/task.cc',
+ 'files/talk/base/task.h',
+ 'files/talk/base/taskrunner.cc',
+ 'files/talk/base/taskrunner.h',
+ 'files/talk/base/testclient.cc',
+ 'files/talk/base/testclient.h',
+ 'files/talk/base/thread.cc',
+ 'files/talk/base/thread.h',
+ 'files/talk/base/time.cc',
+ 'files/talk/base/time.h',
+ 'files/talk/base/urlencode.cc',
+ 'files/talk/base/urlencode.h',
+ 'files/talk/base/virtualsocketserver.cc',
+ 'files/talk/base/virtualsocketserver.h',
+ 'files/talk/base/winsock_initializer.h',
+ 'files/talk/xmllite/qname.cc',
+ 'files/talk/xmllite/qname.h',
+ 'files/talk/xmllite/xmlbuilder.cc',
+ 'files/talk/xmllite/xmlbuilder.h',
+ 'files/talk/xmllite/xmlconstants.cc',
+ 'files/talk/xmllite/xmlconstants.h',
+ 'files/talk/xmllite/xmlelement.cc',
+ 'files/talk/xmllite/xmlelement.h',
+ 'files/talk/xmllite/xmlnsstack.cc',
+ 'files/talk/xmllite/xmlnsstack.h',
+ 'files/talk/xmllite/xmlparser.cc',
+ 'files/talk/xmllite/xmlparser.h',
+ 'files/talk/xmllite/xmlprinter.cc',
+ 'files/talk/xmllite/xmlprinter.h',
+ 'files/talk/xmpp/jid.cc',
+ 'files/talk/xmpp/jid.h',
+ 'files/talk/xmpp/ratelimitmanager.cc',
+ 'files/talk/xmpp/ratelimitmanager.h',
+ 'files/talk/xmpp/saslmechanism.cc',
+ 'files/talk/xmpp/saslmechanism.h',
+ 'files/talk/xmpp/xmppclient.cc',
+ 'files/talk/xmpp/xmppclient.h',
+ 'files/talk/xmpp/xmppconstants.cc',
+ 'files/talk/xmpp/xmppconstants.h',
+ 'files/talk/xmpp/xmppengineimpl.cc',
+ 'files/talk/xmpp/xmppengineimpl.h',
+ 'files/talk/xmpp/xmppengineimpl_iq.cc',
+ 'files/talk/xmpp/xmppengineimpl_iq.h',
+ 'files/talk/xmpp/xmpplogintask.cc',
+ 'files/talk/xmpp/xmpplogintask.h',
+ 'files/talk/xmpp/xmppstanzaparser.cc',
+ 'files/talk/xmpp/xmppstanzaparser.h',
+ 'files/talk/xmpp/xmpptask.cc',
+ 'files/talk/xmpp/xmpptask.h',
'overrides/talk/base/basictypes.h',
'overrides/talk/base/constructormagic.h',
-
- # Need to override logging.h because we need
- # SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS to work.
- # TODO(sergeyu): push SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS to
- # libjingle and remove this override.
- 'overrides/talk/base/logging.h',
-
'overrides/talk/base/scoped_ptr.h',
-
- # Libjingle's QName is not threadsafe, so we need to use our own version
- # here.
- # TODO(sergeyu): Fix QName in Libjingle.
- 'overrides/talk/xmllite/qname.cc',
- 'overrides/talk/xmllite/qname.h',
-
- 'source/talk/base/DiskCacheStd.h',
- 'source/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h',
- 'source/talk/base/asyncfile.h',
- 'source/talk/base/asynchttprequest.cc',
- 'source/talk/base/asynchttprequest.h',
- 'source/talk/base/asyncpacketsocket.cc',
- 'source/talk/base/asyncpacketsocket.h',
- 'source/talk/base/asyncsocket.h',
- 'source/talk/base/asynctcpsocket.cc',
- 'source/talk/base/asynctcpsocket.h',
- 'source/talk/base/asyncudpsocket.cc',
- 'source/talk/base/asyncudpsocket.h',
- 'source/talk/base/autodetectproxy.cc',
- 'source/talk/base/autodetectproxy.h',
- 'source/talk/base/base64.cc',
- 'source/talk/base/base64.h',
- 'source/talk/base/basicdefs.h',
- 'source/talk/base/bytebuffer.cc',
- 'source/talk/base/bytebuffer.h',
- 'source/talk/base/byteorder.h',
- 'source/talk/base/checks.cc',
- 'source/talk/base/checks.h',
- 'source/talk/base/common.cc',
- 'source/talk/base/common.h',
- 'source/talk/base/criticalsection.h',
- 'source/talk/base/cryptstring.h',
- 'source/talk/base/diskcache.cc',
- 'source/talk/base/diskcache.h',
- 'source/talk/base/event.cc',
- 'source/talk/base/event.h',
- 'source/talk/base/fakenetwork.h',
- 'source/talk/base/fileutils.cc',
- 'source/talk/base/fileutils.h',
- 'source/talk/base/fileutils_mock.h',
- 'source/talk/base/firewallsocketserver.cc',
- 'source/talk/base/firewallsocketserver.h',
- 'source/talk/base/flags.cc',
- 'source/talk/base/flags.h',
- 'source/talk/base/hash.h',
- 'source/talk/base/helpers.cc',
- 'source/talk/base/helpers.h',
- 'source/talk/base/host.cc',
- 'source/talk/base/host.h',
- 'source/talk/base/httpbase.cc',
- 'source/talk/base/httpbase.h',
- 'source/talk/base/httpclient.h',
- 'source/talk/base/httpclient.cc',
- 'source/talk/base/httpcommon-inl.h',
- 'source/talk/base/httpcommon.cc',
- 'source/talk/base/httpcommon.h',
- 'source/talk/base/httprequest.cc',
- 'source/talk/base/httprequest.h',
- 'source/talk/base/icftypes.h',
- 'source/talk/base/linked_ptr.h',
- 'source/talk/base/logging.cc',
- 'source/talk/base/md5.h',
- 'source/talk/base/md5c.c',
- 'source/talk/base/messagehandler.cc',
- 'source/talk/base/messagehandler.h',
- 'source/talk/base/messagequeue.cc',
- 'source/talk/base/messagequeue.h',
- 'source/talk/base/netfw.h',
- 'source/talk/base/nethelpers.cc',
- 'source/talk/base/nethelpers.h',
- 'source/talk/base/network.cc',
- 'source/talk/base/network.h',
- 'source/talk/base/pathutils.cc',
- 'source/talk/base/pathutils.h',
- 'source/talk/base/physicalsocketserver.cc',
- 'source/talk/base/physicalsocketserver.h',
- 'source/talk/base/proxydetect.cc',
- 'source/talk/base/proxydetect.h',
- 'source/talk/base/proxyinfo.cc',
- 'source/talk/base/proxyinfo.h',
- 'source/talk/base/sec_buffer.h',
- 'source/talk/base/signalthread.cc',
- 'source/talk/base/signalthread.h',
- 'source/talk/base/sigslot.h',
- 'source/talk/base/sigslotrepeater.h',
- 'source/talk/base/socket.h',
- 'source/talk/base/socketadapters.cc',
- 'source/talk/base/socketadapters.h',
- 'source/talk/base/socketaddress.cc',
- 'source/talk/base/socketaddress.h',
- 'source/talk/base/socketfactory.h',
- 'source/talk/base/socketpool.cc',
- 'source/talk/base/socketpool.h',
- 'source/talk/base/socketserver.h',
- 'source/talk/base/socketstream.h',
- 'source/talk/base/ssladapter.cc',
- 'source/talk/base/ssladapter.h',
- 'source/talk/base/sslsocketfactory.cc',
- 'source/talk/base/sslsocketfactory.h',
- 'source/talk/base/stream.cc',
- 'source/talk/base/stream.h',
- 'source/talk/base/stringdigest.cc',
- 'source/talk/base/stringdigest.h',
- 'source/talk/base/stringencode.cc',
- 'source/talk/base/stringencode.h',
- 'source/talk/base/stringutils.cc',
- 'source/talk/base/stringutils.h',
- 'source/talk/base/task.cc',
- 'source/talk/base/task.h',
- 'source/talk/base/taskparent.cc',
- 'source/talk/base/taskparent.h',
- 'source/talk/base/taskrunner.cc',
- 'source/talk/base/taskrunner.h',
- 'source/talk/base/thread.cc',
- 'source/talk/base/thread.h',
- 'source/talk/base/time.cc',
- 'source/talk/base/time.h',
- 'source/talk/base/urlencode.cc',
- 'source/talk/base/urlencode.h',
- 'source/talk/xmllite/xmlbuilder.cc',
- 'source/talk/xmllite/xmlbuilder.h',
- 'source/talk/xmllite/xmlconstants.cc',
- 'source/talk/xmllite/xmlconstants.h',
- 'source/talk/xmllite/xmlelement.cc',
- 'source/talk/xmllite/xmlelement.h',
- 'source/talk/xmllite/xmlnsstack.cc',
- 'source/talk/xmllite/xmlnsstack.h',
- 'source/talk/xmllite/xmlparser.cc',
- 'source/talk/xmllite/xmlparser.h',
- 'source/talk/xmllite/xmlprinter.cc',
- 'source/talk/xmllite/xmlprinter.h',
- 'source/talk/xmpp/asyncsocket.h',
- 'source/talk/xmpp/constants.cc',
- 'source/talk/xmpp/constants.h',
- 'source/talk/xmpp/jid.cc',
- 'source/talk/xmpp/jid.h',
- 'source/talk/xmpp/plainsaslhandler.h',
- 'source/talk/xmpp/prexmppauth.h',
- 'source/talk/xmpp/ratelimitmanager.cc',
- 'source/talk/xmpp/ratelimitmanager.h',
- 'source/talk/xmpp/saslcookiemechanism.h',
- 'source/talk/xmpp/saslhandler.h',
- 'source/talk/xmpp/saslmechanism.cc',
- 'source/talk/xmpp/saslmechanism.h',
- 'source/talk/xmpp/saslplainmechanism.h',
- 'source/talk/xmpp/xmppclient.cc',
- 'source/talk/xmpp/xmppclient.h',
- 'source/talk/xmpp/xmppclientsettings.h',
- 'source/talk/xmpp/xmppengine.h',
- 'source/talk/xmpp/xmppengineimpl.cc',
- 'source/talk/xmpp/xmppengineimpl.h',
- 'source/talk/xmpp/xmppengineimpl_iq.cc',
- 'source/talk/xmpp/xmpplogintask.cc',
- 'source/talk/xmpp/xmpplogintask.h',
- 'source/talk/xmpp/xmppstanzaparser.cc',
- 'source/talk/xmpp/xmppstanzaparser.h',
- 'source/talk/xmpp/xmpptask.cc',
- 'source/talk/xmpp/xmpptask.h',
+ 'overrides/config.h',
],
'conditions': [
['OS=="win"', {
'sources': [
- 'overrides/talk/base/win32socketinit.cc',
- 'source/talk/base/convert.h', # win32 only
- 'source/talk/base/schanneladapter.cc',
- 'source/talk/base/schanneladapter.h',
- 'source/talk/base/win32.h',
- 'source/talk/base/win32.cc',
- 'source/talk/base/win32filesystem.cc',
- 'source/talk/base/win32filesystem.h',
- 'source/talk/base/win32window.h',
- 'source/talk/base/win32window.cc',
- 'source/talk/base/win32securityerrors.cc',
- 'source/talk/base/winfirewall.cc',
- 'source/talk/base/winfirewall.h',
- 'source/talk/base/winping.cc',
- 'source/talk/base/winping.h',
+ 'files/talk/base/convert.h', # win32 only
+ 'files/talk/base/diskcache_win32.cc', # win32 only
+ 'files/talk/base/diskcache_win32.h', # win32 only
+ 'files/talk/base/schanneladapter.cc',
+ 'files/talk/base/schanneladapter.h',
+ 'files/talk/base/win32.h',
+ 'files/talk/base/win32filesystem.cc',
+ 'files/talk/base/win32filesystem.h',
+ 'files/talk/base/win32window.h',
+ 'files/talk/base/win32window.cc',
+ 'files/talk/base/winfirewall.cc',
+ 'files/talk/base/winfirewall.h',
+ 'files/talk/base/winping.cc',
+ 'files/talk/base/winping.h',
+ 'overrides/talk/base/winsock_initializer.cc',
],
}],
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
'sources': [
- 'source/talk/base/sslstreamadapter.cc',
- 'source/talk/base/sslstreamadapter.h',
- 'source/talk/base/unixfilesystem.cc',
- 'source/talk/base/unixfilesystem.h',
- ],
- }],
- ['OS=="linux"', {
- 'sources': [
- 'source/talk/base/linux.cc',
- 'source/talk/base/linux.h',
+ 'files/talk/base/unixfilesystem.cc',
],
}],
- ['OS=="mac"', {
- 'sources': [
- 'source/talk/base/macconversion.cc',
- 'source/talk/base/macconversion.h',
- 'source/talk/base/macutils.cc',
- 'source/talk/base/macutils.h',
- ],
- }],
- ],
- },
- # This has to be is a separate project due to a bug in MSVS:
- # https://connect.microsoft.com/VisualStudio/feedback/details/368272/duplicate-cpp-filename-in-c-project-visual-studio-2008
- # We have two files named "constants.cc" and MSVS doesn't handle this
- # properly.
- {
- 'target_name': 'libjingle_p2p',
- 'type': '<(library)',
- 'sources': [
- 'source/talk/p2p/base/candidate.h',
- 'source/talk/p2p/base/common.h',
- 'source/talk/p2p/base/constants.cc',
- 'source/talk/p2p/base/constants.h',
- 'source/talk/p2p/base/p2ptransport.cc',
- 'source/talk/p2p/base/p2ptransport.h',
- 'source/talk/p2p/base/p2ptransportchannel.cc',
- 'source/talk/p2p/base/p2ptransportchannel.h',
- 'source/talk/p2p/base/port.cc',
- 'source/talk/p2p/base/port.h',
- 'source/talk/p2p/base/portallocator.h',
- 'source/talk/p2p/base/pseudotcp.cc',
- 'source/talk/p2p/base/pseudotcp.h',
- 'source/talk/p2p/base/rawtransport.cc',
- 'source/talk/p2p/base/rawtransport.h',
- 'source/talk/p2p/base/rawtransportchannel.cc',
- 'source/talk/p2p/base/rawtransportchannel.h',
- 'source/talk/p2p/base/relayport.cc',
- 'source/talk/p2p/base/relayport.h',
- 'source/talk/p2p/base/session.cc',
- 'source/talk/p2p/base/session.h',
- 'source/talk/p2p/base/sessionclient.h',
- 'source/talk/p2p/base/sessiondescription.h',
- 'source/talk/p2p/base/sessionid.h',
- 'source/talk/p2p/base/sessionmanager.cc',
- 'source/talk/p2p/base/sessionmanager.h',
- 'source/talk/p2p/base/stun.cc',
- 'source/talk/p2p/base/stun.h',
- 'source/talk/p2p/base/stunport.cc',
- 'source/talk/p2p/base/stunport.h',
- 'source/talk/p2p/base/stunrequest.cc',
- 'source/talk/p2p/base/stunrequest.h',
- 'source/talk/p2p/base/tcpport.cc',
- 'source/talk/p2p/base/tcpport.h',
- 'source/talk/p2p/base/transport.cc',
- 'source/talk/p2p/base/transport.h',
- 'source/talk/p2p/base/transportchannel.cc',
- 'source/talk/p2p/base/transportchannel.h',
- 'source/talk/p2p/base/transportchannelimpl.h',
- 'source/talk/p2p/base/transportchannelproxy.cc',
- 'source/talk/p2p/base/transportchannelproxy.h',
- 'source/talk/p2p/base/udpport.cc',
- 'source/talk/p2p/base/udpport.h',
- 'source/talk/p2p/client/basicportallocator.cc',
- 'source/talk/p2p/client/basicportallocator.h',
- 'source/talk/p2p/client/httpportallocator.cc',
- 'source/talk/p2p/client/httpportallocator.h',
- 'source/talk/p2p/client/sessionmanagertask.h',
- 'source/talk/p2p/client/sessionsendtask.h',
- 'source/talk/p2p/client/socketmonitor.cc',
- 'source/talk/p2p/client/socketmonitor.h',
- 'source/talk/session/tunnel/pseudotcpchannel.cc',
- 'source/talk/session/tunnel/pseudotcpchannel.h',
- 'source/talk/session/tunnel/securetunnelsessionclient.cc',
- 'source/talk/session/tunnel/securetunnelsessionclient.h',
- 'source/talk/session/tunnel/tunnelsessionclient.cc',
- 'source/talk/session/tunnel/tunnelsessionclient.h',
- ],
- 'dependencies': [
- 'libjingle',
],
},
],
diff --git a/third_party/libjingle/overrides/talk/base/basictypes.h b/third_party/libjingle/overrides/talk/base/basictypes.h
index d6f90cf..9de73d4 100644
--- a/third_party/libjingle/overrides/talk/base/basictypes.h
+++ b/third_party/libjingle/overrides/talk/base/basictypes.h
@@ -44,10 +44,6 @@ typedef int socklen_t;
namespace talk_base {
template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
-
-// For wait functions that take a number of milliseconds, kForever indicates
-// unlimited time.
-const int kForever = -1;
}
#endif // OVERRIDES_TALK_BASE_BASICTYPES_H__
diff --git a/third_party/libjingle/overrides/talk/base/win32socketinit.cc b/third_party/libjingle/overrides/talk/base/winsock_initializer.cc
index 2a05f02..7e1858a 100644
--- a/third_party/libjingle/overrides/talk/base/win32socketinit.cc
+++ b/third_party/libjingle/overrides/talk/base/winsock_initializer.cc
@@ -5,7 +5,7 @@
// Redirect Libjingle's winsock initialization activity into Chromium's
// singleton object that managest precisely that for the browser.
-#include "talk/base/win32socketinit.h"
+#include "talk/base/winsock_initializer.h"
#include "net/base/winsock_init.h"
diff --git a/third_party/libjingle/overrides/talk/xmllite/qname.cc b/third_party/libjingle/overrides/talk/xmllite/qname.cc
deleted file mode 100644
index 5c9e62d..0000000
--- a/third_party/libjingle/overrides/talk/xmllite/qname.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "talk/xmllite/qname.h"
-
-#include "talk/base/common.h"
-#include "talk/xmllite/xmlelement.h"
-#include "talk/xmllite/xmlconstants.h"
-
-namespace buzz {
-
-QName::QName() : namespace_(QN_EMPTY.namespace_),
- local_part_(QN_EMPTY.local_part_) {}
-
-QName::QName(const std::string & ns, const std::string & local) :
- namespace_(ns), local_part_(local) {}
-
-QName::QName(bool add, const std::string & ns, const std::string & local) :
- namespace_(ns), local_part_(local) {}
-
-static std::string
-QName_LocalPart(const std::string & name) {
- size_t i = name.rfind(':');
- if (i == std::string::npos)
- return name;
- return name.substr(i + 1);
-}
-
-static std::string
-QName_Namespace(const std::string & name) {
- size_t i = name.rfind(':');
- if (i == std::string::npos)
- return STR_EMPTY;
- return name.substr(0, i);
-}
-
-QName::QName(const std::string & mergedOrLocal) :
- namespace_(QName_Namespace(mergedOrLocal)),
- local_part_(QName_LocalPart(mergedOrLocal)) {}
-
-std::string
-QName::Merged() const {
- if (namespace_ == STR_EMPTY)
- return local_part_;
- return namespace_ + ':' + local_part_;
-}
-
-bool
-QName::operator==(const QName & other) const {
- return
- local_part_ == other.local_part_ &&
- namespace_ == other.namespace_;
-}
-
-int
-QName::Compare(const QName & other) const {
- int result = local_part_.compare(other.local_part_);
- if (result)
- return result;
-
- return namespace_.compare(other.namespace_);
-}
-
-} // namespace buzz
diff --git a/third_party/libjingle/overrides/talk/xmllite/qname.h b/third_party/libjingle/overrides/talk/xmllite/qname.h
deleted file mode 100644
index db80efb..0000000
--- a/third_party/libjingle/overrides/talk/xmllite/qname.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TALK_XMLLITE_QNAME_H_
-#define TALK_XMLLITE_QNAME_H_
-
-#include <string>
-
-namespace buzz {
-
-// Default libjingle's implementation of QName class is not threadsafe. This
-// one is.
-class QName
-{
-public:
- QName();
- QName(const std::string & ns, const std::string & local);
- QName(bool add, const std::string & ns, const std::string & local);
- explicit QName(const std::string & mergedOrLocal);
-
- const std::string & Namespace() const { return namespace_; }
- const std::string & LocalPart() const { return local_part_; }
- std::string Merged() const;
- int Compare(const QName & other) const;
- bool operator==(const QName & other) const;
- bool operator!=(const QName & other) const { return !operator==(other); }
- bool operator<(const QName & other) const { return Compare(other) < 0; }
-
-private:
- std::string namespace_;
- std::string local_part_;
-};
-
-} // namespace buzz
-
-#endif // TALK_XMLLITE_QNAME_H_