Compare commits

..

267 Commits

Author SHA1 Message Date
Daniel Hammond
0a023409b1 Fix crash on mac (and 32-bit iOS?) - don't represent SRDelegateAvailableMethods as a bitfield (#530)
* Don't represent SRDelegateAvailableMethods as a bitfield

Since Objective-C uses a signed char for BOOL on some platforms (macOS and 32-bit iOS) packing this into a bitfield doesn't work since when it tries to read the field it looks for the sign bit and fails with an EXC_BAD_INSTRUCTION. This change sacrifices a few bits for the extra portability.

* CR - followup
2018-04-28 10:43:15 -07:00
Richard Ross
28035e1a98 Deprecate SSL pinning and trust chain verification. (#534)
Oh boy. Here's a controversial change.
![](http://i.imgur.com/t8JjQix.gif)

Let's give a bit of backstory.

A few weeks ago, Facebook was contacted by a whitehat hacker (the good
guys) about a security vulnerability here in SocketRocket.

For those of you who are truly interested in what that security flaw
was, it is essentially the same flaw as outlined here:

https://www.synopsys.com/blogs/software-security/ineffective-certificate-pinning-implementations/

So, we were faced with a choice - quietly push out a patch, and hope
that eventually existing applications updated, or be transparent and
admit we screwed up.

This is us admititng we screwed up. And while yes, we could probably fix
the implementation. But we talked internally, and decided that the best
approach here is to completely remove the option for pinning.

For all of our existing users that use certificate pinning, while we
understand that in the past there has been a very large barrier to entry
with getting a CA to issue a certificate.

However, since the rollout of CAs like LetsEncrypt, there's become an
ever-dwindling reason to actually use self-signed or unsigned
certificates.

For this reason, we're going to go ahead and deprecate the APIs that
allow SSL pinning and disabling trust chain verification. The pinning
APIs are now going to throw an exception when invoked, and the trust
chain APIs have deprecation warnings.

If you are a user of these APIs, and you for some reason **CANNOT** use
a trust chain validated certificate, PLEASE speak up. While we cannot
think of any reason to use those kinds of certificates, it's entirely
possible we overlooked something. We'll leave this pullrequest unmerged
for a two week period (Monday, August 28th, 2017), at which point,
unless we have feedback convincing us otherwise, we will go ahead with
this change.
2017-08-30 14:19:48 -07:00
Erik Price
877ac7438b Make copying optional when receiving data (#428)
* Reduce memory usage

Reduce memory usage by discarding, not resetting, the frame data buffer.
Let delegate control copying.

* Delegate methods expect `self`

* Add `-sendWithoutCopyingData:error:`

* Add `-webSocket:shouldCopyReceivedData:`

* Fix error messages

* Remove `-webSocket:shouldCopyReceivedData:`

* Revert "Fix error messages"

This reverts commit 4d5f5f018d0c953c9f9c9394f284f8358a039f90.

* Fix typo

* Copy only control frames

* Fix error message
2016-10-31 11:17:35 -07:00
Enrique Osuna
20686b9990 Ensure test environment is ready (#462)
When running tests, lets make sure that the test environment is ready to go.
2016-10-31 11:16:31 -07:00
woudini
41b57bb2fc Fix memory leak by freeing mutex. (#469) 2016-09-14 00:08:27 -07:00
Nikita Lutsenko
04b28a7c56 Add optional delegate method for received ping. (#463) 2016-08-25 16:41:07 -07:00
Nikita Lutsenko
d09212793c Merge pull request #461 from facebook/nlutsenko.lint
Lint, cleanup and fix analyzer warning.
2016-08-24 13:35:34 -07:00
Nikita Lutsenko
eff1db8da7 Fix missing prototypes for C functions. 2016-08-23 17:20:15 -07:00
Nikita Lutsenko
103dc2623b Cleanup and update summary for podspec. 2016-08-23 14:57:52 -07:00
Nikita Lutsenko
45f03ed9b9 Fix static analyzer warning in SRProxyConnect. 2016-08-23 14:53:19 -07:00
Nikita Lutsenko
35e965f2c5 Update xctoolchain to latest. 2016-08-23 14:53:19 -07:00
Nikita Lutsenko
3e5be70f1b Lint and cleanup source files. 2016-08-23 14:53:13 -07:00
Nikita Lutsenko
fc0aad7844 Remove no longer relevant Makefile. 2016-08-23 14:53:03 -07:00
Nikita Lutsenko
00a8a66240 Merge pull request #455 from facebook/nlutsenko.proxy.crash
Optimize input queue processing in SRProxyConnect.
2016-08-22 17:42:44 -07:00
Nikita Lutsenko
47971ebe5e Merge pull request #460 from facebook/nlutsenko.warning
Fix warnings on few potential clang configurations.
2016-08-22 16:06:16 -07:00
Nikita Lutsenko
9c2201f099 Cleanup proxy connect reference when socket is opened asynchronously. 2016-08-22 15:23:50 -07:00
Nikita Lutsenko
88cdc0b586 Optimize input queue processing in SRProxyConnect. 2016-08-22 15:23:50 -07:00
Nikita Lutsenko
ee6dd82992 Remove default: case in switch where all possible values are handled. 2016-08-22 15:12:18 -07:00
Nikita Lutsenko
abea58207e Fix nullability analysis in SRHTTPConnectMessage. 2016-08-22 15:11:58 -07:00
Nikita Lutsenko
cccbf71a7b Merge pull request #453 from facebook/nlutsenko.cleanup
Update configurations and unbreak compilation of a sample app.
2016-08-08 12:57:27 -07:00
Nikita Lutsenko
682be00378 Unbreak compilation of TestChat app. 2016-08-08 10:46:35 -07:00
Nikita Lutsenko
85dd530191 Update xctoolchain to latest. 2016-08-08 10:45:19 -07:00
Nikita Lutsenko
691241f102 Extract and cleanup setting network service type on input/output streams. 2016-08-08 10:45:17 -07:00
Fjölnir Ásgeirsson
ff03b396a0 Fixed build on under iOS 10 SDK (#450)
iOS 10 adds NSURLNetworkServiceTypeCallSignaling
which made this switch in
setupNetworkServiceType non-exhaustive
2016-07-29 11:54:47 -07:00
Nikita Lutsenko
471b99ccde Remove pages submodule reference. (#452) 2016-07-28 15:59:14 -07:00
Nikita Lutsenko
130967bcb9 Unify usage of default buffer size between SRWebSocket and SRProxyConnect. (#449) 2016-07-28 14:38:02 -07:00
Nikita Lutsenko
ecf7f75de3 Force linking of object files for built-in Foundation categories. (#441) 2016-07-08 18:33:15 -07:00
Richard Ross
4184f74f18 Make payload masking use vector instructions. (#440)
This is up to 50x faster when running on an ARM64 device, and effects
every payload we send out from the device.
2016-07-08 15:12:33 -07:00
Nikita Lutsenko
0632997fe7 Merge pull request #439 from mortonfox/patch-1
Update link to license
2016-07-08 11:46:02 -07:00
Morton Fox
84424d470a Update link to license 2016-07-08 12:30:48 -04:00
Nikita Lutsenko
f2e6387948 Improve type-safety on sending frames and remove extraneous class checks. (#438) 2016-07-07 19:53:15 -07:00
Nikita Lutsenko
ab462e597c Merge pull request #437 from facebook/nlutsenko.configurations
Update all targets to use shared configuration files from xctoolchain.
2016-07-06 13:24:02 -07:00
Nikita Lutsenko
e698ab30eb Fix undefined behavior on sending/reading the data. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
b666a4559a Remove usage of deprecated Endian with CFSwap. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
676948f555 Update Travis-CI configuration for new target names. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
eda51aba1b Fix all new warnings. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
a944d5fcbb Fixed documentation for SRWebSocketDelegate. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
e84a8fd596 Update all targets to shared configurations from xctoolchain. 2016-07-06 12:28:29 -07:00
Nikita Lutsenko
4605a70d61 Add xctoolchain submodule. 2016-07-05 19:36:39 -07:00
Nikita Lutsenko
2abdcb9614 Fix errors in TestChat application. (#431) 2016-07-01 17:51:15 -07:00
Nikita Lutsenko
71a52a57a2 Update README and CONTRIBUTING to Markdown and new documentation. (#432) 2016-07-01 14:58:33 -07:00
Michael Kirk
8096fef47d Pluggable, more flexible, security policies. (#429)
Extract @fredericjacobs' CertificateVerifier concept with @nlutsenko's
SRSecurityOptions into a pluggable SRSecurityPolicy model

This retains existing SSL configuration code paths, while allowing users
more flexibility to specify their own security policy.

If you are alread using AFNetworking and an `AFSecurityPolicy`, it's
intended that you can share domain trust logic by delegating
`SRSecurityPolicy evaluateTrust:ForDomain` to your AFSecurityPolicy
instance.

Inspired by original "Require TLS 1.2 & enable pinning" pull request by
Frederic Jacobs (@fredericjacobs) at:

https://github.com/facebook/SocketRocket/pull/274/files
2016-06-30 20:25:06 -07:00
Michael Kirk
b4e7932a59 specify ruby version for CI (#430)
CI is currently failing because the default ruby on travis.org is 2.0,
but a dependency xcpretty, requires the latest activesupport, which
requires ruby >=2.2
2016-06-30 17:09:35 -07:00
Erik Price
fcd482898a Make copying optional when sending data (#427)
* Reduce memory usage

Reduce memory usage by discarding, not resetting, the frame data buffer.
Let delegate control copying.

* Delegate methods expect `self`

* Add `-sendWithoutCopyingData:error:`

* Add `-webSocket:shouldCopyReceivedData:`

* Update test script name in Makefile

* use a Swiftier name

* Fix error messages

* Remove `-webSocket:shouldCopyReceivedData:`

* Remove assertion

* Fix typo
2016-06-28 15:43:44 -07:00
Nikita Lutsenko
48465aeaae Update public APIs for Swift 3 API Guidelines. (#419) 2016-06-27 19:26:54 -07:00
Nikita Lutsenko
16abb5debd Use error pointers instead of asserts for validating status on send:. (#416) 2016-06-27 18:32:08 -07:00
Nikita Lutsenko
e22b67e56a Make readyState KV Observable and fully thread-safe. (#420) 2016-06-27 17:27:58 -07:00
Nikita Lutsenko
52017adfb4 Improve SRStatusCode import into Swift. (#418) 2016-06-27 17:23:55 -07:00
Nikita Lutsenko
29d8e0e832 Unify logging in SRWebSocket, SRProxyConnect. (#417) 2016-06-27 15:20:32 -07:00
Nikita Lutsenko
0af058c221 Merge pull request #415 from facebook/nlutsenko.cleanup
Split creation of CFHTTPMessage and random data into separate source files.
2016-06-17 15:06:14 -07:00
Nikita Lutsenko
86df623629 Split creation of random data into SRRandom. 2016-06-17 14:45:59 -07:00
Nikita Lutsenko
d3beb35574 Split connect CFHTTPMessage creation into SRHTTPConnectMessage. 2016-06-17 13:17:23 -07:00
Nikita Lutsenko
8dafa6908a Cleanup and add few sections to SRWebSocket. 2016-06-17 13:17:23 -07:00
Nikita Lutsenko
aaab4836c3 Merge pull request #414 from facebook/nlutsenko.proxy.crash
Fix crash on SRProxyConnect deallocation, when timeout was encountered.
2016-06-16 21:36:43 -07:00
Nikita Lutsenko
14d35acf6c Explicitly remove delegates, close streams if ProxyConnect is deallocated before full open. 2016-06-15 19:03:38 -07:00
Nikita Lutsenko
dc0b2a7ff6 Replace NSOperationQueue with dispatch_queue in SRProxyConnect. 2016-06-15 18:57:54 -07:00
Nikita Lutsenko
49ab8461b7 Reset delegates on streams if proxy connect failed with error. 2016-06-15 18:45:51 -07:00
Nikita Lutsenko
e17d8ce173 Merge pull request #411 from dharmeshkakadia/patch-1
Fixing broken links in README
2016-06-13 18:18:53 -07:00
Nikita Lutsenko
50399656e5 Fix compilation warnings when building with Xcode 8. (#412) 2016-06-13 17:55:24 -07:00
Dharmesh Kakadia
d6934198a3 Fixing broken links in README 2016-06-12 22:54:11 -07:00
Nikita Lutsenko
e404333501 Merge pull request #407 from facebook/nlutsenko.tests
Enable Autobahn (iOS only) and Carthage tests on Travis-CI.
2016-06-10 15:43:22 -07:00
Nikita Lutsenko
c1dc8647ce Enable autobahn and carthage tests on Travis-CI for iOS. 2016-06-09 21:29:05 -07:00
Nikita Lutsenko
d6ed65d084 Do not open autobahn test results automatically after testing is done. 2016-06-09 16:20:43 -07:00
Nikita Lutsenko
7d0593f1df Add missing SRProxyConnect to all framework targets. 2016-06-09 16:20:43 -07:00
Nikita Lutsenko
8e203e15c2 Remove inaccessible resource file from sample app. 2016-06-09 16:20:43 -07:00
Nikita Lutsenko
8c41a73038 Cleanup TCAppDelegate. 2016-06-09 16:20:43 -07:00
Nikita Lutsenko
56e471ae94 Remove useless import in SRWebSocket.h 2016-06-09 16:20:43 -07:00
Nikita Lutsenko
510d1b1bae Remove CocoaPods version requirement from Gemfile. 2016-06-08 20:28:34 -07:00
Nikita Lutsenko
06b8e936eb Add xcpretty to Gemfile. 2016-06-08 20:23:32 -07:00
Nikita Lutsenko
5ce5f5d1d8 Fix pinned certificates and extract SSL-related things into SRSecurityOptions. (#406) 2016-06-08 20:14:22 -07:00
Nikita Lutsenko
8065053898 Remove usage of deprecated APIs and cleanup TestChat app. (#404) 2016-06-08 20:12:46 -07:00
Nikita Lutsenko
f239c15ed4 Merge pull request #403 from facebook/nlutsenko.tests
Fix and improve autobahn test running on any machine.
2016-06-08 20:11:21 -07:00
Nikita Lutsenko
840c9050c6 Fix and update test running from Xcode. 2016-06-08 02:08:31 -07:00
Nikita Lutsenko
7e97284178 Remove no longer used checked in copy of virtualenv. 2016-06-08 02:08:10 -07:00
Nikita Lutsenko
1f122e7de5 Remove no longer used sr-testharness. 2016-06-08 02:07:49 -07:00
Nikita Lutsenko
c25405ec4b Unbreak test scripts to download python virtualenv and set it up properly. 2016-06-08 02:07:07 -07:00
Nikita Lutsenko
b0aabde705 Merge pull request #399 from facebook/nlutsenko.lint
Cleanup, disable logging and make tests support scripts executable.
2016-06-07 13:36:50 -07:00
Mykola Voronin
383c787add Don't handle payload if server returns masked data (#401) 2016-06-07 11:58:24 -07:00
Nikita Lutsenko
77a4b66b99 Lint/cleanup and remove trailing whitespace. 2016-06-05 16:15:29 -07:00
Nikita Lutsenko
1218028be5 Extract check whether a URL requires SSL for WebSocket/HTTP into a separate function. 2016-06-05 16:14:40 -07:00
Nikita Lutsenko
9872cdc8e3 Disable debug logging in SRWebSocket. 2016-06-05 16:12:25 -07:00
Nikita Lutsenko
e5afe618b5 Make test support scripts executable. 2016-06-05 16:12:10 -07:00
oldshuren
d8a3a39187 Add Proxy support (#395)
* Add Proxy support

* move proxy to a class, add socks support

* should use weakSelf

* Move ProxyConnect to Internal/Proxy/SRProxyConnect
2016-06-05 15:44:36 -07:00
Nikita Lutsenko
c5954964ad Publicize and document readonly 'allowsUntrustedSSLCertificates' property. (#398) 2016-06-01 12:21:05 -07:00
Nikita Lutsenko
8835ee3b13 Fix nullability annotation on . (#397) 2016-05-31 15:03:09 -07:00
Nikita Lutsenko
de9ac0c9ec Merge pull request #389 from teepsllc/master
Added missing files to exported headers.
2016-05-23 13:48:58 -07:00
Jeffrey Klarfeld
b33ea540bc Added missing files to exported headers. 2016-05-23 15:58:19 -04:00
Nikita Lutsenko
a2e21423f0 Merge pull request #386 from facebook/nlutsenko.docs
Document 100% of public API and add nullability annotations.
2016-05-20 14:19:33 -07:00
Nikita Lutsenko
d71f74ee2b Cleanup and remove unused private ivars on SRWebSocket. (#387) 2016-05-20 14:19:25 -07:00
Nikita Lutsenko
2a25ad1599 Add nullability annotations to all public APIs on SRWebSocket. 2016-05-19 21:41:18 -07:00
Nikita Lutsenko
e465e2c4ff Add documentation to all properties of SRWebSocket. 2016-05-19 21:37:56 -07:00
Nikita Lutsenko
23a36beea4 Add designated initializer annotation, mark -init and +new as unavailable. 2016-05-19 21:37:56 -07:00
Nikita Lutsenko
2884b57723 Move NSRunLoop category into separate file and add documentation. 2016-05-19 21:37:56 -07:00
Nikita Lutsenko
9a9739af20 Move NSURLRequest, NSMutableURLRequest categories into separate files and add documentation. 2016-05-19 21:37:56 -07:00
Nikita Lutsenko
c85fa8c17c Add documentation for SRWebSocketDelegate. 2016-05-19 21:12:51 -07:00
Nikita Lutsenko
8b5ce6a0ea Add documentation for all methods of SRWebSocket. 2016-05-19 21:12:51 -07:00
Ben Shanfelder
792255b6e0 Fix crash with sending nil streamError to SRErrorWithCodeDescriptionUnderlyingError (#384)
* Fix crash with sending nil streamError to SRErrorWithCodeDescriptionUnderlyingError

* FIx missed resuse of streamError
2016-05-19 08:52:13 -07:00
Nikita Lutsenko
b5d9155229 Merge pull request #383 from facebook/nlutsenko.pagesize
Use getpagesize() instead of a macro to get the page size.
2016-05-17 17:26:05 -07:00
Nikita Lutsenko
836c660c2e Enable codesigning for unit tests. 2016-05-17 17:14:35 -07:00
Nikita Lutsenko
0a8b420c99 Use getpagesize() instead of a macro to get the page size. 2016-05-17 17:14:35 -07:00
Nikita Lutsenko
a39e0cc00b Merge pull request #379 from facebook/nlutsenko.delegate
Split 'webSocket:didReceiveMessage:' intro string/data methods.
2016-05-16 10:21:23 -07:00
Nikita Lutsenko
eadb8938eb Update tests for new methods. 2016-05-13 21:57:13 -07:00
Nikita Lutsenko
621d3961bb Split webSocket:didReceiveMessage: into string/data methods. 2016-05-13 21:57:00 -07:00
Nikita Lutsenko
00148bbb9e Use page size for default buffer size for reading/writing from streams. (#378) 2016-05-13 20:15:30 -07:00
Nikita Lutsenko
615ed2277d Incrementally flatten the newly received data from socket. (#377) 2016-05-13 14:27:37 -07:00
Nikita Lutsenko
eca38afd5c Fix potential out-of-order writing into output stream. (#374) 2016-05-12 19:43:44 -07:00
Nikita Lutsenko
6f43175832 Unify all error creation logic. (#376) 2016-05-12 17:23:08 -07:00
Nikita Lutsenko
d5f90ac633 Merge pull request #375 from facebook/nlutsenko.cleanup
Cleanup SR_networkRunLoop singleton and remove category on NSURL.
2016-05-12 14:44:00 -07:00
Nikita Lutsenko
7d36cd4beb Replace category on NSURL with SRURLUtitilities. 2016-05-11 21:39:06 -07:00
Nikita Lutsenko
331c2fb64e Move SR_networkRunLoop singleton into SRRunLoopThread. 2016-05-11 21:38:42 -07:00
Nikita Lutsenko
baf79e0869 Merge pull request #373 from facebook/nlutsenko.cleanup.old
Remove no longer needed MRR macros for dispatch objects.
2016-05-11 20:14:49 -07:00
Nikita Lutsenko
111f35258e Remove unused constant. 2016-05-11 17:09:39 -07:00
Nikita Lutsenko
e5dea1008e Remove MRR macros for dispatch objects. 2016-05-11 17:09:39 -07:00
Nikita Lutsenko
3a27290e55 Merge pull request #372 from facebook/nlutsenko.dispatch.data
Use dispatch_data for input/output stream buffers.
2016-05-11 16:42:42 -07:00
Nikita Lutsenko
99fd7576e4 Fix unsafe delegate method invocation. (#371) 2016-05-11 16:38:09 -07:00
Nikita Lutsenko
d0904552ee Use dispatch_data for writing to output stream. 2016-05-10 22:07:57 -07:00
Nikita Lutsenko
c3320bda72 Use dispatch_data for direct reading from input stream. 2016-05-10 22:05:01 -07:00
Nikita Lutsenko
e8efe0bfb2 Add 'sendData:', 'sendString:' and deprecate 'send:'. (#368) 2016-05-10 13:21:28 -07:00
Nikita Lutsenko
7a62f4869f Merge pull request #367 from facebook/nlutsenko.test
Make all tests runtime and Xcode discoverable.
2016-05-10 11:59:04 -07:00
Nikita Lutsenko
bf9252bcd6 Simplify waiting on predicates for operations to finish. 2016-05-09 20:30:46 -07:00
Nikita Lutsenko
396002c4a6 Rewrite SRAutobahnTests to make them runtime discoverable and visible in Xcode. 2016-05-09 20:15:44 -07:00
Nikita Lutsenko
cc4e5dc41a Rewrite SRWebSocketDelegate handling via SRDelegateController. (#366) 2016-05-09 18:29:53 -07:00
Nikita Lutsenko
ba8252279e Add parameterized configuration to autobahn tests. (#365) 2016-05-09 14:31:05 -07:00
Nikita Lutsenko
6f5e1d3175 Merge pull request #362 from facebook/nlutsenko.autobahn
Improve Xcode-based Autobahn testing.
2016-05-09 13:49:28 -07:00
Nikita Lutsenko
6d9bf91425 Rewrite, refactor and cleanup autobahn test operations. 2016-05-09 13:22:56 -07:00
Nikita Lutsenko
ea95661662 Remove unused file. 2016-05-09 13:21:34 -07:00
Nikita Lutsenko
3ccc928a62 Open proper results report after running tests. 2016-05-09 13:21:34 -07:00
Nikita Lutsenko
53fd24acd9 Add compiled python files to gitignore. 2016-05-09 13:21:34 -07:00
Nikita Lutsenko
22a3c97827 Update and unify all product bundle identifiers. (#363) 2016-05-09 13:20:15 -07:00
Nikita Lutsenko
15f86e8eba Change minimum deployment target to iOS 6.0, OS X 10.8. (#364) 2016-05-09 13:00:46 -07:00
Nikita Lutsenko
3b995adaf3 Merge pull request #360 from facebook/nlutsenko.split
Split internal classes into their own source files.
2016-05-06 14:31:12 -07:00
Nikita Lutsenko
b0758413ce Fix no ability to build tvOS framework for Apple TV Simulator. (#359) 2016-05-06 14:01:03 -07:00
ReadmeCritic
d358cc0c90 Update README URLs based on HTTP redirects 2016-05-06 10:18:02 -07:00
Nikita Lutsenko
d22287c928 Update podspec to include everything from SocketRocket folder. 2016-05-05 20:34:17 -07:00
Nikita Lutsenko
e11ac5d93d Split SRRunLoopThread from SRWebSocket. 2016-05-05 20:34:17 -07:00
Nikita Lutsenko
069120d9aa Split SHA1 from SRWebSocket into SRHash and rewrite it. 2016-05-05 20:34:17 -07:00
Nikita Lutsenko
5b9406d3a8 Split SRIOConsumerPool, SRIOConsumer from SRWebSocket. 2016-05-05 20:14:25 -07:00
Nikita Lutsenko
c3abc9a356 Add generic types to all object collections. (#358) 2016-05-05 18:56:10 -07:00
Nikita Lutsenko
93bc3e46c2 Merge pull request #357 from facebook/nlutsenko.travis
Update project and Travis-CI to Xcode 7.3.
2016-05-05 17:52:16 -07:00
Nikita Lutsenko
2d029d2084 Cleanup project settings. 2016-05-05 14:06:20 -07:00
Nikita Lutsenko
58012cfeb7 Update Travis-CI, project for Xcode 7.3. 2016-05-05 14:00:55 -07:00
Nikita Lutsenko
3fbd9411e9 Unify naming convention for framework targets. 2016-05-05 14:00:55 -07:00
Nikita Lutsenko
ee395defcf Update license on example server/cient. (#356) 2016-05-05 14:00:15 -07:00
Nikita Lutsenko
fa129d34c8 Merge pull request #351 from facebook/nlutsenko.info.plists
Unify `Info.plist`s for all platforms.
2016-05-05 12:27:02 -07:00
Nikita Lutsenko
8c228c812e Add common SocketRocket.h umbrella header to all frameworks. 2016-05-05 11:03:15 -07:00
Nikita Lutsenko
8a686b0e7e Unify all Info.plist into a single one. 2016-05-05 11:02:59 -07:00
Nikita Lutsenko
ef22e3a488 Merge pull request #352 from facebook/nlutsenko.instancetype
Make all initializers subclass/type-safe friendly.
2016-05-05 10:01:12 -07:00
Nikita Lutsenko
85030a57c4 Remove prefix headers, enable clang modules. (#350) 2016-05-05 10:00:32 -07:00
Nikita Lutsenko
f491809c9c Unify some custom errors. (#353) 2016-05-05 10:00:13 -07:00
ReadmeCritic
b804836b93 Update Podspec URLs (#354) 2016-05-04 22:38:57 -07:00
Nikita Lutsenko
9a64f67547 Use immutable NSURLRequests when constructing SocketRocket only with URL. 2016-05-04 20:01:20 -07:00
Nikita Lutsenko
0aefc947aa Refactor designated initializer into a single method. 2016-05-04 20:00:57 -07:00
Nikita Lutsenko
e4101f6ad1 Use instancetype instead of id for return types of init methods. 2016-05-04 19:54:39 -07:00
Dan Federman
277ae665d2 Merge pull request #348 from dfed/nlutsenko.license
Update LICENSE, Contributing, README, PATENTS.
2016-05-04 14:30:54 -07:00
Nikita Lutsenko
ca2b585541 Update license in Podspec. 2016-05-04 14:29:25 -07:00
Nikita Lutsenko
9613157ead Update copyright statement on source files. 2016-05-04 14:27:53 -07:00
Nikita Lutsenko
685f756f22 Update LICENSE, Contributing, README, PATENTS. 2016-05-04 14:19:18 -07:00
Dan Federman
36e68c11ab Bump pod version to 0.5.1 2016-05-04 10:18:31 -07:00
Dan Federman
8016b968b3 Merge pull request #335 from danblakemore/kvoverkill
Removed duplicated KVO calls for readyState
2016-05-04 10:10:46 -07:00
Dan Federman
f661897c4b Merge pull request #330 from hamchapman/update-run-test-script
Updates throughout test-related files to try and make run_test.sh work
2016-05-04 10:10:03 -07:00
Dan Federman
0eee9071aa Merge pull request #342 from pm-dev/master
Message handling optimization
2016-03-18 15:38:16 -07:00
Peter Meyers
ad3ad77909 Give the delegate the ability to specify whether SRWebSocket should convert NSData to NSString for TEXT messages. This is an optimization for when the server is sending text serialized as JSON. In this case we would turn the string back into NSData before passing it to NSJSONSerialization, which removes 2 data <--> string conversions. 2016-03-18 15:28:30 -07:00
Dan Federman
43c4a5295d Merge pull request #338 from adematalay/FrameDataCopy
frameData is copied before passing to handlers
2016-03-18 15:13:49 -07:00
Dan Federman
2d1372590c Bump pod version to 0.5.0 2016-03-17 11:40:28 -07:00
Adem Atalay
e6dc61452d frameData is copied before passing to handlers 2016-03-08 22:50:09 +02:00
Dan Federman
19643946d5 Merge pull request #326 from hamchapman/master
Add tvos as deployment target
2016-03-06 13:32:35 -08:00
Hamilton Chapman
802ec4ead2 Update travis.yml to build for tvOS and multiple iOS configs 2016-03-06 09:41:19 +00:00
Dan Federman
541f7b6a11 Merge pull request #169 from jleandroperez/master
Issue #156: Prevents crash in handleEvent method
2016-02-18 16:38:36 -08:00
Dan Federman
4c0d9340fa Merge pull request #334 from ReadmeCritic/master
Correct the capitalization of Xcode in README
2016-02-18 16:27:49 -08:00
Daniel Blakemore
8d23062298 Removed duplicated KVO calls for readyState
The system implicitly supports KVO for this property.
2016-02-18 10:31:03 -07:00
ReadmeCritic
5c5f115798 Correct the capitalization of Xcode in README 2016-02-17 08:44:08 -08:00
Hamilton Chapman
77e89f07e2 Updates throughout test-related files to try and make run_test.sh work 2016-01-28 16:39:43 +00:00
Hamilton Chapman
6e5de1a8f5 Add SocketRocket-tvOS scheme and target. Update project settings 2016-01-28 14:43:49 +00:00
Hamilton Chapman
521818db64 Update podspec to include tvos as a deployment target 2016-01-28 14:39:22 +00:00
Hamilton Chapman
ec3c39cd37 Update cocoapods gem 2016-01-28 14:39:22 +00:00
Hamilton Chapman
9ca0ceefe5 Update travis.yml to use newer xcode image and 10.11 for OSX build 2016-01-28 14:39:22 +00:00
Dan Federman
b437daeaaa Merge pull request #329 from benshan/close-codes
Update close status codes based on spec.
2016-01-25 11:04:21 -08:00
Ben Shanfelder
b0e0bba262 Update close status codes based on spec.
https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
2016-01-25 12:52:48 -05:00
Dan Federman
7bff4f0ac3 Merge pull request #327 from utahiosmac/master
Make SocketRocket usable as a module from within Swift, especially on OS X
2016-01-23 10:16:50 -08:00
Dave DeLong
29dbaa8b7b Make SocketRocket usable as a module from within Swift, especially on OS X 2016-01-21 20:23:50 -08:00
Dan Federman
cc6fea0a4d Merge pull request #309 from fjolnir/master
Fixed connecting limbo
2016-01-20 14:28:37 -08:00
Dan Federman
192e7b769b Merge pull request #323 from isleofcode/master
Respect timeouts set on `NSURLRequest`s passed at init fix #70
2016-01-15 17:16:05 -08:00
@anulman
1185f16186 fix(timeouts): use code 504 when erroring due to nsurl timeout 2016-01-15 20:10:00 -05:00
@anulman
0ea20993d3 fix(timeouts): timeout open attempts based on NSURLRequest params 2016-01-13 19:34:10 -05:00
Dan Federman
91a2c2b68a Merge pull request #318 from miguelsanchez/fix-osx-build
- Fix OS X build by checking if OS is iOS 9 only on iOS target OSs.
2015-12-15 10:25:26 -08:00
Miguel Sanchez
19f0c5eb1d - Fix OS X build by checking if OS is iOS 9 only on iOS target OSs. 2015-12-15 18:59:48 +01:00
Dan Federman
f19d973c8c Merge pull request #317 from square/federman/contributing
Add Contributing.md
2015-12-14 21:03:09 -08:00
Dan Federman
b93aa9097b Add Contributing.md 2015-12-14 12:00:29 -08:00
Dan Federman
0c31c8b0bb Merge pull request #313 from ReadmeCritic/master
Update README URLs based on HTTP redirects
2015-12-04 16:03:37 -08:00
ReadmeCritic
45352e4c0e Update README URLs based on HTTP redirects 2015-11-27 20:03:03 -08:00
Dan Federman
818cec9d83 Merge pull request #300 from jakobsa/master
issue #299: Handle server frames also when ReadyState is SR_Closing
2015-11-17 10:46:06 -08:00
Fjölnir Ásgeirsson
af4ddaed75
Fixed connecting limbo
This fixes an issue where a socket would be stuck in "connecting" state if using SSL without a pinned certificate.
2015-11-17 14:57:16 +09:00
Jorge Leandro Perez
a770a5fd52 Re-applies scheduleCleanup patch 2015-11-16 11:22:44 -03:00
Jorge Leandro Perez
60cec3a09e Nukes strongSelf workaround 2015-11-16 11:11:27 -03:00
Jorge Leandro Perez
b11f4be5f6 Merge remote-tracking branch 'upstream/master' 2015-11-16 11:03:15 -03:00
Jorge Leandro Perez
2c95c1364d Merging upstream 2015-11-16 10:58:56 -03:00
Dan Federman
d2230743f0 Merge pull request #293 from jessearmand/master
Read network service types of NSURLRequest.
2015-11-13 16:39:38 -08:00
Mike Lewis
a46422f9b9 Merge pull request #306 from jder/master
Namespace category names to avoid collisions
2015-11-10 14:19:55 -08:00
Jesse Rusak
826ed64078 Namespace category names to avoid collisions 2015-11-10 10:11:47 -05:00
Jakob Sachse
75017d14a8 To get this merged, please do the following:
1) ...
2) Comment out #define SR_ENABLE_LOG
2015-11-09 11:34:15 +01:00
Jesse Armand
dea0d428f8 Read network service type from requests.
* Set them to the input/output streams
* Network service type VoIP is deprecated in iOS 9.0
2015-11-08 00:51:03 +08:00
Dan Federman
efe1f98b05 Merge pull request #231 from seanwhitsell/master
Fix issue where we make the GET before checking the Server-side cert
2015-11-03 12:04:27 -08:00
Dan Federman
ead962232d Bump podspec 2015-10-30 17:29:22 -07:00
Dan Federman
954c9478b5 Merge pull request #290 from mogstad/carthage
Add dynamic framework for iOS
2015-10-30 17:25:15 -07:00
Jakob Sachse
53c17b879c handle frames as long as not closed 2015-10-21 18:03:00 +02:00
Jakob Sachse
9ff02e49d8 enabled logging 2015-10-21 17:29:16 +02:00
Jakob Sachse
00279da31e pump also while closing 2015-10-21 17:11:13 +02:00
Jakob Sachse
8ae2d77943 test bump 0.4.2 2015-10-21 17:03:27 +02:00
Dan Federman
b47e74ed50 Merge pull request #146 from mk/http-basic-auth
Add support for http basic auth, closes #36
2015-10-16 19:54:58 -04:00
Ken Wigginton
fd84880ad1 Merge pull request #137 from jmkk/cert-trust
Allow the clients to decide if validation of SSL certificates should be skipped
2015-10-16 16:44:27 -07:00
Mike Lewis
9b248a6286 Merge pull request #294 from joenoon/patch-1
Prevent SocketRocket killing the connection before notifying of final messages
2015-10-16 16:43:21 -07:00
Bjarne Mogstad
bd130dc902 fixup! Add dynamic framework for iOS 2015-10-14 14:17:43 +02:00
Dan Federman
51b8e2b0c2 Merge pull request #136 from jakajancar/origin-fix
Origin syntax fix
2015-10-12 16:42:57 -07:00
Joe Noon
dd1bee8c88 Prevent SocketRocket killing the connection before notifying of final messages
The issue appears to be a race between hitting NSStreamEventEndEncountered and receiving any final messages the server may have sent before closing the connection.

My patch just changes closing/cleanup from running immediately, to instead happen on the next dispatch_async _workQueue.  I haven't been able to reproduce the issue since making this change.  _failWithError itself already shells out to dispatch_async _workQueue, so this patch would seem consistent with that behavior.  But we really need someone who knows the internals/implications of this to take a look.
2015-10-08 15:02:39 -07:00
Martin Kavalar
6e0ca9b68c Merge branch 'master' into http-basic-auth 2015-10-06 10:46:35 +02:00
Martin Kavalar
1a12a7c473 Use better variable name 2015-10-06 10:35:14 +02:00
Martin Kavalar
efb080f712 Protect against empty strings 2015-10-06 10:33:48 +02:00
Martin Kavalar
eefd7e0426 Add space after if 2015-10-06 10:33:33 +02:00
John MacKanacKy
bf9bffa0b8 Use dependency injection for setting the "untrusted certs" flag. 2015-10-03 00:00:00 -07:00
John MacKanacKy
23dd00dd7e Merge branch 'original_master' into cert-trust 2015-10-02 23:38:36 -07:00
Dan Federman
21eaa2b7d1 Merge pull request #292 from square/danielrb/change-location-of-headers-for-iOS-static-lib-target
cherry picking https://github.com/square/SocketRocket/pull/74
2015-10-02 17:41:56 -07:00
Dan Federman
00b4b90309 Merge pull request #240 from j0sh/master
Add CLI builds for library and framework
2015-10-02 17:29:03 -07:00
Daniel Ribeiro
60f4713a81 cherry picking https://github.com/square/SocketRocket/pull/74 and fixing merge conflicts 2015-10-02 17:28:54 -07:00
Martin Mroz
dc96e61640 Merge pull request #291 from square/federman/fix_readme
Fix Autobahn link in README
2015-10-02 16:54:17 -07:00
Dan Federman
b14672c505 Fix Autobahn link in README 2015-10-02 16:52:50 -07:00
Bjarne Mogstad
c1b140e341 Add dynamic framework for iOS
Added new schema “SocketRocket-iOS”, a dynamic framework with
deployment target for iOS. Allows SocketRocket to be installed with
Carthage (tested with Carthage v0.9.1)
2015-09-24 17:36:33 +02:00
Mike Lewis
4d7b75b9b2 Merge pull request #281 from noahlt/go_fmt_lint
Make chatroom.go pass golint and gofmt
2015-09-21 13:11:57 -07:00
Jorge Leandro Perez
8449f84211 Merge remote-tracking branch 'upstream/master' 2015-09-21 15:27:52 -03:00
Jorge Leandro Perez
b4c58f8fc1 Removes SocketRocket.xccheckout 2015-09-21 15:23:31 -03:00
Ken Wigginton
20b501e79e Merge pull request #278 from square/kenw/update-gitignore-2
Update gitignore 2
2015-09-21 09:05:17 -07:00
Noah Tye
94fa0305af Make chatroom.go pass golint and gofmt 2015-09-20 18:24:33 -07:00
Dan Federman
75ffad8f61 Merge pull request #280 from jmkk/cookies
Added ability to provide cookies for the web socket connection
2015-09-19 08:14:20 -07:00
jacek
bf09594e3f Added ability to provide cookies for the web socket connection 2015-09-19 00:33:11 -07:00
Ken Wigginton Jr
371723add4 Update gitignore 2015-09-18 17:30:40 -07:00
RoyalPineapple
f14f5255cd Merge pull request #277 from square/kenw/update-gitignore
Update gitconfig
2015-09-18 17:28:12 -07:00
Ken Wigginton Jr
d65f09b667 Update gitconfig 2015-09-18 17:25:16 -07:00
Dan Federman
37b196de51 Merge pull request #111 from aaronvegh/master
Add receivedHTTPHeaders array to public properties
2015-09-18 17:18:09 -07:00
Dan Federman
8dd567e56e Merge pull request #89 from janckoch/bad_access_fix
Fixed bad_access that could occur when releasing _workQueue on dealloc
2015-09-18 17:00:12 -07:00
Dan Federman
21f4b4326b Merge pull request #86 from natevw/lion_compat
Decrement deployment target
2015-09-18 16:56:33 -07:00
Jorge Leandro Perez
3c867d8b00 Merge remote-tracking branch 'upstream/master' 2015-09-14 16:36:41 -03:00
Dan Federman
b4c224c888 Bump pod version to 0.4.1 2015-09-10 14:30:53 -07:00
Dan Federman
5ba1c8a675 Merge pull request #269 from kommen/unprefix-method-names
Remove underscore from _openConnection and _closeConnection. #263
2015-09-10 14:29:54 -07:00
Dieter Komendera
db8c68134b Remove _ from _openConnection and _closeConnection. #263
https://github.com/square/SocketRocket/issues/263
2015-08-14 12:00:21 +02:00
Josh Allmann
a9574d3cbd Build SocketRocket by default in main Makefile.
This is closer to the expected behavior of a Makefile.
2015-04-29 18:07:20 -07:00
Josh Allmann
483aef0ced Add a Makefile for command-line builds.
Generates a static library and a framework by default.
2015-04-29 18:06:44 -07:00
Sean Whitsell
99be5aebfd Fix issue where we make the GET before checking the Server-side certificate when Pinning Certs 2015-03-18 09:28:06 -04:00
Jorge Leandro Perez
3ff6038ad9 Prevents concurrent runloop unschedule glitch 2015-01-28 17:57:20 -03:00
Jorge Leandro Perez
c13b301047 Merge remote-tracking branch 'upstream/master' 2015-01-28 12:30:19 -03:00
Jorge Leandro Perez
04b9c1d135 Implements cleanup failsafe 2014-12-01 17:37:20 -03:00
Jorge Leandro Perez
ad7890a6c6 Prevents bad access on dealloc 2014-12-01 16:44:07 -03:00
Jorge Leandro Perez
bcac6bd87f Merge remote-tracking branch 'original/master'
Conflicts:
	SocketRocket/SRWebSocket.m
2014-12-01 16:36:51 -03:00
John MacKanacKy
7d734d2b5d Incorporating feedback part 2 - fixed code style and comments 2014-07-27 18:40:28 -07:00
John MacKanacKy
a1a32d6770 Incorporating feedback - fixed code style and comments 2014-07-14 20:06:06 -07:00
Jorge Leandro Perez
3244d812c5 Merge remote-tracking branch 'upstream/master'
Conflicts:
	SocketRocket/SRWebSocket.m
2014-07-11 09:40:08 -03:00
Jorge Leandro Perez
1bb40484ff Fixed podspec 2014-07-10 23:43:53 -03:00
Jorge Leandro Perez
cb476d4cb0 Fixes Podspec source url 2014-07-10 17:56:21 -03:00
Jorge Leandro Perez
b434079f84 Nukes redundant stream close call 2014-05-28 15:21:17 -03:00
Jorge Leandro Perez
7e5129f951 Prevents multiple cleanup calls 2014-05-28 14:49:23 -03:00
Jorge Leandro Perez
194bc17f2b Prevents sending close x2 2014-05-27 17:54:31 -03:00
Jorge Leandro Perez
08f26e4f1c Cleaning up NSStream delegates in SR-RunLoop 2014-05-06 15:14:07 -03:00
Jorge Leandro Perez
c02f775d95 Prevents crash in handleEvent method 2014-04-25 16:54:11 -03:00
Martin Kavalar
27390c7516 Add support for http basic auth, closes #36 2014-01-27 12:10:30 +01:00
jacek
c136536a14 Allow the clients to decide if validation of SSL certificates should be skipped 2013-12-27 22:14:06 -08:00
Jaka Jančar
2c241b52c9 Origin syntax fix 2013-12-27 13:35:37 +01:00
Aaron Vegh
1d4ba4905d Add receivedHTTPHeaders array to public properties so applications can access them 2013-08-31 22:55:05 -04:00
Jan Koch
018abc742f Fixed bad_access that could occur when releasing _workQueue on dealloc 2013-03-27 14:34:37 -07:00
Nathan Vander Wilt
a17be5ae3d decrement deployment target 2013-03-12 10:40:03 -07:00
150 changed files with 6408 additions and 13048 deletions

3
.gitignore vendored
View File

@ -17,7 +17,10 @@ xcuserdata/
*.xcworkspace
!default.xcworkspace
*xcuserdata
*.xccheckout
profile
*.moved-aside
DerivedData
extern/
*.pyc

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "pages"]
path = pages
url = git://github.com/square/SocketRocket.git
[submodule "Vendor/xctoolchain"]
path = Vendor/xctoolchain
url = https://github.com/ParsePlatform/xctoolchain.git

1
.ruby-version Normal file
View File

@ -0,0 +1 @@
2.3.1

View File

@ -1,8 +1,43 @@
branches:
only:
- master
language: objective-c
osx_image: xcode6.4
before_script:
- bundle install
os: osx
osx_image: xcode7.3
env:
matrix:
- TEST_TYPE=iOS
- TEST_TYPE=OSX
- TEST_TYPE=tvOS
- TEST_TYPE=CocoaPods
- TEST_TYPE=Carthage
before_install:
- |
if [ "$TEST_TYPE" = iOS ] || [ "$TEST_TYPE" = OSX ] || [ "$TEST_TYPE" = tvOS ]; then
bundle install
elif [ "$TEST_TYPE" = Carthage ]; then
brew update
brew install carthage || brew upgrade carthage
fi
install:
- |
if [ "$TEST_TYPE" = iOS ]; then
./TestSupport/setup_env.sh .env
fi
script:
- xcodebuild -project SocketRocket.xcodeproj -scheme "SocketRocket" -sdk iphonesimulator -configuration Debug -PBXBuildsContinueAfterErrors=0 ACTIVE_ARCH_ONLY=0 build test
- xcodebuild -project SocketRocket.xcodeproj -scheme "SocketRocketOSX" -sdk macosx10.10 -configuration Debug -destination "platform=OS X" -PBXBuildsContinueAfterErrors=0 build
- pod lib lint --verbose --fail-fast
- |
if [ "$TEST_TYPE" = iOS ]; then
set -o pipefail
xcodebuild -project SocketRocket.xcodeproj -scheme "SocketRocket-iOS" -sdk iphonesimulator build test
elif [ "$TEST_TYPE" = OSX ]; then
set -o pipefail
xcodebuild -project SocketRocket.xcodeproj -scheme "SocketRocket-macOS" -sdk macosx build | xcpretty -c
elif [ "$TEST_TYPE" = tvOS ]; then
set -o pipefail
xcodebuild -project SocketRocket.xcodeproj -scheme "SocketRocket-tvOS" -sdk appletvsimulator build | xcpretty -c
elif [ "$TEST_TYPE" = CocoaPods ]; then
pod lib lint SocketRocket.podspec
pod lib lint --use-libraries SocketRocket.podspec
elif [ "$TEST_TYPE" = Carthage ]; then
carthage build --no-skip-current
fi

33
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,33 @@
# Contributing to SocketRocket
We want to make contributing to this project as easy and transparent as possible.
## Pull Requests
We actively welcome your pull requests.
1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
6. If you haven't already, complete the Contributor License Agreement ("CLA").
## Contributor License Agreement ("CLA")
In order to accept your pull request, we need you to submit a CLA.
You only need to do this once to work on any of Facebook's open source projects.
Complete your CLA here: <https://code.facebook.com/cla>
## Issues
We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.
## Coding Style
* Most importantly, match the existing code style as much as possible.
* Try to keep lines under 140 characters, if possible.
## License
By contributing to SocketRocket, you agree that your contributions will be licensed under its BSD license.

1
Configurations/Shared Symbolic link
View File

@ -0,0 +1 @@
../Vendor/xctoolchain/Configurations/

View File

@ -0,0 +1,17 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/iOS.xcconfig"
#include "Shared/Product/DynamicFramework.xcconfig"
PRODUCT_NAME = SocketRocket
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.ios
IPHONEOS_DEPLOYMENT_TARGET = 8.0
INFOPLIST_FILE = $(SRCROOT)/SocketRocket/Resources/Info.plist

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/iOS.xcconfig"
#include "Shared/Product/StaticFramework.xcconfig"
PRODUCT_NAME = SocketRocket
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.ios
IPHONEOS_DEPLOYMENT_TARGET = 6.0
INFOPLIST_FILE = $(SRCROOT)/SocketRocket/Resources/Info.plist
OTHER_CFLAGS[sdk=iphoneos9.*] = $(inherited) -fembed-bitcode
OTHER_LDFLAGS = $(inherited) -Licucore

View File

@ -0,0 +1,17 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/macOS.xcconfig"
#include "Shared/Product/DynamicFramework.xcconfig"
PRODUCT_NAME = SocketRocket
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.macos
MACOSX_DEPLOYMENT_TARGET = 10.8
INFOPLIST_FILE = $(SRCROOT)/SocketRocket/Resources/Info.plist

View File

@ -0,0 +1,16 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/tvOS.xcconfig"
#include "Shared/Product/DynamicFramework.xcconfig"
PRODUCT_NAME = SocketRocket
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.tvos
INFOPLIST_FILE = $(SRCROOT)/SocketRocket/Resources/Info.plist

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/iOS.xcconfig"
#include "Shared/Product/LogicTests.xcconfig"
PRODUCT_NAME = SocketRocketTests-iOS
PRODUCT_MODULE_NAME = SocketRocketTests
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.tests.ios
IPHONEOS_DEPLOYMENT_TARGET = 7.0
INFOPLIST_FILE = $(SRCROOT)/Tests/Resources/Info.plist

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#include "Shared/Platform/iOS.xcconfig"
#include "Shared/Product/Application.xcconfig"
PRODUCT_NAME = TestChat
PRODUCT_MODULE_NAME = TestChat
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.socketrocket.testchat
IPHONEOS_DEPLOYMENT_TARGET = 8.0
INFOPLIST_FILE = $(SRCROOT)/TestChat/TestChat-Info.plist

View File

@ -1,3 +1,4 @@
source 'https://rubygems.org'
gem 'cocoapods', '0.37.2'
gem 'cocoapods'
gem 'xcpretty'

35
LICENSE
View File

@ -1,15 +1,30 @@
BSD License
Copyright 2012 Square Inc.
For SocketRocket software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
http://www.apache.org/licenses/LICENSE-2.0
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
* 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.
* Neither the name Facebook nor the names of its contributors may 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 HOLDER 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.

11
LICENSE-examples Normal file
View File

@ -0,0 +1,11 @@
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
The examples provided by Facebook are for non-commercial testing and evaluation
purposes only. Facebook reserves all rights not expressly granted.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,20 +1,30 @@
TEST_SCENARIOS="[1-8]*"
TEST_URL='ws://localhost:9001/'
test:
all:
$(MAKE) -C SocketRocket
clean:
$(MAKE) -C SocketRocket clean
.env:
./TestSupport/setup_env.sh .env
test: .env
mkdir -p pages/results
bash ./TestSupport/run_test.sh $(TEST_SCENARIOS) $(TEST_URL) Debug || open pages/results/index.html && false
bash ./TestSupport/run_test_server.sh $(TEST_SCENARIOS) $(TEST_URL) Debug || open pages/results/index.html && false
open pages/results/index.html
test_all:
test_all: .env
mkdir -p pages/results
bash ./TestSupport/run_test.sh '*' $(TEST_URL) Debug || open pages/results/index.html && false
bash ./TestSupport/run_test_server.sh '*' $(TEST_URL) Debug || open pages/results/index.html && false
open pages/results/index.html
test_perf:
test_perf: .env
mkdir -p pages/results
bash ./TestSupport/run_test.sh '9.*' $(TEST_URL) Release || open pages/results/index.html && false
bash ./TestSupport/run_test_server.sh '9.*' $(TEST_URL) Release || open pages/results/index.html && false
open pages/results/index.html

33
PATENTS Normal file
View File

@ -0,0 +1,33 @@
Additional Grant of Patent Rights Version 2
"Software" means the SocketRocket software distributed by Facebook, Inc.
Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
(subject to the termination provision below) license under any Necessary
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
transfer the Software. For avoidance of doubt, no license is granted under
Facebooks rights in any patent claims that are infringed by (i) modifications
to the Software made by you or any third party or (ii) the Software in
combination with any software or other technology.
The license granted hereunder will terminate, automatically and without notice,
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
directly or indirectly, or take a direct financial interest in, any Patent
Assertion: (i) against Facebook or any of its subsidiaries or corporate
affiliates, (ii) against any party if such Patent Assertion arises in whole or
in part from any software, technology, product or service of Facebook or any of
its subsidiaries or corporate affiliates, or (iii) against any party relating
to the Software. Notwithstanding the foregoing, if Facebook or any of its
subsidiaries or corporate affiliates files a lawsuit alleging patent
infringement against you in the first instance, and you respond by filing a
patent infringement counterclaim in that lawsuit against that party that is
unrelated to the Software, the license granted hereunder will not terminate
under section (i) of this paragraph due to such counterclaim.
A "Necessary Claim" is a claim of a patent owned by Facebook that is
necessarily infringed by the Software standing alone.
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
or contributory infringement or inducement to infringe any patent, including a
cross-claim or counterclaim.

213
README.md Normal file
View File

@ -0,0 +1,213 @@
# SocketRocket
![Platforms][platforms-svg]
[![License][license-svg]][license-link]
[![Podspec][podspec-svg]][podspec-link]
[![Carthage Compatible][carthage-svg]](carthage-link)
[![Build Status][build-status-svg]][build-status-link]
A conforming WebSocket ([RFC 6455](https://tools.ietf.org/html/rfc6455>)) client library for iOS, macOS and tvOS.
Test results for SocketRocket [here](http://facebook.github.io/SocketRocket/results/).
You can compare to what modern browsers look like [here](http://autobahn.ws/testsuite/reports/clients/index.html).
SocketRocket currently conforms to all core ~300 of [Autobahn](http://autobahn.ws/testsuite/>)'s fuzzing tests
(aside from two UTF-8 ones where it is merely *non-strict* tests 6.4.2 and 6.4.4).
## Features/Design
- TLS (wss) support, including self-signed certificates.
- Seems to perform quite well.
- Supports HTTP Proxies.
- Supports IPv4/IPv6.
- Supports SSL certificate pinning.
- Sends `ping` and can process `pong` events.
- Asynchronous and non-blocking. Most of the work is done on a background thread.
- Supports iOS, macOS, tvOS.
## Installing
There are a few options. Choose one, or just figure it out:
- **[CocoaPods](https://cocoapods.org)**
Add the following line to your Podfile:
```ruby
pod 'SocketRocket'
```
Run `pod install`, and you are all set.
- **[Carthage](https://github.com/carthage/carthage)**
Add the following line to your Cartfile:
```
github "facebook/SocketRocket"
```
Run `carthage update`, and you should now have the latest version of `SocketRocket` in your `Carthage` folder.
- **Using SocketRocket as a sub-project**
You can also include `SocketRocket` as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the `SocketRocket.xcodeproj` file into your workspace.
## API
### `SRWebSocket`
The Web Socket.
#### Note:
`SRWebSocket` will retain itself between `-(void)open` and when it closes, errors, or fails.
This is similar to how `NSURLConnection` behaves (unlike `NSURLConnection`, `SRWebSocket` won't retain the delegate).
#### Interface
```objective-c
@interface SRWebSocket : NSObject
// Make it with this
- (instancetype)initWithURLRequest:(NSURLRequest *)request;
// Set this before opening
@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
// Open with this
- (void)open;
// Close it with this
- (void)close;
// Send a Data
- (void)sendData:(nullable NSData *)data error:(NSError **)error;
// Send a UTF8 String
- (void)sendString:(NSString *)string error:(NSError **)error;
@end
```
### `SRWebSocketDelegate`
You implement this
```objective-c
@protocol SRWebSocketDelegate <NSObject>
@optional
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string;
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data;
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(nullable NSString *)reason wasClean:(BOOL)wasClean;
@end
```
## Testing
Included are setup scripts for the python testing environment.
It comes packaged with vitualenv so all the dependencies are installed in userland.
To run the short test from the command line, run:
```bash
make test
```
To run all the tests, run:
```bash
make test_all
```
The short tests don't include the performance tests
(the test harness is actually the bottleneck, not SocketRocket).
The first time this is run, it may take a while to install the dependencies. It will be smooth sailing after that.
You can also run tests inside Xcode, which runs the same thing, but makes it easier to debug.
- Choose the `SocketRocket` target
- Run the test action (`⌘+U`)
### TestChat Demo Application
SocketRocket includes a demo app, TestChat.
It will "chat" with a listening websocket on port 9900.
#### TestChat Server
The sever takes a message and broadcasts it to all other connected clients.
It requires some dependencies though to run.
We also want to reuse the virtualenv we made when we ran the tests.
If you haven't run the tests yet, go into the SocketRocket root directory and type:
```bash
make test
```
This will set up your [virtualenv](https://pypi.python.org/pypi/virtualenv).
Now, in your terminal:
```bash
source .env/bin/activate
pip install git+https://github.com/tornadoweb/tornado.git
```
In the same terminal session, start the chatroom server:
```bash
python TestChatServer/py/chatroom.py
```
There's also a Go implementation (with the latest weekly) where you can:
```bash
cd TestChatServer/go
go run chatroom.go
```
#### Chatting
Now, start TestChat.app (just run the target in the Xcode project).
If you had it started already you can hit the refresh button to reconnect.
It should say "Connected!" on top.
To talk with the app, open up your browser to [http://localhost:9000](http://localhost:9000) and start chatting.
## WebSocket Server Implementation Recommendations
SocketRocket has been used with the following libraries:
- [Tornado](https://github.com/tornadoweb/tornado)
- Go's [WebSocket package](https://godoc.org/golang.org/x/net/websocket) or Gorilla's [version](http://www.gorillatoolkit.org/pkg/websocket).
- [Autobahn](http://autobahn.ws/testsuite/) (using its fuzzing client).
The Tornado one is dirt simple and works like a charm.
([IPython notebook](http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html) uses it too).
It's much easier to configure handlers and routes than in Autobahn/twisted.
## Contributing
Were glad youre interested in SocketRocket, and wed love to see where you take it.
Please read our [contributing guidelines](https://github.com/facebook/SocketRocket/blob/master/CONTRIBUTING.md) prior to submitting a Pull Request.
[build-status-svg]: https://img.shields.io/travis/facebook/SocketRocket/master.svg
[build-status-link]: https://travis-ci.org/facebook/SocketRocket/branches
[license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg
[license-link]: https://github.com/facebook/SocketRocket/blob/master/LICENSE
[podspec-svg]: https://img.shields.io/cocoapods/v/SocketRocket.svg
[podspec-link]: https://cocoapods.org/pods/SocketRocket
[carthage-svg]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat
[carthage-link]: https://github.com/carthage/carthage
[platforms-svg]: http://img.shields.io/cocoapods/p/SocketRocket.svg?style=flat

View File

@ -1,255 +0,0 @@
SocketRocket Objective-C WebSocket Client (beta)
================================================
A conforming WebSocket (`RFC 6455 <http://tools.ietf.org/html/rfc6455>`_)
client library.
`Test results for SocketRocket here <http://square.github.com/SocketRocket/results/>`_.
You can compare to what `modern browsers look like here
<http://www.tavendo.de/autobahn/testsuite/report/clients/index.html>`_.
SocketRocket currently conforms to all ~300 of `Autobahn
<http://www.tavendo.de/autobahn/testsuite.html>`_'s fuzzing tests (aside from
two UTF-8 ones where it is merely *non-strict*. tests 6.4.2 and 6.4.4)
Features/Design
---------------
- TLS (wss) support. It uses CFStream so we get this for *free*
- Uses NSStream/CFNetworking. Earlier implementations used ``dispatch_io``,
however, this proved to be make TLS nearly impossible. Also I wanted this to
work in iOS 4.x. (SocketRocket only supports 5.0 and above now)
- Uses ARC. It uses the 4.0 compatible subset (no weak refs).
- Seems to perform quite well
- Parallel architecture. Most of the work is done in background worker queues.
- Delegate-based. Had older versions that could use blocks too, but I felt it
didn't blend well with retain cycles and just objective C in general.
Changes
-------
v0.3.1-beta2 - 2013-01-12
`````````````````````````
- Stability fix for ``closeWithCode:reason:`` (Thanks @michaelpetrov!)
- Actually clean up the NSStreams and remove them from their runloops
- ``_SRRunLoopThread``'s ``main`` wasn't correctly wrapped with
``@autoreleasepool``
v0.3.1-beta1 - 2013-01-12
`````````````````````````
- Cleaned up GCD so OS_OBJECT_USE_OBJC_RETAIN_RELEASE is optional
- Removed deprecated ``dispatch_get_current_queue`` in favor of ``dispatch_queue_set_specific`` and ``dispatch_get_specific``
- Dropping support for iOS 4.0 (it may still work)
Installing (iOS)
----------------
There's a few options. Choose one, or just figure it out
- You can copy all the files in the SocketRocket group into your app.
- Include SocketRocket as a subproject and use libSocketRocket
If you do this, you must add -ObjC to your "other linker flags" option
- For OS X you will have to repackage make a .framework target. I will take
contributions. Message me if you are interested.
Depending on how you configure your project you may need to ``#import`` either
``<SocketRocket/SRWebSocket.h>`` or ``"SRWebSocket.h"``
Framework Dependencies
``````````````````````
Your .app must be linked against the following frameworks/dylibs
- libicucore.dylib
- CFNetwork.framework
- Security.framework
- Foundation.framework
Installing (OS X)
-----------------
SocketRocket now has (64-bit only) OS X support. ``SocketRocket.framework``
inside Xcode project is for OS X only. It should be identical in function aside
from the unicode validation. ICU isn't shipped with OS X which is what the
original implementation used for unicode validation. The workaround is much
more rudimentary and less robust.
1. Add SocketRocket.xcodeproj as either a subproject of your app or in your workspace.
2. Add ``SocketRocket.framework`` to the link libraries
3. If you don't have a "copy files" step for ``Framework``, create one
4. Add ``SocketRocket.framework`` to the "copy files" step.
API
---
The classes
``SRWebSocket``
```````````````
The Web Socket.
.. note:: ``SRWebSocket`` will retain itself between ``-(void)open`` and when it
closes, errors, or fails. This is similar to how ``NSURLConnection`` behaves.
(unlike ``NSURLConnection``, ``SRWebSocket`` won't retain the delegate)
What you need to know
.. code-block:: objective-c
@interface SRWebSocket : NSObject
// Make it with this
- (id)initWithURLRequest:(NSURLRequest *)request;
// Set this before opening
@property (nonatomic, assign) id <SRWebSocketDelegate> delegate;
- (void)open;
// Close it with this
- (void)close;
// Send a UTF8 String or Data
- (void)send:(id)data;
@end
``SRWebSocketDelegate``
```````````````````````
You implement this
.. code-block:: objective-c
@protocol SRWebSocketDelegate <NSObject>
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
@optional
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
@end
Known Issues/Server Todo's
--------------------------
- Needs auth delegates (like in NSURLConnection)
- Move the streams off the main runloop (most of the work is backgrounded uses
GCD, but I just haven't gotten around to moving it off the main loop since I
converted it from dispatch_io)
- Re-implement server. I removed an existing implementation as well because it
wasn't being used and I wasn't super happy with the interface. Will revisit
this.
- Separate framer and client logic. This will make it nicer when having a
server.
Testing
-------
Included are setup scripts for the python testing environment. It comes
packaged with vitualenv so all the dependencies are installed in userland.
To run the short test from the command line, run::
make test
To run all the tests, run::
make test_all
The short tests don't include the performance tests. (the test harness is
actually the bottleneck, not SocketRocket).
The first time this is run, it may take a while to install the dependencies. It
will be smooth sailing after that. After the test runs the makefile will open
the results page in your browser. If nothing comes up, you failed. Working on
making this interface a bit nicer.
To run from the app, choose the ``SocketRocket`` target and run the test action
(``cmd+u``). It runs the same thing, but makes it easier to debug. There is
some serious pre/post hooks in the Test action. You can edit it to customize
behavior.
.. note:: Xcode only up to version 4.4 is currently supported for the test
harness
TestChat Demo Application
-------------------------
SocketRocket includes a demo app, TestChat. It will "chat" with a listening
websocket on port 9900.
It's a simple project. Uses storyboard. Storyboard is sweet.
TestChat Server
```````````````
We've included a small server for the chat app. It has a simple function.
It will take a message and broadcast it to all other connected clients.
We have to get some dependencies. We also want to reuse the virtualenv we made
when we ran the tests. If you haven't run the tests yet, go into the
SocketRocket root directory and type::
make test
This will set up your `virtualenv <http://pypi.python.org/pypi/virtualenv>`_.
Now, in your terminal::
source .env/bin/activate
pip install git+https://github.com/facebook/tornado.git
In the same terminal session, start the chatroom server::
python TestChatServer/py/chatroom.py
There's also a Go implementation (with the latest weekly) where you can::
cd TestChatServer/go
go run chatroom.go
Chatting
````````
Now, start TestChat.app (just run the target in the XCode project). If you had
it started already you can hit the refresh button to reconnect. It should say
"Connected!" on top.
To talk with the app, open up your browser to `http://localhost:9000 <http://localhost:9000>`_ and
start chatting.
WebSocket Server Implementation Recommendations
-----------------------------------------------
SocketRocket has been used with the following libraries:
- `Tornado <https://github.com/facebook/tornado>`_
- Go's `WebSocket package <http://godoc.org/code.google.com/p/go.net/websocket>`_ or Gorilla's `version <http://www.gorillatoolkit.org/pkg/websocket>`_
- `Autobahn <http://www.tavendo.de/autobahn/testsuite.html>`_ (using its fuzzing
client)
The Tornado one is dirt simple and works like a charm. (`IPython notebook
<http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html>`_ uses it
too). It's much easier to configure handlers and routes than in
Autobahn/twisted.
As far as Go's goes, it works in my limited testing. I much prefer go's
concurrency model as well. Try it! You may like it.
It could use some more control over things such as pings, etc., but I
am sure it will come in time.
Autobahn is a great test suite. The Python server code is good, and conforms
well (obviously). However for me, twisted would be a deal-breaker for writing
something new. I find it a bit too complex and heavy for a simple service. If
you are already using twisted though, Autobahn is probably for you.
Contributing
------------
Any contributors to the master SocketRocket repository must sign the `Individual
Contributor License Agreement
(CLA)
<https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1>`_.
It's a short form that covers our bases and makes sure you're eligible to
contribute.
When you have a change you'd like to see in the master repository, `send a pull
request <https://github.com/square/SocketRocket/pulls>`_. Before we merge your
request, we'll make sure you're in the list of people who have signed a CLA.

View File

@ -1,339 +0,0 @@
//
// Copyright 2012 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <XCTest/XCTest.h>
#import <XCTest/XCTestRun.h>
#import "SRWebSocket.h"
#import "SRTWebSocketOperation.h"
#import "SenTestCase+SRTAdditions.h"
#define SRLogDebug(format, ...)
//#define SRLogDebug(format, ...) NSLog(format, __VA_ARGS__)
@interface SRTAutobahnTests : XCTestCase
@end
@interface TestOperation : SRTWebSocketOperation <SRWebSocketDelegate>
- (id)initWithBaseURL:(NSURL *)url testNumber:(NSInteger)testNumber agent:(NSString *)agent;
@end
@interface CaseGetterOperation : SRTWebSocketOperation <SRWebSocketDelegate>
- (id)initWithBaseURL:(NSURL *)url;
@property (nonatomic, readonly) NSInteger caseCount;
@end
@interface NSInvocation (SRTBlockInvocation)
+ (NSInvocation *)invocationWithBlock:(dispatch_block_t)block;
@end
@interface SRTBlockInvoker
- (id)initWithBlock:(dispatch_block_t)block;
- (void)invoke;
@end
@interface UpdateOperation : SRTWebSocketOperation <SRWebSocketDelegate>
- (id)initWithBaseURL:(NSURL *)url agent:(NSString *)agent;
@end
@interface TestInfoOperation : SRTWebSocketOperation <SRWebSocketDelegate>
@property (nonatomic) NSDictionary *info;
- (id)initWithBaseURL:(NSURL *)url caseNumber:(NSInteger)caseNumber;
@end
@interface TestResultsOperation : SRTWebSocketOperation <SRWebSocketDelegate>
@property (nonatomic) NSDictionary *info;
- (id)initWithBaseURL:(NSURL *)url caseNumber:(NSInteger)caseNumber agent:(NSString *)agent;
@end
@implementation SRTAutobahnTests {
SRWebSocket *_curWebSocket;
NSInteger _testCount;
NSInteger _curTest;
NSMutableArray *_sockets;
NSString *_testURLString;
NSURL *_prefixURL;
NSString *_agent;
NSString *_description;
}
- (id)initWithInvocation:(NSInvocation *)anInvocation description:(NSString *)description;
{
self = [self initWithInvocation:anInvocation];
if (self) {
_description = description;
}
return self;
}
- (id)initWithInvocation:(NSInvocation *)anInvocation;
{
self = [super initWithInvocation:anInvocation];
if (self) {
_testURLString = [[NSProcessInfo processInfo].environment objectForKey:@"SR_TEST_URL"];
_prefixURL = [NSURL URLWithString:_testURLString];
_agent = [NSBundle bundleForClass:[self class]].bundleIdentifier;
}
return self;
}
- (NSUInteger)testCaseCount;
{
return 0;
if (self.invocation) {
return [super testCaseCount];
}
CaseGetterOperation *caseGetter = [[CaseGetterOperation alloc] initWithBaseURL:_prefixURL];
[caseGetter start];
[self runCurrentRunLoopUntilTestPasses:^BOOL{
return caseGetter.isFinished;
} timeout:20.0];
XCTAssertNil(caseGetter.error, @"CaseGetter should have successfully returned the number of testCases. Instead got error %@", caseGetter.error);
NSInteger caseCount = caseGetter.caseCount;
return caseCount;
}
- (BOOL)isEmpty;
{
return NO;
}
- (void)performTest:(XCTestCaseRun *) aRun
{
if (self.invocation) {
[super performTest:aRun];
return;
}
[aRun start];
for (NSUInteger i = 1; i <= aRun.test.testCaseCount; i++) {
SEL sel = @selector(performTestWithNumber:);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:sel]];
invocation.selector = sel;
invocation.target = self;
[invocation setArgument:&i atIndex:2];
NSString *description = [self caseDescriptionForCaseNumber:i];
XCTestCase *testCase = [[[self class] alloc] initWithInvocation:invocation description:description];
XCTestCaseRun *run = [[XCTestCaseRun alloc] initWithTest:testCase];
[testCase performTest:run];
}
[aRun stop];
[self updateReports];
}
- (NSInteger)testNum;
{
NSInteger i;
[self.invocation getArgument:&i atIndex:2];
return i;
}
- (NSString *)caseDescriptionForCaseNumber:(NSInteger)caseNumber;
{
TestInfoOperation *testInfoOperation = [[TestInfoOperation alloc] initWithBaseURL:_prefixURL caseNumber:caseNumber];
[testInfoOperation start];
[self runCurrentRunLoopUntilTestPasses:^BOOL{
return testInfoOperation.isFinished;
} timeout:60 * 60];
XCTAssertNil(testInfoOperation.error, @"Updating the report should not have errored");
return [NSString stringWithFormat:@"%@ - %@", [testInfoOperation.info objectForKey:@"id"], [testInfoOperation.info objectForKey:@"description"]];
}
- (NSString *)description;
{
if (_description) {
return _description;
} else {
return @"Autobahn Test Harness";
}
}
+ (id) defaultTestSuite
{
return [[[self class] alloc] init];
}
- (void)performTestWithNumber:(NSInteger)testNumber;
{
NSOperationQueue *testQueue = [[NSOperationQueue alloc] init];
testQueue.maxConcurrentOperationCount = 1;
TestOperation *testOp = [[TestOperation alloc] initWithBaseURL:_prefixURL testNumber:testNumber agent:_agent];
[testQueue addOperation:testOp];
TestResultsOperation *resultOp = [[TestResultsOperation alloc] initWithBaseURL:_prefixURL caseNumber:testNumber agent:_agent];
[resultOp addDependency:testOp];
[testQueue addOperation:resultOp];
testQueue.suspended = NO;
[self runCurrentRunLoopUntilTestPasses:^BOOL{
return resultOp.isFinished;
} timeout:60 * 60];
XCTAssertTrue(!testOp.error, @"Test operation should not have failed");
XCTAssertEqualObjects(@"OK", [resultOp.info objectForKey:@"behavior"], @"Test behavior should be OK");
}
- (void)updateReports;
{
UpdateOperation *updateReportOperation = [[UpdateOperation alloc] initWithBaseURL:_prefixURL agent:_agent];
[updateReportOperation start];
[self runCurrentRunLoopUntilTestPasses:^BOOL{
return updateReportOperation.isFinished;
} timeout:60 * 60];
XCTAssertNil(updateReportOperation.error, @"Updating the report should not have errored");
}
@end
@implementation TestOperation {
NSInteger _testNumber;
}
- (id)initWithBaseURL:(NSURL *)url testNumber:(NSInteger)testNumber agent:(NSString *)agent;
{
NSString *path = [[url URLByAppendingPathComponent:@"runCase"] absoluteString];
path = [path stringByAppendingFormat:@"?case=%@&agent=%@", @(testNumber), agent];
self = [super initWithURL:[NSURL URLWithString:path]];
if (self) {
_testNumber = testNumber;
}
return self;
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
{
[webSocket send:message];
}
@end
@implementation CaseGetterOperation
@synthesize caseCount = _caseCount;
- (id)initWithBaseURL:(NSURL *)url;
{
self = [super initWithURL:[url URLByAppendingPathComponent:@"getCaseCount"]];
if (self) {
}
return self;
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
{
_caseCount = [message integerValue];
}
@end
@implementation UpdateOperation
- (id)initWithBaseURL:(NSURL *)url agent:(NSString *)agent;
{
NSString *path = [[url URLByAppendingPathComponent:@"updateReports"] absoluteString];
path = [path stringByAppendingFormat:@"?agent=%@", agent];
return [super initWithURL:[NSURL URLWithString:path]];
}
- (void)start;
{
[super start];
NSLog(@"Updating Reports!");
}
@end
@implementation TestInfoOperation
@synthesize info = _info;
- (id)initWithBaseURL:(NSURL *)url caseNumber:(NSInteger)caseNumber;
{
NSString *path = [[url URLByAppendingPathComponent:@"getCaseInfo"] absoluteString];
path = [path stringByAppendingFormat:@"?case=%@", @(caseNumber)];
return [super initWithURL:[NSURL URLWithString:path]];
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(NSString *)message;
{
self.info = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:0 error:NULL];
}
@end
@implementation TestResultsOperation
@synthesize info = _info;
- (id)initWithBaseURL:(NSURL *)url caseNumber:(NSInteger)caseNumber agent:(NSString *)agent;
{
NSString *path = [[url URLByAppendingPathComponent:@"getCaseStatus"] absoluteString];
path = [path stringByAppendingFormat:@"?case=%@&agent=%@", @(caseNumber), agent];
return [super initWithURL:[NSURL URLWithString:path]];
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(NSString *)message;
{
self.info = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:0 error:NULL];
}
@end

View File

@ -1,26 +0,0 @@
//
// SRTWebSocketOperation.h
// SocketRocket
//
// Created by Mike Lewis on 1/28/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SRWebSocket.h"
@interface SRTWebSocketOperation : NSOperation <SRWebSocketDelegate>
- (id)initWithURL:(NSURL *)URL;
@property (nonatomic) BOOL isFinished;
@property (nonatomic) BOOL isExecuting;
@property (nonatomic, readonly, retain) NSError *error;
// We override these methods. Please call super
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
@end

View File

@ -1,21 +0,0 @@
//
// Copyright 2012 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "SenTestCase+SRTAdditions.h"
#endif

View File

@ -1,13 +0,0 @@
//
// STRDispatchTest.h
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#import <SenTestingKit/SenTestingKit.h>
@interface STRDispatchTest : SenTestCase
@end

View File

@ -1,151 +0,0 @@
//
// STRDispatchTest.m
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
extern "C" {
#import <SenTestingKit/SenTestingKit.h>
}
#include <Security/SecureTransport.h>
#include "DispatchIO.h"
#include "DispatchData.h"
#include "SecureIO.h"
using namespace squareup::dispatch;
@interface STRDispatchTest : SenTestCase
@end
@implementation STRDispatchTest
- (void)testConnect;
{
bool finished = false;
dispatch_queue_t workQueue = dispatch_queue_create("dispatch queue", DISPATCH_QUEUE_SERIAL);
Dial(workQueue, "localhost", "9932", dispatch_get_main_queue(), [&](dispatch_fd_t fd, int error_code, const char *error_message) {
NSLog(@"code: %d, msg: %s", error_code, error_message);
STAssertEquals(error_code, 0, @"Should not error but got %s", error_message);
finished = true;
});
[self runCurrentRunLoopUntilTestPasses:[&finished](){
return (BOOL)finished;
} timeout:100.0];
}
- (void)testSimpleDial;
{
RawIO *raw_io = nullptr;
bool finished = false;
auto cleanupBlock = [&finished](int error) {
finished = true;
};
SimpleDial("localhost", "9934", dispatch_get_main_queue(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [&raw_io, self, &finished](squareup::dispatch::RawIO *io, int error, const char *error_message) {
STAssertEquals(error, 0, @"Should not have errored, but got %s", error_message);
STAssertTrue(io != nullptr, @"io should be valid");
if (!io) {
finished = true;
return;
}
raw_io = io;
io->Write(Data("HELLO THERE!", dispatch_get_main_queue()), dispatch_get_main_queue(), [self, &raw_io](bool done, dispatch_data_t data, int error) {
STAssertEquals(error, 0, @"Error should == 0");
if (done) {
raw_io->Close(0);
}
});
}, cleanupBlock);
[self runCurrentRunLoopUntilTestPasses:[&finished](){
return (BOOL)finished;
} timeout:100.0];
}
- (void)testDialTLS;
{
SecureIO *raw_io = nullptr;
bool finished = false;
auto cleanupBlock = [&finished, raw_io](int error) {
dispatch_async(dispatch_get_main_queue(), [raw_io]{
delete raw_io;
});
NSLog(@"FINISHED");
finished = true;
};
SSLContextRef ctx = SSLCreateContext(CFAllocatorGetDefault(), kSSLClientSide, kSSLStreamType);
DialTLS("10.0.1.15", "10248", ctx, dispatch_get_main_queue(), dispatch_get_main_queue(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [&raw_io, self, &finished](squareup::dispatch::SecureIO *io, int error, const char *error_message) {
STAssertEquals(error, 0, @"Should not have errored, but got %s", error_message);
STAssertTrue(io != nullptr, @"io should be valid");
if (!io) {
finished = true;
return;
}
raw_io = io;
__block bool seenInner = false;
__block bool seenOuter = false;
//
// raw_io->Write(Data("HELLO THERE!\n", dispatch_get_main_queue()), ^(bool done, dispatch_data_t data, int error) {
// STAssertEquals(error, 0, @"Error should == 0");
// STAssertFalse(seenOuter, @"Should only see the outer once");
// if (done) {
// seenOuter = true;
// }
// if (done && !error) {
//
// }
// });
//
// raw_io->Write(Data("HELLO THERE2!\n", dispatch_get_main_queue()), ^(bool done, dispatch_data_t data, int error) {
// STAssertFalse(seenInner, @"Shouldn't have seen inner yet");
// if (done) {
// seenInner = done;
// }
// STAssertEquals(error, 0, @"Error should == 0");
// STAssertFalse(finished, @"Shouldn't have finished");
// });
raw_io->Read(SIZE_MAX, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) {
if (!error) {
raw_io->Write(data, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) {
});
} else {
STAssertTrue(error == ECANCELED, @"Server should terminate");
if (done && !error) {
raw_io->Close(0);
}
}
});
}, cleanupBlock);
[self runCurrentRunLoopUntilTestPasses:[&finished](){
return (BOOL)finished;
} timeout:100.0];
}
@end

View File

@ -1,27 +0,0 @@
//
// Copyright 2012 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <XCTest/XCTest.h>
typedef BOOL (^PXPredicateBlock)();
@interface XCTest (PXAdditions)
- (void)runCurrentRunLoopUntilTestPasses:(PXPredicateBlock)predicate timeout:(NSTimeInterval)timeout;
@end

View File

@ -1,38 +0,0 @@
//
// Copyright 2012 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "SenTestCase+SRTAdditions.h"
@implementation XCTestCase (SRTAdditions)
- (void)runCurrentRunLoopUntilTestPasses:(PXPredicateBlock)predicate timeout:(NSTimeInterval)timeout;
{
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
NSTimeInterval timeoutTime = [timeoutDate timeIntervalSinceReferenceDate];
NSTimeInterval currentTime;
for (currentTime = [NSDate timeIntervalSinceReferenceDate];
!predicate() && currentTime < timeoutTime;
currentTime = [NSDate timeIntervalSinceReferenceDate]) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
XCTAssertTrue(currentTime <= timeoutTime, @"Timed out");
}
@end

View File

@ -1,2 +0,0 @@
/* Localized versions of Info.plist keys */

View File

@ -1,8 +0,0 @@
//
// foo.m
// SocketRocket
//
// Created by Mike Lewis on 10/31/11.
// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

View File

@ -1,19 +1,22 @@
Pod::Spec.new do |s|
s.name = "SocketRocket"
s.version = '0.4'
s.summary = 'A conforming WebSocket (RFC 6455) client library.'
s.homepage = 'https://github.com/square/SocketRocket'
s.authors = 'Square'
s.license = 'Apache License, Version 2.0'
s.source = { :git => 'https://github.com/square/SocketRocket.git', :tag => s.version.to_s }
s.source_files = 'SocketRocket/*.{h,m}'
s.name = 'SocketRocket'
s.version = '0.5.1'
s.summary = 'A conforming WebSocket (RFC 6455) client library for iOS, macOS and tvOS.'
s.homepage = 'https://github.com/facebook/SocketRocket'
s.authors = { 'Nikita Lutsenko' => 'nlutsenko@me.com', 'Dan Federman' => 'federman@squareup.com', 'Mike Lewis' => 'mikelikespie@gmail.com' }
s.license = 'BSD'
s.source = { :git => 'https://github.com/facebook/SocketRocket.git', :tag => s.version.to_s }
s.requires_arc = true
s.source_files = 'SocketRocket/**/*.{h,m}'
s.public_header_files = 'SocketRocket/*.h'
s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'
s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'
s.tvos.deployment_target = '9.0'
s.ios.frameworks = 'CFNetwork', 'Security'
s.osx.frameworks = 'CoreServices', 'Security'
s.libraries = "icucore"
s.tvos.frameworks = 'CFNetwork', 'Security'
s.libraries = 'icucore'
end

File diff suppressed because it is too large Load Diff

View File

@ -1,878 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
<<<<<<< HEAD
2725F85B16A29D18007018E9 /* SecureIO.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2725F85916A29D18007018E9 /* SecureIO.mm */; };
2725F85C16A29D18007018E9 /* SecureIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 2725F85A16A29D18007018E9 /* SecureIO.h */; };
27CA136116A21E4D00A35C2D /* DispatchIO.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27CA135F16A21E4D00A35C2D /* DispatchIO.mm */; };
27CA136216A21E4D00A35C2D /* DispatchIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 27CA136016A21E4D00A35C2D /* DispatchIO.h */; };
27CA136616A2243000A35C2D /* DispatchData.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27CA136416A2243000A35C2D /* DispatchData.mm */; };
27CA136716A2243000A35C2D /* DispatchData.h in Headers */ = {isa = PBXBuildFile; fileRef = 27CA136516A2243000A35C2D /* DispatchData.h */; };
27CA136A16A23AAE00A35C2D /* STRDispatchTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27CA136916A23AAE00A35C2D /* STRDispatchTest.mm */; };
27DC4A9516A64EB800E9C084 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DC4A9416A64EB800E9C084 /* Common.h */; };
F6016C7C146124B20037BB3D /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = F6016C7B146124B20037BB3D /* base64.c */; };
F6016C7F146124ED0037BB3D /* base64.h in Headers */ = {isa = PBXBuildFile; fileRef = F6016C7E146124ED0037BB3D /* base64.h */; };
=======
>>>>>>> origin/master
F6016C8814620EC70037BB3D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD3145122FC00C1D980 /* Security.framework */; };
F6016C8914620ECC0037BB3D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD3145122FC00C1D980 /* Security.framework */; };
F6016C8A1462143C0037BB3D /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD51451231B00C1D980 /* CFNetwork.framework */; };
F60CC2A114D4EA0500A005E4 /* SRTWebSocketOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F60CC2A014D4EA0500A005E4 /* SRTWebSocketOperation.m */; };
F61A0DC81625F44D00365EBD /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F61A0DC71625F44D00365EBD /* Default-568h@2x.png */; };
F62417E614D52F3C003CE997 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F62417E514D52F3C003CE997 /* UIKit.framework */; };
F62417E714D52F3C003CE997 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B208301450F597009315AF /* Foundation.framework */; };
F62417E914D52F3C003CE997 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F62417E814D52F3C003CE997 /* CoreGraphics.framework */; };
F62417EF14D52F3C003CE997 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F62417ED14D52F3C003CE997 /* InfoPlist.strings */; };
F62417F114D52F3C003CE997 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F62417F014D52F3C003CE997 /* main.m */; };
F62417F514D52F3C003CE997 /* TCAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = F62417F414D52F3C003CE997 /* TCAppDelegate.mm */; };
F62417F814D52F3C003CE997 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F62417F614D52F3C003CE997 /* MainStoryboard.storyboard */; };
F62417FB14D52F3C003CE997 /* TCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F62417FA14D52F3C003CE997 /* TCViewController.m */; };
F624180114D5300C003CE997 /* TCChatCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F624180014D5300C003CE997 /* TCChatCell.m */; };
F624180214D532E0003CE997 /* libSocketRocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B2082D1450F597009315AF /* libSocketRocket.a */; };
F624180314D53449003CE997 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD51451231B00C1D980 /* CFNetwork.framework */; };
F624180414D53449003CE997 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD3145122FC00C1D980 /* Security.framework */; };
F624180614D53451003CE997 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F6C41C95145F7C4700641356 /* libicucore.dylib */; };
<<<<<<< HEAD
F6396B86153E67EC00345B5E /* SRWebSocket.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6A12CD0145119B700C1D980 /* SRWebSocket.mm */; };
F6396B87153E67EC00345B5E /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = F6016C7B146124B20037BB3D /* base64.c */; };
F6396B88153E67EC00345B5E /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = F6572124146C7B6A00D6B8A9 /* NSData+SRB64Additions.m */; };
F6572126146C7B6A00D6B8A9 /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = F6572124146C7B6A00D6B8A9 /* NSData+SRB64Additions.m */; };
=======
F6396B86153E67EC00345B5E /* SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = F6A12CD0145119B700C1D980 /* SRWebSocket.m */; };
>>>>>>> origin/master
F668C899153E923C0044DBAC /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6396BA4153E6D7400345B5E /* CoreServices.framework */; };
F668C89A153E923C0044DBAC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6396BA1153E6D4800345B5E /* Foundation.framework */; };
F668C89B153E923C0044DBAC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6396B9F153E6D3700345B5E /* Security.framework */; };
F668C8AA153E92F90044DBAC /* SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = F6A12CCF145119B700C1D980 /* SRWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
<<<<<<< HEAD
F6A12CD1145119B700C1D980 /* SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = F6A12CCF145119B700C1D980 /* SRWebSocket.h */; };
F6A12CD2145119B700C1D980 /* SRWebSocket.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6A12CD0145119B700C1D980 /* SRWebSocket.mm */; };
=======
F6A12CD1145119B700C1D980 /* SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = F6A12CCF145119B700C1D980 /* SRWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
F6A12CD2145119B700C1D980 /* SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = F6A12CD0145119B700C1D980 /* SRWebSocket.m */; };
>>>>>>> origin/master
F6AE451D145906A70022AF3C /* libSocketRocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B2082D1450F597009315AF /* libSocketRocket.a */; };
F6AE4520145906B20022AF3C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B208301450F597009315AF /* Foundation.framework */; };
F6AE45241459071C0022AF3C /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6A12CD51451231B00C1D980 /* CFNetwork.framework */; };
F6AE4528145907D30022AF3C /* SenTestCase+SRTAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = F6AE4527145907D30022AF3C /* SenTestCase+SRTAdditions.m */; };
F6BDA806145900D200FE3253 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B208301450F597009315AF /* Foundation.framework */; };
F6BDA80C145900D200FE3253 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F6BDA80A145900D200FE3253 /* InfoPlist.strings */; };
F6BDA8161459016900FE3253 /* SRTAutobahnTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F6BDA8151459016900FE3253 /* SRTAutobahnTests.m */; };
F6C41C98145F7C6100641356 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F6C41C95145F7C4700641356 /* libicucore.dylib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F62417D514D50869003CE997 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F6B208241450F597009315AF /* Project object */;
proxyType = 1;
remoteGlobalIDString = F6B2082C1450F597009315AF;
remoteInfo = SocketRocket;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
<<<<<<< HEAD
2725F85916A29D18007018E9 /* SecureIO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SecureIO.mm; sourceTree = "<group>"; };
2725F85A16A29D18007018E9 /* SecureIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecureIO.h; sourceTree = "<group>"; };
27CA135F16A21E4D00A35C2D /* DispatchIO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DispatchIO.mm; sourceTree = "<group>"; };
27CA136016A21E4D00A35C2D /* DispatchIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchIO.h; sourceTree = "<group>"; };
27CA136416A2243000A35C2D /* DispatchData.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DispatchData.mm; sourceTree = "<group>"; };
27CA136516A2243000A35C2D /* DispatchData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchData.h; sourceTree = "<group>"; };
27CA136916A23AAE00A35C2D /* STRDispatchTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = STRDispatchTest.mm; sourceTree = "<group>"; };
27DC4A9416A64EB800E9C084 /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
F6016C7B146124B20037BB3D /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
F6016C7E146124ED0037BB3D /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = "<group>"; };
=======
>>>>>>> origin/master
F60CC29F14D4EA0500A005E4 /* SRTWebSocketOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRTWebSocketOperation.h; sourceTree = "<group>"; };
F60CC2A014D4EA0500A005E4 /* SRTWebSocketOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRTWebSocketOperation.m; sourceTree = "<group>"; };
F61A0DC71625F44D00365EBD /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "en.lproj/Default-568h@2x.png"; sourceTree = "<group>"; };
F62417E314D52F3C003CE997 /* TestChat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestChat.app; sourceTree = BUILT_PRODUCTS_DIR; };
F62417E514D52F3C003CE997 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
F62417E814D52F3C003CE997 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
F62417EC14D52F3C003CE997 /* TestChat-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestChat-Info.plist"; sourceTree = "<group>"; };
F62417EE14D52F3C003CE997 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
F62417F014D52F3C003CE997 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
F62417F214D52F3C003CE997 /* TestChat-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TestChat-Prefix.pch"; sourceTree = "<group>"; };
F62417F314D52F3C003CE997 /* TCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TCAppDelegate.h; sourceTree = "<group>"; };
F62417F414D52F3C003CE997 /* TCAppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TCAppDelegate.mm; sourceTree = "<group>"; };
F62417F714D52F3C003CE997 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = "<group>"; };
F62417F914D52F3C003CE997 /* TCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TCViewController.h; sourceTree = "<group>"; };
F62417FA14D52F3C003CE997 /* TCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TCViewController.m; sourceTree = "<group>"; };
F62417FF14D5300C003CE997 /* TCChatCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TCChatCell.h; sourceTree = "<group>"; };
F624180014D5300C003CE997 /* TCChatCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TCChatCell.m; sourceTree = "<group>"; };
F6396B9F153E6D3700345B5E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
F6396BA1153E6D4800345B5E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
F6396BA4153E6D7400345B5E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = DEVELOPER_DIR; };
F668C880153E91210044DBAC /* SocketRocket.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketRocket.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F668C884153E91210044DBAC /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
F668C885153E91210044DBAC /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
F668C886153E91210044DBAC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
F668C889153E91210044DBAC /* SocketRocketOSX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SocketRocketOSX-Info.plist"; sourceTree = "<group>"; };
F6A12CCF145119B700C1D980 /* SRWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRWebSocket.h; sourceTree = "<group>"; };
F6A12CD0145119B700C1D980 /* SRWebSocket.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SRWebSocket.mm; sourceTree = "<group>"; };
F6A12CD3145122FC00C1D980 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
F6A12CD51451231B00C1D980 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
F6AE4526145907D30022AF3C /* SenTestCase+SRTAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SenTestCase+SRTAdditions.h"; sourceTree = "<group>"; };
F6AE4527145907D30022AF3C /* SenTestCase+SRTAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SenTestCase+SRTAdditions.m"; sourceTree = "<group>"; };
F6B2082D1450F597009315AF /* libSocketRocket.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSocketRocket.a; sourceTree = BUILT_PRODUCTS_DIR; };
F6B208301450F597009315AF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
F6B208341450F597009315AF /* SocketRocket-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketRocket-Prefix.pch"; sourceTree = "<group>"; };
F6BDA802145900D200FE3253 /* SRWebSocketTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SRWebSocketTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F6BDA809145900D200FE3253 /* SRWebSocketTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SRWebSocketTests-Info.plist"; sourceTree = "<group>"; };
F6BDA80B145900D200FE3253 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
F6BDA810145900D200FE3253 /* SRWebSocketTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SRWebSocketTests-Prefix.pch"; sourceTree = "<group>"; };
F6BDA8151459016900FE3253 /* SRTAutobahnTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRTAutobahnTests.m; sourceTree = "<group>"; };
F6C41C95145F7C4700641356 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F62417E014D52F3C003CE997 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F62417E614D52F3C003CE997 /* UIKit.framework in Frameworks */,
F62417E714D52F3C003CE997 /* Foundation.framework in Frameworks */,
F62417E914D52F3C003CE997 /* CoreGraphics.framework in Frameworks */,
F624180214D532E0003CE997 /* libSocketRocket.a in Frameworks */,
F624180314D53449003CE997 /* CFNetwork.framework in Frameworks */,
F624180414D53449003CE997 /* Security.framework in Frameworks */,
F624180614D53451003CE997 /* libicucore.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F668C87C153E91210044DBAC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F668C899153E923C0044DBAC /* CoreServices.framework in Frameworks */,
F668C89A153E923C0044DBAC /* Foundation.framework in Frameworks */,
F668C89B153E923C0044DBAC /* Security.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6B2082A1450F597009315AF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F6AE4520145906B20022AF3C /* Foundation.framework in Frameworks */,
F6016C8914620ECC0037BB3D /* Security.framework in Frameworks */,
F6016C8A1462143C0037BB3D /* CFNetwork.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6BDA7FE145900D200FE3253 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F6C41C98145F7C6100641356 /* libicucore.dylib in Frameworks */,
F6BDA806145900D200FE3253 /* Foundation.framework in Frameworks */,
F6AE451D145906A70022AF3C /* libSocketRocket.a in Frameworks */,
F6AE45241459071C0022AF3C /* CFNetwork.framework in Frameworks */,
F6016C8814620EC70037BB3D /* Security.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F62417EA14D52F3C003CE997 /* TestChat */ = {
isa = PBXGroup;
children = (
F62417EB14D52F3C003CE997 /* Supporting Files */,
F62417F314D52F3C003CE997 /* TCAppDelegate.h */,
F62417F414D52F3C003CE997 /* TCAppDelegate.mm */,
F62417F614D52F3C003CE997 /* MainStoryboard.storyboard */,
F62417F914D52F3C003CE997 /* TCViewController.h */,
F62417FA14D52F3C003CE997 /* TCViewController.m */,
F62417FF14D5300C003CE997 /* TCChatCell.h */,
F624180014D5300C003CE997 /* TCChatCell.m */,
);
path = TestChat;
sourceTree = "<group>";
};
F62417EB14D52F3C003CE997 /* Supporting Files */ = {
isa = PBXGroup;
children = (
F61A0DC71625F44D00365EBD /* Default-568h@2x.png */,
F62417EC14D52F3C003CE997 /* TestChat-Info.plist */,
F62417ED14D52F3C003CE997 /* InfoPlist.strings */,
F62417F014D52F3C003CE997 /* main.m */,
F62417F214D52F3C003CE997 /* TestChat-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
F6396BA3153E6D4D00345B5E /* OSX Frameworks */ = {
isa = PBXGroup;
children = (
F6396BA4153E6D7400345B5E /* CoreServices.framework */,
F6396BA1153E6D4800345B5E /* Foundation.framework */,
F6396B9F153E6D3700345B5E /* Security.framework */,
);
name = "OSX Frameworks";
sourceTree = "<group>";
};
F668C883153E91210044DBAC /* Other Frameworks */ = {
isa = PBXGroup;
children = (
F668C884153E91210044DBAC /* AppKit.framework */,
F668C885153E91210044DBAC /* CoreData.framework */,
F668C886153E91210044DBAC /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
F668C887153E91210044DBAC /* SocketRocketOSX */ = {
isa = PBXGroup;
children = (
F668C889153E91210044DBAC /* SocketRocketOSX-Info.plist */,
);
path = SocketRocketOSX;
sourceTree = "<group>";
};
F6B208221450F597009315AF = {
isa = PBXGroup;
children = (
F6B208321450F597009315AF /* SocketRocket */,
F6BDA807145900D200FE3253 /* SRWebSocketTests */,
F62417EA14D52F3C003CE997 /* TestChat */,
F668C887153E91210044DBAC /* SocketRocketOSX */,
F6B2082F1450F597009315AF /* Frameworks */,
F6B2082E1450F597009315AF /* Products */,
);
indentWidth = 4;
sourceTree = "<group>";
tabWidth = 4;
};
F6B2082E1450F597009315AF /* Products */ = {
isa = PBXGroup;
children = (
F6B2082D1450F597009315AF /* libSocketRocket.a */,
F6BDA802145900D200FE3253 /* SRWebSocketTests.xctest */,
F62417E314D52F3C003CE997 /* TestChat.app */,
F668C880153E91210044DBAC /* SocketRocket.framework */,
);
name = Products;
sourceTree = "<group>";
};
F6B2082F1450F597009315AF /* Frameworks */ = {
isa = PBXGroup;
children = (
F6396BA3153E6D4D00345B5E /* OSX Frameworks */,
F6C41C95145F7C4700641356 /* libicucore.dylib */,
F6A12CD51451231B00C1D980 /* CFNetwork.framework */,
F6A12CD3145122FC00C1D980 /* Security.framework */,
F6B208301450F597009315AF /* Foundation.framework */,
F62417E514D52F3C003CE997 /* UIKit.framework */,
F62417E814D52F3C003CE997 /* CoreGraphics.framework */,
F668C883153E91210044DBAC /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
F6B208321450F597009315AF /* SocketRocket */ = {
isa = PBXGroup;
children = (
F6B208331450F597009315AF /* Supporting Files */,
F6A12CCF145119B700C1D980 /* SRWebSocket.h */,
<<<<<<< HEAD
F6A12CD0145119B700C1D980 /* SRWebSocket.mm */,
F6572123146C7B6A00D6B8A9 /* NSData+SRB64Additions.h */,
F6572124146C7B6A00D6B8A9 /* NSData+SRB64Additions.m */,
27CA135F16A21E4D00A35C2D /* DispatchIO.mm */,
27CA136016A21E4D00A35C2D /* DispatchIO.h */,
2725F85916A29D18007018E9 /* SecureIO.mm */,
2725F85A16A29D18007018E9 /* SecureIO.h */,
27CA136416A2243000A35C2D /* DispatchData.mm */,
27CA136516A2243000A35C2D /* DispatchData.h */,
27DC4A9416A64EB800E9C084 /* Common.h */,
=======
F6A12CD0145119B700C1D980 /* SRWebSocket.m */,
>>>>>>> origin/master
);
path = SocketRocket;
sourceTree = "<group>";
};
F6B208331450F597009315AF /* Supporting Files */ = {
isa = PBXGroup;
children = (
F6B208341450F597009315AF /* SocketRocket-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
F6BDA807145900D200FE3253 /* SRWebSocketTests */ = {
isa = PBXGroup;
children = (
F6BDA808145900D200FE3253 /* Supporting Files */,
F6BDA8151459016900FE3253 /* SRTAutobahnTests.m */,
F6BDA810145900D200FE3253 /* SRWebSocketTests-Prefix.pch */,
F6AE4526145907D30022AF3C /* SenTestCase+SRTAdditions.h */,
F6AE4527145907D30022AF3C /* SenTestCase+SRTAdditions.m */,
F60CC29F14D4EA0500A005E4 /* SRTWebSocketOperation.h */,
F60CC2A014D4EA0500A005E4 /* SRTWebSocketOperation.m */,
27CA136916A23AAE00A35C2D /* STRDispatchTest.mm */,
);
path = SRWebSocketTests;
sourceTree = "<group>";
};
F6BDA808145900D200FE3253 /* Supporting Files */ = {
isa = PBXGroup;
children = (
F6BDA809145900D200FE3253 /* SRWebSocketTests-Info.plist */,
F6BDA80A145900D200FE3253 /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
F668C87D153E91210044DBAC /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F668C8AA153E92F90044DBAC /* SRWebSocket.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6B2082B1450F597009315AF /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F6A12CD1145119B700C1D980 /* SRWebSocket.h in Headers */,
<<<<<<< HEAD
F6016C7F146124ED0037BB3D /* base64.h in Headers */,
27CA136216A21E4D00A35C2D /* DispatchIO.h in Headers */,
27CA136716A2243000A35C2D /* DispatchData.h in Headers */,
2725F85C16A29D18007018E9 /* SecureIO.h in Headers */,
27DC4A9516A64EB800E9C084 /* Common.h in Headers */,
=======
>>>>>>> origin/master
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
F62417E214D52F3C003CE997 /* TestChat */ = {
isa = PBXNativeTarget;
buildConfigurationList = F62417FC14D52F3C003CE997 /* Build configuration list for PBXNativeTarget "TestChat" */;
buildPhases = (
F62417DF14D52F3C003CE997 /* Sources */,
F62417E014D52F3C003CE997 /* Frameworks */,
F62417E114D52F3C003CE997 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = TestChat;
productName = TestChat;
productReference = F62417E314D52F3C003CE997 /* TestChat.app */;
productType = "com.apple.product-type.application";
};
F668C87F153E91210044DBAC /* SocketRocketOSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = F668C891153E91210044DBAC /* Build configuration list for PBXNativeTarget "SocketRocketOSX" */;
buildPhases = (
F6396B85153E67EC00345B5E /* Sources */,
F668C87C153E91210044DBAC /* Frameworks */,
F668C87D153E91210044DBAC /* Headers */,
F668C87E153E91210044DBAC /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SocketRocketOSX;
productName = SocketRocketOSX;
productReference = F668C880153E91210044DBAC /* SocketRocket.framework */;
productType = "com.apple.product-type.framework";
};
F6B2082C1450F597009315AF /* SocketRocket */ = {
isa = PBXNativeTarget;
buildConfigurationList = F6B2083A1450F597009315AF /* Build configuration list for PBXNativeTarget "SocketRocket" */;
buildPhases = (
F6B208291450F597009315AF /* Sources */,
F6B2082A1450F597009315AF /* Frameworks */,
F6B2082B1450F597009315AF /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = SocketRocket;
productName = SocketRocket;
productReference = F6B2082D1450F597009315AF /* libSocketRocket.a */;
productType = "com.apple.product-type.library.static";
};
F6BDA801145900D200FE3253 /* SRWebSocketTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = F6BDA813145900D200FE3253 /* Build configuration list for PBXNativeTarget "SRWebSocketTests" */;
buildPhases = (
F6BDA7FD145900D200FE3253 /* Sources */,
F6BDA7FE145900D200FE3253 /* Frameworks */,
F6BDA7FF145900D200FE3253 /* Resources */,
);
buildRules = (
);
dependencies = (
F62417D614D50869003CE997 /* PBXTargetDependency */,
);
name = SRWebSocketTests;
productName = SRWebSocketTests;
productReference = F6BDA802145900D200FE3253 /* SRWebSocketTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F6B208241450F597009315AF /* Project object */ = {
isa = PBXProject;
attributes = {
LastTestingUpgradeCheck = 0640;
LastUpgradeCheck = 0640;
};
buildConfigurationList = F6B208271450F597009315AF /* Build configuration list for PBXProject "SocketRocket" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = F6B208221450F597009315AF;
productRefGroup = F6B2082E1450F597009315AF /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F6B2082C1450F597009315AF /* SocketRocket */,
F668C87F153E91210044DBAC /* SocketRocketOSX */,
F6BDA801145900D200FE3253 /* SRWebSocketTests */,
F62417E214D52F3C003CE997 /* TestChat */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
F62417E114D52F3C003CE997 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F62417EF14D52F3C003CE997 /* InfoPlist.strings in Resources */,
F62417F814D52F3C003CE997 /* MainStoryboard.storyboard in Resources */,
F61A0DC81625F44D00365EBD /* Default-568h@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F668C87E153E91210044DBAC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F6BDA7FF145900D200FE3253 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F6BDA80C145900D200FE3253 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F62417DF14D52F3C003CE997 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F62417F114D52F3C003CE997 /* main.m in Sources */,
F62417F514D52F3C003CE997 /* TCAppDelegate.mm in Sources */,
F62417FB14D52F3C003CE997 /* TCViewController.m in Sources */,
F624180114D5300C003CE997 /* TCChatCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6396B85153E67EC00345B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
<<<<<<< HEAD
F6396B86153E67EC00345B5E /* SRWebSocket.mm in Sources */,
F6396B87153E67EC00345B5E /* base64.c in Sources */,
F6396B88153E67EC00345B5E /* NSData+SRB64Additions.m in Sources */,
=======
F6396B86153E67EC00345B5E /* SRWebSocket.m in Sources */,
>>>>>>> origin/master
);
runOnlyForDeploymentPostprocessing = 0;
};
F6B208291450F597009315AF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
<<<<<<< HEAD
F6A12CD2145119B700C1D980 /* SRWebSocket.mm in Sources */,
F6016C7C146124B20037BB3D /* base64.c in Sources */,
F6572126146C7B6A00D6B8A9 /* NSData+SRB64Additions.m in Sources */,
27CA136116A21E4D00A35C2D /* DispatchIO.mm in Sources */,
27CA136616A2243000A35C2D /* DispatchData.mm in Sources */,
2725F85B16A29D18007018E9 /* SecureIO.mm in Sources */,
=======
F6A12CD2145119B700C1D980 /* SRWebSocket.m in Sources */,
>>>>>>> origin/master
);
runOnlyForDeploymentPostprocessing = 0;
};
F6BDA7FD145900D200FE3253 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F6BDA8161459016900FE3253 /* SRTAutobahnTests.m in Sources */,
F6AE4528145907D30022AF3C /* SenTestCase+SRTAdditions.m in Sources */,
F60CC2A114D4EA0500A005E4 /* SRTWebSocketOperation.m in Sources */,
27CA136A16A23AAE00A35C2D /* STRDispatchTest.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F62417D614D50869003CE997 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F6B2082C1450F597009315AF /* SocketRocket */;
targetProxy = F62417D514D50869003CE997 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
F62417ED14D52F3C003CE997 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F62417EE14D52F3C003CE997 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
F62417F614D52F3C003CE997 /* MainStoryboard.storyboard */ = {
isa = PBXVariantGroup;
children = (
F62417F714D52F3C003CE997 /* en */,
);
name = MainStoryboard.storyboard;
sourceTree = "<group>";
};
F6BDA80A145900D200FE3253 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F6BDA80B145900D200FE3253 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
F62417FD14D52F3C003CE997 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TestChat/TestChat-Prefix.pch";
INFOPLIST_FILE = "TestChat/TestChat-Info.plist";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
F62417FE14D52F3C003CE997 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TestChat/TestChat-Prefix.pch";
INFOPLIST_FILE = "TestChat/TestChat-Info.plist";
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Release;
};
F668C892153E91210044DBAC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"",
);
FRAMEWORK_VERSION = A;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SocketRocket/SocketRocket-Prefix.pch";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INFOPLIST_FILE = "SocketRocketOSX/SocketRocketOSX-Info.plist";
LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = SocketRocket;
SDKROOT = macosx;
WRAPPER_EXTENSION = framework;
};
name = Debug;
};
F668C893153E91210044DBAC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"",
);
FRAMEWORK_VERSION = A;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SocketRocket/SocketRocket-Prefix.pch";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INFOPLIST_FILE = "SocketRocketOSX/SocketRocketOSX-Info.plist";
LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = SocketRocket;
SDKROOT = macosx;
WRAPPER_EXTENSION = framework;
};
name = Release;
};
F6B208381450F597009315AF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
ONLY_ACTIVE_ARCH = YES;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos6.0;
};
name = Debug;
};
F6B208391450F597009315AF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
NDEBUG,
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos6.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
F6B2083B1450F597009315AF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
DSTROOT = /tmp/SocketRocket.dst;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SocketRocket/SocketRocket-Prefix.pch";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/usr/lib/system\"",
"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/usr/lib\"",
);
OTHER_LDFLAGS = "-Licucore";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
F6B2083C1450F597009315AF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
DSTROOT = /tmp/SocketRocket.dst;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SocketRocket/SocketRocket-Prefix.pch";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/usr/lib/system\"",
"\"$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/usr/lib\"",
);
OTHER_LDFLAGS = "-Licucore";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
F6BDA811145900D200FE3253 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SRWebSocketTests/SRWebSocketTests-Prefix.pch";
INFOPLIST_FILE = "SRWebSocketTests/SRWebSocketTests-Info.plist";
OTHER_LDFLAGS = (
"-all_load",
"-ObjC",
"-framework",
XCTest,
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
F6BDA812145900D200FE3253 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SRWebSocketTests/SRWebSocketTests-Prefix.pch";
INFOPLIST_FILE = "SRWebSocketTests/SRWebSocketTests-Info.plist";
OTHER_LDFLAGS = (
"-all_load",
"-ObjC",
"-framework",
XCTest,
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F62417FC14D52F3C003CE997 /* Build configuration list for PBXNativeTarget "TestChat" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F62417FD14D52F3C003CE997 /* Debug */,
F62417FE14D52F3C003CE997 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F668C891153E91210044DBAC /* Build configuration list for PBXNativeTarget "SocketRocketOSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F668C892153E91210044DBAC /* Debug */,
F668C893153E91210044DBAC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F6B208271450F597009315AF /* Build configuration list for PBXProject "SocketRocket" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F6B208381450F597009315AF /* Debug */,
F6B208391450F597009315AF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F6B2083A1450F597009315AF /* Build configuration list for PBXNativeTarget "SocketRocket" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F6B2083B1450F597009315AF /* Debug */,
F6B2083C1450F597009315AF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F6BDA813145900D200FE3253 /* Build configuration list for PBXNativeTarget "SRWebSocketTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F6BDA811145900D200FE3253 /* Debug */,
F6BDA812145900D200FE3253 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F6B208241450F597009315AF /* Project object */;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -14,95 +14,61 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F62417E214D52F3C003CE997"
BuildableName = "TestChat.app"
BlueprintName = "TestChat"
BlueprintIdentifier = "2D4227611BB4358C000C1A6C"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS-Dynamic"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F62417E214D52F3C003CE997"
BuildableName = "TestChat.app"
BlueprintName = "TestChat"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F62417E214D52F3C003CE997"
BuildableName = "TestChat.app"
BlueprintName = "TestChat"
BlueprintIdentifier = "2D4227611BB4358C000C1A6C"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS-Dynamic"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
<<<<<<< HEAD
=======
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
>>>>>>> origin/master
key = "OBJC_PRINT_EXCEPTIONS"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<<<<<<< HEAD
=======
<AdditionalOption
key = "MallocGuardEdges"
value = ""
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "MallocScribble"
value = ""
isEnabled = "YES">
</AdditionalOption>
>>>>>>> origin/master
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F62417E214D52F3C003CE997"
BuildableName = "TestChat.app"
BlueprintName = "TestChat"
BlueprintIdentifier = "2D4227611BB4358C000C1A6C"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS-Dynamic"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0730"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
@ -14,9 +14,9 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6B2082C1450F597009315AF"
BuildableName = "libSocketRocket.a"
BlueprintName = "SocketRocket"
BlueprintIdentifier = "81D6475F1D2CA78800690609"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -25,12 +25,12 @@
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -40,20 +40,19 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "NO">
shouldUseLaunchSchemeArgsEnv = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "PIDFILE=$TMPDIR/srtharness.pid&#10;if [ -r $PIDFILE ]; then&#10; EXISTING_PID=`cat $PIDFILE`&#10; echo &quot;Killing Dangling SRTextharneess PID:&quot; $EXISTING_PID&#10; kill $EXISTING_PID&#10; rm $PIDFILE&#10;fi&#10;&#10;pushd $PROJECT_DIR&#10;&#10;export MACOSX_DEPLOYMENT_TARGET=&#10;&#10;bash TestSupport/ensure_virtualenv.sh $PROJECT_DIR/.env&#10;source .env/bin/activate&#10;&#10;rm -rf &quot;$PROJECT_DIR/reports/clients/&quot;&#10;nohup sr-testharness -i &apos;&apos; -c &apos;*&apos; &amp;&#10;&#10;#nohup sr-testharness -k hello_test_harness -i &apos;&apos; -c &apos;*&apos; &amp;&#10;&#10;echo $! &gt; $PIDFILE&#10;&#10;popd"
shellToInvoke = "/bin/bash">
scriptText = "PIDFILE=$TMPDIR/sr_test_server.pid&#10;&#10;if [ -r $PIDFILE ]; then&#10;EXISTING_PID=`cat $PIDFILE`&#10;echo &quot;Killing Dangling Autobahn Server PID:&quot; $EXISTING_PID&#10;kill $EXISTING_PID || true&#10;rm $PIDFILE&#10;fi&#10;&#10;pushd $PROJECT_DIR&#10;&#10;source .env/bin/activate&#10;nohup ./TestSupport/run_test_server.sh &amp;&#10;&#10;echo $! &gt; $PIDFILE&#10;&#10;popd&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
@ -65,14 +64,13 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "PIDFILE=$TMPDIR/srtharness.pid&#10;if [ -r $PIDFILE ]; then&#10; EXISTING_PID=`cat $PIDFILE`&#10; echo &quot;Killing SRTextharneess PID:&quot; $EXISTING_PID&#10; kill $EXISTING_PID&#10; rm $PIDFILE&#10;fi&#10;&#10;&#10;open $PROJECT_DIR/reports/clients/index.html"
shellToInvoke = "/bin/bash">
scriptText = "PIDFILE=$TMPDIR/sr_test_server.pid&#10;&#10;if [ -r $PIDFILE ]; then&#10;EXISTING_PID=`cat $PIDFILE`&#10;echo &quot;Killing SR TestServer PID:&quot; $EXISTING_PID&#10;kill $EXISTING_PID&#10;rm $PIDFILE&#10;fi&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
@ -85,39 +83,21 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "SRTAutobahnTests">
</Test>
<Test
Identifier = "STRDispatchTest/testConnect">
</Test>
<Test
Identifier = "STRDispatchTest/testSimpleDial">
</Test>
</SkippedTests>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6B2082C1450F597009315AF"
BuildableName = "libSocketRocket.a"
BlueprintName = "SocketRocket"
BlueprintIdentifier = "81D6475F1D2CA78800690609"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "SR_TEST_URL"
value = "ws://localhost:9001"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
@ -134,38 +114,13 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6B2082C1450F597009315AF"
BuildableName = "libSocketRocket.a"
BlueprintName = "SocketRocket"
BlueprintIdentifier = "81D6475F1D2CA78800690609"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
key = "DYLD_INSERT_LIBRARIES"
value = "/usr/lib/libgmalloc.dylib"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "OBJC_PRINT_EXCEPTIONS"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "MallocGuardEdges"
value = ""
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "MallocScribble"
value = ""
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
@ -174,6 +129,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "81D6475F1D2CA78800690609"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "F668C87F153E91210044DBAC"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocketOSX"
BlueprintName = "SocketRocket-macOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -47,7 +47,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "F668C87F153E91210044DBAC"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocketOSX"
BlueprintName = "SocketRocket-macOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -60,6 +60,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F668C87F153E91210044DBAC"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-macOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3345DC821C52ACD70083CCB8"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-tvOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D4227611BB4358C000C1A6C"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-iOS-Dynamic"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3345DC821C52ACD70083CCB8"
BuildableName = "SocketRocket.framework"
BlueprintName = "SocketRocket-tvOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -15,8 +15,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -33,8 +33,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</TestableReference>
@ -56,8 +56,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6BDA801145900D200FE3253"
BuildableName = "SRWebSocketTests.xctest"
BlueprintName = "SRWebSocketTests"
BuildableName = "SocketRocketTests-iOS.xctest"
BlueprintName = "SocketRocketTests-iOS"
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -23,10 +23,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
@ -38,15 +38,18 @@
ReferencedContainer = "container:SocketRocket.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
@ -62,19 +65,30 @@
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "OBJC_PRINT_EXCEPTIONS"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "MallocGuardEdges"
value = ""
isEnabled = "YES">
</AdditionalOption>
<AdditionalOption
key = "MallocScribble"
value = ""
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@ -1,32 +0,0 @@
//
// Common.h
// SocketRocket
//
// Created by Michael Lewis on 1/15/13.
//
//
#ifndef SocketRocket_Common_h
#define SocketRocket_Common_h
#ifdef __cplusplus
extern "C" {
#endif
#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
#define sr_dispatch_retain(x)
#define sr_dispatch_release(x)
#define __sr_maybe_bridge__ __bridge
#define __sr_maybe_strong__ __strong
#else
#define sr_dispatch_retain(x) dispatch_retain(x)
#define sr_dispatch_release(x) dispatch_release(x)
#define __sr_maybe_bridge__
#define __sr_maybe_strong__
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,149 +0,0 @@
//
// DispatchData.h
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#ifndef __SocketRocket__DispatchData__
#define __SocketRocket__DispatchData__
#include <string.h>
#include <iostream>
#include <dispatch/dispatch.h>
#include <deque>
#include "Common.h"
namespace squareup {
namespace dispatch {
class Data {
__sr_maybe_strong__ dispatch_data_t _data;
public:
inline Data() : Data(dispatch_data_empty) {
}
// Initializes a new data. retains the data by default
// Data always releases _data;
inline Data(dispatch_data_t data, bool retain = true) : _data(data) {
if (retain && _data) {
sr_dispatch_retain(_data);
}
}
// Will copy the data
inline Data(const char *str, dispatch_queue_t release_queue) :
_data(dispatch_data_create(reinterpret_cast<const void *>(str), strlen(str), release_queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT)) {
}
// Copy constructor
inline Data(const Data &other) : Data(static_cast<dispatch_data_t>(other), true) {
}
inline Data(const void *bytes, size_t length, dispatch_queue_t release_queue) :
_data(dispatch_data_create(bytes, length, release_queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT)) {
}
inline Data Concat(dispatch_data_t other) const {
return Data(dispatch_data_create_concat(_data, other), false);
}
inline Data operator + (dispatch_data_t other) const {
return Concat(other);
}
inline Data Subrange(size_t offset, size_t length) const {
return Data(dispatch_data_create_subrange(_data, offset, length), false);
}
// copies bytes into the buffer, and returns the remaining.
inline Data TakeInto(size_t length, void *bytes) const {
size_t size = Size();
assert(length <= size);
Apply([&](dispatch_data_t region, size_t offset, const void *buffer, size_t size) -> bool {
size_t numToCopy = std::min(size, length - offset);
memcpy(reinterpret_cast<void *>(reinterpret_cast<uint8_t *>(bytes) + offset), buffer, numToCopy);
return size + offset <= length;
});
if (length == size) {
return dispatch_data_empty;
}
return Subrange(length, size - length);
}
inline Data Map(const void **buffer_ptr, size_t *size_ptr) const {
return Data(dispatch_data_create_map(_data, buffer_ptr, size_ptr), false);
}
inline Data CopyRegion(size_t location, size_t *offset_ptr) const {
return Data(dispatch_data_copy_region(_data, location, offset_ptr), false);
}
inline bool Apply(dispatch_data_applier_t applier) const {
return dispatch_data_apply(_data, applier);
}
inline size_t Size() const {
return dispatch_data_get_size(static_cast<dispatch_data_t>(*this));
}
// This is a workaround since the memory gets quite fragmented if you use it as a stream
inline void FlattenIfNecessary() {
if (NumRegions() > 100) {
size_t size;
const void * buffer;
(*this) = Data(Map(&buffer, &size));
}
}
inline size_t NumRegions() {
size_t ret = 0;
Apply([&ret](dispatch_data_t region, size_t offset, const void *buffer, size_t size) -> bool {
ret += 1;
return true;
});
return ret;
}
inline operator dispatch_data_t() const {
return _data;
}
inline Data &operator = (const dispatch_data_t &other) {
if (other) {
sr_dispatch_retain(other);
}
if (_data) {
sr_dispatch_release(_data);
}
_data = other;
return *this;
}
inline Data &operator += (const Data &other) {
return (*this = Concat(other));
}
virtual ~Data() {
if (_data) {
sr_dispatch_release(_data);
}
}
static const Data empty;
};
}
}
#endif /* defined(__SocketRocket__DispatchData__) */

View File

@ -1,15 +0,0 @@
//
// DispatchData.cpp
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#include "DispatchData.h"
namespace squareup {
namespace dispatch {
const Data Data::empty(dispatch_data_empty);
}
}

View File

@ -1,91 +0,0 @@
//
// DispatchChannel.h
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#ifndef __SocketRocket__DispatchChannel__
#define __SocketRocket__DispatchChannel__
#include <dispatch/dispatch.h>
#include <string>
extern "C" {
#include <netdb.h>
}
namespace squareup {
namespace dispatch {
class RawIO;
typedef void (^dial_callback)(dispatch_fd_t fd, int error_code, const char *error_message);
void Dial(dispatch_queue_t workQueue, const char *hostname, const char *servname, dispatch_queue_t callback_queue, dial_callback callback);
// You are responsible for removing inputStream and outputStream
typedef void (^simple_dial_callback)(RawIO *io, int error, const char *error_message);
// callback_queue is what is sent to the clients but also
// parent_io_queue can be a parallel queue. the
// close_handler is passed to the RawIO
void SimpleDial(const char *hostname, const char *servname, dispatch_queue_t callback_queue, dispatch_queue_t parent_io_queue, simple_dial_callback dial_callback, void(^close_handler)(int error) = nullptr);
class IO {
public:
virtual void Close(dispatch_io_close_flags_t flags) = 0;
virtual void Read(size_t length, dispatch_queue_t queue, dispatch_io_handler_t handler) = 0;
virtual void Write(dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t handler) = 0;
virtual void Barrier(dispatch_block_t barrier) = 0;
virtual void SetHighWater(size_t high_water) = 0;
virtual void SetLowWater(size_t low_water) = 0;
virtual ~IO();
};
class RawIO : public IO {
dispatch_io_t _channel;
public:
void Close(dispatch_io_close_flags_t flags);
void Read(size_t length, dispatch_queue_t queue, dispatch_io_handler_t handler);
void Write(dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t handler);
void Barrier(dispatch_block_t barrier);
void SetHighWater(size_t high_water);
void SetLowWater(size_t low_water);
RawIO(dispatch_fd_t fd,
dispatch_queue_t cleanupQueue,
dispatch_queue_t callbackQueue,
dispatch_queue_t ioQueue,
void (^cleanup_handler)(int error));
// Takes ownership of channel
// retain is only for the channel
RawIO(dispatch_io_t channel,
dispatch_queue_t callbackQueue,
bool retain = true);
// Clones an existing IO
RawIO(dispatch_io_t otherIo,
dispatch_queue_t queue,
dispatch_queue_t callbackQueue,
dispatch_queue_t ioQueue,
void (^cleanup_handler)(int error));
inline operator dispatch_io_t () const {
return _channel;
}
virtual ~RawIO();
};
}
}
#endif /* defined(__SocketRocket__DispatchChannel__) */

View File

@ -1,298 +0,0 @@
//
// DispatchChannel.cpp
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#include "DispatchIO.h"
#include <Block.h>
#include <string>
#include "Common.h"
extern "C" {
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
}
// TODO: add deadlines
namespace squareup {
namespace dispatch {
IO::~IO() {};
class Connector;
typedef void(^finish_callback)(Connector *connector, addrinfo *res0, dispatch_fd_t fd, int error_code, const char *error_message);
class Connector {
addrinfo *_res;
addrinfo *_res0;
__strong finish_callback _finishCallback;
dispatch_queue_t _workQueue;
int _lastError;
const char *_lastErrorMessage;
bool _foundAddr = false;
public:
// Takes ownership of res0;
inline Connector(dispatch_queue_t workQueue, struct addrinfo *res0, finish_callback finishCallback) : _res(res0), _res0(res0), _finishCallback([finishCallback copy]), _workQueue(workQueue) {
sr_dispatch_retain(_workQueue);
}
virtual ~Connector() {
sr_dispatch_release(_workQueue);
}
inline void NextIter() {
_res = _res->ai_next;
dispatch_async(_workQueue, ^{
DoNext();
});
}
inline void DoNext() {
// We ran out of addresses
if (!_res) {
assert(!_foundAddr);
_finishCallback(this, _res0, -1, _lastError, _lastErrorMessage);
_finishCallback = nullptr;
return;
}
dispatch_fd_t fd = socket(_res->ai_family, _res->ai_socktype,
_res->ai_protocol);
if (fd < 0) {
_lastError = errno;
_lastErrorMessage = strerror(_lastError);
NextIter();
return;
}
int curflags = fcntl(fd, F_GETFL);
if (curflags < 0) {
_lastError = errno;
_lastErrorMessage = strerror(_lastError);
NextIter();
return;
}
// Set it to be nonblocking
int error = fcntl(fd, F_SETFL, curflags | O_NONBLOCK);
if (error) {
_lastError = errno;
_lastErrorMessage = strerror(_lastError);
NextIter();
return;
}
dispatch_source_t readSource = nullptr;
readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, _workQueue);
dispatch_resume(readSource);
dispatch_source_set_event_handler(readSource, [this, fd, readSource]{
TryConnect(false, fd, readSource);
});
dispatch_source_set_cancel_handler(readSource, [fd]{
close(fd);
});
TryConnect(true, fd, readSource);
}
private:
// returns true if it is done
// if this is the first try we call connect. otherwise we check the status
inline void TryConnect(bool firstTry, dispatch_fd_t fd, dispatch_source_t readSource) {
// Now, set connection to be non-blocking
assert(!_foundAddr);
assert(fd != -1);
_lastError = 0;
if (firstTry) {
int error = connect(fd, _res->ai_addr, _res->ai_addrlen);
if (error != 0) {
_lastError = errno;
}
} else {
socklen_t len = sizeof(_lastError);
int sockErr = getsockopt(fd, SOL_SOCKET, SO_ERROR, &_lastError, &len);
assert(sockErr == 0);
}
if (_lastError != 0) {
if (_lastError != EINPROGRESS) {
_lastErrorMessage = strerror(_lastError);
dispatch_source_cancel(readSource);
sr_dispatch_release(readSource);
readSource = nullptr;
NextIter();
}
return;
}
_foundAddr = true;
// We don't want to close the FD, so make the cancel handler a noop
dispatch_suspend(readSource);
dispatch_source_set_cancel_handler(readSource, ^{});
dispatch_resume(readSource);
dispatch_source_cancel(readSource);
// Dispose of it without canceling it
sr_dispatch_release(readSource);
// Successful connections get here. Then we don't try anymore
// If we get this far, we're done
dispatch_async(_workQueue, [this, fd]{
_finishCallback(this, _res0, fd, 0, nullptr);
_finishCallback = nullptr;
});
return;
}
};
void Dial(dispatch_queue_t workQueue, const char *hostname, const char *servname, dispatch_queue_t callback_queue, dial_callback callback) {
callback = [callback copy];
sr_dispatch_retain(callback_queue);
// Does cleanup and whatnot
dispatch_async(workQueue, ^{
addrinfo *res0 = nullptr;
int error;
const char *cause = nullptr;
struct addrinfo hints = {0};
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, servname, &hints, &res0);
auto finish = [callback_queue, callback, res0, workQueue](Connector *connector, addrinfo *res0, dispatch_fd_t fd, int error_code, const char *error_message){
NSLog(@"Pew");
dispatch_async(callback_queue, [fd, callback_queue, workQueue, error_message, callback, res0, connector, error_code]{
callback(fd, error_code, error_message);
if (res0) {
freeaddrinfo(res0);
}
if (connector) {
// Delete it after it doesn't reference this block anymore
dispatch_async(callback_queue, [workQueue, connector, callback_queue]{
delete connector;
sr_dispatch_release(callback_queue);
});
} else {
sr_dispatch_release(callback_queue);
}
});
};
if (error) {
cause = gai_strerror(error);
finish(nullptr, res0, -1, error, cause);
return;
}
Connector *connector = new Connector(workQueue, res0, finish);
connector->DoNext();
});
}
// callback_queue is what is sent to the clients but also
// parent_io_queue can be a parallel queue. the
void SimpleDial(const char *hostname, const char *servname, dispatch_queue_t callback_queue, dispatch_queue_t parent_io_queue, simple_dial_callback dial_callback, void (^close_handler)(int error)) {
dispatch_queue_t io_queue = dispatch_queue_create("squareup.dispatch.SimpleDial IO Queue", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(io_queue, parent_io_queue);
sr_dispatch_retain(callback_queue);
if (close_handler != nullptr) {
close_handler = [close_handler copy];
}
Dial(callback_queue, hostname, servname, callback_queue, [=](dispatch_fd_t fd, int error_code, const char *error_message) {
RawIO *io = nullptr;
if (error_code == 0) {
// Going to make the writer the primary.
// The write stream is also appropriate for closing
io = new RawIO(fd, callback_queue, callback_queue, io_queue, [fd, close_handler](int error) {
close(fd);
if (close_handler != nullptr) {
close_handler(error);
}
});
}
dial_callback(io, error_code, error_message);
sr_dispatch_release(io_queue);
sr_dispatch_release(parent_io_queue);
});
}
RawIO::RawIO(dispatch_fd_t fd,
dispatch_queue_t cleanupQueue,
dispatch_queue_t callbackQueue,
dispatch_queue_t ioQueue,
void (^cleanup_handler)(int error)) {
_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, cleanupQueue, cleanup_handler);
dispatch_set_target_queue(_channel, ioQueue);
}
// Takes ownership of channel
// retain is only for the channel
RawIO::RawIO(dispatch_io_t channel, dispatch_queue_t callbackQueue, bool retain) : _channel(channel) {
if (retain) {
sr_dispatch_retain(_channel);
}
};
// Clones an existing IO
RawIO::RawIO(dispatch_io_t otherIo, dispatch_queue_t queue, dispatch_queue_t callbackQueue, dispatch_queue_t ioQueue, void (^cleanup_handler)(int error)) :
RawIO(dispatch_io_create_with_io(DISPATCH_IO_STREAM, otherIo, queue, cleanup_handler), false) {
dispatch_set_target_queue(_channel, ioQueue);
}
RawIO::~RawIO() {
sr_dispatch_release(_channel);
_channel = nullptr;
}
void RawIO::Close(dispatch_io_close_flags_t flags) {
dispatch_io_close(_channel, flags);
}
void RawIO::Read(size_t length, dispatch_queue_t queue, dispatch_io_handler_t handler) {
dispatch_io_read(_channel, 0, length, queue, handler);
}
void RawIO::Write(dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t handler) {
dispatch_io_write(_channel, 0, data, queue, handler);
}
void RawIO::Barrier(dispatch_block_t barrier) {
dispatch_io_barrier(_channel, barrier);
}
void RawIO::SetHighWater(size_t high_water) {
dispatch_io_set_high_water(_channel, high_water);
}
void RawIO::SetLowWater(size_t low_water) {
dispatch_io_set_low_water(_channel, low_water);
}
}
}

View File

@ -0,0 +1,67 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
#import <SocketRocket/SRWebSocket.h>
NS_ASSUME_NONNULL_BEGIN
#if OBJC_BOOL_IS_BOOL
struct SRDelegateAvailableMethods {
BOOL didReceiveMessage : 1;
BOOL didReceiveMessageWithString : 1;
BOOL didReceiveMessageWithData : 1;
BOOL didOpen : 1;
BOOL didFailWithError : 1;
BOOL didCloseWithCode : 1;
BOOL didReceivePing : 1;
BOOL didReceivePong : 1;
BOOL shouldConvertTextFrameToString : 1;
};
#else
struct SRDelegateAvailableMethods {
BOOL didReceiveMessage;
BOOL didReceiveMessageWithString;
BOOL didReceiveMessageWithData;
BOOL didOpen;
BOOL didFailWithError;
BOOL didCloseWithCode;
BOOL didReceivePing;
BOOL didReceivePong;
BOOL shouldConvertTextFrameToString;
};
#endif
typedef struct SRDelegateAvailableMethods SRDelegateAvailableMethods;
typedef void(^SRDelegateBlock)(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods);
@interface SRDelegateController : NSObject
@property (nonatomic, weak) id<SRWebSocketDelegate> delegate;
@property (atomic, readonly) SRDelegateAvailableMethods availableDelegateMethods;
@property (nullable, nonatomic, strong) dispatch_queue_t dispatchQueue;
@property (nullable, nonatomic, strong) NSOperationQueue *operationQueue;
///--------------------------------------
#pragma mark - Perform
///--------------------------------------
- (void)performDelegateBlock:(SRDelegateBlock)block;
- (void)performDelegateQueueBlock:(dispatch_block_t)block;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,138 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRDelegateController.h"
NS_ASSUME_NONNULL_BEGIN
@interface SRDelegateController ()
@property (nonatomic, strong, readonly) dispatch_queue_t accessQueue;
@property (atomic, assign, readwrite) SRDelegateAvailableMethods availableDelegateMethods;
@end
@implementation SRDelegateController
@synthesize delegate = _delegate;
@synthesize dispatchQueue = _dispatchQueue;
@synthesize operationQueue = _operationQueue;
///--------------------------------------
#pragma mark - Init
///--------------------------------------
- (instancetype)init
{
self = [super init];
if (!self) return self;
_accessQueue = dispatch_queue_create("com.facebook.socketrocket.delegate.access", DISPATCH_QUEUE_CONCURRENT);
_dispatchQueue = dispatch_get_main_queue();
return self;
}
///--------------------------------------
#pragma mark - Accessors
///--------------------------------------
- (void)setDelegate:(id<SRWebSocketDelegate> _Nullable)delegate
{
dispatch_barrier_async(self.accessQueue, ^{
_delegate = delegate;
self.availableDelegateMethods = (SRDelegateAvailableMethods){
.didReceiveMessage = [delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)],
.didReceiveMessageWithString = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithString:)],
.didReceiveMessageWithData = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithData:)],
.didOpen = [delegate respondsToSelector:@selector(webSocketDidOpen:)],
.didFailWithError = [delegate respondsToSelector:@selector(webSocket:didFailWithError:)],
.didCloseWithCode = [delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)],
.didReceivePing = [delegate respondsToSelector:@selector(webSocket:didReceivePingWithData:)],
.didReceivePong = [delegate respondsToSelector:@selector(webSocket:didReceivePong:)],
.shouldConvertTextFrameToString = [delegate respondsToSelector:@selector(webSocketShouldConvertTextFrameToString:)]
};
});
}
- (id<SRWebSocketDelegate> _Nullable)delegate
{
__block id<SRWebSocketDelegate> delegate = nil;
dispatch_sync(self.accessQueue, ^{
delegate = _delegate;
});
return delegate;
}
- (void)setDispatchQueue:(dispatch_queue_t _Nullable)queue
{
dispatch_barrier_async(self.accessQueue, ^{
_dispatchQueue = queue ?: dispatch_get_main_queue();
_operationQueue = nil;
});
}
- (dispatch_queue_t _Nullable)dispatchQueue
{
__block dispatch_queue_t queue = nil;
dispatch_sync(self.accessQueue, ^{
queue = _dispatchQueue;
});
return queue;
}
- (void)setOperationQueue:(NSOperationQueue *_Nullable)queue
{
dispatch_barrier_async(self.accessQueue, ^{
_dispatchQueue = queue ? nil : dispatch_get_main_queue();
_operationQueue = queue;
});
}
- (NSOperationQueue *_Nullable)operationQueue
{
__block NSOperationQueue *queue = nil;
dispatch_sync(self.accessQueue, ^{
queue = _operationQueue;
});
return queue;
}
///--------------------------------------
#pragma mark - Perform
///--------------------------------------
- (void)performDelegateBlock:(SRDelegateBlock)block
{
__block __strong id<SRWebSocketDelegate> delegate = nil;
__block SRDelegateAvailableMethods availableMethods = {};
dispatch_sync(self.accessQueue, ^{
delegate = _delegate; // Not `OK` to go through `self`, since queue sync.
availableMethods = self.availableDelegateMethods; // `OK` to call through `self`, since no queue sync.
});
[self performDelegateQueueBlock:^{
block(delegate, availableMethods);
}];
}
- (void)performDelegateQueueBlock:(dispatch_block_t)block
{
dispatch_queue_t dispatchQueue = self.dispatchQueue;
if (dispatchQueue) {
dispatch_async(dispatchQueue, block);
} else {
[self.operationQueue addOperationWithBlock:block];
}
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,40 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
@class SRWebSocket; // TODO: (nlutsenko) Remove dependency on SRWebSocket here.
// Returns number of bytes consumed. Returning 0 means you didn't match.
// Sends bytes to callback handler;
typedef size_t (^stream_scanner)(NSData *collected_data);
typedef void (^data_callback)(SRWebSocket *webSocket, NSData *data);
@interface SRIOConsumer : NSObject {
stream_scanner _scanner;
data_callback _handler;
size_t _bytesNeeded;
BOOL _readToCurrentFrame;
BOOL _unmaskBytes;
}
@property (nonatomic, copy, readonly) stream_scanner consumer;
@property (nonatomic, copy, readonly) data_callback handler;
@property (nonatomic, assign) size_t bytesNeeded;
@property (nonatomic, assign, readonly) BOOL readToCurrentFrame;
@property (nonatomic, assign, readonly) BOOL unmaskBytes;
- (void)resetWithScanner:(stream_scanner)scanner
handler:(data_callback)handler
bytesNeeded:(size_t)bytesNeeded
readToCurrentFrame:(BOOL)readToCurrentFrame
unmaskBytes:(BOOL)unmaskBytes;
@end

View File

@ -0,0 +1,36 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRIOConsumer.h"
@implementation SRIOConsumer
@synthesize bytesNeeded = _bytesNeeded;
@synthesize consumer = _scanner;
@synthesize handler = _handler;
@synthesize readToCurrentFrame = _readToCurrentFrame;
@synthesize unmaskBytes = _unmaskBytes;
- (void)resetWithScanner:(stream_scanner)scanner
handler:(data_callback)handler
bytesNeeded:(size_t)bytesNeeded
readToCurrentFrame:(BOOL)readToCurrentFrame
unmaskBytes:(BOOL)unmaskBytes
{
_scanner = [scanner copy];
_handler = [handler copy];
_bytesNeeded = bytesNeeded;
_readToCurrentFrame = readToCurrentFrame;
_unmaskBytes = unmaskBytes;
assert(_scanner || _bytesNeeded);
}
@end

View File

@ -0,0 +1,28 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
#import "SRIOConsumer.h" // TODO: (nlutsenko) Convert to @class and constants file for block types
// This class is not thread-safe, and is expected to always be run on the same queue.
@interface SRIOConsumerPool : NSObject
- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize;
- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner
handler:(data_callback)handler
bytesNeeded:(size_t)bytesNeeded
readToCurrentFrame:(BOOL)readToCurrentFrame
unmaskBytes:(BOOL)unmaskBytes;
- (void)returnConsumer:(SRIOConsumer *)consumer;
@end

View File

@ -0,0 +1,64 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRIOConsumerPool.h"
@implementation SRIOConsumerPool {
NSUInteger _poolSize;
NSMutableArray<SRIOConsumer *> *_bufferedConsumers;
}
- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize;
{
self = [super init];
if (self) {
_poolSize = poolSize;
_bufferedConsumers = [NSMutableArray arrayWithCapacity:poolSize];
}
return self;
}
- (instancetype)init
{
return [self initWithBufferCapacity:8];
}
- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner
handler:(data_callback)handler
bytesNeeded:(size_t)bytesNeeded
readToCurrentFrame:(BOOL)readToCurrentFrame
unmaskBytes:(BOOL)unmaskBytes
{
SRIOConsumer *consumer = nil;
if (_bufferedConsumers.count) {
consumer = [_bufferedConsumers lastObject];
[_bufferedConsumers removeLastObject];
} else {
consumer = [[SRIOConsumer alloc] init];
}
[consumer resetWithScanner:scanner
handler:handler
bytesNeeded:bytesNeeded
readToCurrentFrame:readToCurrentFrame
unmaskBytes:unmaskBytes];
return consumer;
}
- (void)returnConsumer:(SRIOConsumer *)consumer;
{
if (_bufferedConsumers.count < _poolSize) {
[_bufferedConsumers addObject:consumer];
}
}
@end

View File

@ -0,0 +1,13 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <SocketRocket/NSRunLoop+SRWebSocket.h>
// Empty function that force links the object file for the category.
extern void import_NSRunLoop_SRWebSocket(void);

View File

@ -0,0 +1,13 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <SocketRocket/NSURLRequest+SRWebSocket.h>
// Empty function that force links the object file for the category.
extern void import_NSURLRequest_SRWebSocket(void);

View File

@ -0,0 +1,26 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^SRProxyConnectCompletion)(NSError *_Nullable error,
NSInputStream *_Nullable readStream,
NSOutputStream *_Nullable writeStream);
@interface SRProxyConnect : NSObject
- (instancetype)initWithURL:(NSURL *)url;
- (void)openNetworkStreamWithCompletion:(SRProxyConnectCompletion)completion;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,481 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRProxyConnect.h"
#import "NSRunLoop+SRWebSocket.h"
#import "SRConstants.h"
#import "SRError.h"
#import "SRLog.h"
#import "SRURLUtilities.h"
@interface SRProxyConnect() <NSStreamDelegate>
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, strong) NSInputStream *inputStream;
@property (nonatomic, strong) NSOutputStream *outputStream;
@end
@implementation SRProxyConnect
{
SRProxyConnectCompletion _completion;
NSString *_httpProxyHost;
uint32_t _httpProxyPort;
CFHTTPMessageRef _receivedHTTPHeaders;
NSString *_socksProxyHost;
uint32_t _socksProxyPort;
NSString *_socksProxyUsername;
NSString *_socksProxyPassword;
BOOL _connectionRequiresSSL;
NSMutableArray<NSData *> *_inputQueue;
dispatch_queue_t _writeQueue;
}
///--------------------------------------
#pragma mark - Init
///--------------------------------------
-(instancetype)initWithURL:(NSURL *)url
{
self = [super init];
if (!self) return self;
_url = url;
_connectionRequiresSSL = SRURLRequiresSSL(url);
_writeQueue = dispatch_queue_create("com.facebook.socketrocket.proxyconnect.write", DISPATCH_QUEUE_SERIAL);
_inputQueue = [NSMutableArray arrayWithCapacity:2];
return self;
}
- (void)dealloc
{
// If we get deallocated before the socket open finishes - we need to cleanup everything.
[self.inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
self.inputStream.delegate = nil;
[self.inputStream close];
self.inputStream = nil;
self.outputStream.delegate = nil;
[self.outputStream close];
self.outputStream = nil;
}
///--------------------------------------
#pragma mark - Open
///--------------------------------------
- (void)openNetworkStreamWithCompletion:(SRProxyConnectCompletion)completion
{
_completion = completion;
[self _configureProxy];
}
///--------------------------------------
#pragma mark - Flow
///--------------------------------------
- (void)_didConnect
{
SRDebugLog(@"_didConnect, return streams");
if (_connectionRequiresSSL) {
if (_httpProxyHost) {
// Must set the real peer name before turning on SSL
SRDebugLog(@"proxy set peer name to real host %@", self.url.host);
[self.outputStream setProperty:self.url.host forKey:@"_kCFStreamPropertySocketPeerName"];
}
}
if (_receivedHTTPHeaders) {
CFRelease(_receivedHTTPHeaders);
_receivedHTTPHeaders = NULL;
}
NSInputStream *inputStream = self.inputStream;
NSOutputStream *outputStream = self.outputStream;
self.inputStream = nil;
self.outputStream = nil;
[inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
inputStream.delegate = nil;
outputStream.delegate = nil;
_completion(nil, inputStream, outputStream);
}
- (void)_failWithError:(NSError *)error
{
SRDebugLog(@"_failWithError, return error");
if (!error) {
error = SRHTTPErrorWithCodeDescription(500, 2132,@"Proxy Error");
}
if (_receivedHTTPHeaders) {
CFRelease(_receivedHTTPHeaders);
_receivedHTTPHeaders = NULL;
}
self.inputStream.delegate = nil;
self.outputStream.delegate = nil;
[self.inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop]
forMode:NSDefaultRunLoopMode];
[self.inputStream close];
[self.outputStream close];
self.inputStream = nil;
self.outputStream = nil;
_completion(error, nil, nil);
}
// get proxy setting from device setting
- (void)_configureProxy
{
SRDebugLog(@"configureProxy");
NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings());
// CFNetworkCopyProxiesForURL doesn't understand ws:// or wss://
NSURL *httpURL;
if (_connectionRequiresSSL) {
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
} else {
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
}
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)httpURL, (__bridge CFDictionaryRef)proxySettings));
if (proxies.count == 0) {
SRDebugLog(@"configureProxy no proxies");
[self _openConnection];
return; // no proxy
}
NSDictionary *settings = [proxies objectAtIndex:0];
NSString *proxyType = settings[(NSString *)kCFProxyTypeKey];
if ([proxyType isEqualToString:(NSString *)kCFProxyTypeAutoConfigurationURL]) {
NSURL *pacURL = settings[(NSString *)kCFProxyAutoConfigurationURLKey];
if (pacURL) {
[self _fetchPAC:pacURL withProxySettings:proxySettings];
return;
}
}
if ([proxyType isEqualToString:(__bridge NSString *)kCFProxyTypeAutoConfigurationJavaScript]) {
NSString *script = settings[(__bridge NSString *)kCFProxyAutoConfigurationJavaScriptKey];
if (script) {
[self _runPACScript:script withProxySettings:proxySettings];
return;
}
}
[self _readProxySettingWithType:proxyType settings:settings];
[self _openConnection];
}
- (void)_readProxySettingWithType:(NSString *)proxyType settings:(NSDictionary *)settings
{
if ([proxyType isEqualToString:(NSString *)kCFProxyTypeHTTP] ||
[proxyType isEqualToString:(NSString *)kCFProxyTypeHTTPS]) {
_httpProxyHost = settings[(NSString *)kCFProxyHostNameKey];
NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
if (portValue) {
_httpProxyPort = [portValue intValue];
}
}
if ([proxyType isEqualToString:(NSString *)kCFProxyTypeSOCKS]) {
_socksProxyHost = settings[(NSString *)kCFProxyHostNameKey];
NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
if (portValue)
_socksProxyPort = [portValue intValue];
_socksProxyUsername = settings[(NSString *)kCFProxyUsernameKey];
_socksProxyPassword = settings[(NSString *)kCFProxyPasswordKey];
}
if (_httpProxyHost) {
SRDebugLog(@"Using http proxy %@:%u", _httpProxyHost, _httpProxyPort);
} else if (_socksProxyHost) {
SRDebugLog(@"Using socks proxy %@:%u", _socksProxyHost, _socksProxyPort);
} else {
SRDebugLog(@"configureProxy no proxies");
}
}
- (void)_fetchPAC:(NSURL *)PACurl withProxySettings:(NSDictionary *)proxySettings
{
SRDebugLog(@"SRWebSocket fetchPAC:%@", PACurl);
if ([PACurl isFileURL]) {
NSError *error = nil;
NSString *script = [NSString stringWithContentsOfURL:PACurl
usedEncoding:NULL
error:&error];
if (error) {
[self _openConnection];
} else {
[self _runPACScript:script withProxySettings:proxySettings];
}
return;
}
NSString *scheme = [PACurl.scheme lowercaseString];
if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
// Don't know how to read data from this URL, we'll have to give up
// We'll simply assume no proxies, and start the request as normal
[self _openConnection];
return;
}
__weak typeof(self) wself = self;
NSURLRequest *request = [NSURLRequest requestWithURL:PACurl];
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
__strong typeof(wself) sself = wself;
if (!error) {
NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[sself _runPACScript:script withProxySettings:proxySettings];
} else {
[sself _openConnection];
}
}] resume];
}
- (void)_runPACScript:(NSString *)script withProxySettings:(NSDictionary *)proxySettings
{
if (!script) {
[self _openConnection];
return;
}
SRDebugLog(@"runPACScript");
// From: http://developer.apple.com/samplecode/CFProxySupportTool/listing1.html
// Work around <rdar://problem/5530166>. This dummy call to
// CFNetworkCopyProxiesForURL initialise some state within CFNetwork
// that is required by CFNetworkCopyProxiesForAutoConfigurationScript.
CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)_url, (__bridge CFDictionaryRef)proxySettings));
// Obtain the list of proxies by running the autoconfiguration script
CFErrorRef err = NULL;
// CFNetworkCopyProxiesForAutoConfigurationScript doesn't understand ws:// or wss://
NSURL *httpURL;
if (_connectionRequiresSSL)
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
else
httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script,(__bridge CFURLRef)httpURL, &err));
if (!err && [proxies count] > 0) {
NSDictionary *settings = [proxies objectAtIndex:0];
NSString *proxyType = settings[(NSString *)kCFProxyTypeKey];
[self _readProxySettingWithType:proxyType settings:settings];
}
[self _openConnection];
}
- (void)_openConnection
{
[self _initializeStreams];
[self.inputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
forMode:NSDefaultRunLoopMode];
//[self.outputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
// forMode:NSDefaultRunLoopMode];
[self.outputStream open];
[self.inputStream open];
}
- (void)_initializeStreams
{
assert(_url.port.unsignedIntValue <= UINT32_MAX);
uint32_t port = _url.port.unsignedIntValue;
if (port == 0) {
port = (_connectionRequiresSSL ? 443 : 80);
}
NSString *host = _url.host;
if (_httpProxyHost) {
host = _httpProxyHost;
port = (_httpProxyPort ?: 80);
}
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
SRDebugLog(@"ProxyConnect connect stream to %@:%u", host, port);
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
self.outputStream = CFBridgingRelease(writeStream);
self.inputStream = CFBridgingRelease(readStream);
if (_socksProxyHost) {
SRDebugLog(@"ProxyConnect set sock property stream to %@:%u user %@ password %@", _socksProxyHost, _socksProxyPort, _socksProxyUsername, _socksProxyPassword);
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:4];
settings[NSStreamSOCKSProxyHostKey] = _socksProxyHost;
if (_socksProxyPort) {
settings[NSStreamSOCKSProxyPortKey] = @(_socksProxyPort);
}
if (_socksProxyUsername) {
settings[NSStreamSOCKSProxyUserKey] = _socksProxyUsername;
}
if (_socksProxyPassword) {
settings[NSStreamSOCKSProxyPasswordKey] = _socksProxyPassword;
}
[self.inputStream setProperty:settings forKey:NSStreamSOCKSProxyConfigurationKey];
[self.outputStream setProperty:settings forKey:NSStreamSOCKSProxyConfigurationKey];
}
self.inputStream.delegate = self;
self.outputStream.delegate = self;
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode;
{
SRDebugLog(@"stream handleEvent %u", eventCode);
switch (eventCode) {
case NSStreamEventOpenCompleted: {
if (aStream == self.inputStream) {
if (_httpProxyHost) {
[self _proxyDidConnect];
} else {
[self _didConnect];
}
}
} break;
case NSStreamEventErrorOccurred: {
[self _failWithError:aStream.streamError];
} break;
case NSStreamEventEndEncountered: {
[self _failWithError:aStream.streamError];
} break;
case NSStreamEventHasBytesAvailable: {
if (aStream == _inputStream) {
[self _processInputStream];
}
} break;
case NSStreamEventHasSpaceAvailable:
case NSStreamEventNone:
SRDebugLog(@"(default) %@", aStream);
break;
}
}
- (void)_proxyDidConnect
{
SRDebugLog(@"Proxy Connected");
uint32_t port = _url.port.unsignedIntValue;
if (port == 0) {
port = (_connectionRequiresSSL ? 443 : 80);
}
// Send HTTP CONNECT Request
NSString *connectRequestStr = [NSString stringWithFormat:@"CONNECT %@:%u HTTP/1.1\r\nHost: %@\r\nConnection: keep-alive\r\nProxy-Connection: keep-alive\r\n\r\n", _url.host, port, _url.host];
NSData *message = [connectRequestStr dataUsingEncoding:NSUTF8StringEncoding];
SRDebugLog(@"Proxy sending %@", connectRequestStr);
[self _writeData:message];
}
///handles the incoming bytes and sending them to the proper processing method
- (void)_processInputStream
{
NSMutableData *buf = [NSMutableData dataWithCapacity:SRDefaultBufferSize()];
uint8_t *buffer = buf.mutableBytes;
NSInteger length = [_inputStream read:buffer maxLength:SRDefaultBufferSize()];
if (length <= 0) {
return;
}
BOOL process = (_inputQueue.count == 0);
[_inputQueue addObject:[NSData dataWithBytes:buffer length:length]];
if (process) {
[self _dequeueInput];
}
}
// dequeue the incoming input so it is processed in order
- (void)_dequeueInput
{
while (_inputQueue.count > 0) {
NSData *data = _inputQueue.firstObject;
[_inputQueue removeObjectAtIndex:0];
// No need to process any data further, we got the full header data.
if ([self _proxyProcessHTTPResponseWithData:data]) {
break;
}
}
}
//handle checking the proxy connection status
- (BOOL)_proxyProcessHTTPResponseWithData:(NSData *)data
{
if (_receivedHTTPHeaders == NULL) {
_receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
}
CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
SRDebugLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
[self _proxyHTTPHeadersDidFinish];
return YES;
}
return NO;
}
- (void)_proxyHTTPHeadersDidFinish
{
NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
if (responseCode >= 299) {
SRDebugLog(@"Connect to Proxy Request failed with response code %d", responseCode);
NSError *error = SRHTTPErrorWithCodeDescription(responseCode, 2132,
[NSString stringWithFormat:@"Received bad response code from proxy server: %d.",
(int)responseCode]);
[self _failWithError:error];
return;
}
SRDebugLog(@"proxy connect return %d, call socket connect", responseCode);
[self _didConnect];
}
static NSTimeInterval const SRProxyConnectWriteTimeout = 5.0;
- (void)_writeData:(NSData *)data
{
const uint8_t * bytes = data.bytes;
__block NSInteger timeout = (NSInteger)(SRProxyConnectWriteTimeout * 1000000); // wait timeout before giving up
__weak typeof(self) wself = self;
dispatch_async(_writeQueue, ^{
__strong typeof(wself) sself = self;
if (!sself) {
return;
}
NSOutputStream *outStream = sself.outputStream;
if (!outStream) {
return;
}
while (![outStream hasSpaceAvailable]) {
usleep(100); //wait until the socket is ready
timeout -= 100;
if (timeout < 0) {
NSError *error = SRHTTPErrorWithCodeDescription(408, 2132, @"Proxy timeout");
[sself _failWithError:error];
} else if (outStream.streamError != nil) {
[sself _failWithError:outStream.streamError];
}
}
[outStream write:bytes maxLength:data.length];
});
}
@end

View File

@ -0,0 +1,24 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SRRunLoopThread : NSThread
@property (nonatomic, strong, readonly) NSRunLoop *runLoop;
+ (instancetype)sharedThread;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,83 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRRunLoopThread.h"
@interface SRRunLoopThread ()
{
dispatch_group_t _waitGroup;
}
@property (nonatomic, strong, readwrite) NSRunLoop *runLoop;
@end
@implementation SRRunLoopThread
+ (instancetype)sharedThread
{
static SRRunLoopThread *thread;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
thread = [[SRRunLoopThread alloc] init];
thread.name = @"com.facebook.SocketRocket.NetworkThread";
[thread start];
});
return thread;
}
- (instancetype)init
{
self = [super init];
if (self) {
_waitGroup = dispatch_group_create();
dispatch_group_enter(_waitGroup);
}
return self;
}
- (void)main
{
@autoreleasepool {
_runLoop = [NSRunLoop currentRunLoop];
dispatch_group_leave(_waitGroup);
// Add an empty run loop source to prevent runloop from spinning.
CFRunLoopSourceContext sourceCtx = {
.version = 0,
.info = NULL,
.retain = NULL,
.release = NULL,
.copyDescription = NULL,
.equal = NULL,
.hash = NULL,
.schedule = NULL,
.cancel = NULL,
.perform = NULL
};
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
}
assert(NO);
}
}
- (NSRunLoop *)runLoop;
{
dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER);
return _runLoop;
}
@end

View File

@ -0,0 +1,26 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, SROpCode)
{
SROpCodeTextFrame = 0x1,
SROpCodeBinaryFrame = 0x2,
// 3-7 reserved.
SROpCodeConnectionClose = 0x8,
SROpCodePing = 0x9,
SROpCodePong = 0xA,
// B-F reserved.
};
/**
Default buffer size that is used for reading/writing to streams.
*/
extern size_t SRDefaultBufferSize(void);

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRConstants.h"
size_t SRDefaultBufferSize(void) {
static size_t size;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
size = getpagesize();
});
return size;
}

View File

@ -0,0 +1,27 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
#import <SocketRocket/SRSecurityPolicy.h>
NS_ASSUME_NONNULL_BEGIN
/**
* NOTE: While publicly, SocketRocket does not support configuring the security policy with pinned certificates,
* it is still possible to manually construct a security policy of this class. If you do this, note that you may
* be open to MitM attacks, and we will not support any issues you may have. Dive at your own risk.
*/
@interface SRPinningSecurityPolicy : SRSecurityPolicy
- (instancetype)initWithCertificates:(NSArray *)pinnedCertificates;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,73 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRPinningSecurityPolicy.h"
#import <Foundation/Foundation.h>
#import "SRLog.h"
NS_ASSUME_NONNULL_BEGIN
@interface SRPinningSecurityPolicy ()
@property (nonatomic, copy, readonly) NSArray *pinnedCertificates;
@end
@implementation SRPinningSecurityPolicy
- (instancetype)initWithCertificates:(NSArray *)pinnedCertificates
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
// Do not validate certificate chain since we're pinning to specific certificates.
self = [super initWithCertificateChainValidationEnabled:NO];
#pragma clang diagnostic pop
if (!self) { return self; }
if (pinnedCertificates.count == 0) {
@throw [NSException exceptionWithName:@"Creating security policy failed."
reason:@"Must specify at least one certificate when creating a pinning policy."
userInfo:nil];
}
_pinnedCertificates = [pinnedCertificates copy];
return self;
}
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
{
SRDebugLog(@"Pinned cert count: %d", self.pinnedCertificates.count);
NSUInteger requiredCertCount = self.pinnedCertificates.count;
NSUInteger validatedCertCount = 0;
CFIndex serverCertCount = SecTrustGetCertificateCount(serverTrust);
for (CFIndex i = 0; i < serverCertCount; i++) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(serverTrust, i);
NSData *data = CFBridgingRelease(SecCertificateCopyData(cert));
for (id ref in self.pinnedCertificates) {
SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref;
// TODO: (nlutsenko) Add caching, so we don't copy the data for every pinned cert all the time.
NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert));
if ([trustedCertData isEqualToData:data]) {
validatedCertCount++;
break;
}
}
}
return (requiredCertCount == validatedCertCount);
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
extern NSError *SRErrorWithDomainCodeDescription(NSString *domain, NSInteger code, NSString *description);
extern NSError *SRErrorWithCodeDescription(NSInteger code, NSString *description);
extern NSError *SRErrorWithCodeDescriptionUnderlyingError(NSInteger code, NSString *description, NSError *underlyingError);
extern NSError *SRHTTPErrorWithCodeDescription(NSInteger httpCode, NSInteger errorCode, NSString *description);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,42 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRError.h"
#import "SRWebSocket.h"
NS_ASSUME_NONNULL_BEGIN
NSError *SRErrorWithDomainCodeDescription(NSString *domain, NSInteger code, NSString *description)
{
return [NSError errorWithDomain:domain code:code userInfo:@{ NSLocalizedDescriptionKey: description }];
}
NSError *SRErrorWithCodeDescription(NSInteger code, NSString *description)
{
return SRErrorWithDomainCodeDescription(SRWebSocketErrorDomain, code, description);
}
NSError *SRErrorWithCodeDescriptionUnderlyingError(NSInteger code, NSString *description, NSError *underlyingError)
{
return [NSError errorWithDomain:SRWebSocketErrorDomain
code:code
userInfo:@{ NSLocalizedDescriptionKey: description,
NSUnderlyingErrorKey: underlyingError }];
}
NSError *SRHTTPErrorWithCodeDescription(NSInteger httpCode, NSInteger errorCode, NSString *description)
{
return [NSError errorWithDomain:SRWebSocketErrorDomain
code:errorCode
userInfo:@{ NSLocalizedDescriptionKey: description,
SRHTTPResponseErrorKey: @(httpCode) }];
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
extern CFHTTPMessageRef SRHTTPConnectMessageCreate(NSURLRequest *request,
NSString *securityKey,
uint8_t webSocketProtocolVersion,
NSArray<NSHTTPCookie *> *_Nullable cookies,
NSArray<NSString *> *_Nullable requestedProtocols);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,79 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRHTTPConnectMessage.h"
#import "SRURLUtilities.h"
NS_ASSUME_NONNULL_BEGIN
static NSString *_SRHTTPConnectMessageHost(NSURL *url)
{
NSString *host = url.host;
if (url.port) {
host = [host stringByAppendingFormat:@":%@", url.port];
}
return host;
}
CFHTTPMessageRef SRHTTPConnectMessageCreate(NSURLRequest *request,
NSString *securityKey,
uint8_t webSocketProtocolVersion,
NSArray<NSHTTPCookie *> *_Nullable cookies,
NSArray<NSString *> *_Nullable requestedProtocols)
{
NSURL *url = request.URL;
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)url, kCFHTTPVersion1_1);
// Set host first so it defaults
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Host"), (__bridge CFStringRef)_SRHTTPConnectMessageHost(url));
NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
int result = SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
if (result != 0) {
//TODO: (nlutsenko) Check if there was an error.
}
// Apply cookies if any have been provided
if (cookies) {
NSDictionary<NSString *, NSString *> *messageCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
[messageCookies enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
if (key.length && obj.length) {
CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
}
}];
}
// set header for http basic auth
NSString *basicAuthorizationString = SRBasicAuthorizationHeaderFromURL(url);
if (basicAuthorizationString) {
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Authorization"), (__bridge CFStringRef)basicAuthorizationString);
}
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Upgrade"), CFSTR("websocket"));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Connection"), CFSTR("Upgrade"));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)securityKey);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)@(webSocketProtocolVersion).stringValue);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Origin"), (__bridge CFStringRef)SRURLOrigin(url));
if (requestedProtocols.count) {
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Protocol"),
(__bridge CFStringRef)[requestedProtocols componentsJoinedByString:@", "]);
}
[request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
}];
return message;
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
extern NSData *SRSHA1HashFromString(NSString *string);
extern NSData *SRSHA1HashFromBytes(const char *bytes, size_t length);
extern NSString *SRBase64EncodedStringFromData(NSData *data);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,43 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRHash.h"
#import <CommonCrypto/CommonDigest.h>
NS_ASSUME_NONNULL_BEGIN
NSData *SRSHA1HashFromString(NSString *string)
{
size_t length = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
return SRSHA1HashFromBytes(string.UTF8String, length);
}
NSData *SRSHA1HashFromBytes(const char *bytes, size_t length)
{
uint8_t outputLength = CC_SHA1_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA1(bytes, (CC_LONG)length, output);
return [NSData dataWithBytes:output length:outputLength];
}
NSString *SRBase64EncodedStringFromData(NSData *data)
{
if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
return [data base64EncodedStringWithOptions:0];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [data base64Encoding];
#pragma clang diagnostic pop
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
// Uncomment this line to enable debug logging
//#define SR_DEBUG_LOG_ENABLED
extern void SRErrorLog(NSString *format, ...);
extern void SRDebugLog(NSString *format, ...);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,33 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRLog.h"
NS_ASSUME_NONNULL_BEGIN
extern void SRErrorLog(NSString *format, ...)
{
__block va_list arg_list;
va_start (arg_list, format);
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
va_end(arg_list);
NSLog(@"[SocketRocket] %@", formattedString);
}
extern void SRDebugLog(NSString *format, ...)
{
#ifdef SR_DEBUG_LOG_ENABLED
SRErrorLog(tag, format);
#endif
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,22 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef __attribute__((capability("mutex"))) pthread_mutex_t *SRMutex;
extern SRMutex SRMutexInitRecursive(void);
extern void SRMutexDestroy(SRMutex mutex);
extern void SRMutexLock(SRMutex mutex) __attribute__((acquire_capability(mutex)));
extern void SRMutexUnlock(SRMutex mutex) __attribute__((release_capability(mutex)));
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,47 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRMutex.h"
#import <pthread/pthread.h>
NS_ASSUME_NONNULL_BEGIN
SRMutex SRMutexInitRecursive(void)
{
pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attributes);
pthread_mutexattr_destroy(&attributes);
return mutex;
}
void SRMutexDestroy(SRMutex mutex)
{
pthread_mutex_destroy(mutex);
free(mutex);
}
__attribute__((no_thread_safety_analysis))
void SRMutexLock(SRMutex mutex)
{
pthread_mutex_lock(mutex);
}
__attribute__((no_thread_safety_analysis))
void SRMutexUnlock(SRMutex mutex)
{
pthread_mutex_unlock(mutex);
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
extern NSData *SRRandomData(NSUInteger length);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,26 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRRandom.h"
#import <Security/SecRandom.h>
NS_ASSUME_NONNULL_BEGIN
NSData *SRRandomData(NSUInteger length)
{
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault, data.length, data.mutableBytes);
if (result != 0) {
[NSException raise:NSInternalInconsistencyException format:@"Failed to generate random bytes with OSStatus: %d", result];
}
return data;
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
/**
Unmask bytes using XOR via SIMD.
@param bytes The bytes to unmask.
@param length The number of bytes to unmask.
@param maskKey The mask to XOR with MUST be of length sizeof(uint32_t).
*/
void SRMaskBytesSIMD(uint8_t *bytes, size_t length, uint8_t *maskKey);

View File

@ -0,0 +1,73 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRSIMDHelpers.h"
typedef uint8_t uint8x32_t __attribute__((vector_size(32)));
static void SRMaskBytesManual(uint8_t *bytes, size_t length, uint8_t *maskKey) {
for (size_t i = 0; i < length; i++) {
bytes[i] = bytes[i] ^ maskKey[i % sizeof(uint32_t)];
}
}
/**
Right-shift the elements of a vector, circularly.
@param vector The vector to circular shift.
@param by The number of elements to shift by.
@return A shifted vector.
*/
static uint8x32_t SRShiftVector(uint8x32_t vector, size_t by) {
uint8x32_t vectorCopy = vector;
by = by % _Alignof(uint8x32_t);
uint8_t *vectorPointer = (uint8_t *)&vector;
uint8_t *vectorCopyPointer = (uint8_t *)&vectorCopy;
memmove(vectorPointer + by, vectorPointer, sizeof(vector) - by);
memcpy(vectorPointer, vectorCopyPointer + (sizeof(vector) - by), by);
return vector;
}
void SRMaskBytesSIMD(uint8_t *bytes, size_t length, uint8_t *maskKey) {
size_t alignmentBytes = _Alignof(uint8x32_t) - ((uintptr_t)bytes % _Alignof(uint8x32_t));
if (alignmentBytes == _Alignof(uint8x32_t)) {
alignmentBytes = 0;
}
// If the number of bytes that can be processed after aligning is
// less than the number of bytes we can put into a vector,
// then there's no work to do with SIMD, just call the manual version.
if (alignmentBytes > length || (length - alignmentBytes) < sizeof(uint8x32_t)) {
SRMaskBytesManual(bytes, length, maskKey);
return;
}
size_t vectorLength = (length - alignmentBytes) / sizeof(uint8x32_t);
size_t manualStartOffset = alignmentBytes + (vectorLength * sizeof(uint8x32_t));
size_t manualLength = length - manualStartOffset;
uint8x32_t *vector = (uint8x32_t *)(bytes + alignmentBytes);
uint8x32_t maskVector = { };
memset_pattern4(&maskVector, maskKey, sizeof(uint8x32_t));
maskVector = SRShiftVector(maskVector, alignmentBytes);
SRMaskBytesManual(bytes, alignmentBytes, maskKey);
for (size_t vectorIndex = 0; vectorIndex < vectorLength; vectorIndex++) {
vector[vectorIndex] = vector[vectorIndex] ^ maskVector;
}
// Use the shifted mask for the final manual part.
SRMaskBytesManual(bytes + manualStartOffset, manualLength, (uint8_t *) &maskVector);
}

View File

@ -0,0 +1,26 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
// The origin isn't really applicable for a native application.
// So instead, just map ws -> http and wss -> https.
extern NSString *SRURLOrigin(NSURL *url);
extern BOOL SRURLRequiresSSL(NSURL *url);
// Extracts `user` and `password` from url (if available) into `Basic base64(user:password)`.
extern NSString *_Nullable SRBasicAuthorizationHeaderFromURL(NSURL *url);
// Returns a valid value for `NSStreamNetworkServiceType` or `nil`.
extern NSString *_Nullable SRStreamNetworkServiceTypeFromURLRequest(NSURLRequest *request);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,77 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRURLUtilities.h"
#import "SRHash.h"
NS_ASSUME_NONNULL_BEGIN
NSString *SRURLOrigin(NSURL *url)
{
NSMutableString *origin = [NSMutableString string];
NSString *scheme = url.scheme.lowercaseString;
if ([scheme isEqualToString:@"wss"]) {
scheme = @"https";
} else if ([scheme isEqualToString:@"ws"]) {
scheme = @"http";
}
[origin appendFormat:@"%@://%@", scheme, url.host];
NSNumber *port = url.port;
BOOL portIsDefault = (!port ||
([scheme isEqualToString:@"http"] && port.integerValue == 80) ||
([scheme isEqualToString:@"https"] && port.integerValue == 443));
if (!portIsDefault) {
[origin appendFormat:@":%@", port.stringValue];
}
return origin;
}
extern BOOL SRURLRequiresSSL(NSURL *url)
{
NSString *scheme = url.scheme.lowercaseString;
return ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]);
}
extern NSString *_Nullable SRBasicAuthorizationHeaderFromURL(NSURL *url)
{
NSData *data = [[NSString stringWithFormat:@"%@:%@", url.user, url.password] dataUsingEncoding:NSUTF8StringEncoding];
return [NSString stringWithFormat:@"Basic %@", SRBase64EncodedStringFromData(data)];
}
extern NSString *_Nullable SRStreamNetworkServiceTypeFromURLRequest(NSURLRequest *request)
{
NSString *networkServiceType = nil;
switch (request.networkServiceType) {
case NSURLNetworkServiceTypeDefault:
break;
case NSURLNetworkServiceTypeVoIP:
networkServiceType = NSStreamNetworkServiceTypeVoIP;
break;
case NSURLNetworkServiceTypeVideo:
networkServiceType = NSStreamNetworkServiceTypeVideo;
break;
case NSURLNetworkServiceTypeBackground:
networkServiceType = NSStreamNetworkServiceTypeBackground;
break;
case NSURLNetworkServiceTypeVoice:
networkServiceType = NSStreamNetworkServiceTypeVoice;
break;
#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 || __TV_OS_VERSION_MAX_ALLOWED >= 100000 || __WATCH_OS_VERSION_MAX_ALLOWED >= 30000)
case NSURLNetworkServiceTypeCallSignaling:
networkServiceType = NSStreamNetworkServiceTypeCallSignaling;
break;
#endif
}
return networkServiceType;
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,27 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSRunLoop (SRWebSocket)
/**
Default run loop that will be used to schedule all instances of `SRWebSocket`.
@return An instance of `NSRunLoop`.
*/
+ (NSRunLoop *)SR_networkRunLoop;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,27 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "NSRunLoop+SRWebSocket.h"
#import "NSRunLoop+SRWebSocketPrivate.h"
#import "SRRunLoopThread.h"
// Required for object file to always be linked.
void import_NSRunLoop_SRWebSocket() { }
@implementation NSRunLoop (SRWebSocket)
+ (NSRunLoop *)SR_networkRunLoop
{
return [SRRunLoopThread sharedThread].runLoop;
}
@end

View File

@ -0,0 +1,38 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSURLRequest (SRWebSocket)
/**
An array of pinned `SecCertificateRef` SSL certificates that `SRWebSocket` will use for validation.
*/
@property (nullable, nonatomic, copy, readonly) NSArray *SR_SSLPinnedCertificates
DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
"and leads to security issues. Please use a proper, trust chain validated certificate.");
@end
@interface NSMutableURLRequest (SRWebSocket)
/**
An array of pinned `SecCertificateRef` SSL certificates that `SRWebSocket` will use for validation.
*/
@property (nullable, nonatomic, copy) NSArray *SR_SSLPinnedCertificates
DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
"and leads to security issues. Please use a proper, trust chain validated certificate.");
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,42 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "NSURLRequest+SRWebSocket.h"
#import "NSURLRequest+SRWebSocketPrivate.h"
// Required for object file to always be linked.
void import_NSURLRequest_SRWebSocket() { }
NS_ASSUME_NONNULL_BEGIN
static NSString *const SRSSLPinnnedCertificatesKey = @"SocketRocket_SSLPinnedCertificates";
@implementation NSURLRequest (SRWebSocket)
- (nullable NSArray *)SR_SSLPinnedCertificates
{
return nil;
}
@end
@implementation NSMutableURLRequest (SRWebSocket)
- (void)setSR_SSLPinnedCertificates:(nullable NSArray *)SR_SSLPinnedCertificates
{
[NSException raise:NSInvalidArgumentException
format:@"Using pinned certificates is neither secure nor supported in SocketRocket, "
"and leads to security issues. Please use a proper, trust chain validated certificate."];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,72 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
#import <Security/Security.h>
NS_ASSUME_NONNULL_BEGIN
@interface SRSecurityPolicy : NSObject
/**
A default `SRSecurityPolicy` implementation specifies socket security and
validates the certificate chain.
Use a subclass of `SRSecurityPolicy` for more fine grained customization.
*/
+ (instancetype)defaultPolicy;
/**
Specifies socket security and provider certificate pinning, disregarding certificate
chain validation.
@param pinnedCertificates Array of `SecCertificateRef` SSL certificates to use for validation.
*/
+ (instancetype)pinnningPolicyWithCertificates:(NSArray *)pinnedCertificates
DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
"and leads to security issues. Please use a proper, trust chain validated certificate.");
/**
Specifies socket security and optional certificate chain validation.
@param enabled Whether or not to validate the SSL certificate chain. If you
are considering using this method because your certificate was not issued by a
recognized certificate authority, consider using `pinningPolicyWithCertificates` instead.
*/
- (instancetype)initWithCertificateChainValidationEnabled:(BOOL)enabled
DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
"Please use a proper Certificate Authority to issue your TLS certificates.")
NS_DESIGNATED_INITIALIZER;
/**
Updates all the security options for input and output streams, for example you
can set your socket security level here.
@param stream Stream to update the options in.
*/
- (void)updateSecurityOptionsInStream:(NSStream *)stream;
/**
Whether or not the specified server trust should be accepted, based on the security policy.
This method should be used when responding to an authentication challenge from
a server. In the default implemenation, no further validation is done here, but
you're free to override it in a subclass. See `SRPinningSecurityPolicy.h` for
an example.
@param serverTrust The X.509 certificate trust of the server.
@param domain The domain of serverTrust.
@return Whether or not to trust the server.
*/
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,75 @@
//
// Copyright (c) 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import "SRSecurityPolicy.h"
#import "SRPinningSecurityPolicy.h"
NS_ASSUME_NONNULL_BEGIN
@interface SRSecurityPolicy ()
@property (nonatomic, assign, readonly) BOOL certificateChainValidationEnabled;
@end
@implementation SRSecurityPolicy
+ (instancetype)defaultPolicy
{
return [self new];
}
+ (instancetype)pinnningPolicyWithCertificates:(NSArray *)pinnedCertificates
{
[NSException raise:NSInvalidArgumentException
format:@"Using pinned certificates is neither secure nor supported in SocketRocket, "
"and leads to security issues. Please use a proper, trust chain validated certificate."];
return nil;
}
- (instancetype)initWithCertificateChainValidationEnabled:(BOOL)enabled
{
self = [super init];
if (!self) { return self; }
_certificateChainValidationEnabled = enabled;
return self;
}
- (instancetype)init
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
return [self initWithCertificateChainValidationEnabled:YES];
#pragma clang diagnostic pop
}
- (void)updateSecurityOptionsInStream:(NSStream *)stream
{
// Enforce TLS 1.2
[stream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
// Validate certificate chain for this stream if enabled.
NSDictionary<NSString *, id> *sslOptions = @{ (__bridge NSString *)kCFStreamSSLValidatesCertificateChain : @(self.certificateChainValidationEnabled) };
[stream setProperty:sslOptions forKey:(__bridge NSString *)kCFStreamPropertySSLSettings];
}
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
{
// No further evaluation happens in the default policy.
return YES;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,21 +1,17 @@
//
// Copyright 2012 Square Inc.
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// All rights reserved.
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <Foundation/Foundation.h>
#import <Security/SecCertificate.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, SRReadyState) {
SR_CONNECTING = 0,
@ -24,109 +20,398 @@ typedef NS_ENUM(NSInteger, SRReadyState) {
SR_CLOSED = 3,
};
typedef enum SRStatusCode : NSInteger {
typedef NS_ENUM(NSInteger, SRStatusCode) {
// 0-999: Reserved and not used.
SRStatusCodeNormal = 1000,
SRStatusCodeGoingAway = 1001,
SRStatusCodeProtocolError = 1002,
SRStatusCodeUnhandledType = 1003,
// 1004 reserved.
SRStatusNoStatusReceived = 1005,
// 1004-1006 reserved.
SRStatusCodeAbnormal = 1006,
SRStatusCodeInvalidUTF8 = 1007,
SRStatusCodePolicyViolated = 1008,
SRStatusCodeMessageTooBig = 1009,
} SRStatusCode;
SRStatusCodeMissingExtension = 1010,
SRStatusCodeInternalError = 1011,
SRStatusCodeServiceRestart = 1012,
SRStatusCodeTryAgainLater = 1013,
// 1014: Reserved for future use by the WebSocket standard.
SRStatusCodeTLSHandshake = 1015,
// 1016-1999: Reserved for future use by the WebSocket standard.
// 2000-2999: Reserved for use by WebSocket extensions.
// 3000-3999: Available for use by libraries and frameworks. May not be used by applications. Available for registration at the IANA via first-come, first-serve.
// 4000-4999: Available for use by applications.
};
@class SRWebSocket;
@class SRSecurityPolicy;
/**
Error domain used for errors reported by SRWebSocket.
*/
extern NSString *const SRWebSocketErrorDomain;
extern NSString *const SRHTTPResponseErrorKey;
#pragma mark - SRWebSocketDelegate
/**
Key used for HTTP status code if bad response was received from the server.
*/
extern NSString *const SRHTTPResponseErrorKey;
@protocol SRWebSocketDelegate;
///--------------------------------------
#pragma mark - SRWebSocket
///--------------------------------------
/**
A `SRWebSocket` object lets you connect, send and receive data to a remote Web Socket.
*/
@interface SRWebSocket : NSObject <NSStreamDelegate>
/**
The delegate of the web socket.
The web socket delegate is notified on all state changes that happen to the web socket.
*/
@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
@property (nonatomic, readonly) SRReadyState readyState;
@property (nonatomic, readonly, retain) NSURL *url;
/**
A dispatch queue for scheduling the delegate calls. The queue doesn't need be a serial queue.
// This returns the negotiated protocol.
// It will be nil until after the handshake completes.
@property (nonatomic, readonly, copy) NSString *protocol;
If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
*/
@property (nullable, nonatomic, strong) dispatch_queue_t delegateDispatchQueue;
// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
- (id)initWithURLRequest:(NSURLRequest *)request;
/**
An operation queue for scheduling the delegate calls.
// Some helper constructors.
- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
- (id)initWithURL:(NSURL *)url;
If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
*/
@property (nullable, nonatomic, strong) NSOperationQueue *delegateOperationQueue;
// Delegate queue will be dispatch_main_queue by default.
// You cannot set both OperationQueue and dispatch_queue.
- (void)setDelegateOperationQueue:(NSOperationQueue*) queue;
- (void)setDelegateDispatchQueue:(dispatch_queue_t) queue;
/**
Current ready state of the socket. Default: `SR_CONNECTING`.
// By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes.
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
This property is Key-Value Observable and fully thread-safe.
*/
@property (atomic, assign, readonly) SRReadyState readyState;
// SRWebSockets are intended for one-time-use only. Open should be called once and only once.
/**
An instance of `NSURL` that this socket connects to.
*/
@property (nullable, nonatomic, strong, readonly) NSURL *url;
/**
All HTTP headers that were received by socket or `nil` if none were received so far.
*/
@property (nullable, nonatomic, assign, readonly) CFHTTPMessageRef receivedHTTPHeaders;
/**
Array of `NSHTTPCookie` cookies to apply to the connection.
*/
@property (nullable, nonatomic, copy) NSArray<NSHTTPCookie *> *requestCookies;
/**
The negotiated web socket protocol or `nil` if handshake did not yet complete.
*/
@property (nullable, nonatomic, copy, readonly) NSString *protocol;
/**
A boolean value indicating whether this socket will allow connection without SSL trust chain evaluation.
For DEBUG builds this flag is ignored, and SSL connections are allowed regardless of the certificate trust configuration
*/
@property (nonatomic, assign, readonly) BOOL allowsUntrustedSSLCertificates;
///--------------------------------------
#pragma mark - Constructors
///--------------------------------------
/**
Initializes a web socket with a given `NSURLRequest`.
@param request Request to initialize with.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request;
/**
Initializes a web socket with a given `NSURLRequest`, specifying a transport security policy (e.g. SSL configuration).
@param request Request to initialize with.
@param securityPolicy Policy object describing transport security behavior.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request securityPolicy:(SRSecurityPolicy *)securityPolicy;
/**
Initializes a web socket with a given `NSURLRequest` and list of sub-protocols.
@param request Request to initialize with.
@param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols;
/**
Initializes a web socket with a given `NSURLRequest`, list of sub-protocols and whether untrusted SSL certificates are allowed.
@param request Request to initialize with.
@param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
@param allowsUntrustedSSLCertificates Boolean value indicating whether untrusted SSL certificates are allowed. Default: `false`.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
"Please use a proper Certificate Authority to issue your TLS certificates.");
/**
Initializes a web socket with a given `NSURLRequest`, list of sub-protocols and whether untrusted SSL certificates are allowed.
@param request Request to initialize with.
@param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
@param securityPolicy Policy object describing transport security behavior.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols securityPolicy:(SRSecurityPolicy *)securityPolicy NS_DESIGNATED_INITIALIZER;
/**
Initializes a web socket with a given `NSURL`.
@param url URL to initialize with.
*/
- (instancetype)initWithURL:(NSURL *)url;
/**
Initializes a web socket with a given `NSURL` and list of sub-protocols.
@param url URL to initialize with.
@param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
*/
- (instancetype)initWithURL:(NSURL *)url protocols:(nullable NSArray<NSString *> *)protocols;
/**
Initializes a web socket with a given `NSURL`, specifying a transport security policy (e.g. SSL configuration).
@param url URL to initialize with.
@param securityPolicy Policy object describing transport security behavior.
*/
- (instancetype)initWithURL:(NSURL *)url securityPolicy:(SRSecurityPolicy *)securityPolicy;
/**
Initializes a web socket with a given `NSURL`, list of sub-protocols and whether untrusted SSL certificates are allowed.
@param url URL to initialize with.
@param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
@param allowsUntrustedSSLCertificates Boolean value indicating whether untrusted SSL certificates are allowed. Default: `false`.
*/
- (instancetype)initWithURL:(NSURL *)url protocols:(nullable NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
"Please use a proper Certificate Authority to issue your TLS certificates.");
/**
Unavailable initializer. Please use any other initializer.
*/
- (instancetype)init NS_UNAVAILABLE;
/**
Unavailable constructor. Please use any other initializer.
*/
+ (instancetype)new NS_UNAVAILABLE;
///--------------------------------------
#pragma mark - Schedule
///--------------------------------------
/**
Schedules a received on a given run loop in a given mode.
By default, a web socket will schedule itself on `+[NSRunLoop SR_networkRunLoop]` using `NSDefaultRunLoopMode`.
@param runLoop The run loop on which to schedule the receiver.
@param mode The mode for the run loop.
*/
- (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode NS_SWIFT_NAME(schedule(in:forMode:));
/**
Removes the receiver from a given run loop running in a given mode.
@param runLoop The run loop on which the receiver was scheduled.
@param mode The mode for the run loop.
*/
- (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode NS_SWIFT_NAME(unschedule(from:forMode:));
///--------------------------------------
#pragma mark - Open / Close
///--------------------------------------
/**
Opens web socket, which will trigger connection, authentication and start receiving/sending events.
An instance of `SRWebSocket` is intended for one-time-use only. This method should be called once and only once.
*/
- (void)open;
/**
Closes a web socket using `SRStatusCodeNormal` code and no reason.
*/
- (void)close;
- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
// Send a UTF8 String or Data.
- (void)send:(id)data;
/**
Closes a web socket using a given code and reason.
// Send Data (can be nil) in a ping message.
- (void)sendPing:(NSData *)data;
@param code Code to close the socket with.
@param reason Reason to send to the server or `nil`.
*/
- (void)closeWithCode:(NSInteger)code reason:(nullable NSString *)reason;
///--------------------------------------
#pragma mark Send
///--------------------------------------
/**
Send a UTF-8 string or binary data to the server.
@param message UTF-8 String or Data to send.
@deprecated Please use `sendString:` or `sendData` instead.
*/
- (void)send:(nullable id)message __attribute__((deprecated("Please use `sendString:error:` or `sendData:error:` instead.")));
/**
Send a UTF-8 String to the server.
@param string String to send.
@param error On input, a pointer to variable for an `NSError` object.
If an error occurs, this pointer is set to an `NSError` object containing information about the error.
You may specify `nil` to ignore the error information.
@return `YES` if the string was scheduled to send, otherwise - `NO`.
*/
- (BOOL)sendString:(NSString *)string error:(NSError **)error NS_SWIFT_NAME(send(string:));
/**
Send binary data to the server.
@param data Data to send.
@param error On input, a pointer to variable for an `NSError` object.
If an error occurs, this pointer is set to an `NSError` object containing information about the error.
You may specify `nil` to ignore the error information.
@return `YES` if the string was scheduled to send, otherwise - `NO`.
*/
- (BOOL)sendData:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(send(data:));
/**
Send binary data to the server, without making a defensive copy of it first.
@param data Data to send.
@param error On input, a pointer to variable for an `NSError` object.
If an error occurs, this pointer is set to an `NSError` object containing information about the error.
You may specify `nil` to ignore the error information.
@return `YES` if the string was scheduled to send, otherwise - `NO`.
*/
- (BOOL)sendDataNoCopy:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(send(dataNoCopy:));
/**
Send Ping message to the server with optional data.
@param data Instance of `NSData` or `nil`.
@param error On input, a pointer to variable for an `NSError` object.
If an error occurs, this pointer is set to an `NSError` object containing information about the error.
You may specify `nil` to ignore the error information.
@return `YES` if the string was scheduled to send, otherwise - `NO`.
*/
- (BOOL)sendPing:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(sendPing(_:));
@end
///--------------------------------------
#pragma mark - SRWebSocketDelegate
///--------------------------------------
/**
The `SRWebSocketDelegate` protocol describes the methods that `SRWebSocket` objects
call on their delegates to handle status and messsage events.
*/
@protocol SRWebSocketDelegate <NSObject>
// message will either be an NSString if the server is using text
// or NSData if the server is using binary.
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
@optional
#pragma mark Receive Messages
/**
Called when any message was received from a web socket.
This method is suboptimal and might be deprecated in a future release.
@param webSocket An instance of `SRWebSocket` that received a message.
@param message Received message. Either a `String` or `NSData`.
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
/**
Called when a frame was received from a web socket.
@param webSocket An instance of `SRWebSocket` that received a message.
@param string Received text in a form of UTF-8 `String`.
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string;
/**
Called when a frame was received from a web socket.
@param webSocket An instance of `SRWebSocket` that received a message.
@param data Received data in a form of `NSData`.
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data;
#pragma mark Status & Connection
/**
Called when a given web socket was open and authenticated.
@param webSocket An instance of `SRWebSocket` that was open.
*/
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
/**
Called when a given web socket encountered an error.
@param webSocket An instance of `SRWebSocket` that failed with an error.
@param error An instance of `NSError`.
*/
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
/**
Called when a given web socket was closed.
@param webSocket An instance of `SRWebSocket` that was closed.
@param code Code reported by the server.
@param reason Reason in a form of a String that was reported by the server or `nil`.
@param wasClean Boolean value indicating whether a socket was closed in a clean state.
*/
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(nullable NSString *)reason wasClean:(BOOL)wasClean;
/**
Called on receive of a ping message from the server.
@param webSocket An instance of `SRWebSocket` that received a ping frame.
@param data Payload that was received or `nil` if there was no payload.
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceivePingWithData:(nullable NSData *)data;
/**
Called when a pong data was received in response to ping.
@param webSocket An instance of `SRWebSocket` that received a pong frame.
@param pongData Payload that was received or `nil` if there was no payload.
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(nullable NSData *)pongData;
/**
Sent before reporting a text frame to be able to configure if it shuold be convert to a UTF-8 String or passed as `NSData`.
If the method is not implemented - it will always convert text frames to String.
@param webSocket An instance of `SRWebSocket` that received a text frame.
@return `YES` if text frame should be converted to UTF-8 String, otherwise - `NO`. Default: `YES`.
*/
- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket NS_SWIFT_NAME(webSocketShouldConvertTextFrameToString(_:));
@end
#pragma mark - NSURLRequest (CertificateAdditions)
@interface NSURLRequest (CertificateAdditions)
@property (nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates;
@end
#pragma mark - NSMutableURLRequest (CertificateAdditions)
@interface NSMutableURLRequest (CertificateAdditions)
@property (nonatomic, retain) NSArray *SR_SSLPinnedCertificates;
@end
#pragma mark - NSRunLoop (SRWebSocket)
@interface NSRunLoop (SRWebSocket)
+ (NSRunLoop *)SR_networkRunLoop;
@end
NS_ASSUME_NONNULL_END

1628
SocketRocket/SRWebSocket.m Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +0,0 @@
//
// SecureIO.h
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#ifndef __SocketRocket__SecureIO__
#define __SocketRocket__SecureIO__
#include "DispatchIO.h"
#include "DispatchData.h"
#include <deque>
#include <vector>
struct SSLContext;
namespace squareup {
namespace dispatch {
class SecureIO;
// You are responsible for removing inputStream and outputStream
typedef void (^dial_tls_callback)(SecureIO *io, int error, const char *error_message);
void DialTLS(const char *hostname, const char *servname, SSLContextRef ssl_context, dispatch_queue_t callback_queue, dispatch_queue_t work_queue, dispatch_queue_t parent_io_queue, dial_tls_callback dial_callback, void(^close_handler)(int error) = nullptr);
template <typename FuncType>
class QueuedHandle {
private:
__strong FuncType _handler = nullptr;
__sr_maybe_strong__ dispatch_queue_t _queue = nullptr;
public:
inline QueuedHandle() {
}
inline QueuedHandle(dispatch_queue_t queue, FuncType handler) {
_handler = [handler copy];
_queue = queue;
sr_dispatch_retain(_queue);
}
inline QueuedHandle(const QueuedHandle<FuncType> &other) : QueuedHandle(other._queue, other._handler){
}
inline QueuedHandle &operator=(const QueuedHandle &other){
_handler = other._handler;
_queue = other._queue;
sr_dispatch_release(_queue);
return *this;
}
inline ~QueuedHandle() {
if (_queue) {
sr_dispatch_release(_queue);
}
}
inline bool Valid() const {
return _handler != nullptr;
}
inline void Invalidate() {
_handler = nullptr;
}
template<typename... Args>
void operator () (Args... args) const {
assert(Valid());
FuncType handler = _handler;
dispatch_async(_queue, [handler, args...]{
handler(args...);
});
}
};
typedef QueuedHandle<dispatch_io_handler_t> DispatchHandler;
struct WriteJob {
bool isLast;
size_t rawBytes = 0;
size_t cryptedBytes = 0;
DispatchHandler handler;
};
struct ReadRequest {
// How many rawBytes we're expecting to read.
// This is populated in SSLRead.
size_t rawBytesRemaining = 0;
DispatchHandler handler;
};
class SecureIO : public IO {
IO *_io;
SSLContext *_context;
dispatch_queue_t _workQueue;
std::deque<WriteJob> _writeJobs;
std::deque<ReadRequest> _readRequests;
Data _waitingCryptedData;
size_t _cryptedBytesRequested = 0;
size_t _rawBytesRequested = 0;
size_t _highWater = SIZE_MAX;
size_t _lowWater = 1024 * 8;
bool _cancelled = false;
bool _closing = false;
// Set when we're inside of HandleSSLRead
// If we're reading and get a call to our SSLWriteHandler, the connection is probably being closed
bool _handlingRead = false;
// presence of this means handshake is in progress
DispatchHandler _handshakeHandler;
// This is set to true when we send a NULL data ptr. This is so we can request data we need.
bool _calculatingRequestSize = false;
std::vector<uint8_t> _sslReadBuffer;
public:
// Takes ownership of IO and delete it when done
SecureIO(IO *io, SSLContextRef context, dispatch_queue_t workQueue);
~SecureIO();
// This performs the handshake.
// There will be no data sent back to handler, but it will be called on completion
void Handshake(dispatch_queue_t queue, dispatch_io_handler_t handler);
void Close(dispatch_io_close_flags_t flags);
void Read(size_t length, dispatch_queue_t queue, dispatch_io_handler_t handler);
void Write(dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t handler);
void Barrier(dispatch_block_t barrier);
inline void SetHighWater(size_t high_water) {
_highWater = high_water;
}
void SetLowWater(size_t low_water) {
_lowWater = low_water;
}
private:
// Requests will ask the underlying stream for lenght - _rawBytesRequested
void RequestBytes(size_t length);
void Cancel(dispatch_io_close_flags_t flags, int error);
void CheckHandshake();
void InnerWrite(dispatch_data_t data, const DispatchHandler &handler);
// These really should be private
public:
OSStatus SSLReadHandler(void *data, size_t *dataLength);
OSStatus SSLWriteHandler(const void *data, size_t *dataLength);
private:
void HandleSSLWrite(bool done, size_t requestedLength, int error);
void HandleSSLRead(bool done, dispatch_data_t data, int error);
void PumpSSLRead();
void DoSSLRead();
};
}
}
#endif /* defined(__SocketRocket__SecureIO__) */

View File

@ -1,475 +0,0 @@
//
// SecureIO.cpp
// SocketRocket
//
// Created by Michael Lewis on 1/12/13.
//
//
#include <Security/SecureTransport.h>
#include "SecureIO.h"
#include "DispatchData.h"
#define ALLOW_INSECURE_SSL 1
namespace squareup {
namespace dispatch {
static OSStatus readFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
static OSStatus writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
void DialTLS(const char *hostname,
const char *servname,
SSLContextRef ssl_context,
dispatch_queue_t callback_queue,
dispatch_queue_t work_queue,
dispatch_queue_t parent_io_queue,
dial_tls_callback dial_callback,
void(^close_handler)(int error)) {
if (close_handler != nullptr) {
close_handler = [close_handler copy];
}
dial_callback = [dial_callback copy];
sr_dispatch_retain(callback_queue);
// The work queue is the outer ones callback_queue
SimpleDial(hostname, servname, work_queue, parent_io_queue, [=](squareup::dispatch::RawIO *io, int error, const char *error_message) {
if (error != 0 || io == nullptr) {
dispatch_async(callback_queue, ^{
dial_callback(nullptr, error, error_message);
});
sr_dispatch_release(callback_queue);
return;
}
SecureIO *newIO = new SecureIO(io, ssl_context, work_queue);
sr_dispatch_release(callback_queue);
newIO->Handshake(callback_queue, [newIO, dial_callback](bool done, dispatch_data_t data, int error) {
SecureIO *io = newIO;
if (error) {
delete io;
io = nullptr;
}
// TODO: maybe add message?
dial_callback(io, error, nullptr);
});
}, close_handler);
}
SecureIO::SecureIO(IO *io, SSLContextRef context, dispatch_queue_t workQueue) :
_io(io), _context(context), _workQueue(workQueue) {
sr_dispatch_retain(_workQueue);
CFRetain(_context);
SSLSetConnection(_context, reinterpret_cast<const void *>(this));
SSLSetIOFuncs(_context, readFunc, writeFunc);
// TODO: delegate certificate authentication
#if ALLOW_INSECURE_SSL
SSLSetSessionOption(_context, kSSLSessionOptionBreakOnServerAuth, true);
#endif
}
SecureIO::~SecureIO() {
sr_dispatch_release(_workQueue);
CFRelease(_context);
// make sure things closed before we delete the io
assert(!_io);
}
void SecureIO::Handshake(dispatch_queue_t queue, dispatch_io_handler_t handler) {
_handshakeHandler = DispatchHandler(queue, handler);
dispatch_async(_workQueue, [this]{
CheckHandshake();
});
}
void SecureIO::Close(dispatch_io_close_flags_t flags) {
assert(!_closing);
dispatch_async(_workQueue, [this, flags]{
assert(!_closing);
_closing = true;
OSStatus status = SSLClose(_context);
// This shouldn't be a blocking operation
assert(status != errSSLWouldBlock);
Cancel(flags, status);
return;
});
}
void SecureIO::Read(size_t length, dispatch_queue_t queue, dispatch_io_handler_t handler) {
DispatchHandler dispatchHandler(queue, [handler copy]);
dispatch_async(_workQueue, [length, dispatchHandler, this]{
if (_cancelled) {
dispatchHandler(true, (dispatch_data_t)nullptr, ECANCELED);
return;
}
ReadRequest readRequest;
readRequest.handler = dispatchHandler;
readRequest.rawBytesRemaining += length;
_readRequests.push_back(readRequest);
// TODO: run on queue
_rawBytesRequested += length;
PumpSSLRead();
});
}
void SecureIO::PumpSSLRead() {
size_t buffSize = SIZE_MAX;
// This can happen if we have leftover data and haven't requested more.
while (buffSize > 0) {
// Make sure we are requesting enough;
OSStatus status = SSLGetBufferedReadSize(_context, &buffSize);
assert(status == 0);
if (buffSize > 0) {
if (_readRequests.size() == 0) {
return;
}
DoSSLRead();
}
}
_calculatingRequestSize = true;
const size_t maxBufferSize = 32 * 1024;
// We don't actually want to read anything into the _sslReadBuffer, howevr there's a bug when we go through 2g of data we have a memory issue
_sslReadBuffer.resize(std::max(_sslReadBuffer.capacity(), std::min(_rawBytesRequested, maxBufferSize)));
size_t dummyProcessed;
assert(buffSize == 0);
OSStatus status = ::SSLRead(_context, _sslReadBuffer.data(), _sslReadBuffer.size(), &dummyProcessed);
assert(dummyProcessed == 0);
_calculatingRequestSize = false;
if (status == errSSLClosedGraceful) {
if (!_closing) {
_closing = true;
Cancel(0, 0);
return;
}
}
assert(status == errSSLWouldBlock);
}
void SecureIO::Write(dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t handler) {
sr_dispatch_retain(data);
DispatchHandler dispatchHandler(queue, handler);
Data(data).Apply(^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
return true;
});
dispatch_async(_workQueue, [data, dispatchHandler, this]{
InnerWrite(data, dispatchHandler);
sr_dispatch_release(data);
});
}
void SecureIO::InnerWrite(dispatch_data_t data, const DispatchHandler &handler) {
if (_cancelled) {
handler(true, (dispatch_data_t)nullptr, ECANCELED);
return;
}
OSStatus result = 0;
size_t totalSize = dispatch_data_get_size(data);
dispatch_data_apply(data, [&](dispatch_data_t region, size_t offset, const void *buffer, size_t size) -> bool {
WriteJob newJob;
newJob.handler = handler;
newJob.rawBytes = size;
newJob.isLast = offset + size == totalSize;
newJob.cryptedBytes = 0;
_writeJobs.push_back(newJob);
// WriteSSL will fill in the crypted bytes
// isLast will be set to True for the last one
size_t sizeWritten = 0;
result = ::SSLWrite(_context, buffer, size, &sizeWritten);
// I think we can make this assumption since we don't block at all in our handler.
if (result != 0) {
return false;
};
// We should be able to make this assumptions since our write func never blocks
assert(sizeWritten == size);
return true;
});
if (result) {
Cancel(0, result);
return;
}
}
void SecureIO::RequestBytes(size_t bytesWanted) {
if (bytesWanted > _cryptedBytesRequested) {
size_t requestSize = bytesWanted - _cryptedBytesRequested;
_cryptedBytesRequested += requestSize;
_io->Read(requestSize, _workQueue, [this](bool done, dispatch_data_t data, int error) {
HandleSSLRead(done, data, error);
});
}
};
OSStatus SecureIO::SSLReadHandler(void *data, size_t *dataLength) {
if (_calculatingRequestSize) {
RequestBytes(*dataLength);
*dataLength = 0;
return errSSLWouldBlock;
}
size_t bytesRequested = *dataLength;
// If _calculatingRequestSize is true, always return errSSLWouldBlock and pretend we don't have any data
size_t bytesToCopy = std::min(_waitingCryptedData.Size(), bytesRequested);
*dataLength = bytesToCopy;
if (bytesToCopy > 0) {
// Advance it forward
_waitingCryptedData = _waitingCryptedData.TakeInto(bytesToCopy, data);
_waitingCryptedData.FlattenIfNecessary();
}
if (bytesToCopy < bytesRequested) {
RequestBytes(bytesRequested - bytesToCopy);
return errSSLWouldBlock;
}
return noErr;
}
OSStatus SecureIO::SSLWriteHandler(const void *data, size_t *dataLength) {
size_t requestedLength = *dataLength;
if (!_handshakeHandler.Valid() && !_closing && !_handlingRead) {
assert(_writeJobs.size() > 0);
_writeJobs.back().cryptedBytes += requestedLength;
}
_io->Write(Data(data, requestedLength, _workQueue), _workQueue, [this, requestedLength](bool done, dispatch_data_t data, int error) {
HandleSSLWrite(done, requestedLength, error);
});
return 0;
}
void SecureIO::HandleSSLRead(bool done, dispatch_data_t data, int error) {
if (!_handshakeHandler.Valid() && _readRequests.size() == 0) {
return;
}
if (error != 0) {
if (_handshakeHandler.Valid()) {
_handshakeHandler(done, (dispatch_data_t)nullptr, error);
_handshakeHandler.Invalidate();
} else {
assert(_readRequests.size() > 0);
Cancel(0, error);
}
return;
}
// We got some data, so append it
Data d(data);
_cryptedBytesRequested -= d.Size();
_waitingCryptedData += d;
if (_handshakeHandler.Valid()) {
CheckHandshake();
return;
}
DoSSLRead();
PumpSSLRead();
}
void SecureIO::DoSSLRead() {
assert(_readRequests.size() > 0);
ReadRequest *frontRead = &_readRequests.front();
const DispatchHandler &handler = frontRead->handler;
size_t length = frontRead->rawBytesRemaining;
// Let's cap length at 2x the bytes we have available. probably won't use all of it (it will probably be less than 1x)
length = std::min(length, 2 * _waitingCryptedData.Size());
length = std::min(length, _highWater);
size_t buffSize = 0;
SSLGetBufferedReadSize(_context, &buffSize);
length = std::max(buffSize, length);
size_t sizeRead = 0;
void *buffer = malloc(length);
assert(buffer);
// TODO: optimize this and not malloc memory each time
assert(_calculatingRequestSize == false);
assert(_handlingRead == false);
_handlingRead = true;
OSStatus status = ::SSLRead(_context, buffer, length, &sizeRead);
_handlingRead = false;
if (status != 0 && status != errSSLWouldBlock && status != errSSLClosedGraceful) {
free(buffer);
buffer = nullptr;
// TODO: handle error better
Cancel(0, status);
return;
}
Data rawData(dispatch_data_create(buffer, sizeRead, _workQueue, DISPATCH_DATA_DESTRUCTOR_FREE), false);
frontRead->rawBytesRemaining -= sizeRead;
bool isDone = (frontRead->rawBytesRemaining == 0);
// TODO: honor watermarks
handler(isDone, rawData, 0);
if (status == errSSLClosedGraceful) {
// TODO: handle close
}
if (isDone) {
_readRequests.pop_front();
}
}
void SecureIO::HandleSSLWrite(bool done, size_t requestedLength, int error) {
if (_handshakeHandler.Valid()) {
CheckHandshake();
return;
}
if (_closing) {
return;
}
assert(_writeJobs.size() > 0);
// TODO(lewis): handle rest of errors better
if (error != 0) {
_writeJobs.front().handler(true, dispatch_data_empty, error);
return;
}
assert(_writeJobs.size());
// We only want to call the handlers when we are "done".
// This way we can approximate the bytes that are written
if (done) {
// if we're an error we want to go to the last one
if (error) {
Cancel(0, error);
return;
}
assert(_writeJobs.size());
_writeJobs.front().cryptedBytes -= requestedLength;
WriteJob writeJob = _writeJobs.front();
// Only call them when we're "done" for now, because we don't want to do bookkeeping of remaining data to consume
// TODO: probably change this
if (writeJob.cryptedBytes == 0) {
_writeJobs.pop_front();
if (writeJob.isLast) {
writeJob.handler(true, dispatch_data_empty, error);
}
}
}
}
void SecureIO::CheckHandshake() {
assert(_handshakeHandler.Valid());
OSStatus status = ::SSLHandshake(_context);
// If it would block we got nothing to do
if (status == errSSLWouldBlock) {
return;
}
#if ALLOW_INSECURE_SSL
// TODO: make this better
if (status == errSSLPeerAuthCompleted) {
CheckHandshake();
return;
}
#endif
_handshakeHandler(true, (dispatch_data_t)nullptr, status);
_handshakeHandler.Invalidate();
}
void SecureIO::Cancel(dispatch_io_close_flags_t flags, int error) {
_cancelled = true;
for (const ReadRequest &req : _readRequests) {
req.handler(true, (dispatch_data_t)nullptr, ECANCELED);
}
for (const WriteJob &job : _writeJobs) {
job.handler(true, (dispatch_data_t)nullptr, ECANCELED);
}
_readRequests.clear();
_writeJobs.clear();
_io->Close(flags);
delete _io;
_io = nullptr;
}
void SecureIO::Barrier(dispatch_block_t barrier) {
_io->Barrier(barrier);
}
OSStatus readFunc(SSLConnectionRef connection, void *data, size_t *dataLength) {
return reinterpret_cast<SecureIO *>((void *)connection)->SSLReadHandler(data, dataLength);
};
OSStatus writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength) {
return reinterpret_cast<SecureIO *>((void *)connection)->SSLWriteHandler(data, dataLength);
};
}
}

View File

@ -1,27 +0,0 @@
//
// Copyright 2012 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,15 @@
//
// Copyright 2012 Square Inc.
// Portions Copyright (c) 2016-present, Facebook, Inc.
//
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
#import <SocketRocket/NSRunLoop+SRWebSocket.h>
#import <SocketRocket/NSURLRequest+SRWebSocket.h>
#import <SocketRocket/SRSecurityPolicy.h>
#import <SocketRocket/SRWebSocket.h>

View File

@ -1,142 +0,0 @@
//
// Concurrent.swift
// SocketRocket
//
// Created by Mike Lewis on 8/7/15.
//
//
import Foundation
/// This is a nonblocking once. THis means that the once block
/// may fire after the callers that don't get it succeed
/// This is unlike the behavior of dispatch_once
struct Once {
var count: Int32 = 0
/// If this is the first one to call this, will invoke the block
///
/// :param: bit This structure can be used for more than one bit. We allow the first 16 bits to be used
///
/// :return: true if the block is ecuted
mutating func doMaybe(bit: Int = 0, block: () -> ()) -> Bool {
precondition(bit < 16)
guard !count.atomicTestAndSet(bit) else {
return false
}
block()
return true
}
}
extension Int32 {
mutating func atomicTestAndSet(bit: Int) -> Bool {
return withUnsafeMutablePointer(&self) { ptr in
return OSAtomicTestAndSet(UInt32(bit), ptr)
}
}
}
/// Building block for a
enum PState<V> {
case Pending
case Fulfilled(V)
case Rejected(ErrorType)
}
struct PGroup<T> {
/// TODO: remove locking somehow
typealias LockType = OSSpinLock
typealias Handler = (ErrorOptional<T>) -> ()
private var lock = LockType()
// These should only be mutated inside a lock
private var result: ErrorOptional<T>? = nil
// these are blocks enqueued while we don't have a result. Should be called when we actually fulfill
private var pendingHandlers = [Handler]()
var state = PState<T>.Pending
mutating func cancel() -> Bool {
return reject(Error.Canceled)
}
mutating func reject(e: ErrorType) -> Bool {
return fulfill(.Error(e))
}
mutating func fulfill(v: ErrorOptional<T>) -> Bool {
guard result == nil else {
return false
}
let blocksToRun: [Handler]? = lock.withLock() {
guard self.result == nil else {
return nil
}
self.result = v
let ret = self.pendingHandlers
self.pendingHandlers.removeAll()
return ret
}
guard let b = blocksToRun else {
return false
}
for bl in b {
bl(v)
}
return true
}
/// Adds a handler. Called immediately if result is set. Otherwise it will enqueue
mutating func then(h: Handler) -> Void {
// If we have a result, return it
if let v = self.result {
h(v)
return
}
let valueAgain: ErrorOptional<T>? = lock.withLock {
if let r = result {
return r
}
self.pendingHandlers.append(h)
return nil
}
if let v = valueAgain {
h(v)
}
}
init () {
}
private init(result: ErrorOptional<T>) {
self.result = result
}
static func resolve<T>(v: T) -> PGroup<T> {
return PGroup<T>(result: ErrorOptional<T>(v))
}
static func reject<T>(error: ErrorType) -> PGroup<T> {
return PGroup<T>(result: ErrorOptional<T>(error))
}
}

View File

@ -1,49 +0,0 @@
//
// Error.swift
// SocketRocket
//
// Created by Mike Lewis on 8/7/15.
//
//
/// Wraps errors. Has an uknown type if it cant resolve to an oserror
enum Error: ErrorType {
case Unknown(status: Int32)
case CodecError
case UTF8DecodeError
case Canceled
/// For functions that return negative value on error and expect errno to be set
static func checkReturnCode(returnCode: Int32) -> ErrorType? {
guard returnCode < 0 else {
return nil
}
return errorFromStatusCode(errno)
}
/// Returns an error type based on status code
static func errorFromStatusCode(status: Int32) -> ErrorType? {
guard status != 0 else {
return nil
}
if let e = POSIXError(rawValue: status) {
return e
}
return Error.Unknown(status: status)
}
static func throwIfNotSuccess(status: Int32) throws {
if let e = errorFromStatusCode(status) {
throw e
}
}
// Same as above, but checks if less than 0, and uses errno as the varaible
static func throwIfNotSuccessLessThan0(returnCode: Int32) throws {
if let e = checkReturnCode(returnCode) {
throw e
}
}
}

View File

@ -1,71 +0,0 @@
//
// ErrorOptional.swift
// SocketRocket
//
// Created by Mike Lewis on 8/3/15.
//
//
// Like optional but instead of None, it can take a nil
public enum ErrorOptional<T> {
case Error(ErrorType)
case Some(T)
/// Returns nil if ierrored. Using checkedGet is recommended
var orNil: T? {
get {
switch self {
case let Some(some):
return some
case Error:
return nil
}
}
}
var hasError: Bool {
get {
switch self {
case Some:
return false
case Error:
return true
}
}
}
func checkedGet() throws -> T {
switch self {
case let Some(some):
return some
case let Error(e):
throw e
}
}
/// Construct a non-`nil` instance that stores `some`.
init(_ some: T) {
self = Some(some)
}
init(_ error: ErrorType) {
self = Error(error)
}
// Will catch the first error and return with error wrapped in error optinal
static func attempt(block: () throws -> T) -> ErrorOptional<T> {
do {
return .Some(try block())
} catch let e {
return .Error(e)
}
}
}
public enum Errors: ErrorType {
case MultiError([ErrorType])
}

View File

@ -1,44 +0,0 @@
//
// Extensions.swift
// SocketRocket
//
// Created by Mike Lewis on 8/6/15.
//
//
import Dispatch
extension dispatch_data_t {
func apply(applier: UnsafeBufferPointer<UInt8> -> Bool) -> Bool {
return dispatch_data_apply(self) { (_, offset, buffer, size) -> Bool in
let mappedBuffer = unsafeBitCast(buffer, UnsafePointer<UInt8>.self)
let buffer = UnsafeBufferPointer(start: mappedBuffer.advancedBy(offset), count: size - offset)
return applier(buffer)
}
}
func apply(applier: UnsafeBufferPointer<UInt8> -> ()) -> Bool {
return self.apply { d -> Bool in
applier(d)
return true
}
}
func apply(applier: UnsafeBufferPointer<UInt8> throws -> ()) throws -> Bool {
var error: ErrorType? = nil
let ret = self.apply { d -> Bool in
do {
try applier(d)
return true
} catch let e {
error = e
return false
}
}
if let e = error {
throw e
}
return ret
}
}

View File

@ -1,319 +0,0 @@
//
// IO.swift
// SocketRocket
//
// Created by Mike Lewis on 7/30/15.
//
//
import Foundation
import SystemShims
public struct CloseFlags : OptionSetType {
public init(rawValue: UInt) {
self.rawValue = rawValue
}
public let rawValue: UInt
public static let Stop = CloseFlags(rawValue: DISPATCH_IO_STOP)
}
public typealias DataHandler = (done: Bool, data: dispatch_data_t, error: ErrorType?) -> Void
public typealias ErrorHandler = (error: ErrorType?) -> Void
public protocol IO {
// Closes the IO. the callback will be called when finished. IO can only be closed once
// I/Os only exist once they're open.
func read(length: size_t, queue: Queue, handler: DataHandler)
func write(data: dispatch_data_t, queue: Queue, handler: DataHandler)
func close(queue: Queue, flags: CloseFlags)
}
public class RawIO: IO {
private let channel: dispatch_io_t
public init(channel: dispatch_io_t) {
self.channel = channel
}
public convenience init(fd: dispatch_fd_t,
cleanupQueue: Queue,
callbackQueue: Queue,
ioQueue: Queue,
cleanupHandler: ErrorHandler) {
let channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, cleanupQueue.queue) { errorCode in
cleanupHandler(error: NSError.fromErrorCode(errorCode))
}
dispatch_set_target_queue(channel, ioQueue.queue);
self.init(channel: channel)
}
public func read(length: Int, queue: Queue, handler: DataHandler) {
dispatch_io_read(channel, 0, length, queue.queue, dataHandlerToIoHandler(handler))
}
public func write(data: dispatch_data_t, queue: Queue, handler: DataHandler) {
dispatch_io_write(channel, 0, data, queue.queue, dataHandlerToIoHandler(handler))
}
public func close(queue: Queue, flags: CloseFlags) {
dispatch_io_close(channel, flags.rawValue)
}
}
typealias IOFactory = (fd: dispatch_fd_t) -> IO
public class Listener {
let workQueue: Queue
let ioFactory: IOFactory
var eventSource: dispatch_source_t!
var closeHandler: ErrorHandler!
private init(workQueue: Queue, ioFactory: IOFactory) {
self.workQueue = workQueue
self.ioFactory = ioFactory
}
/// Starts listening
///
/// :param: queue queue callback is called on
/// :param: callback Called when listening starts. AN error if it failed
static func startListening(port: UInt16, address: String, workQueue: Queue, ioFactory: IOFactory, queue: Queue, callback: ErrorHandler) -> Listener {
let l = Listener(workQueue: workQueue, ioFactory: ioFactory)
return l
}
public func close(queue: Queue, handler: ErrorHandler) {
workQueue.dispatchAsync {
self.closeHandler = handler
dispatch_source_cancel(self.eventSource)
self.eventSource = nil
}
}
}
extension NSError {
convenience init(osError: Int32) {
self.init(domain: NSPOSIXErrorDomain, code: Int(osError), userInfo: nil)
}
static func fromErrorCode(osError: Int32) -> NSError? {
if osError == 0 {
return nil;
}
return NSError(osError: osError)
}
}
private func dataHandlerToIoHandler(handler: DataHandler) -> dispatch_io_handler_t {
return { done, data, errorCode in
handler(done: done, data: data, error: NSError.fromErrorCode(errorCode))
}
}
public protocol SockAddr {
init()
mutating func setup(listenAddr: Address, listenPort: UInt16) throws
static var size : Int {get}
static var addressFamily: Int32 { get }
}
public enum Address {
case Loopback
case Any
case IPV6Addr(address: String)
case IPV4Addr(address: String)
}
extension sockaddr_in6: SockAddr {
public mutating func setup(listenAddr: Address, listenPort: UInt16) throws {
switch listenAddr {
case .Any:
self.sin6_addr = in6addr_any
case let .IPV6Addr(address: address):
try Error.throwIfNotSuccess(inet_pton(self.dynamicType.addressFamily, address, &self.sin6_addr))
case .IPV4Addr:
fatalError("Cannot listen to IPV4Address in an ipv6 socket")
case .Loopback:
self.sin6_addr = in6addr_loopback
}
self.sin6_port = listenPort.bigEndian
self.sin6_family = sa_family_t(self.dynamicType.addressFamily)
self.sin6_len = UInt8(self.dynamicType.size)
}
public static let size = sizeof(sockaddr_in6)
public static let addressFamily = AF_INET6
}
let INADDR_ANY = in_addr(s_addr: 0x00000000)
let INADDR_LOOPBACK4 = in_addr(s_addr: UInt32(0x7f000001).bigEndian)
extension sockaddr_in: SockAddr {
public static let size = sizeof(sockaddr_in)
public static let addressFamily = AF_INET
public mutating func setup(listenAddr: Address, listenPort: UInt16) throws {
switch listenAddr {
case .Any:
self.sin_addr = INADDR_ANY
case let .IPV4Addr(address: address):
try Error.throwIfNotSuccess(inet_pton(self.dynamicType.addressFamily, address, &self.sin_addr))
case .IPV6Addr:
fatalError("Cannot listen to IPV6Address in an ipv4 socket")
case .Loopback:
self.sin_addr = INADDR_LOOPBACK4
}
self.sin_port = listenPort.bigEndian
self.sin_family = sa_family_t(self.dynamicType.addressFamily)
self.sin_len = UInt8(self.dynamicType.size)
}
}
extension SockAddr {
// func connect() {
// AF_INET
// }
}
let defaultBacklog: Int32 = 5
// Wrapper around a raw socket. Can do ipv6 or ipv4
public class Socket<T: SockAddr> {
var addr = T()
var fd: dispatch_fd_t = -1
// Initializes as a nonblocking socket and starts listening. DOes not create a dispatch source
public init(address: Address, port: UInt16) throws {
fd = socket(T.addressFamily, SOCK_STREAM, IPPROTO_TCP)
try Error.throwIfNotSuccessLessThan0(fd)
do {
let flags = shim_fcntl(fd, F_GETFL, 0);
try Error.throwIfNotSuccessLessThan0(shim_fcntl(fd, F_SETFL, flags | O_NONBLOCK))
var val: Int32 = 1;
try Error.throwIfNotSuccessLessThan0(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, socklen_t(sizeofValue(val))))
try Error.throwIfNotSuccessLessThan0(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, socklen_t(sizeofValue(val))))
try addr.setup(address, listenPort: port)
try Error.throwIfNotSuccessLessThan0(shim_bind(fd, &addr, addr.dynamicType.size))
try Error.throwIfNotSuccessLessThan0(listen(fd, defaultBacklog))
} catch let e {
close(fd)
self.fd = -1
throw e
}
}
/// Cancel handler isn't guaranteed to dispatch on a specific queue
/// Returns a block that starts the cancel
public func startAccepting(workQueue: Queue, cancelHandler: () -> Void, acceptHandler:(fd: dispatch_fd_t) -> Void) -> (() -> Void) {
precondition(fd >= 0)
let eventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, UInt(fd), 0, workQueue.queue)
dispatch_source_set_event_handler(eventSource) {
var remoteAddress = T()
var len = socklen_t(remoteAddress.dynamicType.size);
let native: dispatch_fd_t = shim_accept(self.fd, &remoteAddress, &len)
if native == -1 {
return;
}
acceptHandler(fd: native)
}
dispatch_source_set_cancel_handler(eventSource) {
precondition(self.fd >= 0)
close(self.fd);
self.fd = -1
cancelHandler()
}
dispatch_resume(eventSource);
return {
dispatch_source_cancel(eventSource)
}
}
}
extension dispatch_data_t {
var empty: Bool {
get {
return dispatch_data_empty === self
}
}
}
private var hints: addrinfo = {
var hints = addrinfo()
hints.ai_family = PF_UNSPEC
hints.ai_socktype = SOCK_STREAM
return hints
}()
extension Queue {
/// Used to dispatch synchronous operations on a specific queue
func blockingPromise<T>(blockingFn: () throws -> T) -> Promise<T> {
let (r, p) = Promise<T>.resolver()
self.dispatchAsync {
r.attemptResolve { return try blockingFn()}
}
return p
}
}
public func getaddrinfoAsync(hostname: String, servname: String, workQueue: Queue = Queue.defaultGlobalQueue) -> Promise<[addrinfo]> {
return workQueue.blockingPromise {
var ai: UnsafeMutablePointer<addrinfo> = nil
defer {
if ai != nil {
freeaddrinfo(ai)
}
}
// ai won't be set if it doesn't work
// TODO(lewis) propagate error up
try Error.throwIfNotSuccess(getaddrinfo(hostname, servname, &hints, &ai))
var ret = [addrinfo]()
var curAi = ai
while curAi != nil {
var mutatedAI = curAi.memory
let next = mutatedAI.ai_next
mutatedAI.ai_next = nil
ret.append(mutatedAI)
curAi = next
}
return ret;
}
}

View File

@ -1,34 +0,0 @@
//
// Lock.swift
// SocketRocket
//
// Created by Mike Lewis on 8/3/15.
//
//
protocol Lock {
mutating func lock()
mutating func unlock()
}
extension Lock {
mutating func withLock<Result>(@noescape fn: () throws -> Result) rethrows -> Result {
lock()
defer {
unlock()
}
return try fn()
}
}
extension OSSpinLock: Lock {
mutating func lock() {
withUnsafeMutablePointer(&self, OSSpinLockLock)
}
mutating func unlock() {
withUnsafeMutablePointer(&self, OSSpinLockUnlock)
}
}

View File

@ -1,188 +0,0 @@
//
// Promise.swift
// SocketRocket
//
// Created by Mike Lewis on 8/3/15.
//
//
import Foundation
// Only part of a promise protocol. It defines that it can be terminated
// Represents a return type that can either be a promise or a value
public enum PromiseOrValue<V> {
public typealias P = Promise<V>
case Promised(P)
case Value(P.ET)
static func of<V>(val: V) -> PromiseOrValue<V> {
return .Value(ErrorOptional<V>(val))
}
}
func wrap<T>(queue: Queue?, fn:(T) -> ()) -> (T) -> () {
if let q = queue {
return q.wrap(fn)
}
return fn
}
extension Queue {
/// wraps a void function and returns a new one. When
/// the new one is called it will be dispatched on the sender
func wrap<T>(fn:(T) -> ()) -> (T) -> () {
return { v in
self.dispatchAsync {
fn(v)
}
}
}
}
public struct Resolver<T> {
public typealias ET = ErrorOptional<T>
typealias P = Promise<T>
private let promise: P
init(promise: P) {
self.promise = promise
}
public func resolve(value: T) {
fulfill(ET(value))
}
public func reject(error: ErrorType) {
fulfill(ET(error))
}
/// resolves with the return value. Otherwise if it throws, it will return as an error type
public func attemptResolve(block: () throws -> T) {
fulfill(ET.attempt { return try block() })
}
public func fulfill(v: ET) {
promise.fulfill(v)
}
}
/// Useful for stuff that can only succeed and not return any errors
public typealias VoidPromiseType = Promise<Void>
public typealias VoidResolverType = Resolver<Void>
public class Promise<T> {
/// Error optional type
public typealias ET = ErrorOptional<T>
typealias PG = PGroup<T>
var pgroup: PG
typealias PV = PromiseOrValue<T>
typealias ValueType = T
private init(pgroup: PG) {
self.pgroup = pgroup
}
public class func resolve(value: T) -> Promise<T> {
return Promise<T>(pgroup: PGroup<T>.resolve(value))
}
public class func reject(error: ErrorType) -> Promise<T> {
return Promise<T>(pgroup: PGroup<T>.reject(error))
}
// Returns a promise and the resolver for it
public class func resolver() -> (Resolver<T>, Promise<T>) {
let p = Promise<T>()
let r = Resolver(promise: p)
return (r, p)
}
// An uninitialized one
init() {
pgroup = PG()
}
// splits the call based one rror or success
public func thenSplit<R>(queue: Queue? = nil, error: ((ErrorType) -> ())? = nil, success: T -> PromiseOrValue<R>) -> Promise<R> {
return self.then { (r:ET) -> PromiseOrValue<R> in
switch r {
case let .Error(e):
error?(e)
// TODO: improve this .Not very efficient
return PromiseOrValue.Value(Promise<R>.ET(e))
case let .Some(val):
return success(val)
}
}
}
public func then<R>(queue: Queue? = nil, handler: ET -> PromiseOrValue<R>) -> Promise<R> {
let (r, p) = Promise<R>.resolver()
self.then(queue) { v -> Void in
switch handler(v) {
case let .Promised(prom):
prom.then(handler: r.fulfill)
case let .Value(val):
r.fulfill(val)
}
}
return p
}
/// Terminating
func then(queue: Queue? = nil, handler: ET -> Void) {
self.pgroup.then(wrap(queue, fn: handler))
}
public func then<R>(queue: Queue? = nil, handler: ET -> Promise<R>.ET) -> Promise<R> {
let (r, p) = Promise<R>.resolver()
self.then(queue) { v -> Void in
r.fulfill(handler(v))
}
return p
}
/// Catches an error and propagates it in the optitional
///
/// Callers of this should use the .checkedGet on the input type to make it easy to propagate errors
///
/// Example:
///
/// p.thenChecked{ v throws in
/// return try v.checkedGet() + 3
/// }
public func thenChecked<R>(queue: Queue? = nil, handler: ET throws -> R) -> Promise<R> {
typealias RP = Promise<R>
typealias RET = RP.ET
return self.then(queue) { val -> ErrorOptional<R> in
do {
return RET(try handler(val))
} catch let e {
return RET(e)
}
}
}
private func fulfill(value: ET) {
pgroup.fulfill(value)
}
}

View File

@ -1,58 +0,0 @@
//
// Queue.swift
// SocketRocket
//
// Created by Mike Lewis on 7/30/15.
//
// Wrappers areound dispatch_queue_t
import Foundation
import Dispatch
/// Simple wrapper around dispatch_queue_t
public class Queue {
let queue: dispatch_queue_t
// used to check current queue
private var ctxKeyValue: UnsafeMutablePointer<Void> = nil
/// same as dispatch_get_main_queue()
public static let mainQueue = Queue(queue: dispatch_get_main_queue())
public static let defaultGlobalQueue = Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
public required init(queue: dispatch_queue_t) {
self.queue = queue
withUnsafeMutablePointer(&self.ctxKeyValue) { ptr in
self.ctxKeyValue = unsafeBitCast(ptr, UnsafeMutablePointer<Void>.self);
}
let destructor: dispatch_function_t! = nil
dispatch_queue_set_specific(self.queue, ctxKeyValue, ctxKeyValue, destructor)
}
public convenience init(label: String, attr: dispatch_queue_attr_t? = DISPATCH_QUEUE_SERIAL) {
self.init(queue: dispatch_queue_create(label, attr))
}
deinit {
let destructor: dispatch_function_t! = nil
dispatch_queue_set_specific(self.queue, ctxKeyValue, nil, destructor)
}
public func dispatchAsync(block: () -> Void) {
dispatch_async(queue, block)
}
/// Returns true if we're on the current queue
public func isCurrentQueue() -> Bool {
let currentContext = dispatch_get_specific(ctxKeyValue)
return currentContext == ctxKeyValue
}
public func checkIsCurrentQueue() {
precondition(isCurrentQueue(), "Expected to be current queue")
}
}

View File

@ -1,18 +0,0 @@
//
// SocketRocketIO.h
// SocketRocketIO
//
// Created by Mike Lewis on 7/30/15.
//
//
#import <Foundation/Foundation.h>
//! Project version number for SocketRocketIO.
FOUNDATION_EXPORT double SocketRocketIOVersionNumber;
//! Project version string for SocketRocketIO.
FOUNDATION_EXPORT const unsigned char SocketRocketIOVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <SocketRocketIO/PublicHeader.h>

View File

@ -1,168 +0,0 @@
//
// Unicode.swift
// SocketRocket
//
// Created by Mike Lewis on 8/6/15.
//
//
extension UTF8 {
/// Returns number of code units. Throws if its not the first bite of a unicode charactser
/// result includes selve
static func numCodeUnits(first: CodeUnit) throws -> Int {
guard first & 0b1100_0000 != 0b1000_0000 else {
throw Error.UTF8DecodeError
}
// If the first bit is 0, its a single code-point
if first & 0b1000_0000 == 0b0000_0000 {
return 1
}
if first & 0b1110_0000 == 0b1100_0000 {
return 2
}
if first & 0b1111_0000 == 0b1110_0000 {
return 3
}
if first & 0b1111_1000 == 0b1111_0000 {
return 4
}
throw Error.UTF8DecodeError
}
/// Returns the number of valid codeunits from the generator
static func numValidCodeUnits<G: GeneratorType where G.Element == CodeUnit>(var g: G) throws -> Int {
var numValidCodeUnits = 0
outOfCharacters:
for var c = g.next(); c != nil; c = g.next() {
let numCodeUnits = try UTF8.numCodeUnits(c!)
for _ in 0..<(numCodeUnits - 1) {
if let c = g.next() {
guard UTF8.isContinuation(c) else {
throw Error.UTF8DecodeError
}
} else {
break outOfCharacters
}
}
numValidCodeUnits += numCodeUnits
}
return numValidCodeUnits
}
}
struct RawUTF8Codec<CT: CollectionType, GT: GeneratorType where CT.Generator == GT, GT.Element == UInt8, CT.Index.Distance == Int, CT.Index: RandomAccessIndexType, CT.Generator.Element == UInt8, CT.SubSequence.Generator.Element == UInt8> : Codec {
typealias InType = CT
typealias OutType = String.UnicodeScalarView
typealias CodeUnit = UInt8
typealias UnicodeCodec = UTF8
var outputBuffer = String()
/// Used to buffer unfinished UTF8 Sequences
var inputBuffer = [CodeUnit]()
/// Consumes to our outputbuffer
mutating func consume<G: GeneratorType where G.Element == CodeUnit>(var g: G) throws {
var uc = UTF8()
while true {
switch uc.decode(&g) {
case .EmptyInput:
return
case .Error:
throw Error.UTF8DecodeError
case let .Result(scalar):
outputBuffer.append(scalar)
}
}
}
mutating func code(input: ValueOrEnd<AnyRandomAccessCollection<InType.Generator.Element>>) throws -> OutType {
defer {
outputBuffer.removeAll(keepCapacity: true)
}
switch input {
case .End:
if inputBuffer.isEmpty {
return "".unicodeScalars
} else {
throw Error.UTF8DecodeError
}
case let .Value(v):
let totalSize = inputBuffer.count + v.count
outputBuffer.reserveCapacity(Int(totalSize))
let numValidCodeUnits = try UTF8.numValidCodeUnits(inputBuffer.generate() + v.generate())
let numUnfinished = totalSize - numValidCodeUnits
// If this happens, we didn't get enough for even one character
if numUnfinished == totalSize {
inputBuffer += v
return "".unicodeScalars
}
if numUnfinished > 0 {
let truncatedG = v[v.startIndex..<v.endIndex.advancedBy(-numUnfinished)].generate()
let g = inputBuffer.generate() + truncatedG
try consume(g)
} else {
try consume(inputBuffer.generate() + v.generate())
}
inputBuffer.removeAll(keepCapacity: true)
if numUnfinished > 0 {
inputBuffer += v[v.endIndex.advancedBy(-numUnfinished)..<v.endIndex]
}
return outputBuffer.unicodeScalars
}
}
}
extension DispatchIO: AsyncReadable {
typealias Collection = UnsafeBufferPointer<UInt8>
func read(size: Collection.Index.Distance, queue: Queue, handler: (AnyRandomAccessCollection<Collection.Generator.Element>) throws -> ()) -> VoidPromiseType {
let (r, p) = VoidPromiseType.resolver()
dispatch_io_read(io, 0, size, queue.queue) { finished, data, error in
guard error == 0 else {
r.reject(Error.errorFromStatusCode(error)!)
return
}
do {
try data.apply { d in
try handler(AnyRandomAccessCollection(d))
}
} catch let e {
// TODO(don't double-call this error)
r.reject(e)
return
}
if finished {
r.resolve(Void())
}
}
return p
}
}

View File

@ -1,135 +0,0 @@
//
// ConcurrentTests.swift
// SocketRocket
//
// Created by Mike Lewis on 8/7/15.
//
//
@testable import SocketRocketIO
import XCTest
class ConcurrentTests: XCTestCase {
func testOnce_simple() {
var once = Once()
let e2 = expectationWithDescription("All done")
let g = dispatch_group_create()
let g2 = dispatch_group_create()
dispatch_group_enter(g)
dispatch_group_notify(g2, Queue.defaultGlobalQueue.queue) {
e2.fulfill()
}
for bit in 0..<8 {
let e = expectationWithDescription("Once filled")
for _ in 0..<1000 {
dispatch_group_enter(g2)
dispatch_group_notify(g, Queue.defaultGlobalQueue.queue) {
once.doMaybe(bit, block: {
e.fulfill()
})
dispatch_group_leave(g2)
}
}
}
dispatch_group_leave(g)
waitForExpectations()
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
func testPGroup_noerr() {
var p = PGroup<Int>()
p.fulfill(ErrorOptional(3))
for i in 0..<20 {
let e = self.expectationWithDescription("e \(i)")
p.then { v in
XCTAssertFalse(v.hasError)
e.fulfill()
}
}
self.waitForExpectations()
}
func testPGroup_after() {
var p = PGroup<Int>()
for i in 0..<20 {
let e = self.expectationWithDescription("e \(i)")
p.then { v in
XCTAssertFalse(v.hasError)
e.fulfill()
switch v {
case let .Some(val):
XCTAssertEqual(val, 3)
default:
XCTFail()
}
}
}
p.fulfill(ErrorOptional(3))
self.waitForExpectations()
}
func testPGroup_calledOnce() {
var p = PGroup<Int>()
for i in 0..<20 {
let e = self.expectationWithDescription("e \(i)")
p.then { v in
switch v {
case let .Some(val):
XCTAssertEqual(val, 3)
default:
XCTFail()
}
e.fulfill()
}
}
p.fulfill(ErrorOptional(3))
p.fulfill(ErrorOptional(4))
p.fulfill(ErrorOptional(Error.Canceled))
self.waitForExpectations()
}
func testPGroup_canceled() {
var p = PGroup<Int>()
for i in 0..<20 {
let e = self.expectationWithDescription("e \(i)")
p.then { v in
switch v {
case .Error(Error.Canceled):
break
default:
XCTFail()
}
e.fulfill()
}
}
p.cancel()
p.fulfill(ErrorOptional(3))
p.fulfill(ErrorOptional(4))
p.fulfill(ErrorOptional(Error.Canceled))
self.waitForExpectations()
}
}

Some files were not shown because too many files have changed in this diff Show More